diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-10 15:22:18 +0100 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-01-13 17:49:49 -0700 |
commit | 9d16947b75831acd317ab9a53e0e94d160731d33 (patch) | |
tree | 6eeee1ae3a6864ceaae7ba60e7abc846f1acb0a9 /drivers/pci/remove.c | |
parent | a870614a5371f8e36676e9bb2e089f4121976135 (diff) | |
download | linux-stable-9d16947b75831acd317ab9a53e0e94d160731d33.tar.gz linux-stable-9d16947b75831acd317ab9a53e0e94d160731d33.tar.bz2 linux-stable-9d16947b75831acd317ab9a53e0e94d160731d33.zip |
PCI: Add global pci_lock_rescan_remove()
There are multiple PCI device addition and removal code paths that may be
run concurrently with the generic PCI bus rescan and device removal that
can be triggered via sysfs. If that happens, it may lead to multiple
different, potentially dangerous race conditions.
The most straightforward way to address those problems is to run
the code in question under the same lock that is used by the
generic rescan/remove code in pci-sysfs.c. To prepare for those
changes, move the definition of the global PCI remove/rescan lock
to probe.c and provide global wrappers, pci_lock_rescan_remove()
and pci_unlock_rescan_remove(), allowing drivers to manipulate
that lock. Also provide pci_stop_and_remove_bus_device_locked()
for the callers of pci_stop_and_remove_bus_device() who only need
to hold the rescan/remove lock around it.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/remove.c')
-rw-r--r-- | drivers/pci/remove.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index f452148e6d55..10fa13f9e309 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -95,6 +95,14 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev) } EXPORT_SYMBOL(pci_stop_and_remove_bus_device); +void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev) +{ + pci_lock_rescan_remove(); + pci_stop_and_remove_bus_device(dev); + pci_unlock_rescan_remove(); +} +EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked); + void pci_stop_root_bus(struct pci_bus *bus) { struct pci_dev *child, *tmp; |