[PATCH v5 1/6] liveupdate: Move file_set_ser handling to luo_session_serialize()

From: Pasha Tatashin

Date: Thu Nov 05 2026 - 00:01:29 EST


In preparation for allowing userspace to freeze a session explicitly
before kexec reboot, luo_file_freeze() and luo_file_unfreeze() need to
be called on session->file_set before any struct luo_session_ser entry
is reserved in luo_session_serialize().

Currently, struct luo_session_ser is populated and cleared across two
layers: luo_session_serialize() writes and clears ser->name, while
luo_file_freeze() and luo_file_unfreeze() write and clear
ser->file_set_ser.

Drop the struct luo_file_set_ser pointer parameter from
luo_file_freeze() and luo_file_unfreeze() (and struct luo_session_ser
from luo_session_freeze_one() and luo_session_unfreeze_one()), and
populate and clear all fields of struct luo_session_ser in
luo_session_serialize().

Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
---
kernel/liveupdate/luo_file.c | 24 ++++++++----------------
kernel/liveupdate/luo_internal.h | 6 ++----
kernel/liveupdate/luo_session.c | 19 ++++++++++---------
3 files changed, 20 insertions(+), 29 deletions(-)

diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index a39992da504f..988eb313a135 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -440,8 +440,7 @@ static void __luo_file_unfreeze(struct luo_file_set *file_set,

/**
* luo_file_freeze - Freezes all preserved files and serializes their metadata.
- * @file_set: The file_set whose files are to be frozen.
- * @file_set_ser: Where to put the serialized file_set.
+ * @file_set: The file_set whose files are to be frozen.
*
* This function is called from the reboot() syscall path, just before the
* kernel transitions to the new image via kexec. Its purpose is to perform the
@@ -457,8 +456,8 @@ static void __luo_file_unfreeze(struct luo_file_set *file_set,
*
* 2. Serializes Metadata: After a successful freeze, it copies the final file
* metadata—the handler's compatible string, the user token, and the final
- * private data handle—into the pre-allocated contiguous memory buffer
- * (file_set->files) that will be handed over to the next kernel via KHO.
+ * private data handle—into the pre-allocated serialization blocks
+ * (file_set->block_set) that will be handed over to the next kernel via KHO.
*
* Error Handling (Rollback):
* This function is atomic. If any handler's .freeze() operation fails, the
@@ -471,8 +470,7 @@ static void __luo_file_unfreeze(struct luo_file_set *file_set,
* Context: Called only from the liveupdate_reboot() path.
* Return: 0 on success, or a negative errno on failure.
*/
-int luo_file_freeze(struct luo_file_set *file_set,
- struct luo_file_set_ser *file_set_ser)
+int luo_file_freeze(struct luo_file_set *file_set)
{
struct luo_file *luo_file;
struct kho_block_set_it it;
@@ -506,9 +504,6 @@ int luo_file_freeze(struct luo_file_set *file_set,
file_ser->token = luo_file->token;
}

- file_set_ser->count = file_set->count;
- file_set_ser->files = kho_block_set_head_pa(&file_set->block_set);
-
return 0;

err_unfreeze:
@@ -519,28 +514,25 @@ int luo_file_freeze(struct luo_file_set *file_set,

/**
* luo_file_unfreeze - Unfreezes all files in a file_set and clear serialization
- * @file_set: The file_set whose files are to be unfrozen.
- * @file_set_ser: Serialized file_set.
+ * @file_set: The file_set whose files are to be unfrozen.
*
* This function rolls back the state of all files in a file_set after the
* freeze phase has begun but must be aborted. It is the counterpart to
* luo_file_freeze().
*
* It invokes the __luo_file_unfreeze() helper with a NULL argument, which
- * signals the helper to iterate through all files in the file_set and call
- * their respective .unfreeze() handler callbacks.
+ * signals the helper to iterate through all files in the file_set, call their
+ * respective .unfreeze() handler callbacks, and clear the serialized blocks.
*
* Context: This is called when the live update is aborted during
* the reboot() syscall, after luo_file_freeze() has been called.
*/
-void luo_file_unfreeze(struct luo_file_set *file_set,
- struct luo_file_set_ser *file_set_ser)
+void luo_file_unfreeze(struct luo_file_set *file_set)
{
if (!file_set->count)
return;

__luo_file_unfreeze(file_set, NULL);
- memset(file_set_ser, 0, sizeof(*file_set_ser));
}

/**
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index dac6644bfb18..01a172cd9d7a 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -103,10 +103,8 @@ int luo_session_deserialize(void);

int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd);
void luo_file_unpreserve_files(struct luo_file_set *file_set);
-int luo_file_freeze(struct luo_file_set *file_set,
- struct luo_file_set_ser *file_set_ser);
-void luo_file_unfreeze(struct luo_file_set *file_set,
- struct luo_file_set_ser *file_set_ser);
+int luo_file_freeze(struct luo_file_set *file_set);
+void luo_file_unfreeze(struct luo_file_set *file_set);
int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
struct file **filep);
int luo_file_finish(struct luo_file_set *file_set);
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 74bc66929f4b..6dea35911181 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -219,18 +219,16 @@ static int luo_session_finish_one(struct luo_session *session)
return luo_file_finish(&session->file_set);
}

-static void luo_session_unfreeze_one(struct luo_session *session,
- struct luo_session_ser *ser)
+static void luo_session_unfreeze_one(struct luo_session *session)
{
guard(mutex)(&session->mutex);
- luo_file_unfreeze(&session->file_set, &ser->file_set_ser);
+ luo_file_unfreeze(&session->file_set);
}

-static int luo_session_freeze_one(struct luo_session *session,
- struct luo_session_ser *ser)
+static int luo_session_freeze_one(struct luo_session *session)
{
guard(mutex)(&session->mutex);
- return luo_file_freeze(&session->file_set, &ser->file_set_ser);
+ return luo_file_freeze(&session->file_set);
}

static int luo_session_release(struct inode *inodep, struct file *filep)
@@ -657,13 +655,16 @@ int luo_session_serialize(void)
goto err_undo;
}

- err = luo_session_freeze_one(session, ser);
+ err = luo_session_freeze_one(session);
if (err) {
kho_block_set_it_prev(&it);
goto err_undo;
}

strscpy(ser->name, session->name, sizeof(ser->name));
+ ser->file_set_ser.count = session->file_set.count;
+ ser->file_set_ser.files =
+ kho_block_set_head_pa(&session->file_set.block_set);
}

if (sh->count > 0)
@@ -676,8 +677,8 @@ int luo_session_serialize(void)
list_for_each_entry_continue_reverse(session, &sh->list, list) {
struct luo_session_ser *ser = kho_block_set_it_prev(&it);

- luo_session_unfreeze_one(session, ser);
- memset(ser->name, 0, sizeof(ser->name));
+ luo_session_unfreeze_one(session);
+ memset(ser, 0, sizeof(*ser));
}
up_write(&sh->rwsem);
up_write(&luo_session_serialize_rwsem);
--
2.56.0.398.g882cbad275-goog