diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-09-21 22:05:34 -0700 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-10-16 10:54:02 -0500 |
commit | 1a34c0640137eed8dabdac3a68a7a84116ac9e0d (patch) | |
tree | fbe141523906f19c10c80bbdbdd4a69446c5fa44 /drivers/scsi/libsas/sas_discover.c | |
parent | 29f366e8a99fdced4c0b5417a478d7539adc66d3 (diff) | |
download | blackbird-op-linux-1a34c0640137eed8dabdac3a68a7a84116ac9e0d.tar.gz blackbird-op-linux-1a34c0640137eed8dabdac3a68a7a84116ac9e0d.zip |
[SCSI] libsas: fix port->dev_list locking
port->dev_list maintains a list of devices attached to a given sas root port.
It needs to be mutated under a lock as contexts outside of the
single-threaded-libsas-workqueue access the list via sas_find_dev_by_rphy().
Fixup locations where the list was being mutated without a lock.
This is a follow-up to commit 5911e963 "[SCSI] libsas: remove expander
from dev list on error", where Luben noted [1]:
> 2/ We have unlocked list manipulations in sas_ex_discover_end_dev(),
> sas_unregister_common_dev(), and sas_ex_discover_end_dev()
Yes, I can see that and that is very unfortunate.
[1]: http://marc.info/?l=linux-scsi&m=131480962006471&w=2
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_discover.c')
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index f5831930df9b..54a5199ceb56 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -219,17 +219,20 @@ out_err2: /* ---------- Device registration and unregistration ---------- */ -static inline void sas_unregister_common_dev(struct domain_device *dev) +static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev) { sas_notify_lldd_dev_gone(dev); if (!dev->parent) dev->port->port_dev = NULL; else list_del_init(&dev->siblings); + + spin_lock_irq(&port->dev_list_lock); list_del_init(&dev->dev_list_node); + spin_unlock_irq(&port->dev_list_lock); } -void sas_unregister_dev(struct domain_device *dev) +void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) { if (dev->rphy) { sas_remove_children(&dev->rphy->dev); @@ -241,15 +244,15 @@ void sas_unregister_dev(struct domain_device *dev) kfree(dev->ex_dev.ex_phy); dev->ex_dev.ex_phy = NULL; } - sas_unregister_common_dev(dev); + sas_unregister_common_dev(port, dev); } void sas_unregister_domain_devices(struct asd_sas_port *port) { struct domain_device *dev, *n; - list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node) - sas_unregister_dev(dev); + list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) + sas_unregister_dev(port, dev); port->port->rphy = NULL; |