summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-10-19 16:35:46 +0200
committerJiri Slaby <jslaby@suse.cz>2016-02-24 10:23:24 +0100
commit259d9d2f2725b1a8ca4d70f10c860259aef1d1a5 (patch)
tree9dd2ebe5fd86ab7205e5e3e966aaa5edef1278f2
parent1661a36984b6a7e5deb4b8a77eb8d1de237226be (diff)
downloadlinux-259d9d2f2725b1a8ca4d70f10c860259aef1d1a5.tar.gz
linux-259d9d2f2725b1a8ca4d70f10c860259aef1d1a5.tar.bz2
linux-259d9d2f2725b1a8ca4d70f10c860259aef1d1a5.zip
scsi: restart list search after unlock in scsi_remove_target
commit 40998193560dab6c3ce8d25f4fa58a23e252ef38 upstream. When dropping a lock while iterating a list we must restart the search as other threads could have manipulated the list under us. Without this we can get stuck in an endless loop. This bug was introduced by commit bc3f02a795d3b4faa99d37390174be2a75d091bd Author: Dan Williams <djbw@fb.com> Date: Tue Aug 28 22:12:10 2012 -0700 [SCSI] scsi_remove_target: fix softlockup regression on hot remove Which was itself trying to fix a reported soft lockup issue http://thread.gmane.org/gmane.linux.kernel/1348679 However, we believe even with this revert of the original patch, the soft lockup problem has been fixed by commit f2495e228fce9f9cec84367547813cbb0d6db15a Author: James Bottomley <JBottomley@Parallels.com> Date: Tue Jan 21 07:01:41 2014 -0800 [SCSI] dual scan thread bug fix Thanks go to Dan Williams <dan.j.williams@intel.com> for tracking all this prior history down. Reported-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Christoph Hellwig <hch@lst.de> Tested-by: Johannes Thumshirn <jthumshirn@suse.de> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Fixes: bc3f02a795d3b4faa99d37390174be2a75d091bd Signed-off-by: James Bottomley <JBottomley@Odin.com> Signed-off-by: Jiri Slaby <jslaby@suse.cz>
-rw-r--r--drivers/scsi/scsi_sysfs.c16
1 files changed, 4 insertions, 12 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index dfb007c95b98..678a9f96588a 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1070,31 +1070,23 @@ static void __scsi_remove_target(struct scsi_target *starget)
void scsi_remove_target(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev->parent);
- struct scsi_target *starget, *last = NULL;
+ struct scsi_target *starget;
unsigned long flags;
- /* remove targets being careful to lookup next entry before
- * deleting the last
- */
+restart:
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(starget, &shost->__targets, siblings) {
if (starget->state == STARGET_DEL)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
- /* assuming new targets arrive at the end */
kref_get(&starget->reap_ref);
spin_unlock_irqrestore(shost->host_lock, flags);
- if (last)
- scsi_target_reap(last);
- last = starget;
__scsi_remove_target(starget);
- spin_lock_irqsave(shost->host_lock, flags);
+ scsi_target_reap(starget);
+ goto restart;
}
}
spin_unlock_irqrestore(shost->host_lock, flags);
-
- if (last)
- scsi_target_reap(last);
}
EXPORT_SYMBOL(scsi_remove_target);