summaryrefslogtreecommitdiff
path: root/drivers/nvme
diff options
context:
space:
mode:
authorNilay Shroff <nilay@linux.ibm.com>2026-05-17 00:06:52 +0530
committerKeith Busch <kbusch@kernel.org>2026-06-04 01:57:28 -0700
commit76b5e1591e8cfa986971d177b5de27ce20ca056a (patch)
tree15e4c0bb7dac0eb2b920688cf64d09be55787fcf /drivers/nvme
parent30ab37a128000600dcaae2b35d4a594e304dfe7e (diff)
nvme: export I/O requeue count when no path is usable via sysfs
When the NVMe namespace head determines that there is no currently available path to handle I/O (for example, while a controller is resetting/connecting or due to a transient link failure), incoming I/Os are added to the requeue list. Currently, there is no visibility into how many I/Os have been requeued in this situation. Add a new ns-head sysfs counter io_requeue_no_usable_path_count, under diag attribute group to expose the number of I/Os that were requeued due to the absence of an available path. This counter is also writable thus allowing user to reset it, if needed. This statistic can help users understand I/O slowdowns or stalls caused by temporary path unavailability, and can be consumed by monitoring tools such as nvme-top for real-time observability. Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com> Signed-off-by: Nilay Shroff <nilay@linux.ibm.com> Signed-off-by: Keith Busch <kbusch@kernel.org>
Diffstat (limited to 'drivers/nvme')
-rw-r--r--drivers/nvme/host/multipath.c30
-rw-r--r--drivers/nvme/host/nvme.h2
-rw-r--r--drivers/nvme/host/sysfs.c5
3 files changed, 37 insertions, 0 deletions
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 51c8d928fc80..9021fd44f193 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -538,6 +538,7 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
spin_lock_irq(&head->requeue_lock);
bio_list_add(&head->requeue_list, bio);
spin_unlock_irq(&head->requeue_lock);
+ atomic_long_inc(&head->io_requeue_no_usable_path_count);
} else {
dev_warn_ratelimited(dev, "no available path - failing I/O\n");
@@ -1192,6 +1193,35 @@ static ssize_t multipath_failover_count_store(struct device *dev,
DEVICE_ATTR_RW(multipath_failover_count);
+static ssize_t io_requeue_no_usable_path_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns_head *head = disk->private_data;
+
+ return sysfs_emit(buf, "%lu\n",
+ atomic_long_read(&head->io_requeue_no_usable_path_count));
+}
+
+static ssize_t io_requeue_no_usable_path_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int err;
+ unsigned long requeue_cnt;
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns_head *head = disk->private_data;
+
+ err = kstrtoul(buf, 0, &requeue_cnt);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&head->io_requeue_no_usable_path_count, requeue_cnt);
+
+ return count;
+}
+
+DEVICE_ATTR_RW(io_requeue_no_usable_path_count);
+
static int nvme_lookup_ana_group_desc(struct nvme_ctrl *ctrl,
struct nvme_ana_group_desc *desc, void *data)
{
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index f2734f03682f..bfd427184d69 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -566,6 +566,7 @@ struct nvme_ns_head {
unsigned long flags;
struct delayed_work remove_work;
unsigned int delayed_removal_secs;
+ atomic_long_t io_requeue_no_usable_path_count;
#define NVME_NSHEAD_DISK_LIVE 0
#define NVME_NSHEAD_QUEUE_IF_NO_PATH 1
struct nvme_ns __rcu *current_path[];
@@ -1069,6 +1070,7 @@ extern struct device_attribute dev_attr_queue_depth;
extern struct device_attribute dev_attr_numa_nodes;
extern struct device_attribute dev_attr_delayed_removal_secs;
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 subsys_attr_iopolicy;
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 a03a22c832d8..7f0575b7cdd0 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -403,6 +403,7 @@ static struct attribute *nvme_ns_diag_attrs[] = {
&dev_attr_io_errors.attr,
#ifdef CONFIG_NVME_MULTIPATH
&dev_attr_multipath_failover_count.attr,
+ &dev_attr_io_requeue_no_usable_path_count.attr,
#endif
NULL,
};
@@ -427,6 +428,10 @@ static umode_t nvme_ns_diag_attrs_are_visible(struct kobject *kobj,
if (nvme_disk_is_ns_head(dev_to_disk(dev)))
return 0;
}
+ if (a == &dev_attr_io_requeue_no_usable_path_count.attr) {
+ if (!nvme_disk_is_ns_head(dev_to_disk(dev)))
+ return 0;
+ }
#endif
return a->mode;
}