diff mbox series

[V4] scsi: core: put LLD module refcnt after SCSI device is released

Message ID 20211008050118.1440686-1-ming.lei@redhat.com (mailing list archive)
State Accepted
Headers show
Series [V4] scsi: core: put LLD module refcnt after SCSI device is released | expand

Commit Message

Ming Lei Oct. 8, 2021, 5:01 a.m. UTC
SCSI host release is triggered when SCSI device is freed, and we have to
make sure that LLD module won't be unloaded before SCSI host instance is
released because shost->hostt is required in host release handler.

So make sure to put LLD module refcnt after SCSI device is released.

Fix one kernel panic of 'BUG: unable to handle page fault for address'
reported by Changhui and Yi.

Reported-by: Changhui Zhong <czhong@redhat.com>
Reported-by: Yi Zhang <yi.zhang@redhat.com>
Tested-by: Yi Zhang <yi.zhang@redhat.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
V4:
	- set module pointer as NULL in case that grabbing mod is failed
	in sdev release handler, suggested by Greg
V3:
	- change to fix the issue by grabbing module during release
V2:
	- add one atomic counter for covering put device

 drivers/scsi/scsi.c       | 4 +++-
 drivers/scsi/scsi_sysfs.c | 9 +++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

Comments

Martin K. Petersen Oct. 13, 2021, 2:32 a.m. UTC | #1
On Fri, 8 Oct 2021 13:01:18 +0800, Ming Lei wrote:

> SCSI host release is triggered when SCSI device is freed, and we have to
> make sure that LLD module won't be unloaded before SCSI host instance is
> released because shost->hostt is required in host release handler.
> 
> So make sure to put LLD module refcnt after SCSI device is released.
> 
> Fix one kernel panic of 'BUG: unable to handle page fault for address'
> reported by Changhui and Yi.
> 
> [...]

Applied to 5.15/scsi-fixes, thanks!

[1/1] scsi: core: put LLD module refcnt after SCSI device is released
      https://git.kernel.org/mkp/scsi/c/f2b85040acec
diff mbox series

Patch

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index b241f9e3885c..291ecc33b1fe 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -553,8 +553,10 @@  EXPORT_SYMBOL(scsi_device_get);
  */
 void scsi_device_put(struct scsi_device *sdev)
 {
-	module_put(sdev->host->hostt->module);
+	struct module *mod = sdev->host->hostt->module;
+
 	put_device(&sdev->sdev_gendev);
+	module_put(mod);
 }
 EXPORT_SYMBOL(scsi_device_put);
 
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 86793259e541..a35841b34bfd 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -449,9 +449,12 @@  static void scsi_device_dev_release_usercontext(struct work_struct *work)
 	struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
 	struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
 	unsigned long flags;
+	struct module *mod;
 
 	sdev = container_of(work, struct scsi_device, ew.work);
 
+	mod = sdev->host->hostt->module;
+
 	scsi_dh_release_device(sdev);
 
 	parent = sdev->sdev_gendev.parent;
@@ -502,11 +505,17 @@  static void scsi_device_dev_release_usercontext(struct work_struct *work)
 
 	if (parent)
 		put_device(parent);
+	module_put(mod);
 }
 
 static void scsi_device_dev_release(struct device *dev)
 {
 	struct scsi_device *sdp = to_scsi_device(dev);
+
+	/* Set module pointer as NULL in case of module unloading */
+	if (!try_module_get(sdp->host->hostt->module))
+		sdp->host->hostt->module = NULL;
+
 	execute_in_process_context(scsi_device_dev_release_usercontext,
 				   &sdp->ew);
 }