From: Eugen Hristev <eugen.hristev@linaro.org>
To: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, tglx@linutronix.de, andersson@kernel.org,
pmladek@suse.com, rdunlap@infradead.org, corbet@lwn.net,
david@redhat.com, mhocko@suse.com
Cc: tudor.ambarus@linaro.org, mukesh.ojha@oss.qualcomm.com,
linux-arm-kernel@lists.infradead.org,
linux-hardening@vger.kernel.org, jonechou@google.com,
rostedt@goodmis.org, linux-doc@vger.kernel.org,
devicetree@vger.kernel.org,
Eugen Hristev <eugen.hristev@linaro.org>
Subject: [RFC][PATCH v3 01/16] kmemdump: Introduce kmemdump
Date: Fri, 12 Sep 2025 18:08:40 +0300 [thread overview]
Message-ID: <20250912150855.2901211-2-eugen.hristev@linaro.org> (raw)
In-Reply-To: <20250912150855.2901211-1-eugen.hristev@linaro.org>
Kmemdump mechanism allows any driver to mark a specific memory area
for later dumping/debugging purpose, depending on the functionality
of the attached backend.
The backend would interface any hardware mechanism that will allow
dumping to complete regardless of the state of the kernel
(running, frozen, crashed, or any particular state).
Signed-off-by: Eugen Hristev <eugen.hristev@linaro.org>
---
MAINTAINERS | 6 ++
include/linux/kmemdump.h | 63 ++++++++++++
mm/Kconfig.debug | 2 +
mm/Makefile | 1 +
mm/kmemdump/Kconfig.debug | 14 +++
mm/kmemdump/Makefile | 3 +
mm/kmemdump/kmemdump.c | 202 ++++++++++++++++++++++++++++++++++++++
7 files changed, 291 insertions(+)
create mode 100644 include/linux/kmemdump.h
create mode 100644 mm/kmemdump/Kconfig.debug
create mode 100644 mm/kmemdump/Makefile
create mode 100644 mm/kmemdump/kmemdump.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 8cf4990a8ff6..1713cccefc91 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13810,6 +13810,12 @@ L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/accel/kionix-kx022a*
+KMEMDUMP
+M: Eugen Hristev <eugen.hristev@linaro.org>
+S: Maintained
+F: include/linux/kmemdump.h
+F: mm/kmemdump/kmemdump.c
+
KMEMLEAK
M: Catalin Marinas <catalin.marinas@arm.com>
S: Maintained
diff --git a/include/linux/kmemdump.h b/include/linux/kmemdump.h
new file mode 100644
index 000000000000..8e764bb2d8ac
--- /dev/null
+++ b/include/linux/kmemdump.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _KMEMDUMP_H
+#define _KMEMDUMP_H
+
+enum kmemdump_uid {
+ KMEMDUMP_ID_START = 0,
+ KMEMDUMP_ID_USER_START,
+ KMEMDUMP_ID_USER_END,
+ KMEMDUMP_ID_NO_ID,
+};
+
+#ifdef CONFIG_KMEMDUMP
+/**
+ * struct kmemdump_zone - region mark zone information
+ * @id: unique id for this zone
+ * @zone: pointer to the memory area for this zone
+ * @size: size of the memory area of this zone
+ */
+struct kmemdump_zone {
+ enum kmemdump_uid id;
+ void *zone;
+ size_t size;
+};
+
+#define KMEMDUMP_BACKEND_MAX_NAME 128
+/**
+ * struct kmemdump_backend - region mark backend information
+ * @name: the name of the backend
+ * @register_region: callback to register region in the backend
+ * @unregister_region: callback to unregister region in the backend
+ */
+struct kmemdump_backend {
+ char name[KMEMDUMP_BACKEND_MAX_NAME];
+ int (*register_region)(const struct kmemdump_backend *be,
+ enum kmemdump_uid uid, void *vaddr, size_t size);
+ int (*unregister_region)(const struct kmemdump_backend *be,
+ enum kmemdump_uid uid);
+};
+
+int kmemdump_register_backend(const struct kmemdump_backend *backend);
+void kmemdump_unregister_backend(const struct kmemdump_backend *backend);
+
+int kmemdump_register_id(enum kmemdump_uid id, void *zone, size_t size);
+
+#define kmemdump_register(...) \
+ kmemdump_register_id(KMEMDUMP_ID_NO_ID, __VA_ARGS__) \
+
+void kmemdump_unregister(enum kmemdump_uid id);
+#else
+static inline int kmemdump_register_id(enum kmemdump_uid uid, void *area,
+ size_t size)
+{
+ return 0;
+}
+
+#define kmemdump_register(...)
+
+static inline void kmemdump_unregister(enum kmemdump_uid id)
+{
+}
+#endif
+
+#endif
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index 32b65073d0cc..b6aad5cb09c1 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -309,3 +309,5 @@ config PER_VMA_LOCK_STATS
overhead in the page fault path.
If in doubt, say N.
+
+source "mm/kmemdump/Kconfig.debug"
diff --git a/mm/Makefile b/mm/Makefile
index 21abb3353550..ca1691dd8924 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o
obj-$(CONFIG_PAGE_POISONING) += page_poison.o
obj-$(CONFIG_KASAN) += kasan/
+obj-$(CONFIG_KMEMDUMP) += kmemdump/
obj-$(CONFIG_KFENCE) += kfence/
obj-$(CONFIG_KMSAN) += kmsan/
obj-$(CONFIG_FAILSLAB) += failslab.o
diff --git a/mm/kmemdump/Kconfig.debug b/mm/kmemdump/Kconfig.debug
new file mode 100644
index 000000000000..5654180141c0
--- /dev/null
+++ b/mm/kmemdump/Kconfig.debug
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config KMEMDUMP
+ bool "KMEMDUMP: Allow the kernel to register memory regions for dumping purpose"
+ help
+ Kmemdump mechanism allows any driver to mark a specific memory area
+ for later dumping/debugging purpose, depending on the functionality
+ of the attached backend.
+ The backend would interface any hardware mechanism that will allow
+ dumping to complete regardless of the state of the kernel
+ (running, frozen, crashed, or any particular state).
+
+ Note that modules using this feature must be rebuilt if option
+ changes.
diff --git a/mm/kmemdump/Makefile b/mm/kmemdump/Makefile
new file mode 100644
index 000000000000..f5b917a6ef5e
--- /dev/null
+++ b/mm/kmemdump/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += kmemdump.o
diff --git a/mm/kmemdump/kmemdump.c b/mm/kmemdump/kmemdump.c
new file mode 100644
index 000000000000..c016457620a4
--- /dev/null
+++ b/mm/kmemdump/kmemdump.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/kmemdump.h>
+
+#define MAX_ZONES 201
+
+static int default_register_region(const struct kmemdump_backend *be,
+ enum kmemdump_uid id, void *area, size_t sz)
+{
+ return 0;
+}
+
+static int default_unregister_region(const struct kmemdump_backend *be,
+ enum kmemdump_uid id)
+{
+ return 0;
+}
+
+static const struct kmemdump_backend kmemdump_default_backend = {
+ .name = "default",
+ .register_region = default_register_region,
+ .unregister_region = default_unregister_region,
+};
+
+static const struct kmemdump_backend *backend = &kmemdump_default_backend;
+static DEFINE_MUTEX(kmemdump_lock);
+static struct kmemdump_zone kmemdump_zones[MAX_ZONES];
+
+/**
+ * kmemdump_register_id() - Register region into kmemdump with given ID.
+ * @req_id: Requested unique kmemdump_uid that identifies the region
+ * This can be KMEMDUMP_ID_NO_ID, in which case the function will
+ * find an unused ID and return it.
+ * @zone: pointer to the zone of memory
+ * @size: region size
+ *
+ * Return: On success, it returns the unique id for the region.
+ * On failure, it returns negative error value.
+ */
+int kmemdump_register_id(enum kmemdump_uid req_id, void *zone, size_t size)
+{
+ struct kmemdump_zone *z;
+ enum kmemdump_uid uid = req_id;
+ int ret;
+
+ if (uid < KMEMDUMP_ID_START)
+ return -EINVAL;
+
+ if (uid >= MAX_ZONES)
+ return -ENOSPC;
+
+ mutex_lock(&kmemdump_lock);
+
+ if (uid == KMEMDUMP_ID_NO_ID)
+ while (uid < MAX_ZONES) {
+ if (!kmemdump_zones[uid].id)
+ break;
+ uid++;
+ }
+
+ if (uid == MAX_ZONES) {
+ mutex_unlock(&kmemdump_lock);
+ return -ENOSPC;
+ }
+
+ z = &kmemdump_zones[uid];
+
+ if (z->id) {
+ mutex_unlock(&kmemdump_lock);
+ return -EALREADY;
+ }
+
+ ret = backend->register_region(backend, uid, zone, size);
+ if (ret) {
+ mutex_unlock(&kmemdump_lock);
+ return ret;
+ }
+
+ z->zone = zone;
+ z->size = size;
+ z->id = uid;
+
+ mutex_unlock(&kmemdump_lock);
+
+ return uid;
+}
+EXPORT_SYMBOL_GPL(kmemdump_register_id);
+
+/**
+ * kmemdump_unregister() - Unregister region from kmemdump.
+ * @id: unique id that was returned when this region was successfully
+ * registered initially.
+ *
+ * Return: None
+ */
+void kmemdump_unregister(enum kmemdump_uid id)
+{
+ struct kmemdump_zone *z = NULL;
+
+ mutex_lock(&kmemdump_lock);
+
+ z = &kmemdump_zones[id];
+ if (!z->id) {
+ mutex_unlock(&kmemdump_lock);
+ return;
+ }
+
+ backend->unregister_region(backend, z->id);
+
+ memset(z, 0, sizeof(*z));
+
+ mutex_unlock(&kmemdump_lock);
+}
+EXPORT_SYMBOL_GPL(kmemdump_unregister);
+
+/**
+ * kmemdump_register_backend() - Register a backend into kmemdump.
+ * @be: Pointer to a driver allocated backend. This backend must have
+ * two callbacks for registering and deregistering a zone from the
+ * backend.
+ *
+ * Only one backend is supported at a time.
+ *
+ * Return: On success, it returns 0, negative error value otherwise.
+ */
+int kmemdump_register_backend(const struct kmemdump_backend *be)
+{
+ enum kmemdump_uid uid;
+ int ret;
+
+ if (!be || !be->register_region || !be->unregister_region)
+ return -EINVAL;
+
+ mutex_lock(&kmemdump_lock);
+
+ /* Try to call the old backend for all existing regions */
+ for (uid = KMEMDUMP_ID_START; uid < MAX_ZONES; uid++)
+ if (kmemdump_zones[uid].id)
+ backend->unregister_region(backend,
+ kmemdump_zones[uid].id);
+
+ backend = be;
+ pr_debug("kmemdump backend %s registered successfully.\n",
+ backend->name);
+
+ /* Call the new backend for all existing regions */
+ for (uid = KMEMDUMP_ID_START; uid < MAX_ZONES; uid++) {
+ if (!kmemdump_zones[uid].id)
+ continue;
+ ret = backend->register_region(backend,
+ kmemdump_zones[uid].id,
+ kmemdump_zones[uid].zone,
+ kmemdump_zones[uid].size);
+ if (ret)
+ pr_debug("register region failed with %d\n", ret);
+ }
+
+ mutex_unlock(&kmemdump_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kmemdump_register_backend);
+
+/**
+ * kmemdump_unregister_backend() - Unregister the backend from kmemdump.
+ * @be: Pointer to a driver allocated backend. This backend must match
+ * the initially registered backend.
+ *
+ * Only one backend is supported at a time.
+ * Before deregistering, this will call the backend to unregister all the
+ * previously registered zones.
+ *
+ * Return: None
+ */
+void kmemdump_unregister_backend(const struct kmemdump_backend *be)
+{
+ enum kmemdump_uid uid;
+
+ mutex_lock(&kmemdump_lock);
+
+ if (backend != be) {
+ mutex_unlock(&kmemdump_lock);
+ return;
+ }
+
+ /* Try to call the old backend for all existing regions */
+ for (uid = KMEMDUMP_ID_START; uid < MAX_ZONES; uid++)
+ if (kmemdump_zones[uid].id)
+ backend->unregister_region(backend,
+ kmemdump_zones[uid].id);
+
+ pr_debug("kmemdump backend %s removed successfully.\n", be->name);
+
+ backend = &kmemdump_default_backend;
+
+ mutex_unlock(&kmemdump_lock);
+}
+EXPORT_SYMBOL_GPL(kmemdump_unregister_backend);
+
--
2.43.0
next prev parent reply other threads:[~2025-09-12 15:09 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-12 15:08 [RFC][PATCH v3 00/16] " Eugen Hristev
2025-09-12 15:08 ` Eugen Hristev [this message]
2025-09-12 15:08 ` [RFC][PATCH v3 02/16] Documentation: Add kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 03/16] kmemdump: Add coreimage ELF layer Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 04/16] Documentation: kmemdump: Add section for coreimage ELF Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 05/16] kernel/vmcore_info: Register dynamic information into Kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 06/16] kmemdump: Introduce qcom-minidump backend driver Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 07/16] soc: qcom: smem: Add minidump device Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 08/16] init/version: Add banner_len to save banner length Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 09/16] genirq/irqdesc: Have nr_irqs as non-static Eugen Hristev
2025-09-16 21:10 ` Thomas Gleixner
2025-09-16 21:16 ` Thomas Gleixner
2025-09-17 5:43 ` Eugen Hristev
2025-09-17 7:16 ` David Hildenbrand
2025-09-17 14:10 ` Thomas Gleixner
2025-09-17 14:26 ` Eugen Hristev
2025-09-17 14:46 ` David Hildenbrand
2025-09-17 15:02 ` Eugen Hristev
2025-09-17 15:18 ` David Hildenbrand
2025-09-17 15:32 ` Eugen Hristev
2025-09-17 15:44 ` David Hildenbrand
2025-09-17 18:42 ` Thomas Gleixner
2025-09-17 19:03 ` David Hildenbrand
2025-09-18 8:23 ` Thomas Gleixner
2025-09-18 13:53 ` Eugen Hristev
2025-09-18 18:43 ` Randy Dunlap
2025-09-25 20:11 ` David Hildenbrand
2025-09-12 15:08 ` [RFC][PATCH v3 10/16] panic: Have tainted_mask " Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 11/16] mm/swapfile: Have nr_swapfiles " Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 12/16] printk: Register information into Kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 13/16] sched: Add sched_get_runqueues_area Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 14/16] kernel/vmcoreinfo: Register kmemdump core image information Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 15/16] kmemdump: Add Kinfo backend driver Eugen Hristev
2025-09-16 5:48 ` Alexey Klimov
2025-09-22 10:01 ` Tudor Ambarus
2025-09-12 15:08 ` [RFC][PATCH v3 16/16] dt-bindings: Add Google Kinfo Eugen Hristev
2025-09-14 11:56 ` Krzysztof Kozlowski
2025-09-12 15:56 ` [RFC][PATCH v3 00/16] Introduce kmemdump David Hildenbrand
2025-09-12 18:35 ` Eugen Hristev
2025-09-16 7:49 ` Mukesh Ojha
2025-09-16 15:25 ` Luck, Tony
2025-09-16 15:27 ` Eugen Hristev
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=20250912150855.2901211-2-eugen.hristev@linaro.org \
--to=eugen.hristev@linaro.org \
--cc=andersson@kernel.org \
--cc=corbet@lwn.net \
--cc=david@redhat.com \
--cc=devicetree@vger.kernel.org \
--cc=jonechou@google.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=mukesh.ojha@oss.qualcomm.com \
--cc=pmladek@suse.com \
--cc=rdunlap@infradead.org \
--cc=rostedt@goodmis.org \
--cc=tglx@linutronix.de \
--cc=tudor.ambarus@linaro.org \
/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