diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-05 06:41:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-05 23:39:38 -0400 |
commit | ebc0ffae5dfb4447e0a431ffe7fe1d467c48bbb9 (patch) | |
tree | 395e50547ffccc6b73e04a44190eb4b4f2d2316b /net/ipv4/fib_semantics.c | |
parent | c2952c314b4fe61820ba8fd6c949eed636140d52 (diff) |
fib: RCU conversion of fib_lookup()
fib_lookup() converted to be called in RCU protected context, no
reference taken and released on a contended cache line (fib_clntref)
fib_table_lookup() and fib_semantic_match() get an additional parameter.
struct fib_info gets an rcu_head field, and is freed after an rcu grace
period.
Stress test :
(Sending 160.000.000 UDP frames on same neighbour,
IP route cache disabled, dual E5540 @2.53GHz,
32bit kernel, FIB_HASH) (about same results for FIB_TRIE)
Before patch :
real 1m31.199s
user 0m13.761s
sys 23m24.780s
After patch:
real 1m5.375s
user 0m14.997s
sys 15m50.115s
Before patch Profile :
13044.00 15.4% __ip_route_output_key vmlinux
8438.00 10.0% dst_destroy vmlinux
5983.00 7.1% fib_semantic_match vmlinux
5410.00 6.4% fib_rules_lookup vmlinux
4803.00 5.7% neigh_lookup vmlinux
4420.00 5.2% _raw_spin_lock vmlinux
3883.00 4.6% rt_set_nexthop vmlinux
3261.00 3.9% _raw_read_lock vmlinux
2794.00 3.3% fib_table_lookup vmlinux
2374.00 2.8% neigh_resolve_output vmlinux
2153.00 2.5% dst_alloc vmlinux
1502.00 1.8% _raw_read_lock_bh vmlinux
1484.00 1.8% kmem_cache_alloc vmlinux
1407.00 1.7% eth_header vmlinux
1406.00 1.7% ipv4_dst_destroy vmlinux
1298.00 1.5% __copy_from_user_ll vmlinux
1174.00 1.4% dev_queue_xmit vmlinux
1000.00 1.2% ip_output vmlinux
After patch Profile :
13712.00 15.8% dst_destroy vmlinux
8548.00 9.9% __ip_route_output_key vmlinux
7017.00 8.1% neigh_lookup vmlinux
4554.00 5.3% fib_semantic_match vmlinux
4067.00 4.7% _raw_read_lock vmlinux
3491.00 4.0% dst_alloc vmlinux
3186.00 3.7% neigh_resolve_output vmlinux
3103.00 3.6% fib_table_lookup vmlinux
2098.00 2.4% _raw_read_lock_bh vmlinux
2081.00 2.4% kmem_cache_alloc vmlinux
2013.00 2.3% _raw_spin_lock vmlinux
1763.00 2.0% __copy_from_user_ll vmlinux
1763.00 2.0% ip_output vmlinux
1761.00 2.0% ipv4_dst_destroy vmlinux
1631.00 1.9% eth_header vmlinux
1440.00 1.7% _raw_read_unlock_bh vmlinux
Reference results, if IP route cache is enabled :
real 0m29.718s
user 0m10.845s
sys 7m37.341s
25213.00 29.5% __ip_route_output_key vmlinux
9011.00 10.5% dst_release vmlinux
4817.00 5.6% ip_push_pending_frames vmlinux
4232.00 5.0% ip_finish_output vmlinux
3940.00 4.6% udp_sendmsg vmlinux
3730.00 4.4% __copy_from_user_ll vmlinux
3716.00 4.4% ip_route_output_flow vmlinux
2451.00 2.9% __xfrm_lookup vmlinux
2221.00 2.6% ip_append_data vmlinux
1718.00 2.0% _raw_spin_lock_bh vmlinux
1655.00 1.9% __alloc_skb vmlinux
1572.00 1.8% sock_wfree vmlinux
1345.00 1.6% kfree vmlinux
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index ba52f399a898..0f80dfc2f7fb 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -148,6 +148,13 @@ static const struct | |||
148 | 148 | ||
149 | /* Release a nexthop info record */ | 149 | /* Release a nexthop info record */ |
150 | 150 | ||
151 | static void free_fib_info_rcu(struct rcu_head *head) | ||
152 | { | ||
153 | struct fib_info *fi = container_of(head, struct fib_info, rcu); | ||
154 | |||
155 | kfree(fi); | ||
156 | } | ||
157 | |||
151 | void free_fib_info(struct fib_info *fi) | 158 | void free_fib_info(struct fib_info *fi) |
152 | { | 159 | { |
153 | if (fi->fib_dead == 0) { | 160 | if (fi->fib_dead == 0) { |
@@ -161,7 +168,7 @@ void free_fib_info(struct fib_info *fi) | |||
161 | } endfor_nexthops(fi); | 168 | } endfor_nexthops(fi); |
162 | fib_info_cnt--; | 169 | fib_info_cnt--; |
163 | release_net(fi->fib_net); | 170 | release_net(fi->fib_net); |
164 | kfree(fi); | 171 | call_rcu(&fi->rcu, free_fib_info_rcu); |
165 | } | 172 | } |
166 | 173 | ||
167 | void fib_release_info(struct fib_info *fi) | 174 | void fib_release_info(struct fib_info *fi) |
@@ -553,6 +560,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, | |||
553 | nh->nh_scope = RT_SCOPE_LINK; | 560 | nh->nh_scope = RT_SCOPE_LINK; |
554 | return 0; | 561 | return 0; |
555 | } | 562 | } |
563 | rcu_read_lock(); | ||
556 | { | 564 | { |
557 | struct flowi fl = { | 565 | struct flowi fl = { |
558 | .nl_u = { | 566 | .nl_u = { |
@@ -568,8 +576,10 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, | |||
568 | if (fl.fl4_scope < RT_SCOPE_LINK) | 576 | if (fl.fl4_scope < RT_SCOPE_LINK) |
569 | fl.fl4_scope = RT_SCOPE_LINK; | 577 | fl.fl4_scope = RT_SCOPE_LINK; |
570 | err = fib_lookup(net, &fl, &res); | 578 | err = fib_lookup(net, &fl, &res); |
571 | if (err) | 579 | if (err) { |
580 | rcu_read_unlock(); | ||
572 | return err; | 581 | return err; |
582 | } | ||
573 | } | 583 | } |
574 | err = -EINVAL; | 584 | err = -EINVAL; |
575 | if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) | 585 | if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) |
@@ -585,7 +595,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, | |||
585 | goto out; | 595 | goto out; |
586 | err = 0; | 596 | err = 0; |
587 | out: | 597 | out: |
588 | fib_res_put(&res); | 598 | rcu_read_unlock(); |
589 | return err; | 599 | return err; |
590 | } else { | 600 | } else { |
591 | struct in_device *in_dev; | 601 | struct in_device *in_dev; |
@@ -879,7 +889,7 @@ failure: | |||
879 | 889 | ||
880 | /* Note! fib_semantic_match intentionally uses RCU list functions. */ | 890 | /* Note! fib_semantic_match intentionally uses RCU list functions. */ |
881 | int fib_semantic_match(struct list_head *head, const struct flowi *flp, | 891 | int fib_semantic_match(struct list_head *head, const struct flowi *flp, |
882 | struct fib_result *res, int prefixlen) | 892 | struct fib_result *res, int prefixlen, int fib_flags) |
883 | { | 893 | { |
884 | struct fib_alias *fa; | 894 | struct fib_alias *fa; |
885 | int nh_sel = 0; | 895 | int nh_sel = 0; |
@@ -943,7 +953,8 @@ out_fill_res: | |||
943 | res->type = fa->fa_type; | 953 | res->type = fa->fa_type; |
944 | res->scope = fa->fa_scope; | 954 | res->scope = fa->fa_scope; |
945 | res->fi = fa->fa_info; | 955 | res->fi = fa->fa_info; |
946 | atomic_inc(&res->fi->fib_clntref); | 956 | if (!(fib_flags & FIB_LOOKUP_NOREF)) |
957 | atomic_inc(&res->fi->fib_clntref); | ||
947 | return 0; | 958 | return 0; |
948 | } | 959 | } |
949 | 960 | ||