Linux-NVME Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Nilay Shroff <nilay@linux.ibm.com>
To: linux-nvme@lists.infradead.org
Cc: kbusch@kernel.org, sagi@grimberg.me, hch@lst.de, axboe@fb.com,
	john.g.garry@oracle.com, wenxiong@linux.ibm.com,
	gjoyce@linux.ibm.com, Nilay Shroff <nilay@linux.ibm.com>
Subject: [PATCH 1/2] nvme: keep transport module referenced while head node is open
Date: Mon, 31 Aug 2026 20:49:54 +0530	[thread overview]
Message-ID: <20260831152006.819471-2-nilay@linux.ibm.com> (raw)
In-Reply-To: <20260831152006.819471-1-nilay@linux.ibm.com>

When a user opens an NVMe multipath head node, we take a reference to
the head node, but this does not prevent the transport module backing
its paths from being unloaded. This can result in the multipath head
remaining open while its underlying transport module is unloaded.

Fix this by taking a reference to the transport module for each active
path when the multipath head node is opened. Keep track of the number
of active head node openers so that dynamically added paths acquire the
same number of transport module references.

Similarly, when a path is removed while the head node is open, release
the transport module reference once for each active head node opener.
When the head node is closed, release the transport module reference
held for each remaining active path.

This ensures that a transport module cannot be unloaded while it is
still referenced by an open multipath head node.

Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
---
 drivers/nvme/host/core.c      |  6 ++++++
 drivers/nvme/host/multipath.c | 37 +++++++++++++++++++++++++++++++++--
 drivers/nvme/host/nvme.h      | 32 ++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 1322c678f4eb..fdf760c57e02 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -4173,6 +4173,9 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
 
 	list_add_tail_rcu(&ns->siblings, &head->list);
 	ns->head = head;
+	ret = nvme_module_get(ns, head->nr_openers);
+	if (ret)
+		goto out_err_module_get;
 	mutex_unlock(&ctrl->subsys->lock);
 
 #ifdef CONFIG_NVME_MULTIPATH
@@ -4181,6 +4184,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
 #endif
 	return 0;
 
+out_err_module_get:
+	list_del_rcu(&ns->siblings);
 out_put_ns_head:
 	nvme_put_ns_head(head);
 out_unlock:
@@ -4370,6 +4375,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
 			list_del_init(&ns->head->entry);
 		last_path = true;
 	}
+	nvme_module_put(ns, ns->head->nr_openers);
 	mutex_unlock(&ns->ctrl->subsys->lock);
 
 	/* guarantee not available in head->list */
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 75dbb58286a3..822cd0d23e1d 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -579,14 +579,47 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
 
 static int nvme_ns_head_open(struct gendisk *disk, blk_mode_t mode)
 {
-	if (!nvme_tryget_ns_head(disk->private_data))
+	struct nvme_ns_head *head = disk->private_data;
+	struct nvme_subsystem *subsys = head->subsys;
+	struct nvme_ns *ns;
+	int ret;
+
+	if (!nvme_tryget_ns_head(head))
 		return -ENXIO;
+
+	mutex_lock(&subsys->lock);
+	list_for_each_entry(ns, &head->list, siblings) {
+		ret = nvme_module_get(ns, 1);
+		if (ret)
+			goto out_unwind;
+	}
+	head->nr_openers++;
+	mutex_unlock(&subsys->lock);
+
 	return 0;
+
+out_unwind:
+	list_for_each_entry_continue_reverse(ns, &head->list, siblings)
+		nvme_module_put(ns, 1);
+	mutex_unlock(&subsys->lock);
+
+	nvme_put_ns_head(head);
+	return ret;
 }
 
 static void nvme_ns_head_release(struct gendisk *disk)
 {
-	nvme_put_ns_head(disk->private_data);
+	struct nvme_ns_head *head = disk->private_data;
+	struct nvme_subsystem *subsys = head->subsys;
+	struct nvme_ns *ns;
+
+	mutex_lock(&subsys->lock);
+	list_for_each_entry(ns, &head->list, siblings)
+		nvme_module_put(ns, 1);
+	head->nr_openers--;
+	mutex_unlock(&subsys->lock);
+
+	nvme_put_ns_head(head);
 }
 
 static int nvme_ns_head_get_unique_id(struct gendisk *disk, u8 id[16],
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 75e5d5a8a77c..db08f4618f92 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -569,6 +569,8 @@ struct nvme_ns_head {
 
 	struct gendisk		*disk;
 
+	unsigned int		nr_openers;
+
 	u16			nr_plids;
 	u16			*plids;
 #ifdef CONFIG_NVME_MULTIPATH
@@ -1109,6 +1111,28 @@ static inline bool nvme_mpath_queue_if_no_path(struct nvme_ns_head *head)
 		return true;
 	return false;
 }
+
+static inline int nvme_module_get(struct nvme_ns *ns, unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		if (!try_module_get(ns->ctrl->ops->module))
+			goto out_unwind;
+	}
+
+	return 0;
+out_unwind:
+	while (i--)
+		module_put(ns->ctrl->ops->module);
+	return -ENXIO;
+}
+
+static inline void nvme_module_put(struct nvme_ns *ns, unsigned int count)
+{
+	while (count--)
+		module_put(ns->ctrl->ops->module);
+}
 #else
 #define multipath false
 static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
@@ -1199,6 +1223,14 @@ static inline bool nvme_disk_is_ns_head(struct gendisk *disk)
 static inline bool nvme_mpath_queue_if_no_path(struct nvme_ns_head *head)
 {
 	return false;
+}
+static inline int nvme_module_get(struct nvme_ns *ns, unsigned int count)
+{
+	return 0;
+}
+static inline void nvme_module_put(struct nvme_ns *ns, unsigned int count)
+{
+
 }
 #endif /* CONFIG_NVME_MULTIPATH */
 
-- 
2.53.0



  reply	other threads:[~2026-08-31 15:20 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 15:19 [PATCH 0/2] nvme: add reference counting for transport modules Nilay Shroff
2026-08-31 15:19 ` Nilay Shroff [this message]
2026-09-01 16:39   ` [PATCH 1/2] nvme: keep transport module referenced while head node is open Keith Busch
2026-09-02  4:55     ` Nilay Shroff
2026-09-02  0:20   ` Wen Xiong
2026-09-02 13:31   ` Christoph Hellwig
2026-09-02 14:09     ` Nilay Shroff
2026-09-02 14:13       ` Christoph Hellwig
2026-09-02 14:25         ` Keith Busch
2026-09-02 14:27         ` Nilay Shroff
2026-09-13 14:03           ` Nilay Shroff
2026-08-31 15:19 ` [PATCH 2/2] nvme: add context annotation for nvme_ns_head::nr_openers Nilay Shroff
2026-09-01  8:14 ` [PATCH 0/2] nvme: add reference counting for transport modules John Garry
2026-09-01  9:47   ` Nilay Shroff
2026-09-01 10:14     ` John Garry

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260831152006.819471-2-nilay@linux.ibm.com \
    --to=nilay@linux.ibm.com \
    --cc=axboe@fb.com \
    --cc=gjoyce@linux.ibm.com \
    --cc=hch@lst.de \
    --cc=john.g.garry@oracle.com \
    --cc=kbusch@kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=sagi@grimberg.me \
    --cc=wenxiong@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox