PCI: Protect pci_reassign_bridge_resources() against concurrent addition/removal
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 25 Sep 2019 01:16:55 +0000 (11:16 +1000)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 30 Sep 2019 19:53:31 +0000 (14:53 -0500)
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>
drivers/pci/setup-bus.c

index e7dbe21..f1c5194 100644 (file)
@@ -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;
 }