Linux userland API discussions
 help / color / mirror / Atom feed
* Re: [PATCH v6 6/9] futex: Wire up get_robust_list2 syscall
From: Arnd Bergmann @ 2025-11-23 19:19 UTC (permalink / raw)
  To: Thomas Gleixner, kernel test robot, André Almeida,
	Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
	Sebastian Andrzej Siewior, Waiman Long, Ryan Houdek
  Cc: oe-kbuild-all, linux-kernel, linux-kselftest, linux-api,
	kernel-dev
In-Reply-To: <87ms4cio14.ffs@tglx>

On Sun, Nov 23, 2025, at 19:47, Thomas Gleixner wrote:
> On Sat, Nov 22 2025 at 14:49, kernel test robot wrote:
>> kernel test robot noticed the following build warnings:
>>
>> [auto build test WARNING on c42ba5a87bdccbca11403b7ca8bad1a57b833732]
>>
>> url:    https://github.com/intel-lab-lkp/linux/commits/Andr-Almeida/futex-Use-explicit-sizes-for-compat_robust_list-structs/20251122-135406
>> base:   c42ba5a87bdccbca11403b7ca8bad1a57b833732
>> patch link:    https://lore.kernel.org/r/20251122-tonyk-robust_futex-v6-6-05fea005a0fd%40igalia.com
>> patch subject: [PATCH v6 6/9] futex: Wire up get_robust_list2 syscall
>> config: arc-allnoconfig (https://download.01.org/0day-ci/archive/20251122/202511221454.rsysOoSt-lkp@intel.com/config)
>> compiler: arc-linux-gcc (GCC) 15.1.0
>> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511221454.rsysOoSt-lkp@intel.com/reproduce)
>>
>> If you fix the issue in a separate patch/commit (i.e. not just a new version of
>> the same patch/commit), kindly add following tags
>> | Reported-by: kernel test robot <lkp@intel.com>
>> | Closes: https://lore.kernel.org/oe-kbuild-all/202511221454.rsysOoSt-lkp@intel.com/
>>
>> All warnings (new ones prefixed by >>):
>>
>>>> <stdin>:1627:2: warning: #warning syscall get_robust_list2 not implemented [-Wcpp]
>> --
>>>> <stdin>:1627:2: warning: #warning syscall get_robust_list2 not implemented [-Wcpp]
>
> Lacks a COND_SYSCALL()

No, it's actually

scripts/syscall.tbl

that is missing, which means that the newer architectures
are missing the update. This used to be include/uapi/asm/unistd.h,
which still exists but is now unused.

     Arnd

^ permalink raw reply

* Re: [PATCH v7 05/22] liveupdate: luo_core: add user interface
From: Pasha Tatashin @ 2025-11-23 19:25 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <aSMX_pnUShilO_sj@kernel.org>

On Sun, Nov 23, 2025 at 9:20 AM Mike Rapoport <rppt@kernel.org> wrote:
>
> On Sat, Nov 22, 2025 at 05:23:32PM -0500, Pasha Tatashin wrote:
> > Introduce the user-space interface for the Live Update Orchestrator
> > via ioctl commands, enabling external control over the live update
> > process and management of preserved resources.
> >
> > The idea is that there is going to be a single userspace agent driving
> > the live update, therefore, only a single process can ever hold this
> > device opened at a time.
> >
> > The following ioctl commands are introduced:
> >
> > LIVEUPDATE_IOCTL_CREATE_SESSION
> > Provides a way for userspace to create a named session for grouping file
> > descriptors that need to be preserved. It returns a new file descriptor
> > representing the session.
> >
> > LIVEUPDATE_IOCTL_RETRIEVE_SESSION
> > Allows the userspace agent in the new kernel to reclaim a preserved
> > session by its name, receiving a new file descriptor to manage the
> > restored resources.
> >
> > Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

Thanks

>
> > ---
> >  include/uapi/linux/liveupdate.h  |  64 +++++++++++
> >  kernel/liveupdate/luo_core.c     | 179 ++++++++++++++++++++++++++++++-
> >  kernel/liveupdate/luo_internal.h |  21 ++++
> >  3 files changed, 263 insertions(+), 1 deletion(-)
>
> --
> Sincerely yours,
> Mike.

^ permalink raw reply

* Re: [PATCH v7 08/22] docs: add luo documentation
From: Pasha Tatashin @ 2025-11-23 19:29 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <aSMwsLstAutayHbC@kernel.org>

On Sun, Nov 23, 2025 at 11:05 AM Mike Rapoport <rppt@kernel.org> wrote:
>
> On Sat, Nov 22, 2025 at 05:23:35PM -0500, Pasha Tatashin wrote:
> > Add the documentation files for the Live Update Orchestrator
> >
> > Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> > ---
>
> > +Public API
> > +==========
> > +.. kernel-doc:: include/linux/liveupdate.h
> > +
> > +.. kernel-doc:: include/linux/kho/abi/luo.h
>
> Please add
>
>    :functions:
>
> here, otherwise "DOC: Live Update Orchestrator ABI" is repeated here as
> well in the generated html.

Done, thanks!

>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
>
> --
> Sincerely yours,
> Mike.

^ permalink raw reply

* Re: [PATCH v7 11/22] mm: shmem: allow freezing inode mapping
From: Pasha Tatashin @ 2025-11-23 19:43 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <aSMoRRtanMkHo9Tr@kernel.org>

On Sun, Nov 23, 2025 at 10:29 AM Mike Rapoport <rppt@kernel.org> wrote:
>
> On Sat, Nov 22, 2025 at 05:23:38PM -0500, Pasha Tatashin wrote:
> > From: Pratyush Yadav <ptyadav@amazon.de>
> >
> > To prepare a shmem inode for live update, its index -> folio mappings
> > must be serialized. Once the mappings are serialized, they cannot change
> > since it would cause the serialized data to become inconsistent. This
> > can be done by pinning the folios to avoid migration, and by making sure
> > no folios can be added to or removed from the inode.
> >
> > While mechanisms to pin folios already exist, the only way to stop
> > folios being added or removed are the grow and shrink file seals. But
> > file seals come with their own semantics, one of which is that they
> > can't be removed. This doesn't work with liveupdate since it can be
> > cancelled or error out, which would need the seals to be removed and the
> > file's normal functionality to be restored.
> >
> > Introduce SHMEM_F_MAPPING_FROZEN to indicate this instead. It is
> > internal to shmem and is not directly exposed to userspace. It functions
> > similar to F_SEAL_GROW | F_SEAL_SHRINK, but additionally disallows hole
> > punching, and can be removed.
> >
> > Signed-off-by: Pratyush Yadav <ptyadav@amazon.de>
> > Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> > ---
> >  include/linux/shmem_fs.h | 17 +++++++++++++++++
> >  mm/shmem.c               | 19 ++++++++++++++++---
> >  2 files changed, 33 insertions(+), 3 deletions(-)
> >
> > diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> > index 650874b400b5..d34a64eafe60 100644
> > --- a/include/linux/shmem_fs.h
> > +++ b/include/linux/shmem_fs.h
> > @@ -24,6 +24,14 @@ struct swap_iocb;
> >  #define SHMEM_F_NORESERVE    BIT(0)
> >  /* Disallow swapping. */
> >  #define SHMEM_F_LOCKED               BIT(1)
> > +/*
> > + * Disallow growing, shrinking, or hole punching in the inode. Combined with
> > + * folio pinning, makes sure the inode's mapping stays fixed.
> > + *
> > + * In some ways similar to F_SEAL_GROW | F_SEAL_SHRINK, but can be removed and
> > + * isn't directly visible to userspace.
> > + */
> > +#define SHMEM_F_MAPPING_FROZEN       BIT(2)
> >
> >  struct shmem_inode_info {
> >       spinlock_t              lock;
> > @@ -186,6 +194,15 @@ static inline bool shmem_file(struct file *file)
> >       return shmem_mapping(file->f_mapping);
> >  }
> >
> > +/* Must be called with inode lock taken exclusive. */
> > +static inline void shmem_freeze(struct inode *inode, bool freeze)
> > +{
> > +     if (freeze)
> > +             SHMEM_I(inode)->flags |= SHMEM_F_MAPPING_FROZEN;
> > +     else
> > +             SHMEM_I(inode)->flags &= ~SHMEM_F_MAPPING_FROZEN;
> > +}
> > +
> >  /*
> >   * If fallocate(FALLOC_FL_KEEP_SIZE) has been used, there may be pages
> >   * beyond i_size's notion of EOF, which fallocate has committed to reserving:
> > diff --git a/mm/shmem.c b/mm/shmem.c
> > index 1d5036dec08a..cb74a5d202ac 100644
> > --- a/mm/shmem.c
> > +++ b/mm/shmem.c
> > @@ -1292,9 +1292,13 @@ static int shmem_setattr(struct mnt_idmap *idmap,
> >               loff_t newsize = attr->ia_size;
> >
> >               /* protected by i_rwsem */
> > -             if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
> > -                 (newsize > oldsize && (info->seals & F_SEAL_GROW)))
> > -                     return -EPERM;
> > +             if (newsize != oldsize) {
> > +                     if (info->flags & SHMEM_F_MAPPING_FROZEN)
> > +                             return -EPERM;
> > +                     if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
> > +                         (newsize > oldsize && (info->seals & F_SEAL_GROW)))
> > +                             return -EPERM;
> > +             }
> >
> >               if (newsize != oldsize) {
>
> I'd stick
>
>                         if (info->flags & SHMEM_F_MAPPING_FROZEN)
>                                 return -EPERM;
>
> here and leave the seals check alone.

Done.

>
> Other than than
>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

Thanks.

>
> --
> Sincerely yours,
> Mike.

^ permalink raw reply

* Re: [PATCH v6 6/9] futex: Wire up get_robust_list2 syscall
From: Thomas Gleixner @ 2025-11-23 20:02 UTC (permalink / raw)
  To: Arnd Bergmann, kernel test robot, André Almeida, Ingo Molnar,
	Peter Zijlstra, Darren Hart, Davidlohr Bueso,
	Sebastian Andrzej Siewior, Waiman Long, Ryan Houdek
  Cc: oe-kbuild-all, linux-kernel, linux-kselftest, linux-api,
	kernel-dev
In-Reply-To: <326957b0-fbce-4850-a8fb-8eed90fc4fae@app.fastmail.com>

On Sun, Nov 23 2025 at 20:19, Arnd Bergmann wrote:
> On Sun, Nov 23, 2025, at 19:47, Thomas Gleixner wrote:
>> On Sat, Nov 22 2025 at 14:49, kernel test robot wrote:
>>> kernel test robot noticed the following build warnings:
>>>
>>> [auto build test WARNING on c42ba5a87bdccbca11403b7ca8bad1a57b833732]
>>>
>>> url:    https://github.com/intel-lab-lkp/linux/commits/Andr-Almeida/futex-Use-explicit-sizes-for-compat_robust_list-structs/20251122-135406
>>> base:   c42ba5a87bdccbca11403b7ca8bad1a57b833732
>>> patch link:    https://lore.kernel.org/r/20251122-tonyk-robust_futex-v6-6-05fea005a0fd%40igalia.com
>>> patch subject: [PATCH v6 6/9] futex: Wire up get_robust_list2 syscall
>>> config: arc-allnoconfig (https://download.01.org/0day-ci/archive/20251122/202511221454.rsysOoSt-lkp@intel.com/config)
>>> compiler: arc-linux-gcc (GCC) 15.1.0
>>> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511221454.rsysOoSt-lkp@intel.com/reproduce)
>>>
>>> If you fix the issue in a separate patch/commit (i.e. not just a new version of
>>> the same patch/commit), kindly add following tags
>>> | Reported-by: kernel test robot <lkp@intel.com>
>>> | Closes: https://lore.kernel.org/oe-kbuild-all/202511221454.rsysOoSt-lkp@intel.com/
>>>
>>> All warnings (new ones prefixed by >>):
>>>
>>>>> <stdin>:1627:2: warning: #warning syscall get_robust_list2 not implemented [-Wcpp]
>>> --
>>>>> <stdin>:1627:2: warning: #warning syscall get_robust_list2 not implemented [-Wcpp]
>>
>> Lacks a COND_SYSCALL()
>
> No, it's actually
>
> scripts/syscall.tbl
>
> that is missing, which means that the newer architectures
> are missing the update. This used to be include/uapi/asm/unistd.h,
> which still exists but is now unused.

So it's both. That syscall depends on CONFIG_FUTEX, which means
COND_SYCALL() is required and it's actually added in patch 9/9 while 5/9
which adds the set() variant adds it right away :)

Thanks,

        tglx

^ permalink raw reply

* Re: [PATCH v7 14/22] mm: memfd_luo: allow preserving memfd
From: Pasha Tatashin @ 2025-11-24  3:13 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <aSMsqD5mB2mHHH9v@kernel.org>

> > +unlock_folio:
> > +     folio_unlock(folio);
> > +     folio_put(folio);
> > +     i++;
>
> I'd add a counter and use it int the below for loop.

Done.

>
> > +put_folios:
> > +     /*
> > +      * Note: don't free the folios already added to the file. They will be
> > +      * freed when the file is freed. Free the ones not added yet here.
> > +      */
> > +     for (; i < nr_folios; i++) {
> > +             const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
> > +
> > +             folio = kho_restore_folio(pfolio->pfn);
> > +             if (folio)
> > +                     folio_put(folio);
> > +     }
> > +
> > +     return err;
> > +}
>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

Thanks!

Pasha

>
> --
> Sincerely yours,
> Mike.

^ permalink raw reply

* Re: [PATCH v7 01/22] liveupdate: luo_core: Live Update Orchestrator
From: Mike Rapoport @ 2025-11-24  5:07 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <CA+CK2bCN7x=eMwfTXF-2+vR=Gn3=41z6Xxx6wM1m7i-rxzug9w@mail.gmail.com>

On Sun, Nov 23, 2025 at 07:15:44AM -0500, Pasha Tatashin wrote:
> On Sun, Nov 23, 2025 at 6:12 AM Mike Rapoport <rppt@kernel.org> wrote:
> >
> > On Sat, Nov 22, 2025 at 05:23:28PM -0500, Pasha Tatashin wrote:
> > > Introduce LUO, a mechanism intended to facilitate kernel updates while
> > > keeping designated devices operational across the transition (e.g., via
> > > kexec). The primary use case is updating hypervisors with minimal
> > > disruption to running virtual machines. For userspace side of hypervisor
> > > update we have copyless migration. LUO is for updating the kernel.
> > >
> > > This initial patch lays the groundwork for the LUO subsystem.
> > >
> > > Further functionality, including the implementation of state transition
> > > logic, integration with KHO, and hooks for subsystems and file
> > > descriptors, will be added in subsequent patches.
> > >
> > > Create a character device at /dev/liveupdate.
> > >
> > > A new uAPI header, <uapi/linux/liveupdate.h>, will define the necessary
> > > structures. The magic number for IOCTL is registered in
> > > Documentation/userspace-api/ioctl/ioctl-number.rst.
> > >
> > > Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> > > Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
> >
> > Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> 
> Thank you
> 
> >
> > with a few nits below
> >
> > > ---
> >
> > > diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig
> > > index a973a54447de..90857dccb359 100644
> > > --- a/kernel/liveupdate/Kconfig
> > > +++ b/kernel/liveupdate/Kconfig
> > > @@ -1,4 +1,10 @@
> > >  # SPDX-License-Identifier: GPL-2.0-only
> > > +#
> > > +# Copyright (c) 2025, Google LLC.
> > > +# Pasha Tatashin <pasha.tatashin@soleen.com>
> > > +#
> > > +# Live Update Orchestrator
> > > +#
> >
> > If you are adding copyrights it should have Amazon and Microsoft as well.
> > I believe those from kexec_handover.c would work.
> >
> > @Alex?
> 
> Sure, or I can remove all of them from Kconfig, whatever you prefer :-)

Quick grepping shows that the vast majority of Kconfigs does not have
copyright, let's just drop it.

> > >  menu "Live Update and Kexec HandOver"
> > >       depends on !DEFERRED_STRUCT_PAGE_INIT
> > > @@ -51,4 +57,25 @@ config KEXEC_HANDOVER_ENABLE_DEFAULT
> > >         The default behavior can still be overridden at boot time by
> > >         passing 'kho=off'.
> > >
> > > +config LIVEUPDATE
> > > +     bool "Live Update Orchestrator"
> > > +     depends on KEXEC_HANDOVER
> > > +     help
> > > +       Enable the Live Update Orchestrator. Live Update is a mechanism,
> > > +       typically based on kexec, that allows the kernel to be updated
> > > +       while keeping selected devices operational across the transition.
> > > +       These devices are intended to be reclaimed by the new kernel and
> > > +       re-attached to their original workload without requiring a device
> > > +       reset.
> > > +
> > > +       Ability to handover a device from current to the next kernel depends
> > > +       on specific support within device drivers and related kernel
> > > +       subsystems.
> >
> > Sorry, somehow this slipped during v6 review.
> > These days LUO is less about devices and more about file descriptors :)
> 
> Device preservation through file descriptors: memfd, iommufd, vfiofd
> are all dependencies for preserving devices.
> 
> That Kconfig description is correct and essential because the core
> complexity of the LUO is the preservation of device state and I/O
> across a kernel transition, which is a harder problem than just
> preserving memory or files, for that we could have used a file system
> instead of inventing something new with logic of can_preserve() etc.
> 
> Device preservation requires exactly what is stated in the description
> for this config:
> "Ability to handover a device from current to the next kernel depends
> on specific support within device drivers and related kernel
> subsystems." The only subsystem that is getting upstreamed with this
> series is MEMFD, it is a hard pre-requirement for iommufd
> preservation; the other subsystems: VFIO, PCI, IOMMU are WIP.
 
Ok.

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 07/22] liveupdate: luo_session: Add ioctls for file preservation
From: Mike Rapoport @ 2025-11-24  5:20 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-8-pasha.tatashin@soleen.com>

On Sat, Nov 22, 2025 at 05:23:34PM -0500, Pasha Tatashin wrote:
> Introducing the userspace interface and internal logic required to
> manage the lifecycle of file descriptors within a session. Previously, a
> session was merely a container; this change makes it a functional
> management unit.
> 
> The following capabilities are added:
> 
> A new set of ioctl commands are added, which operate on the file
> descriptor returned by CREATE_SESSION. This allows userspace to:
> - LIVEUPDATE_SESSION_PRESERVE_FD: Add a file descriptor to a session
>   to be preserved across the live update.
> - LIVEUPDATE_SESSION_RETRIEVE_FD: Retrieve a preserved file in the
>   new kernel using its unique token.
> - LIVEUPDATE_SESSION_FINISH: finish session
> 
> The session's .release handler is enhanced to be state-aware. When a
> session's file descriptor is closed, it correctly unpreserves
> the session based on its current state before freeing all
> associated file resources.
> 
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  include/uapi/linux/liveupdate.h | 103 ++++++++++++++++++
>  kernel/liveupdate/luo_session.c | 187 +++++++++++++++++++++++++++++++-
>  2 files changed, 288 insertions(+), 2 deletions(-)

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 16/22] selftests/liveupdate: Add userspace API selftests
From: Mike Rapoport @ 2025-11-24  5:24 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-17-pasha.tatashin@soleen.com>

On Sat, Nov 22, 2025 at 05:23:43PM -0500, Pasha Tatashin wrote:
> Introduce a selftest suite for LUO. These tests validate the core
> userspace-facing API provided by the /dev/liveupdate device and its
> associated ioctls.
> 
> The suite covers fundamental device behavior, session management, and
> the file preservation mechanism using memfd as a test case. This
> provides regression testing for the LUO uAPI.
> 
> The following functionality is verified:
> 
> Device Access:
>     Basic open and close operations on /dev/liveupdate.
>     Enforcement of exclusive device access (verifying EBUSY on a
>     second open).
> 
> Session Management:
>     Successful creation of sessions with unique names.
>     Failure to create sessions with duplicate names.
> 
> File Preservation:
>     Preserving a single memfd and verifying its content remains
>     intact post-preservation.
>     Preserving multiple memfds within a single session, each with
>     unique data.
>     A complex scenario involving multiple sessions, each containing
>     a mix of empty and data-filled memfds.
> 
> Note: This test suite is limited to verifying the pre-kexec
> functionality of LUO (e.g., session creation, file preservation).
> The post-kexec restoration of resources is not covered, as the kselftest
> framework does not currently support orchestrating a reboot and
> continuing execution in the new kernel.
> 
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  MAINTAINERS                                   |   1 +
>  tools/testing/selftests/Makefile              |   1 +
>  tools/testing/selftests/liveupdate/.gitignore |   9 +
>  tools/testing/selftests/liveupdate/Makefile   |  27 ++
>  tools/testing/selftests/liveupdate/config     |  11 +
>  .../testing/selftests/liveupdate/liveupdate.c | 348 ++++++++++++++++++
>  6 files changed, 397 insertions(+)
>  create mode 100644 tools/testing/selftests/liveupdate/.gitignore
>  create mode 100644 tools/testing/selftests/liveupdate/Makefile
>  create mode 100644 tools/testing/selftests/liveupdate/config
>  create mode 100644 tools/testing/selftests/liveupdate/liveupdate.c

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 17/22] selftests/liveupdate: Add kexec-based selftest for
From: Mike Rapoport @ 2025-11-24  5:29 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-18-pasha.tatashin@soleen.com>

On Sat, Nov 22, 2025 at 05:23:44PM -0500, Pasha Tatashin wrote:
> Subject: selftests/liveupdate: Add kexec-based selftest for

                                                         ^ for what? ;-)

> Introduce a kexec-based selftest, luo_kexec_simple, to validate the
> end-to-end lifecycle of a Live Update Orchestrator (LUO) session across
> a reboot.
> 
> While existing tests verify the uAPI in a pre-reboot context, this test
> ensures that the core functionality—preserving state via Kexec Handover
> and restoring it in a new kernel—works as expected.
> 
> The test operates in two stages, managing its state across the reboot by
> preserving a dedicated "state session" containing a memfd. This
> mechanism dogfoods the LUO feature itself for state tracking, making the
> test self-contained.
> 
> The test validates the following sequence:
> 
> Stage 1 (Pre-kexec):
>  - Creates a test session (test-session).
>  - Creates and preserves a memfd with a known data pattern into the test
>    session.
>  - Creates the state-tracking session to signal progression to Stage 2.
>  - Executes a kexec reboot via a helper script.
> 
> Stage 2 (Post-kexec):
>  - Retrieves the state-tracking session to confirm it is in the
>    post-reboot stage.
>  - Retrieves the preserved test session.
>  - Restores the memfd from the test session and verifies its contents
>    match the original data pattern written in Stage 1.
>  - Finalizes both the test and state sessions to ensure a clean
>    teardown.
> 
> The test relies on a helper script (do_kexec.sh) to perform the reboot
> and a shared utility library (luo_test_utils.c) for common LUO
> operations, keeping the main test logic clean and focused.
> 
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  tools/testing/selftests/liveupdate/Makefile   |   6 +
>  .../testing/selftests/liveupdate/do_kexec.sh  |  16 ++
>  .../selftests/liveupdate/luo_kexec_simple.c   |  89 ++++++
>  .../selftests/liveupdate/luo_test_utils.c     | 266 ++++++++++++++++++
>  .../selftests/liveupdate/luo_test_utils.h     |  44 +++
>  5 files changed, 421 insertions(+)
>  create mode 100755 tools/testing/selftests/liveupdate/do_kexec.sh
>  create mode 100644 tools/testing/selftests/liveupdate/luo_kexec_simple.c
>  create mode 100644 tools/testing/selftests/liveupdate/luo_test_utils.c
>  create mode 100644 tools/testing/selftests/liveupdate/luo_test_utils.h

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 18/22] selftests/liveupdate: Add kexec test for multiple and empty sessions
From: Mike Rapoport @ 2025-11-24  5:30 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-19-pasha.tatashin@soleen.com>

On Sat, Nov 22, 2025 at 05:23:45PM -0500, Pasha Tatashin wrote:
> Introduce a new kexec-based selftest, luo_kexec_multi_session, to
> validate the end-to-end lifecycle of a more complex LUO scenario.
> 
> While the existing luo_kexec_simple test covers the basic end-to-end
> lifecycle, it is limited to a single session with one preserved file.
> This new test significantly expands coverage by verifying LUO's ability
> to handle a mixed workload involving multiple sessions, some of which
> are intentionally empty. This ensures that the LUO core correctly
> preserves and restores the state of all session types across a reboot.
> 
> The test validates the following sequence:
> 
> Stage 1 (Pre-kexec):
> 
>   - Creates two empty test sessions (multi-test-empty-1,
>     multi-test-empty-2).
>   - Creates a session with one preserved memfd (multi-test-files-1).
>   - Creates another session with two preserved memfds
>     (multi-test-files-2), each containing unique data.
>   - Creates a state-tracking session to manage the transition to
>     Stage 2.
>   - Executes a kexec reboot via the helper script.
> 
> Stage 2 (Post-kexec):
> 
>   - Retrieves the state-tracking session to confirm it is in the
>     post-reboot stage.
>   - Retrieves all four test sessions (both the empty and non-empty
>     ones).
>   - For the non-empty sessions, restores the preserved memfds and
>     verifies their contents match the original data patterns.
>   - Finalizes all test sessions and the state session to ensure a clean
>     teardown and that all associated kernel resources are correctly
>     released.
> 
> This test provides greater confidence in the robustness of the LUO
> framework by validating its behavior in a more realistic, multi-faceted
> scenario.
> 
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  tools/testing/selftests/liveupdate/Makefile   |   1 +
>  .../selftests/liveupdate/luo_multi_session.c  | 162 ++++++++++++++++++
>  2 files changed, 163 insertions(+)
>  create mode 100644 tools/testing/selftests/liveupdate/luo_multi_session.c

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 19/22] selftests/liveupdate: add test infrastructure and scripts
From: Mike Rapoport @ 2025-11-24  7:54 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-20-pasha.tatashin@soleen.com>

On Sat, Nov 22, 2025 at 05:23:46PM -0500, Pasha Tatashin wrote:
> Subject: [PATCH v7 19/22] selftests/liveupdate: add test infrastructure and scripts

Maybe                                                ^ end to end

> Add the testing infrastructure required to verify the liveupdate
> feature. This includes a custom init process, a test orchestration
> script, and a batch runner.

And say here that it's end to end test.
 
> The framework consists of:
> 
> init.c:
> A lightweight init process that manages the kexec lifecycle.
> It mounts necessary filesystems, determines the current execution
> stage (1 or 2) via the kernel command line, and handles the
> kexec_file_load() sequence to transition between kernels.
> 
> luo_test.sh:
> The primary KTAP-compliant test driver. It handles:
> - Kernel configuration merging and building.
> - Cross-compilation detection for x86_64 and arm64.
> - Generation of the initrd containing the test binary and init.
> - QEMU execution with automatic accelerator detection (KVM, HVF,
>  or TCG).
> 
> run.sh:
> A wrapper script to discover and execute all `luo_*.c`
> tests across supported architectures, providing a summary of
> pass/fail/skip results.
> 
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
>  tools/testing/selftests/liveupdate/init.c     | 174 ++++++++++
>  .../testing/selftests/liveupdate/luo_test.sh  | 296 ++++++++++++++++++
>  tools/testing/selftests/liveupdate/run.sh     |  68 ++++
>  3 files changed, 538 insertions(+)
>  create mode 100644 tools/testing/selftests/liveupdate/init.c
>  create mode 100755 tools/testing/selftests/liveupdate/luo_test.sh
>  create mode 100755 tools/testing/selftests/liveupdate/run.sh
> 

...

> +static int is_stage_2(void)
> +{
> +	char cmdline[COMMAND_LINE_SIZE];
> +	ssize_t len;
> +	int fd;
> +
> +	fd = open("/proc/cmdline", O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	len = read(fd, cmdline, sizeof(cmdline) - 1);
> +	close(fd);
> +
> +	if (len < 0)
> +		return 0;

Shouldn't we bail out of the test if read of command line failed?

> +
> +	cmdline[len] = 0;
> +
> +	return !!strstr(cmdline, "luo_stage=2");
> +}
> +

...

> +function cleanup() {
> +	local exit_code=$?
> +
> +	if [ -z "$workspace_dir" ]; then
> +		ktap_finished
> +		return
> +	fi
> +
> +	if [ $exit_code -ne 0 ]; then
> +		echo "# Test failed (exit code $exit_code)."
> +		echo "# Workspace preserved at: $workspace_dir"
> +	elif [ "$KEEP_WORKSPACE" -eq 1 ]; then
> +		echo "# Workspace preserved (user request) at: $workspace_dir"
> +	else
> +		rm -fr "$workspace_dir"
> +	fi
> +	ktap_finished

	exit $exit_code

> +}

...

> +function build_kernel() {
> +	local build_dir=$1
> +	local make_cmd=$2
> +	local kimage=$3
> +	local target_arch=$4
> +
> +	local kconfig="$build_dir/.config"
> +	local common_conf="$test_dir/config"
> +	local arch_conf="$test_dir/config.$target_arch"
> +
> +	echo "# Building kernel in: $build_dir"
> +	$make_cmd defconfig
> +
> +	local fragments=""
> +	if [[ -f "$common_conf" ]]; then
> +		fragments="$fragments $common_conf"
> +	fi

Without this CONFIG_LIVEUPDATE won't be set
> +
> +	if [[ -f "$arch_conf" ]]; then
> +		fragments="$fragments $arch_conf"
> +	fi
> +
> +	if [[ -n "$fragments" ]]; then
> +		"$kernel_dir/scripts/kconfig/merge_config.sh" \
> +			-Q -m -O "$build_dir" "$kconfig" $fragments >> /dev/null
> +	fi

I believe you can just

	cat $common_conf $fragments >  $build_dir/.config
	make olddefconfig

without running defconfig at the beginning
It will build faster, just make sure to add CONFIG_SERIAL_ to $arch_conf

> +	$make_cmd olddefconfig
> +	$make_cmd "$kimage"
> +	$make_cmd headers_install INSTALL_HDR_PATH="$headers_dir"
> +}
> +
> +function mkinitrd() {
> +	local build_dir=$1
> +	local kernel_path=$2
> +	local test_name=$3
> +
> +	# 1. Compile the test binary and the init process

Didn't find 2. ;-)
Don't think we want the numbering here, plain comments are fine

> +	"$CROSS_COMPILE"gcc -static -O2 \
> +		-I "$headers_dir/include" \
> +		-I "$test_dir" \
> +		-o "$workspace_dir/test_binary" \
> +		"$test_dir/$test_name.c" "$test_dir/luo_test_utils.c"

This will have hard time cross-compiling with -nolibc toolchains

> +
> +	"$CROSS_COMPILE"gcc -s -static -Os -nostdinc -nostdlib		\
> +			-fno-asynchronous-unwind-tables -fno-ident	\
> +			-fno-stack-protector				\
> +			-I "$headers_dir/include"			\
> +			-I "$kernel_dir/tools/include/nolibc"		\
> +			-o "$workspace_dir/init" "$test_dir/init.c"

This failed for me with gcc 14.2.0 (Debian 14.2.0-19):

/home/mike/git/linux/tools/testing/selftests/liveupdate/init.c: In function ‘run_test’:
/home/mike/git/linux/tools/testing/selftests/liveupdate/init.c:111:65: error: initializer element is not constant
  111 |             static const char *const argv[] = {TEST_BINARY, stage_arg, NULL};
      |                                                             ^~~~~~~~~

/home/mike/git/linux/tools/testing/selftests/liveupdate/init.c:111:65: note: (near initialization for ‘argv[1]’)
/home/mike/git/linux/tools/testing/selftests/liveupdate/init.c:113:37: error: passing argument 2 of ‘execve’ from incompatible pointer type [-Wincompatible-pointer-types]
  113 |                 execve(TEST_BINARY, argv, NULL);
      |                                     ^~~~
      |                                     |
      |                                     const char * const*
In file included from /home/mike/git/linux/tools/testing/selftests/liveupdate/init.c:16:
/usr/include/unistd.h:572:52: note: expected ‘char * const*’ but argument is of type ‘const char * const*’
  572 | extern int execve (const char *__path, char *const __argv[],
      |                                        ~~~~~~~~~~~~^~~~~~~~

> +
> +	cat > "$workspace_dir/cpio_list_inner" <<EOF
> +dir /dev 0755 0 0
> +dir /proc 0755 0 0
> +dir /debugfs 0755 0 0
> +nod /dev/console 0600 0 0 c 5 1

Don't you need /dev/liveupdate node?

> +file /init $workspace_dir/init 0755 0 0
> +file /test_binary $workspace_dir/test_binary 0755 0 0
> +EOF
> +
> +	# Generate inner_initrd.cpio
> +	"$build_dir/usr/gen_init_cpio" "$workspace_dir/cpio_list_inner" > "$workspace_dir/inner_initrd.cpio"
> +
> +	cat > "$workspace_dir/cpio_list" <<EOF
> +dir /dev 0755 0 0
> +dir /proc 0755 0 0
> +dir /debugfs 0755 0 0
> +nod /dev/console 0600 0 0 c 5 1

And here as well.

> +file /init $workspace_dir/init 0755 0 0
> +file /kernel $kernel_path 0644 0 0
> +file /test_binary $workspace_dir/test_binary 0755 0 0
> +file /initrd.img $workspace_dir/inner_initrd.cpio 0644 0 0
> +EOF
> +
> +	# Generate the final initrd
> +	"$build_dir/usr/gen_init_cpio" "$workspace_dir/cpio_list" > "$initrd"
> +	local size=$(du -h "$initrd" | cut -f1)
> +}
> +
> +function run_qemu() {
> +	local qemu_cmd=$1
> +	local cmdline=$2
> +	local kernel_path=$3
> +	local serial="$workspace_dir/qemu.serial"
> +
> +	local accel="-accel tcg"
> +	local host_machine=$(uname -m)
> +
> +	[[ "$host_machine" == "arm64" ]] && host_machine="aarch64"
> +	[[ "$host_machine" == "x86_64" ]] && host_machine="x86_64"
> +
> +	if [[ "$qemu_cmd" == *"$host_machine"* ]]; then
> +		if [ -w /dev/kvm ]; then
> +			accel="-accel kvm"

Just pass both kvm and tcg and let qemu complain.

> +		fi
> +	fi
> +
> +	cmdline="$cmdline liveupdate=on panic=-1"
> +
> +	echo "# Serial Log: $serial"
> +	timeout 30s $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults	\
> +		  $accel							\
> +		  -serial file:"$serial"					\
> +		  -append "$cmdline"						\
> +		  -kernel "$kernel_path"					\
> +		  -initrd "$initrd"
> +
> +	local ret=$?
> +
> +	if [ $ret -eq 124 ]; then
> +		fail "QEMU timed out"
> +	fi
> +
> +	grep "TEST PASSED" "$serial" &> /dev/null || fail "Liveupdate failed. Check $serial for details."
> +}

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 06/22] liveupdate: luo_file: implement file systems callbacks
From: Mike Rapoport @ 2025-11-24  8:18 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, dmatlack, rientjes, corbet, rdunlap,
	ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm, tj,
	yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, ptyadav,
	lennart, brauner, linux-api, linux-fsdevel, saeedm, ajayachandra,
	jgg, parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-7-pasha.tatashin@soleen.com>

On Sat, Nov 22, 2025 at 05:23:33PM -0500, Pasha Tatashin wrote:
> This patch implements the core mechanism for managing preserved
> files throughout the live update lifecycle. It provides the logic to
> invoke the file handler callbacks (preserve, unpreserve, freeze,
> unfreeze, retrieve, and finish) at the appropriate stages.
> 
> During the reboot phase, luo_file_freeze() serializes the final
> metadata for each file (handler compatible string, token, and data
> handle) into a memory region preserved by KHO. In the new kernel,
> luo_file_deserialize() reconstructs the in-memory file list from this
> data, preparing the session for retrieval.
> 
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

With some comments below
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  include/linux/kho/abi/luo.h      |  39 +-
>  include/linux/liveupdate.h       |  98 ++++
>  kernel/liveupdate/Makefile       |   1 +
>  kernel/liveupdate/luo_file.c     | 882 +++++++++++++++++++++++++++++++
>  kernel/liveupdate/luo_internal.h |  38 ++
>  5 files changed, 1057 insertions(+), 1 deletion(-)
>  create mode 100644 kernel/liveupdate/luo_file.c
> 

...

> +int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
> +{
> +	struct liveupdate_file_op_args args = {0};
> +	struct liveupdate_file_handler *fh;
> +	struct luo_file *luo_file;
> +	struct file *file;
> +	int err;
> +
> +	if (luo_token_is_used(file_set, token))
> +		return -EEXIST;
> +
> +	file = fget(fd);
> +	if (!file)
> +		return -EBADF;
> +
> +	err = luo_alloc_files_mem(file_set);
> +	if (err)
> +		goto  err_files_mem;
> +
> +	if (file_set->count == LUO_FILE_MAX) {

This can be checked before getting the file and allocating memory, can't it?

> +		err = -ENOSPC;
> +		goto err_files_mem;

The goto label should say what it does, not what the error was.

> +	}
> +
> +	err = -ENOENT;
> +	luo_list_for_each_private(fh, &luo_file_handler_list, list) {
> +		if (fh->ops->can_preserve(fh, file)) {
> +			err = 0;
> +			break;
> +		}
> +	}
> +
> +	/* err is still -ENOENT if no handler was found */
> +	if (err)
> +		goto err_files_mem;
> +
> +	luo_file = kzalloc(sizeof(*luo_file), GFP_KERNEL);
> +	if (!luo_file) {
> +		err = -ENOMEM;
> +		goto err_files_mem;
> +	}
> +
> +	luo_file->file = file;
> +	luo_file->fh = fh;
> +	luo_file->token = token;
> +	luo_file->retrieved = false;
> +	mutex_init(&luo_file->mutex);
> +
> +	args.handler = fh;
> +	args.file = file;
> +	err = fh->ops->preserve(&args);
> +	if (err)
> +		goto err_kfree;
> +
> +	luo_file->serialized_data = args.serialized_data;
> +	list_add_tail(&luo_file->list, &file_set->files_list);
> +	file_set->count++;
> +
> +	return 0;
> +
> +err_kfree:
> +	mutex_destroy(&luo_file->mutex);

Don't think we need this, luo_file is freed in the next line.

> +	kfree(luo_file);
> +err_files_mem:
> +	fput(file);
> +	luo_free_files_mem(file_set);

I'd have the error path as

err_free_luo_file:
	kfree(luo_file);
err_free_files_mem:
	luo_free_files_mem(file_set);
err_put_file:
	fput(file);

> +
> +	return err;
> +}

...

> +void luo_file_unpreserve_files(struct luo_file_set *file_set)
> +{
> +	struct luo_file *luo_file;
> +
> +	while (!list_empty(&file_set->files_list)) {

list_for_each_entry_safe_reverse()?

> +		struct liveupdate_file_op_args args = {0};
> +
> +		luo_file = list_last_entry(&file_set->files_list,
> +					   struct luo_file, list);
> +
> +		args.handler = luo_file->fh;
> +		args.file = luo_file->file;
> +		args.serialized_data = luo_file->serialized_data;
> +		luo_file->fh->ops->unpreserve(&args);
> +
> +		list_del(&luo_file->list);
> +		file_set->count--;
> +
> +		fput(luo_file->file);
> +		mutex_destroy(&luo_file->mutex);
> +		kfree(luo_file);
> +	}
> +
> +	luo_free_files_mem(file_set);
> +}

...

> +int luo_file_finish(struct luo_file_set *file_set)
> +{
> +	struct list_head *files_list = &file_set->files_list;
> +	struct luo_file *luo_file;
> +	int err;
> +
> +	if (!file_set->count)
> +		return 0;
> +
> +	list_for_each_entry(luo_file, files_list, list) {
> +		err = luo_file_can_finish_one(file_set, luo_file);
> +		if (err)
> +			return err;
> +	}
> +
> +	while (!list_empty(&file_set->files_list)) {

list_for_each_entry_safe_reverse()?

> +		luo_file = list_last_entry(&file_set->files_list,
> +					   struct luo_file, list);
> +
> +		luo_file_finish_one(file_set, luo_file);
> +
> +		if (luo_file->file)
> +			fput(luo_file->file);
> +		list_del(&luo_file->list);
> +		file_set->count--;
> +		mutex_destroy(&luo_file->mutex);
> +		kfree(luo_file);
> +	}
> +

...

> diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
> index 1292ac47eef8..c8973b543d1d 100644
> --- a/kernel/liveupdate/luo_internal.h
> +++ b/kernel/liveupdate/luo_internal.h
> @@ -40,6 +40,28 @@ static inline int luo_ucmd_respond(struct luo_ucmd *ucmd,
>   */
>  #define luo_restore_fail(__fmt, ...) panic(__fmt, ##__VA_ARGS__)
>  
> +/* Mimics list_for_each_entry() but for private list head entries */
> +#define luo_list_for_each_private(pos, head, member)				\
> +	for (struct list_head *__iter = (head)->next;				\
> +	     __iter != (head) &&						\
> +	     ({ pos = container_of(__iter, typeof(*(pos)), member); 1; });	\
> +	     __iter = __iter->next)

Ideally something like this should go to include/linux/list.h, but it can
be done later to avoid bikeshedding about the name :)

And you can reuse most of list_for_each_entry, just replace the line that
accesses __private member:

#define luo_list_for_each_private(pos, head, member)			\
	for (pos = list_first_entry(head, typeof(*pos), member);	\
	     &ACCESS_PRIVATE(pos, member) != head;			\
	     pos = list_next_entry(pos, member))

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v7 02/22] liveupdate: luo_core: integrate with KHO
From: Pratyush Yadav @ 2025-11-24 14:21 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-3-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> Integrate the LUO with the KHO framework to enable passing LUO state
> across a kexec reboot.
>
> This patch implements the lifecycle integration with KHO:
>
> 1. Incoming State: During early boot (`early_initcall`), LUO checks if
>    KHO is active. If so, it retrieves the "LUO" subtree, verifies the
>    "luo-v1" compatibility string, and reads the `liveupdate-number` to
>    track the update count.
>
> 2. Outgoing State: During late initialization (`late_initcall`), LUO
>    allocates a new FDT for the next kernel, populates it with the basic
>    header (compatible string and incremented update number), and
>    registers it with KHO (`kho_add_subtree`).
>
> 3. Finalization: The `liveupdate_reboot()` notifier is updated to invoke
>    `kho_finalize()`. This ensures that all memory segments marked for
>    preservation are properly serialized before the kexec jump.
>
> LUO now depends on `CONFIG_KEXEC_HANDOVER`.

Nit: This patch does not add the dependency. That is done by patch 1. I
guess that change needs to be moved here or the comment removed?

Other than this,

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v4 1/3] init: remove deprecated "load_ramdisk" and "prompt_ramdisk" command line parameters
From: Christoph Hellwig @ 2025-11-24 14:27 UTC (permalink / raw)
  To: Askar Safin
  Cc: linux-fsdevel, linux-kernel, Linus Torvalds, Greg Kroah-Hartman,
	Christian Brauner, Al Viro, Jan Kara, Christoph Hellwig,
	Jens Axboe, Andy Shevchenko, Aleksa Sarai, Thomas Weißschuh,
	Julian Stecklina, Gao Xiang, Art Nikpal, Andrew Morton,
	Alexander Graf, Rob Landley, Lennart Poettering, linux-arch,
	linux-block, initramfs, linux-api, linux-doc, Michal Simek,
	Luis Chamberlain, Kees Cook, Thorsten Blum, Heiko Carstens,
	Arnd Bergmann, Dave Young, Christophe Leroy, Krzysztof Kozlowski,
	Borislav Petkov, Jessica Clarke, Nicolas Schichan,
	David Disseldorp, patches
In-Reply-To: <20251119222407.3333257-2-safinaskar@gmail.com>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH v4 2/3] initrd: remove deprecated code path (linuxrc)
From: Christoph Hellwig @ 2025-11-24 14:27 UTC (permalink / raw)
  To: Askar Safin
  Cc: linux-fsdevel, linux-kernel, Linus Torvalds, Greg Kroah-Hartman,
	Christian Brauner, Al Viro, Jan Kara, Christoph Hellwig,
	Jens Axboe, Andy Shevchenko, Aleksa Sarai, Thomas Weißschuh,
	Julian Stecklina, Gao Xiang, Art Nikpal, Andrew Morton,
	Alexander Graf, Rob Landley, Lennart Poettering, linux-arch,
	linux-block, initramfs, linux-api, linux-doc, Michal Simek,
	Luis Chamberlain, Kees Cook, Thorsten Blum, Heiko Carstens,
	Arnd Bergmann, Dave Young, Christophe Leroy, Krzysztof Kozlowski,
	Borislav Petkov, Jessica Clarke, Nicolas Schichan,
	David Disseldorp, patches
In-Reply-To: <20251119222407.3333257-3-safinaskar@gmail.com>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH v4 3/3] init: remove /proc/sys/kernel/real-root-dev
From: Christoph Hellwig @ 2025-11-24 14:28 UTC (permalink / raw)
  To: Askar Safin
  Cc: linux-fsdevel, linux-kernel, Linus Torvalds, Greg Kroah-Hartman,
	Christian Brauner, Al Viro, Jan Kara, Christoph Hellwig,
	Jens Axboe, Andy Shevchenko, Aleksa Sarai, Thomas Weißschuh,
	Julian Stecklina, Gao Xiang, Art Nikpal, Andrew Morton,
	Alexander Graf, Rob Landley, Lennart Poettering, linux-arch,
	linux-block, initramfs, linux-api, linux-doc, Michal Simek,
	Luis Chamberlain, Kees Cook, Thorsten Blum, Heiko Carstens,
	Arnd Bergmann, Dave Young, Christophe Leroy, Krzysztof Kozlowski,
	Borislav Petkov, Jessica Clarke, Nicolas Schichan,
	David Disseldorp, patches
In-Reply-To: <20251119222407.3333257-4-safinaskar@gmail.com>

On Wed, Nov 19, 2025 at 10:24:07PM +0000, Askar Safin wrote:
> It is not used anymore.

Let's hope whacky userspace agrees with that :)

But we'll have to try this to find out, so:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH v7 04/22] liveupdate: luo_session: add sessions support
From: Pratyush Yadav @ 2025-11-24 14:57 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-5-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> Introduce concept of "Live Update Sessions" within the LUO framework.
> LUO sessions provide a mechanism to group and manage `struct file *`
> instances (representing file descriptors) that need to be preserved
> across a kexec-based live update.
>
> Each session is identified by a unique name and acts as a container
> for file objects whose state is critical to a userspace workload, such
> as a virtual machine or a high-performance database, aiming to maintain
> their functionality across a kernel transition.
>
> This groundwork establishes the framework for preserving file-backed
> state across kernel updates, with the actual file data preservation
> mechanisms to be implemented in subsequent patches.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

With Mike's comments addressed,

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v6 12/20] mm: shmem: allow freezing inode mapping
From: Pratyush Yadav @ 2025-11-24 15:06 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Pasha Tatashin, pratyush, jasonmiu, graf, dmatlack, rientjes,
	corbet, rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl,
	masahiroy, akpm, tj, yoann.congal, mmaurer, roman.gushchin,
	chenridong, axboe, mark.rutland, jannh, vincent.guittot, hannes,
	dan.j.williams, david, joel.granados, rostedt, anna.schumaker,
	song, linux, linux-kernel, linux-doc, linux-mm, gregkh, tglx,
	mingo, bp, dave.hansen, x86, hpa, rafael, dakr,
	bartosz.golaszewski, cw00.choi, myungjoo.ham, yesanishhere,
	Jonathan.Cameron, quic_zijuhu, aleksander.lobakin, ira.weiny,
	andriy.shevchenko, leon, lukas, bhelgaas, wagi, djeffery,
	stuart.w.hayes, lennart, brauner, linux-api, linux-fsdevel,
	saeedm, ajayachandra, jgg, parav, leonro, witu, hughd, skhawaja,
	chrisl
In-Reply-To: <aRr0CQsV16usRW1J@kernel.org>

On Mon, Nov 17 2025, Mike Rapoport wrote:

> On Sat, Nov 15, 2025 at 06:33:58PM -0500, Pasha Tatashin wrote:
>> From: Pratyush Yadav <ptyadav@amazon.de>
>> 
>> To prepare a shmem inode for live update via the Live Update
>> Orchestrator (LUO), its index -> folio mappings must be serialized. Once
>> the mappings are serialized, they cannot change since it would cause the
>> serialized data to become inconsistent. This can be done by pinning the
>> folios to avoid migration, and by making sure no folios can be added to
>> or removed from the inode.
>> 
>> While mechanisms to pin folios already exist, the only way to stop
>> folios being added or removed are the grow and shrink file seals. But
>> file seals come with their own semantics, one of which is that they
>> can't be removed. This doesn't work with liveupdate since it can be
>> cancelled or error out, which would need the seals to be removed and the
>> file's normal functionality to be restored.
>> 
>> Introduce SHMEM_F_MAPPING_FROZEN to indicate this instead. It is
>> internal to shmem and is not directly exposed to userspace. It functions
>> similar to F_SEAL_GROW | F_SEAL_SHRINK, but additionally disallows hole
>> punching, and can be removed.
>> 
>> Signed-off-by: Pratyush Yadav <ptyadav@amazon.de>
>> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
>> ---
[...]
>> diff --git a/mm/shmem.c b/mm/shmem.c
>> index 1d5036dec08a..05c3db840257 100644
>> --- a/mm/shmem.c
>> +++ b/mm/shmem.c
>> @@ -1292,7 +1292,8 @@ static int shmem_setattr(struct mnt_idmap *idmap,
>>  		loff_t newsize = attr->ia_size;
>>  
>>  		/* protected by i_rwsem */
>> -		if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
>> +		if ((info->flags & SHMEM_F_MAPPING_FROZEN) ||
>
> A corner case: if newsize == oldsize this will be a false positive

Good catch. Though I wonder why anyone would do a truncate with the same
size.

>
>> +		    (newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
>>  		    (newsize > oldsize && (info->seals & F_SEAL_GROW)))
>>  			return -EPERM;
>>  
[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v7 05/22] liveupdate: luo_core: add user interface
From: Pratyush Yadav @ 2025-11-24 15:11 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-6-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> Introduce the user-space interface for the Live Update Orchestrator
> via ioctl commands, enabling external control over the live update
> process and management of preserved resources.
>
> The idea is that there is going to be a single userspace agent driving
> the live update, therefore, only a single process can ever hold this
> device opened at a time.
>
> The following ioctl commands are introduced:
>
> LIVEUPDATE_IOCTL_CREATE_SESSION
> Provides a way for userspace to create a named session for grouping file
> descriptors that need to be preserved. It returns a new file descriptor
> representing the session.
>
> LIVEUPDATE_IOCTL_RETRIEVE_SESSION
> Allows the userspace agent in the new kernel to reclaim a preserved
> session by its name, receiving a new file descriptor to manage the
> restored resources.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v7 09/22] MAINTAINERS: add liveupdate entry
From: Pratyush Yadav @ 2025-11-24 15:18 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-10-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> Add a MAINTAINERS file entry for the new Live Update Orchestrator
> introduced in previous patches.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v7 06/22] liveupdate: luo_file: implement file systems callbacks
From: Pratyush Yadav @ 2025-11-24 15:44 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-7-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> This patch implements the core mechanism for managing preserved
> files throughout the live update lifecycle. It provides the logic to
> invoke the file handler callbacks (preserve, unpreserve, freeze,
> unfreeze, retrieve, and finish) at the appropriate stages.
>
> During the reboot phase, luo_file_freeze() serializes the final
> metadata for each file (handler compatible string, token, and data
> handle) into a memory region preserved by KHO. In the new kernel,
> luo_file_deserialize() reconstructs the in-memory file list from this
> data, preparing the session for retrieval.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
>  include/linux/kho/abi/luo.h      |  39 +-
>  include/linux/liveupdate.h       |  98 ++++
>  kernel/liveupdate/Makefile       |   1 +
>  kernel/liveupdate/luo_file.c     | 882 +++++++++++++++++++++++++++++++
>  kernel/liveupdate/luo_internal.h |  38 ++
>  5 files changed, 1057 insertions(+), 1 deletion(-)
>  create mode 100644 kernel/liveupdate/luo_file.c
>
> diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h
> index a2d2940eca6b..fc143f243871 100644
> --- a/include/linux/kho/abi/luo.h
> +++ b/include/linux/kho/abi/luo.h
> @@ -65,6 +65,11 @@
>   *     Metadata for a single session, including its name and a physical pointer
>   *     to another preserved memory block containing an array of
>   *     `struct luo_file_ser` for all files in that session.
> + *
> + *   - struct luo_file_ser:
> + *     Metadata for a single preserved file. Contains the `compatible` string to
> + *     find the correct handler in the new kernel, a user-provided `token` for
> + *     identification, and an opaque `data` handle for the handler to use.
>   */
>  
>  #ifndef _LINUX_KHO_ABI_LUO_H
> @@ -82,13 +87,43 @@
>  #define LUO_FDT_COMPATIBLE	"luo-v1"
>  #define LUO_FDT_LIVEUPDATE_NUM	"liveupdate-number"
>  
> +#define LIVEUPDATE_HNDL_COMPAT_LENGTH	48
> +
> +/**
> + * struct luo_file_ser - Represents the serialized preserves files.
> + * @compatible:  File handler compatible string.
> + * @data:        Private data
> + * @token:       User provided token for this file
> + *
> + * If this structure is modified, LUO_SESSION_COMPATIBLE must be updated.
> + */
> +struct luo_file_ser {
> +	char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
> +	u64 data;
> +	u64 token;
> +} __packed;
> +
> +/**
> + * struct luo_file_set_ser - Represents the serialized metadata for file set
> + * @files:   The physical address of a contiguous memory block that holds
> + *           the serialized state of files (array of luo_file_ser) in this file
> + *           set.
> + * @count:   The total number of files that were part of this session during
> + *           serialization. Used for iteration and validation during
> + *           restoration.
> + */
> +struct luo_file_set_ser {
> +	u64 files;
> +	u64 count;
> +} __packed;

The change to using file_set looks a lot nicer than what the previous
version was doing!

> +
>  /*
>   * LUO FDT session node
>   * LUO_FDT_SESSION_HEADER:  is a u64 physical address of struct
>   *                          luo_session_header_ser
>   */
>  #define LUO_FDT_SESSION_NODE_NAME	"luo-session"
> -#define LUO_FDT_SESSION_COMPATIBLE	"luo-session-v1"
> +#define LUO_FDT_SESSION_COMPATIBLE	"luo-session-v2"
>  #define LUO_FDT_SESSION_HEADER		"luo-session-header"
>  
>  /**
> @@ -110,6 +145,7 @@ struct luo_session_header_ser {
>   * struct luo_session_ser - Represents the serialized metadata for a LUO session.
>   * @name:         The unique name of the session, provided by the userspace at
>   *                the time of session creation.
> + * @file_set_ser: Serialized files belonging to this session,
>   *
>   * This structure is used to package session-specific metadata for transfer
>   * between kernels via Kexec Handover. An array of these structures (one per
> @@ -120,6 +156,7 @@ struct luo_session_header_ser {
>   */
>  struct luo_session_ser {
>  	char name[LIVEUPDATE_SESSION_NAME_LENGTH];
> +	struct luo_file_set_ser file_set_ser;
>  } __packed;
>  
>  #endif /* _LINUX_KHO_ABI_LUO_H */
> diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
> index c6a1d6bd90cb..122ad8f16ff9 100644
> --- a/include/linux/liveupdate.h
> +++ b/include/linux/liveupdate.h
> @@ -8,8 +8,93 @@
>  #define _LINUX_LIVEUPDATE_H
>  
>  #include <linux/bug.h>
> +#include <linux/compiler.h>
> +#include <linux/kho/abi/luo.h>
>  #include <linux/list.h>
>  #include <linux/types.h>
> +#include <uapi/linux/liveupdate.h>
> +
> +struct liveupdate_file_handler;
> +struct file;
> +
> +/**
> + * struct liveupdate_file_op_args - Arguments for file operation callbacks.
> + * @handler:          The file handler being called.
> + * @retrieved:        The retrieve status for the 'can_finish / finish'
> + *                    operation.
> + * @file:             The file object. For retrieve: [OUT] The callback sets
> + *                    this to the new file. For other ops: [IN] The caller sets
> + *                    this to the file being operated on.
> + * @serialized_data:  The opaque u64 handle, preserve/prepare/freeze may update
> + *                    this field.
> + *
> + * This structure bundles all parameters for the file operation callbacks.
> + * The 'data' and 'file' fields are used for both input and output.
> + */
> +struct liveupdate_file_op_args {
> +	struct liveupdate_file_handler *handler;
> +	bool retrieved;
> +	struct file *file;
> +	u64 serialized_data;
> +};
> +
> +/**
> + * struct liveupdate_file_ops - Callbacks for live-updatable files.
> + * @can_preserve: Required. Lightweight check to see if this handler is
> + *                compatible with the given file.
> + * @preserve:     Required. Performs state-saving for the file.
> + * @unpreserve:   Required. Cleans up any resources allocated by @preserve.
> + * @freeze:       Optional. Final actions just before kernel transition.
> + * @unfreeze:     Optional. Undo freeze operations.
> + * @retrieve:     Required. Restores the file in the new kernel.
> + * @can_finish:   Optional. Check if this FD can finish, i.e. all restoration
> + *                pre-requirements for this FD are satisfied. Called prior to
> + *                finish, in order to do successful finish calls for all
> + *                resources in the session.
> + * @finish:       Required. Final cleanup in the new kernel.
> + * @owner:        Module reference
> + *
> + * All operations (except can_preserve) receive a pointer to a
> + * 'struct liveupdate_file_op_args' containing the necessary context.
> + */
> +struct liveupdate_file_ops {
> +	bool (*can_preserve)(struct liveupdate_file_handler *handler,
> +			     struct file *file);
> +	int (*preserve)(struct liveupdate_file_op_args *args);
> +	void (*unpreserve)(struct liveupdate_file_op_args *args);
> +	int (*freeze)(struct liveupdate_file_op_args *args);
> +	void (*unfreeze)(struct liveupdate_file_op_args *args);
> +	int (*retrieve)(struct liveupdate_file_op_args *args);
> +	bool (*can_finish)(struct liveupdate_file_op_args *args);
> +	void (*finish)(struct liveupdate_file_op_args *args);
> +	struct module *owner;
> +};
> +
> +/**
> + * struct liveupdate_file_handler - Represents a handler for a live-updatable file type.
> + * @ops:                Callback functions
> + * @compatible:         The compatibility string (e.g., "memfd-v1", "vfiofd-v1")
> + *                      that uniquely identifies the file type this handler
> + *                      supports. This is matched against the compatible string
> + *                      associated with individual &struct file instances.
> + *
> + * Modules that want to support live update for specific file types should
> + * register an instance of this structure. LUO uses this registration to
> + * determine if a given file can be preserved and to find the appropriate
> + * operations to manage its state across the update.
> + */
> +struct liveupdate_file_handler {
> +	const struct liveupdate_file_ops *ops;
> +	const char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
> +
> +	/* private: */
> +
> +	/*
> +	 * Used for linking this handler instance into a global list of
> +	 * registered file handlers.
> +	 */
> +	struct list_head __private list;
> +};
>  
>  #ifdef CONFIG_LIVEUPDATE
>  
> @@ -19,6 +104,9 @@ bool liveupdate_enabled(void);
>  /* Called during kexec to tell LUO that entered into reboot */
>  int liveupdate_reboot(void);
>  
> +int liveupdate_register_file_handler(struct liveupdate_file_handler *fh);
> +int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);
> +
>  #else /* CONFIG_LIVEUPDATE */
>  
>  static inline bool liveupdate_enabled(void)
> @@ -31,5 +119,15 @@ static inline int liveupdate_reboot(void)
>  	return 0;
>  }
>  
> +static inline int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> +static inline int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
>  #endif /* CONFIG_LIVEUPDATE */
>  #endif /* _LINUX_LIVEUPDATE_H */
> diff --git a/kernel/liveupdate/Makefile b/kernel/liveupdate/Makefile
> index 6af93caa58cf..7cad2eece32d 100644
> --- a/kernel/liveupdate/Makefile
> +++ b/kernel/liveupdate/Makefile
> @@ -2,6 +2,7 @@
>  
>  luo-y :=								\
>  		luo_core.o						\
> +		luo_file.o						\
>  		luo_session.o
>  
>  obj-$(CONFIG_KEXEC_HANDOVER)		+= kexec_handover.o
> diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
> new file mode 100644
> index 000000000000..f10d6c37328c
> --- /dev/null
> +++ b/kernel/liveupdate/luo_file.c
> @@ -0,0 +1,882 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (c) 2025, Google LLC.
> + * Pasha Tatashin <pasha.tatashin@soleen.com>
> + */
> +
> +/**
> + * DOC: LUO File Descriptors
> + *
> + * LUO provides the infrastructure to preserve specific, stateful file
> + * descriptors across a kexec-based live update. The primary goal is to allow
> + * workloads, such as virtual machines using vfio, memfd, or iommufd, to
> + * retain access to their essential resources without interruption.
> + *
> + * The framework is built around a callback-based handler model and a well-
> + * defined lifecycle for each preserved file.
> + *
> + * Handler Registration:
> + * Kernel modules responsible for a specific file type (e.g., memfd, vfio)
> + * register a &struct liveupdate_file_handler. This handler provides a set of
> + * callbacks that LUO invokes at different stages of the update process, most
> + * notably:
> + *
> + *   - can_preserve(): A lightweight check to determine if the handler is
> + *     compatible with a given 'struct file'.
> + *   - preserve(): The heavyweight operation that saves the file's state and
> + *     returns an opaque u64 handle. This is typically performed while the
> + *     workload is still active to minimize the downtime during the
> + *     actual reboot transition.
> + *   - unpreserve(): Cleans up any resources allocated by .preserve(), called
> + *     if the preservation process is aborted before the reboot (i.e. session is
> + *     closed).
> + *   - freeze(): A final pre-reboot opportunity to prepare the state for kexec.
> + *     We are already in reboot syscall, and therefore userspace cannot mutate
> + *     the file anymore.
> + *   - unfreeze(): Undoes the actions of .freeze(), called if the live update
> + *     is aborted after the freeze phase.
> + *   - retrieve(): Reconstructs the file in the new kernel from the preserved
> + *     handle.
> + *   - finish(): Performs final check and cleanup in the new kernel. After
> + *     succesul finish call, LUO gives up ownership to this file.
> + *
> + * File Preservation Lifecycle happy path:
> + *
> + * 1. Preserve (Normal Operation): A userspace agent preserves files one by one
> + *    via an ioctl. For each file, luo_preserve_file() finds a compatible
> + *    handler, calls its .preserve() operation, and creates an internal &struct
> + *    luo_file to track the live state.
> + *
> + * 2. Freeze (Pre-Reboot): Just before the kexec, luo_file_freeze() is called.
> + *    It iterates through all preserved files, calls their respective .freeze()
> + *    operation, and serializes their final metadata (compatible string, token,
> + *    and data handle) into a contiguous memory block for KHO.
> + *
> + * 3. Deserialize: After kexec, luo_file_deserialize() runs when session gets
> + *    deserialized (which is when /dev/liveupdate is first opened). It reads the
> + *    serialized data from the KHO memory region and reconstructs the in-memory
> + *    list of &struct luo_file instances for the new kernel, linking them to
> + *    their corresponding handlers.
> + *
> + * 4. Retrieve (New Kernel - Userspace Ready): The userspace agent can now
> + *    restore file descriptors by providing a token. luo_retrieve_file()
> + *    searches for the matching token, calls the handler's .retrieve() op to
> + *    re-create the 'struct file', and returns a new FD. Files can be
> + *    retrieved in ANY order.
> + *
> + * 5. Finish (New Kernel - Cleanup): Once a session retrival is complete,
> + *    luo_file_finish() is called. It iterates through all files, invokes their
> + *    .finish() operations for final cleanup, and releases all associated kernel
> + *    resources.
> + *
> + * File Preservation Lifecycle unhappy paths:
> + *
> + * 1. Abort Before Reboot: If the userspace agent aborts the live update
> + *    process before calling reboot (e.g., by closing the session file
> + *    descriptor), the session's release handler calls
> + *    luo_file_unpreserve_files(). This invokes the .unpreserve() callback on
> + *    all preserved files, ensuring all allocated resources are cleaned up and
> + *    returning the system to a clean state.
> + *
> + * 2. Freeze Failure: During the reboot() syscall, if any handler's .freeze()
> + *    op fails, the .unfreeze() op is invoked on all previously *successful*
> + *    freezes to roll back their state. The reboot() syscall then returns an
> + *    error to userspace, canceling the live update.
> + *
> + * 3. Finish Failure: In the new kernel, if a handler's .finish() op fails,
> + *    the luo_file_finish() operation is aborted. LUO retains ownership of
> + *    all files within that session, including those that were not yet
> + *    processed. The userspace agent can attempt to call the finish operation
> + *    again later. If the issue cannot be resolved, these resources will be held
> + *    by LUO until the next live update cycle, at which point they will be
> + *    discarded.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/cleanup.h>
> +#include <linux/compiler.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/file.h>
> +#include <linux/fs.h>
> +#include <linux/io.h>
> +#include <linux/kexec_handover.h>
> +#include <linux/kho/abi/luo.h>
> +#include <linux/liveupdate.h>
> +#include <linux/module.h>
> +#include <linux/sizes.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include "luo_internal.h"
> +
> +static LIST_HEAD(luo_file_handler_list);
> +
> +/* 2 4K pages, give space for 128 files per file_set */
> +#define LUO_FILE_PGCNT		2ul
> +#define LUO_FILE_MAX							\
> +	((LUO_FILE_PGCNT << PAGE_SHIFT) / sizeof(struct luo_file_ser))
> +
> +/**
> + * struct luo_file - Represents a single preserved file instance.
> + * @fh:            Pointer to the &struct liveupdate_file_handler that manages
> + *                 this type of file.
> + * @file:          Pointer to the kernel's &struct file that is being preserved.
> + *                 This is NULL in the new kernel until the file is successfully
> + *                 retrieved.
> + * @serialized_data: The opaque u64 handle to the serialized state of the file.
> + *                 This handle is passed back to the handler's .freeze(),
> + *                 .retrieve(), and .finish() callbacks, allowing it to track
> + *                 and update its serialized state across phases.
> + * @retrieved:     A flag indicating whether a user/kernel in the new kernel has
> + *                 successfully called retrieve() on this file. This prevents
> + *                 multiple retrieval attempts.
> + * @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.
> + * @list:          The list_head linking this instance into its parent
> + *                 file_set's list of preserved files.
> + * @token:         The user-provided unique token used to identify this file.
> + *
> + * This structure is the core in-kernel representation of a single file being
> + * managed through a live update. An instance is created by luo_preserve_file()
> + * to link a 'struct file' to its corresponding handler, a user-provided token,
> + * and the serialized state handle returned by the handler's .preserve()
> + * operation.
> + *
> + * These instances are tracked in a per-file_set list. The @serialized_data
> + * field, which holds a handle to the file's serialized state, may be updated
> + * during the .freeze() callback before being serialized for the next kernel.
> + * After reboot, these structures are recreated by luo_file_deserialize() and
> + * are finally cleaned up by luo_file_finish().
> + */
> +struct luo_file {
> +	struct liveupdate_file_handler *fh;
> +	struct file *file;
> +	u64 serialized_data;
> +	bool retrieved;
> +	struct mutex mutex;
> +	struct list_head list;
> +	u64 token;
> +};
> +
> +static int luo_alloc_files_mem(struct luo_file_set *file_set)
> +{
> +	size_t size;
> +	void *mem;
> +
> +	if (file_set->files)
> +		return 0;
> +
> +	WARN_ON_ONCE(file_set->count);
> +
> +	size = LUO_FILE_PGCNT << PAGE_SHIFT;
> +	mem = kho_alloc_preserve(size);
> +	if (IS_ERR(mem))
> +		return PTR_ERR(mem);
> +
> +	file_set->files = mem;
> +
> +	return 0;
> +}
> +
> +static void luo_free_files_mem(struct luo_file_set *file_set)
> +{
> +	/* If file_set has files, no need to free preservation memory */
> +	if (file_set->count)
> +		return;
> +
> +	if (!file_set->files)
> +		return;
> +
> +	kho_unpreserve_free(file_set->files);
> +	file_set->files = NULL;
> +}
> +
> +static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
> +{
> +	struct luo_file *iter;
> +
> +	list_for_each_entry(iter, &file_set->files_list, list) {
> +		if (iter->token == token)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +/**
> + * 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.
> + *
> + * 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
> + * a co-owner of the file. This reference is held until the file is either
> + * unpreserved or successfully finished in the next kernel, preventing the file
> + * from being prematurely destroyed.
> + *
> + * This function orchestrates the first phase of preserving a file. It performs
> + * the following steps:
> + *
> + * 1. Validates that the @token is not already in use within the file_set.
> + * 2. Ensures the file_set's memory for files serialization is allocated
> + *    (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
> + *    and returns an opaque private data handle.
> + * 5. 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.
> + *
> + * In case of any failure, all intermediate allocations (file reference, memory
> + * for the 'luo_file' struct, etc.) are cleaned up before returning an error.
> + *
> + * Context: Can be called from an ioctl handler during normal system operation.
> + * Return: 0 on success. Returns a negative errno on failure:
> + *         -EEXIST if the token is already used.
> + *         -EBADF if the file descriptor is invalid.
> + *         -ENOSPC if the file_set is full.
> + *         -ENOENT if no compatible handler is found.
> + *         -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)
> +{
> +	struct liveupdate_file_op_args args = {0};
> +	struct liveupdate_file_handler *fh;
> +	struct luo_file *luo_file;
> +	struct file *file;
> +	int err;
> +
> +	if (luo_token_is_used(file_set, token))
> +		return -EEXIST;
> +
> +	file = fget(fd);
> +	if (!file)
> +		return -EBADF;
> +
> +	err = luo_alloc_files_mem(file_set);
> +	if (err)
> +		goto  err_files_mem;

Nit:                ^^ two spaces here.

> +
> +	if (file_set->count == LUO_FILE_MAX) {
> +		err = -ENOSPC;
> +		goto err_files_mem;
> +	}
> +
> +	err = -ENOENT;
> +	luo_list_for_each_private(fh, &luo_file_handler_list, list) {
> +		if (fh->ops->can_preserve(fh, file)) {
> +			err = 0;
> +			break;
> +		}
> +	}
> +
> +	/* err is still -ENOENT if no handler was found */
> +	if (err)
> +		goto err_files_mem;
> +
> +	luo_file = kzalloc(sizeof(*luo_file), GFP_KERNEL);
> +	if (!luo_file) {
> +		err = -ENOMEM;
> +		goto err_files_mem;
> +	}
> +
> +	luo_file->file = file;
> +	luo_file->fh = fh;
> +	luo_file->token = token;
> +	luo_file->retrieved = false;
> +	mutex_init(&luo_file->mutex);
> +
> +	args.handler = fh;
> +	args.file = file;
> +	err = fh->ops->preserve(&args);
> +	if (err)
> +		goto err_kfree;
> +
> +	luo_file->serialized_data = args.serialized_data;
> +	list_add_tail(&luo_file->list, &file_set->files_list);
> +	file_set->count++;
> +
> +	return 0;
> +
> +err_kfree:
> +	mutex_destroy(&luo_file->mutex);
> +	kfree(luo_file);
> +err_files_mem:
> +	fput(file);
> +	luo_free_files_mem(file_set);
> +
> +	return err;
> +}
> +
> +/**
> + * luo_file_unpreserve_files - Unpreserves all files from a file_set.
> + * @file_set: The files to be cleaned up.
> + *
> + * This function serves as the primary cleanup path for a file_set. It is
> + * invoked when the userspace agent closes the file_set's file descriptor.
> + *
> + * For each file, it performs the following cleanup actions:
> + *   1. Calls the handler's .unpreserve() callback to allow the handler to
> + *      release any resources it allocated.
> + *   2. Removes the file from the file_set's internal tracking list.
> + *   3. Releases the reference to the 'struct file' that was taken by
> + *      luo_preserve_file() via fput(), returning ownership.
> + *   4. Frees the memory associated with the internal 'struct luo_file'.
> + *
> + * After all individual files are unpreserved, it frees the contiguous memory
> + * block that was allocated to hold their serialization data.
> + */
> +void luo_file_unpreserve_files(struct luo_file_set *file_set)
> +{
> +	struct luo_file *luo_file;
> +
> +	while (!list_empty(&file_set->files_list)) {
> +		struct liveupdate_file_op_args args = {0};
> +
> +		luo_file = list_last_entry(&file_set->files_list,
> +					   struct luo_file, list);
> +
> +		args.handler = luo_file->fh;
> +		args.file = luo_file->file;
> +		args.serialized_data = luo_file->serialized_data;
> +		luo_file->fh->ops->unpreserve(&args);
> +
> +		list_del(&luo_file->list);
> +		file_set->count--;
> +
> +		fput(luo_file->file);
> +		mutex_destroy(&luo_file->mutex);
> +		kfree(luo_file);
> +	}
> +
> +	luo_free_files_mem(file_set);
> +}
> +
> +static int luo_file_freeze_one(struct luo_file_set *file_set,
> +			       struct luo_file *luo_file)
> +{
> +	int err = 0;
> +
> +	guard(mutex)(&luo_file->mutex);
> +
> +	if (luo_file->fh->ops->freeze) {
> +		struct liveupdate_file_op_args args = {0};
> +
> +		args.handler = luo_file->fh;
> +		args.file = luo_file->file;
> +		args.serialized_data = luo_file->serialized_data;
> +
> +		err = luo_file->fh->ops->freeze(&args);
> +		if (!err)
> +			luo_file->serialized_data = args.serialized_data;
> +	}
> +
> +	return err;
> +}
> +
> +static void luo_file_unfreeze_one(struct luo_file_set *file_set,
> +				  struct luo_file *luo_file)
> +{
> +	guard(mutex)(&luo_file->mutex);
> +
> +	if (luo_file->fh->ops->unfreeze) {
> +		struct liveupdate_file_op_args args = {0};
> +
> +		args.handler = luo_file->fh;
> +		args.file = luo_file->file;
> +		args.serialized_data = luo_file->serialized_data;
> +
> +		luo_file->fh->ops->unfreeze(&args);
> +	}
> +
> +	luo_file->serialized_data = 0;
> +}
> +
> +static void __luo_file_unfreeze(struct luo_file_set *file_set,
> +				struct luo_file *failed_entry)
> +{
> +	struct list_head *files_list = &file_set->files_list;
> +	struct luo_file *luo_file;
> +
> +	list_for_each_entry(luo_file, files_list, list) {
> +		if (luo_file == failed_entry)
> +			break;
> +
> +		luo_file_unfreeze_one(file_set, luo_file);
> +	}
> +
> +	memset(file_set->files, 0, LUO_FILE_PGCNT << PAGE_SHIFT);
> +}
> +
> +/**
> + * luo_file_freeze - Freezes all preserved files and serializes their metadata.
> + * @file_set:     The file_set whose files are to be frozen.
> + * @file_set_ser: Where to put the serialized file_set.
> + *
> + * This function is called from the reboot() syscall path, just before the
> + * kernel transitions to the new image via kexec. Its purpose is to perform the
> + * final preparation and serialization of all preserved files in the file_set.
> + *
> + * It iterates through each preserved file in FIFO order (the order of
> + * preservation) and performs two main actions:
> + *
> + * 1. Freezes the File: It calls the handler's .freeze() callback for each
> + *    file. This gives the handler a final opportunity to quiesce the device or
> + *    prepare its state for the upcoming reboot. The handler may update its
> + *    private data handle during this step.
> + *
> + * 2. Serializes Metadata: After a successful freeze, it copies the final file
> + *    metadata—the handler's compatible string, the user token, and the final
> + *    private data handle—into the pre-allocated contiguous memory buffer
> + *    (file_set->files) that will be handed over to the next kernel via KHO.
> + *
> + * Error Handling (Rollback):
> + * This function is atomic. If any handler's .freeze() operation fails, the
> + * entire live update is aborted. The __luo_file_unfreeze() helper is
> + * immediately called to invoke the .unfreeze() op on all files that were
> + * successfully frozen before the point of failure, rolling them back to a
> + * running state. The function then returns an error, causing the reboot()
> + * syscall to fail.
> + *
> + * Context: Called only from the liveupdate_reboot() path.
> + * Return: 0 on success, or a negative errno on failure.
> + */
> +int luo_file_freeze(struct luo_file_set *file_set,
> +		    struct luo_file_set_ser *file_set_ser)
> +{
> +	struct luo_file_ser *file_ser = file_set->files;
> +	struct luo_file *luo_file;
> +	int err;
> +	int i;
> +
> +	if (!file_set->count)
> +		return 0;
> +
> +	if (WARN_ON(!file_ser))
> +		return -EINVAL;
> +
> +	i = 0;
> +	list_for_each_entry(luo_file, &file_set->files_list, list) {
> +		err = luo_file_freeze_one(file_set, luo_file);
> +		if (err < 0) {
> +			pr_warn("Freeze failed for token[%#0llx] handler[%s] err[%pe]\n",
> +				luo_file->token, luo_file->fh->compatible,
> +				ERR_PTR(err));
> +			goto err_unfreeze;
> +		}
> +
> +		strscpy(file_ser[i].compatible, luo_file->fh->compatible,
> +			sizeof(file_ser[i].compatible));
> +		file_ser[i].data = luo_file->serialized_data;
> +		file_ser[i].token = luo_file->token;
> +		i++;
> +	}
> +
> +	file_set_ser->count = file_set->count;
> +	if (file_set->files)
> +		file_set_ser->files = virt_to_phys(file_set->files);
> +
> +	return 0;
> +
> +err_unfreeze:
> +	__luo_file_unfreeze(file_set, luo_file);
> +
> +	return err;
> +}
> +
> +/**
> + * luo_file_unfreeze - Unfreezes all files in a file_set and clear serialization
> + * @file_set:     The file_set whose files are to be unfrozen.
> + * @file_set_ser: Serialized file_set.
> + *
> + * This function rolls back the state of all files in a file_set after the
> + * freeze phase has begun but must be aborted. It is the counterpart to
> + * luo_file_freeze().
> + *
> + * It invokes the __luo_file_unfreeze() helper with a NULL argument, which
> + * signals the helper to iterate through all files in the file_set and call
> + * their respective .unfreeze() handler callbacks.
> + *
> + * Context: This is called when the live update is aborted during
> + *          the reboot() syscall, after luo_file_freeze() has been called.
> + */
> +void luo_file_unfreeze(struct luo_file_set *file_set,
> +		       struct luo_file_set_ser *file_set_ser)
> +{
> +	if (!file_set->count)
> +		return;
> +
> +	__luo_file_unfreeze(file_set, NULL);
> +	memset(file_set_ser, 0, sizeof(*file_set_ser));
> +}
> +
> +/**
> + * 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.
> + * @filep:    Output parameter; on success, this is populated with a pointer
> + *            to the newly retrieved 'struct file'.
> + *
> + * This function is the primary mechanism for recreating a file in the new
> + * kernel after a live update. It searches the file_set's list of deserialized
> + * files for an entry matching the provided @token.
> + *
> + * 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.
> + *
> + * File retrieval can happen in any order; it is not bound by the order of
> + * preservation.
> + *
> + * Context: Can be called from an ioctl or other in-kernel code in the new
> + *          kernel.
> + * Return: 0 on success. Returns a negative errno on failure:
> + *         -ENOENT if no file with the matching token is found.
> + *         Any error code returned by the handler's .retrieve() op.
> + */
> +int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
> +		      struct file **filep)
> +{
> +	struct liveupdate_file_op_args args = {0};
> +	struct luo_file *luo_file;
> +	int err;
> +
> +	if (list_empty(&file_set->files_list))
> +		return -ENOENT;
> +
> +	list_for_each_entry(luo_file, &file_set->files_list, list) {
> +		if (luo_file->token == token)
> +			break;
> +	}
> +
> +	if (luo_file->token != token)
> +		return -ENOENT;
> +
> +	guard(mutex)(&luo_file->mutex);
> +	if (luo_file->retrieved) {
> +		/*
> +		 * Someone is asking for this file again, so get a reference
> +		 * for them.
> +		 */
> +		get_file(luo_file->file);
> +		*filep = luo_file->file;
> +		return 0;
> +	}
> +
> +	args.handler = luo_file->fh;
> +	args.serialized_data = luo_file->serialized_data;
> +	err = luo_file->fh->ops->retrieve(&args);
> +	if (!err) {
> +		luo_file->file = args.file;
> +
> +		/* Get reference so we can keep this file in LUO until finish */
> +		get_file(luo_file->file);
> +		*filep = luo_file->file;
> +		luo_file->retrieved = true;
> +	}
> +
> +	return err;
> +}
> +
> +static int luo_file_can_finish_one(struct luo_file_set *file_set,
> +				   struct luo_file *luo_file)
> +{
> +	bool can_finish = true;
> +
> +	guard(mutex)(&luo_file->mutex);
> +
> +	if (luo_file->fh->ops->can_finish) {
> +		struct liveupdate_file_op_args args = {0};
> +
> +		args.handler = luo_file->fh;
> +		args.file = luo_file->file;
> +		args.serialized_data = luo_file->serialized_data;
> +		args.retrieved = luo_file->retrieved;
> +		can_finish = luo_file->fh->ops->can_finish(&args);
> +	}
> +
> +	return can_finish ? 0 : -EBUSY;
> +}
> +
> +static void luo_file_finish_one(struct luo_file_set *file_set,
> +				struct luo_file *luo_file)
> +{
> +	struct liveupdate_file_op_args args = {0};
> +
> +	guard(mutex)(&luo_file->mutex);
> +
> +	args.handler = luo_file->fh;
> +	args.file = luo_file->file;
> +	args.serialized_data = luo_file->serialized_data;
> +	args.retrieved = luo_file->retrieved;
> +
> +	luo_file->fh->ops->finish(&args);
> +}
> +
> +/**
> + * luo_file_finish - Completes the lifecycle for all files in a file_set.
> + * @file_set: The file_set to be finalized.
> + *
> + * This function orchestrates the final teardown of a live update file_set in
> + * the new kernel. It should be called after all necessary files have been
> + * retrieved and the userspace agent is ready to release the preserved state.
> + *
> + * The function iterates through all tracked files. For each file, it performs
> + * the following sequence of cleanup actions:
> + *
> + * 1. If file is not yet retrieved, retrieves it, and calls can_finish() on
> + *    every file in the file_set. If all can_finish return true, continue to
> + *    finish.
> + * 2. Calls the handler's .finish() callback (via luo_file_finish_one) to
> + *    allow for final resource cleanup within the handler.
> + * 3. Releases LUO's ownership reference on the 'struct file' via fput(). This
> + *    is the counterpart to the get_file() call in luo_retrieve_file().
> + * 4. Removes the 'struct luo_file' from the file_set's internal list.
> + * 5. Frees the memory for the 'struct luo_file' instance itself.
> + *
> + * After successfully finishing all individual files, it frees the
> + * contiguous memory block that was used to transfer the serialized metadata
> + * from the previous kernel.
> + *
> + * Error Handling (Atomic Failure):
> + * This operation is atomic. If any handler's .can_finish() op fails, the entire
> + * function aborts immediately and returns an error.
> + *
> + * Context: Can be called from an ioctl handler in the new kernel.
> + * Return: 0 on success, or a negative errno on failure.
> + */
> +int luo_file_finish(struct luo_file_set *file_set)
> +{
> +	struct list_head *files_list = &file_set->files_list;
> +	struct luo_file *luo_file;
> +	int err;
> +
> +	if (!file_set->count)
> +		return 0;
> +
> +	list_for_each_entry(luo_file, files_list, list) {
> +		err = luo_file_can_finish_one(file_set, luo_file);
> +		if (err)
> +			return err;
> +	}
> +
> +	while (!list_empty(&file_set->files_list)) {
> +		luo_file = list_last_entry(&file_set->files_list,
> +					   struct luo_file, list);
> +
> +		luo_file_finish_one(file_set, luo_file);
> +
> +		if (luo_file->file)
> +			fput(luo_file->file);
> +		list_del(&luo_file->list);
> +		file_set->count--;
> +		mutex_destroy(&luo_file->mutex);
> +		kfree(luo_file);
> +	}
> +
> +	if (file_set->files) {
> +		kho_restore_free(file_set->files);
> +		file_set->files = NULL;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * luo_file_deserialize - Reconstructs the list of preserved files in the new kernel.
> + * @file_set:     The incoming file_set to fill with deserialized data.
> + * @file_set_ser: Serialized KHO file_set data from the previous kernel.
> + *
> + * This function is called during the early boot process of the new kernel. It
> + * takes the raw, contiguous memory block of 'struct luo_file_ser' entries,
> + * provided by the previous kernel, and transforms it back into a live,
> + * in-memory linked list of 'struct luo_file' instances.
> + *
> + * For each serialized entry, it performs the following steps:
> + *   1. Reads the 'compatible' string.
> + *   2. Searches the global list of registered file handlers for one that
> + *      matches the compatible string.
> + *   3. Allocates a new 'struct luo_file'.
> + *   4. Populates the new structure with the deserialized data (token, private
> + *      data handle) and links it to the found handler. The 'file' pointer is
> + *      initialized to NULL, as the file has not been retrieved yet.
> + *   5. Adds the new 'struct luo_file' to the file_set's files_list.
> + *
> + * This prepares the file_set for userspace, which can later call
> + * luo_retrieve_file() to restore the actual file descriptors.
> + *
> + * Context: Called from session deserialization.
> + */
> +int luo_file_deserialize(struct luo_file_set *file_set,
> +			 struct luo_file_set_ser *file_set_ser)
> +{
> +	struct luo_file_ser *file_ser;
> +	u64 i;
> +
> +	if (!file_set_ser->files) {
> +		WARN_ON(file_set_ser->count);
> +		return 0;
> +	}
> +
> +	file_set->count = file_set_ser->count;
> +	file_set->files = phys_to_virt(file_set_ser->files);
> +
> +	/*
> +	 * Note on error handling:
> +	 *
> +	 * If deserialization fails (e.g., allocation failure or corrupt data),
> +	 * we intentionally skip cleanup of files that were already restored.
> +	 *
> +	 * A partial failure leaves the preserved state inconsistent.
> +	 * Implementing a safe "undo" to unwind complex dependencies (sessions,
> +	 * files, hardware state) is error-prone and provides little value, as
> +	 * the system is effectively in a broken state.
> +	 *
> +	 * We treat these resources as leaked. The expected recovery path is for
> +	 * userspace to detect the failure and trigger a reboot, which will
> +	 * reliably reset devices and reclaim memory.
> +	 */
> +	file_ser = file_set->files;
> +	for (i = 0; i < file_set->count; i++) {
> +		struct liveupdate_file_handler *fh;
> +		bool handler_found = false;
> +		struct luo_file *luo_file;
> +
> +		luo_list_for_each_private(fh, &luo_file_handler_list, list) {
> +			if (!strcmp(fh->compatible, file_ser[i].compatible)) {
> +				handler_found = true;
> +				break;
> +			}
> +		}
> +
> +		if (!handler_found) {
> +			pr_warn("No registered handler for compatible '%s'\n",
> +				file_ser[i].compatible);
> +			return -ENOENT;
> +		}
> +
> +		luo_file = kzalloc(sizeof(*luo_file), GFP_KERNEL);
> +		if (!luo_file)
> +			return -ENOMEM;
> +
> +		luo_file->fh = fh;
> +		luo_file->file = NULL;
> +		luo_file->serialized_data = file_ser[i].data;
> +		luo_file->token = file_ser[i].token;
> +		luo_file->retrieved = false;
> +		mutex_init(&luo_file->mutex);
> +		list_add_tail(&luo_file->list, &file_set->files_list);
> +	}
> +
> +	return 0;
> +}
> +
> +void luo_file_set_init(struct luo_file_set *file_set)
> +{
> +	INIT_LIST_HEAD(&file_set->files_list);
> +}
> +
> +void luo_file_set_destroy(struct luo_file_set *file_set)
> +{
> +	WARN_ON(file_set->count);
> +	WARN_ON(!list_empty(&file_set->files_list));
> +}
> +
> +/**
> + * liveupdate_register_file_handler - Register a file handler with LUO.
> + * @fh: Pointer to a caller-allocated &struct liveupdate_file_handler.
> + * The caller must initialize this structure, including a unique
> + * 'compatible' string and a valid 'fh' callbacks. This function adds the
> + * handler to the global list of supported file handlers.
> + *
> + * Context: Typically called during module initialization for file types that
> + * support live update preservation.
> + *
> + * Return: 0 on success. Negative errno on failure.
> + */
> +int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
> +{
> +	struct liveupdate_file_handler *fh_iter;
> +	int err;
> +
> +	if (!liveupdate_enabled())
> +		return -EOPNOTSUPP;
> +
> +	/* Sanity check that all required callbacks are set */
> +	if (!fh->ops->preserve || !fh->ops->unpreserve ||
> +	    !fh->ops->retrieve || !fh->ops->finish) {

You are still missing a check for can_preserve() here. It is a mandatory
callback and luo_preserve_file() calls it without checking for NULL.

With these and Mike's comments addressed,

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Ensure the system is quiescent (no active sessions).
> +	 * This prevents registering new handlers while sessions are active or
> +	 * while deserialization is in progress.
> +	 */
> +	if (!luo_session_quiesce())
> +		return -EBUSY;
> +
> +	/* Check for duplicate compatible strings */
> +	luo_list_for_each_private(fh_iter, &luo_file_handler_list, list) {
> +		if (!strcmp(fh_iter->compatible, fh->compatible)) {
> +			pr_err("File handler registration failed: Compatible string '%s' already registered.\n",
> +			       fh->compatible);
> +			err = -EEXIST;
> +			goto err_resume;
> +		}
> +	}
> +
> +	/* Pin the module implementing the handler */
> +	if (!try_module_get(fh->ops->owner)) {
> +		err = -EAGAIN;
> +		goto err_resume;
> +	}
> +
> +	INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, list));
> +	list_add_tail(&ACCESS_PRIVATE(fh, list), &luo_file_handler_list);
> +	luo_session_resume();
> +
> +	return 0;
> +
> +err_resume:
> +	luo_session_resume();
> +	return err;
> +}
> +
> +/**
> + * liveupdate_unregister_file_handler - Unregister a liveupdate file handler
> + * @fh: The file handler to unregister
> + *
> + * Unregisters the file handler from the liveupdate core. This function
> + * reverses the operations of liveupdate_register_file_handler().
> + *
> + * It ensures safe removal by checking that:
> + * No live update session is currently in progress.
> + *
> + * If the unregistration fails, the internal test state is reverted.
> + *
> + * Return: 0 Success. -EOPNOTSUPP when live update is not enabled. -EBUSY A live
> + * update is in progress, can't quiesce live update.
> + */
> +int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
> +{
> +	if (!liveupdate_enabled())
> +		return -EOPNOTSUPP;
> +
> +	if (!luo_session_quiesce())
> +		return -EBUSY;
> +
> +	list_del(&ACCESS_PRIVATE(fh, list));
> +	module_put(fh->ops->owner);
> +	luo_session_resume();
> +
> +	return 0;
> +}
> diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
> index 1292ac47eef8..c8973b543d1d 100644
> --- a/kernel/liveupdate/luo_internal.h
> +++ b/kernel/liveupdate/luo_internal.h
> @@ -40,6 +40,28 @@ static inline int luo_ucmd_respond(struct luo_ucmd *ucmd,
>   */
>  #define luo_restore_fail(__fmt, ...) panic(__fmt, ##__VA_ARGS__)
>  
> +/* Mimics list_for_each_entry() but for private list head entries */
> +#define luo_list_for_each_private(pos, head, member)				\
> +	for (struct list_head *__iter = (head)->next;				\
> +	     __iter != (head) &&						\
> +	     ({ pos = container_of(__iter, typeof(*(pos)), member); 1; });	\
> +	     __iter = __iter->next)
> +
> +/**
> + * struct luo_file_set - A set of files that belong to the same sessions.
> + * @files_list: An ordered list of files associated with this session, it is
> + *              ordered by preservation time.
> + * @files:      The physically contiguous memory block that holds the serialized
> + *              state of files.
> + * @count:      A counter tracking the number of files currently stored in the
> + *              @files_list for this session.
> + */
> +struct luo_file_set {
> +	struct list_head files_list;
> +	struct luo_file_ser *files;
> +	long count;
> +};
> +
>  /**
>   * struct luo_session - Represents an active or incoming Live Update session.
>   * @name:       A unique name for this session, used for identification and
> @@ -50,6 +72,7 @@ static inline int luo_ucmd_respond(struct luo_ucmd *ucmd,
>   *              previous kernel) sessions.
>   * @retrieved:  A boolean flag indicating whether this session has been
>   *              retrieved by a consumer in the new kernel.
> + * @file_set:   A set of files that belong to this session.
>   * @mutex:      protects fields in the luo_session.
>   */
>  struct luo_session {
> @@ -57,6 +80,7 @@ struct luo_session {
>  	struct luo_session_ser *ser;
>  	struct list_head list;
>  	bool retrieved;
> +	struct luo_file_set file_set;
>  	struct mutex mutex;
>  };
>  
> @@ -69,4 +93,18 @@ int luo_session_deserialize(void);
>  bool luo_session_quiesce(void);
>  void luo_session_resume(void);
>  
> +int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd);
> +void luo_file_unpreserve_files(struct luo_file_set *file_set);
> +int luo_file_freeze(struct luo_file_set *file_set,
> +		    struct luo_file_set_ser *file_set_ser);
> +void luo_file_unfreeze(struct luo_file_set *file_set,
> +		       struct luo_file_set_ser *file_set_ser);
> +int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
> +		      struct file **filep);
> +int luo_file_finish(struct luo_file_set *file_set);
> +int luo_file_deserialize(struct luo_file_set *file_set,
> +			 struct luo_file_set_ser *file_set_ser);
> +void luo_file_set_init(struct luo_file_set *file_set);
> +void luo_file_set_destroy(struct luo_file_set *file_set);
> +
>  #endif /* _LINUX_LUO_INTERNAL_H */

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v7 06/22] liveupdate: luo_file: implement file systems callbacks
From: Pratyush Yadav @ 2025-11-24 15:47 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Pasha Tatashin, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <mafs0tsyjxwoa.fsf@kernel.org>

Hi Pasha,

Sorry, I accidentally sent this without trimming the context first.

Below is the version with the relevant bits:

 On Sat, Nov 22 2025, Pasha Tatashin wrote:

> This patch implements the core mechanism for managing preserved
> files throughout the live update lifecycle. It provides the logic to
> invoke the file handler callbacks (preserve, unpreserve, freeze,
> unfreeze, retrieve, and finish) at the appropriate stages.
>
> During the reboot phase, luo_file_freeze() serializes the final
> metadata for each file (handler compatible string, token, and data
> handle) into a memory region preserved by KHO. In the new kernel,
> luo_file_deserialize() reconstructs the in-memory file list from this
> data, preparing the session for retrieval.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
>  include/linux/kho/abi/luo.h      |  39 +-
>  include/linux/liveupdate.h       |  98 ++++
>  kernel/liveupdate/Makefile       |   1 +
>  kernel/liveupdate/luo_file.c     | 882 +++++++++++++++++++++++++++++++
>  kernel/liveupdate/luo_internal.h |  38 ++
>  5 files changed, 1057 insertions(+), 1 deletion(-)
>  create mode 100644 kernel/liveupdate/luo_file.c
>
> diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h
> index a2d2940eca6b..fc143f243871 100644
> --- a/include/linux/kho/abi/luo.h
> +++ b/include/linux/kho/abi/luo.h
> @@ -65,6 +65,11 @@
>   *     Metadata for a single session, including its name and a physical pointer
>   *     to another preserved memory block containing an array of
>   *     `struct luo_file_ser` for all files in that session.
> + *
> + *   - struct luo_file_ser:
> + *     Metadata for a single preserved file. Contains the `compatible` string to
> + *     find the correct handler in the new kernel, a user-provided `token` for
> + *     identification, and an opaque `data` handle for the handler to use.
>   */
>  
>  #ifndef _LINUX_KHO_ABI_LUO_H
> @@ -82,13 +87,43 @@
>  #define LUO_FDT_COMPATIBLE	"luo-v1"
>  #define LUO_FDT_LIVEUPDATE_NUM	"liveupdate-number"
>  
> +#define LIVEUPDATE_HNDL_COMPAT_LENGTH	48
> +
> +/**
> + * struct luo_file_ser - Represents the serialized preserves files.
> + * @compatible:  File handler compatible string.
> + * @data:        Private data
> + * @token:       User provided token for this file
> + *
> + * If this structure is modified, LUO_SESSION_COMPATIBLE must be updated.
> + */
> +struct luo_file_ser {
> +	char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
> +	u64 data;
> +	u64 token;
> +} __packed;
> +
> +/**
> + * struct luo_file_set_ser - Represents the serialized metadata for file set
> + * @files:   The physical address of a contiguous memory block that holds
> + *           the serialized state of files (array of luo_file_ser) in this file
> + *           set.
> + * @count:   The total number of files that were part of this session during
> + *           serialization. Used for iteration and validation during
> + *           restoration.
> + */
> +struct luo_file_set_ser {
> +	u64 files;
> +	u64 count;
> +} __packed;

 The change to using file_set looks a lot nicer than what the previous
 version was doing!

> +
>  /*
>   * LUO FDT session node
>   * LUO_FDT_SESSION_HEADER:  is a u64 physical address of struct
>   *                          luo_session_header_ser
>   */
>  #define LUO_FDT_SESSION_NODE_NAME	"luo-session"
> -#define LUO_FDT_SESSION_COMPATIBLE	"luo-session-v1"
> +#define LUO_FDT_SESSION_COMPATIBLE	"luo-session-v2"
>  #define LUO_FDT_SESSION_HEADER		"luo-session-header"
>  
>  /**
[...]
> +int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
> +{
> +	struct liveupdate_file_op_args args = {0};
> +	struct liveupdate_file_handler *fh;
> +	struct luo_file *luo_file;
> +	struct file *file;
> +	int err;
> +
> +	if (luo_token_is_used(file_set, token))
> +		return -EEXIST;
> +
> +	file = fget(fd);
> +	if (!file)
> +		return -EBADF;
> +
> +	err = luo_alloc_files_mem(file_set);
> +	if (err)
> +		goto  err_files_mem;

 Nit:                ^^ two spaces here.

> +
> +	if (file_set->count == LUO_FILE_MAX) {
> +		err = -ENOSPC;
> +		goto err_files_mem;
> +	}
> +
> +	err = -ENOENT;
> +	luo_list_for_each_private(fh, &luo_file_handler_list, list) {
> +		if (fh->ops->can_preserve(fh, file)) {
> +			err = 0;
> +			break;
> +		}
> +	}
> +
[...]
> +int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
> +{
> +	struct liveupdate_file_handler *fh_iter;
> +	int err;
> +
> +	if (!liveupdate_enabled())
> +		return -EOPNOTSUPP;
> +
> +	/* Sanity check that all required callbacks are set */
> +	if (!fh->ops->preserve || !fh->ops->unpreserve ||
> +	    !fh->ops->retrieve || !fh->ops->finish) {

 You are still missing a check for can_preserve() here. It is a mandatory
 callback and luo_preserve_file() calls it without checking for NULL.

 With these and Mike's comments addressed,

 Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

> +		return -EINVAL;
> +	}
> +
[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v7 08/22] docs: add luo documentation
From: Pratyush Yadav @ 2025-11-24 15:49 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-9-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> Add the documentation files for the Live Update Orchestrator
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply

* Re: [PATCH v7 16/22] selftests/liveupdate: Add userspace API selftests
From: Pratyush Yadav @ 2025-11-24 15:56 UTC (permalink / raw)
  To: Pasha Tatashin
  Cc: pratyush, jasonmiu, graf, rppt, dmatlack, rientjes, corbet,
	rdunlap, ilpo.jarvinen, kanie, ojeda, aliceryhl, masahiroy, akpm,
	tj, yoann.congal, mmaurer, roman.gushchin, chenridong, axboe,
	mark.rutland, jannh, vincent.guittot, hannes, dan.j.williams,
	david, joel.granados, rostedt, anna.schumaker, song, linux,
	linux-kernel, linux-doc, linux-mm, gregkh, tglx, mingo, bp,
	dave.hansen, x86, hpa, rafael, dakr, bartosz.golaszewski,
	cw00.choi, myungjoo.ham, yesanishhere, Jonathan.Cameron,
	quic_zijuhu, aleksander.lobakin, ira.weiny, andriy.shevchenko,
	leon, lukas, bhelgaas, wagi, djeffery, stuart.w.hayes, lennart,
	brauner, linux-api, linux-fsdevel, saeedm, ajayachandra, jgg,
	parav, leonro, witu, hughd, skhawaja, chrisl
In-Reply-To: <20251122222351.1059049-17-pasha.tatashin@soleen.com>

On Sat, Nov 22 2025, Pasha Tatashin wrote:

> Introduce a selftest suite for LUO. These tests validate the core
> userspace-facing API provided by the /dev/liveupdate device and its
> associated ioctls.
>
> The suite covers fundamental device behavior, session management, and
> the file preservation mechanism using memfd as a test case. This
> provides regression testing for the LUO uAPI.
>
> The following functionality is verified:
>
> Device Access:
>     Basic open and close operations on /dev/liveupdate.
>     Enforcement of exclusive device access (verifying EBUSY on a
>     second open).
>
> Session Management:
>     Successful creation of sessions with unique names.
>     Failure to create sessions with duplicate names.
>
> File Preservation:
>     Preserving a single memfd and verifying its content remains
>     intact post-preservation.
>     Preserving multiple memfds within a single session, each with
>     unique data.
>     A complex scenario involving multiple sessions, each containing
>     a mix of empty and data-filled memfds.
>
> Note: This test suite is limited to verifying the pre-kexec
> functionality of LUO (e.g., session creation, file preservation).
> The post-kexec restoration of resources is not covered, as the kselftest
> framework does not currently support orchestrating a reboot and
> continuing execution in the new kernel.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>

Reviewed-by: Pratyush Yadav <pratyush@kernel.org>

[...]

-- 
Regards,
Pratyush Yadav

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox