[PATCH v3 12/12] kexec: Expose the crash memaction bitmap in debugfs
From: Jan Sebastian Götte
Date: Mon Sep 28 2026 - 13:34:23 EST
Add two files under /sys/kernel/debug/crash_memaction/. "regions" lists
the physical ranges the bits describe and their offset and length in the
bitmap. "bitmap" shows the raw bits as a single blob with all ranges
concatenated. The files are root only and behind
CONFIG_CRASH_MEMACTION_DEBUGFS.
Signed-off-by: Jan Sebastian Götte <linux@xxxxxxxx>
Assisted-by: Claude Opus 5 <noreply@xxxxxxxxxxxxx>
---
Documentation/mm/crash_memaction.rst | 9 ++++++
kernel/Kconfig.kexec | 14 +++++++++
kernel/crash_core.c | 59 ++++++++++++++++++++++++++++++++++++
3 files changed, 82 insertions(+)
diff --git a/Documentation/mm/crash_memaction.rst b/Documentation/mm/crash_memaction.rst
index 3658bff7693c..eacda046477e 100644
--- a/Documentation/mm/crash_memaction.rst
+++ b/Documentation/mm/crash_memaction.rst
@@ -57,3 +57,12 @@ Limitations
trying to mark smaller objects, use lib/secret_pool or a similar mechanism.
* Memory hotplug is not supported at this time. When memory is hotplugged, the
newly hotplugged memory will not be included in the bitmap.
+
+Inspecting the bitmap
+=====================
+
+With ``CONFIG_CRASH_MEMACTION_DEBUGFS`` the bitmap can be read through debugfs::
+
+ # types 0x3000 page_shift 12 nr_regions 1
+ # start_pfn nr_pages offset bytes paddr
+ 0x0000000000000001 0x0000000000800000 0x0 0x100000 0x0000000040000000
diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
index 3cdc8d459ac0..b5380e16bfaf 100644
--- a/kernel/Kconfig.kexec
+++ b/kernel/Kconfig.kexec
@@ -204,4 +204,18 @@ config CRASH_MEMACTION
If unsure, say N.
+config CRASH_MEMACTION_DEBUGFS
+ bool "Expose the crash memaction bitmap in debugfs"
+ depends on CRASH_MEMACTION && DEBUG_FS
+ help
+ Allow reading the live crash_memaction bitmap through
+ /sys/kernel/debug/crash_memaction/. The bitmap is used when
+ CRASH_MEMACTION is set and when a crash_memaction cmdline param is present
+ to tell an eventual kdump kernel about the use of certain memory pages.
+
+ Note that this is a debug interface only that gives no guarantees
+ whatsoever on memory consistency.
+
+ If unsure, say N.
+
endmenu
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 6bb2f5645ca6..5eb5a5ada8e0 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -28,9 +28,11 @@
#include <linux/atomic.h>
#include <linux/bitmap.h>
#include <linux/bitops.h>
+#include <linux/debugfs.h>
#include <linux/jump_label.h>
#include <linux/overflow.h>
#include <linux/pfn.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/sysfs.h>
@@ -66,6 +68,10 @@ static struct crash_memaction_region *crash_memaction_regions __ro_after_init;
static unsigned int crash_memaction_nr_regions __ro_after_init;
static size_t crash_memaction_note_bytes __ro_after_init;
+/* The one allocation all of the bitmaps above were carved out of. */
+static void *crash_ma_bitmap_base __ro_after_init;
+static size_t crash_ma_bitmap_size __ro_after_init;
+
static struct crash_memaction_note *crash_memaction_desc __ro_after_init;
static size_t crash_memaction_desc_bytes __ro_after_init;
@@ -148,6 +154,8 @@ void __init crash_memaction_init(void)
if (!bits)
goto nomem;
+ crash_ma_bitmap_base = bits;
+ crash_ma_bitmap_size = total_bytes;
for (i = 0; i < nr; i++) {
regions[i].bits = bits;
bits += bitmap_size(regions[i].nr_pages);
@@ -341,6 +349,57 @@ void crash_memaction_unmark(void *addr, size_t size)
}
EXPORT_SYMBOL_GPL(crash_memaction_unmark);
+#ifdef CONFIG_CRASH_MEMACTION_DEBUGFS
+
+static struct debugfs_blob_wrapper crash_ma_bitmap_blob;
+
+/* @paddr is what the note gives, so a vmcore can be matched to a live one. */
+static int crash_memaction_regions_show(struct seq_file *m, void *v)
+{
+ unsigned long offset = 0;
+ unsigned int i;
+
+ seq_printf(m, "# types 0x%x page_shift %u nr_regions %u\n",
+ crash_memaction_type_mask, PAGE_SHIFT,
+ crash_memaction_nr_regions);
+ seq_puts(m, "# start_pfn nr_pages offset bytes paddr\n");
+
+ for (i = 0; i < crash_memaction_nr_regions; i++) {
+ struct crash_memaction_region *reg = &crash_memaction_regions[i];
+ size_t bytes = bitmap_size(reg->nr_pages);
+ phys_addr_t paddr = __pa(reg->bits);
+
+ seq_printf(m, "0x%016lx 0x%016lx 0x%016lx 0x%016zx %pa\n",
+ reg->start_pfn, reg->nr_pages, offset, bytes, &paddr);
+ offset += bytes;
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(crash_memaction_regions);
+
+static int __init crash_memaction_debugfs_init(void)
+{
+ struct dentry *dir;
+
+ if (!crash_memaction_nr_regions)
+ return 0;
+
+ dir = debugfs_create_dir("crash_memaction", NULL);
+
+ debugfs_create_file("regions", 0400, dir, NULL,
+ &crash_memaction_regions_fops);
+
+ crash_ma_bitmap_blob.data = crash_ma_bitmap_base;
+ crash_ma_bitmap_blob.size = crash_ma_bitmap_size;
+ debugfs_create_blob("bitmap", 0400, dir, &crash_ma_bitmap_blob);
+
+ return 0;
+}
+fs_initcall(crash_memaction_debugfs_init);
+
+#endif /* CONFIG_CRASH_MEMACTION_DEBUGFS */
+
int crash_load_memaction(struct kimage *image)
{
unsigned long nr_pages, i;
--
2.55.0