diff options
-rw-r--r-- | net/ipv4/fib_hash.c | 33 | ||||
-rw-r--r-- | net/ipv4/fib_lookup.h | 4 |
2 files changed, 23 insertions, 14 deletions
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 499522f3b305..a15b2f1b2721 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -52,6 +52,7 @@ struct fib_node { | |||
52 | struct hlist_node fn_hash; | 52 | struct hlist_node fn_hash; |
53 | struct list_head fn_alias; | 53 | struct list_head fn_alias; |
54 | __be32 fn_key; | 54 | __be32 fn_key; |
55 | struct fib_alias fn_embedded_alias; | ||
55 | }; | 56 | }; |
56 | 57 | ||
57 | struct fn_zone { | 58 | struct fn_zone { |
@@ -193,10 +194,13 @@ static inline void fn_free_node(struct fib_node * f) | |||
193 | kmem_cache_free(fn_hash_kmem, f); | 194 | kmem_cache_free(fn_hash_kmem, f); |
194 | } | 195 | } |
195 | 196 | ||
196 | static inline void fn_free_alias(struct fib_alias *fa) | 197 | static inline void fn_free_alias(struct fib_alias *fa, struct fib_node *f) |
197 | { | 198 | { |
198 | fib_release_info(fa->fa_info); | 199 | fib_release_info(fa->fa_info); |
199 | kmem_cache_free(fn_alias_kmem, fa); | 200 | if (fa == &f->fn_embedded_alias) |
201 | fa->fa_info = NULL; | ||
202 | else | ||
203 | kmem_cache_free(fn_alias_kmem, fa); | ||
200 | } | 204 | } |
201 | 205 | ||
202 | static struct fn_zone * | 206 | static struct fn_zone * |
@@ -476,15 +480,12 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) | |||
476 | goto out; | 480 | goto out; |
477 | 481 | ||
478 | err = -ENOBUFS; | 482 | err = -ENOBUFS; |
479 | new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); | ||
480 | if (new_fa == NULL) | ||
481 | goto out; | ||
482 | 483 | ||
483 | new_f = NULL; | 484 | new_f = NULL; |
484 | if (!f) { | 485 | if (!f) { |
485 | new_f = kmem_cache_alloc(fn_hash_kmem, GFP_KERNEL); | 486 | new_f = kmem_cache_zalloc(fn_hash_kmem, GFP_KERNEL); |
486 | if (new_f == NULL) | 487 | if (new_f == NULL) |
487 | goto out_free_new_fa; | 488 | goto out; |
488 | 489 | ||
489 | INIT_HLIST_NODE(&new_f->fn_hash); | 490 | INIT_HLIST_NODE(&new_f->fn_hash); |
490 | INIT_LIST_HEAD(&new_f->fn_alias); | 491 | INIT_LIST_HEAD(&new_f->fn_alias); |
@@ -492,6 +493,12 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) | |||
492 | f = new_f; | 493 | f = new_f; |
493 | } | 494 | } |
494 | 495 | ||
496 | new_fa = &f->fn_embedded_alias; | ||
497 | if (new_fa->fa_info != NULL) { | ||
498 | new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); | ||
499 | if (new_fa == NULL) | ||
500 | goto out_free_new_f; | ||
501 | } | ||
495 | new_fa->fa_info = fi; | 502 | new_fa->fa_info = fi; |
496 | new_fa->fa_tos = tos; | 503 | new_fa->fa_tos = tos; |
497 | new_fa->fa_type = cfg->fc_type; | 504 | new_fa->fa_type = cfg->fc_type; |
@@ -518,8 +525,8 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) | |||
518 | &cfg->fc_nlinfo, 0); | 525 | &cfg->fc_nlinfo, 0); |
519 | return 0; | 526 | return 0; |
520 | 527 | ||
521 | out_free_new_fa: | 528 | out_free_new_f: |
522 | kmem_cache_free(fn_alias_kmem, new_fa); | 529 | kmem_cache_free(fn_hash_kmem, new_f); |
523 | out: | 530 | out: |
524 | fib_release_info(fi); | 531 | fib_release_info(fi); |
525 | return err; | 532 | return err; |
@@ -595,7 +602,7 @@ static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg) | |||
595 | 602 | ||
596 | if (fa->fa_state & FA_S_ACCESSED) | 603 | if (fa->fa_state & FA_S_ACCESSED) |
597 | rt_cache_flush(-1); | 604 | rt_cache_flush(-1); |
598 | fn_free_alias(fa); | 605 | fn_free_alias(fa, f); |
599 | if (kill_fn) { | 606 | if (kill_fn) { |
600 | fn_free_node(f); | 607 | fn_free_node(f); |
601 | fz->fz_nent--; | 608 | fz->fz_nent--; |
@@ -631,7 +638,7 @@ static int fn_flush_list(struct fn_zone *fz, int idx) | |||
631 | fib_hash_genid++; | 638 | fib_hash_genid++; |
632 | write_unlock_bh(&fib_hash_lock); | 639 | write_unlock_bh(&fib_hash_lock); |
633 | 640 | ||
634 | fn_free_alias(fa); | 641 | fn_free_alias(fa, f); |
635 | found++; | 642 | found++; |
636 | } | 643 | } |
637 | } | 644 | } |
@@ -750,10 +757,10 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin | |||
750 | void __init fib_hash_init(void) | 757 | void __init fib_hash_init(void) |
751 | { | 758 | { |
752 | fn_hash_kmem = kmem_cache_create("ip_fib_hash", sizeof(struct fib_node), | 759 | fn_hash_kmem = kmem_cache_create("ip_fib_hash", sizeof(struct fib_node), |
753 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); | 760 | 0, SLAB_PANIC, NULL); |
754 | 761 | ||
755 | fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias), | 762 | fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias), |
756 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); | 763 | 0, SLAB_PANIC, NULL); |
757 | 764 | ||
758 | } | 765 | } |
759 | 766 | ||
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index 26ee66d78c18..2c1623d2768b 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h | |||
@@ -7,12 +7,14 @@ | |||
7 | 7 | ||
8 | struct fib_alias { | 8 | struct fib_alias { |
9 | struct list_head fa_list; | 9 | struct list_head fa_list; |
10 | struct rcu_head rcu; | ||
11 | struct fib_info *fa_info; | 10 | struct fib_info *fa_info; |
12 | u8 fa_tos; | 11 | u8 fa_tos; |
13 | u8 fa_type; | 12 | u8 fa_type; |
14 | u8 fa_scope; | 13 | u8 fa_scope; |
15 | u8 fa_state; | 14 | u8 fa_state; |
15 | #ifdef CONFIG_IP_FIB_TRIE | ||
16 | struct rcu_head rcu; | ||
17 | #endif | ||
16 | }; | 18 | }; |
17 | 19 | ||
18 | #define FA_S_ACCESSED 0x01 | 20 | #define FA_S_ACCESSED 0x01 |