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()
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);
441 fprintf(stderr, "memory allocation failed\n");
445 memset(set, 0, size);
446 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
451 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
456 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
457 enum btrfs_qgroup_comp_enum comparer,
460 struct btrfs_qgroup_comparer_set *set = *comp_set;
464 BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
465 BUG_ON(set->ncomps > set->total);
467 if (set->ncomps == set->total) {
468 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
469 size = sizeof(*set) +
470 size * sizeof(struct btrfs_qgroup_comparer);
471 set = realloc(set, size);
473 fprintf(stderr, "memory allocation failed\n");
477 memset(&set->comps[set->total], 0,
478 BTRFS_QGROUP_NCOMPS_INCREASE *
479 sizeof(struct btrfs_qgroup_comparer));
480 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
484 BUG_ON(set->comps[set->ncomps].comp_func);
486 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
487 set->comps[set->ncomps].is_descending = is_descending;
492 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
493 struct btrfs_qgroup_comparer_set *set)
495 int qgroupid_compared = 0;
498 if (!set || !set->ncomps)
501 for (i = 0; i < set->ncomps; i++) {
502 if (!set->comps[i].comp_func)
505 ret = set->comps[i].comp_func(entry1, entry2,
506 set->comps[i].is_descending);
510 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
511 qgroupid_compared = 1;
514 if (!qgroupid_compared) {
516 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
523 * insert a new root into the tree. returns the existing root entry
524 * if one is already there. qgroupid is used
527 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
528 struct btrfs_qgroup *ins)
531 struct rb_node **p = &root_tree->root.rb_node;
532 struct rb_node *parent = NULL;
533 struct btrfs_qgroup *curr;
538 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
540 ret = comp_entry_with_qgroupid(ins, curr, 0);
548 rb_link_node(&ins->rb_node, parent, p);
549 rb_insert_color(&ins->rb_node, &root_tree->root);
554 *find a given qgroupid in the tree. We return the smallest one,
555 *rb_next can be used to move forward looking for more if required
557 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
560 struct rb_node *n = root_tree->root.rb_node;
561 struct btrfs_qgroup *entry;
562 struct btrfs_qgroup tmp;
565 tmp.qgroupid = qgroupid;
568 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
570 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
582 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
583 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
584 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
585 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
586 struct btrfs_qgroup *child)
588 struct btrfs_qgroup *bq;
589 struct btrfs_qgroup_list *list;
591 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
592 if (!bq || bq->qgroupid != qgroupid)
596 bq->generation = generation;
600 bq->rfer_cmpr = rfer_cmpr;
604 bq->excl_cmpr = excl_cmpr;
608 bq->max_rfer = max_rfer;
610 bq->max_excl = max_excl;
612 bq->rsv_rfer = rsv_rfer;
614 list = malloc(sizeof(*list));
616 fprintf(stderr, "memory allocation failed\n");
620 list->member = child;
621 list_add_tail(&list->next_qgroup, &child->qgroups);
622 list_add_tail(&list->next_member, &pa->members);
627 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
628 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
629 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
630 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
631 struct btrfs_qgroup *child)
633 struct btrfs_qgroup *bq;
634 struct btrfs_qgroup_list *list;
637 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
638 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
639 max_excl, rsv_rfer, rsv_excl, parent, child);
643 bq = malloc(sizeof(*bq));
645 printf("memory allocation failed\n");
648 memset(bq, 0, sizeof(*bq));
650 bq->qgroupid = qgroupid;
651 INIT_LIST_HEAD(&bq->qgroups);
652 INIT_LIST_HEAD(&bq->members);
655 bq->generation = generation;
659 bq->rfer_cmpr = rfer_cmpr;
663 bq->excl_cmpr = excl_cmpr;
667 bq->max_rfer = max_rfer;
669 bq->max_excl = max_excl;
671 bq->rsv_rfer = rsv_rfer;
672 if (parent && child) {
673 list = malloc(sizeof(*list));
675 fprintf(stderr, "memory allocation failed\n");
678 list->qgroup = parent;
679 list->member = child;
680 list_add_tail(&list->next_qgroup, &child->qgroups);
681 list_add_tail(&list->next_member, &parent->members);
683 ret = qgroup_tree_insert(qgroup_lookup, bq);
685 printf("failed to insert tree %llu\n",
692 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
694 struct btrfs_qgroup_list *list;
695 while (!list_empty(&bq->qgroups)) {
696 list = list_entry((&bq->qgroups)->next,
697 struct btrfs_qgroup_list,
699 list_del(&list->next_qgroup);
700 list_del(&list->next_member);
703 while (!list_empty(&bq->members)) {
704 list = list_entry((&bq->members)->next,
705 struct btrfs_qgroup_list,
707 list_del(&list->next_qgroup);
708 list_del(&list->next_member);
714 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
716 struct btrfs_qgroup *entry;
719 n = rb_first(&root_tree->root);
721 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
722 rb_erase(n, &root_tree->root);
723 __free_btrfs_qgroup(entry);
725 n = rb_first(&root_tree->root);
729 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
730 struct btrfs_qgroup *bq)
732 struct rb_node **p = &sort_tree->root.rb_node;
733 struct rb_node *parent = NULL;
734 struct btrfs_qgroup *curr;
739 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
741 ret = comp_entry_with_qgroupid(bq, curr, 0);
749 rb_link_node(&bq->all_parent_node, parent, p);
750 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
754 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
756 struct btrfs_qgroup *qgroup =
757 (struct btrfs_qgroup *)(unsigned long)data;
761 if (qgroup->qgroupid == bq->qgroupid)
766 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
768 struct qgroup_lookup lookup;
769 struct qgroup_lookup *ql = &lookup;
770 struct btrfs_qgroup_list *list;
772 struct btrfs_qgroup *qgroup =
773 (struct btrfs_qgroup *)(unsigned long)data;
777 if (bq->qgroupid == qgroup->qgroupid)
780 qgroup_lookup_init(ql);
781 filter_all_parent_insert(ql, qgroup);
782 n = rb_first(&ql->root);
784 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
785 if (!list_empty(&qgroup->qgroups)) {
786 list_for_each_entry(list, &qgroup->qgroups,
788 if ((list->qgroup)->qgroupid == bq->qgroupid)
790 filter_all_parent_insert(ql, list->qgroup);
793 rb_erase(n, &ql->root);
794 n = rb_first(&ql->root);
799 static btrfs_qgroup_filter_func all_filter_funcs[] = {
800 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
801 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
804 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
806 struct btrfs_qgroup_filter_set *set;
809 size = sizeof(struct btrfs_qgroup_filter_set) +
810 BTRFS_QGROUP_NFILTERS_INCREASE *
811 sizeof(struct btrfs_qgroup_filter);
814 fprintf(stderr, "memory allocation failed\n");
817 memset(set, 0, size);
818 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
823 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
828 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
829 enum btrfs_qgroup_filter_enum filter, u64 data)
831 struct btrfs_qgroup_filter_set *set = *filter_set;
835 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
836 BUG_ON(set->nfilters > set->total);
838 if (set->nfilters == set->total) {
839 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
840 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
842 set = realloc(set, size);
844 fprintf(stderr, "memory allocation failed\n");
847 memset(&set->filters[set->total], 0,
848 BTRFS_QGROUP_NFILTERS_INCREASE *
849 sizeof(struct btrfs_qgroup_filter));
850 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
853 BUG_ON(set->filters[set->nfilters].filter_func);
854 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
855 set->filters[set->nfilters].data = data;
860 static int filter_qgroup(struct btrfs_qgroup *bq,
861 struct btrfs_qgroup_filter_set *set)
865 if (!set || !set->nfilters)
867 for (i = 0; i < set->nfilters; i++) {
868 if (!set->filters[i].filter_func)
870 ret = set->filters[i].filter_func(bq, set->filters[i].data);
877 static void pre_process_filter_set(struct qgroup_lookup *lookup,
878 struct btrfs_qgroup_filter_set *set)
881 struct btrfs_qgroup *qgroup_for_filter = NULL;
883 for (i = 0; i < set->nfilters; i++) {
885 if (set->filters[i].filter_func == filter_by_all_parent
886 || set->filters[i].filter_func == filter_by_parent) {
887 qgroup_for_filter = qgroup_tree_search(lookup,
888 set->filters[i].data);
889 set->filters[i].data =
890 (u64)(unsigned long)qgroup_for_filter;
895 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
896 struct btrfs_qgroup *bq,
897 struct btrfs_qgroup_comparer_set *comp_set)
899 struct rb_node **p = &sort_tree->root.rb_node;
900 struct rb_node *parent = NULL;
901 struct btrfs_qgroup *curr;
906 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
908 ret = sort_comp(bq, curr, comp_set);
916 rb_link_node(&bq->sort_node, parent, p);
917 rb_insert_color(&bq->sort_node, &sort_tree->root);
921 static void __update_columns_max_len(struct btrfs_qgroup *bq,
922 enum btrfs_qgroup_column_enum column)
924 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
925 struct btrfs_qgroup_list *list = NULL;
928 unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
932 case BTRFS_QGROUP_QGROUPID:
933 sprintf(tmp, "%llu/%llu",
934 btrfs_qgroup_level(bq->qgroupid),
935 btrfs_qgroup_subvid(bq->qgroupid));
937 if (btrfs_qgroup_columns[column].max_len < len)
938 btrfs_qgroup_columns[column].max_len = len;
940 case BTRFS_QGROUP_RFER:
941 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
942 if (btrfs_qgroup_columns[column].max_len < len)
943 btrfs_qgroup_columns[column].max_len = len;
945 case BTRFS_QGROUP_EXCL:
946 len = strlen(pretty_size_mode(bq->excl, unit_mode));
947 if (btrfs_qgroup_columns[column].max_len < len)
948 btrfs_qgroup_columns[column].max_len = len;
950 case BTRFS_QGROUP_MAX_RFER:
951 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
952 if (btrfs_qgroup_columns[column].max_len < len)
953 btrfs_qgroup_columns[column].max_len = len;
955 case BTRFS_QGROUP_MAX_EXCL:
956 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
957 if (btrfs_qgroup_columns[column].max_len < len)
958 btrfs_qgroup_columns[column].max_len = len;
960 case BTRFS_QGROUP_PARENT:
962 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
963 len += sprintf(tmp, "%llu/%llu",
964 btrfs_qgroup_level(list->qgroup->qgroupid),
965 btrfs_qgroup_subvid(list->qgroup->qgroupid));
966 if (!list_is_last(&list->next_qgroup, &bq->qgroups))
969 if (btrfs_qgroup_columns[column].max_len < len)
970 btrfs_qgroup_columns[column].max_len = len;
972 case BTRFS_QGROUP_CHILD:
974 list_for_each_entry(list, &bq->members, next_member) {
975 len += sprintf(tmp, "%llu/%llu",
976 btrfs_qgroup_level(list->member->qgroupid),
977 btrfs_qgroup_subvid(list->member->qgroupid));
978 if (!list_is_last(&list->next_member, &bq->members))
981 if (btrfs_qgroup_columns[column].max_len < len)
982 btrfs_qgroup_columns[column].max_len = len;
990 static void update_columns_max_len(struct btrfs_qgroup *bq)
994 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
995 if (!btrfs_qgroup_columns[i].need_print)
997 __update_columns_max_len(bq, i);
1001 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
1002 struct qgroup_lookup *sort_tree,
1003 struct btrfs_qgroup_filter_set *filter_set,
1004 struct btrfs_qgroup_comparer_set *comp_set)
1007 struct btrfs_qgroup *entry;
1010 qgroup_lookup_init(sort_tree);
1011 pre_process_filter_set(all_qgroups, filter_set);
1013 n = rb_last(&all_qgroups->root);
1015 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
1017 ret = filter_qgroup(entry, filter_set);
1019 sort_tree_insert(sort_tree, entry, comp_set);
1021 update_columns_max_len(entry);
1027 static inline void print_status_flag_warning(u64 flags)
1029 if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
1031 "WARNING: Quota disabled, qgroup data may be out of date\n");
1032 else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
1034 "WARNING: Rescan is running, qgroup data may be incorrect\n");
1035 else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
1037 "WARNING: Qgroup data inconsistent, rescan recommended\n");
1040 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1043 struct btrfs_ioctl_search_args args;
1044 struct btrfs_ioctl_search_key *sk = &args.key;
1045 struct btrfs_ioctl_search_header *sh;
1046 unsigned long off = 0;
1049 struct btrfs_qgroup_info_item *info;
1050 struct btrfs_qgroup_limit_item *limit;
1051 struct btrfs_qgroup *bq;
1052 struct btrfs_qgroup *bq1;
1059 memset(&args, 0, sizeof(args));
1061 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1062 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1063 sk->min_type = BTRFS_QGROUP_STATUS_KEY;
1064 sk->max_objectid = (u64)-1;
1065 sk->max_offset = (u64)-1;
1066 sk->max_transid = (u64)-1;
1067 sk->nr_items = 4096;
1069 qgroup_lookup_init(qgroup_lookup);
1072 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1076 "ERROR: can't perform the search - %s\n",
1080 /* the ioctl returns the number of item it found in nr_items */
1081 if (sk->nr_items == 0)
1086 * for each item, pull the key out of the header and then
1087 * read the root_ref item it contains
1089 for (i = 0; i < sk->nr_items; i++) {
1090 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1094 if (sh->type == BTRFS_QGROUP_STATUS_KEY) {
1095 struct btrfs_qgroup_status_item *si;
1098 si = (struct btrfs_qgroup_status_item *)
1100 flags = btrfs_stack_qgroup_status_flags(si);
1101 print_status_flag_warning(flags);
1102 } else if (sh->type == BTRFS_QGROUP_INFO_KEY) {
1103 info = (struct btrfs_qgroup_info_item *)
1105 a1 = btrfs_stack_qgroup_info_generation(info);
1106 a2 = btrfs_stack_qgroup_info_referenced(info);
1108 btrfs_stack_qgroup_info_referenced_compressed
1110 a4 = btrfs_stack_qgroup_info_exclusive(info);
1112 btrfs_stack_qgroup_info_exclusive_compressed
1114 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
1115 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
1116 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
1117 limit = (struct btrfs_qgroup_limit_item *)
1120 a1 = btrfs_stack_qgroup_limit_flags(limit);
1121 a2 = btrfs_stack_qgroup_limit_max_referenced
1123 a3 = btrfs_stack_qgroup_limit_max_exclusive
1125 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1127 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1129 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1130 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
1131 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
1132 if (sh->offset < sh->objectid)
1134 bq = qgroup_tree_search(qgroup_lookup,
1138 bq1 = qgroup_tree_search(qgroup_lookup,
1142 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1143 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1150 * record the mins in sk so we can make sure the
1151 * next search doesn't repeat this root
1153 sk->min_type = sh->type;
1154 sk->min_offset = sh->offset;
1155 sk->min_objectid = sh->objectid;
1157 sk->nr_items = 4096;
1159 * this iteration is done, step forward one qgroup for the next
1162 if (sk->min_offset < (u64)-1)
1172 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1176 struct btrfs_qgroup *entry;
1180 n = rb_first(&qgroup_lookup->root);
1182 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1183 print_single_qgroup_table(entry);
1188 int btrfs_show_qgroups(int fd,
1189 struct btrfs_qgroup_filter_set *filter_set,
1190 struct btrfs_qgroup_comparer_set *comp_set)
1193 struct qgroup_lookup qgroup_lookup;
1194 struct qgroup_lookup sort_tree;
1197 ret = __qgroups_search(fd, &qgroup_lookup);
1200 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1201 filter_set, comp_set);
1202 print_all_qgroups(&sort_tree);
1204 __free_all_qgroups(&qgroup_lookup);
1205 btrfs_qgroup_free_filter_set(filter_set);
1209 u64 btrfs_get_path_rootid(int fd)
1212 struct btrfs_ioctl_ino_lookup_args args;
1214 memset(&args, 0, sizeof(args));
1215 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1217 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1220 "ERROR: can't perform the search - %s\n",
1227 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1228 struct btrfs_qgroup_comparer_set **comps)
1236 while ((p = strtok(opt_arg, ",")) != NULL) {
1238 ptr_argv = all_sort_items;
1241 if (strcmp(*ptr_argv, p) == 0) {
1246 if (strcmp(*ptr_argv, p) == 0) {
1263 } else if (*p == '-') {
1269 what_to_sort = btrfs_qgroup_get_sort_item(p);
1270 if (what_to_sort < 0)
1272 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1280 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1282 return sizeof(*p) + sizeof(p->qgroups[0]) *
1283 (p->num_qgroups + 2 * p->num_ref_copies +
1284 2 * p->num_excl_copies);
1288 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1290 struct btrfs_qgroup_inherit *out;
1294 nitems = (*inherit)->num_qgroups +
1295 (*inherit)->num_ref_copies +
1296 (*inherit)->num_excl_copies;
1299 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1301 fprintf(stderr, "ERROR: Not enough memory\n");
1306 struct btrfs_qgroup_inherit *i = *inherit;
1307 int s = sizeof(out->qgroups[0]);
1309 out->num_qgroups = i->num_qgroups;
1310 out->num_ref_copies = i->num_ref_copies;
1311 out->num_excl_copies = i->num_excl_copies;
1312 memcpy(out->qgroups, i->qgroups, pos * s);
1313 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1314 (nitems - pos) * s);
1322 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1325 u64 qgroupid = parse_qgroupid(arg);
1328 if (qgroupid == 0) {
1329 fprintf(stderr, "ERROR: bad qgroup specification\n");
1334 pos = (*inherit)->num_qgroups;
1335 ret = qgroup_inherit_realloc(inherit, 1, pos);
1339 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1344 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1353 p = strchr(arg, ':');
1356 fprintf(stderr, "ERROR: bad copy specification\n");
1360 qgroup_src = parse_qgroupid(arg);
1361 qgroup_dst = parse_qgroupid(p + 1);
1364 if (!qgroup_src || !qgroup_dst)
1368 pos = (*inherit)->num_qgroups +
1369 (*inherit)->num_ref_copies * 2 * type;
1371 ret = qgroup_inherit_realloc(inherit, 2, pos);
1375 (*inherit)->qgroups[pos++] = qgroup_src;
1376 (*inherit)->qgroups[pos++] = qgroup_dst;
1379 ++(*inherit)->num_ref_copies;
1381 ++(*inherit)->num_excl_copies;