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
83 } btrfs_qgroup_columns[] = {
86 .column_name = "Qgroupid",
91 .column_name = "Rfer",
96 .column_name = "Excl",
100 .column_name = "Max_rfer",
105 .column_name = "Max_excl",
110 .column_name = "Parent",
115 .column_name = "Child",
125 static btrfs_qgroup_filter_func all_filter_funcs[];
126 static btrfs_qgroup_comp_func all_comp_funcs[];
128 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
132 BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
134 if (column < BTRFS_QGROUP_ALL) {
135 btrfs_qgroup_columns[column].need_print = 1;
138 for (i = 0; i < BTRFS_QGROUP_ALL; i++)
139 btrfs_qgroup_columns[i].need_print = 1;
142 static void print_parent_column(struct btrfs_qgroup *qgroup)
144 struct btrfs_qgroup_list *list = NULL;
146 list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
147 printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
148 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
149 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
152 if (list_empty(&qgroup->qgroups))
156 static void print_child_column(struct btrfs_qgroup *qgroup)
158 struct btrfs_qgroup_list *list = NULL;
160 list_for_each_entry(list, &qgroup->members, next_member) {
161 printf("%llu/%llu", (list->member)->qgroupid >> 48,
162 ((1ll << 48) - 1) & (list->member)->qgroupid);
163 if (!list_is_last(&list->next_member, &qgroup->members))
166 if (list_empty(&qgroup->members))
170 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
171 enum btrfs_qgroup_column_enum column)
173 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
177 case BTRFS_QGROUP_QGROUPID:
178 printf("%llu/%llu", qgroup->qgroupid >> 48,
179 ((1ll << 48) - 1) & qgroup->qgroupid);
181 case BTRFS_QGROUP_RFER:
182 printf("%lld", qgroup->rfer);
184 case BTRFS_QGROUP_EXCL:
185 printf("%lld", qgroup->excl);
187 case BTRFS_QGROUP_PARENT:
188 print_parent_column(qgroup);
190 case BTRFS_QGROUP_MAX_RFER:
191 printf("%llu", qgroup->max_rfer);
193 case BTRFS_QGROUP_MAX_EXCL:
194 printf("%llu", qgroup->max_excl);
196 case BTRFS_QGROUP_CHILD:
197 print_child_column(qgroup);
204 static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
208 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
209 if (!btrfs_qgroup_columns[i].need_print)
211 print_qgroup_column(qgroup, i);
213 if (i != BTRFS_QGROUP_ALL - 1)
219 static void qgroup_lookup_init(struct qgroup_lookup *tree)
221 tree->root.rb_node = NULL;
224 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
225 struct btrfs_qgroup *entry2,
231 if (entry1->qgroupid > entry2->qgroupid)
233 else if (entry1->qgroupid < entry2->qgroupid)
238 return is_descending ? -ret : ret;
241 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
242 struct btrfs_qgroup *entry2,
247 if (entry1->rfer > entry2->rfer)
249 else if (entry1->rfer < entry2->rfer)
254 return is_descending ? -ret : ret;
257 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
258 struct btrfs_qgroup *entry2,
263 if (entry1->excl > entry2->excl)
265 else if (entry1->excl < entry2->excl)
270 return is_descending ? -ret : ret;
273 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
274 struct btrfs_qgroup *entry2,
279 if (entry1->max_rfer > entry2->max_rfer)
281 else if (entry1->max_rfer < entry2->max_rfer)
286 return is_descending ? -ret : ret;
289 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
290 struct btrfs_qgroup *entry2,
295 if (entry1->max_excl > entry2->max_excl)
297 else if (entry1->max_excl < entry2->max_excl)
302 return is_descending ? -ret : ret;
305 static btrfs_qgroup_comp_func all_comp_funcs[] = {
306 [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid,
307 [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer,
308 [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl,
309 [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer,
310 [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl
313 static char *all_sort_items[] = {
314 [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid",
315 [BTRFS_QGROUP_COMP_RFER] = "rfer",
316 [BTRFS_QGROUP_COMP_EXCL] = "excl",
317 [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer",
318 [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl",
319 [BTRFS_QGROUP_COMP_MAX] = NULL,
322 static int btrfs_qgroup_get_sort_item(char *sort_name)
326 for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
327 if (strcmp(sort_name, all_sort_items[i]) == 0)
333 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
335 struct btrfs_qgroup_comparer_set *set;
337 size = sizeof(struct btrfs_qgroup_comparer_set) +
338 BTRFS_QGROUP_NCOMPS_INCREASE *
339 sizeof(struct btrfs_qgroup_comparer);
342 fprintf(stderr, "memory allocation failed\n");
346 memset(set, 0, size);
347 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
352 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
357 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
358 enum btrfs_qgroup_comp_enum comparer,
361 struct btrfs_qgroup_comparer_set *set = *comp_set;
365 BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
366 BUG_ON(set->ncomps > set->total);
368 if (set->ncomps == set->total) {
369 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
370 size = sizeof(*set) +
371 size * sizeof(struct btrfs_qgroup_comparer);
372 set = realloc(set, size);
374 fprintf(stderr, "memory allocation failed\n");
378 memset(&set->comps[set->total], 0,
379 BTRFS_QGROUP_NCOMPS_INCREASE *
380 sizeof(struct btrfs_qgroup_comparer));
381 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
385 BUG_ON(set->comps[set->ncomps].comp_func);
387 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
388 set->comps[set->ncomps].is_descending = is_descending;
393 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
394 struct btrfs_qgroup_comparer_set *set)
396 int qgroupid_compared = 0;
399 if (!set || !set->ncomps)
402 for (i = 0; i < set->ncomps; i++) {
403 if (!set->comps[i].comp_func)
406 ret = set->comps[i].comp_func(entry1, entry2,
407 set->comps[i].is_descending);
411 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
412 qgroupid_compared = 1;
415 if (!qgroupid_compared) {
417 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
424 * insert a new root into the tree. returns the existing root entry
425 * if one is already there. qgroupid is used
428 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
429 struct btrfs_qgroup *ins)
432 struct rb_node **p = &root_tree->root.rb_node;
433 struct rb_node *parent = NULL;
434 struct btrfs_qgroup *curr;
439 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
441 ret = comp_entry_with_qgroupid(ins, curr, 0);
449 rb_link_node(&ins->rb_node, parent, p);
450 rb_insert_color(&ins->rb_node, &root_tree->root);
455 *find a given qgroupid in the tree. We return the smallest one,
456 *rb_next can be used to move forward looking for more if required
458 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
461 struct rb_node *n = root_tree->root.rb_node;
462 struct btrfs_qgroup *entry;
463 struct btrfs_qgroup tmp;
466 tmp.qgroupid = qgroupid;
469 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
471 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
483 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
484 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
485 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
486 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
487 struct btrfs_qgroup *child)
489 struct btrfs_qgroup *bq;
490 struct btrfs_qgroup_list *list;
492 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
493 if (!bq || bq->qgroupid != qgroupid)
497 bq->generation = generation;
501 bq->rfer_cmpr = rfer_cmpr;
505 bq->excl_cmpr = excl_cmpr;
509 bq->max_rfer = max_rfer;
511 bq->max_excl = max_excl;
513 bq->rsv_rfer = rsv_rfer;
515 list = malloc(sizeof(*list));
517 fprintf(stderr, "memory allocation failed\n");
521 list->member = child;
522 list_add_tail(&list->next_qgroup, &child->qgroups);
523 list_add_tail(&list->next_member, &pa->members);
528 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
529 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
530 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
531 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
532 struct btrfs_qgroup *child)
534 struct btrfs_qgroup *bq;
535 struct btrfs_qgroup_list *list;
538 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
539 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
540 max_excl, rsv_rfer, rsv_excl, parent, child);
544 bq = malloc(sizeof(*bq));
546 printf("memory allocation failed\n");
549 memset(bq, 0, sizeof(*bq));
551 bq->qgroupid = qgroupid;
552 INIT_LIST_HEAD(&bq->qgroups);
553 INIT_LIST_HEAD(&bq->members);
556 bq->generation = generation;
560 bq->rfer_cmpr = rfer_cmpr;
564 bq->excl_cmpr = excl_cmpr;
568 bq->max_rfer = max_rfer;
570 bq->max_excl = max_excl;
572 bq->rsv_rfer = rsv_rfer;
573 if (parent && child) {
574 list = malloc(sizeof(*list));
576 fprintf(stderr, "memory allocation failed\n");
579 list->qgroup = parent;
580 list->member = child;
581 list_add_tail(&list->next_qgroup, &child->qgroups);
582 list_add_tail(&list->next_member, &parent->members);
584 ret = qgroup_tree_insert(qgroup_lookup, bq);
586 printf("failed to insert tree %llu\n",
593 void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
595 struct btrfs_qgroup_list *list;
596 while (!list_empty(&bq->qgroups)) {
597 list = list_entry((&bq->qgroups)->next,
598 struct btrfs_qgroup_list,
600 list_del(&list->next_qgroup);
601 list_del(&list->next_member);
604 while (!list_empty(&bq->members)) {
605 list = list_entry((&bq->members)->next,
606 struct btrfs_qgroup_list,
608 list_del(&list->next_qgroup);
609 list_del(&list->next_member);
615 void __free_all_qgroups(struct qgroup_lookup *root_tree)
617 struct btrfs_qgroup *entry;
620 n = rb_first(&root_tree->root);
622 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
623 rb_erase(n, &root_tree->root);
624 __free_btrfs_qgroup(entry);
626 n = rb_first(&root_tree->root);
630 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
631 struct btrfs_qgroup *bq)
633 struct rb_node **p = &sort_tree->root.rb_node;
634 struct rb_node *parent = NULL;
635 struct btrfs_qgroup *curr;
640 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
642 ret = comp_entry_with_qgroupid(bq, curr, 0);
650 rb_link_node(&bq->all_parent_node, parent, p);
651 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
655 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
657 struct btrfs_qgroup *qgroup =
658 (struct btrfs_qgroup *)(unsigned long)data;
662 if (qgroup->qgroupid == bq->qgroupid)
667 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
669 struct qgroup_lookup lookup;
670 struct qgroup_lookup *ql = &lookup;
671 struct btrfs_qgroup_list *list;
673 struct btrfs_qgroup *qgroup =
674 (struct btrfs_qgroup *)(unsigned long)data;
678 if (bq->qgroupid == qgroup->qgroupid)
681 qgroup_lookup_init(ql);
682 filter_all_parent_insert(ql, qgroup);
683 n = rb_first(&ql->root);
685 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
686 if (!list_empty(&qgroup->qgroups)) {
687 list_for_each_entry(list, &qgroup->qgroups,
689 if ((list->qgroup)->qgroupid == bq->qgroupid)
691 filter_all_parent_insert(ql, list->qgroup);
694 rb_erase(n, &ql->root);
695 n = rb_first(&ql->root);
700 static btrfs_qgroup_filter_func all_filter_funcs[] = {
701 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
702 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
705 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
707 struct btrfs_qgroup_filter_set *set;
710 size = sizeof(struct btrfs_qgroup_filter_set) +
711 BTRFS_QGROUP_NFILTERS_INCREASE *
712 sizeof(struct btrfs_qgroup_filter);
715 fprintf(stderr, "memory allocation failed\n");
718 memset(set, 0, size);
719 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
724 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
729 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
730 enum btrfs_qgroup_filter_enum filter, u64 data)
732 struct btrfs_qgroup_filter_set *set = *filter_set;
736 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
737 BUG_ON(set->nfilters > set->total);
739 if (set->nfilters == set->total) {
740 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
741 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
743 set = realloc(set, size);
745 fprintf(stderr, "memory allocation failed\n");
748 memset(&set->filters[set->total], 0,
749 BTRFS_QGROUP_NFILTERS_INCREASE *
750 sizeof(struct btrfs_qgroup_filter));
751 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
754 BUG_ON(set->filters[set->nfilters].filter_func);
755 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
756 set->filters[set->nfilters].data = data;
761 static int filter_qgroup(struct btrfs_qgroup *bq,
762 struct btrfs_qgroup_filter_set *set)
766 if (!set || !set->nfilters)
768 for (i = 0; i < set->nfilters; i++) {
769 if (!set->filters[i].filter_func)
771 ret = set->filters[i].filter_func(bq, set->filters[i].data);
778 static void pre_process_filter_set(struct qgroup_lookup *lookup,
779 struct btrfs_qgroup_filter_set *set)
782 struct btrfs_qgroup *qgroup_for_filter = NULL;
784 for (i = 0; i < set->nfilters; i++) {
786 if (set->filters[i].filter_func == filter_by_all_parent
787 || set->filters[i].filter_func == filter_by_parent) {
788 qgroup_for_filter = qgroup_tree_search(lookup,
789 set->filters[i].data);
790 set->filters[i].data =
791 (u64)(unsigned long)qgroup_for_filter;
796 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
797 struct btrfs_qgroup *bq,
798 struct btrfs_qgroup_comparer_set *comp_set)
800 struct rb_node **p = &sort_tree->root.rb_node;
801 struct rb_node *parent = NULL;
802 struct btrfs_qgroup *curr;
807 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
809 ret = sort_comp(bq, curr, comp_set);
817 rb_link_node(&bq->sort_node, parent, p);
818 rb_insert_color(&bq->sort_node, &sort_tree->root);
822 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
823 struct qgroup_lookup *sort_tree,
824 struct btrfs_qgroup_filter_set *filter_set,
825 struct btrfs_qgroup_comparer_set *comp_set)
828 struct btrfs_qgroup *entry;
831 qgroup_lookup_init(sort_tree);
832 pre_process_filter_set(all_qgroups, filter_set);
834 n = rb_last(&all_qgroups->root);
836 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
838 ret = filter_qgroup(entry, filter_set);
840 sort_tree_insert(sort_tree, entry, comp_set);
845 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
848 struct btrfs_ioctl_search_args args;
849 struct btrfs_ioctl_search_key *sk = &args.key;
850 struct btrfs_ioctl_search_header *sh;
851 unsigned long off = 0;
854 struct btrfs_qgroup_info_item *info;
855 struct btrfs_qgroup_limit_item *limit;
856 struct btrfs_qgroup *bq;
857 struct btrfs_qgroup *bq1;
864 memset(&args, 0, sizeof(args));
866 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
867 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
868 sk->min_type = BTRFS_QGROUP_INFO_KEY;
869 sk->max_objectid = (u64)-1;
870 sk->max_offset = (u64)-1;
871 sk->max_transid = (u64)-1;
874 qgroup_lookup_init(qgroup_lookup);
877 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
881 "ERROR: can't perform the search - %s\n",
885 /* the ioctl returns the number of item it found in nr_items */
886 if (sk->nr_items == 0)
891 * for each item, pull the key out of the header and then
892 * read the root_ref item it contains
894 for (i = 0; i < sk->nr_items; i++) {
895 sh = (struct btrfs_ioctl_search_header *)(args.buf +
899 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
900 info = (struct btrfs_qgroup_info_item *)
902 a1 = btrfs_stack_qgroup_info_generation(info);
903 a2 = btrfs_stack_qgroup_info_referenced(info);
905 btrfs_stack_qgroup_info_referenced_compressed
907 a4 = btrfs_stack_qgroup_info_exclusive(info);
909 btrfs_stack_qgroup_info_exclusive_compressed
911 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
912 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
913 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
914 limit = (struct btrfs_qgroup_limit_item *)
917 a1 = btrfs_stack_qgroup_limit_flags(limit);
918 a2 = btrfs_stack_qgroup_limit_max_referenced
920 a3 = btrfs_stack_qgroup_limit_max_exclusive
922 a4 = btrfs_stack_qgroup_limit_rsv_referenced
924 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
926 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
927 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
928 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
929 if (sh->offset < sh->objectid)
931 bq = qgroup_tree_search(qgroup_lookup,
935 bq1 = qgroup_tree_search(qgroup_lookup,
939 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
940 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
947 * record the mins in sk so we can make sure the
948 * next search doesn't repeat this root
950 sk->min_type = sh->type;
951 sk->min_offset = sh->offset;
952 sk->min_objectid = sh->objectid;
956 * this iteration is done, step forward one qgroup for the next
959 if (sk->min_offset < (u64)-1)
969 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
973 struct btrfs_qgroup *entry;
975 n = rb_first(&qgroup_lookup->root);
977 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
978 print_single_qgroup_default(entry);
983 int btrfs_show_qgroups(int fd,
984 struct btrfs_qgroup_filter_set *filter_set,
985 struct btrfs_qgroup_comparer_set *comp_set)
988 struct qgroup_lookup qgroup_lookup;
989 struct qgroup_lookup sort_tree;
992 ret = __qgroups_search(fd, &qgroup_lookup);
995 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
996 filter_set, comp_set);
997 print_all_qgroups(&sort_tree);
999 __free_all_qgroups(&qgroup_lookup);
1000 btrfs_qgroup_free_filter_set(filter_set);
1004 u64 btrfs_get_path_rootid(int fd)
1007 struct btrfs_ioctl_ino_lookup_args args;
1009 memset(&args, 0, sizeof(args));
1010 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1012 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1015 "ERROR: can't perform the search -%s\n",
1022 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1023 struct btrfs_qgroup_comparer_set **comps)
1031 while ((p = strtok(opt_arg, ",")) != NULL) {
1033 ptr_argv = all_sort_items;
1036 if (strcmp(*ptr_argv, p) == 0) {
1041 if (strcmp(*ptr_argv, p) == 0) {
1058 } else if (*p == '-') {
1064 what_to_sort = btrfs_qgroup_get_sort_item(p);
1065 if (what_to_sort < 0)
1067 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1075 u64 parse_qgroupid(char *p)
1077 char *s = strchr(p, '/');
1078 char *ptr_src_end = p + strlen(p);
1079 char *ptr_parse_end = NULL;
1084 id = strtoull(p, &ptr_parse_end, 10);
1085 if (ptr_parse_end != ptr_src_end)
1089 level = strtoull(p, &ptr_parse_end, 10);
1090 if (ptr_parse_end != s)
1093 id = strtoull(s+1, &ptr_parse_end, 10);
1094 if (ptr_parse_end != ptr_src_end)
1097 return (level << 48) | id;
1099 fprintf(stderr, "ERROR:invalid qgroupid\n");
1103 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1105 return sizeof(*p) + sizeof(p->qgroups[0]) *
1106 (p->num_qgroups + 2 * p->num_ref_copies +
1107 2 * p->num_excl_copies);
1111 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1113 struct btrfs_qgroup_inherit *out;
1117 nitems = (*inherit)->num_qgroups +
1118 (*inherit)->num_ref_copies +
1119 (*inherit)->num_excl_copies;
1122 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1124 fprintf(stderr, "ERROR: Not enough memory\n");
1129 struct btrfs_qgroup_inherit *i = *inherit;
1130 int s = sizeof(out->qgroups[0]);
1132 out->num_qgroups = i->num_qgroups;
1133 out->num_ref_copies = i->num_ref_copies;
1134 out->num_excl_copies = i->num_excl_copies;
1135 memcpy(out->qgroups, i->qgroups, pos * s);
1136 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1137 (nitems - pos) * s);
1145 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1148 u64 qgroupid = parse_qgroupid(arg);
1151 if (qgroupid == 0) {
1152 fprintf(stderr, "ERROR: bad qgroup specification\n");
1157 pos = (*inherit)->num_qgroups;
1158 ret = qgroup_inherit_realloc(inherit, 1, pos);
1162 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1167 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1176 p = strchr(arg, ':');
1179 fprintf(stderr, "ERROR: bad copy specification\n");
1183 qgroup_src = parse_qgroupid(arg);
1184 qgroup_dst = parse_qgroupid(p + 1);
1187 if (!qgroup_src || !qgroup_dst)
1191 pos = (*inherit)->num_qgroups +
1192 (*inherit)->num_ref_copies * 2 * type;
1194 ret = qgroup_inherit_realloc(inherit, 2, pos);
1198 (*inherit)->qgroups[pos++] = qgroup_src;
1199 (*inherit)->qgroups[pos++] = qgroup_dst;
1202 ++(*inherit)->num_ref_copies;
1204 ++(*inherit)->num_excl_copies;