From: Mike Rapoport <rppt@kernel.org>
To: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: linux-kselftest@vger.kernel.org, shuah@kernel.org,
akpm@linux-foundation.org, linux-mm@kvack.org,
vipinsh@google.com, linux-kernel@vger.kernel.org,
dmatlack@google.com, kexec@lists.infradead.org,
pratyush@kernel.org, graf@amazon.com
Subject: Re: [PATCH v2 1/2] liveupdate: Add LIVEUPDATE_SESSION_FREEZE ioctl to freeze sessions early
Date: Fri, 23 Oct 2026 10:27:33 +0300 [thread overview]
Message-ID: <atsMZW4ChOWj7Lqv@kernel.org> (raw)
In-Reply-To: <20261020144710.4154339-2-pasha.tatashin@soleen.com>
On Tue, Oct 20, 2026 at 10:47:03AM -0400, Pasha Tatashin wrote:
> Currently, LUO sessions are frozen automatically only inside the
> reboot(LINUX_REBOOT_CMD_KEXEC) pathway, where luo_session_serialize()
> iterates through all outgoing sessions under global write locks and
> freezes them serially during shutdown. Allowing userspace to decide when
> to freeze a session once it is done with it (and to freeze multiple
> sessions in parallel, since luo_session_freeze() only acquires the
> per-session mutex) avoids postponing this work to kexec shutdown and
> reduces blackout time.
>
> Introduce LIVEUPDATE_SESSION_FREEZE on session file descriptors to freeze
> a session early. The ioctl runs .freeze() across all preserved files in the
> session and serializes their metadata. Once frozen, no additional files can
> be added to the session, and subsequent freeze calls return -EBUSY. Freeze
> is only valid on outgoing sessions and returns -EINVAL on incoming ones.
>
> During kexec, sessions that were already frozen early are skipped, while
> sessions that did not invoke this ioctl auto-freeze as before. If an
> early-frozen session is released before kexec, its files are rolled back
> via .unfreeze() before being unpreserved.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
> include/linux/liveupdate.h | 3 +-
> include/uapi/linux/liveupdate.h | 25 ++++++++++
> kernel/liveupdate/luo_file.c | 73 +++++++++++++---------------
> kernel/liveupdate/luo_internal.h | 9 ++--
> kernel/liveupdate/luo_session.c | 82 +++++++++++++++++++++++++-------
> mm/memfd_luo.c | 5 +-
> 6 files changed, 134 insertions(+), 63 deletions(-)
>
> diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
> index 6051abc0612c..851692571e13 100644
> --- a/include/linux/liveupdate.h
> +++ b/include/linux/liveupdate.h
> @@ -59,7 +59,8 @@ struct liveupdate_file_op_args {
> * compatible with the given file.
> * @preserve: Required. Performs state-saving for the file.
> * @unpreserve: Required. Cleans up any resources allocated by @preserve.
> - * @freeze: Optional. Final actions just before kernel transition.
> + * @freeze: Optional. Prepares final state before kexec (via
> + * LIVEUPDATE_SESSION_FREEZE or during reboot).
> * @unfreeze: Optional. Undo freeze operations.
> * @retrieve: Required. Restores the file in the new kernel.
> * @can_finish: Optional. Check if this FD can finish, i.e. all restoration
> diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
> index 4043d4038712..1644c502521e 100644
> --- a/include/uapi/linux/liveupdate.h
> +++ b/include/uapi/linux/liveupdate.h
> @@ -60,6 +60,7 @@ enum {
> LIVEUPDATE_CMD_SESSION_RETRIEVE_FD = 0x41,
> LIVEUPDATE_CMD_SESSION_FINISH = 0x42,
> LIVEUPDATE_CMD_SESSION_GET_NAME = 0x43,
> + LIVEUPDATE_CMD_SESSION_FREEZE = 0x44,
> };
>
> /**
> @@ -236,4 +237,28 @@ struct liveupdate_session_get_name {
> #define LIVEUPDATE_SESSION_GET_NAME \
> _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_GET_NAME)
>
> +/**
> + * struct liveupdate_session_freeze - ioctl(LIVEUPDATE_SESSION_FREEZE)
> + * @size: Input; sizeof(struct liveupdate_session_freeze)
> + * @reserved: Input; Must be zero. Reserved for future use.
> + *
> + * Freezes the session early from userspace before the reboot kexec phase.
> + *
> + * When this ioctl is called, the kernel executes the .freeze() callback on all
> + * preserved files in the session and serializes their metadata. Once frozen,
> + * no further files can be preserved in the session.
> + *
> + * During the subsequent reboot kexec, this session is recognized as already
Nit: kexec reboot
> + * frozen and is skipped from the late auto freeze.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +struct liveupdate_session_freeze {
> + __u32 size;
> + __u32 reserved;
> +};
> +
> +#define LIVEUPDATE_SESSION_FREEZE \
> + _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_FREEZE)
> +
> #endif /* _UAPI_LIVEUPDATE_H */
> diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
> index a39992da504f..7f79890beb31 100644
> --- a/kernel/liveupdate/luo_file.c
> +++ b/kernel/liveupdate/luo_file.c
> @@ -31,9 +31,9 @@
> * - unpreserve(): Cleans up any resources allocated by .preserve(), called
> * if the preservation process is aborted before the reboot (i.e. session is
> * closed).
> - * - freeze(): A final pre-reboot opportunity to prepare the state for kexec.
> - * We are already in reboot syscall, and therefore userspace cannot mutate
> - * the file anymore.
> + * - freeze(): Prepares the final state for kexec. Invoked either early via
Nit: I'd drop "early", it seems relevant only to the current change, but
will be more confusing than useful later.
> + * the LIVEUPDATE_SESSION_FREEZE ioctl once userspace is done modifying
> + * the session's files, or during the reboot() syscall.
> * - unfreeze(): Undoes the actions of .freeze(), called if the live update
> * is aborted after the freeze phase.
> * - retrieve(): Reconstructs the file in the new kernel from the preserved
> @@ -48,7 +48,8 @@
> * handler, calls its .preserve() operation, and creates an internal &struct
> * luo_file to track the live state.
> *
> - * 2. Freeze (Pre-Reboot): Just before the kexec, luo_file_freeze() is called.
> + * 2. Freeze (Pre-Reboot): Either explicitly via LIVEUPDATE_SESSION_FREEZE or
> + * just before the kexec during reboot(), luo_file_freeze() is called.
> * It iterates through all preserved files, calls their respective .freeze()
> * operation, and serializes their final metadata (compatible string, token,
> * and data handle) into a contiguous memory block for KHO.
> @@ -74,15 +75,16 @@
> *
> * 1. Abort Before Reboot: If the userspace agent aborts the live update
> * process before calling reboot (e.g., by closing the session file
> - * descriptor), the session's release handler calls
> - * luo_file_unpreserve_files(). This invokes the .unpreserve() callback on
> - * all preserved files, ensuring all allocated resources are cleaned up and
> - * returning the system to a clean state.
> + * descriptor), the session's release handler unfreezes the files if the
> + * session was already frozen and calls luo_file_unpreserve_files(). This
> + * invokes the .unpreserve() callback on all preserved files, ensuring all
> + * allocated resources are cleaned up and returning the system to a clean
> + * state.
> *
> - * 2. Freeze Failure: During the reboot() syscall, if any handler's .freeze()
> - * op fails, the .unfreeze() op is invoked on all previously *successful*
> - * freezes to roll back their state. The reboot() syscall then returns an
> - * error to userspace, canceling the live update.
> + * 2. Freeze Failure: During LIVEUPDATE_SESSION_FREEZE or the reboot() syscall,
> + * if any handler's .freeze() op fails, the .unfreeze() op is invoked on all
> + * previously *successful* freezes to roll back their state, and an error is
> + * returned to userspace.
I think we still want to say that freeze failure at reboot cancels live
update.
> *
> * 3. Finish Failure: In the new kernel, if a handler's .finish() op fails,
> * the luo_file_finish() operation is aborted. LUO retains ownership of
> @@ -440,12 +442,11 @@ 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
> - * final preparation and serialization of all preserved files in the file_set.
> + * This function is called from LIVEUPDATE_SESSION_FREEZE or from the reboot()
> + * syscall path. Its purpose is to perform the preparation and serialization of
Nit: ^ final?
> + * all preserved files in the file_set.
> *
> * It iterates through each preserved file in FIFO order (the order of
> * preservation) and performs two main actions:
> @@ -457,22 +458,20 @@ 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
> - * entire live update is aborted. The __luo_file_unfreeze() helper is
> - * immediately called to invoke the .unfreeze() op on all files that were
> - * successfully frozen before the point of failure, rolling them back to a
> - * running state. The function then returns an error, causing the reboot()
> - * syscall to fail.
> + * __luo_file_unfreeze() helper is immediately called to invoke the .unfreeze()
> + * op on all files that were successfully frozen before the point of failure,
> + * rolling them back to an unfrozen state, and an error is returned to the
> + * caller.
Don't you want to say that reboot is canceled here too?
> *
> - * Context: Called only from the liveupdate_reboot() path.
> + * Context: Called from LIVEUPDATE_SESSION_FREEZE or 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 +505,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 +515,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().
> + * freeze phase has begun. 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.
> + * the reboot() syscall, after luo_file_freeze() has been called,
> + * or when an early-frozen session is released before kexec.
> */
> -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)
I went several time back and forth trying to understand why we remove
*file_set_ser here.
Maybe add a preparation patch that does the renames and moves file_set_ser
handling?
> {
> 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..b3fc3dcf5f36 100644
> --- a/kernel/liveupdate/luo_internal.h
> +++ b/kernel/liveupdate/luo_internal.h
> @@ -64,6 +64,8 @@ struct luo_file_set {
> * previous kernel) sessions.
> * @retrieved: A boolean flag indicating whether this session has been
> * retrieved by a consumer in the new kernel.
> + * @frozen: A boolean flag indicating whether this session has been
> + * frozen early from userspace.
s/early/explicitly
> * @file_set: A set of files that belong to this session.
> * @mutex: protects fields in the luo_session.
> */
> @@ -71,6 +73,7 @@ struct luo_session {
> char name[LIVEUPDATE_SESSION_NAME_LENGTH];
> struct list_head list;
> bool retrieved;
> + bool frozen;
> struct luo_file_set file_set;
> struct mutex mutex;
> };
--
Sincerely yours,
Mike.
next prev parent reply other threads:[~2026-10-23 7:27 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 14:47 [PATCH v2 0/2] liveupdate: Add LIVEUPDATE_SESSION_FREEZE ioctl Pasha Tatashin
2026-10-20 14:47 ` [PATCH v2 1/2] liveupdate: Add LIVEUPDATE_SESSION_FREEZE ioctl to freeze sessions early Pasha Tatashin
2026-10-21 10:14 ` Pratyush Yadav
2026-10-22 1:44 ` Pasha Tatashin
2026-10-23 7:27 ` Mike Rapoport [this message]
2026-10-20 14:47 ` [PATCH v2 2/2] selftests: liveupdate: Add tests for LIVEUPDATE_SESSION_FREEZE Pasha Tatashin
2026-10-21 10:17 ` Pratyush Yadav
2026-10-23 7:30 ` Mike Rapoport
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=atsMZW4ChOWj7Lqv@kernel.org \
--to=rppt@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=dmatlack@google.com \
--cc=graf@amazon.com \
--cc=kexec@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=pasha.tatashin@soleen.com \
--cc=pratyush@kernel.org \
--cc=shuah@kernel.org \
--cc=vipinsh@google.com \
/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®