2 * Copyright (C) 2012 STRATO. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
20 #include <sys/ioctl.h>
25 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
26 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
28 struct qgroup_lookup {
33 struct rb_node rb_node;
34 struct rb_node sort_node;
36 *all_parent_node is used to
37 *filter a qgroup's all parent
39 struct rb_node all_parent_node;
46 u64 rfer; /*referenced*/
47 u64 rfer_cmpr; /*referenced compressed*/
48 u64 excl; /*exclusive*/
49 u64 excl_cmpr; /*exclusive compressed*/
54 u64 flags; /*which limits are set*/
60 /*qgroups this group is member of*/
61 struct list_head qgroups;
62 /*qgroups that are members of this group*/
63 struct list_head members;
67 * glue structure to represent the relations
70 struct btrfs_qgroup_list {
71 struct list_head next_qgroup;
72 struct list_head next_member;
73 struct btrfs_qgroup *qgroup;
74 struct btrfs_qgroup *member;
78 * qgroupid,rfer,excl default to set
86 } btrfs_qgroup_columns[] = {
89 .column_name = "Qgroupid",
96 .column_name = "Rfer",
98 .unit_mode = UNITS_DEFAULT,
103 .column_name = "Excl",
105 .unit_mode = UNITS_DEFAULT,
108 { .name = "max_rfer",
109 .column_name = "Max_rfer",
111 .unit_mode = UNITS_DEFAULT,
116 .column_name = "Max_excl",
118 .unit_mode = UNITS_DEFAULT,
123 .column_name = "Parent",
130 .column_name = "Child",
143 static btrfs_qgroup_filter_func all_filter_funcs[];
144 static btrfs_qgroup_comp_func all_comp_funcs[];
146 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
150 BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
152 if (column < BTRFS_QGROUP_ALL) {
153 btrfs_qgroup_columns[column].need_print = 1;
156 for (i = 0; i < BTRFS_QGROUP_ALL; i++)
157 btrfs_qgroup_columns[i].need_print = 1;
160 void btrfs_qgroup_setup_units(unsigned unit_mode)
162 btrfs_qgroup_columns[BTRFS_QGROUP_RFER].unit_mode = unit_mode;
163 btrfs_qgroup_columns[BTRFS_QGROUP_EXCL].unit_mode = unit_mode;
164 btrfs_qgroup_columns[BTRFS_QGROUP_MAX_RFER].unit_mode = unit_mode;
165 btrfs_qgroup_columns[BTRFS_QGROUP_MAX_EXCL].unit_mode = unit_mode;
168 static int print_parent_column(struct btrfs_qgroup *qgroup)
170 struct btrfs_qgroup_list *list = NULL;
173 list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
174 len += printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
175 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
176 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
179 if (list_empty(&qgroup->qgroups))
180 len += printf("---");
185 static int print_child_column(struct btrfs_qgroup *qgroup)
187 struct btrfs_qgroup_list *list = NULL;
190 list_for_each_entry(list, &qgroup->members, next_member) {
191 len += printf("%llu/%llu", (list->member)->qgroupid >> 48,
192 ((1ll << 48) - 1) & (list->member)->qgroupid);
193 if (!list_is_last(&list->next_member, &qgroup->members))
196 if (list_empty(&qgroup->members))
197 len += printf("---");
202 static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
205 len = btrfs_qgroup_columns[column].max_len - len;
210 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
211 enum btrfs_qgroup_column_enum column)
213 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
215 int unit_mode = btrfs_qgroup_columns[column].unit_mode;
216 int max_len = btrfs_qgroup_columns[column].max_len;
220 case BTRFS_QGROUP_QGROUPID:
221 len = printf("%llu/%llu", qgroup->qgroupid >> 48,
222 ((1ll << 48) - 1) & qgroup->qgroupid);
223 print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
225 case BTRFS_QGROUP_RFER:
226 len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
228 case BTRFS_QGROUP_EXCL:
229 len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
231 case BTRFS_QGROUP_PARENT:
232 len = print_parent_column(qgroup);
233 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
235 case BTRFS_QGROUP_MAX_RFER:
236 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
238 case BTRFS_QGROUP_MAX_EXCL:
239 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
241 case BTRFS_QGROUP_CHILD:
242 len = print_child_column(qgroup);
243 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
250 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
254 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
255 if (!btrfs_qgroup_columns[i].need_print)
257 print_qgroup_column(qgroup, i);
259 if (i != BTRFS_QGROUP_CHILD)
265 static void print_table_head()
271 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
272 max_len = btrfs_qgroup_columns[i].max_len;
273 if (!btrfs_qgroup_columns[i].need_print)
275 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
276 (i == BTRFS_QGROUP_CHILD))
277 printf("%-*s", max_len, btrfs_qgroup_columns[i].name);
279 printf("%*s", max_len, btrfs_qgroup_columns[i].name);
283 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
284 max_len = btrfs_qgroup_columns[i].max_len;
285 if (!btrfs_qgroup_columns[i].need_print)
287 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
288 (i == BTRFS_QGROUP_CHILD)) {
289 len = strlen(btrfs_qgroup_columns[i].name);
292 len = max_len - strlen(btrfs_qgroup_columns[i].name);
296 len = max_len - strlen(btrfs_qgroup_columns[i].name);
299 len = strlen(btrfs_qgroup_columns[i].name);
308 static void qgroup_lookup_init(struct qgroup_lookup *tree)
310 tree->root.rb_node = NULL;
313 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
314 struct btrfs_qgroup *entry2,
320 if (entry1->qgroupid > entry2->qgroupid)
322 else if (entry1->qgroupid < entry2->qgroupid)
327 return is_descending ? -ret : ret;
330 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
331 struct btrfs_qgroup *entry2,
336 if (entry1->rfer > entry2->rfer)
338 else if (entry1->rfer < entry2->rfer)
343 return is_descending ? -ret : ret;
346 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
347 struct btrfs_qgroup *entry2,
352 if (entry1->excl > entry2->excl)
354 else if (entry1->excl < entry2->excl)
359 return is_descending ? -ret : ret;
362 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
363 struct btrfs_qgroup *entry2,
368 if (entry1->max_rfer > entry2->max_rfer)
370 else if (entry1->max_rfer < entry2->max_rfer)
375 return is_descending ? -ret : ret;
378 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
379 struct btrfs_qgroup *entry2,
384 if (entry1->max_excl > entry2->max_excl)
386 else if (entry1->max_excl < entry2->max_excl)
391 return is_descending ? -ret : ret;
394 static btrfs_qgroup_comp_func all_comp_funcs[] = {
395 [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid,
396 [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer,
397 [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl,
398 [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer,
399 [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl
402 static char *all_sort_items[] = {
403 [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid",
404 [BTRFS_QGROUP_COMP_RFER] = "rfer",
405 [BTRFS_QGROUP_COMP_EXCL] = "excl",
406 [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer",
407 [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl",
408 [BTRFS_QGROUP_COMP_MAX] = NULL,
411 static int btrfs_qgroup_get_sort_item(char *sort_name)
415 for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
416 if (strcmp(sort_name, all_sort_items[i]) == 0)
422 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
424 struct btrfs_qgroup_comparer_set *set;
426 size = sizeof(struct btrfs_qgroup_comparer_set) +
427 BTRFS_QGROUP_NCOMPS_INCREASE *
428 sizeof(struct btrfs_qgroup_comparer);
431 fprintf(stderr, "memory allocation failed\n");
435 memset(set, 0, size);
436 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
441 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
446 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
447 enum btrfs_qgroup_comp_enum comparer,
450 struct btrfs_qgroup_comparer_set *set = *comp_set;
454 BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
455 BUG_ON(set->ncomps > set->total);
457 if (set->ncomps == set->total) {
458 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
459 size = sizeof(*set) +
460 size * sizeof(struct btrfs_qgroup_comparer);
461 set = realloc(set, size);
463 fprintf(stderr, "memory allocation failed\n");
467 memset(&set->comps[set->total], 0,
468 BTRFS_QGROUP_NCOMPS_INCREASE *
469 sizeof(struct btrfs_qgroup_comparer));
470 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
474 BUG_ON(set->comps[set->ncomps].comp_func);
476 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
477 set->comps[set->ncomps].is_descending = is_descending;
482 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
483 struct btrfs_qgroup_comparer_set *set)
485 int qgroupid_compared = 0;
488 if (!set || !set->ncomps)
491 for (i = 0; i < set->ncomps; i++) {
492 if (!set->comps[i].comp_func)
495 ret = set->comps[i].comp_func(entry1, entry2,
496 set->comps[i].is_descending);
500 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
501 qgroupid_compared = 1;
504 if (!qgroupid_compared) {
506 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
513 * insert a new root into the tree. returns the existing root entry
514 * if one is already there. qgroupid is used
517 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
518 struct btrfs_qgroup *ins)
521 struct rb_node **p = &root_tree->root.rb_node;
522 struct rb_node *parent = NULL;
523 struct btrfs_qgroup *curr;
528 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
530 ret = comp_entry_with_qgroupid(ins, curr, 0);
538 rb_link_node(&ins->rb_node, parent, p);
539 rb_insert_color(&ins->rb_node, &root_tree->root);
544 *find a given qgroupid in the tree. We return the smallest one,
545 *rb_next can be used to move forward looking for more if required
547 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
550 struct rb_node *n = root_tree->root.rb_node;
551 struct btrfs_qgroup *entry;
552 struct btrfs_qgroup tmp;
555 tmp.qgroupid = qgroupid;
558 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
560 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
572 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
573 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
574 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
575 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
576 struct btrfs_qgroup *child)
578 struct btrfs_qgroup *bq;
579 struct btrfs_qgroup_list *list;
581 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
582 if (!bq || bq->qgroupid != qgroupid)
586 bq->generation = generation;
590 bq->rfer_cmpr = rfer_cmpr;
594 bq->excl_cmpr = excl_cmpr;
598 bq->max_rfer = max_rfer;
600 bq->max_excl = max_excl;
602 bq->rsv_rfer = rsv_rfer;
604 list = malloc(sizeof(*list));
606 fprintf(stderr, "memory allocation failed\n");
610 list->member = child;
611 list_add_tail(&list->next_qgroup, &child->qgroups);
612 list_add_tail(&list->next_member, &pa->members);
617 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
618 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
619 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
620 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
621 struct btrfs_qgroup *child)
623 struct btrfs_qgroup *bq;
624 struct btrfs_qgroup_list *list;
627 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
628 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
629 max_excl, rsv_rfer, rsv_excl, parent, child);
633 bq = malloc(sizeof(*bq));
635 printf("memory allocation failed\n");
638 memset(bq, 0, sizeof(*bq));
640 bq->qgroupid = qgroupid;
641 INIT_LIST_HEAD(&bq->qgroups);
642 INIT_LIST_HEAD(&bq->members);
645 bq->generation = generation;
649 bq->rfer_cmpr = rfer_cmpr;
653 bq->excl_cmpr = excl_cmpr;
657 bq->max_rfer = max_rfer;
659 bq->max_excl = max_excl;
661 bq->rsv_rfer = rsv_rfer;
662 if (parent && child) {
663 list = malloc(sizeof(*list));
665 fprintf(stderr, "memory allocation failed\n");
668 list->qgroup = parent;
669 list->member = child;
670 list_add_tail(&list->next_qgroup, &child->qgroups);
671 list_add_tail(&list->next_member, &parent->members);
673 ret = qgroup_tree_insert(qgroup_lookup, bq);
675 printf("failed to insert tree %llu\n",
682 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
684 struct btrfs_qgroup_list *list;
685 while (!list_empty(&bq->qgroups)) {
686 list = list_entry((&bq->qgroups)->next,
687 struct btrfs_qgroup_list,
689 list_del(&list->next_qgroup);
690 list_del(&list->next_member);
693 while (!list_empty(&bq->members)) {
694 list = list_entry((&bq->members)->next,
695 struct btrfs_qgroup_list,
697 list_del(&list->next_qgroup);
698 list_del(&list->next_member);
704 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
706 struct btrfs_qgroup *entry;
709 n = rb_first(&root_tree->root);
711 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
712 rb_erase(n, &root_tree->root);
713 __free_btrfs_qgroup(entry);
715 n = rb_first(&root_tree->root);
719 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
720 struct btrfs_qgroup *bq)
722 struct rb_node **p = &sort_tree->root.rb_node;
723 struct rb_node *parent = NULL;
724 struct btrfs_qgroup *curr;
729 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
731 ret = comp_entry_with_qgroupid(bq, curr, 0);
739 rb_link_node(&bq->all_parent_node, parent, p);
740 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
744 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
746 struct btrfs_qgroup *qgroup =
747 (struct btrfs_qgroup *)(unsigned long)data;
751 if (qgroup->qgroupid == bq->qgroupid)
756 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
758 struct qgroup_lookup lookup;
759 struct qgroup_lookup *ql = &lookup;
760 struct btrfs_qgroup_list *list;
762 struct btrfs_qgroup *qgroup =
763 (struct btrfs_qgroup *)(unsigned long)data;
767 if (bq->qgroupid == qgroup->qgroupid)
770 qgroup_lookup_init(ql);
771 filter_all_parent_insert(ql, qgroup);
772 n = rb_first(&ql->root);
774 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
775 if (!list_empty(&qgroup->qgroups)) {
776 list_for_each_entry(list, &qgroup->qgroups,
778 if ((list->qgroup)->qgroupid == bq->qgroupid)
780 filter_all_parent_insert(ql, list->qgroup);
783 rb_erase(n, &ql->root);
784 n = rb_first(&ql->root);
789 static btrfs_qgroup_filter_func all_filter_funcs[] = {
790 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
791 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
794 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
796 struct btrfs_qgroup_filter_set *set;
799 size = sizeof(struct btrfs_qgroup_filter_set) +
800 BTRFS_QGROUP_NFILTERS_INCREASE *
801 sizeof(struct btrfs_qgroup_filter);
804 fprintf(stderr, "memory allocation failed\n");
807 memset(set, 0, size);
808 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
813 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
818 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
819 enum btrfs_qgroup_filter_enum filter, u64 data)
821 struct btrfs_qgroup_filter_set *set = *filter_set;
825 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
826 BUG_ON(set->nfilters > set->total);
828 if (set->nfilters == set->total) {
829 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
830 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
832 set = realloc(set, size);
834 fprintf(stderr, "memory allocation failed\n");
837 memset(&set->filters[set->total], 0,
838 BTRFS_QGROUP_NFILTERS_INCREASE *
839 sizeof(struct btrfs_qgroup_filter));
840 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
843 BUG_ON(set->filters[set->nfilters].filter_func);
844 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
845 set->filters[set->nfilters].data = data;
850 static int filter_qgroup(struct btrfs_qgroup *bq,
851 struct btrfs_qgroup_filter_set *set)
855 if (!set || !set->nfilters)
857 for (i = 0; i < set->nfilters; i++) {
858 if (!set->filters[i].filter_func)
860 ret = set->filters[i].filter_func(bq, set->filters[i].data);
867 static void pre_process_filter_set(struct qgroup_lookup *lookup,
868 struct btrfs_qgroup_filter_set *set)
871 struct btrfs_qgroup *qgroup_for_filter = NULL;
873 for (i = 0; i < set->nfilters; i++) {
875 if (set->filters[i].filter_func == filter_by_all_parent
876 || set->filters[i].filter_func == filter_by_parent) {
877 qgroup_for_filter = qgroup_tree_search(lookup,
878 set->filters[i].data);
879 set->filters[i].data =
880 (u64)(unsigned long)qgroup_for_filter;
885 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
886 struct btrfs_qgroup *bq,
887 struct btrfs_qgroup_comparer_set *comp_set)
889 struct rb_node **p = &sort_tree->root.rb_node;
890 struct rb_node *parent = NULL;
891 struct btrfs_qgroup *curr;
896 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
898 ret = sort_comp(bq, curr, comp_set);
906 rb_link_node(&bq->sort_node, parent, p);
907 rb_insert_color(&bq->sort_node, &sort_tree->root);
911 static void __update_columns_max_len(struct btrfs_qgroup *bq,
912 enum btrfs_qgroup_column_enum column)
914 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
915 struct btrfs_qgroup_list *list = NULL;
918 unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
922 case BTRFS_QGROUP_QGROUPID:
923 sprintf(tmp, "%llu/%llu", (bq->qgroupid >> 48),
924 bq->qgroupid & ((1ll << 48) - 1));
926 if (btrfs_qgroup_columns[column].max_len < len)
927 btrfs_qgroup_columns[column].max_len = len;
929 case BTRFS_QGROUP_RFER:
930 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
931 if (btrfs_qgroup_columns[column].max_len < len)
932 btrfs_qgroup_columns[column].max_len = len;
934 case BTRFS_QGROUP_EXCL:
935 len = strlen(pretty_size_mode(bq->excl, unit_mode));
936 if (btrfs_qgroup_columns[column].max_len < len)
937 btrfs_qgroup_columns[column].max_len = len;
939 case BTRFS_QGROUP_MAX_RFER:
940 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
941 if (btrfs_qgroup_columns[column].max_len < len)
942 btrfs_qgroup_columns[column].max_len = len;
944 case BTRFS_QGROUP_MAX_EXCL:
945 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
946 if (btrfs_qgroup_columns[column].max_len < len)
947 btrfs_qgroup_columns[column].max_len = len;
949 case BTRFS_QGROUP_PARENT:
951 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
952 len += sprintf(tmp, "%llu/%llu",
953 (list->qgroup)->qgroupid >> 48,
954 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
955 if (!list_is_last(&list->next_qgroup, &bq->qgroups))
958 if (btrfs_qgroup_columns[column].max_len < len)
959 btrfs_qgroup_columns[column].max_len = len;
961 case BTRFS_QGROUP_CHILD:
963 list_for_each_entry(list, &bq->members, next_member) {
964 len += sprintf(tmp, "%llu/%llu",
965 (list->member)->qgroupid >> 48,
966 ((1ll << 48) - 1) & (list->member)->qgroupid);
967 if (!list_is_last(&list->next_member, &bq->members))
970 if (btrfs_qgroup_columns[column].max_len < len)
971 btrfs_qgroup_columns[column].max_len = len;
979 static void update_columns_max_len(struct btrfs_qgroup *bq)
983 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
984 if (!btrfs_qgroup_columns[i].need_print)
986 __update_columns_max_len(bq, i);
990 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
991 struct qgroup_lookup *sort_tree,
992 struct btrfs_qgroup_filter_set *filter_set,
993 struct btrfs_qgroup_comparer_set *comp_set)
996 struct btrfs_qgroup *entry;
999 qgroup_lookup_init(sort_tree);
1000 pre_process_filter_set(all_qgroups, filter_set);
1002 n = rb_last(&all_qgroups->root);
1004 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
1006 ret = filter_qgroup(entry, filter_set);
1008 sort_tree_insert(sort_tree, entry, comp_set);
1010 update_columns_max_len(entry);
1015 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1018 struct btrfs_ioctl_search_args args;
1019 struct btrfs_ioctl_search_key *sk = &args.key;
1020 struct btrfs_ioctl_search_header *sh;
1021 unsigned long off = 0;
1024 struct btrfs_qgroup_info_item *info;
1025 struct btrfs_qgroup_limit_item *limit;
1026 struct btrfs_qgroup *bq;
1027 struct btrfs_qgroup *bq1;
1034 memset(&args, 0, sizeof(args));
1036 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1037 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1038 sk->min_type = BTRFS_QGROUP_INFO_KEY;
1039 sk->max_objectid = (u64)-1;
1040 sk->max_offset = (u64)-1;
1041 sk->max_transid = (u64)-1;
1042 sk->nr_items = 4096;
1044 qgroup_lookup_init(qgroup_lookup);
1047 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1051 "ERROR: can't perform the search - %s\n",
1055 /* the ioctl returns the number of item it found in nr_items */
1056 if (sk->nr_items == 0)
1061 * for each item, pull the key out of the header and then
1062 * read the root_ref item it contains
1064 for (i = 0; i < sk->nr_items; i++) {
1065 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1069 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
1070 info = (struct btrfs_qgroup_info_item *)
1072 a1 = btrfs_stack_qgroup_info_generation(info);
1073 a2 = btrfs_stack_qgroup_info_referenced(info);
1075 btrfs_stack_qgroup_info_referenced_compressed
1077 a4 = btrfs_stack_qgroup_info_exclusive(info);
1079 btrfs_stack_qgroup_info_exclusive_compressed
1081 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
1082 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
1083 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
1084 limit = (struct btrfs_qgroup_limit_item *)
1087 a1 = btrfs_stack_qgroup_limit_flags(limit);
1088 a2 = btrfs_stack_qgroup_limit_max_referenced
1090 a3 = btrfs_stack_qgroup_limit_max_exclusive
1092 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1094 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1096 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1097 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
1098 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
1099 if (sh->offset < sh->objectid)
1101 bq = qgroup_tree_search(qgroup_lookup,
1105 bq1 = qgroup_tree_search(qgroup_lookup,
1109 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1110 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1117 * record the mins in sk so we can make sure the
1118 * next search doesn't repeat this root
1120 sk->min_type = sh->type;
1121 sk->min_offset = sh->offset;
1122 sk->min_objectid = sh->objectid;
1124 sk->nr_items = 4096;
1126 * this iteration is done, step forward one qgroup for the next
1129 if (sk->min_offset < (u64)-1)
1139 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1143 struct btrfs_qgroup *entry;
1147 n = rb_first(&qgroup_lookup->root);
1149 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1150 print_single_qgroup_table(entry);
1155 int btrfs_show_qgroups(int fd,
1156 struct btrfs_qgroup_filter_set *filter_set,
1157 struct btrfs_qgroup_comparer_set *comp_set)
1160 struct qgroup_lookup qgroup_lookup;
1161 struct qgroup_lookup sort_tree;
1164 ret = __qgroups_search(fd, &qgroup_lookup);
1167 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1168 filter_set, comp_set);
1169 print_all_qgroups(&sort_tree);
1171 __free_all_qgroups(&qgroup_lookup);
1172 btrfs_qgroup_free_filter_set(filter_set);
1176 u64 btrfs_get_path_rootid(int fd)
1179 struct btrfs_ioctl_ino_lookup_args args;
1181 memset(&args, 0, sizeof(args));
1182 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1184 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1187 "ERROR: can't perform the search - %s\n",
1194 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1195 struct btrfs_qgroup_comparer_set **comps)
1203 while ((p = strtok(opt_arg, ",")) != NULL) {
1205 ptr_argv = all_sort_items;
1208 if (strcmp(*ptr_argv, p) == 0) {
1213 if (strcmp(*ptr_argv, p) == 0) {
1230 } else if (*p == '-') {
1236 what_to_sort = btrfs_qgroup_get_sort_item(p);
1237 if (what_to_sort < 0)
1239 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1247 u64 parse_qgroupid(char *p)
1249 char *s = strchr(p, '/');
1250 char *ptr_src_end = p + strlen(p);
1251 char *ptr_parse_end = NULL;
1256 id = strtoull(p, &ptr_parse_end, 10);
1257 if (ptr_parse_end != ptr_src_end)
1261 level = strtoull(p, &ptr_parse_end, 10);
1262 if (ptr_parse_end != s)
1265 id = strtoull(s+1, &ptr_parse_end, 10);
1266 if (ptr_parse_end != ptr_src_end)
1269 return (level << 48) | id;
1271 fprintf(stderr, "ERROR:invalid qgroupid\n");
1275 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1277 return sizeof(*p) + sizeof(p->qgroups[0]) *
1278 (p->num_qgroups + 2 * p->num_ref_copies +
1279 2 * p->num_excl_copies);
1283 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1285 struct btrfs_qgroup_inherit *out;
1289 nitems = (*inherit)->num_qgroups +
1290 (*inherit)->num_ref_copies +
1291 (*inherit)->num_excl_copies;
1294 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1296 fprintf(stderr, "ERROR: Not enough memory\n");
1301 struct btrfs_qgroup_inherit *i = *inherit;
1302 int s = sizeof(out->qgroups[0]);
1304 out->num_qgroups = i->num_qgroups;
1305 out->num_ref_copies = i->num_ref_copies;
1306 out->num_excl_copies = i->num_excl_copies;
1307 memcpy(out->qgroups, i->qgroups, pos * s);
1308 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1309 (nitems - pos) * s);
1317 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1320 u64 qgroupid = parse_qgroupid(arg);
1323 if (qgroupid == 0) {
1324 fprintf(stderr, "ERROR: bad qgroup specification\n");
1329 pos = (*inherit)->num_qgroups;
1330 ret = qgroup_inherit_realloc(inherit, 1, pos);
1334 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1339 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1348 p = strchr(arg, ':');
1351 fprintf(stderr, "ERROR: bad copy specification\n");
1355 qgroup_src = parse_qgroupid(arg);
1356 qgroup_dst = parse_qgroupid(p + 1);
1359 if (!qgroup_src || !qgroup_dst)
1363 pos = (*inherit)->num_qgroups +
1364 (*inherit)->num_ref_copies * 2 * type;
1366 ret = qgroup_inherit_realloc(inherit, 2, pos);
1370 (*inherit)->qgroups[pos++] = qgroup_src;
1371 (*inherit)->qgroups[pos++] = qgroup_dst;
1374 ++(*inherit)->num_ref_copies;
1376 ++(*inherit)->num_excl_copies;