Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Hold pci_slot_mutex while searching bus->slots list

Previously, pci_setup_device() and similar functions searched the
pci_bus->slots list without any locking. It was possible for another
thread to update the list while we searched it.

Add pci_dev_assign_slot() to search the list while holding pci_slot_mutex.

[bhelgaas: changelog, fold in CONFIG_SYSFS fix]
Tested-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Yijing Wang and committed by
Bjorn Helgaas
017ffe64 67546762

+19 -15
+1 -5
arch/powerpc/kernel/pci_of_scan.c
··· 126 126 { 127 127 struct pci_dev *dev; 128 128 const char *type; 129 - struct pci_slot *slot; 130 129 131 130 dev = pci_alloc_dev(bus); 132 131 if (!dev) ··· 144 145 dev->needs_freset = 0; /* pcie fundamental reset required */ 145 146 set_pcie_port_type(dev); 146 147 147 - list_for_each_entry(slot, &dev->bus->slots, list) 148 - if (PCI_SLOT(dev->devfn) == slot->number) 149 - dev->slot = slot; 150 - 148 + pci_dev_assign_slot(dev); 151 149 dev->vendor = get_int_prop(node, "vendor-id", 0xffff); 152 150 dev->device = get_int_prop(node, "device-id", 0xffff); 153 151 dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
+1 -5
arch/sparc/kernel/pci.c
··· 249 249 struct pci_bus *bus, int devfn) 250 250 { 251 251 struct dev_archdata *sd; 252 - struct pci_slot *slot; 253 252 struct platform_device *op; 254 253 struct pci_dev *dev; 255 254 const char *type; ··· 289 290 dev->multifunction = 0; /* maybe a lie? */ 290 291 set_pcie_port_type(dev); 291 292 292 - list_for_each_entry(slot, &dev->bus->slots, list) 293 - if (PCI_SLOT(dev->devfn) == slot->number) 294 - dev->slot = slot; 295 - 293 + pci_dev_assign_slot(dev); 296 294 dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); 297 295 dev->device = of_getintprop_default(node, "device-id", 0xffff); 298 296 dev->subsystem_vendor =
+1 -5
drivers/pci/probe.c
··· 1133 1133 { 1134 1134 u32 class; 1135 1135 u8 hdr_type; 1136 - struct pci_slot *slot; 1137 1136 int pos = 0; 1138 1137 struct pci_bus_region region; 1139 1138 struct resource *res; ··· 1148 1149 dev->error_state = pci_channel_io_normal; 1149 1150 set_pcie_port_type(dev); 1150 1151 1151 - list_for_each_entry(slot, &dev->bus->slots, list) 1152 - if (PCI_SLOT(dev->devfn) == slot->number) 1153 - dev->slot = slot; 1154 - 1152 + pci_dev_assign_slot(dev); 1155 1153 /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) 1156 1154 set this higher, assuming the system even supports it. */ 1157 1155 dev->dma_mask = 0xffffffff;
+11
drivers/pci/slot.c
··· 194 194 return result; 195 195 } 196 196 197 + void pci_dev_assign_slot(struct pci_dev *dev) 198 + { 199 + struct pci_slot *slot; 200 + 201 + mutex_lock(&pci_slot_mutex); 202 + list_for_each_entry(slot, &dev->bus->slots, list) 203 + if (PCI_SLOT(dev->devfn) == slot->number) 204 + dev->slot = slot; 205 + mutex_unlock(&pci_slot_mutex); 206 + } 207 + 197 208 static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) 198 209 { 199 210 struct pci_slot *slot;
+5
include/linux/pci.h
··· 798 798 const char *name, 799 799 struct hotplug_slot *hotplug); 800 800 void pci_destroy_slot(struct pci_slot *slot); 801 + #ifdef CONFIG_SYSFS 802 + void pci_dev_assign_slot(struct pci_dev *dev); 803 + #else 804 + static inline void pci_dev_assign_slot(struct pci_dev *dev) { } 805 + #endif 801 806 int pci_scan_slot(struct pci_bus *bus, int devfn); 802 807 struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); 803 808 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);