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 ASSERT(0 <= column && 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)
217 int unit_mode = btrfs_qgroup_columns[column].unit_mode;
218 int max_len = btrfs_qgroup_columns[column].max_len;
220 ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
224 case BTRFS_QGROUP_QGROUPID:
225 len = printf("%llu/%llu",
226 btrfs_qgroup_level(qgroup->qgroupid),
227 btrfs_qgroup_subvid(qgroup->qgroupid));
228 print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
230 case BTRFS_QGROUP_RFER:
231 len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
233 case BTRFS_QGROUP_EXCL:
234 len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
236 case BTRFS_QGROUP_PARENT:
237 len = print_parent_column(qgroup);
238 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
240 case BTRFS_QGROUP_MAX_RFER:
241 if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
242 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
244 len = printf("%*s", max_len, "none");
246 case BTRFS_QGROUP_MAX_EXCL:
247 if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
248 len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
250 len = printf("%*s", max_len, "none");
252 case BTRFS_QGROUP_CHILD:
253 len = print_child_column(qgroup);
254 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
261 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
265 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
266 if (!btrfs_qgroup_columns[i].need_print)
268 print_qgroup_column(qgroup, i);
270 if (i != BTRFS_QGROUP_CHILD)
276 static void print_table_head(void)
282 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
283 max_len = btrfs_qgroup_columns[i].max_len;
284 if (!btrfs_qgroup_columns[i].need_print)
286 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
287 (i == BTRFS_QGROUP_CHILD))
288 printf("%-*s", max_len, btrfs_qgroup_columns[i].name);
290 printf("%*s", max_len, btrfs_qgroup_columns[i].name);
294 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
295 max_len = btrfs_qgroup_columns[i].max_len;
296 if (!btrfs_qgroup_columns[i].need_print)
298 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
299 (i == BTRFS_QGROUP_CHILD)) {
300 len = strlen(btrfs_qgroup_columns[i].name);
303 len = max_len - strlen(btrfs_qgroup_columns[i].name);
307 len = max_len - strlen(btrfs_qgroup_columns[i].name);
310 len = strlen(btrfs_qgroup_columns[i].name);
319 static void qgroup_lookup_init(struct qgroup_lookup *tree)
321 tree->root.rb_node = NULL;
324 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
325 struct btrfs_qgroup *entry2,
331 if (entry1->qgroupid > entry2->qgroupid)
333 else if (entry1->qgroupid < entry2->qgroupid)
338 return is_descending ? -ret : ret;
341 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
342 struct btrfs_qgroup *entry2,
347 if (entry1->rfer > entry2->rfer)
349 else if (entry1->rfer < entry2->rfer)
354 return is_descending ? -ret : ret;
357 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
358 struct btrfs_qgroup *entry2,
363 if (entry1->excl > entry2->excl)
365 else if (entry1->excl < entry2->excl)
370 return is_descending ? -ret : ret;
373 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
374 struct btrfs_qgroup *entry2,
379 if (entry1->max_rfer > entry2->max_rfer)
381 else if (entry1->max_rfer < entry2->max_rfer)
386 return is_descending ? -ret : ret;
389 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
390 struct btrfs_qgroup *entry2,
395 if (entry1->max_excl > entry2->max_excl)
397 else if (entry1->max_excl < entry2->max_excl)
402 return is_descending ? -ret : ret;
405 static btrfs_qgroup_comp_func all_comp_funcs[] = {
406 [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid,
407 [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer,
408 [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl,
409 [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer,
410 [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl
413 static char *all_sort_items[] = {
414 [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid",
415 [BTRFS_QGROUP_COMP_RFER] = "rfer",
416 [BTRFS_QGROUP_COMP_EXCL] = "excl",
417 [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer",
418 [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl",
419 [BTRFS_QGROUP_COMP_MAX] = NULL,
422 static int btrfs_qgroup_get_sort_item(char *sort_name)
426 for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
427 if (strcmp(sort_name, all_sort_items[i]) == 0)
433 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
435 struct btrfs_qgroup_comparer_set *set;
437 size = sizeof(struct btrfs_qgroup_comparer_set) +
438 BTRFS_QGROUP_NCOMPS_INCREASE *
439 sizeof(struct btrfs_qgroup_comparer);
440 set = calloc(1, size);
442 error("memory allocation failed");
446 set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
451 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
452 enum btrfs_qgroup_comp_enum comparer,
455 struct btrfs_qgroup_comparer_set *set = *comp_set;
459 ASSERT(comparer < BTRFS_QGROUP_COMP_MAX);
460 ASSERT(set->ncomps <= set->total);
462 if (set->ncomps == set->total) {
465 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
466 size = sizeof(*set) +
467 size * sizeof(struct btrfs_qgroup_comparer);
469 set = realloc(set, size);
471 error("memory allocation failed");
476 memset(&set->comps[set->total], 0,
477 BTRFS_QGROUP_NCOMPS_INCREASE *
478 sizeof(struct btrfs_qgroup_comparer));
479 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
483 ASSERT(set->comps[set->ncomps].comp_func == NULL);
485 set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
486 set->comps[set->ncomps].is_descending = is_descending;
491 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
492 struct btrfs_qgroup_comparer_set *set)
494 int qgroupid_compared = 0;
497 if (!set || !set->ncomps)
500 for (i = 0; i < set->ncomps; i++) {
501 if (!set->comps[i].comp_func)
504 ret = set->comps[i].comp_func(entry1, entry2,
505 set->comps[i].is_descending);
509 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
510 qgroupid_compared = 1;
513 if (!qgroupid_compared) {
515 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
522 * insert a new root into the tree. returns the existing root entry
523 * if one is already there. qgroupid is used
526 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
527 struct btrfs_qgroup *ins)
530 struct rb_node **p = &root_tree->root.rb_node;
531 struct rb_node *parent = NULL;
532 struct btrfs_qgroup *curr;
537 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
539 ret = comp_entry_with_qgroupid(ins, curr, 0);
547 rb_link_node(&ins->rb_node, parent, p);
548 rb_insert_color(&ins->rb_node, &root_tree->root);
553 *find a given qgroupid in the tree. We return the smallest one,
554 *rb_next can be used to move forward looking for more if required
556 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
559 struct rb_node *n = root_tree->root.rb_node;
560 struct btrfs_qgroup *entry;
561 struct btrfs_qgroup tmp;
564 tmp.qgroupid = qgroupid;
567 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
569 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
582 * Lookup or insert btrfs_qgroup into qgroup_lookup.
584 * Search a btrfs_qgroup with @qgroupid from the @qgroup_lookup. If not found,
585 * initialize a btrfs_qgroup with the given qgroupid and insert it to the
588 * Return the pointer to the btrfs_qgroup if found or if inserted successfully.
589 * Return ERR_PTR if any error occurred.
591 static struct btrfs_qgroup *get_or_add_qgroup(
592 struct qgroup_lookup *qgroup_lookup, u64 qgroupid)
594 struct btrfs_qgroup *bq;
597 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
601 bq = calloc(1, sizeof(*bq));
603 error("memory allocation failed");
604 return ERR_PTR(-ENOMEM);
607 bq->qgroupid = qgroupid;
608 INIT_LIST_HEAD(&bq->qgroups);
609 INIT_LIST_HEAD(&bq->members);
611 ret = qgroup_tree_insert(qgroup_lookup, bq);
613 error("failed to insert %llu into tree: %s",
614 (unsigned long long)bq->qgroupid, strerror(-ret));
622 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
623 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
624 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
625 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
626 struct btrfs_qgroup *child)
628 struct btrfs_qgroup *bq;
629 struct btrfs_qgroup_list *list;
631 bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
632 if (IS_ERR_OR_NULL(bq))
636 bq->generation = generation;
640 bq->rfer_cmpr = rfer_cmpr;
644 bq->excl_cmpr = excl_cmpr;
648 bq->max_rfer = max_rfer;
650 bq->max_excl = max_excl;
652 bq->rsv_rfer = rsv_rfer;
654 list = malloc(sizeof(*list));
656 error("memory allocation failed");
660 list->member = child;
661 list_add_tail(&list->next_qgroup, &child->qgroups);
662 list_add_tail(&list->next_member, &pa->members);
667 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
669 struct btrfs_qgroup_list *list;
670 while (!list_empty(&bq->qgroups)) {
671 list = list_entry((&bq->qgroups)->next,
672 struct btrfs_qgroup_list,
674 list_del(&list->next_qgroup);
675 list_del(&list->next_member);
678 while (!list_empty(&bq->members)) {
679 list = list_entry((&bq->members)->next,
680 struct btrfs_qgroup_list,
682 list_del(&list->next_qgroup);
683 list_del(&list->next_member);
689 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
691 struct btrfs_qgroup *entry;
694 n = rb_first(&root_tree->root);
696 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
697 rb_erase(n, &root_tree->root);
698 __free_btrfs_qgroup(entry);
700 n = rb_first(&root_tree->root);
704 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
705 struct btrfs_qgroup *bq)
707 struct rb_node **p = &sort_tree->root.rb_node;
708 struct rb_node *parent = NULL;
709 struct btrfs_qgroup *curr;
714 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
716 ret = comp_entry_with_qgroupid(bq, curr, 0);
724 rb_link_node(&bq->all_parent_node, parent, p);
725 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
729 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
731 struct btrfs_qgroup *qgroup =
732 (struct btrfs_qgroup *)(unsigned long)data;
736 if (qgroup->qgroupid == bq->qgroupid)
741 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
743 struct qgroup_lookup lookup;
744 struct qgroup_lookup *ql = &lookup;
745 struct btrfs_qgroup_list *list;
747 struct btrfs_qgroup *qgroup =
748 (struct btrfs_qgroup *)(unsigned long)data;
752 if (bq->qgroupid == qgroup->qgroupid)
755 qgroup_lookup_init(ql);
756 filter_all_parent_insert(ql, qgroup);
757 n = rb_first(&ql->root);
759 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
760 if (!list_empty(&qgroup->qgroups)) {
761 list_for_each_entry(list, &qgroup->qgroups,
763 if ((list->qgroup)->qgroupid == bq->qgroupid)
765 filter_all_parent_insert(ql, list->qgroup);
768 rb_erase(n, &ql->root);
769 n = rb_first(&ql->root);
774 static btrfs_qgroup_filter_func all_filter_funcs[] = {
775 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
776 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
779 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
781 struct btrfs_qgroup_filter_set *set;
784 size = sizeof(struct btrfs_qgroup_filter_set) +
785 BTRFS_QGROUP_NFILTERS_INCREASE *
786 sizeof(struct btrfs_qgroup_filter);
787 set = calloc(1, size);
789 error("memory allocation failed");
792 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
797 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
798 enum btrfs_qgroup_filter_enum filter, u64 data)
800 struct btrfs_qgroup_filter_set *set = *filter_set;
804 ASSERT(filter < BTRFS_QGROUP_FILTER_MAX);
805 ASSERT(set->nfilters <= set->total);
807 if (set->nfilters == set->total) {
810 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
811 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
814 set = realloc(set, size);
816 error("memory allocation failed");
820 memset(&set->filters[set->total], 0,
821 BTRFS_QGROUP_NFILTERS_INCREASE *
822 sizeof(struct btrfs_qgroup_filter));
823 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
827 ASSERT(set->filters[set->nfilters].filter_func == NULL);
828 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
829 set->filters[set->nfilters].data = data;
834 static int filter_qgroup(struct btrfs_qgroup *bq,
835 struct btrfs_qgroup_filter_set *set)
839 if (!set || !set->nfilters)
841 for (i = 0; i < set->nfilters; i++) {
842 if (!set->filters[i].filter_func)
844 ret = set->filters[i].filter_func(bq, set->filters[i].data);
851 static void pre_process_filter_set(struct qgroup_lookup *lookup,
852 struct btrfs_qgroup_filter_set *set)
855 struct btrfs_qgroup *qgroup_for_filter = NULL;
857 for (i = 0; i < set->nfilters; i++) {
859 if (set->filters[i].filter_func == filter_by_all_parent
860 || set->filters[i].filter_func == filter_by_parent) {
861 qgroup_for_filter = qgroup_tree_search(lookup,
862 set->filters[i].data);
863 set->filters[i].data =
864 (u64)(unsigned long)qgroup_for_filter;
869 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
870 struct btrfs_qgroup *bq,
871 struct btrfs_qgroup_comparer_set *comp_set)
873 struct rb_node **p = &sort_tree->root.rb_node;
874 struct rb_node *parent = NULL;
875 struct btrfs_qgroup *curr;
880 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
882 ret = sort_comp(bq, curr, comp_set);
890 rb_link_node(&bq->sort_node, parent, p);
891 rb_insert_color(&bq->sort_node, &sort_tree->root);
895 static void __update_columns_max_len(struct btrfs_qgroup *bq,
896 enum btrfs_qgroup_column_enum column)
898 struct btrfs_qgroup_list *list = NULL;
901 unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
903 ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
907 case BTRFS_QGROUP_QGROUPID:
908 sprintf(tmp, "%llu/%llu",
909 btrfs_qgroup_level(bq->qgroupid),
910 btrfs_qgroup_subvid(bq->qgroupid));
912 if (btrfs_qgroup_columns[column].max_len < len)
913 btrfs_qgroup_columns[column].max_len = len;
915 case BTRFS_QGROUP_RFER:
916 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
917 if (btrfs_qgroup_columns[column].max_len < len)
918 btrfs_qgroup_columns[column].max_len = len;
920 case BTRFS_QGROUP_EXCL:
921 len = strlen(pretty_size_mode(bq->excl, unit_mode));
922 if (btrfs_qgroup_columns[column].max_len < len)
923 btrfs_qgroup_columns[column].max_len = len;
925 case BTRFS_QGROUP_MAX_RFER:
926 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
927 if (btrfs_qgroup_columns[column].max_len < len)
928 btrfs_qgroup_columns[column].max_len = len;
930 case BTRFS_QGROUP_MAX_EXCL:
931 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
932 if (btrfs_qgroup_columns[column].max_len < len)
933 btrfs_qgroup_columns[column].max_len = len;
935 case BTRFS_QGROUP_PARENT:
937 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
938 len += sprintf(tmp, "%llu/%llu",
939 btrfs_qgroup_level(list->qgroup->qgroupid),
940 btrfs_qgroup_subvid(list->qgroup->qgroupid));
941 if (!list_is_last(&list->next_qgroup, &bq->qgroups))
944 if (btrfs_qgroup_columns[column].max_len < len)
945 btrfs_qgroup_columns[column].max_len = len;
947 case BTRFS_QGROUP_CHILD:
949 list_for_each_entry(list, &bq->members, next_member) {
950 len += sprintf(tmp, "%llu/%llu",
951 btrfs_qgroup_level(list->member->qgroupid),
952 btrfs_qgroup_subvid(list->member->qgroupid));
953 if (!list_is_last(&list->next_member, &bq->members))
956 if (btrfs_qgroup_columns[column].max_len < len)
957 btrfs_qgroup_columns[column].max_len = len;
965 static void update_columns_max_len(struct btrfs_qgroup *bq)
969 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
970 if (!btrfs_qgroup_columns[i].need_print)
972 __update_columns_max_len(bq, i);
976 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
977 struct qgroup_lookup *sort_tree,
978 struct btrfs_qgroup_filter_set *filter_set,
979 struct btrfs_qgroup_comparer_set *comp_set)
982 struct btrfs_qgroup *entry;
985 qgroup_lookup_init(sort_tree);
986 pre_process_filter_set(all_qgroups, filter_set);
988 n = rb_last(&all_qgroups->root);
990 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
992 ret = filter_qgroup(entry, filter_set);
994 sort_tree_insert(sort_tree, entry, comp_set);
996 update_columns_max_len(entry);
1002 static inline void print_status_flag_warning(u64 flags)
1004 if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
1005 warning("quota disabled, qgroup data may be out of date");
1006 else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
1007 warning("rescan is running, qgroup data may be incorrect");
1008 else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
1009 warning("qgroup data inconsistent, rescan recommended");
1012 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1015 struct btrfs_ioctl_search_args args;
1016 struct btrfs_ioctl_search_key *sk = &args.key;
1017 struct btrfs_ioctl_search_header *sh;
1018 unsigned long off = 0;
1020 struct btrfs_qgroup_info_item *info;
1021 struct btrfs_qgroup_limit_item *limit;
1022 struct btrfs_qgroup *bq;
1023 struct btrfs_qgroup *bq1;
1030 memset(&args, 0, sizeof(args));
1032 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1033 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1034 sk->min_type = BTRFS_QGROUP_STATUS_KEY;
1035 sk->max_objectid = (u64)-1;
1036 sk->max_offset = (u64)-1;
1037 sk->max_transid = (u64)-1;
1038 sk->nr_items = 4096;
1040 qgroup_lookup_init(qgroup_lookup);
1043 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1047 /* the ioctl returns the number of item it found in nr_items */
1048 if (sk->nr_items == 0)
1053 * for each item, pull the key out of the header and then
1054 * read the root_ref item it contains
1056 for (i = 0; i < sk->nr_items; i++) {
1057 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1061 if (btrfs_search_header_type(sh)
1062 == BTRFS_QGROUP_STATUS_KEY) {
1063 struct btrfs_qgroup_status_item *si;
1066 si = (struct btrfs_qgroup_status_item *)
1068 flags = btrfs_stack_qgroup_status_flags(si);
1069 print_status_flag_warning(flags);
1070 } else if (btrfs_search_header_type(sh)
1071 == BTRFS_QGROUP_INFO_KEY) {
1072 info = (struct btrfs_qgroup_info_item *)
1074 a1 = btrfs_stack_qgroup_info_generation(info);
1075 a2 = btrfs_stack_qgroup_info_referenced(info);
1077 btrfs_stack_qgroup_info_referenced_compressed
1079 a4 = btrfs_stack_qgroup_info_exclusive(info);
1081 btrfs_stack_qgroup_info_exclusive_compressed
1083 update_qgroup(qgroup_lookup,
1084 btrfs_search_header_offset(sh), a1,
1085 a2, a3, a4, a5, 0, 0, 0, 0, 0, NULL,
1087 } else if (btrfs_search_header_type(sh)
1088 == BTRFS_QGROUP_LIMIT_KEY) {
1089 limit = (struct btrfs_qgroup_limit_item *)
1092 a1 = btrfs_stack_qgroup_limit_flags(limit);
1093 a2 = btrfs_stack_qgroup_limit_max_referenced
1095 a3 = btrfs_stack_qgroup_limit_max_exclusive
1097 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1099 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1101 update_qgroup(qgroup_lookup,
1102 btrfs_search_header_offset(sh), 0,
1103 0, 0, 0, 0, a1, a2, a3, a4, a5,
1105 } else if (btrfs_search_header_type(sh)
1106 == BTRFS_QGROUP_RELATION_KEY) {
1107 if (btrfs_search_header_offset(sh)
1108 < btrfs_search_header_objectid(sh))
1110 bq = qgroup_tree_search(qgroup_lookup,
1111 btrfs_search_header_offset(sh));
1114 bq1 = qgroup_tree_search(qgroup_lookup,
1115 btrfs_search_header_objectid(sh));
1118 update_qgroup(qgroup_lookup,
1119 btrfs_search_header_offset(sh), 0,
1120 0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1124 off += btrfs_search_header_len(sh);
1127 * record the mins in sk so we can make sure the
1128 * next search doesn't repeat this root
1130 sk->min_type = btrfs_search_header_type(sh);
1131 sk->min_offset = btrfs_search_header_offset(sh);
1132 sk->min_objectid = btrfs_search_header_objectid(sh);
1134 sk->nr_items = 4096;
1136 * this iteration is done, step forward one qgroup for the next
1139 if (sk->min_offset < (u64)-1)
1149 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1153 struct btrfs_qgroup *entry;
1157 n = rb_first(&qgroup_lookup->root);
1159 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1160 print_single_qgroup_table(entry);
1165 int btrfs_show_qgroups(int fd,
1166 struct btrfs_qgroup_filter_set *filter_set,
1167 struct btrfs_qgroup_comparer_set *comp_set)
1170 struct qgroup_lookup qgroup_lookup;
1171 struct qgroup_lookup sort_tree;
1174 ret = __qgroups_search(fd, &qgroup_lookup);
1177 __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1178 filter_set, comp_set);
1179 print_all_qgroups(&sort_tree);
1181 __free_all_qgroups(&qgroup_lookup);
1187 int btrfs_qgroup_parse_sort_string(const char *opt_arg,
1188 struct btrfs_qgroup_comparer_set **comps)
1198 opt_tmp = strdup(opt_arg);
1202 p = strtok(opt_tmp, ",");
1205 ptr_argv = all_sort_items;
1208 if (strcmp(*ptr_argv, p) == 0) {
1213 if (strcmp(*ptr_argv, p) == 0) {
1230 } else if (*p == '-') {
1236 what_to_sort = btrfs_qgroup_get_sort_item(p);
1237 if (what_to_sort < 0) {
1241 btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1243 p = strtok(NULL, ",");
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 error("not enough memory");
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 error("invalid qgroup specification, qgroupid must not 0");
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 error("invalid copy specification, missing separator :");
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;