libbtrfsutil: always build libbtrfsutil.so.$MAJOR
[platform/upstream/btrfs-progs.git] / qgroup.c
index 9d10cb8..11659e8 100644 (file)
--- a/qgroup.c
+++ b/qgroup.c
@@ -480,7 +480,7 @@ int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
                *comp_set = set;
        }
 
-       ASSERT(set->comps[set->ncomps].comp_func != NULL);
+       ASSERT(set->comps[set->ncomps].comp_func == NULL);
 
        set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
        set->comps[set->ncomps].is_descending = is_descending;
@@ -578,113 +578,119 @@ static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
        return NULL;
 }
 
-static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
-                        u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
-                        u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
-                        u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
-                        struct btrfs_qgroup *child)
+/*
+ * Lookup or insert btrfs_qgroup into qgroup_lookup.
+ *
+ * Search a btrfs_qgroup with @qgroupid from the @qgroup_lookup. If not found,
+ * initialize a btrfs_qgroup with the given qgroupid and insert it to the
+ * @qgroup_lookup.
+ *
+ * Return the pointer to the btrfs_qgroup if found or if inserted successfully.
+ * Return ERR_PTR if any error occurred.
+ */
+static struct btrfs_qgroup *get_or_add_qgroup(
+               struct qgroup_lookup *qgroup_lookup, u64 qgroupid)
 {
        struct btrfs_qgroup *bq;
-       struct btrfs_qgroup_list *list;
+       int ret;
 
        bq = qgroup_tree_search(qgroup_lookup, qgroupid);
-       if (!bq || bq->qgroupid != qgroupid)
-               return -ENOENT;
+       if (bq)
+               return bq;
 
-       if (generation)
-               bq->generation = generation;
-       if (rfer)
-               bq->rfer = rfer;
-       if (rfer_cmpr)
-               bq->rfer_cmpr = rfer_cmpr;
-       if (excl)
-               bq->excl = excl;
-       if (excl_cmpr)
-               bq->excl_cmpr = excl_cmpr;
-       if (flags)
-               bq->flags = flags;
-       if (max_rfer)
-               bq->max_rfer = max_rfer;
-       if (max_excl)
-               bq->max_excl = max_excl;
-       if (rsv_rfer)
-               bq->rsv_rfer = rsv_rfer;
-       if (pa && child) {
-               list = malloc(sizeof(*list));
-               if (!list) {
-                       error("memory allocation failed");
-                       exit(1);
-               }
-               list->qgroup = pa;
-               list->member = child;
-               list_add_tail(&list->next_qgroup, &child->qgroups);
-               list_add_tail(&list->next_member, &pa->members);
+       bq = calloc(1, sizeof(*bq));
+       if (!bq) {
+               error("memory allocation failed");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       bq->qgroupid = qgroupid;
+       INIT_LIST_HEAD(&bq->qgroups);
+       INIT_LIST_HEAD(&bq->members);
+
+       ret = qgroup_tree_insert(qgroup_lookup, bq);
+       if (ret) {
+               error("failed to insert %llu into tree: %s",
+                      (unsigned long long)bq->qgroupid, strerror(-ret));
+               free(bq);
+               return ERR_PTR(ret);
        }
+
+       return bq;
+}
+
+static int update_qgroup_info(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
+                             struct btrfs_qgroup_info_item *info)
+{
+       struct btrfs_qgroup *bq;
+
+       bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
+       if (IS_ERR_OR_NULL(bq))
+               return PTR_ERR(bq);
+
+       bq->generation = btrfs_stack_qgroup_info_generation(info);
+       bq->rfer = btrfs_stack_qgroup_info_referenced(info);
+       bq->rfer_cmpr = btrfs_stack_qgroup_info_referenced_compressed(info);
+       bq->excl = btrfs_stack_qgroup_info_exclusive(info);
+       bq->excl_cmpr = btrfs_stack_qgroup_info_exclusive_compressed(info);
+
        return 0;
 }
 
-static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
-                     u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
-                     u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
-                     u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
-                     struct btrfs_qgroup *child)
+static int update_qgroup_limit(struct qgroup_lookup *qgroup_lookup,
+                              u64 qgroupid,
+                              struct btrfs_qgroup_limit_item *limit)
 {
        struct btrfs_qgroup *bq;
-       struct btrfs_qgroup_list *list;
-       int ret;
 
-       ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
-                           rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
-                           max_excl, rsv_rfer, rsv_excl, parent, child);
-       if (!ret)
-               return 0;
+       bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
+       if (IS_ERR_OR_NULL(bq))
+               return PTR_ERR(bq);
 
-       bq = calloc(1, sizeof(*bq));
-       if (!bq) {
-               error("memory allocation failed");
-               exit(1);
-       }
-       if (qgroupid) {
-               bq->qgroupid = qgroupid;
-               INIT_LIST_HEAD(&bq->qgroups);
-               INIT_LIST_HEAD(&bq->members);
+       bq->flags = btrfs_stack_qgroup_limit_flags(limit);
+       bq->max_rfer = btrfs_stack_qgroup_limit_max_referenced(limit);
+       bq->max_excl = btrfs_stack_qgroup_limit_max_exclusive(limit);
+       bq->rsv_rfer = btrfs_stack_qgroup_limit_rsv_referenced(limit);
+       bq->rsv_excl = btrfs_stack_qgroup_limit_rsv_exclusive(limit);
+
+       return 0;
+}
+
+static int update_qgroup_relation(struct qgroup_lookup *qgroup_lookup,
+                                 u64 child_id, u64 parent_id)
+{
+       struct btrfs_qgroup *child;
+       struct btrfs_qgroup *parent;
+       struct btrfs_qgroup_list *list;
+
+       child = qgroup_tree_search(qgroup_lookup, child_id);
+       if (!child) {
+               error("cannot find the qgroup %llu/%llu",
+                     btrfs_qgroup_level(child_id),
+                     btrfs_qgroup_subvid(child_id));
+               return -ENOENT;
        }
-       if (generation)
-               bq->generation = generation;
-       if (rfer)
-               bq->rfer = rfer;
-       if (rfer_cmpr)
-               bq->rfer_cmpr = rfer_cmpr;
-       if (excl)
-               bq->excl = excl;
-       if (excl_cmpr)
-               bq->excl_cmpr = excl_cmpr;
-       if (flags)
-               bq->flags = flags;
-       if (max_rfer)
-               bq->max_rfer = max_rfer;
-       if (max_excl)
-               bq->max_excl = max_excl;
-       if (rsv_rfer)
-               bq->rsv_rfer = rsv_rfer;
-       if (parent && child) {
-               list = malloc(sizeof(*list));
-               if (!list) {
-                       error("memory allocation failed");
-                       exit(1);
-               }
-               list->qgroup = parent;
-               list->member = child;
-               list_add_tail(&list->next_qgroup, &child->qgroups);
-               list_add_tail(&list->next_member, &parent->members);
+
+       parent = qgroup_tree_search(qgroup_lookup, parent_id);
+       if (!parent) {
+               error("cannot find the qgroup %llu/%llu",
+                     btrfs_qgroup_level(parent_id),
+                     btrfs_qgroup_subvid(parent_id));
+               return -ENOENT;
        }
-       ret = qgroup_tree_insert(qgroup_lookup, bq);
-       if (ret) {
-               error("failed to insert %llu into tree: %s",
-                      (unsigned long long)bq->qgroupid, strerror(-ret));
-               exit(1);
+
+       list = malloc(sizeof(*list));
+       if (!list) {
+               error("memory allocation failed");
+               return -ENOMEM;
        }
-       return ret;
+
+       list->qgroup = parent;
+       list->member = child;
+       list_add_tail(&list->next_qgroup, &child->qgroups);
+       list_add_tail(&list->next_member, &parent->members);
+
+       return 0;
 }
 
 static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
@@ -847,7 +853,7 @@ int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
                *filter_set = set;
        }
 
-       ASSERT(set->filters[set->nfilters].filter_func != NULL);
+       ASSERT(set->filters[set->nfilters].filter_func == NULL);
        set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
        set->filters[set->nfilters].data = data;
        set->nfilters++;
@@ -1040,15 +1046,12 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
        struct btrfs_ioctl_search_header *sh;
        unsigned long off = 0;
        unsigned int i;
+       struct btrfs_qgroup_status_item *si;
        struct btrfs_qgroup_info_item *info;
        struct btrfs_qgroup_limit_item *limit;
-       struct btrfs_qgroup *bq;
-       struct btrfs_qgroup *bq1;
-       u64 a1;
-       u64 a2;
-       u64 a3;
-       u64 a4;
-       u64 a5;
+       u64 flags;
+       u64 qgroupid;
+       u64 qgroupid1;
 
        memset(&args, 0, sizeof(args));
 
@@ -1065,10 +1068,18 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
        while (1) {
                ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
                if (ret < 0) {
-                       error("cannot perform the search: %s",
-                                       strerror(errno));
-                       return ret;
+                       if (errno == ENOENT) {
+                               error("can't list qgroups: quotas not enabled");
+                               ret = -ENOTTY;
+                       } else {
+                               error("can't list qgroups: %s",
+                                      strerror(errno));
+                               ret = -errno;
+                       }
+
+                       break;
                }
+
                /* the ioctl returns the number of item it found in nr_items */
                if (sk->nr_items == 0)
                        break;
@@ -1083,69 +1094,47 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
                                                                  off);
                        off += sizeof(*sh);
 
-                       if (btrfs_search_header_type(sh)
-                           == BTRFS_QGROUP_STATUS_KEY) {
-                               struct btrfs_qgroup_status_item *si;
-                               u64 flags;
-
+                       switch (btrfs_search_header_type(sh)) {
+                       case BTRFS_QGROUP_STATUS_KEY:
                                si = (struct btrfs_qgroup_status_item *)
                                     (args.buf + off);
                                flags = btrfs_stack_qgroup_status_flags(si);
+
                                print_status_flag_warning(flags);
-                       } else if (btrfs_search_header_type(sh)
-                                  == BTRFS_QGROUP_INFO_KEY) {
+                               break;
+                       case BTRFS_QGROUP_INFO_KEY:
+                               qgroupid = btrfs_search_header_offset(sh);
                                info = (struct btrfs_qgroup_info_item *)
                                       (args.buf + off);
-                               a1 = btrfs_stack_qgroup_info_generation(info);
-                               a2 = btrfs_stack_qgroup_info_referenced(info);
-                               a3 =
-                                 btrfs_stack_qgroup_info_referenced_compressed
-                                 (info);
-                               a4 = btrfs_stack_qgroup_info_exclusive(info);
-                               a5 =
-                                 btrfs_stack_qgroup_info_exclusive_compressed
-                                 (info);
-                               add_qgroup(qgroup_lookup,
-                                       btrfs_search_header_offset(sh), a1,
-                                       a2, a3, a4, a5, 0, 0, 0, 0, 0, NULL,
-                                       NULL);
-                       } else if (btrfs_search_header_type(sh)
-                                  == BTRFS_QGROUP_LIMIT_KEY) {
+
+                               ret = update_qgroup_info(qgroup_lookup,
+                                                        qgroupid, info);
+                               break;
+                       case BTRFS_QGROUP_LIMIT_KEY:
+                               qgroupid = btrfs_search_header_offset(sh);
                                limit = (struct btrfs_qgroup_limit_item *)
-                                   (args.buf + off);
-
-                               a1 = btrfs_stack_qgroup_limit_flags(limit);
-                               a2 = btrfs_stack_qgroup_limit_max_referenced
-                                    (limit);
-                               a3 = btrfs_stack_qgroup_limit_max_exclusive
-                                    (limit);
-                               a4 = btrfs_stack_qgroup_limit_rsv_referenced
-                                    (limit);
-                               a5 = btrfs_stack_qgroup_limit_rsv_exclusive
-                                    (limit);
-                               add_qgroup(qgroup_lookup,
-                                          btrfs_search_header_offset(sh), 0,
-                                          0, 0, 0, 0, a1, a2, a3, a4, a5,
-                                          NULL, NULL);
-                       } else if (btrfs_search_header_type(sh)
-                                  == BTRFS_QGROUP_RELATION_KEY) {
-                               if (btrfs_search_header_offset(sh)
-                                   < btrfs_search_header_objectid(sh))
-                                       goto skip;
-                               bq = qgroup_tree_search(qgroup_lookup,
-                                       btrfs_search_header_offset(sh));
-                               if (!bq)
-                                       goto skip;
-                               bq1 = qgroup_tree_search(qgroup_lookup,
-                                        btrfs_search_header_objectid(sh));
-                               if (!bq1)
-                                       goto skip;
-                               add_qgroup(qgroup_lookup,
-                                          btrfs_search_header_offset(sh), 0,
-                                          0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
-                       } else
-                               goto done;
-skip:
+                                       (args.buf + off);
+
+                               ret = update_qgroup_limit(qgroup_lookup,
+                                                         qgroupid, limit);
+                               break;
+                       case BTRFS_QGROUP_RELATION_KEY:
+                               qgroupid = btrfs_search_header_offset(sh);
+                               qgroupid1 = btrfs_search_header_objectid(sh);
+
+                               if (qgroupid < qgroupid1)
+                                       break;
+
+                               ret = update_qgroup_relation(qgroup_lookup,
+                                                       qgroupid, qgroupid1);
+                               break;
+                       default:
+                               return ret;
+                       }
+
+                       if (ret)
+                               return ret;
+
                        off += btrfs_search_header_len(sh);
 
                        /*
@@ -1167,7 +1156,6 @@ skip:
                        break;
        }
 
-done:
        return ret;
 }
 
@@ -1204,8 +1192,6 @@ int btrfs_show_qgroups(int fd,
        print_all_qgroups(&sort_tree);
 
        __free_all_qgroups(&qgroup_lookup);
-       free(filter_set);
-       free(comp_set);
        return ret;
 }
 
@@ -1224,7 +1210,8 @@ int btrfs_qgroup_parse_sort_string(const char *opt_arg,
        if (!opt_tmp)
                return -ENOMEM;
 
-       while ((p = strtok(opt_tmp, ",")) != NULL) {
+       p = strtok(opt_tmp, ",");
+       while (p) {
                flag = 0;
                ptr_argv = all_sort_items;
 
@@ -1264,8 +1251,7 @@ int btrfs_qgroup_parse_sort_string(const char *opt_arg,
                        }
                        btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
                }
-               free(opt_tmp);
-               opt_tmp = NULL;
+               p = strtok(NULL, ",");
        }
 
 out: