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

Commit f5778c2d authored by Chuck Lever's avatar Chuck Lever Committed by Greg Kroah-Hartman
Browse files

xprtrdma: Fix corner cases when handling device removal



commit 25524288 upstream.

Michal Kalderon has found some corner cases around device unload
with active NFS mounts that I didn't have the imagination to test
when xprtrdma device removal was added last year.

- The ULP device removal handler is responsible for deallocating
  the PD. That wasn't clear to me initially, and my own testing
  suggested it was not necessary, but that is incorrect.

- The transport destruction path can no longer assume that there
  is a valid ID.

- When destroying a transport, ensure that ib_free_cq() is not
  invoked on a CQ that was already released.

Reported-by: default avatarMichal Kalderon <Michal.Kalderon@cavium.com>
Fixes: bebd0318 ("xprtrdma: Support unplugging an HCA from ...")
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Cc: stable@vger.kernel.org # v4.12+
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: default avatarSudip Mukherjee <sudipm.mukherjee@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1083a7e8
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -270,7 +270,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
		wait_for_completion(&ia->ri_remove_done);

		ia->ri_id = NULL;
		ia->ri_pd = NULL;
		ia->ri_device = NULL;
		/* Return 1 to ensure the core destroys the id. */
		return 1;
@@ -464,7 +463,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
		ia->ri_id->qp = NULL;
	}
	ib_free_cq(ep->rep_attr.recv_cq);
	ep->rep_attr.recv_cq = NULL;
	ib_free_cq(ep->rep_attr.send_cq);
	ep->rep_attr.send_cq = NULL;

	/* The ULP is responsible for ensuring all DMA
	 * mappings and MRs are gone.
@@ -477,6 +478,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
		rpcrdma_dma_unmap_regbuf(req->rl_recvbuf);
	}
	rpcrdma_destroy_mrs(buf);
	ib_dealloc_pd(ia->ri_pd);
	ia->ri_pd = NULL;

	/* Allow waiters to continue */
	complete(&ia->ri_remove_done);
@@ -650,13 +653,15 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)

	cancel_delayed_work_sync(&ep->rep_connect_worker);

	if (ia->ri_id->qp) {
	if (ia->ri_id && ia->ri_id->qp) {
		rpcrdma_ep_disconnect(ep, ia);
		rdma_destroy_qp(ia->ri_id);
		ia->ri_id->qp = NULL;
	}

	if (ep->rep_attr.recv_cq)
		ib_free_cq(ep->rep_attr.recv_cq);
	if (ep->rep_attr.send_cq)
		ib_free_cq(ep->rep_attr.send_cq);
}