xprtrdma: Fix ri_max_segs and the result of ro_maxpages
authorChuck Lever <chuck.lever@oracle.com>
Wed, 19 Dec 2018 15:58:45 +0000 (10:58 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 2 Jan 2019 17:05:16 +0000 (12:05 -0500)
With certain combinations of krb5i/p, MR size, and r/wsize, I/O can
fail with EMSGSIZE. This is because the calculated value of
ri_max_segs (the max number of MRs per RPC) exceeded
RPCRDMA_MAX_HDR_SEGS, which caused Read or Write list encoding to
walk off the end of the transport header.

Once that was addressed, the ro_maxpages result has to be corrected
to account for the number of MRs needed for Reply chunks, which is
2 MRs smaller than a normal Read or Write chunk.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
net/sunrpc/xprtrdma/fmr_ops.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/transport.c

index 7f5632cd5a48acad0e258043bd8affbac6406c05..dd1e91bd8ef8796131144d12de4605c8a9bd3edb 100644 (file)
@@ -176,7 +176,10 @@ fmr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep,
 
        ia->ri_max_segs = max_t(unsigned int, 1, RPCRDMA_MAX_DATA_SEGS /
                                RPCRDMA_MAX_FMR_SGES);
-       ia->ri_max_segs += 2;   /* segments for head and tail buffers */
+       /* Reply chunks require segments for head and tail buffers */
+       ia->ri_max_segs += 2;
+       if (ia->ri_max_segs > RPCRDMA_MAX_HDR_SEGS)
+               ia->ri_max_segs = RPCRDMA_MAX_HDR_SEGS;
        return 0;
 }
 
@@ -186,7 +189,7 @@ static size_t
 fmr_op_maxpages(struct rpcrdma_xprt *r_xprt)
 {
        return min_t(unsigned int, RPCRDMA_MAX_DATA_SEGS,
-                    RPCRDMA_MAX_HDR_SEGS * RPCRDMA_MAX_FMR_SGES);
+                    (r_xprt->rx_ia.ri_max_segs - 2) * RPCRDMA_MAX_FMR_SGES);
 }
 
 /* Use the ib_map_phys_fmr() verb to register a memory region
index 27222c034ad233adfa590ca0876e24acc7068450..f587e445d8114b80574487fce1b9e19c0f1dc592 100644 (file)
@@ -244,7 +244,10 @@ frwr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep,
 
        ia->ri_max_segs = max_t(unsigned int, 1, RPCRDMA_MAX_DATA_SEGS /
                                ia->ri_max_frwr_depth);
-       ia->ri_max_segs += 2;   /* segments for head and tail buffers */
+       /* Reply chunks require segments for head and tail buffers */
+       ia->ri_max_segs += 2;
+       if (ia->ri_max_segs > RPCRDMA_MAX_HDR_SEGS)
+               ia->ri_max_segs = RPCRDMA_MAX_HDR_SEGS;
        return 0;
 }
 
@@ -257,7 +260,7 @@ frwr_op_maxpages(struct rpcrdma_xprt *r_xprt)
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
 
        return min_t(unsigned int, RPCRDMA_MAX_DATA_SEGS,
-                    RPCRDMA_MAX_HDR_SEGS * ia->ri_max_frwr_depth);
+                    (ia->ri_max_segs - 2) * ia->ri_max_frwr_depth);
 }
 
 static void
index 134aae2ee779b9951f0359e6cba4807e782c8188..d3f26c57006740158fcf7a810544be9079350a3d 100644 (file)
@@ -703,8 +703,10 @@ xprt_rdma_free(struct rpc_task *task)
  *     %-ENOTCONN if the caller should reconnect and call again
  *     %-EAGAIN if the caller should call again
  *     %-ENOBUFS if the caller should call again after a delay
- *     %-EIO if a permanent error occurred and the request was not
- *             sent. Do not try to send this message again.
+ *     %-EMSGSIZE if encoding ran out of buffer space. The request
+ *             was not sent. Do not try to send this message again.
+ *     %-EIO if an I/O error occurred. The request was not sent.
+ *             Do not try to send this message again.
  */
 static int
 xprt_rdma_send_request(struct rpc_rqst *rqst)