tcp: fix mid stream window clamp.
[ Upstream commit 58d3aade20cdddbac6c9707ac0f3f5f8c1278b74 ]
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: 3aa7857fe1 ("tcp: enable mid stream window clamp")
Reported-by: David Gibson <david@gibson.dropbear.id.au>
Reported-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/705dad54e6e6e9a010e571bf58e0b35a8ae70503.1701706073.git.pabeni@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
9fc81912fc
commit
c91685ac1b
2 changed files with 26 additions and 5 deletions
|
|
@ -1460,17 +1460,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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3473,9 +3473,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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue