Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 467c9674 authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker
Browse files

xprtrdma: unmap all FMRs during transport disconnect



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: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent e7104a2a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
+41 −1
Original line number Diff line number Diff line
@@ -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 @@ rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
		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