diff options
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 33c7c85dfe40..012cf5a68581 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -123,6 +123,7 @@ struct tnode { | |||
123 | union { | 123 | union { |
124 | struct rcu_head rcu; | 124 | struct rcu_head rcu; |
125 | struct work_struct work; | 125 | struct work_struct work; |
126 | struct tnode *tnode_free; | ||
126 | }; | 127 | }; |
127 | struct node *child[0]; | 128 | struct node *child[0]; |
128 | }; | 129 | }; |
@@ -161,6 +162,8 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, | |||
161 | static struct node *resize(struct trie *t, struct tnode *tn); | 162 | static struct node *resize(struct trie *t, struct tnode *tn); |
162 | static struct tnode *inflate(struct trie *t, struct tnode *tn); | 163 | static struct tnode *inflate(struct trie *t, struct tnode *tn); |
163 | static struct tnode *halve(struct trie *t, struct tnode *tn); | 164 | static struct tnode *halve(struct trie *t, struct tnode *tn); |
165 | /* tnodes to free after resize(); protected by RTNL */ | ||
166 | static struct tnode *tnode_free_head; | ||
164 | 167 | ||
165 | static struct kmem_cache *fn_alias_kmem __read_mostly; | 168 | static struct kmem_cache *fn_alias_kmem __read_mostly; |
166 | static struct kmem_cache *trie_leaf_kmem __read_mostly; | 169 | static struct kmem_cache *trie_leaf_kmem __read_mostly; |
@@ -385,6 +388,24 @@ static inline void tnode_free(struct tnode *tn) | |||
385 | call_rcu(&tn->rcu, __tnode_free_rcu); | 388 | call_rcu(&tn->rcu, __tnode_free_rcu); |
386 | } | 389 | } |
387 | 390 | ||
391 | static void tnode_free_safe(struct tnode *tn) | ||
392 | { | ||
393 | BUG_ON(IS_LEAF(tn)); | ||
394 | tn->tnode_free = tnode_free_head; | ||
395 | tnode_free_head = tn; | ||
396 | } | ||
397 | |||
398 | static void tnode_free_flush(void) | ||
399 | { | ||
400 | struct tnode *tn; | ||
401 | |||
402 | while ((tn = tnode_free_head)) { | ||
403 | tnode_free_head = tn->tnode_free; | ||
404 | tn->tnode_free = NULL; | ||
405 | tnode_free(tn); | ||
406 | } | ||
407 | } | ||
408 | |||
388 | static struct leaf *leaf_new(void) | 409 | static struct leaf *leaf_new(void) |
389 | { | 410 | { |
390 | struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); | 411 | struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); |
@@ -495,7 +516,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
495 | 516 | ||
496 | /* No children */ | 517 | /* No children */ |
497 | if (tn->empty_children == tnode_child_length(tn)) { | 518 | if (tn->empty_children == tnode_child_length(tn)) { |
498 | tnode_free(tn); | 519 | tnode_free_safe(tn); |
499 | return NULL; | 520 | return NULL; |
500 | } | 521 | } |
501 | /* One child */ | 522 | /* One child */ |
@@ -509,7 +530,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
509 | 530 | ||
510 | /* compress one level */ | 531 | /* compress one level */ |
511 | node_set_parent(n, NULL); | 532 | node_set_parent(n, NULL); |
512 | tnode_free(tn); | 533 | tnode_free_safe(tn); |
513 | return n; | 534 | return n; |
514 | } | 535 | } |
515 | /* | 536 | /* |
@@ -670,7 +691,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
670 | /* compress one level */ | 691 | /* compress one level */ |
671 | 692 | ||
672 | node_set_parent(n, NULL); | 693 | node_set_parent(n, NULL); |
673 | tnode_free(tn); | 694 | tnode_free_safe(tn); |
674 | return n; | 695 | return n; |
675 | } | 696 | } |
676 | 697 | ||
@@ -756,7 +777,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) | |||
756 | put_child(t, tn, 2*i, inode->child[0]); | 777 | put_child(t, tn, 2*i, inode->child[0]); |
757 | put_child(t, tn, 2*i+1, inode->child[1]); | 778 | put_child(t, tn, 2*i+1, inode->child[1]); |
758 | 779 | ||
759 | tnode_free(inode); | 780 | tnode_free_safe(inode); |
760 | continue; | 781 | continue; |
761 | } | 782 | } |
762 | 783 | ||
@@ -801,9 +822,9 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) | |||
801 | put_child(t, tn, 2*i, resize(t, left)); | 822 | put_child(t, tn, 2*i, resize(t, left)); |
802 | put_child(t, tn, 2*i+1, resize(t, right)); | 823 | put_child(t, tn, 2*i+1, resize(t, right)); |
803 | 824 | ||
804 | tnode_free(inode); | 825 | tnode_free_safe(inode); |
805 | } | 826 | } |
806 | tnode_free(oldtnode); | 827 | tnode_free_safe(oldtnode); |
807 | return tn; | 828 | return tn; |
808 | nomem: | 829 | nomem: |
809 | { | 830 | { |
@@ -885,7 +906,7 @@ static struct tnode *halve(struct trie *t, struct tnode *tn) | |||
885 | put_child(t, newBinNode, 1, right); | 906 | put_child(t, newBinNode, 1, right); |
886 | put_child(t, tn, i/2, resize(t, newBinNode)); | 907 | put_child(t, tn, i/2, resize(t, newBinNode)); |
887 | } | 908 | } |
888 | tnode_free(oldtnode); | 909 | tnode_free_safe(oldtnode); |
889 | return tn; | 910 | return tn; |
890 | nomem: | 911 | nomem: |
891 | { | 912 | { |
@@ -983,13 +1004,12 @@ fib_find_node(struct trie *t, u32 key) | |||
983 | return NULL; | 1004 | return NULL; |
984 | } | 1005 | } |
985 | 1006 | ||
986 | static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | 1007 | static void trie_rebalance(struct trie *t, struct tnode *tn) |
987 | { | 1008 | { |
988 | int wasfull; | 1009 | int wasfull; |
989 | t_key cindex, key; | 1010 | t_key cindex, key; |
990 | struct tnode *tp; | 1011 | struct tnode *tp; |
991 | 1012 | ||
992 | preempt_disable(); | ||
993 | key = tn->key; | 1013 | key = tn->key; |
994 | 1014 | ||
995 | while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { | 1015 | while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { |
@@ -1001,6 +1021,7 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | |||
1001 | (struct node *)tn, wasfull); | 1021 | (struct node *)tn, wasfull); |
1002 | 1022 | ||
1003 | tp = node_parent((struct node *) tn); | 1023 | tp = node_parent((struct node *) tn); |
1024 | tnode_free_flush(); | ||
1004 | if (!tp) | 1025 | if (!tp) |
1005 | break; | 1026 | break; |
1006 | tn = tp; | 1027 | tn = tp; |
@@ -1010,8 +1031,10 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | |||
1010 | if (IS_TNODE(tn)) | 1031 | if (IS_TNODE(tn)) |
1011 | tn = (struct tnode *)resize(t, (struct tnode *)tn); | 1032 | tn = (struct tnode *)resize(t, (struct tnode *)tn); |
1012 | 1033 | ||
1013 | preempt_enable(); | 1034 | rcu_assign_pointer(t->trie, (struct node *)tn); |
1014 | return (struct node *)tn; | 1035 | tnode_free_flush(); |
1036 | |||
1037 | return; | ||
1015 | } | 1038 | } |
1016 | 1039 | ||
1017 | /* only used from updater-side */ | 1040 | /* only used from updater-side */ |
@@ -1159,7 +1182,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) | |||
1159 | 1182 | ||
1160 | /* Rebalance the trie */ | 1183 | /* Rebalance the trie */ |
1161 | 1184 | ||
1162 | rcu_assign_pointer(t->trie, trie_rebalance(t, tp)); | 1185 | trie_rebalance(t, tp); |
1163 | done: | 1186 | done: |
1164 | return fa_head; | 1187 | return fa_head; |
1165 | } | 1188 | } |
@@ -1351,8 +1374,7 @@ static int check_leaf(struct trie *t, struct leaf *l, | |||
1351 | if (l->key != (key & ntohl(mask))) | 1374 | if (l->key != (key & ntohl(mask))) |
1352 | continue; | 1375 | continue; |
1353 | 1376 | ||
1354 | err = fib_semantic_match(&li->falh, flp, res, | 1377 | err = fib_semantic_match(&li->falh, flp, res, plen); |
1355 | htonl(l->key), mask, plen); | ||
1356 | 1378 | ||
1357 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1379 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1358 | if (err <= 0) | 1380 | if (err <= 0) |
@@ -1579,7 +1601,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l) | |||
1579 | if (tp) { | 1601 | if (tp) { |
1580 | t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); | 1602 | t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); |
1581 | put_child(t, (struct tnode *)tp, cindex, NULL); | 1603 | put_child(t, (struct tnode *)tp, cindex, NULL); |
1582 | rcu_assign_pointer(t->trie, trie_rebalance(t, tp)); | 1604 | trie_rebalance(t, tp); |
1583 | } else | 1605 | } else |
1584 | rcu_assign_pointer(t->trie, NULL); | 1606 | rcu_assign_pointer(t->trie, NULL); |
1585 | 1607 | ||