Commit 973ec449 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

tcp: fix an infinite loop in tcp_slow_start()

Since commit 9dc27415 (tcp: fix ABC in tcp_slow_start()),
a nul snd_cwnd triggers an infinite loop in tcp_slow_start()

Avoid this infinite loop and log a one time error for further
analysis. FRTO code is suspected to cause this bug.
Reported-by: default avatarPasi Kärkkäinen <pasik@iki.fi>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 59fa5348
...@@ -310,6 +310,12 @@ void tcp_slow_start(struct tcp_sock *tp) ...@@ -310,6 +310,12 @@ void tcp_slow_start(struct tcp_sock *tp)
{ {
int cnt; /* increase in packets */ int cnt; /* increase in packets */
unsigned int delta = 0; unsigned int delta = 0;
u32 snd_cwnd = tp->snd_cwnd;
if (unlikely(!snd_cwnd)) {
pr_err_once("snd_cwnd is nul, please report this bug.\n");
snd_cwnd = 1U;
}
/* RFC3465: ABC Slow start /* RFC3465: ABC Slow start
* Increase only after a full MSS of bytes is acked * Increase only after a full MSS of bytes is acked
...@@ -324,7 +330,7 @@ void tcp_slow_start(struct tcp_sock *tp) ...@@ -324,7 +330,7 @@ void tcp_slow_start(struct tcp_sock *tp)
if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh) if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh)
cnt = sysctl_tcp_max_ssthresh >> 1; /* limited slow start */ cnt = sysctl_tcp_max_ssthresh >> 1; /* limited slow start */
else else
cnt = tp->snd_cwnd; /* exponential increase */ cnt = snd_cwnd; /* exponential increase */
/* RFC3465: ABC /* RFC3465: ABC
* We MAY increase by 2 if discovered delayed ack * We MAY increase by 2 if discovered delayed ack
...@@ -334,11 +340,11 @@ void tcp_slow_start(struct tcp_sock *tp) ...@@ -334,11 +340,11 @@ void tcp_slow_start(struct tcp_sock *tp)
tp->bytes_acked = 0; tp->bytes_acked = 0;
tp->snd_cwnd_cnt += cnt; tp->snd_cwnd_cnt += cnt;
while (tp->snd_cwnd_cnt >= tp->snd_cwnd) { while (tp->snd_cwnd_cnt >= snd_cwnd) {
tp->snd_cwnd_cnt -= tp->snd_cwnd; tp->snd_cwnd_cnt -= snd_cwnd;
delta++; delta++;
} }
tp->snd_cwnd = min(tp->snd_cwnd + delta, tp->snd_cwnd_clamp); tp->snd_cwnd = min(snd_cwnd + delta, tp->snd_cwnd_clamp);
} }
EXPORT_SYMBOL_GPL(tcp_slow_start); EXPORT_SYMBOL_GPL(tcp_slow_start);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment