mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Ben Hutchings <ben.hutchings@codethink.co.uk> Acked-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
		
							parent
							
								
									c103d6ee69
								
							
						
					
					
						commit
						d320a9551e
					
				
					 7 changed files with 142 additions and 204 deletions
				
			
		| 
						 | 
					@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct block_device_operations virtblk_fops = {
 | 
					static const struct block_device_operations virtblk_fops = {
 | 
				
			||||||
	.ioctl  = virtblk_ioctl,
 | 
						.ioctl  = virtblk_ioctl,
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						.compat_ioctl = blkdev_compat_ptr_ioctl,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	.owner  = THIS_MODULE,
 | 
						.owner  = THIS_MODULE,
 | 
				
			||||||
	.getgeo = virtblk_getgeo,
 | 
						.getgeo = virtblk_getgeo,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
 | 
				
			||||||
			    unsigned int cmd, unsigned long arg)
 | 
								    unsigned int cmd, unsigned long arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	scsi_changer *ch = file->private_data;
 | 
						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) {
 | 
						switch (cmd) {
 | 
				
			||||||
	case CHIOGPARAMS:
 | 
						case CHIOGPARAMS:
 | 
				
			||||||
| 
						 | 
					@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
 | 
				
			||||||
	case CHIOINITELEM:
 | 
						case CHIOINITELEM:
 | 
				
			||||||
	case CHIOSVOLTAG:
 | 
						case CHIOSVOLTAG:
 | 
				
			||||||
		/* compatible */
 | 
							/* compatible */
 | 
				
			||||||
		return ch_ioctl(file, cmd, arg);
 | 
							return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 | 
				
			||||||
	case CHIOGSTATUS32:
 | 
						case CHIOGSTATUS32:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		struct changer_element_status32 ces32;
 | 
							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);
 | 
							return ch_gstatus(ch, ces32.ces_type, data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
 | 
							return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
 | 
				
			||||||
		return -ENOIOCTLCMD;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					 *	Note: most ioctls are forward onto the block subsystem or further
 | 
				
			||||||
 *	down in the scsi subsystem.
 | 
					 *	down in the scsi subsystem.
 | 
				
			||||||
 **/
 | 
					 **/
 | 
				
			||||||
static int sd_ioctl(struct block_device *bdev, fmode_t mode,
 | 
					static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
 | 
				
			||||||
		    unsigned int cmd, unsigned long arg)
 | 
								   unsigned int cmd, void __user *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gendisk *disk = bdev->bd_disk;
 | 
						struct gendisk *disk = bdev->bd_disk;
 | 
				
			||||||
	struct scsi_disk *sdkp = scsi_disk(disk);
 | 
						struct scsi_disk *sdkp = scsi_disk(disk);
 | 
				
			||||||
	struct scsi_device *sdp = sdkp->device;
 | 
						struct scsi_device *sdp = sdkp->device;
 | 
				
			||||||
	void __user *p = (void __user *)arg;
 | 
					 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
 | 
						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;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
 | 
								error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
 | 
				
			||||||
			if (error != -ENOTTY)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			error = scsi_ioctl(sdp, cmd, p);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
| 
						 | 
					@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
 | 
				
			||||||
	revalidate_disk(sdkp->disk);
 | 
						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
 | 
					#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,
 | 
					static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
 | 
				
			||||||
			   unsigned int cmd, unsigned long arg)
 | 
								   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);
 | 
						void __user *p = compat_ptr(arg);
 | 
				
			||||||
	int error;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = scsi_verify_blk_ioctl(bdev, cmd);
 | 
						ret = sd_ioctl_common(bdev, mode, cmd, p);
 | 
				
			||||||
	if (error < 0)
 | 
						if (ret != -ENOTTY)
 | 
				
			||||||
		return error;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
 | 
						return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
 | 
				
			||||||
			(mode & FMODE_NDELAY) != 0);
 | 
					 | 
				
			||||||
	if (error)
 | 
					 | 
				
			||||||
		return error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (is_sed_ioctl(cmd))
 | 
					 | 
				
			||||||
		return sed_ioctl(sdkp->opal_dev, cmd, p);
 | 
					 | 
				
			||||||
	       
 | 
					 | 
				
			||||||
	/* 
 | 
					 | 
				
			||||||
	 * 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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -911,19 +911,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static long
 | 
					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 __user *ip = p;
 | 
				
			||||||
	int result, val, read_only;
 | 
						int result, val, read_only;
 | 
				
			||||||
	Sg_device *sdp;
 | 
					 | 
				
			||||||
	Sg_fd *sfp;
 | 
					 | 
				
			||||||
	Sg_request *srp;
 | 
						Sg_request *srp;
 | 
				
			||||||
	unsigned long iflags;
 | 
						unsigned long iflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 | 
					 | 
				
			||||||
		return -ENXIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
 | 
						SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
 | 
				
			||||||
				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
 | 
									   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
 | 
				
			||||||
	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
 | 
						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);
 | 
								cmd_in, filp->f_flags & O_NDELAY);
 | 
				
			||||||
	if (result)
 | 
						if (result)
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -ENOIOCTLCMD;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 scsi_ioctl(sdp->device, cmd_in, p);
 | 
						return scsi_ioctl(sdp->device, cmd_in, p);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_COMPAT
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 | 
					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_device *sdp;
 | 
				
			||||||
	Sg_fd *sfp;
 | 
						Sg_fd *sfp;
 | 
				
			||||||
	struct scsi_device *sdev;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 | 
						if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 | 
				
			||||||
		return -ENXIO;
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdev = sdp->device;
 | 
						ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
 | 
				
			||||||
	if (sdev->host->hostt->compat_ioctl) { 
 | 
						if (ret != -ENOIOCTLCMD)
 | 
				
			||||||
		int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
	
 | 
						return scsi_compat_ioctl(sdp->device, cmd_in, p);
 | 
				
			||||||
	return -ENOIOCTLCMD;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,7 @@
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/bio.h>
 | 
					#include <linux/bio.h>
 | 
				
			||||||
 | 
					#include <linux/compat.h>
 | 
				
			||||||
#include <linux/string.h>
 | 
					#include <linux/string.h>
 | 
				
			||||||
#include <linux/errno.h>
 | 
					#include <linux/errno.h>
 | 
				
			||||||
#include <linux/cdrom.h>
 | 
					#include <linux/cdrom.h>
 | 
				
			||||||
| 
						 | 
					@ -598,6 +599,55 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 | 
				
			||||||
	return ret;
 | 
						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,
 | 
					static unsigned int sr_block_check_events(struct gendisk *disk,
 | 
				
			||||||
					  unsigned int clearing)
 | 
										  unsigned int clearing)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
 | 
				
			||||||
	.open		= sr_block_open,
 | 
						.open		= sr_block_open,
 | 
				
			||||||
	.release	= sr_block_release,
 | 
						.release	= sr_block_release,
 | 
				
			||||||
	.ioctl		= sr_block_ioctl,
 | 
						.ioctl		= sr_block_ioctl,
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						.ioctl		= sr_block_compat_ioctl,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	.check_events	= sr_block_check_events,
 | 
						.check_events	= sr_block_check_events,
 | 
				
			||||||
	.revalidate_disk = sr_block_revalidate_disk,
 | 
						.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)
 | 
					static int sr_open(struct cdrom_device_info *cdi, int purpose)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3501,7 +3501,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The ioctl command */
 | 
					/* The ioctl command */
 | 
				
			||||||
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
					static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, cmd_nr, cmd_type, bt;
 | 
						int i, cmd_nr, cmd_type, bt;
 | 
				
			||||||
	int retval = 0;
 | 
						int retval = 0;
 | 
				
			||||||
| 
						 | 
					@ -3509,7 +3509,6 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
				
			||||||
	struct scsi_tape *STp = file->private_data;
 | 
						struct scsi_tape *STp = file->private_data;
 | 
				
			||||||
	struct st_modedef *STm;
 | 
						struct st_modedef *STm;
 | 
				
			||||||
	struct st_partstat *STps;
 | 
						struct st_partstat *STps;
 | 
				
			||||||
	void __user *p = (void __user *)arg;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mutex_lock_interruptible(&STp->lock))
 | 
						if (mutex_lock_interruptible(&STp->lock))
 | 
				
			||||||
		return -ERESTARTSYS;
 | 
							return -ERESTARTSYS;
 | 
				
			||||||
| 
						 | 
					@ -3824,9 +3823,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mutex_unlock(&STp->lock);
 | 
						mutex_unlock(&STp->lock);
 | 
				
			||||||
	switch (cmd_in) {
 | 
						switch (cmd_in) {
 | 
				
			||||||
 | 
							case SCSI_IOCTL_STOP_UNIT:
 | 
				
			||||||
 | 
								/* unload */
 | 
				
			||||||
 | 
								retval = scsi_ioctl(STp->device, cmd_in, p);
 | 
				
			||||||
 | 
								if (!retval) {
 | 
				
			||||||
 | 
									STp->rew_at_close = 0;
 | 
				
			||||||
 | 
									STp->ready = ST_NO_TAPE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SCSI_IOCTL_GET_IDLUN:
 | 
							case SCSI_IOCTL_GET_IDLUN:
 | 
				
			||||||
		case SCSI_IOCTL_GET_BUS_NUMBER:
 | 
							case SCSI_IOCTL_GET_BUS_NUMBER:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if ((cmd_in == SG_IO ||
 | 
								if ((cmd_in == SG_IO ||
 | 
				
			||||||
			     cmd_in == SCSI_IOCTL_SEND_COMMAND ||
 | 
								     cmd_in == SCSI_IOCTL_SEND_COMMAND ||
 | 
				
			||||||
| 
						 | 
					@ -3840,42 +3849,46 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
				
			||||||
				return i;
 | 
									return i;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	retval = scsi_ioctl(STp->device, cmd_in, p);
 | 
						return -ENOTTY;
 | 
				
			||||||
	if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
 | 
					 | 
				
			||||||
		STp->rew_at_close = 0;
 | 
					 | 
				
			||||||
		STp->ready = ST_NO_TAPE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return retval;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
	mutex_unlock(&STp->lock);
 | 
						mutex_unlock(&STp->lock);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __user *p = (void __user *)arg;
 | 
				
			||||||
 | 
						struct scsi_tape *STp = file->private_data;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = st_ioctl_common(file, cmd_in, p);
 | 
				
			||||||
 | 
						if (ret != -ENOTTY)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return scsi_ioctl(STp->device, cmd_in, p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_COMPAT
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
					static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void __user *p = compat_ptr(arg);
 | 
						void __user *p = compat_ptr(arg);
 | 
				
			||||||
	struct scsi_tape *STp = file->private_data;
 | 
						struct scsi_tape *STp = file->private_data;
 | 
				
			||||||
	struct scsi_device *sdev = STp->device;
 | 
						int ret;
 | 
				
			||||||
	int ret = -ENOIOCTLCMD;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* argument conversion is handled using put_user_mtpos/put_user_mtget */
 | 
						/* argument conversion is handled using put_user_mtpos/put_user_mtget */
 | 
				
			||||||
	switch (cmd_in) {
 | 
						switch (cmd_in) {
 | 
				
			||||||
	case MTIOCTOP:
 | 
					 | 
				
			||||||
		return st_ioctl(file, MTIOCTOP, (unsigned long)p);
 | 
					 | 
				
			||||||
	case MTIOCPOS32:
 | 
						case MTIOCPOS32:
 | 
				
			||||||
		return st_ioctl(file, MTIOCPOS, (unsigned long)p);
 | 
							return st_ioctl_common(file, MTIOCPOS, p);
 | 
				
			||||||
	case MTIOCGET32:
 | 
						case MTIOCGET32:
 | 
				
			||||||
		return st_ioctl(file, MTIOCGET, (unsigned long)p);
 | 
							return st_ioctl_common(file, MTIOCGET, p);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sdev->host->hostt->compat_ioctl) { 
 | 
						ret = st_ioctl_common(file, cmd_in, p);
 | 
				
			||||||
 | 
						if (ret != -ENOTTY)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
 | 
						return scsi_compat_ioctl(STp->device, cmd_in, p);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,109 +36,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_BLOCK
 | 
					 | 
				
			||||||
#include <linux/cdrom.h>
 | 
					 | 
				
			||||||
#include <linux/fd.h>
 | 
					 | 
				
			||||||
#include <scsi/scsi.h>
 | 
					 | 
				
			||||||
#include <scsi/scsi_ioctl.h>
 | 
					 | 
				
			||||||
#include <scsi/sg.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/uaccess.h>
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
#include <linux/watchdog.h>
 | 
					#include <linux/watchdog.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/hiddev.h>
 | 
					#include <linux/hiddev.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/sort.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * simple reversible transform to make our table more evenly
 | 
					 | 
				
			||||||
 * distributed after sorting.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
 | 
					 | 
				
			||||||
static unsigned int ioctl_pointer[] = {
 | 
					 | 
				
			||||||
#ifdef CONFIG_BLOCK
 | 
					 | 
				
			||||||
/* Big S */
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_BLOCK
 | 
					 | 
				
			||||||
/* SG stuff */
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_IO)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_EMULATED_HOST)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_PACK_ID)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_DEBUG)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SCSI_RESET)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
 | 
					 | 
				
			||||||
COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Convert common ioctl arguments based on their command number
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Please do not add any code in here. Instead, implement
 | 
					 | 
				
			||||||
 * a compat_ioctl operation in the place that handleѕ the
 | 
					 | 
				
			||||||
 * ioctl for the native case.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static long do_ioctl_trans(unsigned int cmd,
 | 
					 | 
				
			||||||
		 unsigned long arg, struct file *file)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return -ENOIOCTLCMD;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int compat_ioctl_check_table(unsigned int xcmd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef CONFIG_BLOCK
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	const int max = ARRAY_SIZE(ioctl_pointer) - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BUILD_BUG_ON(max >= (1 << 16));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* guess initial offset into table, assuming a
 | 
					 | 
				
			||||||
	   normalized distribution */
 | 
					 | 
				
			||||||
	i = ((xcmd >> 16) * max) >> 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* do linear search up first, until greater or equal */
 | 
					 | 
				
			||||||
	while (ioctl_pointer[i] < xcmd && i < max)
 | 
					 | 
				
			||||||
		i++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* then do linear search down */
 | 
					 | 
				
			||||||
	while (ioctl_pointer[i] > xcmd && i > 0)
 | 
					 | 
				
			||||||
		i--;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ioctl_pointer[i] == xcmd;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 | 
					COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 | 
				
			||||||
		       compat_ulong_t, arg32)
 | 
							       compat_ulong_t, arg32)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -216,19 +118,9 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 | 
				
			||||||
				goto out_fput;
 | 
									goto out_fput;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!f.file->f_op->unlocked_ioctl)
 | 
					 | 
				
			||||||
			goto do_ioctl;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (compat_ioctl_check_table(XFORM(cmd)))
 | 
					 | 
				
			||||||
		goto found_handler;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	error = do_ioctl_trans(cmd, arg, f.file);
 | 
					 | 
				
			||||||
	if (error == -ENOIOCTLCMD)
 | 
					 | 
				
			||||||
		error = -ENOTTY;
 | 
							error = -ENOTTY;
 | 
				
			||||||
 | 
							goto out_fput;
 | 
				
			||||||
	goto out_fput;
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 found_handler:
 | 
					 found_handler:
 | 
				
			||||||
	arg = (unsigned long)compat_ptr(arg);
 | 
						arg = (unsigned long)compat_ptr(arg);
 | 
				
			||||||
| 
						 | 
					@ -239,23 +131,3 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned int a, b;
 | 
					 | 
				
			||||||
	a = *(unsigned int *)p;
 | 
					 | 
				
			||||||
	b = *(unsigned int *)q;
 | 
					 | 
				
			||||||
	if (a > b)
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	if (a < b)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init init_sys32_ioctl(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
 | 
					 | 
				
			||||||
		init_sys32_ioctl_cmp, NULL);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
__initcall(init_sys32_ioctl);
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue