scsi: core: Put LLD module refcnt after SCSI device is released
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>
This commit is contained in:
parent
a027d43cf3
commit
c2df161f69
@ -575,8 +575,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);
|
||||||
|
|
||||||
|
@ -431,9 +431,12 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
|
|||||||
struct list_head *this, *tmp;
|
struct list_head *this, *tmp;
|
||||||
struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
|
struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = 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;
|
||||||
@ -474,11 +477,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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user