[PATCH] nvme: fix flush dependency in delete controller flow

Nitzan Carmi nitzanc at mellanox.com
Mon Apr 2 05:37:27 PDT 2018


nvme_delete_ctrl queues a work on a MEM_RECLAIM queue
(nvme_delete_wq), which eventually calls cleanup_srcu_struct,
which in turn flushes a delayed work from an !MEM_RECLAIM
queue. This is unsafe as we might trigger deadlocks under
severe memory pressure.

Fix this by moving the cleanups to a seperate work over
the safe !MEM_RECLAIM system_wq.

Fixes: ed754e5dee ("nvme: track shared namespaces")
Signed-off-by: Nitzan Carmi <nitzanc at mellanox.com>
Reviewed-by: Max Gurtovoy <maxg at mellanox.com>
---
 drivers/nvme/host/core.c | 12 ++++++++++--
 drivers/nvme/host/nvme.h |  1 +
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 75f3e4c..7fc5d9d 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -362,6 +362,14 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 }
 EXPORT_SYMBOL_GPL(nvme_change_ctrl_state);
 
+static void nvme_free_ns_head_work(struct work_struct *work) {
+	struct nvme_ns_head *head =
+		container_of(work, struct nvme_ns_head, free_work);
+
+	cleanup_srcu_struct(&head->srcu);
+	kfree(head);
+}
+
 static void nvme_free_ns_head(struct kref *ref)
 {
 	struct nvme_ns_head *head =
@@ -370,8 +378,7 @@ static void nvme_free_ns_head(struct kref *ref)
 	nvme_mpath_remove_disk(head);
 	ida_simple_remove(&head->subsys->ns_ida, head->instance);
 	list_del_init(&head->entry);
-	cleanup_srcu_struct(&head->srcu);
-	kfree(head);
+	queue_work(system_wq, &head->free_work);
 }
 
 static void nvme_put_ns_head(struct nvme_ns_head *head)
@@ -3099,6 +3106,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
 		goto out_free_head;
 	head->instance = ret;
 	INIT_LIST_HEAD(&head->list);
+	INIT_WORK(&head->free_work, nvme_free_ns_head_work);
 	init_srcu_struct(&head->srcu);
 	head->subsys = ctrl->subsys;
 	head->ns_id = nsid;
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 178aced..f443608 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -270,6 +270,7 @@ struct nvme_ns_head {
 	spinlock_t		requeue_lock;
 	struct work_struct	requeue_work;
 #endif
+	struct work_struct	free_work;
 	struct list_head	list;
 	struct srcu_struct      srcu;
 	struct nvme_subsystem	*subsys;
-- 
1.8.2.3




More information about the Linux-nvme mailing list