Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 906d15fb authored by Christoph Hellwig's avatar Christoph Hellwig
Browse files

scsi: split scsi_nonblockable_ioctl



The calling conventions for this function are bad as it could return
-ENODEV both for a device not currently online and a not recognized ioctl.

Add a new scsi_ioctl_block_when_processing_errors function that wraps
scsi_block_when_processing_errors with the a special case for the
SG_SCSI_RESET ioctl command, and handle the SG_SCSI_RESET case itself
in scsi_ioctl.  All callers of scsi_ioctl now must call the above helper
to check for the EH state, so that the ioctl handler itself doesn't
have to.

Reported-by: default avatarRobert Elliott <Elliott@hp.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
parent 176aa9d6
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -616,6 +616,11 @@ static long ch_ioctl(struct file *file,
	int retval;
	void __user *argp = (void __user *)arg;

	retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
			file->f_flags & O_NDELAY);
	if (retval)
		return retval;

	switch (cmd) {
	case CHIOGPARAMS:
	{
+3 −3
Original line number Diff line number Diff line
@@ -4969,10 +4969,10 @@ static long osst_ioctl(struct file * file,
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */
	if( !scsi_block_when_processing_errors(STp->device) ) {
		retval = (-ENXIO);
	retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
			file->f_flags & O_NDELAY);
	if (retval)
		goto out;
	}

	cmd_type = _IOC_TYPE(cmd_in);
	cmd_nr   = _IOC_NR(cmd_in);
+13 −34
Original line number Diff line number Diff line
@@ -200,19 +200,6 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
{
	char scsi_cmd[MAX_COMMAND_SIZE];

	/* No idea how this happens.... */
	if (!sdev)
		return -ENXIO;

	/*
	 * If we are in the middle of error recovery, don't let anyone
	 * else try and use this device.  Also, if error recovery fails, it
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */
	if (!scsi_block_when_processing_errors(sdev))
		return -ENODEV;

	/* Check for deprecated ioctls ... all the ioctls which don't
	 * follow the new unique numbering scheme are deprecated */
	switch (cmd) {
@@ -273,6 +260,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
				     START_STOP_TIMEOUT, NORMAL_RETRIES);
        case SCSI_IOCTL_GET_PCI:
                return scsi_ioctl_get_pci(sdev, arg);
	case SG_SCSI_RESET:
		return scsi_ioctl_reset(sdev, arg);
	default:
		if (sdev->host->hostt->ioctl)
			return sdev->host->hostt->ioctl(sdev, cmd, arg);
@@ -281,30 +270,20 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
}
EXPORT_SYMBOL(scsi_ioctl);

/**
 * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET
 * @sdev: scsi device receiving ioctl
 * @cmd: Must be SC_SCSI_RESET
 * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,TARGET,BUS,HOST}
 *       possibly OR-ed with SG_SCSI_RESET_NO_ESCALATE
 * @ndelay: file mode O_NDELAY flag
/*
 * We can process a reset even when a device isn't fully operable.
 */
int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
			    void __user *arg, int ndelay)
int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, int cmd,
		bool ndelay)
{
	/* The first set of iocts may be executed even if we're doing
	 * error processing, as long as the device was opened
	 * non-blocking */
	if (ndelay) {
	if (cmd == SG_SCSI_RESET && ndelay) {
		if (scsi_host_in_recovery(sdev->host))
			return -ENODEV;
	} else if (!scsi_block_when_processing_errors(sdev))
	} else {
		if (!scsi_block_when_processing_errors(sdev))
			return -ENODEV;

	switch (cmd) {
	case SG_SCSI_RESET:
		return scsi_ioctl_reset(sdev, arg);
	}
	return -ENODEV;

	return 0;
}
EXPORT_SYMBOL(scsi_nonblockable_ioctl);
EXPORT_SYMBOL_GPL(scsi_ioctl_block_when_processing_errors);
+3 −3
Original line number Diff line number Diff line
@@ -1334,9 +1334,9 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */
	error = scsi_nonblockable_ioctl(sdp, cmd, p,
	error = scsi_ioctl_block_when_processing_errors(sdp, cmd,
			(mode & FMODE_NDELAY) != 0);
	if (!scsi_block_when_processing_errors(sdp) || !error)
	if (error)
		goto out;

	/*
+15 −18
Original line number Diff line number Diff line
@@ -1071,16 +1071,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
		if (atomic_read(&sdp->detaching))
			return -ENODEV;
		return put_user(sdp->device->host->hostt->emulated, ip);
	case SG_SCSI_RESET:
		if (atomic_read(&sdp->detaching))
			return -ENODEV;
		if (filp->f_flags & O_NONBLOCK) {
			if (scsi_host_in_recovery(sdp->device->host))
				return -EBUSY;
		} else if (!scsi_block_when_processing_errors(sdp->device))
			return -EBUSY;

		return scsi_ioctl_reset(sdp->device, ip);
	case SCSI_IOCTL_SEND_COMMAND:
		if (atomic_read(&sdp->detaching))
			return -ENODEV;
@@ -1100,13 +1090,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
			return result;
		sdp->sgdebug = (char) val;
		return 0;
	case SCSI_IOCTL_GET_IDLUN:
	case SCSI_IOCTL_GET_BUS_NUMBER:
	case SCSI_IOCTL_PROBE_HOST:
	case SG_GET_TRANSFORM:
		if (atomic_read(&sdp->detaching))
			return -ENODEV;
		return scsi_ioctl(sdp->device, cmd_in, p);
	case BLKSECTGET:
		return put_user(max_sectors_bytes(sdp->device->request_queue),
				ip);
@@ -1122,11 +1105,25 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
		return blk_trace_startstop(sdp->device->request_queue, 0);
	case BLKTRACETEARDOWN:
		return blk_trace_remove(sdp->device->request_queue);
	case SCSI_IOCTL_GET_IDLUN:
	case SCSI_IOCTL_GET_BUS_NUMBER:
	case SCSI_IOCTL_PROBE_HOST:
	case SG_GET_TRANSFORM:
	case SG_SCSI_RESET:
		if (atomic_read(&sdp->detaching))
			return -ENODEV;
		break;
	default:
		if (read_only)
			return -EPERM;	/* don't know so take safe approach */
		return scsi_ioctl(sdp->device, cmd_in, p);
		break;
	}

	result = scsi_ioctl_block_when_processing_errors(sdp->device,
			cmd_in, filp->f_flags & O_NDELAY);
	if (result)
		return result;
	return scsi_ioctl(sdp->device, cmd_in, p);
}

#ifdef CONFIG_COMPAT
Loading