Skip to content

Commit 25fd86e

Browse files
chuckleverJ. Bruce Fields
authored andcommitted
svcrdma: Don't overrun the SGE array in svc_rdma_send_ctxt
Receive buffers are always the same size, but each Send WR has a variable number of SGEs, based on the contents of the xdr_buf being sent. While assembling a Send WR, keep track of the number of SGEs so that we don't exceed the device's maximum, or walk off the end of the Send SGE array. For now the Send path just fails if it exceeds the maximum. The current logic in svc_rdma_accept bases the maximum number of Send SGEs on the largest NFS request that can be sent or received. In the transport layer, the limit is actually based on the capabilities of the underlying device, not on properties of the Upper Layer Protocol. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent 4201c74 commit 25fd86e

File tree

3 files changed

+33
-25
lines changed

3 files changed

+33
-25
lines changed

include/linux/sunrpc/svc_rdma.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ struct svcxprt_rdma {
9696
struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
9797
struct list_head sc_accept_q; /* Conn. waiting accept */
9898
int sc_ord; /* RDMA read limit */
99-
int sc_max_sge;
99+
int sc_max_send_sges;
100100
bool sc_snd_w_inv; /* OK to use Send With Invalidate */
101101

102102
atomic_t sc_sq_avail; /* SQEs ready to be consumed */
@@ -158,17 +158,14 @@ struct svc_rdma_recv_ctxt {
158158
struct page *rc_pages[RPCSVC_MAXPAGES];
159159
};
160160

161-
enum {
162-
RPCRDMA_MAX_SGES = 1 + (RPCRDMA_MAX_INLINE_THRESH / PAGE_SIZE),
163-
};
164-
165161
struct svc_rdma_send_ctxt {
166162
struct list_head sc_list;
167163
struct ib_send_wr sc_send_wr;
168164
struct ib_cqe sc_cqe;
169165
int sc_page_count;
166+
int sc_cur_sge_no;
170167
struct page *sc_pages[RPCSVC_MAXPAGES];
171-
struct ib_sge sc_sges[RPCRDMA_MAX_SGES];
168+
struct ib_sge sc_sges[];
172169
};
173170

174171
/* svc_rdma_backchannel.c */

net/sunrpc/xprtrdma/svc_rdma_sendto.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,12 @@ static struct svc_rdma_send_ctxt *
127127
svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma)
128128
{
129129
struct svc_rdma_send_ctxt *ctxt;
130+
size_t size;
130131
int i;
131132

132-
ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
133+
size = sizeof(*ctxt);
134+
size += rdma->sc_max_send_sges * sizeof(struct ib_sge);
135+
ctxt = kmalloc(size, GFP_KERNEL);
133136
if (!ctxt)
134137
return NULL;
135138

@@ -138,7 +141,7 @@ svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma)
138141
ctxt->sc_send_wr.wr_cqe = &ctxt->sc_cqe;
139142
ctxt->sc_send_wr.sg_list = ctxt->sc_sges;
140143
ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED;
141-
for (i = 0; i < ARRAY_SIZE(ctxt->sc_sges); i++)
144+
for (i = 0; i < rdma->sc_max_send_sges; i++)
142145
ctxt->sc_sges[i].lkey = rdma->sc_pd->local_dma_lkey;
143146
return ctxt;
144147
}
@@ -482,7 +485,6 @@ static u32 svc_rdma_get_inv_rkey(__be32 *rdma_argp,
482485

483486
static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma,
484487
struct svc_rdma_send_ctxt *ctxt,
485-
unsigned int sge_no,
486488
struct page *page,
487489
unsigned long offset,
488490
unsigned int len)
@@ -494,8 +496,8 @@ static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma,
494496
if (ib_dma_mapping_error(dev, dma_addr))
495497
goto out_maperr;
496498

497-
ctxt->sc_sges[sge_no].addr = dma_addr;
498-
ctxt->sc_sges[sge_no].length = len;
499+
ctxt->sc_sges[ctxt->sc_cur_sge_no].addr = dma_addr;
500+
ctxt->sc_sges[ctxt->sc_cur_sge_no].length = len;
499501
ctxt->sc_send_wr.num_sge++;
500502
return 0;
501503

@@ -509,11 +511,10 @@ static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma,
509511
*/
510512
static int svc_rdma_dma_map_buf(struct svcxprt_rdma *rdma,
511513
struct svc_rdma_send_ctxt *ctxt,
512-
unsigned int sge_no,
513514
unsigned char *base,
514515
unsigned int len)
515516
{
516-
return svc_rdma_dma_map_page(rdma, ctxt, sge_no, virt_to_page(base),
517+
return svc_rdma_dma_map_page(rdma, ctxt, virt_to_page(base),
517518
offset_in_page(base), len);
518519
}
519520

@@ -535,7 +536,8 @@ int svc_rdma_map_reply_hdr(struct svcxprt_rdma *rdma,
535536
{
536537
ctxt->sc_pages[0] = virt_to_page(rdma_resp);
537538
ctxt->sc_page_count++;
538-
return svc_rdma_dma_map_page(rdma, ctxt, 0, ctxt->sc_pages[0], 0, len);
539+
ctxt->sc_cur_sge_no = 0;
540+
return svc_rdma_dma_map_page(rdma, ctxt, ctxt->sc_pages[0], 0, len);
539541
}
540542

541543
/* Load the xdr_buf into the ctxt's sge array, and DMA map each
@@ -547,16 +549,16 @@ static int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
547549
struct svc_rdma_send_ctxt *ctxt,
548550
struct xdr_buf *xdr, __be32 *wr_lst)
549551
{
550-
unsigned int len, sge_no, remaining;
552+
unsigned int len, remaining;
551553
unsigned long page_off;
552554
struct page **ppages;
553555
unsigned char *base;
554556
u32 xdr_pad;
555557
int ret;
556558

557-
sge_no = 1;
558-
559-
ret = svc_rdma_dma_map_buf(rdma, ctxt, sge_no++,
559+
if (++ctxt->sc_cur_sge_no >= rdma->sc_max_send_sges)
560+
return -EIO;
561+
ret = svc_rdma_dma_map_buf(rdma, ctxt,
560562
xdr->head[0].iov_base,
561563
xdr->head[0].iov_len);
562564
if (ret < 0)
@@ -586,8 +588,10 @@ static int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
586588
while (remaining) {
587589
len = min_t(u32, PAGE_SIZE - page_off, remaining);
588590

589-
ret = svc_rdma_dma_map_page(rdma, ctxt, sge_no++,
590-
*ppages++, page_off, len);
591+
if (++ctxt->sc_cur_sge_no >= rdma->sc_max_send_sges)
592+
return -EIO;
593+
ret = svc_rdma_dma_map_page(rdma, ctxt, *ppages++,
594+
page_off, len);
591595
if (ret < 0)
592596
return ret;
593597

@@ -599,7 +603,9 @@ static int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
599603
len = xdr->tail[0].iov_len;
600604
tail:
601605
if (len) {
602-
ret = svc_rdma_dma_map_buf(rdma, ctxt, sge_no++, base, len);
606+
if (++ctxt->sc_cur_sge_no >= rdma->sc_max_send_sges)
607+
return -EIO;
608+
ret = svc_rdma_dma_map_buf(rdma, ctxt, base, len);
603609
if (ret < 0)
604610
return ret;
605611
}

net/sunrpc/xprtrdma/svc_rdma_transport.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,13 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
476476

477477
/* Qualify the transport resource defaults with the
478478
* capabilities of this particular device */
479-
newxprt->sc_max_sge = min((size_t)dev->attrs.max_sge,
480-
(size_t)RPCSVC_MAXPAGES);
479+
newxprt->sc_max_send_sges = dev->attrs.max_sge;
480+
/* transport hdr, head iovec, one page list entry, tail iovec */
481+
if (newxprt->sc_max_send_sges < 4) {
482+
pr_err("svcrdma: too few Send SGEs available (%d)\n",
483+
newxprt->sc_max_send_sges);
484+
goto errout;
485+
}
481486
newxprt->sc_max_req_size = svcrdma_max_req_size;
482487
newxprt->sc_max_requests = svcrdma_max_requests;
483488
newxprt->sc_max_bc_requests = svcrdma_max_bc_requests;
@@ -525,7 +530,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
525530
qp_attr.cap.max_rdma_ctxs = ctxts;
526531
qp_attr.cap.max_send_wr = newxprt->sc_sq_depth - ctxts;
527532
qp_attr.cap.max_recv_wr = rq_depth;
528-
qp_attr.cap.max_send_sge = newxprt->sc_max_sge;
533+
qp_attr.cap.max_send_sge = newxprt->sc_max_send_sges;
529534
qp_attr.cap.max_recv_sge = 1;
530535
qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
531536
qp_attr.qp_type = IB_QPT_RC;
@@ -586,7 +591,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
586591
dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap));
587592
sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
588593
dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap));
589-
dprintk(" max_sge : %d\n", newxprt->sc_max_sge);
594+
dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges);
590595
dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth);
591596
dprintk(" rdma_rw_ctxs : %d\n", ctxts);
592597
dprintk(" max_requests : %d\n", newxprt->sc_max_requests);

0 commit comments

Comments
 (0)