diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2008-01-18 07:30:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-20 23:31:39 -0500 |
commit | 8d3f099abe25c21670cb5728178a1f286952782d (patch) | |
tree | 074339fd500a3af4f89cab67c0a90bae81bc93a7 | |
parent | 49d85c502ec5e6d5998c1a04394c5b24e8f7d32d (diff) |
[IPV4] FIB_HASH : Avoid unecessary loop in fn_hash_dump_zone()
I noticed "ip route list" was slower than "cat /proc/net/route" on a
machine with a full Internet routing table (214392 entries : Special
thanks to Robert ;) )
This is similar to problem reported in commit
d8c9283089287341c85a0a69de32c2287a990e71 ("[IPV4] ROUTE: ip_rt_dump()
is unecessary slow")
Fix is to avoid scanning the begining of fz_hash table, but directly
seek to the right offset.
Before patch :
time ip route >/tmp/ROUTE
real 0m1.285s
user 0m0.712s
sys 0m0.436s
After patch
# time ip route >/tmp/ROUTE
real 0m0.835s
user 0m0.692s
sys 0m0.124s
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/fib_hash.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 99071d79c5e7..0dfee27cfbcd 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -721,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, | |||
721 | { | 721 | { |
722 | int h, s_h; | 722 | int h, s_h; |
723 | 723 | ||
724 | if (fz->fz_hash == NULL) | ||
725 | return skb->len; | ||
724 | s_h = cb->args[3]; | 726 | s_h = cb->args[3]; |
725 | for (h=0; h < fz->fz_divisor; h++) { | 727 | for (h = s_h; h < fz->fz_divisor; h++) { |
726 | if (h < s_h) continue; | 728 | if (hlist_empty(&fz->fz_hash[h])) |
727 | if (h > s_h) | ||
728 | memset(&cb->args[4], 0, | ||
729 | sizeof(cb->args) - 4*sizeof(cb->args[0])); | ||
730 | if (fz->fz_hash == NULL || | ||
731 | hlist_empty(&fz->fz_hash[h])) | ||
732 | continue; | 729 | continue; |
733 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { | 730 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) { |
734 | cb->args[3] = h; | 731 | cb->args[3] = h; |
735 | return -1; | 732 | return -1; |
736 | } | 733 | } |
734 | memset(&cb->args[4], 0, | ||
735 | sizeof(cb->args) - 4*sizeof(cb->args[0])); | ||
737 | } | 736 | } |
738 | cb->args[3] = h; | 737 | cb->args[3] = h; |
739 | return skb->len; | 738 | return skb->len; |
@@ -749,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin | |||
749 | read_lock(&fib_hash_lock); | 748 | read_lock(&fib_hash_lock); |
750 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { | 749 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { |
751 | if (m < s_m) continue; | 750 | if (m < s_m) continue; |
752 | if (m > s_m) | ||
753 | memset(&cb->args[3], 0, | ||
754 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | ||
755 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { | 751 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { |
756 | cb->args[2] = m; | 752 | cb->args[2] = m; |
757 | read_unlock(&fib_hash_lock); | 753 | read_unlock(&fib_hash_lock); |
758 | return -1; | 754 | return -1; |
759 | } | 755 | } |
756 | memset(&cb->args[3], 0, | ||
757 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | ||
760 | } | 758 | } |
761 | read_unlock(&fib_hash_lock); | 759 | read_unlock(&fib_hash_lock); |
762 | cb->args[2] = m; | 760 | cb->args[2] = m; |