diff options
author | Keith Busch <kbusch@kernel.org> | 2024-10-23 00:48:47 +0200 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2024-11-11 20:05:50 +0100 |
commit | 93093ea1f05928b123dae38b710631362bef1601 (patch) | |
tree | d4878a521c9687541a9b9c69da0e4ed8c70434b7 /drivers/pci/remove.c | |
parent | Linux 6.12-rc1 (diff) | |
download | linux-93093ea1f05928b123dae38b710631362bef1601.tar.xz linux-93093ea1f05928b123dae38b710631362bef1601.zip |
PCI: Make pci_stop_dev() concurrent safe
Use the atomic ADDED flag to ensure concurrent callers can't attempt to
stop the device multiple times. Callers should currently all be holding the
pci_rescan_remove_lock, so there shouldn't be an existing race. But that
global lock can cause lock dependency issues, so this is preparing to
reduce reliance on that lock by using the existing existing atomic bit ops.
Link: https://lore.kernel.org/r/20241022224851.340648-2-kbusch@meta.com
Signed-off-by: Keith Busch <kbusch@kernel.org>
[bhelgaas: squash https://lore.kernel.org/r/20241111180659.3321671-1-kbusch@meta.com]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to '')
-rw-r--r-- | drivers/pci/remove.c | 19 |
1 files changed, 9 insertions, 10 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index e4ce1145aa3e..78863f241a88 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -33,16 +33,15 @@ static void pci_stop_dev(struct pci_dev *dev) { pci_pme_active(dev, false); - if (pci_dev_is_added(dev)) { - device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev), - pci_pwrctl_unregister); - device_release_driver(&dev->dev); - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); - of_pci_remove_node(dev); - - pci_dev_assign_added(dev, false); - } + if (!pci_dev_test_and_clear_added(dev)) + return; + + device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev), + pci_pwrctl_unregister); + device_release_driver(&dev->dev); + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + of_pci_remove_node(dev); } static void pci_destroy_dev(struct pci_dev *dev) |