Commit 171938e5 authored by David Sterba's avatar David Sterba

btrfs: track exclusive filesystem operation in flags

There are several operations, usually started from ioctls, that cannot
run concurrently. The status is tracked in
mutually_exclusive_operation_running as an atomic_t. We can easily track
the status as one of the per-filesystem flag bits with same
synchronization guarantees.

The conversion replaces:

* atomic_xchg(..., 1)    ->   test_and_set_bit(FLAG, ...)
* atomic_set(..., 0)     ->   clear_bit(FLAG, ...)
Reviewed-by: default avatarAnand Jain <anand.jain@oracle.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 48a89bc4
...@@ -705,6 +705,11 @@ struct btrfs_delayed_root; ...@@ -705,6 +705,11 @@ struct btrfs_delayed_root;
#define BTRFS_FS_BTREE_ERR 11 #define BTRFS_FS_BTREE_ERR 11
#define BTRFS_FS_LOG1_ERR 12 #define BTRFS_FS_LOG1_ERR 12
#define BTRFS_FS_LOG2_ERR 13 #define BTRFS_FS_LOG2_ERR 13
/*
* Indicate that a whole-filesystem exclusive operation is running
* (device replace, resize, device add/delete, balance)
*/
#define BTRFS_FS_EXCL_OP 14
struct btrfs_fs_info { struct btrfs_fs_info {
u8 fsid[BTRFS_FSID_SIZE]; u8 fsid[BTRFS_FSID_SIZE];
...@@ -1070,8 +1075,6 @@ struct btrfs_fs_info { ...@@ -1070,8 +1075,6 @@ struct btrfs_fs_info {
/* device replace state */ /* device replace state */
struct btrfs_dev_replace dev_replace; struct btrfs_dev_replace dev_replace;
atomic_t mutually_exclusive_operation_running;
struct percpu_counter bio_counter; struct percpu_counter bio_counter;
wait_queue_head_t replace_wait; wait_queue_head_t replace_wait;
......
...@@ -784,8 +784,7 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info) ...@@ -784,8 +784,7 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info)
} }
btrfs_dev_replace_unlock(dev_replace, 1); btrfs_dev_replace_unlock(dev_replace, 1);
WARN_ON(atomic_xchg( WARN_ON(test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags));
&fs_info->mutually_exclusive_operation_running, 1));
task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl"); task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl");
return PTR_ERR_OR_ZERO(task); return PTR_ERR_OR_ZERO(task);
} }
...@@ -814,7 +813,7 @@ static int btrfs_dev_replace_kthread(void *data) ...@@ -814,7 +813,7 @@ static int btrfs_dev_replace_kthread(void *data)
(unsigned int)progress); (unsigned int)progress);
} }
btrfs_dev_replace_continue_on_mount(fs_info); btrfs_dev_replace_continue_on_mount(fs_info);
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
return 0; return 0;
} }
......
...@@ -1504,7 +1504,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, ...@@ -1504,7 +1504,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
if (ret) if (ret)
return ret; return ret;
if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) {
mnt_drop_write_file(file); mnt_drop_write_file(file);
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
} }
...@@ -1619,7 +1619,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, ...@@ -1619,7 +1619,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
kfree(vol_args); kfree(vol_args);
out: out:
mutex_unlock(&fs_info->volume_mutex); mutex_unlock(&fs_info->volume_mutex);
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
mnt_drop_write_file(file); mnt_drop_write_file(file);
return ret; return ret;
} }
...@@ -2661,7 +2661,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) ...@@ -2661,7 +2661,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags))
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->volume_mutex);
...@@ -2680,7 +2680,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) ...@@ -2680,7 +2680,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
kfree(vol_args); kfree(vol_args);
out: out:
mutex_unlock(&fs_info->volume_mutex); mutex_unlock(&fs_info->volume_mutex);
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
return ret; return ret;
} }
...@@ -2708,7 +2708,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) ...@@ -2708,7 +2708,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) {
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
goto out; goto out;
} }
...@@ -2721,7 +2721,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) ...@@ -2721,7 +2721,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
ret = btrfs_rm_device(fs_info, vol_args->name, 0); ret = btrfs_rm_device(fs_info, vol_args->name, 0);
} }
mutex_unlock(&fs_info->volume_mutex); mutex_unlock(&fs_info->volume_mutex);
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
if (!ret) { if (!ret) {
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID)
...@@ -2752,7 +2752,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) ...@@ -2752,7 +2752,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
if (ret) if (ret)
return ret; return ret;
if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) {
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
goto out_drop_write; goto out_drop_write;
} }
...@@ -2772,7 +2772,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) ...@@ -2772,7 +2772,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
btrfs_info(fs_info, "disk deleted %s", vol_args->name); btrfs_info(fs_info, "disk deleted %s", vol_args->name);
kfree(vol_args); kfree(vol_args);
out: out:
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
out_drop_write: out_drop_write:
mnt_drop_write_file(file); mnt_drop_write_file(file);
...@@ -4442,13 +4442,11 @@ static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info, ...@@ -4442,13 +4442,11 @@ static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info,
ret = -EROFS; ret = -EROFS;
goto out; goto out;
} }
if (atomic_xchg( if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) {
&fs_info->mutually_exclusive_operation_running, 1)) {
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
} else { } else {
ret = btrfs_dev_replace_by_ioctl(fs_info, p); ret = btrfs_dev_replace_by_ioctl(fs_info, p);
atomic_set( clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
&fs_info->mutually_exclusive_operation_running, 0);
} }
break; break;
case BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS: case BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS:
...@@ -4643,7 +4641,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) ...@@ -4643,7 +4641,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
return ret; return ret;
again: again:
if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { if (!test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) {
mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->volume_mutex);
mutex_lock(&fs_info->balance_mutex); mutex_lock(&fs_info->balance_mutex);
need_unlock = true; need_unlock = true;
...@@ -4689,7 +4687,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) ...@@ -4689,7 +4687,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
} }
locked: locked:
BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running)); BUG_ON(!test_bit(BTRFS_FS_EXCL_OP, &fs_info->flags));
if (arg) { if (arg) {
bargs = memdup_user(arg, sizeof(*bargs)); bargs = memdup_user(arg, sizeof(*bargs));
...@@ -4745,11 +4743,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) ...@@ -4745,11 +4743,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
do_balance: do_balance:
/* /*
* Ownership of bctl and mutually_exclusive_operation_running * Ownership of bctl and filesystem flag BTRFS_FS_EXCL_OP
* goes to to btrfs_balance. bctl is freed in __cancel_balance, * goes to to btrfs_balance. bctl is freed in __cancel_balance,
* or, if restriper was paused all the way until unmount, in * or, if restriper was paused all the way until unmount, in
* free_fs_info. mutually_exclusive_operation_running is * free_fs_info. The flag is cleared in __cancel_balance.
* cleared in __cancel_balance.
*/ */
need_unlock = false; need_unlock = false;
...@@ -4769,7 +4766,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) ...@@ -4769,7 +4766,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->balance_mutex);
mutex_unlock(&fs_info->volume_mutex); mutex_unlock(&fs_info->volume_mutex);
if (need_unlock) if (need_unlock)
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
out: out:
mnt_drop_write_file(file); mnt_drop_write_file(file);
return ret; return ret;
......
...@@ -3761,7 +3761,7 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info) ...@@ -3761,7 +3761,7 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info)
if (ret) if (ret)
btrfs_handle_fs_error(fs_info, ret, NULL); btrfs_handle_fs_error(fs_info, ret, NULL);
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
} }
/* Non-zero return value signifies invalidity */ /* Non-zero return value signifies invalidity */
...@@ -3941,7 +3941,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, ...@@ -3941,7 +3941,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
__cancel_balance(fs_info); __cancel_balance(fs_info);
else { else {
kfree(bctl); kfree(bctl);
atomic_set(&fs_info->mutually_exclusive_operation_running, 0); clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
} }
return ret; return ret;
} }
...@@ -4031,7 +4031,7 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) ...@@ -4031,7 +4031,7 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
btrfs_balance_sys(leaf, item, &disk_bargs); btrfs_balance_sys(leaf, item, &disk_bargs);
btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); WARN_ON(test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags));
mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->volume_mutex);
mutex_lock(&fs_info->balance_mutex); mutex_lock(&fs_info->balance_mutex);
......
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