btrfs-progs: qgroup: cleanup the redundant function add_qgroup
[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                 error("memory allocation failed");
443                 exit(1);
444         }
445
446         set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
447
448         return set;
449 }
450
451 int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
452                                 enum btrfs_qgroup_comp_enum comparer,
453                                 int is_descending)
454 {
455         struct btrfs_qgroup_comparer_set *set = *comp_set;
456         int size;
457
458         ASSERT(set != NULL);
459         ASSERT(comparer < BTRFS_QGROUP_COMP_MAX);
460         ASSERT(set->ncomps <= set->total);
461
462         if (set->ncomps == set->total) {
463                 void *tmp;
464
465                 size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
466                 size = sizeof(*set) +
467                        size * sizeof(struct btrfs_qgroup_comparer);
468                 tmp = set;
469                 set = realloc(set, size);
470                 if (!set) {
471                         error("memory allocation failed");
472                         free(tmp);
473                         exit(1);
474                 }
475
476                 memset(&set->comps[set->total], 0,
477                        BTRFS_QGROUP_NCOMPS_INCREASE *
478                        sizeof(struct btrfs_qgroup_comparer));
479                 set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
480                 *comp_set = set;
481         }
482
483         ASSERT(set->comps[set->ncomps].comp_func == NULL);
484
485         set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
486         set->comps[set->ncomps].is_descending = is_descending;
487         set->ncomps++;
488         return 0;
489 }
490
491 static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
492                      struct btrfs_qgroup_comparer_set *set)
493 {
494         int qgroupid_compared = 0;
495         int i, ret = 0;
496
497         if (!set || !set->ncomps)
498                 goto comp_qgroupid;
499
500         for (i = 0; i < set->ncomps; i++) {
501                 if (!set->comps[i].comp_func)
502                         break;
503
504                 ret = set->comps[i].comp_func(entry1, entry2,
505                                               set->comps[i].is_descending);
506                 if (ret)
507                         return ret;
508
509                 if (set->comps[i].comp_func == comp_entry_with_qgroupid)
510                         qgroupid_compared = 1;
511         }
512
513         if (!qgroupid_compared) {
514 comp_qgroupid:
515                 ret = comp_entry_with_qgroupid(entry1, entry2, 0);
516         }
517
518         return ret;
519 }
520
521 /*
522  * insert a new root into the tree.  returns the existing root entry
523  * if one is already there.  qgroupid is used
524  * as the key
525  */
526 static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
527                               struct btrfs_qgroup *ins)
528 {
529
530         struct rb_node **p = &root_tree->root.rb_node;
531         struct rb_node *parent = NULL;
532         struct btrfs_qgroup *curr;
533         int ret;
534
535         while (*p) {
536                 parent = *p;
537                 curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
538
539                 ret = comp_entry_with_qgroupid(ins, curr, 0);
540                 if (ret < 0)
541                         p = &(*p)->rb_left;
542                 else if (ret > 0)
543                         p = &(*p)->rb_right;
544                 else
545                         return -EEXIST;
546         }
547         rb_link_node(&ins->rb_node, parent, p);
548         rb_insert_color(&ins->rb_node, &root_tree->root);
549         return 0;
550 }
551
552 /*
553  *find a given qgroupid in the tree. We return the smallest one,
554  *rb_next can be used to move forward looking for more if required
555  */
556 static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
557                                                u64 qgroupid)
558 {
559         struct rb_node *n = root_tree->root.rb_node;
560         struct btrfs_qgroup *entry;
561         struct btrfs_qgroup tmp;
562         int ret;
563
564         tmp.qgroupid = qgroupid;
565
566         while (n) {
567                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
568
569                 ret = comp_entry_with_qgroupid(&tmp, entry, 0);
570                 if (ret < 0)
571                         n = n->rb_left;
572                 else if (ret > 0)
573                         n = n->rb_right;
574                 else
575                         return entry;
576
577         }
578         return NULL;
579 }
580
581 /*
582  * Lookup or insert btrfs_qgroup into qgroup_lookup.
583  *
584  * Search a btrfs_qgroup with @qgroupid from the @qgroup_lookup. If not found,
585  * initialize a btrfs_qgroup with the given qgroupid and insert it to the
586  * @qgroup_lookup.
587  *
588  * Return the pointer to the btrfs_qgroup if found or if inserted successfully.
589  * Return ERR_PTR if any error occurred.
590  */
591 static struct btrfs_qgroup *get_or_add_qgroup(
592                 struct qgroup_lookup *qgroup_lookup, u64 qgroupid)
593 {
594         struct btrfs_qgroup *bq;
595         int ret;
596
597         bq = qgroup_tree_search(qgroup_lookup, qgroupid);
598         if (bq)
599                 return bq;
600
601         bq = calloc(1, sizeof(*bq));
602         if (!bq) {
603                 error("memory allocation failed");
604                 return ERR_PTR(-ENOMEM);
605         }
606
607         bq->qgroupid = qgroupid;
608         INIT_LIST_HEAD(&bq->qgroups);
609         INIT_LIST_HEAD(&bq->members);
610
611         ret = qgroup_tree_insert(qgroup_lookup, bq);
612         if (ret) {
613                 error("failed to insert %llu into tree: %s",
614                        (unsigned long long)bq->qgroupid, strerror(-ret));
615                 free(bq);
616                 return ERR_PTR(ret);
617         }
618
619         return bq;
620 }
621
622 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
623                          u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
624                          u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
625                          u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
626                          struct btrfs_qgroup *child)
627 {
628         struct btrfs_qgroup *bq;
629         struct btrfs_qgroup_list *list;
630
631         bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
632         if (IS_ERR_OR_NULL(bq))
633                 return PTR_ERR(bq);
634
635         if (generation)
636                 bq->generation = generation;
637         if (rfer)
638                 bq->rfer = rfer;
639         if (rfer_cmpr)
640                 bq->rfer_cmpr = rfer_cmpr;
641         if (excl)
642                 bq->excl = excl;
643         if (excl_cmpr)
644                 bq->excl_cmpr = excl_cmpr;
645         if (flags)
646                 bq->flags = flags;
647         if (max_rfer)
648                 bq->max_rfer = max_rfer;
649         if (max_excl)
650                 bq->max_excl = max_excl;
651         if (rsv_rfer)
652                 bq->rsv_rfer = rsv_rfer;
653         if (pa && child) {
654                 list = malloc(sizeof(*list));
655                 if (!list) {
656                         error("memory allocation failed");
657                         return -ENOMEM;
658                 }
659                 list->qgroup = pa;
660                 list->member = child;
661                 list_add_tail(&list->next_qgroup, &child->qgroups);
662                 list_add_tail(&list->next_member, &pa->members);
663         }
664         return 0;
665 }
666
667 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
668 {
669         struct btrfs_qgroup_list *list;
670         while (!list_empty(&bq->qgroups)) {
671                 list = list_entry((&bq->qgroups)->next,
672                                   struct btrfs_qgroup_list,
673                                   next_qgroup);
674                 list_del(&list->next_qgroup);
675                 list_del(&list->next_member);
676                 free(list);
677         }
678         while (!list_empty(&bq->members)) {
679                 list = list_entry((&bq->members)->next,
680                                   struct btrfs_qgroup_list,
681                                   next_member);
682                 list_del(&list->next_qgroup);
683                 list_del(&list->next_member);
684                 free(list);
685         }
686         free(bq);
687 }
688
689 static void __free_all_qgroups(struct qgroup_lookup *root_tree)
690 {
691         struct btrfs_qgroup *entry;
692         struct rb_node *n;
693
694         n = rb_first(&root_tree->root);
695         while (n) {
696                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
697                 rb_erase(n, &root_tree->root);
698                 __free_btrfs_qgroup(entry);
699
700                 n = rb_first(&root_tree->root);
701         }
702 }
703
704 static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
705                                     struct btrfs_qgroup *bq)
706 {
707         struct rb_node **p = &sort_tree->root.rb_node;
708         struct rb_node *parent = NULL;
709         struct btrfs_qgroup *curr;
710         int ret;
711
712         while (*p) {
713                 parent = *p;
714                 curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
715
716                 ret = comp_entry_with_qgroupid(bq, curr, 0);
717                 if (ret < 0)
718                         p = &(*p)->rb_left;
719                 else if (ret > 0)
720                         p = &(*p)->rb_right;
721                 else
722                         return -EEXIST;
723         }
724         rb_link_node(&bq->all_parent_node, parent, p);
725         rb_insert_color(&bq->all_parent_node, &sort_tree->root);
726         return 0;
727 }
728
729 static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
730 {
731         struct btrfs_qgroup *qgroup =
732                 (struct btrfs_qgroup *)(unsigned long)data;
733
734         if (data == 0)
735                 return 0;
736         if (qgroup->qgroupid == bq->qgroupid)
737                 return 1;
738         return 0;
739 }
740
741 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
742 {
743         struct qgroup_lookup lookup;
744         struct qgroup_lookup *ql = &lookup;
745         struct btrfs_qgroup_list *list;
746         struct rb_node *n;
747         struct btrfs_qgroup *qgroup =
748                          (struct btrfs_qgroup *)(unsigned long)data;
749
750         if (data == 0)
751                 return 0;
752         if (bq->qgroupid == qgroup->qgroupid)
753                 return 1;
754
755         qgroup_lookup_init(ql);
756         filter_all_parent_insert(ql, qgroup);
757         n = rb_first(&ql->root);
758         while (n) {
759                 qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
760                 if (!list_empty(&qgroup->qgroups)) {
761                         list_for_each_entry(list, &qgroup->qgroups,
762                                             next_qgroup) {
763                                 if ((list->qgroup)->qgroupid == bq->qgroupid)
764                                         return 1;
765                                 filter_all_parent_insert(ql, list->qgroup);
766                         }
767                 }
768                 rb_erase(n, &ql->root);
769                 n = rb_first(&ql->root);
770         }
771         return 0;
772 }
773
774 static btrfs_qgroup_filter_func all_filter_funcs[] = {
775         [BTRFS_QGROUP_FILTER_PARENT]            = filter_by_parent,
776         [BTRFS_QGROUP_FILTER_ALL_PARENT]        = filter_by_all_parent,
777 };
778
779 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
780 {
781         struct btrfs_qgroup_filter_set *set;
782         int size;
783
784         size = sizeof(struct btrfs_qgroup_filter_set) +
785                BTRFS_QGROUP_NFILTERS_INCREASE *
786                sizeof(struct btrfs_qgroup_filter);
787         set = calloc(1, size);
788         if (!set) {
789                 error("memory allocation failed");
790                 exit(1);
791         }
792         set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
793
794         return set;
795 }
796
797 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
798                               enum btrfs_qgroup_filter_enum filter, u64 data)
799 {
800         struct btrfs_qgroup_filter_set *set = *filter_set;
801         int size;
802
803         ASSERT(set != NULL);
804         ASSERT(filter < BTRFS_QGROUP_FILTER_MAX);
805         ASSERT(set->nfilters <= set->total);
806
807         if (set->nfilters == set->total) {
808                 void *tmp;
809
810                 size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
811                 size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
812
813                 tmp = set;
814                 set = realloc(set, size);
815                 if (!set) {
816                         error("memory allocation failed");
817                         free(tmp);
818                         exit(1);
819                 }
820                 memset(&set->filters[set->total], 0,
821                        BTRFS_QGROUP_NFILTERS_INCREASE *
822                        sizeof(struct btrfs_qgroup_filter));
823                 set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
824                 *filter_set = set;
825         }
826
827         ASSERT(set->filters[set->nfilters].filter_func == NULL);
828         set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
829         set->filters[set->nfilters].data = data;
830         set->nfilters++;
831         return 0;
832 }
833
834 static int filter_qgroup(struct btrfs_qgroup *bq,
835                          struct btrfs_qgroup_filter_set *set)
836 {
837         int i, ret;
838
839         if (!set || !set->nfilters)
840                 return 1;
841         for (i = 0; i < set->nfilters; i++) {
842                 if (!set->filters[i].filter_func)
843                         break;
844                 ret = set->filters[i].filter_func(bq, set->filters[i].data);
845                 if (!ret)
846                         return 0;
847         }
848         return 1;
849 }
850
851 static void pre_process_filter_set(struct qgroup_lookup *lookup,
852                                    struct btrfs_qgroup_filter_set *set)
853 {
854         int i;
855         struct btrfs_qgroup *qgroup_for_filter = NULL;
856
857         for (i = 0; i < set->nfilters; i++) {
858
859                 if (set->filters[i].filter_func == filter_by_all_parent
860                     || set->filters[i].filter_func == filter_by_parent) {
861                         qgroup_for_filter = qgroup_tree_search(lookup,
862                                             set->filters[i].data);
863                         set->filters[i].data =
864                                  (u64)(unsigned long)qgroup_for_filter;
865                 }
866         }
867 }
868
869 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
870                             struct btrfs_qgroup *bq,
871                             struct btrfs_qgroup_comparer_set *comp_set)
872 {
873         struct rb_node **p = &sort_tree->root.rb_node;
874         struct rb_node *parent = NULL;
875         struct btrfs_qgroup *curr;
876         int ret;
877
878         while (*p) {
879                 parent = *p;
880                 curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
881
882                 ret = sort_comp(bq, curr, comp_set);
883                 if (ret < 0)
884                         p = &(*p)->rb_left;
885                 else if (ret > 0)
886                         p = &(*p)->rb_right;
887                 else
888                         return -EEXIST;
889         }
890         rb_link_node(&bq->sort_node, parent, p);
891         rb_insert_color(&bq->sort_node, &sort_tree->root);
892         return 0;
893 }
894
895 static void __update_columns_max_len(struct btrfs_qgroup *bq,
896                                      enum btrfs_qgroup_column_enum column)
897 {
898         struct btrfs_qgroup_list *list = NULL;
899         char tmp[100];
900         int len;
901         unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
902
903         ASSERT(0 <= column && column < BTRFS_QGROUP_ALL);
904
905         switch (column) {
906
907         case BTRFS_QGROUP_QGROUPID:
908                 sprintf(tmp, "%llu/%llu",
909                         btrfs_qgroup_level(bq->qgroupid),
910                         btrfs_qgroup_subvid(bq->qgroupid));
911                 len = strlen(tmp);
912                 if (btrfs_qgroup_columns[column].max_len < len)
913                         btrfs_qgroup_columns[column].max_len = len;
914                 break;
915         case BTRFS_QGROUP_RFER:
916                 len = strlen(pretty_size_mode(bq->rfer, unit_mode));
917                 if (btrfs_qgroup_columns[column].max_len < len)
918                         btrfs_qgroup_columns[column].max_len = len;
919                 break;
920         case BTRFS_QGROUP_EXCL:
921                 len = strlen(pretty_size_mode(bq->excl, unit_mode));
922                 if (btrfs_qgroup_columns[column].max_len < len)
923                         btrfs_qgroup_columns[column].max_len = len;
924                 break;
925         case BTRFS_QGROUP_MAX_RFER:
926                 len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
927                 if (btrfs_qgroup_columns[column].max_len < len)
928                         btrfs_qgroup_columns[column].max_len = len;
929                 break;
930         case BTRFS_QGROUP_MAX_EXCL:
931                 len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
932                 if (btrfs_qgroup_columns[column].max_len < len)
933                         btrfs_qgroup_columns[column].max_len = len;
934                 break;
935         case BTRFS_QGROUP_PARENT:
936                 len = 0;
937                 list_for_each_entry(list, &bq->qgroups, next_qgroup) {
938                         len += sprintf(tmp, "%llu/%llu",
939                                 btrfs_qgroup_level(list->qgroup->qgroupid),
940                                 btrfs_qgroup_subvid(list->qgroup->qgroupid));
941                         if (!list_is_last(&list->next_qgroup, &bq->qgroups))
942                                 len += 1;
943                 }
944                 if (btrfs_qgroup_columns[column].max_len < len)
945                         btrfs_qgroup_columns[column].max_len = len;
946                 break;
947         case BTRFS_QGROUP_CHILD:
948                 len = 0;
949                 list_for_each_entry(list, &bq->members, next_member) {
950                         len += sprintf(tmp, "%llu/%llu",
951                                 btrfs_qgroup_level(list->member->qgroupid),
952                                 btrfs_qgroup_subvid(list->member->qgroupid));
953                         if (!list_is_last(&list->next_member, &bq->members))
954                                 len += 1;
955                 }
956                 if (btrfs_qgroup_columns[column].max_len < len)
957                         btrfs_qgroup_columns[column].max_len = len;
958                 break;
959         default:
960                 break;
961         }
962
963 }
964
965 static void update_columns_max_len(struct btrfs_qgroup *bq)
966 {
967         int i;
968
969         for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
970                 if (!btrfs_qgroup_columns[i].need_print)
971                         continue;
972                 __update_columns_max_len(bq, i);
973         }
974 }
975
976 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
977                                  struct qgroup_lookup *sort_tree,
978                                  struct btrfs_qgroup_filter_set *filter_set,
979                                  struct btrfs_qgroup_comparer_set *comp_set)
980 {
981         struct rb_node *n;
982         struct btrfs_qgroup *entry;
983         int ret;
984
985         qgroup_lookup_init(sort_tree);
986         pre_process_filter_set(all_qgroups, filter_set);
987
988         n = rb_last(&all_qgroups->root);
989         while (n) {
990                 entry = rb_entry(n, struct btrfs_qgroup, rb_node);
991
992                 ret = filter_qgroup(entry, filter_set);
993                 if (ret) {
994                         sort_tree_insert(sort_tree, entry, comp_set);
995
996                         update_columns_max_len(entry);
997                 }
998                 n = rb_prev(n);
999         }
1000 }
1001
1002 static inline void print_status_flag_warning(u64 flags)
1003 {
1004         if (!(flags & BTRFS_QGROUP_STATUS_FLAG_ON))
1005                 warning("quota disabled, qgroup data may be out of date");
1006         else if (flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)
1007                 warning("rescan is running, qgroup data may be incorrect");
1008         else if (flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
1009                 warning("qgroup data inconsistent, rescan recommended");
1010 }
1011
1012 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
1013 {
1014         int ret;
1015         struct btrfs_ioctl_search_args args;
1016         struct btrfs_ioctl_search_key *sk = &args.key;
1017         struct btrfs_ioctl_search_header *sh;
1018         unsigned long off = 0;
1019         unsigned int i;
1020         struct btrfs_qgroup_info_item *info;
1021         struct btrfs_qgroup_limit_item *limit;
1022         struct btrfs_qgroup *bq;
1023         struct btrfs_qgroup *bq1;
1024         u64 a1;
1025         u64 a2;
1026         u64 a3;
1027         u64 a4;
1028         u64 a5;
1029
1030         memset(&args, 0, sizeof(args));
1031
1032         sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
1033         sk->max_type = BTRFS_QGROUP_RELATION_KEY;
1034         sk->min_type = BTRFS_QGROUP_STATUS_KEY;
1035         sk->max_objectid = (u64)-1;
1036         sk->max_offset = (u64)-1;
1037         sk->max_transid = (u64)-1;
1038         sk->nr_items = 4096;
1039
1040         qgroup_lookup_init(qgroup_lookup);
1041
1042         while (1) {
1043                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1044                 if (ret < 0)
1045                         return -errno;
1046
1047                 /* the ioctl returns the number of item it found in nr_items */
1048                 if (sk->nr_items == 0)
1049                         break;
1050
1051                 off = 0;
1052                 /*
1053                  * for each item, pull the key out of the header and then
1054                  * read the root_ref item it contains
1055                  */
1056                 for (i = 0; i < sk->nr_items; i++) {
1057                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
1058                                                                   off);
1059                         off += sizeof(*sh);
1060
1061                         if (btrfs_search_header_type(sh)
1062                             == BTRFS_QGROUP_STATUS_KEY) {
1063                                 struct btrfs_qgroup_status_item *si;
1064                                 u64 flags;
1065
1066                                 si = (struct btrfs_qgroup_status_item *)
1067                                      (args.buf + off);
1068                                 flags = btrfs_stack_qgroup_status_flags(si);
1069                                 print_status_flag_warning(flags);
1070                         } else if (btrfs_search_header_type(sh)
1071                                    == BTRFS_QGROUP_INFO_KEY) {
1072                                 info = (struct btrfs_qgroup_info_item *)
1073                                        (args.buf + off);
1074                                 a1 = btrfs_stack_qgroup_info_generation(info);
1075                                 a2 = btrfs_stack_qgroup_info_referenced(info);
1076                                 a3 =
1077                                   btrfs_stack_qgroup_info_referenced_compressed
1078                                   (info);
1079                                 a4 = btrfs_stack_qgroup_info_exclusive(info);
1080                                 a5 =
1081                                   btrfs_stack_qgroup_info_exclusive_compressed
1082                                   (info);
1083                                 update_qgroup(qgroup_lookup,
1084                                         btrfs_search_header_offset(sh), a1,
1085                                         a2, a3, a4, a5, 0, 0, 0, 0, 0, NULL,
1086                                         NULL);
1087                         } else if (btrfs_search_header_type(sh)
1088                                    == BTRFS_QGROUP_LIMIT_KEY) {
1089                                 limit = (struct btrfs_qgroup_limit_item *)
1090                                     (args.buf + off);
1091
1092                                 a1 = btrfs_stack_qgroup_limit_flags(limit);
1093                                 a2 = btrfs_stack_qgroup_limit_max_referenced
1094                                      (limit);
1095                                 a3 = btrfs_stack_qgroup_limit_max_exclusive
1096                                      (limit);
1097                                 a4 = btrfs_stack_qgroup_limit_rsv_referenced
1098                                      (limit);
1099                                 a5 = btrfs_stack_qgroup_limit_rsv_exclusive
1100                                      (limit);
1101                                 update_qgroup(qgroup_lookup,
1102                                            btrfs_search_header_offset(sh), 0,
1103                                            0, 0, 0, 0, a1, a2, a3, a4, a5,
1104                                            NULL, NULL);
1105                         } else if (btrfs_search_header_type(sh)
1106                                    == BTRFS_QGROUP_RELATION_KEY) {
1107                                 if (btrfs_search_header_offset(sh)
1108                                     < btrfs_search_header_objectid(sh))
1109                                         goto skip;
1110                                 bq = qgroup_tree_search(qgroup_lookup,
1111                                         btrfs_search_header_offset(sh));
1112                                 if (!bq)
1113                                         goto skip;
1114                                 bq1 = qgroup_tree_search(qgroup_lookup,
1115                                          btrfs_search_header_objectid(sh));
1116                                 if (!bq1)
1117                                         goto skip;
1118                                 update_qgroup(qgroup_lookup,
1119                                            btrfs_search_header_offset(sh), 0,
1120                                            0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
1121                         } else
1122                                 goto done;
1123 skip:
1124                         off += btrfs_search_header_len(sh);
1125
1126                         /*
1127                          * record the mins in sk so we can make sure the
1128                          * next search doesn't repeat this root
1129                          */
1130                         sk->min_type = btrfs_search_header_type(sh);
1131                         sk->min_offset = btrfs_search_header_offset(sh);
1132                         sk->min_objectid = btrfs_search_header_objectid(sh);
1133                 }
1134                 sk->nr_items = 4096;
1135                 /*
1136                  * this iteration is done, step forward one qgroup for the next
1137                  * ioctl
1138                  */
1139                 if (sk->min_offset < (u64)-1)
1140                         sk->min_offset++;
1141                 else
1142                         break;
1143         }
1144
1145 done:
1146         return ret;
1147 }
1148
1149 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
1150 {
1151
1152         struct rb_node *n;
1153         struct btrfs_qgroup *entry;
1154
1155         print_table_head();
1156
1157         n = rb_first(&qgroup_lookup->root);
1158         while (n) {
1159                 entry = rb_entry(n, struct btrfs_qgroup, sort_node);
1160                 print_single_qgroup_table(entry);
1161                 n = rb_next(n);
1162         }
1163 }
1164
1165 int btrfs_show_qgroups(int fd,
1166                        struct btrfs_qgroup_filter_set *filter_set,
1167                        struct btrfs_qgroup_comparer_set *comp_set)
1168 {
1169
1170         struct qgroup_lookup qgroup_lookup;
1171         struct qgroup_lookup sort_tree;
1172         int ret;
1173
1174         ret = __qgroups_search(fd, &qgroup_lookup);
1175         if (ret)
1176                 return ret;
1177         __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
1178                                   filter_set, comp_set);
1179         print_all_qgroups(&sort_tree);
1180
1181         __free_all_qgroups(&qgroup_lookup);
1182         free(filter_set);
1183         free(comp_set);
1184         return ret;
1185 }
1186
1187 int btrfs_qgroup_parse_sort_string(const char *opt_arg,
1188                                    struct btrfs_qgroup_comparer_set **comps)
1189 {
1190         int order;
1191         int flag;
1192         char *p;
1193         char **ptr_argv;
1194         int what_to_sort;
1195         char *opt_tmp;
1196         int ret = 0;
1197
1198         opt_tmp = strdup(opt_arg);
1199         if (!opt_tmp)
1200                 return -ENOMEM;
1201
1202         p = strtok(opt_tmp, ",");
1203         while (p) {
1204                 flag = 0;
1205                 ptr_argv = all_sort_items;
1206
1207                 while (*ptr_argv) {
1208                         if (strcmp(*ptr_argv, p) == 0) {
1209                                 flag = 1;
1210                                 break;
1211                         } else {
1212                                 p++;
1213                                 if (strcmp(*ptr_argv, p) == 0) {
1214                                         flag = 1;
1215                                         p--;
1216                                         break;
1217                                 }
1218                                 p--;
1219                         }
1220                         ptr_argv++;
1221                 }
1222
1223                 if (flag == 0) {
1224                         ret = -1;
1225                         goto out;
1226                 } else {
1227                         if (*p == '+') {
1228                                 order = 0;
1229                                 p++;
1230                         } else if (*p == '-') {
1231                                 order = 1;
1232                                 p++;
1233                         } else
1234                                 order = 0;
1235
1236                         what_to_sort = btrfs_qgroup_get_sort_item(p);
1237                         if (what_to_sort < 0) {
1238                                 ret = -1;
1239                                 goto out;
1240                         }
1241                         btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
1242                 }
1243                 p = strtok(NULL, ",");
1244         }
1245
1246 out:
1247         free(opt_tmp);
1248         return ret;
1249 }
1250
1251 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
1252 {
1253         return sizeof(*p) + sizeof(p->qgroups[0]) *
1254                             (p->num_qgroups + 2 * p->num_ref_copies +
1255                              2 * p->num_excl_copies);
1256 }
1257
1258 static int
1259 qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos)
1260 {
1261         struct btrfs_qgroup_inherit *out;
1262         int nitems = 0;
1263
1264         if (*inherit) {
1265                 nitems = (*inherit)->num_qgroups +
1266                          (*inherit)->num_ref_copies +
1267                          (*inherit)->num_excl_copies;
1268         }
1269
1270         out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
1271         if (out == NULL) {
1272                 error("not enough memory");
1273                 return -ENOMEM;
1274         }
1275
1276         if (*inherit) {
1277                 struct btrfs_qgroup_inherit *i = *inherit;
1278                 int s = sizeof(out->qgroups[0]);
1279
1280                 out->num_qgroups = i->num_qgroups;
1281                 out->num_ref_copies = i->num_ref_copies;
1282                 out->num_excl_copies = i->num_excl_copies;
1283                 memcpy(out->qgroups, i->qgroups, pos * s);
1284                 memcpy(out->qgroups + pos + n, i->qgroups + pos,
1285                        (nitems - pos) * s);
1286         }
1287         free(*inherit);
1288         *inherit = out;
1289
1290         return 0;
1291 }
1292
1293 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
1294 {
1295         int ret;
1296         u64 qgroupid = parse_qgroupid(arg);
1297         int pos = 0;
1298
1299         if (qgroupid == 0) {
1300                 error("invalid qgroup specification, qgroupid must not 0");
1301                 return -EINVAL;
1302         }
1303
1304         if (*inherit)
1305                 pos = (*inherit)->num_qgroups;
1306         ret = qgroup_inherit_realloc(inherit, 1, pos);
1307         if (ret)
1308                 return ret;
1309
1310         (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
1311
1312         return 0;
1313 }
1314
1315 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
1316                             int type)
1317 {
1318         int ret;
1319         u64 qgroup_src;
1320         u64 qgroup_dst;
1321         char *p;
1322         int pos = 0;
1323
1324         p = strchr(arg, ':');
1325         if (!p) {
1326 bad:
1327                 error("invalid copy specification, missing separator :");
1328                 return -EINVAL;
1329         }
1330         *p = 0;
1331         qgroup_src = parse_qgroupid(arg);
1332         qgroup_dst = parse_qgroupid(p + 1);
1333         *p = ':';
1334
1335         if (!qgroup_src || !qgroup_dst)
1336                 goto bad;
1337
1338         if (*inherit)
1339                 pos = (*inherit)->num_qgroups +
1340                       (*inherit)->num_ref_copies * 2 * type;
1341
1342         ret = qgroup_inherit_realloc(inherit, 2, pos);
1343         if (ret)
1344                 return ret;
1345
1346         (*inherit)->qgroups[pos++] = qgroup_src;
1347         (*inherit)->qgroups[pos++] = qgroup_dst;
1348
1349         if (!type)
1350                 ++(*inherit)->num_ref_copies;
1351         else
1352                 ++(*inherit)->num_excl_copies;
1353
1354         return 0;
1355 }