[PATCH v7 2/2] kho: Remove finalize state and clients

Mike Rapoport rppt at kernel.org
Tue Jan 20 09:25:01 PST 2026


On Thu, Jan 15, 2026 at 07:44:32PM -0800, Jason Miu wrote:
> Eliminate the `kho_finalize()` function and its associated state from
> the KHO subsystem. The transition to a radix tree for memory tracking
> makes the explicit "finalize" state and its serialization step
> obsolete.
> 
> Remove the `kho_finalize()` and `kho_finalized()` APIs and their stub
> implementations. Update KHO client code and the debugfs interface to
> no longer call or depend on the `kho_finalize()` mechanism.
> 
> Complete the move towards a stateless KHO, simplifying the overall
> design by removing unnecessary state management.
> 
> Signed-off-by: Jason Miu <jasonmiu at google.com>

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

> ---
>  Documentation/admin-guide/mm/kho.rst        | 53 +++++----------------
>  Documentation/core-api/kho/index.rst        | 12 -----
>  kernel/liveupdate/kexec_handover.c          | 21 +-------
>  kernel/liveupdate/kexec_handover_debugfs.c  | 23 ---------
>  kernel/liveupdate/kexec_handover_internal.h |  3 --
>  kernel/liveupdate/luo_core.c                | 12 +----
>  kernel/liveupdate/luo_flb.c                 |  2 +-
>  tools/testing/selftests/kho/init.c          | 20 --------
>  8 files changed, 14 insertions(+), 132 deletions(-)
> 
> diff --git a/Documentation/admin-guide/mm/kho.rst b/Documentation/admin-guide/mm/kho.rst
> index 6dc18ed4b886..454b378cf239 100644
> --- a/Documentation/admin-guide/mm/kho.rst
> +++ b/Documentation/admin-guide/mm/kho.rst
> @@ -28,20 +28,10 @@ per NUMA node scratch regions on boot.
>  Perform a KHO kexec
>  ===================
>  
> -First, before you perform a KHO kexec, you need to move the system into
> -the :ref:`KHO finalization phase <kho-finalization-phase>` ::
> -
> -  $ echo 1 > /sys/kernel/debug/kho/out/finalize
> -
> -After this command, the KHO FDT is available in
> -``/sys/kernel/debug/kho/out/fdt``. Other subsystems may also register
> -their own preserved sub FDTs under
> -``/sys/kernel/debug/kho/out/sub_fdts/``.
> -
> -Next, load the target payload and kexec into it. It is important that you
> -use the ``-s`` parameter to use the in-kernel kexec file loader, as user
> -space kexec tooling currently has no support for KHO with the user space
> -based file loader ::
> +To perform a KHO kexec, load the target payload and kexec into it. It
> +is important that you use the ``-s`` parameter to use the in-kernel
> +kexec file loader, as user space kexec tooling currently has no
> +support for KHO with the user space based file loader ::
>  
>    # kexec -l /path/to/bzImage --initrd /path/to/initrd -s
>    # kexec -e
> @@ -52,40 +42,19 @@ For example, if you used ``reserve_mem`` command line parameter to create
>  an early memory reservation, the new kernel will have that memory at the
>  same physical address as the old kernel.
>  
> -Abort a KHO exec
> -================
> -
> -You can move the system out of KHO finalization phase again by calling ::
> -
> -  $ echo 0 > /sys/kernel/debug/kho/out/active
> -
> -After this command, the KHO FDT is no longer available in
> -``/sys/kernel/debug/kho/out/fdt``.
> -
>  debugfs Interfaces
>  ==================
>  
> +These debugfs interfaces are available when the kernel is compiled with
> +``CONFIG_KEXEC_HANDOVER_DEBUGFS`` enabled.
> +
>  Currently KHO creates the following debugfs interfaces. Notice that these
>  interfaces may change in the future. They will be moved to sysfs once KHO is
>  stabilized.
>  
> -``/sys/kernel/debug/kho/out/finalize``
> -    Kexec HandOver (KHO) allows Linux to transition the state of
> -    compatible drivers into the next kexec'ed kernel. To do so,
> -    device drivers will instruct KHO to preserve memory regions,
> -    which could contain serialized kernel state.
> -    While the state is serialized, they are unable to perform
> -    any modifications to state that was serialized, such as
> -    handed over memory allocations.
> -
> -    When this file contains "1", the system is in the transition
> -    state. When contains "0", it is not. To switch between the
> -    two states, echo the respective number into this file.
> -
>  ``/sys/kernel/debug/kho/out/fdt``
> -    When KHO state tree is finalized, the kernel exposes the
> -    flattened device tree blob that carries its current KHO
> -    state in this file. Kexec user space tooling can use this
> +    The kernel exposes the flattened device tree blob that carries its
> +    current KHO state in this file. Kexec user space tooling can use this
>      as input file for the KHO payload image.
>  
>  ``/sys/kernel/debug/kho/out/scratch_len``
> @@ -100,8 +69,8 @@ stabilized.
>      it should place its payload images.
>  
>  ``/sys/kernel/debug/kho/out/sub_fdts/``
> -    In the KHO finalization phase, KHO producers register their own
> -    FDT blob under this directory.
> +    KHO producers can register their own FDT blob another binary blob under

Nit:                                      ^ FDT or another binary blob

> +    this directory.
>  
>  ``/sys/kernel/debug/kho/in/fdt``
>      When the kernel was booted with Kexec HandOver (KHO),
> diff --git a/Documentation/core-api/kho/index.rst b/Documentation/core-api/kho/index.rst
> index 002bdf0beb2e..0a2dee4f8e7d 100644
> --- a/Documentation/core-api/kho/index.rst
> +++ b/Documentation/core-api/kho/index.rst
> @@ -71,18 +71,6 @@ for boot memory allocations and as target memory for kexec blobs, some parts
>  of that memory region may be reserved. These reservations are irrelevant for
>  the next KHO, because kexec can overwrite even the original kernel.
>  
> -.. _kho-finalization-phase:
> -
> -KHO finalization phase
> -======================
> -
> -To enable user space based kexec file loader, the kernel needs to be able to
> -provide the FDT that describes the current kernel's state before
> -performing the actual kexec. The process of generating that FDT is
> -called serialization. When the FDT is generated, some properties
> -of the system may become immutable because they are already written down
> -in the FDT. That state is called the KHO finalization phase.
> -
>  Kexec Handover Radix Tree
>  =========================
>  
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 06adaf56cd69..14d2c66491a6 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -68,8 +68,7 @@ early_param("kho", kho_parse_enable);
>  
>  struct kho_out {
>  	void *fdt;
> -	bool finalized;
> -	struct mutex lock; /* protects KHO FDT finalization */
> +	struct mutex lock; /* protects KHO FDT */
>  
>  	struct kho_radix_tree radix_tree;
>  	struct kho_debugfs dbg;
> @@ -80,7 +79,6 @@ static struct kho_out kho_out = {
>  	.radix_tree = {
>  		.lock = __MUTEX_INITIALIZER(kho_out.radix_tree.lock),
>  	},
> -	.finalized = false,
>  };
>  
>  /**
> @@ -1209,23 +1207,6 @@ void kho_restore_free(void *mem)
>  }
>  EXPORT_SYMBOL_GPL(kho_restore_free);
>  
> -int kho_finalize(void)
> -{
> -	if (!kho_enable)
> -		return -EOPNOTSUPP;
> -
> -	guard(mutex)(&kho_out.lock);
> -	kho_out.finalized = true;
> -
> -	return 0;
> -}
> -
> -bool kho_finalized(void)
> -{
> -	guard(mutex)(&kho_out.lock);
> -	return kho_out.finalized;
> -}
> -
>  struct kho_in {
>  	phys_addr_t fdt_phys;
>  	phys_addr_t scratch_phys;
> diff --git a/kernel/liveupdate/kexec_handover_debugfs.c b/kernel/liveupdate/kexec_handover_debugfs.c
> index 2abbf62ba942..430c9521d59c 100644
> --- a/kernel/liveupdate/kexec_handover_debugfs.c
> +++ b/kernel/liveupdate/kexec_handover_debugfs.c
> @@ -75,24 +75,6 @@ void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt)
>  	}
>  }
>  
> -static int kho_out_finalize_get(void *data, u64 *val)
> -{
> -	*val = kho_finalized();
> -
> -	return 0;
> -}
> -
> -static int kho_out_finalize_set(void *data, u64 val)
> -{
> -	if (val)
> -		return kho_finalize();
> -	else
> -		return -EINVAL;
> -}
> -
> -DEFINE_DEBUGFS_ATTRIBUTE(kho_out_finalize_fops, kho_out_finalize_get,
> -			 kho_out_finalize_set, "%llu\n");
> -
>  static int scratch_phys_show(struct seq_file *m, void *v)
>  {
>  	for (int i = 0; i < kho_scratch_cnt; i++)
> @@ -198,11 +180,6 @@ __init int kho_out_debugfs_init(struct kho_debugfs *dbg)
>  	if (IS_ERR(f))
>  		goto err_rmdir;
>  
> -	f = debugfs_create_file("finalize", 0600, dir, NULL,
> -				&kho_out_finalize_fops);
> -	if (IS_ERR(f))
> -		goto err_rmdir;
> -
>  	dbg->dir = dir;
>  	dbg->sub_fdt_dir = sub_fdt_dir;
>  	return 0;
> diff --git a/kernel/liveupdate/kexec_handover_internal.h b/kernel/liveupdate/kexec_handover_internal.h
> index 0202c85ad14f..9a832a35254c 100644
> --- a/kernel/liveupdate/kexec_handover_internal.h
> +++ b/kernel/liveupdate/kexec_handover_internal.h
> @@ -22,9 +22,6 @@ struct kho_debugfs {};
>  extern struct kho_scratch *kho_scratch;
>  extern unsigned int kho_scratch_cnt;
>  
> -bool kho_finalized(void);
> -int kho_finalize(void);
> -
>  #ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
>  int kho_debugfs_init(void);
>  void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt);
> diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
> index dda7bb57d421..84ac728d63ba 100644
> --- a/kernel/liveupdate/luo_core.c
> +++ b/kernel/liveupdate/luo_core.c
> @@ -230,17 +230,7 @@ int liveupdate_reboot(void)
>  
>  	luo_flb_serialize();
>  
> -	err = kho_finalize();
> -	if (err) {
> -		pr_err("kho_finalize failed %d\n", err);
> -		/*
> -		 * kho_finalize() may return libfdt errors, to aboid passing to
> -		 * userspace unknown errors, change this to EAGAIN.
> -		 */
> -		err = -EAGAIN;
> -	}
> -
> -	return err;
> +	return 0;
>  }
>  
>  /**
> diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
> index 4c437de5c0b0..22f6409875c9 100644
> --- a/kernel/liveupdate/luo_flb.c
> +++ b/kernel/liveupdate/luo_flb.c
> @@ -630,7 +630,7 @@ int __init luo_flb_setup_incoming(void *fdt_in)
>   * data handle, and the final reference count. This allows the new kernel to
>   * find the appropriate handler and reconstruct the FLB's state.
>   *
> - * Context: Called from liveupdate_reboot() just before kho_finalize().
> + * Context: Called from liveupdate_reboot().
>   */
>  void luo_flb_serialize(void)
>  {
> diff --git a/tools/testing/selftests/kho/init.c b/tools/testing/selftests/kho/init.c
> index 6d9e91d55d68..88a41b6eba95 100644
> --- a/tools/testing/selftests/kho/init.c
> +++ b/tools/testing/selftests/kho/init.c
> @@ -11,7 +11,6 @@
>  /* from arch/x86/include/asm/setup.h */
>  #define COMMAND_LINE_SIZE	2048
>  
> -#define KHO_FINALIZE "/debugfs/kho/out/finalize"
>  #define KERNEL_IMAGE "/kernel"
>  
>  static int mount_filesystems(void)
> @@ -22,22 +21,6 @@ static int mount_filesystems(void)
>  	return mount("proc", "/proc", "proc", 0, NULL);
>  }
>  
> -static int kho_enable(void)
> -{
> -	const char enable[] = "1";
> -	int fd;
> -
> -	fd = open(KHO_FINALIZE, O_RDWR);
> -	if (fd < 0)
> -		return -1;
> -
> -	if (write(fd, enable, sizeof(enable)) != sizeof(enable))
> -		return 1;
> -
> -	close(fd);
> -	return 0;
> -}
> -
>  static long kexec_file_load(int kernel_fd, int initrd_fd,
>  			    unsigned long cmdline_len, const char *cmdline,
>  			    unsigned long flags)
> @@ -78,9 +61,6 @@ int main(int argc, char *argv[])
>  	if (mount_filesystems())
>  		goto err_reboot;
>  
> -	if (kho_enable())
> -		goto err_reboot;
> -
>  	if (kexec_load())
>  		goto err_reboot;
>  
> -- 
> 2.52.0.457.g6b5491de43-goog
> 

-- 
Sincerely yours,
Mike.



More information about the kexec mailing list