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>
24 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
25 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
27 struct qgroup_lookup {
32 struct rb_node rb_node;
33 struct rb_node sort_node;
35 *all_parent_node is used to
36 *filter a qgroup's all parent
38 struct rb_node all_parent_node;
45 u64 rfer; /*referenced*/
46 u64 rfer_cmpr; /*referenced compressed*/
47 u64 excl; /*exclusive*/
48 u64 excl_cmpr; /*exclusive compressed*/
53 u64 flags; /*which limits are set*/
59 /*qgroups this group is member of*/
60 struct list_head qgroups;
61 /*qgroups that are members of this group*/
62 struct list_head members;
66 * glue structure to represent the relations
69 struct btrfs_qgroup_list {
70 struct list_head next_qgroup;
71 struct list_head next_member;
72 struct btrfs_qgroup *qgroup;
73 struct btrfs_qgroup *member;
77 * qgroupid,rfer,excl default to set
84 } btrfs_qgroup_columns[] = {
87 .column_name = "Qgroupid",
93 .column_name = "Rfer",
99 .column_name = "Excl",
103 { .name = "max_rfer",
104 .column_name = "Max_rfer",
110 .column_name = "Max_excl",
116 .column_name = "Parent",
122 .column_name = "Child",
133 static btrfs_qgroup_filter_func all_filter_funcs[];
134 static btrfs_qgroup_comp_func all_comp_funcs[];
136 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
140 BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
142 if (column < BTRFS_QGROUP_ALL) {
143 btrfs_qgroup_columns[column].need_print = 1;
146 for (i = 0; i < BTRFS_QGROUP_ALL; i++)
147 btrfs_qgroup_columns[i].need_print = 1;
150 static int print_parent_column(struct btrfs_qgroup *qgroup)
152 struct btrfs_qgroup_list *list = NULL;
155 list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
156 len += printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
157 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
158 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
161 if (list_empty(&qgroup->qgroups))
162 len += printf("---");
167 static int print_child_column(struct btrfs_qgroup *qgroup)
169 struct btrfs_qgroup_list *list = NULL;
172 list_for_each_entry(list, &qgroup->members, next_member) {
173 len += printf("%llu/%llu", (list->member)->qgroupid >> 48,
174 ((1ll << 48) - 1) & (list->member)->qgroupid);
175 if (!list_is_last(&list->next_member, &qgroup->members))
178 if (list_empty(&qgroup->members))
179 len += printf("---");
184 static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
187 len = btrfs_qgroup_columns[column].max_len - len;
192 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
193 enum btrfs_qgroup_column_enum column)
195 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
200 case BTRFS_QGROUP_QGROUPID:
201 len = printf("%llu/%llu", qgroup->qgroupid >> 48,
202 ((1ll << 48) - 1) & qgroup->qgroupid);
203 print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
205 case BTRFS_QGROUP_RFER:
206 len = printf("%lld", qgroup->rfer);
207 print_qgroup_column_add_blank(BTRFS_QGROUP_RFER, len);
209 case BTRFS_QGROUP_EXCL:
210 len = printf("%lld", qgroup->excl);
211 print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL, len);
213 case BTRFS_QGROUP_PARENT:
214 len = print_parent_column(qgroup);
215 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
217 case BTRFS_QGROUP_MAX_RFER:
218 len = printf("%llu", qgroup->max_rfer);
219 print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER, len);
221 case BTRFS_QGROUP_MAX_EXCL:
222 len = printf("%llu", qgroup->max_excl);
223 print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL, len);
225 case BTRFS_QGROUP_CHILD:
226 len = print_child_column(qgroup);
227 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
234 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
238 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
239 if (!btrfs_qgroup_columns[i].need_print)
241 print_qgroup_column(qgroup, i);
243 if (i != BTRFS_QGROUP_CHILD)
249 static void print_table_head()
254 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
255 if (!btrfs_qgroup_columns[i].need_print)
257 printf("%s", btrfs_qgroup_columns[i].name);
258 len = btrfs_qgroup_columns[i].max_len -
259 strlen(btrfs_qgroup_columns[i].name);
265 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
266 if (!btrfs_qgroup_columns[i].need_print)
269 len = strlen(btrfs_qgroup_columns[i].name);
272 len = btrfs_qgroup_columns[i].max_len -
273 strlen(btrfs_qgroup_columns[i].name);
281 static void qgroup_lookup_init(struct qgroup_lookup *tree)
283 tree->root.rb_node = NULL;
286 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
287 struct btrfs_qgroup *entry2,
293 if (entry1->qgroupid > entry2->qgroupid)
295 else if (entry1->qgroupid < entry2->qgroupid)
300 return is_descending ? -ret : ret;
303 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
304 struct btrfs_qgroup *entry2,
309 if (entry1->rfer > entry2->rfer)
311 else if (entry1->rfer < entry2->rfer)
316 return is_descending ? -ret : ret;
319 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
320 struct btrfs_qgroup *entry2,
325 if (entry1->excl > entry2->excl)
327 else if (entry1->excl < entry2->excl)
332 return is_descending ? -ret : ret;
335 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
336 struct btrfs_qgroup *entry2,
341 if (entry1->max_rfer > entry2->max_rfer)
343 else if (entry1->max_rfer < entry2->max_rfer)
348 return is_descending ? -ret : ret;
351 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
352 struct btrfs_qgroup *entry2,
357 if (entry1->max_excl > entry2->max_excl)
359 else if (entry1->max_excl < entry2->max_excl)
364 return is_descending ? -ret : ret;
367 static btrfs_qgroup_comp_func all_comp_funcs[] = {
368 [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid,
369 [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer,
370 [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl,
371 [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer,
372 [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl
375 static char *all_sort_items[] = {
376 [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid",
377 [BTRFS_QGROUP_COMP_RFER] = "rfer",
378 [BTRFS_QGROUP_COMP_EXCL] = "excl",
379 [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer",
380 [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl",
381 [BTRFS_QGROUP_COMP_MAX] = NULL,
384 static int btrfs_qgroup_get_sort_item(char *sort_name)
388 for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
389 if (strcmp(sort_name, all_sort_items[i]) == 0)
395 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
397 struct btrfs_qgroup_comparer_set *set;
399 size = sizeof(struct btrfs_qgroup_comparer_set) +
400 BTRFS_QGROUP_NCOMPS_INCREASE *
401 sizeof(struct btrfs_qgroup_comparer);
404 fprintf(stderr, "memory allocation failed\n");
408 memset(set, 0, size);
409 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
414 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
419 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
420 enum btrfs_qgroup_comp_enum comparer,
423 struct btrfs_qgroup_comparer_set *set = *comp_set;
427 BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
428 BUG_ON(set->ncomps > set->total);
430 if (set->ncomps == set->total) {
431 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
432 size = sizeof(*set) +
433 size * sizeof(struct btrfs_qgroup_comparer);
434 set = realloc(set, size);
436 fprintf(stderr, "memory allocation failed\n");
440 memset(&set->comps[set->total], 0,
441 BTRFS_QGROUP_NCOMPS_INCREASE *
442 sizeof(struct btrfs_qgroup_comparer));
443 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
447 BUG_ON(set->comps[set->ncomps].comp_func);
449 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
450 set->comps[set->ncomps].is_descending = is_descending;
455 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
456 struct btrfs_qgroup_comparer_set *set)
458 int qgroupid_compared = 0;
461 if (!set || !set->ncomps)
464 for (i = 0; i < set->ncomps; i++) {
465 if (!set->comps[i].comp_func)
468 ret = set->comps[i].comp_func(entry1, entry2,
469 set->comps[i].is_descending);
473 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
474 qgroupid_compared = 1;
477 if (!qgroupid_compared) {
479 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
486 * insert a new root into the tree. returns the existing root entry
487 * if one is already there. qgroupid is used
490 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
491 struct btrfs_qgroup *ins)
494 struct rb_node **p = &root_tree->root.rb_node;
495 struct rb_node *parent = NULL;
496 struct btrfs_qgroup *curr;
501 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
503 ret = comp_entry_with_qgroupid(ins, curr, 0);
511 rb_link_node(&ins->rb_node, parent, p);
512 rb_insert_color(&ins->rb_node, &root_tree->root);
517 *find a given qgroupid in the tree. We return the smallest one,
518 *rb_next can be used to move forward looking for more if required
520 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
523 struct rb_node *n = root_tree->root.rb_node;
524 struct btrfs_qgroup *entry;
525 struct btrfs_qgroup tmp;
528 tmp.qgroupid = qgroupid;
531 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
533 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
545 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
546 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
547 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
548 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
549 struct btrfs_qgroup *child)
551 struct btrfs_qgroup *bq;
552 struct btrfs_qgroup_list *list;
554 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
555 if (!bq || bq->qgroupid != qgroupid)
559 bq->generation = generation;
563 bq->rfer_cmpr = rfer_cmpr;
567 bq->excl_cmpr = excl_cmpr;
571 bq->max_rfer = max_rfer;
573 bq->max_excl = max_excl;
575 bq->rsv_rfer = rsv_rfer;
577 list = malloc(sizeof(*list));
579 fprintf(stderr, "memory allocation failed\n");
583 list->member = child;
584 list_add_tail(&list->next_qgroup, &child->qgroups);
585 list_add_tail(&list->next_member, &pa->members);
590 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
591 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
592 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
593 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
594 struct btrfs_qgroup *child)
596 struct btrfs_qgroup *bq;
597 struct btrfs_qgroup_list *list;
600 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
601 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
602 max_excl, rsv_rfer, rsv_excl, parent, child);
606 bq = malloc(sizeof(*bq));
608 printf("memory allocation failed\n");
611 memset(bq, 0, sizeof(*bq));
613 bq->qgroupid = qgroupid;
614 INIT_LIST_HEAD(&bq->qgroups);
615 INIT_LIST_HEAD(&bq->members);
618 bq->generation = generation;
622 bq->rfer_cmpr = rfer_cmpr;
626 bq->excl_cmpr = excl_cmpr;
630 bq->max_rfer = max_rfer;
632 bq->max_excl = max_excl;
634 bq->rsv_rfer = rsv_rfer;
635 if (parent && child) {
636 list = malloc(sizeof(*list));
638 fprintf(stderr, "memory allocation failed\n");
641 list->qgroup = parent;
642 list->member = child;
643 list_add_tail(&list->next_qgroup, &child->qgroups);
644 list_add_tail(&list->next_member, &parent->members);
646 ret = qgroup_tree_insert(qgroup_lookup, bq);
648 printf("failed to insert tree %llu\n",
655 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
657 struct btrfs_qgroup_list *list;
658 while (!list_empty(&bq->qgroups)) {
659 list = list_entry((&bq->qgroups)->next,
660 struct btrfs_qgroup_list,
662 list_del(&list->next_qgroup);
663 list_del(&list->next_member);
666 while (!list_empty(&bq->members)) {
667 list = list_entry((&bq->members)->next,
668 struct btrfs_qgroup_list,
670 list_del(&list->next_qgroup);
671 list_del(&list->next_member);
677 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
679 struct btrfs_qgroup *entry;
682 n = rb_first(&root_tree->root);
684 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
685 rb_erase(n, &root_tree->root);
686 __free_btrfs_qgroup(entry);
688 n = rb_first(&root_tree->root);
692 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
693 struct btrfs_qgroup *bq)
695 struct rb_node **p = &sort_tree->root.rb_node;
696 struct rb_node *parent = NULL;
697 struct btrfs_qgroup *curr;
702 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
704 ret = comp_entry_with_qgroupid(bq, curr, 0);
712 rb_link_node(&bq->all_parent_node, parent, p);
713 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
717 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
719 struct btrfs_qgroup *qgroup =
720 (struct btrfs_qgroup *)(unsigned long)data;
724 if (qgroup->qgroupid == bq->qgroupid)
729 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
731 struct qgroup_lookup lookup;
732 struct qgroup_lookup *ql = &lookup;
733 struct btrfs_qgroup_list *list;
735 struct btrfs_qgroup *qgroup =
736 (struct btrfs_qgroup *)(unsigned long)data;
740 if (bq->qgroupid == qgroup->qgroupid)
743 qgroup_lookup_init(ql);
744 filter_all_parent_insert(ql, qgroup);
745 n = rb_first(&ql->root);
747 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
748 if (!list_empty(&qgroup->qgroups)) {
749 list_for_each_entry(list, &qgroup->qgroups,
751 if ((list->qgroup)->qgroupid == bq->qgroupid)
753 filter_all_parent_insert(ql, list->qgroup);
756 rb_erase(n, &ql->root);
757 n = rb_first(&ql->root);
762 static btrfs_qgroup_filter_func all_filter_funcs[] = {
763 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
764 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
767 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
769 struct btrfs_qgroup_filter_set *set;
772 size = sizeof(struct btrfs_qgroup_filter_set) +
773 BTRFS_QGROUP_NFILTERS_INCREASE *
774 sizeof(struct btrfs_qgroup_filter);
777 fprintf(stderr, "memory allocation failed\n");
780 memset(set, 0, size);
781 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
786 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
791 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
792 enum btrfs_qgroup_filter_enum filter, u64 data)
794 struct btrfs_qgroup_filter_set *set = *filter_set;
798 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
799 BUG_ON(set->nfilters > set->total);
801 if (set->nfilters == set->total) {
802 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
803 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
805 set = realloc(set, size);
807 fprintf(stderr, "memory allocation failed\n");
810 memset(&set->filters[set->total], 0,
811 BTRFS_QGROUP_NFILTERS_INCREASE *
812 sizeof(struct btrfs_qgroup_filter));
813 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
816 BUG_ON(set->filters[set->nfilters].filter_func);
817 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
818 set->filters[set->nfilters].data = data;
823 static int filter_qgroup(struct btrfs_qgroup *bq,
824 struct btrfs_qgroup_filter_set *set)
828 if (!set || !set->nfilters)
830 for (i = 0; i < set->nfilters; i++) {
831 if (!set->filters[i].filter_func)
833 ret = set->filters[i].filter_func(bq, set->filters[i].data);
840 static void pre_process_filter_set(struct qgroup_lookup *lookup,
841 struct btrfs_qgroup_filter_set *set)
844 struct btrfs_qgroup *qgroup_for_filter = NULL;
846 for (i = 0; i < set->nfilters; i++) {
848 if (set->filters[i].filter_func == filter_by_all_parent
849 || set->filters[i].filter_func == filter_by_parent) {
850 qgroup_for_filter = qgroup_tree_search(lookup,
851 set->filters[i].data);
852 set->filters[i].data =
853 (u64)(unsigned long)qgroup_for_filter;
858 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
859 struct btrfs_qgroup *bq,
860 struct btrfs_qgroup_comparer_set *comp_set)
862 struct rb_node **p = &sort_tree->root.rb_node;
863 struct rb_node *parent = NULL;
864 struct btrfs_qgroup *curr;
869 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
871 ret = sort_comp(bq, curr, comp_set);
879 rb_link_node(&bq->sort_node, parent, p);
880 rb_insert_color(&bq->sort_node, &sort_tree->root);
884 static void __update_columns_max_len(struct btrfs_qgroup *bq,
885 enum btrfs_qgroup_column_enum column)
887 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
888 struct btrfs_qgroup_list *list = NULL;
894 case BTRFS_QGROUP_QGROUPID:
895 sprintf(tmp, "%llu/%llu", (bq->qgroupid >> 48),
896 bq->qgroupid & ((1ll << 48) - 1));
898 if (btrfs_qgroup_columns[column].max_len < len)
899 btrfs_qgroup_columns[column].max_len = len;
901 case BTRFS_QGROUP_RFER:
902 sprintf(tmp, "%llu", bq->rfer);
904 if (btrfs_qgroup_columns[column].max_len < len)
905 btrfs_qgroup_columns[column].max_len = len;
907 case BTRFS_QGROUP_EXCL:
908 sprintf(tmp, "%llu", bq->excl);
910 if (btrfs_qgroup_columns[column].max_len < len)
911 btrfs_qgroup_columns[column].max_len = len;
913 case BTRFS_QGROUP_MAX_RFER:
914 sprintf(tmp, "%llu", bq->max_rfer);
916 if (btrfs_qgroup_columns[column].max_len < len)
917 btrfs_qgroup_columns[column].max_len = len;
919 case BTRFS_QGROUP_MAX_EXCL:
920 sprintf(tmp, "%llu", bq->max_excl);
922 if (btrfs_qgroup_columns[column].max_len < len)
923 btrfs_qgroup_columns[column].max_len = len;
925 case BTRFS_QGROUP_PARENT:
927 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
928 len += sprintf(tmp, "%llu/%llu",
929 (list->qgroup)->qgroupid >> 48,
930 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
931 if (!list_is_last(&list->next_qgroup, &bq->qgroups))
934 if (btrfs_qgroup_columns[column].max_len < len)
935 btrfs_qgroup_columns[column].max_len = len;
937 case BTRFS_QGROUP_CHILD:
939 list_for_each_entry(list, &bq->members, next_member) {
940 len += sprintf(tmp, "%llu/%llu",
941 (list->member)->qgroupid >> 48,
942 ((1ll << 48) - 1) & (list->member)->qgroupid);
943 if (!list_is_last(&list->next_member, &bq->members))
946 if (btrfs_qgroup_columns[column].max_len < len)
947 btrfs_qgroup_columns[column].max_len = len;
955 static void update_columns_max_len(struct btrfs_qgroup *bq)
959 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
960 if (!btrfs_qgroup_columns[i].need_print)
962 __update_columns_max_len(bq, i);
966 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
967 struct qgroup_lookup *sort_tree,
968 struct btrfs_qgroup_filter_set *filter_set,
969 struct btrfs_qgroup_comparer_set *comp_set)
972 struct btrfs_qgroup *entry;
975 qgroup_lookup_init(sort_tree);
976 pre_process_filter_set(all_qgroups, filter_set);
978 n = rb_last(&all_qgroups->root);
980 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
982 ret = filter_qgroup(entry, filter_set);
984 sort_tree_insert(sort_tree, entry, comp_set);
986 update_columns_max_len(entry);
991 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
994 struct btrfs_ioctl_search_args args;
995 struct btrfs_ioctl_search_key *sk = &args.key;
996 struct btrfs_ioctl_search_header *sh;
997 unsigned long off = 0;
1000 struct btrfs_qgroup_info_item *info;
1001 struct btrfs_qgroup_limit_item *limit;
1002 struct btrfs_qgroup *bq;
1003 struct btrfs_qgroup *bq1;
1010 memset(&args, 0, sizeof(args));
1012 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1013 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1014 sk->min_type = BTRFS_QGROUP_INFO_KEY;
1015 sk->max_objectid = (u64)-1;
1016 sk->max_offset = (u64)-1;
1017 sk->max_transid = (u64)-1;
1018 sk->nr_items = 4096;
1020 qgroup_lookup_init(qgroup_lookup);
1023 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1027 "ERROR: can't perform the search - %s\n",
1031 /* the ioctl returns the number of item it found in nr_items */
1032 if (sk->nr_items == 0)
1037 * for each item, pull the key out of the header and then
1038 * read the root_ref item it contains
1040 for (i = 0; i < sk->nr_items; i++) {
1041 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1045 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
1046 info = (struct btrfs_qgroup_info_item *)
1048 a1 = btrfs_stack_qgroup_info_generation(info);
1049 a2 = btrfs_stack_qgroup_info_referenced(info);
1051 btrfs_stack_qgroup_info_referenced_compressed
1053 a4 = btrfs_stack_qgroup_info_exclusive(info);
1055 btrfs_stack_qgroup_info_exclusive_compressed
1057 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
1058 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
1059 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
1060 limit = (struct btrfs_qgroup_limit_item *)
1063 a1 = btrfs_stack_qgroup_limit_flags(limit);
1064 a2 = btrfs_stack_qgroup_limit_max_referenced
1066 a3 = btrfs_stack_qgroup_limit_max_exclusive
1068 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1070 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1072 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1073 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
1074 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
1075 if (sh->offset < sh->objectid)
1077 bq = qgroup_tree_search(qgroup_lookup,
1081 bq1 = qgroup_tree_search(qgroup_lookup,
1085 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
1086 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1093 * record the mins in sk so we can make sure the
1094 * next search doesn't repeat this root
1096 sk->min_type = sh->type;
1097 sk->min_offset = sh->offset;
1098 sk->min_objectid = sh->objectid;
1100 sk->nr_items = 4096;
1102 * this iteration is done, step forward one qgroup for the next
1105 if (sk->min_offset < (u64)-1)
1115 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1119 struct btrfs_qgroup *entry;
1123 n = rb_first(&qgroup_lookup->root);
1125 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1126 print_single_qgroup_table(entry);
1131 int btrfs_show_qgroups(int fd,
1132 struct btrfs_qgroup_filter_set *filter_set,
1133 struct btrfs_qgroup_comparer_set *comp_set)
1136 struct qgroup_lookup qgroup_lookup;
1137 struct qgroup_lookup sort_tree;
1140 ret = __qgroups_search(fd, &qgroup_lookup);
1143 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1144 filter_set, comp_set);
1145 print_all_qgroups(&sort_tree);
1147 __free_all_qgroups(&qgroup_lookup);
1148 btrfs_qgroup_free_filter_set(filter_set);
1152 u64 btrfs_get_path_rootid(int fd)
1155 struct btrfs_ioctl_ino_lookup_args args;
1157 memset(&args, 0, sizeof(args));
1158 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1160 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1163 "ERROR: can't perform the search -%s\n",
1170 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1171 struct btrfs_qgroup_comparer_set **comps)
1179 while ((p = strtok(opt_arg, ",")) != NULL) {
1181 ptr_argv = all_sort_items;
1184 if (strcmp(*ptr_argv, p) == 0) {
1189 if (strcmp(*ptr_argv, p) == 0) {
1206 } else if (*p == '-') {
1212 what_to_sort = btrfs_qgroup_get_sort_item(p);
1213 if (what_to_sort < 0)
1215 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1223 u64 parse_qgroupid(char *p)
1225 char *s = strchr(p, '/');
1226 char *ptr_src_end = p + strlen(p);
1227 char *ptr_parse_end = NULL;
1232 id = strtoull(p, &ptr_parse_end, 10);
1233 if (ptr_parse_end != ptr_src_end)
1237 level = strtoull(p, &ptr_parse_end, 10);
1238 if (ptr_parse_end != s)
1241 id = strtoull(s+1, &ptr_parse_end, 10);
1242 if (ptr_parse_end != ptr_src_end)
1245 return (level << 48) | id;
1247 fprintf(stderr, "ERROR:invalid qgroupid\n");
1251 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1253 return sizeof(*p) + sizeof(p->qgroups[0]) *
1254 (p->num_qgroups + 2 * p->num_ref_copies +
1255 2 * p->num_excl_copies);
1259 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1261 struct btrfs_qgroup_inherit *out;
1265 nitems = (*inherit)->num_qgroups +
1266 (*inherit)->num_ref_copies +
1267 (*inherit)->num_excl_copies;
1270 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1272 fprintf(stderr, "ERROR: Not enough memory\n");
1277 struct btrfs_qgroup_inherit *i = *inherit;
1278 int s = sizeof(out->qgroups[0]);
1280 out->num_qgroups = i->num_qgroups;
1281 out->num_ref_copies = i->num_ref_copies;
1282 out->num_excl_copies = i->num_excl_copies;
1283 memcpy(out->qgroups, i->qgroups, pos * s);
1284 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1285 (nitems - pos) * s);
1293 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1296 u64 qgroupid = parse_qgroupid(arg);
1299 if (qgroupid == 0) {
1300 fprintf(stderr, "ERROR: bad qgroup specification\n");
1305 pos = (*inherit)->num_qgroups;
1306 ret = qgroup_inherit_realloc(inherit, 1, pos);
1310 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1315 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1324 p = strchr(arg, ':');
1327 fprintf(stderr, "ERROR: bad copy specification\n");
1331 qgroup_src = parse_qgroupid(arg);
1332 qgroup_dst = parse_qgroupid(p + 1);
1335 if (!qgroup_src || !qgroup_dst)
1339 pos = (*inherit)->num_qgroups +
1340 (*inherit)->num_ref_copies * 2 * type;
1342 ret = qgroup_inherit_realloc(inherit, 2, pos);
1346 (*inherit)->qgroups[pos++] = qgroup_src;
1347 (*inherit)->qgroups[pos++] = qgroup_dst;
1350 ++(*inherit)->num_ref_copies;
1352 ++(*inherit)->num_excl_copies;