diff --git a/[refs] b/[refs] index ea1c0bf863a9..6cb6e9d3e541 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 225c56960fcafeccc2b6304f96cd3f0dbf42a16a +refs/heads/master: bc3f02a795d3b4faa99d37390174be2a75d091bd diff --git a/trunk/drivers/scsi/scsi_sysfs.c b/trunk/drivers/scsi/scsi_sysfs.c index 093d4f6a54d2..ce5224c92eda 100644 --- a/trunk/drivers/scsi/scsi_sysfs.c +++ b/trunk/drivers/scsi/scsi_sysfs.c @@ -1031,33 +1031,31 @@ 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, *found; + struct scsi_target *starget, *last = NULL; unsigned long flags; - restart: - found = NULL; + /* remove targets being careful to lookup next entry before + * deleting the last + */ 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) { - found = starget; - found->reap_ref++; - break; + /* assuming new targets arrive at the end */ + 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); } } spin_unlock_irqrestore(shost->host_lock, flags); - if (found) { - __scsi_remove_target(found); - scsi_target_reap(found); - /* in the case where @dev has multiple starget children, - * continue removing. - * - * FIXME: does such a case exist? - */ - goto restart; - } + if (last) + scsi_target_reap(last); } EXPORT_SYMBOL(scsi_remove_target);