2 * Copyright (C) 2012 STRATO. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
20 #include <sys/ioctl.h>
26 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
27 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
29 struct qgroup_lookup
{
34 struct rb_node rb_node
;
35 struct rb_node sort_node
;
37 *all_parent_node is used to
38 *filter a qgroup's all parent
40 struct rb_node all_parent_node
;
47 u64 rfer
; /*referenced*/
48 u64 rfer_cmpr
; /*referenced compressed*/
49 u64 excl
; /*exclusive*/
50 u64 excl_cmpr
; /*exclusive compressed*/
55 u64 flags
; /*which limits are set*/
61 /*qgroups this group is member of*/
62 struct list_head qgroups
;
63 /*qgroups that are members of this group*/
64 struct list_head members
;
68 * glue structure to represent the relations
71 struct btrfs_qgroup_list
{
72 struct list_head next_qgroup
;
73 struct list_head next_member
;
74 struct btrfs_qgroup
*qgroup
;
75 struct btrfs_qgroup
*member
;
79 * qgroupid,rfer,excl default to set
87 } btrfs_qgroup_columns
[] = {
90 .column_name
= "Qgroupid",
97 .column_name
= "Rfer",
99 .unit_mode
= UNITS_DEFAULT
,
104 .column_name
= "Excl",
106 .unit_mode
= UNITS_DEFAULT
,
109 { .name
= "max_rfer",
110 .column_name
= "Max_rfer",
112 .unit_mode
= UNITS_DEFAULT
,
117 .column_name
= "Max_excl",
119 .unit_mode
= UNITS_DEFAULT
,
124 .column_name
= "Parent",
131 .column_name
= "Child",
144 static btrfs_qgroup_filter_func all_filter_funcs
[];
145 static btrfs_qgroup_comp_func all_comp_funcs
[];
147 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column
)
151 BUG_ON(column
< 0 || column
> BTRFS_QGROUP_ALL
);
153 if (column
< BTRFS_QGROUP_ALL
) {
154 btrfs_qgroup_columns
[column
].need_print
= 1;
157 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++)
158 btrfs_qgroup_columns
[i
].need_print
= 1;
161 void btrfs_qgroup_setup_units(unsigned unit_mode
)
163 btrfs_qgroup_columns
[BTRFS_QGROUP_RFER
].unit_mode
= unit_mode
;
164 btrfs_qgroup_columns
[BTRFS_QGROUP_EXCL
].unit_mode
= unit_mode
;
165 btrfs_qgroup_columns
[BTRFS_QGROUP_MAX_RFER
].unit_mode
= unit_mode
;
166 btrfs_qgroup_columns
[BTRFS_QGROUP_MAX_EXCL
].unit_mode
= unit_mode
;
169 static int print_parent_column(struct btrfs_qgroup
*qgroup
)
171 struct btrfs_qgroup_list
*list
= NULL
;
174 list_for_each_entry(list
, &qgroup
->qgroups
, next_qgroup
) {
175 len
+= printf("%llu/%llu",
176 btrfs_qgroup_level(list
->qgroup
->qgroupid
),
177 btrfs_qgroup_subvid(list
->qgroup
->qgroupid
));
178 if (!list_is_last(&list
->next_qgroup
, &qgroup
->qgroups
))
181 if (list_empty(&qgroup
->qgroups
))
182 len
+= printf("---");
187 static int print_child_column(struct btrfs_qgroup
*qgroup
)
189 struct btrfs_qgroup_list
*list
= NULL
;
192 list_for_each_entry(list
, &qgroup
->members
, next_member
) {
193 len
+= printf("%llu/%llu",
194 btrfs_qgroup_level(list
->member
->qgroupid
),
195 btrfs_qgroup_subvid(list
->member
->qgroupid
));
196 if (!list_is_last(&list
->next_member
, &qgroup
->members
))
199 if (list_empty(&qgroup
->members
))
200 len
+= printf("---");
205 static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column
,
208 len
= btrfs_qgroup_columns
[column
].max_len
- len
;
213 static void print_qgroup_column(struct btrfs_qgroup
*qgroup
,
214 enum btrfs_qgroup_column_enum column
)
216 BUG_ON(column
>= BTRFS_QGROUP_ALL
|| column
< 0);
218 int unit_mode
= btrfs_qgroup_columns
[column
].unit_mode
;
219 int max_len
= btrfs_qgroup_columns
[column
].max_len
;
223 case BTRFS_QGROUP_QGROUPID
:
224 len
= printf("%llu/%llu",
225 btrfs_qgroup_level(qgroup
->qgroupid
),
226 btrfs_qgroup_subvid(qgroup
->qgroupid
));
227 print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID
, len
);
229 case BTRFS_QGROUP_RFER
:
230 len
= printf("%*s", max_len
, pretty_size_mode(qgroup
->rfer
, unit_mode
));
232 case BTRFS_QGROUP_EXCL
:
233 len
= printf("%*s", max_len
, pretty_size_mode(qgroup
->excl
, unit_mode
));
235 case BTRFS_QGROUP_PARENT
:
236 len
= print_parent_column(qgroup
);
237 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT
, len
);
239 case BTRFS_QGROUP_MAX_RFER
:
240 if (qgroup
->flags
& BTRFS_QGROUP_LIMIT_MAX_RFER
)
241 len
= printf("%*s", max_len
, pretty_size_mode(qgroup
->max_rfer
, unit_mode
));
243 len
= printf("%*s", max_len
, "none");
245 case BTRFS_QGROUP_MAX_EXCL
:
246 if (qgroup
->flags
& BTRFS_QGROUP_LIMIT_MAX_EXCL
)
247 len
= printf("%*s", max_len
, pretty_size_mode(qgroup
->max_excl
, unit_mode
));
249 len
= printf("%*s", max_len
, "none");
251 case BTRFS_QGROUP_CHILD
:
252 len
= print_child_column(qgroup
);
253 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD
, len
);
260 static void print_single_qgroup_table(struct btrfs_qgroup
*qgroup
)
264 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
265 if (!btrfs_qgroup_columns
[i
].need_print
)
267 print_qgroup_column(qgroup
, i
);
269 if (i
!= BTRFS_QGROUP_CHILD
)
275 static void print_table_head(void)
281 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
282 max_len
= btrfs_qgroup_columns
[i
].max_len
;
283 if (!btrfs_qgroup_columns
[i
].need_print
)
285 if ((i
== BTRFS_QGROUP_QGROUPID
) | (i
== BTRFS_QGROUP_PARENT
) |
286 (i
== BTRFS_QGROUP_CHILD
))
287 printf("%-*s", max_len
, btrfs_qgroup_columns
[i
].name
);
289 printf("%*s", max_len
, btrfs_qgroup_columns
[i
].name
);
293 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
294 max_len
= btrfs_qgroup_columns
[i
].max_len
;
295 if (!btrfs_qgroup_columns
[i
].need_print
)
297 if ((i
== BTRFS_QGROUP_QGROUPID
) | (i
== BTRFS_QGROUP_PARENT
) |
298 (i
== BTRFS_QGROUP_CHILD
)) {
299 len
= strlen(btrfs_qgroup_columns
[i
].name
);
302 len
= max_len
- strlen(btrfs_qgroup_columns
[i
].name
);
306 len
= max_len
- strlen(btrfs_qgroup_columns
[i
].name
);
309 len
= strlen(btrfs_qgroup_columns
[i
].name
);
318 static void qgroup_lookup_init(struct qgroup_lookup
*tree
)
320 tree
->root
.rb_node
= NULL
;
323 static int comp_entry_with_qgroupid(struct btrfs_qgroup
*entry1
,
324 struct btrfs_qgroup
*entry2
,
330 if (entry1
->qgroupid
> entry2
->qgroupid
)
332 else if (entry1
->qgroupid
< entry2
->qgroupid
)
337 return is_descending
? -ret
: ret
;
340 static int comp_entry_with_rfer(struct btrfs_qgroup
*entry1
,
341 struct btrfs_qgroup
*entry2
,
346 if (entry1
->rfer
> entry2
->rfer
)
348 else if (entry1
->rfer
< entry2
->rfer
)
353 return is_descending
? -ret
: ret
;
356 static int comp_entry_with_excl(struct btrfs_qgroup
*entry1
,
357 struct btrfs_qgroup
*entry2
,
362 if (entry1
->excl
> entry2
->excl
)
364 else if (entry1
->excl
< entry2
->excl
)
369 return is_descending
? -ret
: ret
;
372 static int comp_entry_with_max_rfer(struct btrfs_qgroup
*entry1
,
373 struct btrfs_qgroup
*entry2
,
378 if (entry1
->max_rfer
> entry2
->max_rfer
)
380 else if (entry1
->max_rfer
< entry2
->max_rfer
)
385 return is_descending
? -ret
: ret
;
388 static int comp_entry_with_max_excl(struct btrfs_qgroup
*entry1
,
389 struct btrfs_qgroup
*entry2
,
394 if (entry1
->max_excl
> entry2
->max_excl
)
396 else if (entry1
->max_excl
< entry2
->max_excl
)
401 return is_descending
? -ret
: ret
;
404 static btrfs_qgroup_comp_func all_comp_funcs
[] = {
405 [BTRFS_QGROUP_COMP_QGROUPID
] = comp_entry_with_qgroupid
,
406 [BTRFS_QGROUP_COMP_RFER
] = comp_entry_with_rfer
,
407 [BTRFS_QGROUP_COMP_EXCL
] = comp_entry_with_excl
,
408 [BTRFS_QGROUP_COMP_MAX_RFER
] = comp_entry_with_max_rfer
,
409 [BTRFS_QGROUP_COMP_MAX_EXCL
] = comp_entry_with_max_excl
412 static char *all_sort_items
[] = {
413 [BTRFS_QGROUP_COMP_QGROUPID
] = "qgroupid",
414 [BTRFS_QGROUP_COMP_RFER
] = "rfer",
415 [BTRFS_QGROUP_COMP_EXCL
] = "excl",
416 [BTRFS_QGROUP_COMP_MAX_RFER
] = "max_rfer",
417 [BTRFS_QGROUP_COMP_MAX_EXCL
] = "max_excl",
418 [BTRFS_QGROUP_COMP_MAX
] = NULL
,
421 static int btrfs_qgroup_get_sort_item(char *sort_name
)
425 for (i
= 0; i
< BTRFS_QGROUP_COMP_MAX
; i
++) {
426 if (strcmp(sort_name
, all_sort_items
[i
]) == 0)
432 struct btrfs_qgroup_comparer_set
*btrfs_qgroup_alloc_comparer_set(void)
434 struct btrfs_qgroup_comparer_set
*set
;
436 size
= sizeof(struct btrfs_qgroup_comparer_set
) +
437 BTRFS_QGROUP_NCOMPS_INCREASE
*
438 sizeof(struct btrfs_qgroup_comparer
);
439 set
= calloc(1, size
);
441 fprintf(stderr
, "memory allocation failed\n");
445 set
->total
= BTRFS_QGROUP_NCOMPS_INCREASE
;
450 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set
*comp_set
)
455 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set
**comp_set
,
456 enum btrfs_qgroup_comp_enum comparer
,
459 struct btrfs_qgroup_comparer_set
*set
= *comp_set
;
463 BUG_ON(comparer
>= BTRFS_QGROUP_COMP_MAX
);
464 BUG_ON(set
->ncomps
> set
->total
);
466 if (set
->ncomps
== set
->total
) {
469 size
= set
->total
+ BTRFS_QGROUP_NCOMPS_INCREASE
;
470 size
= sizeof(*set
) +
471 size
* sizeof(struct btrfs_qgroup_comparer
);
473 set
= realloc(set
, size
);
475 fprintf(stderr
, "memory allocation failed\n");
480 memset(&set
->comps
[set
->total
], 0,
481 BTRFS_QGROUP_NCOMPS_INCREASE
*
482 sizeof(struct btrfs_qgroup_comparer
));
483 set
->total
+= BTRFS_QGROUP_NCOMPS_INCREASE
;
487 BUG_ON(set
->comps
[set
->ncomps
].comp_func
);
489 set
->comps
[set
->ncomps
].comp_func
= all_comp_funcs
[comparer
];
490 set
->comps
[set
->ncomps
].is_descending
= is_descending
;
495 static int sort_comp(struct btrfs_qgroup
*entry1
, struct btrfs_qgroup
*entry2
,
496 struct btrfs_qgroup_comparer_set
*set
)
498 int qgroupid_compared
= 0;
501 if (!set
|| !set
->ncomps
)
504 for (i
= 0; i
< set
->ncomps
; i
++) {
505 if (!set
->comps
[i
].comp_func
)
508 ret
= set
->comps
[i
].comp_func(entry1
, entry2
,
509 set
->comps
[i
].is_descending
);
513 if (set
->comps
[i
].comp_func
== comp_entry_with_qgroupid
)
514 qgroupid_compared
= 1;
517 if (!qgroupid_compared
) {
519 ret
= comp_entry_with_qgroupid(entry1
, entry2
, 0);
526 * insert a new root into the tree. returns the existing root entry
527 * if one is already there. qgroupid is used
530 static int qgroup_tree_insert(struct qgroup_lookup
*root_tree
,
531 struct btrfs_qgroup
*ins
)
534 struct rb_node
**p
= &root_tree
->root
.rb_node
;
535 struct rb_node
*parent
= NULL
;
536 struct btrfs_qgroup
*curr
;
541 curr
= rb_entry(parent
, struct btrfs_qgroup
, rb_node
);
543 ret
= comp_entry_with_qgroupid(ins
, curr
, 0);
551 rb_link_node(&ins
->rb_node
, parent
, p
);
552 rb_insert_color(&ins
->rb_node
, &root_tree
->root
);
557 *find a given qgroupid in the tree. We return the smallest one,
558 *rb_next can be used to move forward looking for more if required
560 static struct btrfs_qgroup
*qgroup_tree_search(struct qgroup_lookup
*root_tree
,
563 struct rb_node
*n
= root_tree
->root
.rb_node
;
564 struct btrfs_qgroup
*entry
;
565 struct btrfs_qgroup tmp
;
568 tmp
.qgroupid
= qgroupid
;
571 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
573 ret
= comp_entry_with_qgroupid(&tmp
, entry
, 0);
585 static int update_qgroup(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
586 u64 generation
, u64 rfer
, u64 rfer_cmpr
, u64 excl
,
587 u64 excl_cmpr
, u64 flags
, u64 max_rfer
, u64 max_excl
,
588 u64 rsv_rfer
, u64 rsv_excl
, struct btrfs_qgroup
*pa
,
589 struct btrfs_qgroup
*child
)
591 struct btrfs_qgroup
*bq
;
592 struct btrfs_qgroup_list
*list
;
594 bq
= qgroup_tree_search(qgroup_lookup
, qgroupid
);
595 if (!bq
|| bq
->qgroupid
!= qgroupid
)
599 bq
->generation
= generation
;
603 bq
->rfer_cmpr
= rfer_cmpr
;
607 bq
->excl_cmpr
= excl_cmpr
;
611 bq
->max_rfer
= max_rfer
;
613 bq
->max_excl
= max_excl
;
615 bq
->rsv_rfer
= rsv_rfer
;
617 list
= malloc(sizeof(*list
));
619 fprintf(stderr
, "memory allocation failed\n");
623 list
->member
= child
;
624 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
625 list_add_tail(&list
->next_member
, &pa
->members
);
630 static int add_qgroup(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
631 u64 generation
, u64 rfer
, u64 rfer_cmpr
, u64 excl
,
632 u64 excl_cmpr
, u64 flags
, u64 max_rfer
, u64 max_excl
,
633 u64 rsv_rfer
, u64 rsv_excl
, struct btrfs_qgroup
*parent
,
634 struct btrfs_qgroup
*child
)
636 struct btrfs_qgroup
*bq
;
637 struct btrfs_qgroup_list
*list
;
640 ret
= update_qgroup(qgroup_lookup
, qgroupid
, generation
, rfer
,
641 rfer_cmpr
, excl
, excl_cmpr
, flags
, max_rfer
,
642 max_excl
, rsv_rfer
, rsv_excl
, parent
, child
);
646 bq
= calloc(1, sizeof(*bq
));
648 printf("memory allocation failed\n");
652 bq
->qgroupid
= qgroupid
;
653 INIT_LIST_HEAD(&bq
->qgroups
);
654 INIT_LIST_HEAD(&bq
->members
);
657 bq
->generation
= generation
;
661 bq
->rfer_cmpr
= rfer_cmpr
;
665 bq
->excl_cmpr
= excl_cmpr
;
669 bq
->max_rfer
= max_rfer
;
671 bq
->max_excl
= max_excl
;
673 bq
->rsv_rfer
= rsv_rfer
;
674 if (parent
&& child
) {
675 list
= malloc(sizeof(*list
));
677 fprintf(stderr
, "memory allocation failed\n");
680 list
->qgroup
= parent
;
681 list
->member
= child
;
682 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
683 list_add_tail(&list
->next_member
, &parent
->members
);
685 ret
= qgroup_tree_insert(qgroup_lookup
, bq
);
687 printf("failed to insert tree %llu\n",
694 static void __free_btrfs_qgroup(struct btrfs_qgroup
*bq
)
696 struct btrfs_qgroup_list
*list
;
697 while (!list_empty(&bq
->qgroups
)) {
698 list
= list_entry((&bq
->qgroups
)->next
,
699 struct btrfs_qgroup_list
,
701 list_del(&list
->next_qgroup
);
702 list_del(&list
->next_member
);
705 while (!list_empty(&bq
->members
)) {
706 list
= list_entry((&bq
->members
)->next
,
707 struct btrfs_qgroup_list
,
709 list_del(&list
->next_qgroup
);
710 list_del(&list
->next_member
);
716 static void __free_all_qgroups(struct qgroup_lookup
*root_tree
)
718 struct btrfs_qgroup
*entry
;
721 n
= rb_first(&root_tree
->root
);
723 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
724 rb_erase(n
, &root_tree
->root
);
725 __free_btrfs_qgroup(entry
);
727 n
= rb_first(&root_tree
->root
);
731 static int filter_all_parent_insert(struct qgroup_lookup
*sort_tree
,
732 struct btrfs_qgroup
*bq
)
734 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
735 struct rb_node
*parent
= NULL
;
736 struct btrfs_qgroup
*curr
;
741 curr
= rb_entry(parent
, struct btrfs_qgroup
, all_parent_node
);
743 ret
= comp_entry_with_qgroupid(bq
, curr
, 0);
751 rb_link_node(&bq
->all_parent_node
, parent
, p
);
752 rb_insert_color(&bq
->all_parent_node
, &sort_tree
->root
);
756 static int filter_by_parent(struct btrfs_qgroup
*bq
, u64 data
)
758 struct btrfs_qgroup
*qgroup
=
759 (struct btrfs_qgroup
*)(unsigned long)data
;
763 if (qgroup
->qgroupid
== bq
->qgroupid
)
768 static int filter_by_all_parent(struct btrfs_qgroup
*bq
, u64 data
)
770 struct qgroup_lookup lookup
;
771 struct qgroup_lookup
*ql
= &lookup
;
772 struct btrfs_qgroup_list
*list
;
774 struct btrfs_qgroup
*qgroup
=
775 (struct btrfs_qgroup
*)(unsigned long)data
;
779 if (bq
->qgroupid
== qgroup
->qgroupid
)
782 qgroup_lookup_init(ql
);
783 filter_all_parent_insert(ql
, qgroup
);
784 n
= rb_first(&ql
->root
);
786 qgroup
= rb_entry(n
, struct btrfs_qgroup
, all_parent_node
);
787 if (!list_empty(&qgroup
->qgroups
)) {
788 list_for_each_entry(list
, &qgroup
->qgroups
,
790 if ((list
->qgroup
)->qgroupid
== bq
->qgroupid
)
792 filter_all_parent_insert(ql
, list
->qgroup
);
795 rb_erase(n
, &ql
->root
);
796 n
= rb_first(&ql
->root
);
801 static btrfs_qgroup_filter_func all_filter_funcs
[] = {
802 [BTRFS_QGROUP_FILTER_PARENT
] = filter_by_parent
,
803 [BTRFS_QGROUP_FILTER_ALL_PARENT
] = filter_by_all_parent
,
806 struct btrfs_qgroup_filter_set
*btrfs_qgroup_alloc_filter_set(void)
808 struct btrfs_qgroup_filter_set
*set
;
811 size
= sizeof(struct btrfs_qgroup_filter_set
) +
812 BTRFS_QGROUP_NFILTERS_INCREASE
*
813 sizeof(struct btrfs_qgroup_filter
);
814 set
= calloc(1, size
);
816 fprintf(stderr
, "memory allocation failed\n");
819 set
->total
= BTRFS_QGROUP_NFILTERS_INCREASE
;
824 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set
*filter_set
)
829 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set
**filter_set
,
830 enum btrfs_qgroup_filter_enum filter
, u64 data
)
832 struct btrfs_qgroup_filter_set
*set
= *filter_set
;
836 BUG_ON(filter
>= BTRFS_QGROUP_FILTER_MAX
);
837 BUG_ON(set
->nfilters
> set
->total
);
839 if (set
->nfilters
== set
->total
) {
842 size
= set
->total
+ BTRFS_QGROUP_NFILTERS_INCREASE
;
843 size
= sizeof(*set
) + size
* sizeof(struct btrfs_qgroup_filter
);
846 set
= realloc(set
, size
);
848 fprintf(stderr
, "memory allocation failed\n");
852 memset(&set
->filters
[set
->total
], 0,
853 BTRFS_QGROUP_NFILTERS_INCREASE
*
854 sizeof(struct btrfs_qgroup_filter
));
855 set
->total
+= BTRFS_QGROUP_NFILTERS_INCREASE
;
858 BUG_ON(set
->filters
[set
->nfilters
].filter_func
);
859 set
->filters
[set
->nfilters
].filter_func
= all_filter_funcs
[filter
];
860 set
->filters
[set
->nfilters
].data
= data
;
865 static int filter_qgroup(struct btrfs_qgroup
*bq
,
866 struct btrfs_qgroup_filter_set
*set
)
870 if (!set
|| !set
->nfilters
)
872 for (i
= 0; i
< set
->nfilters
; i
++) {
873 if (!set
->filters
[i
].filter_func
)
875 ret
= set
->filters
[i
].filter_func(bq
, set
->filters
[i
].data
);
882 static void pre_process_filter_set(struct qgroup_lookup
*lookup
,
883 struct btrfs_qgroup_filter_set
*set
)
886 struct btrfs_qgroup
*qgroup_for_filter
= NULL
;
888 for (i
= 0; i
< set
->nfilters
; i
++) {
890 if (set
->filters
[i
].filter_func
== filter_by_all_parent
891 || set
->filters
[i
].filter_func
== filter_by_parent
) {
892 qgroup_for_filter
= qgroup_tree_search(lookup
,
893 set
->filters
[i
].data
);
894 set
->filters
[i
].data
=
895 (u64
)(unsigned long)qgroup_for_filter
;
900 static int sort_tree_insert(struct qgroup_lookup
*sort_tree
,
901 struct btrfs_qgroup
*bq
,
902 struct btrfs_qgroup_comparer_set
*comp_set
)
904 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
905 struct rb_node
*parent
= NULL
;
906 struct btrfs_qgroup
*curr
;
911 curr
= rb_entry(parent
, struct btrfs_qgroup
, sort_node
);
913 ret
= sort_comp(bq
, curr
, comp_set
);
921 rb_link_node(&bq
->sort_node
, parent
, p
);
922 rb_insert_color(&bq
->sort_node
, &sort_tree
->root
);
926 static void __update_columns_max_len(struct btrfs_qgroup
*bq
,
927 enum btrfs_qgroup_column_enum column
)
929 BUG_ON(column
>= BTRFS_QGROUP_ALL
|| column
< 0);
930 struct btrfs_qgroup_list
*list
= NULL
;
933 unsigned unit_mode
= btrfs_qgroup_columns
[column
].unit_mode
;
937 case BTRFS_QGROUP_QGROUPID
:
938 sprintf(tmp
, "%llu/%llu",
939 btrfs_qgroup_level(bq
->qgroupid
),
940 btrfs_qgroup_subvid(bq
->qgroupid
));
942 if (btrfs_qgroup_columns
[column
].max_len
< len
)
943 btrfs_qgroup_columns
[column
].max_len
= len
;
945 case BTRFS_QGROUP_RFER
:
946 len
= strlen(pretty_size_mode(bq
->rfer
, unit_mode
));
947 if (btrfs_qgroup_columns
[column
].max_len
< len
)
948 btrfs_qgroup_columns
[column
].max_len
= len
;
950 case BTRFS_QGROUP_EXCL
:
951 len
= strlen(pretty_size_mode(bq
->excl
, unit_mode
));
952 if (btrfs_qgroup_columns
[column
].max_len
< len
)
953 btrfs_qgroup_columns
[column
].max_len
= len
;
955 case BTRFS_QGROUP_MAX_RFER
:
956 len
= strlen(pretty_size_mode(bq
->max_rfer
, unit_mode
));
957 if (btrfs_qgroup_columns
[column
].max_len
< len
)
958 btrfs_qgroup_columns
[column
].max_len
= len
;
960 case BTRFS_QGROUP_MAX_EXCL
:
961 len
= strlen(pretty_size_mode(bq
->max_excl
, unit_mode
));
962 if (btrfs_qgroup_columns
[column
].max_len
< len
)
963 btrfs_qgroup_columns
[column
].max_len
= len
;
965 case BTRFS_QGROUP_PARENT
:
967 list_for_each_entry(list
, &bq
->qgroups
, next_qgroup
) {
968 len
+= sprintf(tmp
, "%llu/%llu",
969 btrfs_qgroup_level(list
->qgroup
->qgroupid
),
970 btrfs_qgroup_subvid(list
->qgroup
->qgroupid
));
971 if (!list_is_last(&list
->next_qgroup
, &bq
->qgroups
))
974 if (btrfs_qgroup_columns
[column
].max_len
< len
)
975 btrfs_qgroup_columns
[column
].max_len
= len
;
977 case BTRFS_QGROUP_CHILD
:
979 list_for_each_entry(list
, &bq
->members
, next_member
) {
980 len
+= sprintf(tmp
, "%llu/%llu",
981 btrfs_qgroup_level(list
->member
->qgroupid
),
982 btrfs_qgroup_subvid(list
->member
->qgroupid
));
983 if (!list_is_last(&list
->next_member
, &bq
->members
))
986 if (btrfs_qgroup_columns
[column
].max_len
< len
)
987 btrfs_qgroup_columns
[column
].max_len
= len
;
995 static void update_columns_max_len(struct btrfs_qgroup
*bq
)
999 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
1000 if (!btrfs_qgroup_columns
[i
].need_print
)
1002 __update_columns_max_len(bq
, i
);
1006 static void __filter_and_sort_qgroups(struct qgroup_lookup
*all_qgroups
,
1007 struct qgroup_lookup
*sort_tree
,
1008 struct btrfs_qgroup_filter_set
*filter_set
,
1009 struct btrfs_qgroup_comparer_set
*comp_set
)
1012 struct btrfs_qgroup
*entry
;
1015 qgroup_lookup_init(sort_tree
);
1016 pre_process_filter_set(all_qgroups
, filter_set
);
1018 n
= rb_last(&all_qgroups
->root
);
1020 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
1022 ret
= filter_qgroup(entry
, filter_set
);
1024 sort_tree_insert(sort_tree
, entry
, comp_set
);
1026 update_columns_max_len(entry
);
1032 static inline void print_status_flag_warning(u64 flags
)
1034 if (!(flags
& BTRFS_QGROUP_STATUS_FLAG_ON
))
1036 "WARNING: Quota disabled, qgroup data may be out of date\n");
1037 else if (flags
& BTRFS_QGROUP_STATUS_FLAG_RESCAN
)
1039 "WARNING: Rescan is running, qgroup data may be incorrect\n");
1040 else if (flags
& BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT
)
1042 "WARNING: Qgroup data inconsistent, rescan recommended\n");
1045 static int __qgroups_search(int fd
, struct qgroup_lookup
*qgroup_lookup
)
1048 struct btrfs_ioctl_search_args args
;
1049 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
1050 struct btrfs_ioctl_search_header
*sh
;
1051 unsigned long off
= 0;
1053 struct btrfs_qgroup_info_item
*info
;
1054 struct btrfs_qgroup_limit_item
*limit
;
1055 struct btrfs_qgroup
*bq
;
1056 struct btrfs_qgroup
*bq1
;
1063 memset(&args
, 0, sizeof(args
));
1065 sk
->tree_id
= BTRFS_QUOTA_TREE_OBJECTID
;
1066 sk
->max_type
= BTRFS_QGROUP_RELATION_KEY
;
1067 sk
->min_type
= BTRFS_QGROUP_STATUS_KEY
;
1068 sk
->max_objectid
= (u64
)-1;
1069 sk
->max_offset
= (u64
)-1;
1070 sk
->max_transid
= (u64
)-1;
1071 sk
->nr_items
= 4096;
1073 qgroup_lookup_init(qgroup_lookup
);
1076 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
1079 "ERROR: can't perform the search - %s\n",
1083 /* the ioctl returns the number of item it found in nr_items */
1084 if (sk
->nr_items
== 0)
1089 * for each item, pull the key out of the header and then
1090 * read the root_ref item it contains
1092 for (i
= 0; i
< sk
->nr_items
; i
++) {
1093 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
1097 if (btrfs_search_header_type(sh
)
1098 == BTRFS_QGROUP_STATUS_KEY
) {
1099 struct btrfs_qgroup_status_item
*si
;
1102 si
= (struct btrfs_qgroup_status_item
*)
1104 flags
= btrfs_stack_qgroup_status_flags(si
);
1105 print_status_flag_warning(flags
);
1106 } else if (btrfs_search_header_type(sh
)
1107 == BTRFS_QGROUP_INFO_KEY
) {
1108 info
= (struct btrfs_qgroup_info_item
*)
1110 a1
= btrfs_stack_qgroup_info_generation(info
);
1111 a2
= btrfs_stack_qgroup_info_referenced(info
);
1113 btrfs_stack_qgroup_info_referenced_compressed
1115 a4
= btrfs_stack_qgroup_info_exclusive(info
);
1117 btrfs_stack_qgroup_info_exclusive_compressed
1119 add_qgroup(qgroup_lookup
,
1120 btrfs_search_header_offset(sh
), a1
,
1121 a2
, a3
, a4
, a5
, 0, 0, 0, 0, 0, NULL
,
1123 } else if (btrfs_search_header_type(sh
)
1124 == BTRFS_QGROUP_LIMIT_KEY
) {
1125 limit
= (struct btrfs_qgroup_limit_item
*)
1128 a1
= btrfs_stack_qgroup_limit_flags(limit
);
1129 a2
= btrfs_stack_qgroup_limit_max_referenced
1131 a3
= btrfs_stack_qgroup_limit_max_exclusive
1133 a4
= btrfs_stack_qgroup_limit_rsv_referenced
1135 a5
= btrfs_stack_qgroup_limit_rsv_exclusive
1137 add_qgroup(qgroup_lookup
,
1138 btrfs_search_header_offset(sh
), 0,
1139 0, 0, 0, 0, a1
, a2
, a3
, a4
, a5
,
1141 } else if (btrfs_search_header_type(sh
)
1142 == BTRFS_QGROUP_RELATION_KEY
) {
1143 if (btrfs_search_header_offset(sh
)
1144 < btrfs_search_header_objectid(sh
))
1146 bq
= qgroup_tree_search(qgroup_lookup
,
1147 btrfs_search_header_offset(sh
));
1150 bq1
= qgroup_tree_search(qgroup_lookup
,
1151 btrfs_search_header_objectid(sh
));
1154 add_qgroup(qgroup_lookup
,
1155 btrfs_search_header_offset(sh
), 0,
1156 0, 0, 0, 0, 0, 0, 0, 0, 0, bq
, bq1
);
1160 off
+= btrfs_search_header_len(sh
);
1163 * record the mins in sk so we can make sure the
1164 * next search doesn't repeat this root
1166 sk
->min_type
= btrfs_search_header_type(sh
);
1167 sk
->min_offset
= btrfs_search_header_offset(sh
);
1168 sk
->min_objectid
= btrfs_search_header_objectid(sh
);
1170 sk
->nr_items
= 4096;
1172 * this iteration is done, step forward one qgroup for the next
1175 if (sk
->min_offset
< (u64
)-1)
1185 static void print_all_qgroups(struct qgroup_lookup
*qgroup_lookup
)
1189 struct btrfs_qgroup
*entry
;
1193 n
= rb_first(&qgroup_lookup
->root
);
1195 entry
= rb_entry(n
, struct btrfs_qgroup
, sort_node
);
1196 print_single_qgroup_table(entry
);
1201 int btrfs_show_qgroups(int fd
,
1202 struct btrfs_qgroup_filter_set
*filter_set
,
1203 struct btrfs_qgroup_comparer_set
*comp_set
)
1206 struct qgroup_lookup qgroup_lookup
;
1207 struct qgroup_lookup sort_tree
;
1210 ret
= __qgroups_search(fd
, &qgroup_lookup
);
1213 __filter_and_sort_qgroups(&qgroup_lookup
, &sort_tree
,
1214 filter_set
, comp_set
);
1215 print_all_qgroups(&sort_tree
);
1217 __free_all_qgroups(&qgroup_lookup
);
1218 btrfs_qgroup_free_filter_set(filter_set
);
1219 btrfs_qgroup_free_comparer_set(comp_set
);
1223 u64
btrfs_get_path_rootid(int fd
)
1226 struct btrfs_ioctl_ino_lookup_args args
;
1228 memset(&args
, 0, sizeof(args
));
1229 args
.objectid
= BTRFS_FIRST_FREE_OBJECTID
;
1231 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
1234 "ERROR: can't perform the search - %s\n",
1241 int btrfs_qgroup_parse_sort_string(char *opt_arg
,
1242 struct btrfs_qgroup_comparer_set
**comps
)
1250 while ((p
= strtok(opt_arg
, ",")) != NULL
) {
1252 ptr_argv
= all_sort_items
;
1255 if (strcmp(*ptr_argv
, p
) == 0) {
1260 if (strcmp(*ptr_argv
, p
) == 0) {
1277 } else if (*p
== '-') {
1283 what_to_sort
= btrfs_qgroup_get_sort_item(p
);
1284 if (what_to_sort
< 0)
1286 btrfs_qgroup_setup_comparer(comps
, what_to_sort
, order
);
1294 int qgroup_inherit_size(struct btrfs_qgroup_inherit
*p
)
1296 return sizeof(*p
) + sizeof(p
->qgroups
[0]) *
1297 (p
->num_qgroups
+ 2 * p
->num_ref_copies
+
1298 2 * p
->num_excl_copies
);
1302 qgroup_inherit_realloc(struct btrfs_qgroup_inherit
**inherit
, int n
, int pos
)
1304 struct btrfs_qgroup_inherit
*out
;
1308 nitems
= (*inherit
)->num_qgroups
+
1309 (*inherit
)->num_ref_copies
+
1310 (*inherit
)->num_excl_copies
;
1313 out
= calloc(sizeof(*out
) + sizeof(out
->qgroups
[0]) * (nitems
+ n
), 1);
1315 fprintf(stderr
, "ERROR: Not enough memory\n");
1320 struct btrfs_qgroup_inherit
*i
= *inherit
;
1321 int s
= sizeof(out
->qgroups
[0]);
1323 out
->num_qgroups
= i
->num_qgroups
;
1324 out
->num_ref_copies
= i
->num_ref_copies
;
1325 out
->num_excl_copies
= i
->num_excl_copies
;
1326 memcpy(out
->qgroups
, i
->qgroups
, pos
* s
);
1327 memcpy(out
->qgroups
+ pos
+ n
, i
->qgroups
+ pos
,
1328 (nitems
- pos
) * s
);
1336 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit
**inherit
, char *arg
)
1339 u64 qgroupid
= parse_qgroupid(arg
);
1342 if (qgroupid
== 0) {
1343 fprintf(stderr
, "ERROR: bad qgroup specification\n");
1348 pos
= (*inherit
)->num_qgroups
;
1349 ret
= qgroup_inherit_realloc(inherit
, 1, pos
);
1353 (*inherit
)->qgroups
[(*inherit
)->num_qgroups
++] = qgroupid
;
1358 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit
**inherit
, char *arg
,
1367 p
= strchr(arg
, ':');
1370 fprintf(stderr
, "ERROR: bad copy specification\n");
1374 qgroup_src
= parse_qgroupid(arg
);
1375 qgroup_dst
= parse_qgroupid(p
+ 1);
1378 if (!qgroup_src
|| !qgroup_dst
)
1382 pos
= (*inherit
)->num_qgroups
+
1383 (*inherit
)->num_ref_copies
* 2 * type
;
1385 ret
= qgroup_inherit_realloc(inherit
, 2, pos
);
1389 (*inherit
)->qgroups
[pos
++] = qgroup_src
;
1390 (*inherit
)->qgroups
[pos
++] = qgroup_dst
;
1393 ++(*inherit
)->num_ref_copies
;
1395 ++(*inherit
)->num_excl_copies
;