Skip to content

Commit

Permalink
PCI: Make pci_stop_dev() concurrent safe
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
keithbusch authored and bjorn-helgaas committed Nov 11, 2024
1 parent 9852d85 commit 93093ea
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 13 deletions.
2 changes: 1 addition & 1 deletion drivers/pci/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ void pci_bus_add_device(struct pci_dev *dev)
if (retval < 0 && retval != -EPROBE_DEFER)
pci_warn(dev, "device attach failed (%d)\n", retval);

pci_dev_assign_added(dev, true);
pci_dev_assign_added(dev);

if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
Expand Down
11 changes: 9 additions & 2 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,16 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
#define PCI_DPC_RECOVERED 1
#define PCI_DPC_RECOVERING 2

static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
static inline void pci_dev_assign_added(struct pci_dev *dev)
{
assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
smp_mb__before_atomic();
set_bit(PCI_DEV_ADDED, &dev->priv_flags);
smp_mb__after_atomic();
}

static inline bool pci_dev_test_and_clear_added(struct pci_dev *dev)
{
return test_and_clear_bit(PCI_DEV_ADDED, &dev->priv_flags);
}

static inline bool pci_dev_is_added(const struct pci_dev *dev)
Expand Down
19 changes: 9 additions & 10 deletions drivers/pci/remove.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 93093ea

Please sign in to comment.