btrfs: allow device add if balance is paused
authorNikolay Borisov <nborisov@suse.com>
Thu, 25 Nov 2021 09:14:43 +0000 (11:14 +0200)
committerDavid Sterba <dsterba@suse.com>
Fri, 7 Jan 2022 13:18:23 +0000 (14:18 +0100)
Currently paused balance precludes adding a device since they are both
considered exclusive ops and we can have at most one running at a time.
This is problematic in case a filesystem encounters an ENOSPC situation
while balance is running, in this case the only thing the user can do
is mount the fs with "skip_balance" which pauses balance and delete some
data to free up space for balance. However, it should be possible to add
a new device when balance is paused.

Fix this by allowing device add to proceed when balance is paused.

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 f706287..7565b66 100644 (file)
@@ -3174,13 +3174,25 @@ out:
 static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
 {
        struct btrfs_ioctl_vol_args *vol_args;
+       bool restore_op = false;
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_DEV_ADD))
-               return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_DEV_ADD)) {
+               if (!btrfs_exclop_start_try_lock(fs_info, BTRFS_EXCLOP_DEV_ADD))
+                       return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+
+               /*
+                * We can do the device add because we have a paused balanced,
+                * change the exclusive op type and remember we should bring
+                * back the paused balance
+                */
+               fs_info->exclusive_operation = BTRFS_EXCLOP_DEV_ADD;
+               btrfs_exclop_start_unlock(fs_info);
+               restore_op = true;
+       }
 
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args)) {
@@ -3196,7 +3208,10 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
 
        kfree(vol_args);
 out:
-       btrfs_exclop_finish(fs_info);
+       if (restore_op)
+               btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE_PAUSED);
+       else
+               btrfs_exclop_finish(fs_info);
        return ret;
 }