Skip to content

Commit 16f906d

Browse files
chuckleveramschuma-ntap
authored andcommitted
xprtrdma: Reduce required number of send SGEs
The MAX_SEND_SGES check introduced in commit 655fec6 ("xprtrdma: Use gathered Send for large inline messages") fails for devices that have a small max_sge. Instead of checking for a large fixed maximum number of SGEs, check for a minimum small number. RPC-over-RDMA will switch to using a Read chunk if an xdr_buf has more pages than can fit in the device's max_sge limit. This is considerably better than failing all together to mount the server. This fix supports devices that have as few as three send SGEs available. Reported-by: Selvin Xavier <[email protected]> Reported-by: Devesh Sharma <[email protected]> Reported-by: Honggang Li <[email protected]> Reported-by: Ram Amrani <[email protected]> Fixes: 655fec6 ("xprtrdma: Use gathered Send for large ...") Cc: [email protected] # v4.9+ Tested-by: Honggang Li <[email protected]> Tested-by: Ram Amrani <[email protected]> Tested-by: Steve Wise <[email protected]> Reviewed-by: Parav Pandit <[email protected]> Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent c95a3c6 commit 16f906d

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

net/sunrpc/xprtrdma/rpc_rdma.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,34 @@ void rpcrdma_set_max_header_sizes(struct rpcrdma_xprt *r_xprt)
125125
/* The client can send a request inline as long as the RPCRDMA header
126126
* plus the RPC call fit under the transport's inline limit. If the
127127
* combined call message size exceeds that limit, the client must use
128-
* the read chunk list for this operation.
128+
* a Read chunk for this operation.
129+
*
130+
* A Read chunk is also required if sending the RPC call inline would
131+
* exceed this device's max_sge limit.
129132
*/
130133
static bool rpcrdma_args_inline(struct rpcrdma_xprt *r_xprt,
131134
struct rpc_rqst *rqst)
132135
{
133-
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
136+
struct xdr_buf *xdr = &rqst->rq_snd_buf;
137+
unsigned int count, remaining, offset;
138+
139+
if (xdr->len > r_xprt->rx_ia.ri_max_inline_write)
140+
return false;
134141

135-
return rqst->rq_snd_buf.len <= ia->ri_max_inline_write;
142+
if (xdr->page_len) {
143+
remaining = xdr->page_len;
144+
offset = xdr->page_base & ~PAGE_MASK;
145+
count = 0;
146+
while (remaining) {
147+
remaining -= min_t(unsigned int,
148+
PAGE_SIZE - offset, remaining);
149+
offset = 0;
150+
if (++count > r_xprt->rx_ia.ri_max_send_sges)
151+
return false;
152+
}
153+
}
154+
155+
return true;
136156
}
137157

138158
/* The client can't know how large the actual reply will be. Thus it

net/sunrpc/xprtrdma/verbs.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,18 +488,19 @@ rpcrdma_ia_close(struct rpcrdma_ia *ia)
488488
*/
489489
int
490490
rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
491-
struct rpcrdma_create_data_internal *cdata)
491+
struct rpcrdma_create_data_internal *cdata)
492492
{
493493
struct rpcrdma_connect_private *pmsg = &ep->rep_cm_private;
494+
unsigned int max_qp_wr, max_sge;
494495
struct ib_cq *sendcq, *recvcq;
495-
unsigned int max_qp_wr;
496496
int rc;
497497

498-
if (ia->ri_device->attrs.max_sge < RPCRDMA_MAX_SEND_SGES) {
499-
dprintk("RPC: %s: insufficient sge's available\n",
500-
__func__);
498+
max_sge = min(ia->ri_device->attrs.max_sge, RPCRDMA_MAX_SEND_SGES);
499+
if (max_sge < RPCRDMA_MIN_SEND_SGES) {
500+
pr_warn("rpcrdma: HCA provides only %d send SGEs\n", max_sge);
501501
return -ENOMEM;
502502
}
503+
ia->ri_max_send_sges = max_sge - RPCRDMA_MIN_SEND_SGES;
503504

504505
if (ia->ri_device->attrs.max_qp_wr <= RPCRDMA_BACKWARD_WRS) {
505506
dprintk("RPC: %s: insufficient wqe's available\n",
@@ -524,7 +525,7 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
524525
ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
525526
ep->rep_attr.cap.max_recv_wr += RPCRDMA_BACKWARD_WRS;
526527
ep->rep_attr.cap.max_recv_wr += 1; /* drain cqe */
527-
ep->rep_attr.cap.max_send_sge = RPCRDMA_MAX_SEND_SGES;
528+
ep->rep_attr.cap.max_send_sge = max_sge;
528529
ep->rep_attr.cap.max_recv_sge = 1;
529530
ep->rep_attr.cap.max_inline_data = 0;
530531
ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;

net/sunrpc/xprtrdma/xprt_rdma.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct rpcrdma_ia {
7474
unsigned int ri_max_frmr_depth;
7575
unsigned int ri_max_inline_write;
7676
unsigned int ri_max_inline_read;
77+
unsigned int ri_max_send_sges;
7778
bool ri_reminv_expected;
7879
bool ri_implicit_roundup;
7980
enum ib_mr_type ri_mrtype;
@@ -311,6 +312,7 @@ struct rpcrdma_mr_seg { /* chunk descriptors */
311312
* - xdr_buf tail iovec
312313
*/
313314
enum {
315+
RPCRDMA_MIN_SEND_SGES = 3,
314316
RPCRDMA_MAX_SEND_PAGES = PAGE_SIZE + RPCRDMA_MAX_INLINE - 1,
315317
RPCRDMA_MAX_PAGE_SGES = (RPCRDMA_MAX_SEND_PAGES >> PAGE_SHIFT) + 1,
316318
RPCRDMA_MAX_SEND_SGES = 1 + 1 + RPCRDMA_MAX_PAGE_SGES + 1,

0 commit comments

Comments
 (0)