[PATCH 3/3] OF: kobj ops should only happen on attached nodes

From: Pantelis Antoniou
Date: Tue Dec 10 2013 - 09:14:53 EST


kobject operation should only take place on already attached (live)
device nodes. The same restriction applies to the invocation of
device tree notifiers.

Introduce a simple of_node_is_attached() test which tests whether
the given node is attached via means of the allnodes member.

Signed-off-by: Pantelis Antoniou <panto@xxxxxxxxxxxxxxxxxxxxxxx>
---
drivers/of/base.c | 87 ++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 64 insertions(+), 23 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index db0de86..c6299bd 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -89,6 +89,13 @@ int __weak of_node_to_nid(struct device_node *np)
#endif

#if defined(CONFIG_OF_DYNAMIC)
+
+/* simple test for figuring out if node is attached */
+static inline int of_node_is_attached(struct device_node *np)
+{
+ return np && np->allnodes == &of_allnodes;
+}
+
/**
* of_node_get - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to
@@ -98,7 +105,7 @@ int __weak of_node_to_nid(struct device_node *np)
*/
struct device_node *of_node_get(struct device_node *node)
{
- if (node && of_kset)
+ if (node && of_kset && of_node_is_attached(node))
kobject_get(&node->kobj);
return node;
}
@@ -156,7 +163,7 @@ static void of_node_release(struct kobject *kobj)
*/
void of_node_put(struct device_node *node)
{
- if (node && of_kset)
+ if (node && of_kset && of_node_is_attached(node))
kobject_put(&node->kobj);
}
EXPORT_SYMBOL(of_node_put);
@@ -210,6 +217,10 @@ static int __of_add_property(struct device_node *np, struct property *pp)
if (!of_kset)
return 0;

+ /* don't do anything with a detached node */
+ if (!of_node_is_attached(np))
+ return 0;
+
/* Important: Don't leak passwords */
secure = strncmp(pp->name, "security-", 9) == 0;

@@ -235,6 +246,9 @@ static int __of_node_add(struct device_node *np)
if (!of_kset)
return 0;

+ if (!of_node_is_attached(np))
+ return 0;
+
np->kobj.kset = of_kset;
if (!np->parent) {
/* Nodes without parents are new top level trees */
@@ -259,6 +273,9 @@ int of_node_add(struct device_node *np)
{
int rc = 0;

+ if (!of_node_is_attached(np))
+ return 0;
+
/* fake the return while of_init is not yet called */
mutex_lock(&of_aliases_mutex);
kobject_init(&np->kobj, &of_node_ktype);
@@ -274,10 +291,16 @@ static void of_node_remove(struct device_node *np)
{
struct property *pp;

+ /* don't do anything with a detached node */
+ if (!of_node_is_attached(np))
+ return;
+
for_each_property_of_node(np, pp)
sysfs_remove_bin_file(&np->kobj, &pp->attr);

kobject_del(&np->kobj);
+
+ of_node_put(np);
}
#endif

@@ -1626,9 +1649,11 @@ int of_add_property(struct device_node *np, struct property *prop)
unsigned long flags;
int rc;

- rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop);
- if (rc)
- return rc;
+ if (of_node_is_attached(np)) {
+ rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop);
+ if (rc)
+ return rc;
+ }

prop->next = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
@@ -1664,9 +1689,11 @@ int of_remove_property(struct device_node *np, struct property *prop)
int found = 0;
int rc;

- rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
- if (rc)
- return rc;
+ if (of_node_is_attached(np)) {
+ rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
+ if (rc)
+ return rc;
+ }

raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
@@ -1686,7 +1713,8 @@ int of_remove_property(struct device_node *np, struct property *prop)
if (!found)
return -ENODEV;

- sysfs_remove_bin_file(&np->kobj, &prop->attr);
+ if (of_node_is_attached(np))
+ sysfs_remove_bin_file(&np->kobj, &prop->attr);

return 0;
}
@@ -1706,9 +1734,11 @@ int of_update_property(struct device_node *np, struct property *newprop)
unsigned long flags;
int rc, found = 0;

- rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
- if (rc)
- return rc;
+ if (of_node_is_attached(np)) {
+ rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
+ if (rc)
+ return rc;
+ }

if (!newprop->name)
return -EINVAL;
@@ -1736,9 +1766,11 @@ int of_update_property(struct device_node *np, struct property *newprop)
if (!found)
return -ENODEV;

- /* Update the sysfs attribute */
- sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
- __of_add_property(np, newprop);
+ if (of_node_is_attached(np)) {
+ /* Update the sysfs attribute */
+ sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+ __of_add_property(np, newprop);
+ }

return 0;
}
@@ -1782,10 +1814,6 @@ int of_attach_node(struct device_node *np)
unsigned long flags;
int rc;

- rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np);
- if (rc)
- return rc;
-
raw_spin_lock_irqsave(&devtree_lock, flags);
np->sibling = np->parent->child;
np->allnext = of_allnodes;
@@ -1794,7 +1822,18 @@ int of_attach_node(struct device_node *np)
np->allnodes = &of_allnodes;
raw_spin_unlock_irqrestore(&devtree_lock, flags);

- of_node_add(np);
+ rc = of_node_add(np);
+ if (rc != 0)
+ goto err_detach;
+
+ rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np);
+ if (rc)
+ goto err_detach;
+
+ return 0;
+
+err_detach:
+ of_node_remove(np);
return 0;
}

@@ -1810,9 +1849,11 @@ int of_detach_node(struct device_node *np)
unsigned long flags;
int rc = 0;

- rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
- if (rc)
- return rc;
+ if (of_node_is_attached(np)) {
+ rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
+ if (rc)
+ return rc;
+ }

raw_spin_lock_irqsave(&devtree_lock, flags);

--
1.7.12

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/