|
69 | 69 | /*
|
70 | 70 | * internal functions
|
71 | 71 | */
|
| 72 | +static void rpcrdma_destroy_mrs(struct rpcrdma_buffer *buf); |
| 73 | +static void rpcrdma_dma_unmap_regbuf(struct rpcrdma_regbuf *rb); |
72 | 74 |
|
73 | 75 | static struct workqueue_struct *rpcrdma_receive_wq;
|
74 | 76 |
|
@@ -262,6 +264,21 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
|
262 | 264 | __func__, ep);
|
263 | 265 | complete(&ia->ri_done);
|
264 | 266 | break;
|
| 267 | + case RDMA_CM_EVENT_DEVICE_REMOVAL: |
| 268 | +#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
| 269 | + pr_info("rpcrdma: removing device for %pIS:%u\n", |
| 270 | + sap, rpc_get_port(sap)); |
| 271 | +#endif |
| 272 | + set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags); |
| 273 | + ep->rep_connected = -ENODEV; |
| 274 | + xprt_force_disconnect(&xprt->rx_xprt); |
| 275 | + wait_for_completion(&ia->ri_remove_done); |
| 276 | + |
| 277 | + ia->ri_id = NULL; |
| 278 | + ia->ri_pd = NULL; |
| 279 | + ia->ri_device = NULL; |
| 280 | + /* Return 1 to ensure the core destroys the id. */ |
| 281 | + return 1; |
265 | 282 | case RDMA_CM_EVENT_ESTABLISHED:
|
266 | 283 | connstate = 1;
|
267 | 284 | ib_query_qp(ia->ri_id->qp, attr,
|
@@ -291,9 +308,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
|
291 | 308 | goto connected;
|
292 | 309 | case RDMA_CM_EVENT_DISCONNECTED:
|
293 | 310 | connstate = -ECONNABORTED;
|
294 |
| - goto connected; |
295 |
| - case RDMA_CM_EVENT_DEVICE_REMOVAL: |
296 |
| - connstate = -ENODEV; |
297 | 311 | connected:
|
298 | 312 | dprintk("RPC: %s: %sconnected\n",
|
299 | 313 | __func__, connstate > 0 ? "" : "dis");
|
@@ -346,6 +360,7 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt,
|
346 | 360 | int rc;
|
347 | 361 |
|
348 | 362 | init_completion(&ia->ri_done);
|
| 363 | + init_completion(&ia->ri_remove_done); |
349 | 364 |
|
350 | 365 | id = rdma_create_id(&init_net, rpcrdma_conn_upcall, xprt, RDMA_PS_TCP,
|
351 | 366 | IB_QPT_RC);
|
@@ -468,6 +483,56 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr)
|
468 | 483 | return rc;
|
469 | 484 | }
|
470 | 485 |
|
| 486 | +/** |
| 487 | + * rpcrdma_ia_remove - Handle device driver unload |
| 488 | + * @ia: interface adapter being removed |
| 489 | + * |
| 490 | + * Divest transport H/W resources associated with this adapter, |
| 491 | + * but allow it to be restored later. |
| 492 | + */ |
| 493 | +void |
| 494 | +rpcrdma_ia_remove(struct rpcrdma_ia *ia) |
| 495 | +{ |
| 496 | + struct rpcrdma_xprt *r_xprt = container_of(ia, struct rpcrdma_xprt, |
| 497 | + rx_ia); |
| 498 | + struct rpcrdma_ep *ep = &r_xprt->rx_ep; |
| 499 | + struct rpcrdma_buffer *buf = &r_xprt->rx_buf; |
| 500 | + struct rpcrdma_req *req; |
| 501 | + struct rpcrdma_rep *rep; |
| 502 | + |
| 503 | + cancel_delayed_work_sync(&buf->rb_refresh_worker); |
| 504 | + |
| 505 | + /* This is similar to rpcrdma_ep_destroy, but: |
| 506 | + * - Don't cancel the connect worker. |
| 507 | + * - Don't call rpcrdma_ep_disconnect, which waits |
| 508 | + * for another conn upcall, which will deadlock. |
| 509 | + * - rdma_disconnect is unneeded, the underlying |
| 510 | + * connection is already gone. |
| 511 | + */ |
| 512 | + if (ia->ri_id->qp) { |
| 513 | + ib_drain_qp(ia->ri_id->qp); |
| 514 | + rdma_destroy_qp(ia->ri_id); |
| 515 | + ia->ri_id->qp = NULL; |
| 516 | + } |
| 517 | + ib_free_cq(ep->rep_attr.recv_cq); |
| 518 | + ib_free_cq(ep->rep_attr.send_cq); |
| 519 | + |
| 520 | + /* The ULP is responsible for ensuring all DMA |
| 521 | + * mappings and MRs are gone. |
| 522 | + */ |
| 523 | + list_for_each_entry(rep, &buf->rb_recv_bufs, rr_list) |
| 524 | + rpcrdma_dma_unmap_regbuf(rep->rr_rdmabuf); |
| 525 | + list_for_each_entry(req, &buf->rb_allreqs, rl_all) { |
| 526 | + rpcrdma_dma_unmap_regbuf(req->rl_rdmabuf); |
| 527 | + rpcrdma_dma_unmap_regbuf(req->rl_sendbuf); |
| 528 | + rpcrdma_dma_unmap_regbuf(req->rl_recvbuf); |
| 529 | + } |
| 530 | + rpcrdma_destroy_mrs(buf); |
| 531 | + |
| 532 | + /* Allow waiters to continue */ |
| 533 | + complete(&ia->ri_remove_done); |
| 534 | +} |
| 535 | + |
471 | 536 | /**
|
472 | 537 | * rpcrdma_ia_close - Clean up/close an IA.
|
473 | 538 | * @ia: interface adapter to close
|
@@ -1080,7 +1145,8 @@ rpcrdma_get_mw(struct rpcrdma_xprt *r_xprt)
|
1080 | 1145 |
|
1081 | 1146 | out_nomws:
|
1082 | 1147 | dprintk("RPC: %s: no MWs available\n", __func__);
|
1083 |
| - schedule_delayed_work(&buf->rb_refresh_worker, 0); |
| 1148 | + if (r_xprt->rx_ep.rep_connected != -ENODEV) |
| 1149 | + schedule_delayed_work(&buf->rb_refresh_worker, 0); |
1084 | 1150 |
|
1085 | 1151 | /* Allow the reply handler and refresh worker to run */
|
1086 | 1152 | cond_resched();
|
|
0 commit comments