rxrpc: Fix return in rxrpc_recvmsg_data() for service calls

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: d001648ec7 ("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@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261006133011.531806-10-dhowells@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
David Howells 2026-10-06 14:30:01 +01:00 committed by Paolo Abeni
parent 41eb0af096
commit 18a71e111c
4 changed files with 35 additions and 11 deletions

View File

@ -909,10 +909,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

View File

@ -541,7 +541,7 @@ 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)
@ -934,7 +934,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);

View File

@ -638,9 +638,11 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
* 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.
*
* 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 data and
* %-EAGAIN if we need more data.
* 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,
@ -679,6 +681,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 (rxrpc_call_is_complete(call))
goto call_failed;
ret = 2;
}
out:
if (_service)
*_service = call->dest_srx.srx_service;

View File

@ -293,8 +293,20 @@ static void rxperf_deliver_to_call(struct work_struct *work)
state == RXPERF_CALL_SV_AWAIT_ACK
) {
if (state == RXPERF_CALL_SV_AWAIT_ACK) {
if (!rxrpc_kernel_check_life(rxperf_socket, call->rxcall))
size_t len = 0;
iov_iter_kvec(&call->iter, ITER_DEST, NULL, 0, 0);
ret = rxrpc_kernel_recv_data(rxperf_socket,
call->rxcall, &call->iter,
&len, false, &remote_abort,
&call->service_id);
if (ret == -EAGAIN || ret == 2)
return;
if (ret < 0 || ret == 1) {
if (ret == 1)
ret = 0;
goto call_complete;
}
return;
}
@ -369,7 +381,7 @@ static int rxperf_extract_data(struct rxperf_call *call, bool want_more)
if (ret == 0 || ret == -EAGAIN)
return ret;
if (ret == 1) {
if (ret == 1 || ret == 2) {
switch (call->state) {
case RXPERF_CALL_SV_AWAIT_REQUEST:
rxperf_set_call_state(call, RXPERF_CALL_SV_REPLYING);