[PATCH 5.15.y] rxrpc: Fix return in rxrpc_recvmsg_data() for service calls
Sasha Levin
sashal at kernel.org
Fri Nov 6 07:10:42 PST 2026
From: David Howells <dhowells at redhat.com>
[ Upstream commit 18a71e111c7505e16c2de91480561fc491f41341 ]
When rxrpc_recvmsg_data() gets called on a service call that has received
all of the request, RXRPC_CALL_RECVMSG_READ_ALL has been set, and this
causes rxrpc_recvmsg_data() to jump straight out, indicating the end of the
call (ie. rxrpc_kernel_recv_data() returns 1) without waiting for the call
to be processed or the reply to be transmitted.
rxperf_deliver_to_call() also has to be altered to call
rxrpc_kernel_recv_data() to collect the final ACK on a service call as does
afs_deliver_to_call().
Fixes: d001648ec7cf ("rxrpc: Don't expose skbs to in-kernel users [ver #2]")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260914151340.3227501-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells at redhat.com>
cc: Marc Dionne <marc.dionne at auristor.com>
cc: Jeffrey Altman <jaltman at auristor.com>
cc: Eric Dumazet <edumazet at google.com>
cc: "David S. Miller" <davem at davemloft.net>
cc: Jakub Kicinski <kuba at kernel.org>
cc: Paolo Abeni <pabeni at redhat.com>
cc: Simon Horman <horms at kernel.org>
cc: linux-afs at lists.infradead.org
cc: stable at vger.kernel.org
Link: https://patch.msgid.link/20261006133011.531806-10-dhowells@redhat.com
Signed-off-by: Paolo Abeni <pabeni at redhat.com>
[ sashal: adapted service-call completion handling to check call->state directly and use the existing call_complete label ]
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
Documentation/networking/rxrpc.rst | 13 +++++++++----
fs/afs/rxrpc.c | 4 ++--
net/rxrpc/recvmsg.c | 21 +++++++++++++++------
3 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 39c2249c7aa78..1928582e90298 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -903,10 +903,15 @@ The kernel interface functions are as follows:
want_more should be true if further data will be required after this is
satisfied and false if this is the last item of the receive phase.
- There are three normal returns: 0 if the buffer was filled and want_more
- was true; 1 if the buffer was filled, the last DATA packet has been
- emptied and want_more was false; and -EAGAIN if the function needs to be
- called again.
+ For client calls, there are three normal returns: 0 if the buffer was
+ filled and want_more was true; 1 if the buffer was filled, the last DATA
+ packet has been emptied and want_more was false; and -EAGAIN if the
+ function needs to be called again.
+
+ For service calls, there are four normal returns: 0 and -EAGAIN are the
+ same as for client calls; 2 indicates that the last DATA packet of the
+ request has been received, want_more was false and the call is still in
+ progress; and 1 indicates that the call is now successfully complete.
If the last DATA packet is processed but the buffer contains less than
the amount requested, EBADMSG is returned. If want_more wasn't set, but
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 624ca9a2bc8a1..871777ddaa8a8 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -497,7 +497,7 @@ static void afs_deliver_to_call(struct afs_call *call)
&call->service_id);
trace_afs_receive_data(call, &call->def_iter, false, ret);
- if (ret == -EINPROGRESS || ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == 2)
return;
if (ret < 0 || ret == 1) {
if (ret == 1)
@@ -910,7 +910,7 @@ int afs_extract_data(struct afs_call *call, bool want_more)
return ret;
state = READ_ONCE(call->state);
- if (ret == 1) {
+ if (ret == 1 || ret == 2) {
switch (state) {
case AFS_CALL_CL_AWAIT_REPLY:
afs_set_call_state(call, state, AFS_CALL_CL_PROC_REPLY);
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index b7783d2af6be3..a7071c61dabfe 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -687,14 +687,16 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
* @_service: Where to store the actual service ID (may be upgraded)
*
* Allow a kernel service to receive data and pick up information about the
- * state of a call. Returns 0 if got what was asked for and there's more
- * available, 1 if we got what was asked for and we're at the end of the data
- * and -EAGAIN if we need more data.
+ * state of a call. Note that *@_abort should also be initialised to %0.
*
- * Note that we may return -EAGAIN to drain empty packets at the end of the
- * data, even if we've already copied over the requested data.
+ * Note that we may return %-EAGAIN to drain empty packets at the end
+ * of the data, even if we've already copied over the requested data.
*
- * *_abort should also be initialised to 0.
+ * Return: %0 if got what was asked for and there's more available, %1 if we
+ * got what was asked for and we're at the end of the call, %2 if a service
+ * call received all of the request but is still in progress and %-EAGAIN if we
+ * need more data. A variety of other errors can be returned if the call
+ * completed with failure.
*/
int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
struct iov_iter *iter, size_t *_len,
@@ -715,6 +717,8 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
case RXRPC_CALL_CLIENT_RECV_REPLY:
case RXRPC_CALL_SERVER_RECV_REQUEST:
case RXRPC_CALL_SERVER_ACK_REQUEST:
+ case RXRPC_CALL_SERVER_SEND_REPLY:
+ case RXRPC_CALL_SERVER_AWAIT_ACK:
ret = rxrpc_recvmsg_data(sock, call, NULL, iter,
*_len, 0, &offset);
*_len -= offset;
@@ -748,6 +752,11 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
read_phase_complete:
ret = 1;
+ if (rxrpc_is_service_call(call)) {
+ if (READ_ONCE(call->state) == RXRPC_CALL_COMPLETE)
+ goto call_complete;
+ ret = 2;
+ }
out:
switch (call->ackr_reason) {
case RXRPC_ACK_IDLE:
--
2.53.0
More information about the linux-afs
mailing list