Commit 7d613cda authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

[PATCH] sd_shutdown cannot be called when in state SDEV_DEL

sd_remove calls sd_shutdown to finish I/O to the disc.  However, the
state model puts the device in SDEV_DEL before triggering the
sd_remove (which won't allow any further I/O at all).

Fix by making SDEV_CANCEL the intermediate state and only transitioning to 
SDEV_DEL after calling device_del().
parent de706cdb
...@@ -977,7 +977,7 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) ...@@ -977,7 +977,7 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
*/ */
int scsi_device_get(struct scsi_device *sdev) int scsi_device_get(struct scsi_device *sdev)
{ {
if (sdev->sdev_state == SDEV_DEL) if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
return -ENXIO; return -ENXIO;
if (!get_device(&sdev->sdev_gendev)) if (!get_device(&sdev->sdev_gendev))
return -ENXIO; return -ENXIO;
......
...@@ -502,18 +502,19 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) ...@@ -502,18 +502,19 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
**/ **/
void scsi_remove_device(struct scsi_device *sdev) void scsi_remove_device(struct scsi_device *sdev)
{ {
if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) { if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
scsi_device_set_state(sdev, SDEV_DEL); return;
class_device_unregister(&sdev->sdev_classdev);
if (sdev->transport_classdev.class) class_device_unregister(&sdev->sdev_classdev);
class_device_unregister(&sdev->transport_classdev); if (sdev->transport_classdev.class)
device_del(&sdev->sdev_gendev); class_device_unregister(&sdev->transport_classdev);
if (sdev->host->hostt->slave_destroy) device_del(&sdev->sdev_gendev);
sdev->host->hostt->slave_destroy(sdev); scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->transportt->cleanup) if (sdev->host->hostt->slave_destroy)
sdev->host->transportt->cleanup(sdev); sdev->host->hostt->slave_destroy(sdev);
put_device(&sdev->sdev_gendev); if (sdev->host->transportt->cleanup)
} sdev->host->transportt->cleanup(sdev);
put_device(&sdev->sdev_gendev);
} }
int scsi_register_driver(struct device_driver *drv) int scsi_register_driver(struct device_driver *drv)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment