diff options
author | Stefan Behrens <sbehrens@giantdisaster.de> | 2012-11-05 11:54:08 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2012-12-12 17:15:38 -0500 |
commit | 5ac00addc7ac09110995fe967071d191b5981cc1 (patch) | |
tree | a5290cc4e69c434b24c091a212d1723bae56e46c /fs | |
parent | a2bff64025d7a707ac49155bb6678a636e55096e (diff) |
Btrfs: disallow mutually exclusive admin operations from user mode
Btrfs admin operations that are manually started from user mode
and that cannot be executed at the same time return -EINPROGRESS.
A common way to enter and leave this locked section is introduced
since it used to be specific to the balance operation.
Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 53 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 2 |
3 files changed, 40 insertions, 17 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 147406d0f9a9..e9dc78014f09 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1527,6 +1527,8 @@ struct btrfs_fs_info { | |||
1527 | 1527 | ||
1528 | /* device replace state */ | 1528 | /* device replace state */ |
1529 | struct btrfs_dev_replace dev_replace; | 1529 | struct btrfs_dev_replace dev_replace; |
1530 | |||
1531 | atomic_t mutually_exclusive_operation_running; | ||
1530 | }; | 1532 | }; |
1531 | 1533 | ||
1532 | /* | 1534 | /* |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b40b827f93e7..26f46dad3b0e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1317,13 +1317,13 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1317 | if (!capable(CAP_SYS_ADMIN)) | 1317 | if (!capable(CAP_SYS_ADMIN)) |
1318 | return -EPERM; | 1318 | return -EPERM; |
1319 | 1319 | ||
1320 | mutex_lock(&root->fs_info->volume_mutex); | 1320 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, |
1321 | if (root->fs_info->balance_ctl) { | 1321 | 1)) { |
1322 | printk(KERN_INFO "btrfs: balance in progress\n"); | 1322 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); |
1323 | ret = -EINVAL; | 1323 | return -EINPROGRESS; |
1324 | goto out; | ||
1325 | } | 1324 | } |
1326 | 1325 | ||
1326 | mutex_lock(&root->fs_info->volume_mutex); | ||
1327 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1327 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
1328 | if (IS_ERR(vol_args)) { | 1328 | if (IS_ERR(vol_args)) { |
1329 | ret = PTR_ERR(vol_args); | 1329 | ret = PTR_ERR(vol_args); |
@@ -1419,6 +1419,7 @@ out_free: | |||
1419 | kfree(vol_args); | 1419 | kfree(vol_args); |
1420 | out: | 1420 | out: |
1421 | mutex_unlock(&root->fs_info->volume_mutex); | 1421 | mutex_unlock(&root->fs_info->volume_mutex); |
1422 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); | ||
1422 | return ret; | 1423 | return ret; |
1423 | } | 1424 | } |
1424 | 1425 | ||
@@ -2160,9 +2161,17 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
2160 | if (btrfs_root_readonly(root)) | 2161 | if (btrfs_root_readonly(root)) |
2161 | return -EROFS; | 2162 | return -EROFS; |
2162 | 2163 | ||
2164 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, | ||
2165 | 1)) { | ||
2166 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); | ||
2167 | return -EINPROGRESS; | ||
2168 | } | ||
2163 | ret = mnt_want_write_file(file); | 2169 | ret = mnt_want_write_file(file); |
2164 | if (ret) | 2170 | if (ret) { |
2171 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, | ||
2172 | 0); | ||
2165 | return ret; | 2173 | return ret; |
2174 | } | ||
2166 | 2175 | ||
2167 | switch (inode->i_mode & S_IFMT) { | 2176 | switch (inode->i_mode & S_IFMT) { |
2168 | case S_IFDIR: | 2177 | case S_IFDIR: |
@@ -2214,6 +2223,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
2214 | } | 2223 | } |
2215 | out: | 2224 | out: |
2216 | mnt_drop_write_file(file); | 2225 | mnt_drop_write_file(file); |
2226 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); | ||
2217 | return ret; | 2227 | return ret; |
2218 | } | 2228 | } |
2219 | 2229 | ||
@@ -2225,13 +2235,13 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) | |||
2225 | if (!capable(CAP_SYS_ADMIN)) | 2235 | if (!capable(CAP_SYS_ADMIN)) |
2226 | return -EPERM; | 2236 | return -EPERM; |
2227 | 2237 | ||
2228 | mutex_lock(&root->fs_info->volume_mutex); | 2238 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, |
2229 | if (root->fs_info->balance_ctl) { | 2239 | 1)) { |
2230 | printk(KERN_INFO "btrfs: balance in progress\n"); | 2240 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); |
2231 | ret = -EINVAL; | 2241 | return -EINPROGRESS; |
2232 | goto out; | ||
2233 | } | 2242 | } |
2234 | 2243 | ||
2244 | mutex_lock(&root->fs_info->volume_mutex); | ||
2235 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 2245 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
2236 | if (IS_ERR(vol_args)) { | 2246 | if (IS_ERR(vol_args)) { |
2237 | ret = PTR_ERR(vol_args); | 2247 | ret = PTR_ERR(vol_args); |
@@ -2244,6 +2254,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) | |||
2244 | kfree(vol_args); | 2254 | kfree(vol_args); |
2245 | out: | 2255 | out: |
2246 | mutex_unlock(&root->fs_info->volume_mutex); | 2256 | mutex_unlock(&root->fs_info->volume_mutex); |
2257 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); | ||
2247 | return ret; | 2258 | return ret; |
2248 | } | 2259 | } |
2249 | 2260 | ||
@@ -2258,13 +2269,13 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
2258 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 2269 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
2259 | return -EROFS; | 2270 | return -EROFS; |
2260 | 2271 | ||
2261 | mutex_lock(&root->fs_info->volume_mutex); | 2272 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, |
2262 | if (root->fs_info->balance_ctl) { | 2273 | 1)) { |
2263 | printk(KERN_INFO "btrfs: balance in progress\n"); | 2274 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); |
2264 | ret = -EINVAL; | 2275 | return -EINPROGRESS; |
2265 | goto out; | ||
2266 | } | 2276 | } |
2267 | 2277 | ||
2278 | mutex_lock(&root->fs_info->volume_mutex); | ||
2268 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 2279 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
2269 | if (IS_ERR(vol_args)) { | 2280 | if (IS_ERR(vol_args)) { |
2270 | ret = PTR_ERR(vol_args); | 2281 | ret = PTR_ERR(vol_args); |
@@ -2277,6 +2288,7 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
2277 | kfree(vol_args); | 2288 | kfree(vol_args); |
2278 | out: | 2289 | out: |
2279 | mutex_unlock(&root->fs_info->volume_mutex); | 2290 | mutex_unlock(&root->fs_info->volume_mutex); |
2291 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); | ||
2280 | return ret; | 2292 | return ret; |
2281 | } | 2293 | } |
2282 | 2294 | ||
@@ -3319,6 +3331,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) | |||
3319 | struct btrfs_ioctl_balance_args *bargs; | 3331 | struct btrfs_ioctl_balance_args *bargs; |
3320 | struct btrfs_balance_control *bctl; | 3332 | struct btrfs_balance_control *bctl; |
3321 | int ret; | 3333 | int ret; |
3334 | int need_to_clear_lock = 0; | ||
3322 | 3335 | ||
3323 | if (!capable(CAP_SYS_ADMIN)) | 3336 | if (!capable(CAP_SYS_ADMIN)) |
3324 | return -EPERM; | 3337 | return -EPERM; |
@@ -3354,10 +3367,13 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) | |||
3354 | bargs = NULL; | 3367 | bargs = NULL; |
3355 | } | 3368 | } |
3356 | 3369 | ||
3357 | if (fs_info->balance_ctl) { | 3370 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, |
3371 | 1)) { | ||
3372 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); | ||
3358 | ret = -EINPROGRESS; | 3373 | ret = -EINPROGRESS; |
3359 | goto out_bargs; | 3374 | goto out_bargs; |
3360 | } | 3375 | } |
3376 | need_to_clear_lock = 1; | ||
3361 | 3377 | ||
3362 | bctl = kzalloc(sizeof(*bctl), GFP_NOFS); | 3378 | bctl = kzalloc(sizeof(*bctl), GFP_NOFS); |
3363 | if (!bctl) { | 3379 | if (!bctl) { |
@@ -3391,6 +3407,9 @@ do_balance: | |||
3391 | out_bargs: | 3407 | out_bargs: |
3392 | kfree(bargs); | 3408 | kfree(bargs); |
3393 | out: | 3409 | out: |
3410 | if (need_to_clear_lock) | ||
3411 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, | ||
3412 | 0); | ||
3394 | mutex_unlock(&fs_info->balance_mutex); | 3413 | mutex_unlock(&fs_info->balance_mutex); |
3395 | mutex_unlock(&fs_info->volume_mutex); | 3414 | mutex_unlock(&fs_info->volume_mutex); |
3396 | mnt_drop_write_file(file); | 3415 | mnt_drop_write_file(file); |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d2c0bccca607..33ca36b37a6a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -2952,6 +2952,7 @@ static int balance_kthread(void *data) | |||
2952 | ret = btrfs_balance(fs_info->balance_ctl, NULL); | 2952 | ret = btrfs_balance(fs_info->balance_ctl, NULL); |
2953 | } | 2953 | } |
2954 | 2954 | ||
2955 | atomic_set(&fs_info->mutually_exclusive_operation_running, 0); | ||
2955 | mutex_unlock(&fs_info->balance_mutex); | 2956 | mutex_unlock(&fs_info->balance_mutex); |
2956 | mutex_unlock(&fs_info->volume_mutex); | 2957 | mutex_unlock(&fs_info->volume_mutex); |
2957 | 2958 | ||
@@ -2974,6 +2975,7 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) | |||
2974 | return 0; | 2975 | return 0; |
2975 | } | 2976 | } |
2976 | 2977 | ||
2978 | WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); | ||
2977 | tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); | 2979 | tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); |
2978 | if (IS_ERR(tsk)) | 2980 | if (IS_ERR(tsk)) |
2979 | return PTR_ERR(tsk); | 2981 | return PTR_ERR(tsk); |