aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorYanmin Zhang <yanmin_zhang@linux.intel.com>2012-05-23 11:39:45 -0400
committerLuis Henriques <luis.henriques@canonical.com>2012-07-03 11:29:03 -0400
commitb457b5b19c6484670ea162666f1b3a4699cc6de2 (patch)
treed251e7d31fe0507b4a1731b56120a352e0342184 /net
parentebb99653d81d73bb9b07ade372c264cf3a089438 (diff)
ipv4: fix the rcu race between free_fib_info and ip_route_output_slow
BugLink: http://bugs.launchpad.net/bugs/1013748 [ Upstream commit e49cc0da7283088c5e03d475ffe2fdcb24a6d5b1 ] We hit a kernel OOPS. <3>[23898.789643] BUG: sleeping function called from invalid context at /data/buildbot/workdir/ics/hardware/intel/linux-2.6/arch/x86/mm/fault.c:1103 <3>[23898.862215] in_atomic(): 0, irqs_disabled(): 0, pid: 10526, name: Thread-6683 <4>[23898.967805] HSU serial 0000:00:05.1: 0000:00:05.2:HSU serial prevented me to suspend... <4>[23899.258526] Pid: 10526, comm: Thread-6683 Tainted: G W 3.0.8-137685-ge7742f9 #1 <4>[23899.357404] HSU serial 0000:00:05.1: 0000:00:05.2:HSU serial prevented me to suspend... <4>[23899.904225] Call Trace: <4>[23899.989209] [<c1227f50>] ? pgtable_bad+0x130/0x130 <4>[23900.000416] [<c1238c2a>] __might_sleep+0x10a/0x110 <4>[23900.007357] [<c1228021>] do_page_fault+0xd1/0x3c0 <4>[23900.013764] [<c18e9ba9>] ? restore_all+0xf/0xf <4>[23900.024024] [<c17c007b>] ? napi_complete+0x8b/0x690 <4>[23900.029297] [<c1227f50>] ? pgtable_bad+0x130/0x130 <4>[23900.123739] [<c1227f50>] ? pgtable_bad+0x130/0x130 <4>[23900.128955] [<c18ea0c3>] error_code+0x5f/0x64 <4>[23900.133466] [<c1227f50>] ? pgtable_bad+0x130/0x130 <4>[23900.138450] [<c17f6298>] ? __ip_route_output_key+0x698/0x7c0 <4>[23900.144312] [<c17f5f8d>] ? __ip_route_output_key+0x38d/0x7c0 <4>[23900.150730] [<c17f63df>] ip_route_output_flow+0x1f/0x60 <4>[23900.156261] [<c181de58>] ip4_datagram_connect+0x188/0x2b0 <4>[23900.161960] [<c18e981f>] ? _raw_spin_unlock_bh+0x1f/0x30 <4>[23900.167834] [<c18298d6>] inet_dgram_connect+0x36/0x80 <4>[23900.173224] [<c14f9e88>] ? _copy_from_user+0x48/0x140 <4>[23900.178817] [<c17ab9da>] sys_connect+0x9a/0xd0 <4>[23900.183538] [<c132e93c>] ? alloc_file+0xdc/0x240 <4>[23900.189111] [<c123925d>] ? sub_preempt_count+0x3d/0x50 Function free_fib_info resets nexthop_nh->nh_dev to NULL before releasing fi. Other cpu might be accessing fi. Fixing it by delaying the releasing. With the patch, we ran MTBF testing on Android mobile for 12 hours and didn't trigger the issue. Thank Eric for very detailed review/checking the issue. Signed-off-by: Yanmin Zhang <yanmin_zhang@linux.intel.com> Signed-off-by: Kun Jiang <kunx.jiang@intel.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Herton Ronaldo Krzesinski <herton.krzesinski@canonical.com>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_semantics.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 33e2c35b74b..7e454ba8e85 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -142,6 +142,18 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
142}; 142};
143 143
144/* Release a nexthop info record */ 144/* Release a nexthop info record */
145static void free_fib_info_rcu(struct rcu_head *head)
146{
147 struct fib_info *fi = container_of(head, struct fib_info, rcu);
148
149 change_nexthops(fi) {
150 if (nexthop_nh->nh_dev)
151 dev_put(nexthop_nh->nh_dev);
152 } endfor_nexthops(fi);
153
154 release_net(fi->fib_net);
155 kfree(fi);
156}
145 157
146void free_fib_info(struct fib_info *fi) 158void free_fib_info(struct fib_info *fi)
147{ 159{
@@ -149,14 +161,8 @@ void free_fib_info(struct fib_info *fi)
149 pr_warning("Freeing alive fib_info %p\n", fi); 161 pr_warning("Freeing alive fib_info %p\n", fi);
150 return; 162 return;
151 } 163 }
152 change_nexthops(fi) {
153 if (nexthop_nh->nh_dev)
154 dev_put(nexthop_nh->nh_dev);
155 nexthop_nh->nh_dev = NULL;
156 } endfor_nexthops(fi);
157 fib_info_cnt--; 164 fib_info_cnt--;
158 release_net(fi->fib_net); 165 call_rcu(&fi->rcu, free_fib_info_rcu);
159 kfree_rcu(fi, rcu);
160} 166}
161 167
162void fib_release_info(struct fib_info *fi) 168void fib_release_info(struct fib_info *fi)