From nobody Sat Feb 7 08:13:50 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 6D80C3101B6 for ; Tue, 27 Jan 2026 14:38:28 +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=1769524710; cv=none; b=YBlIhUA0yjxqnQnv4uB3zu1YwVpzHLvGijHc9WpudMKT1HI9MefVYn5e2S2PSHzcVemYcpZ42DiyQsFFsRbFu6kRdfaVVPTPMBH1NFwHva6kZa1Kf+vP6MsD9vU0ed/IHC65wq/YcUaP0V2ZqKih/Coi0yaAU2i8c3oXgCbXt+w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769524710; c=relaxed/simple; bh=nk3yyun6LiJx2hB1RVium4TTK98kuuyYqMmz5Tx1hAc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Q7o1jbE0D3Htk3FD5kFg6Iu5U3n91S45JfOh43azjonO8L6LD6SYjklK7/W/g5csa8qNpmVAL9bhb2RaRb6YDNs16STw7tVnYhrFtWQ29Wo7bNq8/gYFLTkOG0r0QZQTge6RuQ7T9zgDQkuRMTfdZKwf5SzNYNr3/lpWOzcEyG0= 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=iX4++nwm; 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="iX4++nwm" 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=ppkYoCuCIwbG08Yog1w1PKZoiZaGtf8kK0Yf9zB3YpY=; b=iX4++nwmPyyfA9UIOdjH2mSyHF Jw2TGQpc8CK0TuxKaivM6Ut1YtVbgkbzz3i3OipDWGK/y+dAKh7mNRsBXJ8zervKp/6Lvwvttv7ua gpLVJIg7nxpG1pYMkk5BS6CP2UkJy29go0G0f7Z/bMW9azK6R/HIabSTttfgVNQgOlY5y73+1yX/S IW8vnoYDW55ogz1sEiRiLP1WCMgYx1bDxh9nhVi1OWH86QDcakpQL3RlqLERmnzp3inqkuP+A1X83 kiSjwDCgJsXldxyoxN6lI3Y5KBYRQnMYjiaAOdU7Q7gsuFynTlFee3TrEixgHNAm3IcI5tzfszHLU EOU/w3lw==; 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 1vkkD3-00H3b9-MS; Tue, 27 Jan 2026 14:38:26 +0000 From: Breno Leitao Date: Tue, 27 Jan 2026 06:37:36 -0800 Subject: [PATCH v6 1/4] kho: add size parameter to kho_add_subtree() 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: <20260127-kho-v6-1-56f9396681c2@debian.org> References: <20260127-kho-v6-0-56f9396681c2@debian.org> In-Reply-To: <20260127-kho-v6-0-56f9396681c2@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-f4305 X-Developer-Signature: v=1; a=openpgp-sha256; l=9092; i=leitao@debian.org; h=from:subject:message-id; bh=nk3yyun6LiJx2hB1RVium4TTK98kuuyYqMmz5Tx1hAc=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpeM3Wnk5kJhqw21vjInix4DA5gZacK/0QQ2Ckq LMAStNlioyJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaXjN1gAKCRA1o5Of/Hh3 bTdBD/9jXaXJvc23pY8B3+/fv4tKZqlbkoijG6RR/T1DyACmP3943c/gwoIZTcJCUTl5/bup/vE aBSptIjtYz4+FZGzu37omfjUU6frY+vS6gE8Nwx97zMuxAA1jfW6fAvLvDagyYgfzSUcV/6g0X7 5RxDmj0OVaiq08orWHyfYZUY61MEy/o76114FYj3qyDbUm6L+sdwyRnEP2AqXQeCSMfPw2DWMda YDxLQLgAnF/icmdLKuXGXk99fZuVG30yDhaLw6V8tc4IRBVLSIwX9Z9NGOXSELi2Ke7Zl49DoWY 6lKFAl2GOuJHC8DpEtUdRNMpJhNxV9E9/Ik+535Ii3rnpoUEGE4lhic2VVsE5rCvJ0tBMh/Cn1a DP9Thcm1qx9U5U5Nkf9jNam0u4NcWSG4t0WAwImyzG0HiGfv9NEuORY00yPIKWzcflg0+rkcsq+ E8A3/O56XS63mqGh1LrEOyz4ALG+4uFcZ3vPMMFQBNbTJZJNLFGlsH5yjqS58hZfTrwckS4NsNr tulrzon/DE7epcWHop6o3YwRgUK9dHG7/erTuPmxUQ1hUGm1RLGUG7YtCpCNBGXXAlYiVaADzQv PK60F5iE4CTZGqaO03nweNEwHqhF7VdYF+Led+hvM0XEZLUfifHmAQwXhOEUxncXOubJY7J3ffH 1LFeYfAkNugoiTw== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao kho_add_subtree() assumes the fdt argument is always an FDT and calls fdt_totalsize() on it in the debugfs code path. This assumption will break if a caller passes arbitrary data instead of an FDT. When CONFIG_KEXEC_HANDOVER_DEBUGFS is enabled, kho_debugfs_fdt_add() calls __kho_debugfs_fdt_add(), which executes: f->wrapper.size =3D fdt_totalsize(fdt); Fix this by adding an explicit size parameter to kho_add_subtree() so callers specify the blob size. This allows subtrees to contain arbitrary data formats, not just FDTs. Update all callers: - memblock.c: use fdt_totalsize(fdt) - luo_core.c: use fdt_totalsize(fdt_out) - test_kho.c: use fdt_totalsize() - kexec_handover.c (root fdt): use fdt_totalsize(kho_out.fdt) Also update kho_in_debugfs_init() to compute sizes using fdt_totalsize() for the root and sub-FDTs it processes, since these are known to be actual FDT blobs. Suggested-by: Pratyush Yadav Reviewed-by: Mike Rapoport (Microsoft) Signed-off-by: Breno Leitao Acked-by: SeongJae Park --- include/linux/kexec_handover.h | 4 ++-- kernel/liveupdate/kexec_handover.c | 8 +++++--- kernel/liveupdate/kexec_handover_debugfs.c | 15 +++++++++------ kernel/liveupdate/kexec_handover_internal.h | 5 +++-- kernel/liveupdate/luo_core.c | 3 ++- lib/test_kho.c | 3 ++- mm/memblock.c | 2 +- 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index ac4129d1d7416..abb1d324f42d0 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -32,7 +32,7 @@ void kho_restore_free(void *mem); struct folio *kho_restore_folio(phys_addr_t phys); struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages); void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); -int kho_add_subtree(const char *name, void *fdt); +int kho_add_subtree(const char *name, void *fdt, size_t size); void kho_remove_subtree(void *fdt); int kho_retrieve_subtree(const char *name, phys_addr_t *phys); =20 @@ -97,7 +97,7 @@ static inline void *kho_restore_vmalloc(const struct kho_= vmalloc *preservation) return NULL; } =20 -static inline int kho_add_subtree(const char *name, void *fdt) +static inline int kho_add_subtree(const char *name, void *fdt, size_t size) { return -EOPNOTSUPP; } diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index 8a2b2a7e50fc6..ad2da9e4e6a04 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -726,6 +726,7 @@ static void __init kho_reserve_scratch(void) * kho_add_subtree - record the physical address of a sub FDT in KHO root = tree. * @name: name of the sub tree. * @fdt: the sub tree blob. + * @size: size of the blob in bytes. * * Creates a new child node named @name in KHO root FDT and records * the physical address of @fdt. The pages of @fdt must also be preserved @@ -737,7 +738,7 @@ static void __init kho_reserve_scratch(void) * * Return: 0 on success, error code on failure */ -int kho_add_subtree(const char *name, void *fdt) +int kho_add_subtree(const char *name, void *fdt, size_t size) { phys_addr_t phys =3D virt_to_phys(fdt); void *root_fdt =3D kho_out.fdt; @@ -762,7 +763,7 @@ int kho_add_subtree(const char *name, void *fdt) if (err < 0) goto out_pack; =20 - WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, false)); + WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, size, false)); =20 out_pack: fdt_pack(root_fdt); @@ -1402,7 +1403,8 @@ static __init int kho_init(void) } =20 WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, "fdt", - kho_out.fdt, true)); + kho_out.fdt, + fdt_totalsize(kho_out.fdt), true)); =20 return 0; =20 diff --git a/kernel/liveupdate/kexec_handover_debugfs.c b/kernel/liveupdate= /kexec_handover_debugfs.c index 2abbf62ba9424..64970c88c483c 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -24,7 +24,7 @@ struct fdt_debugfs { }; =20 static int __kho_debugfs_fdt_add(struct list_head *list, struct dentry *di= r, - const char *name, const void *fdt) + const char *name, const void *fdt, size_t size) { struct fdt_debugfs *f; struct dentry *file; @@ -34,7 +34,7 @@ static int __kho_debugfs_fdt_add(struct list_head *list, = struct dentry *dir, return -ENOMEM; =20 f->wrapper.data =3D (void *)fdt; - f->wrapper.size =3D fdt_totalsize(fdt); + f->wrapper.size =3D size; =20 file =3D debugfs_create_blob(name, 0400, dir, &f->wrapper); if (IS_ERR(file)) { @@ -49,7 +49,7 @@ static int __kho_debugfs_fdt_add(struct list_head *list, = struct dentry *dir, } =20 int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, - const void *fdt, bool root) + const void *fdt, size_t size, bool root) { struct dentry *dir; =20 @@ -58,7 +58,7 @@ int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const ch= ar *name, else dir =3D dbg->sub_fdt_dir; =20 - return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt); + return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt, size); } =20 void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt) @@ -130,7 +130,8 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg= , const void *fdt) goto err_rmdir; } =20 - err =3D __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt); + err =3D __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt, + fdt_totalsize(fdt)); if (err) goto err_rmdir; =20 @@ -138,6 +139,7 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg= , const void *fdt) int len =3D 0; const char *name =3D fdt_get_name(fdt, child, NULL); const u64 *fdt_phys; + void *sub_fdt; =20 fdt_phys =3D fdt_getprop(fdt, child, "fdt", &len); if (!fdt_phys) @@ -147,8 +149,9 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg= , const void *fdt) name, len); continue; } + sub_fdt =3D phys_to_virt(*fdt_phys); err =3D __kho_debugfs_fdt_add(&dbg->fdt_list, sub_fdt_dir, name, - phys_to_virt(*fdt_phys)); + sub_fdt, fdt_totalsize(sub_fdt)); if (err) { pr_warn("failed to add fdt %s to debugfs: %pe\n", name, ERR_PTR(err)); diff --git a/kernel/liveupdate/kexec_handover_internal.h b/kernel/liveupdat= e/kexec_handover_internal.h index 0202c85ad14f9..a51f97f0fa0e6 100644 --- a/kernel/liveupdate/kexec_handover_internal.h +++ b/kernel/liveupdate/kexec_handover_internal.h @@ -30,7 +30,7 @@ int kho_debugfs_init(void); void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt); int kho_out_debugfs_init(struct kho_debugfs *dbg); int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, - const void *fdt, bool root); + const void *fdt, size_t size, bool root); void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt); #else static inline int kho_debugfs_init(void) { return 0; } @@ -38,7 +38,8 @@ static inline void kho_in_debugfs_init(struct kho_debugfs= *dbg, const void *fdt) { } static inline int kho_out_debugfs_init(struct kho_debugfs *dbg) { return 0= ; } static inline int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char = *name, - const void *fdt, bool root) { return 0; } + const void *fdt, size_t size, + bool root) { return 0; } static inline void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt) { } #endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */ diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index dda7bb57d421c..a4721813dd994 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -172,7 +172,8 @@ static int __init luo_fdt_setup(void) if (err) goto exit_free; =20 - err =3D kho_add_subtree(LUO_FDT_KHO_ENTRY_NAME, fdt_out); + err =3D kho_add_subtree(LUO_FDT_KHO_ENTRY_NAME, fdt_out, + fdt_totalsize(fdt_out)); if (err) goto exit_free; luo_global.fdt_out =3D fdt_out; diff --git a/lib/test_kho.c b/lib/test_kho.c index a20fafaf9846b..f2d7d9108cf41 100644 --- a/lib/test_kho.c +++ b/lib/test_kho.c @@ -143,7 +143,8 @@ static int kho_test_preserve(struct kho_test_state *sta= te) if (err) goto err_unpreserve_data; =20 - err =3D kho_add_subtree(KHO_TEST_FDT, folio_address(state->fdt)); + err =3D kho_add_subtree(KHO_TEST_FDT, folio_address(state->fdt), + fdt_totalsize(folio_address(state->fdt))); if (err) goto err_unpreserve_data; =20 diff --git a/mm/memblock.c b/mm/memblock.c index b3ddfdec7a809..91d4162eec63f 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -2510,7 +2510,7 @@ static int __init prepare_kho_fdt(void) if (err) goto err_unpreserve_fdt; =20 - err =3D kho_add_subtree(MEMBLOCK_KHO_FDT, fdt); + err =3D kho_add_subtree(MEMBLOCK_KHO_FDT, fdt, fdt_totalsize(fdt)); if (err) goto err_unpreserve_fdt; =20 --=20 2.47.3 From nobody Sat Feb 7 08:13:50 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 6B42D35CB6E for ; Tue, 27 Jan 2026 14:38:32 +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=1769524714; cv=none; b=m+T5kptIGl3rCK3rCIsC0WZVKFi8Ywr8tj7nAmhVyPm9N8RDhW448dGXvw5vzydS0yEzONw+kqRqHkaLHdCy7vtUBTzGJc4GTRayIkG6hKP0KzsklFShJg4qT4hQ6Ta5on63Uo3FKJKgbfcoyal7w1avApILzsxHGeTLmEYhe7o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769524714; c=relaxed/simple; bh=fBFjGCRbh8U8cSZ/cSJa5284Iw7B+/T8EZSL8NRnjyA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OFZhOJwI9K/R/L2NinUz1dyleHy8XDlik7qXiZTpcLNxL8+DtjfQUIy39S2YMFVFs2IXhgrid69vO3QoHnAL/JqyjSkXErgQWjr2T0wqN6J+v4Yn5UkvwgP3gj+TaVEh2g/AVqc9M906DJGc5uTXJoNVPycbdNt5KsabACFXfVE= 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=PWIeUnf4; 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="PWIeUnf4" 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=dFfwAjrRh4mQezNKju2gMfLCWiP68PLgDj7Wjykp+Uk=; b=PWIeUnf4oRHiE9UCxOc8AVN6JC xK1rEZD0FYsudh4HY0nB/2APUnIfyspi1GgozGWy81LPauwPEzWarfK6+hVtmZjnJM9MEbtHP898j 0DZispTLlFbuzPwsGKECLGxXpt1+pOBCALScHcQWs525+5Lx434FvDRrd/jc8dfQXn64vA8YBYCM6 wioLHVH8lZNDSFVPoCxBhCd6vdQ4cRrOB/HOq+Kag5UhJgigSnyOjDyl/S3KN4bKSW3r+IKwQMTpX Se1rdaToknhAhpWqo+KeHQS3rdMi2eyG6UiBIQvVTD+Ugil5tVdiklKUXR2kYQScdj8PNH+QVuOTC tAlWcMdg==; 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 1vkkD8-00H3bH-8P; Tue, 27 Jan 2026 14:38:30 +0000 From: Breno Leitao Date: Tue, 27 Jan 2026 06:37:37 -0800 Subject: [PATCH v6 2/4] kho: rename fdt parameter to blob in kho_add/remove_subtree() 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: <20260127-kho-v6-2-56f9396681c2@debian.org> References: <20260127-kho-v6-0-56f9396681c2@debian.org> In-Reply-To: <20260127-kho-v6-0-56f9396681c2@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-f4305 X-Developer-Signature: v=1; a=openpgp-sha256; l=9203; i=leitao@debian.org; h=from:subject:message-id; bh=fBFjGCRbh8U8cSZ/cSJa5284Iw7B+/T8EZSL8NRnjyA=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpeM3WjdulbFNE7ZsiXr2cBZ7aAadiSvtDild7e Q1wcrkuPROJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaXjN1gAKCRA1o5Of/Hh3 bZDPD/9fwANioD6pzsQEgUpAGHOIhaG9zgspZi2bhghkFkExBaoAuxBUE5iLc2xetKfL0DlhiJH jGt8hTUWgXxy5gtjQDOipnwCjdpBoMCsSoRmDOVbaNN3SxImfFuO4IgOUd/9+2NdBYXllVqt65H Szo8P/ZISwyHgqpWrYuUWcPFhNUCY3JUexB27+OrufuiBcXrDF3PtfoAGSOmO5OfXsjgFkdhPz1 REiEc0dPmcs/RDJ5z6KnpVesEHIN8tI15Gz0sydtnUC0BdawEwgti36v5i2mDxeJ3qFwCoIubjw Jl/V1eE3JbIQI1GSbVeXIK+IS8XH5TPPBlBAVvGanCR9rQ3X55PVSfERC4KqDCeND2DRT1g1tDc gLDBsg9K2AWz17PLJhzJaoQR7E0E7SwbZRwVp3dh7pwTtWTvA60XtUncgosDbFTPHbze27A/JuH ld84Xnmz07hBvWm749O4quWzy/Eg6w6f+vgS67MvAs9trOGcerCBv+InGbyrssUyVDq1R9q5r0e raY7PjnMKgyMSmnpf/pSei/CFIeWTGZyUvlR8xBmuR4BoR6DsTtLuznHHBkPYrkcs3ayDgLD68Y xjsp51ZBU9dWvtk8clATOgHTA7JKzb69UlOMCN4mWYQmrGk2BzbI3siulFBcqybvCWHMm41ccEL Hes55jBXqIqrf7w== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao Since kho_add_subtree() now accepts arbitrary data blobs (not just FDTs), rename the parameter from 'fdt' to 'blob' to better reflect its purpose. Apply the same rename to kho_remove_subtree() for consistency. Also rename kho_debugfs_fdt_add() and kho_debugfs_fdt_remove() to kho_debugfs_blob_add() and kho_debugfs_blob_remove() respectively, with the same parameter rename from 'fdt' to 'blob'. Signed-off-by: Breno Leitao Acked-by: SeongJae Park Reviewed-by: Mike Rapoport (Microsoft) --- include/linux/kexec_handover.h | 8 ++++---- kernel/liveupdate/kexec_handover.c | 25 +++++++++++++------------ kernel/liveupdate/kexec_handover_debugfs.c | 25 +++++++++++++------------ kernel/liveupdate/kexec_handover_internal.h | 16 ++++++++-------- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index abb1d324f42d0..0666cf298c7f4 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -32,8 +32,8 @@ void kho_restore_free(void *mem); struct folio *kho_restore_folio(phys_addr_t phys); struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages); void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); -int kho_add_subtree(const char *name, void *fdt, size_t size); -void kho_remove_subtree(void *fdt); +int kho_add_subtree(const char *name, void *blob, size_t size); +void kho_remove_subtree(void *blob); int kho_retrieve_subtree(const char *name, phys_addr_t *phys); =20 void kho_memory_init(void); @@ -97,12 +97,12 @@ static inline void *kho_restore_vmalloc(const struct kh= o_vmalloc *preservation) return NULL; } =20 -static inline int kho_add_subtree(const char *name, void *fdt, size_t size) +static inline int kho_add_subtree(const char *name, void *blob, size_t siz= e) { return -EOPNOTSUPP; } =20 -static inline void kho_remove_subtree(void *fdt) { } +static inline void kho_remove_subtree(void *blob) { } =20 static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys) { diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index ad2da9e4e6a04..e87f77e43acef 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -723,13 +723,13 @@ static void __init kho_reserve_scratch(void) } =20 /** - * kho_add_subtree - record the physical address of a sub FDT in KHO root = tree. + * kho_add_subtree - record the physical address of a sub blob in KHO root= tree. * @name: name of the sub tree. - * @fdt: the sub tree blob. + * @blob: the sub tree blob. * @size: size of the blob in bytes. * * Creates a new child node named @name in KHO root FDT and records - * the physical address of @fdt. The pages of @fdt must also be preserved + * the physical address of @blob. The pages of @blob must also be preserved * by KHO for the new kernel to retrieve it after kexec. * * A debugfs blob entry is also created at @@ -738,9 +738,9 @@ static void __init kho_reserve_scratch(void) * * Return: 0 on success, error code on failure */ -int kho_add_subtree(const char *name, void *fdt, size_t size) +int kho_add_subtree(const char *name, void *blob, size_t size) { - phys_addr_t phys =3D virt_to_phys(fdt); + phys_addr_t phys =3D virt_to_phys(blob); void *root_fdt =3D kho_out.fdt; int err =3D -ENOMEM; int off, fdt_err; @@ -763,7 +763,8 @@ int kho_add_subtree(const char *name, void *fdt, size_t= size) if (err < 0) goto out_pack; =20 - WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, size, false)); + WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob, + size, false)); =20 out_pack: fdt_pack(root_fdt); @@ -772,9 +773,9 @@ int kho_add_subtree(const char *name, void *fdt, size_t= size) } EXPORT_SYMBOL_GPL(kho_add_subtree); =20 -void kho_remove_subtree(void *fdt) +void kho_remove_subtree(void *blob) { - phys_addr_t target_phys =3D virt_to_phys(fdt); + phys_addr_t target_phys =3D virt_to_phys(blob); void *root_fdt =3D kho_out.fdt; int off; int err; @@ -796,7 +797,7 @@ void kho_remove_subtree(void *fdt) =20 if ((phys_addr_t)*val =3D=3D target_phys) { fdt_del_node(root_fdt, off); - kho_debugfs_fdt_remove(&kho_out.dbg, fdt); + kho_debugfs_blob_remove(&kho_out.dbg, blob); break; } } @@ -1402,9 +1403,9 @@ static __init int kho_init(void) init_cma_reserved_pageblock(pfn_to_page(pfn)); } =20 - WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, "fdt", - kho_out.fdt, - fdt_totalsize(kho_out.fdt), true)); + WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, "fdt", + kho_out.fdt, + fdt_totalsize(kho_out.fdt), true)); =20 return 0; =20 diff --git a/kernel/liveupdate/kexec_handover_debugfs.c b/kernel/liveupdate= /kexec_handover_debugfs.c index 64970c88c483c..6fdb558669b7c 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -23,8 +23,9 @@ struct fdt_debugfs { struct dentry *file; }; =20 -static int __kho_debugfs_fdt_add(struct list_head *list, struct dentry *di= r, - const char *name, const void *fdt, size_t size) +static int __kho_debugfs_blob_add(struct list_head *list, struct dentry *d= ir, + const char *name, const void *blob, + size_t size) { struct fdt_debugfs *f; struct dentry *file; @@ -33,7 +34,7 @@ static int __kho_debugfs_fdt_add(struct list_head *list, = struct dentry *dir, if (!f) return -ENOMEM; =20 - f->wrapper.data =3D (void *)fdt; + f->wrapper.data =3D (void *)blob; f->wrapper.size =3D size; =20 file =3D debugfs_create_blob(name, 0400, dir, &f->wrapper); @@ -48,8 +49,8 @@ static int __kho_debugfs_fdt_add(struct list_head *list, = struct dentry *dir, return 0; } =20 -int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, - const void *fdt, size_t size, bool root) +int kho_debugfs_blob_add(struct kho_debugfs *dbg, const char *name, + const void *blob, size_t size, bool root) { struct dentry *dir; =20 @@ -58,15 +59,15 @@ int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const = char *name, else dir =3D dbg->sub_fdt_dir; =20 - return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt, size); + return __kho_debugfs_blob_add(&dbg->fdt_list, dir, name, blob, size); } =20 -void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt) +void kho_debugfs_blob_remove(struct kho_debugfs *dbg, void *blob) { struct fdt_debugfs *ff; =20 list_for_each_entry(ff, &dbg->fdt_list, list) { - if (ff->wrapper.data =3D=3D fdt) { + if (ff->wrapper.data =3D=3D blob) { debugfs_remove(ff->file); list_del(&ff->list); kfree(ff); @@ -130,8 +131,8 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg= , const void *fdt) goto err_rmdir; } =20 - err =3D __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt, - fdt_totalsize(fdt)); + err =3D __kho_debugfs_blob_add(&dbg->fdt_list, dir, "fdt", fdt, + fdt_totalsize(fdt)); if (err) goto err_rmdir; =20 @@ -150,8 +151,8 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg= , const void *fdt) continue; } sub_fdt =3D phys_to_virt(*fdt_phys); - err =3D __kho_debugfs_fdt_add(&dbg->fdt_list, sub_fdt_dir, name, - sub_fdt, fdt_totalsize(sub_fdt)); + err =3D __kho_debugfs_blob_add(&dbg->fdt_list, sub_fdt_dir, name, + sub_fdt, fdt_totalsize(sub_fdt)); if (err) { pr_warn("failed to add fdt %s to debugfs: %pe\n", name, ERR_PTR(err)); diff --git a/kernel/liveupdate/kexec_handover_internal.h b/kernel/liveupdat= e/kexec_handover_internal.h index a51f97f0fa0e6..080a62ad61ea3 100644 --- a/kernel/liveupdate/kexec_handover_internal.h +++ b/kernel/liveupdate/kexec_handover_internal.h @@ -29,19 +29,19 @@ int kho_finalize(void); int kho_debugfs_init(void); void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt); int kho_out_debugfs_init(struct kho_debugfs *dbg); -int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, - const void *fdt, size_t size, bool root); -void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt); +int kho_debugfs_blob_add(struct kho_debugfs *dbg, const char *name, + const void *blob, size_t size, bool root); +void kho_debugfs_blob_remove(struct kho_debugfs *dbg, void *blob); #else static inline int kho_debugfs_init(void) { return 0; } static inline void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt) { } static inline int kho_out_debugfs_init(struct kho_debugfs *dbg) { return 0= ; } -static inline int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char = *name, - const void *fdt, size_t size, - bool root) { return 0; } -static inline void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, - void *fdt) { } +static inline int kho_debugfs_blob_add(struct kho_debugfs *dbg, + const char *name, const void *blob, + size_t size, bool root) { return 0; } +static inline void kho_debugfs_blob_remove(struct kho_debugfs *dbg, + void *blob) { } #endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */ =20 #ifdef CONFIG_KEXEC_HANDOVER_DEBUG --=20 2.47.3 From nobody Sat Feb 7 08:13:50 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 D1DF235C1AC for ; Tue, 27 Jan 2026 14:38:36 +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=1769524718; cv=none; b=fT6nsyKEpCHWAFCwglFB2hUnJzeoP4uxrPl6dtBDyLLfwiugLKn5JzIBkhmMv8/KzrUk6lFjTgY3FoKVBMF164iwvOoU5QvvU5RO+9ojLnVCfdUVRW/PRCDHrvIP553CgJEpGc3b7496flv4k7wIZEsPi313in1DWhAWkhonshY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769524718; c=relaxed/simple; bh=nQ2uJqVyCqxIH+d/C38pFSbZu9SALipnEqB+BOtpe4I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jM35SKtVCm8DkZ/YL6iYRTV/HRnkYorH1Mfn/BD/AoqtsW+zjhNCKsmLgQjJTLJdMsLs+ViB0WPBOCHIIPZ30UJsBGO1dcGcOHZcrx9PZaywyr86XdNN0NdvXr5xBbIFQqFc4NLldrBqGE79HYfmZDZbSPk3rdtkmTAWqlOmxXk= 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=Kv+FXLSZ; 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="Kv+FXLSZ" 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=WCDrOXcJNIUfA28QBY/Owm5GFq3or2BPQOrG06isADg=; b=Kv+FXLSZi0fznOq91r7SJpnC5c ud13k5oJi/1nOUb8YSMYnd86laupStHGGBWS4EYmg6meRbjpY7YhkQoz7wA6Ur7iQ1tMtMdJGVdM9 3RM8L1xtUWLOWg0CILu8IyWK63Sz5kMmDAzpP9weRKdTC+C8pXQ7waT1avt7PKHfQc5pJNs/3zonU oS/NFBU/8JxjT1ncriO6gAxE4wiw6QrJoQdB59FMJv0ZmaIMRM0y5cDzS40NaMWIUMKdc1jQYJ4KU 87JwD7htbMwuvWQP452GNwC2XVvSe++iueARbQ3IKkIyclklthvyLudhpEUW4j6xpymNIDM+Tmqpe +xUKxz7A==; 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 1vkkDC-00H3bU-LB; Tue, 27 Jan 2026 14:38:34 +0000 From: Breno Leitao Date: Tue, 27 Jan 2026 06:37:38 -0800 Subject: [PATCH v6 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: <20260127-kho-v6-3-56f9396681c2@debian.org> References: <20260127-kho-v6-0-56f9396681c2@debian.org> In-Reply-To: <20260127-kho-v6-0-56f9396681c2@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-f4305 X-Developer-Signature: v=1; a=openpgp-sha256; l=6803; i=leitao@debian.org; h=from:subject:message-id; bh=nQ2uJqVyCqxIH+d/C38pFSbZu9SALipnEqB+BOtpe4I=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpeM3XMQqiaQEGS46c/oC8zoYAv/xv47rnqZFNg X/ScosTcJOJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaXjN1wAKCRA1o5Of/Hh3 bTs+D/9upN5s5as9HokxaKKzABdgEi0BVl36KQlDVYbTry9AaBO5IfnFzDtiztekRFW+uK3sNRD LMTrUDvj6o7fCuG4ZA2N+NltXwNLNfq8woQ1zbNFUxetg9lVY4W/6y5/OGjc0aEMOxVu1X/eWzk yqyXsV4ZBLLeuMGw3rnkHPgTHnOoOIBYbxkaeuPiSPBJbRm2r/QuGhKMh6BC9OO63Do8l3IvLLy 7KNdLFQ9SAL5/V9zNJaOk99wsVKcIY5vt+8MYVKCikq+y2KtsOOlbNLeP4Ep7u6kZ7PC84syEs7 35Rsmk20CTJYIq2DrfNBedP7x6uMWVF9I0nSyhpGRl5kbidUExDkUNJfJsaFeP65JdcF95/iC15 WAl5nwCUM97HZUgv+WDC9QQ0JTG6h7o3DrELZh7kQqOr4VvEEt/fXCzGLvCV5jgEwV7Cq3qIe1L hBy2q0BxXjWH7J4oH/7bjwBTTFU+9rnNSCClFgUMU33BnHBZIV1siAUDm8yXYkOY2BCUJphvJYZ wnUTwk7mL2387r0IVeDaHNK1YSQ45shWjsgim8AU+IRxjqCbdIwMevJaKNFlh/BpypJkyQSclgM lGWxYpQ0fhtKOziuRV9TPMtj//gvplPLfkWJYzd6FaYjzl79/6yPB8HOE+EtJAPd6ZWmcD4Eqsr Mz/KAmOC6JKNdFw== 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. Acked-by: SeongJae Park Reviewed-by: Mike Rapoport (Microsoft) Signed-off-by: Breno Leitao --- 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..f41576eed7cbd 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 uABI, 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 e87f77e43acef..ae31380936b09 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1268,6 +1269,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 @@ -1353,6 +1356,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(); @@ -1379,6 +1449,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 From nobody Sat Feb 7 08:13:50 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 139F635C1BC for ; Tue, 27 Jan 2026 14:38:40 +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=1769524722; cv=none; b=QBmwW4ClY5Vj43x0PlLw9TjS0xbjiequb89SW4Tr4Fhb3wiwXHlNqjRrLAD/s5FgE0CAaE9OOO4pRSKEor15alVLtnkoxqifVqCuggcBIH3Hi18bWKoyQjS/Ke6OZpoTnWP1+Ntf9ZHc5hi0gaF8BRkpqXO0H3hnYjlhRUAnO+A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769524722; c=relaxed/simple; bh=BibzqRu4Th29Z9ZLDMxo+dYOx89bJU5ET1VM3xltlKE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oLQo/h6sSP7UbUeDxlx+WJtUIvCLA8dkhwWCzRGV/ly52f1LqQ/02c7V3CQ4IP+v7/l1QrFxvx4MkrnBoWr0lOHjNnjHZMIA4+g23xF+qjbU9Qg5qO9VOp0YGqr8azdUB0VsGjBG9dM1BqFINDq+1gkE+10xQ4y0rQjEp6YeqrE= 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=Q1GNF3jd; 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="Q1GNF3jd" 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=mGV9QY0eKC+XLC5jci/d/FFQqBpectBL2Qr4Jd0liqE=; b=Q1GNF3jdZtMn3P4r5/R4swjm0H 3yUVhKTRKvrV3Kn3O6O6PrJZ9qQtu+MGveR9TBXf0QG/h7G4dfNYoNB0RTmvYrdehJ+TdBrfXiTQM opXZSQg5NymiQfotFJJXTlkF59l6CNxQoiM5Th3sNlsN36ssJi/h0zPw+Ty3AnQskbqOF6hha/A/U xt0ufAkOO4ewK5AGtMJkGqTXwejFC3MK43AXlxweD5Xg7SToiXnICmKYiojiWbLY6P2hbRGuUnwNS KM56g3mb5GJcjtdTCXmPTPuVNwY0f7xsd8d5zn94hZ20fwcDF40y6AvtWyNCtxF8OmB8vEtY56VWT F9BJlIqA==; 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 1vkkDG-00H3bi-VI; Tue, 27 Jan 2026 14:38:39 +0000 From: Breno Leitao Date: Tue, 27 Jan 2026 06:37:39 -0800 Subject: [PATCH v6 4/4] kho: document kexec-metadata tracking feature 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: <20260127-kho-v6-4-56f9396681c2@debian.org> References: <20260127-kho-v6-0-56f9396681c2@debian.org> In-Reply-To: <20260127-kho-v6-0-56f9396681c2@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-f4305 X-Developer-Signature: v=1; a=openpgp-sha256; l=2465; i=leitao@debian.org; h=from:subject:message-id; bh=BibzqRu4Th29Z9ZLDMxo+dYOx89bJU5ET1VM3xltlKE=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpeM3XfBATMClwlLj2ScoQxI7DhQS7XCCiu3I5D FtWzWXHM32JAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaXjN1wAKCRA1o5Of/Hh3 bT7WD/41L7tomElTT+B/OFwWEDmD1wkVMFmcJDn4NThPerzTRJ16JJaxnLwDPKxdO9zeHGNw5d0 nN4ounqpCCm6im1A/MwlfK4BJHlPVp4yfZM/x1WKXGwwRELNyxBVx1rQCmzk76Jo30v0n7aqC/n 4374aKlmnLBDboqebEyzibBkMI3ORDPaQZyCz7IqZTc8wA35G5CqraUwN3GZjV99zsaFw/v18zt /3afIV7lpZD1KCUKxLsRgUQPUZV87oTOn/VmFI5BCfBt91jII4fRIaYeZf0ppOQKS7Hv7UkG+8+ halD0xRANRnrceVvs83HsA7SgrSMoM33X8xCo0DWbzJCuE9eXHAcd+7lXaCY4pJz+kuZ/RO8SIf 8wwjqyc64nteoaG8m4CYwL4mhRhWECW5VWer/xNKXZXwHTLUYR32eXDiYpetNvSLiG9B+eji/Uk CdtK/gTZK7aU7TXoJ79kI1uerPEyn7gSyK3ADnwBgaNK+ej5PmLec15uXw9mV1CHDaZB1IgQLc8 9Br6cicR2iiVlFYzDgpcVbVAyWEuVbOHuOSSvQsvgWj0p4Q6bmRc5KlFx5AwJKxaxL1B+JGGKUF Gh8ZblvWHSE/QeNGsxcvad8RwH4eZ86cTCjDM2HSvwNk36BWmSp/cZfgVeVoXbCkXh020Q35Hl9 xdCbfDI/GQcqWHA== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao Add documentation for the kexec-metadata feature that tracks the previous kernel version and kexec boot count across kexec reboots. This helps diagnose bugs that only reproduce when kexecing from specific kernel versions. Suggested-by: Mike Rapoport Reviewed-by: Mike Rapoport (Microsoft) Signed-off-by: Breno Leitao Acked-by: SeongJae Park --- Documentation/admin-guide/mm/kho.rst | 39 ++++++++++++++++++++++++++++++++= ++++ 1 file changed, 39 insertions(+) diff --git a/Documentation/admin-guide/mm/kho.rst b/Documentation/admin-gui= de/mm/kho.rst index 6dc18ed4b8861..3771e764bb513 100644 --- a/Documentation/admin-guide/mm/kho.rst +++ b/Documentation/admin-guide/mm/kho.rst @@ -62,6 +62,45 @@ You can move the system out of KHO finalization phase ag= ain by calling :: After this command, the KHO FDT is no longer available in ``/sys/kernel/debug/kho/out/fdt``. =20 +Kexec Metadata +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +KHO automatically tracks metadata about the kexec chain, passing informati= on +about the previous kernel to the next kernel. This feature helps diagnose +bugs that only reproduce when kexecing from specific kernel versions. + +On each KHO kexec, the kernel logs the previous kernel's version and the +number of kexec reboots since the last cold boot:: + + [ 0.000000] KHO: exec from: 6.19.0-rc4-next-20260107 (count 1) + +The metadata includes: + +``previous_release`` + The kernel version string (from ``uname -r``) of the kernel that + initiated the kexec. + +``kexec_count`` + The number of kexec boots since the last cold boot. On cold boot, + this counter starts at 0 and increments with each kexec. This helps + identify issues that only manifest after multiple consecutive kexec + reboots. + +Use Cases +--------- + +This metadata is particularly useful for debugging kexec transition bugs, +where a buggy kernel kexecs into a new kernel and the bug manifests only +in the second kernel. Examples of such bugs include: + +- Memory corruption from the previous kernel affecting the new kernel +- Incorrect hardware state left by the previous kernel +- Firmware/ACPI state issues that only appear in kexec scenarios + +At scale, correlating crashes to the previous kernel version enables +faster root cause analysis when issues only occur in specific kernel +transition scenarios. + debugfs Interfaces =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 --=20 2.47.3