Commit 58d3aade authored by Paolo Abeni's avatar Paolo Abeni Committed by Jakub Kicinski

tcp: fix mid stream window clamp.

After the blamed commit below, if the user-space application performs
window clamping when tp->rcv_wnd is 0, the TCP socket will never be
able to announce a non 0 receive window, even after completely emptying
the receive buffer and re-setting the window clamp to higher values.

Refactor tcp_set_window_clamp() to address the issue: when the user
decreases the current clamp value, set rcv_ssthresh according to the
same logic used at buffer initialization, but ensuring reserved mem
provisioning.

To avoid code duplication factor-out the relevant bits from
tcp_adjust_rcv_ssthresh() in a new helper and reuse it in the above
scenario.

When increasing the clamp value, give the rcv_ssthresh a chance to grow
according to previously implemented heuristic.

Fixes: 3aa7857f ("tcp: enable mid stream window clamp")
Reported-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Reported-by: default avatarStefano Brivio <sbrivio@redhat.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/705dad54e6e6e9a010e571bf58e0b35a8ae70503.1701706073.git.pabeni@redhat.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent d007caaa
...@@ -1514,17 +1514,22 @@ static inline int tcp_full_space(const struct sock *sk) ...@@ -1514,17 +1514,22 @@ static inline int tcp_full_space(const struct sock *sk)
return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf)); return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf));
} }
static inline void tcp_adjust_rcv_ssthresh(struct sock *sk) static inline void __tcp_adjust_rcv_ssthresh(struct sock *sk, u32 new_ssthresh)
{ {
int unused_mem = sk_unused_reserved_mem(sk); int unused_mem = sk_unused_reserved_mem(sk);
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); tp->rcv_ssthresh = min(tp->rcv_ssthresh, new_ssthresh);
if (unused_mem) if (unused_mem)
tp->rcv_ssthresh = max_t(u32, tp->rcv_ssthresh, tp->rcv_ssthresh = max_t(u32, tp->rcv_ssthresh,
tcp_win_from_space(sk, unused_mem)); tcp_win_from_space(sk, unused_mem));
} }
static inline void tcp_adjust_rcv_ssthresh(struct sock *sk)
{
__tcp_adjust_rcv_ssthresh(sk, 4U * tcp_sk(sk)->advmss);
}
void tcp_cleanup_rbuf(struct sock *sk, int copied); void tcp_cleanup_rbuf(struct sock *sk, int copied);
void __tcp_cleanup_rbuf(struct sock *sk, int copied); void __tcp_cleanup_rbuf(struct sock *sk, int copied);
......
...@@ -3368,9 +3368,25 @@ int tcp_set_window_clamp(struct sock *sk, int val) ...@@ -3368,9 +3368,25 @@ int tcp_set_window_clamp(struct sock *sk, int val)
return -EINVAL; return -EINVAL;
tp->window_clamp = 0; tp->window_clamp = 0;
} else { } else {
tp->window_clamp = val < SOCK_MIN_RCVBUF / 2 ? u32 new_rcv_ssthresh, old_window_clamp = tp->window_clamp;
SOCK_MIN_RCVBUF / 2 : val; u32 new_window_clamp = val < SOCK_MIN_RCVBUF / 2 ?
tp->rcv_ssthresh = min(tp->rcv_wnd, tp->window_clamp); SOCK_MIN_RCVBUF / 2 : val;
if (new_window_clamp == old_window_clamp)
return 0;
tp->window_clamp = new_window_clamp;
if (new_window_clamp < old_window_clamp) {
/* need to apply the reserved mem provisioning only
* when shrinking the window clamp
*/
__tcp_adjust_rcv_ssthresh(sk, tp->window_clamp);
} else {
new_rcv_ssthresh = min(tp->rcv_wnd, tp->window_clamp);
tp->rcv_ssthresh = max(new_rcv_ssthresh,
tp->rcv_ssthresh);
}
} }
return 0; return 0;
} }
......
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