diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2016-06-29 13:53:43 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2016-07-11 15:50:43 -0400 |
commit | 7a89f9c626e337ba6528d8a2829b228c933877fb (patch) | |
tree | fb37fd67ab882087a162d6ae0d1966909f7ee4e6 /net | |
parent | 3d4cf35bd4fab56c3aa0ec4323fccb24970aaf79 (diff) |
xprtrdma: Honor ->send_request API contract
Commit c93c62231cf5 ("xprtrdma: Disconnect on registration failure")
added a disconnect for some RPC marshaling failures. This is needed
only in a handful of cases, but it was triggering for simple stuff
like temporary resource shortages. Try to straighten this out.
Fix up the lower layers so they don't return -ENOMEM or other error
codes that the RPC client's FSM doesn't explicitly recognize.
Also fix up the places in the send_request path that do want a
disconnect. For example, when ib_post_send or ib_post_recv fail,
this is a sign that there is a send or receive queue resource
miscalculation. That should be rare, and is a sign of a software
bug. But xprtrdma can recover: disconnect to reset the transport and
start over.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Tested-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/xprtrdma/fmr_ops.c | 6 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/frwr_ops.c | 13 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/transport.c | 20 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 22 |
5 files changed, 39 insertions, 24 deletions
diff --git a/net/sunrpc/xprtrdma/fmr_ops.c b/net/sunrpc/xprtrdma/fmr_ops.c index 8b6ce8ebe60f..aae4c372a40f 100644 --- a/net/sunrpc/xprtrdma/fmr_ops.c +++ b/net/sunrpc/xprtrdma/fmr_ops.c | |||
@@ -219,7 +219,7 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, | |||
219 | rpcrdma_defer_mr_recovery(mw); | 219 | rpcrdma_defer_mr_recovery(mw); |
220 | mw = rpcrdma_get_mw(r_xprt); | 220 | mw = rpcrdma_get_mw(r_xprt); |
221 | if (!mw) | 221 | if (!mw) |
222 | return -ENOMEM; | 222 | return -ENOBUFS; |
223 | 223 | ||
224 | pageoff = offset_in_page(seg1->mr_offset); | 224 | pageoff = offset_in_page(seg1->mr_offset); |
225 | seg1->mr_offset -= pageoff; /* start of page */ | 225 | seg1->mr_offset -= pageoff; /* start of page */ |
@@ -269,14 +269,14 @@ out_dmamap_err: | |||
269 | pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n", | 269 | pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n", |
270 | mw->mw_sg, mw->mw_nents); | 270 | mw->mw_sg, mw->mw_nents); |
271 | rpcrdma_defer_mr_recovery(mw); | 271 | rpcrdma_defer_mr_recovery(mw); |
272 | return -ENOMEM; | 272 | return -EIO; |
273 | 273 | ||
274 | out_maperr: | 274 | out_maperr: |
275 | pr_err("rpcrdma: ib_map_phys_fmr %u@0x%llx+%i (%d) status %i\n", | 275 | pr_err("rpcrdma: ib_map_phys_fmr %u@0x%llx+%i (%d) status %i\n", |
276 | len, (unsigned long long)dma_pages[0], | 276 | len, (unsigned long long)dma_pages[0], |
277 | pageoff, mw->mw_nents, rc); | 277 | pageoff, mw->mw_nents, rc); |
278 | rpcrdma_defer_mr_recovery(mw); | 278 | rpcrdma_defer_mr_recovery(mw); |
279 | return rc; | 279 | return -EIO; |
280 | } | 280 | } |
281 | 281 | ||
282 | /* Invalidate all memory regions that were registered for "req". | 282 | /* Invalidate all memory regions that were registered for "req". |
diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c index fc2826b3518c..d7613db9185d 100644 --- a/net/sunrpc/xprtrdma/frwr_ops.c +++ b/net/sunrpc/xprtrdma/frwr_ops.c | |||
@@ -382,7 +382,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, | |||
382 | rpcrdma_defer_mr_recovery(mw); | 382 | rpcrdma_defer_mr_recovery(mw); |
383 | mw = rpcrdma_get_mw(r_xprt); | 383 | mw = rpcrdma_get_mw(r_xprt); |
384 | if (!mw) | 384 | if (!mw) |
385 | return -ENOMEM; | 385 | return -ENOBUFS; |
386 | } while (mw->frmr.fr_state != FRMR_IS_INVALID); | 386 | } while (mw->frmr.fr_state != FRMR_IS_INVALID); |
387 | frmr = &mw->frmr; | 387 | frmr = &mw->frmr; |
388 | frmr->fr_state = FRMR_IS_VALID; | 388 | frmr->fr_state = FRMR_IS_VALID; |
@@ -456,18 +456,18 @@ out_dmamap_err: | |||
456 | pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n", | 456 | pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n", |
457 | mw->mw_sg, mw->mw_nents); | 457 | mw->mw_sg, mw->mw_nents); |
458 | rpcrdma_defer_mr_recovery(mw); | 458 | rpcrdma_defer_mr_recovery(mw); |
459 | return -ENOMEM; | 459 | return -EIO; |
460 | 460 | ||
461 | out_mapmr_err: | 461 | out_mapmr_err: |
462 | pr_err("rpcrdma: failed to map mr %p (%u/%u)\n", | 462 | pr_err("rpcrdma: failed to map mr %p (%u/%u)\n", |
463 | frmr->fr_mr, n, mw->mw_nents); | 463 | frmr->fr_mr, n, mw->mw_nents); |
464 | rc = n < 0 ? n : -EIO; | ||
465 | rpcrdma_defer_mr_recovery(mw); | 464 | rpcrdma_defer_mr_recovery(mw); |
466 | return rc; | 465 | return -EIO; |
467 | 466 | ||
468 | out_senderr: | 467 | out_senderr: |
468 | pr_err("rpcrdma: FRMR registration ib_post_send returned %i\n", rc); | ||
469 | rpcrdma_defer_mr_recovery(mw); | 469 | rpcrdma_defer_mr_recovery(mw); |
470 | return rc; | 470 | return -ENOTCONN; |
471 | } | 471 | } |
472 | 472 | ||
473 | static struct ib_send_wr * | 473 | static struct ib_send_wr * |
@@ -569,7 +569,8 @@ unmap: | |||
569 | return; | 569 | return; |
570 | 570 | ||
571 | reset_mrs: | 571 | reset_mrs: |
572 | pr_warn("%s: ib_post_send failed %i\n", __func__, rc); | 572 | pr_err("rpcrdma: FRMR invalidate ib_post_send returned %i\n", rc); |
573 | rdma_disconnect(ia->ri_id); | ||
573 | 574 | ||
574 | /* Find and reset the MRs in the LOCAL_INV WRs that did not | 575 | /* Find and reset the MRs in the LOCAL_INV WRs that did not |
575 | * get posted. This is synchronous, and slow. | 576 | * get posted. This is synchronous, and slow. |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 35a81096e83d..77e002f4d005 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
@@ -251,7 +251,7 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, | |||
251 | /* alloc the pagelist for receiving buffer */ | 251 | /* alloc the pagelist for receiving buffer */ |
252 | ppages[p] = alloc_page(GFP_ATOMIC); | 252 | ppages[p] = alloc_page(GFP_ATOMIC); |
253 | if (!ppages[p]) | 253 | if (!ppages[p]) |
254 | return -ENOMEM; | 254 | return -EAGAIN; |
255 | } | 255 | } |
256 | seg[n].mr_page = ppages[p]; | 256 | seg[n].mr_page = ppages[p]; |
257 | seg[n].mr_offset = (void *)(unsigned long) page_base; | 257 | seg[n].mr_offset = (void *)(unsigned long) page_base; |
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 4c8e7f11b906..be4dd2c7c680 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
@@ -558,7 +558,6 @@ out_sendbuf: | |||
558 | 558 | ||
559 | out_fail: | 559 | out_fail: |
560 | rpcrdma_buffer_put(req); | 560 | rpcrdma_buffer_put(req); |
561 | r_xprt->rx_stats.failed_marshal_count++; | ||
562 | return NULL; | 561 | return NULL; |
563 | } | 562 | } |
564 | 563 | ||
@@ -590,8 +589,19 @@ xprt_rdma_free(void *buffer) | |||
590 | rpcrdma_buffer_put(req); | 589 | rpcrdma_buffer_put(req); |
591 | } | 590 | } |
592 | 591 | ||
593 | /* | 592 | /** |
593 | * xprt_rdma_send_request - marshal and send an RPC request | ||
594 | * @task: RPC task with an RPC message in rq_snd_buf | ||
595 | * | ||
596 | * Return values: | ||
597 | * 0: The request has been sent | ||
598 | * ENOTCONN: Caller needs to invoke connect logic then call again | ||
599 | * ENOBUFS: Call again later to send the request | ||
600 | * EIO: A permanent error occurred. The request was not sent, | ||
601 | * and don't try it again | ||
602 | * | ||
594 | * send_request invokes the meat of RPC RDMA. It must do the following: | 603 | * send_request invokes the meat of RPC RDMA. It must do the following: |
604 | * | ||
595 | * 1. Marshal the RPC request into an RPC RDMA request, which means | 605 | * 1. Marshal the RPC request into an RPC RDMA request, which means |
596 | * putting a header in front of data, and creating IOVs for RDMA | 606 | * putting a header in front of data, and creating IOVs for RDMA |
597 | * from those in the request. | 607 | * from those in the request. |
@@ -600,7 +610,6 @@ xprt_rdma_free(void *buffer) | |||
600 | * the request (rpcrdma_ep_post). | 610 | * the request (rpcrdma_ep_post). |
601 | * 4. No partial sends are possible in the RPC-RDMA protocol (as in UDP). | 611 | * 4. No partial sends are possible in the RPC-RDMA protocol (as in UDP). |
602 | */ | 612 | */ |
603 | |||
604 | static int | 613 | static int |
605 | xprt_rdma_send_request(struct rpc_task *task) | 614 | xprt_rdma_send_request(struct rpc_task *task) |
606 | { | 615 | { |
@@ -630,11 +639,12 @@ xprt_rdma_send_request(struct rpc_task *task) | |||
630 | return 0; | 639 | return 0; |
631 | 640 | ||
632 | failed_marshal: | 641 | failed_marshal: |
633 | r_xprt->rx_stats.failed_marshal_count++; | ||
634 | dprintk("RPC: %s: rpcrdma_marshal_req failed, status %i\n", | 642 | dprintk("RPC: %s: rpcrdma_marshal_req failed, status %i\n", |
635 | __func__, rc); | 643 | __func__, rc); |
636 | if (rc == -EIO) | 644 | if (rc == -EIO) |
637 | return -EIO; | 645 | r_xprt->rx_stats.failed_marshal_count++; |
646 | if (rc != -ENOTCONN) | ||
647 | return rc; | ||
638 | drop_connection: | 648 | drop_connection: |
639 | xprt_disconnect_done(xprt); | 649 | xprt_disconnect_done(xprt); |
640 | return -ENOTCONN; /* implies disconnect */ | 650 | return -ENOTCONN; /* implies disconnect */ |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 6fb73ff26183..db935ed3ac75 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -1151,7 +1151,7 @@ rpcrdma_ep_post(struct rpcrdma_ia *ia, | |||
1151 | if (rep) { | 1151 | if (rep) { |
1152 | rc = rpcrdma_ep_post_recv(ia, ep, rep); | 1152 | rc = rpcrdma_ep_post_recv(ia, ep, rep); |
1153 | if (rc) | 1153 | if (rc) |
1154 | goto out; | 1154 | return rc; |
1155 | req->rl_reply = NULL; | 1155 | req->rl_reply = NULL; |
1156 | } | 1156 | } |
1157 | 1157 | ||
@@ -1176,10 +1176,12 @@ rpcrdma_ep_post(struct rpcrdma_ia *ia, | |||
1176 | 1176 | ||
1177 | rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail); | 1177 | rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail); |
1178 | if (rc) | 1178 | if (rc) |
1179 | dprintk("RPC: %s: ib_post_send returned %i\n", __func__, | 1179 | goto out_postsend_err; |
1180 | rc); | 1180 | return 0; |
1181 | out: | 1181 | |
1182 | return rc; | 1182 | out_postsend_err: |
1183 | pr_err("rpcrdma: RDMA Send ib_post_send returned %i\n", rc); | ||
1184 | return -ENOTCONN; | ||
1183 | } | 1185 | } |
1184 | 1186 | ||
1185 | /* | 1187 | /* |
@@ -1204,11 +1206,13 @@ rpcrdma_ep_post_recv(struct rpcrdma_ia *ia, | |||
1204 | DMA_BIDIRECTIONAL); | 1206 | DMA_BIDIRECTIONAL); |
1205 | 1207 | ||
1206 | rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail); | 1208 | rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail); |
1207 | |||
1208 | if (rc) | 1209 | if (rc) |
1209 | dprintk("RPC: %s: ib_post_recv returned %i\n", __func__, | 1210 | goto out_postrecv; |
1210 | rc); | 1211 | return 0; |
1211 | return rc; | 1212 | |
1213 | out_postrecv: | ||
1214 | pr_err("rpcrdma: ib_post_recv returned %i\n", rc); | ||
1215 | return -ENOTCONN; | ||
1212 | } | 1216 | } |
1213 | 1217 | ||
1214 | /** | 1218 | /** |