[PATCH v4 12/19] liveupdate: Add feature header to struct luo_file_ser

From: Tarun Sahu

Date: Tue Nov 10 2026 - 00:08:11 EST


Precede each serialized file entry in a LUO file set KHO block set with
struct kho_ser_hdr via DECLARE_KHO_SER so future per-file metadata
features can append fields to struct luo_file_ser without breaking
compatibility between adjacent kernels.

Initialize file set block sets with kho_ser_size(luo_file_ser), initialize
each entry feature header in luo_file_freeze(), and validate the incoming
feature header in luo_file_deserialize_one() before accessing the struct
luo_file_ser payload.

Signed-off-by: Tarun Sahu <tarunsahu@xxxxxxxxxx>
---
include/linux/kho/abi/luo.h | 6 +++---
kernel/liveupdate/luo_file.c | 26 +++++++++++++++++++-------
2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h
index bd19211c64e1..38b4658183a2 100644
--- a/include/linux/kho/abi/luo.h
+++ b/include/linux/kho/abi/luo.h
@@ -92,6 +92,8 @@ DECLARE_KHO_SER(luo_ser, 24, 0, 0);
* @compatible: File handler compatible string.
* @data: Private data
* @token: User provided token for this file
+ *
+ * Preceded by &struct kho_ser_hdr.
*/
struct luo_file_ser {
char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
@@ -99,9 +101,7 @@ struct luo_file_ser {
u64 token;
};

-static_assert(sizeof(struct luo_file_ser) == 64);
-static_assert(!IS_ENABLED(CONFIG_64BIT) ||
- __alignof__(struct luo_file_ser) == 8);
+DECLARE_KHO_SER(luo_file_ser, 64, 0, 0);

/**
* struct luo_file_set_ser - Represents the serialized metadata for file set
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 02d09a80d785..2da327f8bdae 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -486,10 +486,12 @@ int luo_file_freeze(struct luo_file_set *file_set,
kho_block_set_it_init(&it, &file_set->block_set);

list_for_each_entry(luo_file, &file_set->files_list, list) {
- struct luo_file_ser *file_ser = kho_block_set_it_reserve_entry(&it);
+ DECLARE_KHO_SER_HDR(luo_file_ser, *fhdr) =
+ kho_block_set_it_reserve_entry(&it);
+ struct luo_file_ser *file_ser;

/* This should not fail normally as blocks were pre-allocated */
- if (WARN_ON_ONCE(!file_ser)) {
+ if (WARN_ON_ONCE(!fhdr)) {
err = -ENOSPC;
goto err_unfreeze;
}
@@ -502,6 +504,8 @@ int luo_file_freeze(struct luo_file_set *file_set,
goto err_unfreeze;
}

+ kho_ser_init(fhdr, luo_file_ser);
+ file_ser = kho_ser_payload(fhdr, luo_file_ser);
strscpy(file_ser->compatible, luo_file->fh->compatible,
sizeof(file_ser->compatible));
file_ser->data = luo_file->serialized_data;
@@ -742,11 +746,19 @@ int luo_file_finish(struct luo_file_set *file_set)
}

static int luo_file_deserialize_one(struct luo_file_set *file_set,
- struct luo_file_ser *ser)
+ DECLARE_KHO_SER_HDR(luo_file_ser, *fhdr))
{
struct liveupdate_file_handler *fh;
bool handler_found = false;
+ struct luo_file_ser *ser;
struct luo_file *luo_file;
+ int err;
+
+ err = kho_ser_validate(fhdr, luo_file_ser);
+ if (err)
+ return err;
+
+ ser = kho_ser_payload(fhdr, luo_file_ser);

down_read(&luo_register_rwlock);
list_private_for_each_entry(fh, &luo_file_handler_list, list) {
@@ -810,7 +822,7 @@ int luo_file_deserialize(struct luo_file_set *file_set,
DECLARE_KHO_SER_HDR(luo_file_set_ser, *file_set_fhdr))
{
struct luo_file_set_ser *file_set_ser;
- struct luo_file_ser *file_ser;
+ DECLARE_KHO_SER_HDR(luo_file_ser, *fhdr);
struct kho_block_set_it it;
int err;

@@ -848,8 +860,8 @@ int luo_file_deserialize(struct luo_file_set *file_set,
* reliably reset devices and reclaim memory.
*/
kho_block_set_it_init(&it, &file_set->block_set);
- while ((file_ser = kho_block_set_it_read_entry(&it))) {
- err = luo_file_deserialize_one(file_set, file_ser);
+ while ((fhdr = kho_block_set_it_read_entry(&it))) {
+ err = luo_file_deserialize_one(file_set, fhdr);
if (err)
goto err_destroy_blocks;
file_set->count++;
@@ -883,7 +895,7 @@ int luo_file_deserialize(struct luo_file_set *file_set,
void luo_file_set_init(struct luo_file_set *file_set)
{
INIT_LIST_HEAD(&file_set->files_list);
- kho_block_set_init(&file_set->block_set, sizeof(struct luo_file_ser));
+ kho_block_set_init(&file_set->block_set, kho_ser_size(luo_file_ser));
}

void luo_file_set_destroy(struct luo_file_set *file_set)
--
2.56.0.506.g506a7eabc5-goog