2 * Copyright (C) 2012 STRATO. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
20 #include <sys/ioctl.h>
24 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
25 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
27 struct qgroup_lookup
{
32 struct rb_node rb_node
;
33 struct rb_node sort_node
;
35 *all_parent_node is used to
36 *filter a qgroup's all parent
38 struct rb_node all_parent_node
;
45 u64 rfer
; /*referenced*/
46 u64 rfer_cmpr
; /*referenced compressed*/
47 u64 excl
; /*exclusive*/
48 u64 excl_cmpr
; /*exclusive compressed*/
53 u64 flags
; /*which limits are set*/
59 /*qgroups this group is member of*/
60 struct list_head qgroups
;
61 /*qgroups that are members of this group*/
62 struct list_head members
;
66 * glue structure to represent the relations
69 struct btrfs_qgroup_list
{
70 struct list_head next_qgroup
;
71 struct list_head next_member
;
72 struct btrfs_qgroup
*qgroup
;
73 struct btrfs_qgroup
*member
;
77 * qgroupid,rfer,excl default to set
84 } btrfs_qgroup_columns
[] = {
87 .column_name
= "Qgroupid",
93 .column_name
= "Rfer",
99 .column_name
= "Excl",
103 { .name
= "max_rfer",
104 .column_name
= "Max_rfer",
110 .column_name
= "Max_excl",
116 .column_name
= "Parent",
122 .column_name
= "Child",
133 static btrfs_qgroup_filter_func all_filter_funcs
[];
134 static btrfs_qgroup_comp_func all_comp_funcs
[];
136 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column
)
140 BUG_ON(column
< 0 || column
> BTRFS_QGROUP_ALL
);
142 if (column
< BTRFS_QGROUP_ALL
) {
143 btrfs_qgroup_columns
[column
].need_print
= 1;
146 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++)
147 btrfs_qgroup_columns
[i
].need_print
= 1;
150 static int print_parent_column(struct btrfs_qgroup
*qgroup
)
152 struct btrfs_qgroup_list
*list
= NULL
;
155 list_for_each_entry(list
, &qgroup
->qgroups
, next_qgroup
) {
156 len
+= printf("%llu/%llu", (list
->qgroup
)->qgroupid
>> 48,
157 ((1ll << 48) - 1) & (list
->qgroup
)->qgroupid
);
158 if (!list_is_last(&list
->next_qgroup
, &qgroup
->qgroups
))
161 if (list_empty(&qgroup
->qgroups
))
162 len
+= printf("---");
167 static int print_child_column(struct btrfs_qgroup
*qgroup
)
169 struct btrfs_qgroup_list
*list
= NULL
;
172 list_for_each_entry(list
, &qgroup
->members
, next_member
) {
173 len
+= printf("%llu/%llu", (list
->member
)->qgroupid
>> 48,
174 ((1ll << 48) - 1) & (list
->member
)->qgroupid
);
175 if (!list_is_last(&list
->next_member
, &qgroup
->members
))
178 if (list_empty(&qgroup
->members
))
179 len
+= printf("---");
184 static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column
,
187 len
= btrfs_qgroup_columns
[column
].max_len
- len
;
192 static void print_qgroup_column(struct btrfs_qgroup
*qgroup
,
193 enum btrfs_qgroup_column_enum column
)
195 BUG_ON(column
>= BTRFS_QGROUP_ALL
|| column
< 0);
200 case BTRFS_QGROUP_QGROUPID
:
201 len
= printf("%llu/%llu", qgroup
->qgroupid
>> 48,
202 ((1ll << 48) - 1) & qgroup
->qgroupid
);
203 print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID
, len
);
205 case BTRFS_QGROUP_RFER
:
206 len
= printf("%lld", qgroup
->rfer
);
207 print_qgroup_column_add_blank(BTRFS_QGROUP_RFER
, len
);
209 case BTRFS_QGROUP_EXCL
:
210 len
= printf("%lld", qgroup
->excl
);
211 print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL
, len
);
213 case BTRFS_QGROUP_PARENT
:
214 len
= print_parent_column(qgroup
);
215 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT
, len
);
217 case BTRFS_QGROUP_MAX_RFER
:
218 len
= printf("%llu", qgroup
->max_rfer
);
219 print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER
, len
);
221 case BTRFS_QGROUP_MAX_EXCL
:
222 len
= printf("%llu", qgroup
->max_excl
);
223 print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL
, len
);
225 case BTRFS_QGROUP_CHILD
:
226 len
= print_child_column(qgroup
);
227 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD
, len
);
234 static void print_single_qgroup_table(struct btrfs_qgroup
*qgroup
)
238 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
239 if (!btrfs_qgroup_columns
[i
].need_print
)
241 print_qgroup_column(qgroup
, i
);
243 if (i
!= BTRFS_QGROUP_CHILD
)
249 static void print_table_head()
254 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
255 if (!btrfs_qgroup_columns
[i
].need_print
)
257 printf("%s", btrfs_qgroup_columns
[i
].name
);
258 len
= btrfs_qgroup_columns
[i
].max_len
-
259 strlen(btrfs_qgroup_columns
[i
].name
);
265 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
266 if (!btrfs_qgroup_columns
[i
].need_print
)
269 len
= strlen(btrfs_qgroup_columns
[i
].name
);
272 len
= btrfs_qgroup_columns
[i
].max_len
-
273 strlen(btrfs_qgroup_columns
[i
].name
);
281 static void qgroup_lookup_init(struct qgroup_lookup
*tree
)
283 tree
->root
.rb_node
= NULL
;
286 static int comp_entry_with_qgroupid(struct btrfs_qgroup
*entry1
,
287 struct btrfs_qgroup
*entry2
,
293 if (entry1
->qgroupid
> entry2
->qgroupid
)
295 else if (entry1
->qgroupid
< entry2
->qgroupid
)
300 return is_descending
? -ret
: ret
;
303 static int comp_entry_with_rfer(struct btrfs_qgroup
*entry1
,
304 struct btrfs_qgroup
*entry2
,
309 if (entry1
->rfer
> entry2
->rfer
)
311 else if (entry1
->rfer
< entry2
->rfer
)
316 return is_descending
? -ret
: ret
;
319 static int comp_entry_with_excl(struct btrfs_qgroup
*entry1
,
320 struct btrfs_qgroup
*entry2
,
325 if (entry1
->excl
> entry2
->excl
)
327 else if (entry1
->excl
< entry2
->excl
)
332 return is_descending
? -ret
: ret
;
335 static int comp_entry_with_max_rfer(struct btrfs_qgroup
*entry1
,
336 struct btrfs_qgroup
*entry2
,
341 if (entry1
->max_rfer
> entry2
->max_rfer
)
343 else if (entry1
->max_rfer
< entry2
->max_rfer
)
348 return is_descending
? -ret
: ret
;
351 static int comp_entry_with_max_excl(struct btrfs_qgroup
*entry1
,
352 struct btrfs_qgroup
*entry2
,
357 if (entry1
->max_excl
> entry2
->max_excl
)
359 else if (entry1
->max_excl
< entry2
->max_excl
)
364 return is_descending
? -ret
: ret
;
367 static btrfs_qgroup_comp_func all_comp_funcs
[] = {
368 [BTRFS_QGROUP_COMP_QGROUPID
] = comp_entry_with_qgroupid
,
369 [BTRFS_QGROUP_COMP_RFER
] = comp_entry_with_rfer
,
370 [BTRFS_QGROUP_COMP_EXCL
] = comp_entry_with_excl
,
371 [BTRFS_QGROUP_COMP_MAX_RFER
] = comp_entry_with_max_rfer
,
372 [BTRFS_QGROUP_COMP_MAX_EXCL
] = comp_entry_with_max_excl
375 static char *all_sort_items
[] = {
376 [BTRFS_QGROUP_COMP_QGROUPID
] = "qgroupid",
377 [BTRFS_QGROUP_COMP_RFER
] = "rfer",
378 [BTRFS_QGROUP_COMP_EXCL
] = "excl",
379 [BTRFS_QGROUP_COMP_MAX_RFER
] = "max_rfer",
380 [BTRFS_QGROUP_COMP_MAX_EXCL
] = "max_excl",
381 [BTRFS_QGROUP_COMP_MAX
] = NULL
,
384 static int btrfs_qgroup_get_sort_item(char *sort_name
)
388 for (i
= 0; i
< BTRFS_QGROUP_COMP_MAX
; i
++) {
389 if (strcmp(sort_name
, all_sort_items
[i
]) == 0)
395 struct btrfs_qgroup_comparer_set
*btrfs_qgroup_alloc_comparer_set(void)
397 struct btrfs_qgroup_comparer_set
*set
;
399 size
= sizeof(struct btrfs_qgroup_comparer_set
) +
400 BTRFS_QGROUP_NCOMPS_INCREASE
*
401 sizeof(struct btrfs_qgroup_comparer
);
404 fprintf(stderr
, "memory allocation failed\n");
408 memset(set
, 0, size
);
409 set
->total
= BTRFS_QGROUP_NCOMPS_INCREASE
;
414 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set
*comp_set
)
419 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set
**comp_set
,
420 enum btrfs_qgroup_comp_enum comparer
,
423 struct btrfs_qgroup_comparer_set
*set
= *comp_set
;
427 BUG_ON(comparer
>= BTRFS_QGROUP_COMP_MAX
);
428 BUG_ON(set
->ncomps
> set
->total
);
430 if (set
->ncomps
== set
->total
) {
431 size
= set
->total
+ BTRFS_QGROUP_NCOMPS_INCREASE
;
432 size
= sizeof(*set
) +
433 size
* sizeof(struct btrfs_qgroup_comparer
);
434 set
= realloc(set
, size
);
436 fprintf(stderr
, "memory allocation failed\n");
440 memset(&set
->comps
[set
->total
], 0,
441 BTRFS_QGROUP_NCOMPS_INCREASE
*
442 sizeof(struct btrfs_qgroup_comparer
));
443 set
->total
+= BTRFS_QGROUP_NCOMPS_INCREASE
;
447 BUG_ON(set
->comps
[set
->ncomps
].comp_func
);
449 set
->comps
[set
->ncomps
].comp_func
= all_comp_funcs
[comparer
];
450 set
->comps
[set
->ncomps
].is_descending
= is_descending
;
455 static int sort_comp(struct btrfs_qgroup
*entry1
, struct btrfs_qgroup
*entry2
,
456 struct btrfs_qgroup_comparer_set
*set
)
458 int qgroupid_compared
= 0;
461 if (!set
|| !set
->ncomps
)
464 for (i
= 0; i
< set
->ncomps
; i
++) {
465 if (!set
->comps
[i
].comp_func
)
468 ret
= set
->comps
[i
].comp_func(entry1
, entry2
,
469 set
->comps
[i
].is_descending
);
473 if (set
->comps
[i
].comp_func
== comp_entry_with_qgroupid
)
474 qgroupid_compared
= 1;
477 if (!qgroupid_compared
) {
479 ret
= comp_entry_with_qgroupid(entry1
, entry2
, 0);
486 * insert a new root into the tree. returns the existing root entry
487 * if one is already there. qgroupid is used
490 static int qgroup_tree_insert(struct qgroup_lookup
*root_tree
,
491 struct btrfs_qgroup
*ins
)
494 struct rb_node
**p
= &root_tree
->root
.rb_node
;
495 struct rb_node
*parent
= NULL
;
496 struct btrfs_qgroup
*curr
;
501 curr
= rb_entry(parent
, struct btrfs_qgroup
, rb_node
);
503 ret
= comp_entry_with_qgroupid(ins
, curr
, 0);
511 rb_link_node(&ins
->rb_node
, parent
, p
);
512 rb_insert_color(&ins
->rb_node
, &root_tree
->root
);
517 *find a given qgroupid in the tree. We return the smallest one,
518 *rb_next can be used to move forward looking for more if required
520 static struct btrfs_qgroup
*qgroup_tree_search(struct qgroup_lookup
*root_tree
,
523 struct rb_node
*n
= root_tree
->root
.rb_node
;
524 struct btrfs_qgroup
*entry
;
525 struct btrfs_qgroup tmp
;
528 tmp
.qgroupid
= qgroupid
;
531 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
533 ret
= comp_entry_with_qgroupid(&tmp
, entry
, 0);
545 static int update_qgroup(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
546 u64 generation
, u64 rfer
, u64 rfer_cmpr
, u64 excl
,
547 u64 excl_cmpr
, u64 flags
, u64 max_rfer
, u64 max_excl
,
548 u64 rsv_rfer
, u64 rsv_excl
, struct btrfs_qgroup
*pa
,
549 struct btrfs_qgroup
*child
)
551 struct btrfs_qgroup
*bq
;
552 struct btrfs_qgroup_list
*list
;
554 bq
= qgroup_tree_search(qgroup_lookup
, qgroupid
);
555 if (!bq
|| bq
->qgroupid
!= qgroupid
)
559 bq
->generation
= generation
;
563 bq
->rfer_cmpr
= rfer_cmpr
;
567 bq
->excl_cmpr
= excl_cmpr
;
571 bq
->max_rfer
= max_rfer
;
573 bq
->max_excl
= max_excl
;
575 bq
->rsv_rfer
= rsv_rfer
;
577 list
= malloc(sizeof(*list
));
579 fprintf(stderr
, "memory allocation failed\n");
583 list
->member
= child
;
584 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
585 list_add_tail(&list
->next_member
, &pa
->members
);
590 static int add_qgroup(struct qgroup_lookup
*qgroup_lookup
, u64 qgroupid
,
591 u64 generation
, u64 rfer
, u64 rfer_cmpr
, u64 excl
,
592 u64 excl_cmpr
, u64 flags
, u64 max_rfer
, u64 max_excl
,
593 u64 rsv_rfer
, u64 rsv_excl
, struct btrfs_qgroup
*parent
,
594 struct btrfs_qgroup
*child
)
596 struct btrfs_qgroup
*bq
;
597 struct btrfs_qgroup_list
*list
;
600 ret
= update_qgroup(qgroup_lookup
, qgroupid
, generation
, rfer
,
601 rfer_cmpr
, excl
, excl_cmpr
, flags
, max_rfer
,
602 max_excl
, rsv_rfer
, rsv_excl
, parent
, child
);
606 bq
= malloc(sizeof(*bq
));
608 printf("memory allocation failed\n");
611 memset(bq
, 0, sizeof(*bq
));
613 bq
->qgroupid
= qgroupid
;
614 INIT_LIST_HEAD(&bq
->qgroups
);
615 INIT_LIST_HEAD(&bq
->members
);
618 bq
->generation
= generation
;
622 bq
->rfer_cmpr
= rfer_cmpr
;
626 bq
->excl_cmpr
= excl_cmpr
;
630 bq
->max_rfer
= max_rfer
;
632 bq
->max_excl
= max_excl
;
634 bq
->rsv_rfer
= rsv_rfer
;
635 if (parent
&& child
) {
636 list
= malloc(sizeof(*list
));
638 fprintf(stderr
, "memory allocation failed\n");
641 list
->qgroup
= parent
;
642 list
->member
= child
;
643 list_add_tail(&list
->next_qgroup
, &child
->qgroups
);
644 list_add_tail(&list
->next_member
, &parent
->members
);
646 ret
= qgroup_tree_insert(qgroup_lookup
, bq
);
648 printf("failed to insert tree %llu\n",
655 static void __free_btrfs_qgroup(struct btrfs_qgroup
*bq
)
657 struct btrfs_qgroup_list
*list
;
658 while (!list_empty(&bq
->qgroups
)) {
659 list
= list_entry((&bq
->qgroups
)->next
,
660 struct btrfs_qgroup_list
,
662 list_del(&list
->next_qgroup
);
663 list_del(&list
->next_member
);
666 while (!list_empty(&bq
->members
)) {
667 list
= list_entry((&bq
->members
)->next
,
668 struct btrfs_qgroup_list
,
670 list_del(&list
->next_qgroup
);
671 list_del(&list
->next_member
);
677 static void __free_all_qgroups(struct qgroup_lookup
*root_tree
)
679 struct btrfs_qgroup
*entry
;
682 n
= rb_first(&root_tree
->root
);
684 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
685 rb_erase(n
, &root_tree
->root
);
686 __free_btrfs_qgroup(entry
);
688 n
= rb_first(&root_tree
->root
);
692 static int filter_all_parent_insert(struct qgroup_lookup
*sort_tree
,
693 struct btrfs_qgroup
*bq
)
695 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
696 struct rb_node
*parent
= NULL
;
697 struct btrfs_qgroup
*curr
;
702 curr
= rb_entry(parent
, struct btrfs_qgroup
, all_parent_node
);
704 ret
= comp_entry_with_qgroupid(bq
, curr
, 0);
712 rb_link_node(&bq
->all_parent_node
, parent
, p
);
713 rb_insert_color(&bq
->all_parent_node
, &sort_tree
->root
);
717 static int filter_by_parent(struct btrfs_qgroup
*bq
, u64 data
)
719 struct btrfs_qgroup
*qgroup
=
720 (struct btrfs_qgroup
*)(unsigned long)data
;
724 if (qgroup
->qgroupid
== bq
->qgroupid
)
729 static int filter_by_all_parent(struct btrfs_qgroup
*bq
, u64 data
)
731 struct qgroup_lookup lookup
;
732 struct qgroup_lookup
*ql
= &lookup
;
733 struct btrfs_qgroup_list
*list
;
735 struct btrfs_qgroup
*qgroup
=
736 (struct btrfs_qgroup
*)(unsigned long)data
;
740 if (bq
->qgroupid
== qgroup
->qgroupid
)
743 qgroup_lookup_init(ql
);
744 filter_all_parent_insert(ql
, qgroup
);
745 n
= rb_first(&ql
->root
);
747 qgroup
= rb_entry(n
, struct btrfs_qgroup
, all_parent_node
);
748 if (!list_empty(&qgroup
->qgroups
)) {
749 list_for_each_entry(list
, &qgroup
->qgroups
,
751 if ((list
->qgroup
)->qgroupid
== bq
->qgroupid
)
753 filter_all_parent_insert(ql
, list
->qgroup
);
756 rb_erase(n
, &ql
->root
);
757 n
= rb_first(&ql
->root
);
762 static btrfs_qgroup_filter_func all_filter_funcs
[] = {
763 [BTRFS_QGROUP_FILTER_PARENT
] = filter_by_parent
,
764 [BTRFS_QGROUP_FILTER_ALL_PARENT
] = filter_by_all_parent
,
767 struct btrfs_qgroup_filter_set
*btrfs_qgroup_alloc_filter_set(void)
769 struct btrfs_qgroup_filter_set
*set
;
772 size
= sizeof(struct btrfs_qgroup_filter_set
) +
773 BTRFS_QGROUP_NFILTERS_INCREASE
*
774 sizeof(struct btrfs_qgroup_filter
);
777 fprintf(stderr
, "memory allocation failed\n");
780 memset(set
, 0, size
);
781 set
->total
= BTRFS_QGROUP_NFILTERS_INCREASE
;
786 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set
*filter_set
)
791 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set
**filter_set
,
792 enum btrfs_qgroup_filter_enum filter
, u64 data
)
794 struct btrfs_qgroup_filter_set
*set
= *filter_set
;
798 BUG_ON(filter
>= BTRFS_QGROUP_FILTER_MAX
);
799 BUG_ON(set
->nfilters
> set
->total
);
801 if (set
->nfilters
== set
->total
) {
802 size
= set
->total
+ BTRFS_QGROUP_NFILTERS_INCREASE
;
803 size
= sizeof(*set
) + size
* sizeof(struct btrfs_qgroup_filter
);
805 set
= realloc(set
, size
);
807 fprintf(stderr
, "memory allocation failed\n");
810 memset(&set
->filters
[set
->total
], 0,
811 BTRFS_QGROUP_NFILTERS_INCREASE
*
812 sizeof(struct btrfs_qgroup_filter
));
813 set
->total
+= BTRFS_QGROUP_NFILTERS_INCREASE
;
816 BUG_ON(set
->filters
[set
->nfilters
].filter_func
);
817 set
->filters
[set
->nfilters
].filter_func
= all_filter_funcs
[filter
];
818 set
->filters
[set
->nfilters
].data
= data
;
823 static int filter_qgroup(struct btrfs_qgroup
*bq
,
824 struct btrfs_qgroup_filter_set
*set
)
828 if (!set
|| !set
->nfilters
)
830 for (i
= 0; i
< set
->nfilters
; i
++) {
831 if (!set
->filters
[i
].filter_func
)
833 ret
= set
->filters
[i
].filter_func(bq
, set
->filters
[i
].data
);
840 static void pre_process_filter_set(struct qgroup_lookup
*lookup
,
841 struct btrfs_qgroup_filter_set
*set
)
844 struct btrfs_qgroup
*qgroup_for_filter
= NULL
;
846 for (i
= 0; i
< set
->nfilters
; i
++) {
848 if (set
->filters
[i
].filter_func
== filter_by_all_parent
849 || set
->filters
[i
].filter_func
== filter_by_parent
) {
850 qgroup_for_filter
= qgroup_tree_search(lookup
,
851 set
->filters
[i
].data
);
852 set
->filters
[i
].data
=
853 (u64
)(unsigned long)qgroup_for_filter
;
858 static int sort_tree_insert(struct qgroup_lookup
*sort_tree
,
859 struct btrfs_qgroup
*bq
,
860 struct btrfs_qgroup_comparer_set
*comp_set
)
862 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
863 struct rb_node
*parent
= NULL
;
864 struct btrfs_qgroup
*curr
;
869 curr
= rb_entry(parent
, struct btrfs_qgroup
, sort_node
);
871 ret
= sort_comp(bq
, curr
, comp_set
);
879 rb_link_node(&bq
->sort_node
, parent
, p
);
880 rb_insert_color(&bq
->sort_node
, &sort_tree
->root
);
884 static void __update_columns_max_len(struct btrfs_qgroup
*bq
,
885 enum btrfs_qgroup_column_enum column
)
887 BUG_ON(column
>= BTRFS_QGROUP_ALL
|| column
< 0);
888 struct btrfs_qgroup_list
*list
= NULL
;
894 case BTRFS_QGROUP_QGROUPID
:
895 sprintf(tmp
, "%llu/%llu", (bq
->qgroupid
>> 48),
896 bq
->qgroupid
& ((1ll << 48) - 1));
898 if (btrfs_qgroup_columns
[column
].max_len
< len
)
899 btrfs_qgroup_columns
[column
].max_len
= len
;
901 case BTRFS_QGROUP_RFER
:
902 sprintf(tmp
, "%llu", bq
->rfer
);
904 if (btrfs_qgroup_columns
[column
].max_len
< len
)
905 btrfs_qgroup_columns
[column
].max_len
= len
;
907 case BTRFS_QGROUP_EXCL
:
908 sprintf(tmp
, "%llu", bq
->excl
);
910 if (btrfs_qgroup_columns
[column
].max_len
< len
)
911 btrfs_qgroup_columns
[column
].max_len
= len
;
913 case BTRFS_QGROUP_MAX_RFER
:
914 sprintf(tmp
, "%llu", bq
->max_rfer
);
916 if (btrfs_qgroup_columns
[column
].max_len
< len
)
917 btrfs_qgroup_columns
[column
].max_len
= len
;
919 case BTRFS_QGROUP_MAX_EXCL
:
920 sprintf(tmp
, "%llu", bq
->max_excl
);
922 if (btrfs_qgroup_columns
[column
].max_len
< len
)
923 btrfs_qgroup_columns
[column
].max_len
= len
;
925 case BTRFS_QGROUP_PARENT
:
927 list_for_each_entry(list
, &bq
->qgroups
, next_qgroup
) {
928 len
+= sprintf(tmp
, "%llu/%llu",
929 (list
->qgroup
)->qgroupid
>> 48,
930 ((1ll << 48) - 1) & (list
->qgroup
)->qgroupid
);
931 if (!list_is_last(&list
->next_qgroup
, &bq
->qgroups
))
934 if (btrfs_qgroup_columns
[column
].max_len
< len
)
935 btrfs_qgroup_columns
[column
].max_len
= len
;
937 case BTRFS_QGROUP_CHILD
:
939 list_for_each_entry(list
, &bq
->members
, next_member
) {
940 len
+= sprintf(tmp
, "%llu/%llu",
941 (list
->member
)->qgroupid
>> 48,
942 ((1ll << 48) - 1) & (list
->member
)->qgroupid
);
943 if (!list_is_last(&list
->next_member
, &bq
->members
))
946 if (btrfs_qgroup_columns
[column
].max_len
< len
)
947 btrfs_qgroup_columns
[column
].max_len
= len
;
955 static void update_columns_max_len(struct btrfs_qgroup
*bq
)
959 for (i
= 0; i
< BTRFS_QGROUP_ALL
; i
++) {
960 if (!btrfs_qgroup_columns
[i
].need_print
)
962 __update_columns_max_len(bq
, i
);
966 static void __filter_and_sort_qgroups(struct qgroup_lookup
*all_qgroups
,
967 struct qgroup_lookup
*sort_tree
,
968 struct btrfs_qgroup_filter_set
*filter_set
,
969 struct btrfs_qgroup_comparer_set
*comp_set
)
972 struct btrfs_qgroup
*entry
;
975 qgroup_lookup_init(sort_tree
);
976 pre_process_filter_set(all_qgroups
, filter_set
);
978 n
= rb_last(&all_qgroups
->root
);
980 entry
= rb_entry(n
, struct btrfs_qgroup
, rb_node
);
982 ret
= filter_qgroup(entry
, filter_set
);
984 sort_tree_insert(sort_tree
, entry
, comp_set
);
986 update_columns_max_len(entry
);
991 static int __qgroups_search(int fd
, struct qgroup_lookup
*qgroup_lookup
)
994 struct btrfs_ioctl_search_args args
;
995 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
996 struct btrfs_ioctl_search_header
*sh
;
997 unsigned long off
= 0;
1000 struct btrfs_qgroup_info_item
*info
;
1001 struct btrfs_qgroup_limit_item
*limit
;
1002 struct btrfs_qgroup
*bq
;
1003 struct btrfs_qgroup
*bq1
;
1010 memset(&args
, 0, sizeof(args
));
1012 sk
->tree_id
= BTRFS_QUOTA_TREE_OBJECTID
;
1013 sk
->max_type
= BTRFS_QGROUP_RELATION_KEY
;
1014 sk
->min_type
= BTRFS_QGROUP_INFO_KEY
;
1015 sk
->max_objectid
= (u64
)-1;
1016 sk
->max_offset
= (u64
)-1;
1017 sk
->max_transid
= (u64
)-1;
1018 sk
->nr_items
= 4096;
1020 qgroup_lookup_init(qgroup_lookup
);
1023 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
1027 "ERROR: can't perform the search - %s\n",
1031 /* the ioctl returns the number of item it found in nr_items */
1032 if (sk
->nr_items
== 0)
1037 * for each item, pull the key out of the header and then
1038 * read the root_ref item it contains
1040 for (i
= 0; i
< sk
->nr_items
; i
++) {
1041 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
1045 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
1046 info
= (struct btrfs_qgroup_info_item
*)
1048 a1
= btrfs_stack_qgroup_info_generation(info
);
1049 a2
= btrfs_stack_qgroup_info_referenced(info
);
1051 btrfs_stack_qgroup_info_referenced_compressed
1053 a4
= btrfs_stack_qgroup_info_exclusive(info
);
1055 btrfs_stack_qgroup_info_exclusive_compressed
1057 add_qgroup(qgroup_lookup
, sh
->offset
, a1
, a2
,
1058 a3
, a4
, a5
, 0, 0, 0, 0, 0, 0, 0);
1059 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
1060 limit
= (struct btrfs_qgroup_limit_item
*)
1063 a1
= btrfs_stack_qgroup_limit_flags(limit
);
1064 a2
= btrfs_stack_qgroup_limit_max_referenced
1066 a3
= btrfs_stack_qgroup_limit_max_exclusive
1068 a4
= btrfs_stack_qgroup_limit_rsv_referenced
1070 a5
= btrfs_stack_qgroup_limit_rsv_exclusive
1072 add_qgroup(qgroup_lookup
, sh
->offset
, 0, 0,
1073 0, 0, 0, a1
, a2
, a3
, a4
, a5
, 0, 0);
1074 } else if (sh
->type
== BTRFS_QGROUP_RELATION_KEY
) {
1075 if (sh
->offset
< sh
->objectid
)
1077 bq
= qgroup_tree_search(qgroup_lookup
,
1081 bq1
= qgroup_tree_search(qgroup_lookup
,
1085 add_qgroup(qgroup_lookup
, sh
->offset
, 0, 0,
1086 0, 0, 0, 0, 0, 0, 0, 0, bq
, bq1
);
1093 * record the mins in sk so we can make sure the
1094 * next search doesn't repeat this root
1096 sk
->min_type
= sh
->type
;
1097 sk
->min_offset
= sh
->offset
;
1098 sk
->min_objectid
= sh
->objectid
;
1100 sk
->nr_items
= 4096;
1102 * this iteration is done, step forward one qgroup for the next
1105 if (sk
->min_offset
< (u64
)-1)
1115 static void print_all_qgroups(struct qgroup_lookup
*qgroup_lookup
)
1119 struct btrfs_qgroup
*entry
;
1123 n
= rb_first(&qgroup_lookup
->root
);
1125 entry
= rb_entry(n
, struct btrfs_qgroup
, sort_node
);
1126 print_single_qgroup_table(entry
);
1131 int btrfs_show_qgroups(int fd
,
1132 struct btrfs_qgroup_filter_set
*filter_set
,
1133 struct btrfs_qgroup_comparer_set
*comp_set
)
1136 struct qgroup_lookup qgroup_lookup
;
1137 struct qgroup_lookup sort_tree
;
1140 ret
= __qgroups_search(fd
, &qgroup_lookup
);
1143 __filter_and_sort_qgroups(&qgroup_lookup
, &sort_tree
,
1144 filter_set
, comp_set
);
1145 print_all_qgroups(&sort_tree
);
1147 __free_all_qgroups(&qgroup_lookup
);
1148 btrfs_qgroup_free_filter_set(filter_set
);
1152 u64
btrfs_get_path_rootid(int fd
)
1155 struct btrfs_ioctl_ino_lookup_args args
;
1157 memset(&args
, 0, sizeof(args
));
1158 args
.objectid
= BTRFS_FIRST_FREE_OBJECTID
;
1160 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
1163 "ERROR: can't perform the search -%s\n",
1170 int btrfs_qgroup_parse_sort_string(char *opt_arg
,
1171 struct btrfs_qgroup_comparer_set
**comps
)
1179 while ((p
= strtok(opt_arg
, ",")) != NULL
) {
1181 ptr_argv
= all_sort_items
;
1184 if (strcmp(*ptr_argv
, p
) == 0) {
1189 if (strcmp(*ptr_argv
, p
) == 0) {
1206 } else if (*p
== '-') {
1212 what_to_sort
= btrfs_qgroup_get_sort_item(p
);
1213 if (what_to_sort
< 0)
1215 btrfs_qgroup_setup_comparer(comps
, what_to_sort
, order
);
1223 u64
parse_qgroupid(char *p
)
1225 char *s
= strchr(p
, '/');
1226 char *ptr_src_end
= p
+ strlen(p
);
1227 char *ptr_parse_end
= NULL
;
1232 id
= strtoull(p
, &ptr_parse_end
, 10);
1233 if (ptr_parse_end
!= ptr_src_end
)
1237 level
= strtoull(p
, &ptr_parse_end
, 10);
1238 if (ptr_parse_end
!= s
)
1241 id
= strtoull(s
+1, &ptr_parse_end
, 10);
1242 if (ptr_parse_end
!= ptr_src_end
)
1245 return (level
<< 48) | id
;
1247 fprintf(stderr
, "ERROR:invalid qgroupid\n");
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 fprintf(stderr
, "ERROR: Not enough memory\n");
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 fprintf(stderr
, "ERROR: bad qgroup specification\n");
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 fprintf(stderr
, "ERROR: bad copy specification\n");
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
;