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_info(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
623 struct btrfs_qgroup_info_item
*info
)
625 struct btrfs_qgroup
*bq
;
627 bq
= get_or_add_qgroup(qgroup_lookup
, qgroupid
);
628 if (IS_ERR_OR_NULL(bq
))
631 bq
->generation
= btrfs_stack_qgroup_info_generation(info
);
632 bq
->rfer
= btrfs_stack_qgroup_info_referenced(info
);
633 bq
->rfer_cmpr
= btrfs_stack_qgroup_info_referenced_compressed(info
);
634 bq
->excl
= btrfs_stack_qgroup_info_exclusive(info
);
635 bq
->excl_cmpr
= btrfs_stack_qgroup_info_exclusive_compressed(info
);
640 static int update_qgroup_limit(struct qgroup_lookup
*qgroup_lookup
,
642 struct btrfs_qgroup_limit_item
*limit
)
644 struct btrfs_qgroup
*bq
;
646 bq
= get_or_add_qgroup(qgroup_lookup
, qgroupid
);
647 if (IS_ERR_OR_NULL(bq
))
650 bq
->flags
= btrfs_stack_qgroup_limit_flags(limit
);
651 bq
->max_rfer
= btrfs_stack_qgroup_limit_max_referenced(limit
);
652 bq
->max_excl
= btrfs_stack_qgroup_limit_max_exclusive(limit
);
653 bq
->rsv_rfer
= btrfs_stack_qgroup_limit_rsv_referenced(limit
);
654 bq
->rsv_excl
= btrfs_stack_qgroup_limit_rsv_exclusive(limit
);
659 static int update_qgroup_relation(struct qgroup_lookup
*qgroup_lookup
,
660 u64 child_id
, u64 parent_id
)
662 struct btrfs_qgroup
*child
;
663 struct btrfs_qgroup
*parent
;
664 struct btrfs_qgroup_list
*list
;
666 child
= qgroup_tree_search(qgroup_lookup
, child_id
);
668 error("cannot find the qgroup %llu/%llu",
669 btrfs_qgroup_level(child_id
),
670 btrfs_qgroup_subvid(child_id
));
674 parent
= qgroup_tree_search(qgroup_lookup
, parent_id
);
676 error("cannot find the qgroup %llu/%llu",
677 btrfs_qgroup_level(parent_id
),
678 btrfs_qgroup_subvid(parent_id
));
682 list
= malloc(sizeof(*list
));
684 error("memory allocation failed");
688 list
->qgroup
= parent
;
689 list
->member
= child
;
690 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
691 list_add_tail(&list
->next_member
, &parent
->members
);
696 static void __free_btrfs_qgroup(struct btrfs_qgroup
*bq
)
698 struct btrfs_qgroup_list
*list
;
699 while (!list_empty(&bq
->qgroups
)) {
700 list
= list_entry((&bq
->qgroups
)->next
,
701 struct btrfs_qgroup_list
,
703 list_del(&list
->next_qgroup
);
704 list_del(&list
->next_member
);
707 while (!list_empty(&bq
->members
)) {
708 list
= list_entry((&bq
->members
)->next
,
709 struct btrfs_qgroup_list
,
711 list_del(&list
->next_qgroup
);
712 list_del(&list
->next_member
);
718 static void __free_all_qgroups(struct qgroup_lookup
*root_tree
)
720 struct btrfs_qgroup
*entry
;
723 n
= rb_first(&root_tree
->root
);
725 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
726 rb_erase(n
, &root_tree
->root
);
727 __free_btrfs_qgroup(entry
);
729 n
= rb_first(&root_tree
->root
);
733 static int filter_all_parent_insert(struct qgroup_lookup
*sort_tree
,
734 struct btrfs_qgroup
*bq
)
736 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
737 struct rb_node
*parent
= NULL
;
738 struct btrfs_qgroup
*curr
;
743 curr
= rb_entry(parent
, struct btrfs_qgroup
, all_parent_node
);
745 ret
= comp_entry_with_qgroupid(bq
, curr
, 0);
753 rb_link_node(&bq
->all_parent_node
, parent
, p
);
754 rb_insert_color(&bq
->all_parent_node
, &sort_tree
->root
);
758 static int filter_by_parent(struct btrfs_qgroup
*bq
, u64 data
)
760 struct btrfs_qgroup
*qgroup
=
761 (struct btrfs_qgroup
*)(unsigned long)data
;
765 if (qgroup
->qgroupid
== bq
->qgroupid
)
770 static int filter_by_all_parent(struct btrfs_qgroup
*bq
, u64 data
)
772 struct qgroup_lookup lookup
;
773 struct qgroup_lookup
*ql
= &lookup
;
774 struct btrfs_qgroup_list
*list
;
776 struct btrfs_qgroup
*qgroup
=
777 (struct btrfs_qgroup
*)(unsigned long)data
;
781 if (bq
->qgroupid
== qgroup
->qgroupid
)
784 qgroup_lookup_init(ql
);
785 filter_all_parent_insert(ql
, qgroup
);
786 n
= rb_first(&ql
->root
);
788 qgroup
= rb_entry(n
, struct btrfs_qgroup
, all_parent_node
);
789 if (!list_empty(&qgroup
->qgroups
)) {
790 list_for_each_entry(list
, &qgroup
->qgroups
,
792 if ((list
->qgroup
)->qgroupid
== bq
->qgroupid
)
794 filter_all_parent_insert(ql
, list
->qgroup
);
797 rb_erase(n
, &ql
->root
);
798 n
= rb_first(&ql
->root
);
803 static btrfs_qgroup_filter_func all_filter_funcs
[] = {
804 [BTRFS_QGROUP_FILTER_PARENT
] = filter_by_parent
,
805 [BTRFS_QGROUP_FILTER_ALL_PARENT
] = filter_by_all_parent
,
808 struct btrfs_qgroup_filter_set
*btrfs_qgroup_alloc_filter_set(void)
810 struct btrfs_qgroup_filter_set
*set
;
813 size
= sizeof(struct btrfs_qgroup_filter_set
) +
814 BTRFS_QGROUP_NFILTERS_INCREASE
*
815 sizeof(struct btrfs_qgroup_filter
);
816 set
= calloc(1, size
);
818 error("memory allocation failed");
821 set
->total
= BTRFS_QGROUP_NFILTERS_INCREASE
;
826 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set
**filter_set
,
827 enum btrfs_qgroup_filter_enum filter
, u64 data
)
829 struct btrfs_qgroup_filter_set
*set
= *filter_set
;
833 ASSERT(filter
< BTRFS_QGROUP_FILTER_MAX
);
834 ASSERT(set
->nfilters
<= set
->total
);
836 if (set
->nfilters
== set
->total
) {
839 size
= set
->total
+ BTRFS_QGROUP_NFILTERS_INCREASE
;
840 size
= sizeof(*set
) + size
* sizeof(struct btrfs_qgroup_filter
);
843 set
= realloc(set
, size
);
845 error("memory allocation failed");
849 memset(&set
->filters
[set
->total
], 0,
850 BTRFS_QGROUP_NFILTERS_INCREASE
*
851 sizeof(struct btrfs_qgroup_filter
));
852 set
->total
+= BTRFS_QGROUP_NFILTERS_INCREASE
;
856 ASSERT(set
->filters
[set
->nfilters
].filter_func
== NULL
);
857 set
->filters
[set
->nfilters
].filter_func
= all_filter_funcs
[filter
];
858 set
->filters
[set
->nfilters
].data
= data
;
863 static int filter_qgroup(struct btrfs_qgroup
*bq
,
864 struct btrfs_qgroup_filter_set
*set
)
868 if (!set
|| !set
->nfilters
)
870 for (i
= 0; i
< set
->nfilters
; i
++) {
871 if (!set
->filters
[i
].filter_func
)
873 ret
= set
->filters
[i
].filter_func(bq
, set
->filters
[i
].data
);
880 static void pre_process_filter_set(struct qgroup_lookup
*lookup
,
881 struct btrfs_qgroup_filter_set
*set
)
884 struct btrfs_qgroup
*qgroup_for_filter
= NULL
;
886 for (i
= 0; i
< set
->nfilters
; i
++) {
888 if (set
->filters
[i
].filter_func
== filter_by_all_parent
889 || set
->filters
[i
].filter_func
== filter_by_parent
) {
890 qgroup_for_filter
= qgroup_tree_search(lookup
,
891 set
->filters
[i
].data
);
892 set
->filters
[i
].data
=
893 (u64
)(unsigned long)qgroup_for_filter
;
898 static int sort_tree_insert(struct qgroup_lookup
*sort_tree
,
899 struct btrfs_qgroup
*bq
,
900 struct btrfs_qgroup_comparer_set
*comp_set
)
902 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
903 struct rb_node
*parent
= NULL
;
904 struct btrfs_qgroup
*curr
;
909 curr
= rb_entry(parent
, struct btrfs_qgroup
, sort_node
);
911 ret
= sort_comp(bq
, curr
, comp_set
);
919 rb_link_node(&bq
->sort_node
, parent
, p
);
920 rb_insert_color(&bq
->sort_node
, &sort_tree
->root
);
924 static void __update_columns_max_len(struct btrfs_qgroup
*bq
,
925 enum btrfs_qgroup_column_enum column
)
927 struct btrfs_qgroup_list
*list
= NULL
;
930 unsigned unit_mode
= btrfs_qgroup_columns
[column
].unit_mode
;
932 ASSERT(0 <= column
&& column
< BTRFS_QGROUP_ALL
);
936 case BTRFS_QGROUP_QGROUPID
:
937 sprintf(tmp
, "%llu/%llu",
938 btrfs_qgroup_level(bq
->qgroupid
),
939 btrfs_qgroup_subvid(bq
->qgroupid
));
941 if (btrfs_qgroup_columns
[column
].max_len
< len
)
942 btrfs_qgroup_columns
[column
].max_len
= len
;
944 case BTRFS_QGROUP_RFER
:
945 len
= strlen(pretty_size_mode(bq
->rfer
, unit_mode
));
946 if (btrfs_qgroup_columns
[column
].max_len
< len
)
947 btrfs_qgroup_columns
[column
].max_len
= len
;
949 case BTRFS_QGROUP_EXCL
:
950 len
= strlen(pretty_size_mode(bq
->excl
, unit_mode
));
951 if (btrfs_qgroup_columns
[column
].max_len
< len
)
952 btrfs_qgroup_columns
[column
].max_len
= len
;
954 case BTRFS_QGROUP_MAX_RFER
:
955 len
= strlen(pretty_size_mode(bq
->max_rfer
, unit_mode
));
956 if (btrfs_qgroup_columns
[column
].max_len
< len
)
957 btrfs_qgroup_columns
[column
].max_len
= len
;
959 case BTRFS_QGROUP_MAX_EXCL
:
960 len
= strlen(pretty_size_mode(bq
->max_excl
, unit_mode
));
961 if (btrfs_qgroup_columns
[column
].max_len
< len
)
962 btrfs_qgroup_columns
[column
].max_len
= len
;
964 case BTRFS_QGROUP_PARENT
:
966 list_for_each_entry(list
, &bq
->qgroups
, next_qgroup
) {
967 len
+= sprintf(tmp
, "%llu/%llu",
968 btrfs_qgroup_level(list
->qgroup
->qgroupid
),
969 btrfs_qgroup_subvid(list
->qgroup
->qgroupid
));
970 if (!list_is_last(&list
->next_qgroup
, &bq
->qgroups
))
973 if (btrfs_qgroup_columns
[column
].max_len
< len
)
974 btrfs_qgroup_columns
[column
].max_len
= len
;
976 case BTRFS_QGROUP_CHILD
:
978 list_for_each_entry(list
, &bq
->members
, next_member
) {
979 len
+= sprintf(tmp
, "%llu/%llu",
980 btrfs_qgroup_level(list
->member
->qgroupid
),
981 btrfs_qgroup_subvid(list
->member
->qgroupid
));
982 if (!list_is_last(&list
->next_member
, &bq
->members
))
985 if (btrfs_qgroup_columns
[column
].max_len
< len
)
986 btrfs_qgroup_columns
[column
].max_len
= len
;
994 static void update_columns_max_len(struct btrfs_qgroup
*bq
)
998 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
999 if (!btrfs_qgroup_columns
[i
].need_print
)
1001 __update_columns_max_len(bq
, i
);
1005 static void __filter_and_sort_qgroups(struct qgroup_lookup
*all_qgroups
,
1006 struct qgroup_lookup
*sort_tree
,
1007 struct btrfs_qgroup_filter_set
*filter_set
,
1008 struct btrfs_qgroup_comparer_set
*comp_set
)
1011 struct btrfs_qgroup
*entry
;
1014 qgroup_lookup_init(sort_tree
);
1015 pre_process_filter_set(all_qgroups
, filter_set
);
1017 n
= rb_last(&all_qgroups
->root
);
1019 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
1021 ret
= filter_qgroup(entry
, filter_set
);
1023 sort_tree_insert(sort_tree
, entry
, comp_set
);
1025 update_columns_max_len(entry
);
1031 static inline void print_status_flag_warning(u64 flags
)
1033 if (!(flags
& BTRFS_QGROUP_STATUS_FLAG_ON
))
1034 warning("quota disabled, qgroup data may be out of date");
1035 else if (flags
& BTRFS_QGROUP_STATUS_FLAG_RESCAN
)
1036 warning("rescan is running, qgroup data may be incorrect");
1037 else if (flags
& BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT
)
1038 warning("qgroup data inconsistent, rescan recommended");
1041 static int __qgroups_search(int fd
, struct qgroup_lookup
*qgroup_lookup
)
1044 struct btrfs_ioctl_search_args args
;
1045 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
1046 struct btrfs_ioctl_search_header
*sh
;
1047 unsigned long off
= 0;
1049 struct btrfs_qgroup_status_item
*si
;
1050 struct btrfs_qgroup_info_item
*info
;
1051 struct btrfs_qgroup_limit_item
*limit
;
1056 memset(&args
, 0, sizeof(args
));
1058 sk
->tree_id
= BTRFS_QUOTA_TREE_OBJECTID
;
1059 sk
->max_type
= BTRFS_QGROUP_RELATION_KEY
;
1060 sk
->min_type
= BTRFS_QGROUP_STATUS_KEY
;
1061 sk
->max_objectid
= (u64
)-1;
1062 sk
->max_offset
= (u64
)-1;
1063 sk
->max_transid
= (u64
)-1;
1064 sk
->nr_items
= 4096;
1066 qgroup_lookup_init(qgroup_lookup
);
1069 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
1071 if (errno
== ENOENT
) {
1072 error("can't list qgroups: quotas not enabled");
1075 error("can't list qgroups: %s",
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 switch (btrfs_search_header_type(sh
)) {
1098 case BTRFS_QGROUP_STATUS_KEY
:
1099 si
= (struct btrfs_qgroup_status_item
*)
1101 flags
= btrfs_stack_qgroup_status_flags(si
);
1103 print_status_flag_warning(flags
);
1105 case BTRFS_QGROUP_INFO_KEY
:
1106 qgroupid
= btrfs_search_header_offset(sh
);
1107 info
= (struct btrfs_qgroup_info_item
*)
1110 ret
= update_qgroup_info(qgroup_lookup
,
1113 case BTRFS_QGROUP_LIMIT_KEY
:
1114 qgroupid
= btrfs_search_header_offset(sh
);
1115 limit
= (struct btrfs_qgroup_limit_item
*)
1118 ret
= update_qgroup_limit(qgroup_lookup
,
1121 case BTRFS_QGROUP_RELATION_KEY
:
1122 child
= btrfs_search_header_offset(sh
);
1123 parent
= btrfs_search_header_objectid(sh
);
1125 if (parent
<= child
)
1128 ret
= update_qgroup_relation(qgroup_lookup
,
1138 off
+= btrfs_search_header_len(sh
);
1141 * record the mins in sk so we can make sure the
1142 * next search doesn't repeat this root
1144 sk
->min_type
= btrfs_search_header_type(sh
);
1145 sk
->min_offset
= btrfs_search_header_offset(sh
);
1146 sk
->min_objectid
= btrfs_search_header_objectid(sh
);
1148 sk
->nr_items
= 4096;
1150 * this iteration is done, step forward one qgroup for the next
1153 if (sk
->min_offset
< (u64
)-1)
1162 static void print_all_qgroups(struct qgroup_lookup
*qgroup_lookup
)
1166 struct btrfs_qgroup
*entry
;
1170 n
= rb_first(&qgroup_lookup
->root
);
1172 entry
= rb_entry(n
, struct btrfs_qgroup
, sort_node
);
1173 print_single_qgroup_table(entry
);
1178 int btrfs_show_qgroups(int fd
,
1179 struct btrfs_qgroup_filter_set
*filter_set
,
1180 struct btrfs_qgroup_comparer_set
*comp_set
)
1183 struct qgroup_lookup qgroup_lookup
;
1184 struct qgroup_lookup sort_tree
;
1187 ret
= __qgroups_search(fd
, &qgroup_lookup
);
1190 __filter_and_sort_qgroups(&qgroup_lookup
, &sort_tree
,
1191 filter_set
, comp_set
);
1192 print_all_qgroups(&sort_tree
);
1194 __free_all_qgroups(&qgroup_lookup
);
1198 int btrfs_qgroup_parse_sort_string(const char *opt_arg
,
1199 struct btrfs_qgroup_comparer_set
**comps
)
1209 opt_tmp
= strdup(opt_arg
);
1213 p
= strtok(opt_tmp
, ",");
1216 ptr_argv
= all_sort_items
;
1219 if (strcmp(*ptr_argv
, p
) == 0) {
1224 if (strcmp(*ptr_argv
, p
) == 0) {
1241 } else if (*p
== '-') {
1247 what_to_sort
= btrfs_qgroup_get_sort_item(p
);
1248 if (what_to_sort
< 0) {
1252 btrfs_qgroup_setup_comparer(comps
, what_to_sort
, order
);
1254 p
= strtok(NULL
, ",");
1262 int qgroup_inherit_size(struct btrfs_qgroup_inherit
*p
)
1264 return sizeof(*p
) + sizeof(p
->qgroups
[0]) *
1265 (p
->num_qgroups
+ 2 * p
->num_ref_copies
+
1266 2 * p
->num_excl_copies
);
1270 qgroup_inherit_realloc(struct btrfs_qgroup_inherit
**inherit
, int n
, int pos
)
1272 struct btrfs_qgroup_inherit
*out
;
1276 nitems
= (*inherit
)->num_qgroups
+
1277 (*inherit
)->num_ref_copies
+
1278 (*inherit
)->num_excl_copies
;
1281 out
= calloc(sizeof(*out
) + sizeof(out
->qgroups
[0]) * (nitems
+ n
), 1);
1283 error("not enough memory");
1288 struct btrfs_qgroup_inherit
*i
= *inherit
;
1289 int s
= sizeof(out
->qgroups
[0]);
1291 out
->num_qgroups
= i
->num_qgroups
;
1292 out
->num_ref_copies
= i
->num_ref_copies
;
1293 out
->num_excl_copies
= i
->num_excl_copies
;
1294 memcpy(out
->qgroups
, i
->qgroups
, pos
* s
);
1295 memcpy(out
->qgroups
+ pos
+ n
, i
->qgroups
+ pos
,
1296 (nitems
- pos
) * s
);
1304 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit
**inherit
, char *arg
)
1307 u64 qgroupid
= parse_qgroupid(arg
);
1310 if (qgroupid
== 0) {
1311 error("invalid qgroup specification, qgroupid must not 0");
1316 pos
= (*inherit
)->num_qgroups
;
1317 ret
= qgroup_inherit_realloc(inherit
, 1, pos
);
1321 (*inherit
)->qgroups
[(*inherit
)->num_qgroups
++] = qgroupid
;
1326 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit
**inherit
, char *arg
,
1335 p
= strchr(arg
, ':');
1338 error("invalid copy specification, missing separator :");
1342 qgroup_src
= parse_qgroupid(arg
);
1343 qgroup_dst
= parse_qgroupid(p
+ 1);
1346 if (!qgroup_src
|| !qgroup_dst
)
1350 pos
= (*inherit
)->num_qgroups
+
1351 (*inherit
)->num_ref_copies
* 2 * type
;
1353 ret
= qgroup_inherit_realloc(inherit
, 2, pos
);
1357 (*inherit
)->qgroups
[pos
++] = qgroup_src
;
1358 (*inherit
)->qgroups
[pos
++] = qgroup_dst
;
1361 ++(*inherit
)->num_ref_copies
;
1363 ++(*inherit
)->num_excl_copies
;