rbd: add ioctl for rbd

When running the following commands:
    [root@ceph0 mnt]# blockdev --setro /dev/rbd1
    [root@ceph0 mnt]# blockdev --getro /dev/rbd1
    0

The block setro didn't take effect, it is because
the rbd doesn't support ioctl of block driver.

This resolves:
	http://tracker.ceph.com/issues/6265

Signed-off-by: Guangliang Zhao <guangliang@unitedstack.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
This commit is contained in:
Guangliang Zhao 2013-09-24 11:25:36 +08:00 committed by Josh Durgin
parent 4e217b5dc8
commit 131fd9f6fc

View File

@ -559,10 +559,69 @@ static void rbd_release(struct gendisk *disk, fmode_t mode)
put_device(&rbd_dev->dev);
}
static int rbd_ioctl_set_ro(struct rbd_device *rbd_dev, unsigned long arg)
{
int val;
bool ro;
if (get_user(val, (int __user *)(arg)))
return -EFAULT;
ro = val ? true : false;
/* Snapshot doesn't allow to write*/
if (rbd_dev->spec->snap_id != CEPH_NOSNAP && !ro)
return -EROFS;
if (rbd_dev->mapping.read_only != ro) {
rbd_dev->mapping.read_only = ro;
set_disk_ro(rbd_dev->disk, ro ? 1 : 0);
}
return 0;
}
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;
spin_lock_irq(&rbd_dev->lock);
/* prevent others open this device */
if (rbd_dev->open_count > 1) {
ret = -EBUSY;
goto out;
}
switch (cmd) {
case BLKROSET:
ret = rbd_ioctl_set_ro(rbd_dev, arg);
break;
default:
ret = -ENOTTY;
}
out:
spin_unlock_irq(&rbd_dev->lock);
return ret;
}
#ifdef CONFIG_COMPAT
static int rbd_compat_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
return rbd_ioctl(bdev, mode, cmd, arg);
}
#endif /* CONFIG_COMPAT */
static const struct block_device_operations rbd_bd_ops = {
.owner = THIS_MODULE,
.open = rbd_open,
.release = rbd_release,
.ioctl = rbd_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = rbd_compat_ioctl,
#endif
};
/*
@ -3114,7 +3173,6 @@ static void rbd_request_fn(struct request_queue *q)
__releases(q->queue_lock) __acquires(q->queue_lock)
{
struct rbd_device *rbd_dev = q->queuedata;
bool read_only = rbd_dev->mapping.read_only;
struct request *rq;
int result;
@ -3150,7 +3208,7 @@ static void rbd_request_fn(struct request_queue *q)
if (write_request) {
result = -EROFS;
if (read_only)
if (rbd_dev->mapping.read_only)
goto end_request;
rbd_assert(rbd_dev->spec->snap_id == CEPH_NOSNAP);
}