aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2018-03-19 14:23:16 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2018-04-10 16:07:10 -0400
commit25524288631fc5b7d33259fca1e0dc38146be5d6 (patch)
tree2b148001eb639023f8c308937c841c94522f6480
parent571745935b2ec276345faec81af732fb9f51082b (diff)
xprtrdma: Fix corner cases when handling device removal
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: Michal Kalderon <Michal.Kalderon@cavium.com> Fixes: bebd031866ca ("xprtrdma: Support unplugging an HCA from ...") Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--net/sunrpc/xprtrdma/verbs.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 6a7a5a277e75..fe5eaca2d197 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -250,7 +250,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
250 wait_for_completion(&ia->ri_remove_done); 250 wait_for_completion(&ia->ri_remove_done);
251 251
252 ia->ri_id = NULL; 252 ia->ri_id = NULL;
253 ia->ri_pd = NULL;
254 ia->ri_device = NULL; 253 ia->ri_device = NULL;
255 /* Return 1 to ensure the core destroys the id. */ 254 /* Return 1 to ensure the core destroys the id. */
256 return 1; 255 return 1;
@@ -447,7 +446,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
447 ia->ri_id->qp = NULL; 446 ia->ri_id->qp = NULL;
448 } 447 }
449 ib_free_cq(ep->rep_attr.recv_cq); 448 ib_free_cq(ep->rep_attr.recv_cq);
449 ep->rep_attr.recv_cq = NULL;
450 ib_free_cq(ep->rep_attr.send_cq); 450 ib_free_cq(ep->rep_attr.send_cq);
451 ep->rep_attr.send_cq = NULL;
451 452
452 /* The ULP is responsible for ensuring all DMA 453 /* The ULP is responsible for ensuring all DMA
453 * mappings and MRs are gone. 454 * mappings and MRs are gone.
@@ -460,6 +461,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
460 rpcrdma_dma_unmap_regbuf(req->rl_recvbuf); 461 rpcrdma_dma_unmap_regbuf(req->rl_recvbuf);
461 } 462 }
462 rpcrdma_mrs_destroy(buf); 463 rpcrdma_mrs_destroy(buf);
464 ib_dealloc_pd(ia->ri_pd);
465 ia->ri_pd = NULL;
463 466
464 /* Allow waiters to continue */ 467 /* Allow waiters to continue */
465 complete(&ia->ri_remove_done); 468 complete(&ia->ri_remove_done);
@@ -627,14 +630,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
627{ 630{
628 cancel_delayed_work_sync(&ep->rep_connect_worker); 631 cancel_delayed_work_sync(&ep->rep_connect_worker);
629 632
630 if (ia->ri_id->qp) { 633 if (ia->ri_id && ia->ri_id->qp) {
631 rpcrdma_ep_disconnect(ep, ia); 634 rpcrdma_ep_disconnect(ep, ia);
632 rdma_destroy_qp(ia->ri_id); 635 rdma_destroy_qp(ia->ri_id);
633 ia->ri_id->qp = NULL; 636 ia->ri_id->qp = NULL;
634 } 637 }
635 638
636 ib_free_cq(ep->rep_attr.recv_cq); 639 if (ep->rep_attr.recv_cq)
637 ib_free_cq(ep->rep_attr.send_cq); 640 ib_free_cq(ep->rep_attr.recv_cq);
641 if (ep->rep_attr.send_cq)
642 ib_free_cq(ep->rep_attr.send_cq);
638} 643}
639 644
640/* Re-establish a connection after a device removal event. 645/* Re-establish a connection after a device removal event.