Commit f2b85040 authored by Ming Lei's avatar Ming Lei Committed by Martin K. Petersen

scsi: core: Put LLD module refcnt after SCSI device is released

SCSI host release is triggered when SCSI device is freed. We have to make
sure that the low-level device driver module won't be unloaded before SCSI
host instance is released because shost->hostt is required in the release
handler.

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

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

Link: https://lore.kernel.org/r/20211008050118.1440686-1-ming.lei@redhat.com
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reported-by: default avatarChanghui Zhong <czhong@redhat.com>
Reported-by: default avatarYi Zhang <yi.zhang@redhat.com>
Tested-by: default avatarYi Zhang <yi.zhang@redhat.com>
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 6fd13d69
...@@ -553,8 +553,10 @@ EXPORT_SYMBOL(scsi_device_get); ...@@ -553,8 +553,10 @@ EXPORT_SYMBOL(scsi_device_get);
*/ */
void scsi_device_put(struct scsi_device *sdev) 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); put_device(&sdev->sdev_gendev);
module_put(mod);
} }
EXPORT_SYMBOL(scsi_device_put); EXPORT_SYMBOL(scsi_device_put);
......
...@@ -449,9 +449,12 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) ...@@ -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_pg80 = NULL, *vpd_pg83 = NULL;
struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
unsigned long flags; unsigned long flags;
struct module *mod;
sdev = container_of(work, struct scsi_device, ew.work); sdev = container_of(work, struct scsi_device, ew.work);
mod = sdev->host->hostt->module;
scsi_dh_release_device(sdev); scsi_dh_release_device(sdev);
parent = sdev->sdev_gendev.parent; parent = sdev->sdev_gendev.parent;
...@@ -502,11 +505,17 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) ...@@ -502,11 +505,17 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
if (parent) if (parent)
put_device(parent); put_device(parent);
module_put(mod);
} }
static void scsi_device_dev_release(struct device *dev) static void scsi_device_dev_release(struct device *dev)
{ {
struct scsi_device *sdp = to_scsi_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, execute_in_process_context(scsi_device_dev_release_usercontext,
&sdp->ew); &sdp->ew);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment