Loading fs/btrfs/ioctl.c +79 −28 Original line number Diff line number Diff line Loading @@ -1340,7 +1340,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); mnt_drop_write_file(file); return -EINPROGRESS; return -EINVAL; } mutex_lock(&root->fs_info->volume_mutex); Loading Loading @@ -1446,8 +1446,8 @@ out_free: kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); mnt_drop_write_file(file); atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); mnt_drop_write_file(file); return ret; } Loading Loading @@ -2186,19 +2186,20 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) struct btrfs_ioctl_defrag_range_args *range; int ret; if (btrfs_root_readonly(root)) return -EROFS; ret = mnt_want_write_file(file); if (ret) return ret; if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); return -EINPROGRESS; mnt_drop_write_file(file); return -EINVAL; } ret = mnt_want_write_file(file); if (ret) { atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); return ret; if (btrfs_root_readonly(root)) { ret = -EROFS; goto out; } switch (inode->i_mode & S_IFMT) { Loading Loading @@ -2250,8 +2251,8 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) ret = -EINVAL; } out: mnt_drop_write_file(file); atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); mnt_drop_write_file(file); return ret; } Loading @@ -2266,7 +2267,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); return -EINPROGRESS; return -EINVAL; } mutex_lock(&root->fs_info->volume_mutex); Loading Loading @@ -2303,7 +2304,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); mnt_drop_write_file(file); return -EINPROGRESS; return -EINVAL; } mutex_lock(&root->fs_info->volume_mutex); Loading @@ -2319,8 +2320,8 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); mnt_drop_write_file(file); atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); mnt_drop_write_file(file); return ret; } Loading Loading @@ -3440,8 +3441,8 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_ioctl_balance_args *bargs; struct btrfs_balance_control *bctl; bool need_unlock; /* for mut. excl. ops lock */ int ret; int need_to_clear_lock = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; Loading @@ -3450,14 +3451,61 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) if (ret) return ret; again: if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); need_unlock = true; goto locked; } /* * mut. excl. ops lock is locked. Three possibilites: * (1) some other op is running * (2) balance is running * (3) balance is paused -- special case (think resume) */ mutex_lock(&fs_info->balance_mutex); if (fs_info->balance_ctl) { /* this is either (2) or (3) */ if (!atomic_read(&fs_info->balance_running)) { mutex_unlock(&fs_info->balance_mutex); if (!mutex_trylock(&fs_info->volume_mutex)) goto again; mutex_lock(&fs_info->balance_mutex); if (fs_info->balance_ctl && !atomic_read(&fs_info->balance_running)) { /* this is (3) */ need_unlock = false; goto locked; } mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); goto again; } else { /* this is (2) */ mutex_unlock(&fs_info->balance_mutex); ret = -EINPROGRESS; goto out; } } else { /* this is (1) */ mutex_unlock(&fs_info->balance_mutex); pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); ret = -EINVAL; goto out; } locked: BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running)); if (arg) { bargs = memdup_user(arg, sizeof(*bargs)); if (IS_ERR(bargs)) { ret = PTR_ERR(bargs); goto out; goto out_unlock; } if (bargs->flags & BTRFS_BALANCE_RESUME) { Loading @@ -3477,13 +3525,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) bargs = NULL; } if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); if (fs_info->balance_ctl) { ret = -EINPROGRESS; goto out_bargs; } need_to_clear_lock = 1; bctl = kzalloc(sizeof(*bctl), GFP_NOFS); if (!bctl) { Loading @@ -3504,11 +3549,17 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) } do_balance: ret = btrfs_balance(bctl, bargs); /* * bctl is freed in __cancel_balance or in free_fs_info if * restriper was paused all the way until unmount * Ownership of bctl and mutually_exclusive_operation_running * goes to to btrfs_balance. bctl is freed in __cancel_balance, * or, if restriper was paused all the way until unmount, in * free_fs_info. mutually_exclusive_operation_running is * cleared in __cancel_balance. */ need_unlock = false; ret = btrfs_balance(bctl, bargs); if (arg) { if (copy_to_user(arg, bargs, sizeof(*bargs))) ret = -EFAULT; Loading @@ -3516,12 +3567,12 @@ do_balance: out_bargs: kfree(bargs); out: if (need_to_clear_lock) atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); out_unlock: mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); if (need_unlock) atomic_set(&fs_info->mutually_exclusive_operation_running, 0); out: mnt_drop_write_file(file); return ret; } Loading fs/btrfs/volumes.c +7 −3 Original line number Diff line number Diff line Loading @@ -2959,6 +2959,8 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info) unset_balance_control(fs_info); ret = del_balance_item(fs_info->tree_root); BUG_ON(ret); atomic_set(&fs_info->mutually_exclusive_operation_running, 0); } void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, Loading Loading @@ -3138,8 +3140,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl, out: if (bctl->flags & BTRFS_BALANCE_RESUME) __cancel_balance(fs_info); else else { kfree(bctl); atomic_set(&fs_info->mutually_exclusive_operation_running, 0); } return ret; } Loading @@ -3156,7 +3160,6 @@ static int balance_kthread(void *data) ret = btrfs_balance(fs_info->balance_ctl, NULL); } atomic_set(&fs_info->mutually_exclusive_operation_running, 0); mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); Loading @@ -3179,7 +3182,6 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) return 0; } WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); if (IS_ERR(tsk)) return PTR_ERR(tsk); Loading Loading @@ -3233,6 +3235,8 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) btrfs_balance_sys(leaf, item, &disk_bargs); btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); Loading Loading
fs/btrfs/ioctl.c +79 −28 Original line number Diff line number Diff line Loading @@ -1340,7 +1340,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); mnt_drop_write_file(file); return -EINPROGRESS; return -EINVAL; } mutex_lock(&root->fs_info->volume_mutex); Loading Loading @@ -1446,8 +1446,8 @@ out_free: kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); mnt_drop_write_file(file); atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); mnt_drop_write_file(file); return ret; } Loading Loading @@ -2186,19 +2186,20 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) struct btrfs_ioctl_defrag_range_args *range; int ret; if (btrfs_root_readonly(root)) return -EROFS; ret = mnt_want_write_file(file); if (ret) return ret; if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); return -EINPROGRESS; mnt_drop_write_file(file); return -EINVAL; } ret = mnt_want_write_file(file); if (ret) { atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); return ret; if (btrfs_root_readonly(root)) { ret = -EROFS; goto out; } switch (inode->i_mode & S_IFMT) { Loading Loading @@ -2250,8 +2251,8 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) ret = -EINVAL; } out: mnt_drop_write_file(file); atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); mnt_drop_write_file(file); return ret; } Loading @@ -2266,7 +2267,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); return -EINPROGRESS; return -EINVAL; } mutex_lock(&root->fs_info->volume_mutex); Loading Loading @@ -2303,7 +2304,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); mnt_drop_write_file(file); return -EINPROGRESS; return -EINVAL; } mutex_lock(&root->fs_info->volume_mutex); Loading @@ -2319,8 +2320,8 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); mnt_drop_write_file(file); atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); mnt_drop_write_file(file); return ret; } Loading Loading @@ -3440,8 +3441,8 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_ioctl_balance_args *bargs; struct btrfs_balance_control *bctl; bool need_unlock; /* for mut. excl. ops lock */ int ret; int need_to_clear_lock = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; Loading @@ -3450,14 +3451,61 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) if (ret) return ret; again: if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); need_unlock = true; goto locked; } /* * mut. excl. ops lock is locked. Three possibilites: * (1) some other op is running * (2) balance is running * (3) balance is paused -- special case (think resume) */ mutex_lock(&fs_info->balance_mutex); if (fs_info->balance_ctl) { /* this is either (2) or (3) */ if (!atomic_read(&fs_info->balance_running)) { mutex_unlock(&fs_info->balance_mutex); if (!mutex_trylock(&fs_info->volume_mutex)) goto again; mutex_lock(&fs_info->balance_mutex); if (fs_info->balance_ctl && !atomic_read(&fs_info->balance_running)) { /* this is (3) */ need_unlock = false; goto locked; } mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); goto again; } else { /* this is (2) */ mutex_unlock(&fs_info->balance_mutex); ret = -EINPROGRESS; goto out; } } else { /* this is (1) */ mutex_unlock(&fs_info->balance_mutex); pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); ret = -EINVAL; goto out; } locked: BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running)); if (arg) { bargs = memdup_user(arg, sizeof(*bargs)); if (IS_ERR(bargs)) { ret = PTR_ERR(bargs); goto out; goto out_unlock; } if (bargs->flags & BTRFS_BALANCE_RESUME) { Loading @@ -3477,13 +3525,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) bargs = NULL; } if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); if (fs_info->balance_ctl) { ret = -EINPROGRESS; goto out_bargs; } need_to_clear_lock = 1; bctl = kzalloc(sizeof(*bctl), GFP_NOFS); if (!bctl) { Loading @@ -3504,11 +3549,17 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) } do_balance: ret = btrfs_balance(bctl, bargs); /* * bctl is freed in __cancel_balance or in free_fs_info if * restriper was paused all the way until unmount * Ownership of bctl and mutually_exclusive_operation_running * goes to to btrfs_balance. bctl is freed in __cancel_balance, * or, if restriper was paused all the way until unmount, in * free_fs_info. mutually_exclusive_operation_running is * cleared in __cancel_balance. */ need_unlock = false; ret = btrfs_balance(bctl, bargs); if (arg) { if (copy_to_user(arg, bargs, sizeof(*bargs))) ret = -EFAULT; Loading @@ -3516,12 +3567,12 @@ do_balance: out_bargs: kfree(bargs); out: if (need_to_clear_lock) atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); out_unlock: mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); if (need_unlock) atomic_set(&fs_info->mutually_exclusive_operation_running, 0); out: mnt_drop_write_file(file); return ret; } Loading
fs/btrfs/volumes.c +7 −3 Original line number Diff line number Diff line Loading @@ -2959,6 +2959,8 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info) unset_balance_control(fs_info); ret = del_balance_item(fs_info->tree_root); BUG_ON(ret); atomic_set(&fs_info->mutually_exclusive_operation_running, 0); } void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, Loading Loading @@ -3138,8 +3140,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl, out: if (bctl->flags & BTRFS_BALANCE_RESUME) __cancel_balance(fs_info); else else { kfree(bctl); atomic_set(&fs_info->mutually_exclusive_operation_running, 0); } return ret; } Loading @@ -3156,7 +3160,6 @@ static int balance_kthread(void *data) ret = btrfs_balance(fs_info->balance_ctl, NULL); } atomic_set(&fs_info->mutually_exclusive_operation_running, 0); mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); Loading @@ -3179,7 +3182,6 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) return 0; } WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); if (IS_ERR(tsk)) return PTR_ERR(tsk); Loading Loading @@ -3233,6 +3235,8 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) btrfs_balance_sys(leaf, item, &disk_bargs); btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); Loading