aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2019-09-25 11:16:55 +1000
committerBjorn Helgaas <bhelgaas@google.com>2019-09-30 14:53:31 -0500
commitfb794a708a71d7c6af55f04cc4ed2d5823fb8b33 (patch)
tree4343000cc3fd5f453cd8a6943330ad1a25840ccb
parentLinux 5.4-rc1 (diff)
downloadlinux-dev-fb794a708a71d7c6af55f04cc4ed2d5823fb8b33.tar.xz
linux-dev-fb794a708a71d7c6af55f04cc4ed2d5823fb8b33.zip
PCI: Protect pci_reassign_bridge_resources() against concurrent addition/removal
pci_reassign_bridge_resources() can be called by pci_resize_resource() at runtime, it walks the PCI tree up and down, and it isn't currently protected against any changes or hotplug operation. Hold the pci_bus_sem to protect it. Link: https://lore.kernel.org/r/7339fd73ccaf58552737ab10008333fd9f7723f2.camel@kernel.crashing.org Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/setup-bus.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index e7dbe21705ba..f1c51943bdfc 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2066,6 +2066,8 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
unsigned int i;
int ret;
+ down_read(&pci_bus_sem);
+
/* Walk to the root hub, releasing bridge BARs when possible */
next = bridge;
do {
@@ -2100,8 +2102,10 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
next = bridge->bus ? bridge->bus->self : NULL;
} while (next);
- if (list_empty(&saved))
+ if (list_empty(&saved)) {
+ up_read(&pci_bus_sem);
return -ENOENT;
+ }
__pci_bus_size_bridges(bridge->subordinate, &added);
__pci_bridge_assign_resources(bridge, &added, &failed);
@@ -2122,6 +2126,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
}
free_list(&saved);
+ up_read(&pci_bus_sem);
return 0;
cleanup:
@@ -2150,6 +2155,7 @@ cleanup:
pci_setup_bridge(bridge->subordinate);
}
free_list(&saved);
+ up_read(&pci_bus_sem);
return ret;
}