Skip to content

Commit 773f91b

Browse files
committed
SUNRPC: Fix NFSD's request deferral on RDMA transports
Trond Myklebust reports an NFSD crash in svc_rdma_sendto(). Further investigation shows that the crash occurred while NFSD was handling a deferred request. This patch addresses two inter-related issues that prevent request deferral from working correctly for RPC/RDMA requests: 1. Prevent the crash by ensuring that the original svc_rqst::rq_xprt_ctxt value is available when the request is revisited. Otherwise svc_rdma_sendto() does not have a Receive context available with which to construct its reply. 2. Possibly since before commit 71641d9 ("svcrdma: Properly compute .len and .buflen for received RPC Calls"), svc_rdma_recvfrom() did not include the transport header in the returned xdr_buf. There should have been no need for svc_defer() and friends to save and restore that header, as of that commit. This issue is addressed in a backport-friendly way by simply having svc_rdma_recvfrom() set rq_xprt_hlen to zero unconditionally, just as svc_tcp_recvfrom() does. This enables svc_deferred_recv() to correctly reconstruct an RPC message received via RPC/RDMA. Reported-by: Trond Myklebust <trondmy@hammerspace.com> Link: https://lore.kernel.org/linux-nfs/82662b7190f26fb304eb0ab1bb04279072439d4e.camel@hammerspace.com/ Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Cc: <stable@vger.kernel.org>
1 parent 9993979 commit 773f91b

3 files changed

Lines changed: 5 additions & 1 deletion

File tree

include/linux/sunrpc/svc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ struct svc_deferred_req {
395395
size_t addrlen;
396396
struct sockaddr_storage daddr; /* where reply must come from */
397397
size_t daddrlen;
398+
void *xprt_ctxt;
398399
struct cache_deferred_req handle;
399400
size_t xprt_hlen;
400401
int argslen;

net/sunrpc/svc_xprt.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,8 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
12311231
dr->daddr = rqstp->rq_daddr;
12321232
dr->argslen = rqstp->rq_arg.len >> 2;
12331233
dr->xprt_hlen = rqstp->rq_xprt_hlen;
1234+
dr->xprt_ctxt = rqstp->rq_xprt_ctxt;
1235+
rqstp->rq_xprt_ctxt = NULL;
12341236

12351237
/* back up head to the start of the buffer and copy */
12361238
skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
@@ -1269,6 +1271,7 @@ static noinline int svc_deferred_recv(struct svc_rqst *rqstp)
12691271
rqstp->rq_xprt_hlen = dr->xprt_hlen;
12701272
rqstp->rq_daddr = dr->daddr;
12711273
rqstp->rq_respages = rqstp->rq_pages;
1274+
rqstp->rq_xprt_ctxt = dr->xprt_ctxt;
12721275
svc_xprt_received(rqstp->rq_xprt);
12731276
return (dr->argslen<<2) - dr->xprt_hlen;
12741277
}

net/sunrpc/xprtrdma/svc_rdma_recvfrom.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
831831
goto out_err;
832832
if (ret == 0)
833833
goto out_drop;
834-
rqstp->rq_xprt_hlen = ret;
834+
rqstp->rq_xprt_hlen = 0;
835835

836836
if (svc_rdma_is_reverse_direction_reply(xprt, ctxt))
837837
goto out_backchannel;

0 commit comments

Comments
 (0)