btrfs-progs: prop: also allow "none" to disable compression
[platform/upstream/btrfs-progs.git] / qgroup.c
index 84f5fc1..fffdbb1 100644 (file)
--- a/qgroup.c
+++ b/qgroup.c
@@ -20,6 +20,8 @@
 #include <sys/ioctl.h>
 #include "ctree.h"
 #include "ioctl.h"
+#include "utils.h"
+#include <errno.h>
 
 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
@@ -76,49 +78,66 @@ struct btrfs_qgroup_list {
 /*
  * qgroupid,rfer,excl default to set
  */
-struct {
+static struct {
        char *name;
        char *column_name;
        int need_print;
+       unsigned unit_mode;
+       int max_len;
 } btrfs_qgroup_columns[] = {
        {
                .name           = "qgroupid",
                .column_name    = "Qgroupid",
                .need_print     = 1,
+               .unit_mode      = 0,
+               .max_len        = 8,
        },
        {
                .name           = "rfer",
                .column_name    = "Rfer",
                .need_print     = 1,
+               .unit_mode      = UNITS_DEFAULT,
+               .max_len        = 12,
        },
        {
                .name           = "excl",
                .column_name    = "Excl",
                .need_print     = 1,
+               .unit_mode      = UNITS_DEFAULT,
+               .max_len        = 12,
        },
        {       .name           = "max_rfer",
                .column_name    = "Max_rfer",
                .need_print     = 0,
+               .unit_mode      = UNITS_DEFAULT,
+               .max_len        = 12,
        },
        {
                .name           = "max_excl",
                .column_name    = "Max_excl",
                .need_print     = 0,
+               .unit_mode      = UNITS_DEFAULT,
+               .max_len        = 12,
        },
        {
                .name           = "parent",
                .column_name    = "Parent",
                .need_print     = 0,
+               .unit_mode      = 0,
+               .max_len        = 7,
        },
        {
                .name           = "child",
                .column_name    = "Child",
                .need_print     = 0,
+               .unit_mode      = 0,
+               .max_len        = 5,
        },
        {
                .name           = NULL,
                .column_name    = NULL,
                .need_print     = 0,
+               .unit_mode      = 0,
        },
 };
 
@@ -129,7 +148,7 @@ void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
 {
        int i;
 
-       BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
+       ASSERT(0 <= column && column <= BTRFS_QGROUP_ALL);
 
        if (column < BTRFS_QGROUP_ALL) {
                btrfs_qgroup_columns[column].need_print = 1;
@@ -139,69 +158,107 @@ void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
                btrfs_qgroup_columns[i].need_print = 1;
 }
 
-static void print_parent_column(struct btrfs_qgroup *qgroup)
+void btrfs_qgroup_setup_units(unsigned unit_mode)
+{
+       btrfs_qgroup_columns[BTRFS_QGROUP_RFER].unit_mode = unit_mode;
+       btrfs_qgroup_columns[BTRFS_QGROUP_EXCL].unit_mode = unit_mode;
+       btrfs_qgroup_columns[BTRFS_QGROUP_MAX_RFER].unit_mode = unit_mode;
+       btrfs_qgroup_columns[BTRFS_QGROUP_MAX_EXCL].unit_mode = unit_mode;
+}
+
+static int print_parent_column(struct btrfs_qgroup *qgroup)
 {
        struct btrfs_qgroup_list *list = NULL;
+       int len = 0;
 
        list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
-               printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
-                     ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
+               len += printf("%llu/%llu",
+                             btrfs_qgroup_level(list->qgroup->qgroupid),
+                             btrfs_qgroup_subvid(list->qgroup->qgroupid));
                if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
-                       printf(",");
+                       len += printf(",");
        }
        if (list_empty(&qgroup->qgroups))
-               printf("---");
+               len += printf("---");
+
+       return len;
 }
 
-static void print_child_column(struct btrfs_qgroup *qgroup)
+static int print_child_column(struct btrfs_qgroup *qgroup)
 {
        struct btrfs_qgroup_list *list = NULL;
+       int len = 0;
 
        list_for_each_entry(list, &qgroup->members, next_member) {
-               printf("%llu/%llu", (list->member)->qgroupid >> 48,
-                     ((1ll << 48) - 1) & (list->member)->qgroupid);
+               len += printf("%llu/%llu",
+                             btrfs_qgroup_level(list->member->qgroupid),
+                             btrfs_qgroup_subvid(list->member->qgroupid));
                if (!list_is_last(&list->next_member, &qgroup->members))
-                       printf(",");
+                       len += printf(",");
        }
        if (list_empty(&qgroup->members))
-               printf("---");
+               len += printf("---");
+
+       return len;
+}
+
+static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
+                                         int len)
+{
+       len = btrfs_qgroup_columns[column].max_len - len;
+       while (len--)
+               printf(" ");
 }
 
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
                                enum btrfs_qgroup_column_enum column)
 {
-       BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
+       int len;
+       int unit_mode = btrfs_qgroup_columns[column].unit_mode;
+       int max_len = btrfs_qgroup_columns[column].max_len;
+
+       ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
 
        switch (column) {
 
        case BTRFS_QGROUP_QGROUPID:
-               printf("%llu/%llu", qgroup->qgroupid >> 48,
-                      ((1ll << 48) - 1) & qgroup->qgroupid);
+               len = printf("%llu/%llu",
+                            btrfs_qgroup_level(qgroup->qgroupid),
+                            btrfs_qgroup_subvid(qgroup->qgroupid));
+               print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
                break;
        case BTRFS_QGROUP_RFER:
-               printf("%lld", qgroup->rfer);
+               len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
                break;
        case BTRFS_QGROUP_EXCL:
-               printf("%lld", qgroup->excl);
+               len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
                break;
        case BTRFS_QGROUP_PARENT:
-               print_parent_column(qgroup);
+               len = print_parent_column(qgroup);
+               print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
                break;
        case BTRFS_QGROUP_MAX_RFER:
-               printf("%llu", qgroup->max_rfer);
+               if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
+                       len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
+               else
+                       len = printf("%*s", max_len, "none");
                break;
        case BTRFS_QGROUP_MAX_EXCL:
-               printf("%llu", qgroup->max_excl);
+               if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
+                       len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
+               else
+                       len = printf("%*s", max_len, "none");
                break;
        case BTRFS_QGROUP_CHILD:
-               print_child_column(qgroup);
+               len = print_child_column(qgroup);
+               print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
                break;
        default:
                break;
        }
 }
 
-static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
+static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
 {
        int i;
 
@@ -210,12 +267,55 @@ static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
                        continue;
                print_qgroup_column(qgroup, i);
 
-               if (i != BTRFS_QGROUP_ALL - 1)
+               if (i != BTRFS_QGROUP_CHILD)
                        printf(" ");
        }
        printf("\n");
 }
 
+static void print_table_head(void)
+{
+       int i;
+       int len;
+       int max_len;
+
+       for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+               max_len = btrfs_qgroup_columns[i].max_len;
+               if (!btrfs_qgroup_columns[i].need_print)
+                       continue;
+               if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
+                       (i == BTRFS_QGROUP_CHILD))
+                       printf("%-*s", max_len, btrfs_qgroup_columns[i].name);
+               else
+                       printf("%*s", max_len, btrfs_qgroup_columns[i].name);
+               printf(" ");
+       }
+       printf("\n");
+       for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+               max_len = btrfs_qgroup_columns[i].max_len;
+               if (!btrfs_qgroup_columns[i].need_print)
+                       continue;
+               if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
+                       (i == BTRFS_QGROUP_CHILD)) {
+                       len = strlen(btrfs_qgroup_columns[i].name);
+                       while (len--)
+                               printf("-");
+                       len = max_len - strlen(btrfs_qgroup_columns[i].name);
+                       while (len--)
+                               printf(" ");
+               } else {
+                       len = max_len - strlen(btrfs_qgroup_columns[i].name);
+                       while (len--)
+                               printf(" ");
+                       len = strlen(btrfs_qgroup_columns[i].name);
+                       while (len--)
+                               printf("-");
+               }
+               printf(" ");
+       }
+       printf("\n");
+}
+
 static void qgroup_lookup_init(struct qgroup_lookup *tree)
 {
        tree->root.rb_node = NULL;
@@ -337,23 +437,17 @@ struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
        size = sizeof(struct btrfs_qgroup_comparer_set) +
               BTRFS_QGROUP_NCOMPS_INCREASE *
               sizeof(struct btrfs_qgroup_comparer);
-       set = malloc(size);
+       set = calloc(1, size);
        if (!set) {
-               fprintf(stderr, "memory allocation failed\n");
+               error("memory allocation failed");
                exit(1);
        }
 
-       memset(set, 0, size);
        set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
 
        return set;
 }
 
-void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
-{
-       free(comp_set);
-}
-
 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
                                enum btrfs_qgroup_comp_enum comparer,
                                int is_descending)
@@ -361,17 +455,21 @@ int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
        struct btrfs_qgroup_comparer_set *set = *comp_set;
        int size;
 
-       BUG_ON(!set);
-       BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
-       BUG_ON(set->ncomps > set->total);
+       ASSERT(set != NULL);
+       ASSERT(comparer < BTRFS_QGROUP_COMP_MAX);
+       ASSERT(set->ncomps <= set->total);
 
        if (set->ncomps == set->total) {
+               void *tmp;
+
                size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
                size = sizeof(*set) +
                       size * sizeof(struct btrfs_qgroup_comparer);
+               tmp = set;
                set = realloc(set, size);
                if (!set) {
-                       fprintf(stderr, "memory allocation failed\n");
+                       error("memory allocation failed");
+                       free(tmp);
                        exit(1);
                }
 
@@ -382,7 +480,7 @@ int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
                *comp_set = set;
        }
 
-       BUG_ON(set->comps[set->ncomps].comp_func);
+       ASSERT(set->comps[set->ncomps].comp_func == NULL);
 
        set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
        set->comps[set->ncomps].is_descending = is_descending;
@@ -514,7 +612,7 @@ static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
        if (pa && child) {
                list = malloc(sizeof(*list));
                if (!list) {
-                       fprintf(stderr, "memory allocation failed\n");
+                       error("memory allocation failed");
                        exit(1);
                }
                list->qgroup = pa;
@@ -541,12 +639,11 @@ static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
        if (!ret)
                return 0;
 
-       bq = malloc(sizeof(*bq));
+       bq = calloc(1, sizeof(*bq));
        if (!bq) {
-               printf("memory allocation failed\n");
+               error("memory allocation failed");
                exit(1);
        }
-       memset(bq, 0, sizeof(*bq));
        if (qgroupid) {
                bq->qgroupid = qgroupid;
                INIT_LIST_HEAD(&bq->qgroups);
@@ -573,7 +670,7 @@ static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
        if (parent && child) {
                list = malloc(sizeof(*list));
                if (!list) {
-                       fprintf(stderr, "memory allocation failed\n");
+                       error("memory allocation failed");
                        exit(1);
                }
                list->qgroup = parent;
@@ -583,14 +680,14 @@ static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
        }
        ret = qgroup_tree_insert(qgroup_lookup, bq);
        if (ret) {
-               printf("failed to insert tree %llu\n",
-                      bq->qgroupid);
+               error("failed to insert %llu into tree: %s",
+                      (unsigned long long)bq->qgroupid, strerror(-ret));
                exit(1);
        }
        return ret;
 }
 
-void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
+static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
 {
        struct btrfs_qgroup_list *list;
        while (!list_empty(&bq->qgroups)) {
@@ -612,7 +709,7 @@ void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
        free(bq);
 }
 
-void __free_all_qgroups(struct qgroup_lookup *root_tree)
+static void __free_all_qgroups(struct qgroup_lookup *root_tree)
 {
        struct btrfs_qgroup *entry;
        struct rb_node *n;
@@ -710,39 +807,37 @@ struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
        size = sizeof(struct btrfs_qgroup_filter_set) +
               BTRFS_QGROUP_NFILTERS_INCREASE *
               sizeof(struct btrfs_qgroup_filter);
-       set = malloc(size);
+       set = calloc(1, size);
        if (!set) {
-               fprintf(stderr, "memory allocation failed\n");
+               error("memory allocation failed");
                exit(1);
        }
-       memset(set, 0, size);
        set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
 
        return set;
 }
 
-void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
-{
-       free(filter_set);
-}
-
 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
                              enum btrfs_qgroup_filter_enum filter, u64 data)
 {
        struct btrfs_qgroup_filter_set *set = *filter_set;
        int size;
 
-       BUG_ON(!set);
-       BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
-       BUG_ON(set->nfilters > set->total);
+       ASSERT(set != NULL);
+       ASSERT(filter < BTRFS_QGROUP_FILTER_MAX);
+       ASSERT(set->nfilters <= set->total);
 
        if (set->nfilters == set->total) {
+               void *tmp;
+
                size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
                size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
 
+               tmp = set;
                set = realloc(set, size);
                if (!set) {
-                       fprintf(stderr, "memory allocation failed\n");
+                       error("memory allocation failed");
+                       free(tmp);
                        exit(1);
                }
                memset(&set->filters[set->total], 0,
@@ -751,7 +846,8 @@ int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
                set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
                *filter_set = set;
        }
-       BUG_ON(set->filters[set->nfilters].filter_func);
+
+       ASSERT(set->filters[set->nfilters].filter_func == NULL);
        set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
        set->filters[set->nfilters].data = data;
        set->nfilters++;
@@ -819,6 +915,87 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree,
        return 0;
 }
 
+static void __update_columns_max_len(struct btrfs_qgroup *bq,
+                                    enum btrfs_qgroup_column_enum column)
+{
+       struct btrfs_qgroup_list *list = NULL;
+       char tmp[100];
+       int len;
+       unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
+
+       ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
+
+       switch (column) {
+
+       case BTRFS_QGROUP_QGROUPID:
+               sprintf(tmp, "%llu/%llu",
+                       btrfs_qgroup_level(bq->qgroupid),
+                       btrfs_qgroup_subvid(bq->qgroupid));
+               len = strlen(tmp);
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       case BTRFS_QGROUP_RFER:
+               len = strlen(pretty_size_mode(bq->rfer, unit_mode));
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       case BTRFS_QGROUP_EXCL:
+               len = strlen(pretty_size_mode(bq->excl, unit_mode));
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       case BTRFS_QGROUP_MAX_RFER:
+               len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       case BTRFS_QGROUP_MAX_EXCL:
+               len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       case BTRFS_QGROUP_PARENT:
+               len = 0;
+               list_for_each_entry(list, &bq->qgroups, next_qgroup) {
+                       len += sprintf(tmp, "%llu/%llu",
+                               btrfs_qgroup_level(list->qgroup->qgroupid),
+                               btrfs_qgroup_subvid(list->qgroup->qgroupid));
+                       if (!list_is_last(&list->next_qgroup, &bq->qgroups))
+                               len += 1;
+               }
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       case BTRFS_QGROUP_CHILD:
+               len = 0;
+               list_for_each_entry(list, &bq->members, next_member) {
+                       len += sprintf(tmp, "%llu/%llu",
+                               btrfs_qgroup_level(list->member->qgroupid),
+                               btrfs_qgroup_subvid(list->member->qgroupid));
+                       if (!list_is_last(&list->next_member, &bq->members))
+                               len += 1;
+               }
+               if (btrfs_qgroup_columns[column].max_len < len)
+                       btrfs_qgroup_columns[column].max_len = len;
+               break;
+       default:
+               break;
+       }
+
+}
+
+static void update_columns_max_len(struct btrfs_qgroup *bq)
+{
+       int i;
+
+       for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+               if (!btrfs_qgroup_columns[i].need_print)
+                       continue;
+               __update_columns_max_len(bq, i);
+       }
+}
+
 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
                                 struct qgroup_lookup *sort_tree,
                                 struct btrfs_qgroup_filter_set *filter_set,
@@ -836,12 +1013,25 @@ static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
                entry = rb_entry(n, struct btrfs_qgroup, rb_node);
 
                ret = filter_qgroup(entry, filter_set);
-               if (ret)
+               if (ret) {
                        sort_tree_insert(sort_tree, entry, comp_set);
 
+                       update_columns_max_len(entry);
+               }
                n = rb_prev(n);
        }
 }
+
+static inline void print_status_flag_warning(u64 flags)
+{
+       if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
+               warning("quota disabled, qgroup data may be out of date");
+       else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
+               warning("rescan is running, qgroup data may be incorrect");
+       else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
+               warning("qgroup data inconsistent, rescan recommended");
+}
+
 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 {
        int ret;
@@ -850,7 +1040,6 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
        struct btrfs_ioctl_search_header *sh;
        unsigned long off = 0;
        unsigned int i;
-       int e;
        struct btrfs_qgroup_info_item *info;
        struct btrfs_qgroup_limit_item *limit;
        struct btrfs_qgroup *bq;
@@ -865,7 +1054,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 
        sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
        sk->max_type = BTRFS_QGROUP_RELATION_KEY;
-       sk->min_type = BTRFS_QGROUP_INFO_KEY;
+       sk->min_type = BTRFS_QGROUP_STATUS_KEY;
        sk->max_objectid = (u64)-1;
        sk->max_offset = (u64)-1;
        sk->max_transid = (u64)-1;
@@ -875,13 +1064,9 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 
        while (1) {
                ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-               e = errno;
-               if (ret < 0) {
-                       fprintf(stderr,
-                               "ERROR: can't perform the search - %s\n",
-                               strerror(e));
-                       return ret;
-               }
+               if (ret < 0)
+                       return -errno;
+
                /* the ioctl returns the number of item it found in nr_items */
                if (sk->nr_items == 0)
                        break;
@@ -896,7 +1081,17 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
                                                                  off);
                        off += sizeof(*sh);
 
-                       if (sh->type == BTRFS_QGROUP_INFO_KEY) {
+                       if (btrfs_search_header_type(sh)
+                           == BTRFS_QGROUP_STATUS_KEY) {
+                               struct btrfs_qgroup_status_item *si;
+                               u64 flags;
+
+                               si = (struct btrfs_qgroup_status_item *)
+                                    (args.buf + off);
+                               flags = btrfs_stack_qgroup_status_flags(si);
+                               print_status_flag_warning(flags);
+                       } else if (btrfs_search_header_type(sh)
+                                  == BTRFS_QGROUP_INFO_KEY) {
                                info = (struct btrfs_qgroup_info_item *)
                                       (args.buf + off);
                                a1 = btrfs_stack_qgroup_info_generation(info);
@@ -908,9 +1103,12 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
                                a5 =
                                  btrfs_stack_qgroup_info_exclusive_compressed
                                  (info);
-                               add_qgroup(qgroup_lookup, sh->offset, a1, a2,
-                                          a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
-                       } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
+                               add_qgroup(qgroup_lookup,
+                                       btrfs_search_header_offset(sh), a1,
+                                       a2, a3, a4, a5, 0, 0, 0, 0, 0, NULL,
+                                       NULL);
+                       } else if (btrfs_search_header_type(sh)
+                                  == BTRFS_QGROUP_LIMIT_KEY) {
                                limit = (struct btrfs_qgroup_limit_item *)
                                    (args.buf + off);
 
@@ -923,33 +1121,38 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
                                     (limit);
                                a5 = btrfs_stack_qgroup_limit_rsv_exclusive
                                     (limit);
-                               add_qgroup(qgroup_lookup, sh->offset, 0, 0,
-                                          0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
-                       } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
-                               if (sh->offset < sh->objectid)
+                               add_qgroup(qgroup_lookup,
+                                          btrfs_search_header_offset(sh), 0,
+                                          0, 0, 0, 0, a1, a2, a3, a4, a5,
+                                          NULL, NULL);
+                       } else if (btrfs_search_header_type(sh)
+                                  == BTRFS_QGROUP_RELATION_KEY) {
+                               if (btrfs_search_header_offset(sh)
+                                   < btrfs_search_header_objectid(sh))
                                        goto skip;
                                bq = qgroup_tree_search(qgroup_lookup,
-                                                       sh->offset);
+                                       btrfs_search_header_offset(sh));
                                if (!bq)
                                        goto skip;
                                bq1 = qgroup_tree_search(qgroup_lookup,
-                                                        sh->objectid);
+                                        btrfs_search_header_objectid(sh));
                                if (!bq1)
                                        goto skip;
-                               add_qgroup(qgroup_lookup, sh->offset, 0, 0,
-                                          0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
+                               add_qgroup(qgroup_lookup,
+                                          btrfs_search_header_offset(sh), 0,
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
                        } else
                                goto done;
 skip:
-                       off += sh->len;
+                       off += btrfs_search_header_len(sh);
 
                        /*
                         * record the mins in sk so we can make sure the
                         * next search doesn't repeat this root
                         */
-                       sk->min_type = sh->type;
-                       sk->min_offset = sh->offset;
-                       sk->min_objectid = sh->objectid;
+                       sk->min_type = btrfs_search_header_type(sh);
+                       sk->min_offset = btrfs_search_header_offset(sh);
+                       sk->min_objectid = btrfs_search_header_objectid(sh);
                }
                sk->nr_items = 4096;
                /*
@@ -972,10 +1175,12 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
        struct rb_node *n;
        struct btrfs_qgroup *entry;
 
+       print_table_head();
+
        n = rb_first(&qgroup_lookup->root);
        while (n) {
                entry = rb_entry(n, struct btrfs_qgroup, sort_node);
-               print_single_qgroup_default(entry);
+               print_single_qgroup_table(entry);
                n = rb_next(n);
        }
 }
@@ -997,29 +1202,12 @@ int btrfs_show_qgroups(int fd,
        print_all_qgroups(&sort_tree);
 
        __free_all_qgroups(&qgroup_lookup);
-       btrfs_qgroup_free_filter_set(filter_set);
+       free(filter_set);
+       free(comp_set);
        return ret;
 }
 
-u64 btrfs_get_path_rootid(int fd)
-{
-       int  ret;
-       struct btrfs_ioctl_ino_lookup_args args;
-
-       memset(&args, 0, sizeof(args));
-       args.objectid = BTRFS_FIRST_FREE_OBJECTID;
-
-       ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
-       if (ret < 0) {
-               fprintf(stderr,
-                       "ERROR: can't perform the search -%s\n",
-                       strerror(errno));
-               return ret;
-       }
-       return args.treeid;
-}
-
-int btrfs_qgroup_parse_sort_string(char *opt_arg,
+int btrfs_qgroup_parse_sort_string(const char *opt_arg,
                                   struct btrfs_qgroup_comparer_set **comps)
 {
        int order;
@@ -1027,8 +1215,14 @@ int btrfs_qgroup_parse_sort_string(char *opt_arg,
        char *p;
        char **ptr_argv;
        int what_to_sort;
+       char *opt_tmp;
+       int ret = 0;
 
-       while ((p = strtok(opt_arg, ",")) != NULL) {
+       opt_tmp = strdup(opt_arg);
+       if (!opt_tmp)
+               return -ENOMEM;
+
+       while ((p = strtok(opt_tmp, ",")) != NULL) {
                flag = 0;
                ptr_argv = all_sort_items;
 
@@ -1048,10 +1242,10 @@ int btrfs_qgroup_parse_sort_string(char *opt_arg,
                        ptr_argv++;
                }
 
-               if (flag == 0)
-                       return -1;
-
-               else {
+               if (flag == 0) {
+                       ret = -1;
+                       goto out;
+               else {
                        if (*p == '+') {
                                order = 0;
                                p++;
@@ -1062,42 +1256,19 @@ int btrfs_qgroup_parse_sort_string(char *opt_arg,
                                order = 0;
 
                        what_to_sort = btrfs_qgroup_get_sort_item(p);
-                       if (what_to_sort < 0)
-                               return -1;
+                       if (what_to_sort < 0) {
+                               ret = -1;
+                               goto out;
+                       }
                        btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
                }
-               opt_arg = NULL;
+               free(opt_tmp);
+               opt_tmp = NULL;
        }
 
-       return 0;
-}
-
-u64 parse_qgroupid(char *p)
-{
-       char *s = strchr(p, '/');
-       char *ptr_src_end = p + strlen(p);
-       char *ptr_parse_end = NULL;
-       u64 level;
-       u64 id;
-
-       if (!s) {
-               id = strtoull(p, &ptr_parse_end, 10);
-               if (ptr_parse_end != ptr_src_end)
-                       goto err;
-               return id;
-       }
-       level = strtoull(p, &ptr_parse_end, 10);
-       if (ptr_parse_end != s)
-               goto err;
-
-       id = strtoull(s+1, &ptr_parse_end, 10);
-       if (ptr_parse_end != ptr_src_end)
-               goto  err;
-
-       return (level << 48) | id;
-err:
-       fprintf(stderr, "ERROR:invalid qgroupid\n");
-       exit(-1);
+out:
+       free(opt_tmp);
+       return ret;
 }
 
 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
@@ -1121,8 +1292,8 @@ qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
 
        out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
        if (out == NULL) {
-               fprintf(stderr, "ERROR: Not enough memory\n");
-               return 13;
+               error("not enough memory");
+               return -ENOMEM;
        }
 
        if (*inherit) {
@@ -1149,8 +1320,8 @@ int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
        int pos = 0;
 
        if (qgroupid == 0) {
-               fprintf(stderr, "ERROR: bad qgroup specification\n");
-               return 12;
+               error("invalid qgroup specification, qgroupid must not 0");
+               return -EINVAL;
        }
 
        if (*inherit)
@@ -1176,8 +1347,8 @@ int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
        p = strchr(arg, ':');
        if (!p) {
 bad:
-               fprintf(stderr, "ERROR: bad copy specification\n");
-               return 12;
+               error("invalid copy specification, missing separator :");
+               return -EINVAL;
        }
        *p = 0;
        qgroup_src = parse_qgroupid(arg);