summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2016-12-21 05:42:43 -0800
committerDavid S. Miller <davem@davemloft.net>2016-12-21 15:30:27 -0500
commit0a9648f1293966c838dc570da73c15a76f4c89d6 (patch)
treeec5986d27bea90c21316d67e408bf06d401ab6b9 /net
parent8354491c9d5b06709384cea91d13019bf5e61449 (diff)
downloadlinux-stable-0a9648f1293966c838dc570da73c15a76f4c89d6.tar.gz
linux-stable-0a9648f1293966c838dc570da73c15a76f4c89d6.tar.bz2
linux-stable-0a9648f1293966c838dc570da73c15a76f4c89d6.zip
tcp: add a missing barrier in tcp_tasklet_func()
Madalin reported crashes happening in tcp_tasklet_func() on powerpc64 Before TSQ_QUEUED bit is cleared, we must ensure the changes done by list_del(&tp->tsq_node); are committed to memory, otherwise corruption might happen, as an other cpu could catch TSQ_QUEUED clearance too soon. We can notice that old kernels were immune to this bug, because TSQ_QUEUED was cleared after a bh_lock_sock(sk)/bh_unlock_sock(sk) section, but they could have missed a kick to write additional bytes, when NIC interrupts for a given flow are spread to multiple cpus. Affected TCP flows would need an incoming ACK or RTO timer to add more packets to the pipe. So overall situation should be better now. Fixes: b223feb9de2a ("tcp: tsq: add shortcut in tcp_tasklet_func()") Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Madalin Bucur <madalin.bucur@nxp.com> Tested-by: Madalin Bucur <madalin.bucur@nxp.com> Tested-by: Xing Lei <xing.lei@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_output.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index b45101f3d2bd..31a255b555ad 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -769,6 +769,7 @@ static void tcp_tasklet_func(unsigned long data)
list_del(&tp->tsq_node);
sk = (struct sock *)tp;
+ smp_mb__before_atomic();
clear_bit(TSQ_QUEUED, &sk->sk_tsq_flags);
if (!sk->sk_lock.owned &&