From: Ming Lei ming.lei@redhat.com
stable inclusion from stable-5.10.78 commit 7b57c38d12aed1b5d92f74748bed25e0d041729f bugzilla: 185700 https://gitee.com/openeuler/kernel/issues/I4IAU2
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit f2b85040acec9a928b4eb1b57a989324e8e38d3f upstream.
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: Changhui Zhong czhong@redhat.com Reported-by: Yi Zhang yi.zhang@redhat.com Tested-by: Yi Zhang yi.zhang@redhat.com Signed-off-by: Ming Lei ming.lei@redhat.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Chen Jun chenjun102@huawei.com Acked-by: Weilong Chen chenweilong@huawei.com
Signed-off-by: Chen Jun chenjun102@huawei.com --- drivers/scsi/scsi.c | 4 +++- drivers/scsi/scsi_sysfs.c | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 24619c3bebd5..6ad834d61d4c 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -545,8 +545,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 8173b67ec7b0..1378bb1a7371 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -450,9 +450,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; @@ -501,11 +504,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); }