Skip to content

Commit 16728aa

Browse files
Ming Leimartinkpetersen
authored andcommitted
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/[email protected] Cc: Christoph Hellwig <[email protected]> Cc: Ming Lei <[email protected]> Cc: Mike Christie <[email protected]> Cc: Hannes Reinecke <[email protected]> Cc: John Garry <[email protected]> Reviewed-by: Mike Christie <[email protected]> Signed-off-by: Ming Lei <[email protected]> Signed-off-by: Bart Van Assche <[email protected]> [ bvanassche: Reworked Ming's patch and split it ] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent fe44260 commit 16728aa

File tree

3 files changed

+18
-0
lines changed

3 files changed

+18
-0
lines changed

drivers/scsi/hosts.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,13 @@ void scsi_remove_host(struct Scsi_Host *shost)
190190
transport_unregister_device(&shost->shost_gendev);
191191
device_unregister(&shost->shost_dev);
192192
device_del(&shost->shost_gendev);
193+
194+
/*
195+
* After scsi_remove_host() has returned the scsi LLD module can be
196+
* unloaded and/or the host resources can be released. Hence wait until
197+
* the dependent SCSI targets and devices are gone before returning.
198+
*/
199+
wait_event(shost->targets_wq, atomic_read(&shost->target_count) == 0);
193200
}
194201
EXPORT_SYMBOL(scsi_remove_host);
195202

@@ -394,6 +401,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
394401
INIT_LIST_HEAD(&shost->starved_list);
395402
init_waitqueue_head(&shost->host_wait);
396403
mutex_init(&shost->scan_mutex);
404+
init_waitqueue_head(&shost->targets_wq);
397405

398406
index = ida_alloc(&host_index_ida, GFP_KERNEL);
399407
if (index < 0) {

drivers/scsi/scsi_scan.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,14 @@ static void scsi_target_destroy(struct scsi_target *starget)
406406
static void scsi_target_dev_release(struct device *dev)
407407
{
408408
struct device *parent = dev->parent;
409+
struct Scsi_Host *shost = dev_to_shost(parent);
409410
struct scsi_target *starget = to_scsi_target(dev);
410411

411412
kfree(starget);
413+
414+
if (atomic_dec_return(&shost->target_count) == 0)
415+
wake_up(&shost->targets_wq);
416+
412417
put_device(parent);
413418
}
414419

@@ -523,6 +528,8 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
523528
starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED;
524529
init_waitqueue_head(&starget->sdev_wq);
525530

531+
atomic_inc(&shost->target_count);
532+
526533
retry:
527534
spin_lock_irqsave(shost->host_lock, flags);
528535

include/scsi/scsi_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,9 @@ struct Scsi_Host {
689689
/* ldm bits */
690690
struct device shost_gendev, shost_dev;
691691

692+
atomic_t target_count;
693+
wait_queue_head_t targets_wq;
694+
692695
/*
693696
* Points to the transport data (if any) which is allocated
694697
* separately

0 commit comments

Comments
 (0)