From: Paolo Bonzini A logical volume can map to just part of underlying physical volume. In this case, it must be treated like a partition. (NB This patch just fixes device-mapper, not scsi.) Signed-off-by: Paolo Bonzini Signed-off-by: Alasdair G Kergon --- block/scsi_ioctl.c | 29 +++++++++++++++++++++++++++++ drivers/md/dm-flakey.c | 11 ++++++++++- drivers/md/dm-linear.c | 12 +++++++++++- drivers/md/dm-mpath.c | 6 ++++++ include/linux/blkdev.h | 1 + 5 files changed, 57 insertions(+), 2 deletions(-) Index: linux/block/scsi_ioctl.c =================================================================== --- linux.orig/block/scsi_ioctl.c +++ linux/block/scsi_ioctl.c @@ -690,6 +690,35 @@ int scsi_cmd_ioctl(struct request_queue } EXPORT_SYMBOL(scsi_cmd_ioctl); +int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) +{ + if (bd && bd == bd->bd_contains) + return 0; + + /* + * Actually none of this is particularly useful on a partition + * device, but let's play it safe. + */ + switch (cmd) { + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + case SCSI_IOCTL_GET_PCI: + case SCSI_IOCTL_PROBE_HOST: + case SG_GET_VERSION_NUM: + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_GET_RESERVED_SIZE: + case SG_SET_RESERVED_SIZE: + case SG_EMULATED_HOST: + return 0; + default: + break; + } + /* In particular, rule out all resets and host-specific ioctls. */ + return -ENOTTY; +} +EXPORT_SYMBOL(scsi_verify_blk_ioctl); + static int __init blk_scsi_ioctl_init(void) { blk_set_cmd_filter_defaults(&blk_default_cmd_filter); Index: linux/drivers/md/dm-flakey.c =================================================================== --- linux.orig/drivers/md/dm-flakey.c +++ linux/drivers/md/dm-flakey.c @@ -368,8 +368,17 @@ static int flakey_status(struct dm_targe static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct flakey_c *fc = ti->private; + struct dm_dev *dev = fc->dev; + int r = 0; - return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (fc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, Index: linux/drivers/md/dm-linear.c =================================================================== --- linux.orig/drivers/md/dm-linear.c +++ linux/drivers/md/dm-linear.c @@ -116,7 +116,17 @@ static int linear_ioctl(struct dm_target unsigned long arg) { struct linear_c *lc = (struct linear_c *) ti->private; - return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg); + struct dm_dev *dev = lc->dev; + int r = 0; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (lc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm, Index: linux/drivers/md/dm-mpath.c =================================================================== --- linux.orig/drivers/md/dm-mpath.c +++ linux/drivers/md/dm-mpath.c @@ -1520,6 +1520,12 @@ static int multipath_ioctl(struct dm_tar spin_unlock_irqrestore(&m->lock, flags); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); } Index: linux/include/linux/blkdev.h =================================================================== --- linux.orig/include/linux/blkdev.h +++ linux/include/linux/blkdev.h @@ -675,6 +675,7 @@ extern int blk_insert_cloned_request(str struct request *rq); extern void blk_delay_queue(struct request_queue *, unsigned long); extern void blk_recount_segments(struct request_queue *, struct bio *); +extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int); extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, unsigned int, void __user *); extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,