Skip to content

Commit 93093ea

Browse files
keithbuschbjorn-helgaas
authored andcommitted
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/[email protected] Signed-off-by: Keith Busch <[email protected]> [bhelgaas: squash https://lore.kernel.org/r/[email protected]] Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]>
1 parent 9852d85 commit 93093ea

File tree

3 files changed

+19
-13
lines changed

3 files changed

+19
-13
lines changed

drivers/pci/bus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ void pci_bus_add_device(struct pci_dev *dev)
348348
if (retval < 0 && retval != -EPROBE_DEFER)
349349
pci_warn(dev, "device attach failed (%d)\n", retval);
350350

351-
pci_dev_assign_added(dev, true);
351+
pci_dev_assign_added(dev);
352352

353353
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
354354
retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,

drivers/pci/pci.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,16 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
470470
#define PCI_DPC_RECOVERED 1
471471
#define PCI_DPC_RECOVERING 2
472472

473-
static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
473+
static inline void pci_dev_assign_added(struct pci_dev *dev)
474474
{
475-
assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
475+
smp_mb__before_atomic();
476+
set_bit(PCI_DEV_ADDED, &dev->priv_flags);
477+
smp_mb__after_atomic();
478+
}
479+
480+
static inline bool pci_dev_test_and_clear_added(struct pci_dev *dev)
481+
{
482+
return test_and_clear_bit(PCI_DEV_ADDED, &dev->priv_flags);
476483
}
477484

478485
static inline bool pci_dev_is_added(const struct pci_dev *dev)

drivers/pci/remove.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,15 @@ static void pci_stop_dev(struct pci_dev *dev)
3333
{
3434
pci_pme_active(dev, false);
3535

36-
if (pci_dev_is_added(dev)) {
37-
device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
38-
pci_pwrctl_unregister);
39-
device_release_driver(&dev->dev);
40-
pci_proc_detach_device(dev);
41-
pci_remove_sysfs_dev_files(dev);
42-
of_pci_remove_node(dev);
43-
44-
pci_dev_assign_added(dev, false);
45-
}
36+
if (!pci_dev_test_and_clear_added(dev))
37+
return;
38+
39+
device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
40+
pci_pwrctl_unregister);
41+
device_release_driver(&dev->dev);
42+
pci_proc_detach_device(dev);
43+
pci_remove_sysfs_dev_files(dev);
44+
of_pci_remove_node(dev);
4645
}
4746

4847
static void pci_destroy_dev(struct pci_dev *dev)

0 commit comments

Comments
 (0)