Commit d320a955 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

compat_ioctl: scsi: move ioctl handling into drivers



Each driver calling scsi_ioctl() gets an equivalent compat_ioctl()
handler that implements the same commands by calling scsi_compat_ioctl().

The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible
at this point, so any driver that calls those can do so for both native
and compat mode, with the argument passed through compat_ptr().

With this, we can remove the entries from fs/compat_ioctl.c.  The new
code is larger, but should be easier to maintain and keep updated with
newly added commands.

Reviewed-by: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Acked-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent c103d6ee
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)

static const struct block_device_operations virtblk_fops = {
	.ioctl  = virtblk_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = blkdev_compat_ptr_ioctl,
#endif
	.owner  = THIS_MODULE,
	.getgeo = virtblk_getgeo,
};
+6 −3
Original line number Diff line number Diff line
@@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
			    unsigned int cmd, unsigned long arg)
{
	scsi_changer *ch = file->private_data;
	int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
							file->f_flags & O_NDELAY);
	if (retval)
		return retval;

	switch (cmd) {
	case CHIOGPARAMS:
@@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
	case CHIOINITELEM:
	case CHIOSVOLTAG:
		/* compatible */
		return ch_ioctl(file, cmd, arg);
		return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
	case CHIOGSTATUS32:
	{
		struct changer_element_status32 ces32;
@@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
		return ch_gstatus(ch, ces32.ces_type, data);
	}
	default:
		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
		return -ENOIOCTLCMD;
		return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));

	}
}
+19 −31
Original line number Diff line number Diff line
@@ -1465,13 +1465,12 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 *	Note: most ioctls are forward onto the block subsystem or further
 *	down in the scsi subsystem.
 **/
static int sd_ioctl(struct block_device *bdev, fmode_t mode,
		    unsigned int cmd, unsigned long arg)
static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
			   unsigned int cmd, void __user *p)
{
	struct gendisk *disk = bdev->bd_disk;
	struct scsi_disk *sdkp = scsi_disk(disk);
	struct scsi_device *sdp = sdkp->device;
	void __user *p = (void __user *)arg;
	int error;
    
	SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
@@ -1507,9 +1506,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
			break;
		default:
			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
			if (error != -ENOTTY)
				break;
			error = scsi_ioctl(sdp, cmd, p);
			break;
	}
out:
@@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
	revalidate_disk(sdkp->disk);
}

static int sd_ioctl(struct block_device *bdev, fmode_t mode,
		    unsigned int cmd, unsigned long arg)
{
	void __user *p = (void __user *)arg;
	int ret;

	ret = sd_ioctl_common(bdev, mode, cmd, p);
	if (ret != -ENOTTY)
		return ret;

	return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
}

#ifdef CONFIG_COMPAT
/* 
 * This gets directly called from VFS. When the ioctl 
 * is not recognized we go back to the other translation paths. 
 */
static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
			   unsigned int cmd, unsigned long arg)
{
	struct gendisk *disk = bdev->bd_disk;
	struct scsi_disk *sdkp = scsi_disk(disk);
	struct scsi_device *sdev = sdkp->device;
	void __user *p = compat_ptr(arg);
	int error;

	error = scsi_verify_blk_ioctl(bdev, cmd);
	if (error < 0)
		return error;

	error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
			(mode & FMODE_NDELAY) != 0);
	if (error)
		return error;
	int ret;

	if (is_sed_ioctl(cmd))
		return sed_ioctl(sdkp->opal_dev, cmd, p);
	ret = sd_ioctl_common(bdev, mode, cmd, p);
	if (ret != -ENOTTY)
		return ret;

	/* 
	 * Let the static ioctl translation table take care of it.
	 */
	if (!sdev->host->hostt->compat_ioctl)
		return -ENOIOCTLCMD; 
	return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
	return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
}
#endif

+27 −17
Original line number Diff line number Diff line
@@ -911,19 +911,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
#endif

static long
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
		unsigned int cmd_in, void __user *p)
{
	void __user *p = (void __user *)arg;
	int __user *ip = p;
	int result, val, read_only;
	Sg_device *sdp;
	Sg_fd *sfp;
	Sg_request *srp;
	unsigned long iflags;

	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
		return -ENXIO;

	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
@@ -1146,29 +1141,44 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
			cmd_in, filp->f_flags & O_NDELAY);
	if (result)
		return result;
	return scsi_ioctl(sdp->device, cmd_in, p);

	return -ENOIOCTLCMD;
}

#ifdef CONFIG_COMPAT
static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
static long
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{
	void __user *p = (void __user *)arg;
	Sg_device *sdp;
	Sg_fd *sfp;
	struct scsi_device *sdev;
	int ret;

	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
		return -ENXIO;

	sdev = sdp->device;
	if (sdev->host->hostt->compat_ioctl) { 
	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
	if (ret != -ENOIOCTLCMD)
		return ret;

	return scsi_ioctl(sdp->device, cmd_in, p);
}

#ifdef CONFIG_COMPAT
static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{
	void __user *p = compat_ptr(arg);
	Sg_device *sdp;
	Sg_fd *sfp;
	int ret;

		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
		return -ENXIO;

	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
	if (ret != -ENOIOCTLCMD)
		return ret;
	}

	return -ENOIOCTLCMD;
	return scsi_compat_ioctl(sdp->device, cmd_in, p);
}
#endif

+53 −4
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/compat.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
@@ -598,6 +599,55 @@ out:
	return ret;
}

#ifdef CONFIG_COMPAT
static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
			  unsigned long arg)
{
	struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
	struct scsi_device *sdev = cd->device;
	void __user *argp = compat_ptr(arg);
	int ret;

	mutex_lock(&sr_mutex);

	ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
			(mode & FMODE_NDELAY) != 0);
	if (ret)
		goto out;

	scsi_autopm_get_device(sdev);

	/*
	 * Send SCSI addressing ioctls directly to mid level, send other
	 * ioctls to cdrom/block level.
	 */
	switch (cmd) {
	case SCSI_IOCTL_GET_IDLUN:
	case SCSI_IOCTL_GET_BUS_NUMBER:
		ret = scsi_compat_ioctl(sdev, cmd, argp);
		goto put;
	}

	/*
	 * CDROM ioctls are handled in the block layer, but
	 * do the scsi blk ioctls here.
	 */
	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
	if (ret != -ENOTTY)
		goto put;

	ret = scsi_compat_ioctl(sdev, cmd, argp);

put:
	scsi_autopm_put_device(sdev);

out:
	mutex_unlock(&sr_mutex);
	return ret;

}
#endif

static unsigned int sr_block_check_events(struct gendisk *disk,
					  unsigned int clearing)
{
@@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
	.open		= sr_block_open,
	.release	= sr_block_release,
	.ioctl		= sr_block_ioctl,
#ifdef CONFIG_COMPAT
	.ioctl		= sr_block_compat_ioctl,
#endif
	.check_events	= sr_block_check_events,
	.revalidate_disk = sr_block_revalidate_disk,
	/* 
	 * No compat_ioctl for now because sr_block_ioctl never
	 * seems to pass arbitrary ioctls down to host drivers.
	 */
};

static int sr_open(struct cdrom_device_info *cdi, int purpose)
Loading