From: Nilay Shroff <nilay@linux.ibm.com>
To: linux-nvme@lists.infradead.org
Cc: kbusch@kernel.org, axboe@kernel.dk, hch@lst.de, sagi@grimberg.me,
hare@suse.de, dwagner@suse.de, wenxiong@linux.ibm.com,
gjoyce@ibm.com, Nilay Shroff <nilay@linux.ibm.com>
Subject: [PATCHv2 3/7] nvme: export command error counters via sysfs
Date: Thu, 5 Feb 2026 18:18:02 +0530 [thread overview]
Message-ID: <20260205124810.682559-4-nilay@linux.ibm.com> (raw)
In-Reply-To: <20260205124810.682559-1-nilay@linux.ibm.com>
When an NVMe command completes with an error status, the driver
logs the error to the kernel log. However, these messages may be
lost or overwritten over time since dmesg is a circular buffer.
Expose per-path and ctrl command error counters through sysfs to
provide persistent visibility into error occurrences. This allows
users to observe the total number of commands that have failed on
a given path over time, which can be useful for diagnosing path
health and stability.
These counters can also be consumed by observability tools such as
nvme-top to provide additional insight into NVMe error behavior.
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
---
drivers/nvme/host/core.c | 10 +++++++++-
drivers/nvme/host/nvme.h | 2 ++
drivers/nvme/host/sysfs.c | 29 +++++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index d2c430ec0077..11eb28117501 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -438,11 +438,19 @@ static inline void nvme_end_req_zoned(struct request *req)
static inline void __nvme_end_req(struct request *req)
{
- if (unlikely(nvme_req(req)->status && !(req->rq_flags & RQF_QUIET))) {
+ struct nvme_ns *ns = req->q->queuedata;
+ struct nvme_request *nr = nvme_req(req);
+
+ if (unlikely(nr->status && !(req->rq_flags & RQF_QUIET))) {
if (blk_rq_is_passthrough(req))
nvme_log_err_passthru(req);
else
nvme_log_error(req);
+
+ if (ns)
+ ns->errors = size_add(ns->errors, 1);
+ else
+ nr->ctrl->errors = size_add(nr->ctrl->errors, 1);
}
nvme_end_req_zoned(req);
nvme_trace_bio_complete(req);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 6307243fd216..83b102a0ad89 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -359,6 +359,7 @@ struct nvme_ctrl {
unsigned long ka_last_check_time;
struct work_struct fw_act_work;
unsigned long events;
+ size_t errors;
#ifdef CONFIG_NVME_MULTIPATH
/* asymmetric namespace access: */
u8 anacap;
@@ -536,6 +537,7 @@ struct nvme_ns {
size_t failover;
#endif
size_t retries;
+ size_t errors;
struct list_head siblings;
struct kref kref;
struct nvme_ns_head *head;
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index 34dcb6db9b5c..4690ef9a1948 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -6,6 +6,7 @@
*/
#include <linux/nvme-auth.h>
+#include <linux/blkdev.h>
#include "nvme.h"
#include "fabrics.h"
@@ -255,6 +256,16 @@ static ssize_t command_retries_show(struct device *dev,
}
static DEVICE_ATTR_RO(command_retries);
+static ssize_t nvme_io_errors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ return sysfs_emit(buf, "%lu\n", ns->errors);
+}
+struct device_attribute dev_attr_io_errors =
+ __ATTR(command_error_count, 0444, nvme_io_errors_show, NULL);
+
static struct attribute *nvme_ns_attrs[] = {
&dev_attr_wwid.attr,
&dev_attr_uuid.attr,
@@ -274,6 +285,7 @@ static struct attribute *nvme_ns_attrs[] = {
#endif
&dev_attr_io_passthru_err_log_enabled.attr,
&dev_attr_command_retries.attr,
+ &dev_attr_io_errors.attr,
NULL,
};
@@ -300,6 +312,12 @@ static umode_t nvme_ns_attrs_are_visible(struct kobject *kobj,
if (nvme_disk_is_ns_head(dev_to_disk(dev)))
return 0;
}
+ if (a == &dev_attr_io_errors.attr) {
+ struct gendisk *disk = dev_to_disk(dev);
+
+ if (nvme_disk_is_ns_head(disk))
+ return 0;
+ }
#ifdef CONFIG_NVME_MULTIPATH
if (a == &dev_attr_ana_grpid.attr || a == &dev_attr_ana_state.attr) {
/* per-path attr */
@@ -620,6 +638,16 @@ static ssize_t dctype_show(struct device *dev,
}
static DEVICE_ATTR_RO(dctype);
+static ssize_t nvme_adm_errors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", ctrl->errors);
+}
+struct device_attribute dev_attr_adm_errors =
+ __ATTR(command_error_count, 0444, nvme_adm_errors_show, NULL);
+
#ifdef CONFIG_NVME_HOST_AUTH
static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -766,6 +794,7 @@ static struct attribute *nvme_dev_attrs[] = {
&dev_attr_dhchap_ctrl_secret.attr,
#endif
&dev_attr_adm_passthru_err_log_enabled.attr,
+ &dev_attr_adm_errors.attr,
NULL
};
--
2.52.0
next prev parent reply other threads:[~2026-02-05 12:49 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-05 12:47 [PATCHv2 0/7] nvme: export additional diagnostic counters via sysfs Nilay Shroff
2026-02-05 12:48 ` [PATCHv2 1/7] nvme: export command retry count " Nilay Shroff
2026-02-07 13:28 ` Sagi Grimberg
2026-02-09 11:48 ` Nilay Shroff
2026-02-05 12:48 ` [PATCHv2 2/7] nvme: export multipath failover " Nilay Shroff
2026-02-07 13:30 ` Sagi Grimberg
2026-02-05 12:48 ` Nilay Shroff [this message]
2026-02-05 12:48 ` [PATCHv2 4/7] nvme: export I/O requeue count when no path is available " Nilay Shroff
2026-02-07 13:33 ` Sagi Grimberg
2026-02-09 11:53 ` Nilay Shroff
2026-02-05 12:48 ` [PATCHv2 5/7] nvme: export I/O failure " Nilay Shroff
2026-02-05 12:48 ` [PATCHv2 6/7] nvme: export controller reset event count " Nilay Shroff
2026-02-05 12:48 ` [PATCHv2 7/7] nvme: export controller reconnect " Nilay Shroff
2026-02-07 13:37 ` Sagi Grimberg
2026-02-09 12:00 ` Nilay Shroff
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=20260205124810.682559-4-nilay@linux.ibm.com \
--to=nilay@linux.ibm.com \
--cc=axboe@kernel.dk \
--cc=dwagner@suse.de \
--cc=gjoyce@ibm.com \
--cc=hare@suse.de \
--cc=hch@lst.de \
--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