Subject: Re: [PATCH net-2.6] Re: rib_trie / Fix inflate_threshold_root. Now=15 size=11 bits

From: Jarek Poplawski <[email-masked]>
Date: Mon, 29 Jun 2009 10:47:03 +0000

On Mon, Jun 29, 2009 at 11:51:52AM +0200, Paweł Staszewski wrote:
> I apply this patch
>
> fib_triestats in attached file :)

Great! But it would be nice to check if this (accidentally ;-) might
fix the previous problem, so I attach below the patch with "manual
RCU", which btw. (or even more important) should verify RCU use here.

It should be applied on top of this last "Fix..., part3". And
again: it's quite probable it can fail, so with caution, no hurry
(it can wait for quiet time)...

Many thanks,
Jarek P.
--------------------> (synchronize_rcu take 4)

diff -Nurp a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
--- a/net/ipv4/fib_trie.c	2009-06-29 10:00:14.000000000 +0000
+++ b/net/ipv4/fib_trie.c	2009-06-29 10:04:22.000000000 +0000
@@ -366,6 +366,17 @@ static void __tnode_vfree(struct work_st
 	vfree(tn);
 }
 
+static void __tnode_free(struct tnode *tn)
+{
+	size_t size = sizeof(struct tnode) +
+		      (sizeof(struct node *) << tn->bits);
+
+	if (size <= PAGE_SIZE)
+		kfree(tn);
+	else
+		vfree(tn);
+}
+
 static void __tnode_free_rcu(struct rcu_head *head)
 {
 	struct tnode *tn = container_of(head, struct tnode, rcu);
@@ -402,7 +413,7 @@ static void tnode_free_flush(void)
 	while ((tn = tnode_free_head)) {
 		tnode_free_head = tn->tnode_free;
 		tn->tnode_free = NULL;
-		tnode_free(tn);
+		__tnode_free(tn);
 	}
 }
 
@@ -1021,21 +1032,27 @@ static void trie_rebalance(struct trie *
 				      (struct node *)tn, wasfull);
 
 		tp = node_parent((struct node *) tn);
-		if (!tp)
+		if (!tp) {
 			rcu_assign_pointer(t->trie, (struct node *)tn);
-
-		tnode_free_flush();
-		if (!tp)
 			break;
+		}
 		tn = tp;
 	}
 
+	if (tnode_free_head) {
+		synchronize_rcu();
+		tnode_free_flush();
+	}
+
 	/* Handle last (top) tnode */
-	if (IS_TNODE(tn))
+	if (IS_TNODE(tn)) {
 		tn = (struct tnode *)resize(t, (struct tnode *)tn);
-
-	rcu_assign_pointer(t->trie, (struct node *)tn);
-	tnode_free_flush();
+		rcu_assign_pointer(t->trie, (struct node *)tn);
+		synchronize_rcu();
+		tnode_free_flush();
+	} else {
+		rcu_assign_pointer(t->trie, (struct node *)tn);
+	}
 
 	return;
 }