btrfs: introduce btrfs_try_lock_balance
authorNikolay Borisov <nborisov@suse.com>
Tue, 3 May 2022 08:36:36 +0000 (11:36 +0300)
committerDavid Sterba <dsterba@suse.com>
Mon, 25 Jul 2022 15:44:34 +0000 (17:44 +0200)
This function contains the factored out locking sequence of
btrfs_ioctl_balance. Having this piece of code separate helps to
simplify btrfs_ioctl_balance which has too complicated.  This will be
used in the next patch to streamline the logic in btrfs_ioctl_balance.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ioctl.c

index 0f79af9..e40ce7a 100644 (file)
@@ -4355,6 +4355,72 @@ void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
        spin_unlock(&fs_info->balance_lock);
 }
 
+/**
+ * Try to acquire fs_info::balance_mutex as well as set BTRFS_EXLCOP_BALANCE as
+ * required.
+ *
+ * @fs_info:       the filesystem
+ * @excl_acquired: ptr to boolean value which is set to false in case balance
+ *                 is being resumed
+ *
+ * Return 0 on success in which case both fs_info::balance is acquired as well
+ * as exclusive ops are blocked. In case of failure return an error code.
+ */
+static int btrfs_try_lock_balance(struct btrfs_fs_info *fs_info, bool *excl_acquired)
+{
+       int ret;
+
+       /*
+        * Exclusive operation is locked. Three possibilities:
+        *   (1) some other op is running
+        *   (2) balance is running
+        *   (3) balance is paused -- special case (think resume)
+        */
+       while (1) {
+               if (btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) {
+                       *excl_acquired = true;
+                       mutex_lock(&fs_info->balance_mutex);
+                       return 0;
+               }
+
+               mutex_lock(&fs_info->balance_mutex);
+               if (fs_info->balance_ctl) {
+                       /* This is either (2) or (3) */
+                       if (test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
+                               /* This is (2) */
+                               ret = -EINPROGRESS;
+                               goto out_failure;
+
+                       } else {
+                               mutex_unlock(&fs_info->balance_mutex);
+                               /*
+                                * Lock released to allow other waiters to
+                                * continue, we'll reexamine the status again.
+                                */
+                               mutex_lock(&fs_info->balance_mutex);
+
+                               if (fs_info->balance_ctl &&
+                                   !test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
+                                       /* This is (3) */
+                                       *excl_acquired = false;
+                                       return 0;
+                               }
+                       }
+               } else {
+                       /* This is (1) */
+                       ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+                       goto out_failure;
+               }
+
+               mutex_unlock(&fs_info->balance_mutex);
+       }
+
+out_failure:
+       mutex_unlock(&fs_info->balance_mutex);
+       *excl_acquired = false;
+       return ret;
+}
+
 static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 {
        struct btrfs_root *root = BTRFS_I(file_inode(file))->root;