From: Paul Mackerras This patch is from Nathan Lynch . This changes struct device_node and associated code to use the kref api for object refcounting and freeing. I've given it some testing on pSeries with cpu add/remove and verified that the release function works. The change is somewhat cosmetic but it does make the code easier to understand... at least I think so =) The only real change is that the refcount on all device_nodes is initialized at 1, and the device node is freed when the refcount reaches 0 (of_remove_node has the extra "put" to ensure that this happens). This lets us get rid of the OF_STALE flag and macros in prom.h. Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras Signed-off-by: Andrew Morton --- 25-akpm/arch/ppc64/kernel/prom.c | 50 ++++++++++++++++++--------------------- 25-akpm/include/asm-ppc64/prom.h | 5 --- 2 files changed, 25 insertions(+), 30 deletions(-) diff -puN arch/ppc64/kernel/prom.c~ppc64-use-kref-for-device_node-refcounting arch/ppc64/kernel/prom.c --- 25/arch/ppc64/kernel/prom.c~ppc64-use-kref-for-device_node-refcounting 2005-01-23 00:51:30.167090144 -0800 +++ 25-akpm/arch/ppc64/kernel/prom.c 2005-01-23 00:51:30.175088928 -0800 @@ -717,6 +717,7 @@ static unsigned long __init unflatten_dt dad->next->sibling = np; dad->next = np; } + kref_init(&np->kref); } while(1) { u32 sz, noff; @@ -1475,24 +1476,31 @@ EXPORT_SYMBOL(of_get_next_child); * @node: Node to inc refcount, NULL is supported to * simplify writing of callers * - * Returns the node itself or NULL if gone. + * Returns node. */ struct device_node *of_node_get(struct device_node *node) { - if (node && !OF_IS_STALE(node)) { - atomic_inc(&node->_users); - return node; - } - return NULL; + if (node) + kref_get(&node->kref); + return node; } EXPORT_SYMBOL(of_node_get); +static inline struct device_node * kref_to_device_node(struct kref *kref) +{ + return container_of(kref, struct device_node, kref); +} + /** - * of_node_cleanup - release a dynamically allocated node - * @arg: Node to be released + * of_node_release - release a dynamically allocated node + * @kref: kref element of the node to be released + * + * In of_node_put() this function is passed to kref_put() + * as the destructor. */ -static void of_node_cleanup(struct device_node *node) +static void of_node_release(struct kref *kref) { + struct device_node *node = kref_to_device_node(kref); struct property *prop = node->properties; if (!OF_IS_DYNAMIC(node)) @@ -1518,19 +1526,8 @@ static void of_node_cleanup(struct devic */ void of_node_put(struct device_node *node) { - if (!node) - return; - - WARN_ON(0 == atomic_read(&node->_users)); - - if (OF_IS_STALE(node)) { - if (atomic_dec_and_test(&node->_users)) { - of_node_cleanup(node); - return; - } - } - else - atomic_dec(&node->_users); + if (node) + kref_put(&node->kref, of_node_release); } EXPORT_SYMBOL(of_node_put); @@ -1773,7 +1770,7 @@ int of_add_node(const char *path, struct np->properties = proplist; OF_MARK_DYNAMIC(np); - of_node_get(np); + kref_init(&np->kref); np->parent = derive_parent(path); if (!np->parent) { kfree(np); @@ -1809,8 +1806,9 @@ static void of_cleanup_node(struct devic } /* - * Remove an OF device node from the system. - * Caller should have already "gotten" np. + * "Unplug" a node from the device tree. The caller must hold + * a reference to the node. The memory associated with the node + * is not freed until its refcount goes to zero. */ int of_remove_node(struct device_node *np) { @@ -1828,7 +1826,6 @@ int of_remove_node(struct device_node *n of_cleanup_node(np); write_lock(&devtree_lock); - OF_MARK_STALE(np); remove_node_proc_entries(np); if (allnodes == np) allnodes = np->allnext; @@ -1853,6 +1850,7 @@ int of_remove_node(struct device_node *n } write_unlock(&devtree_lock); of_node_put(parent); + of_node_put(np); /* Must decrement the refcount */ return 0; } diff -puN include/asm-ppc64/prom.h~ppc64-use-kref-for-device_node-refcounting include/asm-ppc64/prom.h --- 25/include/asm-ppc64/prom.h~ppc64-use-kref-for-device_node-refcounting 2005-01-23 00:51:30.170089688 -0800 +++ 25-akpm/include/asm-ppc64/prom.h 2005-01-23 00:51:30.176088776 -0800 @@ -149,18 +149,15 @@ struct device_node { struct proc_dir_entry *pde; /* this node's proc directory */ struct proc_dir_entry *name_link; /* name symlink */ struct proc_dir_entry *addr_link; /* addr symlink */ - atomic_t _users; /* reference count */ + struct kref kref; unsigned long _flags; }; extern struct device_node *of_chosen; /* flag descriptions */ -#define OF_STALE 0 /* node is slated for deletion */ #define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ -#define OF_IS_STALE(x) test_bit(OF_STALE, &x->_flags) -#define OF_MARK_STALE(x) set_bit(OF_STALE, &x->_flags) #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) _