Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: proper state checking and module refcount handling in scsi_device_get

This effectively reverts commits 85b6c7 ("[SCSI] sd: fix cache flushing on
module removal (and individual device removal)" and dc4515ea ("scsi: always
increment reference count").

We now never call scsi_device_get from the shutdown path, and the fact
that we started grabbing reference there in commit 85b6c7 turned out
turned out to create more problems than it solves, and required
workarounds for workarounds for workarounds. Move back to properly checking
the device state and carefully handle module refcounting.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

authored by

Christoph Hellwig and committed by
James Bottomley
cff549e4 3d9a1f53

+13 -7
+13 -7
drivers/scsi/scsi.c
··· 972 972 * Description: Gets a reference to the scsi_device and increments the use count 973 973 * of the underlying LLDD module. You must hold host_lock of the 974 974 * parent Scsi_Host or already have a reference when calling this. 975 + * 976 + * This will fail if a device is deleted or cancelled, or when the LLD module 977 + * is in the process of being unloaded. 975 978 */ 976 979 int scsi_device_get(struct scsi_device *sdev) 977 980 { 978 - if (sdev->sdev_state == SDEV_DEL) 979 - return -ENXIO; 981 + if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL) 982 + goto fail; 980 983 if (!get_device(&sdev->sdev_gendev)) 981 - return -ENXIO; 982 - /* We can fail try_module_get if we're doing SCSI operations 983 - * from module exit (like cache flush) */ 984 - __module_get(sdev->host->hostt->module); 985 - 984 + goto fail; 985 + if (!try_module_get(sdev->host->hostt->module)) 986 + goto fail_put_device; 986 987 return 0; 988 + 989 + fail_put_device: 990 + put_device(&sdev->sdev_gendev); 991 + fail: 992 + return -ENXIO; 987 993 } 988 994 EXPORT_SYMBOL(scsi_device_get); 989 995