[RFC PATCH] software node: Skip duplicated software_node sysfs

Qian Cai
2021-11-01T20:04:49Z

A recent commit allowed device_create_managed_software_node() to call
software_node_notify() which could generate duplicated "software_node"
sysfs files. For example,

"/devices/platform/808622B7:01/xhci-hcd.3.auto/software_node"

Since it was created earlier from another path,

sysfs_create_link
software_node_notify
device_add
platform_device_add
dwc3_host_init
dwc3_probe
platform_probe
really_probe.part.0
really_probe
__driver_probe_device
driver_probe_device
__driver_attach
bus_for_each_dev
driver_attach
bus_add_driver
driver_register
__platform_driver_register
dwc3_driver_init at drivers/usb/dwc3/core.c:2072
do_one_initcall

Fixed it by using sysfs_create_link_nowarn() in software_node_notify() to
avoid those bad messages during booting,

sysfs: cannot create duplicate filename '/devices/platform/808622B7:01/xhci-hcd.3.auto/software_node'
Call trace:
dump_backtrace
show_stack
dump_stack_lvl
dump_stack
sysfs_warn_dup
sysfs_do_create_link_sd.isra.0
sysfs_create_link
software_node_notify
device_create_managed_software_node
iort_named_component_init
iort_iommu_configure_id
acpi_dma_configure_id
platform_dma_configure
really_probe.part.0
really_probe
__driver_probe_device
driver_probe_device
__driver_attach
bus_for_each_dev
driver_attach
bus_add_driver
driver_register
__platform_driver_register
xhci_plat_init
do_one_initcall
kernel_init_freeable
kernel_init
ret_from_fork

Fixes: 5aeb05b27f81 ("software node: balance refcount for managed software nodes")
Signed-off-by: Qian Cai <quic_qiancai@quicinc.com>
---
drivers/base/swnode.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 4debcea4fb12..0a266c312aa3 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -1126,17 +1126,15 @@ void software_node_notify(struct device *dev)
if (!swnode)
return;

- ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
- if (ret)
+ ret = sysfs_create_link_nowarn(&dev->kobj, &swnode->kobj,
+ "software_node");
+ if (ret && ret != -EEXIST)
return;

- ret = sysfs_create_link(&swnode->kobj, &dev->kobj, dev_name(dev));
- if (ret) {
+ if (!sysfs_create_link(&swnode->kobj, &dev->kobj, dev_name(dev)))
+ kobject_get(&swnode->kobj);
+ else if (!ret)
sysfs_remove_link(&dev->kobj, "software_node");
- return;
- }
-
- kobject_get(&swnode->kobj);
}

void software_node_notify_remove(struct device *dev)
--
2.30.2