* [PATCH v2 0/2] kexec: history: track previous kernel version and kexec boot count
@ 2026-01-02 14:53 Breno Leitao
2026-01-02 14:53 ` [PATCH v2 1/2] kexec: history: track previous kernel version Breno Leitao
2026-01-02 14:53 ` [PATCH v2 2/2] kexec: history: track kexec boot counter Breno Leitao
0 siblings, 2 replies; 11+ messages in thread
From: Breno Leitao @ 2026-01-02 14:53 UTC (permalink / raw)
To: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav
Cc: linux-kernel, kexec, linux-mm, usamaarif642, rmikey, clm, riel,
Breno Leitao, kernel-team
Use Kexec Handover (KHO) to pass the previous kernel's version string
and the number of kexec reboots since the last cold boot to the next
kernel, and print it at boot time.
Example
=======
[ 0.000000] Linux version 6.19.0-rc3-upstream-00047-ge5d992347849
...
[ 0.000000] KHO: This kernel was kexec'ed from kernel release: 6.19.0-rc3-upstream-00048-geda7d9110f99 (kexec count: 3)
Motivation
==========
Bugs that only reproduce when kexecing from specific kernel versions
are difficult to diagnose. These issues occur when a buggy kernel
kexecs into a new kernel, with the bug manifesting only in the second
kernel.
Recent examples include:
* eb2266312507 ("x86/boot: Fix page table access in 5-level to 4-level
paging transition")
* 77d48d39e991 ("efistub/tpm: Use ACPI reclaim memory for event log to
avoid corruption")
* 64b45dd46e15 ("x86/efi: skip memattr table on kexec boot")
As kexec-based reboots become more common, these version-dependent bugs
are appearing more frequently. At scale, correlating crashes to the
previous kernel version is challenging, especially when issues only
occur in specific transition scenarios.
Some bugs manifest only after multiple consecutive kexec reboots.
Tracking the kexec count helps identify these cases (this metric is
already used by live update sub-system).
KHO provides a reliable mechanism to pass information between kernels.
By carrying the previous kernel's release string and kexec count
forward, we can print this context at boot time to aid debugging.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Changes from v1 to RFC
- Track the number of kexecs since cold boot (Pasha)
- Change the printk() order compared to KHO
- Rewording of the commit summary
- Link to RFC: https://patch.msgid.link/20251230-kho-v1-1-4d795a24da9e@debian.org
---
Breno Leitao (2):
kexec: history: track previous kernel version
kexec: history: track kexec boot counter
kernel/Kconfig.kexec | 13 ++++++++++
kernel/liveupdate/kexec_handover.c | 50 ++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
---
base-commit: 7620f9ccfabbdaf07620381264d8b8d91412542f
change-id: 20251230-kho-7707e8a2ef1e
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 1/2] kexec: history: track previous kernel version
2026-01-02 14:53 [PATCH v2 0/2] kexec: history: track previous kernel version and kexec boot count Breno Leitao
@ 2026-01-02 14:53 ` Breno Leitao
2026-01-02 15:02 ` Usama Arif
2026-01-02 16:18 ` Pasha Tatashin
2026-01-02 14:53 ` [PATCH v2 2/2] kexec: history: track kexec boot counter Breno Leitao
1 sibling, 2 replies; 11+ messages in thread
From: Breno Leitao @ 2026-01-02 14:53 UTC (permalink / raw)
To: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav
Cc: linux-kernel, kexec, linux-mm, usamaarif642, rmikey, clm, riel,
Breno Leitao, kernel-team
Add CONFIG_KEXEC_HISTORY to store and display the kernel version from
the previous kexec boot.
When enabled, the current kernel's release string is saved to the
"previous-release" property in the KHO device tree before kexec. On
the next boot, if this property exists, the previous kernel version
is retrieved and printed during early boot.
This helps diagnose bugs that only manifest when kexecing from
specific kernel versions, making it easier to correlate crashes with
the kernel that initiated the kexec.
Disabled by default to avoid overhead for users who don't need this
information.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
kernel/Kconfig.kexec | 13 +++++++++++++
kernel/liveupdate/kexec_handover.c | 29 +++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
index 15632358bcf7..b770c68a3800 100644
--- a/kernel/Kconfig.kexec
+++ b/kernel/Kconfig.kexec
@@ -94,6 +94,19 @@ config KEXEC_JUMP
Jump between original kernel and kexeced kernel and invoke
code in physical address mode via KEXEC
+config KEXEC_HISTORY
+ bool "Track kexec kernel history"
+ depends on KEXEC_HANDOVER
+ help
+ When enabled, the kernel will store its release version in the
+ KHO FDT before kexec, and the newly booted kernel will read and
+ print this information during early boot.
+
+ This is useful for debugging and auditing to know which kernel
+ version performed the kexec that booted the current kernel.
+
+ If unsure, say N.
+
config CRASH_DUMP
bool "kernel crash dumps"
default ARCH_DEFAULT_CRASH_DUMP
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 73da00aeaa99..06d99627bb3c 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -21,6 +21,7 @@
#include <linux/page-isolation.h>
#include <linux/unaligned.h>
#include <linux/vmalloc.h>
+#include <linux/utsname.h>
#include <asm/early_ioremap.h>
@@ -36,6 +37,7 @@
#define KHO_FDT_COMPATIBLE "kho-v1"
#define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
#define PROP_SUB_FDT "fdt"
+#define PROP_PREVIOUS_RELEASE "previous-release"
#define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
@@ -1253,6 +1255,9 @@ bool kho_finalized(void)
struct kho_in {
phys_addr_t fdt_phys;
phys_addr_t scratch_phys;
+#ifdef CONFIG_KEXEC_HISTORY
+ char previous_release[__NEW_UTS_LEN + 1];
+#endif
struct kho_debugfs dbg;
};
@@ -1332,6 +1337,10 @@ static __init int kho_out_fdt_setup(void)
err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE);
err |= fdt_property(root, PROP_PRESERVED_MEMORY_MAP, &empty_mem_map,
sizeof(empty_mem_map));
+#ifdef CONFIG_KEXEC_HISTORY
+ err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
+ init_uts_ns.name.release);
+#endif
err |= fdt_end_node(root);
err |= fdt_finish(root);
@@ -1455,6 +1464,25 @@ void __init kho_memory_init(void)
}
}
+#ifdef CONFIG_KEXEC_HISTORY
+static void __init kho_print_previous_kernel(const void *fdt)
+{
+ const char *prev_release;
+ int len;
+
+ prev_release = fdt_getprop(fdt, 0, PROP_PREVIOUS_RELEASE, &len);
+ if (!prev_release || len <= 0)
+ return;
+
+ strscpy(kho_in.previous_release, prev_release,
+ sizeof(kho_in.previous_release));
+ pr_info("This kernel was kexec'ed from kernel release: %s\n",
+ kho_in.previous_release);
+}
+#else
+static void __init kho_print_previous_kernel(const void *fdt) { }
+#endif
+
void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
phys_addr_t scratch_phys, u64 scratch_len)
{
@@ -1527,6 +1555,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
kho_in.scratch_phys = scratch_phys;
kho_scratch_cnt = scratch_cnt;
pr_info("found kexec handover data.\n");
+ kho_print_previous_kernel(fdt);
out:
if (fdt)
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 2/2] kexec: history: track kexec boot counter
2026-01-02 14:53 [PATCH v2 0/2] kexec: history: track previous kernel version and kexec boot count Breno Leitao
2026-01-02 14:53 ` [PATCH v2 1/2] kexec: history: track previous kernel version Breno Leitao
@ 2026-01-02 14:53 ` Breno Leitao
2026-01-02 15:09 ` Usama Arif
2026-01-02 16:20 ` Pasha Tatashin
1 sibling, 2 replies; 11+ messages in thread
From: Breno Leitao @ 2026-01-02 14:53 UTC (permalink / raw)
To: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav
Cc: linux-kernel, kexec, linux-mm, usamaarif642, rmikey, clm, riel,
Breno Leitao, kernel-team
Track and display the number of kexec boots since the last cold reboot
when CONFIG_KEXEC_HISTORY is enabled.
This extends the previous kernel release tracking feature by adding
a counter that increments with each kexec boot. The counter provides
visibility into the kexec chain depth, which is useful for understanding
boot history in production environments.
Add a new property, "kexec-count" in KHO FDT alongside the existing
"previous-release" property. The counter is:
- Initialized to 0 when kho_in is instantiated.
- Incremented by 1 on each subsequent kexec.
- Printed alongside the previous kernel release version.
The counter is stored as a 32-bit unsigned integer in FDT format and is
only active when CONFIG_KEXEC_HISTORY is enabled.
Signed-off-by: Breno Leitao <leitao@debian.org>
Suggested-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
kernel/liveupdate/kexec_handover.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 06d99627bb3c..fe5a2c5c4c86 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -38,6 +38,7 @@
#define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
#define PROP_SUB_FDT "fdt"
#define PROP_PREVIOUS_RELEASE "previous-release"
+#define PROP_KEXEC_COUNT "kexec-count"
#define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
@@ -1257,6 +1258,7 @@ struct kho_in {
phys_addr_t scratch_phys;
#ifdef CONFIG_KEXEC_HISTORY
char previous_release[__NEW_UTS_LEN + 1];
+ u32 kexec_count;
#endif
struct kho_debugfs dbg;
};
@@ -1330,6 +1332,9 @@ static __init int kho_out_fdt_setup(void)
void *root = kho_out.fdt;
u64 empty_mem_map = 0;
int err;
+#ifdef CONFIG_KEXEC_HISTORY
+ u32 kexec_count;
+#endif
err = fdt_create(root, PAGE_SIZE);
err |= fdt_finish_reservemap(root);
@@ -1340,6 +1345,10 @@ static __init int kho_out_fdt_setup(void)
#ifdef CONFIG_KEXEC_HISTORY
err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
init_uts_ns.name.release);
+ /* kho_in.kexec_count is set to 0 on cold boot */
+ kexec_count = cpu_to_fdt32(kho_in.kexec_count + 1);
+ err |= fdt_property(root, PROP_KEXEC_COUNT, &kexec_count,
+ sizeof(kexec_count));
#endif
err |= fdt_end_node(root);
err |= fdt_finish(root);
@@ -1468,6 +1477,7 @@ void __init kho_memory_init(void)
static void __init kho_print_previous_kernel(const void *fdt)
{
const char *prev_release;
+ const u32 *count_ptr;
int len;
prev_release = fdt_getprop(fdt, 0, PROP_PREVIOUS_RELEASE, &len);
@@ -1476,8 +1486,19 @@ static void __init kho_print_previous_kernel(const void *fdt)
strscpy(kho_in.previous_release, prev_release,
sizeof(kho_in.previous_release));
- pr_info("This kernel was kexec'ed from kernel release: %s\n",
- kho_in.previous_release);
+
+ /* Read the kexec count from the previous kernel */
+ count_ptr = fdt_getprop(fdt, 0, PROP_KEXEC_COUNT, &len);
+ if (WARN_ON_ONCE(!count_ptr || len <= 0))
+ /*
+ * PROP_KEXEC_COUNT should exist if PROP_PREVIOUS_RELEASE
+ * exists.
+ */
+ return;
+ kho_in.kexec_count = fdt32_to_cpu(*count_ptr);
+
+ pr_info("This kernel was kexec'ed from kernel release: %s (kexec count: %u)\n",
+ kho_in.previous_release, kho_in.kexec_count);
}
#else
static void __init kho_print_previous_kernel(const void *fdt) { }
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/2] kexec: history: track previous kernel version
2026-01-02 14:53 ` [PATCH v2 1/2] kexec: history: track previous kernel version Breno Leitao
@ 2026-01-02 15:02 ` Usama Arif
2026-01-02 15:14 ` Breno Leitao
2026-01-02 16:18 ` Pasha Tatashin
1 sibling, 1 reply; 11+ messages in thread
From: Usama Arif @ 2026-01-02 15:02 UTC (permalink / raw)
To: Breno Leitao, Alexander Graf, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav
Cc: linux-kernel, kexec, linux-mm, rmikey, clm, riel, kernel-team
On 02/01/2026 17:53, Breno Leitao wrote:
> Add CONFIG_KEXEC_HISTORY to store and display the kernel version from
> the previous kexec boot.
>
> When enabled, the current kernel's release string is saved to the
> "previous-release" property in the KHO device tree before kexec. On
> the next boot, if this property exists, the previous kernel version
> is retrieved and printed during early boot.
>
> This helps diagnose bugs that only manifest when kexecing from
> specific kernel versions, making it easier to correlate crashes with
> the kernel that initiated the kexec.
>
> Disabled by default to avoid overhead for users who don't need this
> information.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> kernel/Kconfig.kexec | 13 +++++++++++++
> kernel/liveupdate/kexec_handover.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 42 insertions(+)
>
> diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
> index 15632358bcf7..b770c68a3800 100644
> --- a/kernel/Kconfig.kexec
> +++ b/kernel/Kconfig.kexec
> @@ -94,6 +94,19 @@ config KEXEC_JUMP
> Jump between original kernel and kexeced kernel and invoke
> code in physical address mode via KEXEC
>
> +config KEXEC_HISTORY
> + bool "Track kexec kernel history"
> + depends on KEXEC_HANDOVER
> + help
> + When enabled, the kernel will store its release version in the
> + KHO FDT before kexec, and the newly booted kernel will read and
> + print this information during early boot.
> +
> + This is useful for debugging and auditing to know which kernel
> + version performed the kexec that booted the current kernel.
> +
> + If unsure, say N.
> +
I think we should make this default if KHO is enabled, i.e. not have a Kconfig
option for this. The cost of storing the char array is negligable.
> config CRASH_DUMP
> bool "kernel crash dumps"
> default ARCH_DEFAULT_CRASH_DUMP
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 73da00aeaa99..06d99627bb3c 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -21,6 +21,7 @@
> #include <linux/page-isolation.h>
> #include <linux/unaligned.h>
> #include <linux/vmalloc.h>
> +#include <linux/utsname.h>
>
> #include <asm/early_ioremap.h>
>
> @@ -36,6 +37,7 @@
> #define KHO_FDT_COMPATIBLE "kho-v1"
> #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
> #define PROP_SUB_FDT "fdt"
> +#define PROP_PREVIOUS_RELEASE "previous-release"
>
> #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
>
> @@ -1253,6 +1255,9 @@ bool kho_finalized(void)
> struct kho_in {
> phys_addr_t fdt_phys;
> phys_addr_t scratch_phys;
> +#ifdef CONFIG_KEXEC_HISTORY
> + char previous_release[__NEW_UTS_LEN + 1];
> +#endif
> struct kho_debugfs dbg;
> };
>
> @@ -1332,6 +1337,10 @@ static __init int kho_out_fdt_setup(void)
> err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE);
> err |= fdt_property(root, PROP_PRESERVED_MEMORY_MAP, &empty_mem_map,
> sizeof(empty_mem_map));
> +#ifdef CONFIG_KEXEC_HISTORY
> + err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
> + init_uts_ns.name.release);
> +#endif
> err |= fdt_end_node(root);
> err |= fdt_finish(root);
>
> @@ -1455,6 +1464,25 @@ void __init kho_memory_init(void)
> }
> }
>
> +#ifdef CONFIG_KEXEC_HISTORY
> +static void __init kho_print_previous_kernel(const void *fdt)
> +{
> + const char *prev_release;
> + int len;
> +
> + prev_release = fdt_getprop(fdt, 0, PROP_PREVIOUS_RELEASE, &len);
> + if (!prev_release || len <= 0)
> + return;
> +
> + strscpy(kho_in.previous_release, prev_release,
> + sizeof(kho_in.previous_release));
> + pr_info("This kernel was kexec'ed from kernel release: %s\n",
> + kho_in.previous_release);
Maybe s/release/version everywhere? It might not be a release, but no strong opinion.
> +}
> +#else
> +static void __init kho_print_previous_kernel(const void *fdt) { }
> +#endif
> +
> void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
> phys_addr_t scratch_phys, u64 scratch_len)
> {
> @@ -1527,6 +1555,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
> kho_in.scratch_phys = scratch_phys;
> kho_scratch_cnt = scratch_cnt;
> pr_info("found kexec handover data.\n");
> + kho_print_previous_kernel(fdt);
>
> out:
> if (fdt)
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] kexec: history: track kexec boot counter
2026-01-02 14:53 ` [PATCH v2 2/2] kexec: history: track kexec boot counter Breno Leitao
@ 2026-01-02 15:09 ` Usama Arif
2026-01-02 15:24 ` Breno Leitao
2026-01-02 16:20 ` Pasha Tatashin
1 sibling, 1 reply; 11+ messages in thread
From: Usama Arif @ 2026-01-02 15:09 UTC (permalink / raw)
To: Breno Leitao, Alexander Graf, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav
Cc: linux-kernel, kexec, linux-mm, rmikey, clm, riel, kernel-team
On 02/01/2026 17:53, Breno Leitao wrote:
> Track and display the number of kexec boots since the last cold reboot
> when CONFIG_KEXEC_HISTORY is enabled.
>
> This extends the previous kernel release tracking feature by adding
> a counter that increments with each kexec boot. The counter provides
> visibility into the kexec chain depth, which is useful for understanding
> boot history in production environments.
>
> Add a new property, "kexec-count" in KHO FDT alongside the existing
> "previous-release" property. The counter is:
>
> - Initialized to 0 when kho_in is instantiated.
> - Incremented by 1 on each subsequent kexec.
> - Printed alongside the previous kernel release version.
>
> The counter is stored as a 32-bit unsigned integer in FDT format and is
> only active when CONFIG_KEXEC_HISTORY is enabled.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> Suggested-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
> kernel/liveupdate/kexec_handover.c | 25 +++++++++++++++++++++++--
> 1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 06d99627bb3c..fe5a2c5c4c86 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -38,6 +38,7 @@
> #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
> #define PROP_SUB_FDT "fdt"
> #define PROP_PREVIOUS_RELEASE "previous-release"
> +#define PROP_KEXEC_COUNT "kexec-count"
>
> #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
>
> @@ -1257,6 +1258,7 @@ struct kho_in {
> phys_addr_t scratch_phys;
> #ifdef CONFIG_KEXEC_HISTORY
> char previous_release[__NEW_UTS_LEN + 1];
> + u32 kexec_count;
> #endif
> struct kho_debugfs dbg;
> };
> @@ -1330,6 +1332,9 @@ static __init int kho_out_fdt_setup(void)
> void *root = kho_out.fdt;
> u64 empty_mem_map = 0;
> int err;
> +#ifdef CONFIG_KEXEC_HISTORY
> + u32 kexec_count;
> +#endif
>
> err = fdt_create(root, PAGE_SIZE);
> err |= fdt_finish_reservemap(root);
> @@ -1340,6 +1345,10 @@ static __init int kho_out_fdt_setup(void)
> #ifdef CONFIG_KEXEC_HISTORY
> err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
> init_uts_ns.name.release);
> + /* kho_in.kexec_count is set to 0 on cold boot */
> + kexec_count = cpu_to_fdt32(kho_in.kexec_count + 1);
Should this be kexec_count = cpu_to_fdt32(kho_in.kexec_count) + 1; ?
> + err |= fdt_property(root, PROP_KEXEC_COUNT, &kexec_count,
> + sizeof(kexec_count));
> #endif
> err |= fdt_end_node(root);
> err |= fdt_finish(root);
> @@ -1468,6 +1477,7 @@ void __init kho_memory_init(void)
> static void __init kho_print_previous_kernel(const void *fdt)
> {
> const char *prev_release;
> + const u32 *count_ptr;
> int len;
>
> prev_release = fdt_getprop(fdt, 0, PROP_PREVIOUS_RELEASE, &len);
> @@ -1476,8 +1486,19 @@ static void __init kho_print_previous_kernel(const void *fdt)
>
> strscpy(kho_in.previous_release, prev_release,
> sizeof(kho_in.previous_release));
> - pr_info("This kernel was kexec'ed from kernel release: %s\n",
> - kho_in.previous_release);
> +
> + /* Read the kexec count from the previous kernel */
> + count_ptr = fdt_getprop(fdt, 0, PROP_KEXEC_COUNT, &len);
> + if (WARN_ON_ONCE(!count_ptr || len <= 0))
> + /*
> + * PROP_KEXEC_COUNT should exist if PROP_PREVIOUS_RELEASE
> + * exists.
> + */
> + return;
> + kho_in.kexec_count = fdt32_to_cpu(*count_ptr);
> +
> + pr_info("This kernel was kexec'ed from kernel release: %s (kexec count: %u)\n",
> + kho_in.previous_release, kho_in.kexec_count);
> }
> #else
> static void __init kho_print_previous_kernel(const void *fdt) { }
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/2] kexec: history: track previous kernel version
2026-01-02 15:02 ` Usama Arif
@ 2026-01-02 15:14 ` Breno Leitao
2026-01-02 15:33 ` Usama Arif
0 siblings, 1 reply; 11+ messages in thread
From: Breno Leitao @ 2026-01-02 15:14 UTC (permalink / raw)
To: Usama Arif
Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
linux-kernel, kexec, linux-mm, rmikey, clm, riel, kernel-team
Hello Usama,
On Fri, Jan 02, 2026 at 06:02:39PM +0300, Usama Arif wrote:
> On 02/01/2026 17:53, Breno Leitao wrote:
> I think we should make this default if KHO is enabled, i.e. not have a Kconfig
> option for this. The cost of storing the char array is negligable.
Sure, I can get it enabled by default once KHO gets enabled. Thanks for
the feedback.
> > + pr_info("This kernel was kexec'ed from kernel release: %s\n",
> > + kho_in.previous_release);
>
> Maybe s/release/version everywhere? It might not be a release, but no strong opinion.
As I understand, in the kernel parlance, "version" is something
different from "release", and what we want here is "release". Here is an
example of uname, which also matches with kernel source code and UTS.
# uname --kernel-version
#1 SMP Mon Nov 17 07:00:42 PST 2025
# uname --kernel-release
6.16.1-0_gc0739ee5037a
Thanks for the review,
--breno
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] kexec: history: track kexec boot counter
2026-01-02 15:09 ` Usama Arif
@ 2026-01-02 15:24 ` Breno Leitao
2026-01-02 15:31 ` Usama Arif
0 siblings, 1 reply; 11+ messages in thread
From: Breno Leitao @ 2026-01-02 15:24 UTC (permalink / raw)
To: Usama Arif
Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
linux-kernel, kexec, linux-mm, rmikey, clm, riel, kernel-team
Hello Usama,
On Fri, Jan 02, 2026 at 06:09:57PM +0300, Usama Arif wrote:
>
> On 02/01/2026 17:53, Breno Leitao wrote:
> > Track and display the number of kexec boots since the last cold reboot
> > when CONFIG_KEXEC_HISTORY is enabled.
> >
> > This extends the previous kernel release tracking feature by adding
> > a counter that increments with each kexec boot. The counter provides
> > visibility into the kexec chain depth, which is useful for understanding
> > boot history in production environments.
> >
> > Add a new property, "kexec-count" in KHO FDT alongside the existing
> > "previous-release" property. The counter is:
> >
> > - Initialized to 0 when kho_in is instantiated.
> > - Incremented by 1 on each subsequent kexec.
> > - Printed alongside the previous kernel release version.
> >
> > The counter is stored as a 32-bit unsigned integer in FDT format and is
> > only active when CONFIG_KEXEC_HISTORY is enabled.
> >
> > Signed-off-by: Breno Leitao <leitao@debian.org>
> > Suggested-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> > ---
> > kernel/liveupdate/kexec_handover.c | 25 +++++++++++++++++++++++--
> > 1 file changed, 23 insertions(+), 2 deletions(-)
> >
> > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> > index 06d99627bb3c..fe5a2c5c4c86 100644
> > --- a/kernel/liveupdate/kexec_handover.c
> > +++ b/kernel/liveupdate/kexec_handover.c
> > @@ -38,6 +38,7 @@
> > #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
> > #define PROP_SUB_FDT "fdt"
> > #define PROP_PREVIOUS_RELEASE "previous-release"
> > +#define PROP_KEXEC_COUNT "kexec-count"
> >
> > #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
> >
> > @@ -1257,6 +1258,7 @@ struct kho_in {
> > phys_addr_t scratch_phys;
> > #ifdef CONFIG_KEXEC_HISTORY
> > char previous_release[__NEW_UTS_LEN + 1];
> > + u32 kexec_count;
> > #endif
> > struct kho_debugfs dbg;
> > };
> > @@ -1330,6 +1332,9 @@ static __init int kho_out_fdt_setup(void)
> > void *root = kho_out.fdt;
> > u64 empty_mem_map = 0;
> > int err;
> > +#ifdef CONFIG_KEXEC_HISTORY
> > + u32 kexec_count;
> > +#endif
> >
> > err = fdt_create(root, PAGE_SIZE);
> > err |= fdt_finish_reservemap(root);
> > @@ -1340,6 +1345,10 @@ static __init int kho_out_fdt_setup(void)
> > #ifdef CONFIG_KEXEC_HISTORY
> > err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
> > init_uts_ns.name.release);
> > + /* kho_in.kexec_count is set to 0 on cold boot */
> > + kexec_count = cpu_to_fdt32(kho_in.kexec_count + 1);
>
> Should this be kexec_count = cpu_to_fdt32(kho_in.kexec_count) + 1; ?
I don't think so. Basically we want to increment the counter in native
endianess and then convert to the Big Endian (FDT/DT are big endian
AFAIK) and then store (line below) to the DT.
If we convert to big endian and then sum 1, it will mess with the
result.
> + err |= fdt_property(root, PROP_KEXEC_COUNT, &kexec_count,
> > + sizeof(kexec_count));
Thanks for the review,
--breno
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] kexec: history: track kexec boot counter
2026-01-02 15:24 ` Breno Leitao
@ 2026-01-02 15:31 ` Usama Arif
0 siblings, 0 replies; 11+ messages in thread
From: Usama Arif @ 2026-01-02 15:31 UTC (permalink / raw)
To: Breno Leitao
Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
linux-kernel, kexec, linux-mm, rmikey, clm, riel, kernel-team
On 02/01/2026 18:24, Breno Leitao wrote:
> Hello Usama,
>
> On Fri, Jan 02, 2026 at 06:09:57PM +0300, Usama Arif wrote:
>>
>> On 02/01/2026 17:53, Breno Leitao wrote:
>>> Track and display the number of kexec boots since the last cold reboot
>>> when CONFIG_KEXEC_HISTORY is enabled.
>>>
>>> This extends the previous kernel release tracking feature by adding
>>> a counter that increments with each kexec boot. The counter provides
>>> visibility into the kexec chain depth, which is useful for understanding
>>> boot history in production environments.
>>>
>>> Add a new property, "kexec-count" in KHO FDT alongside the existing
>>> "previous-release" property. The counter is:
>>>
>>> - Initialized to 0 when kho_in is instantiated.
>>> - Incremented by 1 on each subsequent kexec.
>>> - Printed alongside the previous kernel release version.
>>>
>>> The counter is stored as a 32-bit unsigned integer in FDT format and is
>>> only active when CONFIG_KEXEC_HISTORY is enabled.
>>>
>>> Signed-off-by: Breno Leitao <leitao@debian.org>
>>> Suggested-by: Pasha Tatashin <pasha.tatashin@soleen.com>
>>> ---
>>> kernel/liveupdate/kexec_handover.c | 25 +++++++++++++++++++++++--
>>> 1 file changed, 23 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
>>> index 06d99627bb3c..fe5a2c5c4c86 100644
>>> --- a/kernel/liveupdate/kexec_handover.c
>>> +++ b/kernel/liveupdate/kexec_handover.c
>>> @@ -38,6 +38,7 @@
>>> #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
>>> #define PROP_SUB_FDT "fdt"
>>> #define PROP_PREVIOUS_RELEASE "previous-release"
>>> +#define PROP_KEXEC_COUNT "kexec-count"
>>>
>>> #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
>>>
>>> @@ -1257,6 +1258,7 @@ struct kho_in {
>>> phys_addr_t scratch_phys;
>>> #ifdef CONFIG_KEXEC_HISTORY
>>> char previous_release[__NEW_UTS_LEN + 1];
>>> + u32 kexec_count;
>>> #endif
>>> struct kho_debugfs dbg;
>>> };
>>> @@ -1330,6 +1332,9 @@ static __init int kho_out_fdt_setup(void)
>>> void *root = kho_out.fdt;
>>> u64 empty_mem_map = 0;
>>> int err;
>>> +#ifdef CONFIG_KEXEC_HISTORY
>>> + u32 kexec_count;
>>> +#endif
>>>
>>> err = fdt_create(root, PAGE_SIZE);
>>> err |= fdt_finish_reservemap(root);
>>> @@ -1340,6 +1345,10 @@ static __init int kho_out_fdt_setup(void)
>>> #ifdef CONFIG_KEXEC_HISTORY
>>> err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
>>> init_uts_ns.name.release);
>>> + /* kho_in.kexec_count is set to 0 on cold boot */
>>> + kexec_count = cpu_to_fdt32(kho_in.kexec_count + 1);
>>
>> Should this be kexec_count = cpu_to_fdt32(kho_in.kexec_count) + 1; ?
>
> I don't think so. Basically we want to increment the counter in native
> endianess and then convert to the Big Endian (FDT/DT are big endian
> AFAIK) and then store (line below) to the DT.
>
> If we convert to big endian and then sum 1, it will mess with the
> result.
ack, Thanks for explaining, I didnt think of endianess!
>
>> + err |= fdt_property(root, PROP_KEXEC_COUNT, &kexec_count,
>>> + sizeof(kexec_count));
>
> Thanks for the review,
> --breno
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/2] kexec: history: track previous kernel version
2026-01-02 15:14 ` Breno Leitao
@ 2026-01-02 15:33 ` Usama Arif
0 siblings, 0 replies; 11+ messages in thread
From: Usama Arif @ 2026-01-02 15:33 UTC (permalink / raw)
To: Breno Leitao
Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
linux-kernel, kexec, linux-mm, rmikey, clm, riel, kernel-team
On 02/01/2026 18:14, Breno Leitao wrote:
> Hello Usama,
>
> On Fri, Jan 02, 2026 at 06:02:39PM +0300, Usama Arif wrote:
>> On 02/01/2026 17:53, Breno Leitao wrote:
>> I think we should make this default if KHO is enabled, i.e. not have a Kconfig
>> option for this. The cost of storing the char array is negligable.
>
> Sure, I can get it enabled by default once KHO gets enabled. Thanks for
> the feedback.
>
>>> + pr_info("This kernel was kexec'ed from kernel release: %s\n",
>>> + kho_in.previous_release);
>>
>> Maybe s/release/version everywhere? It might not be a release, but no strong opinion.
>
> As I understand, in the kernel parlance, "version" is something
> different from "release", and what we want here is "release". Here is an
> example of uname, which also matches with kernel source code and UTS.
>
> # uname --kernel-version
> #1 SMP Mon Nov 17 07:00:42 PST 2025
>
> # uname --kernel-release
> 6.16.1-0_gc0739ee5037a
>
ack
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/2] kexec: history: track previous kernel version
2026-01-02 14:53 ` [PATCH v2 1/2] kexec: history: track previous kernel version Breno Leitao
2026-01-02 15:02 ` Usama Arif
@ 2026-01-02 16:18 ` Pasha Tatashin
1 sibling, 0 replies; 11+ messages in thread
From: Pasha Tatashin @ 2026-01-02 16:18 UTC (permalink / raw)
To: Breno Leitao
Cc: Alexander Graf, Mike Rapoport, Pratyush Yadav, linux-kernel,
kexec, linux-mm, usamaarif642, rmikey, clm, riel, kernel-team
On Fri, Jan 2, 2026 at 9:53 AM Breno Leitao <leitao@debian.org> wrote:
>
> Add CONFIG_KEXEC_HISTORY to store and display the kernel version from
> the previous kexec boot.
I do not think we need a config. Let's just enable this by default, as
I suggested in RFC.
>
> When enabled, the current kernel's release string is saved to the
> "previous-release" property in the KHO device tree before kexec. On
> the next boot, if this property exists, the previous kernel version
> is retrieved and printed during early boot.
>
> This helps diagnose bugs that only manifest when kexecing from
> specific kernel versions, making it easier to correlate crashes with
> the kernel that initiated the kexec.
>
> Disabled by default to avoid overhead for users who don't need this
> information.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> kernel/Kconfig.kexec | 13 +++++++++++++
> kernel/liveupdate/kexec_handover.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 42 insertions(+)
>
> diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
> index 15632358bcf7..b770c68a3800 100644
> --- a/kernel/Kconfig.kexec
> +++ b/kernel/Kconfig.kexec
> @@ -94,6 +94,19 @@ config KEXEC_JUMP
> Jump between original kernel and kexeced kernel and invoke
> code in physical address mode via KEXEC
>
> +config KEXEC_HISTORY
> + bool "Track kexec kernel history"
> + depends on KEXEC_HANDOVER
> + help
> + When enabled, the kernel will store its release version in the
> + KHO FDT before kexec, and the newly booted kernel will read and
> + print this information during early boot.
> +
> + This is useful for debugging and auditing to know which kernel
> + version performed the kexec that booted the current kernel.
> +
> + If unsure, say N.
> +
> config CRASH_DUMP
> bool "kernel crash dumps"
> default ARCH_DEFAULT_CRASH_DUMP
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 73da00aeaa99..06d99627bb3c 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -21,6 +21,7 @@
> #include <linux/page-isolation.h>
> #include <linux/unaligned.h>
> #include <linux/vmalloc.h>
> +#include <linux/utsname.h>
>
> #include <asm/early_ioremap.h>
>
> @@ -36,6 +37,7 @@
> #define KHO_FDT_COMPATIBLE "kho-v1"
> #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
> #define PROP_SUB_FDT "fdt"
> +#define PROP_PREVIOUS_RELEASE "previous-release"
>
> #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
>
> @@ -1253,6 +1255,9 @@ bool kho_finalized(void)
> struct kho_in {
> phys_addr_t fdt_phys;
> phys_addr_t scratch_phys;
> +#ifdef CONFIG_KEXEC_HISTORY
> + char previous_release[__NEW_UTS_LEN + 1];
> +#endif
> struct kho_debugfs dbg;
> };
>
> @@ -1332,6 +1337,10 @@ static __init int kho_out_fdt_setup(void)
> err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE);
> err |= fdt_property(root, PROP_PRESERVED_MEMORY_MAP, &empty_mem_map,
> sizeof(empty_mem_map));
> +#ifdef CONFIG_KEXEC_HISTORY
> + err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
> + init_uts_ns.name.release);
> +#endif
> err |= fdt_end_node(root);
> err |= fdt_finish(root);
>
> @@ -1455,6 +1464,25 @@ void __init kho_memory_init(void)
> }
> }
>
> +#ifdef CONFIG_KEXEC_HISTORY
> +static void __init kho_print_previous_kernel(const void *fdt)
> +{
> + const char *prev_release;
> + int len;
> +
> + prev_release = fdt_getprop(fdt, 0, PROP_PREVIOUS_RELEASE, &len);
> + if (!prev_release || len <= 0)
> + return;
> +
> + strscpy(kho_in.previous_release, prev_release,
> + sizeof(kho_in.previous_release));
> + pr_info("This kernel was kexec'ed from kernel release: %s\n",
> + kho_in.previous_release);
May be reduce the message slightly:
i.e. "kexec from: %s\n, kho_in.previous_release"
> +}
> +#else
> +static void __init kho_print_previous_kernel(const void *fdt) { }
> +#endif
> +
> void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
> phys_addr_t scratch_phys, u64 scratch_len)
> {
> @@ -1527,6 +1555,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
> kho_in.scratch_phys = scratch_phys;
> kho_scratch_cnt = scratch_cnt;
> pr_info("found kexec handover data.\n");
This message is not needed if the previous kernel version is always printed.
> + kho_print_previous_kernel(fdt);
>
> out:
> if (fdt)
>
> --
> 2.47.3
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/2] kexec: history: track kexec boot counter
2026-01-02 14:53 ` [PATCH v2 2/2] kexec: history: track kexec boot counter Breno Leitao
2026-01-02 15:09 ` Usama Arif
@ 2026-01-02 16:20 ` Pasha Tatashin
1 sibling, 0 replies; 11+ messages in thread
From: Pasha Tatashin @ 2026-01-02 16:20 UTC (permalink / raw)
To: Breno Leitao
Cc: Alexander Graf, Mike Rapoport, Pratyush Yadav, linux-kernel,
kexec, linux-mm, usamaarif642, rmikey, clm, riel, kernel-team
On Fri, Jan 2, 2026 at 9:53 AM Breno Leitao <leitao@debian.org> wrote:
>
> Track and display the number of kexec boots since the last cold reboot
> when CONFIG_KEXEC_HISTORY is enabled.
>
> This extends the previous kernel release tracking feature by adding
> a counter that increments with each kexec boot. The counter provides
> visibility into the kexec chain depth, which is useful for understanding
> boot history in production environments.
>
> Add a new property, "kexec-count" in KHO FDT alongside the existing
> "previous-release" property. The counter is:
>
> - Initialized to 0 when kho_in is instantiated.
> - Incremented by 1 on each subsequent kexec.
> - Printed alongside the previous kernel release version.
>
> The counter is stored as a 32-bit unsigned integer in FDT format and is
> only active when CONFIG_KEXEC_HISTORY is enabled.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> Suggested-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
> kernel/liveupdate/kexec_handover.c | 25 +++++++++++++++++++++++--
> 1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 06d99627bb3c..fe5a2c5c4c86 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -38,6 +38,7 @@
> #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
> #define PROP_SUB_FDT "fdt"
> #define PROP_PREVIOUS_RELEASE "previous-release"
> +#define PROP_KEXEC_COUNT "kexec-count"
>
> #define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
>
> @@ -1257,6 +1258,7 @@ struct kho_in {
> phys_addr_t scratch_phys;
> #ifdef CONFIG_KEXEC_HISTORY
> char previous_release[__NEW_UTS_LEN + 1];
> + u32 kexec_count;
> #endif
> struct kho_debugfs dbg;
> };
> @@ -1330,6 +1332,9 @@ static __init int kho_out_fdt_setup(void)
> void *root = kho_out.fdt;
> u64 empty_mem_map = 0;
> int err;
> +#ifdef CONFIG_KEXEC_HISTORY
> + u32 kexec_count;
> +#endif
>
> err = fdt_create(root, PAGE_SIZE);
> err |= fdt_finish_reservemap(root);
> @@ -1340,6 +1345,10 @@ static __init int kho_out_fdt_setup(void)
> #ifdef CONFIG_KEXEC_HISTORY
> err |= fdt_property_string(root, PROP_PREVIOUS_RELEASE,
> init_uts_ns.name.release);
> + /* kho_in.kexec_count is set to 0 on cold boot */
> + kexec_count = cpu_to_fdt32(kho_in.kexec_count + 1);
For KHO preserved data we use native endiness, so do not bother with
cpu_to_fdt32.
> + err |= fdt_property(root, PROP_KEXEC_COUNT, &kexec_count,
> + sizeof(kexec_count));
> #endif
> err |= fdt_end_node(root);
> err |= fdt_finish(root);
> @@ -1468,6 +1477,7 @@ void __init kho_memory_init(void)
> static void __init kho_print_previous_kernel(const void *fdt)
> {
> const char *prev_release;
> + const u32 *count_ptr;
> int len;
>
> prev_release = fdt_getprop(fdt, 0, PROP_PREVIOUS_RELEASE, &len);
> @@ -1476,8 +1486,19 @@ static void __init kho_print_previous_kernel(const void *fdt)
>
> strscpy(kho_in.previous_release, prev_release,
> sizeof(kho_in.previous_release));
> - pr_info("This kernel was kexec'ed from kernel release: %s\n",
> - kho_in.previous_release);
> +
> + /* Read the kexec count from the previous kernel */
> + count_ptr = fdt_getprop(fdt, 0, PROP_KEXEC_COUNT, &len);
> + if (WARN_ON_ONCE(!count_ptr || len <= 0))
This function is called only once anway.
> + /*
> + * PROP_KEXEC_COUNT should exist if PROP_PREVIOUS_RELEASE
> + * exists.
> + */
> + return;
> + kho_in.kexec_count = fdt32_to_cpu(*count_ptr);
> +
> + pr_info("This kernel was kexec'ed from kernel release: %s (kexec count: %u)\n",
> + kho_in.previous_release, kho_in.kexec_count);
> }
> #else
> static void __init kho_print_previous_kernel(const void *fdt) { }
>
> --
> 2.47.3
>
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-01-02 16:21 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-02 14:53 [PATCH v2 0/2] kexec: history: track previous kernel version and kexec boot count Breno Leitao
2026-01-02 14:53 ` [PATCH v2 1/2] kexec: history: track previous kernel version Breno Leitao
2026-01-02 15:02 ` Usama Arif
2026-01-02 15:14 ` Breno Leitao
2026-01-02 15:33 ` Usama Arif
2026-01-02 16:18 ` Pasha Tatashin
2026-01-02 14:53 ` [PATCH v2 2/2] kexec: history: track kexec boot counter Breno Leitao
2026-01-02 15:09 ` Usama Arif
2026-01-02 15:24 ` Breno Leitao
2026-01-02 15:31 ` Usama Arif
2026-01-02 16:20 ` Pasha Tatashin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox