Btrfs-progs: introduces '-c' option to print the ID of the child qgroups
[platform/upstream/btrfs-progs.git] / qgroup.c
1 /*
2  * Copyright (C) 2012 STRATO.  All rights reserved.
3  *
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.
7  *
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.
12  *
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.
17  */
18
19 #include "qgroup.h"
20 #include <sys/ioctl.h>
21 #include "ctree.h"
22 #include "ioctl.h"
23
24 struct qgroup_lookup {
25         struct rb_root root;
26 };
27
28 struct btrfs_qgroup {
29         struct rb_node rb_node;
30         u64 qgroupid;
31
32         /*
33          * info_item
34          */
35         u64 generation;
36         u64 rfer;       /*referenced*/
37         u64 rfer_cmpr;  /*referenced compressed*/
38         u64 excl;       /*exclusive*/
39         u64 excl_cmpr;  /*exclusive compressed*/
40
41         /*
42          *limit_item
43          */
44         u64 flags;      /*which limits are set*/
45         u64 max_rfer;
46         u64 max_excl;
47         u64 rsv_rfer;
48         u64 rsv_excl;
49
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;
54 };
55
56 /*
57  * glue structure to represent the relations
58  * between qgroups
59  */
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;
65 };
66
67 /*
68  * qgroupid,rfer,excl default to set
69  */
70 struct {
71         char *name;
72         char *column_name;
73         int need_print;
74 } btrfs_qgroup_columns[] = {
75         {
76                 .name           = "qgroupid",
77                 .column_name    = "Qgroupid",
78                 .need_print     = 1,
79         },
80         {
81                 .name           = "rfer",
82                 .column_name    = "Rfer",
83                 .need_print     = 1,
84         },
85         {
86                 .name           = "excl",
87                 .column_name    = "Excl",
88                 .need_print     = 1,
89         },
90         {
91                 .name           = "parent",
92                 .column_name    = "Parent",
93                 .need_print     = 0,
94         },
95         {
96                 .name           = "child",
97                 .column_name    = "Child",
98                 .need_print     = 0,
99         },
100         {
101                 .name           = NULL,
102                 .column_name    = NULL,
103                 .need_print     = 0,
104         },
105 };
106
107 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
108 {
109         int i;
110
111         BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
112
113         if (column < BTRFS_QGROUP_ALL) {
114                 btrfs_qgroup_columns[column].need_print = 1;
115                 return;
116         }
117         for (i = 0; i < BTRFS_QGROUP_ALL; i++)
118                 btrfs_qgroup_columns[i].need_print = 1;
119 }
120
121 static void print_parent_column(struct btrfs_qgroup *qgroup)
122 {
123         struct btrfs_qgroup_list *list = NULL;
124
125         list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
126                 printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
127                       ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
128                 if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
129                         printf(",");
130         }
131         if (list_empty(&qgroup->qgroups))
132                 printf("---");
133 }
134
135 static void print_child_column(struct btrfs_qgroup *qgroup)
136 {
137         struct btrfs_qgroup_list *list = NULL;
138
139         list_for_each_entry(list, &qgroup->members, next_member) {
140                 printf("%llu/%llu", (list->member)->qgroupid >> 48,
141                       ((1ll << 48) - 1) & (list->member)->qgroupid);
142                 if (!list_is_last(&list->next_member, &qgroup->members))
143                         printf(",");
144         }
145         if (list_empty(&qgroup->members))
146                 printf("---");
147 }
148
149 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
150                                 enum btrfs_qgroup_column_enum column)
151 {
152         BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
153
154         switch (column) {
155
156         case BTRFS_QGROUP_QGROUPID:
157                 printf("%llu/%llu", qgroup->qgroupid >> 48,
158                        ((1ll << 48) - 1) & qgroup->qgroupid);
159                 break;
160         case BTRFS_QGROUP_RFER:
161                 printf("%lld", qgroup->rfer);
162                 break;
163         case BTRFS_QGROUP_EXCL:
164                 printf("%lld", qgroup->excl);
165                 break;
166         case BTRFS_QGROUP_PARENT:
167                 print_parent_column(qgroup);
168                 break;
169         case BTRFS_QGROUP_CHILD:
170                 print_child_column(qgroup);
171                 break;
172         default:
173                 break;
174         }
175 }
176
177 static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
178 {
179         int i;
180
181         for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
182                 if (!btrfs_qgroup_columns[i].need_print)
183                         continue;
184                 print_qgroup_column(qgroup, i);
185
186                 if (i != BTRFS_QGROUP_ALL - 1)
187                         printf(" ");
188         }
189         printf("\n");
190 }
191
192 static void qgroup_lookup_init(struct qgroup_lookup *tree)
193 {
194         tree->root.rb_node = NULL;
195 }
196
197 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
198                                     struct btrfs_qgroup *entry2,
199                                     int is_descending)
200 {
201
202         int ret;
203
204         if (entry1->qgroupid > entry2->qgroupid)
205                 ret = 1;
206         else if (entry1->qgroupid < entry2->qgroupid)
207                 ret = -1;
208         else
209                 ret = 0;
210
211         return is_descending ? -ret : ret;
212 }
213
214 /*
215  * insert a new root into the tree.  returns the existing root entry
216  * if one is already there.  qgroupid is used
217  * as the key
218  */
219 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
220                               struct btrfs_qgroup *ins)
221 {
222
223         struct rb_node **p = &root_tree->root.rb_node;
224         struct rb_node *parent = NULL;
225         struct btrfs_qgroup *curr;
226         int ret;
227
228         while (*p) {
229                 parent = *p;
230                 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
231
232                 ret = comp_entry_with_qgroupid(ins, curr, 0);
233                 if (ret < 0)
234                         p = &(*p)->rb_left;
235                 else if (ret > 0)
236                         p = &(*p)->rb_right;
237                 else
238                         return -EEXIST;
239         }
240         rb_link_node(&ins->rb_node, parent, p);
241         rb_insert_color(&ins->rb_node, &root_tree->root);
242         return 0;
243 }
244
245 /*
246  *find a given qgroupid in the tree. We return the smallest one,
247  *rb_next can be used to move forward looking for more if required
248  */
249 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
250                                                u64 qgroupid)
251 {
252         struct rb_node *n = root_tree->root.rb_node;
253         struct btrfs_qgroup *entry;
254         struct btrfs_qgroup tmp;
255         int ret;
256
257         tmp.qgroupid = qgroupid;
258
259         while (n) {
260                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
261
262                 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
263                 if (ret < 0)
264                         n = n->rb_left;
265                 else if (ret > 0)
266                         n = n->rb_right;
267                 else
268                         return entry;
269
270         }
271         return NULL;
272 }
273
274 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
275                          u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
276                          u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
277                          u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
278                          struct btrfs_qgroup *child)
279 {
280         struct btrfs_qgroup *bq;
281         struct btrfs_qgroup_list *list;
282
283         bq = qgroup_tree_search(qgroup_lookup, qgroupid);
284         if (!bq || bq->qgroupid != qgroupid)
285                 return -ENOENT;
286
287         if (generation)
288                 bq->generation = generation;
289         if (rfer)
290                 bq->rfer = rfer;
291         if (rfer_cmpr)
292                 bq->rfer_cmpr = rfer_cmpr;
293         if (excl)
294                 bq->excl = excl;
295         if (excl_cmpr)
296                 bq->excl_cmpr = excl_cmpr;
297         if (flags)
298                 bq->flags = flags;
299         if (max_rfer)
300                 bq->max_rfer = max_rfer;
301         if (max_excl)
302                 bq->max_excl = max_excl;
303         if (rsv_rfer)
304                 bq->rsv_rfer = rsv_rfer;
305         if (pa && child) {
306                 list = malloc(sizeof(*list));
307                 if (!list) {
308                         fprintf(stderr, "memory allocation failed\n");
309                         exit(1);
310                 }
311                 list->qgroup = pa;
312                 list->member = child;
313                 list_add_tail(&list->next_qgroup, &child->qgroups);
314                 list_add_tail(&list->next_member, &pa->members);
315         }
316         return 0;
317 }
318
319 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
320                       u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
321                       u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
322                       u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
323                       struct btrfs_qgroup *child)
324 {
325         struct btrfs_qgroup *bq;
326         struct btrfs_qgroup_list *list;
327         int ret;
328
329         ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
330                             rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
331                             max_excl, rsv_rfer, rsv_excl, parent, child);
332         if (!ret)
333                 return 0;
334
335         bq = malloc(sizeof(*bq));
336         if (!bq) {
337                 printf("memory allocation failed\n");
338                 exit(1);
339         }
340         memset(bq, 0, sizeof(*bq));
341         if (qgroupid) {
342                 bq->qgroupid = qgroupid;
343                 INIT_LIST_HEAD(&bq->qgroups);
344                 INIT_LIST_HEAD(&bq->members);
345         }
346         if (generation)
347                 bq->generation = generation;
348         if (rfer)
349                 bq->rfer = rfer;
350         if (rfer_cmpr)
351                 bq->rfer_cmpr = rfer_cmpr;
352         if (excl)
353                 bq->excl = excl;
354         if (excl_cmpr)
355                 bq->excl_cmpr = excl_cmpr;
356         if (flags)
357                 bq->flags = flags;
358         if (max_rfer)
359                 bq->max_rfer = max_rfer;
360         if (max_excl)
361                 bq->max_excl = max_excl;
362         if (rsv_rfer)
363                 bq->rsv_rfer = rsv_rfer;
364         if (parent && child) {
365                 list = malloc(sizeof(*list));
366                 if (!list) {
367                         fprintf(stderr, "memory allocation failed\n");
368                         exit(1);
369                 }
370                 list->qgroup = parent;
371                 list->member = child;
372                 list_add_tail(&list->next_qgroup, &child->qgroups);
373                 list_add_tail(&list->next_member, &parent->members);
374         }
375         ret = qgroup_tree_insert(qgroup_lookup, bq);
376         if (ret) {
377                 printf("failed to insert tree %llu\n",
378                        bq->qgroupid);
379                 exit(1);
380         }
381         return ret;
382 }
383
384 void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
385 {
386         struct btrfs_qgroup_list *list;
387         while (!list_empty(&bq->qgroups)) {
388                 list = list_entry((&bq->qgroups)->next,
389                                   struct btrfs_qgroup_list,
390                                   next_qgroup);
391                 list_del(&list->next_qgroup);
392                 list_del(&list->next_member);
393                 free(list);
394         }
395         while (!list_empty(&bq->members)) {
396                 list = list_entry((&bq->members)->next,
397                                   struct btrfs_qgroup_list,
398                                   next_member);
399                 list_del(&list->next_qgroup);
400                 list_del(&list->next_member);
401                 free(list);
402         }
403         free(bq);
404 }
405
406 void __free_all_qgroups(struct qgroup_lookup *root_tree)
407 {
408         struct btrfs_qgroup *entry;
409         struct rb_node *n;
410
411         n = rb_first(&root_tree->root);
412         while (n) {
413                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
414                 rb_erase(n, &root_tree->root);
415                 __free_btrfs_qgroup(entry);
416
417                 n = rb_first(&root_tree->root);
418         }
419 }
420
421 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
422 {
423         int ret;
424         struct btrfs_ioctl_search_args args;
425         struct btrfs_ioctl_search_key *sk = &args.key;
426         struct btrfs_ioctl_search_header *sh;
427         unsigned long off = 0;
428         unsigned int i;
429         int e;
430         struct btrfs_qgroup_info_item *info;
431         struct btrfs_qgroup_limit_item *limit;
432         struct btrfs_qgroup *bq;
433         struct btrfs_qgroup *bq1;
434         u64 a1;
435         u64 a2;
436         u64 a3;
437         u64 a4;
438         u64 a5;
439
440         memset(&args, 0, sizeof(args));
441
442         sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
443         sk->max_type = BTRFS_QGROUP_RELATION_KEY;
444         sk->min_type = BTRFS_QGROUP_INFO_KEY;
445         sk->max_objectid = (u64)-1;
446         sk->max_offset = (u64)-1;
447         sk->max_transid = (u64)-1;
448         sk->nr_items = 4096;
449
450         qgroup_lookup_init(qgroup_lookup);
451
452         while (1) {
453                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
454                 e = errno;
455                 if (ret < 0) {
456                         fprintf(stderr,
457                                 "ERROR: can't perform the search - %s\n",
458                                 strerror(e));
459                         return ret;
460                 }
461                 /* the ioctl returns the number of item it found in nr_items */
462                 if (sk->nr_items == 0)
463                         break;
464
465                 off = 0;
466                 /*
467                  * for each item, pull the key out of the header and then
468                  * read the root_ref item it contains
469                  */
470                 for (i = 0; i < sk->nr_items; i++) {
471                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
472                                                                   off);
473                         off += sizeof(*sh);
474
475                         if (sh->type == BTRFS_QGROUP_INFO_KEY) {
476                                 info = (struct btrfs_qgroup_info_item *)
477                                        (args.buf + off);
478                                 a1 = btrfs_stack_qgroup_info_generation(info);
479                                 a2 = btrfs_stack_qgroup_info_referenced(info);
480                                 a3 =
481                                   btrfs_stack_qgroup_info_referenced_compressed
482                                   (info);
483                                 a4 = btrfs_stack_qgroup_info_exclusive(info);
484                                 a5 =
485                                   btrfs_stack_qgroup_info_exclusive_compressed
486                                   (info);
487                                 add_qgroup(qgroup_lookup, sh->offset, a1, a2,
488                                            a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
489                         } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
490                                 limit = (struct btrfs_qgroup_limit_item *)
491                                     (args.buf + off);
492
493                                 a1 = btrfs_stack_qgroup_limit_flags(limit);
494                                 a2 = btrfs_stack_qgroup_limit_max_referenced
495                                      (limit);
496                                 a3 = btrfs_stack_qgroup_limit_max_exclusive
497                                      (limit);
498                                 a4 = btrfs_stack_qgroup_limit_rsv_referenced
499                                      (limit);
500                                 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
501                                      (limit);
502                                 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
503                                            0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
504                         } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
505                                 if (sh->offset < sh->objectid)
506                                         goto skip;
507                                 bq = qgroup_tree_search(qgroup_lookup,
508                                                         sh->offset);
509                                 if (!bq)
510                                         goto skip;
511                                 bq1 = qgroup_tree_search(qgroup_lookup,
512                                                          sh->objectid);
513                                 if (!bq1)
514                                         goto skip;
515                                 add_qgroup(qgroup_lookup, sh->offset, 0, 0,
516                                            0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
517                         } else
518                                 goto done;
519 skip:
520                         off += sh->len;
521
522                         /*
523                          * record the mins in sk so we can make sure the
524                          * next search doesn't repeat this root
525                          */
526                         sk->min_type = sh->type;
527                         sk->min_offset = sh->offset;
528                         sk->min_objectid = sh->objectid;
529                 }
530                 sk->nr_items = 4096;
531                 /*
532                  * this iteration is done, step forward one qgroup for the next
533                  * ioctl
534                  */
535                 if (sk->min_offset < (u64)-1)
536                         sk->min_offset++;
537                 else
538                         break;
539         }
540
541 done:
542         return ret;
543 }
544
545 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
546 {
547
548         struct rb_node *n;
549         struct btrfs_qgroup *entry;
550
551         n = rb_first(&qgroup_lookup->root);
552         while (n) {
553                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
554                 print_single_qgroup_default(entry);
555                 n = rb_next(n);
556         }
557 }
558
559 int btrfs_show_qgroups(int fd)
560 {
561
562         struct qgroup_lookup qgroup_lookup;
563         int ret;
564
565         ret = __qgroups_search(fd, &qgroup_lookup);
566         if (ret)
567                 return ret;
568
569         print_all_qgroups(&qgroup_lookup);
570         __free_all_qgroups(&qgroup_lookup);
571
572         return ret;
573 }
574
575 u64 parse_qgroupid(char *p)
576 {
577         char *s = strchr(p, '/');
578         char *ptr_src_end = p + strlen(p);
579         char *ptr_parse_end = NULL;
580         u64 level;
581         u64 id;
582
583         if (!s) {
584                 id = strtoull(p, &ptr_parse_end, 10);
585                 if (ptr_parse_end != ptr_src_end)
586                         goto err;
587                 return id;
588         }
589         level = strtoull(p, &ptr_parse_end, 10);
590         if (ptr_parse_end != s)
591                 goto err;
592
593         id = strtoull(s+1, &ptr_parse_end, 10);
594         if (ptr_parse_end != ptr_src_end)
595                 goto  err;
596
597         return (level << 48) | id;
598 err:
599         fprintf(stderr, "ERROR:invalid qgroupid\n");
600         exit(-1);
601 }
602
603 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
604 {
605         return sizeof(*p) + sizeof(p->qgroups[0]) *
606                             (p->num_qgroups + 2 * p->num_ref_copies +
607                              2 * p->num_excl_copies);
608 }
609
610 static int
611 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
612 {
613         struct btrfs_qgroup_inherit *out;
614         int nitems = 0;
615
616         if (*inherit) {
617                 nitems = (*inherit)->num_qgroups +
618                          (*inherit)->num_ref_copies +
619                          (*inherit)->num_excl_copies;
620         }
621
622         out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
623         if (out == NULL) {
624                 fprintf(stderr, "ERROR: Not enough memory\n");
625                 return 13;
626         }
627
628         if (*inherit) {
629                 struct btrfs_qgroup_inherit *i = *inherit;
630                 int s = sizeof(out->qgroups[0]);
631
632                 out->num_qgroups = i->num_qgroups;
633                 out->num_ref_copies = i->num_ref_copies;
634                 out->num_excl_copies = i->num_excl_copies;
635                 memcpy(out->qgroups, i->qgroups, pos * s);
636                 memcpy(out->qgroups + pos + n, i->qgroups + pos,
637                        (nitems - pos) * s);
638         }
639         free(*inherit);
640         *inherit = out;
641
642         return 0;
643 }
644
645 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
646 {
647         int ret;
648         u64 qgroupid = parse_qgroupid(arg);
649         int pos = 0;
650
651         if (qgroupid == 0) {
652                 fprintf(stderr, "ERROR: bad qgroup specification\n");
653                 return 12;
654         }
655
656         if (*inherit)
657                 pos = (*inherit)->num_qgroups;
658         ret = qgroup_inherit_realloc(inherit, 1, pos);
659         if (ret)
660                 return ret;
661
662         (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
663
664         return 0;
665 }
666
667 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
668                             int type)
669 {
670         int ret;
671         u64 qgroup_src;
672         u64 qgroup_dst;
673         char *p;
674         int pos = 0;
675
676         p = strchr(arg, ':');
677         if (!p) {
678 bad:
679                 fprintf(stderr, "ERROR: bad copy specification\n");
680                 return 12;
681         }
682         *p = 0;
683         qgroup_src = parse_qgroupid(arg);
684         qgroup_dst = parse_qgroupid(p + 1);
685         *p = ':';
686
687         if (!qgroup_src || !qgroup_dst)
688                 goto bad;
689
690         if (*inherit)
691                 pos = (*inherit)->num_qgroups +
692                       (*inherit)->num_ref_copies * 2 * type;
693
694         ret = qgroup_inherit_realloc(inherit, 2, pos);
695         if (ret)
696                 return ret;
697
698         (*inherit)->qgroups[pos++] = qgroup_src;
699         (*inherit)->qgroups[pos++] = qgroup_dst;
700
701         if (!type)
702                 ++(*inherit)->num_ref_copies;
703         else
704                 ++(*inherit)->num_excl_copies;
705
706         return 0;
707 }