Skip to content

Commit 5ab894a

Browse files
jhnikularafaeljw
authored andcommitted
device property: Track owner device of device property
Deletion of subdevice will remove device properties associated to parent when they share the same firmware node after commit 478573c (driver core: Don't leak secondary fwnode on device removal). This was observed with a driver adding subdevice that driver wasn't able to read device properties after rmmod/modprobe cycle. Consider the lifecycle of it: parent device registration ACPI_COMPANION_SET() device_add_properties() pset_copy_set() set_secondary_fwnode(dev, &p->fwnode) device_add() parent probe read device properties ACPI_COMPANION_SET(subdevice, ACPI_COMPANION(parent)) device_add(subdevice) parent remove device_del(subdevice) device_remove_properties() set_secondary_fwnode(dev, NULL); pset_free() Parent device will have its primary firmware node pointing to an ACPI node and secondary firmware node point to device properties. ACPI_COMPANION_SET() call in parent probe will set the subdevice's firmware node to point to the same 'struct fwnode_handle' and the associated secondary firmware node, i.e. the device properties as the parent. When subdevice is deleted in parent remove that will remove those device properties and attempt to read device properties in next parent probe call will fail. Fix this by tracking the owner device of device properties and delete them only when owner device is being deleted. Fixes: 478573c (driver core: Don't leak secondary fwnode on device removal) Cc: 4.9+ <[email protected]> # 4.9+ Signed-off-by: Jarkko Nikula <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 8a5776a commit 5ab894a

File tree

1 file changed

+9
-6
lines changed

1 file changed

+9
-6
lines changed

drivers/base/property.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/phy.h>
2222

2323
struct property_set {
24+
struct device *dev;
2425
struct fwnode_handle fwnode;
2526
const struct property_entry *properties;
2627
};
@@ -891,6 +892,7 @@ static struct property_set *pset_copy_set(const struct property_set *pset)
891892
void device_remove_properties(struct device *dev)
892893
{
893894
struct fwnode_handle *fwnode;
895+
struct property_set *pset;
894896

895897
fwnode = dev_fwnode(dev);
896898
if (!fwnode)
@@ -900,16 +902,16 @@ void device_remove_properties(struct device *dev)
900902
* the pset. If there is no real firmware node (ACPI/DT) primary
901903
* will hold the pset.
902904
*/
903-
if (is_pset_node(fwnode)) {
905+
pset = to_pset_node(fwnode);
906+
if (pset) {
904907
set_primary_fwnode(dev, NULL);
905-
pset_free_set(to_pset_node(fwnode));
906908
} else {
907-
fwnode = fwnode->secondary;
908-
if (!IS_ERR(fwnode) && is_pset_node(fwnode)) {
909+
pset = to_pset_node(fwnode->secondary);
910+
if (pset && dev == pset->dev)
909911
set_secondary_fwnode(dev, NULL);
910-
pset_free_set(to_pset_node(fwnode));
911-
}
912912
}
913+
if (pset && dev == pset->dev)
914+
pset_free_set(pset);
913915
}
914916
EXPORT_SYMBOL_GPL(device_remove_properties);
915917

@@ -938,6 +940,7 @@ int device_add_properties(struct device *dev,
938940

939941
p->fwnode.ops = &pset_fwnode_ops;
940942
set_secondary_fwnode(dev, &p->fwnode);
943+
p->dev = dev;
941944
return 0;
942945
}
943946
EXPORT_SYMBOL_GPL(device_add_properties);

0 commit comments

Comments
 (0)