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/btrfs/ioctl.c | |
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/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 53 |
1 files changed, 36 insertions, 17 deletions
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); |