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)
26 struct qgroup_lookup {
31 struct rb_node rb_node;
32 struct rb_node sort_node;
34 *all_parent_node is used to
35 *filter a qgroup's all parent
37 struct rb_node all_parent_node;
44 u64 rfer; /*referenced*/
45 u64 rfer_cmpr; /*referenced compressed*/
46 u64 excl; /*exclusive*/
47 u64 excl_cmpr; /*exclusive compressed*/
52 u64 flags; /*which limits are set*/
58 /*qgroups this group is member of*/
59 struct list_head qgroups;
60 /*qgroups that are members of this group*/
61 struct list_head members;
65 * glue structure to represent the relations
68 struct btrfs_qgroup_list {
69 struct list_head next_qgroup;
70 struct list_head next_member;
71 struct btrfs_qgroup *qgroup;
72 struct btrfs_qgroup *member;
76 * qgroupid,rfer,excl default to set
82 } btrfs_qgroup_columns[] = {
85 .column_name = "Qgroupid",
90 .column_name = "Rfer",
95 .column_name = "Excl",
99 .column_name = "Max_rfer",
104 .column_name = "Max_excl",
109 .column_name = "Parent",
114 .column_name = "Child",
124 static btrfs_qgroup_filter_func all_filter_funcs[];
126 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
130 BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
132 if (column < BTRFS_QGROUP_ALL) {
133 btrfs_qgroup_columns[column].need_print = 1;
136 for (i = 0; i < BTRFS_QGROUP_ALL; i++)
137 btrfs_qgroup_columns[i].need_print = 1;
140 static void print_parent_column(struct btrfs_qgroup *qgroup)
142 struct btrfs_qgroup_list *list = NULL;
144 list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
145 printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
146 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
147 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
150 if (list_empty(&qgroup->qgroups))
154 static void print_child_column(struct btrfs_qgroup *qgroup)
156 struct btrfs_qgroup_list *list = NULL;
158 list_for_each_entry(list, &qgroup->members, next_member) {
159 printf("%llu/%llu", (list->member)->qgroupid >> 48,
160 ((1ll << 48) - 1) & (list->member)->qgroupid);
161 if (!list_is_last(&list->next_member, &qgroup->members))
164 if (list_empty(&qgroup->members))
168 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
169 enum btrfs_qgroup_column_enum column)
171 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
175 case BTRFS_QGROUP_QGROUPID:
176 printf("%llu/%llu", qgroup->qgroupid >> 48,
177 ((1ll << 48) - 1) & qgroup->qgroupid);
179 case BTRFS_QGROUP_RFER:
180 printf("%lld", qgroup->rfer);
182 case BTRFS_QGROUP_EXCL:
183 printf("%lld", qgroup->excl);
185 case BTRFS_QGROUP_PARENT:
186 print_parent_column(qgroup);
188 case BTRFS_QGROUP_MAX_RFER:
189 printf("%llu", qgroup->max_rfer);
191 case BTRFS_QGROUP_MAX_EXCL:
192 printf("%llu", qgroup->max_excl);
194 case BTRFS_QGROUP_CHILD:
195 print_child_column(qgroup);
202 static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
206 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
207 if (!btrfs_qgroup_columns[i].need_print)
209 print_qgroup_column(qgroup, i);
211 if (i != BTRFS_QGROUP_ALL - 1)
217 static void qgroup_lookup_init(struct qgroup_lookup *tree)
219 tree->root.rb_node = NULL;
222 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
223 struct btrfs_qgroup *entry2,
229 if (entry1->qgroupid > entry2->qgroupid)
231 else if (entry1->qgroupid < entry2->qgroupid)
236 return is_descending ? -ret : ret;
240 * insert a new root into the tree. returns the existing root entry
241 * if one is already there. qgroupid is used
244 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
245 struct btrfs_qgroup *ins)
248 struct rb_node **p = &root_tree->root.rb_node;
249 struct rb_node *parent = NULL;
250 struct btrfs_qgroup *curr;
255 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
257 ret = comp_entry_with_qgroupid(ins, curr, 0);
265 rb_link_node(&ins->rb_node, parent, p);
266 rb_insert_color(&ins->rb_node, &root_tree->root);
271 *find a given qgroupid in the tree. We return the smallest one,
272 *rb_next can be used to move forward looking for more if required
274 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
277 struct rb_node *n = root_tree->root.rb_node;
278 struct btrfs_qgroup *entry;
279 struct btrfs_qgroup tmp;
282 tmp.qgroupid = qgroupid;
285 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
287 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
299 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
300 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
301 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
302 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
303 struct btrfs_qgroup *child)
305 struct btrfs_qgroup *bq;
306 struct btrfs_qgroup_list *list;
308 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
309 if (!bq || bq->qgroupid != qgroupid)
313 bq->generation = generation;
317 bq->rfer_cmpr = rfer_cmpr;
321 bq->excl_cmpr = excl_cmpr;
325 bq->max_rfer = max_rfer;
327 bq->max_excl = max_excl;
329 bq->rsv_rfer = rsv_rfer;
331 list = malloc(sizeof(*list));
333 fprintf(stderr, "memory allocation failed\n");
337 list->member = child;
338 list_add_tail(&list->next_qgroup, &child->qgroups);
339 list_add_tail(&list->next_member, &pa->members);
344 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
345 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
346 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
347 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
348 struct btrfs_qgroup *child)
350 struct btrfs_qgroup *bq;
351 struct btrfs_qgroup_list *list;
354 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
355 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
356 max_excl, rsv_rfer, rsv_excl, parent, child);
360 bq = malloc(sizeof(*bq));
362 printf("memory allocation failed\n");
365 memset(bq, 0, sizeof(*bq));
367 bq->qgroupid = qgroupid;
368 INIT_LIST_HEAD(&bq->qgroups);
369 INIT_LIST_HEAD(&bq->members);
372 bq->generation = generation;
376 bq->rfer_cmpr = rfer_cmpr;
380 bq->excl_cmpr = excl_cmpr;
384 bq->max_rfer = max_rfer;
386 bq->max_excl = max_excl;
388 bq->rsv_rfer = rsv_rfer;
389 if (parent && child) {
390 list = malloc(sizeof(*list));
392 fprintf(stderr, "memory allocation failed\n");
395 list->qgroup = parent;
396 list->member = child;
397 list_add_tail(&list->next_qgroup, &child->qgroups);
398 list_add_tail(&list->next_member, &parent->members);
400 ret = qgroup_tree_insert(qgroup_lookup, bq);
402 printf("failed to insert tree %llu\n",
409 void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
411 struct btrfs_qgroup_list *list;
412 while (!list_empty(&bq->qgroups)) {
413 list = list_entry((&bq->qgroups)->next,
414 struct btrfs_qgroup_list,
416 list_del(&list->next_qgroup);
417 list_del(&list->next_member);
420 while (!list_empty(&bq->members)) {
421 list = list_entry((&bq->members)->next,
422 struct btrfs_qgroup_list,
424 list_del(&list->next_qgroup);
425 list_del(&list->next_member);
431 void __free_all_qgroups(struct qgroup_lookup *root_tree)
433 struct btrfs_qgroup *entry;
436 n = rb_first(&root_tree->root);
438 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
439 rb_erase(n, &root_tree->root);
440 __free_btrfs_qgroup(entry);
442 n = rb_first(&root_tree->root);
446 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
447 struct btrfs_qgroup *bq)
449 struct rb_node **p = &sort_tree->root.rb_node;
450 struct rb_node *parent = NULL;
451 struct btrfs_qgroup *curr;
456 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
458 ret = comp_entry_with_qgroupid(bq, curr, 0);
466 rb_link_node(&bq->all_parent_node, parent, p);
467 rb_insert_color(&bq->all_parent_node, &sort_tree->root);
471 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
473 struct btrfs_qgroup *qgroup =
474 (struct btrfs_qgroup *)(unsigned long)data;
478 if (qgroup->qgroupid == bq->qgroupid)
483 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
485 struct qgroup_lookup lookup;
486 struct qgroup_lookup *ql = &lookup;
487 struct btrfs_qgroup_list *list;
489 struct btrfs_qgroup *qgroup =
490 (struct btrfs_qgroup *)(unsigned long)data;
494 if (bq->qgroupid == qgroup->qgroupid)
497 qgroup_lookup_init(ql);
498 filter_all_parent_insert(ql, qgroup);
499 n = rb_first(&ql->root);
501 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
502 if (!list_empty(&qgroup->qgroups)) {
503 list_for_each_entry(list, &qgroup->qgroups,
505 if ((list->qgroup)->qgroupid == bq->qgroupid)
507 filter_all_parent_insert(ql, list->qgroup);
510 rb_erase(n, &ql->root);
511 n = rb_first(&ql->root);
516 static btrfs_qgroup_filter_func all_filter_funcs[] = {
517 [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent,
518 [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent,
521 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
523 struct btrfs_qgroup_filter_set *set;
526 size = sizeof(struct btrfs_qgroup_filter_set) +
527 BTRFS_QGROUP_NFILTERS_INCREASE *
528 sizeof(struct btrfs_qgroup_filter);
531 fprintf(stderr, "memory allocation failed\n");
534 memset(set, 0, size);
535 set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
540 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
545 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
546 enum btrfs_qgroup_filter_enum filter, u64 data)
548 struct btrfs_qgroup_filter_set *set = *filter_set;
552 BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
553 BUG_ON(set->nfilters > set->total);
555 if (set->nfilters == set->total) {
556 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
557 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
559 set = realloc(set, size);
561 fprintf(stderr, "memory allocation failed\n");
564 memset(&set->filters[set->total], 0,
565 BTRFS_QGROUP_NFILTERS_INCREASE *
566 sizeof(struct btrfs_qgroup_filter));
567 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
570 BUG_ON(set->filters[set->nfilters].filter_func);
571 set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
572 set->filters[set->nfilters].data = data;
577 static int filter_qgroup(struct btrfs_qgroup *bq,
578 struct btrfs_qgroup_filter_set *set)
582 if (!set || !set->nfilters)
584 for (i = 0; i < set->nfilters; i++) {
585 if (!set->filters[i].filter_func)
587 ret = set->filters[i].filter_func(bq, set->filters[i].data);
594 static void pre_process_filter_set(struct qgroup_lookup *lookup,
595 struct btrfs_qgroup_filter_set *set)
598 struct btrfs_qgroup *qgroup_for_filter = NULL;
600 for (i = 0; i < set->nfilters; i++) {
602 if (set->filters[i].filter_func == filter_by_all_parent
603 || set->filters[i].filter_func == filter_by_parent) {
604 qgroup_for_filter = qgroup_tree_search(lookup,
605 set->filters[i].data);
606 set->filters[i].data =
607 (u64)(unsigned long)qgroup_for_filter;
612 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
613 struct btrfs_qgroup *bq)
615 struct rb_node **p = &sort_tree->root.rb_node;
616 struct rb_node *parent = NULL;
617 struct btrfs_qgroup *curr;
622 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
624 ret = comp_entry_with_qgroupid(bq, curr, 0);
632 rb_link_node(&bq->sort_node, parent, p);
633 rb_insert_color(&bq->sort_node, &sort_tree->root);
637 static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups,
638 struct qgroup_lookup *sort_tree,
639 struct btrfs_qgroup_filter_set *filter_set)
642 struct btrfs_qgroup *entry;
645 qgroup_lookup_init(sort_tree);
646 pre_process_filter_set(all_qgroups, filter_set);
648 n = rb_last(&all_qgroups->root);
650 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
652 ret = filter_qgroup(entry, filter_set);
654 sort_tree_insert(sort_tree, entry);
659 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
662 struct btrfs_ioctl_search_args args;
663 struct btrfs_ioctl_search_key *sk = &args.key;
664 struct btrfs_ioctl_search_header *sh;
665 unsigned long off = 0;
668 struct btrfs_qgroup_info_item *info;
669 struct btrfs_qgroup_limit_item *limit;
670 struct btrfs_qgroup *bq;
671 struct btrfs_qgroup *bq1;
678 memset(&args, 0, sizeof(args));
680 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
681 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
682 sk->min_type = BTRFS_QGROUP_INFO_KEY;
683 sk->max_objectid = (u64)-1;
684 sk->max_offset = (u64)-1;
685 sk->max_transid = (u64)-1;
688 qgroup_lookup_init(qgroup_lookup);
691 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
695 "ERROR: can't perform the search - %s\n",
699 /* the ioctl returns the number of item it found in nr_items */
700 if (sk->nr_items == 0)
705 * for each item, pull the key out of the header and then
706 * read the root_ref item it contains
708 for (i = 0; i < sk->nr_items; i++) {
709 sh = (struct btrfs_ioctl_search_header *)(args.buf +
713 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
714 info = (struct btrfs_qgroup_info_item *)
716 a1 = btrfs_stack_qgroup_info_generation(info);
717 a2 = btrfs_stack_qgroup_info_referenced(info);
719 btrfs_stack_qgroup_info_referenced_compressed
721 a4 = btrfs_stack_qgroup_info_exclusive(info);
723 btrfs_stack_qgroup_info_exclusive_compressed
725 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
726 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
727 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
728 limit = (struct btrfs_qgroup_limit_item *)
731 a1 = btrfs_stack_qgroup_limit_flags(limit);
732 a2 = btrfs_stack_qgroup_limit_max_referenced
734 a3 = btrfs_stack_qgroup_limit_max_exclusive
736 a4 = btrfs_stack_qgroup_limit_rsv_referenced
738 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
740 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
741 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
742 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
743 if (sh->offset < sh->objectid)
745 bq = qgroup_tree_search(qgroup_lookup,
749 bq1 = qgroup_tree_search(qgroup_lookup,
753 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
754 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
761 * record the mins in sk so we can make sure the
762 * next search doesn't repeat this root
764 sk->min_type = sh->type;
765 sk->min_offset = sh->offset;
766 sk->min_objectid = sh->objectid;
770 * this iteration is done, step forward one qgroup for the next
773 if (sk->min_offset < (u64)-1)
783 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
787 struct btrfs_qgroup *entry;
789 n = rb_first(&qgroup_lookup->root);
791 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
792 print_single_qgroup_default(entry);
797 int btrfs_show_qgroups(int fd,
798 struct btrfs_qgroup_filter_set *filter_set)
801 struct qgroup_lookup qgroup_lookup;
802 struct qgroup_lookup sort_tree;
805 ret = __qgroups_search(fd, &qgroup_lookup);
808 __filter_all_qgroups(&qgroup_lookup, &sort_tree,
810 print_all_qgroups(&sort_tree);
812 __free_all_qgroups(&qgroup_lookup);
813 btrfs_qgroup_free_filter_set(filter_set);
817 u64 btrfs_get_path_rootid(int fd)
820 struct btrfs_ioctl_ino_lookup_args args;
822 memset(&args, 0, sizeof(args));
823 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
825 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
828 "ERROR: can't perform the search -%s\n",
835 u64 parse_qgroupid(char *p)
837 char *s = strchr(p, '/');
838 char *ptr_src_end = p + strlen(p);
839 char *ptr_parse_end = NULL;
844 id = strtoull(p, &ptr_parse_end, 10);
845 if (ptr_parse_end != ptr_src_end)
849 level = strtoull(p, &ptr_parse_end, 10);
850 if (ptr_parse_end != s)
853 id = strtoull(s+1, &ptr_parse_end, 10);
854 if (ptr_parse_end != ptr_src_end)
857 return (level << 48) | id;
859 fprintf(stderr, "ERROR:invalid qgroupid\n");
863 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
865 return sizeof(*p) + sizeof(p->qgroups[0]) *
866 (p->num_qgroups + 2 * p->num_ref_copies +
867 2 * p->num_excl_copies);
871 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
873 struct btrfs_qgroup_inherit *out;
877 nitems = (*inherit)->num_qgroups +
878 (*inherit)->num_ref_copies +
879 (*inherit)->num_excl_copies;
882 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
884 fprintf(stderr, "ERROR: Not enough memory\n");
889 struct btrfs_qgroup_inherit *i = *inherit;
890 int s = sizeof(out->qgroups[0]);
892 out->num_qgroups = i->num_qgroups;
893 out->num_ref_copies = i->num_ref_copies;
894 out->num_excl_copies = i->num_excl_copies;
895 memcpy(out->qgroups, i->qgroups, pos * s);
896 memcpy(out->qgroups + pos + n, i->qgroups + pos,
905 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
908 u64 qgroupid = parse_qgroupid(arg);
912 fprintf(stderr, "ERROR: bad qgroup specification\n");
917 pos = (*inherit)->num_qgroups;
918 ret = qgroup_inherit_realloc(inherit, 1, pos);
922 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
927 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
936 p = strchr(arg, ':');
939 fprintf(stderr, "ERROR: bad copy specification\n");
943 qgroup_src = parse_qgroupid(arg);
944 qgroup_dst = parse_qgroupid(p + 1);
947 if (!qgroup_src || !qgroup_dst)
951 pos = (*inherit)->num_qgroups +
952 (*inherit)->num_ref_copies * 2 * type;
954 ret = qgroup_inherit_realloc(inherit, 2, pos);
958 (*inherit)->qgroups[pos++] = qgroup_src;
959 (*inherit)->qgroups[pos++] = qgroup_dst;
962 ++(*inherit)->num_ref_copies;
964 ++(*inherit)->num_excl_copies;