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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to