summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hosts.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2022-07-29 00:18:49 +0200
committerMartin K. Petersen <martin.petersen@oracle.com>2022-08-02 01:45:14 +0200
commit16728aaba62e8b3b170735fdc3d8aa972835c136 (patch)
tree126c11cb5076d3a1b8d6cb2aeda76799be6940d5 /drivers/scsi/hosts.c
parentscsi: core: Make sure that targets outlive devices (diff)
downloadlinux-16728aaba62e8b3b170735fdc3d8aa972835c136.tar.xz
linux-16728aaba62e8b3b170735fdc3d8aa972835c136.zip
scsi: core: Make sure that hosts outlive targets
Fix the race conditions between SCSI LLD kernel module unloading and SCSI device and target removal by making sure that SCSI hosts are destroyed after all associated target and device objects have been freed. Link: https://lore.kernel.org/r/20220728221851.1822295-3-bvanassche@acm.org Cc: Christoph Hellwig <hch@lst.de> Cc: Ming Lei <ming.lei@redhat.com> Cc: Mike Christie <michael.christie@oracle.com> Cc: Hannes Reinecke <hare@suse.de> Cc: John Garry <john.garry@huawei.com> Reviewed-by: Mike Christie <michael.christie@oracle.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Bart Van Assche <bvanassche@acm.org> [ bvanassche: Reworked Ming's patch and split it ] Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/hosts.c')
-rw-r--r--drivers/scsi/hosts.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index ef6c0e37acce..8fa98c8d0ee0 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -190,6 +190,13 @@ void scsi_remove_host(struct Scsi_Host *shost)
transport_unregister_device(&shost->shost_gendev);
device_unregister(&shost->shost_dev);
device_del(&shost->shost_gendev);
+
+ /*
+ * After scsi_remove_host() has returned the scsi LLD module can be
+ * unloaded and/or the host resources can be released. Hence wait until
+ * the dependent SCSI targets and devices are gone before returning.
+ */
+ wait_event(shost->targets_wq, atomic_read(&shost->target_count) == 0);
}
EXPORT_SYMBOL(scsi_remove_host);
@@ -394,6 +401,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
INIT_LIST_HEAD(&shost->starved_list);
init_waitqueue_head(&shost->host_wait);
mutex_init(&shost->scan_mutex);
+ init_waitqueue_head(&shost->targets_wq);
index = ida_alloc(&host_index_ida, GFP_KERNEL);
if (index < 0) {