From: Zhu Yanjun <yanjun.zhu@linux.dev>
To: Chenghao Duan <duanchenghao@kylinos.cn>,
viro@zeniv.linux.org.uk, brauner@kernel.org, jack@suse.cz,
linux-fsdevel@vger.kernel.org, pasha.tatashin@soleen.com,
linux-kernel@vger.kernel.org, rppt@kernel.org,
pratyush@kernel.org, kexec@lists.infradead.org,
linux-mm@kvack.org
Cc: jianghaoran@kylinos.cn
Subject: Re: [PATCH v1 1/2] eventfd: luo: luo support for preserving eventfd
Date: Thu, 3 Sep 2026 16:19:39 -0700 [thread overview]
Message-ID: <b29fbb51-5d0f-4f82-a06f-55ea080b5629@linux.dev> (raw)
In-Reply-To: <20260625054946.73445-2-duanchenghao@kylinos.cn>
在 2026/6/24 22:49, Chenghao Duan 写道:
> This patch adds support for preserving eventfd file descriptors across
> kexec live updates using the Live Update Orchestrator (LUO) framework.
> Userspace applications using eventfd for event notification can now
> maintain their state across kernel updates.
>
> Preserved State:
> The following properties of the eventfd are preserved across kexec:
> - Counter Value: The current 64-bit counter value, including any pending
> events that have been signaled but not yet consumed by readers.
> - File Flags: The creation flags (EFD_SEMAPHORE, EFD_CLOEXEC, EFD_NONBLOCK)
> are preserved.
>
> Non-Preserved State:
> - File Descriptor Number: The eventfd will be assigned a new fd number
> in the target process after restore.
> - Wait Queue State: Any processes blocked on read() operations will be
> woken up and need to re-establish their blocking state.
> - All other internal state is reset to default.
>
> Changes:
> - fs/eventfd.c: Add eventfd_luo_get_state() to safely read eventfd state
> (count and flags), and eventfd_create() helper function.
> - fs/eventfd_luo.c: New file implementing LUO file operations:
> preserve, freeze, unpreserve, retrieve, and finish callbacks.
> - include/linux/eventfd.h: Export new functions.
> - include/linux/kho/abi/eventfd.h: Define the ABI contract with
> eventfd_luo_ser structure for serialization.
>
> Signed-off-by: Chenghao Duan <duanchenghao@kylinos.cn>
> ---
> fs/Makefile | 1 +
> fs/eventfd.c | 40 +++++
> fs/eventfd_luo.c | 250 ++++++++++++++++++++++++++++++++
> include/linux/eventfd.h | 2 +
> include/linux/kho/abi/eventfd.h | 39 +++++
> kernel/liveupdate/Kconfig | 16 ++
> 6 files changed, 348 insertions(+)
> create mode 100644 fs/eventfd_luo.c
> create mode 100644 include/linux/kho/abi/eventfd.h
>
> diff --git a/fs/Makefile b/fs/Makefile
> index 89a8a9d207d1..36d568e6cfc7 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -27,6 +27,7 @@ obj-y += anon_inodes.o
> obj-$(CONFIG_SIGNALFD) += signalfd.o
> obj-$(CONFIG_TIMERFD) += timerfd.o
> obj-$(CONFIG_EVENTFD) += eventfd.o
> +obj-$(CONFIG_LIVEUPDATE_EVENTFD)+= eventfd_luo.o
> obj-$(CONFIG_AIO) += aio.o
> obj-$(CONFIG_FS_DAX) += dax.o
> obj-$(CONFIG_FS_ENCRYPTION) += crypto/
> diff --git a/fs/eventfd.c b/fs/eventfd.c
> index 9d33a02757d5..9b76cf06135a 100644
> --- a/fs/eventfd.c
> +++ b/fs/eventfd.c
> @@ -376,6 +376,40 @@ struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
> }
> EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
>
> +/**
> + * eventfd_luo_get_state - Get eventfd state (count and flags) for LUO
> + * @file: Eventfd file
> + * @count: Output parameter for count value
> + * @flags: Output parameter for flags value
> + *
> + * This function is exported for use by LUO to safely read eventfd state.
> + * Since struct eventfd_ctx is defined in this file, we can access its
> + * members directly here. The function uses the wait queue lock to ensure
> + * atomic access to count.
> + *
> + * Returns 0 on success, negative error code on failure.
> + */
> +int eventfd_luo_get_state(struct file *file, __u64 *count, unsigned int *flags)
> +{
> + struct eventfd_ctx *ctx;
> + unsigned long irq_flags;
> +
> + ctx = eventfd_ctx_fileget(file);
> + if (IS_ERR(ctx))
> + return PTR_ERR(ctx);
> +
> + /* Read count with lock (flags don't need lock) */
> + spin_lock_irqsave(&ctx->wqh.lock, irq_flags);
> + *count = ctx->count;
> + spin_unlock_irqrestore(&ctx->wqh.lock, irq_flags);
> +
> + *flags = ctx->flags;
> +
> + eventfd_ctx_put(ctx);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(eventfd_luo_get_state);
> +
> static int do_eventfd(unsigned int count, int flags)
> {
> struct eventfd_ctx *ctx __free(kfree) = NULL;
> @@ -411,6 +445,12 @@ static int do_eventfd(unsigned int count, int flags)
> return fd_publish(fdf);
> }
>
> +int eventfd_create(__u64 count, unsigned int flags)
> +{
> + return do_eventfd(count, flags);
> +}
> +EXPORT_SYMBOL_GPL(eventfd_create);
> +
> SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
> {
> return do_eventfd(count, flags);
> diff --git a/fs/eventfd_luo.c b/fs/eventfd_luo.c
> new file mode 100644
> index 000000000000..781d90635c52
> --- /dev/null
> +++ b/fs/eventfd_luo.c
> @@ -0,0 +1,250 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2026 KylinSoft Corporation.
> + * Author: Chenghao Duan <duanchenghao@kylinos.cn>
> + */
> +
> +/**
> + * DOC: Eventfd Preservation via LUO
> + *
> + * Overview
> + * ========
> + *
> + * Event file descriptors (eventfd) can be preserved over a kexec using the Live
> + * Update Orchestrator (LUO) file preservation. This allows userspace applications
> + * that use eventfd for event notification to maintain their state across kernel
> + * updates.
> + *
> + * Eventfd is a simple notification mechanism that uses a 64-bit counter for
> + * signaling events between userspace processes or between userspace and kernel.
> + * The preservation ensures that pending events and configuration are not lost
> + * during kexec.
> + *
> + * The preservation is not intended to be transparent. Only select properties of
> + * the eventfd are preserved. All others are reset to default. The preserved
> + * properties are described below.
> + *
> + * Preserved Properties
> + * ====================
> + *
> + * The following properties of the eventfd are preserved across kexec:
> + *
> + * Counter Value
> + * The current 64-bit counter value is preserved. This includes any pending
> + * events that have been signaled but not yet consumed by readers.
> + *
> + * File Flags
> + * The creation flags (EFD_SEMAPHORE, EFD_CLOEXEC, EFD_NONBLOCK) are preserved.
> + * These control the behavior of read/write operations and file descriptor
> + * inheritance.
> + *
> + * Non-Preserved Properties
> + * ========================
> + *
> + * All properties which are not preserved must be assumed to be reset to
> + * default. This section describes some of those properties which may be more of
> + * note.
> + *
> + * File Descriptor Number
> + * The file descriptor number itself is not preserved. After restore, the
> + * eventfd will be assigned a new file descriptor number in the target process.
> + *
> + * Wait Queue State
> + * Any processes currently blocked on read() operations will be woken up and
> + * need to re-establish their blocking state if desired.
> + *
> + * File Position
> + * Eventfd files don't have a traditional file position, but any internal
> + * state related to the file descriptor is reset.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/file.h>
> +#include <linux/io.h>
> +#include <linux/kexec_handover.h>
> +#include <linux/kho/abi/eventfd.h>
> +#include <linux/liveupdate.h>
> +#include <linux/module.h>
> +#include <linux/eventfd.h>
> +#include <linux/anon_inodes.h>
> +#include <linux/idr.h>
> +#include <linux/slab.h>
> +#include <linux/wait.h>
> +#include <linux/kref.h>
> +#include <linux/fdtable.h>
> +
> +static int eventfd_luo_preserve(struct liveupdate_file_op_args *args)
> +{
> + struct eventfd_luo_ser *ser;
> + u64 count;
> + unsigned int flags;
> + int err = 0;
> +
> + /* Get eventfd state safely */
> + err = eventfd_luo_get_state(args->file, &count, &flags);
> + if (err) {
> + pr_err("Failed to get eventfd state: %d\n", err);
> + return err;
> + }
> +
> + ser = kho_alloc_preserve(sizeof(*ser));
> + if (IS_ERR(ser)) {
> + err = PTR_ERR(ser);
> + pr_err("Failed to allocate preserve memory: %d\n", err);
> + return err;
> + }
> +
> + /* Save eventfd state */
> + ser->count = count;
> + ser->flags = flags;
> +
> + pr_debug("Preserved eventfd: count=%llu, flags=0x%x\n",
> + ser->count, ser->flags);
> +
> + /* Return physical address of serialization structure */
> + args->serialized_data = virt_to_phys(ser);
> +
> + return 0;
> +}
> +
> +static int eventfd_luo_freeze(struct liveupdate_file_op_args *args)
> +{
> + struct eventfd_luo_ser *ser;
> + u64 count;
> + unsigned int flags;
> + int err;
> +
> + if (WARN_ON_ONCE(!args->serialized_data))
> + return -EINVAL;
> +
> + ser = phys_to_virt(args->serialized_data);
> +
> + /* Get current state and update if changed */
> + err = eventfd_luo_get_state(args->file, &count, &flags);
> + if (err)
> + return err;
> +
> + if (ser->count != count) {
> + pr_debug("WARNING: Count changed during preserve->freeze! old=%llu, new=%llu\n",
> + ser->count, count);
> + }
> +
> + ser->count = count;
> +
> + return 0;
> +}
> +
> +static void eventfd_luo_unpreserve(struct liveupdate_file_op_args *args)
> +{
> + struct eventfd_luo_ser *ser;
> +
> + if (WARN_ON_ONCE(!args->serialized_data))
> + return;
> +
> + ser = phys_to_virt(args->serialized_data);
> + kho_unpreserve_free(ser);
> +}
> +
> +static int eventfd_luo_retrieve(struct liveupdate_file_op_args *args)
> +{
> + struct eventfd_luo_ser *ser;
> + struct eventfd_ctx *ctx;
> + struct file *file = NULL;
> + int eventfd;
> +
> + ser = phys_to_virt(args->serialized_data);
> + if (!ser)
> + return -EINVAL;
> +
> + /* Create a new eventfd with the preserved count and flags */
> + eventfd = eventfd_create(ser->count, ser->flags);
> + if (eventfd < 0) {
> + pr_err("Failed to create eventfd: %d\n", eventfd);
> + return eventfd;
> + }
> +
> + file = fget(eventfd);
> + if (!file) {
> + pr_err("Failed to get file from fd\n");
> + close_fd(eventfd);
> + return -EBADF;
> + }
> +
> + close_fd(eventfd);
> +
> + /* Verify the created file has correct internal state */
> + ctx = eventfd_ctx_fileget(file);
> + if (IS_ERR(ctx)) {
> + pr_err("Failed to get context from file\n");
> + fput(file);
> + return PTR_ERR(ctx);
> + }
> +
> + eventfd_ctx_put(ctx);
> +
> + args->file = file;
> + return 0;
> +}
> +
> +static void eventfd_luo_finish(struct liveupdate_file_op_args *args)
> +{
> + struct eventfd_luo_ser *ser;
> +
> + if (args->retrieve_status)
> + return;
> +
> + if (!args->serialized_data)
> + return;
> +
> + ser = phys_to_virt(args->serialized_data);
> + if (!ser)
> + return;
> +
> + kho_restore_free(ser);
> +}
> +
> +static bool eventfd_luo_can_preserve(struct liveupdate_file_handler *handler,
> + struct file *file)
> +{
> + struct eventfd_ctx *ctx;
> +
> + if (!file->f_op)
> + return false;
> +
> + /* Try to get eventfd context - this will fail if not an eventfd */
> + ctx = eventfd_ctx_fileget(file);
> + if (IS_ERR(ctx))
> + return false;
> +
> + eventfd_ctx_put(ctx);
> + return true;
> +}
> +
> +static const struct liveupdate_file_ops eventfd_luo_file_ops = {
> + .preserve = eventfd_luo_preserve,
> + .unpreserve = eventfd_luo_unpreserve,
> + .freeze = eventfd_luo_freeze,
> + .retrieve = eventfd_luo_retrieve,
> + .finish = eventfd_luo_finish,
> + .can_preserve = eventfd_luo_can_preserve,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct liveupdate_file_handler eventfd_luo_handler = {
> + .ops = &eventfd_luo_file_ops,
> + .compatible = EVENTFD_LUO_FH_COMPATIBLE,
> +};
> +
> +static int __init eventfd_luo_init(void)
> +{
> + int err = liveupdate_register_file_handler(&eventfd_luo_handler);
The function liveupdate_unregister_file_handler should also be invoked
to unregister luo handler.
Zhu Yanjun
> +
> + if (err && err != -EOPNOTSUPP) {
> + pr_err("Could not register eventfd LUO handler: %pe\n",
> + ERR_PTR(err));
> + return err;
> + }
> +
> + return 0;
> +}
> +late_initcall(eventfd_luo_init);
> diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
> index e32bee4345fb..703e1a126c4d 100644
> --- a/include/linux/eventfd.h
> +++ b/include/linux/eventfd.h
> @@ -35,6 +35,8 @@ void eventfd_ctx_put(struct eventfd_ctx *ctx);
> struct file *eventfd_fget(int fd);
> struct eventfd_ctx *eventfd_ctx_fdget(int fd);
> struct eventfd_ctx *eventfd_ctx_fileget(struct file *file);
> +int eventfd_luo_get_state(struct file *file, __u64 *count, unsigned int *flags);
> +int eventfd_create(__u64 count, unsigned int flags);
> void eventfd_signal_mask(struct eventfd_ctx *ctx, __poll_t mask);
> int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *wait,
> __u64 *cnt);
> diff --git a/include/linux/kho/abi/eventfd.h b/include/linux/kho/abi/eventfd.h
> new file mode 100644
> index 000000000000..148beac6bcc7
> --- /dev/null
> +++ b/include/linux/kho/abi/eventfd.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2026 KylinSoft Corporation.
> + * Author: Chenghao Duan <duanchenghao@kylinos.cn>
> + */
> +
> +#ifndef _LINUX_KHO_ABI_EVENTFD_H
> +#define _LINUX_KHO_ABI_EVENTFD_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * Eventfd Live Update ABI
> + *
> + * This header defines the ABI for preserving eventfd state across kexec.
> + *
> + * The state is serialized into a packed structure `struct eventfd_luo_ser`
> + * which is handed over to the next kernel via the KHO mechanism.
> + *
> + */
> +
> +/**
> + * struct eventfd_luo_ser - Serialized state of an eventfd
> + * @count: The current counter value
> + * @flags: File flags (EFD_SEMAPHORE, EFD_CLOEXEC, EFD_NONBLOCK)
> + *
> + * This structure contains the minimal state needed to restore an eventfd
> + * after kexec. The count represents the current value of the event counter,
> + * and flags represent the file creation flags.
> + */
> +struct eventfd_luo_ser {
> + __u64 count;
> + unsigned int flags;
> +} __packed;
> +
> +/* The compatibility string for eventfd file handler */
> +#define EVENTFD_LUO_FH_COMPATIBLE "eventfd-v1"
> +
> +#endif /* _LINUX_KHO_ABI_EVENTFD_H */
> diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig
> index c13af38ba23a..1361b5733f41 100644
> --- a/kernel/liveupdate/Kconfig
> +++ b/kernel/liveupdate/Kconfig
> @@ -86,4 +86,20 @@ config LIVEUPDATE_MEMFD
>
> If unsure, say N.
>
> +config LIVEUPDATE_EVENTFD
> + bool "Eventfd Live Update Orchestrator support"
> + depends on EVENTFD
> + depends on LIVEUPDATE
> + help
> + Enable Live Update Orchestrator support for eventfd file descriptors.
> + This allows eventfd files to be preserved and restored across kexec
> + operations, maintaining their counter values and flags.
> +
> + Eventfd files are commonly used for event notification between
> + userspace processes or between userspace and kernel. With this
> + option enabled, eventfd state can be handed over to a new kernel
> + during live update operations.
> +
> + If unsure, say N.
> +
> endmenu
next prev parent reply other threads:[~2026-09-03 23:19 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-25 5:49 [PATCH v1 0/2] luo support for preserving eventfd Chenghao Duan
2026-06-25 5:49 ` [PATCH v1 1/2] eventfd: luo: " Chenghao Duan
2026-06-25 9:06 ` Pratyush Yadav
2026-06-29 10:06 ` Chenghao Duan
2026-06-30 22:55 ` David Matlack
2026-07-01 12:15 ` Pratyush Yadav
2026-09-03 23:19 ` Zhu Yanjun [this message]
2026-06-25 5:49 ` [PATCH v1 2/2] selftests: liveupdate: Add selftest for eventfd LUO Chenghao Duan
2026-09-01 20:43 ` Zhu Yanjun
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=b29fbb51-5d0f-4f82-a06f-55ea080b5629@linux.dev \
--to=yanjun.zhu@linux.dev \
--cc=brauner@kernel.org \
--cc=duanchenghao@kylinos.cn \
--cc=jack@suse.cz \
--cc=jianghaoran@kylinos.cn \
--cc=kexec@lists.infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=pasha.tatashin@soleen.com \
--cc=pratyush@kernel.org \
--cc=rppt@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/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