aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2014-07-29 17:24:45 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2014-07-31 16:22:55 -0400
commit9f9d802a28a107937ecda4ff78de2ab5cedd439d (patch)
treea531564f760c2113587a8aaec5fd864b32037f2d /net
parentc2922c0235aac1c787fa81e24d7d7e93c2202275 (diff)
xprtrdma: Reset FRMRs when FAST_REG_MR is flushed by a disconnect
FAST_REG_MR Work Requests update a Memory Region's rkey. Rkey's are used to block unwanted access to the memory controlled by an MR. The rkey is passed to the receiver (the NFS server, in our case), and is also used by xprtrdma to invalidate the MR when the RPC is complete. When a FAST_REG_MR Work Request is flushed after a transport disconnect, xprtrdma cannot tell whether the WR actually hit the adapter or not. So it is indeterminant at that point whether the existing rkey is still valid. After the transport connection is re-established, the next FAST_REG_MR or LOCAL_INV Work Request against that MR can sometimes fail because the rkey value does not match what xprtrdma expects. The only reliable way to recover in this case is to deregister and register the MR before it is used again. These operations can be done only in a process context, so handle it in the transport connect worker. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Tested-by: Steve Wise <swise@opengridcomputing.com> Tested-by: Shirley Ma <shirley.ma@oracle.com> Tested-by: Devesh Sharma <devesh.sharma@emulex.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/xprtrdma/verbs.c67
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h1
2 files changed, 66 insertions, 2 deletions
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 017f0abb2a86..3a6376a77fcc 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -61,6 +61,8 @@
61# define RPCDBG_FACILITY RPCDBG_TRANS 61# define RPCDBG_FACILITY RPCDBG_TRANS
62#endif 62#endif
63 63
64static void rpcrdma_reset_frmrs(struct rpcrdma_ia *);
65
64/* 66/*
65 * internal functions 67 * internal functions
66 */ 68 */
@@ -152,8 +154,10 @@ rpcrdma_sendcq_process_wc(struct ib_wc *wc)
152 154
153 if (wc->wr_id == 0ULL) 155 if (wc->wr_id == 0ULL)
154 return; 156 return;
155 if (wc->status != IB_WC_SUCCESS) 157 if (wc->status != IB_WC_SUCCESS) {
158 frmr->r.frmr.fr_state = FRMR_IS_STALE;
156 return; 159 return;
160 }
157 161
158 if (wc->opcode == IB_WC_FAST_REG_MR) 162 if (wc->opcode == IB_WC_FAST_REG_MR)
159 frmr->r.frmr.fr_state = FRMR_IS_VALID; 163 frmr->r.frmr.fr_state = FRMR_IS_VALID;
@@ -881,6 +885,9 @@ retry:
881 " status %i\n", __func__, rc); 885 " status %i\n", __func__, rc);
882 rpcrdma_flush_cqs(ep); 886 rpcrdma_flush_cqs(ep);
883 887
888 if (ia->ri_memreg_strategy == RPCRDMA_FRMR)
889 rpcrdma_reset_frmrs(ia);
890
884 xprt = container_of(ia, struct rpcrdma_xprt, rx_ia); 891 xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
885 id = rpcrdma_create_id(xprt, ia, 892 id = rpcrdma_create_id(xprt, ia,
886 (struct sockaddr *)&xprt->rx_data.addr); 893 (struct sockaddr *)&xprt->rx_data.addr);
@@ -1256,6 +1263,62 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1256 kfree(buf->rb_pool); 1263 kfree(buf->rb_pool);
1257} 1264}
1258 1265
1266/* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in
1267 * an unusable state. Find FRMRs in this state and dereg / reg
1268 * each. FRMRs that are VALID and attached to an rpcrdma_req are
1269 * also torn down.
1270 *
1271 * This gives all in-use FRMRs a fresh rkey and leaves them INVALID.
1272 *
1273 * This is invoked only in the transport connect worker in order
1274 * to serialize with rpcrdma_register_frmr_external().
1275 */
1276static void
1277rpcrdma_reset_frmrs(struct rpcrdma_ia *ia)
1278{
1279 struct rpcrdma_xprt *r_xprt =
1280 container_of(ia, struct rpcrdma_xprt, rx_ia);
1281 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1282 struct list_head *pos;
1283 struct rpcrdma_mw *r;
1284 int rc;
1285
1286 list_for_each(pos, &buf->rb_all) {
1287 r = list_entry(pos, struct rpcrdma_mw, mw_all);
1288
1289 if (r->r.frmr.fr_state == FRMR_IS_INVALID)
1290 continue;
1291
1292 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1293 if (rc)
1294 dprintk("RPC: %s: ib_dereg_mr failed %i\n",
1295 __func__, rc);
1296 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1297
1298 r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd,
1299 ia->ri_max_frmr_depth);
1300 if (IS_ERR(r->r.frmr.fr_mr)) {
1301 rc = PTR_ERR(r->r.frmr.fr_mr);
1302 dprintk("RPC: %s: ib_alloc_fast_reg_mr"
1303 " failed %i\n", __func__, rc);
1304 continue;
1305 }
1306 r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list(
1307 ia->ri_id->device,
1308 ia->ri_max_frmr_depth);
1309 if (IS_ERR(r->r.frmr.fr_pgl)) {
1310 rc = PTR_ERR(r->r.frmr.fr_pgl);
1311 dprintk("RPC: %s: "
1312 "ib_alloc_fast_reg_page_list "
1313 "failed %i\n", __func__, rc);
1314
1315 ib_dereg_mr(r->r.frmr.fr_mr);
1316 continue;
1317 }
1318 r->r.frmr.fr_state = FRMR_IS_INVALID;
1319 }
1320}
1321
1259/* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving 1322/* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving
1260 * some req segments uninitialized. 1323 * some req segments uninitialized.
1261 */ 1324 */
@@ -1575,7 +1638,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
1575 dprintk("RPC: %s: Using frmr %p to map %d segments\n", 1638 dprintk("RPC: %s: Using frmr %p to map %d segments\n",
1576 __func__, mw, i); 1639 __func__, mw, i);
1577 1640
1578 if (unlikely(frmr->fr_state == FRMR_IS_VALID)) { 1641 if (unlikely(frmr->fr_state != FRMR_IS_INVALID)) {
1579 dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n", 1642 dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n",
1580 __func__, mr->rkey); 1643 __func__, mr->rkey);
1581 /* Invalidate before using. */ 1644 /* Invalidate before using. */
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index c1d865287b0e..1ee6db30abc5 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -161,6 +161,7 @@ struct rpcrdma_rep {
161enum rpcrdma_frmr_state { 161enum rpcrdma_frmr_state {
162 FRMR_IS_INVALID, /* ready to be used */ 162 FRMR_IS_INVALID, /* ready to be used */
163 FRMR_IS_VALID, /* in use */ 163 FRMR_IS_VALID, /* in use */
164 FRMR_IS_STALE, /* failed completion */
164}; 165};
165 166
166struct rpcrdma_frmr { 167struct rpcrdma_frmr {