Commit efc0e69c authored by Nikolay Borisov's avatar Nikolay Borisov Committed by David Sterba

btrfs: introduce exclusive operation BALANCE_PAUSED state

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: default avatarNikolay Borisov <nborisov@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent d96b3424
...@@ -611,6 +611,7 @@ enum { ...@@ -611,6 +611,7 @@ enum {
*/ */
enum btrfs_exclusive_operation { enum btrfs_exclusive_operation {
BTRFS_EXCLOP_NONE, BTRFS_EXCLOP_NONE,
BTRFS_EXCLOP_BALANCE_PAUSED,
BTRFS_EXCLOP_BALANCE, BTRFS_EXCLOP_BALANCE,
BTRFS_EXCLOP_DEV_ADD, BTRFS_EXCLOP_DEV_ADD,
BTRFS_EXCLOP_DEV_REMOVE, BTRFS_EXCLOP_DEV_REMOVE,
...@@ -3321,6 +3322,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info, ...@@ -3321,6 +3322,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
enum btrfs_exclusive_operation type); enum btrfs_exclusive_operation type);
void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info); void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info);
void btrfs_exclop_finish(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 */ /* file.c */
int __init btrfs_auto_defrag_init(void); int __init btrfs_auto_defrag_init(void);
......
...@@ -414,6 +414,29 @@ void btrfs_exclop_finish(struct btrfs_fs_info *fs_info) ...@@ -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"); 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) static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
...@@ -4056,6 +4079,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) ...@@ -4056,6 +4079,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
spin_lock(&fs_info->balance_lock); spin_lock(&fs_info->balance_lock);
bctl->flags |= BTRFS_BALANCE_RESUME; bctl->flags |= BTRFS_BALANCE_RESUME;
spin_unlock(&fs_info->balance_lock); spin_unlock(&fs_info->balance_lock);
btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE);
goto do_balance; goto do_balance;
} }
......
...@@ -4394,8 +4394,10 @@ int btrfs_balance(struct btrfs_fs_info *fs_info, ...@@ -4394,8 +4394,10 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
ret = __btrfs_balance(fs_info); ret = __btrfs_balance(fs_info);
mutex_lock(&fs_info->balance_mutex); 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_info(fs_info, "balance: paused");
btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE_PAUSED);
}
/* /*
* Balance can be canceled by: * Balance can be canceled by:
* *
...@@ -4471,6 +4473,10 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) ...@@ -4471,6 +4473,10 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
return 0; 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 * 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 * 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) ...@@ -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 * is in a paused state and must have fs_info::balance_ctl properly
* set up. * 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, btrfs_warn(fs_info,
"balance: cannot set exclusive op status, resume manually"); "balance: cannot set exclusive op status, resume manually");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment