The patchset enhanced btrfs qgroup show command. Firstly, we restructure show_qgroups, make it easy to add new features. And then we add ''-p'' ''-c'', ''-l'',and ''-e'' options to print the parent qgroup id, child qgroup id, max referenced size and max exclusive size of qgroup respectively, add ''-F'' and ''-f'' option to list qgroups that impact the given path. Besides that, the users may want to sort qgroups according to some items. For this case, we introduce ''--sort'' option. With this option, we can sort the qgroup by qgroupid, rfer, excl, max_rfer and max_excl. And finally, Since there are so many columns can be output, the users may be confused about the output result, so i add ''-t'' option to print the result as a table. We can pull this patchset from the URL git://github.com/miaoxie/btrfs-progs.git qgroup Thanks Miao --- Wang Shilong (9): Btrfs-progs: restructure show_qgroups Btrfs-progs: introduces ''-p'' option to print the ID of the parent qgroups Btrfs-progs: introduces ''-c'' option to print the ID of the child qgroups Btrfs-progs: introduce ''-l'' option to print max referenced size of qgroups Btrfs-progs: introduce ''-e'' option to print max exclusive size of qgroups Btrfs-progs: list all qgroups impact given path(include ancestral qgroups) Btrfs-progs: list all qgroups impact given path(exclude ancestral qgroups) Btrfs-progs: enhance btrfs qgroup show to sort qgroups Btrfs-progs: enhance btrfs qgroup to print the result as a table cmds-qgroup.c | 198 +++++----- ctree.h | 11 + qgroup.c | 1216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qgroup.h | 71 ++++ 4 files changed, 1396 insertions(+), 100 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> The current show_qgroups() just shows a little information, and it is hard to add some functions which the users need in the future, so i restructure it, make it easy to add new functions. In order to improve the scalability of show_qgroups(), i add some important structures: struct qgroup_lookup { struct rb_root root; } /* *store qgroup''s information */ struct btrfs_qgroup { struct rb_node rb_node; u64 qgroupid; u64 generation; u64 rfer; u64 rfer_cmpr; u64 excl_cmpr; u64 flags; u64 max_rfer; u64 max_excl; u64 rsv_rfer; u64 rsv_excl; struct list_head qgroups; struct list_head members; } /* *glue structure to represent the relations *between qgroups */ struct btrfs_qgroup_list { struct list_head next_qgroups; struct list_head next_member; struct btrfs_qgroup *qgroup; struct btrfs_qgroup *member; } The above 3 structures are used to manage all the information of qgroups. struct { char *name; char *column_name; int need_print; } btrfs_qgroup_columns[] We define a arrary to manage all the columns that can be outputed, and use a member variant(->need_print) to control the output of the relative column. Some columns are outputed by default. But we can change it according to the requirement of the users. For example: if outputing max referenced size of qgroup is needed,the function ''btrfs_qgroup_setup_column()'' will be called, and the parameter ''BTRFS_QGROUP_MAX_RFER'' (extend in the future) will be passsed to the function. After the function is done, when showing qgroups, max referenced size of qgroup will be output. Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 96 +---------- ctree.h | 11 ++ qgroup.c | 509 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qgroup.h | 9 ++ 4 files changed, 530 insertions(+), 95 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index 70019d0..2d5b59b 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -103,100 +103,6 @@ static int qgroup_create(int create, int argc, char **argv) return 0; } -void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info) -{ - printf("%llu/%llu %lld %lld\n", objectid >> 48, - objectid & ((1ll << 48) - 1), - btrfs_stack_qgroup_info_referenced(info), - btrfs_stack_qgroup_info_exclusive(info)); -} - -int list_qgroups(int fd) -{ - int ret; - struct btrfs_ioctl_search_args args; - struct btrfs_ioctl_search_key *sk = &args.key; - struct btrfs_ioctl_search_header *sh; - unsigned long off = 0; - unsigned int i; - int e; - struct btrfs_qgroup_info_item *info; - - memset(&args, 0, sizeof(args)); - - /* search in the quota tree */ - sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID; - - /* - * set the min and max to backref keys. The search will - * only send back this type of key now. - */ - sk->max_type = BTRFS_QGROUP_INFO_KEY; - sk->min_type = BTRFS_QGROUP_INFO_KEY; - sk->max_objectid = 0; - sk->max_offset = (u64)-1; - sk->max_transid = (u64)-1; - - /* just a big number, doesn''t matter much */ - sk->nr_items = 4096; - - 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; - } - /* the ioctl returns the number of item it found in nr_items */ - if (sk->nr_items == 0) - break; - - off = 0; - - /* - * for each item, pull the key out of the header and then - * read the root_ref item it contains - */ - for (i = 0; i < sk->nr_items; i++) { - sh = (struct btrfs_ioctl_search_header *)(args.buf + - off); - off += sizeof(*sh); - - if (sh->objectid != 0) - goto done; - - if (sh->type != BTRFS_QGROUP_INFO_KEY) - goto done; - - info = (struct btrfs_qgroup_info_item *) - (args.buf + off); - print_qgroup_info(sh->offset, info); - - off += sh->len; - - /* - * record the mins in sk so we can make sure the - * next search doesn''t repeat this root - */ - sk->min_offset = sh->offset; - } - sk->nr_items = 4096; - /* - * this iteration is done, step forward one qgroup for the next - * ioctl - */ - if (sk->min_offset < (u64)-1) - sk->min_offset++; - else - break; - } - -done: - return ret; -} - static int parse_limit(const char *p, unsigned long long *s) { char *endptr; @@ -313,7 +219,7 @@ static int cmd_qgroup_show(int argc, char **argv) return 12; } - ret = list_qgroups(fd); + ret = btrfs_show_qgroups(fd); if (ret < 0) { fprintf(stderr, "ERROR: can''t list qgroups\n"); return 30; diff --git a/ctree.h b/ctree.h index 293b24f..2c1b16b 100644 --- a/ctree.h +++ b/ctree.h @@ -1949,6 +1949,17 @@ BTRFS_SETGET_FUNCS(qgroup_limit_rsv_referenced, struct btrfs_qgroup_limit_item, BTRFS_SETGET_FUNCS(qgroup_limit_rsv_exclusive, struct btrfs_qgroup_limit_item, rsv_exclusive, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags, + struct btrfs_qgroup_limit_item, flags, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_referenced, + struct btrfs_qgroup_limit_item, max_referenced, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_exclusive, + struct btrfs_qgroup_limit_item, max_exclusive, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_referenced, + struct btrfs_qgroup_limit_item, rsv_referenced, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_exclusive, + struct btrfs_qgroup_limit_item, rsv_exclusive, 64); + /* this returns the number of file bytes represented by the inline item. * If an item is compressed, this is the uncompressed size */ diff --git a/qgroup.c b/qgroup.c index dafde12..097811e 100644 --- a/qgroup.c +++ b/qgroup.c @@ -17,7 +17,516 @@ */ #include "qgroup.h" +#include <sys/ioctl.h> #include "ctree.h" +#include "ioctl.h" + +struct qgroup_lookup { + struct rb_root root; +}; + +struct btrfs_qgroup { + struct rb_node rb_node; + u64 qgroupid; + + /* + * info_item + */ + u64 generation; + u64 rfer; /*referenced*/ + u64 rfer_cmpr; /*referenced compressed*/ + u64 excl; /*exclusive*/ + u64 excl_cmpr; /*exclusive compressed*/ + + /* + *limit_item + */ + u64 flags; /*which limits are set*/ + u64 max_rfer; + u64 max_excl; + u64 rsv_rfer; + u64 rsv_excl; + + /*qgroups this group is member of*/ + struct list_head qgroups; + /*qgroups that are members of this group*/ + struct list_head members; +}; + +/* + * glue structure to represent the relations + * between qgroups + */ +struct btrfs_qgroup_list { + struct list_head next_qgroup; + struct list_head next_member; + struct btrfs_qgroup *qgroup; + struct btrfs_qgroup *member; +}; + +/* + * qgroupid,rfer,excl default to set + */ +struct { + char *name; + char *column_name; + int need_print; +} btrfs_qgroup_columns[] = { + { + .name = "qgroupid", + .column_name = "Qgroupid", + .need_print = 1, + }, + { + .name = "rfer", + .column_name = "Rfer", + .need_print = 1, + }, + { + .name = "excl", + .column_name = "Excl", + .need_print = 1, + }, + { + .name = NULL, + .column_name = NULL, + .need_print = 0, + }, +}; + +void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column) +{ + int i; + + BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL); + + if (column < BTRFS_QGROUP_ALL) { + btrfs_qgroup_columns[column].need_print = 1; + return; + } + for (i = 0; i < BTRFS_QGROUP_ALL; i++) + btrfs_qgroup_columns[i].need_print = 1; +} + +static void print_qgroup_column(struct btrfs_qgroup *qgroup, + enum btrfs_qgroup_column_enum column) +{ + BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0); + + switch (column) { + + case BTRFS_QGROUP_QGROUPID: + printf("%llu/%llu", qgroup->qgroupid >> 48, + ((1ll << 48) - 1) & qgroup->qgroupid); + break; + case BTRFS_QGROUP_RFER: + printf("%llu", qgroup->rfer); + break; + case BTRFS_QGROUP_EXCL: + printf("%llu", qgroup->excl); + break; + default: + break; + } +} + +static void print_single_qgroup_default(struct btrfs_qgroup *qgroup) +{ + int i; + + for (i = 0; i < BTRFS_QGROUP_ALL; i++) { + if (!btrfs_qgroup_columns[i].need_print) + continue; + print_qgroup_column(qgroup, i); + + if (i != BTRFS_QGROUP_ALL - 1) + printf(" "); + } + printf("\n"); +} + +static void qgroup_lookup_init(struct qgroup_lookup *tree) +{ + tree->root.rb_node = NULL; +} + +static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1, + struct btrfs_qgroup *entry2, + int is_descending) +{ + + int ret; + + if (entry1->qgroupid > entry2->qgroupid) + ret = 1; + else if (entry1->qgroupid < entry2->qgroupid) + ret = -1; + else + ret = 0; + + return is_descending ? -ret : ret; +} + +/* + * insert a new root into the tree. returns the existing root entry + * if one is already there. qgroupid is used + * as the key + */ +static int qgroup_tree_insert(struct qgroup_lookup *root_tree, + struct btrfs_qgroup *ins) +{ + + struct rb_node **p = &root_tree->root.rb_node; + struct rb_node *parent = NULL; + struct btrfs_qgroup *curr; + int ret; + + while (*p) { + parent = *p; + curr = rb_entry(parent, struct btrfs_qgroup, rb_node); + + ret = comp_entry_with_qgroupid(ins, curr, 0); + if (ret < 0) + p = &(*p)->rb_left; + else if (ret > 0) + p = &(*p)->rb_right; + else + return -EEXIST; + } + rb_link_node(&ins->rb_node, parent, p); + rb_insert_color(&ins->rb_node, &root_tree->root); + return 0; +} + +/* + *find a given qgroupid in the tree. We return the smallest one, + *rb_next can be used to move forward looking for more if required + */ +static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree, + u64 qgroupid) +{ + struct rb_node *n = root_tree->root.rb_node; + struct btrfs_qgroup *entry; + struct btrfs_qgroup tmp; + int ret; + + tmp.qgroupid = qgroupid; + + while (n) { + entry = rb_entry(n, struct btrfs_qgroup, rb_node); + + ret = comp_entry_with_qgroupid(&tmp, entry, 0); + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else + return entry; + + } + 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) +{ + struct btrfs_qgroup *bq; + struct btrfs_qgroup_list *list; + + bq = qgroup_tree_search(qgroup_lookup, qgroupid); + if (!bq || bq->qgroupid != qgroupid) + 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 (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); + } + 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) +{ + 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 = 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); + } + 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); + } + ret = qgroup_tree_insert(qgroup_lookup, bq); + if (ret) { + printf("failed to insert tree %llu\n", + bq->qgroupid); + exit(1); + } + return ret; +} + +void __free_btrfs_qgroup(struct btrfs_qgroup *bq) +{ + struct btrfs_qgroup_list *list; + while (!list_empty(&bq->qgroups)) { + list = list_entry((&bq->qgroups)->next, + struct btrfs_qgroup_list, + next_qgroup); + list_del(&list->next_qgroup); + list_del(&list->next_member); + free(list); + } + while (!list_empty(&bq->members)) { + list = list_entry((&bq->members)->next, + struct btrfs_qgroup_list, + next_member); + list_del(&list->next_qgroup); + list_del(&list->next_member); + free(list); + } + free(bq); +} + +void __free_all_qgroups(struct qgroup_lookup *root_tree) +{ + struct btrfs_qgroup *entry; + struct rb_node *n; + + n = rb_first(&root_tree->root); + while (n) { + entry = rb_entry(n, struct btrfs_qgroup, rb_node); + rb_erase(n, &root_tree->root); + __free_btrfs_qgroup(entry); + + n = rb_first(&root_tree->root); + } +} + +static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup) +{ + int ret; + struct btrfs_ioctl_search_args args; + struct btrfs_ioctl_search_key *sk = &args.key; + 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; + struct btrfs_qgroup *bq1; + u64 a1; + u64 a2; + u64 a3; + u64 a4; + u64 a5; + + 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->max_objectid = (u64)-1; + sk->max_offset = (u64)-1; + sk->max_transid = (u64)-1; + sk->nr_items = 4096; + + qgroup_lookup_init(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; + } + /* the ioctl returns the number of item it found in nr_items */ + if (sk->nr_items == 0) + break; + + off = 0; + /* + * for each item, pull the key out of the header and then + * read the root_ref item it contains + */ + for (i = 0; i < sk->nr_items; i++) { + sh = (struct btrfs_ioctl_search_header *)(args.buf + + off); + off += sizeof(*sh); + + if (sh->type == BTRFS_QGROUP_INFO_KEY) { + 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) { + 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; + + /* + * 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->nr_items = 4096; + /* + * this iteration is done, step forward one qgroup for the next + * ioctl + */ + if (sk->min_offset < (u64)-1) + sk->min_offset++; + else + break; + } + +done: + return ret; +} + +static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup) +{ + + struct rb_node *n; + struct btrfs_qgroup *entry; + + n = rb_first(&qgroup_lookup->root); + while (n) { + entry = rb_entry(n, struct btrfs_qgroup, rb_node); + print_single_qgroup_default(entry); + n = rb_next(n); + } +} + +int btrfs_show_qgroups(int fd) +{ + + struct qgroup_lookup qgroup_lookup; + int ret; + + ret = __qgroups_search(fd, &qgroup_lookup); + if (ret) + return ret; + + print_all_qgroups(&qgroup_lookup); + __free_all_qgroups(&qgroup_lookup); + + return ret; +} u64 parse_qgroupid(char *p) { diff --git a/qgroup.h b/qgroup.h index ad14c88..138c48c 100644 --- a/qgroup.h +++ b/qgroup.h @@ -22,6 +22,15 @@ #include "ioctl.h" #include "kerncompat.h" +enum btrfs_qgroup_column_enum { + BTRFS_QGROUP_QGROUPID, + BTRFS_QGROUP_RFER, + BTRFS_QGROUP_EXCL, + BTRFS_QGROUP_ALL, +}; + +int btrfs_show_qgroups(int fd); +void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column); u64 parse_qgroupid(char *p); int qgroup_inherit_size(struct btrfs_qgroup_inherit *p); int qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:45 UTC
[PATCH 2/9] Btrfs-progs: introduces ''-p'' option to print the ID of the parent qgroups
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduces ''-p'' option to print the ID of the parent qgroups. You may use it like: btrfs qgroup show -p <path> For Example: qgroupid(2/0) / \ / \ / \ qgroupid(1/0) qgroupid(1/1) \ / \ / qgroupid(0/1) If we use the command: btrfs qgroup show -p <path> The result will output 0/1 -- -- 1/0,1/1 1/0 -- -- 2/0 1/1 -- -- 2/0 2/0 -- -- -- Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 24 +++++++++++++++++++++--- qgroup.c | 22 ++++++++++++++++++++++ qgroup.h | 1 + 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index 2d5b59b..f402587 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,20 +199,38 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show <path>", + "btrfs qgroup show -p <path>", "Show all subvolume quota groups.", + "-p print parent qgroup id", NULL }; static int cmd_qgroup_show(int argc, char **argv) { int ret = 0; + char *path; int fd; - char *path = argv[1]; + int c; + + optind = 1; + while (1) { + c = getopt(argc, argv, "p"); + if (c < 0) + break; - if (check_argc_exact(argc, 2)) + switch (c) { + case ''p'': + btrfs_qgroup_setup_print_column( + BTRFS_QGROUP_PARENT); + break; + default: + usage(cmd_qgroup_show_usage); + } + } + if (check_argc_exact(argc - optind, 1)) usage(cmd_qgroup_show_usage); + path = argv[optind]; fd = open_file_or_dir(path); if (fd < 0) { fprintf(stderr, "ERROR: can''t access ''%s''\n", path); diff --git a/qgroup.c b/qgroup.c index 097811e..ebe7d17 100644 --- a/qgroup.c +++ b/qgroup.c @@ -88,6 +88,11 @@ struct { .need_print = 1, }, { + .name = "parent", + .column_name = "Parent", + .need_print = 0, + }, + { .name = NULL, .column_name = NULL, .need_print = 0, @@ -108,6 +113,20 @@ 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) +{ + struct btrfs_qgroup_list *list = NULL; + + list_for_each_entry(list, &qgroup->qgroups, next_qgroup) { + printf("%llu/%llu", (list->qgroup)->qgroupid >> 48, + ((1ll << 48) - 1) & (list->qgroup)->qgroupid); + if (!list_is_last(&list->next_qgroup, &qgroup->qgroups)) + printf(","); + } + if (list_empty(&qgroup->qgroups)) + printf("---"); +} + static void print_qgroup_column(struct btrfs_qgroup *qgroup, enum btrfs_qgroup_column_enum column) { @@ -125,6 +144,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup, case BTRFS_QGROUP_EXCL: printf("%llu", qgroup->excl); break; + case BTRFS_QGROUP_PARENT: + print_parent_column(qgroup); + break; default: break; } diff --git a/qgroup.h b/qgroup.h index 138c48c..e1de675 100644 --- a/qgroup.h +++ b/qgroup.h @@ -26,6 +26,7 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_QGROUPID, BTRFS_QGROUP_RFER, BTRFS_QGROUP_EXCL, + BTRFS_QGROUP_PARENT, BTRFS_QGROUP_ALL, }; -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:46 UTC
[PATCH 3/9] Btrfs-progs: introduces ''-c'' option to print the ID of the child qgroups
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduces ''-c'' option to print the ID of the child qgroups. You may use it like: btrfs qgroup show -c <path> For Example: qgroupid(2/0) / \ / \ / \ qgroupid(1/0) qgroupid(1/1) \ / \ / qgroupid(0/1) If we use the command: btrfs qgroup show -c <path> The result will output 0/1 -- -- -- 1/0 -- -- 0/1 1/1 -- -- 0/1 2/0 -- -- 1/0,1/1 Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 9 +++++++-- qgroup.c | 22 ++++++++++++++++++++++ qgroup.h | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index f402587..f182c90 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,9 +199,10 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show -p <path>", + "btrfs qgroup show -pc <path>", "Show all subvolume quota groups.", "-p print parent qgroup id", + "-c print child qgroup id", NULL }; @@ -214,7 +215,7 @@ static int cmd_qgroup_show(int argc, char **argv) optind = 1; while (1) { - c = getopt(argc, argv, "p"); + c = getopt(argc, argv, "pc"); if (c < 0) break; @@ -223,6 +224,10 @@ static int cmd_qgroup_show(int argc, char **argv) btrfs_qgroup_setup_print_column( BTRFS_QGROUP_PARENT); break; + case ''c'': + btrfs_qgroup_setup_print_column( + BTRFS_QGROUP_CHILD); + break; default: usage(cmd_qgroup_show_usage); } diff --git a/qgroup.c b/qgroup.c index ebe7d17..3bfc408 100644 --- a/qgroup.c +++ b/qgroup.c @@ -93,6 +93,11 @@ struct { .need_print = 0, }, { + .name = "child", + .column_name = "Child", + .need_print = 0, + }, + { .name = NULL, .column_name = NULL, .need_print = 0, @@ -127,6 +132,20 @@ static void print_parent_column(struct btrfs_qgroup *qgroup) printf("---"); } +static void print_child_column(struct btrfs_qgroup *qgroup) +{ + struct btrfs_qgroup_list *list = NULL; + + list_for_each_entry(list, &qgroup->members, next_member) { + printf("%llu/%llu", (list->member)->qgroupid >> 48, + ((1ll << 48) - 1) & (list->member)->qgroupid); + if (!list_is_last(&list->next_member, &qgroup->members)) + printf(","); + } + if (list_empty(&qgroup->members)) + printf("---"); +} + static void print_qgroup_column(struct btrfs_qgroup *qgroup, enum btrfs_qgroup_column_enum column) { @@ -147,6 +166,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup, case BTRFS_QGROUP_PARENT: print_parent_column(qgroup); break; + case BTRFS_QGROUP_CHILD: + print_child_column(qgroup); + break; default: break; } diff --git a/qgroup.h b/qgroup.h index e1de675..02c78be 100644 --- a/qgroup.h +++ b/qgroup.h @@ -27,6 +27,7 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_RFER, BTRFS_QGROUP_EXCL, BTRFS_QGROUP_PARENT, + BTRFS_QGROUP_CHILD, BTRFS_QGROUP_ALL, }; -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:47 UTC
[PATCH 4/9] Btrfs-progs: introduce ''-l'' option to print max referenced size of qgroups
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduces ''-l'' option to print max referenced size of qgroups. You may use it like: btrfs qgroup show -l <path> Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 9 +++++++-- qgroup.c | 7 +++++++ qgroup.h | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index f182c90..a0156a6 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,10 +199,11 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show -pc <path>", + "btrfs qgroup show -pcl <path>", "Show all subvolume quota groups.", "-p print parent qgroup id", "-c print child qgroup id", + "-l print max referenced size of qgroup", NULL }; @@ -215,7 +216,7 @@ static int cmd_qgroup_show(int argc, char **argv) optind = 1; while (1) { - c = getopt(argc, argv, "pc"); + c = getopt(argc, argv, "pcl"); if (c < 0) break; @@ -228,6 +229,10 @@ static int cmd_qgroup_show(int argc, char **argv) btrfs_qgroup_setup_print_column( BTRFS_QGROUP_CHILD); break; + case ''l'': + btrfs_qgroup_setup_print_column( + BTRFS_QGROUP_MAX_RFER); + break; default: usage(cmd_qgroup_show_usage); } diff --git a/qgroup.c b/qgroup.c index 3bfc408..31f3a16 100644 --- a/qgroup.c +++ b/qgroup.c @@ -87,6 +87,10 @@ struct { .column_name = "Excl", .need_print = 1, }, + { .name = "max_rfer", + .column_name = "Max_rfer", + .need_print = 0, + }, { .name = "parent", .column_name = "Parent", @@ -163,6 +167,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup, case BTRFS_QGROUP_EXCL: printf("%llu", qgroup->excl); break; + case BTRFS_QGROUP_MAX_RFER: + printf("%llu", qgroup->max_rfer); + break; case BTRFS_QGROUP_PARENT: print_parent_column(qgroup); break; diff --git a/qgroup.h b/qgroup.h index 02c78be..a212913 100644 --- a/qgroup.h +++ b/qgroup.h @@ -26,6 +26,7 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_QGROUPID, BTRFS_QGROUP_RFER, BTRFS_QGROUP_EXCL, + BTRFS_QGROUP_MAX_RFER, BTRFS_QGROUP_PARENT, BTRFS_QGROUP_CHILD, BTRFS_QGROUP_ALL, -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:47 UTC
[PATCH 5/9] Btrfs-progs: introduce ''-e'' option to print max exclusive size of qgroups
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduce ''-e'' option to print max exclusive size of qgroups. You may use it like this: btrfs qgroup -e <path> Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 9 +++++++-- qgroup.c | 8 ++++++++ qgroup.h | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index a0156a6..e020335 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,11 +199,12 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show -pcl <path>", + "btrfs qgroup show -pcle <path>", "Show all subvolume quota groups.", "-p print parent qgroup id", "-c print child qgroup id", "-l print max referenced size of qgroup", + "-e print max exclusive size of qgroup", NULL }; @@ -216,7 +217,7 @@ static int cmd_qgroup_show(int argc, char **argv) optind = 1; while (1) { - c = getopt(argc, argv, "pcl"); + c = getopt(argc, argv, "pcle"); if (c < 0) break; @@ -233,6 +234,10 @@ static int cmd_qgroup_show(int argc, char **argv) btrfs_qgroup_setup_print_column( BTRFS_QGROUP_MAX_RFER); break; + case ''e'': + btrfs_qgroup_setup_print_column( + BTRFS_QGROUP_MAX_EXCL); + break; default: usage(cmd_qgroup_show_usage); } diff --git a/qgroup.c b/qgroup.c index 31f3a16..94cd202 100644 --- a/qgroup.c +++ b/qgroup.c @@ -92,6 +92,11 @@ struct { .need_print = 0, }, { + .name = "max_excl", + .column_name = "Max_excl", + .need_print = 0, + }, + { .name = "parent", .column_name = "Parent", .need_print = 0, @@ -170,6 +175,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup, case BTRFS_QGROUP_MAX_RFER: printf("%llu", qgroup->max_rfer); break; + case BTRFS_QGROUP_MAX_EXCL: + printf("%llu", qgroup->max_excl); + break; case BTRFS_QGROUP_PARENT: print_parent_column(qgroup); break; diff --git a/qgroup.h b/qgroup.h index a212913..a23da83 100644 --- a/qgroup.h +++ b/qgroup.h @@ -27,6 +27,7 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_RFER, BTRFS_QGROUP_EXCL, BTRFS_QGROUP_MAX_RFER, + BTRFS_QGROUP_MAX_EXCL, BTRFS_QGROUP_PARENT, BTRFS_QGROUP_CHILD, BTRFS_QGROUP_ALL, -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:48 UTC
[PATCH 6/9] Btrfs-progs: list all qgroups impact given path(include ancestral qgroups)
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduces ''-F'' option which can help you filter the qgroups by the path name, you may use it like: btrfs qgroup show -F <path> For example: qgroupid(2/0) / \ / \ qgroupid(1/0) / \ / \ / \ qgroupid(0/1) qgroupid(0/2) sub1 sub2 / \ / \ dir1 file1 If we use the command: btrfs qgroup show -F sub1/dir1 The result will output 0/1 -- -- 1/0 -- -- 2/0 -- -- ''-F'' option help you list all qgroups impact given path. (include ancestral qgroups). Signed-off-by: Wang shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 25 ++++-- qgroup.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- qgroup.h | 27 ++++++- 3 files changed, 281 insertions(+), 10 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index e020335..b6cdb53 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,12 +199,14 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show -pcle <path>", - "Show all subvolume quota groups.", + "btrfs qgroup show -pcleF <path>", + "Show subvolume quota groups.", "-p print parent qgroup id", "-c print child qgroup id", "-l print max referenced size of qgroup", "-e print max exclusive size of qgroup", + "-F list all qgroups which impact the given path" + "(include ancestral qgroups)", NULL }; @@ -214,10 +216,15 @@ static int cmd_qgroup_show(int argc, char **argv) char *path; int fd; int c; + u64 qgroupid; + int filter_flag = 0; + + struct btrfs_qgroup_filter_set *filter_set; + filter_set = btrfs_qgroup_alloc_filter_set(); optind = 1; while (1) { - c = getopt(argc, argv, "pcle"); + c = getopt(argc, argv, "pcleF"); if (c < 0) break; @@ -238,6 +245,9 @@ static int cmd_qgroup_show(int argc, char **argv) btrfs_qgroup_setup_print_column( BTRFS_QGROUP_MAX_EXCL); break; + case ''F'': + filter_flag |= 0x1; + break; default: usage(cmd_qgroup_show_usage); } @@ -251,8 +261,13 @@ static int cmd_qgroup_show(int argc, char **argv) fprintf(stderr, "ERROR: can''t access ''%s''\n", path); return 12; } - - ret = btrfs_show_qgroups(fd); + if (filter_flag) { + qgroupid = btrfs_get_path_rootid(fd); + btrfs_qgroup_setup_filter(&filter_set, + BTRFS_QGROUP_FILTER_ALL_PARENT, + qgroupid); + } + ret = btrfs_show_qgroups(fd, filter_set); if (ret < 0) { fprintf(stderr, "ERROR: can''t list qgroups\n"); return 30; diff --git a/qgroup.c b/qgroup.c index 94cd202..6cb71e9 100644 --- a/qgroup.c +++ b/qgroup.c @@ -21,12 +21,20 @@ #include "ctree.h" #include "ioctl.h" +#define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX) + struct qgroup_lookup { struct rb_root root; }; struct btrfs_qgroup { struct rb_node rb_node; + struct rb_node sort_node; + /* + *all_parent_node is used to + *filter a qgroup''s all parent + */ + struct rb_node all_parent_node; u64 qgroupid; /* @@ -113,6 +121,8 @@ struct { }, }; +static btrfs_qgroup_filter_func all_filter_funcs[]; + void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column) { int i; @@ -433,6 +443,205 @@ void __free_all_qgroups(struct qgroup_lookup *root_tree) } } +static int filter_all_parent_insert(struct qgroup_lookup *sort_tree, + struct btrfs_qgroup *bq) +{ + struct rb_node **p = &sort_tree->root.rb_node; + struct rb_node *parent = NULL; + struct btrfs_qgroup *curr; + int ret; + + while (*p) { + parent = *p; + curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node); + + ret = comp_entry_with_qgroupid(bq, curr, 0); + if (ret < 0) + p = &(*p)->rb_left; + else if (ret > 0) + p = &(*p)->rb_right; + else + return -EEXIST; + } + rb_link_node(&bq->all_parent_node, parent, p); + rb_insert_color(&bq->all_parent_node, &sort_tree->root); + return 0; +} + +static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data) +{ + struct qgroup_lookup lookup; + struct qgroup_lookup *ql = &lookup; + struct btrfs_qgroup_list *list; + struct rb_node *n; + struct btrfs_qgroup *qgroup + (struct btrfs_qgroup *)(unsigned long)data; + + if (data == 0) + return 0; + if (bq->qgroupid == qgroup->qgroupid) + return 1; + + qgroup_lookup_init(ql); + filter_all_parent_insert(ql, qgroup); + n = rb_first(&ql->root); + while (n) { + qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node); + if (!list_empty(&qgroup->qgroups)) { + list_for_each_entry(list, &qgroup->qgroups, + next_qgroup) { + if ((list->qgroup)->qgroupid == bq->qgroupid) + return 1; + filter_all_parent_insert(ql, list->qgroup); + } + } + rb_erase(n, &ql->root); + n = rb_first(&ql->root); + } + return 0; +} + +static btrfs_qgroup_filter_func all_filter_funcs[] = { + [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent, +}; + +struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void) +{ + struct btrfs_qgroup_filter_set *set; + int size; + + size = sizeof(struct btrfs_qgroup_filter_set) + + BTRFS_QGROUP_NFILTERS_INCREASE * + sizeof(struct btrfs_qgroup_filter); + set = malloc(size); + if (!set) { + fprintf(stderr, "memory allocation failed\n"); + 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); + + if (set->nfilters == set->total) { + size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE; + size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter); + + set = realloc(set, size); + if (!set) { + fprintf(stderr, "memory allocation failed\n"); + exit(1); + } + memset(&set->filters[set->total], 0, + BTRFS_QGROUP_NFILTERS_INCREASE * + sizeof(struct btrfs_qgroup_filter)); + set->total += BTRFS_QGROUP_NFILTERS_INCREASE; + *filter_set = set; + } + BUG_ON(set->filters[set->nfilters].filter_func); + set->filters[set->nfilters].filter_func = all_filter_funcs[filter]; + set->filters[set->nfilters].data = data; + set->nfilters++; + return 0; +} + +static int filter_qgroup(struct btrfs_qgroup *bq, + struct btrfs_qgroup_filter_set *set) +{ + int i, ret; + + if (!set || !set->nfilters) + return 1; + for (i = 0; i < set->nfilters; i++) { + if (!set->filters[i].filter_func) + break; + ret = set->filters[i].filter_func(bq, set->filters[i].data); + if (!ret) + return 0; + } + return 1; +} + +static void pre_process_filter_set(struct qgroup_lookup *lookup, + struct btrfs_qgroup_filter_set *set) +{ + int i; + struct btrfs_qgroup *qgroup_for_filter = NULL; + + for (i = 0; i < set->nfilters; i++) { + + if (set->filters[i].filter_func == filter_by_all_parent) { + qgroup_for_filter = qgroup_tree_search(lookup, + set->filters[i].data); + set->filters[i].data + (u64)(unsigned long)qgroup_for_filter; + } + } +} + +static int sort_tree_insert(struct qgroup_lookup *sort_tree, + struct btrfs_qgroup *bq) +{ + struct rb_node **p = &sort_tree->root.rb_node; + struct rb_node *parent = NULL; + struct btrfs_qgroup *curr; + int ret; + + while (*p) { + parent = *p; + curr = rb_entry(parent, struct btrfs_qgroup, sort_node); + + ret = comp_entry_with_qgroupid(bq, curr, 0); + if (ret < 0) + p = &(*p)->rb_left; + else if (ret > 0) + p = &(*p)->rb_right; + else + return -EEXIST; + } + rb_link_node(&bq->sort_node, parent, p); + rb_insert_color(&bq->sort_node, &sort_tree->root); + return 0; +} + +static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups, + struct qgroup_lookup *sort_tree, + struct btrfs_qgroup_filter_set *filter_set) +{ + struct rb_node *n; + struct btrfs_qgroup *entry; + int ret; + + qgroup_lookup_init(sort_tree); + pre_process_filter_set(all_qgroups, filter_set); + + n = rb_last(&all_qgroups->root); + while (n) { + entry = rb_entry(n, struct btrfs_qgroup, rb_node); + + ret = filter_qgroup(entry, filter_set); + if (ret) + sort_tree_insert(sort_tree, entry); + + n = rb_prev(n); + } +} static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup) { int ret; @@ -565,28 +774,50 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup) n = rb_first(&qgroup_lookup->root); while (n) { - entry = rb_entry(n, struct btrfs_qgroup, rb_node); + entry = rb_entry(n, struct btrfs_qgroup, sort_node); print_single_qgroup_default(entry); n = rb_next(n); } } -int btrfs_show_qgroups(int fd) +int btrfs_show_qgroups(int fd, + struct btrfs_qgroup_filter_set *filter_set) { struct qgroup_lookup qgroup_lookup; + struct qgroup_lookup sort_tree; int ret; ret = __qgroups_search(fd, &qgroup_lookup); if (ret) return ret; + __filter_all_qgroups(&qgroup_lookup, &sort_tree, + filter_set); + print_all_qgroups(&sort_tree); - print_all_qgroups(&qgroup_lookup); __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; +} + u64 parse_qgroupid(char *p) { char *s = strchr(p, ''/''); diff --git a/qgroup.h b/qgroup.h index a23da83..30844fe 100644 --- a/qgroup.h +++ b/qgroup.h @@ -22,6 +22,21 @@ #include "ioctl.h" #include "kerncompat.h" +struct btrfs_qgroup; + +typedef int (*btrfs_qgroup_filter_func)(struct btrfs_qgroup *, u64); + +struct btrfs_qgroup_filter { + btrfs_qgroup_filter_func filter_func; + u64 data; +}; + +struct btrfs_qgroup_filter_set { + int total; + int nfilters; + struct btrfs_qgroup_filter filters[0]; +}; + enum btrfs_qgroup_column_enum { BTRFS_QGROUP_QGROUPID, BTRFS_QGROUP_RFER, @@ -33,8 +48,18 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_ALL, }; -int btrfs_show_qgroups(int fd); +enum btrfs_qgroup_filter_enum { + BTRFS_QGROUP_FILTER_ALL_PARENT, + BTRFS_QGROUP_FILTER_MAX, +}; + +u64 btrfs_get_path_rootid(int fd); +int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *); void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column); +struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void); +void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set); +int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set, + enum btrfs_qgroup_filter_enum, u64 data); u64 parse_qgroupid(char *p); int qgroup_inherit_size(struct btrfs_qgroup_inherit *p); int qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:50 UTC
[PATCH 7/9] Btrfs-progs: list all qgroups impact given path(exclude ancestral qgroups)
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduces ''-f'' option which can help you filter the qgroups by the path name, you may use it like: btrfs qgroup show -f <path> For example: qgroupid(2/0) / \ / \ qgroupid(1/0) / \ / \ / \ qgroupid(0/1) qgroupid(0/2) sub1 sub2 / \ / \ dir1 file1 If we use the command: btrfs qgroup show -f sub1/dir1 The result will output 0/1 -- -- ''-f'' option helps you list all qgroups impact given path. (exclude ancestral qgroups) Signed-off-by: Wang shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 14 ++++++++++++-- qgroup.c | 16 +++++++++++++++- qgroup.h | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index b6cdb53..9447179 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -207,6 +207,8 @@ static const char * const cmd_qgroup_show_usage[] = { "-e print max exclusive size of qgroup", "-F list all qgroups which impact the given path" "(include ancestral qgroups)", + "-f list all qgroups which impact the given path" + "(exclude ancestral qgroups)", NULL }; @@ -224,7 +226,7 @@ static int cmd_qgroup_show(int argc, char **argv) optind = 1; while (1) { - c = getopt(argc, argv, "pcleF"); + c = getopt(argc, argv, "pcleFf"); if (c < 0) break; @@ -248,6 +250,9 @@ static int cmd_qgroup_show(int argc, char **argv) case ''F'': filter_flag |= 0x1; break; + case ''f'': + filter_flag |= 0x2; + break; default: usage(cmd_qgroup_show_usage); } @@ -263,9 +268,14 @@ static int cmd_qgroup_show(int argc, char **argv) } if (filter_flag) { qgroupid = btrfs_get_path_rootid(fd); - btrfs_qgroup_setup_filter(&filter_set, + if (filter_flag & 0x1) + btrfs_qgroup_setup_filter(&filter_set, BTRFS_QGROUP_FILTER_ALL_PARENT, qgroupid); + if (filter_flag & 0x2) + btrfs_qgroup_setup_filter(&filter_set, + BTRFS_QGROUP_FILTER_PARENT, + qgroupid); } ret = btrfs_show_qgroups(fd, filter_set); if (ret < 0) { diff --git a/qgroup.c b/qgroup.c index 6cb71e9..b8640dc 100644 --- a/qgroup.c +++ b/qgroup.c @@ -468,6 +468,18 @@ static int filter_all_parent_insert(struct qgroup_lookup *sort_tree, return 0; } +static int filter_by_parent(struct btrfs_qgroup *bq, u64 data) +{ + struct btrfs_qgroup *qgroup + (struct btrfs_qgroup *)(unsigned long)data; + + if (data == 0) + return 0; + if (qgroup->qgroupid == bq->qgroupid) + return 1; + return 0; +} + static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data) { struct qgroup_lookup lookup; @@ -502,6 +514,7 @@ static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data) } static btrfs_qgroup_filter_func all_filter_funcs[] = { + [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent, [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent, }; @@ -586,7 +599,8 @@ static void pre_process_filter_set(struct qgroup_lookup *lookup, for (i = 0; i < set->nfilters; i++) { - if (set->filters[i].filter_func == filter_by_all_parent) { + if (set->filters[i].filter_func == filter_by_all_parent + || set->filters[i].filter_func == filter_by_parent) { qgroup_for_filter = qgroup_tree_search(lookup, set->filters[i].data); set->filters[i].data diff --git a/qgroup.h b/qgroup.h index 30844fe..d1165fd 100644 --- a/qgroup.h +++ b/qgroup.h @@ -49,6 +49,7 @@ enum btrfs_qgroup_column_enum { }; enum btrfs_qgroup_filter_enum { + BTRFS_QGROUP_FILTER_PARENT, BTRFS_QGROUP_FILTER_ALL_PARENT, BTRFS_QGROUP_FILTER_MAX, }; -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:50 UTC
[PATCH 8/9] Btrfs-progs: enhance btrfs qgroup show to sort qgroups
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> You might want to list qgroups in order of some items, such as ''qgroupid'', ''rfer'' and so on, you can use ''--sort''. Now you can sort the qgroups by ''qgroupid'', ''rfer'',''excl'',''max_rfer'' and ''max_excl''. For example: If you want to list qgroups in order of ''qgroupid''. You can use the option like that: btrfs qgroup show --sort=+/-qgroupid <path> Here, ''+'' means the result is sorted by ascending order. ''-'' is by descending order. If you don''t specify either ''+'' nor ''-'', the result is sorted by default - ascending order. If you want to combine sort items, you do it like that: btrfs qgroup show --sort=-qgroupid,+rfer,max_rfer,excl <path> Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 26 +++++- qgroup.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- qgroup.h | 33 +++++++- 3 files changed, 301 insertions(+), 12 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index 9447179..dd74366 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,7 +199,8 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show -pcleF <path>", + "btrfs qgroup show -pcleF " + "[--sort=qgroupid,rfer,excl,max_rfer,max_excl] <path>", "Show subvolume quota groups.", "-p print parent qgroup id", "-c print child qgroup id", @@ -209,6 +210,11 @@ static const char * const cmd_qgroup_show_usage[] = { "(include ancestral qgroups)", "-f list all qgroups which impact the given path" "(exclude ancestral qgroups)", + "--sort=qgroupid,rfer,excl,max_rfer,max_excl", + " list qgroups in order of qgroupid,rfer" + "rfer,max_rfer or max_excl", + " you can use ''+'' or ''-'' in front of each item.", + " (+:ascending, -:descending, ascending default", NULL }; @@ -221,12 +227,20 @@ static int cmd_qgroup_show(int argc, char **argv) u64 qgroupid; int filter_flag = 0; + struct btrfs_qgroup_comparer_set *comparer_set; struct btrfs_qgroup_filter_set *filter_set; filter_set = btrfs_qgroup_alloc_filter_set(); + comparer_set = btrfs_qgroup_alloc_comparer_set(); + struct option long_options[] = { + {"sort", 1, NULL, ''S''}, + {0, 0, 0, 0} + }; + optind = 1; while (1) { - c = getopt(argc, argv, "pcleFf"); + c = getopt_long(argc, argv, "pcleFf", + long_options, NULL); if (c < 0) break; @@ -253,6 +267,12 @@ static int cmd_qgroup_show(int argc, char **argv) case ''f'': filter_flag |= 0x2; break; + case ''S'': + ret = btrfs_qgroup_parse_sort_string(optarg, + &comparer_set); + if (ret) + usage(cmd_qgroup_show_usage); + break; default: usage(cmd_qgroup_show_usage); } @@ -277,7 +297,7 @@ static int cmd_qgroup_show(int argc, char **argv) BTRFS_QGROUP_FILTER_PARENT, qgroupid); } - ret = btrfs_show_qgroups(fd, filter_set); + ret = btrfs_show_qgroups(fd, filter_set, comparer_set); if (ret < 0) { fprintf(stderr, "ERROR: can''t list qgroups\n"); return 30; diff --git a/qgroup.c b/qgroup.c index b8640dc..fba675c 100644 --- a/qgroup.c +++ b/qgroup.c @@ -22,6 +22,7 @@ #include "ioctl.h" #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX) +#define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX) struct qgroup_lookup { struct rb_root root; @@ -122,6 +123,7 @@ struct { }; static btrfs_qgroup_filter_func all_filter_funcs[]; +static btrfs_qgroup_comp_func all_comp_funcs[]; void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column) { @@ -236,6 +238,188 @@ static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1, return is_descending ? -ret : ret; } +static int comp_entry_with_rfer(struct btrfs_qgroup *entry1, + struct btrfs_qgroup *entry2, + int is_descending) +{ + int ret; + + if (entry1->rfer > entry2->rfer) + ret = 1; + else if (entry1->rfer < entry2->rfer) + ret = -1; + else + ret = 0; + + return is_descending ? -ret : ret; +} + +static int comp_entry_with_excl(struct btrfs_qgroup *entry1, + struct btrfs_qgroup *entry2, + int is_descending) +{ + int ret; + + if (entry1->excl > entry2->excl) + ret = 1; + else if (entry1->excl < entry2->excl) + ret = -1; + else + ret = 0; + + return is_descending ? -ret : ret; +} + +static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1, + struct btrfs_qgroup *entry2, + int is_descending) +{ + int ret; + + if (entry1->max_rfer > entry2->max_rfer) + ret = 1; + else if (entry1->max_rfer < entry2->max_rfer) + ret = -1; + else + ret = 0; + + return is_descending ? -ret : ret; +} + +static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1, + struct btrfs_qgroup *entry2, + int is_descending) +{ + int ret; + + if (entry1->max_excl > entry2->max_excl) + ret = 1; + else if (entry1->max_excl < entry2->max_excl) + ret = -1; + else + ret = 0; + + return is_descending ? -ret : ret; +} + +static btrfs_qgroup_comp_func all_comp_funcs[] = { + [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid, + [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer, + [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl, + [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer, + [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl +}; + +static char *all_sort_items[] = { + [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid", + [BTRFS_QGROUP_COMP_RFER] = "rfer", + [BTRFS_QGROUP_COMP_EXCL] = "excl", + [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer", + [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl", + [BTRFS_QGROUP_COMP_MAX] = NULL, +}; + +static int btrfs_qgroup_get_sort_item(char *sort_name) +{ + int i; + + for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) { + if (strcmp(sort_name, all_sort_items[i]) == 0) + return i; + } + return -1; +} + +struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void) +{ + struct btrfs_qgroup_comparer_set *set; + int size; + size = sizeof(struct btrfs_qgroup_comparer_set) + + BTRFS_QGROUP_NCOMPS_INCREASE * + sizeof(struct btrfs_qgroup_comparer); + set = malloc(size); + if (!set) { + fprintf(stderr, "memory allocation failed\n"); + 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) +{ + 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); + + if (set->ncomps == set->total) { + size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE; + size = sizeof(*set) + + size * sizeof(struct btrfs_qgroup_comparer); + set = realloc(set, size); + if (!set) { + fprintf(stderr, "memory allocation failed\n"); + exit(1); + } + + memset(&set->comps[set->total], 0, + BTRFS_QGROUP_NCOMPS_INCREASE * + sizeof(struct btrfs_qgroup_comparer)); + set->total += BTRFS_QGROUP_NCOMPS_INCREASE; + *comp_set = set; + } + + BUG_ON(set->comps[set->ncomps].comp_func); + + set->comps[set->ncomps].comp_func = all_comp_funcs[comparer]; + set->comps[set->ncomps].is_descending = is_descending; + set->ncomps++; + return 0; +} + +static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, + struct btrfs_qgroup_comparer_set *set) +{ + int qgroupid_compared = 0; + int i, ret = 0; + + if (!set || !set->ncomps) + goto comp_qgroupid; + + for (i = 0; i < set->ncomps; i++) { + if (!set->comps[i].comp_func) + break; + + ret = set->comps[i].comp_func(entry1, entry2, + set->comps[i].is_descending); + if (ret) + return ret; + + if (set->comps[i].comp_func == comp_entry_with_qgroupid) + qgroupid_compared = 1; + } + + if (!qgroupid_compared) { +comp_qgroupid: + ret = comp_entry_with_qgroupid(entry1, entry2, 0); + } + + return ret; +} + /* * insert a new root into the tree. returns the existing root entry * if one is already there. qgroupid is used @@ -610,7 +794,8 @@ static void pre_process_filter_set(struct qgroup_lookup *lookup, } static int sort_tree_insert(struct qgroup_lookup *sort_tree, - struct btrfs_qgroup *bq) + struct btrfs_qgroup *bq, + struct btrfs_qgroup_comparer_set *comp_set) { struct rb_node **p = &sort_tree->root.rb_node; struct rb_node *parent = NULL; @@ -621,7 +806,7 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree, parent = *p; curr = rb_entry(parent, struct btrfs_qgroup, sort_node); - ret = comp_entry_with_qgroupid(bq, curr, 0); + ret = sort_comp(bq, curr, comp_set); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) @@ -634,9 +819,10 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree, return 0; } -static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups, +static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups, struct qgroup_lookup *sort_tree, - struct btrfs_qgroup_filter_set *filter_set) + struct btrfs_qgroup_filter_set *filter_set, + struct btrfs_qgroup_comparer_set *comp_set) { struct rb_node *n; struct btrfs_qgroup *entry; @@ -651,7 +837,7 @@ static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups, ret = filter_qgroup(entry, filter_set); if (ret) - sort_tree_insert(sort_tree, entry); + sort_tree_insert(sort_tree, entry, comp_set); n = rb_prev(n); } @@ -795,7 +981,8 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup) } int btrfs_show_qgroups(int fd, - struct btrfs_qgroup_filter_set *filter_set) + struct btrfs_qgroup_filter_set *filter_set, + struct btrfs_qgroup_comparer_set *comp_set) { struct qgroup_lookup qgroup_lookup; @@ -805,8 +992,8 @@ int btrfs_show_qgroups(int fd, ret = __qgroups_search(fd, &qgroup_lookup); if (ret) return ret; - __filter_all_qgroups(&qgroup_lookup, &sort_tree, - filter_set); + __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree, + filter_set, comp_set); print_all_qgroups(&sort_tree); __free_all_qgroups(&qgroup_lookup); @@ -832,6 +1019,57 @@ u64 btrfs_get_path_rootid(int fd) return args.treeid; } +int btrfs_qgroup_parse_sort_string(char *optarg, + struct btrfs_qgroup_comparer_set **comps) +{ + int order; + int flag; + char *p; + char **ptr_argv; + int what_to_sort; + + while ((p = strtok(optarg, ",")) != NULL) { + flag = 0; + ptr_argv = all_sort_items; + + while (*ptr_argv) { + if (strcmp(*ptr_argv, p) == 0) { + flag = 1; + break; + } else { + p++; + if (strcmp(*ptr_argv, p) == 0) { + flag = 1; + p--; + break; + } + p--; + } + ptr_argv++; + } + + if (flag == 0) + return -1; + + else { + if (*p == ''+'') { + order = 0; + p++; + } else if (*p == ''-'') { + order = 1; + p++; + } else + order = 0; + + what_to_sort = btrfs_qgroup_get_sort_item(p); + btrfs_qgroup_setup_comparer(comps, what_to_sort, order); + } + optarg = NULL; + } + + return 0; +} + u64 parse_qgroupid(char *p) { char *s = strchr(p, ''/''); diff --git a/qgroup.h b/qgroup.h index d1165fd..032ceda 100644 --- a/qgroup.h +++ b/qgroup.h @@ -25,18 +25,32 @@ struct btrfs_qgroup; typedef int (*btrfs_qgroup_filter_func)(struct btrfs_qgroup *, u64); +typedef int (*btrfs_qgroup_comp_func)(struct btrfs_qgroup *, + struct btrfs_qgroup *, int); + struct btrfs_qgroup_filter { btrfs_qgroup_filter_func filter_func; u64 data; }; +struct btrfs_qgroup_comparer { + btrfs_qgroup_comp_func comp_func; + int is_descending; +}; + struct btrfs_qgroup_filter_set { int total; int nfilters; struct btrfs_qgroup_filter filters[0]; }; +struct btrfs_qgroup_comparer_set { + int total; + int ncomps; + struct btrfs_qgroup_comparer comps[0]; +}; + enum btrfs_qgroup_column_enum { BTRFS_QGROUP_QGROUPID, BTRFS_QGROUP_RFER, @@ -48,19 +62,36 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_ALL, }; +enum btrfs_qgroup_comp_enum { + BTRFS_QGROUP_COMP_QGROUPID, + BTRFS_QGROUP_COMP_RFER, + BTRFS_QGROUP_COMP_EXCL, + BTRFS_QGROUP_COMP_MAX_RFER, + BTRFS_QGROUP_COMP_MAX_EXCL, + BTRFS_QGROUP_COMP_MAX +}; + enum btrfs_qgroup_filter_enum { BTRFS_QGROUP_FILTER_PARENT, BTRFS_QGROUP_FILTER_ALL_PARENT, BTRFS_QGROUP_FILTER_MAX, }; +int btrfs_qgroup_parse_sort_string(char *optarg, + struct btrfs_qgroup_comparer_set **comps); u64 btrfs_get_path_rootid(int fd); -int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *); +int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *, + struct btrfs_qgroup_comparer_set *); void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column); struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void); void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set); int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set, enum btrfs_qgroup_filter_enum, u64 data); +struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void); +void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set); +int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set, + enum btrfs_qgroup_comp_enum comparer, + int is_descending); u64 parse_qgroupid(char *p); int qgroup_inherit_size(struct btrfs_qgroup_inherit *p); int qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie
2012-Dec-06 09:51 UTC
[PATCH 9/9] Btrfs-progs: enhance btrfs qgroup to print the result as a table
From: Wang Shilong <wangsl-fnst@cn.fujitsu.com> This patch introduce ''-t'' option which can help you print the result as a table. You can use it like: btrfs qgroup show -t <path> However, to table the result better, we make ''-p'' and ''-c'' not present at the same time.If you still want to show both of them at the same time, you may print the result without ''-t'' option. For example: btrfs qgroup show -tpl <path> The result will output as the follow format: qgroupid rfer excl max_excl parent -------- ---- ---- -------- ------ 0/265 1289752576 1289752576 0 --- 1/0 0 0 10999511627776 2/0,3/0 2/0 0 0 0 --- 3/0 0 0 0 --- Signed-off-by: Wang shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> --- cmds-qgroup.c | 20 ++++++- qgroup.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- qgroup.h | 3 +- 3 files changed, 191 insertions(+), 11 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index dd74366..1cba305 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -199,13 +199,14 @@ static int cmd_qgroup_destroy(int argc, char **argv) } static const char * const cmd_qgroup_show_usage[] = { - "btrfs qgroup show -pcleF " + "btrfs qgroup show -pcleFt " "[--sort=qgroupid,rfer,excl,max_rfer,max_excl] <path>", "Show subvolume quota groups.", "-p print parent qgroup id", "-c print child qgroup id", "-l print max referenced size of qgroup", "-e print max exclusive size of qgroup", + "-t print the result as a table", "-F list all qgroups which impact the given path" "(include ancestral qgroups)", "-f list all qgroups which impact the given path" @@ -226,6 +227,8 @@ static int cmd_qgroup_show(int argc, char **argv) int c; u64 qgroupid; int filter_flag = 0; + int is_table_result = 0; + int table_better = 0; struct btrfs_qgroup_comparer_set *comparer_set; struct btrfs_qgroup_filter_set *filter_set; @@ -239,17 +242,19 @@ static int cmd_qgroup_show(int argc, char **argv) optind = 1; while (1) { - c = getopt_long(argc, argv, "pcleFf", + c = getopt_long(argc, argv, "pcleFft", long_options, NULL); if (c < 0) break; switch (c) { case ''p'': + table_better |= 0x1; btrfs_qgroup_setup_print_column( BTRFS_QGROUP_PARENT); break; case ''c'': + table_better |= 0x2; btrfs_qgroup_setup_print_column( BTRFS_QGROUP_CHILD); break; @@ -261,6 +266,9 @@ static int cmd_qgroup_show(int argc, char **argv) btrfs_qgroup_setup_print_column( BTRFS_QGROUP_MAX_EXCL); break; + case ''t'': + is_table_result = 1; + break; case ''F'': filter_flag |= 0x1; break; @@ -297,7 +305,13 @@ static int cmd_qgroup_show(int argc, char **argv) BTRFS_QGROUP_FILTER_PARENT, qgroupid); } - ret = btrfs_show_qgroups(fd, filter_set, comparer_set); + if (is_table_result && table_better == 3) { + fprintf(stderr, "ERROR: ''-p'' and ''-c'' can''t used " + "at the same time\n"); + exit(1); + } + ret = btrfs_show_qgroups(fd, filter_set, comparer_set, + is_table_result); if (ret < 0) { fprintf(stderr, "ERROR: can''t list qgroups\n"); return 30; diff --git a/qgroup.c b/qgroup.c index fba675c..f1218eb 100644 --- a/qgroup.c +++ b/qgroup.c @@ -80,40 +80,48 @@ struct { char *name; char *column_name; int need_print; + int max_len; } btrfs_qgroup_columns[] = { { .name = "qgroupid", .column_name = "Qgroupid", .need_print = 1, + .max_len = 8, }, { .name = "rfer", .column_name = "Rfer", .need_print = 1, + .max_len = 4, }, { .name = "excl", .column_name = "Excl", .need_print = 1, + .max_len = 4, }, { .name = "max_rfer", .column_name = "Max_rfer", .need_print = 0, + .max_len = 8, }, { .name = "max_excl", .column_name = "Max_excl", .need_print = 0, + .max_len = 8, }, { .name = "parent", .column_name = "Parent", .need_print = 0, + .max_len = 7, }, { .name = "child", .column_name = "Child", .need_print = 0, + .max_len = 5, }, { .name = NULL, @@ -167,8 +175,27 @@ static void print_child_column(struct btrfs_qgroup *qgroup) printf("---"); } +static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column, + u64 value) +{ + char tmp[100]; + int len; + + if (column == BTRFS_QGROUP_QGROUPID) { + sprintf(tmp, "%llu/%llu", value >> 48, + ((1ll << 48) - 1) & value); + } else + sprintf(tmp, "%llu", value); + len = btrfs_qgroup_columns[column].max_len - strlen(tmp); + memset(tmp, 0, sizeof(tmp)); + while (len--) + strcat(tmp, " "); + printf("%s", tmp); +} + static void print_qgroup_column(struct btrfs_qgroup *qgroup, - enum btrfs_qgroup_column_enum column) + enum btrfs_qgroup_column_enum column, + int is_table_result) { BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0); @@ -177,18 +204,33 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup, case BTRFS_QGROUP_QGROUPID: printf("%llu/%llu", qgroup->qgroupid >> 48, ((1ll << 48) - 1) & qgroup->qgroupid); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, + qgroup->qgroupid); break; case BTRFS_QGROUP_RFER: printf("%llu", qgroup->rfer); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_RFER, + qgroup->rfer); break; case BTRFS_QGROUP_EXCL: printf("%llu", qgroup->excl); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL, + qgroup->excl); break; case BTRFS_QGROUP_MAX_RFER: printf("%llu", qgroup->max_rfer); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER, + qgroup->max_rfer); break; case BTRFS_QGROUP_MAX_EXCL: printf("%llu", qgroup->max_excl); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL, + qgroup->max_excl); break; case BTRFS_QGROUP_PARENT: print_parent_column(qgroup); @@ -208,7 +250,7 @@ static void print_single_qgroup_default(struct btrfs_qgroup *qgroup) for (i = 0; i < BTRFS_QGROUP_ALL; i++) { if (!btrfs_qgroup_columns[i].need_print) continue; - print_qgroup_column(qgroup, i); + print_qgroup_column(qgroup, i, 0); if (i != BTRFS_QGROUP_ALL - 1) printf(" "); @@ -216,6 +258,58 @@ static void print_single_qgroup_default(struct btrfs_qgroup *qgroup) printf("\n"); } +static void print_single_qgroup_table(struct btrfs_qgroup *qgroup) +{ + int i; + + for (i = 0; i < BTRFS_QGROUP_ALL; i++) { + if (!btrfs_qgroup_columns[i].need_print) + continue; + print_qgroup_column(qgroup, i, 1); + + if (i != BTRFS_QGROUP_CHILD) + printf(" "); + } + printf("\n"); +} + +static void print_table_head() +{ + int i; + int len; + char barrier[20]; + + for (i = 0; i < BTRFS_QGROUP_ALL; i++) { + 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); + memset(barrier, 0, sizeof(barrier)); + while (len--) + strcat(barrier, " "); + printf("%s ", barrier); + } + printf("\n"); + for (i = 0; i < BTRFS_QGROUP_ALL; i++) { + if (!btrfs_qgroup_columns[i].need_print) + continue; + + len = strlen(btrfs_qgroup_columns[i].name); + memset(barrier, 0, sizeof(barrier)); + while (len--) + strcat(barrier, "-"); + printf("%s", barrier); + len = btrfs_qgroup_columns[i].max_len - + strlen(btrfs_qgroup_columns[i].name); + memset(barrier, 0, sizeof(barrier)); + while (len--) + strcat(barrier, " "); + printf("%s ", barrier); + } + printf("\n"); +} + static void qgroup_lookup_init(struct qgroup_lookup *tree) { tree->root.rb_node = NULL; @@ -819,6 +913,67 @@ 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) +{ + BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0); + char tmp[100]; + int len; + + switch (column) { + + case BTRFS_QGROUP_QGROUPID: + sprintf(tmp, "%llu/%llu", (bq->qgroupid >> 48), + bq->qgroupid & ((1ll << 48) - 1)); + 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); + 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); + 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); + 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); + if (btrfs_qgroup_columns[column].max_len < len) + btrfs_qgroup_columns[column].max_len = len; + break; + case BTRFS_QGROUP_PARENT: + break; + case BTRFS_QGROUP_CHILD: + 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,9 +991,11 @@ 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); } } @@ -966,23 +1123,31 @@ done: return ret; } -static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup) +static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup, + int is_table_result) { struct rb_node *n; struct btrfs_qgroup *entry; + if (is_table_result) + 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); + if (!is_table_result) + print_single_qgroup_default(entry); + else + print_single_qgroup_table(entry); n = rb_next(n); } } int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *filter_set, - struct btrfs_qgroup_comparer_set *comp_set) + struct btrfs_qgroup_comparer_set *comp_set, + int is_table_result) { struct qgroup_lookup qgroup_lookup; @@ -994,7 +1159,7 @@ int btrfs_show_qgroups(int fd, return ret; __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree, filter_set, comp_set); - print_all_qgroups(&sort_tree); + print_all_qgroups(&sort_tree, is_table_result); __free_all_qgroups(&qgroup_lookup); btrfs_qgroup_free_filter_set(filter_set); diff --git a/qgroup.h b/qgroup.h index 032ceda..64984a6 100644 --- a/qgroup.h +++ b/qgroup.h @@ -81,7 +81,8 @@ int btrfs_qgroup_parse_sort_string(char *optarg, struct btrfs_qgroup_comparer_set **comps); u64 btrfs_get_path_rootid(int fd); int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *, - struct btrfs_qgroup_comparer_set *); + struct btrfs_qgroup_comparer_set *, + int is_table_result); void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column); struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void); void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set); -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Miao Xie <miaox <at> cn.fujitsu.com> writes:> > The patchset enhanced btrfs qgroup show command. > > Firstly, we restructure show_qgroups, make it easy to add new features. > > And then we add ''-p'' ''-c'', ''-l'',and ''-e'' options to print the parent > qgroup id, child qgroup id, max referenced size and max exclusive size > of qgroup respectively, add ''-F'' and ''-f'' option to list qgroups that > impact the given path.Hi, What is the status of this patch? I don''t ever think it made it in upstream. Was it flawed or just forgotten? Thanks, Dusty -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 09/22/2013 11:14 PM, Dusty Mabe wrote:> Miao Xie <miaox <at> cn.fujitsu.com> writes: > >> The patchset enhanced btrfs qgroup show command. >> >> Firstly, we restructure show_qgroups, make it easy to add new features. >> >> And then we add ''-p'' ''-c'', ''-l'',and ''-e'' options to print the parent >> qgroup id, child qgroup id, max referenced size and max exclusive size >> of qgroup respectively, add ''-F'' and ''-f'' option to list qgroups that >> impact the given path. > > Hi, > > What is the status of this patch? I don''t ever think it made it in upstream. > Was it flawed or just forgotten?I will rebase this patchset and resend. Thanks, Wang> > Thanks, > Dusty > > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Wang, Thank you! There is one other thing I have noticed while playing around with quota and qgroups. If I delete subvolumes I can manage to get some of the qgroup information to be reported as a negative number. If you are interested check out my steps at http://dustymabe.com/2013/09/22/btrfs-how-big-are-my-snapshots/ . The system I was using was Fedora 19 (so not the latest stuff so this may be a known issue already). Feel free to share the post if you think it could help anyone. Dusty On Sun, Sep 22, 2013 at 9:13 PM, Wang Shilong <wangsl.fnst@cn.fujitsu.com> wrote:> On 09/22/2013 11:14 PM, Dusty Mabe wrote: >> Miao Xie <miaox <at> cn.fujitsu.com> writes: >> >>> The patchset enhanced btrfs qgroup show command. >>> >>> Firstly, we restructure show_qgroups, make it easy to add new features. >>> >>> And then we add ''-p'' ''-c'', ''-l'',and ''-e'' options to print the parent >>> qgroup id, child qgroup id, max referenced size and max exclusive size >>> of qgroup respectively, add ''-F'' and ''-f'' option to list qgroups that >>> impact the given path. >> >> Hi, >> >> What is the status of this patch? I don''t ever think it made it in upstream. >> Was it flawed or just forgotten? > I will rebase this patchset and resend. > > Thanks, > Wang >> >> Thanks, >> Dusty >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 09/23/2013 09:53 AM, Dusty Mabe wrote:> Hi Wang, > > Thank you! There is one other thing I have noticed while playing > around with quota and qgroups. If I delete subvolumes I can manage to > get some of the qgroup information to be reported as a negative > number. If you are interested check out my steps at > http://dustymabe.com/2013/09/22/btrfs-how-big-are-my-snapshots/ . The > system I was using was Fedora 19 (so not the latest stuff so this may > be a known issue already).I will take a look at this issue. Thanks, Wang> > Feel free to share the post if you think it could help anyone. > > Dusty > > On Sun, Sep 22, 2013 at 9:13 PM, Wang Shilong > <wangsl.fnst@cn.fujitsu.com> wrote: >> On 09/22/2013 11:14 PM, Dusty Mabe wrote: >>> Miao Xie <miaox <at> cn.fujitsu.com> writes: >>> >>>> The patchset enhanced btrfs qgroup show command. >>>> >>>> Firstly, we restructure show_qgroups, make it easy to add new features. >>>> >>>> And then we add ''-p'' ''-c'', ''-l'',and ''-e'' options to print the parent >>>> qgroup id, child qgroup id, max referenced size and max exclusive size >>>> of qgroup respectively, add ''-F'' and ''-f'' option to list qgroups that >>>> impact the given path. >>> Hi, >>> >>> What is the status of this patch? I don''t ever think it made it in upstream. >>> Was it flawed or just forgotten? >> I will rebase this patchset and resend. >> >> Thanks, >> Wang >>> Thanks, >>> Dusty >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Wang Shilong posted on Mon, 23 Sep 2013 10:18:19 +0800 as excerpted:> On 09/23/2013 09:53 AM, Dusty Mabe wrote:>> There is one other thing I have noticed while playing around >> with quota and qgroups. If I delete subvolumes I can manage to get some >> of the qgroup information to be reported as a negative number. If you >> are interested check out my steps at >> http://dustymabe.com/2013/09/22/btrfs-how-big-are-my-snapshots/ . The >> system I was using was Fedora 19 (so not the latest stuff so this may >> be a known issue already).> I will take a look at this issue.FWIW, I remember seeing discussion of the negative qgroup numbers on- list, but as I don''t use quotas I didn''t track resolution. So it should indeed be a known issue, but I''m not sure if it''s fixed or someone''s at least working on it yet or not. But that might give you a duplicating instance if you need one, anyway. (Unless of course Dusty reported it earlier too and that''s what I''m remembering.) -- Duncan - List replies preferred. No HTML msgs. "Every nonfree program has a lord, a master -- and if you use the program, he is your master." Richard Stallman -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hello,> Wang Shilong posted on Mon, 23 Sep 2013 10:18:19 +0800 as excerpted: > >> On 09/23/2013 09:53 AM, Dusty Mabe wrote: > >>> There is one other thing I have noticed while playing around >>> with quota and qgroups. If I delete subvolumes I can manage to get some >>> of the qgroup information to be reported as a negative number. If you >>> are interested check out my steps at >>> http://dustymabe.com/2013/09/22/btrfs-how-big-are-my-snapshots/ . The >>> system I was using was Fedora 19 (so not the latest stuff so this may >>> be a known issue already). > >> I will take a look at this issue. > > FWIW, I remember seeing discussion of the negative qgroup numbers on- > list, but as I don''t use quotas I didn''t track resolution. So it should > indeed be a known issue, but I''m not sure if it''s fixed or someone''s at > least working on it yet or not.I think this problem reported by Dusty is different from before. Previously, we discussed about negative numbers because quota rescan has not been implemented. In Dusty''s reproduced steps, there are no parent qgroups. So i think every qgroup should works as expected, if negative numbers come out, it must be a *bug*. Thanks, Wang> > But that might give you a duplicating instance if you need one, anyway. > (Unless of course Dusty reported it earlier too and that''s what I''m > remembering.) > > -- > Duncan - List replies preferred. No HTML msgs. > "Every nonfree program has a lord, a master -- > and if you use the program, he is your master." Richard Stallman > > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Wang Shilong <wangshilong1991 <at> gmail.com> writes:> > > In Dusty''s reproduced steps, there are no parent qgroups. So i think every > qgroup should works as expected, if negative numbers come out, it must > be a *bug*.In that case would you like for me to open a new bug report with the details? Dusty -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Sep 23, 2013 at 9:35 PM, Wang Shilong <wangsl.fnst@cn.fujitsu.com> wrote:> On 09/24/2013 12:55 AM, Dusty Mabe wrote: >> >> In that case would you like for me to open a new bug report with the >> details? > > Yes.https://bugzilla.kernel.org/show_bug.cgi?id=61951 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html