diff mbox

[14/29] radix-tree: Move rcu_head into a union with private_list

Message ID 1479341856-30320-53-git-send-email-mawilcox@linuxonhyperv.com (mailing list archive)
State New, archived
Headers show

Commit Message

Matthew Wilcox Nov. 17, 2016, 12:17 a.m. UTC
From: Matthew Wilcox <willy@infradead.org>

I want to be able to reference node->parent after freeing node.
Currently node->parent is in a union with rcu_head, so it is overwritten
when the node is put on the RCU list.  We know that private_list is not
referenced after the node is freed, so it is safe for these two members
to share space.

Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
 include/linux/radix-tree.h | 14 ++++----------
 lib/radix-tree.c           |  1 +
 2 files changed, 5 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 8ffb051..66fb8c0 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -88,18 +88,12 @@  struct radix_tree_node {
 	unsigned char	shift;	/* Bits remaining in each slot */
 	unsigned char	offset;	/* Slot offset in parent */
 	unsigned int	count;
+	struct radix_tree_node *parent;		/* Used when ascending tree */
+	void *private_data;			/* For tree user */
 	union {
-		struct {
-			/* Used when ascending tree */
-			struct radix_tree_node *parent;
-			/* For tree user */
-			void *private_data;
-		};
-		/* Used when freeing node */
-		struct rcu_head	rcu_head;
+		struct list_head private_list;	/* For tree user */
+		struct rcu_head	rcu_head;	/* Used when freeing node */
 	};
-	/* For tree user */
-	struct list_head private_list;
 	void __rcu	*slots[RADIX_TREE_MAP_SIZE];
 	unsigned long	tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
 };
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index e917c56..baf4ba1 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -325,6 +325,7 @@  static void radix_tree_node_rcu_free(struct rcu_head *head)
 	 */
 	memset(node->slots, 0, sizeof(node->slots));
 	memset(node->tags, 0, sizeof(node->tags));
+	INIT_LIST_HEAD(&node->private_list);
 
 	kmem_cache_free(radix_tree_node_cachep, node);
 }