aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2008-01-18 06:33:26 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:02:46 -0500
commita6501e080c318f8d4467679d17807f42b3a33cd5 (patch)
tree02ba4422ec6603b2bfddace52b2fabaaa6725496
parentb59cfbf77dc8368c2c90b012c79553613f4d70c3 (diff)
[IPV4] FIB_HASH: Reduce memory needs and speedup lookups
Currently, sizeof(struct fib_alias) is 24 or 48 bytes on 32/64 bits arches. Because of SLAB_HWCACHE_ALIGN requirement, these are rounded to 32 and 64 bytes respectively. This patch moves rcu to the end of fib_alias, and conditionally defines it only for CONFIG_IP_FIB_TRIE. We also remove SLAB_HWCACHE_ALIGN requirement for fib_alias and fib_node objects because it is not necessary. (BTW SLUB currently denies it for objects smaller than cache_line_size() / 2, but not SLAB) Finally, sizeof(fib_alias) go back to 16 and 32 bytes. Then, we can embed one fib_alias on each fib_node, to favor locality. Most of the time access to the fib_alias will be free because one cache line contains both the list head (fn_alias) and (one of) the list element. Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/fib_hash.c33
-rw-r--r--net/ipv4/fib_lookup.h4
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
57struct fn_zone { 58struct 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
196static inline void fn_free_alias(struct fib_alias *fa) 197static 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
202static struct fn_zone * 206static 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
521out_free_new_fa: 528out_free_new_f:
522 kmem_cache_free(fn_alias_kmem, new_fa); 529 kmem_cache_free(fn_hash_kmem, new_f);
523out: 530out:
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
750void __init fib_hash_init(void) 757void __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
8struct fib_alias { 8struct 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