Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da24927b authored by Miao Xie's avatar Miao Xie Committed by Chris Mason
Browse files

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: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 198605a8
Loading
Loading
Loading
Loading
+8 −4
Original line number Original line Diff line number Diff line
@@ -2270,20 +2270,23 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
	return ret;
	return ret;
}
}


static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
{
{
	struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
	struct btrfs_ioctl_vol_args *vol_args;
	struct btrfs_ioctl_vol_args *vol_args;
	int ret;
	int ret;


	if (!capable(CAP_SYS_ADMIN))
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
		return -EPERM;


	if (root->fs_info->sb->s_flags & MS_RDONLY)
	ret = mnt_want_write_file(file);
		return -EROFS;
	if (ret)
		return ret;


	if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
	if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
			1)) {
			1)) {
		pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
		pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
		mnt_drop_write_file(file);
		return -EINPROGRESS;
		return -EINPROGRESS;
	}
	}


@@ -2300,6 +2303,7 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
	kfree(vol_args);
	kfree(vol_args);
out:
out:
	mutex_unlock(&root->fs_info->volume_mutex);
	mutex_unlock(&root->fs_info->volume_mutex);
	mnt_drop_write_file(file);
	atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
	atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
	return ret;
	return ret;
}
}
@@ -3842,7 +3846,7 @@ long btrfs_ioctl(struct file *file, unsigned int
	case BTRFS_IOC_ADD_DEV:
	case BTRFS_IOC_ADD_DEV:
		return btrfs_ioctl_add_dev(root, argp);
		return btrfs_ioctl_add_dev(root, argp);
	case BTRFS_IOC_RM_DEV:
	case BTRFS_IOC_RM_DEV:
		return btrfs_ioctl_rm_dev(root, argp);
		return btrfs_ioctl_rm_dev(file, argp);
	case BTRFS_IOC_FS_INFO:
	case BTRFS_IOC_FS_INFO:
		return btrfs_ioctl_fs_info(root, argp);
		return btrfs_ioctl_fs_info(root, argp);
	case BTRFS_IOC_DEV_INFO:
	case BTRFS_IOC_DEV_INFO: