On Thu, 2005-09-15 at 21:52 -0400, Alan Stern wrote: > In short, those iterations must be carried out as in my patch. OK, I looked at making this work while reaping the target correctly, but I couldn't (basic problem is that the target list keeps the target until it has no more devices, a condition that could be made untrue by something as simple as an open of the sysfs file). So, rather than try that, I thought a better approach might be to make the host state model work for us. i.e. if we know the host is being removed, there's no point allowing target or device removal because at some point the host removal will do it for us. This enforcement would ensure we're the only legitimate removers of the target and device. The alternative is to migrate to klists, I think ... James diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -7,6 +7,7 @@ struct request_queue; struct scsi_cmnd; struct scsi_device; +struct scsi_target; struct scsi_host_template; struct scsi_request; struct Scsi_Host; @@ -125,6 +126,7 @@ extern void scsi_sysfs_device_initialize extern int scsi_sysfs_target_initialize(struct scsi_device *); extern struct scsi_transport_template blank_transport_template; extern void __scsi_remove_device(struct scsi_device *); +extern void __scsi_remove_target(struct scsi_target *); extern struct bus_type scsi_bus_type; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1481,7 +1481,7 @@ void scsi_forget_host(struct Scsi_Host * spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) { spin_unlock_irqrestore(shost->host_lock, flags); - scsi_remove_target(&starget->dev); + __scsi_remove_target(starget); spin_lock_irqsave(shost->host_lock, flags); } spin_unlock_irqrestore(shost->host_lock, flags); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -710,7 +710,8 @@ void scsi_remove_device(struct scsi_devi struct Scsi_Host *shost = sdev->host; down(&shost->scan_mutex); - __scsi_remove_device(sdev); + if (scsi_host_scan_allowed(shost)) + __scsi_remove_device(sdev); up(&shost->scan_mutex); } EXPORT_SYMBOL(scsi_remove_device); @@ -728,7 +729,7 @@ void __scsi_remove_target(struct scsi_ta sdev->id != starget->id) continue; spin_unlock_irqrestore(shost->host_lock, flags); - scsi_remove_device(sdev); + __scsi_remove_device(sdev); spin_lock_irqsave(shost->host_lock, flags); } spin_unlock_irqrestore(shost->host_lock, flags); @@ -755,7 +756,16 @@ void scsi_remove_target(struct device *d struct device *rdev; if (scsi_is_target_device(dev)) { + struct Scsi_Host *shost = dev_to_shost(dev); + + down(&shost->scan_mutex); + /* We deny target removal here if the host is being + * deleted, since it will remove the target itself */ + if (!scsi_host_scan_allowed(shost)) + goto out; __scsi_remove_target(to_scsi_target(dev)); + out: + up(&shost->scan_mutex); return; } diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -654,7 +654,8 @@ static inline struct device *scsi_get_de **/ static inline int scsi_host_scan_allowed(struct Scsi_Host *shost) { - return shost->shost_state == SHOST_RUNNING; + return shost->shost_state == SHOST_RUNNING || + shost->shost_state == SHOST_RECOVERY; } extern void scsi_unblock_requests(struct Scsi_Host *); - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html