mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
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 71641d99ce
("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>
This commit is contained in:
parent
999397926a
commit
773f91b2cf
@ -395,6 +395,7 @@ struct svc_deferred_req {
|
||||
size_t addrlen;
|
||||
struct sockaddr_storage daddr; /* where reply must come from */
|
||||
size_t daddrlen;
|
||||
void *xprt_ctxt;
|
||||
struct cache_deferred_req handle;
|
||||
size_t xprt_hlen;
|
||||
int argslen;
|
||||
|
@ -1231,6 +1231,8 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
|
||||
dr->daddr = rqstp->rq_daddr;
|
||||
dr->argslen = rqstp->rq_arg.len >> 2;
|
||||
dr->xprt_hlen = rqstp->rq_xprt_hlen;
|
||||
dr->xprt_ctxt = rqstp->rq_xprt_ctxt;
|
||||
rqstp->rq_xprt_ctxt = NULL;
|
||||
|
||||
/* back up head to the start of the buffer and copy */
|
||||
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)
|
||||
rqstp->rq_xprt_hlen = dr->xprt_hlen;
|
||||
rqstp->rq_daddr = dr->daddr;
|
||||
rqstp->rq_respages = rqstp->rq_pages;
|
||||
rqstp->rq_xprt_ctxt = dr->xprt_ctxt;
|
||||
svc_xprt_received(rqstp->rq_xprt);
|
||||
return (dr->argslen<<2) - dr->xprt_hlen;
|
||||
}
|
||||
|
@ -831,7 +831,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
|
||||
goto out_err;
|
||||
if (ret == 0)
|
||||
goto out_drop;
|
||||
rqstp->rq_xprt_hlen = ret;
|
||||
rqstp->rq_xprt_hlen = 0;
|
||||
|
||||
if (svc_rdma_is_reverse_direction_reply(xprt, ctxt))
|
||||
goto out_backchannel;
|
||||
|
Loading…
Reference in New Issue
Block a user