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 struct qgroup_lookup {
29 struct rb_node rb_node;
36 u64 rfer; /*referenced*/
37 u64 rfer_cmpr; /*referenced compressed*/
38 u64 excl; /*exclusive*/
39 u64 excl_cmpr; /*exclusive compressed*/
44 u64 flags; /*which limits are set*/
50 /*qgroups this group is member of*/
51 struct list_head qgroups;
52 /*qgroups that are members of this group*/
53 struct list_head members;
57 * glue structure to represent the relations
60 struct btrfs_qgroup_list {
61 struct list_head next_qgroup;
62 struct list_head next_member;
63 struct btrfs_qgroup *qgroup;
64 struct btrfs_qgroup *member;
68 * qgroupid,rfer,excl default to set
74 } btrfs_qgroup_columns[] = {
77 .column_name = "Qgroupid",
82 .column_name = "Rfer",
87 .column_name = "Excl",
91 .column_name = "Max_rfer",
96 .column_name = "Max_excl",
101 .column_name = "Parent",
106 .column_name = "Child",
116 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
120 BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
122 if (column < BTRFS_QGROUP_ALL) {
123 btrfs_qgroup_columns[column].need_print = 1;
126 for (i = 0; i < BTRFS_QGROUP_ALL; i++)
127 btrfs_qgroup_columns[i].need_print = 1;
130 static void print_parent_column(struct btrfs_qgroup *qgroup)
132 struct btrfs_qgroup_list *list = NULL;
134 list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
135 printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
136 ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
137 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
140 if (list_empty(&qgroup->qgroups))
144 static void print_child_column(struct btrfs_qgroup *qgroup)
146 struct btrfs_qgroup_list *list = NULL;
148 list_for_each_entry(list, &qgroup->members, next_member) {
149 printf("%llu/%llu", (list->member)->qgroupid >> 48,
150 ((1ll << 48) - 1) & (list->member)->qgroupid);
151 if (!list_is_last(&list->next_member, &qgroup->members))
154 if (list_empty(&qgroup->members))
158 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
159 enum btrfs_qgroup_column_enum column)
161 BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
165 case BTRFS_QGROUP_QGROUPID:
166 printf("%llu/%llu", qgroup->qgroupid >> 48,
167 ((1ll << 48) - 1) & qgroup->qgroupid);
169 case BTRFS_QGROUP_RFER:
170 printf("%lld", qgroup->rfer);
172 case BTRFS_QGROUP_EXCL:
173 printf("%lld", qgroup->excl);
175 case BTRFS_QGROUP_PARENT:
176 print_parent_column(qgroup);
178 case BTRFS_QGROUP_MAX_RFER:
179 printf("%llu", qgroup->max_rfer);
181 case BTRFS_QGROUP_MAX_EXCL:
182 printf("%llu", qgroup->max_excl);
184 case BTRFS_QGROUP_CHILD:
185 print_child_column(qgroup);
192 static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
196 for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
197 if (!btrfs_qgroup_columns[i].need_print)
199 print_qgroup_column(qgroup, i);
201 if (i != BTRFS_QGROUP_ALL - 1)
207 static void qgroup_lookup_init(struct qgroup_lookup *tree)
209 tree->root.rb_node = NULL;
212 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
213 struct btrfs_qgroup *entry2,
219 if (entry1->qgroupid > entry2->qgroupid)
221 else if (entry1->qgroupid < entry2->qgroupid)
226 return is_descending ? -ret : ret;
230 * insert a new root into the tree. returns the existing root entry
231 * if one is already there. qgroupid is used
234 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
235 struct btrfs_qgroup *ins)
238 struct rb_node **p = &root_tree->root.rb_node;
239 struct rb_node *parent = NULL;
240 struct btrfs_qgroup *curr;
245 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
247 ret = comp_entry_with_qgroupid(ins, curr, 0);
255 rb_link_node(&ins->rb_node, parent, p);
256 rb_insert_color(&ins->rb_node, &root_tree->root);
261 *find a given qgroupid in the tree. We return the smallest one,
262 *rb_next can be used to move forward looking for more if required
264 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
267 struct rb_node *n = root_tree->root.rb_node;
268 struct btrfs_qgroup *entry;
269 struct btrfs_qgroup tmp;
272 tmp.qgroupid = qgroupid;
275 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
277 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
289 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
290 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
291 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
292 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
293 struct btrfs_qgroup *child)
295 struct btrfs_qgroup *bq;
296 struct btrfs_qgroup_list *list;
298 bq = qgroup_tree_search(qgroup_lookup, qgroupid);
299 if (!bq || bq->qgroupid != qgroupid)
303 bq->generation = generation;
307 bq->rfer_cmpr = rfer_cmpr;
311 bq->excl_cmpr = excl_cmpr;
315 bq->max_rfer = max_rfer;
317 bq->max_excl = max_excl;
319 bq->rsv_rfer = rsv_rfer;
321 list = malloc(sizeof(*list));
323 fprintf(stderr, "memory allocation failed\n");
327 list->member = child;
328 list_add_tail(&list->next_qgroup, &child->qgroups);
329 list_add_tail(&list->next_member, &pa->members);
334 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
335 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
336 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
337 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
338 struct btrfs_qgroup *child)
340 struct btrfs_qgroup *bq;
341 struct btrfs_qgroup_list *list;
344 ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
345 rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
346 max_excl, rsv_rfer, rsv_excl, parent, child);
350 bq = malloc(sizeof(*bq));
352 printf("memory allocation failed\n");
355 memset(bq, 0, sizeof(*bq));
357 bq->qgroupid = qgroupid;
358 INIT_LIST_HEAD(&bq->qgroups);
359 INIT_LIST_HEAD(&bq->members);
362 bq->generation = generation;
366 bq->rfer_cmpr = rfer_cmpr;
370 bq->excl_cmpr = excl_cmpr;
374 bq->max_rfer = max_rfer;
376 bq->max_excl = max_excl;
378 bq->rsv_rfer = rsv_rfer;
379 if (parent && child) {
380 list = malloc(sizeof(*list));
382 fprintf(stderr, "memory allocation failed\n");
385 list->qgroup = parent;
386 list->member = child;
387 list_add_tail(&list->next_qgroup, &child->qgroups);
388 list_add_tail(&list->next_member, &parent->members);
390 ret = qgroup_tree_insert(qgroup_lookup, bq);
392 printf("failed to insert tree %llu\n",
399 void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
401 struct btrfs_qgroup_list *list;
402 while (!list_empty(&bq->qgroups)) {
403 list = list_entry((&bq->qgroups)->next,
404 struct btrfs_qgroup_list,
406 list_del(&list->next_qgroup);
407 list_del(&list->next_member);
410 while (!list_empty(&bq->members)) {
411 list = list_entry((&bq->members)->next,
412 struct btrfs_qgroup_list,
414 list_del(&list->next_qgroup);
415 list_del(&list->next_member);
421 void __free_all_qgroups(struct qgroup_lookup *root_tree)
423 struct btrfs_qgroup *entry;
426 n = rb_first(&root_tree->root);
428 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
429 rb_erase(n, &root_tree->root);
430 __free_btrfs_qgroup(entry);
432 n = rb_first(&root_tree->root);
436 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
439 struct btrfs_ioctl_search_args args;
440 struct btrfs_ioctl_search_key *sk = &args.key;
441 struct btrfs_ioctl_search_header *sh;
442 unsigned long off = 0;
445 struct btrfs_qgroup_info_item *info;
446 struct btrfs_qgroup_limit_item *limit;
447 struct btrfs_qgroup *bq;
448 struct btrfs_qgroup *bq1;
455 memset(&args, 0, sizeof(args));
457 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
458 sk->max_type = BTRFS_QGROUP_RELATION_KEY;
459 sk->min_type = BTRFS_QGROUP_INFO_KEY;
460 sk->max_objectid = (u64)-1;
461 sk->max_offset = (u64)-1;
462 sk->max_transid = (u64)-1;
465 qgroup_lookup_init(qgroup_lookup);
468 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
472 "ERROR: can't perform the search - %s\n",
476 /* the ioctl returns the number of item it found in nr_items */
477 if (sk->nr_items == 0)
482 * for each item, pull the key out of the header and then
483 * read the root_ref item it contains
485 for (i = 0; i < sk->nr_items; i++) {
486 sh = (struct btrfs_ioctl_search_header *)(args.buf +
490 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
491 info = (struct btrfs_qgroup_info_item *)
493 a1 = btrfs_stack_qgroup_info_generation(info);
494 a2 = btrfs_stack_qgroup_info_referenced(info);
496 btrfs_stack_qgroup_info_referenced_compressed
498 a4 = btrfs_stack_qgroup_info_exclusive(info);
500 btrfs_stack_qgroup_info_exclusive_compressed
502 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
503 a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
504 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
505 limit = (struct btrfs_qgroup_limit_item *)
508 a1 = btrfs_stack_qgroup_limit_flags(limit);
509 a2 = btrfs_stack_qgroup_limit_max_referenced
511 a3 = btrfs_stack_qgroup_limit_max_exclusive
513 a4 = btrfs_stack_qgroup_limit_rsv_referenced
515 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
517 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
518 0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
519 } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
520 if (sh->offset < sh->objectid)
522 bq = qgroup_tree_search(qgroup_lookup,
526 bq1 = qgroup_tree_search(qgroup_lookup,
530 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
531 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
538 * record the mins in sk so we can make sure the
539 * next search doesn't repeat this root
541 sk->min_type = sh->type;
542 sk->min_offset = sh->offset;
543 sk->min_objectid = sh->objectid;
547 * this iteration is done, step forward one qgroup for the next
550 if (sk->min_offset < (u64)-1)
560 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
564 struct btrfs_qgroup *entry;
566 n = rb_first(&qgroup_lookup->root);
568 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
569 print_single_qgroup_default(entry);
574 int btrfs_show_qgroups(int fd)
577 struct qgroup_lookup qgroup_lookup;
580 ret = __qgroups_search(fd, &qgroup_lookup);
584 print_all_qgroups(&qgroup_lookup);
585 __free_all_qgroups(&qgroup_lookup);
590 u64 parse_qgroupid(char *p)
592 char *s = strchr(p, '/');
593 char *ptr_src_end = p + strlen(p);
594 char *ptr_parse_end = NULL;
599 id = strtoull(p, &ptr_parse_end, 10);
600 if (ptr_parse_end != ptr_src_end)
604 level = strtoull(p, &ptr_parse_end, 10);
605 if (ptr_parse_end != s)
608 id = strtoull(s+1, &ptr_parse_end, 10);
609 if (ptr_parse_end != ptr_src_end)
612 return (level << 48) | id;
614 fprintf(stderr, "ERROR:invalid qgroupid\n");
618 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
620 return sizeof(*p) + sizeof(p->qgroups[0]) *
621 (p->num_qgroups + 2 * p->num_ref_copies +
622 2 * p->num_excl_copies);
626 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
628 struct btrfs_qgroup_inherit *out;
632 nitems = (*inherit)->num_qgroups +
633 (*inherit)->num_ref_copies +
634 (*inherit)->num_excl_copies;
637 out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
639 fprintf(stderr, "ERROR: Not enough memory\n");
644 struct btrfs_qgroup_inherit *i = *inherit;
645 int s = sizeof(out->qgroups[0]);
647 out->num_qgroups = i->num_qgroups;
648 out->num_ref_copies = i->num_ref_copies;
649 out->num_excl_copies = i->num_excl_copies;
650 memcpy(out->qgroups, i->qgroups, pos * s);
651 memcpy(out->qgroups + pos + n, i->qgroups + pos,
660 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
663 u64 qgroupid = parse_qgroupid(arg);
667 fprintf(stderr, "ERROR: bad qgroup specification\n");
672 pos = (*inherit)->num_qgroups;
673 ret = qgroup_inherit_realloc(inherit, 1, pos);
677 (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
682 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
691 p = strchr(arg, ':');
694 fprintf(stderr, "ERROR: bad copy specification\n");
698 qgroup_src = parse_qgroupid(arg);
699 qgroup_dst = parse_qgroupid(p + 1);
702 if (!qgroup_src || !qgroup_dst)
706 pos = (*inherit)->num_qgroups +
707 (*inherit)->num_ref_copies * 2 * type;
709 ret = qgroup_inherit_realloc(inherit, 2, pos);
713 (*inherit)->qgroups[pos++] = qgroup_src;
714 (*inherit)->qgroups[pos++] = qgroup_dst;
717 ++(*inherit)->num_ref_copies;
719 ++(*inherit)->num_excl_copies;