diff options
author | Yijing Wang <wangyijing@huawei.com> | 2015-07-17 05:16:31 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2015-07-30 16:49:10 -0400 |
commit | 67546762978f523749eac157903e0b01c18e083a (patch) | |
tree | 646a5a8749dae0c3192d9db23dc4eb1f63f90f75 /include/linux/pci.h | |
parent | ac10836b681289f7e430e52b106a209bbdcaa75e (diff) |
PCI: Protect pci_bus->slots with pci_slot_mutex, not pci_bus_sem
Rajat Jain reported a deadlock when PCIe hot-add and AER recovery happen at
the same time:
thread 1:
pciehp_enable_slot
pciehp_configure_device
pci_bus_add_devices
pci_bus_add_device
device_attach
device_lock(dev) # acquire device lock
...
pciehp_probe
init_slot
pci_hp_register
pci_create_slot
down_write(pci_bus_sem) # deadlock here
thread 2:
aer_isr_one_error
aer_process_err_device
do_recovery
broadcast_error_message(..., report_error_detected)
pci_walk_bus(..., cb=report_error_detected, ...)
down_read(&pci_bus_sem) # acquire pci_bus_sem
report_error_detected(dev) # cb()
device_lock(dev) # deadlock here
Previously, the bus->devices and bus->slots list were protected by
pci_bus_sem. In pci_create_slot(), we held it for writing so we could
add to the bus->slots list.
Add a new local pci_slot_mutex to protect bus->slots. Hold pci_bus_sem for
reading while searching the bus->devices list.
[bhelgaas: changelog]
Link: http://lkml.kernel.org/r/CAA93t1qpPqbih+UB0McA_d_+2rVaNkXsinAUxYzK9+JXSS+L-g@mail.gmail.com
Reported-by: Rajat Jain <rajatja@google.com>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'include/linux/pci.h')
-rw-r--r-- | include/linux/pci.h | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..aaee493174e2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -446,7 +446,8 @@ struct pci_bus { | |||
446 | struct list_head children; /* list of child buses */ | 446 | struct list_head children; /* list of child buses */ |
447 | struct list_head devices; /* list of devices on this bus */ | 447 | struct list_head devices; /* list of devices on this bus */ |
448 | struct pci_dev *self; /* bridge device as seen by parent */ | 448 | struct pci_dev *self; /* bridge device as seen by parent */ |
449 | struct list_head slots; /* list of slots on this bus */ | 449 | struct list_head slots; /* list of slots on this bus; |
450 | protected by pci_slot_mutex */ | ||
450 | struct resource *resource[PCI_BRIDGE_RESOURCE_NUM]; | 451 | struct resource *resource[PCI_BRIDGE_RESOURCE_NUM]; |
451 | struct list_head resources; /* address space routed to this bus */ | 452 | struct list_head resources; /* address space routed to this bus */ |
452 | struct resource busn_res; /* bus numbers routed to this bus */ | 453 | struct resource busn_res; /* bus numbers routed to this bus */ |