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 <[email protected]> Suggested-by: Pasha Tatashin <[email protected]> --- 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
