aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
authorYanmin Zhang <yanmin_zhang@linux.intel.com>2012-05-23 11:39:45 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-24 00:28:21 -0400
commite49cc0da7283088c5e03d475ffe2fdcb24a6d5b1 (patch)
tree2bd3c141e3c0a2e671870fb4fe46793f8beee3ba /net/ipv4/fib_semantics.c
parent31fe62b9586643953f0c0c37a6357dafc69034e2 (diff)
ipv4: fix the rcu race between free_fib_info and ip_route_output_slow
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>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index a8bdf7405433..e5b7182fa099 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -145,6 +145,12 @@ static void free_fib_info_rcu(struct rcu_head *head)
145{ 145{
146 struct fib_info *fi = container_of(head, struct fib_info, rcu); 146 struct fib_info *fi = container_of(head, struct fib_info, rcu);
147 147
148 change_nexthops(fi) {
149 if (nexthop_nh->nh_dev)
150 dev_put(nexthop_nh->nh_dev);
151 } endfor_nexthops(fi);
152
153 release_net(fi->fib_net);
148 if (fi->fib_metrics != (u32 *) dst_default_metrics) 154 if (fi->fib_metrics != (u32 *) dst_default_metrics)
149 kfree(fi->fib_metrics); 155 kfree(fi->fib_metrics);
150 kfree(fi); 156 kfree(fi);
@@ -156,13 +162,7 @@ void free_fib_info(struct fib_info *fi)
156 pr_warn("Freeing alive fib_info %p\n", fi); 162 pr_warn("Freeing alive fib_info %p\n", fi);
157 return; 163 return;
158 } 164 }
159 change_nexthops(fi) {
160 if (nexthop_nh->nh_dev)
161 dev_put(nexthop_nh->nh_dev);
162 nexthop_nh->nh_dev = NULL;
163 } endfor_nexthops(fi);
164 fib_info_cnt--; 165 fib_info_cnt--;
165 release_net(fi->fib_net);
166 call_rcu(&fi->rcu, free_fib_info_rcu); 166 call_rcu(&fi->rcu, free_fib_info_rcu);
167} 167}
168 168