[PATCH] use kref for device_node refcounting

Nathan Lynch nathanl at austin.ibm.com
Fri Jan 14 18:05:52 EST 2005


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 <nathanl at austin.ibm.com>


---


diff -puN arch/ppc64/kernel/prom.c~ppc64-device_node-use-kref arch/ppc64/kernel/prom.c
--- linux-2.6.11-rc1-bk1/arch/ppc64/kernel/prom.c~ppc64-device_node-use-kref	2005-01-13 19:04:09.000000000 -0600
+++ linux-2.6.11-rc1-bk1-nathanl/arch/ppc64/kernel/prom.c	2005-01-14 00:24:04.000000000 -0600
@@ -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);
@@ -1808,8 +1805,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)
 {
@@ -1827,7 +1825,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;
@@ -1852,6 +1849,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-device_node-use-kref include/asm-ppc64/prom.h
--- linux-2.6.11-rc1-bk1/include/asm-ppc64/prom.h~ppc64-device_node-use-kref	2005-01-13 19:04:09.000000000 -0600
+++ linux-2.6.11-rc1-bk1-nathanl/include/asm-ppc64/prom.h	2005-01-13 19:04:09.000000000 -0600
@@ -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)
 

_





More information about the Linuxppc64-dev mailing list