Skip to content

Commit 5c8418c

Browse files
computersforpeacebjorn-helgaas
authored andcommitted
PCI/pwrctrl: Unregister platform device only if one actually exists
If a PCI device has an associated device_node with power supplies, pci_bus_add_device() creates platform devices for use by pwrctrl. When the PCI device is removed, pci_stop_dev() uses of_find_device_by_node() to locate the related platform device, then unregisters it. But when we remove a PCI device with no associated device node, dev_of_node(dev) is NULL, and of_find_device_by_node(NULL) returns the first device with "dev->of_node == NULL". The result is that we (a) mistakenly unregister a completely unrelated platform device, leading to issues like the first trace below, and (b) dereference the NULL pointer from dev_of_node() when clearing OF_POPULATED, as in the second trace. Unregister a platform device only if there is one associated with this PCI device. This resolves issues seen when doing: # echo 1 > /sys/bus/pci/devices/.../remove Sample issue from unregistering the wrong platform device: WARNING: CPU: 0 PID: 5095 at drivers/regulator/core.c:5885 regulator_unregister+0x140/0x160 Call trace: regulator_unregister+0x140/0x160 devm_rdev_release+0x1c/0x30 release_nodes+0x68/0x100 devres_release_all+0x98/0xf8 device_unbind_cleanup+0x20/0x70 device_release_driver_internal+0x1f4/0x240 device_release_driver+0x20/0x40 bus_remove_device+0xd8/0x170 device_del+0x154/0x380 device_unregister+0x28/0x88 of_device_unregister+0x1c/0x30 pci_stop_bus_device+0x154/0x1b0 pci_stop_and_remove_bus_device_locked+0x28/0x48 remove_store+0xa0/0xb8 dev_attr_store+0x20/0x40 sysfs_kf_write+0x4c/0x68 Later NULL pointer dereference for of_node_clear_flag(NULL, OF_POPULATED): Unable to handle kernel NULL pointer dereference at virtual address 00000000000000c0 Call trace: pci_stop_bus_device+0x190/0x1b0 pci_stop_and_remove_bus_device_locked+0x28/0x48 remove_store+0xa0/0xb8 dev_attr_store+0x20/0x40 sysfs_kf_write+0x4c/0x68 Link: https://lore.kernel.org/r/[email protected] Fixes: 681725a ("PCI/pwrctl: Remove pwrctl device without iterating over all children of pwrctl parent") Reported-by: Saurabh Sengar <[email protected]> Closes: https://lore.kernel.org/r/[email protected] Signed-off-by: Brian Norris <[email protected]> [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas <[email protected]>
1 parent 1009926 commit 5c8418c

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

drivers/pci/remove.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@ static void pci_free_resources(struct pci_dev *dev)
1919

2020
static void pci_pwrctrl_unregister(struct device *dev)
2121
{
22+
struct device_node *np;
2223
struct platform_device *pdev;
2324

24-
pdev = of_find_device_by_node(dev_of_node(dev));
25+
np = dev_of_node(dev);
26+
if (!np)
27+
return;
28+
29+
pdev = of_find_device_by_node(np);
2530
if (!pdev)
2631
return;
2732

2833
of_device_unregister(pdev);
29-
of_node_clear_flag(dev_of_node(dev), OF_POPULATED);
34+
of_node_clear_flag(np, OF_POPULATED);
3035
}
3136

3237
static void pci_stop_dev(struct pci_dev *dev)

0 commit comments

Comments
 (0)