[PATCH 6.19 73/86] rxrpc: Fix to request an ack if window is limited

Greg Kroah-Hartman
2026-04-13T16:07:06Z

From: Marc Dionne <marc.c.dionne@gmail.com>

commit 0cd3e3f3f2ec1a45aa559e2c0f3d57fac5eb3c25 upstream.

Peers may only send immediate acks for every 2 UDP packets received.
When sending a jumbogram, it is important to check that there is
sufficient window space to send another same sized jumbogram following
the current one, and request an ack if there isn't. Failure to do so may
cause the call to stall waiting for an ack until the resend timer fires.

Where jumbograms are in use this causes a very significant drop in
performance.

Fixes: fe24a5494390 ("rxrpc: Send jumbo DATA packets")
Signed-off-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Link: https://patch.msgid.link/20260408121252.2249051-10-dhowells@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/trace/events/rxrpc.h | 1 +
net/rxrpc/ar-internal.h | 2 +-
net/rxrpc/output.c | 2 ++
net/rxrpc/proc.c | 5 +++--
4 files changed, 7 insertions(+), 3 deletions(-)

--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -521,6 +521,7 @@
#define rxrpc_req_ack_traces \
EM(rxrpc_reqack_ack_lost, "ACK-LOST ") \
EM(rxrpc_reqack_app_stall, "APP-STALL ") \
+ EM(rxrpc_reqack_jumbo_win, "JUMBO-WIN ") \
EM(rxrpc_reqack_more_rtt, "MORE-RTT ") \
EM(rxrpc_reqack_no_srv_last, "NO-SRVLAST") \
EM(rxrpc_reqack_old_rtt, "OLD-RTT ") \
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -117,7 +117,7 @@ struct rxrpc_net {
atomic_t stat_tx_jumbo[10];
atomic_t stat_rx_jumbo[10];

- atomic_t stat_why_req_ack[8];
+ atomic_t stat_why_req_ack[9];

atomic_t stat_io_loop;
};
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -479,6 +479,8 @@ static size_t rxrpc_prepare_data_subpack
why = rxrpc_reqack_old_rtt;
else if (!last && !after(READ_ONCE(call->send_top), txb->seq))
why = rxrpc_reqack_app_stall;
+ else if (call->tx_winsize <= (2 * req->n) || call->cong_cwnd <= (2 * req->n))
+ why = rxrpc_reqack_jumbo_win;
else
goto dont_set_request_ack;

--- a/net/rxrpc/proc.c
+++ b/net/rxrpc/proc.c
@@ -518,11 +518,12 @@ int rxrpc_stats_show(struct seq_file *se
atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_IDLE]),
atomic_read(&rxnet->stat_rx_acks[0]));
seq_printf(seq,
- "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u\n",
+ "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u jwin=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_ack_lost]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_more_rtt]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_old_rtt]),
- atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]));
+ atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]),
+ atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_jumbo_win]));
seq_printf(seq,
"Why-Req-A: nolast=%u retx=%u slows=%u smtxw=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_no_srv_last]),