Commit 7c722a7f authored by Pasha Tatashin's avatar Pasha Tatashin Committed by Andrew Morton
Browse files

liveupdate: luo_file: implement file systems callbacks

This patch implements the core mechanism for managing preserved files
throughout the live update lifecycle.  It provides the logic to invoke the
file handler callbacks (preserve, unpreserve, freeze, unfreeze, retrieve,
and finish) at the appropriate stages.

During the reboot phase, luo_file_freeze() serializes the final metadata
for each file (handler compatible string, token, and data handle) into a
memory region preserved by KHO.  In the new kernel, luo_file_deserialize()
reconstructs the in-memory file list from this data, preparing the session
for retrieval.

Link: https://lkml.kernel.org/r/20251125165850.3389713-7-pasha.tatashin@soleen.com


Signed-off-by: default avatarPasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: default avatarMike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: default avatarPratyush Yadav <pratyush@kernel.org>
Tested-by: default avatarDavid Matlack <dmatlack@google.com>
Cc: Aleksander Lobakin <aleksander.lobakin@intel.com>
Cc: Alexander Graf <graf@amazon.com>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Andriy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: anish kumar <yesanishhere@gmail.com>
Cc: Anna Schumaker <anna.schumaker@oracle.com>
Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Borislav Betkov <bp@alien8.de>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Chen Ridong <chenridong@huawei.com>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Daniel Wagner <wagi@kernel.org>
Cc: Danilo Krummrich <dakr@kernel.org>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Jeffery <djeffery@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Guixin Liu <kanie@linux.alibaba.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Ira Weiny <ira.weiny@intel.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Joanthan Cameron <Jonathan.Cameron@huawei.com>
Cc: Joel Granados <joel.granados@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lennart Poettering <lennart@poettering.net>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Lukas Wunner <lukas@wunner.de>
Cc: Marc Rutland <mark.rutland@arm.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Matthew Maurer <mmaurer@google.com>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Myugnjoo Ham <myungjoo.ham@samsung.com>
Cc: Parav Pandit <parav@nvidia.com>
Cc: Pratyush Yadav <ptyadav@amazon.de>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Saeed Mahameed <saeedm@nvidia.com>
Cc: Samiullah Khawaja <skhawaja@google.com>
Cc: Song Liu <song@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Stuart Hayes <stuart.w.hayes@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Thomas Gleinxer <tglx@linutronix.de>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: William Tu <witu@nvidia.com>
Cc: Yoann Congal <yoann.congal@smile.fr>
Cc: Zhu Yanjun <yanjun.zhu@linux.dev>
Cc: Zijun Hu <quic_zijuhu@quicinc.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 81cd25d2
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -69,6 +69,11 @@
 *     Metadata for a single session, including its name and a physical pointer
 *     to another preserved memory block containing an array of
 *     `struct luo_file_ser` for all files in that session.
 *
 *   - struct luo_file_ser:
 *     Metadata for a single preserved file. Contains the `compatible` string to
 *     find the correct handler in the new kernel, a user-provided `token` for
 *     identification, and an opaque `data` handle for the handler to use.
 */

#ifndef _LINUX_KHO_ABI_LUO_H
@@ -86,13 +91,43 @@
#define LUO_FDT_COMPATIBLE	"luo-v1"
#define LUO_FDT_LIVEUPDATE_NUM	"liveupdate-number"

#define LIVEUPDATE_HNDL_COMPAT_LENGTH	48

/**
 * struct luo_file_ser - Represents the serialized preserves files.
 * @compatible:  File handler compatible string.
 * @data:        Private data
 * @token:       User provided token for this file
 *
 * If this structure is modified, LUO_SESSION_COMPATIBLE must be updated.
 */
struct luo_file_ser {
	char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
	u64 data;
	u64 token;
} __packed;

/**
 * struct luo_file_set_ser - Represents the serialized metadata for file set
 * @files:   The physical address of a contiguous memory block that holds
 *           the serialized state of files (array of luo_file_ser) in this file
 *           set.
 * @count:   The total number of files that were part of this session during
 *           serialization. Used for iteration and validation during
 *           restoration.
 */
struct luo_file_set_ser {
	u64 files;
	u64 count;
} __packed;

/*
 * LUO FDT session node
 * LUO_FDT_SESSION_HEADER:  is a u64 physical address of struct
 *                          luo_session_header_ser
 */
#define LUO_FDT_SESSION_NODE_NAME	"luo-session"
#define LUO_FDT_SESSION_COMPATIBLE	"luo-session-v1"
#define LUO_FDT_SESSION_COMPATIBLE	"luo-session-v2"
#define LUO_FDT_SESSION_HEADER		"luo-session-header"

/**
@@ -114,6 +149,7 @@ struct luo_session_header_ser {
 * struct luo_session_ser - Represents the serialized metadata for a LUO session.
 * @name:         The unique name of the session, provided by the userspace at
 *                the time of session creation.
 * @file_set_ser: Serialized files belonging to this session,
 *
 * This structure is used to package session-specific metadata for transfer
 * between kernels via Kexec Handover. An array of these structures (one per
@@ -124,6 +160,7 @@ struct luo_session_header_ser {
 */
struct luo_session_ser {
	char name[LIVEUPDATE_SESSION_NAME_LENGTH];
	struct luo_file_set_ser file_set_ser;
} __packed;

#endif /* _LINUX_KHO_ABI_LUO_H */
+98 −0
Original line number Diff line number Diff line
@@ -8,8 +8,93 @@
#define _LINUX_LIVEUPDATE_H

#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/kho/abi/luo.h>
#include <linux/list.h>
#include <linux/types.h>
#include <uapi/linux/liveupdate.h>

struct liveupdate_file_handler;
struct file;

/**
 * struct liveupdate_file_op_args - Arguments for file operation callbacks.
 * @handler:          The file handler being called.
 * @retrieved:        The retrieve status for the 'can_finish / finish'
 *                    operation.
 * @file:             The file object. For retrieve: [OUT] The callback sets
 *                    this to the new file. For other ops: [IN] The caller sets
 *                    this to the file being operated on.
 * @serialized_data:  The opaque u64 handle, preserve/prepare/freeze may update
 *                    this field.
 *
 * This structure bundles all parameters for the file operation callbacks.
 * The 'data' and 'file' fields are used for both input and output.
 */
struct liveupdate_file_op_args {
	struct liveupdate_file_handler *handler;
	bool retrieved;
	struct file *file;
	u64 serialized_data;
};

/**
 * struct liveupdate_file_ops - Callbacks for live-updatable files.
 * @can_preserve: Required. Lightweight check to see if this handler is
 *                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.
 * @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
 *                pre-requirements for this FD are satisfied. Called prior to
 *                finish, in order to do successful finish calls for all
 *                resources in the session.
 * @finish:       Required. Final cleanup in the new kernel.
 * @owner:        Module reference
 *
 * All operations (except can_preserve) receive a pointer to a
 * 'struct liveupdate_file_op_args' containing the necessary context.
 */
struct liveupdate_file_ops {
	bool (*can_preserve)(struct liveupdate_file_handler *handler,
			     struct file *file);
	int (*preserve)(struct liveupdate_file_op_args *args);
	void (*unpreserve)(struct liveupdate_file_op_args *args);
	int (*freeze)(struct liveupdate_file_op_args *args);
	void (*unfreeze)(struct liveupdate_file_op_args *args);
	int (*retrieve)(struct liveupdate_file_op_args *args);
	bool (*can_finish)(struct liveupdate_file_op_args *args);
	void (*finish)(struct liveupdate_file_op_args *args);
	struct module *owner;
};

/**
 * struct liveupdate_file_handler - Represents a handler for a live-updatable file type.
 * @ops:                Callback functions
 * @compatible:         The compatibility string (e.g., "memfd-v1", "vfiofd-v1")
 *                      that uniquely identifies the file type this handler
 *                      supports. This is matched against the compatible string
 *                      associated with individual &struct file instances.
 *
 * Modules that want to support live update for specific file types should
 * register an instance of this structure. LUO uses this registration to
 * determine if a given file can be preserved and to find the appropriate
 * operations to manage its state across the update.
 */
struct liveupdate_file_handler {
	const struct liveupdate_file_ops *ops;
	const char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];

	/* private: */

	/*
	 * Used for linking this handler instance into a global list of
	 * registered file handlers.
	 */
	struct list_head __private list;
};

#ifdef CONFIG_LIVEUPDATE

@@ -19,6 +104,9 @@ bool liveupdate_enabled(void);
/* Called during kexec to tell LUO that entered into reboot */
int liveupdate_reboot(void);

int liveupdate_register_file_handler(struct liveupdate_file_handler *fh);
int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);

#else /* CONFIG_LIVEUPDATE */

static inline bool liveupdate_enabled(void)
@@ -31,5 +119,15 @@ static inline int liveupdate_reboot(void)
	return 0;
}

static inline int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
{
	return -EOPNOTSUPP;
}

static inline int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
{
	return -EOPNOTSUPP;
}

#endif /* CONFIG_LIVEUPDATE */
#endif /* _LINUX_LIVEUPDATE_H */
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

luo-y :=								\
		luo_core.o						\
		luo_file.o						\
		luo_session.o

obj-$(CONFIG_KEXEC_HANDOVER)		+= kexec_handover.o
+880 −0

File added.

Preview size limit exceeded, changes collapsed.

+38 −0
Original line number Diff line number Diff line
@@ -40,6 +40,28 @@ static inline int luo_ucmd_respond(struct luo_ucmd *ucmd,
 */
#define luo_restore_fail(__fmt, ...) panic(__fmt, ##__VA_ARGS__)

/* Mimics list_for_each_entry() but for private list head entries */
#define luo_list_for_each_private(pos, head, member)				\
	for (struct list_head *__iter = (head)->next;				\
	     __iter != (head) &&						\
	     ({ pos = container_of(__iter, typeof(*(pos)), member); 1; });	\
	     __iter = __iter->next)

/**
 * struct luo_file_set - A set of files that belong to the same sessions.
 * @files_list: An ordered list of files associated with this session, it is
 *              ordered by preservation time.
 * @files:      The physically contiguous memory block that holds the serialized
 *              state of files.
 * @count:      A counter tracking the number of files currently stored in the
 *              @files_list for this session.
 */
struct luo_file_set {
	struct list_head files_list;
	struct luo_file_ser *files;
	long count;
};

/**
 * struct luo_session - Represents an active or incoming Live Update session.
 * @name:       A unique name for this session, used for identification and
@@ -50,6 +72,7 @@ static inline int luo_ucmd_respond(struct luo_ucmd *ucmd,
 *              previous kernel) sessions.
 * @retrieved:  A boolean flag indicating whether this session has been
 *              retrieved by a consumer in the new kernel.
 * @file_set:   A set of files that belong to this session.
 * @mutex:      protects fields in the luo_session.
 */
struct luo_session {
@@ -57,6 +80,7 @@ struct luo_session {
	struct luo_session_ser *ser;
	struct list_head list;
	bool retrieved;
	struct luo_file_set file_set;
	struct mutex mutex;
};

@@ -69,4 +93,18 @@ int luo_session_deserialize(void);
bool luo_session_quiesce(void);
void luo_session_resume(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_retrieve_file(struct luo_file_set *file_set, u64 token,
		      struct file **filep);
int luo_file_finish(struct luo_file_set *file_set);
int luo_file_deserialize(struct luo_file_set *file_set,
			 struct luo_file_set_ser *file_set_ser);
void luo_file_set_init(struct luo_file_set *file_set);
void luo_file_set_destroy(struct luo_file_set *file_set);

#endif /* _LINUX_LUO_INTERNAL_H */