]> xenbits.xensource.com Git - people/pauldu/linux.git/commitdiff
btrfs: qgroup: add new quota mode for simple quotas
authorBoris Burkov <boris@bur.io>
Tue, 16 May 2023 23:35:45 +0000 (16:35 -0700)
committerDavid Sterba <dsterba@suse.com>
Thu, 12 Oct 2023 14:44:10 +0000 (16:44 +0200)
Add a new quota mode called "simple quotas". It can be enabled by the
existing quota enable ioctl via a new command, and sets an incompat
bit, as the implementation of simple quotas will make backwards
incompatible changes to the disk format of the extent tree.

Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/delayed-ref.c
fs/btrfs/fs.h
fs/btrfs/ioctl.c
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
fs/btrfs/root-tree.c
fs/btrfs/transaction.c
include/uapi/linux/btrfs.h
include/uapi/linux/btrfs_tree.h

index 25d0cdf85a9155aa1561ad8b0b17c2ef15095497..0a80224c87840e4c7ac4be6c045688bb96f7f239 100644 (file)
@@ -959,8 +959,7 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
                return -ENOMEM;
        }
 
-       if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
-           !generic_ref->skip_qgroup) {
+       if (btrfs_qgroup_enabled(fs_info) && !generic_ref->skip_qgroup) {
                record = kzalloc(sizeof(*record), GFP_NOFS);
                if (!record) {
                        kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref);
@@ -1063,8 +1062,7 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
                return -ENOMEM;
        }
 
-       if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
-           !generic_ref->skip_qgroup) {
+       if (btrfs_qgroup_enabled(fs_info) && !generic_ref->skip_qgroup) {
                record = kzalloc(sizeof(*record), GFP_NOFS);
                if (!record) {
                        kmem_cache_free(btrfs_delayed_data_ref_cachep, ref);
index 19f9a444bcd8915f5fdfafc64e22244f8071c2c2..e8fcf34f208a9f7c44d5f4e92c5867d9b58917ba 100644 (file)
@@ -220,7 +220,8 @@ enum {
         BTRFS_FEATURE_INCOMPAT_NO_HOLES        |       \
         BTRFS_FEATURE_INCOMPAT_METADATA_UUID   |       \
         BTRFS_FEATURE_INCOMPAT_RAID1C34        |       \
-        BTRFS_FEATURE_INCOMPAT_ZONED)
+        BTRFS_FEATURE_INCOMPAT_ZONED           |       \
+        BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA)
 
 #ifdef CONFIG_BTRFS_DEBUG
        /*
index 5dbc3de66193e435299dd113b7341786d6130699..58189d99a22c91e0d2ee6bc62ae6342938272ead 100644 (file)
@@ -3697,7 +3697,8 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
 
        switch (sa->cmd) {
        case BTRFS_QUOTA_CTL_ENABLE:
-               ret = btrfs_quota_enable(fs_info);
+       case BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA:
+               ret = btrfs_quota_enable(fs_info, sa);
                break;
        case BTRFS_QUOTA_CTL_DISABLE:
                ret = btrfs_quota_disable(fs_info);
index 69787b87a4f8b819844b45028cecfb2e0d2b7a70..1c0efc1757c13d17ec7554546dc3df1cb34c6db3 100644 (file)
@@ -34,9 +34,21 @@ enum btrfs_qgroup_mode btrfs_qgroup_mode(struct btrfs_fs_info *fs_info)
 {
        if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
                return BTRFS_QGROUP_MODE_DISABLED;
+       if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE)
+               return BTRFS_QGROUP_MODE_SIMPLE;
        return BTRFS_QGROUP_MODE_FULL;
 }
 
+bool btrfs_qgroup_enabled(struct btrfs_fs_info *fs_info)
+{
+       return btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_DISABLED;
+}
+
+bool btrfs_qgroup_full_accounting(struct btrfs_fs_info *fs_info)
+{
+       return btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_FULL;
+}
+
 /*
  * Helpers to access qgroup reservation
  *
@@ -350,6 +362,8 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
 
 static void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info)
 {
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
+               return;
        fs_info->qgroup_flags |= (BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT |
                                  BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN |
                                  BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING);
@@ -370,8 +384,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
        int ret = 0;
        u64 flags = 0;
        u64 rescan_progress = 0;
+       bool simple;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED)
                return 0;
 
        fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
@@ -421,14 +436,14 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
                                 "old qgroup version, quota disabled");
                                goto out;
                        }
+                       fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, ptr);
+                       simple = (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE);
                        if (btrfs_qgroup_status_generation(l, ptr) !=
-                           fs_info->generation) {
+                           fs_info->generation && !simple) {
                                qgroup_mark_inconsistent(fs_info);
                                btrfs_err(fs_info,
                                        "qgroup generation mismatch, marked as inconsistent");
                        }
-                       fs_info->qgroup_flags = btrfs_qgroup_status_flags(l,
-                                                                         ptr);
                        rescan_progress = btrfs_qgroup_status_rescan(l, ptr);
                        goto next1;
                }
@@ -571,7 +586,7 @@ bool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info)
        struct rb_node *node;
        bool ret = false;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED)
                return ret;
        /*
         * Since we're unmounting, there is no race and no need to grab qgroup
@@ -970,7 +985,8 @@ out:
        return ret;
 }
 
-int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
+int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
+                      struct btrfs_ioctl_quota_ctl_args *quota_ctl_args)
 {
        struct btrfs_root *quota_root;
        struct btrfs_root *tree_root = fs_info->tree_root;
@@ -983,6 +999,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
        struct btrfs_qgroup *prealloc = NULL;
        struct btrfs_trans_handle *trans = NULL;
        struct ulist *ulist = NULL;
+       const bool simple = (quota_ctl_args->cmd == BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA);
        int ret = 0;
        int slot;
 
@@ -1085,8 +1102,11 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
                                 struct btrfs_qgroup_status_item);
        btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid);
        btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION);
-       fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON |
-                               BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
+       fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON;
+       if (simple)
+               fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
+       else
+               fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
        btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags &
                                      BTRFS_QGROUP_STATUS_FLAGS_MASK);
        btrfs_set_qgroup_status_rescan(leaf, ptr, 0);
@@ -1214,8 +1234,14 @@ out_add_root:
        spin_lock(&fs_info->qgroup_lock);
        fs_info->quota_root = quota_root;
        set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+       if (simple)
+               btrfs_set_fs_incompat(fs_info, SIMPLE_QUOTA);
        spin_unlock(&fs_info->qgroup_lock);
 
+       /* Skip rescan for simple qgroups. */
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
+               goto out_free_path;
+
        ret = qgroup_rescan_init(fs_info, 0, 1);
        if (!ret) {
                qgroup_rescan_zero_tracking(fs_info);
@@ -1330,6 +1356,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
        fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
+       fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
        fs_info->qgroup_drop_subtree_thres = BTRFS_MAX_LEVEL;
        spin_unlock(&fs_info->qgroup_lock);
 
@@ -1810,6 +1837,9 @@ int btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info,
        struct btrfs_qgroup_extent_record *entry;
        u64 bytenr = record->bytenr;
 
+       if (!btrfs_qgroup_full_accounting(fs_info))
+               return 0;
+
        lockdep_assert_held(&delayed_refs->lock);
        trace_btrfs_qgroup_trace_extent(fs_info, record);
 
@@ -1863,6 +1893,8 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
        struct btrfs_backref_walk_ctx ctx = { 0 };
        int ret;
 
+       if (!btrfs_qgroup_full_accounting(trans->fs_info))
+               return 0;
        /*
         * We are always called in a context where we are already holding a
         * transaction handle. Often we are called when adding a data delayed
@@ -1931,8 +1963,7 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr,
        struct btrfs_delayed_ref_root *delayed_refs;
        int ret;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)
-           || bytenr == 0 || num_bytes == 0)
+       if (!btrfs_qgroup_full_accounting(fs_info) || bytenr == 0 || num_bytes == 0)
                return 0;
        record = kzalloc(sizeof(*record), GFP_NOFS);
        if (!record)
@@ -1970,7 +2001,7 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans,
        u64 bytenr, num_bytes;
 
        /* We can be called directly from walk_up_proc() */
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_full_accounting(fs_info))
                return 0;
 
        for (i = 0; i < nr; i++) {
@@ -2346,7 +2377,7 @@ static int qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans,
        int level;
        int ret;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_full_accounting(fs_info))
                return 0;
 
        /* Wrong parameter order */
@@ -2413,7 +2444,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
        BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL);
        BUG_ON(root_eb == NULL);
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_full_accounting(fs_info))
                return 0;
 
        spin_lock(&fs_info->qgroup_lock);
@@ -2747,7 +2778,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
         * If quotas get disabled meanwhile, the resources need to be freed and
         * we can't just exit here.
         */
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+       if (!btrfs_qgroup_full_accounting(fs_info) ||
            fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING)
                goto out_free;
 
@@ -2816,6 +2847,9 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
        u64 qgroup_to_skip;
        int ret = 0;
 
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
+               return 0;
+
        delayed_refs = &trans->transaction->delayed_refs;
        qgroup_to_skip = delayed_refs->qgroup_to_skip;
        while ((node = rb_first(&delayed_refs->dirty_extent_root))) {
@@ -2931,7 +2965,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
                        qgroup_mark_inconsistent(fs_info);
                spin_lock(&fs_info->qgroup_lock);
        }
-       if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (btrfs_qgroup_enabled(fs_info))
                fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON;
        else
                fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
@@ -2990,7 +3024,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 
        if (!committing)
                mutex_lock(&fs_info->qgroup_ioctl_lock);
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_enabled(fs_info))
                goto out;
 
        quota_root = fs_info->quota_root;
@@ -3076,7 +3110,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
                qgroup_dirty(fs_info, dstgroup);
        }
 
-       if (srcid) {
+       if (srcid && btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_FULL) {
                srcgroup = find_qgroup_rb(fs_info, srcid);
                if (!srcgroup)
                        goto unlock;
@@ -3339,6 +3373,9 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
        int slot;
        int ret;
 
+       if (!btrfs_qgroup_full_accounting(fs_info))
+               return 1;
+
        mutex_lock(&fs_info->qgroup_rescan_lock);
        extent_root = btrfs_extent_root(fs_info,
                                fs_info->qgroup_rescan_progress.objectid);
@@ -3419,10 +3456,15 @@ out:
 
 static bool rescan_should_stop(struct btrfs_fs_info *fs_info)
 {
-       return btrfs_fs_closing(fs_info) ||
-               test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) ||
-               !test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
-                         fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN;
+       if (btrfs_fs_closing(fs_info))
+               return true;
+       if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
+               return true;
+       if (!btrfs_qgroup_enabled(fs_info))
+               return true;
+       if (fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN)
+               return true;
+       return false;
 }
 
 static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
@@ -3436,6 +3478,9 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
        bool stopped = false;
        bool did_leaf_rescans = false;
 
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
+               return;
+
        path = btrfs_alloc_path();
        if (!path)
                goto out;
@@ -3539,6 +3584,11 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
 {
        int ret = 0;
 
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE) {
+               btrfs_warn(fs_info, "qgroup rescan init failed, running in simple mode");
+               return -EINVAL;
+       }
+
        if (!init_flags) {
                /* we're resuming qgroup rescan at mount time */
                if (!(fs_info->qgroup_flags &
@@ -3569,7 +3619,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
                        btrfs_warn(fs_info,
                        "qgroup rescan init failed, qgroup is not enabled");
                        ret = -EINVAL;
-               } else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
+               } else if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) {
                        /* Quota disable is in progress */
                        ret = -EBUSY;
                }
@@ -3828,7 +3878,7 @@ static int qgroup_reserve_data(struct btrfs_inode *inode,
        u64 to_reserve;
        int ret;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) ||
+       if (btrfs_qgroup_mode(root->fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
            !is_fstree(root->root_key.objectid) || len == 0)
                return 0;
 
@@ -3960,7 +4010,7 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode,
        int trace_op = QGROUP_RELEASE;
        int ret;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &inode->root->fs_info->flags))
+       if (btrfs_qgroup_mode(inode->root->fs_info) == BTRFS_QGROUP_MODE_DISABLED)
                return 0;
 
        /* In release case, we shouldn't have @reserved */
@@ -4071,7 +4121,7 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
        struct btrfs_fs_info *fs_info = root->fs_info;
        int ret;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
            !is_fstree(root->root_key.objectid) || num_bytes == 0)
                return 0;
 
@@ -4116,7 +4166,7 @@ void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
            !is_fstree(root->root_key.objectid))
                return;
 
@@ -4132,7 +4182,7 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
            !is_fstree(root->root_key.objectid))
                return;
 
@@ -4191,7 +4241,7 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+       if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
            !is_fstree(root->root_key.objectid))
                return;
        /* Same as btrfs_qgroup_free_meta_prealloc() */
@@ -4299,7 +4349,7 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans,
        int level = btrfs_header_level(subvol_parent) - 1;
        int ret = 0;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_full_accounting(fs_info))
                return 0;
 
        if (btrfs_node_ptr_generation(subvol_parent, subvol_slot) >
@@ -4409,7 +4459,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
        int ret = 0;
        int i;
 
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_full_accounting(fs_info))
                return 0;
        if (!is_fstree(root->root_key.objectid) || !root->reloc_root)
                return 0;
index aed6117740476588b9eb76c5d0fa97d348a6872a..0441d2ff5a49a25dbc0138a2ce7ee20b331ac9e0 100644 (file)
  *     subtree rescan for them.
  */
 
-#define BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN                (1UL << 3)
-#define BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING                (1UL << 4)
+/*
+ * These flags share the flags field of the btrfs_qgroup_status_item with the
+ * persisted flags defined in btrfs_tree.h.
+ *
+ * To minimize the chance of collision with new persisted status flags, these
+ * count backwards from the MSB.
+ */
+#define BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN                (1ULL << 63)
+#define BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING                (1ULL << 62)
 
 /*
  * Record a dirty extent, and info qgroup to update quota on it
@@ -276,13 +283,17 @@ enum {
        ENUM_BIT(QGROUP_FREE),
 };
 
-int btrfs_quota_enable(struct btrfs_fs_info *fs_info);
 enum btrfs_qgroup_mode {
        BTRFS_QGROUP_MODE_DISABLED,
        BTRFS_QGROUP_MODE_FULL,
+       BTRFS_QGROUP_MODE_SIMPLE
 };
 
 enum btrfs_qgroup_mode btrfs_qgroup_mode(struct btrfs_fs_info *fs_info);
+bool btrfs_qgroup_enabled(struct btrfs_fs_info *fs_info);
+bool btrfs_qgroup_full_accounting(struct btrfs_fs_info *fs_info);
+int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
+                      struct btrfs_ioctl_quota_ctl_args *quota_ctl_args);
 int btrfs_quota_disable(struct btrfs_fs_info *fs_info);
 int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info);
 void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info);
index 7c9d87b9b72ee397bcc49ee7d1f36fbf2cc1e1c0..603ad1459368c32c68f851a565ef3da1cc0ac977 100644 (file)
@@ -510,7 +510,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
 
-       if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
+       if (btrfs_qgroup_enabled(fs_info)) {
                /* One for parent inode, two for dir entries */
                qgroup_num_bytes = 3 * fs_info->nodesize;
                ret = btrfs_qgroup_reserve_meta_prealloc(root,
index 3f9f933039c624dda7d49e708ea0f4c4ad971537..f5c3ea01c3d6a95435d368126050a18ab5099b80 100644 (file)
@@ -1620,11 +1620,10 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
        int ret;
 
        /*
-        * Save some performance in the case that qgroups are not
-        * enabled. If this check races with the ioctl, rescan will
-        * kick in anyway.
+        * Save some performance in the case that full qgroups are not enabled.
+        * If this check races with the ioctl, rescan will kick in anyway.
         */
-       if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+       if (!btrfs_qgroup_full_accounting(fs_info))
                return 0;
 
        /*
index b9a1d9af8ae8d3ed325efcdf871537f1c34c93f2..7c29d82db9ee0dcb5ce770b384149c9734a50f30 100644 (file)
@@ -334,6 +334,7 @@ struct btrfs_ioctl_fs_info_args {
 #define BTRFS_FEATURE_INCOMPAT_ZONED           (1ULL << 12)
 #define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2  (1ULL << 13)
 #define BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE        (1ULL << 14)
+#define BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA    (1ULL << 16)
 
 struct btrfs_ioctl_feature_flags {
        __u64 compat_flags;
@@ -754,6 +755,7 @@ struct btrfs_ioctl_get_dev_stats {
 #define BTRFS_QUOTA_CTL_ENABLE 1
 #define BTRFS_QUOTA_CTL_DISABLE        2
 #define BTRFS_QUOTA_CTL_RESCAN__NOTUSED        3
+#define BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA 4
 struct btrfs_ioctl_quota_ctl_args {
        __u64 cmd;
        __u64 status;
index ca65d7b7a6ca19526fd98a81e67a6775a5ec83f8..a1d5347f6adbe9853417472bcbdda92433d93498 100644 (file)
@@ -1233,9 +1233,17 @@ static inline __u16 btrfs_qgroup_level(__u64 qgroupid)
  */
 #define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT  (1ULL << 2)
 
+/*
+ * Whether or not this filesystem is using simple quotas.  Not exactly the
+ * incompat bit, because we support using simple quotas, disabling it, then
+ * going back to full qgroup quotas.
+ */
+#define BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE   (1ULL << 3)
+
 #define BTRFS_QGROUP_STATUS_FLAGS_MASK (BTRFS_QGROUP_STATUS_FLAG_ON |          \
                                         BTRFS_QGROUP_STATUS_FLAG_RESCAN |      \
-                                        BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
+                                        BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT | \
+                                        BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE)
 
 #define BTRFS_QGROUP_STATUS_VERSION        1