提交 44bb4490 编写于 作者: E Eric Dumazet 提交者: Cheng Jian

tcp: fix SO_RCVLOWAT related hangs under mem pressure

stable inclusion
from linux-4.19.178
commit 777d796966484f5b2b6245706057a05d1d1b642a

--------------------------------

[ Upstream commit f969dc5a ]

While commit 24adbc16 ("tcp: fix SO_RCVLOWAT hangs with fat skbs")
fixed an issue vs too small sk_rcvbuf for given sk_rcvlowat constraint,
it missed to address issue caused by memory pressure.

1) If we are under memory pressure and socket receive queue is empty.
First incoming packet is allowed to be queued, after commit
76dfa608 ("tcp: allow one skb to be received per socket under memory pressure")

But we do not send EPOLLIN yet, in case tcp_data_ready() sees sk_rcvlowat
is bigger than skb length.

2) Then, when next packet comes, it is dropped, and we directly
call sk->sk_data_ready().

3) If application is using poll(), tcp_poll() will then use
tcp_stream_is_readable() and decide the socket receive queue is
not yet filled, so nothing will happen.

Even when sender retransmits packets, phases 2) & 3) repeat
and flow is effectively frozen, until memory pressure is off.

Fix is to consider tcp_under_memory_pressure() to take care
of global memory pressure or memcg pressure.

Fixes: 24adbc16 ("tcp: fix SO_RCVLOWAT hangs with fat skbs")
Signed-off-by: NEric Dumazet <edumazet@google.com>
Reported-by: NArjun Roy <arjunroy@google.com>
Suggested-by: NWei Wang <weiwan@google.com>
Reviewed-by: NWei Wang <weiwan@google.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 591569fd
...@@ -1380,8 +1380,13 @@ static inline int tcp_full_space(const struct sock *sk) ...@@ -1380,8 +1380,13 @@ static inline int tcp_full_space(const struct sock *sk)
*/ */
static inline bool tcp_rmem_pressure(const struct sock *sk) static inline bool tcp_rmem_pressure(const struct sock *sk)
{ {
int rcvbuf = READ_ONCE(sk->sk_rcvbuf); int rcvbuf, threshold;
int threshold = rcvbuf - (rcvbuf >> 3);
if (tcp_under_memory_pressure(sk))
return true;
rcvbuf = READ_ONCE(sk->sk_rcvbuf);
threshold = rcvbuf - (rcvbuf >> 3);
return atomic_read(&sk->sk_rmem_alloc) > threshold; return atomic_read(&sk->sk_rmem_alloc) > threshold;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册