summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2016-06-29 13:53:43 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2016-07-11 15:50:43 -0400
commit7a89f9c626e337ba6528d8a2829b228c933877fb (patch)
treefb37fd67ab882087a162d6ae0d1966909f7ee4e6 /net
parent3d4cf35bd4fab56c3aa0ec4323fccb24970aaf79 (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.c6
-rw-r--r--net/sunrpc/xprtrdma/frwr_ops.c13
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c2
-rw-r--r--net/sunrpc/xprtrdma/transport.c20
-rw-r--r--net/sunrpc/xprtrdma/verbs.c22
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
274out_maperr: 274out_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
461out_mapmr_err: 461out_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
468out_senderr: 467out_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
473static struct ib_send_wr * 473static struct ib_send_wr *
@@ -569,7 +569,8 @@ unmap:
569 return; 569 return;
570 570
571reset_mrs: 571reset_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
559out_fail: 559out_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
604static int 613static int
605xprt_rdma_send_request(struct rpc_task *task) 614xprt_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
632failed_marshal: 641failed_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;
638drop_connection: 648drop_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;
1181out: 1181
1182 return rc; 1182out_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
1213out_postrecv:
1214 pr_err("rpcrdma: ib_post_recv returned %i\n", rc);
1215 return -ENOTCONN;
1212} 1216}
1213 1217
1214/** 1218/**