The recoverable hardware error tracking (hwerr_log_error_type() and the
hwerr_data[] counters) was added under vmcoreinfo, but it uses none of the
vmcoreinfo note machinery: hwerr_data[] is a plain global array that crash
tools read from the vmcore by symbol, like any other global.  Functionally
it is RAS code, fed only by the hardware error paths (x86 MCE, APEI GHES
and PCIe AER).

I wanted to expand it, and Baoquan suggested moving it away from vmcore
info, which makes sense. [1]

Move the implementation to drivers/ras/hwerr_tracking.c and the
declaration (with its no-op stub) to <linux/ras.h>.  Give it a dedicated
CONFIG_RAS_HWERR (bool, under RAS, default y) rather than riding
CONFIG_VMCORE_INFO, so it is a first-class RAS feature that can be turned
off on its own.  The producers now reach hwerr_log_error_type() through
<linux/ras.h>: x86 MCE and APEI GHES already include it, so drop their
<linux/vmcore_info.h> include; PCIe AER switches its include from
<linux/vmcore_info.h> to <linux/ras.h>.

enum hwerr_error_type stays in <uapi/linux/vmcore.h> as it has been part
of the UAPI since the feature shipped; <linux/ras.h> includes it from
there.

hwerr_data[] keeps its name and layout, so existing crash/drgn recipes
keep working.  The config gate moves from CONFIG_VMCORE_INFO to
CONFIG_RAS_HWERR (default y).

Link: https://lore.kernel.org/all/aYvi4Y_HNqk_u1-v@fedora/ [1]
Signed-off-by: Breno Leitao <[email protected]>
---
Once we move it outside of vmcore info, I am planning to add new
features that are in the limbo now, given they don't belong to vmcore
info, such as:

Track fatal hardware errors
        https://lore.kernel.org/all/[email protected]/

Expose hardware error recovery statistics via sysfs
        
https://lore.kernel.org/all/[email protected]/
---
 MAINTAINERS                    |  7 +++++++
 arch/x86/kernel/cpu/mce/core.c |  1 -
 drivers/acpi/apei/ghes.c       |  1 -
 drivers/pci/pcie/aer.c         |  2 +-
 drivers/ras/Kconfig            | 12 ++++++++++++
 drivers/ras/Makefile           |  1 +
 drivers/ras/hwerr_tracking.c   | 35 +++++++++++++++++++++++++++++++++++
 include/linux/ras.h            |  7 +++++++
 include/linux/vmcore_info.h    |  7 -------
 kernel/vmcore_info.c           | 21 ---------------------
 10 files changed, 63 insertions(+), 31 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1705eb823dd00..356a51032e4b0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22539,6 +22539,13 @@ L:     [email protected]
 S:     Maintained
 F:     drivers/ras/amd/fmpm.c
 
+RAS RECOVERABLE HARDWARE ERROR TRACKING
+M:     Breno Leitao <[email protected]>
+L:     [email protected]
+S:     Maintained
+F:     Documentation/driver-api/hw-recoverable-errors.rst
+F:     drivers/ras/hwerr_tracking.c
+
 RASPBERRY PI PISP BACK END
 M:     Jacopo Mondi <[email protected]>
 R:     Raspberry Pi Kernel Maintenance <[email protected]>
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
index 9bba1e2f03af7..58f1d7a601883 100644
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -45,7 +45,6 @@
 #include <linux/task_work.h>
 #include <linux/hardirq.h>
 #include <linux/kexec.h>
-#include <linux/vmcore_info.h>
 
 #include <asm/fred.h>
 #include <asm/cpu_device_id.h>
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 3236a3ce79d6b..4b6666bc19c77 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -45,7 +45,6 @@
 #include <linux/uuid.h>
 #include <linux/ras.h>
 #include <linux/task_work.h>
-#include <linux/vmcore_info.h>
 
 #include <acpi/actbl1.h>
 #include <acpi/ghes.h>
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index c4fd9c0b2a548..00cdca26a5114 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -30,7 +30,7 @@
 #include <linux/kfifo.h>
 #include <linux/ratelimit.h>
 #include <linux/slab.h>
-#include <linux/vmcore_info.h>
+#include <linux/ras.h>
 #include <acpi/apei.h>
 #include <acpi/ghes.h>
 #include <ras/ras_event.h>
diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig
index fc4f4bb94a4c6..241642679c1f1 100644
--- a/drivers/ras/Kconfig
+++ b/drivers/ras/Kconfig
@@ -34,6 +34,18 @@ if RAS
 source "arch/x86/ras/Kconfig"
 source "drivers/ras/amd/atl/Kconfig"
 
+config RAS_HWERR
+       bool "Track hardware errors for crash analysis"
+       default y
+       help
+         Record the count and timestamp of the most recent recoverable
+         hardware error for each source (CPU, memory, PCI, CXL, ...).  The
+         data is written at runtime and read post-mortem from a vmcore by
+         tools such as crash or drgn, to correlate recoverable errors with a
+         later panic.
+
+         If unsure, say Y.
+
 config RAS_FMPM
        tristate "FRU Memory Poison Manager"
        default m
diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile
index 11f95d59d3972..4217bee75d910 100644
--- a/drivers/ras/Makefile
+++ b/drivers/ras/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_RAS)      += ras.o
+obj-$(CONFIG_RAS_HWERR)        += hwerr_tracking.o
 obj-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_RAS_CEC)  += cec.o
 
diff --git a/drivers/ras/hwerr_tracking.c b/drivers/ras/hwerr_tracking.c
new file mode 100644
index 0000000000000..847c01fb24d55
--- /dev/null
+++ b/drivers/ras/hwerr_tracking.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Track recoverable hardware errors (visible to the OS but not fatal) so that
+ * crash tools like crash/drgn can read the count and timestamp of the last
+ * occurrence from a vmcore and correlate them with a subsequent panic.
+ *
+ * Copyright (c) 2026 Meta Platforms, Inc. and affiliates
+ * Copyright (c) 2026 Breno Leitao <[email protected]>
+ */
+
+#include <linux/atomic.h>
+#include <linux/export.h>
+#include <linux/ras.h>
+#include <linux/timekeeping.h>
+
+struct hwerr_info {
+       atomic_t count;
+       time64_t timestamp;
+};
+
+/*
+ * Keep hwerr_data[] at global scope so it stays accessible from the vmcore
+ * (via crash/drgn) even when Link Time Optimization (LTO) is enabled.
+ */
+struct hwerr_info hwerr_data[HWERR_RECOV_MAX];
+
+void hwerr_log_error_type(enum hwerr_error_type src)
+{
+       if (src < 0 || src >= HWERR_RECOV_MAX)
+               return;
+
+       atomic_inc(&hwerr_data[src].count);
+       WRITE_ONCE(hwerr_data[src].timestamp, ktime_get_real_seconds());
+}
+EXPORT_SYMBOL_GPL(hwerr_log_error_type);
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 468941bfe855f..1019183c00342 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -5,6 +5,7 @@
 #include <asm/errno.h>
 #include <linux/uuid.h>
 #include <linux/cper.h>
+#include <uapi/linux/vmcore.h>
 
 #ifdef CONFIG_DEBUG_FS
 int ras_userspace_consumers(void);
@@ -35,6 +36,12 @@ static inline void
 log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { return; }
 #endif
 
+#ifdef CONFIG_RAS_HWERR
+void hwerr_log_error_type(enum hwerr_error_type src);
+#else
+static inline void hwerr_log_error_type(enum hwerr_error_type src) { }
+#endif
+
 struct atl_err {
        u64 addr;
        u64 ipid;
diff --git a/include/linux/vmcore_info.h b/include/linux/vmcore_info.h
index e71518caacdfc..fb6f29b7202e3 100644
--- a/include/linux/vmcore_info.h
+++ b/include/linux/vmcore_info.h
@@ -5,7 +5,6 @@
 #include <linux/linkage.h>
 #include <linux/elfcore.h>
 #include <linux/elf.h>
-#include <uapi/linux/vmcore.h>
 
 #define CRASH_CORE_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4)
 #define CRASH_CORE_NOTE_NAME_BYTES ALIGN(sizeof(NN_PRSTATUS), 4)
@@ -79,10 +78,4 @@ Elf_Word *append_elf_note(Elf_Word *buf, char *name, 
unsigned int type,
                          void *data, size_t data_len);
 void final_note(Elf_Word *buf);
 
-#ifdef CONFIG_VMCORE_INFO
-void hwerr_log_error_type(enum hwerr_error_type src);
-#else
-static inline void hwerr_log_error_type(enum hwerr_error_type src) {};
-#endif
-
 #endif /* LINUX_VMCORE_INFO_H */
diff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c
index 8614430ca212a..5c288796bdbf5 100644
--- a/kernel/vmcore_info.c
+++ b/kernel/vmcore_info.c
@@ -29,17 +29,6 @@ u32 *vmcoreinfo_note;
 /* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
 static unsigned char *vmcoreinfo_data_safecopy;
 
-struct hwerr_info {
-       atomic_t count;
-       time64_t timestamp;
-};
-
-/*
- * The hwerr_data[] array is declared with global scope so that it remains
- * accessible to vmcoreinfo even when Link Time Optimization (LTO) is enabled.
- */
-struct hwerr_info hwerr_data[HWERR_RECOV_MAX];
-
 Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
                          void *data, size_t data_len)
 {
@@ -127,16 +116,6 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 }
 EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
-void hwerr_log_error_type(enum hwerr_error_type src)
-{
-       if (src < 0 || src >= HWERR_RECOV_MAX)
-               return;
-
-       atomic_inc(&hwerr_data[src].count);
-       WRITE_ONCE(hwerr_data[src].timestamp, ktime_get_real_seconds());
-}
-EXPORT_SYMBOL_GPL(hwerr_log_error_type);
-
 static int __init crash_save_vmcoreinfo_init(void)
 {
        int order;

---
base-commit: 3d5670d672ae08b8c534b7beed6f57c8b44e7b43
change-id: 20260629-hwerr-ras-e26664926c58

Best regards,
--  
Breno Leitao <[email protected]>


Reply via email to