aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2012-11-05 11:54:08 -0500
committerJosef Bacik <jbacik@fusionio.com>2012-12-12 17:15:38 -0500
commit5ac00addc7ac09110995fe967071d191b5981cc1 (patch)
treea5290cc4e69c434b24c091a212d1723bae56e46c /fs
parenta2bff64025d7a707ac49155bb6678a636e55096e (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.h2
-rw-r--r--fs/btrfs/ioctl.c53
-rw-r--r--fs/btrfs/volumes.c2
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);
1420out: 1420out:
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 }
2215out: 2224out:
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);
2245out: 2255out:
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);
2278out: 2289out:
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:
3391out_bargs: 3407out_bargs:
3392 kfree(bargs); 3408 kfree(bargs);
3393out: 3409out:
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);