From nobody Fri Apr 3 03:08:24 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 7FD78392838 for ; Mon, 16 Mar 2026 11:56:16 +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=1773662178; cv=none; b=GgSiWB/z0XYuKvEy/73e541HmYUAbemg9JUO3THlEvZu5XDhXeqTNZVSpOWfb/ohWOuRuJHN8lHjWMIYsr+c/Hq6blL0IZrnWtrJpGQBG/1lP2O47KTwxgy11KUaNtV9e7LZZUj8iLx7AHPWU1vag0e2LVBbbdTgMYyBJRH1Bis= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773662178; c=relaxed/simple; bh=ZINrtSAqEMynn+IK2Mha2BFhMjVOo8eeR6qkY8mCn3Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mPx+ttqg+7zcKLoOBRnDzyZVOuSkOWLEHt9L0NCsD0JSBBGOSJD0Cr79HFW7Dp+V6k/2fHrlBMdjabD35ox63QC1wp82GPxBc1rTLxyVLsOoN1QyCbf6k+eQnQCYlm1kTO2TCBBMQrJG2t6msfvs5T7yxVVnACJH/tcac9QdWl4= 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=uCBj+Dq2; 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="uCBj+Dq2" 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=pcJSSMgXdtqSd0+U3RfszD90qV0ESOhNKpQO5qlUuk4=; b=uCBj+Dq2YKsg9NtvU0RYACTdnT /D42zyTmlwd2iMFWUI+GWv0Z4J6oLKf2KbDRrBV0SNbEGNNpMxZhiSt8tmnD1ECYxL1x5Ph2sUiwM 5gsOQ5nv2vS/74qb8JF1D2svK3U25IorDO5J/jWKjSO9sYhgdkwz3Tj3JTO61N+c2ufPgkN1dCFsR HcCYprLUq+cHmdHAbAimKU7KtCkr9RaL+5Se1uNSGN+QLz6sRCqDZbhvthFpX29tmzX6uddHwQ8pp ywoh38zgsm4Nbo6MZGQN11DcIn1N1UtAEzVT915zqcjQDw+vKCnP48OAft0vJaOM1oVOsgGT5+zgZ eA2qa6CA==; 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 1w26YN-0025yw-JG; Mon, 16 Mar 2026 11:56:10 +0000 From: Breno Leitao Date: Mon, 16 Mar 2026 04:54:31 -0700 Subject: [PATCH v9 1/6] 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: <20260316-kho-v9-1-ed6dcd951988@debian.org> References: <20260316-kho-v9-0-ed6dcd951988@debian.org> In-Reply-To: <20260316-kho-v9-0-ed6dcd951988@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, usama.arif@linux.dev, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-363b9 X-Developer-Signature: v=1; a=openpgp-sha256; l=9305; i=leitao@debian.org; h=from:subject:message-id; bh=ZINrtSAqEMynn+IK2Mha2BFhMjVOo8eeR6qkY8mCn3Q=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpt+/QRUXxNVd9164+/pNrm/TpfyExDD5YV1mc3 hmtdGhCSi2JAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCabfv0AAKCRA1o5Of/Hh3 bSAYEACON8fL8GUSVSmsSJg0qQk5osBc0D9+p0+C543bZHSyImySFR8MqvWo92DDQ1C1aSbU11M 5MEAU7zlEIzVYYulpYTL+AgGmqJTlLtd5f2BGaWwOBNwwO3g70+cUv0EdnZ/6lVjCTGH5oanM0a 3y+Q/fUZR7VIQfzCyyBYidBA11YyYEVOl58dmezl/1T32V33/T1/zMP40VJT7Bydjjuevnbqc0j rCTVSuRjERl3BLIpQHszFp5URKm2REmt6mDq/pzcpcuiC3+aLR64g7So/LYK/KUMqwNCbdV+lxr ocSk2Ea50DGzdCO2qKMe5m5rJ+SgG55MNB4SoLONG5OLrFC8+pKUNkQWuLOUa0APxn8iIfLEYcT x3gZM3r0yL81+Yk0R1mblWvSRgVMTKugqHRonq7nnKr8GJ8Wpe/qnm9TwNhByyG4ASaBim2VmZA LszmN453122tKqMZhjMZBU8kjuSC1SvYMMRGM9M9RvRYn2S9lGFS18QjjTCUr+lOLWase31kymY Ha+1dZnOy+WZb2KzG7adZ4crRLAtCYyeOX1NiPLbKcCPEKyTkTxrp3j+SigkWvH1A9L9VoxIjr6 0b5BDIHK/7xWf17om8vSaC7Vge9G9+RqC3TpwjCTJY7fyrk0a9IE2qlYaGKYdKZS4XyJau/dU/i j5cEVemYvfQs30Q== 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_debugfs_fdt_add() to receive the size explicitly instead of computing it internally via fdt_totalsize(). In kho_in_debugfs_init(), pass fdt_totalsize() for the root FDT and sub-blobs since all current users are FDTs. A subsequent patch will persist the size in the KHO FDT so the incoming side can handle non-FDT blobs correctly. 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 b64f36a452965..55bdc5d2d1929 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -752,6 +752,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 @@ -763,7 +764,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; @@ -788,7 +789,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); @@ -1452,7 +1453,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 acf3682226824..ca0153736af13 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -25,7 +25,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; @@ -35,7 +35,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)) { @@ -50,7 +50,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 @@ -59,7 +59,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) @@ -113,7 +113,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 @@ -121,6 +122,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, KHO_FDT_SUB_TREE_PROP_NAME, &len); if (!fdt_phys) @@ -130,8 +132,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 9a832a35254cf..2a28cb8db9b0a 100644 --- a/kernel/liveupdate/kexec_handover_internal.h +++ b/kernel/liveupdate/kexec_handover_internal.h @@ -27,7 +27,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; } @@ -35,7 +35,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 84ac728d63baa..04d06a0906c0e 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 7ef9e40618696..2631824373152 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 ae6a5af46bd78..29e12ea2a854c 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -2488,7 +2488,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.52.0 From nobody Fri Apr 3 03:08:24 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 C076F392837 for ; Mon, 16 Mar 2026 11:56:20 +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=1773662182; cv=none; b=u0U2XN5RM3BPuAqSzOgoCj6kBUe4ggXXWiUBgV13nzzgtoWrVjYuWmyCDie+URXwili+tTC5szY33dJvHdZ5c3FsYkqtVtRtZL+6ArTZGYHH0Yv0N0CAWhl9vzrxFCMmEc/Gj5Z4pq0G5HCvY3ZL/0YopaPNAhjfOsxpnM3DW78= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773662182; c=relaxed/simple; bh=A5hGUTB5B0dJRe//bQuK51G/RASyzCe8VrBsohQJcGY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=F5amXD9Tym/k7ikGqsSHzeGF+yRY1eQH1ysv4H0LmiM/6EKM+Ur/1Pc0SNX5gNkm08TvYe9ZRl6dbKP18bVQI/6BeGK8qnt7/1azcZOC/CCPXvG8QHae3yaCGiQDZ7nSxpqICRaGXVPk3fJW6R3vePFylD6V0KUmQNoWEovolro= 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=dMJerSV4; 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="dMJerSV4" 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=wR2D4Vlv0K3VWoQ+q8ZEgWqatcXgCMFwIfCjQmN6kzQ=; b=dMJerSV4Mo2MYbBXEM69PSlM3W FSE0xxylVaUkW+B3rB7PUF0d/xllN+XomolFIi+S24BnKr3RKcGGGHk3cksTgSQKDSXQ7Ij//qLxH Agx69pDEyjN2TDENin8uwz7UniLZgfBwFQut4ZgAK+DlEXhgoS6iJQxN0Nn+0tVzxV8iuNIfOad2v hz0CRpujeaBV6MMIjvduRUIH1LUbJQHBYWde6bs7AdJskbpxN/55loal0mYbyWusXFclS7V+N+uUO 0RyMjzIWFHXa9iiT4eIA8jHj3EXO7FWRnIoId6+82yaqARjot+ogPGQEvQ9XwRY6bQqHlkQdnQfgr Aj8/72BA==; 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 1w26YR-0025z6-Oi; Mon, 16 Mar 2026 11:56:14 +0000 From: Breno Leitao Date: Mon, 16 Mar 2026 04:54:32 -0700 Subject: [PATCH v9 2/6] 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: <20260316-kho-v9-2-ed6dcd951988@debian.org> References: <20260316-kho-v9-0-ed6dcd951988@debian.org> In-Reply-To: <20260316-kho-v9-0-ed6dcd951988@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, usama.arif@linux.dev, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-363b9 X-Developer-Signature: v=1; a=openpgp-sha256; l=10604; i=leitao@debian.org; h=from:subject:message-id; bh=A5hGUTB5B0dJRe//bQuK51G/RASyzCe8VrBsohQJcGY=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpt+/Q3ZH1Cv0gPlft2JktXnWVuSCm8gN3rEeD8 b2ojEXQT2qJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCabfv0AAKCRA1o5Of/Hh3 bckCD/oCwQ56RbqMQAttItawUCeGpKIaGkkVCcvSAe5uAHHCJ+bOJNuEiUi16QQABPOxIZyIFYx /xID8G/oplIbvOvQvBQxh6FTPKBp61duWRBepzDCsctPyXQbZaSRIZcPM2BEpjz2ET2oXGm/+5l eq2Z11fGqKwkall0l4bv99sFyNN3LoTJoIxqxhGHf08MOtALoEMy0eVy2i2VkM0PJz+KqwbAzOw VqL5iLDnLru/drgRpXnDHfMMKYZ0ItTAWHhI+gBWISAHFP9jysTEvVGyULpry7A1/GI9crjd1wu CaDvefDowQGYCjcotGPm9DSWGcrdGeW1Dw/xHa3Bi2PkS7slgLVfqMlsdea4RDEcnmxGIqj2soz KJw1YcNRdanKfweBBeBmH7Xzf0GUTfKeBZWWwtMNgYfDLbf0N2MLZzKCF+6VDTszoZRUu0OhaRI uE9ket21U+XahlbImPUjgD84dMfnLtiPCDqi9P3bZaQx8adZcnMf8KRnHmAGr/Ov1cVkZWrilI7 tZ9koGnSmMUGYL4znSIzuzlUhbJYqRSjlfUzXcEJOYHy18SJlSaf+id+gLrcfni61TBQI935sag kkzxOy4A0fS9vRxWwoHDNyA6/0B3m7QyaS5l9G4REHyJGsuzojY54O75CtyGtY/rJWD85ocbAUX UCi0HZ0zQoIc/ZQ== 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'. Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: Pratyush Yadav Signed-off-by: Breno Leitao Acked-by: SeongJae Park --- Documentation/admin-guide/mm/kho.rst | 2 +- include/linux/kexec_handover.h | 8 +++---- kernel/liveupdate/kexec_handover.c | 33 +++++++++++++++----------= ---- kernel/liveupdate/kexec_handover_debugfs.c | 25 +++++++++++----------- kernel/liveupdate/kexec_handover_internal.h | 16 +++++++------- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/Documentation/admin-guide/mm/kho.rst b/Documentation/admin-gui= de/mm/kho.rst index cb9a20f649206..6a4ddf3440465 100644 --- a/Documentation/admin-guide/mm/kho.rst +++ b/Documentation/admin-guide/mm/kho.rst @@ -80,5 +80,5 @@ stabilized. it finished to interpret their metadata. =20 ``/sys/kernel/debug/kho/in/sub_fdts/`` - Similar to ``kho/out/sub_fdts/``, but contains sub FDT blobs + Similar to ``kho/out/sub_fdts/``, but contains sub blobs of KHO producers passed from the old kernel. 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 55bdc5d2d1929..54fe59fe43acd 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -749,13 +749,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 @@ -764,9 +764,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; @@ -789,7 +789,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); @@ -798,9 +799,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; @@ -822,7 +823,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; } } @@ -1310,11 +1311,11 @@ bool is_kho_boot(void) EXPORT_SYMBOL_GPL(is_kho_boot); =20 /** - * kho_retrieve_subtree - retrieve a preserved sub FDT by its name. - * @name: the name of the sub FDT passed to kho_add_subtree(). - * @phys: if found, the physical address of the sub FDT is stored in @phys. + * kho_retrieve_subtree - retrieve a preserved sub blob by its name. + * @name: the name of the sub blob passed to kho_add_subtree(). + * @phys: if found, the physical address of the sub blob is stored in @phy= s. * - * Retrieve a preserved sub FDT named @name and store its physical + * Retrieve a preserved sub blob named @name and store its physical * address in @phys. * * Return: 0 on success, error code on failure @@ -1452,9 +1453,9 @@ static __init int kho_init(void) return 0; } =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 ca0153736af13..cab923e4f5c8d 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -24,8 +24,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; @@ -34,7 +35,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); @@ -49,8 +50,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 @@ -59,15 +60,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); @@ -113,8 +114,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 @@ -133,8 +134,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 2a28cb8db9b0a..0399ff1077750 100644 --- a/kernel/liveupdate/kexec_handover_internal.h +++ b/kernel/liveupdate/kexec_handover_internal.h @@ -26,19 +26,19 @@ extern unsigned int kho_scratch_cnt; 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.52.0 From nobody Fri Apr 3 03:08:24 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 D1FFE392838 for ; Mon, 16 Mar 2026 11:56:24 +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=1773662186; cv=none; b=LUKY2MdCrb+2N3QWgVddfcBYSxL41Ey3Vp92FU8Nd+spYykHUMTwuwy+eLiSaPzR2ddcoc09VtIOX5WiTdpk68jqgz2BT9m/l4CmvBSIDPWTbTooBJI+eDPuJHnr2+Ww5KxEI6t5PpzOO0UBHtJCCbQb3B99PHOyWXeFBZFLWY0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773662186; c=relaxed/simple; bh=051C+wlXXANkMIKsppb0xbp15xPloCr4ParEX+3dVfQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qcvDf/XqiP3riOlWfVpISjVB3d3p47OF0CSVlLCMSYD8r0jK9vXbwRdeeqc3tJUEHjoKkmxDEIMLIjQYOHn6Fn6Euxdv+sReiJbJHgVmpE7p36XnVk3NNUhmadpkIvfEfXs6FsPU8EffNgFR8o002MY/NzHVaqT3fr3bsR7JOOI= 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=vVGp+VIt; 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="vVGp+VIt" 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=zlcVx0W0VtTFst28aefWpydWDS6cGWkZyYfBnt7a02Q=; b=vVGp+VItaaV2p2pJiYKm9hxnD8 LBsdzLfpw1Q+Rb2HUtT1dfD02BZgvsivANkiRByFgANPC5hIqrFTxpSUSPQyHFefXJk7fd6KJdN3M zNYCl+RZxxDkn9tMJEHFhJ9Ln4qKTXsVGMUMdLXYE1roDErharYaqo/ewk+FeWlMx/HDwxnqhFsdt 8yjg3ClOovkMacIJkRTAhrrukU9+o0nkMFkN+hBbi8qu6t+glTa1J74NINgkqlkS8k8AwML6h7utf kouLoohDDijyV5iuof9p3WomB0lW0yBuJwezY/4dKUrCgFMbB4uawJ84bAg50Axz/O2ljj6HWZFYT wraXQvFA==; 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 1w26YV-0025zJ-RG; Mon, 16 Mar 2026 11:56:18 +0000 From: Breno Leitao Date: Mon, 16 Mar 2026 04:54:33 -0700 Subject: [PATCH v9 3/6] kho: persist blob size in KHO FDT 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: <20260316-kho-v9-3-ed6dcd951988@debian.org> References: <20260316-kho-v9-0-ed6dcd951988@debian.org> In-Reply-To: <20260316-kho-v9-0-ed6dcd951988@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, usama.arif@linux.dev, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-363b9 X-Developer-Signature: v=1; a=openpgp-sha256; l=9060; i=leitao@debian.org; h=from:subject:message-id; bh=051C+wlXXANkMIKsppb0xbp15xPloCr4ParEX+3dVfQ=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpt+/QAagOvEjH+4Kb2F7XeWd2dYke4ca0A+WRu CzHwqqx3/iJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCabfv0AAKCRA1o5Of/Hh3 bY1HD/9cURrNPM32kFPiGDQtiEdASq3a5nKciMcaXLOzru3nUFWMZZnNH7QhUq5Jn6WbCTAmAAl ajbvSmAtmF8NrE5+YLR7i+v3S0+BusZYY+oSpbZOufwpDS4cGWp3CUlxi6NdIbwEhQV6DQCeyjm oBZSmj4JChL0bDjbH4nfb2ekMQ3iI8PrKCNA87R1oztt/3pGqQ3c0ZLCKeeU60YTbmwj87yRw9J txXGBquXuW5HVbB+bxk3EOBygn8ZtUEId1x/ep9nSpwFDL02v7BBcFH5JvBnM5pgRJU3/2xrFgQ Ab3trrYYHQJrta3wDbxCCIKOs3U9NyFxtPIWVKzkOiA900xZdZrY4wc8jIGRkh9Qjw1FWneazwN ZGyjZwH/73MXUzZpiN1DTJIVkOSgKlUqTUytp5MGOqoI1na8I4ZlrFlg94GRNspRzghLz3gARm/ 2ss4+aWnDsPeHcURukMGGGfDmSS4BiMoEg/suPzJG1ZcfQtyuIM2lGb14OKRSk7aIYANZBOBX8J ja0cmHEJGf5kqwSD1EWhrljfIV2RyowPR9MPaxiw7CVdrS5bgrBQ3Py/lbRdra51cDM200pMYS9 N3BOgK9IybNBWtnxHQe7pFf76IqpTrkz08NiiDE7QTsKz/u4diwBKDIVZSP7tjwMCvL4ylFfFBq iqH42we+pFwcsaw== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao kho_add_subtree() accepts a size parameter but only forwards it to debugfs. The size is not persisted in the KHO FDT, so it is lost across kexec. This makes it impossible for the incoming kernel to determine the blob size without understanding the blob format. Store the blob size as a "blob-size" property in the KHO FDT alongside the "preserved-data" physical address. This allows the receiving kernel to recover the size for any blob regardless of format. Also extend kho_retrieve_subtree() with an optional size output parameter so callers can learn the blob size without needing to understand the blob format. Update all callers to pass NULL for the new parameter. Reviewed-by: Mike Rapoport (Microsoft) Signed-off-by: Breno Leitao Acked-by: SeongJae Park --- include/linux/kexec_handover.h | 5 +++-- include/linux/kho/abi/kexec_handover.h | 20 ++++++++++++++++---- kernel/liveupdate/kexec_handover.c | 27 ++++++++++++++++++++++----- kernel/liveupdate/kexec_handover_debugfs.c | 3 ++- kernel/liveupdate/luo_core.c | 2 +- lib/test_kho.c | 2 +- mm/memblock.c | 2 +- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 0666cf298c7f4..8968c56d2d73e 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -34,7 +34,7 @@ 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 *blob, size_t size); void kho_remove_subtree(void *blob); -int kho_retrieve_subtree(const char *name, phys_addr_t *phys); +int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size= ); =20 void kho_memory_init(void); =20 @@ -104,7 +104,8 @@ static inline int kho_add_subtree(const char *name, voi= d *blob, size_t size) =20 static inline void kho_remove_subtree(void *blob) { } =20 -static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys) +static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys, + size_t *size) { return -EOPNOTSUPP; } diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi= /kexec_handover.h index 6b7d8ef550f98..7e847a2339b09 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -41,25 +41,28 @@ * restore the preserved data.:: * * / { - * compatible =3D "kho-v2"; + * compatible =3D "kho-v3"; * * preserved-memory-map =3D <0x...>; * * { * preserved-data =3D <0x...>; + * blob-size =3D <0x...>; * }; * * { * preserved-data =3D <0x...>; + * blob-size =3D <0x...>; * }; * ... ... * { * preserved-data =3D <0x...>; + * blob-size =3D <0x...>; * }; * }; * * Root KHO Node (/): - * - compatible: "kho-v2" + * - compatible: "kho-v3" * * Indentifies the overall KHO ABI version. * @@ -78,16 +81,25 @@ * * Physical address pointing to a subnode data blob that is also * being preserved. + * + * - blob-size: u64 + * + * Size in bytes of the preserved data blob. This is needed because + * blobs may use arbitrary formats (not just FDT), so the size + * cannot be determined from the blob content alone. */ =20 /* The compatible string for the KHO FDT root node. */ -#define KHO_FDT_COMPATIBLE "kho-v2" +#define KHO_FDT_COMPATIBLE "kho-v3" =20 /* The FDT property for the preserved memory map. */ #define KHO_FDT_MEMORY_MAP_PROP_NAME "preserved-memory-map" =20 /* The FDT property for preserved data blobs. */ -#define KHO_FDT_SUB_TREE_PROP_NAME "preserved-data" +#define KHO_SUB_TREE_PROP_NAME "preserved-data" + +/* The FDT property for the size of preserved data blobs. */ +#define KHO_SUB_TREE_SIZE_PROP_NAME "blob-size" =20 /** * DOC: Kexec Handover ABI for vmalloc Preservation diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index 54fe59fe43acd..b768fb7b41280 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -768,6 +768,7 @@ int kho_add_subtree(const char *name, void *blob, size_= t size) { phys_addr_t phys =3D virt_to_phys(blob); void *root_fdt =3D kho_out.fdt; + u64 size_u64 =3D size; int err =3D -ENOMEM; int off, fdt_err; =20 @@ -784,11 +785,16 @@ int kho_add_subtree(const char *name, void *blob, siz= e_t size) goto out_pack; } =20 - err =3D fdt_setprop(root_fdt, off, KHO_FDT_SUB_TREE_PROP_NAME, + err =3D fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, &phys, sizeof(phys)); if (err < 0) goto out_pack; =20 + err =3D fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME, + &size_u64, sizeof(size_u64)); + if (err < 0) + goto out_pack; + WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob, size, false)); =20 @@ -817,7 +823,7 @@ void kho_remove_subtree(void *blob) const u64 *val; int len; =20 - val =3D fdt_getprop(root_fdt, off, KHO_FDT_SUB_TREE_PROP_NAME, &len); + val =3D fdt_getprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, &len); if (!val || len !=3D sizeof(phys_addr_t)) continue; =20 @@ -1314,13 +1320,14 @@ EXPORT_SYMBOL_GPL(is_kho_boot); * kho_retrieve_subtree - retrieve a preserved sub blob by its name. * @name: the name of the sub blob passed to kho_add_subtree(). * @phys: if found, the physical address of the sub blob is stored in @phy= s. + * @size: if not NULL and found, the size of the sub blob is stored in @si= ze. * * Retrieve a preserved sub blob named @name and store its physical - * address in @phys. + * address in @phys and optionally its size in @size. * * Return: 0 on success, error code on failure */ -int kho_retrieve_subtree(const char *name, phys_addr_t *phys) +int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size) { const void *fdt =3D kho_get_fdt(); const u64 *val; @@ -1336,12 +1343,22 @@ int kho_retrieve_subtree(const char *name, phys_add= r_t *phys) if (offset < 0) return -ENOENT; =20 - val =3D fdt_getprop(fdt, offset, KHO_FDT_SUB_TREE_PROP_NAME, &len); + val =3D fdt_getprop(fdt, offset, KHO_SUB_TREE_PROP_NAME, &len); if (!val || len !=3D sizeof(*val)) return -EINVAL; =20 *phys =3D (phys_addr_t)*val; =20 + val =3D fdt_getprop(fdt, offset, KHO_SUB_TREE_SIZE_PROP_NAME, &len); + if (!val || len !=3D sizeof(*val)) { + pr_warn("broken KHO subnode '%s': missing or invalid blob-size property\= n", + name); + return -EINVAL; + } + + if (size) + *size =3D (size_t)*val; + return 0; } EXPORT_SYMBOL_GPL(kho_retrieve_subtree); diff --git a/kernel/liveupdate/kexec_handover_debugfs.c b/kernel/liveupdate= /kexec_handover_debugfs.c index cab923e4f5c8d..b416846810d78 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -125,7 +125,8 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg= , const void *fdt) const u64 *fdt_phys; void *sub_fdt; =20 - fdt_phys =3D fdt_getprop(fdt, child, KHO_FDT_SUB_TREE_PROP_NAME, &len); + fdt_phys =3D fdt_getprop(fdt, child, + KHO_SUB_TREE_PROP_NAME, &len); if (!fdt_phys) continue; if (len !=3D sizeof(*fdt_phys)) { diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 04d06a0906c0e..48b25c9abeda3 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -88,7 +88,7 @@ static int __init luo_early_startup(void) } =20 /* Retrieve LUO subtree, and verify its format. */ - err =3D kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys); + err =3D kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, NULL); if (err) { if (err !=3D -ENOENT) { pr_err("failed to retrieve FDT '%s' from KHO: %pe\n", diff --git a/lib/test_kho.c b/lib/test_kho.c index 2631824373152..aa6a0956bb8b7 100644 --- a/lib/test_kho.c +++ b/lib/test_kho.c @@ -319,7 +319,7 @@ static int __init kho_test_init(void) if (!kho_is_enabled()) return 0; =20 - err =3D kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys); + err =3D kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys, NULL); if (!err) { err =3D kho_test_restore(fdt_phys); if (err) diff --git a/mm/memblock.c b/mm/memblock.c index 29e12ea2a854c..4f4bf1a9d7900 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -2533,7 +2533,7 @@ static void *__init reserve_mem_kho_retrieve_fdt(void) if (fdt) return fdt; =20 - err =3D kho_retrieve_subtree(MEMBLOCK_KHO_FDT, &fdt_phys); + err =3D kho_retrieve_subtree(MEMBLOCK_KHO_FDT, &fdt_phys, NULL); if (err) { if (err !=3D -ENOENT) pr_warn("failed to retrieve FDT '%s' from KHO: %d\n", --=20 2.52.0 From nobody Fri Apr 3 03:08:24 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 55E36392C24 for ; Mon, 16 Mar 2026 11:56: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=1773662189; cv=none; b=QfnIeUgZ6u7QIlL06VqhbrKixeXwaSJ9OiNUpuEfZHjx72tlhhXdjQjTeQQylO2X0iWDkBGpZi8JBaBwRqO5QLVlvvszOd0eLJKDHKIA9L7VMcSPE6/1TWiPbCM8aX6tgOHeFlf3BER6CMDS8TFBzF4jfc98v5LMz/L5Vr6Ywxg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773662189; c=relaxed/simple; bh=NdnEnb82h7S9muDEUV3/7Wtzdn0YHHb9hUPR57PIUzA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PZh/ipNkcM9gspKdrdXHiUHfFpo9RDydgPGyZmIUpytBto1JZVPqWs3MR9MJ5ZsJfTEXGOqmnfW6+8SiYYfIylGOyTTxk8c3BvS4FrM6KsoRNh1dMjvt6rOJll4XyBHzCb4Azdzih4hb/snBexXIecPFrwMATd1oDu2hTAm00CM= 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=eNv2Gl9d; 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="eNv2Gl9d" 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=CrU8iiVUzo7pzSuSlrROr+d13XFM4fDOr9PEDnip+Ig=; b=eNv2Gl9d4wYCGxiYb9k5o8EJfY eNiOmFRtE5PUpTBnH28VW7jwhd/8SQe852fGq6zh51WyuRLYq8TgQpz2wIN8lOgYb65Di77WPieLz WC8fqGpv1Ahls+R/W5QUGkAjc4oMwGT/BMbCVCTOV6nZn0+ANauxTK0aY+ISlRJ4pvvdt6LvrN0Mg 4Oae993m4dkSRkyXLMRCAblIe8b54fYdDrYmHZf6Flavp8mgwVymBHqqL3NB2vZE0oofbQ4Nu/sBL AV9dJN8MY5VDLdVnSxwfx3Cf+d5Nwhm97/wjT4ktXeqqoxvF+VLkY6fRdf8hpdYALmI3fhneTF7SI Pg884qZw==; 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 1w26YZ-0025zV-Rq; Mon, 16 Mar 2026 11:56:22 +0000 From: Breno Leitao Date: Mon, 16 Mar 2026 04:54:34 -0700 Subject: [PATCH v9 4/6] kho: fix kho_in_debugfs_init() to handle non-FDT blobs 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: <20260316-kho-v9-4-ed6dcd951988@debian.org> References: <20260316-kho-v9-0-ed6dcd951988@debian.org> In-Reply-To: <20260316-kho-v9-0-ed6dcd951988@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, usama.arif@linux.dev, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-363b9 X-Developer-Signature: v=1; a=openpgp-sha256; l=2322; i=leitao@debian.org; h=from:subject:message-id; bh=NdnEnb82h7S9muDEUV3/7Wtzdn0YHHb9hUPR57PIUzA=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpt+/QHPzXS1ApQQHREue5wikETwUmtKSVrZnZ3 eHOP/JL5c6JAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCabfv0AAKCRA1o5Of/Hh3 beOTD/42Ij2t2+/+Rqjfwm8NNjanxcOJ58mHmWDZuXoyPvGHmSXH/SY69y40/LrHEJNf9TRZgZ7 Riyh8VL6H6HMJnHTYFuQc0cymBgEBTn9QqDeiOAmWjWJTfH5fCufmVWTTseNRrYFP3xhtmruHxz 0kdGvpz7a4DUsJhWlnwyWJSZrGDVXp/kI+jkNDvYimoO3pVwt1txEhOn01K0Y6bQV8RRfLJTcHn Jd/Rj3qlXJB0v/oN4WevdrZjExLxykDRwkDKVvskGGCYEmC/kQlEnSLvrM3YjQmSgRwxI9O4LRn bjQSLwEFSMrqpO1KxeKe4X1B6GEWPWHaxappsva0lNkH25FFgG2Ofrj4b+o99ZrvoXGq4icPr/l Oa469NQz8su/0HBEfLvGCTxZniQiqhYVCXnEB6AzRhOKvnTgllFFp+RtZ/MPUVSxjs7lc8Xlkv0 c+U2TFB/5HSkDgtXv/2ikSA4Jpb0mvjR6fZbvae9o4wcwUG1OKKTak59W9WUuJYWW0+2Rak7oxL uJ2ARLkaLXLLCC2yChKodg58TBI7OZ5UYJP7lAoxttq4fcKAmEDKCyZIaT31W41MaHg0pNUcwhD DNvuh1KVfOSK7/3Gms85Qs86wJ1kZ4WVif2Soo8RK1jBObxAvGjvjWfmSn5xICgcPVoO/VXndkk 14u+16jjvmFTo0w== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao kho_in_debugfs_init() calls fdt_totalsize() to determine blob sizes, which assumes all blobs are FDTs. This breaks for non-FDT blobs like struct kho_kexec_metadata. Fix this by reading the "blob-size" property from the FDT (persisted by kho_add_subtree()) instead of calling fdt_totalsize(). Also rename local variables from fdt_phys/sub_fdt to blob_phys/blob for consistency with the non-FDT-specific naming. Signed-off-by: Breno Leitao Acked-by: SeongJae Park --- kernel/liveupdate/kexec_handover_debugfs.c | 32 ++++++++++++++++++++------= ---- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/kernel/liveupdate/kexec_handover_debugfs.c b/kernel/liveupdate= /kexec_handover_debugfs.c index b416846810d78..257ee8a52be66 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -122,24 +122,34 @@ __init void kho_in_debugfs_init(struct kho_debugfs *d= bg, const void *fdt) fdt_for_each_subnode(child, fdt, 0) { int len =3D 0; const char *name =3D fdt_get_name(fdt, child, NULL); - const u64 *fdt_phys; - void *sub_fdt; + const u64 *blob_phys; + const u64 *blob_size; + void *blob; =20 - fdt_phys =3D fdt_getprop(fdt, child, + blob_phys =3D fdt_getprop(fdt, child, KHO_SUB_TREE_PROP_NAME, &len); - if (!fdt_phys) + if (!blob_phys) continue; - if (len !=3D sizeof(*fdt_phys)) { - pr_warn("node %s prop fdt has invalid length: %d\n", - name, len); + if (len !=3D sizeof(*blob_phys)) { + pr_warn("node %s prop %s has invalid length: %d\n", + name, KHO_SUB_TREE_PROP_NAME, len); continue; } - sub_fdt =3D phys_to_virt(*fdt_phys); + + blob_size =3D fdt_getprop(fdt, child, + KHO_SUB_TREE_SIZE_PROP_NAME, &len); + if (!blob_size || len !=3D sizeof(*blob_size)) { + pr_warn("node %s missing or invalid %s property\n", + name, KHO_SUB_TREE_SIZE_PROP_NAME); + continue; + } + + blob =3D phys_to_virt(*blob_phys); err =3D __kho_debugfs_blob_add(&dbg->fdt_list, sub_fdt_dir, name, - sub_fdt, fdt_totalsize(sub_fdt)); + blob, *blob_size); if (err) { - pr_warn("failed to add fdt %s to debugfs: %pe\n", name, - ERR_PTR(err)); + pr_warn("failed to add blob %s to debugfs: %pe\n", + name, ERR_PTR(err)); continue; } } --=20 2.52.0 From nobody Fri Apr 3 03:08:24 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 D94ED34EF01 for ; Mon, 16 Mar 2026 11:56: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=1773662194; cv=none; b=ksDZOs+8aTJbGAwtqY1x8CKL9ehywpKEoU8fpdnucJ0lRiRg3hbmsr1+FfYpWHbGQYpWIgnXZiSeNfCFjwY19vjKzRLqdd/ofd/rF0hY1rb930rawFv6SoAGwDYllZUeD5sTpp6Pww9FsuRSd3pZIXIJZyV3lX7mKwj2LjrVjZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773662194; c=relaxed/simple; bh=tZwmah9BwtjUspXeFH3zT9+1gw6bedkgV6HPu8Vqbko=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pvw+Hqcewaw+KzWhel6M1Toq7Ha+rqQCJfCMqq8CM+yCm5ETNWPRkx65gh5ryMfVi819SN0LcDor+APiSlYeH2hh0rMpJ6jF7Ort3YUDaKcvkKUF+IoTC+5lyVV1YPApuTujwz5jg6QUCfUCqDqDrn472lORuRJ3O8Jl4oLvsMQ= 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=TTPcz3cR; 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="TTPcz3cR" 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=GilGYiXFEL76/A5yC5soz5ziXjKLkl4hsXD/ZnoWJGs=; b=TTPcz3cRNvzA+rHOyuiYGIboVE WtSIPkoTsqzN6WS/sracHHi0KUAo47COASqazwz3B5H+gHhRxLBukk6Csu0giu0QDyPC+ZPlbTOe7 L4KKHoscTl8Q31H+kZLFOlBQItp5J+jHkw5PLIqv83VPEe9otyTGFxbRagm9m61q2ZTV32W84jx+T vJ4vXuoHSC1axHqM5bSL7q094qh9djTdXeVNf9rdx//qglGoVfGWivHqw9A4H6e+jx8yZH+7mLqN8 4FSQjg2LJaVyRefX6DHMx/zotUuqUYnFoLM8hiNduz8unQzR+hMP8U5bT4QxVFwoVWf/0k5cDiMhw XDEuG9og==; 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 1w26Yd-0025zn-On; Mon, 16 Mar 2026 11:56:26 +0000 From: Breno Leitao Date: Mon, 16 Mar 2026 04:54:35 -0700 Subject: [PATCH v9 5/6] 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: <20260316-kho-v9-5-ed6dcd951988@debian.org> References: <20260316-kho-v9-0-ed6dcd951988@debian.org> In-Reply-To: <20260316-kho-v9-0-ed6dcd951988@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, usama.arif@linux.dev, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-363b9 X-Developer-Signature: v=1; a=openpgp-sha256; l=7860; i=leitao@debian.org; h=from:subject:message-id; bh=tZwmah9BwtjUspXeFH3zT9+1gw6bedkgV6HPu8Vqbko=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpt+/QA8hvw9tAeJC0GPMFyUiMS98yYS/pGL7EV S8guHU/ruuJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCabfv0AAKCRA1o5Of/Hh3 bblEEACq5FaVAJomTjfoBm/Hwr0UxRWUirk6zQ0J2Lp4mJXqqO4z9S5EmGMfCTPbO8r+qyvd4vo U2VmjtWUhU0bmjz2y5XOl5q24OjHkjAXs/xRR/t4YjxvY/DdWYnPyO4PQ/hbg6OBm7CWdwv/YKI AfZaVkVk3EBOz+B5EHDzj/e8TUSSG9b7nT1lTzsptPpQWeojhP/x7LPw8lZiG43HnKdMv+fhQRh kwLAGAGg1uFTfGTjWrik1D8RLy9SF17itY+dP1Xe8MtZZcBu9NI6qQNUv1+u1vkoPS14586DW6w R210D+m83BFI8F6wpesvoD6NyupCKECdyz/WTwtjQBOvWv6GkDFihCULgTE9IiyKmHpy+3CnUXI HVd0+2TRnt6vodWr2P3jDBYCUGcQP3vQ27HOubL0yBZh5ai0V/Wzk3Rw/gQHwgOvpUWgXARxUNf N8DECkzSG0dJDC5pO3z9ZCVl/i4QSKGZISkN6WCDVTFL69vhIO0APFzKNLOlbcbYc6jqoVwowOB v+xVIb8VRMcUCtTdELd9dE1iorZIQu1VAhq7jKS/CSY4jPP81AoNeQzsTAba1PbIlQKHG5EDhPS 7ooG3lzYYPnGkb+xWl3VKoWgxTNTY3/8FQ76eaY6tAzB5XLnKVhqMICCMszyP0PgZCvYfxNJuDS y1lvLFqxGOeuu2w== 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: * commit eb2266312507 ("x86/boot: Fix page table access in 5-level to 4-level paging transition") * commit 77d48d39e991 ("efistub/tpm: Use ACPI reclaim memory for event log to avoid corruption") * commit 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_kexec_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_metadata.h | 46 ++++++++++++++++ kernel/liveupdate/kexec_handover.c | 98 ++++++++++++++++++++++++++++++= ++++ 2 files changed, 144 insertions(+) diff --git a/include/linux/kho/abi/kexec_metadata.h b/include/linux/kho/abi= /kexec_metadata.h new file mode 100644 index 0000000000000..e9e3f7e38a7c4 --- /dev/null +++ b/include/linux/kho/abi/kexec_metadata.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/** + * 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. + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates. + * Copyright (c) 2026 Breno Leitao + */ + +#ifndef _LINUX_KHO_ABI_KEXEC_METADATA_H +#define _LINUX_KHO_ABI_KEXEC_METADATA_H + +#include +#include + +#define KHO_KEXEC_METADATA_VERSION 1 + +/** + * struct kho_kexec_metadata - Kexec metadata passed between kernels + * @version: ABI version of this struct (must be first field) + * @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 { + u32 version; + char previous_release[__NEW_UTS_LEN + 1]; + u32 kexec_count; +} __packed; + +#define KHO_METADATA_NODE_NAME "kexec-metadata" + +#endif /* _LINUX_KHO_ABI_KEXEC_METADATA_H */ diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index b768fb7b41280..2eb9e47558ccb 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -1285,6 +1287,8 @@ EXPORT_SYMBOL_GPL(kho_restore_free); struct kho_in { phys_addr_t fdt_phys; phys_addr_t scratch_phys; + char previous_release[__NEW_UTS_LEN + 1]; + u32 kexec_count; struct kho_debugfs dbg; }; =20 @@ -1409,6 +1413,96 @@ 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; + size_t blob_size; + int err; + + err =3D kho_retrieve_subtree(KHO_METADATA_NODE_NAME, &metadata_phys, + &blob_size); + if (err) + /* This is fine, previous kernel didn't export metadata */ + return; + + /* Check that, at least, "version" is present */ + if (blob_size < sizeof(u32)) { + pr_warn("kexec-metadata blob too small (%zu bytes)\n", + blob_size); + return; + } + + metadata =3D phys_to_virt(metadata_phys); + + if (metadata->version !=3D KHO_KEXEC_METADATA_VERSION) { + pr_warn("kexec-metadata version %u not supported (expected %u)\n", + metadata->version, KHO_KEXEC_METADATA_VERSION); + return; + } + + if (blob_size < sizeof(*metadata)) { + pr_warn("kexec-metadata blob too small for v%u (%zu < %zu)\n", + metadata->version, blob_size, sizeof(*metadata)); + return; + } + + /* + * 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); + + metadata->version =3D KHO_KEXEC_METADATA_VERSION; + 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) { struct kho_radix_tree *tree =3D &kho_out.radix_tree; @@ -1442,6 +1536,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; + for (int i =3D 0; i < kho_scratch_cnt; i++) { unsigned long base_pfn =3D PHYS_PFN(kho_scratch[i].addr); unsigned long count =3D kho_scratch[i].size >> PAGE_SHIFT; --=20 2.52.0 From nobody Fri Apr 3 03:08:24 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 0BE50392C49 for ; Mon, 16 Mar 2026 11:56:35 +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=1773662197; cv=none; b=gSSYvNwW0346Q436KnMueFaKrfuuI93DrKi3S31XLvzASSWM46jS0XkzB8FYPOco9KlHDTdPSc4q9G/gcjBEs3yynY3trMKGkQCYttW6JFGsmc5vxGxznAHv4NB2Pp+Dp3i/5PV88VMZ1E12/bZ8oqID5Sa+7wkQbWLzNAaqcxU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773662197; c=relaxed/simple; bh=Hlw5chBPs/GGmVd2Vfxvsk1mq2UGfEKb5hoy1/gHS0w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hME/t58N237QassLD8bnZ9S+dguXsYOmUEzhQk5DGGErYjp/aunkei4qPxEoBh79SOiUeUcyqy85HlLlMw/vcvr259YSWMmsv9OcDziG13igpA4E/Im1b2iLV5ORbtnKYHAafF2ajOV1UKOAf1+nh5JxDVzrtDY3lRMTooY523c= 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=dDQO5U45; 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="dDQO5U45" 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=BIYteLscNbuJ8M2TNSr6zCYdcchlP9A8lbucS9J/eKM=; b=dDQO5U45OCJInWUfMljGpNPgtG RwOlhLLZ/NVovVcj0BZxiSxD3u++sO4Yk0hEPH9w78eUOSub5y59p3743N7mO61WsJNaiWMt1XLCm 51I0YretIcEO314uOiH1306FlRQxx25idisr0wDsQi4B3zLwmNNN6SvJWiw6joUTXDvsiUEr7ez83 pD0aCItoagki9+0ZHpllMTrHb2O6+F2JDvwac6dx/KNevobmOfoL+7O7yNqK43QltNEBdZpoJHviW HFNnxNjmFDLKtPkJBTwtkrlCcqN7P1aQVgCeN/vHnpLtgHOvy1gIPZgTkHDAAzeXte+fCih66Ukeq 40SgN6Vw==; 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 1w26Yh-002600-Pc; Mon, 16 Mar 2026 11:56:30 +0000 From: Breno Leitao Date: Mon, 16 Mar 2026 04:54:36 -0700 Subject: [PATCH v9 6/6] 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: <20260316-kho-v9-6-ed6dcd951988@debian.org> References: <20260316-kho-v9-0-ed6dcd951988@debian.org> In-Reply-To: <20260316-kho-v9-0-ed6dcd951988@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, usama.arif@linux.dev, Breno Leitao , SeongJae Park , kernel-team@meta.com X-Mailer: b4 0.15-dev-363b9 X-Developer-Signature: v=1; a=openpgp-sha256; l=2537; i=leitao@debian.org; h=from:subject:message-id; bh=Hlw5chBPs/GGmVd2Vfxvsk1mq2UGfEKb5hoy1/gHS0w=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBpt+/R5Ez+Wu4VpdqaIcba4CabNLUTikRuvc4JA kTxLX2vZ2aJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCabfv0QAKCRA1o5Of/Hh3 bZAvD/9v6OGnwOodgkswz4dXFI57BWYERIzbFFV8eyQEWwpYnEMvn4ucpEsAjnFtM3axRJvRZUQ zgtWrLUsGbsh6s/uzr7aNyorRMRMZgHtV2uPH9CwOzzeSuPU9KA+b/wg8i3QvsxKGYL3Twxp4Ma YnpTsVVYeOOzWRRbB4c/FmljQfVDpxkAvi33oKRYKxNXLQGJIZ1ffcnocBeVekqBJVWfltzSbuQ j3T6H8Lyyr7Iim59ZGeCACPdS1u/8vAz/zhFTIBeJxx6UCsdlpP5zK41ydlaOSAXoAhYtEckezK uuq2wrS5CdfYOKvH0K8qrf1qz0hxOseu3CVyOOgr4F/on1fmXkIpzh6+Gnjk92u9/W3UBho53HW QyXG6m5ZyBm+GWLTt8JbKCSRgTNIqwbC1bG2G9k7/CmhKDvWYI3eFkWfB9lTCQJoG6krEE74cTp vrhH9++h8XWFvj2Dwv5/xf8m9AltqFtKYS75RbhghrDxk+67/lWWVi3WDjxRhsmTgc/YgUyKZgS jkvyiMIDMiN8ewfgrfc+2myP0z3x5fNixbklx5B43LKvRLj6ulHHoxfux8nnIVjdoJaMo1ojCnB thkFsdEdhNDenMvPgUz4OfGYQNQGTicZumN3qLD+HWWKBxqrchmwlR2ByMqljUd7JUmu+csnS4n UHR5TfwPVACncRg== 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) Reviewed-by: Pratyush Yadav 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 6a4ddf3440465..2c26e560bd78a 100644 --- a/Documentation/admin-guide/mm/kho.rst +++ b/Documentation/admin-guide/mm/kho.rst @@ -42,6 +42,45 @@ For example, if you used ``reserve_mem`` command line pa= rameter to create an early memory reservation, the new kernel will have that memory at the same physical address as the old kernel. =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.52.0