aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2013-01-21 20:39:06 -0500
committerChris Mason <chris.mason@fusionio.com>2013-01-21 20:39:06 -0500
commit83bfccb5c085658b0ad1450a6fc13b0bb5440970 (patch)
treef1f6fe9dccd23c76f750c25f91e18d7fc0ccccd7
parentdaf2c08911522d1739c55baf35f03531a29c87ef (diff)
parent25122d15e21cf252e91e4cad7cea760f97df29f1 (diff)
Merge branch 'mutex-ops@next-for-chris' of git://github.com/idryomov/btrfs-unstable into linus
-rw-r--r--fs/btrfs/ioctl.c107
-rw-r--r--fs/btrfs/volumes.c10
2 files changed, 86 insertions, 31 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 982c0b9ceea5..afbf3ac2079d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1340,7 +1340,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
1340 1)) { 1340 1)) {
1341 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); 1341 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
1342 mnt_drop_write_file(file); 1342 mnt_drop_write_file(file);
1343 return -EINPROGRESS; 1343 return -EINVAL;
1344 } 1344 }
1345 1345
1346 mutex_lock(&root->fs_info->volume_mutex); 1346 mutex_lock(&root->fs_info->volume_mutex);
@@ -1446,8 +1446,8 @@ out_free:
1446 kfree(vol_args); 1446 kfree(vol_args);
1447out: 1447out:
1448 mutex_unlock(&root->fs_info->volume_mutex); 1448 mutex_unlock(&root->fs_info->volume_mutex);
1449 mnt_drop_write_file(file);
1450 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); 1449 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
1450 mnt_drop_write_file(file);
1451 return ret; 1451 return ret;
1452} 1452}
1453 1453
@@ -2186,19 +2186,20 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
2186 struct btrfs_ioctl_defrag_range_args *range; 2186 struct btrfs_ioctl_defrag_range_args *range;
2187 int ret; 2187 int ret;
2188 2188
2189 if (btrfs_root_readonly(root)) 2189 ret = mnt_want_write_file(file);
2190 return -EROFS; 2190 if (ret)
2191 return ret;
2191 2192
2192 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 2193 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
2193 1)) { 2194 1)) {
2194 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); 2195 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
2195 return -EINPROGRESS; 2196 mnt_drop_write_file(file);
2197 return -EINVAL;
2196 } 2198 }
2197 ret = mnt_want_write_file(file); 2199
2198 if (ret) { 2200 if (btrfs_root_readonly(root)) {
2199 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 2201 ret = -EROFS;
2200 0); 2202 goto out;
2201 return ret;
2202 } 2203 }
2203 2204
2204 switch (inode->i_mode & S_IFMT) { 2205 switch (inode->i_mode & S_IFMT) {
@@ -2250,8 +2251,8 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
2250 ret = -EINVAL; 2251 ret = -EINVAL;
2251 } 2252 }
2252out: 2253out:
2253 mnt_drop_write_file(file);
2254 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); 2254 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
2255 mnt_drop_write_file(file);
2255 return ret; 2256 return ret;
2256} 2257}
2257 2258
@@ -2266,7 +2267,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
2266 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 2267 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
2267 1)) { 2268 1)) {
2268 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); 2269 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
2269 return -EINPROGRESS; 2270 return -EINVAL;
2270 } 2271 }
2271 2272
2272 mutex_lock(&root->fs_info->volume_mutex); 2273 mutex_lock(&root->fs_info->volume_mutex);
@@ -2303,7 +2304,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
2303 1)) { 2304 1)) {
2304 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); 2305 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
2305 mnt_drop_write_file(file); 2306 mnt_drop_write_file(file);
2306 return -EINPROGRESS; 2307 return -EINVAL;
2307 } 2308 }
2308 2309
2309 mutex_lock(&root->fs_info->volume_mutex); 2310 mutex_lock(&root->fs_info->volume_mutex);
@@ -2319,8 +2320,8 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
2319 kfree(vol_args); 2320 kfree(vol_args);
2320out: 2321out:
2321 mutex_unlock(&root->fs_info->volume_mutex); 2322 mutex_unlock(&root->fs_info->volume_mutex);
2322 mnt_drop_write_file(file);
2323 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); 2323 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
2324 mnt_drop_write_file(file);
2324 return ret; 2325 return ret;
2325} 2326}
2326 2327
@@ -3440,8 +3441,8 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3440 struct btrfs_fs_info *fs_info = root->fs_info; 3441 struct btrfs_fs_info *fs_info = root->fs_info;
3441 struct btrfs_ioctl_balance_args *bargs; 3442 struct btrfs_ioctl_balance_args *bargs;
3442 struct btrfs_balance_control *bctl; 3443 struct btrfs_balance_control *bctl;
3444 bool need_unlock; /* for mut. excl. ops lock */
3443 int ret; 3445 int ret;
3444 int need_to_clear_lock = 0;
3445 3446
3446 if (!capable(CAP_SYS_ADMIN)) 3447 if (!capable(CAP_SYS_ADMIN))
3447 return -EPERM; 3448 return -EPERM;
@@ -3450,14 +3451,61 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3450 if (ret) 3451 if (ret)
3451 return ret; 3452 return ret;
3452 3453
3453 mutex_lock(&fs_info->volume_mutex); 3454again:
3455 if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) {
3456 mutex_lock(&fs_info->volume_mutex);
3457 mutex_lock(&fs_info->balance_mutex);
3458 need_unlock = true;
3459 goto locked;
3460 }
3461
3462 /*
3463 * mut. excl. ops lock is locked. Three possibilites:
3464 * (1) some other op is running
3465 * (2) balance is running
3466 * (3) balance is paused -- special case (think resume)
3467 */
3454 mutex_lock(&fs_info->balance_mutex); 3468 mutex_lock(&fs_info->balance_mutex);
3469 if (fs_info->balance_ctl) {
3470 /* this is either (2) or (3) */
3471 if (!atomic_read(&fs_info->balance_running)) {
3472 mutex_unlock(&fs_info->balance_mutex);
3473 if (!mutex_trylock(&fs_info->volume_mutex))
3474 goto again;
3475 mutex_lock(&fs_info->balance_mutex);
3476
3477 if (fs_info->balance_ctl &&
3478 !atomic_read(&fs_info->balance_running)) {
3479 /* this is (3) */
3480 need_unlock = false;
3481 goto locked;
3482 }
3483
3484 mutex_unlock(&fs_info->balance_mutex);
3485 mutex_unlock(&fs_info->volume_mutex);
3486 goto again;
3487 } else {
3488 /* this is (2) */
3489 mutex_unlock(&fs_info->balance_mutex);
3490 ret = -EINPROGRESS;
3491 goto out;
3492 }
3493 } else {
3494 /* this is (1) */
3495 mutex_unlock(&fs_info->balance_mutex);
3496 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
3497 ret = -EINVAL;
3498 goto out;
3499 }
3500
3501locked:
3502 BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running));
3455 3503
3456 if (arg) { 3504 if (arg) {
3457 bargs = memdup_user(arg, sizeof(*bargs)); 3505 bargs = memdup_user(arg, sizeof(*bargs));
3458 if (IS_ERR(bargs)) { 3506 if (IS_ERR(bargs)) {
3459 ret = PTR_ERR(bargs); 3507 ret = PTR_ERR(bargs);
3460 goto out; 3508 goto out_unlock;
3461 } 3509 }
3462 3510
3463 if (bargs->flags & BTRFS_BALANCE_RESUME) { 3511 if (bargs->flags & BTRFS_BALANCE_RESUME) {
@@ -3477,13 +3525,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3477 bargs = NULL; 3525 bargs = NULL;
3478 } 3526 }
3479 3527
3480 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 3528 if (fs_info->balance_ctl) {
3481 1)) {
3482 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
3483 ret = -EINPROGRESS; 3529 ret = -EINPROGRESS;
3484 goto out_bargs; 3530 goto out_bargs;
3485 } 3531 }
3486 need_to_clear_lock = 1;
3487 3532
3488 bctl = kzalloc(sizeof(*bctl), GFP_NOFS); 3533 bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
3489 if (!bctl) { 3534 if (!bctl) {
@@ -3504,11 +3549,17 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3504 } 3549 }
3505 3550
3506do_balance: 3551do_balance:
3507 ret = btrfs_balance(bctl, bargs);
3508 /* 3552 /*
3509 * bctl is freed in __cancel_balance or in free_fs_info if 3553 * Ownership of bctl and mutually_exclusive_operation_running
3510 * restriper was paused all the way until unmount 3554 * goes to to btrfs_balance. bctl is freed in __cancel_balance,
3555 * or, if restriper was paused all the way until unmount, in
3556 * free_fs_info. mutually_exclusive_operation_running is
3557 * cleared in __cancel_balance.
3511 */ 3558 */
3559 need_unlock = false;
3560
3561 ret = btrfs_balance(bctl, bargs);
3562
3512 if (arg) { 3563 if (arg) {
3513 if (copy_to_user(arg, bargs, sizeof(*bargs))) 3564 if (copy_to_user(arg, bargs, sizeof(*bargs)))
3514 ret = -EFAULT; 3565 ret = -EFAULT;
@@ -3516,12 +3567,12 @@ do_balance:
3516 3567
3517out_bargs: 3568out_bargs:
3518 kfree(bargs); 3569 kfree(bargs);
3519out: 3570out_unlock:
3520 if (need_to_clear_lock)
3521 atomic_set(&root->fs_info->mutually_exclusive_operation_running,
3522 0);
3523 mutex_unlock(&fs_info->balance_mutex); 3571 mutex_unlock(&fs_info->balance_mutex);
3524 mutex_unlock(&fs_info->volume_mutex); 3572 mutex_unlock(&fs_info->volume_mutex);
3573 if (need_unlock)
3574 atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
3575out:
3525 mnt_drop_write_file(file); 3576 mnt_drop_write_file(file);
3526 return ret; 3577 return ret;
3527} 3578}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 86279c37de64..9c84dbe64f18 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2959,6 +2959,8 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info)
2959 unset_balance_control(fs_info); 2959 unset_balance_control(fs_info);
2960 ret = del_balance_item(fs_info->tree_root); 2960 ret = del_balance_item(fs_info->tree_root);
2961 BUG_ON(ret); 2961 BUG_ON(ret);
2962
2963 atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
2962} 2964}
2963 2965
2964void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, 2966void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
@@ -3138,8 +3140,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
3138out: 3140out:
3139 if (bctl->flags & BTRFS_BALANCE_RESUME) 3141 if (bctl->flags & BTRFS_BALANCE_RESUME)
3140 __cancel_balance(fs_info); 3142 __cancel_balance(fs_info);
3141 else 3143 else {
3142 kfree(bctl); 3144 kfree(bctl);
3145 atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
3146 }
3143 return ret; 3147 return ret;
3144} 3148}
3145 3149
@@ -3156,7 +3160,6 @@ static int balance_kthread(void *data)
3156 ret = btrfs_balance(fs_info->balance_ctl, NULL); 3160 ret = btrfs_balance(fs_info->balance_ctl, NULL);
3157 } 3161 }
3158 3162
3159 atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
3160 mutex_unlock(&fs_info->balance_mutex); 3163 mutex_unlock(&fs_info->balance_mutex);
3161 mutex_unlock(&fs_info->volume_mutex); 3164 mutex_unlock(&fs_info->volume_mutex);
3162 3165
@@ -3179,7 +3182,6 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
3179 return 0; 3182 return 0;
3180 } 3183 }
3181 3184
3182 WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1));
3183 tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); 3185 tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance");
3184 if (IS_ERR(tsk)) 3186 if (IS_ERR(tsk))
3185 return PTR_ERR(tsk); 3187 return PTR_ERR(tsk);
@@ -3233,6 +3235,8 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
3233 btrfs_balance_sys(leaf, item, &disk_bargs); 3235 btrfs_balance_sys(leaf, item, &disk_bargs);
3234 btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); 3236 btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
3235 3237
3238 WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1));
3239
3236 mutex_lock(&fs_info->volume_mutex); 3240 mutex_lock(&fs_info->volume_mutex);
3237 mutex_lock(&fs_info->balance_mutex); 3241 mutex_lock(&fs_info->balance_mutex);
3238 3242