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>
26 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
27 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
29 struct qgroup_lookup {
34 struct rb_node rb_node;
35 struct rb_node sort_node;
37 *all_parent_node is used to
38 *filter a qgroup's all parent
40 struct rb_node all_parent_node;
47 u64 rfer; /*referenced*/
48 u64 rfer_cmpr; /*referenced compressed*/
49 u64 excl; /*exclusive*/
50 u64 excl_cmpr; /*exclusive compressed*/
55 u64 flags; /*which limits are set*/
61 /*qgroups this group is member of*/
62 struct list_head qgroups;
63 /*qgroups that are members of this group*/
64 struct list_head members;
68 * glue structure to represent the relations
71 struct btrfs_qgroup_list {
72 struct list_head next_qgroup;
73 struct list_head next_member;
74 struct btrfs_qgroup *qgroup;
75 struct btrfs_qgroup *member;
79 * qgroupid,rfer,excl default to set
87 } btrfs_qgroup_columns[] = {
90 .column_name = "Qgroupid",
97 .column_name = "Rfer",
99 .unit_mode = UNITS_DEFAULT,
104 .column_name = "Excl",
106 .unit_mode = UNITS_DEFAULT,
109 { .name = "max_rfer",
110 .column_name = "Max_rfer",
112 .unit_mode = UNITS_DEFAULT,
117 .column_name = "Max_excl",
119 .unit_mode = UNITS_DEFAULT,
124 .column_name = "Parent",
131 .column_name = "Child",
144 static btrfs_qgroup_filter_func all_filter_funcs[];
145 static btrfs_qgroup_comp_func all_comp_funcs[];
147 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
151 BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
153 if (column < BTRFS_QGROUP_ALL) {
154 btrfs_qgroup_columns[column].need_print = 1;
157 for (i = 0; i < BTRFS_QGROUP_ALL; i++)
158 btrfs_qgroup_columns[i].need_print = 1;
161 void btrfs_qgroup_setup_units(unsigned unit_mode)
163 btrfs_qgroup_columns[BTRFS_QGROUP_RFER].unit_mode = unit_mode;
164 btrfs_qgroup_columns[BTRFS_QGROUP_EXCL].unit_mode = unit_mode;
165 btrfs_qgroup_columns[BTRFS_QGROUP_MAX_RFER].unit_mode = unit_mode;
166 btrfs_qgroup_columns[BTRFS_QGROUP_MAX_EXCL].unit_mode = unit_mode;
169 static int print_parent_column(struct btrfs_qgroup *qgroup)
171 struct btrfs_qgroup_list *list = NULL;
174 list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
175 len += printf("%llu/%llu",
176 btrfs_qgroup_level(list->qgroup->qgroupid),
177 btrfs_qgroup_subvid(list->qgroup->qgroupid));
178 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
181 if (list_empty(&qgroup->qgroups))
182 len += printf("---");
187 static int print_child_column(struct btrfs_qgroup *qgroup)
189 struct btrfs_qgroup_list *list = NULL;
192 list_for_each_entry(list, &qgroup->members, next_member) {
193 len += printf("%llu/%llu",
194 btrfs_qgroup_level(list->member->qgroupid),
195 btrfs_qgroup_subvid(list->member->qgroupid));
196 if (!list_is_last(&list->next_member, &qgroup->members))
199 if (list_empty(&qgroup->members))
200 len += printf("---");
205 static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
208 len = btrfs_qgroup_columns[column].max_len - len;
213 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
214 enum btrfs_qgroup_column_enum column)
216 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
218 int unit_mode = btrfs_qgroup_columns[column].unit_mode;
219 int max_len = btrfs_qgroup_columns[column].max_len;
223 case BTRFS_QGROUP_QGROUPID:
224 len = printf("%llu/%llu",
225 btrfs_qgroup_level(qgroup->qgroupid),
226 btrfs_qgroup_subvid(qgroup->qgroupid));
227 print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
229 case BTRFS_QGROUP_RFER:
230 len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
232 case BTRFS_QGROUP_EXCL:
233 len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
235 case BTRFS_QGROUP_PARENT:
236 len = print_parent_column(qgroup);
237 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
239 case BTRFS_QGROUP_MAX_RFER:
240 if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
241 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
243 len = printf("%*s", max_len, "none");
245 case BTRFS_QGROUP_MAX_EXCL:
246 if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
247 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
249 len = printf("%*s", max_len, "none");
251 case BTRFS_QGROUP_CHILD:
252 len = print_child_column(qgroup);
253 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
260 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
264 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
265 if (!btrfs_qgroup_columns[i].need_print)
267 print_qgroup_column(qgroup, i);
269 if (i != BTRFS_QGROUP_CHILD)
275 static void print_table_head(void)
281 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
282 max_len = btrfs_qgroup_columns[i].max_len;
283 if (!btrfs_qgroup_columns[i].need_print)
285 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
286 (i == BTRFS_QGROUP_CHILD))
287 printf("%-*s", max_len, btrfs_qgroup_columns[i].name);
289 printf("%*s", max_len, btrfs_qgroup_columns[i].name);
293 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
294 max_len = btrfs_qgroup_columns[i].max_len;
295 if (!btrfs_qgroup_columns[i].need_print)
297 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
298 (i == BTRFS_QGROUP_CHILD)) {
299 len = strlen(btrfs_qgroup_columns[i].name);
302 len = max_len - strlen(btrfs_qgroup_columns[i].name);
306 len = max_len - strlen(btrfs_qgroup_columns[i].name);
309 len = strlen(btrfs_qgroup_columns[i].name);
318 static void qgroup_lookup_init(struct qgroup_lookup *tree)
320 tree->root.rb_node = NULL;
323 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
324 struct btrfs_qgroup *entry2,
330 if (entry1->qgroupid > entry2->qgroupid)
332 else if (entry1->qgroupid < entry2->qgroupid)
337 return is_descending ? -ret : ret;
340 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
341 struct btrfs_qgroup *entry2,
346 if (entry1->rfer > entry2->rfer)
348 else if (entry1->rfer < entry2->rfer)
353 return is_descending ? -ret : ret;
356 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
357 struct btrfs_qgroup *entry2,
362 if (entry1->excl > entry2->excl)
364 else if (entry1->excl < entry2->excl)
369 return is_descending ? -ret : ret;
372 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
373 struct btrfs_qgroup *entry2,
378 if (entry1->max_rfer > entry2->max_rfer)
380 else if (entry1->max_rfer < entry2->max_rfer)
385 return is_descending ? -ret : ret;
388 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
389 struct btrfs_qgroup *entry2,
394 if (entry1->max_excl > entry2->max_excl)
396 else if (entry1->max_excl < entry2->max_excl)
401 return is_descending ? -ret : ret;
404 static btrfs_qgroup_comp_func all_comp_funcs[] = {
405 [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid,
406 [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer,
407 [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl,
408 [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer,
409 [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl
412 static char *all_sort_items[] = {
413 [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid",
414 [BTRFS_QGROUP_COMP_RFER] = "rfer",
415 [BTRFS_QGROUP_COMP_EXCL] = "excl",
416 [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer",
417 [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl",
418 [BTRFS_QGROUP_COMP_MAX] = NULL,
421 static int btrfs_qgroup_get_sort_item(char *sort_name)
425 for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
426 if (strcmp(sort_name, all_sort_items[i]) == 0)
432 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
434 struct btrfs_qgroup_comparer_set *set;
436 size = sizeof(struct btrfs_qgroup_comparer_set) +
437 BTRFS_QGROUP_NCOMPS_INCREASE *
438 sizeof(struct btrfs_qgroup_comparer);
439 set = calloc(1, size);
441 fprintf(stderr, "memory allocation failed\n");
445 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
450 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
455 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
456 enum btrfs_qgroup_comp_enum comparer,
459 struct btrfs_qgroup_comparer_set *set = *comp_set;
463 BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
464 BUG_ON(set->ncomps > set->total);
466 if (set->ncomps == set->total) {
469 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
470 size = sizeof(*set) +
471 size * sizeof(struct btrfs_qgroup_comparer);
473 set = realloc(set, size);
475 fprintf(stderr, "memory allocation failed\n");
480 memset(&set->comps[set->total], 0,
481 BTRFS_QGROUP_NCOMPS_INCREASE *
482 sizeof(struct btrfs_qgroup_comparer));
483 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
487 BUG_ON(set->comps[set->ncomps].comp_func);
489 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
490 set->comps[set->ncomps].is_descending = is_descending;
495 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
496 struct btrfs_qgroup_comparer_set *set)
498 int qgroupid_compared = 0;
501 if (!set || !set->ncomps)
504 for (i = 0; i < set->ncomps; i++) {
505 if (!set->comps[i].comp_func)
508 ret = set->comps[i].comp_func(entry1, entry2,
509 set->comps[i].is_descending);
513 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
514 qgroupid_compared = 1;
517 if (!qgroupid_compared) {
519 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
526 * insert a new root into the tree. returns the existing root entry
527 * if one is already there. qgroupid is used
530 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
531 struct btrfs_qgroup *ins)
534 struct rb_node **p = &root_tree->root.rb_node;
535 struct rb_node *parent = NULL;
536 struct btrfs_qgroup *curr;
541 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
543 ret = comp_entry_with_qgroupid(ins, curr, 0);
551 rb_link_node(&ins->rb_node, parent, p);
552 rb_insert_color(&ins->rb_node, &root_tree->root);
557 *find a given qgroupid in the tree. We return the smallest one,
558 *rb_next can be used to move forward looking for more if required
560 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
563 struct rb_node *n = root_tree->root.rb_node;
564 struct btrfs_qgroup *entry;
565 struct btrfs_qgroup tmp;
568 tmp.qgroupid = qgroupid;
571 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
573 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
585 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
586 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
587 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
588 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
589 struct btrfs_qgroup *child)
591 struct btrfs_qgroup *bq;
592 struct btrfs_qgroup_list *list;
594 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
595 if (!bq || bq->qgroupid != qgroupid)
599 bq->generation = generation;
603 bq->rfer_cmpr = rfer_cmpr;
607 bq->excl_cmpr = excl_cmpr;
611 bq->max_rfer = max_rfer;
613 bq->max_excl = max_excl;
615 bq->rsv_rfer = rsv_rfer;
617 list = malloc(sizeof(*list));
619 fprintf(stderr, "memory allocation failed\n");
623 list->member = child;
624 list_add_tail(&list->next_qgroup, &child->qgroups);
625 list_add_tail(&list->next_member, &pa->members);
630 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
631 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
632 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
633 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
634 struct btrfs_qgroup *child)
636 struct btrfs_qgroup *bq;
637 struct btrfs_qgroup_list *list;
640 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
641 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
642 max_excl, rsv_rfer, rsv_excl, parent, child);
646 bq = calloc(1, sizeof(*bq));
648 printf("memory allocation failed\n");
652 bq->qgroupid = qgroupid;
653 INIT_LIST_HEAD(&bq->qgroups);
654 INIT_LIST_HEAD(&bq->members);
657 bq->generation = generation;
661 bq->rfer_cmpr = rfer_cmpr;
665 bq->excl_cmpr = excl_cmpr;
669 bq->max_rfer = max_rfer;
671 bq->max_excl = max_excl;
673 bq->rsv_rfer = rsv_rfer;
674 if (parent && child) {
675 list = malloc(sizeof(*list));
677 fprintf(stderr, "memory allocation failed\n");
680 list->qgroup = parent;
681 list->member = child;
682 list_add_tail(&list->next_qgroup, &child->qgroups);
683 list_add_tail(&list->next_member, &parent->members);
685 ret = qgroup_tree_insert(qgroup_lookup, bq);
687 printf("failed to insert tree %llu\n",
694 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
696 struct btrfs_qgroup_list *list;
697 while (!list_empty(&bq->qgroups)) {
698 list = list_entry((&bq->qgroups)->next,
699 struct btrfs_qgroup_list,
701 list_del(&list->next_qgroup);
702 list_del(&list->next_member);
705 while (!list_empty(&bq->members)) {
706 list = list_entry((&bq->members)->next,
707 struct btrfs_qgroup_list,
709 list_del(&list->next_qgroup);
710 list_del(&list->next_member);
716 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
718 struct btrfs_qgroup *entry;
721 n = rb_first(&root_tree->root);
723 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
724 rb_erase(n, &root_tree->root);
725 __free_btrfs_qgroup(entry);
727 n = rb_first(&root_tree->root);
731 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
732 struct btrfs_qgroup *bq)
734 struct rb_node **p = &sort_tree->root.rb_node;
735 struct rb_node *parent = NULL;
736 struct btrfs_qgroup *curr;
741 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
743 ret = comp_entry_with_qgroupid(bq, curr, 0);
751 rb_link_node(&bq->all_parent_node, parent, p);
752 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
756 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
758 struct btrfs_qgroup *qgroup =
759 (struct btrfs_qgroup *)(unsigned long)data;
763 if (qgroup->qgroupid == bq->qgroupid)
768 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
770 struct qgroup_lookup lookup;
771 struct qgroup_lookup *ql = &lookup;
772 struct btrfs_qgroup_list *list;
774 struct btrfs_qgroup *qgroup =
775 (struct btrfs_qgroup *)(unsigned long)data;
779 if (bq->qgroupid == qgroup->qgroupid)
782 qgroup_lookup_init(ql);
783 filter_all_parent_insert(ql, qgroup);
784 n = rb_first(&ql->root);
786 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
787 if (!list_empty(&qgroup->qgroups)) {
788 list_for_each_entry(list, &qgroup->qgroups,
790 if ((list->qgroup)->qgroupid == bq->qgroupid)
792 filter_all_parent_insert(ql, list->qgroup);
795 rb_erase(n, &ql->root);
796 n = rb_first(&ql->root);
801 static btrfs_qgroup_filter_func all_filter_funcs[] = {
802 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
803 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
806 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
808 struct btrfs_qgroup_filter_set *set;
811 size = sizeof(struct btrfs_qgroup_filter_set) +
812 BTRFS_QGROUP_NFILTERS_INCREASE *
813 sizeof(struct btrfs_qgroup_filter);
814 set = calloc(1, size);
816 fprintf(stderr, "memory allocation failed\n");
819 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
824 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
829 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
830 enum btrfs_qgroup_filter_enum filter, u64 data)
832 struct btrfs_qgroup_filter_set *set = *filter_set;
836 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
837 BUG_ON(set->nfilters > set->total);
839 if (set->nfilters == set->total) {
842 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
843 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
846 set = realloc(set, size);
848 fprintf(stderr, "memory allocation failed\n");
852 memset(&set->filters[set->total], 0,
853 BTRFS_QGROUP_NFILTERS_INCREASE *
854 sizeof(struct btrfs_qgroup_filter));
855 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
858 BUG_ON(set->filters[set->nfilters].filter_func);
859 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
860 set->filters[set->nfilters].data = data;
865 static int filter_qgroup(struct btrfs_qgroup *bq,
866 struct btrfs_qgroup_filter_set *set)
870 if (!set || !set->nfilters)
872 for (i = 0; i < set->nfilters; i++) {
873 if (!set->filters[i].filter_func)
875 ret = set->filters[i].filter_func(bq, set->filters[i].data);
882 static void pre_process_filter_set(struct qgroup_lookup *lookup,
883 struct btrfs_qgroup_filter_set *set)
886 struct btrfs_qgroup *qgroup_for_filter = NULL;
888 for (i = 0; i < set->nfilters; i++) {
890 if (set->filters[i].filter_func == filter_by_all_parent
891 || set->filters[i].filter_func == filter_by_parent) {
892 qgroup_for_filter = qgroup_tree_search(lookup,
893 set->filters[i].data);
894 set->filters[i].data =
895 (u64)(unsigned long)qgroup_for_filter;
900 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
901 struct btrfs_qgroup *bq,
902 struct btrfs_qgroup_comparer_set *comp_set)
904 struct rb_node **p = &sort_tree->root.rb_node;
905 struct rb_node *parent = NULL;
906 struct btrfs_qgroup *curr;
911 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
913 ret = sort_comp(bq, curr, comp_set);
921 rb_link_node(&bq->sort_node, parent, p);
922 rb_insert_color(&bq->sort_node, &sort_tree->root);
926 static void __update_columns_max_len(struct btrfs_qgroup *bq,
927 enum btrfs_qgroup_column_enum column)
929 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
930 struct btrfs_qgroup_list *list = NULL;
933 unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
937 case BTRFS_QGROUP_QGROUPID:
938 sprintf(tmp, "%llu/%llu",
939 btrfs_qgroup_level(bq->qgroupid),
940 btrfs_qgroup_subvid(bq->qgroupid));
942 if (btrfs_qgroup_columns[column].max_len < len)
943 btrfs_qgroup_columns[column].max_len = len;
945 case BTRFS_QGROUP_RFER:
946 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
947 if (btrfs_qgroup_columns[column].max_len < len)
948 btrfs_qgroup_columns[column].max_len = len;
950 case BTRFS_QGROUP_EXCL:
951 len = strlen(pretty_size_mode(bq->excl, unit_mode));
952 if (btrfs_qgroup_columns[column].max_len < len)
953 btrfs_qgroup_columns[column].max_len = len;
955 case BTRFS_QGROUP_MAX_RFER:
956 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
957 if (btrfs_qgroup_columns[column].max_len < len)
958 btrfs_qgroup_columns[column].max_len = len;
960 case BTRFS_QGROUP_MAX_EXCL:
961 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
962 if (btrfs_qgroup_columns[column].max_len < len)
963 btrfs_qgroup_columns[column].max_len = len;
965 case BTRFS_QGROUP_PARENT:
967 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
968 len += sprintf(tmp, "%llu/%llu",
969 btrfs_qgroup_level(list->qgroup->qgroupid),
970 btrfs_qgroup_subvid(list->qgroup->qgroupid));
971 if (!list_is_last(&list->next_qgroup, &bq->qgroups))
974 if (btrfs_qgroup_columns[column].max_len < len)
975 btrfs_qgroup_columns[column].max_len = len;
977 case BTRFS_QGROUP_CHILD:
979 list_for_each_entry(list, &bq->members, next_member) {
980 len += sprintf(tmp, "%llu/%llu",
981 btrfs_qgroup_level(list->member->qgroupid),
982 btrfs_qgroup_subvid(list->member->qgroupid));
983 if (!list_is_last(&list->next_member, &bq->members))
986 if (btrfs_qgroup_columns[column].max_len < len)
987 btrfs_qgroup_columns[column].max_len = len;
995 static void update_columns_max_len(struct btrfs_qgroup *bq)
999 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
1000 if (!btrfs_qgroup_columns[i].need_print)
1002 __update_columns_max_len(bq, i);
1006 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
1007 struct qgroup_lookup *sort_tree,
1008 struct btrfs_qgroup_filter_set *filter_set,
1009 struct btrfs_qgroup_comparer_set *comp_set)
1012 struct btrfs_qgroup *entry;
1015 qgroup_lookup_init(sort_tree);
1016 pre_process_filter_set(all_qgroups, filter_set);
1018 n = rb_last(&all_qgroups->root);
1020 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
1022 ret = filter_qgroup(entry, filter_set);
1024 sort_tree_insert(sort_tree, entry, comp_set);
1026 update_columns_max_len(entry);
1032 static inline void print_status_flag_warning(u64 flags)
1034 if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
1036 "WARNING: Quota disabled, qgroup data may be out of date\n");
1037 else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
1039 "WARNING: Rescan is running, qgroup data may be incorrect\n");
1040 else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
1042 "WARNING: Qgroup data inconsistent, rescan recommended\n");
1045 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1048 struct btrfs_ioctl_search_args args;
1049 struct btrfs_ioctl_search_key *sk = &args.key;
1050 struct btrfs_ioctl_search_header *sh;
1051 unsigned long off = 0;
1053 struct btrfs_qgroup_info_item *info;
1054 struct btrfs_qgroup_limit_item *limit;
1055 struct btrfs_qgroup *bq;
1056 struct btrfs_qgroup *bq1;
1063 memset(&args, 0, sizeof(args));
1065 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1066 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1067 sk->min_type = BTRFS_QGROUP_STATUS_KEY;
1068 sk->max_objectid = (u64)-1;
1069 sk->max_offset = (u64)-1;
1070 sk->max_transid = (u64)-1;
1071 sk->nr_items = 4096;
1073 qgroup_lookup_init(qgroup_lookup);
1076 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1079 "ERROR: can't perform the search - %s\n",
1083 /* the ioctl returns the number of item it found in nr_items */
1084 if (sk->nr_items == 0)
1089 * for each item, pull the key out of the header and then
1090 * read the root_ref item it contains
1092 for (i = 0; i < sk->nr_items; i++) {
1093 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1097 if (btrfs_search_header_type(sh)
1098 == BTRFS_QGROUP_STATUS_KEY) {
1099 struct btrfs_qgroup_status_item *si;
1102 si = (struct btrfs_qgroup_status_item *)
1104 flags = btrfs_stack_qgroup_status_flags(si);
1105 print_status_flag_warning(flags);
1106 } else if (btrfs_search_header_type(sh)
1107 == BTRFS_QGROUP_INFO_KEY) {
1108 info = (struct btrfs_qgroup_info_item *)
1110 a1 = btrfs_stack_qgroup_info_generation(info);
1111 a2 = btrfs_stack_qgroup_info_referenced(info);
1113 btrfs_stack_qgroup_info_referenced_compressed
1115 a4 = btrfs_stack_qgroup_info_exclusive(info);
1117 btrfs_stack_qgroup_info_exclusive_compressed
1119 add_qgroup(qgroup_lookup,
1120 btrfs_search_header_offset(sh), a1,
1121 a2, a3, a4, a5, 0, 0, 0, 0, 0, NULL,
1123 } else if (btrfs_search_header_type(sh)
1124 == BTRFS_QGROUP_LIMIT_KEY) {
1125 limit = (struct btrfs_qgroup_limit_item *)
1128 a1 = btrfs_stack_qgroup_limit_flags(limit);
1129 a2 = btrfs_stack_qgroup_limit_max_referenced
1131 a3 = btrfs_stack_qgroup_limit_max_exclusive
1133 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1135 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1137 add_qgroup(qgroup_lookup,
1138 btrfs_search_header_offset(sh), 0,
1139 0, 0, 0, 0, a1, a2, a3, a4, a5,
1141 } else if (btrfs_search_header_type(sh)
1142 == BTRFS_QGROUP_RELATION_KEY) {
1143 if (btrfs_search_header_offset(sh)
1144 < btrfs_search_header_objectid(sh))
1146 bq = qgroup_tree_search(qgroup_lookup,
1147 btrfs_search_header_offset(sh));
1150 bq1 = qgroup_tree_search(qgroup_lookup,
1151 btrfs_search_header_objectid(sh));
1154 add_qgroup(qgroup_lookup,
1155 btrfs_search_header_offset(sh), 0,
1156 0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1160 off += btrfs_search_header_len(sh);
1163 * record the mins in sk so we can make sure the
1164 * next search doesn't repeat this root
1166 sk->min_type = btrfs_search_header_type(sh);
1167 sk->min_offset = btrfs_search_header_offset(sh);
1168 sk->min_objectid = btrfs_search_header_objectid(sh);
1170 sk->nr_items = 4096;
1172 * this iteration is done, step forward one qgroup for the next
1175 if (sk->min_offset < (u64)-1)
1185 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1189 struct btrfs_qgroup *entry;
1193 n = rb_first(&qgroup_lookup->root);
1195 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1196 print_single_qgroup_table(entry);
1201 int btrfs_show_qgroups(int fd,
1202 struct btrfs_qgroup_filter_set *filter_set,
1203 struct btrfs_qgroup_comparer_set *comp_set)
1206 struct qgroup_lookup qgroup_lookup;
1207 struct qgroup_lookup sort_tree;
1210 ret = __qgroups_search(fd, &qgroup_lookup);
1213 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1214 filter_set, comp_set);
1215 print_all_qgroups(&sort_tree);
1217 __free_all_qgroups(&qgroup_lookup);
1218 btrfs_qgroup_free_filter_set(filter_set);
1219 btrfs_qgroup_free_comparer_set(comp_set);
1223 u64 btrfs_get_path_rootid(int fd)
1226 struct btrfs_ioctl_ino_lookup_args args;
1228 memset(&args, 0, sizeof(args));
1229 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1231 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1234 "ERROR: can't perform the search - %s\n",
1241 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1242 struct btrfs_qgroup_comparer_set **comps)
1250 while ((p = strtok(opt_arg, ",")) != NULL) {
1252 ptr_argv = all_sort_items;
1255 if (strcmp(*ptr_argv, p) == 0) {
1260 if (strcmp(*ptr_argv, p) == 0) {
1277 } else if (*p == '-') {
1283 what_to_sort = btrfs_qgroup_get_sort_item(p);
1284 if (what_to_sort < 0)
1286 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1294 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1296 return sizeof(*p) + sizeof(p->qgroups[0]) *
1297 (p->num_qgroups + 2 * p->num_ref_copies +
1298 2 * p->num_excl_copies);
1302 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1304 struct btrfs_qgroup_inherit *out;
1308 nitems = (*inherit)->num_qgroups +
1309 (*inherit)->num_ref_copies +
1310 (*inherit)->num_excl_copies;
1313 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1315 fprintf(stderr, "ERROR: Not enough memory\n");
1320 struct btrfs_qgroup_inherit *i = *inherit;
1321 int s = sizeof(out->qgroups[0]);
1323 out->num_qgroups = i->num_qgroups;
1324 out->num_ref_copies = i->num_ref_copies;
1325 out->num_excl_copies = i->num_excl_copies;
1326 memcpy(out->qgroups, i->qgroups, pos * s);
1327 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1328 (nitems - pos) * s);
1336 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1339 u64 qgroupid = parse_qgroupid(arg);
1342 if (qgroupid == 0) {
1343 fprintf(stderr, "ERROR: bad qgroup specification\n");
1348 pos = (*inherit)->num_qgroups;
1349 ret = qgroup_inherit_realloc(inherit, 1, pos);
1353 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1358 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1367 p = strchr(arg, ':');
1370 fprintf(stderr, "ERROR: bad copy specification\n");
1374 qgroup_src = parse_qgroupid(arg);
1375 qgroup_dst = parse_qgroupid(p + 1);
1378 if (!qgroup_src || !qgroup_dst)
1382 pos = (*inherit)->num_qgroups +
1383 (*inherit)->num_ref_copies * 2 * type;
1385 ret = qgroup_inherit_realloc(inherit, 2, pos);
1389 (*inherit)->qgroups[pos++] = qgroup_src;
1390 (*inherit)->qgroups[pos++] = qgroup_dst;
1393 ++(*inherit)->num_ref_copies;
1395 ++(*inherit)->num_excl_copies;