aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2007-06-19 16:08:00 +1000
committerPaul Mackerras <paulus@samba.org>2007-07-10 21:53:47 +1000
commit6a281856c02d2291df2f7d9df5bfdee2e7bdd747 (patch)
treef9dee0818d797edef6fdb59ddeb069883a7b191c /arch/powerpc/kernel/prom.c
parent[POWERPC] Generalise device_node flag interface (diff)
downloadlinux-dev-6a281856c02d2291df2f7d9df5bfdee2e7bdd747.tar.xz
linux-dev-6a281856c02d2291df2f7d9df5bfdee2e7bdd747.zip
[POWERPC] Add a warning to help trackdown device_node refcounting bugs
When the refcount for a device node goes to 0, we call the destructor - of_node_release(). This should only happen if we've already detached the node from the device tree. So add a flag OF_DETACHED which tracks detached-ness, and if we find ourselves in of_node_release() without it set, issue a warning and don't free the device_node. To avoid warning continuously reinitialise the kref to a sane value. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r--arch/powerpc/kernel/prom.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index bcd1c5ed44a3..6d5e601097a0 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1375,8 +1375,17 @@ static void of_node_release(struct kref *kref)
struct device_node *node = kref_to_device_node(kref);
struct property *prop = node->properties;
+ /* We should never be releasing nodes that haven't been detached. */
+ if (!of_node_check_flag(node, OF_DETACHED)) {
+ printk("WARNING: Bad of_node_put() on %s\n", node->full_name);
+ dump_stack();
+ kref_init(&node->kref);
+ return;
+ }
+
if (!of_node_check_flag(node, OF_DYNAMIC))
return;
+
while (prop) {
struct property *next = prop->next;
kfree(prop->name);
@@ -1457,6 +1466,8 @@ void of_detach_node(const struct device_node *np)
prevsib->sibling = np->sibling;
}
+ of_node_set_flag(np, OF_DETACHED);
+
out_unlock:
write_unlock(&devtree_lock);
}