[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250807014442.3829950-19-pasha.tatashin@soleen.com>
Date: Thu, 7 Aug 2025 01:44:24 +0000
From: Pasha Tatashin <pasha.tatashin@...een.com>
To: pratyush@...nel.org,
jasonmiu@...gle.com,
graf@...zon.com,
changyuanl@...gle.com,
pasha.tatashin@...een.com,
rppt@...nel.org,
dmatlack@...gle.com,
rientjes@...gle.com,
corbet@....net,
rdunlap@...radead.org,
ilpo.jarvinen@...ux.intel.com,
kanie@...ux.alibaba.com,
ojeda@...nel.org,
aliceryhl@...gle.com,
masahiroy@...nel.org,
akpm@...ux-foundation.org,
tj@...nel.org,
yoann.congal@...le.fr,
mmaurer@...gle.com,
roman.gushchin@...ux.dev,
chenridong@...wei.com,
axboe@...nel.dk,
mark.rutland@....com,
jannh@...gle.com,
vincent.guittot@...aro.org,
hannes@...xchg.org,
dan.j.williams@...el.com,
david@...hat.com,
joel.granados@...nel.org,
rostedt@...dmis.org,
anna.schumaker@...cle.com,
song@...nel.org,
zhangguopeng@...inos.cn,
linux@...ssschuh.net,
linux-kernel@...r.kernel.org,
linux-doc@...r.kernel.org,
linux-mm@...ck.org,
gregkh@...uxfoundation.org,
tglx@...utronix.de,
mingo@...hat.com,
bp@...en8.de,
dave.hansen@...ux.intel.com,
x86@...nel.org,
hpa@...or.com,
rafael@...nel.org,
dakr@...nel.org,
bartosz.golaszewski@...aro.org,
cw00.choi@...sung.com,
myungjoo.ham@...sung.com,
yesanishhere@...il.com,
Jonathan.Cameron@...wei.com,
quic_zijuhu@...cinc.com,
aleksander.lobakin@...el.com,
ira.weiny@...el.com,
andriy.shevchenko@...ux.intel.com,
leon@...nel.org,
lukas@...ner.de,
bhelgaas@...gle.com,
wagi@...nel.org,
djeffery@...hat.com,
stuart.w.hayes@...il.com,
ptyadav@...zon.de,
lennart@...ttering.net,
brauner@...nel.org,
linux-api@...r.kernel.org,
linux-fsdevel@...r.kernel.org,
saeedm@...dia.com,
ajayachandra@...dia.com,
jgg@...dia.com,
parav@...dia.com,
leonro@...dia.com,
witu@...dia.com
Subject: [PATCH v3 18/30] liveupdate: luo_files: luo_ioctl: Add ioctls for per-file state management
Introduce a set of new ioctls to allow a userspace agent to query and
control the live update state of individual file descriptors that have
been registered for preservation.
Previously, state transitions (prepare, freeze, finish) were handled
globally for all registered resources by the main LUO state machine.
This patch provides a more granular interface, enabling a controlling
agent to manage the lifecycle of specific FDs independently, which is
useful for performance reasons.
- Adds LIVEUPDATE_IOCTL_GET_FD_STATE to query the current state
(e.g., NORMAL, PREPARED, FROZEN) of a file identified by its token.
- Adds LIVEUPDATE_IOCTL_SET_FD_EVENT to trigger state transitions
(PREPARE, FREEZE, CANCEL, FINISH) for a single file.
Signed-off-by: Pasha Tatashin <pasha.tatashin@...een.com>
---
include/uapi/linux/liveupdate.h | 62 +++++++++++++
kernel/liveupdate/luo_files.c | 152 +++++++++++++++++++++++++++++++
kernel/liveupdate/luo_internal.h | 8 ++
kernel/liveupdate/luo_ioctl.c | 48 ++++++++++
4 files changed, 270 insertions(+)
diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
index 37ec5656443b..833da5a8c064 100644
--- a/include/uapi/linux/liveupdate.h
+++ b/include/uapi/linux/liveupdate.h
@@ -128,6 +128,8 @@ enum {
LIVEUPDATE_CMD_FD_RESTORE = 0x02,
LIVEUPDATE_CMD_GET_STATE = 0x03,
LIVEUPDATE_CMD_SET_EVENT = 0x04,
+ LIVEUPDATE_CMD_GET_FD_STATE = 0x05,
+ LIVEUPDATE_CMD_SET_FD_EVENT = 0x06,
};
/**
@@ -334,4 +336,64 @@ struct liveupdate_ioctl_set_event {
#define LIVEUPDATE_IOCTL_SET_EVENT \
_IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SET_EVENT)
+/**
+ * struct liveupdate_ioctl_get_fd_state - ioctl(LIVEUPDATE_IOCTL_GET_FD_STATE)
+ * @size: Input; sizeof(struct liveupdate_ioctl_get_fd_state)
+ * @incoming: Input; If 1, query the state of a restored file from the incoming
+ * (previous kernel's) set. If 0, query a file being prepared for
+ * preservation in the current set.
+ * @token: Input; Token of FD for which to get state.
+ * @state: Output; The live update state of this FD.
+ *
+ * Query the current live update state of a specific preserved file descriptor.
+ *
+ * - %LIVEUPDATE_STATE_NORMAL: Default state
+ * - %LIVEUPDATE_STATE_PREPARED: Prepare callback has been performed on this FD.
+ * - %LIVEUPDATE_STATE_FROZEN: Freeze callback ahs been performed on this FD.
+ * - %LIVEUPDATE_STATE_UPDATED: The system has successfully rebooted into the
+ * new kernel.
+ *
+ * See the definition of &enum liveupdate_state for more details on each state.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+struct liveupdate_ioctl_get_fd_state {
+ __u32 size;
+ __u8 incoming;
+ __aligned_u64 token;
+ __u32 state;
+};
+
+#define LIVEUPDATE_IOCTL_GET_FD_STATE \
+ _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_GET_FD_STATE)
+
+/**
+ * struct liveupdate_ioctl_set_fd_event - ioctl(LIVEUPDATE_IOCTL_SET_FD_EVENT)
+ * @size: Input; sizeof(struct liveupdate_ioctl_set_fd_event)
+ * @event: Input; The live update event.
+ * @token: Input; Token of FD for which to set the provided event.
+ *
+ * Notify a specific preserved file descriptor of an event, that causes a state
+ * transition for that file descriptor.
+ *
+ * Event, can be one of the following:
+ *
+ * - %LIVEUPDATE_PREPARE: Initiates the FD live update preparation phase.
+ * - %LIVEUPDATE_FREEZE: Initiates the FD live update freeze phase.
+ * - %LIVEUPDATE_CANCEL: Cancel the FD preparation or freeze phase.
+ * - %LIVEUPDATE_FINISH: FD Restoration completion and trigger cleanup.
+ *
+ * See the definition of &enum liveupdate_event for more details on each state.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+struct liveupdate_ioctl_set_fd_event {
+ __u32 size;
+ __u32 event;
+ __aligned_u64 token;
+};
+
+#define LIVEUPDATE_IOCTL_SET_FD_EVENT \
+ _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SET_FD_EVENT)
+
#endif /* _UAPI_LIVEUPDATE_H */
diff --git a/kernel/liveupdate/luo_files.c b/kernel/liveupdate/luo_files.c
index 63f8b086b785..0d68d0c8c45e 100644
--- a/kernel/liveupdate/luo_files.c
+++ b/kernel/liveupdate/luo_files.c
@@ -740,6 +740,158 @@ void luo_unregister_all_files(void)
WARN_ON_ONCE(atomic64_read(&luo_files_count) != 0);
}
+/**
+ * luo_file_get_state - Get the preservation state of a specific file.
+ * @token: The token of the file to query.
+ * @statep: Output pointer to store the file's current live update state.
+ * @incoming: If true, query the state of a restored file from the incoming
+ * (previous kernel's) set. If false, query a file being prepared
+ * for preservation in the current set.
+ *
+ * Finds the file associated with the given @token in either the incoming
+ * or outgoing tracking arrays and returns its current LUO state
+ * (NORMAL, PREPARED, FROZEN, UPDATED).
+ *
+ * Return: 0 on success, -ENOENT if the token is not found.
+ */
+int luo_file_get_state(u64 token, enum liveupdate_state *statep, bool incoming)
+{
+ struct luo_file *luo_file;
+ struct xarray *target_xa;
+ int ret = 0;
+
+ luo_state_read_enter();
+
+ target_xa = incoming ? &luo_files_xa_in : &luo_files_xa_out;
+ luo_file = xa_load(target_xa, token);
+
+ if (!luo_file) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ scoped_guard(mutex, &luo_file->mutex)
+ *statep = luo_file->state;
+
+out_unlock:
+ luo_state_read_exit();
+ return ret;
+}
+
+/**
+ * luo_file_prepare - Prepare a single registered file for live update.
+ * @token: The token of the file to prepare.
+ *
+ * Finds the file associated with @token and transitions it to the PREPARED
+ * state by invoking its handler's ->prepare() callback. This allows for
+ * granular, per-file preparation before the global LUO PREPARE event.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int luo_file_prepare(u64 token)
+{
+ struct luo_file *luo_file;
+ int ret;
+
+ luo_state_read_enter();
+ luo_file = xa_load(&luo_files_xa_out, token);
+ if (!luo_file) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ ret = luo_files_prepare_one(luo_file);
+out_unlock:
+ luo_state_read_exit();
+ return ret;
+}
+
+/**
+ * luo_file_freeze - Freeze a single prepared file for live update.
+ * @token: The token of the file to freeze.
+ *
+ * Finds the file associated with @token and transitions it from the PREPARED
+ * to the FROZEN state by invoking its handler's ->freeze() callback. This is
+ * typically used for final, "blackout window" state saving for a specific
+ * file.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int luo_file_freeze(u64 token)
+{
+ struct luo_file *luo_file;
+ int ret;
+
+ luo_state_read_enter();
+ luo_file = xa_load(&luo_files_xa_out, token);
+ if (!luo_file) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ ret = luo_files_freeze_one(luo_file);
+out_unlock:
+ luo_state_read_exit();
+ return ret;
+}
+
+int luo_file_cancel(u64 token)
+{
+ struct luo_file *luo_file;
+ int ret = 0;
+
+ luo_state_read_enter();
+ luo_file = xa_load(&luo_files_xa_out, token);
+ if (!luo_file) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ luo_files_cancel_one(luo_file);
+out_unlock:
+ luo_state_read_exit();
+ return ret;
+}
+
+/**
+ * luo_file_finish - Clean-up a single restored file after live update.
+ * @token: The token of the file to finalize.
+ *
+ * This function is called in the new kernel after a live update, typically
+ * after a file has been restored via luo_retrieve_file() and is no longer
+ * needed by the userspace agent in its preserved state. It invokes the
+ * handler's ->finish() callback, allowing for any final cleanup of the
+ * preserved state associated with this specific file.
+ *
+ * This must be called when LUO is in the UPDATED state.
+ *
+ * Return: 0 on success, -ENOENT if the token is not found, -EBUSY if not
+ * in the UPDATED state.
+ */
+int luo_file_finish(u64 token)
+{
+ struct luo_file *luo_file;
+ int ret = 0;
+
+ luo_state_read_enter();
+ if (!liveupdate_state_updated()) {
+ pr_warn("finish can only be done in UPDATED state\n");
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ luo_file = xa_load(&luo_files_xa_in, token);
+ if (!luo_file) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ luo_files_finish_one(luo_file);
+out_unlock:
+ luo_state_read_exit();
+ return ret;
+}
+
/**
* luo_retrieve_file - Find a registered file instance by its token.
* @token: The unique token of the file instance to retrieve.
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index 189e032d7738..01bd0d3b023b 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -8,6 +8,8 @@
#ifndef _LINUX_LUO_INTERNAL_H
#define _LINUX_LUO_INTERNAL_H
+#include <uapi/linux/liveupdate.h>
+
/*
* Handles a deserialization failure: devices and memory is in unpredictable
* state.
@@ -39,4 +41,10 @@ int luo_register_file(u64 token, int fd);
int luo_unregister_file(u64 token);
void luo_unregister_all_files(void);
+int luo_file_get_state(u64 token, enum liveupdate_state *statep, bool incoming);
+int luo_file_prepare(u64 token);
+int luo_file_freeze(u64 token);
+int luo_file_cancel(u64 token);
+int luo_file_finish(u64 token);
+
#endif /* _LINUX_LUO_INTERNAL_H */
diff --git a/kernel/liveupdate/luo_ioctl.c b/kernel/liveupdate/luo_ioctl.c
index 7ca33d1c868f..4c0f6708e411 100644
--- a/kernel/liveupdate/luo_ioctl.c
+++ b/kernel/liveupdate/luo_ioctl.c
@@ -127,6 +127,48 @@ static int luo_ioctl_set_event(struct luo_ucmd *ucmd)
return ret;
}
+static int luo_ioctl_get_fd_state(struct luo_ucmd *ucmd)
+{
+ struct liveupdate_ioctl_get_fd_state *argp = ucmd->cmd;
+ enum liveupdate_state state;
+ int ret;
+
+ ret = luo_file_get_state(argp->token, &state, !!argp->incoming);
+ if (ret)
+ return ret;
+
+ argp->state = state;
+ if (copy_to_user(ucmd->ubuffer, argp, ucmd->user_size))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int luo_ioctl_set_fd_event(struct luo_ucmd *ucmd)
+{
+ struct liveupdate_ioctl_set_fd_event *argp = ucmd->cmd;
+ int ret;
+
+ switch (argp->event) {
+ case LIVEUPDATE_PREPARE:
+ ret = luo_file_prepare(argp->token);
+ break;
+ case LIVEUPDATE_FREEZE:
+ ret = luo_file_freeze(argp->token);
+ break;
+ case LIVEUPDATE_FINISH:
+ ret = luo_file_finish(argp->token);
+ break;
+ case LIVEUPDATE_CANCEL:
+ ret = luo_file_cancel(argp->token);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static int luo_open(struct inode *inodep, struct file *filep)
{
if (atomic_cmpxchg(&luo_device_in_use, 0, 1))
@@ -149,6 +191,8 @@ union ucmd_buffer {
struct liveupdate_ioctl_fd_restore restore;
struct liveupdate_ioctl_get_state state;
struct liveupdate_ioctl_set_event event;
+ struct liveupdate_ioctl_get_fd_state fd_state;
+ struct liveupdate_ioctl_set_fd_event fd_event;
};
struct luo_ioctl_op {
@@ -179,6 +223,10 @@ static const struct luo_ioctl_op luo_ioctl_ops[] = {
struct liveupdate_ioctl_get_state, state),
IOCTL_OP(LIVEUPDATE_IOCTL_SET_EVENT, luo_ioctl_set_event,
struct liveupdate_ioctl_set_event, event),
+ IOCTL_OP(LIVEUPDATE_IOCTL_GET_FD_STATE, luo_ioctl_get_fd_state,
+ struct liveupdate_ioctl_get_fd_state, token),
+ IOCTL_OP(LIVEUPDATE_IOCTL_SET_FD_EVENT, luo_ioctl_set_fd_event,
+ struct liveupdate_ioctl_set_fd_event, token),
};
static long luo_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
--
2.50.1.565.gc32cd1483b-goog
Powered by blists - more mailing lists