btrfs-progs: switch column values to asserts
[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 #include "utils.h"
24 #include <errno.h>
25
26 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
27 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
28
29 struct qgroup_lookup {
30         struct rb_root root;
31 };
32
33 struct btrfs_qgroup {
34         struct rb_node rb_node;
35         struct rb_node sort_node;
36         /*
37          *all_parent_node is used to
38          *filter a qgroup's all parent
39          */
40         struct rb_node all_parent_node;
41         u64 qgroupid;
42
43         /*
44          * info_item
45          */
46         u64 generation;
47         u64 rfer;       /*referenced*/
48         u64 rfer_cmpr;  /*referenced compressed*/
49         u64 excl;       /*exclusive*/
50         u64 excl_cmpr;  /*exclusive compressed*/
51
52         /*
53          *limit_item
54          */
55         u64 flags;      /*which limits are set*/
56         u64 max_rfer;
57         u64 max_excl;
58         u64 rsv_rfer;
59         u64 rsv_excl;
60
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;
65 };
66
67 /*
68  * glue structure to represent the relations
69  * between qgroups
70  */
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;
76 };
77
78 /*
79  * qgroupid,rfer,excl default to set
80  */
81 static struct {
82         char *name;
83         char *column_name;
84         int need_print;
85         unsigned unit_mode;
86         int max_len;
87 } btrfs_qgroup_columns[] = {
88         {
89                 .name           = "qgroupid",
90                 .column_name    = "Qgroupid",
91                 .need_print     = 1,
92                 .unit_mode      = 0,
93                 .max_len        = 8,
94         },
95         {
96                 .name           = "rfer",
97                 .column_name    = "Rfer",
98                 .need_print     = 1,
99                 .unit_mode      = UNITS_DEFAULT,
100                 .max_len        = 12,
101         },
102         {
103                 .name           = "excl",
104                 .column_name    = "Excl",
105                 .need_print     = 1,
106                 .unit_mode      = UNITS_DEFAULT,
107                 .max_len        = 12,
108         },
109         {       .name           = "max_rfer",
110                 .column_name    = "Max_rfer",
111                 .need_print     = 0,
112                 .unit_mode      = UNITS_DEFAULT,
113                 .max_len        = 12,
114         },
115         {
116                 .name           = "max_excl",
117                 .column_name    = "Max_excl",
118                 .need_print     = 0,
119                 .unit_mode      = UNITS_DEFAULT,
120                 .max_len        = 12,
121         },
122         {
123                 .name           = "parent",
124                 .column_name    = "Parent",
125                 .need_print     = 0,
126                 .unit_mode      = 0,
127                 .max_len        = 7,
128         },
129         {
130                 .name           = "child",
131                 .column_name    = "Child",
132                 .need_print     = 0,
133                 .unit_mode      = 0,
134                 .max_len        = 5,
135         },
136         {
137                 .name           = NULL,
138                 .column_name    = NULL,
139                 .need_print     = 0,
140                 .unit_mode      = 0,
141         },
142 };
143
144 static btrfs_qgroup_filter_func all_filter_funcs[];
145 static btrfs_qgroup_comp_func all_comp_funcs[];
146
147 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
148 {
149         int i;
150
151         ASSERT(0 <= column && column <= BTRFS_QGROUP_ALL);
152
153         if (column < BTRFS_QGROUP_ALL) {
154                 btrfs_qgroup_columns[column].need_print = 1;
155                 return;
156         }
157         for (i = 0; i < BTRFS_QGROUP_ALL; i++)
158                 btrfs_qgroup_columns[i].need_print = 1;
159 }
160
161 void btrfs_qgroup_setup_units(unsigned unit_mode)
162 {
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;
167 }
168
169 static int print_parent_column(struct btrfs_qgroup *qgroup)
170 {
171         struct btrfs_qgroup_list *list = NULL;
172         int len = 0;
173
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))
179                         len += printf(",");
180         }
181         if (list_empty(&qgroup->qgroups))
182                 len += printf("---");
183
184         return len;
185 }
186
187 static int print_child_column(struct btrfs_qgroup *qgroup)
188 {
189         struct btrfs_qgroup_list *list = NULL;
190         int len = 0;
191
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))
197                         len += printf(",");
198         }
199         if (list_empty(&qgroup->members))
200                 len += printf("---");
201
202         return len;
203 }
204
205 static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
206                                           int len)
207 {
208         len = btrfs_qgroup_columns[column].max_len - len;
209         while (len--)
210                 printf(" ");
211 }
212
213 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
214                                 enum btrfs_qgroup_column_enum column)
215 {
216         int len;
217         int unit_mode = btrfs_qgroup_columns[column].unit_mode;
218         int max_len = btrfs_qgroup_columns[column].max_len;
219
220         ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
221
222         switch (column) {
223
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);
229                 break;
230         case BTRFS_QGROUP_RFER:
231                 len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
232                 break;
233         case BTRFS_QGROUP_EXCL:
234                 len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
235                 break;
236         case BTRFS_QGROUP_PARENT:
237                 len = print_parent_column(qgroup);
238                 print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
239                 break;
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));
243                 else
244                         len = printf("%*s", max_len, "none");
245                 break;
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));
249                 else
250                         len = printf("%*s", max_len, "none");
251                 break;
252         case BTRFS_QGROUP_CHILD:
253                 len = print_child_column(qgroup);
254                 print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
255                 break;
256         default:
257                 break;
258         }
259 }
260
261 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
262 {
263         int i;
264
265         for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
266                 if (!btrfs_qgroup_columns[i].need_print)
267                         continue;
268                 print_qgroup_column(qgroup, i);
269
270                 if (i != BTRFS_QGROUP_CHILD)
271                         printf(" ");
272         }
273         printf("\n");
274 }
275
276 static void print_table_head(void)
277 {
278         int i;
279         int len;
280         int max_len;
281
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)
285                         continue;
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);
289                 else
290                         printf("%*s", max_len, btrfs_qgroup_columns[i].name);
291                 printf(" ");
292         }
293         printf("\n");
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)
297                         continue;
298                 if ((i == BTRFS_QGROUP_QGROUPID) | (i == BTRFS_QGROUP_PARENT) |
299                         (i == BTRFS_QGROUP_CHILD)) {
300                         len = strlen(btrfs_qgroup_columns[i].name);
301                         while (len--)
302                                 printf("-");
303                         len = max_len - strlen(btrfs_qgroup_columns[i].name);
304                         while (len--)
305                                 printf(" ");
306                 } else {
307                         len = max_len - strlen(btrfs_qgroup_columns[i].name);
308                         while (len--)
309                                 printf(" ");
310                         len = strlen(btrfs_qgroup_columns[i].name);
311                         while (len--)
312                                 printf("-");
313                 }
314                 printf(" ");
315         }
316         printf("\n");
317 }
318
319 static void qgroup_lookup_init(struct qgroup_lookup *tree)
320 {
321         tree->root.rb_node = NULL;
322 }
323
324 static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
325                                     struct btrfs_qgroup *entry2,
326                                     int is_descending)
327 {
328
329         int ret;
330
331         if (entry1->qgroupid > entry2->qgroupid)
332                 ret = 1;
333         else if (entry1->qgroupid < entry2->qgroupid)
334                 ret = -1;
335         else
336                 ret = 0;
337
338         return is_descending ? -ret : ret;
339 }
340
341 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
342                                 struct btrfs_qgroup *entry2,
343                                 int is_descending)
344 {
345         int ret;
346
347         if (entry1->rfer > entry2->rfer)
348                 ret = 1;
349         else if (entry1->rfer < entry2->rfer)
350                 ret = -1;
351         else
352                 ret = 0;
353
354         return is_descending ? -ret : ret;
355 }
356
357 static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
358                                 struct btrfs_qgroup *entry2,
359                                 int is_descending)
360 {
361         int ret;
362
363         if (entry1->excl > entry2->excl)
364                 ret = 1;
365         else if (entry1->excl < entry2->excl)
366                 ret = -1;
367         else
368                 ret = 0;
369
370         return is_descending ? -ret : ret;
371 }
372
373 static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
374                                     struct btrfs_qgroup *entry2,
375                                     int is_descending)
376 {
377         int ret;
378
379         if (entry1->max_rfer > entry2->max_rfer)
380                 ret = 1;
381         else if (entry1->max_rfer < entry2->max_rfer)
382                 ret = -1;
383         else
384                 ret = 0;
385
386         return is_descending ? -ret : ret;
387 }
388
389 static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
390                                     struct btrfs_qgroup *entry2,
391                                     int is_descending)
392 {
393         int ret;
394
395         if (entry1->max_excl > entry2->max_excl)
396                 ret = 1;
397         else if (entry1->max_excl < entry2->max_excl)
398                 ret = -1;
399         else
400                 ret = 0;
401
402         return is_descending ? -ret : ret;
403 }
404
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
411 };
412
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,
420 };
421
422 static int  btrfs_qgroup_get_sort_item(char *sort_name)
423 {
424         int i;
425
426         for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
427                 if (strcmp(sort_name, all_sort_items[i]) == 0)
428                         return i;
429         }
430         return -1;
431 }
432
433 struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
434 {
435         struct btrfs_qgroup_comparer_set *set;
436         int size;
437         size = sizeof(struct btrfs_qgroup_comparer_set) +
438                BTRFS_QGROUP_NCOMPS_INCREASE *
439                sizeof(struct btrfs_qgroup_comparer);
440         set = calloc(1, size);
441         if (!set) {
442                 fprintf(stderr, "memory allocation failed\n");
443                 exit(1);
444         }
445
446         set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
447
448         return set;
449 }
450
451 void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
452 {
453         free(comp_set);
454 }
455
456 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
457                                 enum btrfs_qgroup_comp_enum comparer,
458                                 int is_descending)
459 {
460         struct btrfs_qgroup_comparer_set *set = *comp_set;
461         int size;
462
463         ASSERT(set != NULL);
464         ASSERT(comparer < BTRFS_QGROUP_COMP_MAX);
465         ASSERT(set->ncomps <= set->total);
466
467         if (set->ncomps == set->total) {
468                 void *tmp;
469
470                 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
471                 size = sizeof(*set) +
472                        size * sizeof(struct btrfs_qgroup_comparer);
473                 tmp = set;
474                 set = realloc(set, size);
475                 if (!set) {
476                         fprintf(stderr, "memory allocation failed\n");
477                         free(tmp);
478                         exit(1);
479                 }
480
481                 memset(&set->comps[set->total], 0,
482                        BTRFS_QGROUP_NCOMPS_INCREASE *
483                        sizeof(struct btrfs_qgroup_comparer));
484                 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
485                 *comp_set = set;
486         }
487
488         ASSERT(set->comps[set->ncomps].comp_func != NULL);
489
490         set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
491         set->comps[set->ncomps].is_descending = is_descending;
492         set->ncomps++;
493         return 0;
494 }
495
496 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
497                      struct btrfs_qgroup_comparer_set *set)
498 {
499         int qgroupid_compared = 0;
500         int i, ret = 0;
501
502         if (!set || !set->ncomps)
503                 goto comp_qgroupid;
504
505         for (i = 0; i < set->ncomps; i++) {
506                 if (!set->comps[i].comp_func)
507                         break;
508
509                 ret = set->comps[i].comp_func(entry1, entry2,
510                                               set->comps[i].is_descending);
511                 if (ret)
512                         return ret;
513
514                 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
515                         qgroupid_compared = 1;
516         }
517
518         if (!qgroupid_compared) {
519 comp_qgroupid:
520                 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
521         }
522
523         return ret;
524 }
525
526 /*
527  * insert a new root into the tree.  returns the existing root entry
528  * if one is already there.  qgroupid is used
529  * as the key
530  */
531 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
532                               struct btrfs_qgroup *ins)
533 {
534
535         struct rb_node **p = &root_tree->root.rb_node;
536         struct rb_node *parent = NULL;
537         struct btrfs_qgroup *curr;
538         int ret;
539
540         while (*p) {
541                 parent = *p;
542                 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
543
544                 ret = comp_entry_with_qgroupid(ins, curr, 0);
545                 if (ret < 0)
546                         p = &(*p)->rb_left;
547                 else if (ret > 0)
548                         p = &(*p)->rb_right;
549                 else
550                         return -EEXIST;
551         }
552         rb_link_node(&ins->rb_node, parent, p);
553         rb_insert_color(&ins->rb_node, &root_tree->root);
554         return 0;
555 }
556
557 /*
558  *find a given qgroupid in the tree. We return the smallest one,
559  *rb_next can be used to move forward looking for more if required
560  */
561 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
562                                                u64 qgroupid)
563 {
564         struct rb_node *n = root_tree->root.rb_node;
565         struct btrfs_qgroup *entry;
566         struct btrfs_qgroup tmp;
567         int ret;
568
569         tmp.qgroupid = qgroupid;
570
571         while (n) {
572                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
573
574                 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
575                 if (ret < 0)
576                         n = n->rb_left;
577                 else if (ret > 0)
578                         n = n->rb_right;
579                 else
580                         return entry;
581
582         }
583         return NULL;
584 }
585
586 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
587                          u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
588                          u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
589                          u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
590                          struct btrfs_qgroup *child)
591 {
592         struct btrfs_qgroup *bq;
593         struct btrfs_qgroup_list *list;
594
595         bq = qgroup_tree_search(qgroup_lookup, qgroupid);
596         if (!bq || bq->qgroupid != qgroupid)
597                 return -ENOENT;
598
599         if (generation)
600                 bq->generation = generation;
601         if (rfer)
602                 bq->rfer = rfer;
603         if (rfer_cmpr)
604                 bq->rfer_cmpr = rfer_cmpr;
605         if (excl)
606                 bq->excl = excl;
607         if (excl_cmpr)
608                 bq->excl_cmpr = excl_cmpr;
609         if (flags)
610                 bq->flags = flags;
611         if (max_rfer)
612                 bq->max_rfer = max_rfer;
613         if (max_excl)
614                 bq->max_excl = max_excl;
615         if (rsv_rfer)
616                 bq->rsv_rfer = rsv_rfer;
617         if (pa && child) {
618                 list = malloc(sizeof(*list));
619                 if (!list) {
620                         fprintf(stderr, "memory allocation failed\n");
621                         exit(1);
622                 }
623                 list->qgroup = pa;
624                 list->member = child;
625                 list_add_tail(&list->next_qgroup, &child->qgroups);
626                 list_add_tail(&list->next_member, &pa->members);
627         }
628         return 0;
629 }
630
631 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
632                       u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
633                       u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
634                       u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
635                       struct btrfs_qgroup *child)
636 {
637         struct btrfs_qgroup *bq;
638         struct btrfs_qgroup_list *list;
639         int ret;
640
641         ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
642                             rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
643                             max_excl, rsv_rfer, rsv_excl, parent, child);
644         if (!ret)
645                 return 0;
646
647         bq = calloc(1, sizeof(*bq));
648         if (!bq) {
649                 printf("memory allocation failed\n");
650                 exit(1);
651         }
652         if (qgroupid) {
653                 bq->qgroupid = qgroupid;
654                 INIT_LIST_HEAD(&bq->qgroups);
655                 INIT_LIST_HEAD(&bq->members);
656         }
657         if (generation)
658                 bq->generation = generation;
659         if (rfer)
660                 bq->rfer = rfer;
661         if (rfer_cmpr)
662                 bq->rfer_cmpr = rfer_cmpr;
663         if (excl)
664                 bq->excl = excl;
665         if (excl_cmpr)
666                 bq->excl_cmpr = excl_cmpr;
667         if (flags)
668                 bq->flags = flags;
669         if (max_rfer)
670                 bq->max_rfer = max_rfer;
671         if (max_excl)
672                 bq->max_excl = max_excl;
673         if (rsv_rfer)
674                 bq->rsv_rfer = rsv_rfer;
675         if (parent && child) {
676                 list = malloc(sizeof(*list));
677                 if (!list) {
678                         fprintf(stderr, "memory allocation failed\n");
679                         exit(1);
680                 }
681                 list->qgroup = parent;
682                 list->member = child;
683                 list_add_tail(&list->next_qgroup, &child->qgroups);
684                 list_add_tail(&list->next_member, &parent->members);
685         }
686         ret = qgroup_tree_insert(qgroup_lookup, bq);
687         if (ret) {
688                 printf("failed to insert tree %llu\n",
689                        bq->qgroupid);
690                 exit(1);
691         }
692         return ret;
693 }
694
695 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
696 {
697         struct btrfs_qgroup_list *list;
698         while (!list_empty(&bq->qgroups)) {
699                 list = list_entry((&bq->qgroups)->next,
700                                   struct btrfs_qgroup_list,
701                                   next_qgroup);
702                 list_del(&list->next_qgroup);
703                 list_del(&list->next_member);
704                 free(list);
705         }
706         while (!list_empty(&bq->members)) {
707                 list = list_entry((&bq->members)->next,
708                                   struct btrfs_qgroup_list,
709                                   next_member);
710                 list_del(&list->next_qgroup);
711                 list_del(&list->next_member);
712                 free(list);
713         }
714         free(bq);
715 }
716
717 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
718 {
719         struct btrfs_qgroup *entry;
720         struct rb_node *n;
721
722         n = rb_first(&root_tree->root);
723         while (n) {
724                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
725                 rb_erase(n, &root_tree->root);
726                 __free_btrfs_qgroup(entry);
727
728                 n = rb_first(&root_tree->root);
729         }
730 }
731
732 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
733                                     struct btrfs_qgroup *bq)
734 {
735         struct rb_node **p = &sort_tree->root.rb_node;
736         struct rb_node *parent = NULL;
737         struct btrfs_qgroup *curr;
738         int ret;
739
740         while (*p) {
741                 parent = *p;
742                 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
743
744                 ret = comp_entry_with_qgroupid(bq, curr, 0);
745                 if (ret < 0)
746                         p = &(*p)->rb_left;
747                 else if (ret > 0)
748                         p = &(*p)->rb_right;
749                 else
750                         return -EEXIST;
751         }
752         rb_link_node(&bq->all_parent_node, parent, p);
753         rb_insert_color(&bq->all_parent_node, &sort_tree->root);
754         return 0;
755 }
756
757 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
758 {
759         struct btrfs_qgroup *qgroup =
760                 (struct btrfs_qgroup *)(unsigned long)data;
761
762         if (data == 0)
763                 return 0;
764         if (qgroup->qgroupid == bq->qgroupid)
765                 return 1;
766         return 0;
767 }
768
769 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
770 {
771         struct qgroup_lookup lookup;
772         struct qgroup_lookup *ql = &lookup;
773         struct btrfs_qgroup_list *list;
774         struct rb_node *n;
775         struct btrfs_qgroup *qgroup =
776                          (struct btrfs_qgroup *)(unsigned long)data;
777
778         if (data == 0)
779                 return 0;
780         if (bq->qgroupid == qgroup->qgroupid)
781                 return 1;
782
783         qgroup_lookup_init(ql);
784         filter_all_parent_insert(ql, qgroup);
785         n = rb_first(&ql->root);
786         while (n) {
787                 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
788                 if (!list_empty(&qgroup->qgroups)) {
789                         list_for_each_entry(list, &qgroup->qgroups,
790                                             next_qgroup) {
791                                 if ((list->qgroup)->qgroupid == bq->qgroupid)
792                                         return 1;
793                                 filter_all_parent_insert(ql, list->qgroup);
794                         }
795                 }
796                 rb_erase(n, &ql->root);
797                 n = rb_first(&ql->root);
798         }
799         return 0;
800 }
801
802 static btrfs_qgroup_filter_func all_filter_funcs[] = {
803         [BTRFS_QGROUP_FILTER_PARENT]            = filter_by_parent,
804         [BTRFS_QGROUP_FILTER_ALL_PARENT]        = filter_by_all_parent,
805 };
806
807 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
808 {
809         struct btrfs_qgroup_filter_set *set;
810         int size;
811
812         size = sizeof(struct btrfs_qgroup_filter_set) +
813                BTRFS_QGROUP_NFILTERS_INCREASE *
814                sizeof(struct btrfs_qgroup_filter);
815         set = calloc(1, size);
816         if (!set) {
817                 fprintf(stderr, "memory allocation failed\n");
818                 exit(1);
819         }
820         set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
821
822         return set;
823 }
824
825 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
826 {
827         free(filter_set);
828 }
829
830 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
831                               enum btrfs_qgroup_filter_enum filter, u64 data)
832 {
833         struct btrfs_qgroup_filter_set *set = *filter_set;
834         int size;
835
836         ASSERT(set != NULL);
837         ASSERT(filter < BTRFS_QGROUP_FILTER_MAX);
838         ASSERT(set->nfilters <= set->total);
839
840         if (set->nfilters == set->total) {
841                 void *tmp;
842
843                 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
844                 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
845
846                 tmp = set;
847                 set = realloc(set, size);
848                 if (!set) {
849                         fprintf(stderr, "memory allocation failed\n");
850                         free(tmp);
851                         exit(1);
852                 }
853                 memset(&set->filters[set->total], 0,
854                        BTRFS_QGROUP_NFILTERS_INCREASE *
855                        sizeof(struct btrfs_qgroup_filter));
856                 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
857                 *filter_set = set;
858         }
859
860         ASSERT(set->filters[set->nfilters].filter_func != NULL);
861         set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
862         set->filters[set->nfilters].data = data;
863         set->nfilters++;
864         return 0;
865 }
866
867 static int filter_qgroup(struct btrfs_qgroup *bq,
868                          struct btrfs_qgroup_filter_set *set)
869 {
870         int i, ret;
871
872         if (!set || !set->nfilters)
873                 return 1;
874         for (i = 0; i < set->nfilters; i++) {
875                 if (!set->filters[i].filter_func)
876                         break;
877                 ret = set->filters[i].filter_func(bq, set->filters[i].data);
878                 if (!ret)
879                         return 0;
880         }
881         return 1;
882 }
883
884 static void pre_process_filter_set(struct qgroup_lookup *lookup,
885                                    struct btrfs_qgroup_filter_set *set)
886 {
887         int i;
888         struct btrfs_qgroup *qgroup_for_filter = NULL;
889
890         for (i = 0; i < set->nfilters; i++) {
891
892                 if (set->filters[i].filter_func == filter_by_all_parent
893                     || set->filters[i].filter_func == filter_by_parent) {
894                         qgroup_for_filter = qgroup_tree_search(lookup,
895                                             set->filters[i].data);
896                         set->filters[i].data =
897                                  (u64)(unsigned long)qgroup_for_filter;
898                 }
899         }
900 }
901
902 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
903                             struct btrfs_qgroup *bq,
904                             struct btrfs_qgroup_comparer_set *comp_set)
905 {
906         struct rb_node **p = &sort_tree->root.rb_node;
907         struct rb_node *parent = NULL;
908         struct btrfs_qgroup *curr;
909         int ret;
910
911         while (*p) {
912                 parent = *p;
913                 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
914
915                 ret = sort_comp(bq, curr, comp_set);
916                 if (ret < 0)
917                         p = &(*p)->rb_left;
918                 else if (ret > 0)
919                         p = &(*p)->rb_right;
920                 else
921                         return -EEXIST;
922         }
923         rb_link_node(&bq->sort_node, parent, p);
924         rb_insert_color(&bq->sort_node, &sort_tree->root);
925         return 0;
926 }
927
928 static void __update_columns_max_len(struct btrfs_qgroup *bq,
929                                      enum btrfs_qgroup_column_enum column)
930 {
931         struct btrfs_qgroup_list *list = NULL;
932         char tmp[100];
933         int len;
934         unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
935
936         ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
937
938         switch (column) {
939
940         case BTRFS_QGROUP_QGROUPID:
941                 sprintf(tmp, "%llu/%llu",
942                         btrfs_qgroup_level(bq->qgroupid),
943                         btrfs_qgroup_subvid(bq->qgroupid));
944                 len = strlen(tmp);
945                 if (btrfs_qgroup_columns[column].max_len < len)
946                         btrfs_qgroup_columns[column].max_len = len;
947                 break;
948         case BTRFS_QGROUP_RFER:
949                 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
950                 if (btrfs_qgroup_columns[column].max_len < len)
951                         btrfs_qgroup_columns[column].max_len = len;
952                 break;
953         case BTRFS_QGROUP_EXCL:
954                 len = strlen(pretty_size_mode(bq->excl, unit_mode));
955                 if (btrfs_qgroup_columns[column].max_len < len)
956                         btrfs_qgroup_columns[column].max_len = len;
957                 break;
958         case BTRFS_QGROUP_MAX_RFER:
959                 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
960                 if (btrfs_qgroup_columns[column].max_len < len)
961                         btrfs_qgroup_columns[column].max_len = len;
962                 break;
963         case BTRFS_QGROUP_MAX_EXCL:
964                 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
965                 if (btrfs_qgroup_columns[column].max_len < len)
966                         btrfs_qgroup_columns[column].max_len = len;
967                 break;
968         case BTRFS_QGROUP_PARENT:
969                 len = 0;
970                 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
971                         len += sprintf(tmp, "%llu/%llu",
972                                 btrfs_qgroup_level(list->qgroup->qgroupid),
973                                 btrfs_qgroup_subvid(list->qgroup->qgroupid));
974                         if (!list_is_last(&list->next_qgroup, &bq->qgroups))
975                                 len += 1;
976                 }
977                 if (btrfs_qgroup_columns[column].max_len < len)
978                         btrfs_qgroup_columns[column].max_len = len;
979                 break;
980         case BTRFS_QGROUP_CHILD:
981                 len = 0;
982                 list_for_each_entry(list, &bq->members, next_member) {
983                         len += sprintf(tmp, "%llu/%llu",
984                                 btrfs_qgroup_level(list->member->qgroupid),
985                                 btrfs_qgroup_subvid(list->member->qgroupid));
986                         if (!list_is_last(&list->next_member, &bq->members))
987                                 len += 1;
988                 }
989                 if (btrfs_qgroup_columns[column].max_len < len)
990                         btrfs_qgroup_columns[column].max_len = len;
991                 break;
992         default:
993                 break;
994         }
995
996 }
997
998 static void update_columns_max_len(struct btrfs_qgroup *bq)
999 {
1000         int i;
1001
1002         for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
1003                 if (!btrfs_qgroup_columns[i].need_print)
1004                         continue;
1005                 __update_columns_max_len(bq, i);
1006         }
1007 }
1008
1009 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
1010                                  struct qgroup_lookup *sort_tree,
1011                                  struct btrfs_qgroup_filter_set *filter_set,
1012                                  struct btrfs_qgroup_comparer_set *comp_set)
1013 {
1014         struct rb_node *n;
1015         struct btrfs_qgroup *entry;
1016         int ret;
1017
1018         qgroup_lookup_init(sort_tree);
1019         pre_process_filter_set(all_qgroups, filter_set);
1020
1021         n = rb_last(&all_qgroups->root);
1022         while (n) {
1023                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
1024
1025                 ret = filter_qgroup(entry, filter_set);
1026                 if (ret) {
1027                         sort_tree_insert(sort_tree, entry, comp_set);
1028
1029                         update_columns_max_len(entry);
1030                 }
1031                 n = rb_prev(n);
1032         }
1033 }
1034
1035 static inline void print_status_flag_warning(u64 flags)
1036 {
1037         if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
1038                 fprintf(stderr,
1039                 "WARNING: Quota disabled, qgroup data may be out of date\n");
1040         else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
1041                 fprintf(stderr,
1042                 "WARNING: Rescan is running, qgroup data may be incorrect\n");
1043         else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
1044                 fprintf(stderr,
1045                 "WARNING: Qgroup data inconsistent, rescan recommended\n");
1046 }
1047
1048 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1049 {
1050         int ret;
1051         struct btrfs_ioctl_search_args args;
1052         struct btrfs_ioctl_search_key *sk = &args.key;
1053         struct btrfs_ioctl_search_header *sh;
1054         unsigned long off = 0;
1055         unsigned int i;
1056         struct btrfs_qgroup_info_item *info;
1057         struct btrfs_qgroup_limit_item *limit;
1058         struct btrfs_qgroup *bq;
1059         struct btrfs_qgroup *bq1;
1060         u64 a1;
1061         u64 a2;
1062         u64 a3;
1063         u64 a4;
1064         u64 a5;
1065
1066         memset(&args, 0, sizeof(args));
1067
1068         sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1069         sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1070         sk->min_type = BTRFS_QGROUP_STATUS_KEY;
1071         sk->max_objectid = (u64)-1;
1072         sk->max_offset = (u64)-1;
1073         sk->max_transid = (u64)-1;
1074         sk->nr_items = 4096;
1075
1076         qgroup_lookup_init(qgroup_lookup);
1077
1078         while (1) {
1079                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1080                 if (ret < 0) {
1081                         fprintf(stderr,
1082                                 "ERROR: can't perform the search - %s\n",
1083                                 strerror(errno));
1084                         return ret;
1085                 }
1086                 /* the ioctl returns the number of item it found in nr_items */
1087                 if (sk->nr_items == 0)
1088                         break;
1089
1090                 off = 0;
1091                 /*
1092                  * for each item, pull the key out of the header and then
1093                  * read the root_ref item it contains
1094                  */
1095                 for (i = 0; i < sk->nr_items; i++) {
1096                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
1097                                                                   off);
1098                         off += sizeof(*sh);
1099
1100                         if (btrfs_search_header_type(sh)
1101                             == BTRFS_QGROUP_STATUS_KEY) {
1102                                 struct btrfs_qgroup_status_item *si;
1103                                 u64 flags;
1104
1105                                 si = (struct btrfs_qgroup_status_item *)
1106                                      (args.buf + off);
1107                                 flags = btrfs_stack_qgroup_status_flags(si);
1108                                 print_status_flag_warning(flags);
1109                         } else if (btrfs_search_header_type(sh)
1110                                    == BTRFS_QGROUP_INFO_KEY) {
1111                                 info = (struct btrfs_qgroup_info_item *)
1112                                        (args.buf + off);
1113                                 a1 = btrfs_stack_qgroup_info_generation(info);
1114                                 a2 = btrfs_stack_qgroup_info_referenced(info);
1115                                 a3 =
1116                                   btrfs_stack_qgroup_info_referenced_compressed
1117                                   (info);
1118                                 a4 = btrfs_stack_qgroup_info_exclusive(info);
1119                                 a5 =
1120                                   btrfs_stack_qgroup_info_exclusive_compressed
1121                                   (info);
1122                                 add_qgroup(qgroup_lookup,
1123                                         btrfs_search_header_offset(sh), a1,
1124                                         a2, a3, a4, a5, 0, 0, 0, 0, 0, NULL,
1125                                         NULL);
1126                         } else if (btrfs_search_header_type(sh)
1127                                    == BTRFS_QGROUP_LIMIT_KEY) {
1128                                 limit = (struct btrfs_qgroup_limit_item *)
1129                                     (args.buf + off);
1130
1131                                 a1 = btrfs_stack_qgroup_limit_flags(limit);
1132                                 a2 = btrfs_stack_qgroup_limit_max_referenced
1133                                      (limit);
1134                                 a3 = btrfs_stack_qgroup_limit_max_exclusive
1135                                      (limit);
1136                                 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1137                                      (limit);
1138                                 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1139                                      (limit);
1140                                 add_qgroup(qgroup_lookup,
1141                                            btrfs_search_header_offset(sh), 0,
1142                                            0, 0, 0, 0, a1, a2, a3, a4, a5,
1143                                            NULL, NULL);
1144                         } else if (btrfs_search_header_type(sh)
1145                                    == BTRFS_QGROUP_RELATION_KEY) {
1146                                 if (btrfs_search_header_offset(sh)
1147                                     < btrfs_search_header_objectid(sh))
1148                                         goto skip;
1149                                 bq = qgroup_tree_search(qgroup_lookup,
1150                                         btrfs_search_header_offset(sh));
1151                                 if (!bq)
1152                                         goto skip;
1153                                 bq1 = qgroup_tree_search(qgroup_lookup,
1154                                          btrfs_search_header_objectid(sh));
1155                                 if (!bq1)
1156                                         goto skip;
1157                                 add_qgroup(qgroup_lookup,
1158                                            btrfs_search_header_offset(sh), 0,
1159                                            0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1160                         } else
1161                                 goto done;
1162 skip:
1163                         off += btrfs_search_header_len(sh);
1164
1165                         /*
1166                          * record the mins in sk so we can make sure the
1167                          * next search doesn't repeat this root
1168                          */
1169                         sk->min_type = btrfs_search_header_type(sh);
1170                         sk->min_offset = btrfs_search_header_offset(sh);
1171                         sk->min_objectid = btrfs_search_header_objectid(sh);
1172                 }
1173                 sk->nr_items = 4096;
1174                 /*
1175                  * this iteration is done, step forward one qgroup for the next
1176                  * ioctl
1177                  */
1178                 if (sk->min_offset < (u64)-1)
1179                         sk->min_offset++;
1180                 else
1181                         break;
1182         }
1183
1184 done:
1185         return ret;
1186 }
1187
1188 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1189 {
1190
1191         struct rb_node *n;
1192         struct btrfs_qgroup *entry;
1193
1194         print_table_head();
1195
1196         n = rb_first(&qgroup_lookup->root);
1197         while (n) {
1198                 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1199                 print_single_qgroup_table(entry);
1200                 n = rb_next(n);
1201         }
1202 }
1203
1204 int btrfs_show_qgroups(int fd,
1205                        struct btrfs_qgroup_filter_set *filter_set,
1206                        struct btrfs_qgroup_comparer_set *comp_set)
1207 {
1208
1209         struct qgroup_lookup qgroup_lookup;
1210         struct qgroup_lookup sort_tree;
1211         int ret;
1212
1213         ret = __qgroups_search(fd, &qgroup_lookup);
1214         if (ret)
1215                 return ret;
1216         __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1217                                   filter_set, comp_set);
1218         print_all_qgroups(&sort_tree);
1219
1220         __free_all_qgroups(&qgroup_lookup);
1221         btrfs_qgroup_free_filter_set(filter_set);
1222         btrfs_qgroup_free_comparer_set(comp_set);
1223         return ret;
1224 }
1225
1226 u64 btrfs_get_path_rootid(int fd)
1227 {
1228         int  ret;
1229         struct btrfs_ioctl_ino_lookup_args args;
1230
1231         memset(&args, 0, sizeof(args));
1232         args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1233
1234         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1235         if (ret < 0) {
1236                 fprintf(stderr,
1237                         "ERROR: can't perform the search - %s\n",
1238                         strerror(errno));
1239                 return ret;
1240         }
1241         return args.treeid;
1242 }
1243
1244 int btrfs_qgroup_parse_sort_string(char *opt_arg,
1245                                    struct btrfs_qgroup_comparer_set **comps)
1246 {
1247         int order;
1248         int flag;
1249         char *p;
1250         char **ptr_argv;
1251         int what_to_sort;
1252
1253         while ((p = strtok(opt_arg, ",")) != NULL) {
1254                 flag = 0;
1255                 ptr_argv = all_sort_items;
1256
1257                 while (*ptr_argv) {
1258                         if (strcmp(*ptr_argv, p) == 0) {
1259                                 flag = 1;
1260                                 break;
1261                         } else {
1262                                 p++;
1263                                 if (strcmp(*ptr_argv, p) == 0) {
1264                                         flag = 1;
1265                                         p--;
1266                                         break;
1267                                 }
1268                                 p--;
1269                         }
1270                         ptr_argv++;
1271                 }
1272
1273                 if (flag == 0)
1274                         return -1;
1275
1276                 else {
1277                         if (*p == '+') {
1278                                 order = 0;
1279                                 p++;
1280                         } else if (*p == '-') {
1281                                 order = 1;
1282                                 p++;
1283                         } else
1284                                 order = 0;
1285
1286                         what_to_sort = btrfs_qgroup_get_sort_item(p);
1287                         if (what_to_sort < 0)
1288                                 return -1;
1289                         btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1290                 }
1291                 opt_arg = NULL;
1292         }
1293
1294         return 0;
1295 }
1296
1297 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1298 {
1299         return sizeof(*p) + sizeof(p->qgroups[0]) *
1300                             (p->num_qgroups + 2 * p->num_ref_copies +
1301                              2 * p->num_excl_copies);
1302 }
1303
1304 static int
1305 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1306 {
1307         struct btrfs_qgroup_inherit *out;
1308         int nitems = 0;
1309
1310         if (*inherit) {
1311                 nitems = (*inherit)->num_qgroups +
1312                          (*inherit)->num_ref_copies +
1313                          (*inherit)->num_excl_copies;
1314         }
1315
1316         out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1317         if (out == NULL) {
1318                 fprintf(stderr, "ERROR: Not enough memory\n");
1319                 return -ENOMEM;
1320         }
1321
1322         if (*inherit) {
1323                 struct btrfs_qgroup_inherit *i = *inherit;
1324                 int s = sizeof(out->qgroups[0]);
1325
1326                 out->num_qgroups = i->num_qgroups;
1327                 out->num_ref_copies = i->num_ref_copies;
1328                 out->num_excl_copies = i->num_excl_copies;
1329                 memcpy(out->qgroups, i->qgroups, pos * s);
1330                 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1331                        (nitems - pos) * s);
1332         }
1333         free(*inherit);
1334         *inherit = out;
1335
1336         return 0;
1337 }
1338
1339 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1340 {
1341         int ret;
1342         u64 qgroupid = parse_qgroupid(arg);
1343         int pos = 0;
1344
1345         if (qgroupid == 0) {
1346                 fprintf(stderr, "ERROR: bad qgroup specification\n");
1347                 return -EINVAL;
1348         }
1349
1350         if (*inherit)
1351                 pos = (*inherit)->num_qgroups;
1352         ret = qgroup_inherit_realloc(inherit, 1, pos);
1353         if (ret)
1354                 return ret;
1355
1356         (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1357
1358         return 0;
1359 }
1360
1361 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1362                             int type)
1363 {
1364         int ret;
1365         u64 qgroup_src;
1366         u64 qgroup_dst;
1367         char *p;
1368         int pos = 0;
1369
1370         p = strchr(arg, ':');
1371         if (!p) {
1372 bad:
1373                 fprintf(stderr, "ERROR: bad copy specification\n");
1374                 return -EINVAL;
1375         }
1376         *p = 0;
1377         qgroup_src = parse_qgroupid(arg);
1378         qgroup_dst = parse_qgroupid(p + 1);
1379         *p = ':';
1380
1381         if (!qgroup_src || !qgroup_dst)
1382                 goto bad;
1383
1384         if (*inherit)
1385                 pos = (*inherit)->num_qgroups +
1386                       (*inherit)->num_ref_copies * 2 * type;
1387
1388         ret = qgroup_inherit_realloc(inherit, 2, pos);
1389         if (ret)
1390                 return ret;
1391
1392         (*inherit)->qgroups[pos++] = qgroup_src;
1393         (*inherit)->qgroups[pos++] = qgroup_dst;
1394
1395         if (!type)
1396                 ++(*inherit)->num_ref_copies;
1397         else
1398                 ++(*inherit)->num_excl_copies;
1399
1400         return 0;
1401 }