linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count
@ 2026-01-08 16:40 Breno Leitao
  2026-01-08 16:40 ` [PATCH v3 1/2] kho: history: track previous kernel version Breno Leitao
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Breno Leitao @ 2026-01-08 16:40 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: exec from: 6.19.0-rc4-next-20260107upstream-00004-g3071b0dc4498 (count 1)

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.

The goal of this feature is to have this information being printed in
early boot, so, users can trace back kernel releases in kexec. Systemd
is not helpful because we cannot assume that the previous kernel has
systemd or even write access to the disk (common when using Linux as
bootloaders)

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

---
Changes in v3:
- Remove the extra CONFIG for this feature.
- Reworded some identifiers, properties and printks.
- Better documented the questions raised during v2.
- Link to v2: https://patch.msgid.link/20260102-kho-v2-0-1747b1a3a1d6@debian.org

---
Breno Leitao (2):
      kho: history: track previous kernel version
      kho: history: track kexec boot counter

 include/linux/kho/abi/kexec_handover.h |  6 ++++++
 kernel/liveupdate/kexec_handover.c     | 39 +++++++++++++++++++++++++++++++++-
 2 files changed, 44 insertions(+), 1 deletion(-)
---
base-commit: 5eec2b2e1f37acff8b926d2494eadaeef59be279
change-id: 20251230-kho-7707e8a2ef1e

Best regards,
--  
Breno Leitao <leitao@debian.org>



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/2] kho: history: track previous kernel version
  2026-01-08 16:40 [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count Breno Leitao
@ 2026-01-08 16:40 ` Breno Leitao
  2026-01-14 19:19   ` Pratyush Yadav
  2026-01-08 16:40 ` [PATCH v3 2/2] kho: history: track kexec boot counter Breno Leitao
  2026-01-09  1:45 ` [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count SeongJae Park
  2 siblings, 1 reply; 9+ messages in thread
From: Breno Leitao @ 2026-01-08 16:40 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

Store and display the kernel version from the previous kexec boot.

The current kernel's release string is saved to the "previous-release"
property in the KHO FDT 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.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 include/linux/kho/abi/kexec_handover.h |  3 +++
 kernel/liveupdate/kexec_handover.c     | 25 ++++++++++++++++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
index 285eda8a36e4..f4f31e8f575b 100644
--- a/include/linux/kho/abi/kexec_handover.h
+++ b/include/linux/kho/abi/kexec_handover.h
@@ -84,6 +84,9 @@
 /* The FDT property for sub-FDTs. */
 #define KHO_FDT_SUB_TREE_PROP_NAME "fdt"
 
+/* The FDT property to track previous kernel (kexec caller) */
+#define KHO_PROP_PREVIOUS_RELEASE "previous-release"
+
 /**
  * DOC: Kexec Handover ABI for vmalloc Preservation
  *
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 3cf2dc6840c9..b2d57868d22f 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -22,6 +22,7 @@
 #include <linux/page-isolation.h>
 #include <linux/unaligned.h>
 #include <linux/vmalloc.h>
+#include <linux/utsname.h>
 
 #include <asm/early_ioremap.h>
 
@@ -1246,6 +1247,7 @@ struct kho_in {
 	phys_addr_t fdt_phys;
 	phys_addr_t scratch_phys;
 	phys_addr_t mem_map_phys;
+	char previous_release[__NEW_UTS_LEN + 1];
 	struct kho_debugfs dbg;
 };
 
@@ -1325,6 +1327,8 @@ static __init int kho_out_fdt_setup(void)
 	err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE);
 	err |= fdt_property(root, KHO_FDT_MEMORY_MAP_PROP_NAME, &empty_mem_map,
 			    sizeof(empty_mem_map));
+	err |= fdt_property_string(root, KHO_PROP_PREVIOUS_RELEASE,
+				   init_uts_ns.name.release);
 	err |= fdt_end_node(root);
 	err |= fdt_finish(root);
 
@@ -1436,6 +1440,22 @@ void __init kho_memory_init(void)
 	}
 }
 
+static int __init kho_print_previous_kernel(const void *fdt)
+{
+	const char *prev_release;
+	int len;
+
+	prev_release = fdt_getprop(fdt, 0, KHO_PROP_PREVIOUS_RELEASE, &len);
+	if (!prev_release || len <= 0)
+		return -ENOENT;
+
+	strscpy(kho_in.previous_release, prev_release,
+		sizeof(kho_in.previous_release));
+	pr_info("exec from: %s\n", kho_in.previous_release);
+
+	return 0;
+}
+
 void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
 			 phys_addr_t scratch_phys, u64 scratch_len)
 {
@@ -1513,7 +1533,10 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
 	kho_in.scratch_phys = scratch_phys;
 	kho_in.mem_map_phys = mem_map_phys;
 	kho_scratch_cnt = scratch_cnt;
-	pr_info("found kexec handover data.\n");
+
+	if (kho_print_previous_kernel(fdt))
+		/* Fallback message when previous kernel info unavailable */
+		pr_info("found kexec handover data.\n");
 
 out:
 	if (fdt)

-- 
2.47.3



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 2/2] kho: history: track kexec boot counter
  2026-01-08 16:40 [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count Breno Leitao
  2026-01-08 16:40 ` [PATCH v3 1/2] kho: history: track previous kernel version Breno Leitao
@ 2026-01-08 16:40 ` Breno Leitao
  2026-01-09  1:45 ` [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count SeongJae Park
  2 siblings, 0 replies; 9+ messages in thread
From: Breno Leitao @ 2026-01-08 16:40 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.

This extends the previous kernel release tracking 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 on cold boot (when kho_in is first 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.

This is different than counter for LUO, given KHO can be used
independently from LUO.

Also WARN() if KHO_PROP_PREVIOUS_RELEASE doesn't exist, because it
must exist if KHO_PROP_PREVIOUS_RELEASE exists.

Signed-off-by: Breno Leitao <leitao@debian.org>
Suggested-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 include/linux/kho/abi/kexec_handover.h |  3 +++
 kernel/liveupdate/kexec_handover.c     | 16 +++++++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
index f4f31e8f575b..9c4fc4c6a212 100644
--- a/include/linux/kho/abi/kexec_handover.h
+++ b/include/linux/kho/abi/kexec_handover.h
@@ -87,6 +87,9 @@
 /* The FDT property to track previous kernel (kexec caller) */
 #define KHO_PROP_PREVIOUS_RELEASE "previous-release"
 
+/* The FDT property to track number of kexec counts so far */
+#define KHO_PROP_KEXEC_COUNT "kexec-count"
+
 /**
  * DOC: Kexec Handover ABI for vmalloc Preservation
  *
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index b2d57868d22f..34cfc98076b8 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -1248,6 +1248,7 @@ struct kho_in {
 	phys_addr_t scratch_phys;
 	phys_addr_t mem_map_phys;
 	char previous_release[__NEW_UTS_LEN + 1];
+	u32 kexec_count;
 	struct kho_debugfs dbg;
 };
 
@@ -1319,6 +1320,7 @@ static __init int kho_out_fdt_setup(void)
 {
 	void *root = kho_out.fdt;
 	u64 empty_mem_map = 0;
+	u32 kexec_count;
 	int err;
 
 	err = fdt_create(root, PAGE_SIZE);
@@ -1329,6 +1331,10 @@ static __init int kho_out_fdt_setup(void)
 			    sizeof(empty_mem_map));
 	err |= fdt_property_string(root, KHO_PROP_PREVIOUS_RELEASE,
 				   init_uts_ns.name.release);
+	/* kho_in.kexec_count is set to 0 on cold boot */
+	kexec_count = kho_in.kexec_count + 1;
+	err |= fdt_property(root, KHO_PROP_KEXEC_COUNT, &kexec_count,
+			    sizeof(kexec_count));
 	err |= fdt_end_node(root);
 	err |= fdt_finish(root);
 
@@ -1443,15 +1449,23 @@ void __init kho_memory_init(void)
 static int __init kho_print_previous_kernel(const void *fdt)
 {
 	const char *prev_release;
+	const u32 *count_ptr;
 	int len;
 
 	prev_release = fdt_getprop(fdt, 0, KHO_PROP_PREVIOUS_RELEASE, &len);
 	if (!prev_release || len <= 0)
 		return -ENOENT;
 
+	/* Read the kexec count from the previous kernel */
+	count_ptr = fdt_getprop(fdt, 0, KHO_PROP_KEXEC_COUNT, &len);
+	if (WARN_ON(!count_ptr || len != sizeof(u32)))
+		return -ENOENT;
+	kho_in.kexec_count = *count_ptr;
+
 	strscpy(kho_in.previous_release, prev_release,
 		sizeof(kho_in.previous_release));
-	pr_info("exec from: %s\n", kho_in.previous_release);
+	pr_info("exec from: %s (count %u)\n", kho_in.previous_release,
+					      kho_in.kexec_count);
 
 	return 0;
 }

-- 
2.47.3



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count
  2026-01-08 16:40 [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count Breno Leitao
  2026-01-08 16:40 ` [PATCH v3 1/2] kho: history: track previous kernel version Breno Leitao
  2026-01-08 16:40 ` [PATCH v3 2/2] kho: history: track kexec boot counter Breno Leitao
@ 2026-01-09  1:45 ` SeongJae Park
  2026-01-09 11:00   ` Breno Leitao
  2 siblings, 1 reply; 9+ messages in thread
From: SeongJae Park @ 2026-01-09  1:45 UTC (permalink / raw)
  To: Breno Leitao
  Cc: SeongJae Park, Alexander Graf, Mike Rapoport, Pasha Tatashin,
	Pratyush Yadav, linux-kernel, kexec, linux-mm, usamaarif642,
	rmikey, clm, riel, kernel-team

On Thu, 08 Jan 2026 08:40:57 -0800 Breno Leitao <leitao@debian.org> wrote:

> 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: exec from: 6.19.0-rc4-next-20260107upstream-00004-g3071b0dc4498 (count 1)

Nit.  The above snippet uses tabs for first two lines, while the third line
uses spaces.  I don't really mind this of course, please feel free to ignore.
I just wanted to prove I did read your cover letter ;)

> 
> 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.
> 
> The goal of this feature is to have this information being printed in
> early boot, so, users can trace back kernel releases in kexec. Systemd
> is not helpful because we cannot assume that the previous kernel has
> systemd or even write access to the disk (common when using Linux as
> bootloaders)

Sounds this feature will be useful!  Thank you for detailed cover letter.

> 
> Signed-off-by: Breno Leitao <leitao@debian.org>

The patches also look good to me.  For the series,

Acked-by: SeongJae Park <sj@kernel.org>

> ---
> Changes from v1 to RFC

Nit.  You mean "from RFC (v1) to v2"?  Again, I don't really mind this trivial
thing, so please feel free to ignore.

> - 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
> 
> ---
> Changes in v3:
> - Remove the extra CONFIG for this feature.
> - Reworded some identifiers, properties and printks.
> - Better documented the questions raised during v2.
> - Link to v2: https://patch.msgid.link/20260102-kho-v2-0-1747b1a3a1d6@debian.org


Thanks,
SJ

[...]


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count
  2026-01-09  1:45 ` [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count SeongJae Park
@ 2026-01-09 11:00   ` Breno Leitao
  0 siblings, 0 replies; 9+ messages in thread
From: Breno Leitao @ 2026-01-09 11:00 UTC (permalink / raw)
  To: SeongJae Park
  Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
	linux-kernel, kexec, linux-mm, usamaarif642, rmikey, clm, riel,
	kernel-team

Hello SJ,

On Thu, Jan 08, 2026 at 05:45:58PM -0800, SeongJae Park wrote:
> On Thu, 08 Jan 2026 08:40:57 -0800 Breno Leitao <leitao@debian.org> wrote:
> 
> > 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: exec from: 6.19.0-rc4-next-20260107upstream-00004-g3071b0dc4498 (count 1)
> 
> Nit.  The above snippet uses tabs for first two lines, while the third line
> uses spaces.  I don't really mind this of course, please feel free to ignore.
> I just wanted to prove I did read your cover letter ;)

Thanks for reading it very carefully.

[...]
> Sounds this feature will be useful!  Thank you for detailed cover letter.
> 
> > Signed-off-by: Breno Leitao <leitao@debian.org>
> 
> The patches also look good to me.  For the series,
> 
> Acked-by: SeongJae Park <sj@kernel.org>
> 
> > ---
> > Changes from v1 to RFC
> 
> Nit.  You mean "from RFC (v1) to v2"?  Again, I don't really mind this trivial
> thing, so please feel free to ignore.

Ack, my fault here. I am using b4, and I need to learn how to deal with 
RFC -> V1 ambiguity better.

If there is a need to update this patchset, I will get them fixed in the
next version.

Thanks for the review,
--breno


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/2] kho: history: track previous kernel version
  2026-01-08 16:40 ` [PATCH v3 1/2] kho: history: track previous kernel version Breno Leitao
@ 2026-01-14 19:19   ` Pratyush Yadav
  2026-01-16 15:50     ` Breno Leitao
  0 siblings, 1 reply; 9+ messages in thread
From: Pratyush Yadav @ 2026-01-14 19:19 UTC (permalink / raw)
  To: Breno Leitao
  Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
	linux-kernel, kexec, linux-mm, usamaarif642, rmikey, clm, riel,
	kernel-team

Hi Breno,

On Thu, Jan 08 2026, Breno Leitao wrote:

> Store and display the kernel version from the previous kexec boot.
>
> The current kernel's release string is saved to the "previous-release"
> property in the KHO FDT 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.

The KHO FDT is ABI. So you should be bumping the version number when you
make changes to it.

But honestly, adding this "optional" stuff to the core KHO ABI makes me
uneasy. I say optional since it is not needed for the main functionality
of KHO. Making this a part of the ABI increases the surface area we
have. The more things we stuff in the ABI, the more inflexible it gets
over time.

Any changes to the KHO ABI means all consumers also need a version bump.
This includes LUO and all its users for example. So I would really like
to avoid adding optional things in core KHO FDT.

The easy fix is to add a separate subtree for the optional metadata. You
would still need to create an ABI for the data format, but being
independent of core KHO, it will make it more flexible and easier to
change in the future. You can keep the code in kexec_handover.c.

>
> Signed-off-by: Breno Leitao <leitao@debian.org>
[...]

-- 
Regards,
Pratyush Yadav


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/2] kho: history: track previous kernel version
  2026-01-14 19:19   ` Pratyush Yadav
@ 2026-01-16 15:50     ` Breno Leitao
  2026-01-20 15:40       ` Pratyush Yadav
  0 siblings, 1 reply; 9+ messages in thread
From: Breno Leitao @ 2026-01-16 15:50 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Alexander Graf, Mike Rapoport, Pasha Tatashin, linux-kernel,
	kexec, linux-mm, usamaarif642, rmikey, clm, riel, kernel-team

Hello Pratyush,

On Wed, Jan 14, 2026 at 07:19:11PM +0000, Pratyush Yadav wrote:
> On Thu, Jan 08 2026, Breno Leitao wrote:
> 
> > Store and display the kernel version from the previous kexec boot.
> >
> > The current kernel's release string is saved to the "previous-release"
> > property in the KHO FDT 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.
> 
> The KHO FDT is ABI. So you should be bumping the version number when you
> make changes to it.
> 
> But honestly, adding this "optional" stuff to the core KHO ABI makes me
> uneasy. I say optional since it is not needed for the main functionality
> of KHO. Making this a part of the ABI increases the surface area we
> have. The more things we stuff in the ABI, the more inflexible it gets
> over time.
> 
> Any changes to the KHO ABI means all consumers also need a version bump.
> This includes LUO and all its users for example. So I would really like
> to avoid adding optional things in core KHO FDT.
> 
> The easy fix is to add a separate subtree for the optional metadata. You
> would still need to create an ABI for the data format, but being
> independent of core KHO, it will make it more flexible and easier to
> change in the future. You can keep the code in kexec_handover.c.

Thanks for the feedback and guidance!

I was able to hack this a bit and I came up with something like the
follow. Is this what you have in mind?

Author: Breno Leitao <leitao@debian.org>
Date:   Fri Jan 16 06:42:56 2026 -0800

    kho: history: track previous kernel version and kexec count
    
    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 output:
        [    0.000000] KHO: exec from: 6.19.0-rc4-next-20260107 (count 1)
    
    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.
    
    Implementation
    ==============
    
    The history metadata is stored in a separate FDT subtree registered via
    kho_add_subtree(), rather than being embedded directly in the root KHO
    FDT. This design choice:
    
     - Keeps the core KHO ABI minimal and stable
     - Allows the history format to evolve independently
     - Avoids requiring version bumps for all KHO consumers (LUO, etc.)
       when the history format changes
    
    The history subtree uses its own compatible string "kho-history-v1" and
    contains two properties:
     - previous-release: The kernel version that initiated the kexec
     - kexec-count: Number of kexec boots since last cold boot
    
    On cold boot, kexec-count starts at 0 and increments with each kexec.
    The count helps identify issues that only manifest after multiple
    consecutive kexec reboots.
    
    Signed-off-by: Breno Leitao <leitao@debian.org>

diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
index 285eda8a36e4..da19d6029815 100644
--- a/include/linux/kho/abi/kexec_handover.h
+++ b/include/linux/kho/abi/kexec_handover.h
@@ -84,6 +84,29 @@
 /* The FDT property for sub-FDTs. */
 #define KHO_FDT_SUB_TREE_PROP_NAME "fdt"
 
+/*
+ * The "history" subtree stores optional metadata about the kexec chain.
+ * It is registered as a separate FDT via kho_add_subtree(), keeping it
+ * independent from the core KHO ABI. This allows the history format to
+ * evolve without affecting other KHO consumers.
+ *
+ * The history FDT structure:
+ *
+ *   / {
+ *       compatible = "kho-history-v1";
+ *       previous-release = "6.x.y-...";
+ *       kexec-count = <N>;
+ *   };
+ */
+#define KHO_HISTORY_NODE_NAME "history"
+#define KHO_HISTORY_COMPATIBLE "kho-history-v1"
+
+/* The FDT property to track previous kernel (kexec caller) */
+#define KHO_PROP_PREVIOUS_RELEASE "previous-release"
+
+/* The FDT property to track number of kexec counts so far */
+#define KHO_PROP_KEXEC_COUNT "kexec-count"
+
 /**
  * DOC: Kexec Handover ABI for vmalloc Preservation
  *
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 3cf2dc6840c9..fd22b0947587 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -15,6 +15,7 @@
 #include <linux/count_zeros.h>
 #include <linux/kexec.h>
 #include <linux/kexec_handover.h>
+#include <linux/utsname.h>
 #include <linux/kho/abi/kexec_handover.h>
 #include <linux/libfdt.h>
 #include <linux/list.h>
@@ -1246,6 +1247,8 @@ struct kho_in {
 	phys_addr_t fdt_phys;
 	phys_addr_t scratch_phys;
 	phys_addr_t mem_map_phys;
+	char previous_release[__NEW_UTS_LEN + 1];
+	u32 kexec_count;
 	struct kho_debugfs dbg;
 };
 
@@ -1331,6 +1334,48 @@ static __init int kho_out_fdt_setup(void)
 	return err;
 }
 
+/*
+ * Create a separate FDT subtree for optional history metadata.
+ * This keeps the core KHO ABI minimal and allows the history format
+ * to evolve independently.
+ */
+static __init int kho_history_init(void)
+{
+	u32 kexec_count;
+	void *fdt;
+	int err;
+
+	fdt = kho_alloc_preserve(PAGE_SIZE);
+	if (IS_ERR(fdt))
+		return PTR_ERR(fdt);
+
+	err = fdt_create(fdt, PAGE_SIZE);
+	err |= fdt_finish_reservemap(fdt);
+	err |= fdt_begin_node(fdt, "");
+	err |= fdt_property_string(fdt, "compatible", KHO_HISTORY_COMPATIBLE);
+	err |= fdt_property_string(fdt, KHO_PROP_PREVIOUS_RELEASE,
+				   init_uts_ns.name.release);
+	/* kho_in.kexec_count is set to 0 on cold boot */
+	kexec_count = kho_in.kexec_count + 1;
+	err |= fdt_property(fdt, KHO_PROP_KEXEC_COUNT, &kexec_count,
+			    sizeof(kexec_count));
+	err |= fdt_end_node(fdt);
+	err |= fdt_finish(fdt);
+
+	if (err) {
+		kho_unpreserve_free(fdt);
+		return err;
+	}
+
+	err = kho_add_subtree(KHO_HISTORY_NODE_NAME, fdt);
+	if (err) {
+		kho_unpreserve_free(fdt);
+		return err;
+	}
+
+	return 0;
+}
+
 static __init int kho_init(void)
 {
 	const void *fdt = kho_get_fdt();
@@ -1357,6 +1402,10 @@ static __init int kho_init(void)
 	if (err)
 		goto err_free_fdt;
 
+	err = kho_history_init();
+	if (err)
+		pr_warn("failed to initialize history subtree: %d\n", err);
+
 	if (fdt) {
 		kho_in_debugfs_init(&kho_in.dbg, fdt);
 		return 0;
@@ -1425,6 +1474,61 @@ static void __init kho_release_scratch(void)
 	}
 }
 
+static int __init kho_print_previous_kernel(const void *fdt)
+{
+	const char *prev_release;
+	const u64 *history_phys;
+	const u32 *count_ptr;
+	void *history_fdt;
+	int history_node;
+	int len;
+	int ret;
+
+	/* Find the history subtree reference in root FDT */
+	history_node = fdt_subnode_offset(fdt, 0, KHO_HISTORY_NODE_NAME);
+	if (history_node < 0)
+		/* This is fine, previous kernel didn't export history */
+		return -ENOENT;
+
+	/* Get the physical address of the history FDT */
+	history_phys = fdt_getprop(fdt, history_node, KHO_FDT_SUB_TREE_PROP_NAME, &len);
+	if (!history_phys || len != sizeof(*history_phys))
+		return -ENOENT;
+
+	/* Map the history FDT */
+	history_fdt = early_memremap(*history_phys, PAGE_SIZE);
+	if (!history_fdt)
+		return -ENOMEM;
+
+	prev_release = fdt_getprop(history_fdt, 0, KHO_PROP_PREVIOUS_RELEASE, &len);
+	if (!prev_release || len <= 0) {
+		ret = -ENOENT;
+		goto exit;
+	}
+
+	/* Read the kexec count from the previous kernel */
+	count_ptr = fdt_getprop(history_fdt, 0, KHO_PROP_KEXEC_COUNT, &len);
+	if (WARN_ON(!count_ptr || len != sizeof(u32))) {
+		ret = -ENOENT;
+		goto exit;
+	}
+	/*
+	 * This populate the kernel structure that will be persisted during
+	 * kernel life time, and the fdt will be unmapped
+	 */
+	kho_in.kexec_count = *count_ptr;
+
+	strscpy(kho_in.previous_release, prev_release,
+		sizeof(kho_in.previous_release));
+	pr_info("exec from: %s (count %u)\n", kho_in.previous_release,
+					      kho_in.kexec_count);
+
+	ret = 0;
+exit:
+	early_memunmap(history_fdt, PAGE_SIZE);
+	return ret;
+}
+
 void __init kho_memory_init(void)
 {
 	if (kho_in.mem_map_phys) {
@@ -1513,7 +1617,10 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
 	kho_in.scratch_phys = scratch_phys;
 	kho_in.mem_map_phys = mem_map_phys;
 	kho_scratch_cnt = scratch_cnt;
-	pr_info("found kexec handover data.\n");
+
+	if (kho_print_previous_kernel(fdt))
+		/* Fallback message when previous kernel info unavailable */
+		pr_info("found kexec handover data.\n");
 
 out:
 	if (fdt)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/2] kho: history: track previous kernel version
  2026-01-16 15:50     ` Breno Leitao
@ 2026-01-20 15:40       ` Pratyush Yadav
  2026-01-20 18:58         ` Mike Rapoport
  0 siblings, 1 reply; 9+ messages in thread
From: Pratyush Yadav @ 2026-01-20 15:40 UTC (permalink / raw)
  To: Breno Leitao
  Cc: Pratyush Yadav, Alexander Graf, Mike Rapoport, Pasha Tatashin,
	linux-kernel, kexec, linux-mm, usamaarif642, rmikey, clm, riel,
	kernel-team

On Fri, Jan 16 2026, Breno Leitao wrote:

> Hello Pratyush,
>
> On Wed, Jan 14, 2026 at 07:19:11PM +0000, Pratyush Yadav wrote:
>> On Thu, Jan 08 2026, Breno Leitao wrote:
>> 
>> > Store and display the kernel version from the previous kexec boot.
>> >
>> > The current kernel's release string is saved to the "previous-release"
>> > property in the KHO FDT 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.
>> 
>> The KHO FDT is ABI. So you should be bumping the version number when you
>> make changes to it.
>> 
>> But honestly, adding this "optional" stuff to the core KHO ABI makes me
>> uneasy. I say optional since it is not needed for the main functionality
>> of KHO. Making this a part of the ABI increases the surface area we
>> have. The more things we stuff in the ABI, the more inflexible it gets
>> over time.
>> 
>> Any changes to the KHO ABI means all consumers also need a version bump.
>> This includes LUO and all its users for example. So I would really like
>> to avoid adding optional things in core KHO FDT.
>> 
>> The easy fix is to add a separate subtree for the optional metadata. You
>> would still need to create an ABI for the data format, but being
>> independent of core KHO, it will make it more flexible and easier to
>> change in the future. You can keep the code in kexec_handover.c.
>
> Thanks for the feedback and guidance!
>
> I was able to hack this a bit and I came up with something like the
> follow. Is this what you have in mind?

Thanks! Yes, this looks much better. Some comments below.

>
> Author: Breno Leitao <leitao@debian.org>
> Date:   Fri Jan 16 06:42:56 2026 -0800
>
>     kho: history: track previous kernel version and kexec count
>     
>     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 output:
>         [    0.000000] KHO: exec from: 6.19.0-rc4-next-20260107 (count 1)
>     
>     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.
>     
>     Implementation
>     ==============
>     
>     The history metadata is stored in a separate FDT subtree registered via
>     kho_add_subtree(), rather than being embedded directly in the root KHO
>     FDT. This design choice:
>     
>      - Keeps the core KHO ABI minimal and stable
>      - Allows the history format to evolve independently
>      - Avoids requiring version bumps for all KHO consumers (LUO, etc.)
>        when the history format changes
>     
>     The history subtree uses its own compatible string "kho-history-v1" and
>     contains two properties:
>      - previous-release: The kernel version that initiated the kexec
>      - kexec-count: Number of kexec boots since last cold boot
>     
>     On cold boot, kexec-count starts at 0 and increments with each kexec.
>     The count helps identify issues that only manifest after multiple
>     consecutive kexec reboots.

Very well written changelog!

>     
>     Signed-off-by: Breno Leitao <leitao@debian.org>
>
> diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
> index 285eda8a36e4..da19d6029815 100644
> --- a/include/linux/kho/abi/kexec_handover.h
> +++ b/include/linux/kho/abi/kexec_handover.h
> @@ -84,6 +84,29 @@
>  /* The FDT property for sub-FDTs. */
>  #define KHO_FDT_SUB_TREE_PROP_NAME "fdt"
>  
> +/*
> + * The "history" subtree stores optional metadata about the kexec chain.
> + * It is registered as a separate FDT via kho_add_subtree(), keeping it
> + * independent from the core KHO ABI. This allows the history format to
> + * evolve without affecting other KHO consumers.
> + *
> + * The history FDT structure:

I don't have a strong preference here, but you don't _have_ to use FDT.
For example, with memfd, we moved from FDT to plain C structs during the
evolution of the patchset. Main reason is that FDT programming is a bit
annoying. C structs make many things much easier. For example, you can
always assume a certain property always exists and is of a given size,
and you don't have to validate every single property you read.

Anyway, I don't mind either way.

> + *
> + *   / {
> + *       compatible = "kho-history-v1";
> + *       previous-release = "6.x.y-...";
> + *       kexec-count = <N>;
> + *   };
> + */
> +#define KHO_HISTORY_NODE_NAME "history"

Do we want to call it history? Perhaps "kexec-metadata" instead? So we
could use it for other misc information if needed later.

Mike/Pasha, any thoughts?

> +#define KHO_HISTORY_COMPATIBLE "kho-history-v1"
> +
> +/* The FDT property to track previous kernel (kexec caller) */
> +#define KHO_PROP_PREVIOUS_RELEASE "previous-release"
> +
> +/* The FDT property to track number of kexec counts so far */
> +#define KHO_PROP_KEXEC_COUNT "kexec-count"
> +
>  /**
>   * DOC: Kexec Handover ABI for vmalloc Preservation
>   *
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 3cf2dc6840c9..fd22b0947587 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -15,6 +15,7 @@
>  #include <linux/count_zeros.h>
>  #include <linux/kexec.h>
>  #include <linux/kexec_handover.h>
> +#include <linux/utsname.h>
>  #include <linux/kho/abi/kexec_handover.h>
>  #include <linux/libfdt.h>
>  #include <linux/list.h>
> @@ -1246,6 +1247,8 @@ struct kho_in {
>  	phys_addr_t fdt_phys;
>  	phys_addr_t scratch_phys;
>  	phys_addr_t mem_map_phys;
> +	char previous_release[__NEW_UTS_LEN + 1];
> +	u32 kexec_count;
>  	struct kho_debugfs dbg;
>  };
>  
> @@ -1331,6 +1334,48 @@ static __init int kho_out_fdt_setup(void)
>  	return err;
>  }
>  
> +/*
> + * Create a separate FDT subtree for optional history metadata.
> + * This keeps the core KHO ABI minimal and allows the history format
> + * to evolve independently.
> + */
> +static __init int kho_history_init(void)
> +{
> +	u32 kexec_count;
> +	void *fdt;
> +	int err;
> +
> +	fdt = kho_alloc_preserve(PAGE_SIZE);
> +	if (IS_ERR(fdt))
> +		return PTR_ERR(fdt);
> +
> +	err = fdt_create(fdt, PAGE_SIZE);
> +	err |= fdt_finish_reservemap(fdt);
> +	err |= fdt_begin_node(fdt, "");
> +	err |= fdt_property_string(fdt, "compatible", KHO_HISTORY_COMPATIBLE);
> +	err |= fdt_property_string(fdt, KHO_PROP_PREVIOUS_RELEASE,
> +				   init_uts_ns.name.release);
> +	/* kho_in.kexec_count is set to 0 on cold boot */
> +	kexec_count = kho_in.kexec_count + 1;
> +	err |= fdt_property(fdt, KHO_PROP_KEXEC_COUNT, &kexec_count,
> +			    sizeof(kexec_count));
> +	err |= fdt_end_node(fdt);
> +	err |= fdt_finish(fdt);
> +
> +	if (err) {
> +		kho_unpreserve_free(fdt);
> +		return err;
> +	}
> +
> +	err = kho_add_subtree(KHO_HISTORY_NODE_NAME, fdt);
> +	if (err) {
> +		kho_unpreserve_free(fdt);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
>  static __init int kho_init(void)
>  {
>  	const void *fdt = kho_get_fdt();
> @@ -1357,6 +1402,10 @@ static __init int kho_init(void)
>  	if (err)
>  		goto err_free_fdt;
>  
> +	err = kho_history_init();
> +	if (err)
> +		pr_warn("failed to initialize history subtree: %d\n", err);
> +
>  	if (fdt) {
>  		kho_in_debugfs_init(&kho_in.dbg, fdt);
>  		return 0;
> @@ -1425,6 +1474,61 @@ static void __init kho_release_scratch(void)
>  	}
>  }
>  
> +static int __init kho_print_previous_kernel(const void *fdt)
> +{
> +	const char *prev_release;
> +	const u64 *history_phys;
> +	const u32 *count_ptr;
> +	void *history_fdt;
> +	int history_node;
> +	int len;
> +	int ret;
> +
> +	/* Find the history subtree reference in root FDT */
> +	history_node = fdt_subnode_offset(fdt, 0, KHO_HISTORY_NODE_NAME);
> +	if (history_node < 0)
> +		/* This is fine, previous kernel didn't export history */
> +		return -ENOENT;
> +
> +	/* Get the physical address of the history FDT */
> +	history_phys = fdt_getprop(fdt, history_node, KHO_FDT_SUB_TREE_PROP_NAME, &len);
> +	if (!history_phys || len != sizeof(*history_phys))
> +		return -ENOENT;
> +
> +	/* Map the history FDT */
> +	history_fdt = early_memremap(*history_phys, PAGE_SIZE);
> +	if (!history_fdt)
> +		return -ENOMEM;

There is no real reason to call this so early in boot. You can call it
from an initcall or from kho_init(). Then you won't need the
early_memremap(). And you should also not poke into the KHO FDT
directly. Use kho_retrieve_subtree() instead.

> +
> +	prev_release = fdt_getprop(history_fdt, 0, KHO_PROP_PREVIOUS_RELEASE, &len);
> +	if (!prev_release || len <= 0) {
> +		ret = -ENOENT;
> +		goto exit;
> +	}
> +
> +	/* Read the kexec count from the previous kernel */
> +	count_ptr = fdt_getprop(history_fdt, 0, KHO_PROP_KEXEC_COUNT, &len);
> +	if (WARN_ON(!count_ptr || len != sizeof(u32))) {
> +		ret = -ENOENT;
> +		goto exit;
> +	}
> +	/*
> +	 * This populate the kernel structure that will be persisted during
> +	 * kernel life time, and the fdt will be unmapped
> +	 */
> +	kho_in.kexec_count = *count_ptr;

This is another annoying thing about FDT. Alignment is only guaranteed
at 32 bits. So you should use get_unaligned() AFAIK.

> +
> +	strscpy(kho_in.previous_release, prev_release,
> +		sizeof(kho_in.previous_release));
> +	pr_info("exec from: %s (count %u)\n", kho_in.previous_release,
> +					      kho_in.kexec_count);
> +
> +	ret = 0;
> +exit:
> +	early_memunmap(history_fdt, PAGE_SIZE);
> +	return ret;
> +}
> +
>  void __init kho_memory_init(void)
>  {
>  	if (kho_in.mem_map_phys) {
> @@ -1513,7 +1617,10 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
>  	kho_in.scratch_phys = scratch_phys;
>  	kho_in.mem_map_phys = mem_map_phys;
>  	kho_scratch_cnt = scratch_cnt;
> -	pr_info("found kexec handover data.\n");
> +
> +	if (kho_print_previous_kernel(fdt))
> +		/* Fallback message when previous kernel info unavailable */
> +		pr_info("found kexec handover data.\n");
>  
>  out:
>  	if (fdt)

-- 
Regards,
Pratyush Yadav


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/2] kho: history: track previous kernel version
  2026-01-20 15:40       ` Pratyush Yadav
@ 2026-01-20 18:58         ` Mike Rapoport
  0 siblings, 0 replies; 9+ messages in thread
From: Mike Rapoport @ 2026-01-20 18:58 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Breno Leitao, Alexander Graf, Pasha Tatashin, linux-kernel,
	kexec, linux-mm, usamaarif642, rmikey, clm, riel, kernel-team

Hi,

On Tue, Jan 20, 2026 at 03:40:12PM +0000, Pratyush Yadav wrote:
> On Fri, Jan 16 2026, Breno Leitao wrote:
> >     
> >     On cold boot, kexec-count starts at 0 and increments with each kexec.
> >     The count helps identify issues that only manifest after multiple
> >     consecutive kexec reboots.
> 
> Very well written changelog!

@Breno, the submission would be perfect if you'd start a new thread rather
than reply to v1 ;-)
 
> > +/*
> > + * The "history" subtree stores optional metadata about the kexec chain.
> > + * It is registered as a separate FDT via kho_add_subtree(), keeping it
> > + * independent from the core KHO ABI. This allows the history format to
> > + * evolve without affecting other KHO consumers.
> > + *
> > + * The history FDT structure:
> 
> I don't have a strong preference here, but you don't _have_ to use FDT.
> For example, with memfd, we moved from FDT to plain C structs during the
> evolution of the patchset. Main reason is that FDT programming is a bit
> annoying. C structs make many things much easier. For example, you can
> always assume a certain property always exists and is of a given size,
> and you don't have to validate every single property you read.
> 
> Anyway, I don't mind either way.

Yeah, I agree that a plain C structure with an array of chars and u64 will
make things simpler.

> > + *
> > + *   / {
> > + *       compatible = "kho-history-v1";
> > + *       previous-release = "6.x.y-...";
> > + *       kexec-count = <N>;
> > + *   };
> > + */
> > +#define KHO_HISTORY_NODE_NAME "history"
> 
> Do we want to call it history? Perhaps "kexec-metadata" instead? So we
> could use it for other misc information if needed later.
> 
> Mike/Pasha, any thoughts?

I like kexec-metadata.

-- 
Sincerely yours,
Mike.


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-01-20 18:58 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-08 16:40 [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count Breno Leitao
2026-01-08 16:40 ` [PATCH v3 1/2] kho: history: track previous kernel version Breno Leitao
2026-01-14 19:19   ` Pratyush Yadav
2026-01-16 15:50     ` Breno Leitao
2026-01-20 15:40       ` Pratyush Yadav
2026-01-20 18:58         ` Mike Rapoport
2026-01-08 16:40 ` [PATCH v3 2/2] kho: history: track kexec boot counter Breno Leitao
2026-01-09  1:45 ` [PATCH v3 0/2] kho: history: track previous kernel version and kexec boot count SeongJae Park
2026-01-09 11:00   ` Breno Leitao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox