diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2005-07-26 16:27:10 +0200 |
---|---|---|
committer | James Bottomley <jejb@titanic.(none)> | 2005-09-18 22:22:06 +0200 |
commit | a64358db1253b35d508a411e80a3ad23b859ec88 (patch) | |
tree | e222f3f17d6962a84d966620485d19f67d7fafa7 /drivers/scsi/scsi_sysfs.c | |
parent | [SCSI] fix oops in scsi_release_buffers() (diff) | |
download | linux-a64358db1253b35d508a411e80a3ad23b859ec88.tar.xz linux-a64358db1253b35d508a411e80a3ad23b859ec88.zip |
[SCSI] SCSI scanning and removal fixes
This patch (as545) fixes the list traversals in __scsi_remove_target and
scsi_forget_host. In each case the existing code list_for_each_entry_safe
in an _unsafe_ manner, because the list was not protected from outside
modification while the iteration was running.
The new scsi_forget_host routine takes the moderately controversial step
of iterating over devices for removal rather than iterating over targets.
This makes more sense to me because the current scheme treats targets as
second-class citizens, created and removed on demand, rather than as
objects corresponding to actual hardware. (Also I couldn't figure out any
safe way to iterate over the target list, since it's not so easy to tell
when a target has already been removed.)
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 83f87c41b18d..1e47b7eddef4 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -719,17 +719,20 @@ void __scsi_remove_target(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; - struct scsi_device *sdev, *tmp; + struct scsi_device *sdev; spin_lock_irqsave(shost->host_lock, flags); starget->reap_ref++; - list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) { + restart: + list_for_each_entry(sdev, &shost->__devices, siblings) { if (sdev->channel != starget->channel || - sdev->id != starget->id) + sdev->id != starget->id || + sdev->sdev_state == SDEV_DEL) continue; spin_unlock_irqrestore(shost->host_lock, flags); scsi_remove_device(sdev); spin_lock_irqsave(shost->host_lock, flags); + goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); scsi_target_reap(starget); |