diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2015-01-22 21:52:47 -0500 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-01-22 23:12:16 -0500 |
| commit | dc4515ea26d6c7fed3d978cd2bd36adc0d057bc5 (patch) | |
| tree | 5af9b7e384ae01cacea65f9a85cee4967fd2d494 | |
| parent | d5db139ab3764640e0882a1746e7b9fdee33fd87 (diff) | |
scsi: always increment reference count
James reported:
> After e513cc1 module: Remove stop_machine from module unloading,
> module_refcount() is returning (unsigned long)-1 when called from within
> a routine that runs in module_exit. This is confusing the scsi device
> put code which is coded to detect a module_refcount() of zero for
> running within a module exit routine and not try to do another
> module_put. The fix is to restore the original behaviour of
> module_refcount() and return zero if we're running inside an exit
> routine.
The correct fix is to turn try_module_get() into __module_get(), and
always do the module_put().
Acked-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
| -rw-r--r-- | drivers/scsi/scsi.c | 13 |
1 files changed, 3 insertions, 10 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index e02885451425..9b3829931f40 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
| @@ -986,9 +986,9 @@ int scsi_device_get(struct scsi_device *sdev) | |||
| 986 | return -ENXIO; | 986 | return -ENXIO; |
| 987 | if (!get_device(&sdev->sdev_gendev)) | 987 | if (!get_device(&sdev->sdev_gendev)) |
| 988 | return -ENXIO; | 988 | return -ENXIO; |
| 989 | /* We can fail this if we're doing SCSI operations | 989 | /* We can fail try_module_get if we're doing SCSI operations |
| 990 | * from module exit (like cache flush) */ | 990 | * from module exit (like cache flush) */ |
| 991 | try_module_get(sdev->host->hostt->module); | 991 | __module_get(sdev->host->hostt->module); |
| 992 | 992 | ||
| 993 | return 0; | 993 | return 0; |
| 994 | } | 994 | } |
| @@ -1004,14 +1004,7 @@ EXPORT_SYMBOL(scsi_device_get); | |||
| 1004 | */ | 1004 | */ |
| 1005 | void scsi_device_put(struct scsi_device *sdev) | 1005 | void scsi_device_put(struct scsi_device *sdev) |
| 1006 | { | 1006 | { |
| 1007 | #ifdef CONFIG_MODULE_UNLOAD | 1007 | module_put(sdev->host->hostt->module); |
| 1008 | struct module *module = sdev->host->hostt->module; | ||
| 1009 | |||
| 1010 | /* The module refcount will be zero if scsi_device_get() | ||
| 1011 | * was called from a module removal routine */ | ||
| 1012 | if (module && module_refcount(module) != 0) | ||
| 1013 | module_put(module); | ||
| 1014 | #endif | ||
| 1015 | put_device(&sdev->sdev_gendev); | 1008 | put_device(&sdev->sdev_gendev); |
| 1016 | } | 1009 | } |
| 1017 | EXPORT_SYMBOL(scsi_device_put); | 1010 | EXPORT_SYMBOL(scsi_device_put); |
