mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Tarun Sahu <tarunsahu@google.com>
To: Pasha Tatashin <pasha.tatashin@soleen.com>,
	Mike Rapoport <rppt@kernel.org>,
	robin.murphy@arm.com,  maz@kernel.org, will@kernel.org,
	David Matlack <dmatlack@google.com>,
	 Alexander Graf <graf@amazon.com>,
	seanjc@google.com, jgg@nvidia.com, loganodell@google.com,
	 arnd@arndb.de, dwmw2@infradead.org, baolu.lu@linux.intel.com,
	 Bjorn Helgaas <bhelgaas@google.com>,
	oupton@kernel.org, alex@shazbot.org,  gle.com@google.com,
	pbonzini@redhat.com,  Andrew Morton <akpm@linux-foundation.org>,
	kevin.tian@intel.com, joro@8bytes.org
Cc: kvmarm@lists.linux.dev, linux-pci@vger.kernel.org,
	 Pratyush Yadav <pratyush@kernel.org>,
	kexec@lists.infradead.org, kvm@vger.kernel.org,
	 iommu@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
	 skhawaja@google.com, sagis@google.com,
	linux-arch@vger.kernel.org,  linux-mm@kvack.org,
	linux-kernel@vger.kernel.org,  Tarun Sahu <tarunsahu@google.com>
Subject: [PATCH v4 09/19] liveupdate: Add feature header to struct luo_ser
Date: Tue, 10 Nov 2026 05:01:52 +0000	[thread overview]
Message-ID: <20261110050202.529473-10-tarunsahu@google.com> (raw)
In-Reply-To: <20261110050202.529473-1-tarunsahu@google.com>

LUO and its file handlers currently rely solely on coarse-grained
compatibility strings (such as luo-v6 and memfd-v3) to validate
handed-over state across kexec. Because compatibility is checked only
at the whole-structure level, any change to a serialized structure,
even an optional additive field, requires bumping the compatibility
string and breaks live update between adjacent kernels.

Precede the centralized struct luo_ser with struct kho_ser_hdr using
DECLARE_KHO_SER. Subsystems can now evolve their serialized state at
per-feature granularity. Each subsystem groups the fields of its
serialized structure under feature indices, starting with index 0 for the
base fields. When a subsystem adds a new capability, it appends any new
fields to the end of its payload structure under a new feature index.
Retired fields are kept in place so existing field offsets never shift;
if the type or format of a field needs to change, the existing field and
feature are kept intact until retired and a new feature index with an
appended field of the new type is added. Only when a change requires a
complete break in the serialized layout or semantics that feature flags
cannot handle, a new handler can be introduced with an incremented version
number in its compatibility string.

Signed-off-by: Logan Odell <loganodell@google.com>
Signed-off-by: Tarun Sahu <tarunsahu@google.com>
---
 include/linux/kho/abi/luo.h  | 64 +++++++++++++++---------------------
 kernel/liveupdate/luo_core.c | 39 +++++++++++++---------
 2 files changed, 50 insertions(+), 53 deletions(-)

diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h
index f1152470f71a..dfa7ea434d0d 100644
--- a/include/linux/kho/abi/luo.h
+++ b/include/linux/kho/abi/luo.h
@@ -9,29 +9,26 @@
  * DOC: Live Update Orchestrator ABI
  *
  * Live Update Orchestrator uses the stable Application Binary Interface
- * defined below to pass state from a pre-update kernel to a post-update
- * kernel. The ABI is built upon the Kexec HandOver framework and registers
- * the central `struct luo_ser` via the KHO raw subtree API.
+ * defined below to pass state from a source kernel to a target kernel.
+ * The ABI is built upon the Kexec HandOver framework and registers the
+ * central `struct luo_ser` via the KHO raw subtree API.
  *
- * This interface is a contract. Any modification to the structure fields,
- * compatible strings, or the layout of the `__packed` serialization
- * structures defined here constitutes a breaking change. Such changes require
- * incrementing the version number in the relevant `_COMPATIBLE` string to
- * prevent a new kernel from misinterpreting data from an old kernel.
- *
- * Changes are allowed provided the compatibility version is incremented;
- * however, backward/forward compatibility is only guaranteed for kernels
- * supporting the same ABI version.
+ * This interface is a contract. `struct luo_ser`, and the serialized state
+ * of each file handler that uses it, are preceded by `struct kho_ser_hdr`.
+ * See the KHO Serialization Feature Header ABI documentation in
+ * include/linux/kho/abi/feature.h for the header layout, the feature rules
+ * and validation.
  *
  * KHO Structure Overview:
  *   The entire LUO state is encapsulated within a single KHO entry named "LUO".
- *   This entry contains the `struct luo_ser` structure.
+ *   This entry contains a `struct kho_ser_hdr` followed by the
+ *   `struct luo_ser` payload.
  *
  * Serialization Structures:
  *   - struct luo_ser:
- *     The central ABI structure that contains the overall state of the LUO.
- *     It includes the compatibility string, the liveupdate-number, and pointers
- *     to sessions and FLBs.
+ *     The central ABI payload structure that contains the overall state of
+ *     the LUO (the liveupdate-number and physical pointers to sessions and
+ *     FLBs), preceded by `struct kho_ser_hdr`.
  *
  *   - struct luo_session_ser:
  *     Metadata for a single session, including its name and a physical pointer
@@ -40,7 +37,7 @@
  *
  *   - struct luo_file_ser:
  *     Metadata for a single preserved file. Contains the `compatible` string to
- *     find the correct handler in the new kernel, a user-provided `token` for
+ *     find the correct handler in the target kernel, a user-provided `token` for
  *     identification, and an opaque `data` handle for the handler to use.
  *
  *   - struct luo_flb_header_ser:
@@ -57,39 +54,36 @@
 #ifndef _LINUX_KHO_ABI_LUO_H
 #define _LINUX_KHO_ABI_LUO_H
 
-#include <linux/align.h>
 #include <linux/build_bug.h>
 #include <linux/kconfig.h>
 #include <linux/kho/abi/block.h>
+#include <linux/kho/abi/feature.h>
 #include <linux/kho/abi/kexec_handover.h>
+#include <linux/types.h>
 #include <uapi/linux/liveupdate.h>
 
 /*
  * The LUO state is registered under this KHO entry name.
  */
 #define LUO_KHO_ENTRY_NAME	"LUO"
-#define LUO_ABI_COMPATIBLE	"luo-v6"
-#define LUO_ABI_COMPAT_LEN	ALIGN(sizeof(LUO_ABI_COMPATIBLE), 8)
 
 /**
- * struct luo_ser - Centralized LUO ABI header.
- * @compatible:     Compatibility string identifying the LUO ABI version.
+ * struct luo_ser - Centralized LUO ABI payload.
  * @liveupdate_num: A counter tracking the number of successful live updates.
  * @sessions_pa:    Physical address of the first session block header.
  * @flbs_pa:        Physical address of the FLB header.
  *
- * This structure is the root of all preserved LUO state.
+ * This structure is the root payload of all preserved LUO state, preceded by
+ * &struct kho_ser_hdr.
  */
 struct luo_ser {
-	char compatible[LUO_ABI_COMPAT_LEN];
 	u64 liveupdate_num;
 	u64 sessions_pa;
 	u64 flbs_pa;
 };
 
-static_assert(sizeof(struct luo_ser) == 32);
-static_assert(!IS_ENABLED(CONFIG_64BIT) ||
-	      __alignof__(struct luo_ser) == 8);
+/* Register luo_ser with KHO serialization accessors */
+DECLARE_KHO_SER(luo_ser, 24, 0, 0);
 
 #define LIVEUPDATE_HNDL_COMPAT_LENGTH	48
 
@@ -98,8 +92,6 @@ static_assert(!IS_ENABLED(CONFIG_64BIT) ||
  * @compatible:  File handler compatible string.
  * @data:        Private data
  * @token:       User provided token for this file
- *
- * If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
  */
 struct luo_file_ser {
 	char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
@@ -138,10 +130,8 @@ static_assert(!IS_ENABLED(CONFIG_64BIT) ||
  *
  * This structure is used to package session-specific metadata for transfer
  * between kernels via Kexec Handover. An array of these structures (one per
- * session) is created and passed to the new kernel, allowing it to reconstruct
- * the session context.
- *
- * If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
+ * session) is created and passed to the target kernel, allowing it to
+ * reconstruct the session context.
  */
 struct luo_session_ser {
 	char name[LIVEUPDATE_SESSION_NAME_LENGTH];
@@ -180,13 +170,13 @@ static_assert(!IS_ENABLED(CONFIG_64BIT) ||
 /**
  * struct luo_flb_ser - Represents the serialized state of a single FLB object.
  * @name:    The unique compatibility string of the FLB object, used to find the
- *           corresponding &struct liveupdate_flb handler in the new kernel.
+ *           corresponding &struct liveupdate_flb in the target kernel.
  * @data:    The opaque u64 handle returned by the FLB's .preserve() operation
- *           in the old kernel. This handle encapsulates the entire state needed
- *           for restoration.
+ *           in the source kernel. This handle encapsulates the entire state
+ *           needed for restoration.
  * @count:   The reference count at the time of serialization; i.e., the number
  *           of preserved files that depended on this FLB. This is used by the
- *           new kernel to correctly manage the FLB's lifecycle.
+ *           target kernel to correctly manage the FLB's lifecycle.
  *
  * An array of these structures is created in a preserved memory region and
  * passed to the new kernel. Each entry allows the LUO core to restore one
diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
index 1b2bda22902d..d0f72f27001d 100644
--- a/kernel/liveupdate/luo_core.c
+++ b/kernel/liveupdate/luo_core.c
@@ -66,7 +66,7 @@
 
 static struct {
 	bool enabled;
-	struct luo_ser *luo_ser_out;
+	DECLARE_KHO_SER_HDR(luo_ser, *luo_ser_out);
 	u64 liveupdate_num;
 } luo_global;
 
@@ -83,6 +83,7 @@ early_param("liveupdate", early_liveupdate_param);
 
 static int __init luo_early_startup(void)
 {
+	DECLARE_KHO_SER_HDR(luo_ser, *fhdr);
 	phys_addr_t luo_ser_phys;
 	struct luo_ser *luo_ser;
 	size_t len;
@@ -107,17 +108,21 @@ static int __init luo_early_startup(void)
 		return 0;
 	}
 
-	if (len < sizeof(*luo_ser)) {
-		pr_err("LUO state is too small (%zu < %zu)\n", len, sizeof(*luo_ser));
-		return -EINVAL;
+	fhdr = phys_to_virt(luo_ser_phys);
+	if (len < sizeof(*fhdr) || fhdr->size > len) {
+		pr_err("LUO state size invalid (source kernel header size=%u, KHO len=%zu)\n",
+		       len >= sizeof(*fhdr) ? fhdr->size : 0, len);
+		err = -EINVAL;
+		goto out_free_ser;
 	}
 
-	luo_ser = phys_to_virt(luo_ser_phys);
-	if (strncmp(luo_ser->compatible, LUO_ABI_COMPATIBLE, LUO_ABI_COMPAT_LEN)) {
-		pr_err("LUO state is incompatible with '%s'\n", LUO_ABI_COMPATIBLE);
-		return -EINVAL;
+	err = kho_ser_validate(fhdr, luo_ser);
+	if (err) {
+		pr_err("LUO state feature validation failed: %pe\n", ERR_PTR(err));
+		goto out_free_ser;
 	}
 
+	luo_ser = kho_ser_payload(fhdr, luo_ser);
 	luo_global.liveupdate_num = luo_ser->liveupdate_num;
 	pr_info("Retrieved live update data, liveupdate number: %lld\n",
 		luo_global.liveupdate_num);
@@ -131,7 +136,7 @@ static int __init luo_early_startup(void)
 	err = 0;
 
 out_free_ser:
-	kho_restore_free(luo_ser);
+	kho_restore_free(fhdr);
 	return err;
 }
 
@@ -153,16 +158,18 @@ early_initcall(liveupdate_early_init);
 /* Called during boot to create outgoing LUO state */
 static int __init luo_state_setup(void)
 {
+	DECLARE_KHO_SER_HDR(luo_ser, *fhdr);
 	struct luo_ser *luo_ser;
 	int err;
 
-	luo_ser = kho_alloc_preserve(sizeof(*luo_ser));
-	if (IS_ERR(luo_ser)) {
+	fhdr = kho_alloc_preserve(kho_ser_size(luo_ser));
+	if (IS_ERR(fhdr)) {
 		pr_err("failed to allocate/preserve LUO state memory\n");
-		return PTR_ERR(luo_ser);
+		return PTR_ERR(fhdr);
 	}
+	kho_ser_init(fhdr, luo_ser);
 
-	strscpy(luo_ser->compatible, LUO_ABI_COMPATIBLE, sizeof(luo_ser->compatible));
+	luo_ser = kho_ser_payload(fhdr, luo_ser);
 	luo_ser->liveupdate_num = luo_global.liveupdate_num + 1;
 
 	luo_session_setup_outgoing(&luo_ser->sessions_pa);
@@ -171,16 +178,16 @@ static int __init luo_state_setup(void)
 	if (err)
 		goto exit_free_luo_ser;
 
-	err = kho_add_subtree(LUO_KHO_ENTRY_NAME, luo_ser, sizeof(*luo_ser));
+	err = kho_add_subtree(LUO_KHO_ENTRY_NAME, fhdr, fhdr->size);
 	if (err)
 		goto exit_free_luo_ser;
 
-	luo_global.luo_ser_out = luo_ser;
+	luo_global.luo_ser_out = fhdr;
 
 	return 0;
 
 exit_free_luo_ser:
-	kho_unpreserve_free(luo_ser);
+	kho_unpreserve_free(fhdr);
 	pr_err("failed to prepare LUO state: %d\n", err);
 
 	return err;
-- 
2.56.0.506.g506a7eabc5-goog


  parent reply	other threads:[~2026-11-10  5:02 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10  5:01 [PATCH v4 00/19] kho, liveupdate: Add feature header for fine-grained ABI compatibility Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 01/19] liveupdate, kho: Remove __packed from KHO, LUO and memfd ABI structures Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 02/19] kho: block: Record the entry size in the block header Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 03/19] kho, memfd_luo: Reference struct kho_vmalloc via serialized pointer Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 04/19] liveupdate: Reference struct luo_file_set_ser " Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 05/19] kho: Add feature header for fine-grained ABI compatibility Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 06/19] kho: kexec_metadata: Add the feature header Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 07/19] kho: vmalloc: " Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 08/19] kho: block: Add the feature header to blocks Tarun Sahu
2026-11-10  5:01 ` Tarun Sahu [this message]
2026-11-10  5:01 ` [PATCH v4 10/19] liveupdate: Add feature header to struct luo_session_ser Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 11/19] liveupdate: Add feature header to struct luo_file_set_ser Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 12/19] liveupdate: Add feature header to struct luo_file_ser Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 13/19] liveupdate: Add feature header to struct luo_flb_header_ser Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 14/19] liveupdate: Add feature header to struct luo_flb_ser Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 15/19] PCI: liveupdate: Add feature header to struct pci_ser Tarun Sahu
2026-11-10  5:01 ` [PATCH v4 16/19] PCI: liveupdate: Add feature header to struct pci_dev_ser Tarun Sahu
2026-11-10  5:02 ` [PATCH v4 17/19] mm: memfd_luo: Add feature header to struct memfd_luo_ser Tarun Sahu
2026-11-10  5:02 ` [PATCH v4 18/19] mm: memfd_luo: Add feature header to struct memfd_luo_folio_ser Tarun Sahu
2026-11-10  5:02 ` [PATCH v4 19/19] kho: Add KUnit test for the feature header helpers Tarun Sahu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261110050202.529473-10-tarunsahu@google.com \
    --to=tarunsahu@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=alex@shazbot.org \
    --cc=arnd@arndb.de \
    --cc=baolu.lu@linux.intel.com \
    --cc=bhelgaas@google.com \
    --cc=dmatlack@google.com \
    --cc=dwmw2@infradead.org \
    --cc=gle.com@google.com \
    --cc=graf@amazon.com \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@nvidia.com \
    --cc=joro@8bytes.org \
    --cc=kevin.tian@intel.com \
    --cc=kexec@lists.infradead.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=loganodell@google.com \
    --cc=maz@kernel.org \
    --cc=oupton@kernel.org \
    --cc=pasha.tatashin@soleen.com \
    --cc=pbonzini@redhat.com \
    --cc=pratyush@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=rppt@kernel.org \
    --cc=sagis@google.com \
    --cc=seanjc@google.com \
    --cc=skhawaja@google.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®