diff options
author | Eric Dumazet <edumazet@google.com> | 2018-10-18 12:12:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-10-18 19:51:02 -0400 |
commit | 79861919b8896e14b8e5707242721f2312c57ae4 (patch) | |
tree | e4d0a3a96f8109c5a0aaf295a31bdfffc611622f /net/ipv4/tcp_output.c | |
parent | cc18a7543d2f63a2c93fc61cfa7fd8be5464f75e (diff) |
tcp: fix TCP_REPAIR xmit queue setup
Andrey reported the following warning triggered while running CRIU tests:
tcp_clean_rtx_queue()
...
last_ackt = tcp_skb_timestamp_us(skb);
WARN_ON_ONCE(last_ackt == 0);
This is caused by 5f6188a8003d ("tcp: do not change tcp_wstamp_ns
in tcp_mstamp_refresh"), as we end up having skbs in retransmit queue
with a zero skb->skb_mstamp_ns field.
We could fix this bug in different ways, like making sure
tp->tcp_wstamp_ns is not zero at socket creation, but as Neal pointed
out, we also do not want that pacing status of a repaired socket
could push tp->tcp_wstamp_ns far ahead in the future.
So we prefer changing tcp_write_xmit() to not call tcp_update_skb_after_send()
and instead do what is requested by TCP_REPAIR logic.
Fixes: 5f6188a8003d ("tcp: do not change tcp_wstamp_ns in tcp_mstamp_refresh")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Andrey Vagin <avagin@openvz.org>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index d212e4cbc689..c07990a35ff3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2321,18 +2321,19 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, | |||
2321 | while ((skb = tcp_send_head(sk))) { | 2321 | while ((skb = tcp_send_head(sk))) { |
2322 | unsigned int limit; | 2322 | unsigned int limit; |
2323 | 2323 | ||
2324 | if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { | ||
2325 | /* "skb_mstamp_ns" is used as a start point for the retransmit timer */ | ||
2326 | skb->skb_mstamp_ns = tp->tcp_wstamp_ns = tp->tcp_clock_cache; | ||
2327 | list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); | ||
2328 | goto repair; /* Skip network transmission */ | ||
2329 | } | ||
2330 | |||
2324 | if (tcp_pacing_check(sk)) | 2331 | if (tcp_pacing_check(sk)) |
2325 | break; | 2332 | break; |
2326 | 2333 | ||
2327 | tso_segs = tcp_init_tso_segs(skb, mss_now); | 2334 | tso_segs = tcp_init_tso_segs(skb, mss_now); |
2328 | BUG_ON(!tso_segs); | 2335 | BUG_ON(!tso_segs); |
2329 | 2336 | ||
2330 | if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { | ||
2331 | /* "skb_mstamp" is used as a start point for the retransmit timer */ | ||
2332 | tcp_update_skb_after_send(sk, skb, tp->tcp_wstamp_ns); | ||
2333 | goto repair; /* Skip network transmission */ | ||
2334 | } | ||
2335 | |||
2336 | cwnd_quota = tcp_cwnd_test(tp, skb); | 2337 | cwnd_quota = tcp_cwnd_test(tp, skb); |
2337 | if (!cwnd_quota) { | 2338 | if (!cwnd_quota) { |
2338 | if (push_one == 2) | 2339 | if (push_one == 2) |