[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