diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2017-10-12 12:35:19 +0200 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2017-11-13 12:11:41 +0100 |
commit | 1de797bb248d2276337139fecaffbd3bbc0f736d (patch) | |
tree | c8ee0b09435866327547ce07b5603346588e079a /drivers/block/rbd.c | |
parent | bb0581f01c38ff525295fc6128bc3a49202dabae (diff) | |
download | linux-1de797bb248d2276337139fecaffbd3bbc0f736d.tar.bz2 |
rbd: fix and simplify rbd_ioctl_set_ro()
->open_count/-EBUSY check is bogus and wrong: when an open device is
set read-only, blkdev_write_iter() refuses further writes with -EPERM.
This is standard behaviour and all other block devices allow this.
set_disk_ro() call is also problematic: we affect the entire device
when called on a single partition.
All rbd_ioctl_set_ro() needs to do is refuse ro -> rw transition for
mapped snapshots. Everything else can be handled by generic code.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'drivers/block/rbd.c')
-rw-r--r-- | drivers/block/rbd.c | 34 |
1 files changed, 6 insertions, 28 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index adc877dfef5c..fb7cb38a6d83 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -640,46 +640,24 @@ static void rbd_release(struct gendisk *disk, fmode_t mode) static int rbd_ioctl_set_ro(struct rbd_device *rbd_dev, unsigned long arg) { - int ret = 0; - int val; - bool ro; - bool ro_changed = false; + int ro; - /* get_user() may sleep, so call it before taking rbd_dev->lock */ - if (get_user(val, (int __user *)(arg))) + if (get_user(ro, (int __user *)arg)) return -EFAULT; - ro = val ? true : false; - /* Snapshot doesn't allow to write*/ + /* Snapshots can't be marked read-write */ if (rbd_dev->spec->snap_id != CEPH_NOSNAP && !ro) return -EROFS; - spin_lock_irq(&rbd_dev->lock); - /* prevent others open this device */ - if (rbd_dev->open_count > 1) { - ret = -EBUSY; - goto out; - } - - if (rbd_dev->mapping.read_only != ro) { - rbd_dev->mapping.read_only = ro; - ro_changed = true; - } - -out: - spin_unlock_irq(&rbd_dev->lock); - /* set_disk_ro() may sleep, so call it after releasing rbd_dev->lock */ - if (ret == 0 && ro_changed) - set_disk_ro(rbd_dev->disk, ro ? 1 : 0); - - return ret; + /* Let blkdev_roset() handle it */ + return -ENOTTY; } static int rbd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct rbd_device *rbd_dev = bdev->bd_disk->private_data; - int ret = 0; + int ret; switch (cmd) { case BLKROSET: |