mirror of https://gitee.com/openkylin/linux.git
tcp: limit sk_rcvlowat by the maximum receive buffer
The user-provided value to setsockopt(SO_RCVLOWAT) can be
larger than the maximum possible receive buffer. Such values
mute POLLIN signals on the socket which can stall progress
on the socket.
Limit the user-provided value to half of the maximum receive
buffer, i.e., half of sk_rcvbuf when the receive buffer size
is set by the user, or otherwise half of sysctl_tcp_rmem[2].
Fixes: d1361840f8
("tcp: fix SO_RCVLOWAT and RCVBUF autotuning")
Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b718e8c8f4
commit
867f816bad
|
@ -1694,6 +1694,13 @@ EXPORT_SYMBOL(tcp_peek_len);
|
||||||
/* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */
|
/* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */
|
||||||
int tcp_set_rcvlowat(struct sock *sk, int val)
|
int tcp_set_rcvlowat(struct sock *sk, int val)
|
||||||
{
|
{
|
||||||
|
int cap;
|
||||||
|
|
||||||
|
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
|
||||||
|
cap = sk->sk_rcvbuf >> 1;
|
||||||
|
else
|
||||||
|
cap = sock_net(sk)->ipv4.sysctl_tcp_rmem[2] >> 1;
|
||||||
|
val = min(val, cap);
|
||||||
sk->sk_rcvlowat = val ? : 1;
|
sk->sk_rcvlowat = val ? : 1;
|
||||||
|
|
||||||
/* Check if we need to signal EPOLLIN right now */
|
/* Check if we need to signal EPOLLIN right now */
|
||||||
|
@ -1702,12 +1709,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
|
||||||
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
|
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* val comes from user space and might be close to INT_MAX */
|
|
||||||
val <<= 1;
|
val <<= 1;
|
||||||
if (val < 0)
|
|
||||||
val = INT_MAX;
|
|
||||||
|
|
||||||
val = min(val, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
|
|
||||||
if (val > sk->sk_rcvbuf) {
|
if (val > sk->sk_rcvbuf) {
|
||||||
sk->sk_rcvbuf = val;
|
sk->sk_rcvbuf = val;
|
||||||
tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val);
|
tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val);
|
||||||
|
|
Loading…
Reference in New Issue