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);
581 static int update_qgroup(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
582 u64 generation
, u64 rfer
, u64 rfer_cmpr
, u64 excl
,
583 u64 excl_cmpr
, u64 flags
, u64 max_rfer
, u64 max_excl
,
584 u64 rsv_rfer
, u64 rsv_excl
, struct btrfs_qgroup
*pa
,
585 struct btrfs_qgroup
*child
)
587 struct btrfs_qgroup
*bq
;
588 struct btrfs_qgroup_list
*list
;
590 bq
= qgroup_tree_search(qgroup_lookup
, qgroupid
);
591 if (!bq
|| bq
->qgroupid
!= qgroupid
)
595 bq
->generation
= generation
;
599 bq
->rfer_cmpr
= rfer_cmpr
;
603 bq
->excl_cmpr
= excl_cmpr
;
607 bq
->max_rfer
= max_rfer
;
609 bq
->max_excl
= max_excl
;
611 bq
->rsv_rfer
= rsv_rfer
;
613 list
= malloc(sizeof(*list
));
615 error("memory allocation failed");
619 list
->member
= child
;
620 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
621 list_add_tail(&list
->next_member
, &pa
->members
);
626 static int add_qgroup(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
627 u64 generation
, u64 rfer
, u64 rfer_cmpr
, u64 excl
,
628 u64 excl_cmpr
, u64 flags
, u64 max_rfer
, u64 max_excl
,
629 u64 rsv_rfer
, u64 rsv_excl
, struct btrfs_qgroup
*parent
,
630 struct btrfs_qgroup
*child
)
632 struct btrfs_qgroup
*bq
;
633 struct btrfs_qgroup_list
*list
;
636 ret
= update_qgroup(qgroup_lookup
, qgroupid
, generation
, rfer
,
637 rfer_cmpr
, excl
, excl_cmpr
, flags
, max_rfer
,
638 max_excl
, rsv_rfer
, rsv_excl
, parent
, child
);
642 bq
= calloc(1, sizeof(*bq
));
644 error("memory allocation failed");
648 bq
->qgroupid
= qgroupid
;
649 INIT_LIST_HEAD(&bq
->qgroups
);
650 INIT_LIST_HEAD(&bq
->members
);
653 bq
->generation
= generation
;
657 bq
->rfer_cmpr
= rfer_cmpr
;
661 bq
->excl_cmpr
= excl_cmpr
;
665 bq
->max_rfer
= max_rfer
;
667 bq
->max_excl
= max_excl
;
669 bq
->rsv_rfer
= rsv_rfer
;
670 if (parent
&& child
) {
671 list
= malloc(sizeof(*list
));
673 error("memory allocation failed");
676 list
->qgroup
= parent
;
677 list
->member
= child
;
678 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
679 list_add_tail(&list
->next_member
, &parent
->members
);
681 ret
= qgroup_tree_insert(qgroup_lookup
, bq
);
683 error("failed to insert %llu into tree: %s",
684 (unsigned long long)bq
->qgroupid
, strerror(-ret
));
690 static void __free_btrfs_qgroup(struct btrfs_qgroup
*bq
)
692 struct btrfs_qgroup_list
*list
;
693 while (!list_empty(&bq
->qgroups
)) {
694 list
= list_entry((&bq
->qgroups
)->next
,
695 struct btrfs_qgroup_list
,
697 list_del(&list
->next_qgroup
);
698 list_del(&list
->next_member
);
701 while (!list_empty(&bq
->members
)) {
702 list
= list_entry((&bq
->members
)->next
,
703 struct btrfs_qgroup_list
,
705 list_del(&list
->next_qgroup
);
706 list_del(&list
->next_member
);
712 static void __free_all_qgroups(struct qgroup_lookup
*root_tree
)
714 struct btrfs_qgroup
*entry
;
717 n
= rb_first(&root_tree
->root
);
719 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
720 rb_erase(n
, &root_tree
->root
);
721 __free_btrfs_qgroup(entry
);
723 n
= rb_first(&root_tree
->root
);
727 static int filter_all_parent_insert(struct qgroup_lookup
*sort_tree
,
728 struct btrfs_qgroup
*bq
)
730 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
731 struct rb_node
*parent
= NULL
;
732 struct btrfs_qgroup
*curr
;
737 curr
= rb_entry(parent
, struct btrfs_qgroup
, all_parent_node
);
739 ret
= comp_entry_with_qgroupid(bq
, curr
, 0);
747 rb_link_node(&bq
->all_parent_node
, parent
, p
);
748 rb_insert_color(&bq
->all_parent_node
, &sort_tree
->root
);
752 static int filter_by_parent(struct btrfs_qgroup
*bq
, u64 data
)
754 struct btrfs_qgroup
*qgroup
=
755 (struct btrfs_qgroup
*)(unsigned long)data
;
759 if (qgroup
->qgroupid
== bq
->qgroupid
)
764 static int filter_by_all_parent(struct btrfs_qgroup
*bq
, u64 data
)
766 struct qgroup_lookup lookup
;
767 struct qgroup_lookup
*ql
= &lookup
;
768 struct btrfs_qgroup_list
*list
;
770 struct btrfs_qgroup
*qgroup
=
771 (struct btrfs_qgroup
*)(unsigned long)data
;
775 if (bq
->qgroupid
== qgroup
->qgroupid
)
778 qgroup_lookup_init(ql
);
779 filter_all_parent_insert(ql
, qgroup
);
780 n
= rb_first(&ql
->root
);
782 qgroup
= rb_entry(n
, struct btrfs_qgroup
, all_parent_node
);
783 if (!list_empty(&qgroup
->qgroups
)) {
784 list_for_each_entry(list
, &qgroup
->qgroups
,
786 if ((list
->qgroup
)->qgroupid
== bq
->qgroupid
)
788 filter_all_parent_insert(ql
, list
->qgroup
);
791 rb_erase(n
, &ql
->root
);
792 n
= rb_first(&ql
->root
);
797 static btrfs_qgroup_filter_func all_filter_funcs
[] = {
798 [BTRFS_QGROUP_FILTER_PARENT
] = filter_by_parent
,
799 [BTRFS_QGROUP_FILTER_ALL_PARENT
] = filter_by_all_parent
,
802 struct btrfs_qgroup_filter_set
*btrfs_qgroup_alloc_filter_set(void)
804 struct btrfs_qgroup_filter_set
*set
;
807 size
= sizeof(struct btrfs_qgroup_filter_set
) +
808 BTRFS_QGROUP_NFILTERS_INCREASE
*
809 sizeof(struct btrfs_qgroup_filter
);
810 set
= calloc(1, size
);
812 error("memory allocation failed");
815 set
->total
= BTRFS_QGROUP_NFILTERS_INCREASE
;
820 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set
**filter_set
,
821 enum btrfs_qgroup_filter_enum filter
, u64 data
)
823 struct btrfs_qgroup_filter_set
*set
= *filter_set
;
827 ASSERT(filter
< BTRFS_QGROUP_FILTER_MAX
);
828 ASSERT(set
->nfilters
<= set
->total
);
830 if (set
->nfilters
== set
->total
) {
833 size
= set
->total
+ BTRFS_QGROUP_NFILTERS_INCREASE
;
834 size
= sizeof(*set
) + size
* sizeof(struct btrfs_qgroup_filter
);
837 set
= realloc(set
, size
);
839 error("memory allocation failed");
843 memset(&set
->filters
[set
->total
], 0,
844 BTRFS_QGROUP_NFILTERS_INCREASE
*
845 sizeof(struct btrfs_qgroup_filter
));
846 set
->total
+= BTRFS_QGROUP_NFILTERS_INCREASE
;
850 ASSERT(set
->filters
[set
->nfilters
].filter_func
== NULL
);
851 set
->filters
[set
->nfilters
].filter_func
= all_filter_funcs
[filter
];
852 set
->filters
[set
->nfilters
].data
= data
;
857 static int filter_qgroup(struct btrfs_qgroup
*bq
,
858 struct btrfs_qgroup_filter_set
*set
)
862 if (!set
|| !set
->nfilters
)
864 for (i
= 0; i
< set
->nfilters
; i
++) {
865 if (!set
->filters
[i
].filter_func
)
867 ret
= set
->filters
[i
].filter_func(bq
, set
->filters
[i
].data
);
874 static void pre_process_filter_set(struct qgroup_lookup
*lookup
,
875 struct btrfs_qgroup_filter_set
*set
)
878 struct btrfs_qgroup
*qgroup_for_filter
= NULL
;
880 for (i
= 0; i
< set
->nfilters
; i
++) {
882 if (set
->filters
[i
].filter_func
== filter_by_all_parent
883 || set
->filters
[i
].filter_func
== filter_by_parent
) {
884 qgroup_for_filter
= qgroup_tree_search(lookup
,
885 set
->filters
[i
].data
);
886 set
->filters
[i
].data
=
887 (u64
)(unsigned long)qgroup_for_filter
;
892 static int sort_tree_insert(struct qgroup_lookup
*sort_tree
,
893 struct btrfs_qgroup
*bq
,
894 struct btrfs_qgroup_comparer_set
*comp_set
)
896 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
897 struct rb_node
*parent
= NULL
;
898 struct btrfs_qgroup
*curr
;
903 curr
= rb_entry(parent
, struct btrfs_qgroup
, sort_node
);
905 ret
= sort_comp(bq
, curr
, comp_set
);
913 rb_link_node(&bq
->sort_node
, parent
, p
);
914 rb_insert_color(&bq
->sort_node
, &sort_tree
->root
);
918 static void __update_columns_max_len(struct btrfs_qgroup
*bq
,
919 enum btrfs_qgroup_column_enum column
)
921 struct btrfs_qgroup_list
*list
= NULL
;
924 unsigned unit_mode
= btrfs_qgroup_columns
[column
].unit_mode
;
926 ASSERT(0 <= column
&& column
< BTRFS_QGROUP_ALL
);
930 case BTRFS_QGROUP_QGROUPID
:
931 sprintf(tmp
, "%llu/%llu",
932 btrfs_qgroup_level(bq
->qgroupid
),
933 btrfs_qgroup_subvid(bq
->qgroupid
));
935 if (btrfs_qgroup_columns
[column
].max_len
< len
)
936 btrfs_qgroup_columns
[column
].max_len
= len
;
938 case BTRFS_QGROUP_RFER
:
939 len
= strlen(pretty_size_mode(bq
->rfer
, unit_mode
));
940 if (btrfs_qgroup_columns
[column
].max_len
< len
)
941 btrfs_qgroup_columns
[column
].max_len
= len
;
943 case BTRFS_QGROUP_EXCL
:
944 len
= strlen(pretty_size_mode(bq
->excl
, unit_mode
));
945 if (btrfs_qgroup_columns
[column
].max_len
< len
)
946 btrfs_qgroup_columns
[column
].max_len
= len
;
948 case BTRFS_QGROUP_MAX_RFER
:
949 len
= strlen(pretty_size_mode(bq
->max_rfer
, unit_mode
));
950 if (btrfs_qgroup_columns
[column
].max_len
< len
)
951 btrfs_qgroup_columns
[column
].max_len
= len
;
953 case BTRFS_QGROUP_MAX_EXCL
:
954 len
= strlen(pretty_size_mode(bq
->max_excl
, unit_mode
));
955 if (btrfs_qgroup_columns
[column
].max_len
< len
)
956 btrfs_qgroup_columns
[column
].max_len
= len
;
958 case BTRFS_QGROUP_PARENT
:
960 list_for_each_entry(list
, &bq
->qgroups
, next_qgroup
) {
961 len
+= sprintf(tmp
, "%llu/%llu",
962 btrfs_qgroup_level(list
->qgroup
->qgroupid
),
963 btrfs_qgroup_subvid(list
->qgroup
->qgroupid
));
964 if (!list_is_last(&list
->next_qgroup
, &bq
->qgroups
))
967 if (btrfs_qgroup_columns
[column
].max_len
< len
)
968 btrfs_qgroup_columns
[column
].max_len
= len
;
970 case BTRFS_QGROUP_CHILD
:
972 list_for_each_entry(list
, &bq
->members
, next_member
) {
973 len
+= sprintf(tmp
, "%llu/%llu",
974 btrfs_qgroup_level(list
->member
->qgroupid
),
975 btrfs_qgroup_subvid(list
->member
->qgroupid
));
976 if (!list_is_last(&list
->next_member
, &bq
->members
))
979 if (btrfs_qgroup_columns
[column
].max_len
< len
)
980 btrfs_qgroup_columns
[column
].max_len
= len
;
988 static void update_columns_max_len(struct btrfs_qgroup
*bq
)
992 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
993 if (!btrfs_qgroup_columns
[i
].need_print
)
995 __update_columns_max_len(bq
, i
);
999 static void __filter_and_sort_qgroups(struct qgroup_lookup
*all_qgroups
,
1000 struct qgroup_lookup
*sort_tree
,
1001 struct btrfs_qgroup_filter_set
*filter_set
,
1002 struct btrfs_qgroup_comparer_set
*comp_set
)
1005 struct btrfs_qgroup
*entry
;
1008 qgroup_lookup_init(sort_tree
);
1009 pre_process_filter_set(all_qgroups
, filter_set
);
1011 n
= rb_last(&all_qgroups
->root
);
1013 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
1015 ret
= filter_qgroup(entry
, filter_set
);
1017 sort_tree_insert(sort_tree
, entry
, comp_set
);
1019 update_columns_max_len(entry
);
1025 static inline void print_status_flag_warning(u64 flags
)
1027 if (!(flags
& BTRFS_QGROUP_STATUS_FLAG_ON
))
1028 warning("quota disabled, qgroup data may be out of date");
1029 else if (flags
& BTRFS_QGROUP_STATUS_FLAG_RESCAN
)
1030 warning("rescan is running, qgroup data may be incorrect");
1031 else if (flags
& BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT
)
1032 warning("qgroup data inconsistent, rescan recommended");
1035 static int __qgroups_search(int fd
, struct qgroup_lookup
*qgroup_lookup
)
1038 struct btrfs_ioctl_search_args args
;
1039 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
1040 struct btrfs_ioctl_search_header
*sh
;
1041 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 /* the ioctl returns the number of item it found in nr_items */
1071 if (sk
->nr_items
== 0)
1076 * for each item, pull the key out of the header and then
1077 * read the root_ref item it contains
1079 for (i
= 0; i
< sk
->nr_items
; i
++) {
1080 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
1084 if (btrfs_search_header_type(sh
)
1085 == BTRFS_QGROUP_STATUS_KEY
) {
1086 struct btrfs_qgroup_status_item
*si
;
1089 si
= (struct btrfs_qgroup_status_item
*)
1091 flags
= btrfs_stack_qgroup_status_flags(si
);
1092 print_status_flag_warning(flags
);
1093 } else if (btrfs_search_header_type(sh
)
1094 == BTRFS_QGROUP_INFO_KEY
) {
1095 info
= (struct btrfs_qgroup_info_item
*)
1097 a1
= btrfs_stack_qgroup_info_generation(info
);
1098 a2
= btrfs_stack_qgroup_info_referenced(info
);
1100 btrfs_stack_qgroup_info_referenced_compressed
1102 a4
= btrfs_stack_qgroup_info_exclusive(info
);
1104 btrfs_stack_qgroup_info_exclusive_compressed
1106 add_qgroup(qgroup_lookup
,
1107 btrfs_search_header_offset(sh
), a1
,
1108 a2
, a3
, a4
, a5
, 0, 0, 0, 0, 0, NULL
,
1110 } else if (btrfs_search_header_type(sh
)
1111 == BTRFS_QGROUP_LIMIT_KEY
) {
1112 limit
= (struct btrfs_qgroup_limit_item
*)
1115 a1
= btrfs_stack_qgroup_limit_flags(limit
);
1116 a2
= btrfs_stack_qgroup_limit_max_referenced
1118 a3
= btrfs_stack_qgroup_limit_max_exclusive
1120 a4
= btrfs_stack_qgroup_limit_rsv_referenced
1122 a5
= btrfs_stack_qgroup_limit_rsv_exclusive
1124 add_qgroup(qgroup_lookup
,
1125 btrfs_search_header_offset(sh
), 0,
1126 0, 0, 0, 0, a1
, a2
, a3
, a4
, a5
,
1128 } else if (btrfs_search_header_type(sh
)
1129 == BTRFS_QGROUP_RELATION_KEY
) {
1130 if (btrfs_search_header_offset(sh
)
1131 < btrfs_search_header_objectid(sh
))
1133 bq
= qgroup_tree_search(qgroup_lookup
,
1134 btrfs_search_header_offset(sh
));
1137 bq1
= qgroup_tree_search(qgroup_lookup
,
1138 btrfs_search_header_objectid(sh
));
1141 add_qgroup(qgroup_lookup
,
1142 btrfs_search_header_offset(sh
), 0,
1143 0, 0, 0, 0, 0, 0, 0, 0, 0, bq
, bq1
);
1147 off
+= btrfs_search_header_len(sh
);
1150 * record the mins in sk so we can make sure the
1151 * next search doesn't repeat this root
1153 sk
->min_type
= btrfs_search_header_type(sh
);
1154 sk
->min_offset
= btrfs_search_header_offset(sh
);
1155 sk
->min_objectid
= btrfs_search_header_objectid(sh
);
1157 sk
->nr_items
= 4096;
1159 * this iteration is done, step forward one qgroup for the next
1162 if (sk
->min_offset
< (u64
)-1)
1172 static void print_all_qgroups(struct qgroup_lookup
*qgroup_lookup
)
1176 struct btrfs_qgroup
*entry
;
1180 n
= rb_first(&qgroup_lookup
->root
);
1182 entry
= rb_entry(n
, struct btrfs_qgroup
, sort_node
);
1183 print_single_qgroup_table(entry
);
1188 int btrfs_show_qgroups(int fd
,
1189 struct btrfs_qgroup_filter_set
*filter_set
,
1190 struct btrfs_qgroup_comparer_set
*comp_set
)
1193 struct qgroup_lookup qgroup_lookup
;
1194 struct qgroup_lookup sort_tree
;
1197 ret
= __qgroups_search(fd
, &qgroup_lookup
);
1200 __filter_and_sort_qgroups(&qgroup_lookup
, &sort_tree
,
1201 filter_set
, comp_set
);
1202 print_all_qgroups(&sort_tree
);
1204 __free_all_qgroups(&qgroup_lookup
);
1210 int btrfs_qgroup_parse_sort_string(const char *opt_arg
,
1211 struct btrfs_qgroup_comparer_set
**comps
)
1221 opt_tmp
= strdup(opt_arg
);
1225 while ((p
= strtok(opt_tmp
, ",")) != NULL
) {
1227 ptr_argv
= all_sort_items
;
1230 if (strcmp(*ptr_argv
, p
) == 0) {
1235 if (strcmp(*ptr_argv
, p
) == 0) {
1252 } else if (*p
== '-') {
1258 what_to_sort
= btrfs_qgroup_get_sort_item(p
);
1259 if (what_to_sort
< 0) {
1263 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 error("not enough memory");
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 error("invalid qgroup specification, qgroupid must not 0");
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 error("invalid copy specification, missing separator :");
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
;