diff options
author | Jens Axboe <axboe@fb.com> | 2016-08-08 09:42:42 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-08-08 09:42:42 -0400 |
commit | d3f422c8d58b2f0d68a51db88389a715dc10b4d2 (patch) | |
tree | 128fe3046bdb500af63a38d5ed407add7c969e76 | |
parent | 29b4817d4018df78086157ea3a55c1d9424a7cfc (diff) | |
parent | e3266378bdbca82c2854fc612fa9a391eba1f173 (diff) |
Merge branch 'nvmf-4.8-rc' of git://git.infradead.org/nvme-fabrics into for-linus
Sagi writes:
Mostly stability fixes for nvmet, rdma:
- fix uninitialized rdma_cm private data from Roland.
- rdma device removal handling (host and target).
- fix controller disconnect during active mounts.
- fix namespaces lost after fabric reconnects.
- remove redundant calls to namespace removal (rdma, loop).
- actually send controller shutdown when disconnecting.
- reconnect fixes (ns rescan and aen requeue)
- nvmet controller serial number inconsistency fix.
-rw-r--r-- | drivers/nvme/host/rdma.c | 83 | ||||
-rw-r--r-- | drivers/nvme/target/admin-cmd.c | 6 | ||||
-rw-r--r-- | drivers/nvme/target/core.c | 4 | ||||
-rw-r--r-- | drivers/nvme/target/loop.c | 4 | ||||
-rw-r--r-- | drivers/nvme/target/nvmet.h | 1 | ||||
-rw-r--r-- | drivers/nvme/target/rdma.c | 100 |
6 files changed, 126 insertions, 72 deletions
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 3e3ce2b0424e..8d2875b4c56d 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c | |||
@@ -12,13 +12,11 @@ | |||
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
15 | #include <linux/delay.h> | ||
16 | #include <linux/module.h> | 15 | #include <linux/module.h> |
17 | #include <linux/init.h> | 16 | #include <linux/init.h> |
18 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
19 | #include <linux/err.h> | 18 | #include <linux/err.h> |
20 | #include <linux/string.h> | 19 | #include <linux/string.h> |
21 | #include <linux/jiffies.h> | ||
22 | #include <linux/atomic.h> | 20 | #include <linux/atomic.h> |
23 | #include <linux/blk-mq.h> | 21 | #include <linux/blk-mq.h> |
24 | #include <linux/types.h> | 22 | #include <linux/types.h> |
@@ -26,7 +24,6 @@ | |||
26 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
27 | #include <linux/scatterlist.h> | 25 | #include <linux/scatterlist.h> |
28 | #include <linux/nvme.h> | 26 | #include <linux/nvme.h> |
29 | #include <linux/t10-pi.h> | ||
30 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
31 | 28 | ||
32 | #include <rdma/ib_verbs.h> | 29 | #include <rdma/ib_verbs.h> |
@@ -169,7 +166,6 @@ MODULE_PARM_DESC(register_always, | |||
169 | static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, | 166 | static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, |
170 | struct rdma_cm_event *event); | 167 | struct rdma_cm_event *event); |
171 | static void nvme_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc); | 168 | static void nvme_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc); |
172 | static int __nvme_rdma_del_ctrl(struct nvme_rdma_ctrl *ctrl); | ||
173 | 169 | ||
174 | /* XXX: really should move to a generic header sooner or later.. */ | 170 | /* XXX: really should move to a generic header sooner or later.. */ |
175 | static inline void put_unaligned_le24(u32 val, u8 *p) | 171 | static inline void put_unaligned_le24(u32 val, u8 *p) |
@@ -687,11 +683,6 @@ static void nvme_rdma_free_ctrl(struct nvme_ctrl *nctrl) | |||
687 | list_del(&ctrl->list); | 683 | list_del(&ctrl->list); |
688 | mutex_unlock(&nvme_rdma_ctrl_mutex); | 684 | mutex_unlock(&nvme_rdma_ctrl_mutex); |
689 | 685 | ||
690 | if (ctrl->ctrl.tagset) { | ||
691 | blk_cleanup_queue(ctrl->ctrl.connect_q); | ||
692 | blk_mq_free_tag_set(&ctrl->tag_set); | ||
693 | nvme_rdma_dev_put(ctrl->device); | ||
694 | } | ||
695 | kfree(ctrl->queues); | 686 | kfree(ctrl->queues); |
696 | nvmf_free_options(nctrl->opts); | 687 | nvmf_free_options(nctrl->opts); |
697 | free_ctrl: | 688 | free_ctrl: |
@@ -748,8 +739,11 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work) | |||
748 | changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE); | 739 | changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE); |
749 | WARN_ON_ONCE(!changed); | 740 | WARN_ON_ONCE(!changed); |
750 | 741 | ||
751 | if (ctrl->queue_count > 1) | 742 | if (ctrl->queue_count > 1) { |
752 | nvme_start_queues(&ctrl->ctrl); | 743 | nvme_start_queues(&ctrl->ctrl); |
744 | nvme_queue_scan(&ctrl->ctrl); | ||
745 | nvme_queue_async_events(&ctrl->ctrl); | ||
746 | } | ||
753 | 747 | ||
754 | dev_info(ctrl->ctrl.device, "Successfully reconnected\n"); | 748 | dev_info(ctrl->ctrl.device, "Successfully reconnected\n"); |
755 | 749 | ||
@@ -1269,7 +1263,7 @@ static int nvme_rdma_route_resolved(struct nvme_rdma_queue *queue) | |||
1269 | { | 1263 | { |
1270 | struct nvme_rdma_ctrl *ctrl = queue->ctrl; | 1264 | struct nvme_rdma_ctrl *ctrl = queue->ctrl; |
1271 | struct rdma_conn_param param = { }; | 1265 | struct rdma_conn_param param = { }; |
1272 | struct nvme_rdma_cm_req priv; | 1266 | struct nvme_rdma_cm_req priv = { }; |
1273 | int ret; | 1267 | int ret; |
1274 | 1268 | ||
1275 | param.qp_num = queue->qp->qp_num; | 1269 | param.qp_num = queue->qp->qp_num; |
@@ -1318,37 +1312,39 @@ out_destroy_queue_ib: | |||
1318 | * that caught the event. Since we hold the callout until the controller | 1312 | * that caught the event. Since we hold the callout until the controller |
1319 | * deletion is completed, we'll deadlock if the controller deletion will | 1313 | * deletion is completed, we'll deadlock if the controller deletion will |
1320 | * call rdma_destroy_id on this queue's cm_id. Thus, we claim ownership | 1314 | * call rdma_destroy_id on this queue's cm_id. Thus, we claim ownership |
1321 | * of destroying this queue before-hand, destroy the queue resources | 1315 | * of destroying this queue before-hand, destroy the queue resources, |
1322 | * after the controller deletion completed with the exception of destroying | 1316 | * then queue the controller deletion which won't destroy this queue and |
1323 | * the cm_id implicitely by returning a non-zero rc to the callout. | 1317 | * we destroy the cm_id implicitely by returning a non-zero rc to the callout. |
1324 | */ | 1318 | */ |
1325 | static int nvme_rdma_device_unplug(struct nvme_rdma_queue *queue) | 1319 | static int nvme_rdma_device_unplug(struct nvme_rdma_queue *queue) |
1326 | { | 1320 | { |
1327 | struct nvme_rdma_ctrl *ctrl = queue->ctrl; | 1321 | struct nvme_rdma_ctrl *ctrl = queue->ctrl; |
1328 | int ret, ctrl_deleted = 0; | 1322 | int ret; |
1329 | 1323 | ||
1330 | /* First disable the queue so ctrl delete won't free it */ | 1324 | /* Own the controller deletion */ |
1331 | if (!test_and_clear_bit(NVME_RDMA_Q_CONNECTED, &queue->flags)) | 1325 | if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING)) |
1332 | goto out; | 1326 | return 0; |
1333 | 1327 | ||
1334 | /* delete the controller */ | 1328 | dev_warn(ctrl->ctrl.device, |
1335 | ret = __nvme_rdma_del_ctrl(ctrl); | 1329 | "Got rdma device removal event, deleting ctrl\n"); |
1336 | if (!ret) { | ||
1337 | dev_warn(ctrl->ctrl.device, | ||
1338 | "Got rdma device removal event, deleting ctrl\n"); | ||
1339 | flush_work(&ctrl->delete_work); | ||
1340 | 1330 | ||
1341 | /* Return non-zero so the cm_id will destroy implicitly */ | 1331 | /* Get rid of reconnect work if its running */ |
1342 | ctrl_deleted = 1; | 1332 | cancel_delayed_work_sync(&ctrl->reconnect_work); |
1343 | 1333 | ||
1334 | /* Disable the queue so ctrl delete won't free it */ | ||
1335 | if (test_and_clear_bit(NVME_RDMA_Q_CONNECTED, &queue->flags)) { | ||
1344 | /* Free this queue ourselves */ | 1336 | /* Free this queue ourselves */ |
1345 | rdma_disconnect(queue->cm_id); | 1337 | nvme_rdma_stop_queue(queue); |
1346 | ib_drain_qp(queue->qp); | ||
1347 | nvme_rdma_destroy_queue_ib(queue); | 1338 | nvme_rdma_destroy_queue_ib(queue); |
1339 | |||
1340 | /* Return non-zero so the cm_id will destroy implicitly */ | ||
1341 | ret = 1; | ||
1348 | } | 1342 | } |
1349 | 1343 | ||
1350 | out: | 1344 | /* Queue controller deletion */ |
1351 | return ctrl_deleted; | 1345 | queue_work(nvme_rdma_wq, &ctrl->delete_work); |
1346 | flush_work(&ctrl->delete_work); | ||
1347 | return ret; | ||
1352 | } | 1348 | } |
1353 | 1349 | ||
1354 | static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, | 1350 | static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, |
@@ -1648,7 +1644,7 @@ static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl) | |||
1648 | nvme_rdma_free_io_queues(ctrl); | 1644 | nvme_rdma_free_io_queues(ctrl); |
1649 | } | 1645 | } |
1650 | 1646 | ||
1651 | if (ctrl->ctrl.state == NVME_CTRL_LIVE) | 1647 | if (test_bit(NVME_RDMA_Q_CONNECTED, &ctrl->queues[0].flags)) |
1652 | nvme_shutdown_ctrl(&ctrl->ctrl); | 1648 | nvme_shutdown_ctrl(&ctrl->ctrl); |
1653 | 1649 | ||
1654 | blk_mq_stop_hw_queues(ctrl->ctrl.admin_q); | 1650 | blk_mq_stop_hw_queues(ctrl->ctrl.admin_q); |
@@ -1657,15 +1653,27 @@ static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl) | |||
1657 | nvme_rdma_destroy_admin_queue(ctrl); | 1653 | nvme_rdma_destroy_admin_queue(ctrl); |
1658 | } | 1654 | } |
1659 | 1655 | ||
1656 | static void __nvme_rdma_remove_ctrl(struct nvme_rdma_ctrl *ctrl, bool shutdown) | ||
1657 | { | ||
1658 | nvme_uninit_ctrl(&ctrl->ctrl); | ||
1659 | if (shutdown) | ||
1660 | nvme_rdma_shutdown_ctrl(ctrl); | ||
1661 | |||
1662 | if (ctrl->ctrl.tagset) { | ||
1663 | blk_cleanup_queue(ctrl->ctrl.connect_q); | ||
1664 | blk_mq_free_tag_set(&ctrl->tag_set); | ||
1665 | nvme_rdma_dev_put(ctrl->device); | ||
1666 | } | ||
1667 | |||
1668 | nvme_put_ctrl(&ctrl->ctrl); | ||
1669 | } | ||
1670 | |||
1660 | static void nvme_rdma_del_ctrl_work(struct work_struct *work) | 1671 | static void nvme_rdma_del_ctrl_work(struct work_struct *work) |
1661 | { | 1672 | { |
1662 | struct nvme_rdma_ctrl *ctrl = container_of(work, | 1673 | struct nvme_rdma_ctrl *ctrl = container_of(work, |
1663 | struct nvme_rdma_ctrl, delete_work); | 1674 | struct nvme_rdma_ctrl, delete_work); |
1664 | 1675 | ||
1665 | nvme_remove_namespaces(&ctrl->ctrl); | 1676 | __nvme_rdma_remove_ctrl(ctrl, true); |
1666 | nvme_rdma_shutdown_ctrl(ctrl); | ||
1667 | nvme_uninit_ctrl(&ctrl->ctrl); | ||
1668 | nvme_put_ctrl(&ctrl->ctrl); | ||
1669 | } | 1677 | } |
1670 | 1678 | ||
1671 | static int __nvme_rdma_del_ctrl(struct nvme_rdma_ctrl *ctrl) | 1679 | static int __nvme_rdma_del_ctrl(struct nvme_rdma_ctrl *ctrl) |
@@ -1698,9 +1706,7 @@ static void nvme_rdma_remove_ctrl_work(struct work_struct *work) | |||
1698 | struct nvme_rdma_ctrl *ctrl = container_of(work, | 1706 | struct nvme_rdma_ctrl *ctrl = container_of(work, |
1699 | struct nvme_rdma_ctrl, delete_work); | 1707 | struct nvme_rdma_ctrl, delete_work); |
1700 | 1708 | ||
1701 | nvme_remove_namespaces(&ctrl->ctrl); | 1709 | __nvme_rdma_remove_ctrl(ctrl, false); |
1702 | nvme_uninit_ctrl(&ctrl->ctrl); | ||
1703 | nvme_put_ctrl(&ctrl->ctrl); | ||
1704 | } | 1710 | } |
1705 | 1711 | ||
1706 | static void nvme_rdma_reset_ctrl_work(struct work_struct *work) | 1712 | static void nvme_rdma_reset_ctrl_work(struct work_struct *work) |
@@ -1739,6 +1745,7 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) | |||
1739 | if (ctrl->queue_count > 1) { | 1745 | if (ctrl->queue_count > 1) { |
1740 | nvme_start_queues(&ctrl->ctrl); | 1746 | nvme_start_queues(&ctrl->ctrl); |
1741 | nvme_queue_scan(&ctrl->ctrl); | 1747 | nvme_queue_scan(&ctrl->ctrl); |
1748 | nvme_queue_async_events(&ctrl->ctrl); | ||
1742 | } | 1749 | } |
1743 | 1750 | ||
1744 | return; | 1751 | return; |
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 2fac17a5ad53..47c564b5a289 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c | |||
@@ -13,7 +13,6 @@ | |||
13 | */ | 13 | */ |
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/random.h> | ||
17 | #include <generated/utsrelease.h> | 16 | #include <generated/utsrelease.h> |
18 | #include "nvmet.h" | 17 | #include "nvmet.h" |
19 | 18 | ||
@@ -83,7 +82,6 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) | |||
83 | { | 82 | { |
84 | struct nvmet_ctrl *ctrl = req->sq->ctrl; | 83 | struct nvmet_ctrl *ctrl = req->sq->ctrl; |
85 | struct nvme_id_ctrl *id; | 84 | struct nvme_id_ctrl *id; |
86 | u64 serial; | ||
87 | u16 status = 0; | 85 | u16 status = 0; |
88 | 86 | ||
89 | id = kzalloc(sizeof(*id), GFP_KERNEL); | 87 | id = kzalloc(sizeof(*id), GFP_KERNEL); |
@@ -96,10 +94,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) | |||
96 | id->vid = 0; | 94 | id->vid = 0; |
97 | id->ssvid = 0; | 95 | id->ssvid = 0; |
98 | 96 | ||
99 | /* generate a random serial number as our controllers are ephemeral: */ | ||
100 | get_random_bytes(&serial, sizeof(serial)); | ||
101 | memset(id->sn, ' ', sizeof(id->sn)); | 97 | memset(id->sn, ' ', sizeof(id->sn)); |
102 | snprintf(id->sn, sizeof(id->sn), "%llx", serial); | 98 | snprintf(id->sn, sizeof(id->sn), "%llx", ctrl->serial); |
103 | 99 | ||
104 | memset(id->mn, ' ', sizeof(id->mn)); | 100 | memset(id->mn, ' ', sizeof(id->mn)); |
105 | strncpy((char *)id->mn, "Linux", sizeof(id->mn)); | 101 | strncpy((char *)id->mn, "Linux", sizeof(id->mn)); |
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 8a891ca53367..6559d5afa7bf 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/random.h> | ||
16 | #include "nvmet.h" | 17 | #include "nvmet.h" |
17 | 18 | ||
18 | static struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX]; | 19 | static struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX]; |
@@ -728,6 +729,9 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, | |||
728 | memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); | 729 | memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); |
729 | memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); | 730 | memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); |
730 | 731 | ||
732 | /* generate a random serial number as our controllers are ephemeral: */ | ||
733 | get_random_bytes(&ctrl->serial, sizeof(ctrl->serial)); | ||
734 | |||
731 | kref_init(&ctrl->ref); | 735 | kref_init(&ctrl->ref); |
732 | ctrl->subsys = subsys; | 736 | ctrl->subsys = subsys; |
733 | 737 | ||
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index 94e782987cc9..7affd40a6b33 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c | |||
@@ -414,9 +414,8 @@ static void nvme_loop_del_ctrl_work(struct work_struct *work) | |||
414 | struct nvme_loop_ctrl *ctrl = container_of(work, | 414 | struct nvme_loop_ctrl *ctrl = container_of(work, |
415 | struct nvme_loop_ctrl, delete_work); | 415 | struct nvme_loop_ctrl, delete_work); |
416 | 416 | ||
417 | nvme_remove_namespaces(&ctrl->ctrl); | ||
418 | nvme_loop_shutdown_ctrl(ctrl); | ||
419 | nvme_uninit_ctrl(&ctrl->ctrl); | 417 | nvme_uninit_ctrl(&ctrl->ctrl); |
418 | nvme_loop_shutdown_ctrl(ctrl); | ||
420 | nvme_put_ctrl(&ctrl->ctrl); | 419 | nvme_put_ctrl(&ctrl->ctrl); |
421 | } | 420 | } |
422 | 421 | ||
@@ -501,7 +500,6 @@ out_free_queues: | |||
501 | nvme_loop_destroy_admin_queue(ctrl); | 500 | nvme_loop_destroy_admin_queue(ctrl); |
502 | out_disable: | 501 | out_disable: |
503 | dev_warn(ctrl->ctrl.device, "Removing after reset failure\n"); | 502 | dev_warn(ctrl->ctrl.device, "Removing after reset failure\n"); |
504 | nvme_remove_namespaces(&ctrl->ctrl); | ||
505 | nvme_uninit_ctrl(&ctrl->ctrl); | 503 | nvme_uninit_ctrl(&ctrl->ctrl); |
506 | nvme_put_ctrl(&ctrl->ctrl); | 504 | nvme_put_ctrl(&ctrl->ctrl); |
507 | } | 505 | } |
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 57dd6d834c28..76b6eedccaf9 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h | |||
@@ -113,6 +113,7 @@ struct nvmet_ctrl { | |||
113 | 113 | ||
114 | struct mutex lock; | 114 | struct mutex lock; |
115 | u64 cap; | 115 | u64 cap; |
116 | u64 serial; | ||
116 | u32 cc; | 117 | u32 cc; |
117 | u32 csts; | 118 | u32 csts; |
118 | 119 | ||
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index e06d504bdf0c..b4d648536c3e 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c | |||
@@ -77,6 +77,7 @@ enum nvmet_rdma_queue_state { | |||
77 | NVMET_RDMA_Q_CONNECTING, | 77 | NVMET_RDMA_Q_CONNECTING, |
78 | NVMET_RDMA_Q_LIVE, | 78 | NVMET_RDMA_Q_LIVE, |
79 | NVMET_RDMA_Q_DISCONNECTING, | 79 | NVMET_RDMA_Q_DISCONNECTING, |
80 | NVMET_RDMA_IN_DEVICE_REMOVAL, | ||
80 | }; | 81 | }; |
81 | 82 | ||
82 | struct nvmet_rdma_queue { | 83 | struct nvmet_rdma_queue { |
@@ -615,15 +616,10 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp, | |||
615 | if (!len) | 616 | if (!len) |
616 | return 0; | 617 | return 0; |
617 | 618 | ||
618 | /* use the already allocated data buffer if possible */ | 619 | status = nvmet_rdma_alloc_sgl(&rsp->req.sg, &rsp->req.sg_cnt, |
619 | if (len <= NVMET_RDMA_INLINE_DATA_SIZE && rsp->queue->host_qid) { | 620 | len); |
620 | nvmet_rdma_use_inline_sg(rsp, len, 0); | 621 | if (status) |
621 | } else { | 622 | return status; |
622 | status = nvmet_rdma_alloc_sgl(&rsp->req.sg, &rsp->req.sg_cnt, | ||
623 | len); | ||
624 | if (status) | ||
625 | return status; | ||
626 | } | ||
627 | 623 | ||
628 | ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num, | 624 | ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num, |
629 | rsp->req.sg, rsp->req.sg_cnt, 0, addr, key, | 625 | rsp->req.sg, rsp->req.sg_cnt, 0, addr, key, |
@@ -984,7 +980,10 @@ static void nvmet_rdma_release_queue_work(struct work_struct *w) | |||
984 | struct nvmet_rdma_device *dev = queue->dev; | 980 | struct nvmet_rdma_device *dev = queue->dev; |
985 | 981 | ||
986 | nvmet_rdma_free_queue(queue); | 982 | nvmet_rdma_free_queue(queue); |
987 | rdma_destroy_id(cm_id); | 983 | |
984 | if (queue->state != NVMET_RDMA_IN_DEVICE_REMOVAL) | ||
985 | rdma_destroy_id(cm_id); | ||
986 | |||
988 | kref_put(&dev->ref, nvmet_rdma_free_dev); | 987 | kref_put(&dev->ref, nvmet_rdma_free_dev); |
989 | } | 988 | } |
990 | 989 | ||
@@ -1233,8 +1232,9 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue) | |||
1233 | switch (queue->state) { | 1232 | switch (queue->state) { |
1234 | case NVMET_RDMA_Q_CONNECTING: | 1233 | case NVMET_RDMA_Q_CONNECTING: |
1235 | case NVMET_RDMA_Q_LIVE: | 1234 | case NVMET_RDMA_Q_LIVE: |
1236 | disconnect = true; | ||
1237 | queue->state = NVMET_RDMA_Q_DISCONNECTING; | 1235 | queue->state = NVMET_RDMA_Q_DISCONNECTING; |
1236 | case NVMET_RDMA_IN_DEVICE_REMOVAL: | ||
1237 | disconnect = true; | ||
1238 | break; | 1238 | break; |
1239 | case NVMET_RDMA_Q_DISCONNECTING: | 1239 | case NVMET_RDMA_Q_DISCONNECTING: |
1240 | break; | 1240 | break; |
@@ -1272,6 +1272,62 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id, | |||
1272 | schedule_work(&queue->release_work); | 1272 | schedule_work(&queue->release_work); |
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | /** | ||
1276 | * nvme_rdma_device_removal() - Handle RDMA device removal | ||
1277 | * @queue: nvmet rdma queue (cm id qp_context) | ||
1278 | * @addr: nvmet address (cm_id context) | ||
1279 | * | ||
1280 | * DEVICE_REMOVAL event notifies us that the RDMA device is about | ||
1281 | * to unplug so we should take care of destroying our RDMA resources. | ||
1282 | * This event will be generated for each allocated cm_id. | ||
1283 | * | ||
1284 | * Note that this event can be generated on a normal queue cm_id | ||
1285 | * and/or a device bound listener cm_id (where in this case | ||
1286 | * queue will be null). | ||
1287 | * | ||
1288 | * we claim ownership on destroying the cm_id. For queues we move | ||
1289 | * the queue state to NVMET_RDMA_IN_DEVICE_REMOVAL and for port | ||
1290 | * we nullify the priv to prevent double cm_id destruction and destroying | ||
1291 | * the cm_id implicitely by returning a non-zero rc to the callout. | ||
1292 | */ | ||
1293 | static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id, | ||
1294 | struct nvmet_rdma_queue *queue) | ||
1295 | { | ||
1296 | unsigned long flags; | ||
1297 | |||
1298 | if (!queue) { | ||
1299 | struct nvmet_port *port = cm_id->context; | ||
1300 | |||
1301 | /* | ||
1302 | * This is a listener cm_id. Make sure that | ||
1303 | * future remove_port won't invoke a double | ||
1304 | * cm_id destroy. use atomic xchg to make sure | ||
1305 | * we don't compete with remove_port. | ||
1306 | */ | ||
1307 | if (xchg(&port->priv, NULL) != cm_id) | ||
1308 | return 0; | ||
1309 | } else { | ||
1310 | /* | ||
1311 | * This is a queue cm_id. Make sure that | ||
1312 | * release queue will not destroy the cm_id | ||
1313 | * and schedule all ctrl queues removal (only | ||
1314 | * if the queue is not disconnecting already). | ||
1315 | */ | ||
1316 | spin_lock_irqsave(&queue->state_lock, flags); | ||
1317 | if (queue->state != NVMET_RDMA_Q_DISCONNECTING) | ||
1318 | queue->state = NVMET_RDMA_IN_DEVICE_REMOVAL; | ||
1319 | spin_unlock_irqrestore(&queue->state_lock, flags); | ||
1320 | nvmet_rdma_queue_disconnect(queue); | ||
1321 | flush_scheduled_work(); | ||
1322 | } | ||
1323 | |||
1324 | /* | ||
1325 | * We need to return 1 so that the core will destroy | ||
1326 | * it's own ID. What a great API design.. | ||
1327 | */ | ||
1328 | return 1; | ||
1329 | } | ||
1330 | |||
1275 | static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id, | 1331 | static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id, |
1276 | struct rdma_cm_event *event) | 1332 | struct rdma_cm_event *event) |
1277 | { | 1333 | { |
@@ -1294,20 +1350,11 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id, | |||
1294 | break; | 1350 | break; |
1295 | case RDMA_CM_EVENT_ADDR_CHANGE: | 1351 | case RDMA_CM_EVENT_ADDR_CHANGE: |
1296 | case RDMA_CM_EVENT_DISCONNECTED: | 1352 | case RDMA_CM_EVENT_DISCONNECTED: |
1297 | case RDMA_CM_EVENT_DEVICE_REMOVAL: | ||
1298 | case RDMA_CM_EVENT_TIMEWAIT_EXIT: | 1353 | case RDMA_CM_EVENT_TIMEWAIT_EXIT: |
1299 | /* | 1354 | nvmet_rdma_queue_disconnect(queue); |
1300 | * We can get the device removal callback even for a | 1355 | break; |
1301 | * CM ID that we aren't actually using. In that case | 1356 | case RDMA_CM_EVENT_DEVICE_REMOVAL: |
1302 | * the context pointer is NULL, so we shouldn't try | 1357 | ret = nvmet_rdma_device_removal(cm_id, queue); |
1303 | * to disconnect a non-existing queue. But we also | ||
1304 | * need to return 1 so that the core will destroy | ||
1305 | * it's own ID. What a great API design.. | ||
1306 | */ | ||
1307 | if (queue) | ||
1308 | nvmet_rdma_queue_disconnect(queue); | ||
1309 | else | ||
1310 | ret = 1; | ||
1311 | break; | 1358 | break; |
1312 | case RDMA_CM_EVENT_REJECTED: | 1359 | case RDMA_CM_EVENT_REJECTED: |
1313 | case RDMA_CM_EVENT_UNREACHABLE: | 1360 | case RDMA_CM_EVENT_UNREACHABLE: |
@@ -1396,9 +1443,10 @@ out_destroy_id: | |||
1396 | 1443 | ||
1397 | static void nvmet_rdma_remove_port(struct nvmet_port *port) | 1444 | static void nvmet_rdma_remove_port(struct nvmet_port *port) |
1398 | { | 1445 | { |
1399 | struct rdma_cm_id *cm_id = port->priv; | 1446 | struct rdma_cm_id *cm_id = xchg(&port->priv, NULL); |
1400 | 1447 | ||
1401 | rdma_destroy_id(cm_id); | 1448 | if (cm_id) |
1449 | rdma_destroy_id(cm_id); | ||
1402 | } | 1450 | } |
1403 | 1451 | ||
1404 | static struct nvmet_fabrics_ops nvmet_rdma_ops = { | 1452 | static struct nvmet_fabrics_ops nvmet_rdma_ops = { |