diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-13 04:22:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-16 14:13:23 -0400 |
commit | 10da66f7552b3c7966c2f4f1f72009fb0b5539ec (patch) | |
tree | 517c39912a0aea9d4da3c3915c78e832dfbba855 /net | |
parent | 874ffa8f72444d6253d2669fed304875c128f86b (diff) |
fib: avoid false sharing on fib_table_hash
While doing profile analysis, I found fib_hash_table was sometime in a
cache line shared by a possibly often written kernel structure.
(CONFIG_IP_ROUTE_MULTIPATH || !CONFIG_IPV6_MULTIPLE_TABLES)
It's hard to detect because not easily reproductible.
Make sure we allocate a full cache line to keep this shared in all cpus
caches.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fib_frontend.c | 11 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 9 |
2 files changed, 11 insertions, 9 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 919f2ad19b49..3df057e89640 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -1016,16 +1016,15 @@ static struct notifier_block fib_netdev_notifier = { | |||
1016 | static int __net_init ip_fib_net_init(struct net *net) | 1016 | static int __net_init ip_fib_net_init(struct net *net) |
1017 | { | 1017 | { |
1018 | int err; | 1018 | int err; |
1019 | unsigned int i; | 1019 | size_t size = sizeof(struct hlist_head) * FIB_TABLE_HASHSZ; |
1020 | |||
1021 | /* Avoid false sharing : Use at least a full cache line */ | ||
1022 | size = max_t(size_t, size, L1_CACHE_BYTES); | ||
1020 | 1023 | ||
1021 | net->ipv4.fib_table_hash = kzalloc( | 1024 | net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL); |
1022 | sizeof(struct hlist_head)*FIB_TABLE_HASHSZ, GFP_KERNEL); | ||
1023 | if (net->ipv4.fib_table_hash == NULL) | 1025 | if (net->ipv4.fib_table_hash == NULL) |
1024 | return -ENOMEM; | 1026 | return -ENOMEM; |
1025 | 1027 | ||
1026 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) | ||
1027 | INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]); | ||
1028 | |||
1029 | err = fib4_rules_init(net); | 1028 | err = fib4_rules_init(net); |
1030 | if (err < 0) | 1029 | if (err < 0) |
1031 | goto fail; | 1030 | goto fail; |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b6a585909d35..de382114609b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1500,15 +1500,18 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
1500 | 1500 | ||
1501 | static int __net_init fib6_net_init(struct net *net) | 1501 | static int __net_init fib6_net_init(struct net *net) |
1502 | { | 1502 | { |
1503 | size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ; | ||
1504 | |||
1503 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1505 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
1504 | 1506 | ||
1505 | net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); | 1507 | net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); |
1506 | if (!net->ipv6.rt6_stats) | 1508 | if (!net->ipv6.rt6_stats) |
1507 | goto out_timer; | 1509 | goto out_timer; |
1508 | 1510 | ||
1509 | net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ, | 1511 | /* Avoid false sharing : Use at least a full cache line */ |
1510 | sizeof(*net->ipv6.fib_table_hash), | 1512 | size = max_t(size_t, size, L1_CACHE_BYTES); |
1511 | GFP_KERNEL); | 1513 | |
1514 | net->ipv6.fib_table_hash = kzalloc(size, GFP_KERNEL); | ||
1512 | if (!net->ipv6.fib_table_hash) | 1515 | if (!net->ipv6.fib_table_hash) |
1513 | goto out_rt6_stats; | 1516 | goto out_rt6_stats; |
1514 | 1517 | ||