Skip to content
/ linux Public

Commit 97a907b

Browse files
chuckleverSasha Levin
authored andcommitted
RDMA/core: add rdma_rw_max_sge() helper for SQ sizing
[ Upstream commit afcae7d ] svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the number of rdma_rw contexts (ctxts). This value is used to allocate the Send CQ and to initialize the sc_sq_avail credit pool. However, when the device uses memory registration for RDMA operations, rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three per context to account for REG and INV work requests. The Send CQ and credit pool remain sized for only one work request per context, causing Send Queue exhaustion under heavy NFS WRITE workloads. Introduce rdma_rw_max_sge() to compute the actual number of Send Queue entries required for a given number of rdma_rw contexts. Upper layer protocols call this helper before creating a Queue Pair so that their Send CQs and credit accounting match the QP's true capacity. Update svc_rdma_accept() to use rdma_rw_max_sge() when computing sc_sq_depth, ensuring the credit pool reflects the work requests that rdma_rw_init_qp() will reserve. Reviewed-by: Christoph Hellwig <hch@lst.de> Fixes: 00bd143 ("RDMA/rw: Support threshold for registration vs scattering to local pages") Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org Signed-off-by: Leon Romanovsky <leon@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 6ba731f commit 97a907b

File tree

3 files changed

+46
-17
lines changed

3 files changed

+46
-17
lines changed

drivers/infiniband/core/rw.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num,
651651
}
652652
EXPORT_SYMBOL(rdma_rw_mr_factor);
653653

654+
/**
655+
* rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts
656+
* @dev: RDMA device
657+
* @port_num: port number
658+
* @max_rdma_ctxs: number of rdma_rw_ctx structures
659+
* @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if
660+
* data integrity will be enabled on the QP)
661+
*
662+
* Returns the total number of Send Queue entries needed for
663+
* @max_rdma_ctxs. The result accounts for memory registration and
664+
* invalidation work requests when the device requires them.
665+
*
666+
* ULPs use this to size Send Queues and Send CQs before creating a
667+
* Queue Pair.
668+
*/
669+
unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num,
670+
unsigned int max_rdma_ctxs, u32 create_flags)
671+
{
672+
unsigned int factor = 1;
673+
unsigned int result;
674+
675+
if (create_flags & IB_QP_CREATE_INTEGRITY_EN ||
676+
rdma_rw_can_use_mr(dev, port_num))
677+
factor += 2; /* reg + inv */
678+
679+
if (check_mul_overflow(factor, max_rdma_ctxs, &result))
680+
return UINT_MAX;
681+
return result;
682+
}
683+
EXPORT_SYMBOL(rdma_rw_max_send_wr);
684+
654685
void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr)
655686
{
656-
u32 factor;
687+
unsigned int factor = 1;
657688

658689
WARN_ON_ONCE(attr->port_num == 0);
659690

660691
/*
661-
* Each context needs at least one RDMA READ or WRITE WR.
662-
*
663-
* For some hardware we might need more, eventually we should ask the
664-
* HCA driver for a multiplier here.
665-
*/
666-
factor = 1;
667-
668-
/*
669-
* If the device needs MRs to perform RDMA READ or WRITE operations,
670-
* we'll need two additional MRs for the registrations and the
671-
* invalidation.
692+
* If the device uses MRs to perform RDMA READ or WRITE operations,
693+
* or if data integrity is enabled, account for registration and
694+
* invalidation work requests.
672695
*/
673696
if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN ||
674697
rdma_rw_can_use_mr(dev, attr->port_num))
675-
factor += 2; /* inv + reg */
698+
factor += 2; /* reg + inv */
676699

677700
attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs;
678701

679702
/*
680-
* But maybe we were just too high in the sky and the device doesn't
681-
* even support all we need, and we'll have to live with what we get..
703+
* The device might not support all we need, and we'll have to
704+
* live with what we get.
682705
*/
683706
attr->cap.max_send_wr =
684707
min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr);

include/rdma/rw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num,
6666

6767
unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num,
6868
unsigned int maxpages);
69+
unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num,
70+
unsigned int max_rdma_ctxs, u32 create_flags);
6971
void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr);
7072
int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr);
7173
void rdma_rw_cleanup_mrs(struct ib_qp *qp);

net/sunrpc/xprtrdma/svc_rdma_transport.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,15 +418,19 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
418418
newxprt->sc_max_bc_requests = 2;
419419
}
420420

421-
/* Arbitrary estimate of the needed number of rdma_rw contexts.
421+
/* Estimate the needed number of rdma_rw contexts. The maximum
422+
* Read and Write chunks have one segment each. Each request
423+
* can involve one Read chunk and either a Write chunk or Reply
424+
* chunk; thus a factor of three.
422425
*/
423426
maxpayload = min(xprt->xpt_server->sv_max_payload,
424427
RPCSVC_MAXPAYLOAD_RDMA);
425428
ctxts = newxprt->sc_max_requests * 3 *
426429
rdma_rw_mr_factor(dev, newxprt->sc_port_num,
427430
maxpayload >> PAGE_SHIFT);
428431

429-
newxprt->sc_sq_depth = rq_depth + ctxts;
432+
newxprt->sc_sq_depth = rq_depth +
433+
rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0);
430434
if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr)
431435
newxprt->sc_sq_depth = dev->attrs.max_qp_wr;
432436
atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth);

0 commit comments

Comments
 (0)