From nobody Tue Jan 27 00:10:29 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D9DAF2D73A8 for ; Mon, 26 Jan 2026 16:08:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769443692; cv=none; b=h8bROsBusaoLDrIPIwe6rt6eNuH5dQ2kE8Bt7n4l80erD98O7snBxqcu8+4zrR/qbfqWjRUKztSkjqBSObxMamyXfUkMEnnDx6ARJ3r0Y16IHOtUrufs6H9y97d/GsUsdihiXVXmOeELpYdNZ9h0RkhbNrzBkemVhf9qDNB0DOk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769443692; c=relaxed/simple; bh=RkXHBAO2rWRvBZyOTvq+Rsg40/Yaxfq39GNC5H2Vd/4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LEIHi7cGaTRxPvWMZ1NvL3gwBvuVkU0O7+Ibuak/7YFE7Rs3+0yEdpICrALlPmzr1R+mUlkonligxwVwzxzBOZxaCTbFyIyBCY8oTzgAgQPYx9X20MdQcmciIlTksAWFytdfC9DOMMJyCtEY5O4dFZI0oHO931x6fABt7R6w9Ys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=debian.org; spf=none smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=f87Wmtga; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="f87Wmtga" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=rELLbr3n1mvaAH8Jb6foKISzoRm/h7jGZezo/WIwGx8=; b=f87WmtgafJ0nCAUDS9JncRQhly cVhSmx5ZJ1zv07ks7ALi3SmIkaE7y3Uq+MCrYJBD6irqIiDQsqjQjYCVptBxjcgguaPyY0NF4MSys FIoY3zLhGiWWz6kwwakMPw7jGock4KmUjaX2ewEqqxJjPYLQKIp7QAtFw9tUJYkegYuPF67QC4pMf L3mahJc/rfFXQRpu0+l8wCrfsFyGfg5lTg7UxoeryoSsaGdaF8nnMhE9q5/dBNyby+ZU045T7k0IS ZozTEA0fqau9HTsATYbncc8Y8Qnvt1erqxTOB3YTcGtEfSKGpkrmQIX3/xnoQX+sHB2N1lstskr5r fn+T/VJw==; Received: from authenticated user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2) (envelope-from ) id 1vkP8D-00GI7Y-0t; Mon, 26 Jan 2026 16:08:01 +0000 From: Breno Leitao Date: Mon, 26 Jan 2026 08:07:25 -0800 Subject: [PATCH v5 3/4] kho: kexec-metadata: track previous kernel chain Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260126-kho-v5-3-7cd0f69ab204@debian.org> References: <20260126-kho-v5-0-7cd0f69ab204@debian.org> In-Reply-To: <20260126-kho-v5-0-7cd0f69ab204@debian.org> To: Alexander Graf , Mike Rapoport , Pasha Tatashin , Pratyush Yadav Cc: linux-kernel@vger.kernel.org, kexec@lists.infradead.org, linux-mm@kvack.org, usamaarif642@gmail.com, rmikey@meta.com, clm@fb.com, riel@surriel.com, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=openpgp-sha256; l=6745; i=leitao@debian.org; h=from:subject:message-id; bh=RkXHBAO2rWRvBZyOTvq+Rsg40/Yaxfq39GNC5H2Vd/4=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpd5FNIOtcvaP+mCzRl5ihLA/uECxANnIMeuoIs jaAi/aC+dWJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaXeRTQAKCRA1o5Of/Hh3 bWkwD/9l0X8jRNd7k1f9D4OM79/4D9vU14dyIwNlQ7/N8I6GGW2nZTR9d6X6XO1yDSoOTsZsGZ9 TboWX6xqPcIa1VArLdsBJssMemFV0LycOlUnvxGYjA/IkDap1V5hX36tW6A/Ho2VwZ/jgu+Ljl3 Lfo6MKMMuhSN9XgDFQilN03iQlpJ5cuWULi7G1xiDp7zlah8Lbu40s+Lb2ON5oWyUeZ0DlB2nan BAy86Dxz4d6jVuUEdPVc29dJkc2prYctqky680xfm+UviFyUQ+pnixD7NxN2WdhWsr33yOFm8Ls kX/itqBS/sk+bcRwvaKt6uT3IIEquKC25y938o39tqxQ6SO6aS54TqZHgx7JNvtfI1quQSGy6z9 mN8E3bWUwHMhuUndFYp0tUHMf8a6awq9bOv42jfmBpPHQD3wLcY4XRJ5599zwxjED9uBFflRlrs i9f0s/ZMbK+DFkWYa17RdBuLs8UOepoptAQfUQq3WKvLPmw+ei53aVQhzNhHsVhHRt7CipfyYMf 5gW8INgMjkrpGWHaX1SAF43sQuQvue6bAhD0axh/RoRI1YlqpW6ccItEn3RPbWDSQnQ/6N4lr6t LSNFL4zGQkI9/I9+t3sZCZg7AGf3g+20W1DnUkUvNDiyhQQy/wbkzyX0SkTjq5Gdl3JTzNgoVan 9AxGTm/fhR2oxhg== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 the following commits: * eb2266312507 ("x86/boot: Fix page table access in 5-level to 4-level pag= ing transition") * 77d48d39e991 ("efistub/tpm: Use ACPI reclaim memory for event log to avo= id 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D The kexec metadata is stored as a plain C struct (struct kho_kexec_metadata) rather than FDT format, for simplicity and direct field access. It is registered via kho_add_subtree() as a separate subtree, keeping it independent from the core KHO ABI. This design choice: - Keeps the core KHO ABI minimal and stable - Allows the metadata format to evolve independently - Avoids requiring version bumps for all KHO consumers (LUO, etc.) when the metadata format changes The struct kho_metadata contains two fields: - 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 Acked-by: SeongJae Park --- include/linux/kho/abi/kexec_handover.h | 31 ++++++++++++++ kernel/liveupdate/kexec_handover.c | 74 ++++++++++++++++++++++++++++++= ++++ 2 files changed, 105 insertions(+) diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi= /kexec_handover.h index 2201a0d2c159a..1f017756e9991 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -11,6 +11,7 @@ #define _LINUX_KHO_ABI_KEXEC_HANDOVER_H =20 #include +#include =20 /** * DOC: Kexec Handover ABI @@ -84,6 +85,36 @@ /* The FDT property for sub-FDTs. */ #define KHO_FDT_SUB_TREE_PROP_NAME "fdt" =20 +/** + * DOC: Kexec Metadata ABI + * + * The "kexec-metadata" subtree stores optional metadata about the kexec c= hain. + * It is registered via kho_add_subtree(), keeping it independent from the= core + * KHO ABI. This allows the metadata format to evolve without affecting ot= her + * KHO consumers. + * + * The metadata is stored as a plain C struct rather than FDT format for + * simplicity and direct field access. + */ + +/** + * struct kho_kexec_metadata - Kexec metadata passed between kernels + * @previous_release: Kernel version string that initiated the kexec + * @kexec_count: Number of kexec boots since last cold boot + * + * This structure is preserved across kexec and allows the new kernel to + * identify which kernel it was booted from and how many kexec reboots + * have occurred. + * + * __NEW_UTS_LEN is part of UAPI, so it safe to use it in here. + */ +struct kho_kexec_metadata { + char previous_release[__NEW_UTS_LEN + 1]; + u32 kexec_count; +} __packed; + +#define KHO_METADATA_NODE_NAME "kexec-metadata" + /** * DOC: Kexec Handover ABI for vmalloc Preservation * diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index b1f3222a0052a..8250f318c4f69 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1267,6 +1268,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; }; =20 @@ -1352,6 +1355,73 @@ static __init int kho_out_fdt_setup(void) return err; } =20 +static void __init kho_in_kexec_metadata(void) +{ + struct kho_kexec_metadata *metadata; + phys_addr_t metadata_phys; + int err; + + err =3D kho_retrieve_subtree(KHO_METADATA_NODE_NAME, &metadata_phys); + if (err) + /* This is fine, previous kernel didn't export metadata */ + return; + metadata =3D phys_to_virt(metadata_phys); + + /* + * Copy data to the kernel structure that will persist during + * kernel lifetime. + */ + kho_in.kexec_count =3D metadata->kexec_count; + strscpy(kho_in.previous_release, metadata->previous_release, + sizeof(kho_in.previous_release)); + + pr_info("exec from: %s (count %u)\n", kho_in.previous_release, + kho_in.kexec_count); +} + +/* + * Create kexec metadata to pass kernel version and boot count to the + * next kernel. This keeps the core KHO ABI minimal and allows the + * metadata format to evolve independently. + */ +static __init int kho_out_kexec_metadata(void) +{ + struct kho_kexec_metadata *metadata; + int err; + + metadata =3D kho_alloc_preserve(sizeof(*metadata)); + if (IS_ERR(metadata)) + return PTR_ERR(metadata); + + strscpy(metadata->previous_release, init_uts_ns.name.release, + sizeof(metadata->previous_release)); + /* kho_in.kexec_count is set to 0 on cold boot */ + metadata->kexec_count =3D kho_in.kexec_count + 1; + + err =3D kho_add_subtree(KHO_METADATA_NODE_NAME, metadata, + sizeof(*metadata)); + if (err) + kho_unpreserve_free(metadata); + + return err; +} + +static int __init kho_kexec_metadata_init(const void *fdt) +{ + int err; + + if (fdt) + kho_in_kexec_metadata(); + + /* Populate kexec metadata for the possible next kexec */ + err =3D kho_out_kexec_metadata(); + if (err) + pr_warn("failed to initialize kexec-metadata subtree: %d\n", + err); + + return err; +} + static __init int kho_init(void) { const void *fdt =3D kho_get_fdt(); @@ -1378,6 +1448,10 @@ static __init int kho_init(void) if (err) goto err_free_fdt; =20 + err =3D kho_kexec_metadata_init(fdt); + if (err) + goto err_free_fdt; + if (fdt) { kho_in_debugfs_init(&kho_in.dbg, fdt); return 0; --=20 2.47.3