diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2006-08-31 18:15:22 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-09-01 17:56:56 -0400 |
commit | 85b6c720b0931101c8bcc3a5abdc2b8514b0fb4b (patch) | |
tree | a6d2883ef3b4f40a71d59c9db0fda87d43419463 /drivers/scsi/scsi.c | |
parent | 86e33a296c2c9ed6eece0bfff4ac776f42040504 (diff) | |
download | blackbird-op-linux-85b6c720b0931101c8bcc3a5abdc2b8514b0fb4b.tar.gz blackbird-op-linux-85b6c720b0931101c8bcc3a5abdc2b8514b0fb4b.zip |
[SCSI] sd: fix cache flushing on module removal (and individual device removal)
The fix isn't actually in sd: it's in scsi_device_get(). I modified it
to allow devices to be returned in SDEV_CANCEL, but not SDEV_DEL. This
means that the device_remove_driver, which occurs in device_del() in
scsi_remove_device() after the device has gone into SDEV_CANCEL is now
effective at flushing the cache.
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 94df671d776a..37843927e47f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -851,14 +851,14 @@ EXPORT_SYMBOL(scsi_track_queue_full); */ int scsi_device_get(struct scsi_device *sdev) { - if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL) + if (sdev->sdev_state == SDEV_DEL) return -ENXIO; if (!get_device(&sdev->sdev_gendev)) return -ENXIO; - if (!try_module_get(sdev->host->hostt->module)) { - put_device(&sdev->sdev_gendev); - return -ENXIO; - } + /* We can fail this if we're doing SCSI operations + * from module exit (like cache flush) */ + try_module_get(sdev->host->hostt->module); + return 0; } EXPORT_SYMBOL(scsi_device_get); @@ -873,7 +873,10 @@ EXPORT_SYMBOL(scsi_device_get); */ void scsi_device_put(struct scsi_device *sdev) { - module_put(sdev->host->hostt->module); + /* The module refcount will be zero if scsi_device_get() + * was called from a module removal routine */ + if (likely(module_refcount(sdev->host->hostt->module) != 0)) + module_put(sdev->host->hostt->module); put_device(&sdev->sdev_gendev); } EXPORT_SYMBOL(scsi_device_put); |