diff options
author | Steve Wise <swise@opengridcomputing.com> | 2016-09-02 12:01:54 -0400 |
---|---|---|
committer | Sagi Grimberg <sagi@grimberg.me> | 2016-09-12 15:29:41 -0400 |
commit | e87a911fed07e368c6f97e75152e6297a7dfba48 (patch) | |
tree | 993be810cc0bd7019f3e1c5faf2d2a02b33202a4 | |
parent | e89ca58f9c901c8c4cfb09f96d879b186bb01492 (diff) |
nvme-rdma: use ib_client API to detect device removal
Change nvme-rdma to use the IB Client API to detect device removal.
This has the wonderful benefit of being able to blow away all the
ib/rdma_cm resources for the device being removed. No craziness about
not destroying the cm_id handling the event. No deadlocks due to broken
iw_cm/rdma_cm/iwarp dependencies. And no need to have a bound cm_id
around during controller recovery/reconnect to catch device removal
events.
We don't use the device_add aspect of the ib_client service since we only
want to create resources for an IB device if we have a target utilizing
that device.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
-rw-r--r-- | drivers/nvme/host/rdma.c | 108 |
1 files changed, 40 insertions, 68 deletions
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index eeb08b658640..d6bdf55a969e 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c | |||
@@ -1320,64 +1320,6 @@ out_destroy_queue_ib: | |||
1320 | return ret; | 1320 | return ret; |
1321 | } | 1321 | } |
1322 | 1322 | ||
1323 | /** | ||
1324 | * nvme_rdma_device_unplug() - Handle RDMA device unplug | ||
1325 | * @queue: Queue that owns the cm_id that caught the event | ||
1326 | * | ||
1327 | * DEVICE_REMOVAL event notifies us that the RDMA device is about | ||
1328 | * to unplug so we should take care of destroying our RDMA resources. | ||
1329 | * This event will be generated for each allocated cm_id. | ||
1330 | * | ||
1331 | * In our case, the RDMA resources are managed per controller and not | ||
1332 | * only per queue. So the way we handle this is we trigger an implicit | ||
1333 | * controller deletion upon the first DEVICE_REMOVAL event we see, and | ||
1334 | * hold the event inflight until the controller deletion is completed. | ||
1335 | * | ||
1336 | * One exception that we need to handle is the destruction of the cm_id | ||
1337 | * that caught the event. Since we hold the callout until the controller | ||
1338 | * deletion is completed, we'll deadlock if the controller deletion will | ||
1339 | * call rdma_destroy_id on this queue's cm_id. Thus, we claim ownership | ||
1340 | * of destroying this queue before-hand, destroy the queue resources, | ||
1341 | * then queue the controller deletion which won't destroy this queue and | ||
1342 | * we destroy the cm_id implicitely by returning a non-zero rc to the callout. | ||
1343 | */ | ||
1344 | static int nvme_rdma_device_unplug(struct nvme_rdma_queue *queue) | ||
1345 | { | ||
1346 | struct nvme_rdma_ctrl *ctrl = queue->ctrl; | ||
1347 | int ret = 0; | ||
1348 | |||
1349 | /* Own the controller deletion */ | ||
1350 | if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING)) | ||
1351 | return 0; | ||
1352 | |||
1353 | dev_warn(ctrl->ctrl.device, | ||
1354 | "Got rdma device removal event, deleting ctrl\n"); | ||
1355 | |||
1356 | /* Get rid of reconnect work if its running */ | ||
1357 | cancel_delayed_work_sync(&ctrl->reconnect_work); | ||
1358 | |||
1359 | /* Disable the queue so ctrl delete won't free it */ | ||
1360 | if (!test_and_set_bit(NVME_RDMA_Q_DELETING, &queue->flags)) { | ||
1361 | /* Free this queue ourselves */ | ||
1362 | nvme_rdma_stop_queue(queue); | ||
1363 | nvme_rdma_destroy_queue_ib(queue); | ||
1364 | |||
1365 | /* Return non-zero so the cm_id will destroy implicitly */ | ||
1366 | ret = 1; | ||
1367 | } | ||
1368 | |||
1369 | /* | ||
1370 | * Queue controller deletion. Keep a reference until all | ||
1371 | * work is flushed since delete_work will free the ctrl mem | ||
1372 | */ | ||
1373 | kref_get(&ctrl->ctrl.kref); | ||
1374 | queue_work(nvme_rdma_wq, &ctrl->delete_work); | ||
1375 | flush_work(&ctrl->delete_work); | ||
1376 | nvme_put_ctrl(&ctrl->ctrl); | ||
1377 | |||
1378 | return ret; | ||
1379 | } | ||
1380 | |||
1381 | static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, | 1323 | static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, |
1382 | struct rdma_cm_event *ev) | 1324 | struct rdma_cm_event *ev) |
1383 | { | 1325 | { |
@@ -1419,8 +1361,8 @@ static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, | |||
1419 | nvme_rdma_error_recovery(queue->ctrl); | 1361 | nvme_rdma_error_recovery(queue->ctrl); |
1420 | break; | 1362 | break; |
1421 | case RDMA_CM_EVENT_DEVICE_REMOVAL: | 1363 | case RDMA_CM_EVENT_DEVICE_REMOVAL: |
1422 | /* return 1 means impliciy CM ID destroy */ | 1364 | /* device removal is handled via the ib_client API */ |
1423 | return nvme_rdma_device_unplug(queue); | 1365 | break; |
1424 | default: | 1366 | default: |
1425 | dev_err(queue->ctrl->ctrl.device, | 1367 | dev_err(queue->ctrl->ctrl.device, |
1426 | "Unexpected RDMA CM event (%d)\n", ev->event); | 1368 | "Unexpected RDMA CM event (%d)\n", ev->event); |
@@ -2030,27 +1972,57 @@ static struct nvmf_transport_ops nvme_rdma_transport = { | |||
2030 | .create_ctrl = nvme_rdma_create_ctrl, | 1972 | .create_ctrl = nvme_rdma_create_ctrl, |
2031 | }; | 1973 | }; |
2032 | 1974 | ||
1975 | static void nvme_rdma_add_one(struct ib_device *ib_device) | ||
1976 | { | ||
1977 | } | ||
1978 | |||
1979 | static void nvme_rdma_remove_one(struct ib_device *ib_device, void *client_data) | ||
1980 | { | ||
1981 | struct nvme_rdma_ctrl *ctrl; | ||
1982 | |||
1983 | /* Delete all controllers using this device */ | ||
1984 | mutex_lock(&nvme_rdma_ctrl_mutex); | ||
1985 | list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list) { | ||
1986 | if (ctrl->device->dev != ib_device) | ||
1987 | continue; | ||
1988 | dev_info(ctrl->ctrl.device, | ||
1989 | "Removing ctrl: NQN \"%s\", addr %pISp\n", | ||
1990 | ctrl->ctrl.opts->subsysnqn, &ctrl->addr); | ||
1991 | __nvme_rdma_del_ctrl(ctrl); | ||
1992 | } | ||
1993 | mutex_unlock(&nvme_rdma_ctrl_mutex); | ||
1994 | |||
1995 | flush_workqueue(nvme_rdma_wq); | ||
1996 | } | ||
1997 | |||
1998 | static struct ib_client nvme_rdma_ib_client = { | ||
1999 | .name = "nvme_rdma", | ||
2000 | .add = nvme_rdma_add_one, | ||
2001 | .remove = nvme_rdma_remove_one | ||
2002 | }; | ||
2003 | |||
2033 | static int __init nvme_rdma_init_module(void) | 2004 | static int __init nvme_rdma_init_module(void) |
2034 | { | 2005 | { |
2006 | int ret; | ||
2007 | |||
2035 | nvme_rdma_wq = create_workqueue("nvme_rdma_wq"); | 2008 | nvme_rdma_wq = create_workqueue("nvme_rdma_wq"); |
2036 | if (!nvme_rdma_wq) | 2009 | if (!nvme_rdma_wq) |
2037 | return -ENOMEM; | 2010 | return -ENOMEM; |
2038 | 2011 | ||
2012 | ret = ib_register_client(&nvme_rdma_ib_client); | ||
2013 | if (ret) { | ||
2014 | destroy_workqueue(nvme_rdma_wq); | ||
2015 | return ret; | ||
2016 | } | ||
2017 | |||
2039 | nvmf_register_transport(&nvme_rdma_transport); | 2018 | nvmf_register_transport(&nvme_rdma_transport); |
2040 | return 0; | 2019 | return 0; |
2041 | } | 2020 | } |
2042 | 2021 | ||
2043 | static void __exit nvme_rdma_cleanup_module(void) | 2022 | static void __exit nvme_rdma_cleanup_module(void) |
2044 | { | 2023 | { |
2045 | struct nvme_rdma_ctrl *ctrl; | ||
2046 | |||
2047 | nvmf_unregister_transport(&nvme_rdma_transport); | 2024 | nvmf_unregister_transport(&nvme_rdma_transport); |
2048 | 2025 | ib_unregister_client(&nvme_rdma_ib_client); | |
2049 | mutex_lock(&nvme_rdma_ctrl_mutex); | ||
2050 | list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list) | ||
2051 | __nvme_rdma_del_ctrl(ctrl); | ||
2052 | mutex_unlock(&nvme_rdma_ctrl_mutex); | ||
2053 | |||
2054 | destroy_workqueue(nvme_rdma_wq); | 2026 | destroy_workqueue(nvme_rdma_wq); |
2055 | } | 2027 | } |
2056 | 2028 | ||