summaryrefslogtreecommitdiff
path: root/include/linux/pci.h
diff options
context:
space:
mode:
authorYijing Wang <wangyijing@huawei.com>2015-07-17 17:16:31 +0800
committerBjorn Helgaas <bhelgaas@google.com>2015-07-30 15:49:10 -0500
commit67546762978f523749eac157903e0b01c18e083a (patch)
tree646a5a8749dae0c3192d9db23dc4eb1f63f90f75 /include/linux/pci.h
parentac10836b681289f7e430e52b106a209bbdcaa75e (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.h3
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 {
struct list_head children; /* list of child buses */
struct list_head devices; /* list of devices on this bus */
struct pci_dev *self; /* bridge device as seen by parent */
- struct list_head slots; /* list of slots on this bus */
+ struct list_head slots; /* list of slots on this bus;
+ protected by pci_slot_mutex */
struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
struct list_head resources; /* address space routed to this bus */
struct resource busn_res; /* bus numbers routed to this bus */