diff options
author | Chris Mason <chris.mason@fusionio.com> | 2013-01-21 20:39:06 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-01-21 20:39:06 -0500 |
commit | 83bfccb5c085658b0ad1450a6fc13b0bb5440970 (patch) | |
tree | f1f6fe9dccd23c76f750c25f91e18d7fc0ccccd7 | |
parent | daf2c08911522d1739c55baf35f03531a29c87ef (diff) | |
parent | 25122d15e21cf252e91e4cad7cea760f97df29f1 (diff) |
Merge branch 'mutex-ops@next-for-chris' of git://github.com/idryomov/btrfs-unstable into linus
-rw-r--r-- | fs/btrfs/ioctl.c | 107 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 10 |
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); |
1447 | out: | 1447 | out: |
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 | } |
2252 | out: | 2253 | out: |
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); |
2320 | out: | 2321 | out: |
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); | 3454 | again: |
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 | |||
3501 | locked: | ||
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 | ||
3506 | do_balance: | 3551 | do_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 | ||
3517 | out_bargs: | 3568 | out_bargs: |
3518 | kfree(bargs); | 3569 | kfree(bargs); |
3519 | out: | 3570 | out_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); | ||
3575 | out: | ||
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 | ||
2964 | void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, | 2966 | void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, |
@@ -3138,8 +3140,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
3138 | out: | 3140 | out: |
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 | ||