diff options
author | David S. Miller <davem@davemloft.net> | 2023-08-13 14:21:38 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2023-08-13 14:21:38 +0300 |
commit | 86f03776f6d58558912bc05158fa75add1886aca (patch) | |
tree | 7a98005eb4c3cc91e5bfe987db7f8b6da28e072d /net/ipv4/tcp_output.c | |
parent | 3e6860ec3a2252249e310b0e6e88e2258171b3d0 (diff) | |
parent | 031c44b7527aec2f22ddaae4bcd8b085ff810ec4 (diff) | |
download | linux-86f03776f6d58558912bc05158fa75add1886aca.tar.xz |
Merge branch 'tcp-oom-probe'
Menglong Dong says:
====================
net: tcp: support probing OOM
In this series, we make some small changes to make the tcp
retransmission become zero-window probes if the receiver drops the skb
because of memory pressure.
In the 1st patch, we reply a zero-window ACK if the skb is dropped
because out of memory, instead of dropping the skb silently.
In the 2nd patch, we allow a zero-window ACK to update the window.
In the 3rd patch, fix unexcepted socket die when snd_wnd is 0 in
tcp_retransmit_timer().
In the 4th patch, we refactor the debug message in
tcp_retransmit_timer() to make it more correct.
After these changes, the tcp can probe the OOM of the receiver forever.
Changes since v3:
- make the timeout "2 * TCP_RTO_MAX" in the 3rd patch
- tp->retrans_stamp is not based on jiffies and can't be compared with
icsk->icsk_timeout in the 3rd patch. Fix it.
- introduce the 4th patch
Changes since v2:
- refactor the code to avoid code duplication in the 1st patch
- use after() instead of max() in tcp_rtx_probe0_timed_out()
Changes since v1:
- send 0 rwin ACK for the receive queue empty case when necessary in the
1st patch
- send the ACK immediately by using the ICSK_ACK_NOW flag in the 1st
patch
- consider the case of the connection restart from idle, as Neal comment,
in the 3rd patch
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c5412ee77fc8..769a558159ee 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -257,11 +257,19 @@ EXPORT_SYMBOL(tcp_select_initial_window); static u16 tcp_select_window(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); - u32 old_win = tp->rcv_wnd; - u32 cur_win = tcp_receive_window(tp); - u32 new_win = __tcp_select_window(sk); struct net *net = sock_net(sk); + u32 old_win = tp->rcv_wnd; + u32 cur_win, new_win; + + /* Make the window 0 if we failed to queue the data because we + * are out of memory. The window is temporary, so we don't store + * it on the socket. + */ + if (unlikely(inet_csk(sk)->icsk_ack.pending & ICSK_ACK_NOMEM)) + return 0; + cur_win = tcp_receive_window(tp); + new_win = __tcp_select_window(sk); if (new_win < cur_win) { /* Danger Will Robinson! * Don't update rcv_wup/rcv_wnd here or else |