From: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> commit 46d26819a5056f4831649c5887ad5c71a16d86f7 upstream. Sometimes it is better to unregister individual nodes instead of trying to do them all at once with software_node_unregister_nodes(), so create software_node_unregister() so that you can unregister them one at a time. This is especially important when creating nodes in a hierarchy, with parent -> children representations. Children always need to be removed before a parent is, as the swnode logic assumes this is going to be the case. Fix up the lib/test_printf.c fwnode_pointer() test which to use this new function as it had the problem of tearing things down in the backwards order. Fixes: f1ce39df508d ("lib/test_printf: Add tests for %pfw printk modifier") Cc: stable <stable@xxxxxxxxxxxxxxx> Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> Cc: Brendan Higgins <brendanhiggins@xxxxxxxxxx> Cc: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> Cc: Petr Mladek <pmladek@xxxxxxxx> Cc: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> Cc: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx> Cc: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx> Cc: Sergey Senozhatsky <sergey.senozhatsky@xxxxxxxxx> Cc: Steven Rostedt <rostedt@xxxxxxxxxxx> Reported-by: Naresh Kamboju <naresh.kamboju@xxxxxxxxxx> Reported-by: kernel test robot <rong.a.chen@xxxxxxxxx> Reported-by: Randy Dunlap <rdunlap@xxxxxxxxxxxxx> Tested-by: Petr Mladek <pmladek@xxxxxxxx> Tested-by: Randy Dunlap <rdunlap@xxxxxxxxxxxxx> Tested-by: Guenter Roeck <linux@xxxxxxxxxxxx> Reviewed-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> Acked-by: Randy Dunlap <rdunlap@xxxxxxxxxxxxx> Link: https://lore.kernel.org/r/20200524153041.2361-1-gregkh@xxxxxxxxxxxxxxxxxxx Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/base/swnode.c | 27 +++++++++++++++++++++------ include/linux/property.h | 1 + lib/test_printf.c | 4 +++- 3 files changed, 25 insertions(+), 7 deletions(-) --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -712,17 +712,18 @@ EXPORT_SYMBOL_GPL(software_node_register * @nodes: Zero terminated array of software nodes to be unregistered * * Unregister multiple software nodes at once. + * + * NOTE: Be careful using this call if the nodes had parent pointers set up in + * them before registering. If so, it is wiser to remove the nodes + * individually, in the correct order (child before parent) instead of relying + * on the sequential order of the list of nodes in the array. */ void software_node_unregister_nodes(const struct software_node *nodes) { - struct swnode *swnode; int i; - for (i = 0; nodes[i].name; i++) { - swnode = software_node_to_swnode(&nodes[i]); - if (swnode) - fwnode_remove_software_node(&swnode->fwnode); - } + for (i = 0; nodes[i].name; i++) + software_node_unregister(&nodes[i]); } EXPORT_SYMBOL_GPL(software_node_unregister_nodes); @@ -741,6 +742,20 @@ int software_node_register(const struct } EXPORT_SYMBOL_GPL(software_node_register); +/** + * software_node_unregister - Unregister static software node + * @node: The software node to be unregistered + */ +void software_node_unregister(const struct software_node *node) +{ + struct swnode *swnode; + + swnode = software_node_to_swnode(node); + if (swnode) + fwnode_remove_software_node(&swnode->fwnode); +} +EXPORT_SYMBOL_GPL(software_node_unregister); + struct fwnode_handle * fwnode_create_software_node(const struct property_entry *properties, const struct fwnode_handle *parent) --- a/include/linux/property.h +++ b/include/linux/property.h @@ -441,6 +441,7 @@ int software_node_register_nodes(const s void software_node_unregister_nodes(const struct software_node *nodes); int software_node_register(const struct software_node *node); +void software_node_unregister(const struct software_node *node); int software_node_notify(struct device *dev, unsigned long action); --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -637,7 +637,9 @@ static void __init fwnode_pointer(void) test(second_name, "%pfwP", software_node_fwnode(&softnodes[1])); test(third_name, "%pfwP", software_node_fwnode(&softnodes[2])); - software_node_unregister_nodes(softnodes); + software_node_unregister(&softnodes[2]); + software_node_unregister(&softnodes[1]); + software_node_unregister(&softnodes[0]); } static void __init