[PATCH V2 1/2] nvme-loop: use xarray for loop ctrl tracking

Chaitanya Kulkarni chaitanya.kulkarni at wdc.com
Wed Sep 30 00:55:56 EDT 2020


For nvme-loop ctrls are tracked with nvme_loop_ctrl_list. This requires
an extra locking just for list operations.

The Xarray data structure provides a clear API which handles locking
implicitly so we can get rid of the locking and the list loops if any.

Replace nvme loop ctrl list and its lock nvme_loop_ctrl_mutex with
nvme_loop_ctrls XArray.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/loop.c | 46 ++++++++++++++++++--------------------
 1 file changed, 22 insertions(+), 24 deletions(-)

diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index f6d81239be21..2f2e16fb9f29 100644
--- a/drivers/nvme/target/loop.c
+++ b/drivers/nvme/target/loop.c
@@ -31,7 +31,6 @@ struct nvme_loop_ctrl {
 
 	struct blk_mq_tag_set	admin_tag_set;
 
-	struct list_head	list;
 	struct blk_mq_tag_set	tag_set;
 	struct nvme_loop_iod	async_event_iod;
 	struct nvme_ctrl	ctrl;
@@ -58,8 +57,7 @@ struct nvme_loop_queue {
 static LIST_HEAD(nvme_loop_ports);
 static DEFINE_MUTEX(nvme_loop_ports_mutex);
 
-static LIST_HEAD(nvme_loop_ctrl_list);
-static DEFINE_MUTEX(nvme_loop_ctrl_mutex);
+static DEFINE_XARRAY(nvme_loop_ctrls);
 
 static void nvme_loop_queue_response(struct nvmet_req *nvme_req);
 static void nvme_loop_delete_ctrl(struct nvmet_ctrl *ctrl);
@@ -262,12 +260,10 @@ static void nvme_loop_free_ctrl(struct nvme_ctrl *nctrl)
 {
 	struct nvme_loop_ctrl *ctrl = to_loop_ctrl(nctrl);
 
-	if (list_empty(&ctrl->list))
+	if (!xa_load(&nvme_loop_ctrls, nctrl->cntlid))
 		goto free_ctrl;
 
-	mutex_lock(&nvme_loop_ctrl_mutex);
-	list_del(&ctrl->list);
-	mutex_unlock(&nvme_loop_ctrl_mutex);
+	xa_erase(&nvme_loop_ctrls, nctrl->cntlid);
 
 	if (nctrl->tagset) {
 		blk_cleanup_queue(ctrl->ctrl.connect_q);
@@ -430,14 +426,10 @@ static void nvme_loop_delete_ctrl_host(struct nvme_ctrl *ctrl)
 
 static void nvme_loop_delete_ctrl(struct nvmet_ctrl *nctrl)
 {
-	struct nvme_loop_ctrl *ctrl;
+	struct nvme_loop_ctrl *ctrl = xa_load(&nvme_loop_ctrls, nctrl->cntlid);
 
-	mutex_lock(&nvme_loop_ctrl_mutex);
-	list_for_each_entry(ctrl, &nvme_loop_ctrl_list, list) {
-		if (ctrl->ctrl.cntlid == nctrl->cntlid)
-			nvme_delete_ctrl(&ctrl->ctrl);
-	}
-	mutex_unlock(&nvme_loop_ctrl_mutex);
+	if (ctrl)
+		nvme_delete_ctrl(&ctrl->ctrl);
 }
 
 static void nvme_loop_reset_ctrl_work(struct work_struct *work)
@@ -572,7 +564,6 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
 	if (!ctrl)
 		return ERR_PTR(-ENOMEM);
 	ctrl->ctrl.opts = opts;
-	INIT_LIST_HEAD(&ctrl->list);
 
 	INIT_WORK(&ctrl->ctrl.reset_work, nvme_loop_reset_ctrl_work);
 
@@ -599,6 +590,12 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
 	if (ret)
 		goto out_free_queues;
 
+	/* unusual place to update xarray, makes unwind code simple */
+	ret = xa_insert(&nvme_loop_ctrls, ctrl->ctrl.cntlid, &ctrl,
+			GFP_KERNEL);
+	if (ret)
+		goto out_remove_ctrl;
+
 	if (opts->queue_size > ctrl->ctrl.maxcmd) {
 		/* warn if maxcmd is lower than queue_size */
 		dev_warn(ctrl->ctrl.device,
@@ -621,16 +618,14 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
 	if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE))
 		WARN_ON_ONCE(1);
 
-	mutex_lock(&nvme_loop_ctrl_mutex);
-	list_add_tail(&ctrl->list, &nvme_loop_ctrl_list);
-	mutex_unlock(&nvme_loop_ctrl_mutex);
-
 	nvme_start_ctrl(&ctrl->ctrl);
 
 	return &ctrl->ctrl;
 
 out_remove_admin_queue:
 	nvme_loop_destroy_admin_queue(ctrl);
+out_remove_ctrl:
+	xa_erase(&nvme_loop_ctrls, ctrl->ctrl.cntlid);
 out_free_queues:
 	kfree(ctrl->queues);
 out_uninit_ctrl:
@@ -678,7 +673,7 @@ static struct nvmf_transport_ops nvme_loop_transport = {
 	.name		= "loop",
 	.module		= THIS_MODULE,
 	.create_ctrl	= nvme_loop_create_ctrl,
-	.allowed_opts	= NVMF_OPT_TRADDR,
+	.allowed_opts	= NVMF_OPT_TRADDR | NVMF_OPT_CTRL_LOSS_TMO,
 };
 
 static int __init nvme_loop_init_module(void)
@@ -693,20 +688,23 @@ static int __init nvme_loop_init_module(void)
 	if (ret)
 		nvmet_unregister_transport(&nvme_loop_ops);
 
+	xa_init(&nvme_loop_ctrls);
+
 	return ret;
 }
 
 static void __exit nvme_loop_cleanup_module(void)
 {
-	struct nvme_loop_ctrl *ctrl, *next;
+	struct nvme_loop_ctrl *ctrl;
+	unsigned long idx;
 
 	nvmf_unregister_transport(&nvme_loop_transport);
 	nvmet_unregister_transport(&nvme_loop_ops);
 
-	mutex_lock(&nvme_loop_ctrl_mutex);
-	list_for_each_entry_safe(ctrl, next, &nvme_loop_ctrl_list, list)
+	xa_for_each(&nvme_loop_ctrls, idx, ctrl)
 		nvme_delete_ctrl(&ctrl->ctrl);
-	mutex_unlock(&nvme_loop_ctrl_mutex);
+
+	xa_destroy(&nvme_loop_ctrls);
 
 	flush_workqueue(nvme_delete_wq);
 }
-- 
2.22.1




More information about the Linux-nvme mailing list