diff options
author | Josh Hunt <joshhunt00@gmail.com> | 2011-12-28 08:23:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-30 17:07:33 -0500 |
commit | 32b293a53deeb220769f9a29357cb151cfb8ee26 (patch) | |
tree | 449cac8df3c48be49657331c9b6958ccdd360e18 /net/ipv6/route.c | |
parent | c9da99e6475f92653139e43f3c30c0cd011a0fd8 (diff) |
IPv6: Avoid taking write lock for /proc/net/ipv6_route
During some debugging I needed to look into how /proc/net/ipv6_route
operated and in my digging I found its calling fib6_clean_all() which uses
"write_lock_bh(&table->tb6_lock)" before doing the walk of the table. I
found this on 2.6.32, but reading the code I believe the same basic idea
exists currently. Looking at the rtnetlink code they are only calling
"read_lock_bh(&table->tb6_lock);" via fib6_dump_table(). While I realize
reading from proc isn't the recommended way of fetching the ipv6 route
table; taking a write lock seems unnecessary and would probably cause
network performance issues.
To verify this I loaded up the ipv6 route table and then ran iperf in 3
cases:
* doing nothing
* reading ipv6 route table via proc
(while :; do cat /proc/net/ipv6_route > /dev/null; done)
* reading ipv6 route table via rtnetlink
(while :; do ip -6 route show table all > /dev/null; done)
* Load the ipv6 route table up with:
* for ((i = 0;i < 4000;i++)); do ip route add unreachable 2000::$i; done
* iperf commands:
* client: iperf -i 1 -V -c <ipv6 addr>
* server: iperf -V -s
* iperf results - 3 runs each (in Mbits/sec)
* nothing: client: 927,927,927 server: 927,927,927
* proc: client: 179,97,96,113 server: 142,112,133
* iproute: client: 928,927,928 server: 927,927,927
lock_stat shows taking the write lock is causing the slowdown. Using this
info I decided to write a version of fib6_clean_all() which replaces
write_lock_bh(&table->tb6_lock) with read_lock_bh(&table->tb6_lock). With
this new function I see the same results as with my rtnetlink iperf test.
Signed-off-by: Josh Hunt <joshhunt00@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4a62c47599b4..07361dfa8085 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -2680,7 +2680,7 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2680 | static int ipv6_route_show(struct seq_file *m, void *v) | 2680 | static int ipv6_route_show(struct seq_file *m, void *v) |
2681 | { | 2681 | { |
2682 | struct net *net = (struct net *)m->private; | 2682 | struct net *net = (struct net *)m->private; |
2683 | fib6_clean_all(net, rt6_info_route, 0, m); | 2683 | fib6_clean_all_ro(net, rt6_info_route, 0, m); |
2684 | return 0; | 2684 | return 0; |
2685 | } | 2685 | } |
2686 | 2686 | ||