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 Suggested-by: Pasha Tatashin --- 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