aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-02-05 08:48:03 -0500
committerTakashi Iwai <tiwai@suse.de>2013-02-05 08:48:03 -0500
commit2faea5274f079630991800bd579f85a621f96ef5 (patch)
tree4afb9032f0ae3a3e8b539e0abe40cda320989ac3 /fs/btrfs/ioctl.c
parent16c5ab1d3a6d1b11ed2966fa33a3a4fecd13a2bc (diff)
parentedac894389f9c9de2a1368c78809c824b343f3a5 (diff)
Merge branch 'for-linus' into for-next
Merge pending fixes that haven't pulled into 3.8.
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c129
1 files changed, 94 insertions, 35 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4b4516770f05..5b22d45d3c6a 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1339,7 +1339,8 @@ static noinline int btrfs_ioctl_resize(struct file *file,
1339 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1339 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
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 return -EINPROGRESS; 1342 mnt_drop_write_file(file);
1343 return -EINVAL;
1343 } 1344 }
1344 1345
1345 mutex_lock(&root->fs_info->volume_mutex); 1346 mutex_lock(&root->fs_info->volume_mutex);
@@ -1362,6 +1363,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
1362 printk(KERN_INFO "btrfs: resizing devid %llu\n", 1363 printk(KERN_INFO "btrfs: resizing devid %llu\n",
1363 (unsigned long long)devid); 1364 (unsigned long long)devid);
1364 } 1365 }
1366
1365 device = btrfs_find_device(root->fs_info, devid, NULL, NULL); 1367 device = btrfs_find_device(root->fs_info, devid, NULL, NULL);
1366 if (!device) { 1368 if (!device) {
1367 printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", 1369 printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
@@ -1369,9 +1371,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,
1369 ret = -EINVAL; 1371 ret = -EINVAL;
1370 goto out_free; 1372 goto out_free;
1371 } 1373 }
1372 if (device->fs_devices && device->fs_devices->seeding) { 1374
1375 if (!device->writeable) {
1373 printk(KERN_INFO "btrfs: resizer unable to apply on " 1376 printk(KERN_INFO "btrfs: resizer unable to apply on "
1374 "seeding device %llu\n", 1377 "readonly device %llu\n",
1375 (unsigned long long)devid); 1378 (unsigned long long)devid);
1376 ret = -EINVAL; 1379 ret = -EINVAL;
1377 goto out_free; 1380 goto out_free;
@@ -1443,8 +1446,8 @@ out_free:
1443 kfree(vol_args); 1446 kfree(vol_args);
1444out: 1447out:
1445 mutex_unlock(&root->fs_info->volume_mutex); 1448 mutex_unlock(&root->fs_info->volume_mutex);
1446 mnt_drop_write_file(file);
1447 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);
1448 return ret; 1451 return ret;
1449} 1452}
1450 1453
@@ -2095,13 +2098,13 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
2095 err = inode_permission(inode, MAY_WRITE | MAY_EXEC); 2098 err = inode_permission(inode, MAY_WRITE | MAY_EXEC);
2096 if (err) 2099 if (err)
2097 goto out_dput; 2100 goto out_dput;
2098
2099 /* check if subvolume may be deleted by a non-root user */
2100 err = btrfs_may_delete(dir, dentry, 1);
2101 if (err)
2102 goto out_dput;
2103 } 2101 }
2104 2102
2103 /* check if subvolume may be deleted by a user */
2104 err = btrfs_may_delete(dir, dentry, 1);
2105 if (err)
2106 goto out_dput;
2107
2105 if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { 2108 if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
2106 err = -EINVAL; 2109 err = -EINVAL;
2107 goto out_dput; 2110 goto out_dput;
@@ -2183,19 +2186,20 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
2183 struct btrfs_ioctl_defrag_range_args *range; 2186 struct btrfs_ioctl_defrag_range_args *range;
2184 int ret; 2187 int ret;
2185 2188
2186 if (btrfs_root_readonly(root)) 2189 ret = mnt_want_write_file(file);
2187 return -EROFS; 2190 if (ret)
2191 return ret;
2188 2192
2189 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 2193 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
2190 1)) { 2194 1)) {
2191 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");
2192 return -EINPROGRESS; 2196 mnt_drop_write_file(file);
2197 return -EINVAL;
2193 } 2198 }
2194 ret = mnt_want_write_file(file); 2199
2195 if (ret) { 2200 if (btrfs_root_readonly(root)) {
2196 atomic_set(&root->fs_info->mutually_exclusive_operation_running, 2201 ret = -EROFS;
2197 0); 2202 goto out;
2198 return ret;
2199 } 2203 }
2200 2204
2201 switch (inode->i_mode & S_IFMT) { 2205 switch (inode->i_mode & S_IFMT) {
@@ -2247,8 +2251,8 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
2247 ret = -EINVAL; 2251 ret = -EINVAL;
2248 } 2252 }
2249out: 2253out:
2250 mnt_drop_write_file(file);
2251 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);
2252 return ret; 2256 return ret;
2253} 2257}
2254 2258
@@ -2263,7 +2267,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
2263 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 2267 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
2264 1)) { 2268 1)) {
2265 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");
2266 return -EINPROGRESS; 2270 return -EINVAL;
2267 } 2271 }
2268 2272
2269 mutex_lock(&root->fs_info->volume_mutex); 2273 mutex_lock(&root->fs_info->volume_mutex);
@@ -2300,7 +2304,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
2300 1)) { 2304 1)) {
2301 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");
2302 mnt_drop_write_file(file); 2306 mnt_drop_write_file(file);
2303 return -EINPROGRESS; 2307 return -EINVAL;
2304 } 2308 }
2305 2309
2306 mutex_lock(&root->fs_info->volume_mutex); 2310 mutex_lock(&root->fs_info->volume_mutex);
@@ -2316,8 +2320,8 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
2316 kfree(vol_args); 2320 kfree(vol_args);
2317out: 2321out:
2318 mutex_unlock(&root->fs_info->volume_mutex); 2322 mutex_unlock(&root->fs_info->volume_mutex);
2319 mnt_drop_write_file(file);
2320 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);
2321 return ret; 2325 return ret;
2322} 2326}
2323 2327
@@ -3437,8 +3441,8 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3437 struct btrfs_fs_info *fs_info = root->fs_info; 3441 struct btrfs_fs_info *fs_info = root->fs_info;
3438 struct btrfs_ioctl_balance_args *bargs; 3442 struct btrfs_ioctl_balance_args *bargs;
3439 struct btrfs_balance_control *bctl; 3443 struct btrfs_balance_control *bctl;
3444 bool need_unlock; /* for mut. excl. ops lock */
3440 int ret; 3445 int ret;
3441 int need_to_clear_lock = 0;
3442 3446
3443 if (!capable(CAP_SYS_ADMIN)) 3447 if (!capable(CAP_SYS_ADMIN))
3444 return -EPERM; 3448 return -EPERM;
@@ -3447,14 +3451,61 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3447 if (ret) 3451 if (ret)
3448 return ret; 3452 return ret;
3449 3453
3450 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 */
3451 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));
3452 3503
3453 if (arg) { 3504 if (arg) {
3454 bargs = memdup_user(arg, sizeof(*bargs)); 3505 bargs = memdup_user(arg, sizeof(*bargs));
3455 if (IS_ERR(bargs)) { 3506 if (IS_ERR(bargs)) {
3456 ret = PTR_ERR(bargs); 3507 ret = PTR_ERR(bargs);
3457 goto out; 3508 goto out_unlock;
3458 } 3509 }
3459 3510
3460 if (bargs->flags & BTRFS_BALANCE_RESUME) { 3511 if (bargs->flags & BTRFS_BALANCE_RESUME) {
@@ -3474,13 +3525,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3474 bargs = NULL; 3525 bargs = NULL;
3475 } 3526 }
3476 3527
3477 if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 3528 if (fs_info->balance_ctl) {
3478 1)) {
3479 pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
3480 ret = -EINPROGRESS; 3529 ret = -EINPROGRESS;
3481 goto out_bargs; 3530 goto out_bargs;
3482 } 3531 }
3483 need_to_clear_lock = 1;
3484 3532
3485 bctl = kzalloc(sizeof(*bctl), GFP_NOFS); 3533 bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
3486 if (!bctl) { 3534 if (!bctl) {
@@ -3501,11 +3549,17 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
3501 } 3549 }
3502 3550
3503do_balance: 3551do_balance:
3504 ret = btrfs_balance(bctl, bargs);
3505 /* 3552 /*
3506 * bctl is freed in __cancel_balance or in free_fs_info if 3553 * Ownership of bctl and mutually_exclusive_operation_running
3507 * 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.
3508 */ 3558 */
3559 need_unlock = false;
3560
3561 ret = btrfs_balance(bctl, bargs);
3562
3509 if (arg) { 3563 if (arg) {
3510 if (copy_to_user(arg, bargs, sizeof(*bargs))) 3564 if (copy_to_user(arg, bargs, sizeof(*bargs)))
3511 ret = -EFAULT; 3565 ret = -EFAULT;
@@ -3513,12 +3567,12 @@ do_balance:
3513 3567
3514out_bargs: 3568out_bargs:
3515 kfree(bargs); 3569 kfree(bargs);
3516out: 3570out_unlock:
3517 if (need_to_clear_lock)
3518 atomic_set(&root->fs_info->mutually_exclusive_operation_running,
3519 0);
3520 mutex_unlock(&fs_info->balance_mutex); 3571 mutex_unlock(&fs_info->balance_mutex);
3521 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:
3522 mnt_drop_write_file(file); 3576 mnt_drop_write_file(file);
3523 return ret; 3577 return ret;
3524} 3578}
@@ -3698,6 +3752,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
3698 goto drop_write; 3752 goto drop_write;
3699 } 3753 }
3700 3754
3755 if (!sa->qgroupid) {
3756 ret = -EINVAL;
3757 goto out;
3758 }
3759
3701 trans = btrfs_join_transaction(root); 3760 trans = btrfs_join_transaction(root);
3702 if (IS_ERR(trans)) { 3761 if (IS_ERR(trans)) {
3703 ret = PTR_ERR(trans); 3762 ret = PTR_ERR(trans);