From: anton@samba.org Fixes for OF device tree update code, from Nathan Lynch --- arch/ppc64/kernel/proc_ppc64.c | 6 +--- arch/ppc64/kernel/prom.c | 53 +++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff -puN arch/ppc64/kernel/proc_ppc64.c~ppc64-of_removal_fix arch/ppc64/kernel/proc_ppc64.c --- 25/arch/ppc64/kernel/proc_ppc64.c~ppc64-of_removal_fix 2004-02-04 00:12:03.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/proc_ppc64.c 2004-02-04 00:12:03.000000000 -0800 @@ -268,12 +268,10 @@ out: static int do_remove_node(char *buf) { struct device_node *node; - int rv = 0; + int rv = -ENODEV; if ((node = of_find_node_by_path(buf))) - of_remove_node(node); - else - rv = -ENODEV; + rv = of_remove_node(node); of_node_put(node); return rv; diff -puN arch/ppc64/kernel/prom.c~ppc64-of_removal_fix arch/ppc64/kernel/prom.c --- 25/arch/ppc64/kernel/prom.c~ppc64-of_removal_fix 2004-02-04 00:12:03.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/prom.c 2004-02-04 00:12:03.000000000 -0800 @@ -2507,29 +2507,48 @@ int of_add_node(const char *path, struct /* * Remove an OF device node from the system. + * Caller should have already "gotten" np. */ int of_remove_node(struct device_node *np) { struct device_node *parent, *child; parent = of_get_parent(np); - child = of_get_next_child(np, NULL); - if (child && !child->child && !child->sibling) { - /* For now, we will allow removal of a - * node with one and only one child, so - * that we can support removing a slot with - * an IOA in it. More general support for - * subtree removal to be implemented later, if - * necessary. - */ - of_remove_node(child); - } - else if (child) { - of_node_put(child); - of_node_put(parent); + + if (!parent) return -EINVAL; + + /* Make sure we are not recursively removing + * more than one level of nodes. We need to + * allow this so we can remove a slot containing + * an IOA. + */ + for (child = of_get_next_child(np, NULL); + child != NULL; + child = of_get_next_child(np, child)) { + struct device_node *grandchild; + + if ((grandchild = of_get_next_child(child, NULL))) { + /* Too deep */ + of_node_put(grandchild); + of_node_put(child); + return -EBUSY; + } + } + + /* Now that we're reasonably sure that we won't + * overflow our stack, remove any children of np. + */ + for (child = of_get_next_child(np, NULL); + child != NULL; + child = of_get_next_child(np, child)) { + int rc; + + if ((rc = of_remove_node(child))) { + of_node_put(child); + return rc; + } } - of_node_put(child); write_lock(&devtree_lock); OF_MARK_STALE(np); @@ -2545,8 +2564,8 @@ int of_remove_node(struct device_node *n prev->allnext = np->allnext; } - if (np->parent->child == np) - np->parent->child = np->sibling; + if (parent->child == np) + parent->child = np->sibling; else { struct device_node *prevsib; for (prevsib = np->parent->child; _