diff options
author | Robert Olsson <robert.olsson@its.uu.se> | 2009-05-21 18:20:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-21 18:20:59 -0400 |
commit | 3ed18d76d959e5cbfa5d70c8f7ba95476582a556 (patch) | |
tree | 9fbd15b820b43627440fd6961f687c30e8d4e130 /net | |
parent | 5b5f792a6a9a2f9ae812d151ed621f72e99b1725 (diff) |
ipv4: Fix oops with FIB_TRIE
It seems we can fix this by disabling preemption while we re-balance the
trie. This is with the CONFIG_CLASSIC_RCU. It's been stress-tested at high
loads continuesly taking a full BGP table up/down via iproute -batch.
Note. fib_trie is not updated for CONFIG_PREEMPT_RCU
Reported-by: Andrei Popa
Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fib_trie.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ec0ae490f0b6..33c7c85dfe40 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -986,9 +986,12 @@ fib_find_node(struct trie *t, u32 key) | |||
986 | static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | 986 | static struct node *trie_rebalance(struct trie *t, struct tnode *tn) |
987 | { | 987 | { |
988 | int wasfull; | 988 | int wasfull; |
989 | t_key cindex, key = tn->key; | 989 | t_key cindex, key; |
990 | struct tnode *tp; | 990 | struct tnode *tp; |
991 | 991 | ||
992 | preempt_disable(); | ||
993 | key = tn->key; | ||
994 | |||
992 | while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { | 995 | while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { |
993 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); | 996 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); |
994 | wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); | 997 | wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); |
@@ -1007,6 +1010,7 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | |||
1007 | if (IS_TNODE(tn)) | 1010 | if (IS_TNODE(tn)) |
1008 | tn = (struct tnode *)resize(t, (struct tnode *)tn); | 1011 | tn = (struct tnode *)resize(t, (struct tnode *)tn); |
1009 | 1012 | ||
1013 | preempt_enable(); | ||
1010 | return (struct node *)tn; | 1014 | return (struct node *)tn; |
1011 | } | 1015 | } |
1012 | 1016 | ||