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: 12+ 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-20 14:52 ` sashiko-bot
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-26 1:10 ` Pasha Tatashin
2026-10-20 14:47 ` [PATCH v2 2/2] selftests: liveupdate: Add tests for LIVEUPDATE_SESSION_FREEZE Pasha Tatashin
2026-10-20 14:52 ` sashiko-bot
2026-10-21 10:17 ` Pratyush Yadav
2026-10-23 7:30 ` Mike Rapoport
2026-10-26 1:16 ` Pasha Tatashin
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.