btrfs: qgroup: Update trace events to use new separate rsv types
[sfrench/cifs-2.6.git] / fs / btrfs / qgroup.c
index aa259d6986e1c24049c8f500184b2393d99b0549..8ec103deb3619f635ecbd6233282f0465c0b6273 100644 (file)
  *  - check all ioctl parameters
  */
 
+/*
+ * Helpers to access qgroup reservation
+ *
+ * Callers should ensure the lock context and type are valid
+ */
+
+static u64 qgroup_rsv_total(const struct btrfs_qgroup *qgroup)
+{
+       u64 ret = 0;
+       int i;
+
+       for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+               ret += qgroup->rsv.values[i];
+
+       return ret;
+}
+
+#ifdef CONFIG_BTRFS_DEBUG
+static const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type)
+{
+       if (type == BTRFS_QGROUP_RSV_DATA)
+               return "data";
+       if (type == BTRFS_QGROUP_RSV_META)
+               return "meta";
+       return NULL;
+}
+#endif
+
+static void qgroup_rsv_add(struct btrfs_fs_info *fs_info,
+                          struct btrfs_qgroup *qgroup, u64 num_bytes,
+                          enum btrfs_qgroup_rsv_type type)
+{
+       trace_qgroup_update_reserve(fs_info, qgroup, num_bytes, type);
+       qgroup->rsv.values[type] += num_bytes;
+}
+
+static void qgroup_rsv_release(struct btrfs_fs_info *fs_info,
+                              struct btrfs_qgroup *qgroup, u64 num_bytes,
+                              enum btrfs_qgroup_rsv_type type)
+{
+       trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type);
+       if (qgroup->rsv.values[type] >= num_bytes) {
+               qgroup->rsv.values[type] -= num_bytes;
+               return;
+       }
+#ifdef CONFIG_BTRFS_DEBUG
+       WARN_RATELIMIT(1,
+               "qgroup %llu %s reserved space underflow, have %llu to free %llu",
+               qgroup->qgroupid, qgroup_rsv_type_str(type),
+               qgroup->rsv.values[type], num_bytes);
+#endif
+       qgroup->rsv.values[type] = 0;
+}
+
+static void qgroup_rsv_add_by_qgroup(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_qgroup *dest,
+                                    struct btrfs_qgroup *src)
+{
+       int i;
+
+       for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+               qgroup_rsv_add(fs_info, dest, src->rsv.values[i], i);
+}
+
+static void qgroup_rsv_release_by_qgroup(struct btrfs_fs_info *fs_info,
+                                        struct btrfs_qgroup *dest,
+                                         struct btrfs_qgroup *src)
+{
+       int i;
+
+       for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+               qgroup_rsv_release(fs_info, dest, src->rsv.values[i], i);
+}
+
 static void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq,
                                           int mod)
 {
@@ -826,10 +900,8 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
        int slot;
 
        mutex_lock(&fs_info->qgroup_ioctl_lock);
-       if (fs_info->quota_root) {
-               set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags);
+       if (fs_info->quota_root)
                goto out;
-       }
 
        fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
        if (!fs_info->qgroup_ulist) {
@@ -923,8 +995,15 @@ out_add_root:
        }
        spin_lock(&fs_info->qgroup_lock);
        fs_info->quota_root = quota_root;
-       set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags);
+       set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
        spin_unlock(&fs_info->qgroup_lock);
+       ret = qgroup_rescan_init(fs_info, 0, 1);
+       if (!ret) {
+               qgroup_rescan_zero_tracking(fs_info);
+               btrfs_queue_work(fs_info->qgroup_rescan_workers,
+                                &fs_info->qgroup_rescan_work);
+       }
+
 out_free_path:
        btrfs_free_path(path);
 out_free_root:
@@ -1003,21 +1082,30 @@ static void report_reserved_underflow(struct btrfs_fs_info *fs_info,
 #endif
        qgroup->reserved = 0;
 }
+
 /*
- * The easy accounting, if we are adding/removing the only ref for an extent
- * then this qgroup and all of the parent qgroups get their reference and
- * exclusive counts adjusted.
+ * The easy accounting, we're updating qgroup relationship whose child qgroup
+ * only has exclusive extents.
+ *
+ * In this case, all exclsuive extents will also be exlusive for parent, so
+ * excl/rfer just get added/removed.
+ *
+ * So is qgroup reservation space, which should also be added/removed to
+ * parent.
+ * Or when child tries to release reservation space, parent will underflow its
+ * reservation (for relationship adding case).
  *
  * Caller should hold fs_info->qgroup_lock.
  */
 static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
                                    struct ulist *tmp, u64 ref_root,
-                                   u64 num_bytes, int sign)
+                                   struct btrfs_qgroup *src, int sign)
 {
        struct btrfs_qgroup *qgroup;
        struct btrfs_qgroup_list *glist;
        struct ulist_node *unode;
        struct ulist_iterator uiter;
+       u64 num_bytes = src->excl;
        int ret = 0;
 
        qgroup = find_qgroup_rb(fs_info, ref_root);
@@ -1030,13 +1118,11 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
        WARN_ON(sign < 0 && qgroup->excl < num_bytes);
        qgroup->excl += sign * num_bytes;
        qgroup->excl_cmpr += sign * num_bytes;
-       if (sign > 0) {
-               trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes);
-               if (qgroup->reserved < num_bytes)
-                       report_reserved_underflow(fs_info, qgroup, num_bytes);
-               else
-                       qgroup->reserved -= num_bytes;
-       }
+
+       if (sign > 0)
+               qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+       else
+               qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
 
        qgroup_dirty(fs_info, qgroup);
 
@@ -1056,15 +1142,10 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
                qgroup->rfer_cmpr += sign * num_bytes;
                WARN_ON(sign < 0 && qgroup->excl < num_bytes);
                qgroup->excl += sign * num_bytes;
-               if (sign > 0) {
-                       trace_qgroup_update_reserve(fs_info, qgroup,
-                                                   -(s64)num_bytes);
-                       if (qgroup->reserved < num_bytes)
-                               report_reserved_underflow(fs_info, qgroup,
-                                                         num_bytes);
-                       else
-                               qgroup->reserved -= num_bytes;
-               }
+               if (sign > 0)
+                       qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+               else
+                       qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
                qgroup->excl_cmpr += sign * num_bytes;
                qgroup_dirty(fs_info, qgroup);
 
@@ -1107,7 +1188,7 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info,
        if (qgroup->excl == qgroup->rfer) {
                ret = 0;
                err = __qgroup_excl_accounting(fs_info, tmp, dst,
-                                              qgroup->excl, sign);
+                                              qgroup, sign);
                if (err < 0) {
                        ret = err;
                        goto out;
@@ -2009,9 +2090,9 @@ out_free:
        return ret;
 }
 
-int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans,
-                                struct btrfs_fs_info *fs_info)
+int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
 {
+       struct btrfs_fs_info *fs_info = trans->fs_info;
        struct btrfs_qgroup_extent_record *record;
        struct btrfs_delayed_ref_root *delayed_refs;
        struct ulist *new_roots = NULL;
@@ -2080,17 +2161,9 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
 {
        struct btrfs_root *quota_root = fs_info->quota_root;
        int ret = 0;
-       int start_rescan_worker = 0;
 
        if (!quota_root)
-               goto out;
-
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
-           test_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags))
-               start_rescan_worker = 1;
-
-       if (test_and_clear_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags))
-               set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+               return ret;
 
        spin_lock(&fs_info->qgroup_lock);
        while (!list_empty(&fs_info->dirty_qgroups)) {
@@ -2119,18 +2192,6 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
        if (ret)
                fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
 
-       if (!ret && start_rescan_worker) {
-               ret = qgroup_rescan_init(fs_info, 0, 1);
-               if (!ret) {
-                       qgroup_rescan_zero_tracking(fs_info);
-                       btrfs_queue_work(fs_info->qgroup_rescan_workers,
-                                        &fs_info->qgroup_rescan_work);
-               }
-               ret = 0;
-       }
-
-out:
-
        return ret;
 }
 
@@ -2338,17 +2399,18 @@ out:
 static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes)
 {
        if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
-           qg->reserved + (s64)qg->rfer + num_bytes > qg->max_rfer)
+           qgroup_rsv_total(qg) + (s64)qg->rfer + num_bytes > qg->max_rfer)
                return false;
 
        if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
-           qg->reserved + (s64)qg->excl + num_bytes > qg->max_excl)
+           qgroup_rsv_total(qg) + (s64)qg->excl + num_bytes > qg->max_excl)
                return false;
 
        return true;
 }
 
-static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
+static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce,
+                         enum btrfs_qgroup_rsv_type type)
 {
        struct btrfs_root *quota_root;
        struct btrfs_qgroup *qgroup;
@@ -2400,7 +2462,7 @@ retry:
                         * Commit the tree and retry, since we may have
                         * deletions which would free up space.
                         */
-                       if (!retried && qg->reserved > 0) {
+                       if (!retried && qgroup_rsv_total(qg) > 0) {
                                struct btrfs_trans_handle *trans;
 
                                spin_unlock(&fs_info->qgroup_lock);
@@ -2439,8 +2501,8 @@ retry:
 
                qg = unode_aux_to_qgroup(unode);
 
-               trace_qgroup_update_reserve(fs_info, qg, num_bytes);
-               qg->reserved += num_bytes;
+               trace_qgroup_update_reserve(fs_info, qg, num_bytes, type);
+               qgroup_rsv_add(fs_info, qg, num_bytes, type);
        }
 
 out:
@@ -2449,7 +2511,8 @@ out:
 }
 
 void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
-                              u64 ref_root, u64 num_bytes)
+                              u64 ref_root, u64 num_bytes,
+                              enum btrfs_qgroup_rsv_type type)
 {
        struct btrfs_root *quota_root;
        struct btrfs_qgroup *qgroup;
@@ -2485,11 +2548,8 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
 
                qg = unode_aux_to_qgroup(unode);
 
-               trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes);
-               if (qg->reserved < num_bytes)
-                       report_reserved_underflow(fs_info, qg, num_bytes);
-               else
-                       qg->reserved -= num_bytes;
+               trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes, type);
+               qgroup_rsv_release(fs_info, qg, num_bytes, type);
 
                list_for_each_entry(glist, &qg->groups, next_group) {
                        ret = ulist_add(fs_info->qgroup_ulist,
@@ -2877,7 +2937,7 @@ int btrfs_qgroup_reserve_data(struct inode *inode,
                                        to_reserve, QGROUP_RESERVE);
        if (ret < 0)
                goto cleanup;
-       ret = qgroup_reserve(root, to_reserve, true);
+       ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA);
        if (ret < 0)
                goto cleanup;
 
@@ -2940,7 +3000,8 @@ static int qgroup_free_reserved_data(struct inode *inode,
                        goto out;
                freed += changeset.bytes_changed;
        }
-       btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed);
+       btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed,
+                                 BTRFS_QGROUP_RSV_DATA);
        ret = freed;
 out:
        extent_changeset_release(&changeset);
@@ -2972,7 +3033,7 @@ static int __btrfs_qgroup_release_data(struct inode *inode,
        if (free)
                btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info,
                                BTRFS_I(inode)->root->objectid,
-                               changeset.bytes_changed);
+                               changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA);
        ret = changeset.bytes_changed;
 out:
        extent_changeset_release(&changeset);
@@ -3029,7 +3090,7 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
 
        BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
        trace_qgroup_meta_reserve(root, (s64)num_bytes);
-       ret = qgroup_reserve(root, num_bytes, enforce);
+       ret = qgroup_reserve(root, num_bytes, enforce, BTRFS_QGROUP_RSV_META);
        if (ret < 0)
                return ret;
        atomic64_add(num_bytes, &root->qgroup_meta_rsv);
@@ -3049,7 +3110,8 @@ void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
        if (reserved == 0)
                return;
        trace_qgroup_meta_reserve(root, -(s64)reserved);
-       btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved);
+       btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved,
+                                 BTRFS_QGROUP_RSV_META);
 }
 
 void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
@@ -3064,7 +3126,8 @@ void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
        WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes);
        atomic64_sub(num_bytes, &root->qgroup_meta_rsv);
        trace_qgroup_meta_reserve(root, -(s64)num_bytes);
-       btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes);
+       btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes,
+                                 BTRFS_QGROUP_RSV_META);
 }
 
 /*
@@ -3092,7 +3155,7 @@ void btrfs_qgroup_check_reserved_leak(struct inode *inode)
                }
                btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info,
                                BTRFS_I(inode)->root->objectid,
-                               changeset.bytes_changed);
+                               changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA);
 
        }
        extent_changeset_release(&changeset);