X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=qgroup.c;h=11659e8394dda15fcfac2731de41b23bf7896ed5;hb=f44a0550123be92245943d832df64134c5fd6241;hp=94d1febf4b07f679a0fadec0ce30f471a051421c;hpb=72f1835ae4ed46c56d47fe10e9189708e7704246;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/qgroup.c b/qgroup.c index 94d1feb..11659e8 100644 --- a/qgroup.c +++ b/qgroup.c @@ -20,6 +20,8 @@ #include #include "ctree.h" #include "ioctl.h" +#include "utils.h" +#include #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX) #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX) @@ -80,53 +82,62 @@ 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, - .max_len = 4, + .unit_mode = UNITS_DEFAULT, + .max_len = 12, }, { .name = "excl", .column_name = "Excl", .need_print = 1, - .max_len = 4, + .unit_mode = UNITS_DEFAULT, + .max_len = 12, }, { .name = "max_rfer", .column_name = "Max_rfer", .need_print = 0, - .max_len = 8, + .unit_mode = UNITS_DEFAULT, + .max_len = 12, }, { .name = "max_excl", .column_name = "Max_excl", .need_print = 0, - .max_len = 8, + .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, }, }; @@ -137,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; @@ -147,14 +158,23 @@ void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column) btrfs_qgroup_columns[i].need_print = 1; } +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) { - len += 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)) len += printf(","); } @@ -170,8 +190,9 @@ static int print_child_column(struct btrfs_qgroup *qgroup) int len = 0; list_for_each_entry(list, &qgroup->members, next_member) { - len += 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)) len += printf(","); } @@ -192,35 +213,41 @@ static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column, 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: - len = 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: - len = printf("%lld", qgroup->rfer); - print_qgroup_column_add_blank(BTRFS_QGROUP_RFER, len); + len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode)); break; case BTRFS_QGROUP_EXCL: - len = printf("%lld", qgroup->excl); - print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL, len); + len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode)); break; case BTRFS_QGROUP_PARENT: len = print_parent_column(qgroup); print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len); break; case BTRFS_QGROUP_MAX_RFER: - len = printf("%llu", qgroup->max_rfer); - print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER, len); + 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: - len = printf("%llu", qgroup->max_excl); - print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL, len); + 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: len = print_child_column(qgroup); @@ -246,34 +273,45 @@ static void print_single_qgroup_table(struct btrfs_qgroup *qgroup) printf("\n"); } -static void print_table_head() +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; - printf("%s", btrfs_qgroup_columns[i].name); - len = btrfs_qgroup_columns[i].max_len - - strlen(btrfs_qgroup_columns[i].name); - while (len--) - printf(" "); + 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; - - len = strlen(btrfs_qgroup_columns[i].name); - while (len--) - printf("-"); - len = btrfs_qgroup_columns[i].max_len - - strlen(btrfs_qgroup_columns[i].name); + 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(" "); - while (len--) - printf(" "); } printf("\n"); } @@ -399,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) @@ -423,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); } @@ -444,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; @@ -542,114 +578,119 @@ static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree, return NULL; } -static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid, - u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl, - u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl, - u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa, - struct btrfs_qgroup *child) +/* + * Lookup or insert btrfs_qgroup into qgroup_lookup. + * + * Search a btrfs_qgroup with @qgroupid from the @qgroup_lookup. If not found, + * initialize a btrfs_qgroup with the given qgroupid and insert it to the + * @qgroup_lookup. + * + * Return the pointer to the btrfs_qgroup if found or if inserted successfully. + * Return ERR_PTR if any error occurred. + */ +static struct btrfs_qgroup *get_or_add_qgroup( + struct qgroup_lookup *qgroup_lookup, u64 qgroupid) { struct btrfs_qgroup *bq; - struct btrfs_qgroup_list *list; + int ret; bq = qgroup_tree_search(qgroup_lookup, qgroupid); - if (!bq || bq->qgroupid != qgroupid) - return -ENOENT; + if (bq) + return bq; - if (generation) - bq->generation = generation; - if (rfer) - bq->rfer = rfer; - if (rfer_cmpr) - bq->rfer_cmpr = rfer_cmpr; - if (excl) - bq->excl = excl; - if (excl_cmpr) - bq->excl_cmpr = excl_cmpr; - if (flags) - bq->flags = flags; - if (max_rfer) - bq->max_rfer = max_rfer; - if (max_excl) - bq->max_excl = max_excl; - if (rsv_rfer) - bq->rsv_rfer = rsv_rfer; - if (pa && child) { - list = malloc(sizeof(*list)); - if (!list) { - fprintf(stderr, "memory allocation failed\n"); - exit(1); - } - list->qgroup = pa; - list->member = child; - list_add_tail(&list->next_qgroup, &child->qgroups); - list_add_tail(&list->next_member, &pa->members); + bq = calloc(1, sizeof(*bq)); + if (!bq) { + error("memory allocation failed"); + return ERR_PTR(-ENOMEM); + } + + bq->qgroupid = qgroupid; + INIT_LIST_HEAD(&bq->qgroups); + INIT_LIST_HEAD(&bq->members); + + ret = qgroup_tree_insert(qgroup_lookup, bq); + if (ret) { + error("failed to insert %llu into tree: %s", + (unsigned long long)bq->qgroupid, strerror(-ret)); + free(bq); + return ERR_PTR(ret); } + + return bq; +} + +static int update_qgroup_info(struct qgroup_lookup *qgroup_lookup, u64 qgroupid, + struct btrfs_qgroup_info_item *info) +{ + struct btrfs_qgroup *bq; + + bq = get_or_add_qgroup(qgroup_lookup, qgroupid); + if (IS_ERR_OR_NULL(bq)) + return PTR_ERR(bq); + + bq->generation = btrfs_stack_qgroup_info_generation(info); + bq->rfer = btrfs_stack_qgroup_info_referenced(info); + bq->rfer_cmpr = btrfs_stack_qgroup_info_referenced_compressed(info); + bq->excl = btrfs_stack_qgroup_info_exclusive(info); + bq->excl_cmpr = btrfs_stack_qgroup_info_exclusive_compressed(info); + return 0; } -static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid, - u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl, - u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl, - u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent, - struct btrfs_qgroup *child) +static int update_qgroup_limit(struct qgroup_lookup *qgroup_lookup, + u64 qgroupid, + struct btrfs_qgroup_limit_item *limit) { struct btrfs_qgroup *bq; - struct btrfs_qgroup_list *list; - int ret; - ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer, - rfer_cmpr, excl, excl_cmpr, flags, max_rfer, - max_excl, rsv_rfer, rsv_excl, parent, child); - if (!ret) - return 0; + bq = get_or_add_qgroup(qgroup_lookup, qgroupid); + if (IS_ERR_OR_NULL(bq)) + return PTR_ERR(bq); - bq = malloc(sizeof(*bq)); - if (!bq) { - printf("memory allocation failed\n"); - exit(1); - } - memset(bq, 0, sizeof(*bq)); - if (qgroupid) { - bq->qgroupid = qgroupid; - INIT_LIST_HEAD(&bq->qgroups); - INIT_LIST_HEAD(&bq->members); + bq->flags = btrfs_stack_qgroup_limit_flags(limit); + bq->max_rfer = btrfs_stack_qgroup_limit_max_referenced(limit); + bq->max_excl = btrfs_stack_qgroup_limit_max_exclusive(limit); + bq->rsv_rfer = btrfs_stack_qgroup_limit_rsv_referenced(limit); + bq->rsv_excl = btrfs_stack_qgroup_limit_rsv_exclusive(limit); + + return 0; +} + +static int update_qgroup_relation(struct qgroup_lookup *qgroup_lookup, + u64 child_id, u64 parent_id) +{ + struct btrfs_qgroup *child; + struct btrfs_qgroup *parent; + struct btrfs_qgroup_list *list; + + child = qgroup_tree_search(qgroup_lookup, child_id); + if (!child) { + error("cannot find the qgroup %llu/%llu", + btrfs_qgroup_level(child_id), + btrfs_qgroup_subvid(child_id)); + return -ENOENT; } - if (generation) - bq->generation = generation; - if (rfer) - bq->rfer = rfer; - if (rfer_cmpr) - bq->rfer_cmpr = rfer_cmpr; - if (excl) - bq->excl = excl; - if (excl_cmpr) - bq->excl_cmpr = excl_cmpr; - if (flags) - bq->flags = flags; - if (max_rfer) - bq->max_rfer = max_rfer; - if (max_excl) - bq->max_excl = max_excl; - if (rsv_rfer) - bq->rsv_rfer = rsv_rfer; - if (parent && child) { - list = malloc(sizeof(*list)); - if (!list) { - fprintf(stderr, "memory allocation failed\n"); - exit(1); - } - list->qgroup = parent; - list->member = child; - list_add_tail(&list->next_qgroup, &child->qgroups); - list_add_tail(&list->next_member, &parent->members); + + parent = qgroup_tree_search(qgroup_lookup, parent_id); + if (!parent) { + error("cannot find the qgroup %llu/%llu", + btrfs_qgroup_level(parent_id), + btrfs_qgroup_subvid(parent_id)); + return -ENOENT; } - ret = qgroup_tree_insert(qgroup_lookup, bq); - if (ret) { - printf("failed to insert tree %llu\n", - bq->qgroupid); - exit(1); + + list = malloc(sizeof(*list)); + if (!list) { + error("memory allocation failed"); + return -ENOMEM; } - return ret; + + list->qgroup = parent; + list->member = child; + list_add_tail(&list->next_qgroup, &child->qgroups); + list_add_tail(&list->next_member, &parent->members); + + return 0; } static void __free_btrfs_qgroup(struct btrfs_qgroup *bq) @@ -772,39 +813,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, @@ -813,7 +852,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++; @@ -884,41 +924,40 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree, static void __update_columns_max_len(struct btrfs_qgroup *bq, enum btrfs_qgroup_column_enum column) { - BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0); 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", (bq->qgroupid >> 48), - bq->qgroupid & ((1ll << 48) - 1)); + 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: - sprintf(tmp, "%llu", bq->rfer); - len = strlen(tmp); + 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: - sprintf(tmp, "%llu", bq->excl); - len = strlen(tmp); + 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: - sprintf(tmp, "%llu", bq->max_rfer); - len = strlen(tmp); + 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: - sprintf(tmp, "%llu", bq->max_excl); - len = strlen(tmp); + 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; @@ -926,8 +965,8 @@ static void __update_columns_max_len(struct btrfs_qgroup *bq, len = 0; list_for_each_entry(list, &bq->qgroups, next_qgroup) { len += sprintf(tmp, "%llu/%llu", - (list->qgroup)->qgroupid >> 48, - ((1ll << 48) - 1) & (list->qgroup)->qgroupid); + btrfs_qgroup_level(list->qgroup->qgroupid), + btrfs_qgroup_subvid(list->qgroup->qgroupid)); if (!list_is_last(&list->next_qgroup, &bq->qgroups)) len += 1; } @@ -938,8 +977,8 @@ static void __update_columns_max_len(struct btrfs_qgroup *bq, len = 0; list_for_each_entry(list, &bq->members, next_member) { len += sprintf(tmp, "%llu/%llu", - (list->member)->qgroupid >> 48, - ((1ll << 48) - 1) & (list->member)->qgroupid); + btrfs_qgroup_level(list->member->qgroupid), + btrfs_qgroup_subvid(list->member->qgroupid)); if (!list_is_last(&list->next_member, &bq->members)) len += 1; } @@ -988,6 +1027,17 @@ static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups, 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; @@ -996,22 +1046,18 @@ 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_status_item *si; struct btrfs_qgroup_info_item *info; struct btrfs_qgroup_limit_item *limit; - struct btrfs_qgroup *bq; - struct btrfs_qgroup *bq1; - u64 a1; - u64 a2; - u64 a3; - u64 a4; - u64 a5; + u64 flags; + u64 qgroupid; + u64 qgroupid1; memset(&args, 0, sizeof(args)); 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; @@ -1021,13 +1067,19 @@ 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 (errno == ENOENT) { + error("can't list qgroups: quotas not enabled"); + ret = -ENOTTY; + } else { + error("can't list qgroups: %s", + strerror(errno)); + ret = -errno; + } + + break; } + /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; @@ -1042,60 +1094,56 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup) off); off += sizeof(*sh); - if (sh->type == BTRFS_QGROUP_INFO_KEY) { + switch (btrfs_search_header_type(sh)) { + case BTRFS_QGROUP_STATUS_KEY: + si = (struct btrfs_qgroup_status_item *) + (args.buf + off); + flags = btrfs_stack_qgroup_status_flags(si); + + print_status_flag_warning(flags); + break; + case BTRFS_QGROUP_INFO_KEY: + qgroupid = btrfs_search_header_offset(sh); info = (struct btrfs_qgroup_info_item *) (args.buf + off); - a1 = btrfs_stack_qgroup_info_generation(info); - a2 = btrfs_stack_qgroup_info_referenced(info); - a3 = - btrfs_stack_qgroup_info_referenced_compressed - (info); - a4 = btrfs_stack_qgroup_info_exclusive(info); - 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) { + + ret = update_qgroup_info(qgroup_lookup, + qgroupid, info); + break; + case BTRFS_QGROUP_LIMIT_KEY: + qgroupid = btrfs_search_header_offset(sh); limit = (struct btrfs_qgroup_limit_item *) - (args.buf + off); - - a1 = btrfs_stack_qgroup_limit_flags(limit); - a2 = btrfs_stack_qgroup_limit_max_referenced - (limit); - a3 = btrfs_stack_qgroup_limit_max_exclusive - (limit); - a4 = btrfs_stack_qgroup_limit_rsv_referenced - (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) - goto skip; - bq = qgroup_tree_search(qgroup_lookup, - sh->offset); - if (!bq) - goto skip; - bq1 = qgroup_tree_search(qgroup_lookup, - sh->objectid); - if (!bq1) - goto skip; - add_qgroup(qgroup_lookup, sh->offset, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1); - } else - goto done; -skip: - off += sh->len; + (args.buf + off); + + ret = update_qgroup_limit(qgroup_lookup, + qgroupid, limit); + break; + case BTRFS_QGROUP_RELATION_KEY: + qgroupid = btrfs_search_header_offset(sh); + qgroupid1 = btrfs_search_header_objectid(sh); + + if (qgroupid < qgroupid1) + break; + + ret = update_qgroup_relation(qgroup_lookup, + qgroupid, qgroupid1); + break; + default: + return ret; + } + + if (ret) + return ret; + + 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; /* @@ -1108,7 +1156,6 @@ skip: break; } -done: return ret; } @@ -1145,29 +1192,10 @@ int btrfs_show_qgroups(int fd, print_all_qgroups(&sort_tree); __free_all_qgroups(&qgroup_lookup); - btrfs_qgroup_free_filter_set(filter_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; @@ -1175,8 +1203,15 @@ 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; + + p = strtok(opt_tmp, ","); + while (p) { flag = 0; ptr_argv = all_sort_items; @@ -1196,10 +1231,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++; @@ -1210,42 +1245,18 @@ 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; + p = strtok(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) @@ -1269,8 +1280,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) { @@ -1297,8 +1308,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) @@ -1324,8 +1335,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);