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. You can pull this patchset from the URL: git://github.com/wangshilong/Btrfs-progs.git qgroup Changelog v1->v2: rebase the patchset on david''s integration-20130920 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 | 190 ++++----- ctree.h | 11 + qgroup.c | 1218 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qgroup.h | 71 ++++ 4 files changed, 1396 insertions(+), 94 deletions(-) -- 1.8.3.1 -- 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 | 91 +---------- ctree.h | 11 ++ qgroup.c | 509 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qgroup.h | 10 ++ 4 files changed, 531 insertions(+), 90 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index ff2a1fa..d3c699f 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -106,95 +106,6 @@ static int qgroup_create(int create, int argc, char **argv) return 0; } -static 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)); -} - -static 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; - 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); - if (ret < 0) - 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 +224,7 @@ static int cmd_qgroup_show(int argc, char **argv) return 1; } - ret = list_qgroups(fd); + ret = btrfs_show_qgroups(fd); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) diff --git a/ctree.h b/ctree.h index 5b4c859..c90581a 100644 --- a/ctree.h +++ b/ctree.h @@ -2059,6 +2059,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 86fe2b2..bd9658e 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("%lld", qgroup->rfer); + break; + case BTRFS_QGROUP_EXCL: + printf("%lld", 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 da6d113..8b34cd7 100644 --- a/qgroup.h +++ b/qgroup.h @@ -22,6 +22,16 @@ #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_add_group(struct btrfs_qgroup_inherit **inherit, char *arg); -- 1.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 | 23 ++++++++++++++++++++--- qgroup.c | 22 ++++++++++++++++++++++ qgroup.h | 1 + 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index d3c699f..96098c1 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,22 +202,39 @@ 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) { + char *path; int ret = 0; int fd; int e; - char *path = argv[1]; DIR *dirstream = NULL; + int c; - if (check_argc_exact(argc, 2)) + optind = 1; + while (1) { + c = getopt(argc, argv, "p"); + if (c < 0) + break; + 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, &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can''t access ''%s''\n", path); diff --git a/qgroup.c b/qgroup.c index bd9658e..0dbf28c 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("%lld", qgroup->excl); break; + case BTRFS_QGROUP_PARENT: + print_parent_column(qgroup); + break; default: break; } diff --git a/qgroup.h b/qgroup.h index 8b34cd7..cefdfe1 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.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 96098c1..147bedc 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,9 +202,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 }; @@ -219,7 +220,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; switch (c) { @@ -227,6 +228,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 0dbf28c..1592dd4 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 cefdfe1..33682ae 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.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 147bedc..32537f9 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,10 +202,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 }; @@ -220,7 +221,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; switch (c) { @@ -232,6 +233,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 1592dd4..f9eb52d 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", @@ -166,6 +170,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup, case BTRFS_QGROUP_PARENT: print_parent_column(qgroup); break; + case BTRFS_QGROUP_MAX_RFER: + printf("%llu", qgroup->max_rfer); + break; case BTRFS_QGROUP_CHILD: print_child_column(qgroup); break; diff --git a/qgroup.h b/qgroup.h index 33682ae..168fac0 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.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 32537f9..0bfca33 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,11 +202,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 }; @@ -221,7 +222,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; switch (c) { @@ -237,6 +238,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 f9eb52d..2cd37b1 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, @@ -173,6 +178,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_CHILD: print_child_column(qgroup); break; diff --git a/qgroup.h b/qgroup.h index 168fac0..e7a65ba 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.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 | 24 +++++- qgroup.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- qgroup.h | 28 ++++++- 3 files changed, 281 insertions(+), 10 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index 0bfca33..5480d2a 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,12 +202,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 }; @@ -219,10 +221,15 @@ static int cmd_qgroup_show(int argc, char **argv) int e; DIR *dirstream = NULL; 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; switch (c) { @@ -242,6 +249,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); } @@ -256,7 +266,13 @@ static int cmd_qgroup_show(int argc, char **argv) return 1; } - 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); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) diff --git a/qgroup.c b/qgroup.c index 2cd37b1..306b638 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 e7a65ba..bcc2b4b 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,9 +48,18 @@ enum btrfs_qgroup_column_enum { BTRFS_QGROUP_ALL, }; -int btrfs_show_qgroups(int fd); -void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column); +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_add_group(struct btrfs_qgroup_inherit **inherit, char *arg); -- 1.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 | 18 ++++++++++++++---- qgroup.c | 16 +++++++++++++++- qgroup.h | 1 + 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index 5480d2a..bcf0487 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -210,6 +210,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 }; @@ -229,7 +231,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; switch (c) { @@ -252,6 +254,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); } @@ -268,9 +273,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, - BTRFS_QGROUP_FILTER_ALL_PARENT, - qgroupid); + 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); e = errno; diff --git a/qgroup.c b/qgroup.c index 306b638..28772d6 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 bcc2b4b..5fcdd8a 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.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 | 25 +++++- qgroup.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- qgroup.h | 33 +++++++- 3 files changed, 302 insertions(+), 12 deletions(-) diff --git a/cmds-qgroup.c b/cmds-qgroup.c index bcf0487..780fb21 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,7 +202,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", @@ -212,6 +213,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,max_rfer or max_excl", + " you can use ''+'' or ''-'' in front of each item.", + " (+:ascending, -:descending, ascending default", NULL }; @@ -226,12 +232,19 @@ 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; switch (c) { @@ -257,6 +270,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); } @@ -282,7 +301,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); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) diff --git a/qgroup.c b/qgroup.c index 28772d6..84f5fc1 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,59 @@ u64 btrfs_get_path_rootid(int fd) return args.treeid; } +int btrfs_qgroup_parse_sort_string(char *opt_arg, + struct btrfs_qgroup_comparer_set **comps) +{ + int order; + int flag; + char *p; + char **ptr_argv; + int what_to_sort; + + while ((p = strtok(opt_arg, ",")) != 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); + if (what_to_sort < 0) + return -1; + btrfs_qgroup_setup_comparer(comps, what_to_sort, order); + } + opt_arg = NULL; + } + + return 0; +} + u64 parse_qgroupid(char *p) { char *s = strchr(p, ''/''); diff --git a/qgroup.h b/qgroup.h index 5fcdd8a..653cf1c 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 *opt_arg, + 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_add_group(struct btrfs_qgroup_inherit **inherit, char *arg); -- 1.8.3.1 -- 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
2013-Sep-23 06:17 UTC
[PATCH v2 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 780fb21..1f71e3c 100644 --- a/cmds-qgroup.c +++ b/cmds-qgroup.c @@ -202,13 +202,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" @@ -231,6 +232,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; @@ -243,16 +246,18 @@ 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; @@ -264,6 +269,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; @@ -301,7 +309,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); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) diff --git a/qgroup.c b/qgroup.c index 84f5fc1..eafb1bf 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,21 +204,36 @@ 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("%lld", qgroup->rfer); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_RFER, + qgroup->rfer); break; case BTRFS_QGROUP_EXCL: printf("%lld", qgroup->excl); + if (is_table_result) + print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL, + qgroup->excl); break; case BTRFS_QGROUP_PARENT: print_parent_column(qgroup); 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_CHILD: print_child_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 653cf1c..4dd666d 100644 --- a/qgroup.h +++ b/qgroup.h @@ -81,7 +81,8 @@ int btrfs_qgroup_parse_sort_string(char *opt_arg, 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.8.3.1 -- 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 02:17:19PM +0800, Wang Shilong wrote:> 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.Well done! I really like it. Minor comments: * -l sounds less intuitive, I suggest to use -r as for ''referenced'', given that there is -e for ''exclusive''. * the size should be pretty-printed by default or in bytes if a commandline option is given * in the long term, the tabular output would be much better as default, and the current terse output available via commandline option for batch processing thanks, david -- 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 David,> On Mon, Sep 23, 2013 at 02:17:19PM +0800, Wang Shilong wrote: >> 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. > > Well done! I really like it. > > Minor comments: > > * -l sounds less intuitive, I suggest to use -r as for > ''referenced'', given that there is -e for ''exclusive''.Yeah, here -l means limited size. Anyway, this is a little obscure. Maybe -r is better, but it may let user think it is a qgroup''s referenced size but not max referenced size..> * the size should be pretty-printed by default or in bytes if a > commandline option is givenAgree, maybe i can add an options for example ''-h'' here.> > * in the long term, the tabular output would be much better as > default, and the current terse output available via commandline option > for batch processingThe main reason that i don''t use table result as default is because there are so many columns here, and my first table result will be a head name like: rfer excl max_refer max_excl ---- ----- ----------- ------------- In order to keep compatibility with previous ''btrfs qgroup show'', i add ''-t''. Thanks, Wang> > thanks, > david > -- > 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 Tue, Oct 01, 2013 at 08:25:38PM +0800, Wang Shilong wrote:> > * -l sounds less intuitive, I suggest to use -r as for > > ''referenced'', given that there is -e for ''exclusive''. > > Yeah, here -l means limited size. Anyway, this is a little obscure. > Maybe -r is better, but it may let user think it is a qgroup''s referenced size > but not max referenced size..The referenced and exclusive sizes are always printed, I think that''s ok to assign -r to the referenced limit. If we want to reserve -r for something else, next option is to use -R and -E for the limits. During the time I was testing it the 2 most frequent uses were ''-t'' or ''-tcle''.> > * the size should be pretty-printed by default or in bytes if a > > commandline option is given > > Agree, maybe i can add an options for example ''-h'' here.-h prints help. But we haven''t solved selecting units in other commands as well, so this should be possibly done consistently and in one go.> > * in the long term, the tabular output would be much better as > > default, and the current terse output available via commandline option > > for batch processing > > The main reason that i don''t use table result as default is because there > are so many columns here, and my first table result will be a head name like: > > rfer excl max_refer max_excl > ---- ----- ----------- ------------- > > In order to keep compatibility with previous ''btrfs qgroup show'', i add ''-t''.That''s fine for now. -- 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