Skip to content

Commit ff48b37

Browse files
committed
scsi: Do not attempt to rescan suspended devices
scsi_rescan_device() takes a scsi device lock before executing a device handler and device driver rescan methods. Waiting for the completion of any command issued to the device by these methods will thus be done with the device lock held. As a result, there is a risk of deadlocking within the power management code if scsi_rescan_device() is called to handle a device resume with the associated scsi device not yet resumed. Avoid such situation by checking that the target scsi device is in the running state, that is, fully capable of executing commands, before proceeding with the rescan and bailout returning -EWOULDBLOCK otherwise. With this error return, the caller can retry rescaning the device after a delay. The state check is done with the device lock held and is thus safe against incoming suspend power management operations. Fixes: 6aa0365 ("ata: libata-scsi: Avoid deadlock on rescan after device resume") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
1 parent aa3998d commit ff48b37

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

drivers/scsi/scsi_scan.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1619,12 +1619,24 @@ int scsi_add_device(struct Scsi_Host *host, uint channel,
16191619
}
16201620
EXPORT_SYMBOL(scsi_add_device);
16211621

1622-
void scsi_rescan_device(struct scsi_device *sdev)
1622+
int scsi_rescan_device(struct scsi_device *sdev)
16231623
{
16241624
struct device *dev = &sdev->sdev_gendev;
1625+
int ret = 0;
16251626

16261627
device_lock(dev);
16271628

1629+
/*
1630+
* Bail out if the device is not running. Otherwise, the rescan may
1631+
* block waiting for commands to be executed, with us holding the
1632+
* device lock. This can result in a potential deadlock in the power
1633+
* management core code when system resume is on-going.
1634+
*/
1635+
if (sdev->sdev_state != SDEV_RUNNING) {
1636+
ret = -EWOULDBLOCK;
1637+
goto unlock;
1638+
}
1639+
16281640
scsi_attach_vpd(sdev);
16291641
scsi_cdl_check(sdev);
16301642

@@ -1638,7 +1650,11 @@ void scsi_rescan_device(struct scsi_device *sdev)
16381650
drv->rescan(dev);
16391651
module_put(dev->driver->owner);
16401652
}
1653+
1654+
unlock:
16411655
device_unlock(dev);
1656+
1657+
return ret;
16421658
}
16431659
EXPORT_SYMBOL(scsi_rescan_device);
16441660

include/scsi/scsi_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ scsi_template_proc_dir(const struct scsi_host_template *sht);
764764
#define scsi_template_proc_dir(sht) NULL
765765
#endif
766766
extern void scsi_scan_host(struct Scsi_Host *);
767-
extern void scsi_rescan_device(struct scsi_device *);
767+
extern int scsi_rescan_device(struct scsi_device *sdev);
768768
extern void scsi_remove_host(struct Scsi_Host *);
769769
extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
770770
extern int scsi_host_busy(struct Scsi_Host *shost);

0 commit comments

Comments
 (0)