* [PATCH v9 1/6] liveupdate: reject LIVEUPDATE_IOCTL_CREATE_SESSION with invalid name length
2026-04-20 14:15 [PATCH v9 0/6] liveupdate: new ioctl, change session inode type, bug fixes luca.boccassi
@ 2026-04-20 14:15 ` luca.boccassi
2026-04-21 10:24 ` Mike Rapoport
2026-04-20 14:15 ` [PATCH v9 2/6] selftests/liveupdate: add test cases for LIVEUPDATE_IOCTL_CREATE_SESSION calls with invalid length luca.boccassi
` (4 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: luca.boccassi @ 2026-04-20 14:15 UTC (permalink / raw)
To: kexec
Cc: linux-mm, graf, rppt, pasha.tatashin, pratyush, brauner,
linux-kernel, Luca Boccassi
From: Luca Boccassi <luca.boccassi@gmail.com>
A session name must not be an empty string, and must not exceed the
maximum size define in the uapi header, including null termination.
Fixes: 0153094d03df ("liveupdate: luo_session: add sessions support")
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
kernel/liveupdate/luo_session.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 25ae704d7787..5e316a4c5d71 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -382,9 +382,13 @@ static int luo_session_getfile(struct luo_session *session, struct file **filep)
int luo_session_create(const char *name, struct file **filep)
{
+ size_t len = strnlen(name, LIVEUPDATE_SESSION_NAME_LENGTH);
struct luo_session *session;
int err;
+ if (len == 0 || len > LIVEUPDATE_SESSION_NAME_LENGTH - 1)
+ return -EINVAL;
+
session = luo_session_alloc(name);
if (IS_ERR(session))
return PTR_ERR(session);
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v9 1/6] liveupdate: reject LIVEUPDATE_IOCTL_CREATE_SESSION with invalid name length
2026-04-20 14:15 ` [PATCH v9 1/6] liveupdate: reject LIVEUPDATE_IOCTL_CREATE_SESSION with invalid name length luca.boccassi
@ 2026-04-21 10:24 ` Mike Rapoport
0 siblings, 0 replies; 14+ messages in thread
From: Mike Rapoport @ 2026-04-21 10:24 UTC (permalink / raw)
To: luca.boccassi
Cc: kexec, linux-mm, graf, pasha.tatashin, pratyush, brauner,
linux-kernel
On Mon, Apr 20, 2026 at 03:15:09PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> A session name must not be an empty string, and must not exceed the
> maximum size define in the uapi header, including null termination.
>
> Fixes: 0153094d03df ("liveupdate: luo_session: add sessions support")
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> kernel/liveupdate/luo_session.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
> index 25ae704d7787..5e316a4c5d71 100644
> --- a/kernel/liveupdate/luo_session.c
> +++ b/kernel/liveupdate/luo_session.c
> @@ -382,9 +382,13 @@ static int luo_session_getfile(struct luo_session *session, struct file **filep)
>
> int luo_session_create(const char *name, struct file **filep)
> {
> + size_t len = strnlen(name, LIVEUPDATE_SESSION_NAME_LENGTH);
> struct luo_session *session;
> int err;
>
> + if (len == 0 || len > LIVEUPDATE_SESSION_NAME_LENGTH - 1)
> + return -EINVAL;
> +
> session = luo_session_alloc(name);
> if (IS_ERR(session))
> return PTR_ERR(session);
> --
> 2.47.3
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 2/6] selftests/liveupdate: add test cases for LIVEUPDATE_IOCTL_CREATE_SESSION calls with invalid length
2026-04-20 14:15 [PATCH v9 0/6] liveupdate: new ioctl, change session inode type, bug fixes luca.boccassi
2026-04-20 14:15 ` [PATCH v9 1/6] liveupdate: reject LIVEUPDATE_IOCTL_CREATE_SESSION with invalid name length luca.boccassi
@ 2026-04-20 14:15 ` luca.boccassi
2026-04-21 10:25 ` Mike Rapoport
2026-04-20 14:15 ` [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type luca.boccassi
` (3 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: luca.boccassi @ 2026-04-20 14:15 UTC (permalink / raw)
To: kexec
Cc: linux-mm, graf, rppt, pasha.tatashin, pratyush, brauner,
linux-kernel, Luca Boccassi
From: Luca Boccassi <luca.boccassi@gmail.com>
Verify that LIVEUPDATE_IOCTL_CREATE_SESSION ioctl which provide a name
that is an empty string or too long are not allowed.
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
.../testing/selftests/liveupdate/liveupdate.c | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
index c2878e3d5ef9..f0a8e600c154 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -345,4 +345,46 @@ TEST_F(liveupdate_device, preserve_unsupported_fd)
ASSERT_EQ(close(session_fd), 0);
}
+/*
+ * Test Case: Create Session with No Null Termination
+ *
+ * Verifies that filling the entire 64-byte name field with non-null characters
+ * (no '\0' terminator) is rejected by the kernel with EINVAL.
+ */
+TEST_F(liveupdate_device, create_session_no_null_termination)
+{
+ struct liveupdate_ioctl_create_session args = {};
+
+ 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);
+
+ /* Fill entire name field with 'X', no null terminator */
+ args.size = sizeof(args);
+ memset(args.name, 'X', sizeof(args.name));
+
+ EXPECT_LT(ioctl(self->fd1, LIVEUPDATE_IOCTL_CREATE_SESSION, &args), 0);
+ EXPECT_EQ(errno, EINVAL);
+}
+
+/*
+ * Test Case: Create Session with Empty Name
+ *
+ * Verifies that creating a session with an empty string name fails
+ * with EINVAL.
+ */
+TEST_F(liveupdate_device, create_session_empty_name)
+{
+ int session_fd;
+
+ 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 = create_session(self->fd1, "");
+ EXPECT_EQ(session_fd, -EINVAL);
+}
+
TEST_HARNESS_MAIN
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v9 2/6] selftests/liveupdate: add test cases for LIVEUPDATE_IOCTL_CREATE_SESSION calls with invalid length
2026-04-20 14:15 ` [PATCH v9 2/6] selftests/liveupdate: add test cases for LIVEUPDATE_IOCTL_CREATE_SESSION calls with invalid length luca.boccassi
@ 2026-04-21 10:25 ` Mike Rapoport
0 siblings, 0 replies; 14+ messages in thread
From: Mike Rapoport @ 2026-04-21 10:25 UTC (permalink / raw)
To: luca.boccassi
Cc: kexec, linux-mm, graf, pasha.tatashin, pratyush, brauner,
linux-kernel
On Mon, Apr 20, 2026 at 03:15:10PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> Verify that LIVEUPDATE_IOCTL_CREATE_SESSION ioctl which provide a name
> that is an empty string or too long are not allowed.
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> .../testing/selftests/liveupdate/liveupdate.c | 42 +++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
> index c2878e3d5ef9..f0a8e600c154 100644
> --- a/tools/testing/selftests/liveupdate/liveupdate.c
> +++ b/tools/testing/selftests/liveupdate/liveupdate.c
> @@ -345,4 +345,46 @@ TEST_F(liveupdate_device, preserve_unsupported_fd)
> ASSERT_EQ(close(session_fd), 0);
> }
>
> +/*
> + * Test Case: Create Session with No Null Termination
> + *
> + * Verifies that filling the entire 64-byte name field with non-null characters
> + * (no '\0' terminator) is rejected by the kernel with EINVAL.
> + */
> +TEST_F(liveupdate_device, create_session_no_null_termination)
> +{
> + struct liveupdate_ioctl_create_session args = {};
> +
> + 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);
> +
> + /* Fill entire name field with 'X', no null terminator */
> + args.size = sizeof(args);
> + memset(args.name, 'X', sizeof(args.name));
> +
> + EXPECT_LT(ioctl(self->fd1, LIVEUPDATE_IOCTL_CREATE_SESSION, &args), 0);
> + EXPECT_EQ(errno, EINVAL);
> +}
> +
> +/*
> + * Test Case: Create Session with Empty Name
> + *
> + * Verifies that creating a session with an empty string name fails
> + * with EINVAL.
> + */
> +TEST_F(liveupdate_device, create_session_empty_name)
> +{
> + int session_fd;
> +
> + 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 = create_session(self->fd1, "");
> + EXPECT_EQ(session_fd, -EINVAL);
> +}
> +
> TEST_HARNESS_MAIN
> --
> 2.47.3
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type
2026-04-20 14:15 [PATCH v9 0/6] liveupdate: new ioctl, change session inode type, bug fixes luca.boccassi
2026-04-20 14:15 ` [PATCH v9 1/6] liveupdate: reject LIVEUPDATE_IOCTL_CREATE_SESSION with invalid name length luca.boccassi
2026-04-20 14:15 ` [PATCH v9 2/6] selftests/liveupdate: add test cases for LIVEUPDATE_IOCTL_CREATE_SESSION calls with invalid length luca.boccassi
@ 2026-04-20 14:15 ` luca.boccassi
2026-04-21 10:33 ` Mike Rapoport
2026-04-22 11:58 ` Christian Brauner
2026-04-20 14:15 ` [PATCH v9 4/6] selftests/liveupdate: add test case for LUO_SESSION_MAGIC luca.boccassi
` (2 subsequent siblings)
5 siblings, 2 replies; 14+ messages in thread
From: luca.boccassi @ 2026-04-20 14:15 UTC (permalink / raw)
To: kexec
Cc: linux-mm, graf, rppt, pasha.tatashin, pratyush, brauner,
linux-kernel, Luca Boccassi
From: Luca Boccassi <luca.boccassi@gmail.com>
In userspace when managing LUO sessions we want to be able to identify
a FD as a LUO session, in order to be able to do the special handling
that they require in order to function as intended on kexec.
Currently this requires scraping procfs and doing string matching on
the prefix of the dname, which is not an ideal interface.
Add a singleton inode type with a magic value, so that we can
programmatically identify a fd as a LUO session via fstatfs().
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
include/uapi/linux/magic.h | 1 +
kernel/liveupdate/luo_core.c | 10 +++-
kernel/liveupdate/luo_internal.h | 2 +
kernel/liveupdate/luo_session.c | 91 ++++++++++++++++++++++++++++++--
4 files changed, 98 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index 4f2da935a76c..4f51005522ff 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -105,5 +105,6 @@
#define PID_FS_MAGIC 0x50494446 /* "PIDF" */
#define GUEST_MEMFD_MAGIC 0x474d454d /* "GMEM" */
#define NULL_FS_MAGIC 0x4E554C4C /* "NULL" */
+#define LUO_SESSION_MAGIC 0x4c554f53 /* "LUOS" */
#endif /* __LINUX_MAGIC_H__ */
diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
index dda7bb57d421..f1a63ebe4fa4 100644
--- a/kernel/liveupdate/luo_core.c
+++ b/kernel/liveupdate/luo_core.c
@@ -197,9 +197,17 @@ static int __init luo_late_startup(void)
if (!liveupdate_enabled())
return 0;
+ err = luo_session_fs_init();
+ if (err) {
+ luo_global.enabled = false;
+ return err;
+ }
+
err = luo_fdt_setup();
- if (err)
+ if (err) {
+ luo_session_fs_cleanup();
luo_global.enabled = false;
+ }
return err;
}
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index 8083d8739b09..d4ac7b4c5882 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -79,6 +79,8 @@ struct luo_session {
int luo_session_create(const char *name, struct file **filep);
int luo_session_retrieve(const char *name, struct file **filep);
+int __init luo_session_fs_init(void);
+void __init luo_session_fs_cleanup(void);
int __init luo_session_setup_outgoing(void *fdt);
int __init luo_session_setup_incoming(void *fdt);
int luo_session_serialize(void);
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 5e316a4c5d71..9e343b6ce513 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -50,7 +50,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/anon_inodes.h>
#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -62,11 +61,15 @@
#include <linux/libfdt.h>
#include <linux/list.h>
#include <linux/liveupdate.h>
+#include <linux/magic.h>
+#include <linux/mount.h>
#include <linux/mutex.h>
+#include <linux/pseudo_fs.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/unaligned.h>
#include <uapi/linux/liveupdate.h>
+#include "../fs/internal.h"
#include "luo_internal.h"
/* 16 4K pages, give space for 744 sessions */
@@ -363,18 +366,74 @@ static const struct file_operations luo_session_fops = {
.unlocked_ioctl = luo_session_ioctl,
};
+static struct vfsmount *luo_session_mnt __ro_after_init;
+static struct inode *luo_session_inode __ro_after_init;
+
+/*
+ * Reject all attribute changes on the singleton session inode.
+ * Without this the VFS falls back to simple_setattr(), allowing
+ * fchmod()/fchown() to modify the shared inode.
+ */
+static const struct inode_operations luo_session_inode_operations = {
+ .setattr = anon_inode_setattr,
+};
+
+static char *luo_session_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+ return dynamic_dname(buffer, buflen, "luo_session:[%s]",
+ dentry->d_name.name);
+}
+
+static const struct dentry_operations luo_session_dentry_operations = {
+ .d_dname = luo_session_dname,
+};
+
+static const struct super_operations luo_session_sops = {
+ .drop_inode = inode_just_drop,
+ .statfs = simple_statfs,
+};
+
+static int luo_session_init_fs_context(struct fs_context *fc)
+{
+ struct pseudo_fs_context *ctx;
+
+ ctx = init_pseudo(fc, LUO_SESSION_MAGIC);
+ if (!ctx)
+ return -ENOMEM;
+
+ fc->s_iflags |= SB_I_NOEXEC;
+ fc->s_iflags |= SB_I_NODEV;
+ ctx->s_d_flags |= DCACHE_DONTCACHE;
+ ctx->dops = &luo_session_dentry_operations;
+ ctx->ops = &luo_session_sops;
+ return 0;
+}
+
+static struct file_system_type luo_session_fs_type = {
+ .name = "luo_session",
+ .init_fs_context = luo_session_init_fs_context,
+ .kill_sb = kill_anon_super,
+};
+
/* Create a "struct file" for session */
static int luo_session_getfile(struct luo_session *session, struct file **filep)
{
- char name_buf[128];
+ char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH + 1];
struct file *file;
lockdep_assert_held(&session->mutex);
- snprintf(name_buf, sizeof(name_buf), "[luo_session] %s", session->name);
- file = anon_inode_getfile(name_buf, &luo_session_fops, session, O_RDWR);
- if (IS_ERR(file))
+
+ ihold(luo_session_inode);
+
+ snprintf(name_buf, sizeof(name_buf), "%s", session->name);
+ file = alloc_file_pseudo(luo_session_inode, luo_session_mnt, name_buf,
+ O_RDWR, &luo_session_fops);
+ if (IS_ERR(file)) {
+ iput(luo_session_inode);
return PTR_ERR(file);
+ }
+ file->private_data = session;
*filep = file;
return 0;
@@ -653,3 +712,25 @@ void luo_session_resume(void)
up_write(&luo_session_global.outgoing.rwsem);
up_write(&luo_session_global.incoming.rwsem);
}
+
+int __init luo_session_fs_init(void)
+{
+ luo_session_mnt = kern_mount(&luo_session_fs_type);
+ if (IS_ERR(luo_session_mnt))
+ panic("Cannot create LUO Session pseudo-fs");
+
+ luo_session_inode = alloc_anon_inode(luo_session_mnt->mnt_sb);
+ if (IS_ERR(luo_session_inode)) {
+ kern_unmount(luo_session_mnt);
+ return PTR_ERR(luo_session_inode);
+ }
+ luo_session_inode->i_op = &luo_session_inode_operations;
+
+ return 0;
+}
+
+void __init luo_session_fs_cleanup(void)
+{
+ iput(luo_session_inode);
+ kern_unmount(luo_session_mnt);
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type
2026-04-20 14:15 ` [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type luca.boccassi
@ 2026-04-21 10:33 ` Mike Rapoport
2026-04-22 11:58 ` Christian Brauner
1 sibling, 0 replies; 14+ messages in thread
From: Mike Rapoport @ 2026-04-21 10:33 UTC (permalink / raw)
To: luca.boccassi
Cc: kexec, linux-mm, graf, pasha.tatashin, pratyush, brauner,
linux-kernel
On Mon, Apr 20, 2026 at 03:15:11PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> In userspace when managing LUO sessions we want to be able to identify
> a FD as a LUO session, in order to be able to do the special handling
> that they require in order to function as intended on kexec.
>
> Currently this requires scraping procfs and doing string matching on
> the prefix of the dname, which is not an ideal interface.
>
> Add a singleton inode type with a magic value, so that we can
> programmatically identify a fd as a LUO session via fstatfs().
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
> include/uapi/linux/magic.h | 1 +
> kernel/liveupdate/luo_core.c | 10 +++-
> kernel/liveupdate/luo_internal.h | 2 +
> kernel/liveupdate/luo_session.c | 91 ++++++++++++++++++++++++++++++--
> 4 files changed, 98 insertions(+), 6 deletions(-)
>
> diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
> index 4f2da935a76c..4f51005522ff 100644
> --- a/include/uapi/linux/magic.h
> +++ b/include/uapi/linux/magic.h
> @@ -105,5 +105,6 @@
> #define PID_FS_MAGIC 0x50494446 /* "PIDF" */
> #define GUEST_MEMFD_MAGIC 0x474d454d /* "GMEM" */
> #define NULL_FS_MAGIC 0x4E554C4C /* "NULL" */
> +#define LUO_SESSION_MAGIC 0x4c554f53 /* "LUOS" */
>
> #endif /* __LINUX_MAGIC_H__ */
> diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
> index dda7bb57d421..f1a63ebe4fa4 100644
> --- a/kernel/liveupdate/luo_core.c
> +++ b/kernel/liveupdate/luo_core.c
> @@ -197,9 +197,17 @@ static int __init luo_late_startup(void)
> if (!liveupdate_enabled())
> return 0;
>
> + err = luo_session_fs_init();
> + if (err) {
> + luo_global.enabled = false;
Please use goto here and on luo_fdt_setup() failure to handle cleanup on error.
Other than that
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> + return err;
> + }
> +
> err = luo_fdt_setup();
> - if (err)
> + if (err) {
> + luo_session_fs_cleanup();
> luo_global.enabled = false;
> + }
>
> return err;
> }
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type
2026-04-20 14:15 ` [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type luca.boccassi
2026-04-21 10:33 ` Mike Rapoport
@ 2026-04-22 11:58 ` Christian Brauner
1 sibling, 0 replies; 14+ messages in thread
From: Christian Brauner @ 2026-04-22 11:58 UTC (permalink / raw)
To: pasha.tatashin
Cc: kexec, linux-mm, graf, rppt, pratyush, linux-kernel,
luca.boccassi
On Mon, Apr 20, 2026 at 03:15:11PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> In userspace when managing LUO sessions we want to be able to identify
> a FD as a LUO session, in order to be able to do the special handling
> that they require in order to function as intended on kexec.
>
> Currently this requires scraping procfs and doing string matching on
> the prefix of the dname, which is not an ideal interface.
>
> Add a singleton inode type with a magic value, so that we can
> programmatically identify a fd as a LUO session via fstatfs().
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
Fold the following diff [1] into this commit (and the test), please.
Btw, I see that currently you only allow to retrieve one file per
session. If you ever want to allow multiple files for a session
but single shared inode amongst the same session so that different files
for the same session still compare as identical I added a mechanism
called path_from_stashed() which would easily allow for this. The luo
session just needs to stash a dentry pointer to achieve this. Just a
heads-up.
[1]:
From 7a11a931eaf4766e70c81d32093668ecd60f4952 Mon Sep 17 00:00:00 2001
From: Christian Brauner <brauner@kernel.org>
Date: Wed, 22 Apr 2026 12:41:25 +0200
Subject: [PATCH] liveupdate: allocate per-session inodes
The luo_session pseudo-fs handed every session the same singleton inode,
so fstat() on two session fds could not tell them apart. Give each
session its own inode via new_inode_pseudo(), with a unique cookie for
i_ino (and the upper bits in i_generation so 32-bit configs still get
distinct inode numbers).
Leave inode->i_fop unset. Session file descriptors must only come from
the LIVEUPDATE_IOCTL_{CREATE,RETRIEVE}_SESSION ioctls, so an unset i_fop
makes open() on /proc/<pid>/fd/N fail.
Lifetime continues to hang off file->private_data and the .release
callback; this patch only changes where the inode comes from.
Rename LUO_SESSION_MAGIC to LUO_FS_MAGIC and flip the session_fstat
selftest to assert distinct inode numbers.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
include/uapi/linux/magic.h | 2 +-
kernel/liveupdate/luo_session.c | 59 +++++++++++++------
.../testing/selftests/liveupdate/liveupdate.c | 13 ++--
3 files changed, 48 insertions(+), 26 deletions(-)
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index 4f51005522ff..afc3f935d00d 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -105,6 +105,6 @@
#define PID_FS_MAGIC 0x50494446 /* "PIDF" */
#define GUEST_MEMFD_MAGIC 0x474d454d /* "GMEM" */
#define NULL_FS_MAGIC 0x4E554C4C /* "NULL" */
-#define LUO_SESSION_MAGIC 0x4c554f53 /* "LUOS" */
+#define LUO_FS_MAGIC 0x4c554f53 /* "LUOS" */
#endif /* __LINUX_MAGIC_H__ */
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 885e1f346caa..2484feaf102a 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -51,6 +51,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cleanup.h>
+#include <linux/cookie.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/file.h>
@@ -380,17 +381,43 @@ static const struct file_operations luo_session_fops = {
};
static struct vfsmount *luo_session_mnt __ro_after_init;
-static struct inode *luo_session_inode __ro_after_init;
-/*
- * Reject all attribute changes on the singleton session inode.
- * Without this the VFS falls back to simple_setattr(), allowing
- * fchmod()/fchown() to modify the shared inode.
- */
+DEFINE_COOKIE(luo_session_cookie);
+
+static u64 luo_session_alloc_ino(void)
+{
+ guard(preempt)();
+ return gen_cookie_next(&luo_session_cookie);
+}
+
+/* .setattr rejects attribute changes to prevent fchmod()/fchown(). */
static const struct inode_operations luo_session_inode_operations = {
.setattr = anon_inode_setattr,
};
+static struct inode *luo_new_inode(struct super_block *sb)
+{
+ struct inode *inode;
+ u64 ino;
+
+ inode = new_inode_pseudo(sb);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ ino = luo_session_alloc_ino();
+ inode->i_ino = ino;
+ inode->i_generation = ino >> 32;
+ inode->i_flags |= S_IMMUTABLE | S_PRIVATE | S_ANON_INODE;
+ inode->i_mode |= S_IRUSR | S_IWUSR;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
+ inode->i_op = &luo_session_inode_operations;
+ /* i_fop left unset: session fds must not be reopenable via procfs. */
+ simple_inode_init_ts(inode);
+
+ return inode;
+}
+
static char *luo_session_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(buffer, buflen, "luo_session:[%s]",
@@ -410,7 +437,7 @@ static int luo_session_init_fs_context(struct fs_context *fc)
{
struct pseudo_fs_context *ctx;
- ctx = init_pseudo(fc, LUO_SESSION_MAGIC);
+ ctx = init_pseudo(fc, LUO_FS_MAGIC);
if (!ctx)
return -ENOMEM;
@@ -432,17 +459,20 @@ static struct file_system_type luo_session_fs_type = {
static int luo_session_getfile(struct luo_session *session, struct file **filep)
{
char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH + 1];
+ struct inode *inode;
struct file *file;
lockdep_assert_held(&session->mutex);
- ihold(luo_session_inode);
+ inode = luo_new_inode(luo_session_mnt->mnt_sb);
+ if (IS_ERR(inode))
+ return PTR_ERR(inode);
snprintf(name_buf, sizeof(name_buf), "%s", session->name);
- file = alloc_file_pseudo(luo_session_inode, luo_session_mnt, name_buf,
+ file = alloc_file_pseudo(inode, luo_session_mnt, name_buf,
O_RDWR, &luo_session_fops);
if (IS_ERR(file)) {
- iput(luo_session_inode);
+ iput(inode);
return PTR_ERR(file);
}
@@ -731,19 +761,10 @@ int __init luo_session_fs_init(void)
luo_session_mnt = kern_mount(&luo_session_fs_type);
if (IS_ERR(luo_session_mnt))
panic("Cannot create LUO Session pseudo-fs");
-
- luo_session_inode = alloc_anon_inode(luo_session_mnt->mnt_sb);
- if (IS_ERR(luo_session_inode)) {
- kern_unmount(luo_session_mnt);
- return PTR_ERR(luo_session_inode);
- }
- luo_session_inode->i_op = &luo_session_inode_operations;
-
return 0;
}
void __init luo_session_fs_cleanup(void)
{
- iput(luo_session_inode);
kern_unmount(luo_session_mnt);
}
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
index c21354dc9b93..34f3ecb21396 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -410,8 +410,9 @@ TEST_F(liveupdate_device, create_session_empty_name)
* Test Case: Session fstat
*
* Verifies that fstatfs() on a session file descriptor reports the
- * LUO_SESSION_MAGIC filesystem type, and that fstat() returns consistent
- * inode numbers across different sessions (shared singleton inode).
+ * LUO_FS_MAGIC filesystem type, and that fstat() returns distinct inode
+ * numbers across different sessions so userspace can compare two session
+ * file descriptors for equality using stat().
*/
TEST_F(liveupdate_device, session_fstat)
{
@@ -430,14 +431,14 @@ TEST_F(liveupdate_device, session_fstat)
session_fd2 = create_session(self->fd1, "fstat-session-2");
ASSERT_GE(session_fd2, 0);
- /* Verify the filesystem type is LUO_SESSION_MAGIC */
+ /* Verify the filesystem type is LUO_FS_MAGIC */
ASSERT_EQ(fstatfs(session_fd1, &sfs), 0);
- EXPECT_EQ(sfs.f_type, LUO_SESSION_MAGIC);
+ EXPECT_EQ(sfs.f_type, LUO_FS_MAGIC);
- /* Verify both sessions share the same inode number */
+ /* Each session has its own inode, so inode numbers must differ. */
ASSERT_EQ(fstat(session_fd1, &st1), 0);
ASSERT_EQ(fstat(session_fd2, &st2), 0);
- EXPECT_EQ(st1.st_ino, st2.st_ino);
+ EXPECT_NE(st1.st_ino, st2.st_ino);
ASSERT_EQ(close(session_fd1), 0);
ASSERT_EQ(close(session_fd2), 0);
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v9 4/6] selftests/liveupdate: add test case for LUO_SESSION_MAGIC
2026-04-20 14:15 [PATCH v9 0/6] liveupdate: new ioctl, change session inode type, bug fixes luca.boccassi
` (2 preceding siblings ...)
2026-04-20 14:15 ` [PATCH v9 3/6] liveupdate: add LUO_SESSION_MAGIC magic inode type luca.boccassi
@ 2026-04-20 14:15 ` luca.boccassi
2026-04-21 10:34 ` Mike Rapoport
2026-04-20 14:15 ` [PATCH v9 5/6] liveupdate: add LIVEUPDATE_SESSION_GET_NAME ioctl luca.boccassi
2026-04-20 14:15 ` [PATCH v9 6/6] selftests/liveupdate: add test cases for LIVEUPDATE_SESSION_GET_NAME luca.boccassi
5 siblings, 1 reply; 14+ messages in thread
From: luca.boccassi @ 2026-04-20 14:15 UTC (permalink / raw)
To: kexec
Cc: linux-mm, graf, rppt, pasha.tatashin, pratyush, brauner,
linux-kernel, Luca Boccassi
From: Luca Boccassi <luca.boccassi@gmail.com>
Verify that fstat works as expected after the switch from anon_inode
to the new magic number.
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
.../testing/selftests/liveupdate/liveupdate.c | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
index f0a8e600c154..5e99af0cc6e9 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -22,9 +22,12 @@
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
#include <unistd.h>
#include <linux/liveupdate.h>
+#include <linux/magic.h>
#include "../kselftest.h"
#include "../kselftest_harness.h"
@@ -387,4 +390,41 @@ TEST_F(liveupdate_device, create_session_empty_name)
EXPECT_EQ(session_fd, -EINVAL);
}
+/*
+ * Test Case: Session fstat
+ *
+ * Verifies that fstatfs() on a session file descriptor reports the
+ * LUO_SESSION_MAGIC filesystem type, and that fstat() returns consistent
+ * inode numbers across different sessions (shared singleton inode).
+ */
+TEST_F(liveupdate_device, session_fstat)
+{
+ int session_fd1, session_fd2;
+ struct stat st1, st2;
+ struct statfs sfs;
+
+ 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_fd1 = create_session(self->fd1, "fstat-session-1");
+ ASSERT_GE(session_fd1, 0);
+
+ session_fd2 = create_session(self->fd1, "fstat-session-2");
+ ASSERT_GE(session_fd2, 0);
+
+ /* Verify the filesystem type is LUO_SESSION_MAGIC */
+ ASSERT_EQ(fstatfs(session_fd1, &sfs), 0);
+ EXPECT_EQ(sfs.f_type, LUO_SESSION_MAGIC);
+
+ /* Verify both sessions share the same inode number */
+ ASSERT_EQ(fstat(session_fd1, &st1), 0);
+ ASSERT_EQ(fstat(session_fd2, &st2), 0);
+ EXPECT_EQ(st1.st_ino, st2.st_ino);
+
+ ASSERT_EQ(close(session_fd1), 0);
+ ASSERT_EQ(close(session_fd2), 0);
+}
+
TEST_HARNESS_MAIN
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v9 4/6] selftests/liveupdate: add test case for LUO_SESSION_MAGIC
2026-04-20 14:15 ` [PATCH v9 4/6] selftests/liveupdate: add test case for LUO_SESSION_MAGIC luca.boccassi
@ 2026-04-21 10:34 ` Mike Rapoport
0 siblings, 0 replies; 14+ messages in thread
From: Mike Rapoport @ 2026-04-21 10:34 UTC (permalink / raw)
To: luca.boccassi
Cc: kexec, linux-mm, graf, pasha.tatashin, pratyush, brauner,
linux-kernel
On Mon, Apr 20, 2026 at 03:15:12PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> Verify that fstat works as expected after the switch from anon_inode
> to the new magic number.
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> .../testing/selftests/liveupdate/liveupdate.c | 40 +++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
> index f0a8e600c154..5e99af0cc6e9 100644
> --- a/tools/testing/selftests/liveupdate/liveupdate.c
> +++ b/tools/testing/selftests/liveupdate/liveupdate.c
> @@ -22,9 +22,12 @@
> #include <fcntl.h>
> #include <string.h>
> #include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <sys/vfs.h>
> #include <unistd.h>
>
> #include <linux/liveupdate.h>
> +#include <linux/magic.h>
>
> #include "../kselftest.h"
> #include "../kselftest_harness.h"
> @@ -387,4 +390,41 @@ TEST_F(liveupdate_device, create_session_empty_name)
> EXPECT_EQ(session_fd, -EINVAL);
> }
>
> +/*
> + * Test Case: Session fstat
> + *
> + * Verifies that fstatfs() on a session file descriptor reports the
> + * LUO_SESSION_MAGIC filesystem type, and that fstat() returns consistent
> + * inode numbers across different sessions (shared singleton inode).
> + */
> +TEST_F(liveupdate_device, session_fstat)
> +{
> + int session_fd1, session_fd2;
> + struct stat st1, st2;
> + struct statfs sfs;
> +
> + 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_fd1 = create_session(self->fd1, "fstat-session-1");
> + ASSERT_GE(session_fd1, 0);
> +
> + session_fd2 = create_session(self->fd1, "fstat-session-2");
> + ASSERT_GE(session_fd2, 0);
> +
> + /* Verify the filesystem type is LUO_SESSION_MAGIC */
> + ASSERT_EQ(fstatfs(session_fd1, &sfs), 0);
> + EXPECT_EQ(sfs.f_type, LUO_SESSION_MAGIC);
> +
> + /* Verify both sessions share the same inode number */
> + ASSERT_EQ(fstat(session_fd1, &st1), 0);
> + ASSERT_EQ(fstat(session_fd2, &st2), 0);
> + EXPECT_EQ(st1.st_ino, st2.st_ino);
> +
> + ASSERT_EQ(close(session_fd1), 0);
> + ASSERT_EQ(close(session_fd2), 0);
> +}
> +
> TEST_HARNESS_MAIN
> --
> 2.47.3
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 5/6] liveupdate: add LIVEUPDATE_SESSION_GET_NAME ioctl
2026-04-20 14:15 [PATCH v9 0/6] liveupdate: new ioctl, change session inode type, bug fixes luca.boccassi
` (3 preceding siblings ...)
2026-04-20 14:15 ` [PATCH v9 4/6] selftests/liveupdate: add test case for LUO_SESSION_MAGIC luca.boccassi
@ 2026-04-20 14:15 ` luca.boccassi
2026-04-21 10:34 ` Mike Rapoport
2026-04-20 14:15 ` [PATCH v9 6/6] selftests/liveupdate: add test cases for LIVEUPDATE_SESSION_GET_NAME luca.boccassi
5 siblings, 1 reply; 14+ messages in thread
From: luca.boccassi @ 2026-04-20 14:15 UTC (permalink / raw)
To: kexec
Cc: linux-mm, graf, rppt, pasha.tatashin, pratyush, brauner,
linux-kernel, Luca Boccassi
From: Luca Boccassi <luca.boccassi@gmail.com>
Userspace when requesting a session via the ioctl specifies a name and
gets a FD, but then there is no ioctl to go back the other way and get
the name given a LUO session FD. This is problematic especially when
there is a userspace orchestrator that wants to check what FDs it is
handling for clients without having to do manual string scraping of
procfs, or without procfs at all.
Add a ioctl to simply get the name from an FD.
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
include/uapi/linux/liveupdate.h | 21 +++++++++++++++++++++
kernel/liveupdate/luo_session.c | 13 +++++++++++++
2 files changed, 34 insertions(+)
diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
index 30bc66ee9436..3a9ff53b02e0 100644
--- a/include/uapi/linux/liveupdate.h
+++ b/include/uapi/linux/liveupdate.h
@@ -59,6 +59,7 @@ enum {
LIVEUPDATE_CMD_SESSION_PRESERVE_FD = LIVEUPDATE_CMD_SESSION_BASE,
LIVEUPDATE_CMD_SESSION_RETRIEVE_FD = 0x41,
LIVEUPDATE_CMD_SESSION_FINISH = 0x42,
+ LIVEUPDATE_CMD_SESSION_GET_NAME = 0x43,
};
/**
@@ -213,4 +214,24 @@ struct liveupdate_session_finish {
#define LIVEUPDATE_SESSION_FINISH \
_IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_FINISH)
+/**
+ * struct liveupdate_session_get_name - ioctl(LIVEUPDATE_SESSION_GET_NAME)
+ * @size: Input; sizeof(struct liveupdate_session_get_name)
+ * @reserved: Input; Must be zero. Reserved for future use.
+ * @name: Output; A null-terminated string with the full session name.
+ *
+ * Retrieves the full name of the session associated with this file descriptor.
+ * This is useful because the kernel may truncate the name shown in /proc.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+struct liveupdate_session_get_name {
+ __u32 size;
+ __u32 reserved;
+ __u8 name[LIVEUPDATE_SESSION_NAME_LENGTH];
+};
+
+#define LIVEUPDATE_SESSION_GET_NAME \
+ _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_GET_NAME)
+
#endif /* _UAPI_LIVEUPDATE_H */
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 9e343b6ce513..885e1f346caa 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -292,10 +292,21 @@ static int luo_session_finish(struct luo_session *session,
return luo_ucmd_respond(ucmd, sizeof(*argp));
}
+static int luo_session_get_name(struct luo_session *session,
+ struct luo_ucmd *ucmd)
+{
+ struct liveupdate_session_get_name *argp = ucmd->cmd;
+
+ strscpy((char *)argp->name, session->name, sizeof(argp->name));
+
+ return luo_ucmd_respond(ucmd, sizeof(*argp));
+}
+
union ucmd_buffer {
struct liveupdate_session_finish finish;
struct liveupdate_session_preserve_fd preserve;
struct liveupdate_session_retrieve_fd retrieve;
+ struct liveupdate_session_get_name get_name;
};
struct luo_ioctl_op {
@@ -322,6 +333,8 @@ static const struct luo_ioctl_op luo_session_ioctl_ops[] = {
struct liveupdate_session_preserve_fd, token),
IOCTL_OP(LIVEUPDATE_SESSION_RETRIEVE_FD, luo_session_retrieve_fd,
struct liveupdate_session_retrieve_fd, token),
+ IOCTL_OP(LIVEUPDATE_SESSION_GET_NAME, luo_session_get_name,
+ struct liveupdate_session_get_name, name),
};
static long luo_session_ioctl(struct file *filep, unsigned int cmd,
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v9 5/6] liveupdate: add LIVEUPDATE_SESSION_GET_NAME ioctl
2026-04-20 14:15 ` [PATCH v9 5/6] liveupdate: add LIVEUPDATE_SESSION_GET_NAME ioctl luca.boccassi
@ 2026-04-21 10:34 ` Mike Rapoport
0 siblings, 0 replies; 14+ messages in thread
From: Mike Rapoport @ 2026-04-21 10:34 UTC (permalink / raw)
To: luca.boccassi
Cc: kexec, linux-mm, graf, pasha.tatashin, pratyush, brauner,
linux-kernel
On Mon, Apr 20, 2026 at 03:15:13PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> Userspace when requesting a session via the ioctl specifies a name and
> gets a FD, but then there is no ioctl to go back the other way and get
> the name given a LUO session FD. This is problematic especially when
> there is a userspace orchestrator that wants to check what FDs it is
> handling for clients without having to do manual string scraping of
> procfs, or without procfs at all.
>
> Add a ioctl to simply get the name from an FD.
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/uapi/linux/liveupdate.h | 21 +++++++++++++++++++++
> kernel/liveupdate/luo_session.c | 13 +++++++++++++
> 2 files changed, 34 insertions(+)
>
> diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdate.h
> index 30bc66ee9436..3a9ff53b02e0 100644
> --- a/include/uapi/linux/liveupdate.h
> +++ b/include/uapi/linux/liveupdate.h
> @@ -59,6 +59,7 @@ enum {
> LIVEUPDATE_CMD_SESSION_PRESERVE_FD = LIVEUPDATE_CMD_SESSION_BASE,
> LIVEUPDATE_CMD_SESSION_RETRIEVE_FD = 0x41,
> LIVEUPDATE_CMD_SESSION_FINISH = 0x42,
> + LIVEUPDATE_CMD_SESSION_GET_NAME = 0x43,
> };
>
> /**
> @@ -213,4 +214,24 @@ struct liveupdate_session_finish {
> #define LIVEUPDATE_SESSION_FINISH \
> _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_FINISH)
>
> +/**
> + * struct liveupdate_session_get_name - ioctl(LIVEUPDATE_SESSION_GET_NAME)
> + * @size: Input; sizeof(struct liveupdate_session_get_name)
> + * @reserved: Input; Must be zero. Reserved for future use.
> + * @name: Output; A null-terminated string with the full session name.
> + *
> + * Retrieves the full name of the session associated with this file descriptor.
> + * This is useful because the kernel may truncate the name shown in /proc.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +struct liveupdate_session_get_name {
> + __u32 size;
> + __u32 reserved;
> + __u8 name[LIVEUPDATE_SESSION_NAME_LENGTH];
> +};
> +
> +#define LIVEUPDATE_SESSION_GET_NAME \
> + _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_GET_NAME)
> +
> #endif /* _UAPI_LIVEUPDATE_H */
> diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
> index 9e343b6ce513..885e1f346caa 100644
> --- a/kernel/liveupdate/luo_session.c
> +++ b/kernel/liveupdate/luo_session.c
> @@ -292,10 +292,21 @@ static int luo_session_finish(struct luo_session *session,
> return luo_ucmd_respond(ucmd, sizeof(*argp));
> }
>
> +static int luo_session_get_name(struct luo_session *session,
> + struct luo_ucmd *ucmd)
> +{
> + struct liveupdate_session_get_name *argp = ucmd->cmd;
> +
> + strscpy((char *)argp->name, session->name, sizeof(argp->name));
> +
> + return luo_ucmd_respond(ucmd, sizeof(*argp));
> +}
> +
> union ucmd_buffer {
> struct liveupdate_session_finish finish;
> struct liveupdate_session_preserve_fd preserve;
> struct liveupdate_session_retrieve_fd retrieve;
> + struct liveupdate_session_get_name get_name;
> };
>
> struct luo_ioctl_op {
> @@ -322,6 +333,8 @@ static const struct luo_ioctl_op luo_session_ioctl_ops[] = {
> struct liveupdate_session_preserve_fd, token),
> IOCTL_OP(LIVEUPDATE_SESSION_RETRIEVE_FD, luo_session_retrieve_fd,
> struct liveupdate_session_retrieve_fd, token),
> + IOCTL_OP(LIVEUPDATE_SESSION_GET_NAME, luo_session_get_name,
> + struct liveupdate_session_get_name, name),
> };
>
> static long luo_session_ioctl(struct file *filep, unsigned int cmd,
> --
> 2.47.3
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 6/6] selftests/liveupdate: add test cases for LIVEUPDATE_SESSION_GET_NAME
2026-04-20 14:15 [PATCH v9 0/6] liveupdate: new ioctl, change session inode type, bug fixes luca.boccassi
` (4 preceding siblings ...)
2026-04-20 14:15 ` [PATCH v9 5/6] liveupdate: add LIVEUPDATE_SESSION_GET_NAME ioctl luca.boccassi
@ 2026-04-20 14:15 ` luca.boccassi
2026-04-21 10:34 ` Mike Rapoport
5 siblings, 1 reply; 14+ messages in thread
From: luca.boccassi @ 2026-04-20 14:15 UTC (permalink / raw)
To: kexec
Cc: linux-mm, graf, rppt, pasha.tatashin, pratyush, brauner,
linux-kernel, Luca Boccassi
From: Luca Boccassi <luca.boccassi@gmail.com>
Verify that the new LIVEUPDATE_SESSION_GET_NAME ioctl works
as expected via new test cases in the existing liveupdate selftest.
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
.../testing/selftests/liveupdate/liveupdate.c | 71 +++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
index 5e99af0cc6e9..c21354dc9b93 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -105,6 +105,22 @@ static int create_session(int lu_fd, const char *name)
return args.fd;
}
+/* Helper function to get a session name via ioctl. */
+static int get_session_name(int session_fd, char *name, size_t name_len)
+{
+ struct liveupdate_session_get_name args = {};
+
+ args.size = sizeof(args);
+
+ if (ioctl(session_fd, LIVEUPDATE_SESSION_GET_NAME, &args))
+ return -errno;
+
+ strncpy(name, (char *)args.name, name_len - 1);
+ name[name_len - 1] = '\0';
+
+ return 0;
+}
+
/*
* Test Case: Create Duplicate Session
*
@@ -427,4 +443,59 @@ TEST_F(liveupdate_device, session_fstat)
ASSERT_EQ(close(session_fd2), 0);
}
+/*
+ * Test Case: Get Session Name
+ *
+ * Verifies that the full session name can be retrieved from a session file
+ * descriptor via ioctl.
+ */
+TEST_F(liveupdate_device, get_session_name)
+{
+ char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
+ const char *session_name = "get-name-test-session";
+ int session_fd;
+
+ 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 = create_session(self->fd1, session_name);
+ ASSERT_GE(session_fd, 0);
+
+ ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
+ ASSERT_STREQ(name_buf, session_name);
+
+ ASSERT_EQ(close(session_fd), 0);
+}
+
+/*
+ * Test Case: Get Session Name at Maximum Length
+ *
+ * Verifies that a session name using the full LIVEUPDATE_SESSION_NAME_LENGTH
+ * (minus the null terminator) can be correctly retrieved.
+ */
+TEST_F(liveupdate_device, get_session_name_max_length)
+{
+ char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
+ char long_name[LIVEUPDATE_SESSION_NAME_LENGTH];
+ int session_fd;
+
+ memset(long_name, 'A', sizeof(long_name) - 1);
+ long_name[sizeof(long_name) - 1] = '\0';
+
+ 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 = create_session(self->fd1, long_name);
+ ASSERT_GE(session_fd, 0);
+
+ ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
+ ASSERT_STREQ(name_buf, long_name);
+
+ ASSERT_EQ(close(session_fd), 0);
+}
+
TEST_HARNESS_MAIN
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v9 6/6] selftests/liveupdate: add test cases for LIVEUPDATE_SESSION_GET_NAME
2026-04-20 14:15 ` [PATCH v9 6/6] selftests/liveupdate: add test cases for LIVEUPDATE_SESSION_GET_NAME luca.boccassi
@ 2026-04-21 10:34 ` Mike Rapoport
0 siblings, 0 replies; 14+ messages in thread
From: Mike Rapoport @ 2026-04-21 10:34 UTC (permalink / raw)
To: luca.boccassi
Cc: kexec, linux-mm, graf, pasha.tatashin, pratyush, brauner,
linux-kernel
On Mon, Apr 20, 2026 at 03:15:14PM +0100, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> Verify that the new LIVEUPDATE_SESSION_GET_NAME ioctl works
> as expected via new test cases in the existing liveupdate selftest.
>
> Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> .../testing/selftests/liveupdate/liveupdate.c | 71 +++++++++++++++++++
> 1 file changed, 71 insertions(+)
>
> diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
> index 5e99af0cc6e9..c21354dc9b93 100644
> --- a/tools/testing/selftests/liveupdate/liveupdate.c
> +++ b/tools/testing/selftests/liveupdate/liveupdate.c
> @@ -105,6 +105,22 @@ static int create_session(int lu_fd, const char *name)
> return args.fd;
> }
>
> +/* Helper function to get a session name via ioctl. */
> +static int get_session_name(int session_fd, char *name, size_t name_len)
> +{
> + struct liveupdate_session_get_name args = {};
> +
> + args.size = sizeof(args);
> +
> + if (ioctl(session_fd, LIVEUPDATE_SESSION_GET_NAME, &args))
> + return -errno;
> +
> + strncpy(name, (char *)args.name, name_len - 1);
> + name[name_len - 1] = '\0';
> +
> + return 0;
> +}
> +
> /*
> * Test Case: Create Duplicate Session
> *
> @@ -427,4 +443,59 @@ TEST_F(liveupdate_device, session_fstat)
> ASSERT_EQ(close(session_fd2), 0);
> }
>
> +/*
> + * Test Case: Get Session Name
> + *
> + * Verifies that the full session name can be retrieved from a session file
> + * descriptor via ioctl.
> + */
> +TEST_F(liveupdate_device, get_session_name)
> +{
> + char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
> + const char *session_name = "get-name-test-session";
> + int session_fd;
> +
> + 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 = create_session(self->fd1, session_name);
> + ASSERT_GE(session_fd, 0);
> +
> + ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
> + ASSERT_STREQ(name_buf, session_name);
> +
> + ASSERT_EQ(close(session_fd), 0);
> +}
> +
> +/*
> + * Test Case: Get Session Name at Maximum Length
> + *
> + * Verifies that a session name using the full LIVEUPDATE_SESSION_NAME_LENGTH
> + * (minus the null terminator) can be correctly retrieved.
> + */
> +TEST_F(liveupdate_device, get_session_name_max_length)
> +{
> + char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
> + char long_name[LIVEUPDATE_SESSION_NAME_LENGTH];
> + int session_fd;
> +
> + memset(long_name, 'A', sizeof(long_name) - 1);
> + long_name[sizeof(long_name) - 1] = '\0';
> +
> + 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 = create_session(self->fd1, long_name);
> + ASSERT_GE(session_fd, 0);
> +
> + ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
> + ASSERT_STREQ(name_buf, long_name);
> +
> + ASSERT_EQ(close(session_fd), 0);
> +}
> +
> TEST_HARNESS_MAIN
> --
> 2.47.3
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 14+ messages in thread