* [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 1:03 ` sashiko-bot
2026-11-04 13:17 ` Pratyush Yadav
2026-11-03 1:02 ` [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument David Matlack
` (8 subsequent siblings)
9 siblings, 2 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
From: Pasha Tatashin <pasha.tatashin@soleen.com>
Allow userspace to pass a file-handler-specific argument structure when
preserving or retrieving an FD via LUO. File handlers may need
additional context during preservation or retrieval, such as a target
FD, device location, or handler-specific parameters, without introducing
separate ioctls for each file type. Whether the argument is required,
optional, or unused is defined by the file handler.
Extend struct liveupdate_session_preserve_fd and
struct liveupdate_session_retrieve_fd with a 64-bit arg field pointing
to a handler-defined argument structure that begins with a 32-bit size
field. Because IOCTL_OP validates a minimum size up to the token field,
existing callers passing the 16-byte struct remain compatible and have
arg zero-filled by copy_struct_from_user().
Add parg and rarg (struct liveupdate_arg_spec) to
struct liveupdate_file_ops, initialized via LIVEUPDATE_ARG(_struct,
_min_last), which records the full struct size and minimum required size
while enforcing at compile time that handler argument structures begin
with a 32-bit size field. When arg is non-zero, LUO validates the
minimum size and copies the user argument via copy_struct_from_user() up
to the handler's expected size and passes the kernel copy in
struct liveupdate_file_op_args, or returns -EOPNOTSUPP if the handler
does not accept an argument.
The argument only applies to the retrieve that restores the file.
Retrieving a token that was already retrieved returns the existing file,
so fail with -EBUSY if a non-zero argument is passed then, instead of
silently ignoring it.
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
include/linux/liveupdate.h | 44 +++++++++++++++++++
include/uapi/linux/liveupdate.h | 10 +++++
kernel/liveupdate/luo_file.c | 73 +++++++++++++++++++++++++++++---
kernel/liveupdate/luo_internal.h | 5 ++-
kernel/liveupdate/luo_session.c | 6 ++-
5 files changed, 128 insertions(+), 10 deletions(-)
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 6051abc0612c..7543f5d648d3 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -22,6 +22,36 @@ struct liveupdate_flb;
struct liveupdate_session;
struct file;
+/**
+ * struct liveupdate_arg_spec - Specification of a file handler user argument.
+ * @size: Full size of the argument structure in the current kernel.
+ * @min_size: Minimum valid user-supplied size (offsetofend of the last
+ * required field).
+ */
+struct liveupdate_arg_spec {
+ size_t size;
+ size_t min_size;
+};
+
+/**
+ * LIVEUPDATE_ARG - Validated specification of a file handler argument struct.
+ * @_struct: The argument structure type.
+ * @_min_last: The last required member in @_struct.
+ *
+ * All file handler argument structures passed via
+ * &liveupdate_session_preserve_fd.arg or &liveupdate_session_retrieve_fd.arg
+ * must begin with a 32-bit @size field so they can be extended compatibly.
+ * Use this macro to initialize &liveupdate_file_ops.parg and
+ * &liveupdate_file_ops.rarg.
+ */
+#define LIVEUPDATE_ARG(_struct, _min_last) \
+ { \
+ .size = sizeof(_struct) + \
+ BUILD_BUG_ON_ZERO(offsetof(_struct, size) != 0) + \
+ BUILD_BUG_ON_ZERO(sizeof_field(_struct, size) != sizeof(u32)), \
+ .min_size = offsetofend(_struct, _min_last), \
+ }
+
/**
* struct liveupdate_file_op_args - Arguments for file operation callbacks.
* @handler: The file handler being called.
@@ -40,6 +70,11 @@ struct file;
* is not preserved. Set by the handler's .preserve()
* callback, and must be freed in the handler's
* .unpreserve() callback.
+ * @arg: Kernel copy of the user-provided argument for .preserve()
+ * and .retrieve(), or %NULL if none was provided. Allocated
+ * to the handler's expected argument size with any trailing
+ * bytes beyond the user-supplied size zero-filled. Valid
+ * only for the duration of the callback.
*
* This structure bundles all parameters for the file operation callbacks.
* The 'data' and 'file' fields are used for both input and output.
@@ -51,6 +86,7 @@ struct liveupdate_file_op_args {
struct file *file;
u64 serialized_data;
void *private_data;
+ const void *arg;
};
/**
@@ -68,6 +104,12 @@ struct liveupdate_file_op_args {
* resources in the session.
* @finish: Required. Final cleanup in the new kernel.
* @get_id: Optional. Returns a unique identifier for the file.
+ * @parg: Optional. Specification of the user argument structure
+ * accepted by @preserve, initialized via LIVEUPDATE_ARG(). If
+ * unset, non-zero user arguments are rejected with -EOPNOTSUPP.
+ * @rarg: Optional. Specification of the user argument structure
+ * accepted by @retrieve, initialized via LIVEUPDATE_ARG(). If
+ * unset, non-zero user arguments are rejected with -EOPNOTSUPP.
* @owner: Module reference
*
* All operations (except can_preserve) receive a pointer to a
@@ -84,6 +126,8 @@ struct liveupdate_file_ops {
bool (*can_finish)(struct liveupdate_file_op_args *args);
void (*finish)(struct liveupdate_file_op_args *args);
unsigned long (*get_id)(struct file *file);
+ struct liveupdate_arg_spec parg;
+ struct liveupdate_arg_spec rarg;
struct module *owner;
};
diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
index 4043d4038712..e806752c2fc6 100644
--- a/include/uapi/linux/liveupdate.h
+++ b/include/uapi/linux/liveupdate.h
@@ -126,6 +126,8 @@ struct liveupdate_ioctl_retrieve_session {
* @size: Input; sizeof(struct liveupdate_session_preserve_fd)
* @fd: Input; The user-space file descriptor to be preserved.
* @token: Input; An opaque, unique token for preserved resource.
+ * @arg: Input; User-space pointer to a file-handler-specific argument
+ * structure starting with a 32-bit size field, or 0 if unused.
*
* Holds parameters for preserving a file descriptor.
*
@@ -149,6 +151,7 @@ struct liveupdate_session_preserve_fd {
__u32 size;
__s32 fd;
__aligned_u64 token;
+ __aligned_u64 arg;
};
#define LIVEUPDATE_SESSION_PRESERVE_FD \
@@ -160,6 +163,8 @@ struct liveupdate_session_preserve_fd {
* @fd: Output; The new file descriptor representing the fully restored
* kernel resource.
* @token: Input; An opaque, token that was used to preserve the resource.
+ * @arg: Input; User-space pointer to a file-handler-specific argument
+ * structure starting with a 32-bit size field, or 0 if unused.
*
* Retrieve a previously preserved file descriptor.
*
@@ -173,12 +178,17 @@ struct liveupdate_session_preserve_fd {
* attempts to retrieve the token fail with the same error code. Failed
* retrieves are not retried.
*
+ * Retrieving a token that was already retrieved successfully returns a new file
+ * descriptor for the same file. The @arg only applies to the retrieve that
+ * restores the file, so passing a non-zero @arg then fails with -EBUSY.
+ *
* Return: 0 on success, negative error code on failure (e.g., invalid token).
*/
struct liveupdate_session_retrieve_fd {
__u32 size;
__s32 fd;
__aligned_u64 token;
+ __aligned_u64 arg;
};
#define LIVEUPDATE_SESSION_RETRIEVE_FD \
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index a39992da504f..eeeb3b5ff2fa 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -126,6 +126,7 @@
#include <linux/xarray.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/uaccess.h>
#include "luo_internal.h"
static LIST_HEAD(luo_file_handler_list);
@@ -202,11 +203,45 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
return false;
}
+static int luo_copy_user_arg(u64 user_arg, const void **argp,
+ const struct liveupdate_arg_spec *spec)
+{
+ void *karg __free(kfree) = NULL;
+ void __user *uptr;
+ u32 user_size;
+ int err;
+
+ if (!user_arg)
+ return 0;
+ if (!spec->size)
+ return -EOPNOTSUPP;
+
+ uptr = u64_to_user_ptr(user_arg);
+ if (get_user(user_size, (u32 __user *)uptr))
+ return -EFAULT;
+ if (user_size < spec->min_size)
+ return -EINVAL;
+ if (user_size > PAGE_SIZE)
+ return -E2BIG;
+
+ karg = kmalloc(spec->size, GFP_KERNEL);
+ if (!karg)
+ return -ENOMEM;
+
+ err = copy_struct_from_user(karg, spec->size, uptr, user_size);
+ if (err)
+ return err;
+
+ *argp = no_free_ptr(karg);
+ return 0;
+}
+
/**
* luo_preserve_file - Initiate the preservation of a file descriptor.
* @file_set: The file_set to which the preserved file will be added.
* @token: A unique, user-provided identifier for the file.
* @fd: The file descriptor to be preserved.
+ * @arg: User-space pointer to the handler argument structure, or 0.
*
* This function orchestrates the first phase of preserving a file. Upon entry,
* it takes a reference to the 'struct file' via fget(), effectively making LUO
@@ -222,9 +257,11 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
* (allocates if needed).
* 3. Iterates through registered handlers, calling can_preserve() to find one
* compatible with the given @fd.
- * 4. Calls the handler's .preserve() operation, which saves the file's state
+ * 4. Copies the user argument structure (if @arg is non-zero) according to the
+ * handler's parg specification.
+ * 5. Calls the handler's .preserve() operation, which saves the file's state
* and returns an opaque private data handle.
- * 5. Adds the new instance to the file_set's internal list.
+ * 6. Adds the new instance to the file_set's internal list.
*
* On success, LUO takes a reference to the 'struct file' and considers it
* under its management until it is unpreserved or finished.
@@ -239,10 +276,12 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
* -EBADF if the file descriptor is invalid.
* -ENOSPC if the file_set is full.
* -ENOENT if no compatible handler is found.
+ * -EOPNOTSUPP if @arg is non-zero and the handler does not accept an arg.
* -ENOMEM on memory allocation failure.
* Other erros might be returned by .preserve().
*/
-int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
+int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd,
+ u64 arg)
{
struct liveupdate_file_op_args args = {0};
struct liveupdate_file_handler *fh;
@@ -278,10 +317,14 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
if (err)
goto err_fput;
+ err = luo_copy_user_arg(arg, &args.arg, &fh->ops->parg);
+ if (err)
+ goto err_module_put;
+
err = xa_insert(&luo_preserved_files, luo_get_id(fh, file),
file, GFP_KERNEL);
if (err)
- goto err_module_put;
+ goto err_free_arg;
err = luo_flb_file_preserve(fh);
if (err)
@@ -305,6 +348,7 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
if (err)
goto err_kfree;
+ kfree(args.arg);
luo_file->serialized_data = args.serialized_data;
luo_file->private_data = args.private_data;
list_add_tail(&luo_file->list, &file_set->files_list);
@@ -318,6 +362,8 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
luo_flb_file_unpreserve(fh);
err_erase_xa:
xa_erase(&luo_preserved_files, luo_get_id(fh, file));
+err_free_arg:
+ kfree(args.arg);
err_module_put:
module_put(fh->ops->owner);
err_fput:
@@ -547,6 +593,7 @@ void luo_file_unfreeze(struct luo_file_set *file_set,
* luo_retrieve_file - Restores a preserved file from a file_set by its token.
* @file_set: The file_set from which to retrieve the file.
* @token: The unique token identifying the file to be restored.
+ * @arg: User-space pointer to the handler argument structure, or 0.
* @filep: Output parameter; on success, this is populated with a pointer
* to the newly retrieved 'struct file'.
*
@@ -566,9 +613,11 @@ void luo_file_unfreeze(struct luo_file_set *file_set,
* kernel.
* Return: 0 on success. Returns a negative errno on failure:
* -ENOENT if no file with the matching token is found.
+ * -EOPNOTSUPP if @arg is non-zero and the handler does not accept an arg.
+ * -EBUSY if @arg is non-zero and the file was already retrieved.
* Any error code returned by the handler's .retrieve() op.
*/
-int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
+int luo_retrieve_file(struct luo_file_set *file_set, u64 token, u64 arg,
struct file **filep)
{
struct liveupdate_file_op_args args = {0};
@@ -596,6 +645,13 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
}
if (luo_file->retrieve_status > 0) {
+ /*
+ * The argument only applies to the retrieve that restores the
+ * file. Don't silently ignore it.
+ */
+ if (arg)
+ return -EBUSY;
+
/*
* Someone is asking for this file again, so get a reference
* for them.
@@ -605,10 +661,15 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
return 0;
}
+ err = luo_copy_user_arg(arg, &args.arg, &luo_file->fh->ops->rarg);
+ if (err)
+ return err;
+
args.handler = luo_file->fh;
args.session = luo_session_from_file_set(file_set);
args.serialized_data = luo_file->serialized_data;
err = luo_file->fh->ops->retrieve(&args);
+ kfree(args.arg);
if (err) {
/* Keep the error code for later use. */
luo_file->retrieve_status = err;
@@ -1007,6 +1068,6 @@ int liveupdate_get_file_incoming(struct liveupdate_session *s, u64 token,
struct file **filep)
{
return luo_retrieve_file(luo_file_set_from_session_locked(s),
- token, filep);
+ token, 0, filep);
}
EXPORT_SYMBOL_GPL(liveupdate_get_file_incoming);
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index dac6644bfb18..4126b71e9a2e 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -101,13 +101,14 @@ int __init luo_session_setup_incoming(u64 sessions_pa);
int luo_session_serialize(void);
int luo_session_deserialize(void);
-int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd);
+int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd,
+ u64 arg);
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,
+int luo_retrieve_file(struct luo_file_set *file_set, u64 token, u64 arg,
struct file **filep);
int luo_file_finish(struct luo_file_set *file_set);
int luo_file_deserialize(struct luo_file_set *file_set,
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index f48e9a4185f9..ed9d53c7db77 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -267,7 +267,8 @@ static int luo_session_preserve_fd(struct luo_session *session,
int err;
guard(mutex)(&session->mutex);
- err = luo_preserve_file(&session->file_set, argp->token, argp->fd);
+ err = luo_preserve_file(&session->file_set, argp->token, argp->fd,
+ argp->arg);
if (err)
return err;
@@ -290,7 +291,8 @@ static int luo_session_retrieve_fd(struct luo_session *session,
return argp->fd;
mutex_lock(&session->mutex);
- err = luo_retrieve_file(&session->file_set, argp->token, &file);
+ err = luo_retrieve_file(&session->file_set, argp->token, argp->arg,
+ &file);
mutex_unlock(&session->mutex);
if (err < 0)
goto err_put_fd;
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve
2026-11-03 1:02 ` [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve David Matlack
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 13:17 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] liveupdate: karg __free(kfree) declared as NULL at top of luo_copy_user_arg()
--
commit c4f18d427b088994ba26ccc665552744e8d63e5a
Author: Pasha Tatashin <pasha.tatashin@soleen.com>
liveupdate: Pass user argument to file preserve and retrieve
This commit extends LIVEUPDATE_SESSION_PRESERVE_FD and
LIVEUPDATE_SESSION_RETRIEVE_FD with an optional user-space argument pointer,
allowing file handlers to specify and receive handler-specific argument
structures during file preservation and retrieval.
> diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
> index a39992da504fb..eeeb3b5ff2faa 100644
> --- a/kernel/liveupdate/luo_file.c
> +++ b/kernel/liveupdate/luo_file.c
[ ... ]
> @@ -202,11 +203,45 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
> return false;
> }
>
> +static int luo_copy_user_arg(u64 user_arg, const void **argp,
> + const struct liveupdate_arg_spec *spec)
> +{
> + void *karg __free(kfree) = NULL;
> + void __user *uptr;
> + u32 user_size;
> + int err;
> +
> + if (!user_arg)
> + return 0;
> + if (!spec->size)
> + return -EOPNOTSUPP;
> +
> + uptr = u64_to_user_ptr(user_arg);
> + if (get_user(user_size, (u32 __user *)uptr))
> + return -EFAULT;
> + if (user_size < spec->min_size)
> + return -EINVAL;
> + if (user_size > PAGE_SIZE)
> + return -E2BIG;
> +
> + karg = kmalloc(spec->size, GFP_KERNEL);
> + if (!karg)
> + return -ENOMEM;
[Severity: Low]
This isn't a bug, but in luo_copy_user_arg(), karg is declared with
__free(kfree) = NULL at the top of the function and assigned later after the
early validation checks.
Per the Cleanup API conventions in include/linux/cleanup.h, could karg be
defined and initialized in a single statement at the allocation site instead:
void *karg __free(kfree) = kmalloc(spec->size, GFP_KERNEL);
if (!karg)
return -ENOMEM;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=1
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve
2026-11-03 1:02 ` [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve David Matlack
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 13:17 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 13:17 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
Hi David,
On Tue, Nov 03 2026, David Matlack wrote:
> From: Pasha Tatashin <pasha.tatashin@soleen.com>
>
> Allow userspace to pass a file-handler-specific argument structure when
> preserving or retrieving an FD via LUO. File handlers may need
> additional context during preservation or retrieval, such as a target
> FD, device location, or handler-specific parameters, without introducing
> separate ioctls for each file type. Whether the argument is required,
> optional, or unused is defined by the file handler.
>
> Extend struct liveupdate_session_preserve_fd and
> struct liveupdate_session_retrieve_fd with a 64-bit arg field pointing
> to a handler-defined argument structure that begins with a 32-bit size
> field. Because IOCTL_OP validates a minimum size up to the token field,
> existing callers passing the 16-byte struct remain compatible and have
> arg zero-filled by copy_struct_from_user().
>
> Add parg and rarg (struct liveupdate_arg_spec) to
> struct liveupdate_file_ops, initialized via LIVEUPDATE_ARG(_struct,
> _min_last), which records the full struct size and minimum required size
> while enforcing at compile time that handler argument structures begin
> with a 32-bit size field. When arg is non-zero, LUO validates the
> minimum size and copies the user argument via copy_struct_from_user() up
> to the handler's expected size and passes the kernel copy in
> struct liveupdate_file_op_args, or returns -EOPNOTSUPP if the handler
> does not accept an argument.
>
> The argument only applies to the retrieve that restores the file.
> Retrieving a token that was already retrieved returns the existing file,
> so fail with -EBUSY if a non-zero argument is passed then, instead of
> silently ignoring it.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
LGTM for the most part, only a couple nitpicks below.
[...]
> @@ -173,12 +178,17 @@ struct liveupdate_session_preserve_fd {
> * attempts to retrieve the token fail with the same error code. Failed
> * retrieves are not retried.
> *
> + * Retrieving a token that was already retrieved successfully returns a new file
> + * descriptor for the same file. The @arg only applies to the retrieve that
> + * restores the file, so passing a non-zero @arg then fails with -EBUSY.
> + *
Hmm, let's see how that plays out in practice. I would guess that code
which does multiple retrieves isn't smart enough to know the file was
already retrieved by someone else.
Anyway, that's not really a kernel problem, so no need to change
anything. Just thinking out loud.
[...]
> /**
> * luo_preserve_file - Initiate the preservation of a file descriptor.
> * @file_set: The file_set to which the preserved file will be added.
> * @token: A unique, user-provided identifier for the file.
> * @fd: The file descriptor to be preserved.
> + * @arg: User-space pointer to the handler argument structure, or 0.
> *
> * This function orchestrates the first phase of preserving a file. Upon entry,
> * it takes a reference to the 'struct file' via fget(), effectively making LUO
> @@ -222,9 +257,11 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
> * (allocates if needed).
> * 3. Iterates through registered handlers, calling can_preserve() to find one
> * compatible with the given @fd.
> - * 4. Calls the handler's .preserve() operation, which saves the file's state
> + * 4. Copies the user argument structure (if @arg is non-zero) according to the
> + * handler's parg specification.
> + * 5. Calls the handler's .preserve() operation, which saves the file's state
> * and returns an opaque private data handle.
> - * 5. Adds the new instance to the file_set's internal list.
> + * 6. Adds the new instance to the file_set's internal list.
TBH, I think this whole list is pointless. There is no reason to list
what the code does in a comment. It's only purpose would be to go stale.
The comment should be a high level description of the function, and the
details are already in the code.
It would be very nice if you add a preparatory patch deleting the whole
thing, but since it isn't something added by your patch, I won't insist
on it. It's optional for this series.
> *
> * On success, LUO takes a reference to the 'struct file' and considers it
> * under its management until it is unpreserved or finished.
> @@ -239,10 +276,12 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
> * -EBADF if the file descriptor is invalid.
> * -ENOSPC if the file_set is full.
> * -ENOENT if no compatible handler is found.
> + * -EOPNOTSUPP if @arg is non-zero and the handler does not accept an arg.
> * -ENOMEM on memory allocation failure.
> * Other erros might be returned by .preserve().
> */
[...]
> diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
> index f48e9a4185f9..ed9d53c7db77 100644
> --- a/kernel/liveupdate/luo_session.c
> +++ b/kernel/liveupdate/luo_session.c
> @@ -267,7 +267,8 @@ static int luo_session_preserve_fd(struct luo_session *session,
> int err;
>
> guard(mutex)(&session->mutex);
> - err = luo_preserve_file(&session->file_set, argp->token, argp->fd);
> + err = luo_preserve_file(&session->file_set, argp->token, argp->fd,
> + argp->arg);
Nit: I would prefer to start marking this as __user from here on out,
instead of keeping it u64 and hiding the fact that this is a user
pointer.
So luo_preserve_file() should take a "const void __user *arg" as
argument, instead of "u64 arg". And here we should pass
u64_to_user_ptr(argp->arg). Same for retrieve.
> if (err)
> return err;
>
> @@ -290,7 +291,8 @@ static int luo_session_retrieve_fd(struct luo_session *session,
> return argp->fd;
>
> mutex_lock(&session->mutex);
> - err = luo_retrieve_file(&session->file_set, argp->token, &file);
> + err = luo_retrieve_file(&session->file_set, argp->token, argp->arg,
> + &file);
> mutex_unlock(&session->mutex);
> if (err < 0)
> goto err_put_fd;
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
2026-11-03 1:02 ` [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 1:03 ` sashiko-bot
2026-11-04 13:26 ` Pratyush Yadav
2026-11-03 1:02 ` [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable David Matlack
` (7 subsequent siblings)
9 siblings, 2 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
From: Pasha Tatashin <pasha.tatashin@soleen.com>
Verify the user argument support in LIVEUPDATE_SESSION_PRESERVE_FD and
LIVEUPDATE_SESSION_RETRIEVE_FD. Add luo_session_preserve_fd_arg() and
luo_session_retrieve_fd_arg() helpers to libliveupdate so tests can pass
a handler-specific argument.
Add a preserve_memfd_with_arg test case to verify that memfd
preservation rejects a non-zero argument with -EOPNOTSUPP, accepts an
explicit zero argument, and remains compatible with callers passing the
legacy struct size up to the token field.
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../liveupdate/lib/include/libliveupdate.h | 3 ++
.../selftests/liveupdate/lib/lu_utils.c | 17 ++++++-
.../testing/selftests/liveupdate/liveupdate.c | 44 +++++++++++++++++++
3 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
index fa07fed08364..cd1d843a0d3d 100644
--- a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
+++ b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
@@ -29,7 +29,10 @@ int luo_get_session_name(int session_fd, char *name, size_t name_len);
int luo_ensure_nofile_limit(long min_limit);
int luo_session_preserve_fd(int session_fd, int fd, __u64 token);
+int luo_session_preserve_fd_arg(int session_fd, int fd, __u64 token,
+ __u64 user_arg);
int luo_session_retrieve_fd(int session_fd, __u64 token);
+int luo_session_retrieve_fd_arg(int session_fd, __u64 token, __u64 user_arg);
int create_and_preserve_memfd(int session_fd, int token, const char *data);
int restore_and_verify_memfd(int session_fd, int token, const char *expected_data);
diff --git a/tools/testing/selftests/liveupdate/lib/lu_utils.c b/tools/testing/selftests/liveupdate/lib/lu_utils.c
index 74d41115c281..db7a90b002cb 100644
--- a/tools/testing/selftests/liveupdate/lib/lu_utils.c
+++ b/tools/testing/selftests/liveupdate/lib/lu_utils.c
@@ -79,12 +79,14 @@ int luo_retrieve_session(int luo_fd, const char *name)
return arg.fd;
}
-int luo_session_preserve_fd(int session_fd, int fd, __u64 token)
+int luo_session_preserve_fd_arg(int session_fd, int fd, __u64 token,
+ __u64 user_arg)
{
struct liveupdate_session_preserve_fd arg = {
.size = sizeof(arg),
.fd = fd,
.token = token,
+ .arg = user_arg,
};
if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg))
@@ -93,11 +95,17 @@ int luo_session_preserve_fd(int session_fd, int fd, __u64 token)
return 0;
}
-int luo_session_retrieve_fd(int session_fd, __u64 token)
+int luo_session_preserve_fd(int session_fd, int fd, __u64 token)
+{
+ return luo_session_preserve_fd_arg(session_fd, fd, token, 0);
+}
+
+int luo_session_retrieve_fd_arg(int session_fd, __u64 token, __u64 user_arg)
{
struct liveupdate_session_retrieve_fd arg = {
.size = sizeof(arg),
.token = token,
+ .arg = user_arg,
};
if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg))
@@ -106,6 +114,11 @@ int luo_session_retrieve_fd(int session_fd, __u64 token)
return arg.fd;
}
+int luo_session_retrieve_fd(int session_fd, __u64 token)
+{
+ return luo_session_retrieve_fd_arg(session_fd, token, 0);
+}
+
/* Helper function to get a session name via ioctl. */
int luo_get_session_name(int session_fd, char *name, size_t name_len)
{
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
index 2dedd5fc2534..4c4272167635 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
@@ -530,4 +531,47 @@ TEST_F(liveupdate_device, preserve_many_files)
ASSERT_EQ(close(session_fd), 0);
}
+/*
+ * Test Case: Preserve MemFD with User Argument
+ *
+ * Verifies that passing a non-zero user argument to memfd preservation fails
+ * with -EOPNOTSUPP, while passing a zero argument or using the minimum struct
+ * size without the arg field succeeds.
+ */
+TEST_F(liveupdate_device, preserve_memfd_with_arg)
+{
+ struct liveupdate_session_preserve_fd min_arg = {};
+ int session_fd, mem_fd1, mem_fd2;
+
+ self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
+ if (self->fd1 < 0 && errno == ENOENT)
+ SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
+ ASSERT_GE(self->fd1, 0);
+
+ session_fd = luo_create_session(self->fd1, "preserve-arg-test");
+ ASSERT_GE(session_fd, 0);
+
+ mem_fd1 = memfd_create("arg-memfd-1", 0);
+ ASSERT_GE(mem_fd1, 0);
+
+ /* Non-zero arg is not supported by memfd handler */
+ EXPECT_EQ(luo_session_preserve_fd_arg(session_fd, mem_fd1, 0x1111, 1),
+ -EOPNOTSUPP);
+
+ /* Legacy struct size (up to token) should zero-fill arg and succeed */
+ min_arg.size = offsetof(struct liveupdate_session_preserve_fd, arg);
+ min_arg.fd = mem_fd1;
+ min_arg.token = 0x1111;
+ ASSERT_EQ(ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &min_arg), 0);
+
+ /* Explicit zero arg with full struct size should also succeed */
+ mem_fd2 = memfd_create("arg-memfd-2", 0);
+ ASSERT_GE(mem_fd2, 0);
+ ASSERT_EQ(luo_session_preserve_fd_arg(session_fd, mem_fd2, 0x2222, 0), 0);
+
+ ASSERT_EQ(close(session_fd), 0);
+ ASSERT_EQ(close(mem_fd1), 0);
+ ASSERT_EQ(close(mem_fd2), 0);
+}
+
TEST_HARNESS_MAIN
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument
2026-11-03 1:02 ` [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument David Matlack
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 13:26 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] selftests/liveupdate: zero min_arg.arg in preserve_memfd_with_arg()
--
commit 0eae9757b9fca17ee60f5d085e6dce0d9304a977
Author: Pasha Tatashin <pasha.tatashin@soleen.com>
selftests: liveupdate: Add tests for preserve and retrieve user argument
This commit adds libliveupdate helpers for passing user arguments to
LIVEUPDATE_SESSION_PRESERVE_FD and LIVEUPDATE_SESSION_RETRIEVE_FD, and adds
the preserve_memfd_with_arg test case to verify memfd argument validation and
legacy struct size handling.
> diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
> index 2dedd5fc2534f..4c4272167635b 100644
> --- a/tools/testing/selftests/liveupdate/liveupdate.c
> +++ b/tools/testing/selftests/liveupdate/liveupdate.c
[ ... ]
> @@ -530,4 +531,47 @@ TEST_F(liveupdate_device, preserve_many_files)
> ASSERT_EQ(close(session_fd), 0);
> }
>
> +/*
> + * Test Case: Preserve MemFD with User Argument
> + *
> + * Verifies that passing a non-zero user argument to memfd preservation fails
> + * with -EOPNOTSUPP, while passing a zero argument or using the minimum struct
> + * size without the arg field succeeds.
> + */
> +TEST_F(liveupdate_device, preserve_memfd_with_arg)
> +{
> + struct liveupdate_session_preserve_fd min_arg = {};
> + int session_fd, mem_fd1, mem_fd2;
> +
> + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
> + if (self->fd1 < 0 && errno == ENOENT)
> + SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
> + ASSERT_GE(self->fd1, 0);
> +
> + session_fd = luo_create_session(self->fd1, "preserve-arg-test");
> + ASSERT_GE(session_fd, 0);
> +
> + mem_fd1 = memfd_create("arg-memfd-1", 0);
> + ASSERT_GE(mem_fd1, 0);
> +
> + /* Non-zero arg is not supported by memfd handler */
> + EXPECT_EQ(luo_session_preserve_fd_arg(session_fd, mem_fd1, 0x1111, 1),
> + -EOPNOTSUPP);
> +
> + /* Legacy struct size (up to token) should zero-fill arg and succeed */
> + min_arg.size = offsetof(struct liveupdate_session_preserve_fd, arg);
> + min_arg.fd = mem_fd1;
> + min_arg.token = 0x1111;
> + ASSERT_EQ(ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &min_arg), 0);
[Severity: Low]
In preserve_memfd_with_arg, min_arg is zero-initialized at declaration:
struct liveupdate_session_preserve_fd min_arg = {};
Because min_arg.arg is already 0 in userspace memory when ioctl() is called
with LIVEUPDATE_SESSION_PRESERVE_FD, the call would still see min_arg.arg == 0
even if the kernel read the entire struct from userspace instead of truncating
at min_arg.size and zero-filling the trailing arg field.
Should min_arg.arg be set to a non-zero value before the ioctl() call so that
this subtest verifies the kernel ignores bytes beyond min_arg.size and
zero-fills arg?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=2
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument
2026-11-03 1:02 ` [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument David Matlack
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 13:26 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 13:26 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> From: Pasha Tatashin <pasha.tatashin@soleen.com>
>
> Verify the user argument support in LIVEUPDATE_SESSION_PRESERVE_FD and
> LIVEUPDATE_SESSION_RETRIEVE_FD. Add luo_session_preserve_fd_arg() and
> luo_session_retrieve_fd_arg() helpers to libliveupdate so tests can pass
> a handler-specific argument.
>
> Add a preserve_memfd_with_arg test case to verify that memfd
> preservation rejects a non-zero argument with -EOPNOTSUPP, accepts an
> explicit zero argument, and remains compatible with callers passing the
> legacy struct size up to the token field.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
2026-11-03 1:02 ` [PATCH v3 01/10] liveupdate: Pass user argument to file preserve and retrieve David Matlack
2026-11-03 1:02 ` [PATCH v3 02/10] selftests: liveupdate: Add tests for preserve and retrieve user argument David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 1:03 ` sashiko-bot
2026-11-04 14:12 ` Pratyush Yadav
2026-11-03 1:02 ` [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo David Matlack
` (6 subsequent siblings)
9 siblings, 2 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
From: Pasha Tatashin <pasha.tatashin@soleen.com>
When luo_retrieve_file() invokes a handler's .retrieve() callback and it
returns an error, LUO currently records the error in
luo_file->retrieve_status and blocks any subsequent retrieve attempts.
This is necessary when the handler has already partially consumed or
freed the preserved KHO state.
However, with user arguments passed to .retrieve(), a handler may fail
early while validating caller-supplied parameters (such as a missing
argument, an invalid or read-only target file descriptor, or a non-empty
target file) before touching any preserved KHO state. In such cases,
userspace should be able to fix the argument and retry
LIVEUPDATE_SESSION_RETRIEVE_FD, and if the file is never retrieved,
.finish() must still run to release the preserved KHO state.
Add a retryable output flag to struct liveupdate_file_op_args. When a
handler sets args->retryable = true on error, luo_retrieve_file() leaves
luo_file->retrieve_status at 0 so the retrieve operation can be retried
and .finish() will still clean up the unconsumed preserved state if the
session is finished without retrieving the file.
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
include/linux/liveupdate.h | 11 ++++++++---
include/uapi/linux/liveupdate.h | 7 ++++---
kernel/liveupdate/luo_file.c | 20 ++++++++++++++------
3 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 7543f5d648d3..e4ad0bf78a5c 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -58,9 +58,13 @@ struct liveupdate_arg_spec {
* @session: The session this file belongs to.
* @retrieve_status: The retrieve status for the 'can_finish / finish'
* operation. A value of 0 means the retrieve has not been
- * attempted, a positive value means the retrieve was
- * successful, and a negative value means the retrieve failed,
- * and the value is the error code of the call.
+ * attempted (or only failed with a retryable error), a
+ * positive value means the retrieve was successful, and a
+ * negative value means the retrieve permanently failed, and
+ * the value is the error code of the call.
+ * @retryable: For .retrieve(): [OUT] Set to true by the callback on
+ * error when the preserved state has not been consumed and
+ * retrieval may be retried.
* @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.
@@ -83,6 +87,7 @@ struct liveupdate_file_op_args {
struct liveupdate_file_handler *handler;
struct liveupdate_session *session;
int retrieve_status;
+ bool retryable;
struct file *file;
u64 serialized_data;
void *private_data;
diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
index e806752c2fc6..953ffe0823be 100644
--- a/include/uapi/linux/liveupdate.h
+++ b/include/uapi/linux/liveupdate.h
@@ -174,9 +174,10 @@ struct liveupdate_session_preserve_fd {
* associated with the token and populates the @fd field with a new file
* descriptor referencing the restored resource in the current (new) kernel.
* This operation must be performed *before* signaling completion via
- * %LIVEUPDATE_IOCTL_FINISH. If a retrieve of a token fails, subsequent
- * attempts to retrieve the token fail with the same error code. Failed
- * retrieves are not retried.
+ * %LIVEUPDATE_IOCTL_FINISH. If a retrieve of a token fails after consuming
+ * preserved state, subsequent attempts to retrieve the token fail with the
+ * same error code. Early argument or target validation errors before
+ * preserved state is consumed leave the token intact and may be retried.
*
* Retrieving a token that was already retrieved successfully returns a new file
* descriptor for the same file. The @arg only applies to the retrieve that
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index eeeb3b5ff2fa..908ae124ea5e 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -152,9 +152,10 @@ static DEFINE_XARRAY(luo_preserved_files);
* @retrieve_status: Status code indicating whether a user/kernel in the new kernel has
* successfully called retrieve() on this file. This prevents
* multiple retrieval attempts. A value of 0 means a retrieve()
- * has not been attempted, a positive value means the retrieve()
- * was successful, and a negative value means the retrieve()
- * failed, and the value is the error code of the call.
+ * has not been attempted (or only failed with a retryable
+ * error), a positive value means the retrieve() was successful,
+ * and a negative value means the retrieve() permanently failed,
+ * and the value is the error code of the call.
* @mutex: A mutex that protects the fields of this specific instance
* (e.g., @retrieved, @file), ensuring that operations like
* retrieving or finishing a file are atomic.
@@ -604,7 +605,9 @@ void luo_file_unfreeze(struct luo_file_set *file_set,
* The operation is idempotent: if a file has already been successfully
* retrieved, this function will simply return a pointer to the existing
* 'struct file' and report success without re-executing the retrieve
- * operation. This is handled by checking the 'retrieved' flag under a lock.
+ * operation. If a previous retrieve failed permanently, it returns that
+ * saved error code; if a previous retrieve failed with a retryable error
+ * before consuming preserved state, the retrieve operation is re-attempted.
*
* File retrieval can happen in any order; it is not bound by the order of
* preservation.
@@ -671,8 +674,13 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token, u64 arg,
err = luo_file->fh->ops->retrieve(&args);
kfree(args.arg);
if (err) {
- /* Keep the error code for later use. */
- luo_file->retrieve_status = err;
+ /*
+ * Keep the error code for later use unless the handler marked
+ * the failure as retryable (e.g. invalid user argument before
+ * preserved state was consumed).
+ */
+ if (!args.retryable)
+ luo_file->retrieve_status = err;
return err;
}
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable
2026-11-03 1:02 ` [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable David Matlack
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 14:12 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> From: Pasha Tatashin <pasha.tatashin@soleen.com>
>
> When luo_retrieve_file() invokes a handler's .retrieve() callback and it
> returns an error, LUO currently records the error in
> luo_file->retrieve_status and blocks any subsequent retrieve attempts.
> This is necessary when the handler has already partially consumed or
> freed the preserved KHO state.
>
> However, with user arguments passed to .retrieve(), a handler may fail
> early while validating caller-supplied parameters (such as a missing
> argument, an invalid or read-only target file descriptor, or a non-empty
> target file) before touching any preserved KHO state. In such cases,
> userspace should be able to fix the argument and retry
> LIVEUPDATE_SESSION_RETRIEVE_FD, and if the file is never retrieved,
> .finish() must still run to release the preserved KHO state.
>
> Add a retryable output flag to struct liveupdate_file_op_args. When a
> handler sets args->retryable = true on error, luo_retrieve_file() leaves
> luo_file->retrieve_status at 0 so the retrieve operation can be retried
> and .finish() will still clean up the unconsumed preserved state if the
> session is finished without retrieving the file.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=3
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable
2026-11-03 1:02 ` [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable David Matlack
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 14:12 ` Pratyush Yadav
2026-11-04 16:15 ` Pasha Tatashin
1 sibling, 1 reply; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 14:12 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> From: Pasha Tatashin <pasha.tatashin@soleen.com>
>
> When luo_retrieve_file() invokes a handler's .retrieve() callback and it
> returns an error, LUO currently records the error in
> luo_file->retrieve_status and blocks any subsequent retrieve attempts.
> This is necessary when the handler has already partially consumed or
> freed the preserved KHO state.
>
> However, with user arguments passed to .retrieve(), a handler may fail
> early while validating caller-supplied parameters (such as a missing
> argument, an invalid or read-only target file descriptor, or a non-empty
> target file) before touching any preserved KHO state. In such cases,
> userspace should be able to fix the argument and retry
> LIVEUPDATE_SESSION_RETRIEVE_FD, and if the file is never retrieved,
> .finish() must still run to release the preserved KHO state.
>
> Add a retryable output flag to struct liveupdate_file_op_args. When a
> handler sets args->retryable = true on error, luo_retrieve_file() leaves
> luo_file->retrieve_status at 0 so the retrieve operation can be retried
> and .finish() will still clean up the unconsumed preserved state if the
> session is finished without retrieving the file.
Should we give some sort of signal to userspace whether the error is
retriable or not? How would it know it can or should try again?
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable
2026-11-04 14:12 ` Pratyush Yadav
@ 2026-11-04 16:15 ` Pasha Tatashin
0 siblings, 0 replies; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 16:15 UTC (permalink / raw)
To: Pratyush Yadav
Cc: David Matlack, kexec, linux-doc, linux-kernel, linux-kselftest,
linux-mm, Alexander Graf, Andrew Morton, Baolin Wang,
Christian Brauner, David Hildenbrand, Hugh Dickins,
Jonathan Corbet, Liam R. Howlett, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Pasha Tatashin, Randy Dunlap, Samiullah Khawaja,
Shuah Khan, Suren Baghdasaryan, Vlastimil Babka
On 11-04 15:12, Pratyush Yadav wrote:
> On Tue, Nov 03 2026, David Matlack wrote:
>
> > From: Pasha Tatashin <pasha.tatashin@soleen.com>
> >
> > When luo_retrieve_file() invokes a handler's .retrieve() callback and it
> > returns an error, LUO currently records the error in
> > luo_file->retrieve_status and blocks any subsequent retrieve attempts.
> > This is necessary when the handler has already partially consumed or
> > freed the preserved KHO state.
> >
> > However, with user arguments passed to .retrieve(), a handler may fail
> > early while validating caller-supplied parameters (such as a missing
> > argument, an invalid or read-only target file descriptor, or a non-empty
> > target file) before touching any preserved KHO state. In such cases,
> > userspace should be able to fix the argument and retry
> > LIVEUPDATE_SESSION_RETRIEVE_FD, and if the file is never retrieved,
> > .finish() must still run to release the preserved KHO state.
> >
> > Add a retryable output flag to struct liveupdate_file_op_args. When a
> > handler sets args->retryable = true on error, luo_retrieve_file() leaves
> > luo_file->retrieve_status at 0 so the retrieve operation can be retried
> > and .finish() will still clean up the unconsumed preserved state if the
> > session is finished without retrieving the file.
>
> Should we give some sort of signal to userspace whether the error is
> retriable or not? How would it know it can or should try again?
The goal of args->retryable is internal kernel state tracking.
From userspace's perspective, LUO ioctls behave like any other syscall
where errno is the signal: userspace decides whether and how to retry
based on the error code (e.g. retrying on -EAGAIN, or picking a
different mount on -EROFS/-EACCES, or adjusting flags/arguments on
-EINVAL).
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
` (2 preceding siblings ...)
2026-11-03 1:02 ` [PATCH v3 03/10] liveupdate: Allow file handlers to mark retrieve failures as retryable David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 1:03 ` sashiko-bot
2026-11-04 14:25 ` Pratyush Yadav
2026-11-03 1:02 ` [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails David Matlack
` (5 subsequent siblings)
9 siblings, 2 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
Rename the memfd Live Update file handler from memfd_luo to shmem_luo,
including the source file, its KHO ABI header, its documentation and its
Kconfig option (CONFIG_LIVEUPDATE_MEMFD to CONFIG_LIVEUPDATE_SHMEM).
The handler preserves shmem files. Today those are memfds, but following
commits extend it to other files on tmpfs mounts, for which the memfd
name is confusing. Preserving memfds created with MFD_HUGETLB, which are
hugetlbfs files, will need a separate handler, so naming the handler
after the filesystem that backs the files also avoids having to rename
it again then.
Don't change the compatible string of the handler, "memfd-v2". It is
matched against the preserved state from the previous kernel, so
changing it would break live updates from kernels that use the old
name. The serialized format doesn't change either.
Also clarify in the documentation that memfd means a memfd created
without MFD_HUGETLB, and name the ABI documentation after the handler.
No functional change intended.
Signed-off-by: David Matlack <dmatlack@google.com>
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
Documentation/core-api/liveupdate.rst | 2 +-
Documentation/mm/index.rst | 2 +-
...reservation.rst => shmem_preservation.rst} | 8 +-
MAINTAINERS | 4 +-
include/linux/kho/abi/{memfd.h => shmem.h} | 41 ++++---
kernel/liveupdate/Kconfig | 2 +-
mm/Makefile | 2 +-
mm/{memfd_luo.c => shmem_luo.c} | 115 +++++++++---------
8 files changed, 89 insertions(+), 87 deletions(-)
rename Documentation/mm/{memfd_preservation.rst => shmem_preservation.rst} (66%)
rename include/linux/kho/abi/{memfd.h => shmem.h} (65%)
rename mm/{memfd_luo.c => shmem_luo.c} (81%)
diff --git a/Documentation/core-api/liveupdate.rst b/Documentation/core-api/liveupdate.rst
index 2bce2644eba2..669722002440 100644
--- a/Documentation/core-api/liveupdate.rst
+++ b/Documentation/core-api/liveupdate.rst
@@ -37,7 +37,7 @@ The following types of file descriptors can be preserved
.. toctree::
:maxdepth: 1
- ../mm/memfd_preservation
+ ../mm/shmem_preservation
Public API
==========
diff --git a/Documentation/mm/index.rst b/Documentation/mm/index.rst
index 13a79f5d092c..b8ab2f89002d 100644
--- a/Documentation/mm/index.rst
+++ b/Documentation/mm/index.rst
@@ -61,7 +61,7 @@ documentation, or deleted if it has served its purpose.
hugetlbfs_reserv
ksm
memory-model
- memfd_preservation
+ shmem_preservation
mmu_notifier
multigen_lru
numa
diff --git a/Documentation/mm/memfd_preservation.rst b/Documentation/mm/shmem_preservation.rst
similarity index 66%
rename from Documentation/mm/memfd_preservation.rst
rename to Documentation/mm/shmem_preservation.rst
index c908a12dffa7..e79bf8afaa9e 100644
--- a/Documentation/mm/memfd_preservation.rst
+++ b/Documentation/mm/shmem_preservation.rst
@@ -4,16 +4,16 @@
Memfd Preservation via LUO
==========================
-.. kernel-doc:: mm/memfd_luo.c
+.. kernel-doc:: mm/shmem_luo.c
:doc: Memfd Preservation via LUO
Memfd Preservation ABI
======================
-.. kernel-doc:: include/linux/kho/abi/memfd.h
- :doc: memfd Live Update ABI
+.. kernel-doc:: include/linux/kho/abi/shmem.h
+ :doc: shmem Live Update ABI
-.. kernel-doc:: include/linux/kho/abi/memfd.h
+.. kernel-doc:: include/linux/kho/abi/shmem.h
:internal:
See Also
diff --git a/MAINTAINERS b/MAINTAINERS
index 5d1b58271989..742cdce14cf9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15184,14 +15184,14 @@ L: linux-kernel@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
F: Documentation/core-api/liveupdate.rst
-F: Documentation/mm/memfd_preservation.rst
+F: Documentation/mm/shmem_preservation.rst
F: Documentation/userspace-api/liveupdate.rst
F: include/linux/kho/abi/
F: include/linux/liveupdate.h
F: include/uapi/linux/liveupdate.h
F: kernel/liveupdate/
F: lib/tests/liveupdate.c
-F: mm/memfd_luo.c
+F: mm/shmem_luo.c
F: tools/testing/selftests/liveupdate/
LLC (802.2)
diff --git a/include/linux/kho/abi/memfd.h b/include/linux/kho/abi/shmem.h
similarity index 65%
rename from include/linux/kho/abi/memfd.h
rename to include/linux/kho/abi/shmem.h
index 08b10fea2afc..b61687e358a2 100644
--- a/include/linux/kho/abi/memfd.h
+++ b/include/linux/kho/abi/shmem.h
@@ -8,49 +8,50 @@
* Pratyush Yadav <ptyadav@amazon.de>
*/
-#ifndef _LINUX_KHO_ABI_MEMFD_H
-#define _LINUX_KHO_ABI_MEMFD_H
+#ifndef _LINUX_KHO_ABI_SHMEM_H
+#define _LINUX_KHO_ABI_SHMEM_H
#include <linux/types.h>
#include <linux/kho/abi/kexec_handover.h>
/**
- * DOC: memfd Live Update ABI
+ * DOC: shmem Live Update ABI
*
- * memfd uses the ABI defined below for preserving its state across a kexec
- * reboot using the LUO.
+ * The shmem file handler, which preserves memfds created without
+ * ``MFD_HUGETLB``, uses the ABI defined below for preserving their state across
+ * a kexec reboot using the LUO.
*
- * The state is serialized into a packed structure `struct memfd_luo_ser`
+ * The state is serialized into a packed structure `struct shmem_luo_ser`
* which is handed over to the next kernel via the KHO mechanism.
*
* This interface is a contract. Any modification to the structure layout
* constitutes a breaking change. Such changes require incrementing the
- * version number in the MEMFD_LUO_FH_COMPATIBLE string.
+ * version number in the SHMEM_LUO_FH_COMPATIBLE string.
*/
/**
- * MEMFD_LUO_FOLIO_DIRTY - The folio is dirty.
+ * SHMEM_LUO_FOLIO_DIRTY - The folio is dirty.
*
* This flag indicates the folio contains data from user. A non-dirty folio is
* one that was allocated (say using fallocate(2)) but not written to.
*/
-#define MEMFD_LUO_FOLIO_DIRTY BIT(0)
+#define SHMEM_LUO_FOLIO_DIRTY BIT(0)
/**
- * MEMFD_LUO_FOLIO_UPTODATE - The folio is up-to-date.
+ * SHMEM_LUO_FOLIO_UPTODATE - The folio is up-to-date.
*
* An up-to-date folio has been zeroed out. shmem zeroes out folios on first
* use. This flag tracks which folios need zeroing.
*/
-#define MEMFD_LUO_FOLIO_UPTODATE BIT(1)
+#define SHMEM_LUO_FOLIO_UPTODATE BIT(1)
/**
- * struct memfd_luo_folio_ser - Serialized state of a single folio.
+ * struct shmem_luo_folio_ser - Serialized state of a single folio.
* @pfn: The page frame number of the folio.
* @flags: Flags to describe the state of the folio.
* @index: The page offset (pgoff_t) of the folio within the original file.
*/
-struct memfd_luo_folio_ser {
+struct shmem_luo_folio_ser {
u64 pfn:52;
u64 flags:12;
u64 index;
@@ -60,7 +61,7 @@ struct memfd_luo_folio_ser {
* The set of seals this version supports preserving. If support for any new
* seals is needed, add it here and bump version.
*/
-#define MEMFD_LUO_ALL_SEALS (F_SEAL_SEAL | \
+#define SHMEM_LUO_ALL_SEALS (F_SEAL_SEAL | \
F_SEAL_SHRINK | \
F_SEAL_GROW | \
F_SEAL_WRITE | \
@@ -68,7 +69,7 @@ struct memfd_luo_folio_ser {
F_SEAL_EXEC)
/**
- * struct memfd_luo_ser - Main serialization structure for a memfd.
+ * struct shmem_luo_ser - Main serialization structure for a memfd.
* @pos: The file's current position (f_pos).
* @size: The total size of the file in bytes (i_size).
* @seals: The seals present on the memfd. The seals are uABI so it is safe
@@ -76,9 +77,9 @@ struct memfd_luo_folio_ser {
* @flags: Flags for the file. Unused flag bits must be set to 0.
* @nr_folios: Number of folios in the folios array.
* @folios: KHO vmalloc descriptor pointing to the array of
- * struct memfd_luo_folio_ser.
+ * struct shmem_luo_folio_ser.
*/
-struct memfd_luo_ser {
+struct shmem_luo_ser {
u64 pos;
u64 size;
u32 seals;
@@ -87,7 +88,7 @@ struct memfd_luo_ser {
struct kho_vmalloc folios;
} __packed;
-/* The compatibility string for memfd file handler */
-#define MEMFD_LUO_FH_COMPATIBLE "memfd-v2"
+/* The compatibility string for the shmem file handler */
+#define SHMEM_LUO_FH_COMPATIBLE "memfd-v2"
-#endif /* _LINUX_KHO_ABI_MEMFD_H */
+#endif /* _LINUX_KHO_ABI_SHMEM_H */
diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig
index f50daee8eff0..9a1c49e2e0c4 100644
--- a/kernel/liveupdate/Kconfig
+++ b/kernel/liveupdate/Kconfig
@@ -69,7 +69,7 @@ config LIVEUPDATE
If unsure, say N.
-config LIVEUPDATE_MEMFD
+config LIVEUPDATE_SHMEM
bool "Live update support for memfd"
depends on LIVEUPDATE
depends on MEMFD_CREATE
diff --git a/mm/Makefile b/mm/Makefile
index e7245cb88c66..cbdcc2c6b296 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -100,7 +100,7 @@ obj-$(CONFIG_NUMA) += memory-tiers.o
obj-$(CONFIG_DEVICE_MIGRATION) += migrate_device.o
obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o
obj-$(CONFIG_PAGE_COUNTER) += page_counter.o
-obj-$(CONFIG_LIVEUPDATE_MEMFD) += memfd_luo.o
+obj-$(CONFIG_LIVEUPDATE_SHMEM) += shmem_luo.o
obj-$(CONFIG_MEMCG_V1) += memcontrol-v1.o
obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o
ifdef CONFIG_BPF_SYSCALL
diff --git a/mm/memfd_luo.c b/mm/shmem_luo.c
similarity index 81%
rename from mm/memfd_luo.c
rename to mm/shmem_luo.c
index 6b68220275eb..b8d86055912d 100644
--- a/mm/memfd_luo.c
+++ b/mm/shmem_luo.c
@@ -18,6 +18,11 @@
* Update Orchestrator (LUO) file preservation. This allows userspace to
* transfer its memory contents to the next kernel after a kexec.
*
+ * Here, a memfd is a memfd created without ``MFD_HUGETLB``, which is a shmem
+ * file on the kernel's internal shmem mount. Memfds created with
+ * ``MFD_HUGETLB`` are hugetlbfs files, which this file handler doesn't
+ * preserve. Preserving them fails with ``-ENOENT``.
+ *
* The preservation is not intended to be transparent. Only select properties of
* the file are preserved. All others are reset to default. The preserved
* properties are described below.
@@ -26,10 +31,6 @@
* The LUO API is not stabilized yet, so the preserved properties of a memfd
* are also not stable and are subject to backwards incompatible changes.
*
- * .. note::
- * Currently a memfd backed by Hugetlb is not supported. Memfds created
- * with ``MFD_HUGETLB`` will be rejected.
- *
* Preserved Properties
* ====================
*
@@ -52,7 +53,7 @@
*
* Seals
* File seals set on the memfd are preserved and re-applied on restore.
- * Only seals known to this LUO version (see ``MEMFD_LUO_ALL_SEALS``) may
+ * Only seals known to this LUO version (see ``SHMEM_LUO_ALL_SEALS``) may
* be present; preservation fails with ``-EOPNOTSUPP`` otherwise.
*
* Non-Preserved Properties
@@ -75,7 +76,7 @@
#include <linux/file.h>
#include <linux/io.h>
#include <linux/kexec_handover.h>
-#include <linux/kho/abi/memfd.h>
+#include <linux/kho/abi/shmem.h>
#include <linux/liveupdate.h>
#include <linux/shmem_fs.h>
#include <linux/vmalloc.h>
@@ -84,13 +85,13 @@
#include "internal.h"
-static int memfd_luo_preserve_folios(struct file *file,
+static int shmem_luo_preserve_folios(struct file *file,
struct kho_vmalloc *kho_vmalloc,
- struct memfd_luo_folio_ser **out_folios_ser,
+ struct shmem_luo_folio_ser **out_folios_ser,
u64 *nr_foliosp)
{
struct inode *inode = file_inode(file);
- struct memfd_luo_folio_ser *folios_ser;
+ struct shmem_luo_folio_ser *folios_ser;
unsigned int max_folios;
long i, size, nr_pinned;
struct folio **folios;
@@ -145,7 +146,7 @@ static int memfd_luo_preserve_folios(struct file *file,
}
for (i = 0; i < nr_folios; i++) {
- struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
+ struct shmem_luo_folio_ser *pfolio = &folios_ser[i];
struct folio *folio = folios[i];
err = kho_preserve_folio(folio);
@@ -196,7 +197,7 @@ static int memfd_luo_preserve_folios(struct file *file,
folio_unlock(folio);
pfolio->pfn = folio_pfn(folio);
- pfolio->flags = MEMFD_LUO_FOLIO_DIRTY | MEMFD_LUO_FOLIO_UPTODATE;
+ pfolio->flags = SHMEM_LUO_FOLIO_DIRTY | SHMEM_LUO_FOLIO_UPTODATE;
pfolio->index = folio->index;
}
@@ -227,8 +228,8 @@ static int memfd_luo_preserve_folios(struct file *file,
return err;
}
-static void memfd_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
- struct memfd_luo_folio_ser *folios_ser,
+static void shmem_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
+ struct shmem_luo_folio_ser *folios_ser,
u64 nr_folios)
{
long i;
@@ -239,7 +240,7 @@ static void memfd_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
kho_unpreserve_vmalloc(kho_vmalloc);
for (i = 0; i < nr_folios; i++) {
- const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
+ const struct shmem_luo_folio_ser *pfolio = &folios_ser[i];
struct folio *folio;
if (!pfolio->pfn)
@@ -254,11 +255,11 @@ static void memfd_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
vfree(folios_ser);
}
-static int memfd_luo_preserve(struct liveupdate_file_op_args *args)
+static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
{
struct inode *inode = file_inode(args->file);
- struct memfd_luo_folio_ser *folios_ser;
- struct memfd_luo_ser *ser;
+ struct shmem_luo_folio_ser *folios_ser;
+ struct shmem_luo_ser *ser;
u64 nr_folios, inode_size;
int err = 0, seals;
@@ -279,7 +280,7 @@ static int memfd_luo_preserve(struct liveupdate_file_op_args *args)
}
/* Make sure the file only has the seals supported by this version. */
- if (seals & ~MEMFD_LUO_ALL_SEALS) {
+ if (seals & ~SHMEM_LUO_ALL_SEALS) {
err = -EOPNOTSUPP;
goto err_free_ser;
}
@@ -299,7 +300,7 @@ static int memfd_luo_preserve(struct liveupdate_file_op_args *args)
ser->size = inode_size;
ser->seals = seals;
- err = memfd_luo_preserve_folios(args->file, &ser->folios,
+ err = shmem_luo_preserve_folios(args->file, &ser->folios,
&folios_ser, &nr_folios);
if (err)
goto err_free_ser;
@@ -320,9 +321,9 @@ static int memfd_luo_preserve(struct liveupdate_file_op_args *args)
return err;
}
-static int memfd_luo_freeze(struct liveupdate_file_op_args *args)
+static int shmem_luo_freeze(struct liveupdate_file_op_args *args)
{
- struct memfd_luo_ser *ser;
+ struct shmem_luo_ser *ser;
if (WARN_ON_ONCE(!args->serialized_data))
return -EINVAL;
@@ -338,10 +339,10 @@ static int memfd_luo_freeze(struct liveupdate_file_op_args *args)
return 0;
}
-static void memfd_luo_unpreserve(struct liveupdate_file_op_args *args)
+static void shmem_luo_unpreserve(struct liveupdate_file_op_args *args)
{
struct inode *inode = file_inode(args->file);
- struct memfd_luo_ser *ser;
+ struct shmem_luo_ser *ser;
if (WARN_ON_ONCE(!args->serialized_data))
return;
@@ -351,20 +352,20 @@ static void memfd_luo_unpreserve(struct liveupdate_file_op_args *args)
ser = phys_to_virt(args->serialized_data);
- memfd_luo_unpreserve_folios(&ser->folios, args->private_data,
+ shmem_luo_unpreserve_folios(&ser->folios, args->private_data,
ser->nr_folios);
kho_unpreserve_free(ser);
inode_unlock(inode);
}
-static void memfd_luo_discard_folios(const struct memfd_luo_folio_ser *folios_ser,
+static void shmem_luo_discard_folios(const struct shmem_luo_folio_ser *folios_ser,
u64 nr_folios)
{
u64 i;
for (i = 0; i < nr_folios; i++) {
- const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
+ const struct shmem_luo_folio_ser *pfolio = &folios_ser[i];
struct folio *folio;
phys_addr_t phys;
@@ -383,10 +384,10 @@ static void memfd_luo_discard_folios(const struct memfd_luo_folio_ser *folios_se
}
}
-static void memfd_luo_finish(struct liveupdate_file_op_args *args)
+static void shmem_luo_finish(struct liveupdate_file_op_args *args)
{
- struct memfd_luo_folio_ser *folios_ser;
- struct memfd_luo_ser *ser;
+ struct shmem_luo_folio_ser *folios_ser;
+ struct shmem_luo_ser *ser;
/*
* If retrieve was successful, nothing to do. If it failed, retrieve()
@@ -405,7 +406,7 @@ static void memfd_luo_finish(struct liveupdate_file_op_args *args)
if (!folios_ser)
goto out;
- memfd_luo_discard_folios(folios_ser, ser->nr_folios);
+ shmem_luo_discard_folios(folios_ser, ser->nr_folios);
vfree(folios_ser);
}
@@ -413,8 +414,8 @@ static void memfd_luo_finish(struct liveupdate_file_op_args *args)
kho_restore_free(ser);
}
-static int memfd_luo_retrieve_folios(struct file *file,
- struct memfd_luo_folio_ser *folios_ser,
+static int shmem_luo_retrieve_folios(struct file *file,
+ struct shmem_luo_folio_ser *folios_ser,
u64 nr_folios)
{
struct inode *inode = file_inode(file);
@@ -425,7 +426,7 @@ static int memfd_luo_retrieve_folios(struct file *file,
long i;
for (i = 0; i < nr_folios; i++) {
- const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
+ const struct shmem_luo_folio_ser *pfolio = &folios_ser[i];
phys_addr_t phys;
u64 index;
int flags;
@@ -463,9 +464,9 @@ static int memfd_luo_retrieve_folios(struct file *file,
goto unlock_folio;
}
- if (flags & MEMFD_LUO_FOLIO_UPTODATE)
+ if (flags & SHMEM_LUO_FOLIO_UPTODATE)
folio_mark_uptodate(folio);
- if (flags & MEMFD_LUO_FOLIO_DIRTY)
+ if (flags & SHMEM_LUO_FOLIO_DIRTY)
folio_mark_dirty(folio);
npages = folio_nr_pages(folio);
@@ -497,7 +498,7 @@ static int memfd_luo_retrieve_folios(struct file *file,
* freed when the file is freed. Free the ones not added yet here.
*/
for (long j = i + 1; j < nr_folios; j++) {
- const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
+ const struct shmem_luo_folio_ser *pfolio = &folios_ser[j];
phys_addr_t phys;
if (!pfolio->pfn)
@@ -514,10 +515,10 @@ static int memfd_luo_retrieve_folios(struct file *file,
return err;
}
-static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
+static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
{
- struct memfd_luo_folio_ser *folios_ser;
- struct memfd_luo_ser *ser;
+ struct shmem_luo_folio_ser *folios_ser;
+ struct shmem_luo_ser *ser;
struct file *file;
int err;
@@ -526,7 +527,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
return -EINVAL;
/* Make sure the file only has seals supported by this version. */
- if (ser->seals & ~MEMFD_LUO_ALL_SEALS) {
+ if (ser->seals & ~SHMEM_LUO_ALL_SEALS) {
err = -EOPNOTSUPP;
goto free_ser;
}
@@ -558,7 +559,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
goto put_file;
}
- err = memfd_luo_retrieve_folios(file, folios_ser, ser->nr_folios);
+ err = shmem_luo_retrieve_folios(file, folios_ser, ser->nr_folios);
vfree(folios_ser);
if (err)
goto put_file;
@@ -576,7 +577,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
return err;
}
-static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler,
+static bool shmem_luo_can_preserve(struct liveupdate_file_handler *handler,
struct file *file)
{
struct inode *inode = file_inode(file);
@@ -584,30 +585,30 @@ static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler,
return shmem_file(file) && !inode->i_nlink;
}
-static unsigned long memfd_luo_get_id(struct file *file)
+static unsigned long shmem_luo_get_id(struct file *file)
{
return (unsigned long)file_inode(file);
}
-static const struct liveupdate_file_ops memfd_luo_file_ops = {
- .freeze = memfd_luo_freeze,
- .finish = memfd_luo_finish,
- .retrieve = memfd_luo_retrieve,
- .preserve = memfd_luo_preserve,
- .unpreserve = memfd_luo_unpreserve,
- .can_preserve = memfd_luo_can_preserve,
- .get_id = memfd_luo_get_id,
+static const struct liveupdate_file_ops shmem_luo_file_ops = {
+ .freeze = shmem_luo_freeze,
+ .finish = shmem_luo_finish,
+ .retrieve = shmem_luo_retrieve,
+ .preserve = shmem_luo_preserve,
+ .unpreserve = shmem_luo_unpreserve,
+ .can_preserve = shmem_luo_can_preserve,
+ .get_id = shmem_luo_get_id,
.owner = THIS_MODULE,
};
-static struct liveupdate_file_handler memfd_luo_handler = {
- .ops = &memfd_luo_file_ops,
- .compatible = MEMFD_LUO_FH_COMPATIBLE,
+static struct liveupdate_file_handler shmem_luo_handler = {
+ .ops = &shmem_luo_file_ops,
+ .compatible = SHMEM_LUO_FH_COMPATIBLE,
};
-static int __init memfd_luo_init(void)
+static int __init shmem_luo_init(void)
{
- int err = liveupdate_register_file_handler(&memfd_luo_handler);
+ int err = liveupdate_register_file_handler(&shmem_luo_handler);
if (err && err != -EOPNOTSUPP) {
pr_err("Could not register luo filesystem handler: %pe\n",
@@ -618,4 +619,4 @@ static int __init memfd_luo_init(void)
return 0;
}
-late_initcall(memfd_luo_init);
+late_initcall(shmem_luo_init);
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo
2026-11-03 1:02 ` [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo David Matlack
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 14:25 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Rename the memfd Live Update file handler from memfd_luo to shmem_luo,
> including the source file, its KHO ABI header, its documentation and its
> Kconfig option (CONFIG_LIVEUPDATE_MEMFD to CONFIG_LIVEUPDATE_SHMEM).
>
> The handler preserves shmem files. Today those are memfds, but following
> commits extend it to other files on tmpfs mounts, for which the memfd
> name is confusing. Preserving memfds created with MFD_HUGETLB, which are
> hugetlbfs files, will need a separate handler, so naming the handler
> after the filesystem that backs the files also avoids having to rename
> it again then.
>
> Don't change the compatible string of the handler, "memfd-v2". It is
> matched against the preserved state from the previous kernel, so
> changing it would break live updates from kernels that use the old
> name. The serialized format doesn't change either.
>
> Also clarify in the documentation that memfd means a memfd created
> without MFD_HUGETLB, and name the ABI documentation after the handler.
>
> No functional change intended.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=4
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo
2026-11-03 1:02 ` [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo David Matlack
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 14:25 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 14:25 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> Rename the memfd Live Update file handler from memfd_luo to shmem_luo,
> including the source file, its KHO ABI header, its documentation and its
> Kconfig option (CONFIG_LIVEUPDATE_MEMFD to CONFIG_LIVEUPDATE_SHMEM).
>
> The handler preserves shmem files. Today those are memfds, but following
> commits extend it to other files on tmpfs mounts, for which the memfd
> name is confusing. Preserving memfds created with MFD_HUGETLB, which are
> hugetlbfs files, will need a separate handler, so naming the handler
> after the filesystem that backs the files also avoids having to rename
> it again then.
>
> Don't change the compatible string of the handler, "memfd-v2". It is
> matched against the preserved state from the previous kernel, so
> changing it would break live updates from kernels that use the old
> name. The serialized format doesn't change either.
>
> Also clarify in the documentation that memfd means a memfd created
> without MFD_HUGETLB, and name the ABI documentation after the handler.
>
> No functional change intended.
>
[...]
> diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig
> index f50daee8eff0..9a1c49e2e0c4 100644
> --- a/kernel/liveupdate/Kconfig
> +++ b/kernel/liveupdate/Kconfig
> @@ -69,7 +69,7 @@ config LIVEUPDATE
>
> If unsure, say N.
>
> -config LIVEUPDATE_MEMFD
> +config LIVEUPDATE_SHMEM
Update the description too?
LGTM otherwise.
Acked-by: Pratyush Yadav (Google) <pratyush@kernel.org>
> bool "Live update support for memfd"
> depends on LIVEUPDATE
> depends on MEMFD_CREATE
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
` (3 preceding siblings ...)
2026-11-03 1:02 ` [PATCH v3 04/10] mm: Rename memfd_luo to shmem_luo David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 1:03 ` sashiko-bot
2026-11-04 14:32 ` Pratyush Yadav
2026-11-03 1:02 ` [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent David Matlack
` (4 subsequent siblings)
9 siblings, 2 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
Handle a failure to add a retrieved file to luo_preserved_files instead
of triggering a WARN_ON(). Make the failure permanent, and keep the file
until the file set is finished, like any other retrieved file.
xa_insert() can fail with -ENOMEM, and userspace can trigger that with
LIVEUPDATE_SESSION_RETRIEVE_FD, so warning about it lets userspace crash
systems with panic_on_warn.
The handler has already consumed the preserved state when this happens,
so the retrieve can't be retried. Keeping the file ensures that its
resources are not released before the file set is finished. Finishing
the file set then erases the file from luo_preserved_files, which does
nothing for a file that was never added.
Fixes: 00d0b372374f ("liveupdate: prevent double management of files")
Signed-off-by: David Matlack <dmatlack@google.com>
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
kernel/liveupdate/luo_file.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 908ae124ea5e..5a82e45b9062 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -684,14 +684,25 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token, u64 arg,
return err;
}
+ err = xa_insert(&luo_preserved_files,
+ luo_get_id(luo_file->fh, args.file), args.file,
+ GFP_KERNEL);
+ if (err) {
+ /*
+ * The handler has consumed the preserved state, so the retrieve
+ * can't be retried. Keep the file until the file set is
+ * finished, so that its resources are released at the same
+ * time as those of other retrieved files.
+ */
+ luo_file->file = args.file;
+ luo_file->retrieve_status = err;
+ return err;
+ }
+
luo_file->file = args.file;
/* Get reference so we can keep this file in LUO until finish */
get_file(luo_file->file);
- WARN_ON(xa_insert(&luo_preserved_files,
- luo_get_id(luo_file->fh, luo_file->file),
- luo_file->file, GFP_KERNEL));
-
*filep = luo_file->file;
luo_file->retrieve_status = 1;
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails
2026-11-03 1:02 ` [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails David Matlack
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 14:32 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Handle a failure to add a retrieved file to luo_preserved_files instead
> of triggering a WARN_ON(). Make the failure permanent, and keep the file
> until the file set is finished, like any other retrieved file.
>
> xa_insert() can fail with -ENOMEM, and userspace can trigger that with
> LIVEUPDATE_SESSION_RETRIEVE_FD, so warning about it lets userspace crash
> systems with panic_on_warn.
>
> The handler has already consumed the preserved state when this happens,
> so the retrieve can't be retried. Keeping the file ensures that its
> resources are not released before the file set is finished. Finishing
> the file set then erases the file from luo_preserved_files, which does
> nothing for a file that was never added.
>
> Fixes: 00d0b372374f ("liveupdate: prevent double management of files")
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=5
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails
2026-11-03 1:02 ` [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails David Matlack
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 14:32 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 14:32 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> Handle a failure to add a retrieved file to luo_preserved_files instead
> of triggering a WARN_ON(). Make the failure permanent, and keep the file
> until the file set is finished, like any other retrieved file.
>
> xa_insert() can fail with -ENOMEM, and userspace can trigger that with
> LIVEUPDATE_SESSION_RETRIEVE_FD, so warning about it lets userspace crash
> systems with panic_on_warn.
>
> The handler has already consumed the preserved state when this happens,
> so the retrieve can't be retried. Keeping the file ensures that its
> resources are not released before the file set is finished. Finishing
> the file set then erases the file from luo_preserved_files, which does
> nothing for a file that was never added.
>
> Fixes: 00d0b372374f ("liveupdate: prevent double management of files")
> Signed-off-by: David Matlack <dmatlack@google.com>
> Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
> kernel/liveupdate/luo_file.c | 19 +++++++++++++++----
> 1 file changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
> index 908ae124ea5e..5a82e45b9062 100644
> --- a/kernel/liveupdate/luo_file.c
> +++ b/kernel/liveupdate/luo_file.c
> @@ -684,14 +684,25 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token, u64 arg,
> return err;
> }
>
> + err = xa_insert(&luo_preserved_files,
> + luo_get_id(luo_file->fh, args.file), args.file,
> + GFP_KERNEL);
> + if (err) {
I think you should do a WARN_ON_ONCE(err == -EBUSY) here. Because if
someone can somehow retrieve the same file twice, something really bad
has happened and must be reported.
> + /*
> + * The handler has consumed the preserved state, so the retrieve
> + * can't be retried. Keep the file until the file set is
> + * finished, so that its resources are released at the same
> + * time as those of other retrieved files.
> + */
> + luo_file->file = args.file;
> + luo_file->retrieve_status = err;
> + return err;
> + }
> +
> luo_file->file = args.file;
> /* Get reference so we can keep this file in LUO until finish */
> get_file(luo_file->file);
>
> - WARN_ON(xa_insert(&luo_preserved_files,
> - luo_get_id(luo_file->fh, luo_file->file),
> - luo_file->file, GFP_KERNEL));
> -
> *filep = luo_file->file;
> luo_file->retrieve_status = 1;
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
` (4 preceding siblings ...)
2026-11-03 1:02 ` [PATCH v3 05/10] liveupdate: Don't WARN if tracking a retrieved file fails David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 1:03 ` sashiko-bot
2026-11-04 15:01 ` Pratyush Yadav
2026-11-03 1:02 ` [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace David Matlack
` (3 subsequent siblings)
9 siblings, 2 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
Mark failures in shmem_luo_retrieve() before it starts restoring the
folios as retryable, and return the error without freeing the serialized
state. If no retrieve succeeds, finish() frees the preserved folios,
like it does for a file that was never retrieved.
Nothing has consumed the preserved state before the folios are
restored, so the retrieve can be tried again.
This also fixes leaking the preserved folios when one of these early
steps fails, e.g. because the file has seals that this kernel doesn't
support. The retrieve freed the serialized state but not the folios, and
finish() then skipped the file because its retrieve had failed. There is
no Fixes tag, since the fix relies on args->retryable, which was only
added earlier in this series.
Signed-off-by: David Matlack <dmatlack@google.com>
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
mm/shmem_luo.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/mm/shmem_luo.c b/mm/shmem_luo.c
index b8d86055912d..bcac1bbb3db3 100644
--- a/mm/shmem_luo.c
+++ b/mm/shmem_luo.c
@@ -390,9 +390,9 @@ static void shmem_luo_finish(struct liveupdate_file_op_args *args)
struct shmem_luo_ser *ser;
/*
- * If retrieve was successful, nothing to do. If it failed, retrieve()
- * already cleaned up everything it could. So nothing to do there
- * either. Only need to clean up when retrieve was not called.
+ * If retrieve was successful, nothing to do. If it failed permanently,
+ * retrieve() already cleaned up everything it could. So nothing to do
+ * there either. Only need to clean up when the file was not retrieved.
*/
if (args->retrieve_status)
return;
@@ -526,11 +526,16 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
if (!ser)
return -EINVAL;
+ /*
+ * Nothing has consumed the preserved state until the folios are
+ * restored below, so failures before that can be retried. If no
+ * retrieve succeeds, finish() frees the preserved state.
+ */
+ args->retryable = true;
+
/* Make sure the file only has seals supported by this version. */
- if (ser->seals & ~SHMEM_LUO_ALL_SEALS) {
- err = -EOPNOTSUPP;
- goto free_ser;
- }
+ if (ser->seals & ~SHMEM_LUO_ALL_SEALS)
+ return -EOPNOTSUPP;
/*
* The seals are preserved. Allow sealing here so they can be added
@@ -539,8 +544,7 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
file = memfd_alloc_file("", MFD_ALLOW_SEALING);
if (IS_ERR(file)) {
pr_err("failed to setup file: %pe\n", file);
- err = PTR_ERR(file);
- goto free_ser;
+ return PTR_ERR(file);
}
err = memfd_add_seals(file, ser->seals);
@@ -552,17 +556,20 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
vfs_setpos(file, ser->pos, MAX_LFS_FILESIZE);
i_size_write(file_inode(file), ser->size);
+ /* The preserved state is consumed from here on. */
+ args->retryable = false;
+
if (ser->nr_folios) {
folios_ser = kho_restore_vmalloc(&ser->folios);
if (!folios_ser) {
err = -EINVAL;
- goto put_file;
+ goto free_ser;
}
err = shmem_luo_retrieve_folios(file, folios_ser, ser->nr_folios);
vfree(folios_ser);
if (err)
- goto put_file;
+ goto free_ser;
}
args->file = file;
@@ -570,10 +577,10 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
return 0;
-put_file:
- fput(file);
free_ser:
kho_restore_free(ser);
+put_file:
+ fput(file);
return err;
}
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent
2026-11-03 1:02 ` [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent David Matlack
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 15:01 ` Pratyush Yadav
1 sibling, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Mark failures in shmem_luo_retrieve() before it starts restoring the
> folios as retryable, and return the error without freeing the serialized
> state. If no retrieve succeeds, finish() frees the preserved folios,
> like it does for a file that was never retrieved.
>
> Nothing has consumed the preserved state before the folios are
> restored, so the retrieve can be tried again.
>
> This also fixes leaking the preserved folios when one of these early
> steps fails, e.g. because the file has seals that this kernel doesn't
> support. The retrieve freed the serialized state but not the folios, and
> finish() then skipped the file because its retrieve had failed. There is
> no Fixes tag, since the fix relies on args->retryable, which was only
> added earlier in this series.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=6
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent
2026-11-03 1:02 ` [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent David Matlack
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 15:01 ` Pratyush Yadav
2026-11-04 22:28 ` David Matlack
1 sibling, 1 reply; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 15:01 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> Mark failures in shmem_luo_retrieve() before it starts restoring the
> folios as retryable, and return the error without freeing the serialized
> state. If no retrieve succeeds, finish() frees the preserved folios,
> like it does for a file that was never retrieved.
>
> Nothing has consumed the preserved state before the folios are
> restored, so the retrieve can be tried again.
>
> This also fixes leaking the preserved folios when one of these early
> steps fails, e.g. because the file has seals that this kernel doesn't
> support. The retrieve freed the serialized state but not the folios, and
> finish() then skipped the file because its retrieve had failed. There is
> no Fixes tag, since the fix relies on args->retryable, which was only
> added earlier in this series.
If the seals don't match, the retrieve is not retryable. It will always
fail.
I think the only retriable part is memfd_alloc_file(), although even
that is quite unlikely to fail. But I think that also fits pretty well
with the most important type of error you want to retry on, which is bad
arguments. In later patches, you check the argument on
shmem_luo_create_tmpfs_file() or shmem_luo_create_memfd(), so perhaps
set retriable in those functions?
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent
2026-11-04 15:01 ` Pratyush Yadav
@ 2026-11-04 22:28 ` David Matlack
0 siblings, 0 replies; 42+ messages in thread
From: David Matlack @ 2026-11-04 22:28 UTC (permalink / raw)
To: Pratyush Yadav
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Randy Dunlap, Samiullah Khawaja, Shuah Khan, Suren Baghdasaryan,
Vlastimil Babka
On 2026-11-04 04:01 PM, Pratyush Yadav wrote:
> On Tue, Nov 03 2026, David Matlack wrote:
>
> > Mark failures in shmem_luo_retrieve() before it starts restoring the
> > folios as retryable, and return the error without freeing the serialized
> > state. If no retrieve succeeds, finish() frees the preserved folios,
> > like it does for a file that was never retrieved.
> >
> > Nothing has consumed the preserved state before the folios are
> > restored, so the retrieve can be tried again.
> >
> > This also fixes leaking the preserved folios when one of these early
> > steps fails, e.g. because the file has seals that this kernel doesn't
> > support. The retrieve freed the serialized state but not the folios, and
> > finish() then skipped the file because its retrieve had failed. There is
> > no Fixes tag, since the fix relies on args->retryable, which was only
> > added earlier in this series.
>
> If the seals don't match, the retrieve is not retryable. It will always
> fail.
>
> I think the only retriable part is memfd_alloc_file(), although even
> that is quite unlikely to fail. But I think that also fits pretty well
> with the most important type of error you want to retry on, which is bad
> arguments. In later patches, you check the argument on
> shmem_luo_create_tmpfs_file() or shmem_luo_create_memfd(), so perhaps
> set retriable in those functions?
When retryable is set, LUO leaves the file unretrieved and finish()
frees the preserved folios. If the seal failure did not set retryable,
finish() would skip the file and the folios would leak.
In v4 I can move the seal checks into shmem_luo_create_memfd() and
shmem_luo_create_tmpfs_file(), since the valid seals differ between the
two, and reword the commit message so it doesn't suggest that a bad seal
can be fixed by retrying.
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
` (5 preceding siblings ...)
2026-11-03 1:02 ` [PATCH v3 06/10] mm/shmem_luo: Don't make early retrieve failures permanent David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 0:43 ` Pasha Tatashin
` (2 more replies)
2026-11-03 1:02 ` [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked David Matlack
` (2 subsequent siblings)
9 siblings, 3 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
Retrieve files that were preserved from a tmpfs mount onto a tmpfs mount
chosen by userspace, instead of as memfds on the internal tmpfs mount.
Add struct liveupdate_shmem_retrieve_arg, which userspace passes as the
retrieve argument of LIVEUPDATE_SESSION_RETRIEVE_FD to choose the mount.
Record which mount a file was on with a new SHMEM_LUO_FLAG_TMPFS flag in
struct shmem_luo_ser, based on the superblock of the file.
shmem_luo already accepts unlinked tmpfs files, such as files created
with O_TMPFILE, and a following commit also accepts linked ones. The
mount such a file was on doesn't exist in the new kernel, and userspace
may want to put the file elsewhere anyway.
Model struct liveupdate_shmem_retrieve_arg on open(): The kernel creates
a new file as if by openat(dirfd, ".", O_TMPFILE | flags, mode), so the
file gets the owner, permission checks and security labels of any new
file in that directory, and is charged to that mount. The kernel then
fills the file with the preserved contents, size, position and seals
before returning it, so nothing else can access the file before it is
complete. Userspace links the file at the path it wants with linkat(),
or passes O_EXCL to keep it unlinked. Neither the path nor any other
inode attribute of the file is part of the preserved state, which keeps
them out of the KHO ABI.
Pass the flags from userspace to file_open_root(), so that the VFS
checks them like for open(). file_open_root() silently ignores unknown
flags and mode bits, so reject those like openat2() does. Also reject
O_PATH, with which file_open_root() would ignore O_TMPFILE and open the
directory.
Keep the type of the file: memfds can only be retrieved as memfds, and
files on tmpfs mounts only onto tmpfs mounts, so that e.g. a file
can't be moved off the mount whose size limit and quotas it was subject
to. Passing the argument when retrieving a memfd, or not passing it when
retrieving a file from a tmpfs mount, fails with -EINVAL. Unlinked tmpfs
files were retrieved as memfds until now, but nothing relies on that, as
the LUO uAPI is not stable yet.
Like the other failures before the folios are restored, problems with
the argument and with creating the file can be retried.
Signed-off-by: David Matlack <dmatlack@google.com>
---
Documentation/mm/shmem_preservation.rst | 8 +-
include/linux/kho/abi/shmem.h | 21 ++-
include/uapi/linux/liveupdate.h | 35 +++++
kernel/liveupdate/Kconfig | 6 +-
mm/internal.h | 1 +
mm/shmem.c | 9 ++
mm/shmem_luo.c | 180 ++++++++++++++++++++----
7 files changed, 221 insertions(+), 39 deletions(-)
diff --git a/Documentation/mm/shmem_preservation.rst b/Documentation/mm/shmem_preservation.rst
index e79bf8afaa9e..030a8f18680c 100644
--- a/Documentation/mm/shmem_preservation.rst
+++ b/Documentation/mm/shmem_preservation.rst
@@ -1,11 +1,11 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
-==========================
-Memfd Preservation via LUO
-==========================
+====================================
+Memfd and Tmpfs Preservation via LUO
+====================================
.. kernel-doc:: mm/shmem_luo.c
- :doc: Memfd Preservation via LUO
+ :doc: Memfd and Tmpfs Preservation via LUO
Memfd Preservation ABI
======================
diff --git a/include/linux/kho/abi/shmem.h b/include/linux/kho/abi/shmem.h
index b61687e358a2..88ef7d49b5f3 100644
--- a/include/linux/kho/abi/shmem.h
+++ b/include/linux/kho/abi/shmem.h
@@ -18,8 +18,8 @@
* DOC: shmem Live Update ABI
*
* The shmem file handler, which preserves memfds created without
- * ``MFD_HUGETLB``, uses the ABI defined below for preserving their state across
- * a kexec reboot using the LUO.
+ * ``MFD_HUGETLB`` and tmpfs files, uses the ABI defined below for preserving
+ * their state across a kexec reboot using the LUO.
*
* The state is serialized into a packed structure `struct shmem_luo_ser`
* which is handed over to the next kernel via the KHO mechanism.
@@ -69,12 +69,25 @@ struct shmem_luo_folio_ser {
F_SEAL_EXEC)
/**
- * struct shmem_luo_ser - Main serialization structure for a memfd.
+ * SHMEM_LUO_FLAG_TMPFS - The file was on a tmpfs mount.
+ *
+ * Set for files that were not on the internal shmem mount that memfds are
+ * created on. Such a file is retrieved onto a tmpfs mount chosen by userspace,
+ * instead of as a memfd.
+ */
+#define SHMEM_LUO_FLAG_TMPFS BIT(0)
+
+/* The set of flags this version supports. */
+#define SHMEM_LUO_ALL_FLAGS SHMEM_LUO_FLAG_TMPFS
+
+/**
+ * struct shmem_luo_ser - Main serialization structure for a memfd or tmpfs file.
* @pos: The file's current position (f_pos).
* @size: The total size of the file in bytes (i_size).
* @seals: The seals present on the memfd. The seals are uABI so it is safe
* to directly use them in the ABI.
- * @flags: Flags for the file. Unused flag bits must be set to 0.
+ * @flags: Flags for the file (SHMEM_LUO_FLAG_*). Unused flag bits must be
+ * set to 0.
* @nr_folios: Number of folios in the folios array.
* @folios: KHO vmalloc descriptor pointing to the array of
* struct shmem_luo_folio_ser.
diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
index 953ffe0823be..a9dcc4fcc87b 100644
--- a/include/uapi/linux/liveupdate.h
+++ b/include/uapi/linux/liveupdate.h
@@ -247,4 +247,39 @@ struct liveupdate_session_get_name {
#define LIVEUPDATE_SESSION_GET_NAME \
_IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_GET_NAME)
+/**
+ * struct liveupdate_shmem_retrieve_arg - Argument to retrieve a tmpfs file
+ * @size: Input; sizeof(struct liveupdate_shmem_retrieve_arg)
+ * @dirfd: Input; A file descriptor for a directory on the tmpfs mount to create
+ * the file on.
+ * @flags: Input; The flags of the file, like the flags argument of open(),
+ * except for O_TMPFILE, which is implied, and O_PATH, which is not
+ * allowed.
+ * @mode: Input; The mode of the file, like the mode argument of open().
+ *
+ * Passed via &struct liveupdate_session_retrieve_fd.arg to retrieve a file that
+ * was preserved from a tmpfs mount. Such files can only be retrieved with this
+ * argument, and memfds, i.e. files that were preserved from the kernel's
+ * internal shmem mount, can only be retrieved without it. Otherwise, the
+ * retrieve fails with -EINVAL.
+ *
+ * The kernel creates a new file as if by openat(@dirfd, ".", O_TMPFILE |
+ * @flags, @mode), fills it with the preserved contents, and returns it in
+ * &struct liveupdate_session_retrieve_fd.fd. Like any O_TMPFILE file, the file
+ * is not linked into the filesystem. Userspace can link it with linkat(),
+ * unless @flags contains O_EXCL.
+ *
+ * If @flags contains unknown flags or O_PATH, if @mode contains unknown mode
+ * bits, or if @dirfd is not on a tmpfs mount, the retrieve fails with -EINVAL.
+ * If the file can't be created, the retrieve fails with the same errors as
+ * open(). A retrieve that fails before the preserved contents are restored can
+ * be retried.
+ */
+struct liveupdate_shmem_retrieve_arg {
+ __u32 size;
+ __s32 dirfd;
+ __aligned_u64 flags;
+ __aligned_u64 mode;
+};
+
#endif /* _UAPI_LIVEUPDATE_H */
diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig
index 9a1c49e2e0c4..61d01f5a336e 100644
--- a/kernel/liveupdate/Kconfig
+++ b/kernel/liveupdate/Kconfig
@@ -70,14 +70,14 @@ config LIVEUPDATE
If unsure, say N.
config LIVEUPDATE_SHMEM
- bool "Live update support for memfd"
+ bool "Live update support for memfd and tmpfs files"
depends on LIVEUPDATE
depends on MEMFD_CREATE
depends on SHMEM
default LIVEUPDATE
help
- Enable live update support for memfd regions. This allows preserving
- memfd-backed memory across kernel live updates.
+ Enable live update support for memfds and tmpfs files. This allows
+ preserving their contents across kernel live updates.
This can be used to back VM memory with memfds, allowing the guest
memory to persist, or for other user workloads needing to preserve
diff --git a/mm/internal.h b/mm/internal.h
index 38b1165212c9..630ae0297dd5 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1436,6 +1436,7 @@ int shmem_add_to_page_cache(struct folio *folio,
pgoff_t index, void *expected, gfp_t gfp);
int shmem_inode_acct_blocks(struct inode *inode, long pages);
bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped);
+bool shmem_inode_on_internal_mount(const struct inode *inode);
#ifdef CONFIG_SHRINKER_DEBUG
static inline __printf(2, 0) int shrinker_debugfs_name_alloc(
diff --git a/mm/shmem.c b/mm/shmem.c
index 897fa2b61346..9c67daa35d66 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -468,6 +468,15 @@ bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped)
return first_swapped;
}
+/*
+ * Whether @inode is on the internal shmem mount, which is used by
+ * shmem_file_setup() and thus by memfd_create().
+ */
+bool shmem_inode_on_internal_mount(const struct inode *inode)
+{
+ return inode->i_sb == shm_mnt->mnt_sb;
+}
+
bool shmem_charge(struct inode *inode, long pages)
{
struct address_space *mapping = inode->i_mapping;
diff --git a/mm/shmem_luo.c b/mm/shmem_luo.c
index bcac1bbb3db3..ecbeb37d33a8 100644
--- a/mm/shmem_luo.c
+++ b/mm/shmem_luo.c
@@ -9,19 +9,20 @@
*/
/**
- * DOC: Memfd Preservation via LUO
+ * DOC: Memfd and Tmpfs Preservation via LUO
*
* Overview
* ========
*
- * Memory file descriptors (memfd) can be preserved over a kexec using the Live
- * Update Orchestrator (LUO) file preservation. This allows userspace to
- * transfer its memory contents to the next kernel after a kexec.
+ * Memory file descriptors (memfd) and tmpfs files can be preserved over a kexec
+ * using the Live Update Orchestrator (LUO) file preservation. This allows
+ * userspace to transfer its memory contents to the next kernel after a kexec.
*
* Here, a memfd is a memfd created without ``MFD_HUGETLB``, which is a shmem
- * file on the kernel's internal shmem mount. Memfds created with
- * ``MFD_HUGETLB`` are hugetlbfs files, which this file handler doesn't
- * preserve. Preserving them fails with ``-ENOENT``.
+ * file on the kernel's internal shmem mount, and a tmpfs file is a file on any
+ * other tmpfs mount. Memfds created with ``MFD_HUGETLB`` and other files on
+ * hugetlbfs are not shmem files, and this file handler doesn't preserve them.
+ * Preserving them fails with ``-ENOENT``.
*
* The preservation is not intended to be transparent. Only select properties of
* the file are preserved. All others are reset to default. The preserved
@@ -29,12 +30,13 @@
*
* .. note::
* The LUO API is not stabilized yet, so the preserved properties of a memfd
- * are also not stable and are subject to backwards incompatible changes.
+ * or tmpfs file are also not stable and are subject to backwards
+ * incompatible changes.
*
* Preserved Properties
* ====================
*
- * The following properties of the memfd are preserved across kexec:
+ * The following properties of the file are preserved across kexec:
*
* File Contents
* All data stored in the file is preserved.
@@ -49,10 +51,12 @@
*
* File Status Flags
* memfds are always opened with ``O_RDWR`` and ``O_LARGEFILE``. This property
- * is maintained.
+ * is maintained. The file status flags of tmpfs files are not preserved.
+ * Userspace chooses the flags when retrieving them, as described in
+ * "Retrieving Tmpfs Files" below.
*
* Seals
- * File seals set on the memfd are preserved and re-applied on restore.
+ * The seals of the file are preserved and re-applied on restore.
* Only seals known to this LUO version (see ``SHMEM_LUO_ALL_SEALS``) may
* be present; preservation fails with ``-EOPNOTSUPP`` otherwise.
*
@@ -67,12 +71,50 @@
* A memfd can be created with the ``MFD_CLOEXEC`` flag that sets the
* ``FD_CLOEXEC`` on the file. This flag is not preserved and must be set
* again after restore via ``fcntl()``.
+ *
+ * Inode Attributes
+ * The name, path, owner, mode, timestamps and extended attributes of the
+ * file are not preserved.
+ *
+ * Retrieving Tmpfs Files
+ * ======================
+ *
+ * A tmpfs file can be retrieved onto any tmpfs mount that userspace chooses.
+ * The mount that the file was on doesn't exist in the new kernel, and userspace
+ * may want to put the file elsewhere anyway.
+ *
+ * To retrieve a tmpfs file, userspace passes a
+ * ``struct liveupdate_shmem_retrieve_arg`` to
+ * ``LIVEUPDATE_SESSION_RETRIEVE_FD``. The argument specifies a directory on the
+ * target mount, and the flags and mode of the new file. The kernel creates the
+ * file as if by ``openat(dirfd, ".", O_TMPFILE | flags, mode)``, so the file
+ * gets the same flags, owner, permission checks and security labels as any
+ * other new file in that directory. The kernel then fills the file with the
+ * preserved contents, size, position and seals before it returns the file, so
+ * nothing else can access the file before it is complete.
+ *
+ * Like any ``O_TMPFILE`` file, the new file is not linked into the filesystem.
+ * Userspace can link it at the path it wants with ``linkat()``, unless it asked
+ * for ``O_EXCL``. Like with ``open()``, the file must be opened for writing.
+ * LUO keeps the file open until the session is finished, so a retrieved binary
+ * can't be executed until then.
+ *
+ * The blocks of the file are charged to the target mount, so the size limit
+ * and quotas of the mount apply. If the file doesn't fit, the retrieve fails
+ * permanently, since the preserved contents have already been restored at that
+ * point. If the argument is invalid or the file can't be created, the retrieve
+ * fails before the preserved contents are restored, so it can be retried.
+ *
+ * memfds can only be retrieved as memfds, and files on tmpfs mounts can only be
+ * retrieved onto tmpfs mounts. Retrieving a memfd with the argument, or a tmpfs
+ * file without it, fails with ``-EINVAL``.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bits.h>
#include <linux/err.h>
+#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/io.h>
#include <linux/kexec_handover.h>
@@ -81,6 +123,7 @@
#include <linux/shmem_fs.h>
#include <linux/vmalloc.h>
#include <linux/memfd.h>
+#include <uapi/linux/magic.h>
#include <uapi/linux/memfd.h>
#include "internal.h"
@@ -299,6 +342,8 @@ static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
ser->size = inode_size;
ser->seals = seals;
+ if (!shmem_inode_on_internal_mount(inode))
+ ser->flags |= SHMEM_LUO_FLAG_TMPFS;
err = shmem_luo_preserve_folios(args->file, &ser->folios,
&folios_ser, &nr_folios);
@@ -515,6 +560,92 @@ static int shmem_luo_retrieve_folios(struct file *file,
return err;
}
+/* Create the memfd to retrieve a file from the internal shmem mount into. */
+static struct file *shmem_luo_create_memfd(const struct liveupdate_shmem_retrieve_arg *arg,
+ unsigned int seals)
+{
+ struct file *file;
+ int err;
+
+ /* memfds are retrieved as memfds, so there is nothing to choose. */
+ if (arg)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * The seals are preserved. Allow sealing here so they can be added
+ * later.
+ */
+ file = memfd_alloc_file("", MFD_ALLOW_SEALING);
+ if (IS_ERR(file)) {
+ pr_err("failed to setup file: %pe\n", file);
+ return file;
+ }
+
+ err = memfd_add_seals(file, seals);
+ if (err) {
+ pr_err("failed to add seals: %pe\n", ERR_PTR(err));
+ fput(file);
+ return ERR_PTR(err);
+ }
+
+ return file;
+}
+
+/*
+ * Create the file to retrieve a file from a tmpfs mount into, on the tmpfs
+ * mount chosen by userspace.
+ */
+static struct file *shmem_luo_create_tmpfs_file(const struct liveupdate_shmem_retrieve_arg *arg,
+ unsigned int seals)
+{
+ struct file *file;
+ int err;
+
+ if (!arg)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Like openat2(), reject unknown flags and mode bits instead of
+ * ignoring them. Also reject O_PATH, which would make file_open_root()
+ * ignore O_TMPFILE and open the directory instead of creating a file.
+ */
+ if (arg->flags & ~(u64)VALID_OPEN_FLAGS || arg->flags & O_PATH ||
+ arg->mode & ~(u64)S_IALLUGO)
+ return ERR_PTR(-EINVAL);
+
+ CLASS(fd_raw, dir)(arg->dirfd);
+ if (fd_empty(dir))
+ return ERR_PTR(-EBADF);
+
+ if (fd_file(dir)->f_path.dentry->d_sb->s_magic != TMPFS_MAGIC)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Create the file like open(O_TMPFILE) does, so that it gets the same
+ * flag checks, permission checks, owner and security labels.
+ */
+ file = file_open_root(&fd_file(dir)->f_path, ".",
+ O_TMPFILE | O_LARGEFILE | arg->flags, arg->mode);
+ if (IS_ERR(file))
+ return file;
+
+ /*
+ * Nothing else can access the new file yet, so set the preserved seals
+ * directly. memfd_add_seals() refuses to, since files on tmpfs mounts
+ * are created with F_SEAL_SEAL.
+ */
+ if (seals & F_SEAL_WRITE) {
+ err = mapping_deny_writable(file->f_mapping);
+ if (err) {
+ fput(file);
+ return ERR_PTR(err);
+ }
+ }
+ SHMEM_I(file_inode(file))->seals = seals;
+
+ return file;
+}
+
static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
{
struct shmem_luo_folio_ser *folios_ser;
@@ -533,25 +664,18 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
*/
args->retryable = true;
- /* Make sure the file only has seals supported by this version. */
- if (ser->seals & ~SHMEM_LUO_ALL_SEALS)
+ /* Make sure the file only has seals and flags this version supports. */
+ if ((ser->seals & ~SHMEM_LUO_ALL_SEALS) ||
+ (ser->flags & ~SHMEM_LUO_ALL_FLAGS))
return -EOPNOTSUPP;
- /*
- * The seals are preserved. Allow sealing here so they can be added
- * later.
- */
- file = memfd_alloc_file("", MFD_ALLOW_SEALING);
- if (IS_ERR(file)) {
- pr_err("failed to setup file: %pe\n", file);
+ /* Retrieve memfds as memfds, and other files onto a tmpfs mount. */
+ if (ser->flags & SHMEM_LUO_FLAG_TMPFS)
+ file = shmem_luo_create_tmpfs_file(args->arg, ser->seals);
+ else
+ file = shmem_luo_create_memfd(args->arg, ser->seals);
+ if (IS_ERR(file))
return PTR_ERR(file);
- }
-
- err = memfd_add_seals(file, ser->seals);
- if (err) {
- pr_err("failed to add seals: %pe\n", ERR_PTR(err));
- goto put_file;
- }
vfs_setpos(file, ser->pos, MAX_LFS_FILESIZE);
i_size_write(file_inode(file), ser->size);
@@ -579,7 +703,6 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
free_ser:
kho_restore_free(ser);
-put_file:
fput(file);
return err;
}
@@ -605,6 +728,7 @@ static const struct liveupdate_file_ops shmem_luo_file_ops = {
.unpreserve = shmem_luo_unpreserve,
.can_preserve = shmem_luo_can_preserve,
.get_id = shmem_luo_get_id,
+ .rarg = LIVEUPDATE_ARG(struct liveupdate_shmem_retrieve_arg, mode),
.owner = THIS_MODULE,
};
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace
2026-11-03 1:02 ` [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace David Matlack
@ 2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:27 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 0:43 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Retrieve files that were preserved from a tmpfs mount onto a tmpfs mount
> chosen by userspace, instead of as memfds on the internal tmpfs mount.
> Add struct liveupdate_shmem_retrieve_arg, which userspace passes as the
> retrieve argument of LIVEUPDATE_SESSION_RETRIEVE_FD to choose the mount.
> Record which mount a file was on with a new SHMEM_LUO_FLAG_TMPFS flag in
> struct shmem_luo_ser, based on the superblock of the file.
>
> shmem_luo already accepts unlinked tmpfs files, such as files created
> with O_TMPFILE, and a following commit also accepts linked ones. The
> mount such a file was on doesn't exist in the new kernel, and userspace
> may want to put the file elsewhere anyway.
>
> Model struct liveupdate_shmem_retrieve_arg on open(): The kernel creates
> a new file as if by openat(dirfd, ".", O_TMPFILE | flags, mode), so the
> file gets the owner, permission checks and security labels of any new
> file in that directory, and is charged to that mount. The kernel then
> fills the file with the preserved contents, size, position and seals
> before returning it, so nothing else can access the file before it is
> complete. Userspace links the file at the path it wants with linkat(),
> or passes O_EXCL to keep it unlinked. Neither the path nor any other
> inode attribute of the file is part of the preserved state, which keeps
> them out of the KHO ABI.
>
> Pass the flags from userspace to file_open_root(), so that the VFS
> checks them like for open(). file_open_root() silently ignores unknown
> flags and mode bits, so reject those like openat2() does. Also reject
> O_PATH, with which file_open_root() would ignore O_TMPFILE and open the
> directory.
>
> Keep the type of the file: memfds can only be retrieved as memfds, and
> files on tmpfs mounts only onto tmpfs mounts, so that e.g. a file
> can't be moved off the mount whose size limit and quotas it was subject
> to. Passing the argument when retrieving a memfd, or not passing it when
> retrieving a file from a tmpfs mount, fails with -EINVAL. Unlinked tmpfs
> files were retrieved as memfds until now, but nothing relies on that, as
> the LUO uAPI is not stable yet.
>
> Like the other failures before the folios are restored, problems with
> the argument and with creating the file can be retried.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> Link: https://patch.msgid.link/20261103010216.3447716-8-dmatlack@google.com
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
--
Pasha
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace
2026-11-03 1:02 ` [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace David Matlack
2026-11-04 0:43 ` Pasha Tatashin
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:27 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Retrieve files that were preserved from a tmpfs mount onto a tmpfs mount
> chosen by userspace, instead of as memfds on the internal tmpfs mount.
> Add struct liveupdate_shmem_retrieve_arg, which userspace passes as the
> retrieve argument of LIVEUPDATE_SESSION_RETRIEVE_FD to choose the mount.
> Record which mount a file was on with a new SHMEM_LUO_FLAG_TMPFS flag in
> struct shmem_luo_ser, based on the superblock of the file.
>
> shmem_luo already accepts unlinked tmpfs files, such as files created
> with O_TMPFILE, and a following commit also accepts linked ones. The
> mount such a file was on doesn't exist in the new kernel, and userspace
> may want to put the file elsewhere anyway.
>
> Model struct liveupdate_shmem_retrieve_arg on open(): The kernel creates
> a new file as if by openat(dirfd, ".", O_TMPFILE | flags, mode), so the
> file gets the owner, permission checks and security labels of any new
> [ ... ]
>
> Like the other failures before the folios are restored, problems with
> the argument and with creating the file can be retried.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=7
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace
2026-11-03 1:02 ` [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace David Matlack
2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 16:27 ` Pratyush Yadav
2026-11-04 22:30 ` David Matlack
2 siblings, 1 reply; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 16:27 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
Hi David,
On Tue, Nov 03 2026, David Matlack wrote:
> Retrieve files that were preserved from a tmpfs mount onto a tmpfs mount
> chosen by userspace, instead of as memfds on the internal tmpfs mount.
> Add struct liveupdate_shmem_retrieve_arg, which userspace passes as the
> retrieve argument of LIVEUPDATE_SESSION_RETRIEVE_FD to choose the mount.
> Record which mount a file was on with a new SHMEM_LUO_FLAG_TMPFS flag in
> struct shmem_luo_ser, based on the superblock of the file.
>
> shmem_luo already accepts unlinked tmpfs files, such as files created
> with O_TMPFILE, and a following commit also accepts linked ones. The
Nit: that's a bug, not a supported feature (well, before this patch at
least).
> mount such a file was on doesn't exist in the new kernel, and userspace
> may want to put the file elsewhere anyway.
>
> Model struct liveupdate_shmem_retrieve_arg on open(): The kernel creates
> a new file as if by openat(dirfd, ".", O_TMPFILE | flags, mode), so the
> file gets the owner, permission checks and security labels of any new
> file in that directory, and is charged to that mount. The kernel then
> fills the file with the preserved contents, size, position and seals
> before returning it, so nothing else can access the file before it is
> complete. Userspace links the file at the path it wants with linkat(),
> or passes O_EXCL to keep it unlinked. Neither the path nor any other
> inode attribute of the file is part of the preserved state, which keeps
> them out of the KHO ABI.
>
> Pass the flags from userspace to file_open_root(), so that the VFS
> checks them like for open(). file_open_root() silently ignores unknown
> flags and mode bits, so reject those like openat2() does. Also reject
> O_PATH, with which file_open_root() would ignore O_TMPFILE and open the
> directory.
>
> Keep the type of the file: memfds can only be retrieved as memfds, and
> files on tmpfs mounts only onto tmpfs mounts, so that e.g. a file
> can't be moved off the mount whose size limit and quotas it was subject
Nit: that's not true. It only can't be moved to the internal mount. All
other tmpfs mounts are fair game. You can take 5 files from a single
mount on preserve, and put them on 5 different mounts on retrieve.
Nothing wrong with that, just that this claim isn't exactly accurate.
> to. Passing the argument when retrieving a memfd, or not passing it when
> retrieving a file from a tmpfs mount, fails with -EINVAL. Unlinked tmpfs
> files were retrieved as memfds until now, but nothing relies on that, as
> the LUO uAPI is not stable yet.
LUO uAPI _is_ stable. We have to keep backwards compatibility. It is
only the preservation ABI that is not stable.
And as I said above, that was a bug and not a supported feature. This
patch happens to fix that bug, and hopefully no user was relying on it.
If a user is relying on it, we'd either have to ask them to move to the
new uAPI or reinstate the old bug (as long as the end result is
reasonable and secure). That's the promise we have to keep with uAPI.
>
> Like the other failures before the folios are restored, problems with
> the argument and with creating the file can be retried.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> Documentation/mm/shmem_preservation.rst | 8 +-
> include/linux/kho/abi/shmem.h | 21 ++-
> include/uapi/linux/liveupdate.h | 35 +++++
> kernel/liveupdate/Kconfig | 6 +-
> mm/internal.h | 1 +
> mm/shmem.c | 9 ++
> mm/shmem_luo.c | 180 ++++++++++++++++++++----
> 7 files changed, 221 insertions(+), 39 deletions(-)
>
> diff --git a/Documentation/mm/shmem_preservation.rst b/Documentation/mm/shmem_preservation.rst
> index e79bf8afaa9e..030a8f18680c 100644
> --- a/Documentation/mm/shmem_preservation.rst
> +++ b/Documentation/mm/shmem_preservation.rst
> @@ -1,11 +1,11 @@
> .. SPDX-License-Identifier: GPL-2.0-or-later
>
> -==========================
> -Memfd Preservation via LUO
> -==========================
> +====================================
> +Memfd and Tmpfs Preservation via LUO
> +====================================
>
> .. kernel-doc:: mm/shmem_luo.c
> - :doc: Memfd Preservation via LUO
> + :doc: Memfd and Tmpfs Preservation via LUO
>
> Memfd Preservation ABI
> ======================
> diff --git a/include/linux/kho/abi/shmem.h b/include/linux/kho/abi/shmem.h
> index b61687e358a2..88ef7d49b5f3 100644
> --- a/include/linux/kho/abi/shmem.h
> +++ b/include/linux/kho/abi/shmem.h
> @@ -18,8 +18,8 @@
> * DOC: shmem Live Update ABI
> *
> * The shmem file handler, which preserves memfds created without
> - * ``MFD_HUGETLB``, uses the ABI defined below for preserving their state across
> - * a kexec reboot using the LUO.
> + * ``MFD_HUGETLB`` and tmpfs files, uses the ABI defined below for preserving
> + * their state across a kexec reboot using the LUO.
> *
> * The state is serialized into a packed structure `struct shmem_luo_ser`
> * which is handed over to the next kernel via the KHO mechanism.
> @@ -69,12 +69,25 @@ struct shmem_luo_folio_ser {
> F_SEAL_EXEC)
>
> /**
> - * struct shmem_luo_ser - Main serialization structure for a memfd.
> + * SHMEM_LUO_FLAG_TMPFS - The file was on a tmpfs mount.
> + *
> + * Set for files that were not on the internal shmem mount that memfds are
> + * created on. Such a file is retrieved onto a tmpfs mount chosen by userspace,
> + * instead of as a memfd.
> + */
Nit: perhaps the below is slightly better?
Set for files on a user-visible tmpfs mount. Such files can only be
retrieved into a tmpfs mount, and never as a memfd.
> +#define SHMEM_LUO_FLAG_TMPFS BIT(0)
> +
> +/* The set of flags this version supports. */
> +#define SHMEM_LUO_ALL_FLAGS SHMEM_LUO_FLAG_TMPFS
> +
> +/**
> + * struct shmem_luo_ser - Main serialization structure for a memfd or tmpfs file.
> * @pos: The file's current position (f_pos).
> * @size: The total size of the file in bytes (i_size).
> * @seals: The seals present on the memfd. The seals are uABI so it is safe
> * to directly use them in the ABI.
> - * @flags: Flags for the file. Unused flag bits must be set to 0.
> + * @flags: Flags for the file (SHMEM_LUO_FLAG_*). Unused flag bits must be
> + * set to 0.
> * @nr_folios: Number of folios in the folios array.
> * @folios: KHO vmalloc descriptor pointing to the array of
> * struct shmem_luo_folio_ser.
> diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
> index 953ffe0823be..a9dcc4fcc87b 100644
> --- a/include/uapi/linux/liveupdate.h
> +++ b/include/uapi/linux/liveupdate.h
> @@ -247,4 +247,39 @@ struct liveupdate_session_get_name {
> #define LIVEUPDATE_SESSION_GET_NAME \
> _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_GET_NAME)
>
> +/**
> + * struct liveupdate_shmem_retrieve_arg - Argument to retrieve a tmpfs file
> + * @size: Input; sizeof(struct liveupdate_shmem_retrieve_arg)
> + * @dirfd: Input; A file descriptor for a directory on the tmpfs mount to create
> + * the file on.
> + * @flags: Input; The flags of the file, like the flags argument of open(),
> + * except for O_TMPFILE, which is implied, and O_PATH, which is not
> + * allowed.
> + * @mode: Input; The mode of the file, like the mode argument of open().
> + *
> + * Passed via &struct liveupdate_session_retrieve_fd.arg to retrieve a file that
> + * was preserved from a tmpfs mount. Such files can only be retrieved with this
> + * argument, and memfds, i.e. files that were preserved from the kernel's
> + * internal shmem mount, can only be retrieved without it. Otherwise, the
Nit: "internal shmem mount" is a kernel internal detail, no point of it
in user facing documentation.
> + * retrieve fails with -EINVAL.
> + *
> + * The kernel creates a new file as if by openat(@dirfd, ".", O_TMPFILE |
> + * @flags, @mode), fills it with the preserved contents, and returns it in
> + * &struct liveupdate_session_retrieve_fd.fd. Like any O_TMPFILE file, the file
> + * is not linked into the filesystem. Userspace can link it with linkat(),
> + * unless @flags contains O_EXCL.
> + *
> + * If @flags contains unknown flags or O_PATH, if @mode contains unknown mode
> + * bits, or if @dirfd is not on a tmpfs mount, the retrieve fails with -EINVAL.
> + * If the file can't be created, the retrieve fails with the same errors as
> + * open(). A retrieve that fails before the preserved contents are restored can
> + * be retried.
How is userspace supposed to tell if preserved contents were restored?
> + */
> +struct liveupdate_shmem_retrieve_arg {
> + __u32 size;
> + __s32 dirfd;
> + __aligned_u64 flags;
> + __aligned_u64 mode;
> +};
> +
> #endif /* _UAPI_LIVEUPDATE_H */
> diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig
> index 9a1c49e2e0c4..61d01f5a336e 100644
> --- a/kernel/liveupdate/Kconfig
> +++ b/kernel/liveupdate/Kconfig
> @@ -70,14 +70,14 @@ config LIVEUPDATE
> If unsure, say N.
>
> config LIVEUPDATE_SHMEM
> - bool "Live update support for memfd"
> + bool "Live update support for memfd and tmpfs files"
> depends on LIVEUPDATE
> depends on MEMFD_CREATE
> depends on SHMEM
> default LIVEUPDATE
> help
> - Enable live update support for memfd regions. This allows preserving
> - memfd-backed memory across kernel live updates.
> + Enable live update support for memfds and tmpfs files. This allows
> + preserving their contents across kernel live updates.
>
> This can be used to back VM memory with memfds, allowing the guest
> memory to persist, or for other user workloads needing to preserve
> diff --git a/mm/internal.h b/mm/internal.h
> index 38b1165212c9..630ae0297dd5 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -1436,6 +1436,7 @@ int shmem_add_to_page_cache(struct folio *folio,
> pgoff_t index, void *expected, gfp_t gfp);
> int shmem_inode_acct_blocks(struct inode *inode, long pages);
> bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped);
> +bool shmem_inode_on_internal_mount(const struct inode *inode);
>
> #ifdef CONFIG_SHRINKER_DEBUG
> static inline __printf(2, 0) int shrinker_debugfs_name_alloc(
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 897fa2b61346..9c67daa35d66 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -468,6 +468,15 @@ bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped)
> return first_swapped;
> }
>
> +/*
> + * Whether @inode is on the internal shmem mount, which is used by
> + * shmem_file_setup() and thus by memfd_create().
> + */
> +bool shmem_inode_on_internal_mount(const struct inode *inode)
> +{
> + return inode->i_sb == shm_mnt->mnt_sb;
> +}
> +
> bool shmem_charge(struct inode *inode, long pages)
> {
> struct address_space *mapping = inode->i_mapping;
> diff --git a/mm/shmem_luo.c b/mm/shmem_luo.c
> index bcac1bbb3db3..ecbeb37d33a8 100644
> --- a/mm/shmem_luo.c
> +++ b/mm/shmem_luo.c
> @@ -9,19 +9,20 @@
> */
>
> /**
> - * DOC: Memfd Preservation via LUO
> + * DOC: Memfd and Tmpfs Preservation via LUO
> *
> * Overview
> * ========
> *
> - * Memory file descriptors (memfd) can be preserved over a kexec using the Live
> - * Update Orchestrator (LUO) file preservation. This allows userspace to
> - * transfer its memory contents to the next kernel after a kexec.
> + * Memory file descriptors (memfd) and tmpfs files can be preserved over a kexec
> + * using the Live Update Orchestrator (LUO) file preservation. This allows
> + * userspace to transfer its memory contents to the next kernel after a kexec.
> *
> * Here, a memfd is a memfd created without ``MFD_HUGETLB``, which is a shmem
> - * file on the kernel's internal shmem mount. Memfds created with
> - * ``MFD_HUGETLB`` are hugetlbfs files, which this file handler doesn't
> - * preserve. Preserving them fails with ``-ENOENT``.
> + * file on the kernel's internal shmem mount, and a tmpfs file is a file on any
> + * other tmpfs mount. Memfds created with ``MFD_HUGETLB`` and other files on
> + * hugetlbfs are not shmem files, and this file handler doesn't preserve them.
> + * Preserving them fails with ``-ENOENT``.
> *
> * The preservation is not intended to be transparent. Only select properties of
> * the file are preserved. All others are reset to default. The preserved
> @@ -29,12 +30,13 @@
> *
> * .. note::
> * The LUO API is not stabilized yet, so the preserved properties of a memfd
> - * are also not stable and are subject to backwards incompatible changes.
> + * or tmpfs file are also not stable and are subject to backwards
> + * incompatible changes.
> *
> * Preserved Properties
> * ====================
> *
> - * The following properties of the memfd are preserved across kexec:
> + * The following properties of the file are preserved across kexec:
> *
> * File Contents
> * All data stored in the file is preserved.
> @@ -49,10 +51,12 @@
> *
> * File Status Flags
> * memfds are always opened with ``O_RDWR`` and ``O_LARGEFILE``. This property
> - * is maintained.
> + * is maintained. The file status flags of tmpfs files are not preserved.
> + * Userspace chooses the flags when retrieving them, as described in
> + * "Retrieving Tmpfs Files" below.
> *
> * Seals
> - * File seals set on the memfd are preserved and re-applied on restore.
> + * The seals of the file are preserved and re-applied on restore.
> * Only seals known to this LUO version (see ``SHMEM_LUO_ALL_SEALS``) may
> * be present; preservation fails with ``-EOPNOTSUPP`` otherwise.
> *
> @@ -67,12 +71,50 @@
> * A memfd can be created with the ``MFD_CLOEXEC`` flag that sets the
> * ``FD_CLOEXEC`` on the file. This flag is not preserved and must be set
> * again after restore via ``fcntl()``.
> + *
> + * Inode Attributes
> + * The name, path, owner, mode, timestamps and extended attributes of the
> + * file are not preserved.
> + *
> + * Retrieving Tmpfs Files
> + * ======================
> + *
> + * A tmpfs file can be retrieved onto any tmpfs mount that userspace chooses.
> + * The mount that the file was on doesn't exist in the new kernel, and userspace
> + * may want to put the file elsewhere anyway.
> + *
> + * To retrieve a tmpfs file, userspace passes a
> + * ``struct liveupdate_shmem_retrieve_arg`` to
> + * ``LIVEUPDATE_SESSION_RETRIEVE_FD``. The argument specifies a directory on the
> + * target mount, and the flags and mode of the new file. The kernel creates the
> + * file as if by ``openat(dirfd, ".", O_TMPFILE | flags, mode)``, so the file
> + * gets the same flags, owner, permission checks and security labels as any
> + * other new file in that directory. The kernel then fills the file with the
> + * preserved contents, size, position and seals before it returns the file, so
> + * nothing else can access the file before it is complete.
> + *
> + * Like any ``O_TMPFILE`` file, the new file is not linked into the filesystem.
> + * Userspace can link it at the path it wants with ``linkat()``, unless it asked
> + * for ``O_EXCL``. Like with ``open()``, the file must be opened for writing.
> + * LUO keeps the file open until the session is finished, so a retrieved binary
> + * can't be executed until then.
Nit: this information seems to be repeated in the uAPI documentation.
Perhaps keep it only there and refer to it from here?
> + *
> + * The blocks of the file are charged to the target mount, so the size limit
> + * and quotas of the mount apply. If the file doesn't fit, the retrieve fails
> + * permanently, since the preserved contents have already been restored at that
> + * point. If the argument is invalid or the file can't be created, the retrieve
> + * fails before the preserved contents are restored, so it can be retried.
> + *
> + * memfds can only be retrieved as memfds, and files on tmpfs mounts can only be
> + * retrieved onto tmpfs mounts. Retrieving a memfd with the argument, or a tmpfs
> + * file without it, fails with ``-EINVAL``.
> */
>
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
> #include <linux/bits.h>
> #include <linux/err.h>
> +#include <linux/fcntl.h>
> #include <linux/file.h>
> #include <linux/io.h>
> #include <linux/kexec_handover.h>
> @@ -81,6 +123,7 @@
> #include <linux/shmem_fs.h>
> #include <linux/vmalloc.h>
> #include <linux/memfd.h>
> +#include <uapi/linux/magic.h>
> #include <uapi/linux/memfd.h>
>
> #include "internal.h"
> @@ -299,6 +342,8 @@ static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
>
> ser->size = inode_size;
> ser->seals = seals;
> + if (!shmem_inode_on_internal_mount(inode))
> + ser->flags |= SHMEM_LUO_FLAG_TMPFS;
>
> err = shmem_luo_preserve_folios(args->file, &ser->folios,
> &folios_ser, &nr_folios);
> @@ -515,6 +560,92 @@ static int shmem_luo_retrieve_folios(struct file *file,
> return err;
> }
>
> +/* Create the memfd to retrieve a file from the internal shmem mount into. */
> +static struct file *shmem_luo_create_memfd(const struct liveupdate_shmem_retrieve_arg *arg,
> + unsigned int seals)
> +{
> + struct file *file;
> + int err;
> +
> + /* memfds are retrieved as memfds, so there is nothing to choose. */
Nit: I can't make any sense of this comment. "memfds are retrieved as
memfds": well I'd hope so. "there is nothing to choose": ... what are we
choosing?
Perhaps something simpler like "no arguments needed with memfds".
Something along these lines.
> + if (arg)
> + return ERR_PTR(-EINVAL);
> +
> + /*
> + * The seals are preserved. Allow sealing here so they can be added
> + * later.
> + */
> + file = memfd_alloc_file("", MFD_ALLOW_SEALING);
> + if (IS_ERR(file)) {
> + pr_err("failed to setup file: %pe\n", file);
> + return file;
> + }
> +
> + err = memfd_add_seals(file, seals);
> + if (err) {
> + pr_err("failed to add seals: %pe\n", ERR_PTR(err));
> + fput(file);
> + return ERR_PTR(err);
> + }
> +
> + return file;
> +}
> +
> +/*
> + * Create the file to retrieve a file from a tmpfs mount into, on the tmpfs
> + * mount chosen by userspace.
> + */
> +static struct file *shmem_luo_create_tmpfs_file(const struct liveupdate_shmem_retrieve_arg *arg,
> + unsigned int seals)
> +{
> + struct file *file;
> + int err;
> +
> + if (!arg)
> + return ERR_PTR(-EINVAL);
> +
> + /*
> + * Like openat2(), reject unknown flags and mode bits instead of
> + * ignoring them. Also reject O_PATH, which would make file_open_root()
> + * ignore O_TMPFILE and open the directory instead of creating a file.
> + */
> + if (arg->flags & ~(u64)VALID_OPEN_FLAGS || arg->flags & O_PATH ||
> + arg->mode & ~(u64)S_IALLUGO)
> + return ERR_PTR(-EINVAL);
> +
> + CLASS(fd_raw, dir)(arg->dirfd);
> + if (fd_empty(dir))
> + return ERR_PTR(-EBADF);
> +
> + if (fd_file(dir)->f_path.dentry->d_sb->s_magic != TMPFS_MAGIC)
> + return ERR_PTR(-EINVAL);
> +
> + /*
> + * Create the file like open(O_TMPFILE) does, so that it gets the same
> + * flag checks, permission checks, owner and security labels.
> + */
> + file = file_open_root(&fd_file(dir)->f_path, ".",
> + O_TMPFILE | O_LARGEFILE | arg->flags, arg->mode);
> + if (IS_ERR(file))
> + return file;
> +
> + /*
> + * Nothing else can access the new file yet, so set the preserved seals
> + * directly. memfd_add_seals() refuses to, since files on tmpfs mounts
> + * are created with F_SEAL_SEAL.
> + */
> + if (seals & F_SEAL_WRITE) {
> + err = mapping_deny_writable(file->f_mapping);
> + if (err) {
> + fput(file);
> + return ERR_PTR(err);
> + }
> + }
> + SHMEM_I(file_inode(file))->seals = seals;
No, no, no. If a tmpfs payload has seals other than F_SEAL_SEAL, it is
_invalid_ and must be rejected. Let's not do things on retrieve that
can't be done on a normal file.
> +
> + return file;
> +}
> +
> static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
> {
> struct shmem_luo_folio_ser *folios_ser;
> @@ -533,25 +664,18 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
> */
> args->retryable = true;
>
> - /* Make sure the file only has seals supported by this version. */
> - if (ser->seals & ~SHMEM_LUO_ALL_SEALS)
> + /* Make sure the file only has seals and flags this version supports. */
> + if ((ser->seals & ~SHMEM_LUO_ALL_SEALS) ||
> + (ser->flags & ~SHMEM_LUO_ALL_FLAGS))
As I said above, the set of valid seals depends on memfd or tmpfs, so it
should be checked in their respective functions.
This also isn't backwards compatible, but we haven't solved that problem
yet so it's fine for now.
> return -EOPNOTSUPP;
>
> - /*
> - * The seals are preserved. Allow sealing here so they can be added
> - * later.
> - */
> - file = memfd_alloc_file("", MFD_ALLOW_SEALING);
> - if (IS_ERR(file)) {
> - pr_err("failed to setup file: %pe\n", file);
> + /* Retrieve memfds as memfds, and other files onto a tmpfs mount. */
Nit: this comment doesn't add any value.
> + if (ser->flags & SHMEM_LUO_FLAG_TMPFS)
> + file = shmem_luo_create_tmpfs_file(args->arg, ser->seals);
> + else
> + file = shmem_luo_create_memfd(args->arg, ser->seals);
> + if (IS_ERR(file))
> return PTR_ERR(file);
> - }
> -
> - err = memfd_add_seals(file, ser->seals);
> - if (err) {
> - pr_err("failed to add seals: %pe\n", ERR_PTR(err));
> - goto put_file;
> - }
>
> vfs_setpos(file, ser->pos, MAX_LFS_FILESIZE);
> i_size_write(file_inode(file), ser->size);
> @@ -579,7 +703,6 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
>
> free_ser:
> kho_restore_free(ser);
> -put_file:
> fput(file);
> return err;
> }
> @@ -605,6 +728,7 @@ static const struct liveupdate_file_ops shmem_luo_file_ops = {
> .unpreserve = shmem_luo_unpreserve,
> .can_preserve = shmem_luo_can_preserve,
> .get_id = shmem_luo_get_id,
> + .rarg = LIVEUPDATE_ARG(struct liveupdate_shmem_retrieve_arg, mode),
> .owner = THIS_MODULE,
> };
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace
2026-11-04 16:27 ` Pratyush Yadav
@ 2026-11-04 22:30 ` David Matlack
0 siblings, 0 replies; 42+ messages in thread
From: David Matlack @ 2026-11-04 22:30 UTC (permalink / raw)
To: Pratyush Yadav
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Randy Dunlap, Samiullah Khawaja, Shuah Khan, Suren Baghdasaryan,
Vlastimil Babka
On 2026-11-04 05:27 PM, Pratyush Yadav wrote:
> > + * If @flags contains unknown flags or O_PATH, if @mode contains unknown mode
> > + * bits, or if @dirfd is not on a tmpfs mount, the retrieve fails with -EINVAL.
> > + * If the file can't be created, the retrieve fails with the same errors as
> > + * open(). A retrieve that fails before the preserved contents are restored can
> > + * be retried.
>
> How is userspace supposed to tell if preserved contents were restored?
Through the error code, like Pasha said on patch 3. I'll reword this in
v4 in terms of errors instead of kernel internals: errors from checking
the argument and creating the file, e.g. -EINVAL, -EBADF and the errors
that open() returns, can be retried after fixing the argument. Errors
while restoring the contents, e.g. -ENOMEM, or -ENOSPC when the contents
don't fit on the mount, are permanent, and retrieving the token again
returns the same error.
Thanks for the review. I'll address the rest in v4.
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
` (6 preceding siblings ...)
2026-11-03 1:02 ` [PATCH v3 07/10] mm/shmem_luo: Retrieve tmpfs files onto a tmpfs mount chosen by userspace David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 0:43 ` Pasha Tatashin
` (2 more replies)
2026-11-03 1:02 ` [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY David Matlack
[not found] ` <20261103010216.3447716-11-dmatlack@google.com>
9 siblings, 3 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
Allow preserving tmpfs files that are still linked. To preserve any
file, require permission to write to it and the file to be opened for
reading, and reject append-only files.
shmem_luo already accepts any shmem file without links, which includes
unlinked tmpfs files and files created with O_TMPFILE. Accepting linked
files means that userspace doesn't have to unlink files to preserve them
and can keep using them by path until the live update.
The path of the file isn't preserved. Like other files from tmpfs
mounts, a linked file is retrieved onto a tmpfs mount chosen by
userspace, which can then link it at the path it wants.
While a file is preserved, its size is frozen, so truncating it,
fallocate() and writes past its end fail with -EPERM. For a linked file,
this affects everyone who opens the file by its path, so a caller that
can only read the file, e.g. a world-readable file in /dev/shm, could
use it to break the owner of the file. So require permission to write to
the file to preserve it, for all files. Like FS_IOC_ENABLE_VERITY, don't
require a file opened for writing, so that binaries that are being
executed can still be preserved through read-only fds. Also don't
require a writable mount, since preserving a file doesn't write to the
filesystem. If the size of the file can't change anyway, because it is
immutable or on a read-only superblock, also let its owner preserve it.
Don't let others do that, since the size could change again once the
file is made writable. Like FS_IOC_ENABLE_VERITY, reject append-only
files, since their writers can only append to them, and freezing their
size would stop all appends.
Also like FS_IOC_ENABLE_VERITY, require the file to be opened for
reading. The retrieved file can be read, so otherwise a caller that can
only write to a file could preserve it to read its contents.
Preserving a file also fills its holes, but don't require any permission
for that. Anyone who can read a tmpfs file can already fill its holes by
faulting them in through a read-only mapping, also on read-only mounts
and for immutable files.
Document the frozen size and the permission requirements.
Signed-off-by: David Matlack <dmatlack@google.com>
---
mm/shmem_luo.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 64 insertions(+), 3 deletions(-)
diff --git a/mm/shmem_luo.c b/mm/shmem_luo.c
index ecbeb37d33a8..0c012f242fc5 100644
--- a/mm/shmem_luo.c
+++ b/mm/shmem_luo.c
@@ -28,6 +28,24 @@
* the file are preserved. All others are reset to default. The preserved
* properties are described below.
*
+ * A tmpfs file can be preserved even if it is linked, but its path is not
+ * preserved. Userspace chooses where to put the file when retrieving it, as
+ * described in "Retrieving Tmpfs Files" below.
+ *
+ * Preserving a file requires it to be opened for reading, since the retrieved
+ * file can be read. It also requires permission to write to the file, since
+ * preserving it affects all of its users, as described below. But the file
+ * doesn't need to be opened for writing. For example, a binary that is being
+ * executed can be preserved through a read-only file descriptor. The owner of
+ * a file whose size can't change anyway, because it is immutable or on a
+ * read-only superblock, may also preserve it. The file can be preserved
+ * through a read-only mount. Append-only files can't be preserved.
+ *
+ * While a file is preserved, its size can't change and no holes can be punched
+ * into it. Truncating the file, ``fallocate()`` and writes past the end of the
+ * file fail with ``-EPERM``. This applies to all users of the file, including
+ * users that open it by its path.
+ *
* .. note::
* The LUO API is not stabilized yet, so the preserved properties of a memfd
* or tmpfs file are also not stable and are subject to backwards
@@ -298,6 +316,45 @@ static void shmem_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
vfree(folios_ser);
}
+/*
+ * Check whether the caller may preserve @file. The retrieved file can be read,
+ * so require @file to be opened for reading, like FS_IOC_ENABLE_VERITY does.
+ *
+ * Preserving the file freezes its size until it is unpreserved, for all users
+ * of the file, so require permission to write to the file. Like
+ * FS_IOC_ENABLE_VERITY, don't require a file opened for writing, so that e.g.
+ * a binary that is being executed can be preserved. Also don't require a
+ * writable mount, since preserving the file doesn't write to the filesystem.
+ * If the size of the file can't change anyway, because it is on a read-only
+ * superblock or immutable, its owner may also preserve it. The size could only
+ * change again after the file is made writable, which is up to the owner or
+ * root. Reject append-only files: Their writers can only append to them, and
+ * freezing the size would stop all appends.
+ *
+ * Preserving the file also fills its holes, but that doesn't need any more
+ * permission: Anyone who can read the file can fill its holes by faulting
+ * them in through a read-only mapping.
+ */
+static int shmem_luo_may_preserve(struct file *file)
+{
+ struct mnt_idmap *idmap = file_mnt_idmap(file);
+ struct inode *inode = file_inode(file);
+ int err;
+
+ if (!(file->f_mode & FMODE_READ))
+ return -EBADF;
+
+ if (IS_APPEND(inode))
+ return -EPERM;
+
+ err = inode_permission(idmap, inode, MAY_WRITE);
+ if (err && (sb_rdonly(inode->i_sb) || IS_IMMUTABLE(inode)) &&
+ inode_owner_or_capable(idmap, inode))
+ return 0;
+
+ return err;
+}
+
static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
{
struct inode *inode = file_inode(args->file);
@@ -307,6 +364,11 @@ static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
int err = 0, seals;
inode_lock(inode);
+
+ err = shmem_luo_may_preserve(args->file);
+ if (err)
+ goto err_unlock_inode;
+
shmem_freeze(inode, true);
/* Allocate the main serialization structure in preserved memory */
@@ -362,6 +424,7 @@ static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
kho_unpreserve_free(ser);
err_unlock:
shmem_freeze(inode, false);
+err_unlock_inode:
inode_unlock(inode);
return err;
}
@@ -710,9 +773,7 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
static bool shmem_luo_can_preserve(struct liveupdate_file_handler *handler,
struct file *file)
{
- struct inode *inode = file_inode(file);
-
- return shmem_file(file) && !inode->i_nlink;
+ return shmem_file(file);
}
static unsigned long shmem_luo_get_id(struct file *file)
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked
2026-11-03 1:02 ` [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked David Matlack
@ 2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:45 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 0:43 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Allow preserving tmpfs files that are still linked. To preserve any
> file, require permission to write to it and the file to be opened for
> reading, and reject append-only files.
>
> shmem_luo already accepts any shmem file without links, which includes
> unlinked tmpfs files and files created with O_TMPFILE. Accepting linked
> files means that userspace doesn't have to unlink files to preserve them
> and can keep using them by path until the live update.
>
> The path of the file isn't preserved. Like other files from tmpfs
> mounts, a linked file is retrieved onto a tmpfs mount chosen by
> userspace, which can then link it at the path it wants.
>
> While a file is preserved, its size is frozen, so truncating it,
> fallocate() and writes past its end fail with -EPERM. For a linked file,
> this affects everyone who opens the file by its path, so a caller that
> can only read the file, e.g. a world-readable file in /dev/shm, could
> use it to break the owner of the file. So require permission to write to
> the file to preserve it, for all files. Like FS_IOC_ENABLE_VERITY, don't
> require a file opened for writing, so that binaries that are being
> executed can still be preserved through read-only fds. Also don't
> require a writable mount, since preserving a file doesn't write to the
> filesystem. If the size of the file can't change anyway, because it is
> immutable or on a read-only superblock, also let its owner preserve it.
> Don't let others do that, since the size could change again once the
> file is made writable. Like FS_IOC_ENABLE_VERITY, reject append-only
> files, since their writers can only append to them, and freezing their
> size would stop all appends.
>
> Also like FS_IOC_ENABLE_VERITY, require the file to be opened for
> reading. The retrieved file can be read, so otherwise a caller that can
> only write to a file could preserve it to read its contents.
>
> Preserving a file also fills its holes, but don't require any permission
> for that. Anyone who can read a tmpfs file can already fill its holes by
> faulting them in through a read-only mapping, also on read-only mounts
> and for immutable files.
>
> Document the frozen size and the permission requirements.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> Link: https://patch.msgid.link/20261103010216.3447716-9-dmatlack@google.com
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
--
Pasha
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked
2026-11-03 1:02 ` [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked David Matlack
2026-11-04 0:43 ` Pasha Tatashin
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:45 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Allow preserving tmpfs files that are still linked. To preserve any
> file, require permission to write to it and the file to be opened for
> reading, and reject append-only files.
>
> shmem_luo already accepts any shmem file without links, which includes
> unlinked tmpfs files and files created with O_TMPFILE. Accepting linked
> files means that userspace doesn't have to unlink files to preserve them
> and can keep using them by path until the live update.
>
> The path of the file isn't preserved. Like other files from tmpfs
> mounts, a linked file is retrieved onto a tmpfs mount chosen by
> userspace, which can then link it at the path it wants.
>
> While a file is preserved, its size is frozen, so truncating it,
> fallocate() and writes past its end fail with -EPERM. For a linked file,
> [ ... ]
> and for immutable files.
>
> Document the frozen size and the permission requirements.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=8
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked
2026-11-03 1:02 ` [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked David Matlack
2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 16:45 ` Pratyush Yadav
2026-11-04 22:32 ` David Matlack
2 siblings, 1 reply; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 16:45 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
Hi David,
On Tue, Nov 03 2026, David Matlack wrote:
> Allow preserving tmpfs files that are still linked. To preserve any
> file, require permission to write to it and the file to be opened for
> reading, and reject append-only files.
>
> shmem_luo already accepts any shmem file without links, which includes
> unlinked tmpfs files and files created with O_TMPFILE. Accepting linked
> files means that userspace doesn't have to unlink files to preserve them
> and can keep using them by path until the live update.
No, no. As I wrote in the previous patch too, this is a *bug*, and not
"supported". Please don't treat it as such. Tell your LLM to also not
treat it as such ;-)
This patch doesn't do "Allow preserving tmpfs files that are still
linked", it does "Allow preserving tmpfs files".
>
> The path of the file isn't preserved. Like other files from tmpfs
> mounts, a linked file is retrieved onto a tmpfs mount chosen by
> userspace, which can then link it at the path it wants.
>
> While a file is preserved, its size is frozen, so truncating it,
> fallocate() and writes past its end fail with -EPERM. For a linked file,
> this affects everyone who opens the file by its path, so a caller that
> can only read the file, e.g. a world-readable file in /dev/shm, could
> use it to break the owner of the file. So require permission to write to
> the file to preserve it, for all files. Like FS_IOC_ENABLE_VERITY, don't
That makes sense, but can you do it for memfd as well please, as a
preparatory patch?
> require a file opened for writing, so that binaries that are being
> executed can still be preserved through read-only fds. Also don't
> require a writable mount, since preserving a file doesn't write to the
> filesystem. If the size of the file can't change anyway, because it is
> immutable or on a read-only superblock, also let its owner preserve it.
> Don't let others do that, since the size could change again once the
> file is made writable. Like FS_IOC_ENABLE_VERITY, reject append-only
> files, since their writers can only append to them, and freezing their
> size would stop all appends.
>
> Also like FS_IOC_ENABLE_VERITY, require the file to be opened for
> reading. The retrieved file can be read, so otherwise a caller that can
> only write to a file could preserve it to read its contents.
I've stopped reading it by this point. Sounds too LLM-ey. Please try
to make this easier to read for humans.
For example, why are we even talking about FS_IOC_ENABLE_VERITY? I
reckon you have it in your chat as an example to draw design from, but
then LLMs have a tendency to leak those information in patch logs. I
usually spawn a subagent with clean context and a high level description
of the goal to review the changes and changelogs, to clean up these
things, and then of course review everything manually.
Same thing in your comments.
Please clean them up.
>
> Preserving a file also fills its holes, but don't require any permission
> for that. Anyone who can read a tmpfs file can already fill its holes by
> faulting them in through a read-only mapping, also on read-only mounts
> and for immutable files.
>
> Document the frozen size and the permission requirements.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> mm/shmem_luo.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 64 insertions(+), 3 deletions(-)
>
> diff --git a/mm/shmem_luo.c b/mm/shmem_luo.c
> index ecbeb37d33a8..0c012f242fc5 100644
> --- a/mm/shmem_luo.c
> +++ b/mm/shmem_luo.c
> @@ -28,6 +28,24 @@
> * the file are preserved. All others are reset to default. The preserved
> * properties are described below.
> *
> + * A tmpfs file can be preserved even if it is linked, but its path is not
> + * preserved. Userspace chooses where to put the file when retrieving it, as
> + * described in "Retrieving Tmpfs Files" below.
> + *
> + * Preserving a file requires it to be opened for reading, since the retrieved
> + * file can be read. It also requires permission to write to the file, since
> + * preserving it affects all of its users, as described below. But the file
> + * doesn't need to be opened for writing. For example, a binary that is being
> + * executed can be preserved through a read-only file descriptor. The owner of
Why are you talking about preserving binaries being executed? Seems
oddly specific. I didn't know that was a use case we cared about.
> + * a file whose size can't change anyway, because it is immutable or on a
> + * read-only superblock, may also preserve it. The file can be preserved
> + * through a read-only mount. Append-only files can't be preserved.
> + *
> + * While a file is preserved, its size can't change and no holes can be punched
> + * into it. Truncating the file, ``fallocate()`` and writes past the end of the
> + * file fail with ``-EPERM``. This applies to all users of the file, including
> + * users that open it by its path.
> + *
> * .. note::
> * The LUO API is not stabilized yet, so the preserved properties of a memfd
> * or tmpfs file are also not stable and are subject to backwards
> @@ -298,6 +316,45 @@ static void shmem_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
> vfree(folios_ser);
> }
>
> +/*
> + * Check whether the caller may preserve @file. The retrieved file can be read,
> + * so require @file to be opened for reading, like FS_IOC_ENABLE_VERITY does.
> + *
> + * Preserving the file freezes its size until it is unpreserved, for all users
> + * of the file, so require permission to write to the file. Like
> + * FS_IOC_ENABLE_VERITY, don't require a file opened for writing, so that e.g.
> + * a binary that is being executed can be preserved. Also don't require a
> + * writable mount, since preserving the file doesn't write to the filesystem.
> + * If the size of the file can't change anyway, because it is on a read-only
> + * superblock or immutable, its owner may also preserve it. The size could only
> + * change again after the file is made writable, which is up to the owner or
> + * root. Reject append-only files: Their writers can only append to them, and
> + * freezing the size would stop all appends.
> + *
> + * Preserving the file also fills its holes, but that doesn't need any more
> + * permission: Anyone who can read the file can fill its holes by faulting
> + * them in through a read-only mapping.
Please rework this whole block, it's unreadable.
> + */
> +static int shmem_luo_may_preserve(struct file *file)
> +{
> + struct mnt_idmap *idmap = file_mnt_idmap(file);
> + struct inode *inode = file_inode(file);
> + int err;
> +
> + if (!(file->f_mode & FMODE_READ))
> + return -EBADF;
> +
> + if (IS_APPEND(inode))
> + return -EPERM;
> +
> + err = inode_permission(idmap, inode, MAY_WRITE);
> + if (err && (sb_rdonly(inode->i_sb) || IS_IMMUTABLE(inode)) &&
> + inode_owner_or_capable(idmap, inode))
Nit: can you move these conditions up, and directly return 0 there? Much
more readable.
> + return 0;
> +
> + return err;
> +}
> +
> static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
> {
> struct inode *inode = file_inode(args->file);
> @@ -307,6 +364,11 @@ static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
> int err = 0, seals;
>
> inode_lock(inode);
> +
> + err = shmem_luo_may_preserve(args->file);
> + if (err)
> + goto err_unlock_inode;
> +
> shmem_freeze(inode, true);
>
> /* Allocate the main serialization structure in preserved memory */
> @@ -362,6 +424,7 @@ static int shmem_luo_preserve(struct liveupdate_file_op_args *args)
> kho_unpreserve_free(ser);
> err_unlock:
> shmem_freeze(inode, false);
> +err_unlock_inode:
> inode_unlock(inode);
> return err;
> }
> @@ -710,9 +773,7 @@ static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
> static bool shmem_luo_can_preserve(struct liveupdate_file_handler *handler,
> struct file *file)
> {
> - struct inode *inode = file_inode(file);
> -
> - return shmem_file(file) && !inode->i_nlink;
> + return shmem_file(file);
> }
>
> static unsigned long shmem_luo_get_id(struct file *file)
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked
2026-11-04 16:45 ` Pratyush Yadav
@ 2026-11-04 22:32 ` David Matlack
0 siblings, 0 replies; 42+ messages in thread
From: David Matlack @ 2026-11-04 22:32 UTC (permalink / raw)
To: Pratyush Yadav
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Randy Dunlap, Samiullah Khawaja, Shuah Khan, Suren Baghdasaryan,
Vlastimil Babka
On 2026-11-04 05:45 PM, Pratyush Yadav wrote:
[...]
> > + * Preserving a file requires it to be opened for reading, since the retrieved
> > + * file can be read. It also requires permission to write to the file, since
> > + * preserving it affects all of its users, as described below. But the file
> > + * doesn't need to be opened for writing. For example, a binary that is being
> > + * executed can be preserved through a read-only file descriptor. The owner of
>
> Why are you talking about preserving binaries being executed? Seems
> oddly specific. I didn't know that was a use case we cared about.
It's the reason the check looks at permission on the inode instead of
requiring an fd opened for writing: a running binary can't be opened for
writing (-ETXTBSY), so requiring a writable fd would make it impossible
to preserve. Preserving binaries is a use case we care about, e.g. to
carry over the binaries of services across a Live Update. I'll keep the
comment shorter and more general in v4.
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY
2026-11-03 1:02 [PATCH v3 00/10] liveupdate: Preserve tmpfs files across Live Update David Matlack
` (7 preceding siblings ...)
2026-11-03 1:02 ` [PATCH v3 08/10] mm/shmem_luo: Allow preserving tmpfs files that are still linked David Matlack
@ 2026-11-03 1:02 ` David Matlack
2026-11-04 0:43 ` Pasha Tatashin
` (2 more replies)
[not found] ` <20261103010216.3447716-11-dmatlack@google.com>
9 siblings, 3 replies; 42+ messages in thread
From: David Matlack @ 2026-11-03 1:02 UTC (permalink / raw)
To: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, David Matlack
Allow userspace to pass O_RDONLY in struct liveupdate_shmem_retrieve_arg
to retrieve a tmpfs file read-only.
open() requires write access for O_TMPFILE, so create the file writable
like before, then reopen it read-only with dentry_open() using the flags
of the writable file, which file_open_root() normalized, and drop the
writable file. Like open(), which grants the requested access to a new
file regardless of its mode, don't check permission for the read-only
open.
Retrieving a file read-only allows a restored binary to be executed
before the session is finished. LUO keeps the retrieved file open until
then, and executing a binary that is open for writing fails with
-ETXTBSY. Being able to execute restored binaries right away matters
when they are needed to finish restoring the system, e.g. to bring up
the services that retrieve and finish the remaining sessions.
Signed-off-by: David Matlack <dmatlack@google.com>
---
include/uapi/linux/liveupdate.h | 6 +++---
mm/shmem_luo.c | 34 ++++++++++++++++++++++++++-------
2 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
index a9dcc4fcc87b..790742a247e8 100644
--- a/include/uapi/linux/liveupdate.h
+++ b/include/uapi/linux/liveupdate.h
@@ -265,9 +265,9 @@ struct liveupdate_session_get_name {
*
* The kernel creates a new file as if by openat(@dirfd, ".", O_TMPFILE |
* @flags, @mode), fills it with the preserved contents, and returns it in
- * &struct liveupdate_session_retrieve_fd.fd. Like any O_TMPFILE file, the file
- * is not linked into the filesystem. Userspace can link it with linkat(),
- * unless @flags contains O_EXCL.
+ * &struct liveupdate_session_retrieve_fd.fd. Unlike open(), O_RDONLY is
+ * allowed. Like any O_TMPFILE file, the file is not linked into the filesystem.
+ * Userspace can link it with linkat(), unless @flags contains O_EXCL.
*
* If @flags contains unknown flags or O_PATH, if @mode contains unknown mode
* bits, or if @dirfd is not on a tmpfs mount, the retrieve fails with -EINVAL.
diff --git a/mm/shmem_luo.c b/mm/shmem_luo.c
index 0c012f242fc5..c669416a8a59 100644
--- a/mm/shmem_luo.c
+++ b/mm/shmem_luo.c
@@ -113,9 +113,10 @@
*
* Like any ``O_TMPFILE`` file, the new file is not linked into the filesystem.
* Userspace can link it at the path it wants with ``linkat()``, unless it asked
- * for ``O_EXCL``. Like with ``open()``, the file must be opened for writing.
- * LUO keeps the file open until the session is finished, so a retrieved binary
- * can't be executed until then.
+ * for ``O_EXCL``. Unlike ``open()``, the file can be retrieved with
+ * ``O_RDONLY``. LUO keeps the file open until the session is finished, so a
+ * binary retrieved with ``O_RDWR`` or ``O_WRONLY`` can't be executed until
+ * then.
*
* The blocks of the file are charged to the target mount, so the size limit
* and quotas of the mount apply. If the file doesn't fit, the retrieve fails
@@ -661,7 +662,9 @@ static struct file *shmem_luo_create_memfd(const struct liveupdate_shmem_retriev
static struct file *shmem_luo_create_tmpfs_file(const struct liveupdate_shmem_retrieve_arg *arg,
unsigned int seals)
{
- struct file *file;
+ struct file *file, *ro_file;
+ bool rdonly;
+ int flags;
int err;
if (!arg)
@@ -685,10 +688,16 @@ static struct file *shmem_luo_create_tmpfs_file(const struct liveupdate_shmem_re
/*
* Create the file like open(O_TMPFILE) does, so that it gets the same
- * flag checks, permission checks, owner and security labels.
+ * flag checks, permission checks, owner and security labels. open()
+ * requires write access for O_TMPFILE, so create the file writable and
+ * reopen it read-only below if that is what userspace asked for. LUO
+ * keeps the file until the session is finished, and a file opened for
+ * writing couldn't be executed until then.
*/
+ flags = O_TMPFILE | O_LARGEFILE | arg->flags;
+ rdonly = (flags & O_ACCMODE) == O_RDONLY;
file = file_open_root(&fd_file(dir)->f_path, ".",
- O_TMPFILE | O_LARGEFILE | arg->flags, arg->mode);
+ flags | (rdonly ? O_RDWR : 0), arg->mode);
if (IS_ERR(file))
return file;
@@ -706,7 +715,18 @@ static struct file *shmem_luo_create_tmpfs_file(const struct liveupdate_shmem_re
}
SHMEM_I(file_inode(file))->seals = seals;
- return file;
+ if (!rdonly)
+ return file;
+
+ /*
+ * Reopen the file with the flags of the writable file, which
+ * file_open_root() normalized, e.g. by dropping O_CLOEXEC.
+ */
+ ro_file = dentry_open(&file->f_path,
+ (file->f_flags & ~O_ACCMODE) | O_RDONLY,
+ current_cred());
+ fput(file);
+ return ro_file;
}
static int shmem_luo_retrieve(struct liveupdate_file_op_args *args)
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 42+ messages in thread* Re: [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY
2026-11-03 1:02 ` [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY David Matlack
@ 2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:52 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 0:43 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Allow userspace to pass O_RDONLY in struct liveupdate_shmem_retrieve_arg
> to retrieve a tmpfs file read-only.
>
> open() requires write access for O_TMPFILE, so create the file writable
> like before, then reopen it read-only with dentry_open() using the flags
> of the writable file, which file_open_root() normalized, and drop the
> writable file. Like open(), which grants the requested access to a new
> file regardless of its mode, don't check permission for the read-only
> open.
>
> Retrieving a file read-only allows a restored binary to be executed
> before the session is finished. LUO keeps the retrieved file open until
> then, and executing a binary that is open for writing fails with
> -ETXTBSY. Being able to execute restored binaries right away matters
> when they are needed to finish restoring the system, e.g. to bring up
> the services that retrieve and finish the remaining sessions.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> Link: https://patch.msgid.link/20261103010216.3447716-10-dmatlack@google.com
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
--
Pasha
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY
2026-11-03 1:02 ` [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY David Matlack
2026-11-04 0:43 ` Pasha Tatashin
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:52 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Allow userspace to pass O_RDONLY in struct liveupdate_shmem_retrieve_arg
> to retrieve a tmpfs file read-only.
>
> open() requires write access for O_TMPFILE, so create the file writable
> like before, then reopen it read-only with dentry_open() using the flags
> of the writable file, which file_open_root() normalized, and drop the
> writable file. Like open(), which grants the requested access to a new
> file regardless of its mode, don't check permission for the read-only
> open.
>
> Retrieving a file read-only allows a restored binary to be executed
> before the session is finished. LUO keeps the retrieved file open until
> then, and executing a binary that is open for writing fails with
> -ETXTBSY. Being able to execute restored binaries right away matters
> when they are needed to finish restoring the system, e.g. to bring up
> the services that retrieve and finish the remaining sessions.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=9
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY
2026-11-03 1:02 ` [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY David Matlack
2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 16:52 ` Pratyush Yadav
2026-11-04 19:45 ` Pasha Tatashin
2 siblings, 1 reply; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 16:52 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> Allow userspace to pass O_RDONLY in struct liveupdate_shmem_retrieve_arg
> to retrieve a tmpfs file read-only.
>
> open() requires write access for O_TMPFILE, so create the file writable
> like before, then reopen it read-only with dentry_open() using the flags
> of the writable file, which file_open_root() normalized, and drop the
> writable file. Like open(), which grants the requested access to a new
> file regardless of its mode, don't check permission for the read-only
> open.
>
> Retrieving a file read-only allows a restored binary to be executed
> before the session is finished. LUO keeps the retrieved file open until
> then, and executing a binary that is open for writing fails with
> -ETXTBSY. Being able to execute restored binaries right away matters
> when they are needed to finish restoring the system, e.g. to bring up
> the services that retrieve and finish the remaining sessions.
Can't you put all your binaries in a separate session, retrieve it as
the very first thing, and then finish the session? Then you can execute
those and retrieve all the other sessions.
Why do we need to support this in the kernel?
Also, please put the motivation as on the top-ish of the commit message,
and the mechanics later. For example, your second paragraph should
likely come below this one.
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY
2026-11-04 16:52 ` Pratyush Yadav
@ 2026-11-04 19:45 ` Pasha Tatashin
2026-11-04 22:35 ` David Matlack
0 siblings, 1 reply; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 19:45 UTC (permalink / raw)
To: Pratyush Yadav
Cc: David Matlack, kexec, linux-doc, linux-kernel, linux-kselftest,
linux-mm, Alexander Graf, Andrew Morton, Baolin Wang,
Christian Brauner, David Hildenbrand, Hugh Dickins,
Jonathan Corbet, Liam R. Howlett, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Pasha Tatashin, Randy Dunlap, Samiullah Khawaja,
Shuah Khan, Suren Baghdasaryan, Vlastimil Babka
On 11-04 17:52, Pratyush Yadav wrote:
> On Tue, Nov 03 2026, David Matlack wrote:
>
> > Allow userspace to pass O_RDONLY in struct liveupdate_shmem_retrieve_arg
> > to retrieve a tmpfs file read-only.
> >
> > open() requires write access for O_TMPFILE, so create the file writable
> > like before, then reopen it read-only with dentry_open() using the flags
> > of the writable file, which file_open_root() normalized, and drop the
> > writable file. Like open(), which grants the requested access to a new
> > file regardless of its mode, don't check permission for the read-only
> > open.
> >
> > Retrieving a file read-only allows a restored binary to be executed
> > before the session is finished. LUO keeps the retrieved file open until
> > then, and executing a binary that is open for writing fails with
> > -ETXTBSY. Being able to execute restored binaries right away matters
> > when they are needed to finish restoring the system, e.g. to bring up
> > the services that retrieve and finish the remaining sessions.
>
> Can't you put all your binaries in a separate session, retrieve it as
> the very first thing, and then finish the session? Then you can execute
> those and retrieve all the other sessions.
This is a good workaround. I am not opposed to this patch for
completeness of functionality, but if we decide to keep it, perhaps it
should simply be squashed into an earlier patch. The current diffstat
looks bad, as it mostly deletes code that was introduced earlier in this
series.
In any case, given Pratyush's suggestion, we could also drop it.
>
> Why do we need to support this in the kernel?
>
> Also, please put the motivation as on the top-ish of the commit message,
> and the mechanics later. For example, your second paragraph should
> likely come below this one.
>
> [...]
>
> --
> Regards,
> Pratyush Yadav
--
Pasha
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 09/10] mm/shmem_luo: Allow retrieving tmpfs files with O_RDONLY
2026-11-04 19:45 ` Pasha Tatashin
@ 2026-11-04 22:35 ` David Matlack
0 siblings, 0 replies; 42+ messages in thread
From: David Matlack @ 2026-11-04 22:35 UTC (permalink / raw)
To: Pasha Tatashin
Cc: Pratyush Yadav, kexec, linux-doc, linux-kernel, linux-kselftest,
linux-mm, Alexander Graf, Andrew Morton, Baolin Wang,
Christian Brauner, David Hildenbrand, Hugh Dickins,
Jonathan Corbet, Liam R. Howlett, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On 2026-11-04 02:45 PM, Pasha Tatashin wrote:
> On 11-04 17:52, Pratyush Yadav wrote:
> > On Tue, Nov 03 2026, David Matlack wrote:
> > [...]
> >
> > Can't you put all your binaries in a separate session, retrieve it as
> > the very first thing, and then finish the session? Then you can execute
> > those and retrieve all the other sessions.
>
> This is a good workaround. I am not opposed to this patch for
> completeness of functionality, but if we decide to keep it, perhaps it
> should simply be squashed into an earlier patch. The current diffstat
> looks bad, as it mostly deletes code that was introduced earlier in this
> series.
>
> In any case, given Pratyush's suggestion, we could also drop it.
>
> >
> > Why do we need to support this in the kernel?
That would work for binaries, and I agree that use case alone doesn't
justify this. But I see O_RDONLY as part of the retrieve interface, not
a feature for one use case. The retrieve argument is modeled on
openat(), and openat() lets you open an existing file read-only.
open(O_TMPFILE) only requires write access because it creates an empty
file, and an empty read-only file is useless. A retrieved file isn't
empty, it has the preserved contents, so O_RDONLY makes as much sense as
it does for any other existing file. Without it, every retrieved file is
writable, even when userspace only needs to read it.
Preserve already works the same way: a file can be preserved through a
read-only fd, as long as the caller has permission to write to it.
If we keep it, I'll squash it into patch 7 in v4, so retrieve supports
O_RDONLY from the start. The commit message will lead with the openat()
reasoning and keep binaries as just an example.
^ permalink raw reply [flat|nested] 42+ messages in thread
[parent not found: <20261103010216.3447716-11-dmatlack@google.com>]
* Re: [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files
[not found] ` <20261103010216.3447716-11-dmatlack@google.com>
@ 2026-11-04 0:43 ` Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:59 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 0:43 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Add luo_tmpfs, a kexec test for preserving tmpfs files and memfds, and
> for retrieving tmpfs files onto a tmpfs mount with struct
> liveupdate_shmem_retrieve_arg.
>
> Stage 1 preserves the source files of each test case. Stage 2 runs
> each test case in its own directory, with its own tmpfs mounts, so that
> block usage can be checked exactly with statfs() and st_blocks. The test
> cases cover:
>
> - The restored file: contents, size, position, seals and holes, for
> linked and unlinked source files.
>
> - Creating the file: it is created like with open(O_TMPFILE), with the
> requested mode minus the umask, owned by the caller, and not linked
> until userspace links it, unless it asked for O_EXCL. Also O_RDONLY
> and O_WRONLY files, other open() flags such as O_APPEND, O_NONBLOCK
> and O_CLOEXEC, read-only mounts, and directories that the caller
> can't write to.
>
> - Preserving files that can't be written to: a binary while it is
> executed, through a read-only fd, files on read-only mounts and
> superblocks, and immutable files, including sparse ones, whose holes
> are filled. Preserving someone else's file that the caller can't
> write to fails, and so does preserving a file through a write-only
> fd or an append-only file.
>
> - Executing restored binaries: a restored binary can be executed
> before the session is finished if it was retrieved with O_RDONLY, but
> not if it was retrieved for writing, since LUO keeps the file open
> until then. These test cases execute copies of the test binary.
>
> - Block accounting: the file fits a mount of exactly its size, and a
> large folio that extends past the end of the file is charged in full.
> Running out of space, or hitting the memcg limit, fails permanently,
> and leaves nothing charged to the mount or the memcg. The session can
> still be finished.
>
> - memfds: they are only retrieved as memfds, with their seals, and
> files from tmpfs mounts only onto a tmpfs mount.
>
> - Interactions with LUO: invalid arguments, which can be retried,
> retrieving a token twice, and outgoing sessions.
>
> Also check that the size of a preserved file is frozen, and that the
> test doesn't trigger kernel warnings.
>
> Enable CONFIG_TRANSPARENT_HUGEPAGE for the large folio test cases,
> CONFIG_MEMCG for the memcg test case and CONFIG_TMPFS_XATTR for
> FS_IOC_SETFLAGS. Those test cases are skipped without them.
>
> tmpfs quotas are not tested, since the test runs as root, which is not
> subject to quota limits.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> Link: https://patch.msgid.link/20261103010216.3447716-11-dmatlack@google.com
Overall, I like the series. As a follow-up, it would also be nice to add
non-kexec tests to liveupdate.c covering preserve/unpreserve/freeze and
restrictions on various tmpfs files without rebooting.
While that won't test retrieval, liveupdate.c runs as part
of regular kselftest by pretty much everyone, unlike the much heavier
vmtest.sh run.
Acked-by: Pasha Tatashin <pasha.tatashin@soleen.com>
--
Pasha
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files
[not found] ` <20261103010216.3447716-11-dmatlack@google.com>
2026-11-04 0:43 ` [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files Pasha Tatashin
@ 2026-11-04 1:03 ` sashiko-bot
2026-11-04 16:59 ` Pratyush Yadav
2 siblings, 0 replies; 42+ messages in thread
From: sashiko-bot @ 2026-11-04 1:03 UTC (permalink / raw)
To: David Matlack, kexec
Cc: Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
> Add luo_tmpfs, a kexec test for preserving tmpfs files and memfds, and
> for retrieving tmpfs files onto a tmpfs mount with struct
> liveupdate_shmem_retrieve_arg.
>
> Stage 1 preserves the source files of each test case. Stage 2 runs
> each test case in its own directory, with its own tmpfs mounts, so that
> block usage can be checked exactly with statfs() and st_blocks. The test
> cases cover:
>
> - The restored file: contents, size, position, seals and holes, for
> linked and unlinked source files.
>
> - Creating the file: it is created like with open(O_TMPFILE), with the
> requested mode minus the umask, owned by the caller, and not linked
> until userspace links it, unless it asked for O_EXCL. Also O_RDONLY
> [ ... ]
>
> tmpfs quotas are not tested, since the test runs as root, which is not
> subject to quota limits.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103010216.3447716-1-dmatlack@google.com?part=10
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files
[not found] ` <20261103010216.3447716-11-dmatlack@google.com>
2026-11-04 0:43 ` [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files Pasha Tatashin
2026-11-04 1:03 ` sashiko-bot
@ 2026-11-04 16:59 ` Pratyush Yadav
2026-11-04 19:37 ` Pasha Tatashin
2 siblings, 1 reply; 42+ messages in thread
From: Pratyush Yadav @ 2026-11-04 16:59 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-kselftest, linux-mm,
Alexander Graf, Andrew Morton, Baolin Wang, Christian Brauner,
David Hildenbrand, Hugh Dickins, Jonathan Corbet, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On Tue, Nov 03 2026, David Matlack wrote:
> Add luo_tmpfs, a kexec test for preserving tmpfs files and memfds, and
> for retrieving tmpfs files onto a tmpfs mount with struct
> liveupdate_shmem_retrieve_arg.
>
> Stage 1 preserves the source files of each test case. Stage 2 runs
> each test case in its own directory, with its own tmpfs mounts, so that
> block usage can be checked exactly with statfs() and st_blocks. The test
> cases cover:
>
> - The restored file: contents, size, position, seals and holes, for
> linked and unlinked source files.
>
> - Creating the file: it is created like with open(O_TMPFILE), with the
> requested mode minus the umask, owned by the caller, and not linked
> until userspace links it, unless it asked for O_EXCL. Also O_RDONLY
> and O_WRONLY files, other open() flags such as O_APPEND, O_NONBLOCK
> and O_CLOEXEC, read-only mounts, and directories that the caller
> can't write to.
>
> - Preserving files that can't be written to: a binary while it is
> executed, through a read-only fd, files on read-only mounts and
> superblocks, and immutable files, including sparse ones, whose holes
> are filled. Preserving someone else's file that the caller can't
> write to fails, and so does preserving a file through a write-only
> fd or an append-only file.
>
> - Executing restored binaries: a restored binary can be executed
> before the session is finished if it was retrieved with O_RDONLY, but
> not if it was retrieved for writing, since LUO keeps the file open
> until then. These test cases execute copies of the test binary.
>
> - Block accounting: the file fits a mount of exactly its size, and a
> large folio that extends past the end of the file is charged in full.
> Running out of space, or hitting the memcg limit, fails permanently,
> and leaves nothing charged to the mount or the memcg. The session can
> still be finished.
>
> - memfds: they are only retrieved as memfds, with their seals, and
> files from tmpfs mounts only onto a tmpfs mount.
>
> - Interactions with LUO: invalid arguments, which can be retried,
> retrieving a token twice, and outgoing sessions.
>
> Also check that the size of a preserved file is frozen, and that the
> test doesn't trigger kernel warnings.
>
> Enable CONFIG_TRANSPARENT_HUGEPAGE for the large folio test cases,
> CONFIG_MEMCG for the memcg test case and CONFIG_TMPFS_XATTR for
> FS_IOC_SETFLAGS. Those test cases are skipped without them.
>
> tmpfs quotas are not tested, since the test runs as root, which is not
> subject to quota limits.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> tools/testing/selftests/liveupdate/Makefile | 1 +
> tools/testing/selftests/liveupdate/config | 4 +
> .../testing/selftests/liveupdate/luo_tmpfs.c | 2055 +++++++++++++++++
Umm, no way I am reading all this...
LLMs are great at generating tests, and I'm not saying there is no value
in this. It is just that this massive code dump is unreviewable by
humans. It is also unfair to the human reviewer because it took many
orders of magnitude less effort to _write_ them with an LLM.
What do you all reckon we should do about this? Trust the LLM to get the
testing right? Do we give up human maintenance of tests entirely? Do we
do fault injection to test the tests themselves?
Or do we make the tests smaller and more human reviewable?
> .../selftests/liveupdate/run-vmtests.sh | 1 +
> 4 files changed, 2061 insertions(+)
> create mode 100644 tools/testing/selftests/liveupdate/luo_tmpfs.c
>
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files
2026-11-04 16:59 ` Pratyush Yadav
@ 2026-11-04 19:37 ` Pasha Tatashin
2026-11-04 22:42 ` David Matlack
0 siblings, 1 reply; 42+ messages in thread
From: Pasha Tatashin @ 2026-11-04 19:37 UTC (permalink / raw)
To: Pratyush Yadav
Cc: David Matlack, kexec, linux-doc, linux-kernel, linux-kselftest,
linux-mm, Alexander Graf, Andrew Morton, Baolin Wang,
Christian Brauner, David Hildenbrand, Hugh Dickins,
Jonathan Corbet, Liam R. Howlett, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Pasha Tatashin, Randy Dunlap, Samiullah Khawaja,
Shuah Khan, Suren Baghdasaryan, Vlastimil Babka
On 11-04 17:59, Pratyush Yadav wrote:
> On Tue, Nov 03 2026, David Matlack wrote:
>
> > Add luo_tmpfs, a kexec test for preserving tmpfs files and memfds, and
> > for retrieving tmpfs files onto a tmpfs mount with struct
> > liveupdate_shmem_retrieve_arg.
> >
> > Stage 1 preserves the source files of each test case. Stage 2 runs
> > each test case in its own directory, with its own tmpfs mounts, so that
> > block usage can be checked exactly with statfs() and st_blocks. The test
> > cases cover:
> >
> > - The restored file: contents, size, position, seals and holes, for
> > linked and unlinked source files.
> >
> > - Creating the file: it is created like with open(O_TMPFILE), with the
> > requested mode minus the umask, owned by the caller, and not linked
> > until userspace links it, unless it asked for O_EXCL. Also O_RDONLY
> > and O_WRONLY files, other open() flags such as O_APPEND, O_NONBLOCK
> > and O_CLOEXEC, read-only mounts, and directories that the caller
> > can't write to.
> >
> > - Preserving files that can't be written to: a binary while it is
> > executed, through a read-only fd, files on read-only mounts and
> > superblocks, and immutable files, including sparse ones, whose holes
> > are filled. Preserving someone else's file that the caller can't
> > write to fails, and so does preserving a file through a write-only
> > fd or an append-only file.
> >
> > - Executing restored binaries: a restored binary can be executed
> > before the session is finished if it was retrieved with O_RDONLY, but
> > not if it was retrieved for writing, since LUO keeps the file open
> > until then. These test cases execute copies of the test binary.
> >
> > - Block accounting: the file fits a mount of exactly its size, and a
> > large folio that extends past the end of the file is charged in full.
> > Running out of space, or hitting the memcg limit, fails permanently,
> > and leaves nothing charged to the mount or the memcg. The session can
> > still be finished.
> >
> > - memfds: they are only retrieved as memfds, with their seals, and
> > files from tmpfs mounts only onto a tmpfs mount.
> >
> > - Interactions with LUO: invalid arguments, which can be retried,
> > retrieving a token twice, and outgoing sessions.
> >
> > Also check that the size of a preserved file is frozen, and that the
> > test doesn't trigger kernel warnings.
> >
> > Enable CONFIG_TRANSPARENT_HUGEPAGE for the large folio test cases,
> > CONFIG_MEMCG for the memcg test case and CONFIG_TMPFS_XATTR for
> > FS_IOC_SETFLAGS. Those test cases are skipped without them.
> >
> > tmpfs quotas are not tested, since the test runs as root, which is not
> > subject to quota limits.
> >
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> > tools/testing/selftests/liveupdate/Makefile | 1 +
> > tools/testing/selftests/liveupdate/config | 4 +
> > .../testing/selftests/liveupdate/luo_tmpfs.c | 2055 +++++++++++++++++
>
> Umm, no way I am reading all this...
>
> LLMs are great at generating tests, and I'm not saying there is no value
> in this. It is just that this massive code dump is unreviewable by
> humans. It is also unfair to the human reviewer because it took many
> orders of magnitude less effort to _write_ them with an LLM.
>
> What do you all reckon we should do about this? Trust the LLM to get the
> testing right? Do we give up human maintenance of tests entirely? Do we
> do fault injection to test the tests themselves?
>
> Or do we make the tests smaller and more human reviewable?
We need good test coverage, but I believe we can break this patch down
into smaller changes where tested features are incrementally added.
>
> > .../selftests/liveupdate/run-vmtests.sh | 1 +
> > 4 files changed, 2061 insertions(+)
> > create mode 100644 tools/testing/selftests/liveupdate/luo_tmpfs.c
> >
> [...]
>
> --
> Regards,
> Pratyush Yadav
--
Pasha
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v3 10/10] selftests/liveupdate: Add a test for preserving tmpfs files
2026-11-04 19:37 ` Pasha Tatashin
@ 2026-11-04 22:42 ` David Matlack
0 siblings, 0 replies; 42+ messages in thread
From: David Matlack @ 2026-11-04 22:42 UTC (permalink / raw)
To: Pasha Tatashin
Cc: Pratyush Yadav, kexec, linux-doc, linux-kernel, linux-kselftest,
linux-mm, Alexander Graf, Andrew Morton, Baolin Wang,
Christian Brauner, David Hildenbrand, Hugh Dickins,
Jonathan Corbet, Liam R. Howlett, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Randy Dunlap, Samiullah Khawaja, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka
On 2026-11-04 02:37 PM, Pasha Tatashin wrote:
> On 11-04 17:59, Pratyush Yadav wrote:
> > On Tue, Nov 03 2026, David Matlack wrote:
> > [...]
> >
> > Umm, no way I am reading all this...
> >
> > LLMs are great at generating tests, and I'm not saying there is no value
> > in this. It is just that this massive code dump is unreviewable by
> > humans. It is also unfair to the human reviewer because it took many
> > orders of magnitude less effort to _write_ them with an LLM.
> >
> > What do you all reckon we should do about this? Trust the LLM to get the
> > testing right? Do we give up human maintenance of tests entirely? Do we
> > do fault injection to test the tests themselves?
> >
> > Or do we make the tests smaller and more human reviewable?
>
> We need good test coverage, but I believe we can break this patch down
> into smaller changes where tested features are incrementally added.
Agreed that it needs to be easier to review, but I'd like to keep the
coverage. Here's what I have in mind for v4:
- Move the preserve-side checks that don't need a kexec into
liveupdate.c, like Pasha suggested in his earlier reply: which files
can be preserved (permissions, read-only and append-only files), the
frozen size while preserved, and unpreserve. Those then run with the
regular kselftests instead of only in vmtest.sh.
- Split the rest of luo_tmpfs into several smaller commits that add the
tested features incrementally, e.g. one for the test infrastructure
and basic retrieve, one for the open() flags and creation checks, and
one for block accounting. That makes the series longer, but each
commit is a few hundred lines and can be reviewed on its own.
It will still be long, but I think having the test coverage is worth it.
Does that sound reasonable?
^ permalink raw reply [flat|nested] 42+ messages in thread