[PATCH] nvme-multipath: add iopolicies sysfs attribute

loberman at redhat.com loberman at redhat.com
Sun Sep 20 09:40:00 PDT 2026


From: Laurence Oberman <loberman at redhat.com>

The subsystem iopolicy attribute only shows the active policy, so
there is no way to see which policies are available. The block layer
solves this for I/O schedulers by listing all options with the
active one in brackets in queue/scheduler.

Changing the output of iopolicy the same way would break existing
userspace, since nvme-cli compares the value against a bare policy
name. Leave iopolicy unchanged and add a read-only iopolicies
attribute that gives equivalent visibility:

  # cat iopolicies
  [numa] round-robin queue-depth

Signed-off-by: Laurence Oberman <loberman at redhat.com>
Assisted-by: LLM
---
 drivers/nvme/host/multipath.c | 25 +++++++++++++++++++++++++
 drivers/nvme/host/nvme.h      |  1 +
 drivers/nvme/host/sysfs.c     |  1 +
 3 files changed, 27 insertions(+)

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 75dbb58286a3..7b282ab05dab 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -1085,6 +1085,31 @@ static ssize_t nvme_subsys_iopolicy_store(struct device *dev,
 SUBSYS_ATTR_RW(iopolicy, S_IRUGO | S_IWUSR,
 		      nvme_subsys_iopolicy_show, nvme_subsys_iopolicy_store);
 
+static ssize_t iopolicies_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct nvme_subsystem *subsys =
+		container_of(dev, struct nvme_subsystem, dev);
+	int cur = READ_ONCE(subsys->iopolicy);
+	int i, len = 0;
+
+	/*
+	 * List all available policies with the active one in brackets,
+	 * matching the format of the block layer's "scheduler" attribute.
+	 */
+	for (i = 0; i < ARRAY_SIZE(nvme_iopolicy_names); i++)
+		len += sysfs_emit_at(buf, len, "%s%s%s%s",
+				     i ? " " : "",
+				     i == cur ? "[" : "",
+				     nvme_iopolicy_names[i],
+				     i == cur ? "]" : "");
+
+	len += sysfs_emit_at(buf, len, "\n");
+	return len;
+}
+
+struct device_attribute subsys_attr_iopolicies = __ATTR_RO(iopolicies);
+
 static ssize_t ana_grpid_show(struct device *dev, struct device_attribute *attr,
 		char *buf)
 {
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 75e5d5a8a77c..b419c6fc6081 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -1098,6 +1098,7 @@ extern struct device_attribute dev_attr_multipath_failover_count;
 extern struct device_attribute dev_attr_io_requeue_no_usable_path_count;
 extern struct device_attribute dev_attr_io_fail_no_available_path_count;
 extern struct device_attribute subsys_attr_iopolicy;
+extern struct device_attribute subsys_attr_iopolicies;
 
 static inline bool nvme_disk_is_ns_head(struct gendisk *disk)
 {
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index abf8edaae371..4c4518b6b7d5 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -1298,6 +1298,7 @@ static struct attribute *nvme_subsys_attrs[] = {
 	&subsys_attr_subsystype.attr,
 #ifdef CONFIG_NVME_MULTIPATH
 	&subsys_attr_iopolicy.attr,
+	&subsys_attr_iopolicies.attr,
 #endif
 	NULL,
 };
-- 
2.55.0




More information about the Linux-nvme mailing list