aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorSoheil Hassas Yeganeh <soheil@google.com>2018-06-08 22:47:10 -0400
committerDavid S. Miller <davem@davemloft.net>2018-06-10 17:12:50 -0400
commit867f816badc01e6da655028810d468c9f935b37c (patch)
tree8638841a4e39647569a24e5021bfa45586c90a3b /net/ipv4/tcp.c
parentb718e8c8f4f5920aaddc2e52d5e32f494c91129c (diff)
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: d1361840f8c5 ("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>
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2741953adaba..141acd92e58a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1694,6 +1694,13 @@ EXPORT_SYMBOL(tcp_peek_len);
1694/* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */ 1694/* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */
1695int tcp_set_rcvlowat(struct sock *sk, int val) 1695int tcp_set_rcvlowat(struct sock *sk, int val)
1696{ 1696{
1697 int cap;
1698
1699 if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
1700 cap = sk->sk_rcvbuf >> 1;
1701 else
1702 cap = sock_net(sk)->ipv4.sysctl_tcp_rmem[2] >> 1;
1703 val = min(val, cap);
1697 sk->sk_rcvlowat = val ? : 1; 1704 sk->sk_rcvlowat = val ? : 1;
1698 1705
1699 /* Check if we need to signal EPOLLIN right now */ 1706 /* Check if we need to signal EPOLLIN right now */
@@ -1702,12 +1709,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
1702 if (sk->sk_userlocks & SOCK_RCVBUF_LOCK) 1709 if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
1703 return 0; 1710 return 0;
1704 1711
1705 /* val comes from user space and might be close to INT_MAX */
1706 val <<= 1; 1712 val <<= 1;
1707 if (val < 0)
1708 val = INT_MAX;
1709
1710 val = min(val, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
1711 if (val > sk->sk_rcvbuf) { 1713 if (val > sk->sk_rcvbuf) {
1712 sk->sk_rcvbuf = val; 1714 sk->sk_rcvbuf = val;
1713 tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val); 1715 tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val);