[RFC PATCHv3 4/6] nvme: add sysfs attribute adp_weight_timeout

Nilay Shroff nilay at linux.ibm.com
Mon Oct 27 02:29:38 PDT 2025


By default, the adaptive I/O policy accumulates latency samples over a
15-second window. When this window expires, the driver computes the
average latency and updates the smoothed (EWMA) latency value. The
path weight is then recalculated based on this data.

A 15-second window provides a good balance for most workloads, as it
helps smooth out transient latency spikes and produces a more stable
path weight profile. However, some workloads may benefit from faster
or slower adaptation to changing latency conditions.

This commit introduces a new sysfs attribute, adp_weight_timeout,
which allows users to configure the path weight calculation interval
based on their workload requirements.

Signed-off-by: Nilay Shroff <nilay at linux.ibm.com>
---
 drivers/nvme/host/core.c      |  6 ++++++
 drivers/nvme/host/multipath.c | 38 +++++++++++++++++++++++++++++++++--
 drivers/nvme/host/nvme.h      |  4 +++-
 drivers/nvme/host/sysfs.c     |  1 +
 4 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ab09b9724674..f48c6bc25055 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3248,6 +3248,12 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
 	 * used while adding latency sample for adaptive iopolicy.
 	 */
 	subsys->adp_ewma_shift = NVME_DEFAULT_ADP_EWMA_SHIFT;
+	/*
+	 * Path weight calculation timeout interval used for adaptive iopolicy.
+	 * The default value of this paremeter is set to 15 seconds. However, it
+	 * could be also changed through sysfs.
+	 */
+	subsys->adp_weight_timeout = NVME_DEFAULT_ADP_WEIGHT_TIMEOUT;
 #endif
 	subsys->dev.class = &nvme_subsys_class;
 	subsys->dev.release = nvme_release_subsystem;
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 95407c0f2f4b..d4df01511ee9 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -362,8 +362,11 @@ static void nvme_mpath_add_sample(struct request *rq, struct nvme_ns *ns)
 	stat->batch_count++;
 	stat->nr_samples++;
 
-	if (now > stat->last_weight_ts &&
-	    (now - stat->last_weight_ts) >= NVME_DEFAULT_ADP_WEIGHT_TIMEOUT) {
+	if (now > stat->last_weight_ts) {
+		u64 timeout = READ_ONCE(head->subsys->adp_weight_timeout);
+
+		if ((now - stat->last_weight_ts) < timeout)
+			return;
 
 		stat->last_weight_ts = now;
 
@@ -1495,6 +1498,37 @@ static ssize_t nvme_subsys_adp_ewma_shift_store(struct device *dev,
 SUBSYS_ATTR_RW(adp_ewma_shift, 0644, nvme_subsys_adp_ewma_shift_show,
 		nvme_subsys_adp_ewma_shift_store);
 
+static ssize_t nvme_subsys_adp_weight_timeout_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct nvme_subsystem *subsys =
+		container_of(dev, struct nvme_subsystem, dev);
+
+	return sysfs_emit(buf, "%llu\n",
+		div_u64(READ_ONCE(subsys->adp_weight_timeout), NSEC_PER_SEC));
+}
+
+static ssize_t nvme_subsys_adp_weight_timeout_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int timeout, err;
+	struct nvme_subsystem *subsys =
+		container_of(dev, struct nvme_subsystem, dev);
+
+	err = kstrtoint(buf, 0, &timeout);
+	if (err)
+		return -EINVAL;
+
+	if (timeout <= 0)
+		return -EINVAL;
+
+	WRITE_ONCE(subsys->adp_weight_timeout, timeout * NSEC_PER_SEC);
+	return count;
+}
+
+SUBSYS_ATTR_RW(adp_weight_timeout, 0644, nvme_subsys_adp_weight_timeout_show,
+		nvme_subsys_adp_weight_timeout_store);
+
 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 9f5b233c747a..2e58d4d6902a 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -450,7 +450,8 @@ struct nvme_subsystem {
 	struct ida		ns_ida;
 #ifdef CONFIG_NVME_MULTIPATH
 	enum nvme_iopolicy	iopolicy;
-	int			adp_ewma_shift; /* used for adaptive iopolicy */
+	int			adp_ewma_shift;     /* used for adaptive iopolicy */
+	u64			adp_weight_timeout; /* used for adaptive iopolicy */
 #endif
 };
 
@@ -1045,6 +1046,7 @@ extern struct device_attribute dev_attr_numa_nodes;
 extern struct device_attribute dev_attr_delayed_removal_secs;
 extern struct device_attribute subsys_attr_iopolicy;
 extern struct device_attribute subsys_attr_adp_ewma_shift;
+extern struct device_attribute subsys_attr_adp_weight_timeout;
 
 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 cf9711961b00..18d7eddd477a 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -918,6 +918,7 @@ static struct attribute *nvme_subsys_attrs[] = {
 #ifdef CONFIG_NVME_MULTIPATH
 	&subsys_attr_iopolicy.attr,
 	&subsys_attr_adp_ewma_shift.attr,
+	&subsys_attr_adp_weight_timeout.attr,
 #endif
 	NULL,
 };
-- 
2.51.0




More information about the Linux-nvme mailing list