diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2012-11-26 03:44:50 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-12-16 20:46:09 -0500 |
commit | da24927b1e1925da5c1885cb483231dabe027e15 (patch) | |
tree | 6d28cb9342d4251a8eb0116f79ee3816843c9a61 /fs | |
parent | 198605a8e2077f174c9834c97b836f535e4e56dd (diff) |
Btrfs: get write access when removing a device
Steps to reproduce:
# mkfs.btrfs -d single -m single <disk0> <disk1>
# mount -o ro <disk0> <mnt0>
# mount -o ro <disk0> <mnt1>
# mount -o remount,rw <mnt0>
# umount <mnt0>
# btrfs device delete <disk1> <mnt1>
We can remove a device from a R/O filesystem. The reason is that we just check
the R/O flag of the super block object. It is not enough, because the kernel
may set the R/O flag only for the mount point. We need invoke
mnt_want_write_file()
to do a full check.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ioctl.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 2be49b4c82d6..ee36009f8aa1 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -2270,20 +2270,23 @@ out: | |||
2270 | return ret; | 2270 | return ret; |
2271 | } | 2271 | } |
2272 | 2272 | ||
2273 | static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | 2273 | static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) |
2274 | { | 2274 | { |
2275 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
2275 | struct btrfs_ioctl_vol_args *vol_args; | 2276 | struct btrfs_ioctl_vol_args *vol_args; |
2276 | int ret; | 2277 | int ret; |
2277 | 2278 | ||
2278 | if (!capable(CAP_SYS_ADMIN)) | 2279 | if (!capable(CAP_SYS_ADMIN)) |
2279 | return -EPERM; | 2280 | return -EPERM; |
2280 | 2281 | ||
2281 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 2282 | ret = mnt_want_write_file(file); |
2282 | return -EROFS; | 2283 | if (ret) |
2284 | return ret; | ||
2283 | 2285 | ||
2284 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, | 2286 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, |
2285 | 1)) { | 2287 | 1)) { |
2286 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); | 2288 | pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); |
2289 | mnt_drop_write_file(file); | ||
2287 | return -EINPROGRESS; | 2290 | return -EINPROGRESS; |
2288 | } | 2291 | } |
2289 | 2292 | ||
@@ -2300,6 +2303,7 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
2300 | kfree(vol_args); | 2303 | kfree(vol_args); |
2301 | out: | 2304 | out: |
2302 | mutex_unlock(&root->fs_info->volume_mutex); | 2305 | mutex_unlock(&root->fs_info->volume_mutex); |
2306 | mnt_drop_write_file(file); | ||
2303 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); | 2307 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); |
2304 | return ret; | 2308 | return ret; |
2305 | } | 2309 | } |
@@ -3842,7 +3846,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3842 | case BTRFS_IOC_ADD_DEV: | 3846 | case BTRFS_IOC_ADD_DEV: |
3843 | return btrfs_ioctl_add_dev(root, argp); | 3847 | return btrfs_ioctl_add_dev(root, argp); |
3844 | case BTRFS_IOC_RM_DEV: | 3848 | case BTRFS_IOC_RM_DEV: |
3845 | return btrfs_ioctl_rm_dev(root, argp); | 3849 | return btrfs_ioctl_rm_dev(file, argp); |
3846 | case BTRFS_IOC_FS_INFO: | 3850 | case BTRFS_IOC_FS_INFO: |
3847 | return btrfs_ioctl_fs_info(root, argp); | 3851 | return btrfs_ioctl_fs_info(root, argp); |
3848 | case BTRFS_IOC_DEV_INFO: | 3852 | case BTRFS_IOC_DEV_INFO: |