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 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
242 case BTRFS_QGROUP_MAX_EXCL:
243 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
245 case BTRFS_QGROUP_CHILD:
246 len = print_child_column(qgroup);
247 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
254 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
258 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
259 if (!btrfs_qgroup_columns[i].need_print)
261 print_qgroup_column(qgroup, i);
263 if (i != BTRFS_QGROUP_CHILD)
269 static void print_table_head()
275 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
276 max_len = btrfs_qgroup_columns[i].max_len;
277 if (!btrfs_qgroup_columns[i].need_print)
279 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
280 (i == BTRFS_QGROUP_CHILD))
281 printf("%-*s", max_len, btrfs_qgroup_columns[i].name);
283 printf("%*s", max_len, btrfs_qgroup_columns[i].name);
287 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
288 max_len = btrfs_qgroup_columns[i].max_len;
289 if (!btrfs_qgroup_columns[i].need_print)
291 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
292 (i == BTRFS_QGROUP_CHILD)) {
293 len = strlen(btrfs_qgroup_columns[i].name);
296 len = max_len - strlen(btrfs_qgroup_columns[i].name);
300 len = max_len - strlen(btrfs_qgroup_columns[i].name);
303 len = strlen(btrfs_qgroup_columns[i].name);
312 static void qgroup_lookup_init(struct qgroup_lookup *tree)
314 tree->root.rb_node = NULL;
317 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
318 struct btrfs_qgroup *entry2,
324 if (entry1->qgroupid > entry2->qgroupid)
326 else if (entry1->qgroupid < entry2->qgroupid)
331 return is_descending ? -ret : ret;
334 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
335 struct btrfs_qgroup *entry2,
340 if (entry1->rfer > entry2->rfer)
342 else if (entry1->rfer < entry2->rfer)
347 return is_descending ? -ret : ret;
350 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
351 struct btrfs_qgroup *entry2,
356 if (entry1->excl > entry2->excl)
358 else if (entry1->excl < entry2->excl)
363 return is_descending ? -ret : ret;
366 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
367 struct btrfs_qgroup *entry2,
372 if (entry1->max_rfer > entry2->max_rfer)
374 else if (entry1->max_rfer < entry2->max_rfer)
379 return is_descending ? -ret : ret;
382 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
383 struct btrfs_qgroup *entry2,
388 if (entry1->max_excl > entry2->max_excl)
390 else if (entry1->max_excl < entry2->max_excl)
395 return is_descending ? -ret : ret;
398 static btrfs_qgroup_comp_func all_comp_funcs[] = {
399 [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid,
400 [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer,
401 [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl,
402 [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer,
403 [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl
406 static char *all_sort_items[] = {
407 [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid",
408 [BTRFS_QGROUP_COMP_RFER] = "rfer",
409 [BTRFS_QGROUP_COMP_EXCL] = "excl",
410 [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer",
411 [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl",
412 [BTRFS_QGROUP_COMP_MAX] = NULL,
415 static int btrfs_qgroup_get_sort_item(char *sort_name)
419 for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
420 if (strcmp(sort_name, all_sort_items[i]) == 0)
426 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
428 struct btrfs_qgroup_comparer_set *set;
430 size = sizeof(struct btrfs_qgroup_comparer_set) +
431 BTRFS_QGROUP_NCOMPS_INCREASE *
432 sizeof(struct btrfs_qgroup_comparer);
435 fprintf(stderr, "memory allocation failed\n");
439 memset(set, 0, size);
440 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
445 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
450 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
451 enum btrfs_qgroup_comp_enum comparer,
454 struct btrfs_qgroup_comparer_set *set = *comp_set;
458 BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
459 BUG_ON(set->ncomps > set->total);
461 if (set->ncomps == set->total) {
462 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
463 size = sizeof(*set) +
464 size * sizeof(struct btrfs_qgroup_comparer);
465 set = realloc(set, size);
467 fprintf(stderr, "memory allocation failed\n");
471 memset(&set->comps[set->total], 0,
472 BTRFS_QGROUP_NCOMPS_INCREASE *
473 sizeof(struct btrfs_qgroup_comparer));
474 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
478 BUG_ON(set->comps[set->ncomps].comp_func);
480 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
481 set->comps[set->ncomps].is_descending = is_descending;
486 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
487 struct btrfs_qgroup_comparer_set *set)
489 int qgroupid_compared = 0;
492 if (!set || !set->ncomps)
495 for (i = 0; i < set->ncomps; i++) {
496 if (!set->comps[i].comp_func)
499 ret = set->comps[i].comp_func(entry1, entry2,
500 set->comps[i].is_descending);
504 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
505 qgroupid_compared = 1;
508 if (!qgroupid_compared) {
510 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
517 * insert a new root into the tree. returns the existing root entry
518 * if one is already there. qgroupid is used
521 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
522 struct btrfs_qgroup *ins)
525 struct rb_node **p = &root_tree->root.rb_node;
526 struct rb_node *parent = NULL;
527 struct btrfs_qgroup *curr;
532 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
534 ret = comp_entry_with_qgroupid(ins, curr, 0);
542 rb_link_node(&ins->rb_node, parent, p);
543 rb_insert_color(&ins->rb_node, &root_tree->root);
548 *find a given qgroupid in the tree. We return the smallest one,
549 *rb_next can be used to move forward looking for more if required
551 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
554 struct rb_node *n = root_tree->root.rb_node;
555 struct btrfs_qgroup *entry;
556 struct btrfs_qgroup tmp;
559 tmp.qgroupid = qgroupid;
562 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
564 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
576 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
577 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
578 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
579 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
580 struct btrfs_qgroup *child)
582 struct btrfs_qgroup *bq;
583 struct btrfs_qgroup_list *list;
585 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
586 if (!bq || bq->qgroupid != qgroupid)
590 bq->generation = generation;
594 bq->rfer_cmpr = rfer_cmpr;
598 bq->excl_cmpr = excl_cmpr;
602 bq->max_rfer = max_rfer;
604 bq->max_excl = max_excl;
606 bq->rsv_rfer = rsv_rfer;
608 list = malloc(sizeof(*list));
610 fprintf(stderr, "memory allocation failed\n");
614 list->member = child;
615 list_add_tail(&list->next_qgroup, &child->qgroups);
616 list_add_tail(&list->next_member, &pa->members);
621 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
622 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
623 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
624 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
625 struct btrfs_qgroup *child)
627 struct btrfs_qgroup *bq;
628 struct btrfs_qgroup_list *list;
631 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
632 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
633 max_excl, rsv_rfer, rsv_excl, parent, child);
637 bq = malloc(sizeof(*bq));
639 printf("memory allocation failed\n");
642 memset(bq, 0, sizeof(*bq));
644 bq->qgroupid = qgroupid;
645 INIT_LIST_HEAD(&bq->qgroups);
646 INIT_LIST_HEAD(&bq->members);
649 bq->generation = generation;
653 bq->rfer_cmpr = rfer_cmpr;
657 bq->excl_cmpr = excl_cmpr;
661 bq->max_rfer = max_rfer;
663 bq->max_excl = max_excl;
665 bq->rsv_rfer = rsv_rfer;
666 if (parent && child) {
667 list = malloc(sizeof(*list));
669 fprintf(stderr, "memory allocation failed\n");
672 list->qgroup = parent;
673 list->member = child;
674 list_add_tail(&list->next_qgroup, &child->qgroups);
675 list_add_tail(&list->next_member, &parent->members);
677 ret = qgroup_tree_insert(qgroup_lookup, bq);
679 printf("failed to insert tree %llu\n",
686 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
688 struct btrfs_qgroup_list *list;
689 while (!list_empty(&bq->qgroups)) {
690 list = list_entry((&bq->qgroups)->next,
691 struct btrfs_qgroup_list,
693 list_del(&list->next_qgroup);
694 list_del(&list->next_member);
697 while (!list_empty(&bq->members)) {
698 list = list_entry((&bq->members)->next,
699 struct btrfs_qgroup_list,
701 list_del(&list->next_qgroup);
702 list_del(&list->next_member);
708 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
710 struct btrfs_qgroup *entry;
713 n = rb_first(&root_tree->root);
715 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
716 rb_erase(n, &root_tree->root);
717 __free_btrfs_qgroup(entry);
719 n = rb_first(&root_tree->root);
723 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
724 struct btrfs_qgroup *bq)
726 struct rb_node **p = &sort_tree->root.rb_node;
727 struct rb_node *parent = NULL;
728 struct btrfs_qgroup *curr;
733 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
735 ret = comp_entry_with_qgroupid(bq, curr, 0);
743 rb_link_node(&bq->all_parent_node, parent, p);
744 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
748 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
750 struct btrfs_qgroup *qgroup =
751 (struct btrfs_qgroup *)(unsigned long)data;
755 if (qgroup->qgroupid == bq->qgroupid)
760 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
762 struct qgroup_lookup lookup;
763 struct qgroup_lookup *ql = &lookup;
764 struct btrfs_qgroup_list *list;
766 struct btrfs_qgroup *qgroup =
767 (struct btrfs_qgroup *)(unsigned long)data;
771 if (bq->qgroupid == qgroup->qgroupid)
774 qgroup_lookup_init(ql);
775 filter_all_parent_insert(ql, qgroup);
776 n = rb_first(&ql->root);
778 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
779 if (!list_empty(&qgroup->qgroups)) {
780 list_for_each_entry(list, &qgroup->qgroups,
782 if ((list->qgroup)->qgroupid == bq->qgroupid)
784 filter_all_parent_insert(ql, list->qgroup);
787 rb_erase(n, &ql->root);
788 n = rb_first(&ql->root);
793 static btrfs_qgroup_filter_func all_filter_funcs[] = {
794 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
795 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
798 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
800 struct btrfs_qgroup_filter_set *set;
803 size = sizeof(struct btrfs_qgroup_filter_set) +
804 BTRFS_QGROUP_NFILTERS_INCREASE *
805 sizeof(struct btrfs_qgroup_filter);
808 fprintf(stderr, "memory allocation failed\n");
811 memset(set, 0, size);
812 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
817 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
822 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
823 enum btrfs_qgroup_filter_enum filter, u64 data)
825 struct btrfs_qgroup_filter_set *set = *filter_set;
829 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
830 BUG_ON(set->nfilters > set->total);
832 if (set->nfilters == set->total) {
833 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
834 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
836 set = realloc(set, size);
838 fprintf(stderr, "memory allocation failed\n");
841 memset(&set->filters[set->total], 0,
842 BTRFS_QGROUP_NFILTERS_INCREASE *
843 sizeof(struct btrfs_qgroup_filter));
844 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
847 BUG_ON(set->filters[set->nfilters].filter_func);
848 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
849 set->filters[set->nfilters].data = data;
854 static int filter_qgroup(struct btrfs_qgroup *bq,
855 struct btrfs_qgroup_filter_set *set)
859 if (!set || !set->nfilters)
861 for (i = 0; i < set->nfilters; i++) {
862 if (!set->filters[i].filter_func)
864 ret = set->filters[i].filter_func(bq, set->filters[i].data);
871 static void pre_process_filter_set(struct qgroup_lookup *lookup,
872 struct btrfs_qgroup_filter_set *set)
875 struct btrfs_qgroup *qgroup_for_filter = NULL;
877 for (i = 0; i < set->nfilters; i++) {
879 if (set->filters[i].filter_func == filter_by_all_parent
880 || set->filters[i].filter_func == filter_by_parent) {
881 qgroup_for_filter = qgroup_tree_search(lookup,
882 set->filters[i].data);
883 set->filters[i].data =
884 (u64)(unsigned long)qgroup_for_filter;
889 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
890 struct btrfs_qgroup *bq,
891 struct btrfs_qgroup_comparer_set *comp_set)
893 struct rb_node **p = &sort_tree->root.rb_node;
894 struct rb_node *parent = NULL;
895 struct btrfs_qgroup *curr;
900 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
902 ret = sort_comp(bq, curr, comp_set);
910 rb_link_node(&bq->sort_node, parent, p);
911 rb_insert_color(&bq->sort_node, &sort_tree->root);
915 static void __update_columns_max_len(struct btrfs_qgroup *bq,
916 enum btrfs_qgroup_column_enum column)
918 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
919 struct btrfs_qgroup_list *list = NULL;
922 unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
926 case BTRFS_QGROUP_QGROUPID:
927 sprintf(tmp, "%llu/%llu",
928 btrfs_qgroup_level(bq->qgroupid),
929 btrfs_qgroup_subvid(bq->qgroupid));
931 if (btrfs_qgroup_columns[column].max_len < len)
932 btrfs_qgroup_columns[column].max_len = len;
934 case BTRFS_QGROUP_RFER:
935 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
936 if (btrfs_qgroup_columns[column].max_len < len)
937 btrfs_qgroup_columns[column].max_len = len;
939 case BTRFS_QGROUP_EXCL:
940 len = strlen(pretty_size_mode(bq->excl, unit_mode));
941 if (btrfs_qgroup_columns[column].max_len < len)
942 btrfs_qgroup_columns[column].max_len = len;
944 case BTRFS_QGROUP_MAX_RFER:
945 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
946 if (btrfs_qgroup_columns[column].max_len < len)
947 btrfs_qgroup_columns[column].max_len = len;
949 case BTRFS_QGROUP_MAX_EXCL:
950 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
951 if (btrfs_qgroup_columns[column].max_len < len)
952 btrfs_qgroup_columns[column].max_len = len;
954 case BTRFS_QGROUP_PARENT:
956 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
957 len += sprintf(tmp, "%llu/%llu",
958 btrfs_qgroup_level(list->qgroup->qgroupid),
959 btrfs_qgroup_subvid(list->qgroup->qgroupid));
960 if (!list_is_last(&list->next_qgroup, &bq->qgroups))
963 if (btrfs_qgroup_columns[column].max_len < len)
964 btrfs_qgroup_columns[column].max_len = len;
966 case BTRFS_QGROUP_CHILD:
968 list_for_each_entry(list, &bq->members, next_member) {
969 len += sprintf(tmp, "%llu/%llu",
970 btrfs_qgroup_level(list->member->qgroupid),
971 btrfs_qgroup_subvid(list->member->qgroupid));
972 if (!list_is_last(&list->next_member, &bq->members))
975 if (btrfs_qgroup_columns[column].max_len < len)
976 btrfs_qgroup_columns[column].max_len = len;
984 static void update_columns_max_len(struct btrfs_qgroup *bq)
988 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
989 if (!btrfs_qgroup_columns[i].need_print)
991 __update_columns_max_len(bq, i);
995 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
996 struct qgroup_lookup *sort_tree,
997 struct btrfs_qgroup_filter_set *filter_set,
998 struct btrfs_qgroup_comparer_set *comp_set)
1001 struct btrfs_qgroup *entry;
1004 qgroup_lookup_init(sort_tree);
1005 pre_process_filter_set(all_qgroups, filter_set);
1007 n = rb_last(&all_qgroups->root);
1009 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
1011 ret = filter_qgroup(entry, filter_set);
1013 sort_tree_insert(sort_tree, entry, comp_set);
1015 update_columns_max_len(entry);
1021 static inline void print_status_flag_warning(u64 flags)
1023 if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
1025 "WARNING: Quota disabled, qgroup data may be out of date\n");
1026 else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
1028 "WARNING: Rescan is running, qgroup data may be incorrect\n");
1029 else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
1031 "WARNING: Qgroup data inconsistent, rescan recommended\n");
1034 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1037 struct btrfs_ioctl_search_args args;
1038 struct btrfs_ioctl_search_key *sk = &args.key;
1039 struct btrfs_ioctl_search_header *sh;
1040 unsigned long off = 0;
1043 struct btrfs_qgroup_info_item *info;
1044 struct btrfs_qgroup_limit_item *limit;
1045 struct btrfs_qgroup *bq;
1046 struct btrfs_qgroup *bq1;
1053 memset(&args, 0, sizeof(args));
1055 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1056 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1057 sk->min_type = BTRFS_QGROUP_STATUS_KEY;
1058 sk->max_objectid = (u64)-1;
1059 sk->max_offset = (u64)-1;
1060 sk->max_transid = (u64)-1;
1061 sk->nr_items = 4096;
1063 qgroup_lookup_init(qgroup_lookup);
1066 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1070 "ERROR: can't perform the search - %s\n",
1074 /* the ioctl returns the number of item it found in nr_items */
1075 if (sk->nr_items == 0)
1080 * for each item, pull the key out of the header and then
1081 * read the root_ref item it contains
1083 for (i = 0; i < sk->nr_items; i++) {
1084 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1088 if (sh->type == BTRFS_QGROUP_STATUS_KEY) {
1089 struct btrfs_qgroup_status_item *si;
1092 si = (struct btrfs_qgroup_status_item *)
1094 flags = btrfs_stack_qgroup_status_flags(si);
1095 print_status_flag_warning(flags);
1096 } else if (sh->type == BTRFS_QGROUP_INFO_KEY) {
1097 info = (struct btrfs_qgroup_info_item *)
1099 a1 = btrfs_stack_qgroup_info_generation(info);
1100 a2 = btrfs_stack_qgroup_info_referenced(info);
1102 btrfs_stack_qgroup_info_referenced_compressed
1104 a4 = btrfs_stack_qgroup_info_exclusive(info);
1106 btrfs_stack_qgroup_info_exclusive_compressed
1108 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
1109 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
1110 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
1111 limit = (struct btrfs_qgroup_limit_item *)
1114 a1 = btrfs_stack_qgroup_limit_flags(limit);
1115 a2 = btrfs_stack_qgroup_limit_max_referenced
1117 a3 = btrfs_stack_qgroup_limit_max_exclusive
1119 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1121 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1123 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1124 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
1125 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
1126 if (sh->offset < sh->objectid)
1128 bq = qgroup_tree_search(qgroup_lookup,
1132 bq1 = qgroup_tree_search(qgroup_lookup,
1136 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1137 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1144 * record the mins in sk so we can make sure the
1145 * next search doesn't repeat this root
1147 sk->min_type = sh->type;
1148 sk->min_offset = sh->offset;
1149 sk->min_objectid = sh->objectid;
1151 sk->nr_items = 4096;
1153 * this iteration is done, step forward one qgroup for the next
1156 if (sk->min_offset < (u64)-1)
1166 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1170 struct btrfs_qgroup *entry;
1174 n = rb_first(&qgroup_lookup->root);
1176 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1177 print_single_qgroup_table(entry);
1182 int btrfs_show_qgroups(int fd,
1183 struct btrfs_qgroup_filter_set *filter_set,
1184 struct btrfs_qgroup_comparer_set *comp_set)
1187 struct qgroup_lookup qgroup_lookup;
1188 struct qgroup_lookup sort_tree;
1191 ret = __qgroups_search(fd, &qgroup_lookup);
1194 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1195 filter_set, comp_set);
1196 print_all_qgroups(&sort_tree);
1198 __free_all_qgroups(&qgroup_lookup);
1199 btrfs_qgroup_free_filter_set(filter_set);
1203 u64 btrfs_get_path_rootid(int fd)
1206 struct btrfs_ioctl_ino_lookup_args args;
1208 memset(&args, 0, sizeof(args));
1209 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1211 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1214 "ERROR: can't perform the search - %s\n",
1221 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1222 struct btrfs_qgroup_comparer_set **comps)
1230 while ((p = strtok(opt_arg, ",")) != NULL) {
1232 ptr_argv = all_sort_items;
1235 if (strcmp(*ptr_argv, p) == 0) {
1240 if (strcmp(*ptr_argv, p) == 0) {
1257 } else if (*p == '-') {
1263 what_to_sort = btrfs_qgroup_get_sort_item(p);
1264 if (what_to_sort < 0)
1266 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1274 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1276 return sizeof(*p) + sizeof(p->qgroups[0]) *
1277 (p->num_qgroups + 2 * p->num_ref_copies +
1278 2 * p->num_excl_copies);
1282 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1284 struct btrfs_qgroup_inherit *out;
1288 nitems = (*inherit)->num_qgroups +
1289 (*inherit)->num_ref_copies +
1290 (*inherit)->num_excl_copies;
1293 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1295 fprintf(stderr, "ERROR: Not enough memory\n");
1300 struct btrfs_qgroup_inherit *i = *inherit;
1301 int s = sizeof(out->qgroups[0]);
1303 out->num_qgroups = i->num_qgroups;
1304 out->num_ref_copies = i->num_ref_copies;
1305 out->num_excl_copies = i->num_excl_copies;
1306 memcpy(out->qgroups, i->qgroups, pos * s);
1307 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1308 (nitems - pos) * s);
1316 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1319 u64 qgroupid = parse_qgroupid(arg);
1322 if (qgroupid == 0) {
1323 fprintf(stderr, "ERROR: bad qgroup specification\n");
1328 pos = (*inherit)->num_qgroups;
1329 ret = qgroup_inherit_realloc(inherit, 1, pos);
1333 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1338 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1347 p = strchr(arg, ':');
1350 fprintf(stderr, "ERROR: bad copy specification\n");
1354 qgroup_src = parse_qgroupid(arg);
1355 qgroup_dst = parse_qgroupid(p + 1);
1358 if (!qgroup_src || !qgroup_dst)
1362 pos = (*inherit)->num_qgroups +
1363 (*inherit)->num_ref_copies * 2 * type;
1365 ret = qgroup_inherit_realloc(inherit, 2, pos);
1369 (*inherit)->qgroups[pos++] = qgroup_src;
1370 (*inherit)->qgroups[pos++] = qgroup_dst;
1373 ++(*inherit)->num_ref_copies;
1375 ++(*inherit)->num_excl_copies;