]> www.infradead.org Git - users/willy/xarray.git/commitdiff
btrfs: protect exclusive_operation by super_lock
authorDavid Sterba <dsterba@suse.com>
Fri, 14 May 2021 15:42:30 +0000 (17:42 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 21 Jun 2021 13:19:06 +0000 (15:19 +0200)
The exclusive operation is now atomically checked and set using bit
operations. Switch it to protection by spinlock. The super block lock is
not frequently used and adding a new lock seems like an overkill so it
should be safe to reuse it.

The reason to use spinlock is to enhance the locking context so more
checks can be done, eg. allowing the same exclusive operation enter
the exclop section and cancel the running one. This will be used for
resize and device delete.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.h
fs/btrfs/ioctl.c

index a3b628ea4d64eeb39de89158fc054c87578a3934..4049f533e35e40bbc93188523dacb2f31394c94f 100644 (file)
@@ -992,8 +992,8 @@ struct btrfs_fs_info {
         */
        int send_in_progress;
 
-       /* Type of exclusive operation running */
-       unsigned long exclusive_operation;
+       /* Type of exclusive operation running, protected by super_lock */
+       enum btrfs_exclusive_operation exclusive_operation;
 
        /*
         * Zone size > 0 when in ZONED mode, otherwise it's used for a check
index a7739461533d33f79a84e8c908595800a945bbfd..c4e710ea08baafb8ff2f27c1ec6e4c2f9e62392c 100644 (file)
@@ -353,15 +353,29 @@ update_flags:
        return ret;
 }
 
+/*
+ * Start exclusive operation @type, return true on success
+ */
 bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
                        enum btrfs_exclusive_operation type)
 {
-       return !cmpxchg(&fs_info->exclusive_operation, BTRFS_EXCLOP_NONE, type);
+       bool ret = false;
+
+       spin_lock(&fs_info->super_lock);
+       if (fs_info->exclusive_operation == BTRFS_EXCLOP_NONE) {
+               fs_info->exclusive_operation = type;
+               ret = true;
+       }
+       spin_unlock(&fs_info->super_lock);
+
+       return ret;
 }
 
 void btrfs_exclop_finish(struct btrfs_fs_info *fs_info)
 {
+       spin_lock(&fs_info->super_lock);
        WRITE_ONCE(fs_info->exclusive_operation, BTRFS_EXCLOP_NONE);
+       spin_unlock(&fs_info->super_lock);
        sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation");
 }