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