diff options
-rw-r--r-- | drivers/block/rbd.c | 62 |
1 files changed, 60 insertions, 2 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8295b3afa8e0..1c88fba98c8e 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -559,10 +559,69 @@ static void rbd_release(struct gendisk *disk, fmode_t mode) | |||
559 | put_device(&rbd_dev->dev); | 559 | put_device(&rbd_dev->dev); |
560 | } | 560 | } |
561 | 561 | ||
562 | static int rbd_ioctl_set_ro(struct rbd_device *rbd_dev, unsigned long arg) | ||
563 | { | ||
564 | int val; | ||
565 | bool ro; | ||
566 | |||
567 | if (get_user(val, (int __user *)(arg))) | ||
568 | return -EFAULT; | ||
569 | |||
570 | ro = val ? true : false; | ||
571 | /* Snapshot doesn't allow to write*/ | ||
572 | if (rbd_dev->spec->snap_id != CEPH_NOSNAP && !ro) | ||
573 | return -EROFS; | ||
574 | |||
575 | if (rbd_dev->mapping.read_only != ro) { | ||
576 | rbd_dev->mapping.read_only = ro; | ||
577 | set_disk_ro(rbd_dev->disk, ro ? 1 : 0); | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int rbd_ioctl(struct block_device *bdev, fmode_t mode, | ||
584 | unsigned int cmd, unsigned long arg) | ||
585 | { | ||
586 | struct rbd_device *rbd_dev = bdev->bd_disk->private_data; | ||
587 | int ret = 0; | ||
588 | |||
589 | spin_lock_irq(&rbd_dev->lock); | ||
590 | /* prevent others open this device */ | ||
591 | if (rbd_dev->open_count > 1) { | ||
592 | ret = -EBUSY; | ||
593 | goto out; | ||
594 | } | ||
595 | |||
596 | switch (cmd) { | ||
597 | case BLKROSET: | ||
598 | ret = rbd_ioctl_set_ro(rbd_dev, arg); | ||
599 | break; | ||
600 | default: | ||
601 | ret = -ENOTTY; | ||
602 | } | ||
603 | |||
604 | out: | ||
605 | spin_unlock_irq(&rbd_dev->lock); | ||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | #ifdef CONFIG_COMPAT | ||
610 | static int rbd_compat_ioctl(struct block_device *bdev, fmode_t mode, | ||
611 | unsigned int cmd, unsigned long arg) | ||
612 | { | ||
613 | return rbd_ioctl(bdev, mode, cmd, arg); | ||
614 | } | ||
615 | #endif /* CONFIG_COMPAT */ | ||
616 | |||
562 | static const struct block_device_operations rbd_bd_ops = { | 617 | static const struct block_device_operations rbd_bd_ops = { |
563 | .owner = THIS_MODULE, | 618 | .owner = THIS_MODULE, |
564 | .open = rbd_open, | 619 | .open = rbd_open, |
565 | .release = rbd_release, | 620 | .release = rbd_release, |
621 | .ioctl = rbd_ioctl, | ||
622 | #ifdef CONFIG_COMPAT | ||
623 | .compat_ioctl = rbd_compat_ioctl, | ||
624 | #endif | ||
566 | }; | 625 | }; |
567 | 626 | ||
568 | /* | 627 | /* |
@@ -3114,7 +3173,6 @@ static void rbd_request_fn(struct request_queue *q) | |||
3114 | __releases(q->queue_lock) __acquires(q->queue_lock) | 3173 | __releases(q->queue_lock) __acquires(q->queue_lock) |
3115 | { | 3174 | { |
3116 | struct rbd_device *rbd_dev = q->queuedata; | 3175 | struct rbd_device *rbd_dev = q->queuedata; |
3117 | bool read_only = rbd_dev->mapping.read_only; | ||
3118 | struct request *rq; | 3176 | struct request *rq; |
3119 | int result; | 3177 | int result; |
3120 | 3178 | ||
@@ -3150,7 +3208,7 @@ static void rbd_request_fn(struct request_queue *q) | |||
3150 | 3208 | ||
3151 | if (write_request) { | 3209 | if (write_request) { |
3152 | result = -EROFS; | 3210 | result = -EROFS; |
3153 | if (read_only) | 3211 | if (rbd_dev->mapping.read_only) |
3154 | goto end_request; | 3212 | goto end_request; |
3155 | rbd_assert(rbd_dev->spec->snap_id == CEPH_NOSNAP); | 3213 | rbd_assert(rbd_dev->spec->snap_id == CEPH_NOSNAP); |
3156 | } | 3214 | } |