xprtrdma: unmap all FMRs during transport disconnect
authorChuck Lever <chuck.lever@oracle.com>
Sun, 9 Nov 2014 01:14:29 +0000 (20:14 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 25 Nov 2014 18:39:20 +0000 (13:39 -0500)
When using RPCRDMA_MTHCAFMR memory registration, after a few
transport disconnect / reconnect cycles, ib_map_phys_fmr() starts to
return EINVAL because the provider has exhausted its map pool.

Make sure that all FMRs are unmapped during transport disconnect,
and that ->send_request remarshals them during an RPC retransmit.
This resets the transport's MRs to ensure that none are leaked
during a disconnect.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c

index 6a4615dd02618318ce145b95367011150fd35a68..cfe9a810e6bcfefce644bcfce6763145251678a4 100644 (file)
@@ -599,7 +599,7 @@ xprt_rdma_send_request(struct rpc_task *task)
 
        if (req->rl_niovs == 0)
                rc = rpcrdma_marshal_req(rqst);
-       else if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR)
+       else if (r_xprt->rx_ia.ri_memreg_strategy != RPCRDMA_ALLPHYSICAL)
                rc = rpcrdma_marshal_chunks(rqst, 0);
        if (rc < 0)
                goto failed_marshal;
index af45cf390126089ddbab36ecd51b293600a5fef1..3c88276090e37771496ad31d8a0066d68aa58e02 100644 (file)
@@ -62,6 +62,7 @@
 #endif
 
 static void rpcrdma_reset_frmrs(struct rpcrdma_ia *);
+static void rpcrdma_reset_fmrs(struct rpcrdma_ia *);
 
 /*
  * internal functions
@@ -868,8 +869,19 @@ retry:
                rpcrdma_ep_disconnect(ep, ia);
                rpcrdma_flush_cqs(ep);
 
-               if (ia->ri_memreg_strategy == RPCRDMA_FRMR)
+               switch (ia->ri_memreg_strategy) {
+               case RPCRDMA_FRMR:
                        rpcrdma_reset_frmrs(ia);
+                       break;
+               case RPCRDMA_MTHCAFMR:
+                       rpcrdma_reset_fmrs(ia);
+                       break;
+               case RPCRDMA_ALLPHYSICAL:
+                       break;
+               default:
+                       rc = -EIO;
+                       goto out;
+               }
 
                xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
                id = rpcrdma_create_id(xprt, ia,
@@ -1289,6 +1301,34 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
        kfree(buf->rb_pool);
 }
 
+/* After a disconnect, unmap all FMRs.
+ *
+ * This is invoked only in the transport connect worker in order
+ * to serialize with rpcrdma_register_fmr_external().
+ */
+static void
+rpcrdma_reset_fmrs(struct rpcrdma_ia *ia)
+{
+       struct rpcrdma_xprt *r_xprt =
+                               container_of(ia, struct rpcrdma_xprt, rx_ia);
+       struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
+       struct list_head *pos;
+       struct rpcrdma_mw *r;
+       LIST_HEAD(l);
+       int rc;
+
+       list_for_each(pos, &buf->rb_all) {
+               r = list_entry(pos, struct rpcrdma_mw, mw_all);
+
+               INIT_LIST_HEAD(&l);
+               list_add(&r->r.fmr->list, &l);
+               rc = ib_unmap_fmr(&l);
+               if (rc)
+                       dprintk("RPC:       %s: ib_unmap_fmr failed %i\n",
+                               __func__, rc);
+       }
+}
+
 /* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in
  * an unusable state. Find FRMRs in this state and dereg / reg
  * each.  FRMRs that are VALID and attached to an rpcrdma_req are