diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2018-05-07 15:28:25 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2018-05-11 15:48:57 -0400 |
commit | 99722fe4d5a634707ced8d8f42b883b87a86b3c5 (patch) | |
tree | bc89587516be20f4c18330e63c28f087d8749896 | |
parent | 3abb03facee06ea052be6e3a435f6dbb4e54fc04 (diff) |
svcrdma: Persistently allocate and DMA-map Send buffers
While sending each RPC Reply, svc_rdma_sendto allocates and DMA-
maps a separate buffer where the RPC/RDMA transport header is
constructed. The buffer is unmapped and released in the Send
completion handler. This is significant per-RPC overhead,
especially for small RPCs.
Instead, allocate and DMA-map a buffer, and cache it in each
svc_rdma_send_ctxt. This buffer and its mapping can be re-used
for each RPC, saving the cost of memory allocation and DMA
mapping.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | include/linux/sunrpc/svc_rdma.h | 8 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 51 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 25 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_sendto.c | 149 |
4 files changed, 105 insertions, 128 deletions
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index a8bfc214614b..96b14a72d359 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h | |||
@@ -162,6 +162,7 @@ struct svc_rdma_send_ctxt { | |||
162 | struct list_head sc_list; | 162 | struct list_head sc_list; |
163 | struct ib_send_wr sc_send_wr; | 163 | struct ib_send_wr sc_send_wr; |
164 | struct ib_cqe sc_cqe; | 164 | struct ib_cqe sc_cqe; |
165 | void *sc_xprt_buf; | ||
165 | int sc_page_count; | 166 | int sc_page_count; |
166 | int sc_cur_sge_no; | 167 | int sc_cur_sge_no; |
167 | struct page *sc_pages[RPCSVC_MAXPAGES]; | 168 | struct page *sc_pages[RPCSVC_MAXPAGES]; |
@@ -199,9 +200,12 @@ extern struct svc_rdma_send_ctxt * | |||
199 | extern void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma, | 200 | extern void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma, |
200 | struct svc_rdma_send_ctxt *ctxt); | 201 | struct svc_rdma_send_ctxt *ctxt); |
201 | extern int svc_rdma_send(struct svcxprt_rdma *rdma, struct ib_send_wr *wr); | 202 | extern int svc_rdma_send(struct svcxprt_rdma *rdma, struct ib_send_wr *wr); |
202 | extern int svc_rdma_map_reply_hdr(struct svcxprt_rdma *rdma, | 203 | extern void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, |
204 | struct svc_rdma_send_ctxt *ctxt, | ||
205 | unsigned int len); | ||
206 | extern int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, | ||
203 | struct svc_rdma_send_ctxt *ctxt, | 207 | struct svc_rdma_send_ctxt *ctxt, |
204 | __be32 *rdma_resp, unsigned int len); | 208 | struct xdr_buf *xdr, __be32 *wr_lst); |
205 | extern int svc_rdma_sendto(struct svc_rqst *); | 209 | extern int svc_rdma_sendto(struct svc_rqst *); |
206 | 210 | ||
207 | /* svc_rdma_transport.c */ | 211 | /* svc_rdma_transport.c */ |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 40f5e4afbcc8..343e7add672c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c | |||
@@ -115,43 +115,21 @@ out_notfound: | |||
115 | * the adapter has a small maximum SQ depth. | 115 | * the adapter has a small maximum SQ depth. |
116 | */ | 116 | */ |
117 | static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma, | 117 | static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma, |
118 | struct rpc_rqst *rqst) | 118 | struct rpc_rqst *rqst, |
119 | struct svc_rdma_send_ctxt *ctxt) | ||
119 | { | 120 | { |
120 | struct svc_rdma_send_ctxt *ctxt; | ||
121 | int ret; | 121 | int ret; |
122 | 122 | ||
123 | ctxt = svc_rdma_send_ctxt_get(rdma); | 123 | ret = svc_rdma_map_reply_msg(rdma, ctxt, &rqst->rq_snd_buf, NULL); |
124 | if (!ctxt) { | ||
125 | ret = -ENOMEM; | ||
126 | goto out_err; | ||
127 | } | ||
128 | |||
129 | /* rpcrdma_bc_send_request builds the transport header and | ||
130 | * the backchannel RPC message in the same buffer. Thus only | ||
131 | * one SGE is needed to send both. | ||
132 | */ | ||
133 | ret = svc_rdma_map_reply_hdr(rdma, ctxt, rqst->rq_buffer, | ||
134 | rqst->rq_snd_buf.len); | ||
135 | if (ret < 0) | 124 | if (ret < 0) |
136 | goto out_err; | 125 | return -EIO; |
137 | 126 | ||
138 | /* Bump page refcnt so Send completion doesn't release | 127 | /* Bump page refcnt so Send completion doesn't release |
139 | * the rq_buffer before all retransmits are complete. | 128 | * the rq_buffer before all retransmits are complete. |
140 | */ | 129 | */ |
141 | get_page(virt_to_page(rqst->rq_buffer)); | 130 | get_page(virt_to_page(rqst->rq_buffer)); |
142 | ctxt->sc_send_wr.opcode = IB_WR_SEND; | 131 | ctxt->sc_send_wr.opcode = IB_WR_SEND; |
143 | ret = svc_rdma_send(rdma, &ctxt->sc_send_wr); | 132 | return svc_rdma_send(rdma, &ctxt->sc_send_wr); |
144 | if (ret) | ||
145 | goto out_unmap; | ||
146 | |||
147 | out_err: | ||
148 | dprintk("svcrdma: %s returns %d\n", __func__, ret); | ||
149 | return ret; | ||
150 | |||
151 | out_unmap: | ||
152 | svc_rdma_send_ctxt_put(rdma, ctxt); | ||
153 | ret = -EIO; | ||
154 | goto out_err; | ||
155 | } | 133 | } |
156 | 134 | ||
157 | /* Server-side transport endpoint wants a whole page for its send | 135 | /* Server-side transport endpoint wants a whole page for its send |
@@ -198,13 +176,15 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct rpc_rqst *rqst) | |||
198 | { | 176 | { |
199 | struct rpc_xprt *xprt = rqst->rq_xprt; | 177 | struct rpc_xprt *xprt = rqst->rq_xprt; |
200 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); | 178 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); |
179 | struct svc_rdma_send_ctxt *ctxt; | ||
201 | __be32 *p; | 180 | __be32 *p; |
202 | int rc; | 181 | int rc; |
203 | 182 | ||
204 | /* Space in the send buffer for an RPC/RDMA header is reserved | 183 | ctxt = svc_rdma_send_ctxt_get(rdma); |
205 | * via xprt->tsh_size. | 184 | if (!ctxt) |
206 | */ | 185 | goto drop_connection; |
207 | p = rqst->rq_buffer; | 186 | |
187 | p = ctxt->sc_xprt_buf; | ||
208 | *p++ = rqst->rq_xid; | 188 | *p++ = rqst->rq_xid; |
209 | *p++ = rpcrdma_version; | 189 | *p++ = rpcrdma_version; |
210 | *p++ = cpu_to_be32(r_xprt->rx_buf.rb_bc_max_requests); | 190 | *p++ = cpu_to_be32(r_xprt->rx_buf.rb_bc_max_requests); |
@@ -212,14 +192,17 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct rpc_rqst *rqst) | |||
212 | *p++ = xdr_zero; | 192 | *p++ = xdr_zero; |
213 | *p++ = xdr_zero; | 193 | *p++ = xdr_zero; |
214 | *p = xdr_zero; | 194 | *p = xdr_zero; |
195 | svc_rdma_sync_reply_hdr(rdma, ctxt, RPCRDMA_HDRLEN_MIN); | ||
215 | 196 | ||
216 | #ifdef SVCRDMA_BACKCHANNEL_DEBUG | 197 | #ifdef SVCRDMA_BACKCHANNEL_DEBUG |
217 | pr_info("%s: %*ph\n", __func__, 64, rqst->rq_buffer); | 198 | pr_info("%s: %*ph\n", __func__, 64, rqst->rq_buffer); |
218 | #endif | 199 | #endif |
219 | 200 | ||
220 | rc = svc_rdma_bc_sendto(rdma, rqst); | 201 | rc = svc_rdma_bc_sendto(rdma, rqst, ctxt); |
221 | if (rc) | 202 | if (rc) { |
203 | svc_rdma_send_ctxt_put(rdma, ctxt); | ||
222 | goto drop_connection; | 204 | goto drop_connection; |
205 | } | ||
223 | return rc; | 206 | return rc; |
224 | 207 | ||
225 | drop_connection: | 208 | drop_connection: |
@@ -327,7 +310,7 @@ xprt_setup_rdma_bc(struct xprt_create *args) | |||
327 | xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO; | 310 | xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO; |
328 | 311 | ||
329 | xprt->prot = XPRT_TRANSPORT_BC_RDMA; | 312 | xprt->prot = XPRT_TRANSPORT_BC_RDMA; |
330 | xprt->tsh_size = RPCRDMA_HDRLEN_MIN / sizeof(__be32); | 313 | xprt->tsh_size = 0; |
331 | xprt->ops = &xprt_rdma_bc_procs; | 314 | xprt->ops = &xprt_rdma_bc_procs; |
332 | 315 | ||
333 | memcpy(&xprt->addr, args->dstaddr, args->addrlen); | 316 | memcpy(&xprt->addr, args->dstaddr, args->addrlen); |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 68648e6c5be2..09ce09b3ac6e 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
@@ -602,17 +602,15 @@ static void svc_rdma_send_error(struct svcxprt_rdma *xprt, | |||
602 | __be32 *rdma_argp, int status) | 602 | __be32 *rdma_argp, int status) |
603 | { | 603 | { |
604 | struct svc_rdma_send_ctxt *ctxt; | 604 | struct svc_rdma_send_ctxt *ctxt; |
605 | __be32 *p, *err_msgp; | ||
606 | unsigned int length; | 605 | unsigned int length; |
607 | struct page *page; | 606 | __be32 *p; |
608 | int ret; | 607 | int ret; |
609 | 608 | ||
610 | page = alloc_page(GFP_KERNEL); | 609 | ctxt = svc_rdma_send_ctxt_get(xprt); |
611 | if (!page) | 610 | if (!ctxt) |
612 | return; | 611 | return; |
613 | err_msgp = page_address(page); | ||
614 | 612 | ||
615 | p = err_msgp; | 613 | p = ctxt->sc_xprt_buf; |
616 | *p++ = *rdma_argp; | 614 | *p++ = *rdma_argp; |
617 | *p++ = *(rdma_argp + 1); | 615 | *p++ = *(rdma_argp + 1); |
618 | *p++ = xprt->sc_fc_credits; | 616 | *p++ = xprt->sc_fc_credits; |
@@ -628,19 +626,8 @@ static void svc_rdma_send_error(struct svcxprt_rdma *xprt, | |||
628 | *p++ = err_chunk; | 626 | *p++ = err_chunk; |
629 | trace_svcrdma_err_chunk(*rdma_argp); | 627 | trace_svcrdma_err_chunk(*rdma_argp); |
630 | } | 628 | } |
631 | length = (unsigned long)p - (unsigned long)err_msgp; | 629 | length = (unsigned long)p - (unsigned long)ctxt->sc_xprt_buf; |
632 | 630 | svc_rdma_sync_reply_hdr(xprt, ctxt, length); | |
633 | /* Map transport header; no RPC message payload */ | ||
634 | ctxt = svc_rdma_send_ctxt_get(xprt); | ||
635 | if (!ctxt) | ||
636 | return; | ||
637 | |||
638 | ret = svc_rdma_map_reply_hdr(xprt, ctxt, err_msgp, length); | ||
639 | if (ret) { | ||
640 | dprintk("svcrdma: Error %d mapping send for protocol error\n", | ||
641 | ret); | ||
642 | return; | ||
643 | } | ||
644 | 631 | ||
645 | ctxt->sc_send_wr.opcode = IB_WR_SEND; | 632 | ctxt->sc_send_wr.opcode = IB_WR_SEND; |
646 | ret = svc_rdma_send(xprt, &ctxt->sc_send_wr); | 633 | ret = svc_rdma_send(xprt, &ctxt->sc_send_wr); |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index edfeca45ac1c..4a3efaea277c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c | |||
@@ -127,6 +127,8 @@ static struct svc_rdma_send_ctxt * | |||
127 | svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma) | 127 | svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma) |
128 | { | 128 | { |
129 | struct svc_rdma_send_ctxt *ctxt; | 129 | struct svc_rdma_send_ctxt *ctxt; |
130 | dma_addr_t addr; | ||
131 | void *buffer; | ||
130 | size_t size; | 132 | size_t size; |
131 | int i; | 133 | int i; |
132 | 134 | ||
@@ -134,16 +136,33 @@ svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma) | |||
134 | size += rdma->sc_max_send_sges * sizeof(struct ib_sge); | 136 | size += rdma->sc_max_send_sges * sizeof(struct ib_sge); |
135 | ctxt = kmalloc(size, GFP_KERNEL); | 137 | ctxt = kmalloc(size, GFP_KERNEL); |
136 | if (!ctxt) | 138 | if (!ctxt) |
137 | return NULL; | 139 | goto fail0; |
140 | buffer = kmalloc(rdma->sc_max_req_size, GFP_KERNEL); | ||
141 | if (!buffer) | ||
142 | goto fail1; | ||
143 | addr = ib_dma_map_single(rdma->sc_pd->device, buffer, | ||
144 | rdma->sc_max_req_size, DMA_TO_DEVICE); | ||
145 | if (ib_dma_mapping_error(rdma->sc_pd->device, addr)) | ||
146 | goto fail2; | ||
138 | 147 | ||
139 | ctxt->sc_cqe.done = svc_rdma_wc_send; | ||
140 | ctxt->sc_send_wr.next = NULL; | 148 | ctxt->sc_send_wr.next = NULL; |
141 | ctxt->sc_send_wr.wr_cqe = &ctxt->sc_cqe; | 149 | ctxt->sc_send_wr.wr_cqe = &ctxt->sc_cqe; |
142 | ctxt->sc_send_wr.sg_list = ctxt->sc_sges; | 150 | ctxt->sc_send_wr.sg_list = ctxt->sc_sges; |
143 | ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED; | 151 | ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED; |
152 | ctxt->sc_cqe.done = svc_rdma_wc_send; | ||
153 | ctxt->sc_xprt_buf = buffer; | ||
154 | ctxt->sc_sges[0].addr = addr; | ||
155 | |||
144 | for (i = 0; i < rdma->sc_max_send_sges; i++) | 156 | for (i = 0; i < rdma->sc_max_send_sges; i++) |
145 | ctxt->sc_sges[i].lkey = rdma->sc_pd->local_dma_lkey; | 157 | ctxt->sc_sges[i].lkey = rdma->sc_pd->local_dma_lkey; |
146 | return ctxt; | 158 | return ctxt; |
159 | |||
160 | fail2: | ||
161 | kfree(buffer); | ||
162 | fail1: | ||
163 | kfree(ctxt); | ||
164 | fail0: | ||
165 | return NULL; | ||
147 | } | 166 | } |
148 | 167 | ||
149 | /** | 168 | /** |
@@ -157,6 +176,11 @@ void svc_rdma_send_ctxts_destroy(struct svcxprt_rdma *rdma) | |||
157 | 176 | ||
158 | while ((ctxt = svc_rdma_next_send_ctxt(&rdma->sc_send_ctxts))) { | 177 | while ((ctxt = svc_rdma_next_send_ctxt(&rdma->sc_send_ctxts))) { |
159 | list_del(&ctxt->sc_list); | 178 | list_del(&ctxt->sc_list); |
179 | ib_dma_unmap_single(rdma->sc_pd->device, | ||
180 | ctxt->sc_sges[0].addr, | ||
181 | rdma->sc_max_req_size, | ||
182 | DMA_TO_DEVICE); | ||
183 | kfree(ctxt->sc_xprt_buf); | ||
160 | kfree(ctxt); | 184 | kfree(ctxt); |
161 | } | 185 | } |
162 | } | 186 | } |
@@ -181,6 +205,7 @@ struct svc_rdma_send_ctxt *svc_rdma_send_ctxt_get(struct svcxprt_rdma *rdma) | |||
181 | 205 | ||
182 | out: | 206 | out: |
183 | ctxt->sc_send_wr.num_sge = 0; | 207 | ctxt->sc_send_wr.num_sge = 0; |
208 | ctxt->sc_cur_sge_no = 0; | ||
184 | ctxt->sc_page_count = 0; | 209 | ctxt->sc_page_count = 0; |
185 | return ctxt; | 210 | return ctxt; |
186 | 211 | ||
@@ -205,7 +230,10 @@ void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma, | |||
205 | struct ib_device *device = rdma->sc_cm_id->device; | 230 | struct ib_device *device = rdma->sc_cm_id->device; |
206 | unsigned int i; | 231 | unsigned int i; |
207 | 232 | ||
208 | for (i = 0; i < ctxt->sc_send_wr.num_sge; i++) | 233 | /* The first SGE contains the transport header, which |
234 | * remains mapped until @ctxt is destroyed. | ||
235 | */ | ||
236 | for (i = 1; i < ctxt->sc_send_wr.num_sge; i++) | ||
209 | ib_dma_unmap_page(device, | 237 | ib_dma_unmap_page(device, |
210 | ctxt->sc_sges[i].addr, | 238 | ctxt->sc_sges[i].addr, |
211 | ctxt->sc_sges[i].length, | 239 | ctxt->sc_sges[i].length, |
@@ -519,35 +547,37 @@ static int svc_rdma_dma_map_buf(struct svcxprt_rdma *rdma, | |||
519 | } | 547 | } |
520 | 548 | ||
521 | /** | 549 | /** |
522 | * svc_rdma_map_reply_hdr - DMA map the transport header buffer | 550 | * svc_rdma_sync_reply_hdr - DMA sync the transport header buffer |
523 | * @rdma: controlling transport | 551 | * @rdma: controlling transport |
524 | * @ctxt: op_ctxt for the Send WR | 552 | * @ctxt: send_ctxt for the Send WR |
525 | * @rdma_resp: buffer containing transport header | ||
526 | * @len: length of transport header | 553 | * @len: length of transport header |
527 | * | 554 | * |
528 | * Returns: | ||
529 | * %0 if the header is DMA mapped, | ||
530 | * %-EIO if DMA mapping failed. | ||
531 | */ | 555 | */ |
532 | int svc_rdma_map_reply_hdr(struct svcxprt_rdma *rdma, | 556 | void svc_rdma_sync_reply_hdr(struct svcxprt_rdma *rdma, |
533 | struct svc_rdma_send_ctxt *ctxt, | 557 | struct svc_rdma_send_ctxt *ctxt, |
534 | __be32 *rdma_resp, | 558 | unsigned int len) |
535 | unsigned int len) | ||
536 | { | 559 | { |
537 | ctxt->sc_pages[0] = virt_to_page(rdma_resp); | 560 | ctxt->sc_sges[0].length = len; |
538 | ctxt->sc_page_count++; | 561 | ctxt->sc_send_wr.num_sge++; |
539 | ctxt->sc_cur_sge_no = 0; | 562 | ib_dma_sync_single_for_device(rdma->sc_pd->device, |
540 | return svc_rdma_dma_map_page(rdma, ctxt, ctxt->sc_pages[0], 0, len); | 563 | ctxt->sc_sges[0].addr, len, |
564 | DMA_TO_DEVICE); | ||
541 | } | 565 | } |
542 | 566 | ||
543 | /* Load the xdr_buf into the ctxt's sge array, and DMA map each | 567 | /* svc_rdma_map_reply_msg - Map the buffer holding RPC message |
568 | * @rdma: controlling transport | ||
569 | * @ctxt: send_ctxt for the Send WR | ||
570 | * @xdr: prepared xdr_buf containing RPC message | ||
571 | * @wr_lst: pointer to Call header's Write list, or NULL | ||
572 | * | ||
573 | * Load the xdr_buf into the ctxt's sge array, and DMA map each | ||
544 | * element as it is added. | 574 | * element as it is added. |
545 | * | 575 | * |
546 | * Returns zero on success, or a negative errno on failure. | 576 | * Returns zero on success, or a negative errno on failure. |
547 | */ | 577 | */ |
548 | static int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, | 578 | int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, |
549 | struct svc_rdma_send_ctxt *ctxt, | 579 | struct svc_rdma_send_ctxt *ctxt, |
550 | struct xdr_buf *xdr, __be32 *wr_lst) | 580 | struct xdr_buf *xdr, __be32 *wr_lst) |
551 | { | 581 | { |
552 | unsigned int len, remaining; | 582 | unsigned int len, remaining; |
553 | unsigned long page_off; | 583 | unsigned long page_off; |
@@ -624,7 +654,7 @@ static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, | |||
624 | 654 | ||
625 | ctxt->sc_page_count += pages; | 655 | ctxt->sc_page_count += pages; |
626 | for (i = 0; i < pages; i++) { | 656 | for (i = 0; i < pages; i++) { |
627 | ctxt->sc_pages[i + 1] = rqstp->rq_respages[i]; | 657 | ctxt->sc_pages[i] = rqstp->rq_respages[i]; |
628 | rqstp->rq_respages[i] = NULL; | 658 | rqstp->rq_respages[i] = NULL; |
629 | } | 659 | } |
630 | rqstp->rq_next_page = rqstp->rq_respages + 1; | 660 | rqstp->rq_next_page = rqstp->rq_respages + 1; |
@@ -649,27 +679,18 @@ static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, | |||
649 | * - The Reply's transport header will never be larger than a page. | 679 | * - The Reply's transport header will never be larger than a page. |
650 | */ | 680 | */ |
651 | static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, | 681 | static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, |
652 | __be32 *rdma_argp, __be32 *rdma_resp, | 682 | struct svc_rdma_send_ctxt *ctxt, |
683 | __be32 *rdma_argp, | ||
653 | struct svc_rqst *rqstp, | 684 | struct svc_rqst *rqstp, |
654 | __be32 *wr_lst, __be32 *rp_ch) | 685 | __be32 *wr_lst, __be32 *rp_ch) |
655 | { | 686 | { |
656 | struct svc_rdma_send_ctxt *ctxt; | ||
657 | int ret; | 687 | int ret; |
658 | 688 | ||
659 | ctxt = svc_rdma_send_ctxt_get(rdma); | ||
660 | if (!ctxt) | ||
661 | return -ENOMEM; | ||
662 | |||
663 | ret = svc_rdma_map_reply_hdr(rdma, ctxt, rdma_resp, | ||
664 | svc_rdma_reply_hdr_len(rdma_resp)); | ||
665 | if (ret < 0) | ||
666 | goto err; | ||
667 | |||
668 | if (!rp_ch) { | 689 | if (!rp_ch) { |
669 | ret = svc_rdma_map_reply_msg(rdma, ctxt, | 690 | ret = svc_rdma_map_reply_msg(rdma, ctxt, |
670 | &rqstp->rq_res, wr_lst); | 691 | &rqstp->rq_res, wr_lst); |
671 | if (ret < 0) | 692 | if (ret < 0) |
672 | goto err; | 693 | return ret; |
673 | } | 694 | } |
674 | 695 | ||
675 | svc_rdma_save_io_pages(rqstp, ctxt); | 696 | svc_rdma_save_io_pages(rqstp, ctxt); |
@@ -683,15 +704,7 @@ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma, | |||
683 | } | 704 | } |
684 | dprintk("svcrdma: posting Send WR with %u sge(s)\n", | 705 | dprintk("svcrdma: posting Send WR with %u sge(s)\n", |
685 | ctxt->sc_send_wr.num_sge); | 706 | ctxt->sc_send_wr.num_sge); |
686 | ret = svc_rdma_send(rdma, &ctxt->sc_send_wr); | 707 | return svc_rdma_send(rdma, &ctxt->sc_send_wr); |
687 | if (ret) | ||
688 | goto err; | ||
689 | |||
690 | return 0; | ||
691 | |||
692 | err: | ||
693 | svc_rdma_send_ctxt_put(rdma, ctxt); | ||
694 | return ret; | ||
695 | } | 708 | } |
696 | 709 | ||
697 | /* Given the client-provided Write and Reply chunks, the server was not | 710 | /* Given the client-provided Write and Reply chunks, the server was not |
@@ -702,40 +715,29 @@ err: | |||
702 | * Remote Invalidation is skipped for simplicity. | 715 | * Remote Invalidation is skipped for simplicity. |
703 | */ | 716 | */ |
704 | static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, | 717 | static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, |
705 | __be32 *rdma_resp, struct svc_rqst *rqstp) | 718 | struct svc_rdma_send_ctxt *ctxt, |
719 | struct svc_rqst *rqstp) | ||
706 | { | 720 | { |
707 | struct svc_rdma_send_ctxt *ctxt; | ||
708 | __be32 *p; | 721 | __be32 *p; |
709 | int ret; | 722 | int ret; |
710 | 723 | ||
711 | ctxt = svc_rdma_send_ctxt_get(rdma); | 724 | p = ctxt->sc_xprt_buf; |
712 | if (!ctxt) | 725 | trace_svcrdma_err_chunk(*p); |
713 | return -ENOMEM; | 726 | p += 3; |
714 | |||
715 | /* Replace the original transport header with an | ||
716 | * RDMA_ERROR response. XID etc are preserved. | ||
717 | */ | ||
718 | trace_svcrdma_err_chunk(*rdma_resp); | ||
719 | p = rdma_resp + 3; | ||
720 | *p++ = rdma_error; | 727 | *p++ = rdma_error; |
721 | *p = err_chunk; | 728 | *p = err_chunk; |
722 | 729 | svc_rdma_sync_reply_hdr(rdma, ctxt, RPCRDMA_HDRLEN_ERR); | |
723 | ret = svc_rdma_map_reply_hdr(rdma, ctxt, rdma_resp, 20); | ||
724 | if (ret < 0) | ||
725 | goto err; | ||
726 | 730 | ||
727 | svc_rdma_save_io_pages(rqstp, ctxt); | 731 | svc_rdma_save_io_pages(rqstp, ctxt); |
728 | 732 | ||
729 | ctxt->sc_send_wr.opcode = IB_WR_SEND; | 733 | ctxt->sc_send_wr.opcode = IB_WR_SEND; |
730 | ret = svc_rdma_send(rdma, &ctxt->sc_send_wr); | 734 | ret = svc_rdma_send(rdma, &ctxt->sc_send_wr); |
731 | if (ret) | 735 | if (ret) { |
732 | goto err; | 736 | svc_rdma_send_ctxt_put(rdma, ctxt); |
737 | return ret; | ||
738 | } | ||
733 | 739 | ||
734 | return 0; | 740 | return 0; |
735 | |||
736 | err: | ||
737 | svc_rdma_send_ctxt_put(rdma, ctxt); | ||
738 | return ret; | ||
739 | } | 741 | } |
740 | 742 | ||
741 | void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp) | 743 | void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp) |
@@ -762,7 +764,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) | |||
762 | struct svc_rdma_recv_ctxt *rctxt = rqstp->rq_xprt_ctxt; | 764 | struct svc_rdma_recv_ctxt *rctxt = rqstp->rq_xprt_ctxt; |
763 | __be32 *p, *rdma_argp, *rdma_resp, *wr_lst, *rp_ch; | 765 | __be32 *p, *rdma_argp, *rdma_resp, *wr_lst, *rp_ch; |
764 | struct xdr_buf *xdr = &rqstp->rq_res; | 766 | struct xdr_buf *xdr = &rqstp->rq_res; |
765 | struct page *res_page; | 767 | struct svc_rdma_send_ctxt *sctxt; |
766 | int ret; | 768 | int ret; |
767 | 769 | ||
768 | rdma_argp = rctxt->rc_recv_buf; | 770 | rdma_argp = rctxt->rc_recv_buf; |
@@ -775,10 +777,10 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) | |||
775 | * critical section. | 777 | * critical section. |
776 | */ | 778 | */ |
777 | ret = -ENOMEM; | 779 | ret = -ENOMEM; |
778 | res_page = alloc_page(GFP_KERNEL); | 780 | sctxt = svc_rdma_send_ctxt_get(rdma); |
779 | if (!res_page) | 781 | if (!sctxt) |
780 | goto err0; | 782 | goto err0; |
781 | rdma_resp = page_address(res_page); | 783 | rdma_resp = sctxt->sc_xprt_buf; |
782 | 784 | ||
783 | p = rdma_resp; | 785 | p = rdma_resp; |
784 | *p++ = *rdma_argp; | 786 | *p++ = *rdma_argp; |
@@ -805,10 +807,11 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) | |||
805 | svc_rdma_xdr_encode_reply_chunk(rdma_resp, rp_ch, ret); | 807 | svc_rdma_xdr_encode_reply_chunk(rdma_resp, rp_ch, ret); |
806 | } | 808 | } |
807 | 809 | ||
808 | ret = svc_rdma_send_reply_msg(rdma, rdma_argp, rdma_resp, rqstp, | 810 | svc_rdma_sync_reply_hdr(rdma, sctxt, svc_rdma_reply_hdr_len(rdma_resp)); |
811 | ret = svc_rdma_send_reply_msg(rdma, sctxt, rdma_argp, rqstp, | ||
809 | wr_lst, rp_ch); | 812 | wr_lst, rp_ch); |
810 | if (ret < 0) | 813 | if (ret < 0) |
811 | goto err0; | 814 | goto err1; |
812 | ret = 0; | 815 | ret = 0; |
813 | 816 | ||
814 | out: | 817 | out: |
@@ -820,14 +823,14 @@ out: | |||
820 | if (ret != -E2BIG && ret != -EINVAL) | 823 | if (ret != -E2BIG && ret != -EINVAL) |
821 | goto err1; | 824 | goto err1; |
822 | 825 | ||
823 | ret = svc_rdma_send_error_msg(rdma, rdma_resp, rqstp); | 826 | ret = svc_rdma_send_error_msg(rdma, sctxt, rqstp); |
824 | if (ret < 0) | 827 | if (ret < 0) |
825 | goto err0; | 828 | goto err1; |
826 | ret = 0; | 829 | ret = 0; |
827 | goto out; | 830 | goto out; |
828 | 831 | ||
829 | err1: | 832 | err1: |
830 | put_page(res_page); | 833 | svc_rdma_send_ctxt_put(rdma, sctxt); |
831 | err0: | 834 | err0: |
832 | trace_svcrdma_send_failed(rqstp, ret); | 835 | trace_svcrdma_send_failed(rqstp, ret); |
833 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | 836 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |