btrfs: introduce exclusive operation BALANCE_PAUSED state
authorNikolay Borisov <nborisov@suse.com>
Thu, 25 Nov 2021 09:14:41 +0000 (11:14 +0200)
committerDavid Sterba <dsterba@suse.com>
Fri, 7 Jan 2022 13:18:23 +0000 (14:18 +0100)
Current set of exclusive operation states is not sufficient to handle
all practical use cases. In particular there is a need to be able to add
a device to a filesystem that have paused balance. Currently there is no
way to distinguish between a running and a paused balance. Fix this by
introducing BTRFS_EXCLOP_BALANCE_PAUSED which is going to be set in 2
occasions:

1. When a filesystem is mounted with skip_balance and there is an
   unfinished balance it will now be into BALANCE_PAUSED instead of
   simply BALANCE state.

2. When a running 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/ctree.h
fs/btrfs/ioctl.c
fs/btrfs/volumes.c

index 0c92158..4ea7157 100644 (file)
@@ -611,6 +611,7 @@ enum {
  */
 enum btrfs_exclusive_operation {
        BTRFS_EXCLOP_NONE,
+       BTRFS_EXCLOP_BALANCE_PAUSED,
        BTRFS_EXCLOP_BALANCE,
        BTRFS_EXCLOP_DEV_ADD,
        BTRFS_EXCLOP_DEV_REMOVE,
@@ -3321,6 +3322,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
                                 enum btrfs_exclusive_operation type);
 void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info);
 void btrfs_exclop_finish(struct btrfs_fs_info *fs_info);
+void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
+                         enum btrfs_exclusive_operation op);
+
 
 /* file.c */
 int __init btrfs_auto_defrag_init(void);
index af77098..6752e4b 100644 (file)
@@ -414,6 +414,29 @@ void btrfs_exclop_finish(struct btrfs_fs_info *fs_info)
        sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation");
 }
 
+void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
+                         enum btrfs_exclusive_operation op)
+{
+       switch (op) {
+       case BTRFS_EXCLOP_BALANCE_PAUSED:
+               spin_lock(&fs_info->super_lock);
+               ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE ||
+                      fs_info->exclusive_operation == BTRFS_EXCLOP_DEV_ADD);
+               fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE_PAUSED;
+               spin_unlock(&fs_info->super_lock);
+               break;
+       case BTRFS_EXCLOP_BALANCE:
+               spin_lock(&fs_info->super_lock);
+               ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
+               fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE;
+               spin_unlock(&fs_info->super_lock);
+               break;
+       default:
+               btrfs_warn(fs_info,
+                       "invalid exclop balance operation %d requested", op);
+       }
+}
+
 static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
 {
        struct inode *inode = file_inode(file);
@@ -4056,6 +4079,7 @@ locked:
                        spin_lock(&fs_info->balance_lock);
                        bctl->flags |= BTRFS_BALANCE_RESUME;
                        spin_unlock(&fs_info->balance_lock);
+                       btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE);
 
                        goto do_balance;
                }
index 4f77268..9db9d66 100644 (file)
@@ -4394,8 +4394,10 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
        ret = __btrfs_balance(fs_info);
 
        mutex_lock(&fs_info->balance_mutex);
-       if (ret == -ECANCELED && atomic_read(&fs_info->balance_pause_req))
+       if (ret == -ECANCELED && atomic_read(&fs_info->balance_pause_req)) {
                btrfs_info(fs_info, "balance: paused");
+               btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE_PAUSED);
+       }
        /*
         * Balance can be canceled by:
         *
@@ -4471,6 +4473,10 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
                return 0;
        }
 
+       spin_lock(&fs_info->super_lock);
+       ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
+       fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE;
+       spin_unlock(&fs_info->super_lock);
        /*
         * A ro->rw remount sequence should continue with the paused balance
         * regardless of who pauses it, system or the user as of now, so set
@@ -4539,7 +4545,7 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
         * is in a paused state and must have fs_info::balance_ctl properly
         * set up.
         */
-       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE))
+       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE_PAUSED))
                btrfs_warn(fs_info,
        "balance: cannot set exclusive op status, resume manually");