diff options
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); | |||
851 | */ | 851 | */ |
852 | int scsi_device_get(struct scsi_device *sdev) | 852 | int scsi_device_get(struct scsi_device *sdev) |
853 | { | 853 | { |
854 | if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL) | 854 | if (sdev->sdev_state == SDEV_DEL) |
855 | return -ENXIO; | 855 | return -ENXIO; |
856 | if (!get_device(&sdev->sdev_gendev)) | 856 | if (!get_device(&sdev->sdev_gendev)) |
857 | return -ENXIO; | 857 | return -ENXIO; |
858 | if (!try_module_get(sdev->host->hostt->module)) { | 858 | /* We can fail this if we're doing SCSI operations |
859 | put_device(&sdev->sdev_gendev); | 859 | * from module exit (like cache flush) */ |
860 | return -ENXIO; | 860 | try_module_get(sdev->host->hostt->module); |
861 | } | 861 | |
862 | return 0; | 862 | return 0; |
863 | } | 863 | } |
864 | EXPORT_SYMBOL(scsi_device_get); | 864 | EXPORT_SYMBOL(scsi_device_get); |
@@ -873,7 +873,10 @@ EXPORT_SYMBOL(scsi_device_get); | |||
873 | */ | 873 | */ |
874 | void scsi_device_put(struct scsi_device *sdev) | 874 | void scsi_device_put(struct scsi_device *sdev) |
875 | { | 875 | { |
876 | module_put(sdev->host->hostt->module); | 876 | /* The module refcount will be zero if scsi_device_get() |
877 | * was called from a module removal routine */ | ||
878 | if (likely(module_refcount(sdev->host->hostt->module) != 0)) | ||
879 | module_put(sdev->host->hostt->module); | ||
877 | put_device(&sdev->sdev_gendev); | 880 | put_device(&sdev->sdev_gendev); |
878 | } | 881 | } |
879 | EXPORT_SYMBOL(scsi_device_put); | 882 | EXPORT_SYMBOL(scsi_device_put); |