diff options
author | Christoph Hellwig <hch@lst.de> | 2014-10-11 10:25:31 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-11-12 05:16:11 -0500 |
commit | 906d15fbd23c1267addab361063c1c8119992215 (patch) | |
tree | 419ba148925c3651fe9337af24a932097e2c3d8a /drivers/scsi/scsi_ioctl.c | |
parent | 176aa9d6ee2db582e7e856dbe1983004a82869b4 (diff) |
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: Robert Elliott <Elliott@hp.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Diffstat (limited to 'drivers/scsi/scsi_ioctl.c')
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 47 |
1 files changed, 13 insertions, 34 deletions
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 5ddc08f39987..712f159ebb69 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c | |||
@@ -200,19 +200,6 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | |||
200 | { | 200 | { |
201 | char scsi_cmd[MAX_COMMAND_SIZE]; | 201 | char scsi_cmd[MAX_COMMAND_SIZE]; |
202 | 202 | ||
203 | /* No idea how this happens.... */ | ||
204 | if (!sdev) | ||
205 | return -ENXIO; | ||
206 | |||
207 | /* | ||
208 | * If we are in the middle of error recovery, don't let anyone | ||
209 | * else try and use this device. Also, if error recovery fails, it | ||
210 | * may try and take the device offline, in which case all further | ||
211 | * access to the device is prohibited. | ||
212 | */ | ||
213 | if (!scsi_block_when_processing_errors(sdev)) | ||
214 | return -ENODEV; | ||
215 | |||
216 | /* Check for deprecated ioctls ... all the ioctls which don't | 203 | /* Check for deprecated ioctls ... all the ioctls which don't |
217 | * follow the new unique numbering scheme are deprecated */ | 204 | * follow the new unique numbering scheme are deprecated */ |
218 | switch (cmd) { | 205 | switch (cmd) { |
@@ -273,6 +260,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | |||
273 | START_STOP_TIMEOUT, NORMAL_RETRIES); | 260 | START_STOP_TIMEOUT, NORMAL_RETRIES); |
274 | case SCSI_IOCTL_GET_PCI: | 261 | case SCSI_IOCTL_GET_PCI: |
275 | return scsi_ioctl_get_pci(sdev, arg); | 262 | return scsi_ioctl_get_pci(sdev, arg); |
263 | case SG_SCSI_RESET: | ||
264 | return scsi_ioctl_reset(sdev, arg); | ||
276 | default: | 265 | default: |
277 | if (sdev->host->hostt->ioctl) | 266 | if (sdev->host->hostt->ioctl) |
278 | return sdev->host->hostt->ioctl(sdev, cmd, arg); | 267 | return sdev->host->hostt->ioctl(sdev, cmd, arg); |
@@ -281,30 +270,20 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | |||
281 | } | 270 | } |
282 | EXPORT_SYMBOL(scsi_ioctl); | 271 | EXPORT_SYMBOL(scsi_ioctl); |
283 | 272 | ||
284 | /** | 273 | /* |
285 | * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET | 274 | * We can process a reset even when a device isn't fully operable. |
286 | * @sdev: scsi device receiving ioctl | ||
287 | * @cmd: Must be SC_SCSI_RESET | ||
288 | * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,TARGET,BUS,HOST} | ||
289 | * possibly OR-ed with SG_SCSI_RESET_NO_ESCALATE | ||
290 | * @ndelay: file mode O_NDELAY flag | ||
291 | */ | 275 | */ |
292 | int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, | 276 | int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, int cmd, |
293 | void __user *arg, int ndelay) | 277 | bool ndelay) |
294 | { | 278 | { |
295 | /* The first set of iocts may be executed even if we're doing | 279 | if (cmd == SG_SCSI_RESET && ndelay) { |
296 | * error processing, as long as the device was opened | ||
297 | * non-blocking */ | ||
298 | if (ndelay) { | ||
299 | if (scsi_host_in_recovery(sdev->host)) | 280 | if (scsi_host_in_recovery(sdev->host)) |
300 | return -ENODEV; | 281 | return -ENODEV; |
301 | } else if (!scsi_block_when_processing_errors(sdev)) | 282 | } else { |
302 | return -ENODEV; | 283 | if (!scsi_block_when_processing_errors(sdev)) |
303 | 284 | return -ENODEV; | |
304 | switch (cmd) { | ||
305 | case SG_SCSI_RESET: | ||
306 | return scsi_ioctl_reset(sdev, arg); | ||
307 | } | 285 | } |
308 | return -ENODEV; | 286 | |
287 | return 0; | ||
309 | } | 288 | } |
310 | EXPORT_SYMBOL(scsi_nonblockable_ioctl); | 289 | EXPORT_SYMBOL_GPL(scsi_ioctl_block_when_processing_errors); |