Patch "ip_tunnel: disable preemption when updating per-cpu tstats" has been added to the 4.1-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
ip_tunnel: disable preemption when updating per-cpu tstats
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
ip_tunnel-disable-preemption-when-updating-per-cpu-tstats.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From foo@baz Fri Dec 11 11:39:13 EST 2015
From: "Jason A. Donenfeld" <[email protected]>
Date: Thu, 12 Nov 2015 17:35:58 +0100
Subject: ip_tunnel: disable preemption when updating per-cpu tstats
From: "Jason A. Donenfeld" <[email protected]>
[ Upstream commit b4fe85f9c9146f60457e9512fb6055e69e6a7a65 ]
Drivers like vxlan use the recently introduced udp_tunnel_xmit_skb/udp_tunnel6_xmit_skb APIs. udp_tunnel6_xmit_skb makes use of ip6tunnel_xmit, and ip6tunnel_xmit, after sending the packet, updates the struct stats using the usual u64_stats_update_begin/end calls on this_cpu_ptr(dev->tstats). udp_tunnel_xmit_skb makes use of iptunnel_xmit, which doesn't touch tstats, so drivers like vxlan, immediately after, call iptunnel_xmit_stats, which does the same thing - calls u64_stats_update_begin/end on this_cpu_ptr(dev->tstats).
While vxlan is probably fine (I don't know?), calling a similar function from, say, an unbound workqueue, on a fully preemptable kernel causes real issues:
[ 188.434537] BUG: using smp_processor_id() in preemptible [00000000] code: kworker/u8:0/6 [ 188.435579] caller is debug_smp_processor_id+0x17/0x20 [ 188.435583] CPU: 0 PID: 6 Comm: kworker/u8:0 Not tainted 4.2.6 #2 [ 188.435607] Call Trace: [ 188.435611] [<ffffffff8234e936>] dump_stack+0x4f/0x7b [ 188.435615] [<ffffffff81915f3d>] check_preemption_disabled+0x19d/0x1c0 [ 188.435619] [<ffffffff81915f77>] debug_smp_processor_id+0x17/0x20
The solution would be to protect the whole this_cpu_ptr(dev->tstats)/u64_stats_update_begin/end blocks with disabling preemption and then reenabling it.
--- include/net/ip6_tunnel.h | 3 ++- include/net/ip_tunnels.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
include/net/ip6_tunnel.h +2 -1
@@ -83,11 +83,12 @@ static inline void ip6tunnel_xmit(struct err =ip6_local_out_sk (sk, skb);if (net_xmit_eval (err) ==0 ) { -struct pcpu_sw_netstats *tstats =this_cpu_ptr (dev->tstats); +struct pcpu_sw_netstats *tstats =get_cpu_ptr (dev->tstats);u64_stats_update_begin (&tstats->syncp); tstats->tx_bytes += pkt_len; tstats->tx_packets++;u64_stats_update_end (&tstats->syncp); +put_cpu_ptr (tstats); }else { stats->tx_errors++; stats->tx_aborted_errors++;
include/net/ip_tunnels.h +2 -1
@@ -207,12 +207,13 @@ static inline void iptunnel_xmit_stats(i struct pcpu_sw_netstats __percpu *stats) {if (err >0 ) { -struct pcpu_sw_netstats *tstats =this_cpu_ptr (stats); +struct pcpu_sw_netstats *tstats =get_cpu_ptr (stats);u64_stats_update_begin (&tstats->syncp); tstats->tx_bytes += err; tstats->tx_packets++;u64_stats_update_end (&tstats->syncp); +put_cpu_ptr (tstats); }else if (err <0 ) { err_stats->tx_errors++; err_stats->tx_aborted_errors++;
Patches currently in stable-queue which might be from [email protected] are
queue-4.1/ip_tunnel-disable-preemption-when-updating-per-cpu-tstats.patch