[PATCH v9 1/9] kho: make debugfs interface optional

Pasha Tatashin posted 9 patches 1 month, 2 weeks ago
[PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month, 2 weeks ago
Currently, KHO is controlled via debugfs interface, but once LUO is
introduced, it can control KHO, and the debug interface becomes
optional.

Add a separate config CONFIG_KEXEC_HANDOVER_DEBUGFS that enables
the debugfs interface, and allows to inspect the tree.

Move all debugfs related code to a new file to keep the .c files
clear of ifdefs.

Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
---
 MAINTAINERS                           |   2 +-
 kernel/Kconfig.kexec                  |  12 +-
 kernel/Makefile                       |   1 +
 kernel/kexec_handover.c               | 273 +++++---------------------
 kernel/kexec_handover_debugfs.c       | 216 ++++++++++++++++++++
 kernel/kexec_handover_internal.h      |  39 ++++
 tools/testing/selftests/kho/vmtest.sh |   1 +
 7 files changed, 320 insertions(+), 224 deletions(-)
 create mode 100644 kernel/kexec_handover_debugfs.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2628431dcdfe..bdd0a1260421 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13795,7 +13795,7 @@ S:	Maintained
 F:	Documentation/admin-guide/mm/kho.rst
 F:	Documentation/core-api/kho/*
 F:	include/linux/kexec_handover.h
-F:	kernel/kexec_handover.c
+F:	kernel/kexec_handover*
 F:	tools/testing/selftests/kho/
 
 KEYS-ENCRYPTED
diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
index 54e581072617..cc6743137946 100644
--- a/kernel/Kconfig.kexec
+++ b/kernel/Kconfig.kexec
@@ -100,7 +100,6 @@ config KEXEC_HANDOVER
 	depends on !DEFERRED_STRUCT_PAGE_INIT
 	select MEMBLOCK_KHO_SCRATCH
 	select KEXEC_FILE
-	select DEBUG_FS
 	select LIBFDT
 	select CMA
 	help
@@ -118,6 +117,17 @@ config KEXEC_HANDOVER_DEBUG
 	  scenarios and the extra code might be adding overhead it is
 	  only optionally enabled.
 
+config KEXEC_HANDOVER_DEBUGFS
+	bool "kexec handover debugfs interface"
+	default KEXEC_HANDOVER
+	depends on KEXEC_HANDOVER
+	select DEBUG_FS
+	help
+	  Allow to control kexec handover device tree via debugfs
+	  interface, i.e. finalize the state or aborting the finalization.
+	  Also, enables inspecting the KHO fdt trees with the debugfs binary
+	  blobs.
+
 config CRASH_DUMP
 	bool "kernel crash dumps"
 	default ARCH_DEFAULT_CRASH_DUMP
diff --git a/kernel/Makefile b/kernel/Makefile
index 9fe722305c9b..2cf7909a74e5 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
 obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
 obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o
 obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o
+obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) += kexec_handover_debugfs.o
 obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_CGROUPS) += cgroup/
diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c
index de4466b47455..da071277d85e 100644
--- a/kernel/kexec_handover.c
+++ b/kernel/kexec_handover.c
@@ -11,7 +11,6 @@
 #include <linux/cleanup.h>
 #include <linux/cma.h>
 #include <linux/count_zeros.h>
-#include <linux/debugfs.h>
 #include <linux/kexec.h>
 #include <linux/kexec_handover.h>
 #include <linux/libfdt.h>
@@ -30,6 +29,7 @@
  */
 #include "../mm/internal.h"
 #include "kexec_internal.h"
+#include "kexec_handover_internal.h"
 
 #define KHO_FDT_COMPATIBLE "kho-v1"
 #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
@@ -105,8 +105,6 @@ struct khoser_mem_chunk;
 
 struct kho_serialization {
 	struct page *fdt;
-	struct list_head fdt_list;
-	struct dentry *sub_fdt_dir;
 	struct kho_mem_track track;
 	/* First chunk of serialized preserved memory map */
 	struct khoser_mem_chunk *preserved_mem_map;
@@ -114,20 +112,16 @@ struct kho_serialization {
 
 struct kho_out {
 	struct blocking_notifier_head chain_head;
-
-	struct dentry *dir;
-
 	struct mutex lock; /* protects KHO FDT finalization */
-
 	struct kho_serialization ser;
 	bool finalized;
+	struct kho_debugfs dbg;
 };
 
 static struct kho_out kho_out = {
 	.chain_head = BLOCKING_NOTIFIER_INIT(kho_out.chain_head),
 	.lock = __MUTEX_INITIALIZER(kho_out.lock),
 	.ser = {
-		.fdt_list = LIST_HEAD_INIT(kho_out.ser.fdt_list),
 		.track = {
 			.orders = XARRAY_INIT(kho_out.ser.track.orders, 0),
 		},
@@ -477,8 +471,8 @@ static void __init kho_mem_deserialize(const void *fdt)
  * area for early allocations that happen before page allocator is
  * initialized.
  */
-static struct kho_scratch *kho_scratch;
-static unsigned int kho_scratch_cnt;
+struct kho_scratch *kho_scratch;
+unsigned int kho_scratch_cnt;
 
 /*
  * The scratch areas are scaled by default as percent of memory allocated from
@@ -674,37 +668,6 @@ static void __init kho_reserve_scratch(void)
 	kho_enable = false;
 }
 
-struct fdt_debugfs {
-	struct list_head list;
-	struct debugfs_blob_wrapper wrapper;
-	struct dentry *file;
-};
-
-static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
-			       const char *name, const void *fdt)
-{
-	struct fdt_debugfs *f;
-	struct dentry *file;
-
-	f = kmalloc(sizeof(*f), GFP_KERNEL);
-	if (!f)
-		return -ENOMEM;
-
-	f->wrapper.data = (void *)fdt;
-	f->wrapper.size = fdt_totalsize(fdt);
-
-	file = debugfs_create_blob(name, 0400, dir, &f->wrapper);
-	if (IS_ERR(file)) {
-		kfree(f);
-		return PTR_ERR(file);
-	}
-
-	f->file = file;
-	list_add(&f->list, list);
-
-	return 0;
-}
-
 /**
  * kho_add_subtree - record the physical address of a sub FDT in KHO root tree.
  * @ser: serialization control object passed by KHO notifiers.
@@ -716,7 +679,8 @@ static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
  * by KHO for the new kernel to retrieve it after kexec.
  *
  * A debugfs blob entry is also created at
- * ``/sys/kernel/debug/kho/out/sub_fdts/@name``.
+ * ``/sys/kernel/debug/kho/out/sub_fdts/@name`` when kernel is configured with
+ * CONFIG_KEXEC_HANDOVER_DEBUGFS
  *
  * Return: 0 on success, error code on failure
  */
@@ -733,7 +697,7 @@ int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt)
 	if (err)
 		return err;
 
-	return kho_debugfs_fdt_add(&ser->fdt_list, ser->sub_fdt_dir, name, fdt);
+	return kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, false);
 }
 EXPORT_SYMBOL_GPL(kho_add_subtree);
 
@@ -1064,30 +1028,7 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation)
 }
 EXPORT_SYMBOL_GPL(kho_restore_vmalloc);
 
-/* Handling for debug/kho/out */
-
-static struct dentry *debugfs_root;
-
-static int kho_out_update_debugfs_fdt(void)
-{
-	int err = 0;
-	struct fdt_debugfs *ff, *tmp;
-
-	if (kho_out.finalized) {
-		err = kho_debugfs_fdt_add(&kho_out.ser.fdt_list, kho_out.dir,
-					  "fdt", page_to_virt(kho_out.ser.fdt));
-	} else {
-		list_for_each_entry_safe(ff, tmp, &kho_out.ser.fdt_list, list) {
-			debugfs_remove(ff->file);
-			list_del(&ff->list);
-			kfree(ff);
-		}
-	}
-
-	return err;
-}
-
-static int kho_abort(void)
+static int __kho_abort(void)
 {
 	int err;
 	unsigned long order;
@@ -1120,7 +1061,28 @@ static int kho_abort(void)
 	return err;
 }
 
-static int kho_finalize(void)
+int kho_abort(void)
+{
+	int ret = 0;
+
+	if (!kho_enable)
+		return -EOPNOTSUPP;
+
+	guard(mutex)(&kho_out.lock);
+	if (!kho_out.finalized)
+		return -ENOENT;
+
+	ret = __kho_abort();
+	if (ret)
+		return ret;
+
+	kho_out.finalized = false;
+	kho_debugfs_cleanup(&kho_out.dbg);
+
+	return 0;
+}
+
+static int __kho_finalize(void)
 {
 	int err = 0;
 	u64 *preserved_mem_map;
@@ -1163,118 +1125,46 @@ static int kho_finalize(void)
 abort:
 	if (err) {
 		pr_err("Failed to convert KHO state tree: %d\n", err);
-		kho_abort();
+		__kho_abort();
 	}
 
 	return err;
 }
 
-static int kho_out_finalize_get(void *data, u64 *val)
+int kho_finalize(void)
 {
-	mutex_lock(&kho_out.lock);
-	*val = kho_out.finalized;
-	mutex_unlock(&kho_out.lock);
-
-	return 0;
-}
-
-static int kho_out_finalize_set(void *data, u64 _val)
-{
-	int ret = 0;
-	bool val = !!_val;
-
-	mutex_lock(&kho_out.lock);
+	int ret;
 
-	if (val == kho_out.finalized) {
-		if (kho_out.finalized)
-			ret = -EEXIST;
-		else
-			ret = -ENOENT;
-		goto unlock;
-	}
+	if (!kho_enable)
+		return -EOPNOTSUPP;
 
-	if (val)
-		ret = kho_finalize();
-	else
-		ret = kho_abort();
+	guard(mutex)(&kho_out.lock);
+	if (kho_out.finalized)
+		return -EEXIST;
 
+	ret = __kho_finalize();
 	if (ret)
-		goto unlock;
-
-	kho_out.finalized = val;
-	ret = kho_out_update_debugfs_fdt();
-
-unlock:
-	mutex_unlock(&kho_out.lock);
-	return ret;
-}
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_kho_out_finalize, 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++)
-		seq_printf(m, "0x%llx\n", kho_scratch[i].addr);
-
-	return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(scratch_phys);
+		return ret;
 
-static int scratch_len_show(struct seq_file *m, void *v)
-{
-	for (int i = 0; i < kho_scratch_cnt; i++)
-		seq_printf(m, "0x%llx\n", kho_scratch[i].size);
+	kho_out.finalized = true;
 
-	return 0;
+	return kho_debugfs_fdt_add(&kho_out.dbg, "fdt",
+				   page_to_virt(kho_out.ser.fdt), true);
 }
-DEFINE_SHOW_ATTRIBUTE(scratch_len);
 
-static __init int kho_out_debugfs_init(void)
+bool kho_finalized(void)
 {
-	struct dentry *dir, *f, *sub_fdt_dir;
-
-	dir = debugfs_create_dir("out", debugfs_root);
-	if (IS_ERR(dir))
-		return -ENOMEM;
-
-	sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
-	if (IS_ERR(sub_fdt_dir))
-		goto err_rmdir;
-
-	f = debugfs_create_file("scratch_phys", 0400, dir, NULL,
-				&scratch_phys_fops);
-	if (IS_ERR(f))
-		goto err_rmdir;
-
-	f = debugfs_create_file("scratch_len", 0400, dir, NULL,
-				&scratch_len_fops);
-	if (IS_ERR(f))
-		goto err_rmdir;
-
-	f = debugfs_create_file("finalize", 0600, dir, NULL,
-				&fops_kho_out_finalize);
-	if (IS_ERR(f))
-		goto err_rmdir;
-
-	kho_out.dir = dir;
-	kho_out.ser.sub_fdt_dir = sub_fdt_dir;
-	return 0;
-
-err_rmdir:
-	debugfs_remove_recursive(dir);
-	return -ENOENT;
+	guard(mutex)(&kho_out.lock);
+	return kho_out.finalized;
 }
 
 struct kho_in {
-	struct dentry *dir;
 	phys_addr_t fdt_phys;
 	phys_addr_t scratch_phys;
-	struct list_head fdt_list;
+	struct kho_debugfs dbg;
 };
 
 static struct kho_in kho_in = {
-	.fdt_list = LIST_HEAD_INIT(kho_in.fdt_list),
 };
 
 static const void *kho_get_fdt(void)
@@ -1338,56 +1228,6 @@ int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
 }
 EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
-/* Handling for debugfs/kho/in */
-
-static __init int kho_in_debugfs_init(const void *fdt)
-{
-	struct dentry *sub_fdt_dir;
-	int err, child;
-
-	kho_in.dir = debugfs_create_dir("in", debugfs_root);
-	if (IS_ERR(kho_in.dir))
-		return PTR_ERR(kho_in.dir);
-
-	sub_fdt_dir = debugfs_create_dir("sub_fdts", kho_in.dir);
-	if (IS_ERR(sub_fdt_dir)) {
-		err = PTR_ERR(sub_fdt_dir);
-		goto err_rmdir;
-	}
-
-	err = kho_debugfs_fdt_add(&kho_in.fdt_list, kho_in.dir, "fdt", fdt);
-	if (err)
-		goto err_rmdir;
-
-	fdt_for_each_subnode(child, fdt, 0) {
-		int len = 0;
-		const char *name = fdt_get_name(fdt, child, NULL);
-		const u64 *fdt_phys;
-
-		fdt_phys = fdt_getprop(fdt, child, "fdt", &len);
-		if (!fdt_phys)
-			continue;
-		if (len != sizeof(*fdt_phys)) {
-			pr_warn("node `%s`'s prop `fdt` has invalid length: %d\n",
-				name, len);
-			continue;
-		}
-		err = kho_debugfs_fdt_add(&kho_in.fdt_list, sub_fdt_dir, name,
-					  phys_to_virt(*fdt_phys));
-		if (err) {
-			pr_warn("failed to add fdt `%s` to debugfs: %d\n", name,
-				err);
-			continue;
-		}
-	}
-
-	return 0;
-
-err_rmdir:
-	debugfs_remove_recursive(kho_in.dir);
-	return err;
-}
-
 static __init int kho_init(void)
 {
 	int err = 0;
@@ -1402,27 +1242,16 @@ static __init int kho_init(void)
 		goto err_free_scratch;
 	}
 
-	debugfs_root = debugfs_create_dir("kho", NULL);
-	if (IS_ERR(debugfs_root)) {
-		err = -ENOENT;
+	err = kho_debugfs_init();
+	if (err)
 		goto err_free_fdt;
-	}
 
-	err = kho_out_debugfs_init();
+	err = kho_out_debugfs_init(&kho_out.dbg);
 	if (err)
 		goto err_free_fdt;
 
 	if (fdt) {
-		err = kho_in_debugfs_init(fdt);
-		/*
-		 * Failure to create /sys/kernel/debug/kho/in does not prevent
-		 * reviving state from KHO and setting up KHO for the next
-		 * kexec.
-		 */
-		if (err)
-			pr_err("failed exposing handover FDT in debugfs: %d\n",
-			       err);
-
+		kho_in_debugfs_init(&kho_in.dbg, fdt);
 		return 0;
 	}
 
diff --git a/kernel/kexec_handover_debugfs.c b/kernel/kexec_handover_debugfs.c
new file mode 100644
index 000000000000..a91b279f1b23
--- /dev/null
+++ b/kernel/kexec_handover_debugfs.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * kexec_handover_debugfs.c - kexec handover debugfs interfaces
+ * Copyright (C) 2023 Alexander Graf <graf@amazon.com>
+ * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport <rppt@kernel.org>
+ * Copyright (C) 2025 Google LLC, Changyuan Lyu <changyuanl@google.com>
+ * Copyright (C) 2025 Google LLC, Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+
+#define pr_fmt(fmt) "KHO: " fmt
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/libfdt.h>
+#include <linux/mm.h>
+#include "kexec_handover_internal.h"
+
+static struct dentry *debugfs_root;
+
+struct fdt_debugfs {
+	struct list_head list;
+	struct debugfs_blob_wrapper wrapper;
+	struct dentry *file;
+};
+
+static int __kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
+				 const char *name, const void *fdt)
+{
+	struct fdt_debugfs *f;
+	struct dentry *file;
+
+	f = kmalloc(sizeof(*f), GFP_KERNEL);
+	if (!f)
+		return -ENOMEM;
+
+	f->wrapper.data = (void *)fdt;
+	f->wrapper.size = fdt_totalsize(fdt);
+
+	file = debugfs_create_blob(name, 0400, dir, &f->wrapper);
+	if (IS_ERR(file)) {
+		kfree(f);
+		return PTR_ERR(file);
+	}
+
+	f->file = file;
+	list_add(&f->list, list);
+
+	return 0;
+}
+
+int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
+			const void *fdt, bool root)
+{
+	struct dentry *dir;
+
+	if (root)
+		dir = dbg->dir;
+	else
+		dir = dbg->sub_fdt_dir;
+
+	return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt);
+}
+
+void kho_debugfs_cleanup(struct kho_debugfs *dbg)
+{
+	struct fdt_debugfs *ff, *tmp;
+
+	list_for_each_entry_safe(ff, tmp, &dbg->fdt_list, list) {
+		debugfs_remove(ff->file);
+		list_del(&ff->list);
+		kfree(ff);
+	}
+}
+
+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 kho_abort();
+}
+
+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++)
+		seq_printf(m, "0x%llx\n", kho_scratch[i].addr);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(scratch_phys);
+
+static int scratch_len_show(struct seq_file *m, void *v)
+{
+	for (int i = 0; i < kho_scratch_cnt; i++)
+		seq_printf(m, "0x%llx\n", kho_scratch[i].size);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(scratch_len);
+
+__init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt)
+{
+	struct dentry *dir, *sub_fdt_dir;
+	int err, child;
+
+	INIT_LIST_HEAD(&dbg->fdt_list);
+
+	dir = debugfs_create_dir("in", debugfs_root);
+	if (IS_ERR(dir)) {
+		err = PTR_ERR(dir);
+		goto err_out;
+	}
+
+	sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
+	if (IS_ERR(sub_fdt_dir)) {
+		err = PTR_ERR(sub_fdt_dir);
+		goto err_rmdir;
+	}
+
+	err = __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt);
+	if (err)
+		goto err_rmdir;
+
+	fdt_for_each_subnode(child, fdt, 0) {
+		int len = 0;
+		const char *name = fdt_get_name(fdt, child, NULL);
+		const u64 *fdt_phys;
+
+		fdt_phys = fdt_getprop(fdt, child, "fdt", &len);
+		if (!fdt_phys)
+			continue;
+		if (len != sizeof(*fdt_phys)) {
+			pr_warn("node %s prop fdt has invalid length: %d\n",
+				name, len);
+			continue;
+		}
+		err = __kho_debugfs_fdt_add(&dbg->fdt_list, sub_fdt_dir, name,
+					    phys_to_virt(*fdt_phys));
+		if (err) {
+			pr_warn("failed to add fdt %s to debugfs: %d\n", name,
+				err);
+			continue;
+		}
+	}
+
+	dbg->dir = dir;
+	dbg->sub_fdt_dir = sub_fdt_dir;
+
+	return;
+err_rmdir:
+	debugfs_remove_recursive(dir);
+err_out:
+	/*
+	 * Failure to create /sys/kernel/debug/kho/in does not prevent
+	 * reviving state from KHO and setting up KHO for the next
+	 * kexec.
+	 */
+	if (err)
+		pr_err("failed exposing handover FDT in debugfs: %d\n", err);
+}
+
+__init int kho_out_debugfs_init(struct kho_debugfs *dbg)
+{
+	struct dentry *dir, *f, *sub_fdt_dir;
+
+	INIT_LIST_HEAD(&dbg->fdt_list);
+
+	dir = debugfs_create_dir("out", debugfs_root);
+	if (IS_ERR(dir))
+		return -ENOMEM;
+
+	sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
+	if (IS_ERR(sub_fdt_dir))
+		goto err_rmdir;
+
+	f = debugfs_create_file("scratch_phys", 0400, dir, NULL,
+				&scratch_phys_fops);
+	if (IS_ERR(f))
+		goto err_rmdir;
+
+	f = debugfs_create_file("scratch_len", 0400, dir, NULL,
+				&scratch_len_fops);
+	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;
+
+err_rmdir:
+	debugfs_remove_recursive(dir);
+	return -ENOENT;
+}
+
+__init int kho_debugfs_init(void)
+{
+	debugfs_root = debugfs_create_dir("kho", NULL);
+	if (IS_ERR(debugfs_root))
+		return -ENOENT;
+	return 0;
+}
diff --git a/kernel/kexec_handover_internal.h b/kernel/kexec_handover_internal.h
index 05e9720ba7b9..217b8b25a542 100644
--- a/kernel/kexec_handover_internal.h
+++ b/kernel/kexec_handover_internal.h
@@ -2,8 +2,47 @@
 #ifndef LINUX_KEXEC_HANDOVER_INTERNAL_H
 #define LINUX_KEXEC_HANDOVER_INTERNAL_H
 
+#include <linux/kexec_handover.h>
+#include <linux/list.h>
 #include <linux/types.h>
 
+#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
+#include <linux/debugfs.h>
+
+struct kho_debugfs {
+	struct dentry *dir;
+	struct dentry *sub_fdt_dir;
+	struct list_head fdt_list;
+};
+
+#else
+struct kho_debugfs {};
+#endif
+
+extern struct kho_scratch *kho_scratch;
+extern unsigned int kho_scratch_cnt;
+
+bool kho_finalized(void);
+int kho_finalize(void);
+int kho_abort(void);
+
+#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
+int kho_debugfs_init(void);
+void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt);
+int kho_out_debugfs_init(struct kho_debugfs *dbg);
+int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
+			const void *fdt, bool root);
+void kho_debugfs_cleanup(struct kho_debugfs *dbg);
+#else
+static inline int kho_debugfs_init(void) { return 0; }
+static inline void kho_in_debugfs_init(struct kho_debugfs *dbg,
+				       const void *fdt) { }
+static inline int kho_out_debugfs_init(struct kho_debugfs *dbg) { return 0; }
+static inline int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
+				      const void *fdt, bool root) { return 0; }
+static inline void kho_debugfs_cleanup(struct kho_debugfs *dbg) {}
+#endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */
+
 #ifdef CONFIG_KEXEC_HANDOVER_DEBUG
 bool kho_scratch_overlap(phys_addr_t phys, size_t size);
 #else
diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh
index 3f6c17166846..49fdac8e8b15 100755
--- a/tools/testing/selftests/kho/vmtest.sh
+++ b/tools/testing/selftests/kho/vmtest.sh
@@ -59,6 +59,7 @@ function build_kernel() {
 	tee "$kconfig" > "$kho_config" <<EOF
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KEXEC_HANDOVER=y
+CONFIG_KEXEC_HANDOVER_DEBUGFS=y
 CONFIG_TEST_KEXEC_HANDOVER=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_VM=y
-- 
2.51.1.930.gacf6e81ea2-goog
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Zhu Yanjun 1 month, 1 week ago
在 2025/11/1 7:23, Pasha Tatashin 写道:
> Currently, KHO is controlled via debugfs interface, but once LUO is
> introduced, it can control KHO, and the debug interface becomes
> optional.
> 
> Add a separate config CONFIG_KEXEC_HANDOVER_DEBUGFS that enables
> the debugfs interface, and allows to inspect the tree.
> 
> Move all debugfs related code to a new file to keep the .c files
> clear of ifdefs.
> 
> Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
> ---
>   MAINTAINERS                           |   2 +-
>   kernel/Kconfig.kexec                  |  12 +-
>   kernel/Makefile                       |   1 +
>   kernel/kexec_handover.c               | 273 +++++---------------------
>   kernel/kexec_handover_debugfs.c       | 216 ++++++++++++++++++++
>   kernel/kexec_handover_internal.h      |  39 ++++
>   tools/testing/selftests/kho/vmtest.sh |   1 +
>   7 files changed, 320 insertions(+), 224 deletions(-)
>   create mode 100644 kernel/kexec_handover_debugfs.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2628431dcdfe..bdd0a1260421 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13795,7 +13795,7 @@ S:	Maintained
>   F:	Documentation/admin-guide/mm/kho.rst
>   F:	Documentation/core-api/kho/*
>   F:	include/linux/kexec_handover.h
> -F:	kernel/kexec_handover.c
> +F:	kernel/kexec_handover*
>   F:	tools/testing/selftests/kho/
>   
>   KEYS-ENCRYPTED
> diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
> index 54e581072617..cc6743137946 100644
> --- a/kernel/Kconfig.kexec
> +++ b/kernel/Kconfig.kexec
> @@ -100,7 +100,6 @@ config KEXEC_HANDOVER
>   	depends on !DEFERRED_STRUCT_PAGE_INIT
>   	select MEMBLOCK_KHO_SCRATCH
>   	select KEXEC_FILE
> -	select DEBUG_FS
>   	select LIBFDT
>   	select CMA
>   	help
> @@ -118,6 +117,17 @@ config KEXEC_HANDOVER_DEBUG
>   	  scenarios and the extra code might be adding overhead it is
>   	  only optionally enabled.
>   
> +config KEXEC_HANDOVER_DEBUGFS
> +	bool "kexec handover debugfs interface"
> +	default KEXEC_HANDOVER
> +	depends on KEXEC_HANDOVER
> +	select DEBUG_FS
> +	help
> +	  Allow to control kexec handover device tree via debugfs
> +	  interface, i.e. finalize the state or aborting the finalization.
> +	  Also, enables inspecting the KHO fdt trees with the debugfs binary
> +	  blobs.

Hi, Pasha

In our previous discussion, we talked about counting the number of times 
the kernel is rebooted via kexec. At that time, you suggested adding a 
variable in debugfs to keep track of this count.
However, since debugfs is now optional, where would be an appropriate 
place to store this variable?

BR,
Yanjun.Zhu

> +
>   config CRASH_DUMP
>   	bool "kernel crash dumps"
>   	default ARCH_DEFAULT_CRASH_DUMP
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 9fe722305c9b..2cf7909a74e5 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -84,6 +84,7 @@ obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
>   obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
>   obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o
>   obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o
> +obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) += kexec_handover_debugfs.o
>   obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
>   obj-$(CONFIG_COMPAT) += compat.o
>   obj-$(CONFIG_CGROUPS) += cgroup/
> diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c
> index de4466b47455..da071277d85e 100644
> --- a/kernel/kexec_handover.c
> +++ b/kernel/kexec_handover.c
> @@ -11,7 +11,6 @@
>   #include <linux/cleanup.h>
>   #include <linux/cma.h>
>   #include <linux/count_zeros.h>
> -#include <linux/debugfs.h>
>   #include <linux/kexec.h>
>   #include <linux/kexec_handover.h>
>   #include <linux/libfdt.h>
> @@ -30,6 +29,7 @@
>    */
>   #include "../mm/internal.h"
>   #include "kexec_internal.h"
> +#include "kexec_handover_internal.h"
>   
>   #define KHO_FDT_COMPATIBLE "kho-v1"
>   #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
> @@ -105,8 +105,6 @@ struct khoser_mem_chunk;
>   
>   struct kho_serialization {
>   	struct page *fdt;
> -	struct list_head fdt_list;
> -	struct dentry *sub_fdt_dir;
>   	struct kho_mem_track track;
>   	/* First chunk of serialized preserved memory map */
>   	struct khoser_mem_chunk *preserved_mem_map;
> @@ -114,20 +112,16 @@ struct kho_serialization {
>   
>   struct kho_out {
>   	struct blocking_notifier_head chain_head;
> -
> -	struct dentry *dir;
> -
>   	struct mutex lock; /* protects KHO FDT finalization */
> -
>   	struct kho_serialization ser;
>   	bool finalized;
> +	struct kho_debugfs dbg;
>   };
>   
>   static struct kho_out kho_out = {
>   	.chain_head = BLOCKING_NOTIFIER_INIT(kho_out.chain_head),
>   	.lock = __MUTEX_INITIALIZER(kho_out.lock),
>   	.ser = {
> -		.fdt_list = LIST_HEAD_INIT(kho_out.ser.fdt_list),
>   		.track = {
>   			.orders = XARRAY_INIT(kho_out.ser.track.orders, 0),
>   		},
> @@ -477,8 +471,8 @@ static void __init kho_mem_deserialize(const void *fdt)
>    * area for early allocations that happen before page allocator is
>    * initialized.
>    */
> -static struct kho_scratch *kho_scratch;
> -static unsigned int kho_scratch_cnt;
> +struct kho_scratch *kho_scratch;
> +unsigned int kho_scratch_cnt;
>   
>   /*
>    * The scratch areas are scaled by default as percent of memory allocated from
> @@ -674,37 +668,6 @@ static void __init kho_reserve_scratch(void)
>   	kho_enable = false;
>   }
>   
> -struct fdt_debugfs {
> -	struct list_head list;
> -	struct debugfs_blob_wrapper wrapper;
> -	struct dentry *file;
> -};
> -
> -static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
> -			       const char *name, const void *fdt)
> -{
> -	struct fdt_debugfs *f;
> -	struct dentry *file;
> -
> -	f = kmalloc(sizeof(*f), GFP_KERNEL);
> -	if (!f)
> -		return -ENOMEM;
> -
> -	f->wrapper.data = (void *)fdt;
> -	f->wrapper.size = fdt_totalsize(fdt);
> -
> -	file = debugfs_create_blob(name, 0400, dir, &f->wrapper);
> -	if (IS_ERR(file)) {
> -		kfree(f);
> -		return PTR_ERR(file);
> -	}
> -
> -	f->file = file;
> -	list_add(&f->list, list);
> -
> -	return 0;
> -}
> -
>   /**
>    * kho_add_subtree - record the physical address of a sub FDT in KHO root tree.
>    * @ser: serialization control object passed by KHO notifiers.
> @@ -716,7 +679,8 @@ static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
>    * by KHO for the new kernel to retrieve it after kexec.
>    *
>    * A debugfs blob entry is also created at
> - * ``/sys/kernel/debug/kho/out/sub_fdts/@name``.
> + * ``/sys/kernel/debug/kho/out/sub_fdts/@name`` when kernel is configured with
> + * CONFIG_KEXEC_HANDOVER_DEBUGFS
>    *
>    * Return: 0 on success, error code on failure
>    */
> @@ -733,7 +697,7 @@ int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt)
>   	if (err)
>   		return err;
>   
> -	return kho_debugfs_fdt_add(&ser->fdt_list, ser->sub_fdt_dir, name, fdt);
> +	return kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, false);
>   }
>   EXPORT_SYMBOL_GPL(kho_add_subtree);
>   
> @@ -1064,30 +1028,7 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation)
>   }
>   EXPORT_SYMBOL_GPL(kho_restore_vmalloc);
>   
> -/* Handling for debug/kho/out */
> -
> -static struct dentry *debugfs_root;
> -
> -static int kho_out_update_debugfs_fdt(void)
> -{
> -	int err = 0;
> -	struct fdt_debugfs *ff, *tmp;
> -
> -	if (kho_out.finalized) {
> -		err = kho_debugfs_fdt_add(&kho_out.ser.fdt_list, kho_out.dir,
> -					  "fdt", page_to_virt(kho_out.ser.fdt));
> -	} else {
> -		list_for_each_entry_safe(ff, tmp, &kho_out.ser.fdt_list, list) {
> -			debugfs_remove(ff->file);
> -			list_del(&ff->list);
> -			kfree(ff);
> -		}
> -	}
> -
> -	return err;
> -}
> -
> -static int kho_abort(void)
> +static int __kho_abort(void)
>   {
>   	int err;
>   	unsigned long order;
> @@ -1120,7 +1061,28 @@ static int kho_abort(void)
>   	return err;
>   }
>   
> -static int kho_finalize(void)
> +int kho_abort(void)
> +{
> +	int ret = 0;
> +
> +	if (!kho_enable)
> +		return -EOPNOTSUPP;
> +
> +	guard(mutex)(&kho_out.lock);
> +	if (!kho_out.finalized)
> +		return -ENOENT;
> +
> +	ret = __kho_abort();
> +	if (ret)
> +		return ret;
> +
> +	kho_out.finalized = false;
> +	kho_debugfs_cleanup(&kho_out.dbg);
> +
> +	return 0;
> +}
> +
> +static int __kho_finalize(void)
>   {
>   	int err = 0;
>   	u64 *preserved_mem_map;
> @@ -1163,118 +1125,46 @@ static int kho_finalize(void)
>   abort:
>   	if (err) {
>   		pr_err("Failed to convert KHO state tree: %d\n", err);
> -		kho_abort();
> +		__kho_abort();
>   	}
>   
>   	return err;
>   }
>   
> -static int kho_out_finalize_get(void *data, u64 *val)
> +int kho_finalize(void)
>   {
> -	mutex_lock(&kho_out.lock);
> -	*val = kho_out.finalized;
> -	mutex_unlock(&kho_out.lock);
> -
> -	return 0;
> -}
> -
> -static int kho_out_finalize_set(void *data, u64 _val)
> -{
> -	int ret = 0;
> -	bool val = !!_val;
> -
> -	mutex_lock(&kho_out.lock);
> +	int ret;
>   
> -	if (val == kho_out.finalized) {
> -		if (kho_out.finalized)
> -			ret = -EEXIST;
> -		else
> -			ret = -ENOENT;
> -		goto unlock;
> -	}
> +	if (!kho_enable)
> +		return -EOPNOTSUPP;
>   
> -	if (val)
> -		ret = kho_finalize();
> -	else
> -		ret = kho_abort();
> +	guard(mutex)(&kho_out.lock);
> +	if (kho_out.finalized)
> +		return -EEXIST;
>   
> +	ret = __kho_finalize();
>   	if (ret)
> -		goto unlock;
> -
> -	kho_out.finalized = val;
> -	ret = kho_out_update_debugfs_fdt();
> -
> -unlock:
> -	mutex_unlock(&kho_out.lock);
> -	return ret;
> -}
> -
> -DEFINE_DEBUGFS_ATTRIBUTE(fops_kho_out_finalize, 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++)
> -		seq_printf(m, "0x%llx\n", kho_scratch[i].addr);
> -
> -	return 0;
> -}
> -DEFINE_SHOW_ATTRIBUTE(scratch_phys);
> +		return ret;
>   
> -static int scratch_len_show(struct seq_file *m, void *v)
> -{
> -	for (int i = 0; i < kho_scratch_cnt; i++)
> -		seq_printf(m, "0x%llx\n", kho_scratch[i].size);
> +	kho_out.finalized = true;
>   
> -	return 0;
> +	return kho_debugfs_fdt_add(&kho_out.dbg, "fdt",
> +				   page_to_virt(kho_out.ser.fdt), true);
>   }
> -DEFINE_SHOW_ATTRIBUTE(scratch_len);
>   
> -static __init int kho_out_debugfs_init(void)
> +bool kho_finalized(void)
>   {
> -	struct dentry *dir, *f, *sub_fdt_dir;
> -
> -	dir = debugfs_create_dir("out", debugfs_root);
> -	if (IS_ERR(dir))
> -		return -ENOMEM;
> -
> -	sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
> -	if (IS_ERR(sub_fdt_dir))
> -		goto err_rmdir;
> -
> -	f = debugfs_create_file("scratch_phys", 0400, dir, NULL,
> -				&scratch_phys_fops);
> -	if (IS_ERR(f))
> -		goto err_rmdir;
> -
> -	f = debugfs_create_file("scratch_len", 0400, dir, NULL,
> -				&scratch_len_fops);
> -	if (IS_ERR(f))
> -		goto err_rmdir;
> -
> -	f = debugfs_create_file("finalize", 0600, dir, NULL,
> -				&fops_kho_out_finalize);
> -	if (IS_ERR(f))
> -		goto err_rmdir;
> -
> -	kho_out.dir = dir;
> -	kho_out.ser.sub_fdt_dir = sub_fdt_dir;
> -	return 0;
> -
> -err_rmdir:
> -	debugfs_remove_recursive(dir);
> -	return -ENOENT;
> +	guard(mutex)(&kho_out.lock);
> +	return kho_out.finalized;
>   }
>   
>   struct kho_in {
> -	struct dentry *dir;
>   	phys_addr_t fdt_phys;
>   	phys_addr_t scratch_phys;
> -	struct list_head fdt_list;
> +	struct kho_debugfs dbg;
>   };
>   
>   static struct kho_in kho_in = {
> -	.fdt_list = LIST_HEAD_INIT(kho_in.fdt_list),
>   };
>   
>   static const void *kho_get_fdt(void)
> @@ -1338,56 +1228,6 @@ int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
>   }
>   EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
>   
> -/* Handling for debugfs/kho/in */
> -
> -static __init int kho_in_debugfs_init(const void *fdt)
> -{
> -	struct dentry *sub_fdt_dir;
> -	int err, child;
> -
> -	kho_in.dir = debugfs_create_dir("in", debugfs_root);
> -	if (IS_ERR(kho_in.dir))
> -		return PTR_ERR(kho_in.dir);
> -
> -	sub_fdt_dir = debugfs_create_dir("sub_fdts", kho_in.dir);
> -	if (IS_ERR(sub_fdt_dir)) {
> -		err = PTR_ERR(sub_fdt_dir);
> -		goto err_rmdir;
> -	}
> -
> -	err = kho_debugfs_fdt_add(&kho_in.fdt_list, kho_in.dir, "fdt", fdt);
> -	if (err)
> -		goto err_rmdir;
> -
> -	fdt_for_each_subnode(child, fdt, 0) {
> -		int len = 0;
> -		const char *name = fdt_get_name(fdt, child, NULL);
> -		const u64 *fdt_phys;
> -
> -		fdt_phys = fdt_getprop(fdt, child, "fdt", &len);
> -		if (!fdt_phys)
> -			continue;
> -		if (len != sizeof(*fdt_phys)) {
> -			pr_warn("node `%s`'s prop `fdt` has invalid length: %d\n",
> -				name, len);
> -			continue;
> -		}
> -		err = kho_debugfs_fdt_add(&kho_in.fdt_list, sub_fdt_dir, name,
> -					  phys_to_virt(*fdt_phys));
> -		if (err) {
> -			pr_warn("failed to add fdt `%s` to debugfs: %d\n", name,
> -				err);
> -			continue;
> -		}
> -	}
> -
> -	return 0;
> -
> -err_rmdir:
> -	debugfs_remove_recursive(kho_in.dir);
> -	return err;
> -}
> -
>   static __init int kho_init(void)
>   {
>   	int err = 0;
> @@ -1402,27 +1242,16 @@ static __init int kho_init(void)
>   		goto err_free_scratch;
>   	}
>   
> -	debugfs_root = debugfs_create_dir("kho", NULL);
> -	if (IS_ERR(debugfs_root)) {
> -		err = -ENOENT;
> +	err = kho_debugfs_init();
> +	if (err)
>   		goto err_free_fdt;
> -	}
>   
> -	err = kho_out_debugfs_init();
> +	err = kho_out_debugfs_init(&kho_out.dbg);
>   	if (err)
>   		goto err_free_fdt;
>   
>   	if (fdt) {
> -		err = kho_in_debugfs_init(fdt);
> -		/*
> -		 * Failure to create /sys/kernel/debug/kho/in does not prevent
> -		 * reviving state from KHO and setting up KHO for the next
> -		 * kexec.
> -		 */
> -		if (err)
> -			pr_err("failed exposing handover FDT in debugfs: %d\n",
> -			       err);
> -
> +		kho_in_debugfs_init(&kho_in.dbg, fdt);
>   		return 0;
>   	}
>   
> diff --git a/kernel/kexec_handover_debugfs.c b/kernel/kexec_handover_debugfs.c
> new file mode 100644
> index 000000000000..a91b279f1b23
> --- /dev/null
> +++ b/kernel/kexec_handover_debugfs.c
> @@ -0,0 +1,216 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * kexec_handover_debugfs.c - kexec handover debugfs interfaces
> + * Copyright (C) 2023 Alexander Graf <graf@amazon.com>
> + * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport <rppt@kernel.org>
> + * Copyright (C) 2025 Google LLC, Changyuan Lyu <changyuanl@google.com>
> + * Copyright (C) 2025 Google LLC, Pasha Tatashin <pasha.tatashin@soleen.com>
> + */
> +
> +#define pr_fmt(fmt) "KHO: " fmt
> +
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/libfdt.h>
> +#include <linux/mm.h>
> +#include "kexec_handover_internal.h"
> +
> +static struct dentry *debugfs_root;
> +
> +struct fdt_debugfs {
> +	struct list_head list;
> +	struct debugfs_blob_wrapper wrapper;
> +	struct dentry *file;
> +};
> +
> +static int __kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
> +				 const char *name, const void *fdt)
> +{
> +	struct fdt_debugfs *f;
> +	struct dentry *file;
> +
> +	f = kmalloc(sizeof(*f), GFP_KERNEL);
> +	if (!f)
> +		return -ENOMEM;
> +
> +	f->wrapper.data = (void *)fdt;
> +	f->wrapper.size = fdt_totalsize(fdt);
> +
> +	file = debugfs_create_blob(name, 0400, dir, &f->wrapper);
> +	if (IS_ERR(file)) {
> +		kfree(f);
> +		return PTR_ERR(file);
> +	}
> +
> +	f->file = file;
> +	list_add(&f->list, list);
> +
> +	return 0;
> +}
> +
> +int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
> +			const void *fdt, bool root)
> +{
> +	struct dentry *dir;
> +
> +	if (root)
> +		dir = dbg->dir;
> +	else
> +		dir = dbg->sub_fdt_dir;
> +
> +	return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt);
> +}
> +
> +void kho_debugfs_cleanup(struct kho_debugfs *dbg)
> +{
> +	struct fdt_debugfs *ff, *tmp;
> +
> +	list_for_each_entry_safe(ff, tmp, &dbg->fdt_list, list) {
> +		debugfs_remove(ff->file);
> +		list_del(&ff->list);
> +		kfree(ff);
> +	}
> +}
> +
> +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 kho_abort();
> +}
> +
> +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++)
> +		seq_printf(m, "0x%llx\n", kho_scratch[i].addr);
> +
> +	return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(scratch_phys);
> +
> +static int scratch_len_show(struct seq_file *m, void *v)
> +{
> +	for (int i = 0; i < kho_scratch_cnt; i++)
> +		seq_printf(m, "0x%llx\n", kho_scratch[i].size);
> +
> +	return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(scratch_len);
> +
> +__init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt)
> +{
> +	struct dentry *dir, *sub_fdt_dir;
> +	int err, child;
> +
> +	INIT_LIST_HEAD(&dbg->fdt_list);
> +
> +	dir = debugfs_create_dir("in", debugfs_root);
> +	if (IS_ERR(dir)) {
> +		err = PTR_ERR(dir);
> +		goto err_out;
> +	}
> +
> +	sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
> +	if (IS_ERR(sub_fdt_dir)) {
> +		err = PTR_ERR(sub_fdt_dir);
> +		goto err_rmdir;
> +	}
> +
> +	err = __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt);
> +	if (err)
> +		goto err_rmdir;
> +
> +	fdt_for_each_subnode(child, fdt, 0) {
> +		int len = 0;
> +		const char *name = fdt_get_name(fdt, child, NULL);
> +		const u64 *fdt_phys;
> +
> +		fdt_phys = fdt_getprop(fdt, child, "fdt", &len);
> +		if (!fdt_phys)
> +			continue;
> +		if (len != sizeof(*fdt_phys)) {
> +			pr_warn("node %s prop fdt has invalid length: %d\n",
> +				name, len);
> +			continue;
> +		}
> +		err = __kho_debugfs_fdt_add(&dbg->fdt_list, sub_fdt_dir, name,
> +					    phys_to_virt(*fdt_phys));
> +		if (err) {
> +			pr_warn("failed to add fdt %s to debugfs: %d\n", name,
> +				err);
> +			continue;
> +		}
> +	}
> +
> +	dbg->dir = dir;
> +	dbg->sub_fdt_dir = sub_fdt_dir;
> +
> +	return;
> +err_rmdir:
> +	debugfs_remove_recursive(dir);
> +err_out:
> +	/*
> +	 * Failure to create /sys/kernel/debug/kho/in does not prevent
> +	 * reviving state from KHO and setting up KHO for the next
> +	 * kexec.
> +	 */
> +	if (err)
> +		pr_err("failed exposing handover FDT in debugfs: %d\n", err);
> +}
> +
> +__init int kho_out_debugfs_init(struct kho_debugfs *dbg)
> +{
> +	struct dentry *dir, *f, *sub_fdt_dir;
> +
> +	INIT_LIST_HEAD(&dbg->fdt_list);
> +
> +	dir = debugfs_create_dir("out", debugfs_root);
> +	if (IS_ERR(dir))
> +		return -ENOMEM;
> +
> +	sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
> +	if (IS_ERR(sub_fdt_dir))
> +		goto err_rmdir;
> +
> +	f = debugfs_create_file("scratch_phys", 0400, dir, NULL,
> +				&scratch_phys_fops);
> +	if (IS_ERR(f))
> +		goto err_rmdir;
> +
> +	f = debugfs_create_file("scratch_len", 0400, dir, NULL,
> +				&scratch_len_fops);
> +	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;
> +
> +err_rmdir:
> +	debugfs_remove_recursive(dir);
> +	return -ENOENT;
> +}
> +
> +__init int kho_debugfs_init(void)
> +{
> +	debugfs_root = debugfs_create_dir("kho", NULL);
> +	if (IS_ERR(debugfs_root))
> +		return -ENOENT;
> +	return 0;
> +}
> diff --git a/kernel/kexec_handover_internal.h b/kernel/kexec_handover_internal.h
> index 05e9720ba7b9..217b8b25a542 100644
> --- a/kernel/kexec_handover_internal.h
> +++ b/kernel/kexec_handover_internal.h
> @@ -2,8 +2,47 @@
>   #ifndef LINUX_KEXEC_HANDOVER_INTERNAL_H
>   #define LINUX_KEXEC_HANDOVER_INTERNAL_H
>   
> +#include <linux/kexec_handover.h>
> +#include <linux/list.h>
>   #include <linux/types.h>
>   
> +#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
> +#include <linux/debugfs.h>
> +
> +struct kho_debugfs {
> +	struct dentry *dir;
> +	struct dentry *sub_fdt_dir;
> +	struct list_head fdt_list;
> +};
> +
> +#else
> +struct kho_debugfs {};
> +#endif
> +
> +extern struct kho_scratch *kho_scratch;
> +extern unsigned int kho_scratch_cnt;
> +
> +bool kho_finalized(void);
> +int kho_finalize(void);
> +int kho_abort(void);
> +
> +#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
> +int kho_debugfs_init(void);
> +void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt);
> +int kho_out_debugfs_init(struct kho_debugfs *dbg);
> +int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
> +			const void *fdt, bool root);
> +void kho_debugfs_cleanup(struct kho_debugfs *dbg);
> +#else
> +static inline int kho_debugfs_init(void) { return 0; }
> +static inline void kho_in_debugfs_init(struct kho_debugfs *dbg,
> +				       const void *fdt) { }
> +static inline int kho_out_debugfs_init(struct kho_debugfs *dbg) { return 0; }
> +static inline int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
> +				      const void *fdt, bool root) { return 0; }
> +static inline void kho_debugfs_cleanup(struct kho_debugfs *dbg) {}
> +#endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */
> +
>   #ifdef CONFIG_KEXEC_HANDOVER_DEBUG
>   bool kho_scratch_overlap(phys_addr_t phys, size_t size);
>   #else
> diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh
> index 3f6c17166846..49fdac8e8b15 100755
> --- a/tools/testing/selftests/kho/vmtest.sh
> +++ b/tools/testing/selftests/kho/vmtest.sh
> @@ -59,6 +59,7 @@ function build_kernel() {
>   	tee "$kconfig" > "$kho_config" <<EOF
>   CONFIG_BLK_DEV_INITRD=y
>   CONFIG_KEXEC_HANDOVER=y
> +CONFIG_KEXEC_HANDOVER_DEBUGFS=y
>   CONFIG_TEST_KEXEC_HANDOVER=y
>   CONFIG_DEBUG_KERNEL=y
>   CONFIG_DEBUG_VM=y

Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month, 1 week ago
> Hi, Pasha
>
> In our previous discussion, we talked about counting the number of times
> the kernel is rebooted via kexec. At that time, you suggested adding a
> variable in debugfs to keep track of this count.
> However, since debugfs is now optional, where would be an appropriate
> place to store this variable?

It is an optional config and can still be enabled if the live update
reboot number value needs to be accessed through debugfs. However,
given that debugfs does not guarantee a stable interface, tooling
should not be built to require these interfaces.

In the WIP LUO [1] I have, I pr_info() the live update number during
boot and also store it in the incoming LUO FDT tree, which can also be
accessed through this optional debugfs interface.

The pr_info message appears like this during boot:
[    0.000000] luo: Retrieved live update data, liveupdate number: 17

Pasha
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month, 1 week ago
On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>
> > Hi, Pasha
> >
> > In our previous discussion, we talked about counting the number of times
> > the kernel is rebooted via kexec. At that time, you suggested adding a
> > variable in debugfs to keep track of this count.
> > However, since debugfs is now optional, where would be an appropriate
> > place to store this variable?
>
> It is an optional config and can still be enabled if the live update
> reboot number value needs to be accessed through debugfs. However,
> given that debugfs does not guarantee a stable interface, tooling
> should not be built to require these interfaces.
>
> In the WIP LUO [1] I have, I pr_info() the live update number during
> boot and also store it in the incoming LUO FDT tree, which can also be
> accessed through this optional debugfs interface.
>
> The pr_info message appears like this during boot:
> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>
> Pasha

Forgot to add link to WIP LUOv5:
[1] https://github.com/soleen/linux/tree/luo/v5rc04
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Yanjun.Zhu 1 month, 1 week ago
On 11/7/25 4:02 AM, Pasha Tatashin wrote:
> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>>> Hi, Pasha
>>>
>>> In our previous discussion, we talked about counting the number of times
>>> the kernel is rebooted via kexec. At that time, you suggested adding a
>>> variable in debugfs to keep track of this count.
>>> However, since debugfs is now optional, where would be an appropriate
>>> place to store this variable?
>> It is an optional config and can still be enabled if the live update
>> reboot number value needs to be accessed through debugfs. However,
>> given that debugfs does not guarantee a stable interface, tooling
>> should not be built to require these interfaces.
>>
>> In the WIP LUO [1] I have, I pr_info() the live update number during
>> boot and also store it in the incoming LUO FDT tree, which can also be
>> accessed through this optional debugfs interface.
>>
>> The pr_info message appears like this during boot:
>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>>
>> Pasha
> Forgot to add link to WIP LUOv5:
> [1] https://github.com/soleen/linux/tree/luo/v5rc04


Thanks a lot. I’ve carefully read this commit: 
https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.

To be honest, I’d like to run some tests with who/luo, including the 
selftest for kho/luo. Could you please share the steps with me?

If the testing steps have already been documented somewhere, could you 
please share the link?

Best Regards,

Yanjun.Zhu

Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month, 1 week ago
On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>
>
> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
> > On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
> >>> Hi, Pasha
> >>>
> >>> In our previous discussion, we talked about counting the number of times
> >>> the kernel is rebooted via kexec. At that time, you suggested adding a
> >>> variable in debugfs to keep track of this count.
> >>> However, since debugfs is now optional, where would be an appropriate
> >>> place to store this variable?
> >> It is an optional config and can still be enabled if the live update
> >> reboot number value needs to be accessed through debugfs. However,
> >> given that debugfs does not guarantee a stable interface, tooling
> >> should not be built to require these interfaces.
> >>
> >> In the WIP LUO [1] I have, I pr_info() the live update number during
> >> boot and also store it in the incoming LUO FDT tree, which can also be
> >> accessed through this optional debugfs interface.
> >>
> >> The pr_info message appears like this during boot:
> >> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
> >>
> >> Pasha
> > Forgot to add link to WIP LUOv5:
> > [1] https://github.com/soleen/linux/tree/luo/v5rc04
>
>
> Thanks a lot. I’ve carefully read this commit:
> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
>
> To be honest, I’d like to run some tests with who/luo, including the
> selftest for kho/luo. Could you please share the steps with me?
>
> If the testing steps have already been documented somewhere, could you
> please share the link?

Currently the test performs in-kernel tests for FLB data, it creates a
number of FLB for every registered LUO file-handler, which at the
moment is only memfd.

It works together with any of the kexec based live update tests. In
v5, I introduce two tests:
luo_kexec_simple
luo_multi_session

For example, with luo_multi_session:
# ./luo_multi_session
# [STAGE 1] Starting pre-kexec setup for multi-session test...
# [STAGE 1] Creating state file for next stage (2)...
# [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
'multi-test-empty-2'...
# [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
# [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
# [STAGE 1] Executing kexec...

... reboot ...
After reboot:

$ ./luo_multi_session
# [STAGE 2] Starting post-kexec verification...
# [STAGE 2] Retrieving all sessions...
# [STAGE 2] Verifying contents of session 'multi-test-files-1'...
# [STAGE 2] Verifying contents of session 'multi-test-files-2'...
# [STAGE 2] Test data verified successfully.
# [STAGE 2] Finalizing all test sessions...
# [STAGE 2] Finalizing state session...
#
--- MULTI-SESSION KEXEC TEST PASSED ---

Dmesg data, shows that in-kernel live update test was also successful:

[    0.000000] luo: Retrieved live update data, liveupdate number: 1
[    0.034513] liveupdate test: test-flb-v0: found flb data from the
previous boot
[    0.034517] liveupdate test: test-flb-v1: found flb data from the
previous boot
[    0.034518] liveupdate test: test-flb-v2: found flb data from the
previous boot
[    0.676891] liveupdate test: Registered 3 FLBs with file handler: [memfd-v1]

Pasha

> Best Regards,
>
> Yanjun.Zhu
>
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Zhu Yanjun 1 month, 1 week ago
在 2025/11/8 10:13, Pasha Tatashin 写道:
> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>>
>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>>>>> Hi, Pasha
>>>>>
>>>>> In our previous discussion, we talked about counting the number of times
>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
>>>>> variable in debugfs to keep track of this count.
>>>>> However, since debugfs is now optional, where would be an appropriate
>>>>> place to store this variable?
>>>> It is an optional config and can still be enabled if the live update
>>>> reboot number value needs to be accessed through debugfs. However,
>>>> given that debugfs does not guarantee a stable interface, tooling
>>>> should not be built to require these interfaces.
>>>>
>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
>>>> boot and also store it in the incoming LUO FDT tree, which can also be
>>>> accessed through this optional debugfs interface.
>>>>
>>>> The pr_info message appears like this during boot:
>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>>>>
>>>> Pasha
>>> Forgot to add link to WIP LUOv5:
>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
>>
>> Thanks a lot. I’ve carefully read this commit:
>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
>>
>> To be honest, I’d like to run some tests with who/luo, including the
>> selftest for kho/luo. Could you please share the steps with me?
>>
>> If the testing steps have already been documented somewhere, could you
>> please share the link?
> Currently the test performs in-kernel tests for FLB data, it creates a
> number of FLB for every registered LUO file-handler, which at the
> moment is only memfd.
>
> It works together with any of the kexec based live update tests. In
> v5, I introduce two tests:
> luo_kexec_simple
> luo_multi_session
>
> For example, with luo_multi_session:

Hi, Pasha

I enabled "CONFIG_LIVEUPDATE=y"

# ./luo_multi_session
1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?

# ls /dev/liveupdate
ls: cannot access '/dev/liveupdate': No such file or directory

# grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
/boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
/boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y

I made tests on FC42. But /dev/liveupdate is missing.

Thanks

Yanjun.Zhu

> # ./luo_multi_session
> # [STAGE 1] Starting pre-kexec setup for multi-session test...
> # [STAGE 1] Creating state file for next stage (2)...
> # [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
> 'multi-test-empty-2'...
> # [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
> # [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
> # [STAGE 1] Executing kexec...
>
> ... reboot ...
> After reboot:
>
> $ ./luo_multi_session
> # [STAGE 2] Starting post-kexec verification...
> # [STAGE 2] Retrieving all sessions...
> # [STAGE 2] Verifying contents of session 'multi-test-files-1'...
> # [STAGE 2] Verifying contents of session 'multi-test-files-2'...
> # [STAGE 2] Test data verified successfully.
> # [STAGE 2] Finalizing all test sessions...
> # [STAGE 2] Finalizing state session...
> #
> --- MULTI-SESSION KEXEC TEST PASSED ---
>
> Dmesg data, shows that in-kernel live update test was also successful:
>
> [    0.000000] luo: Retrieved live update data, liveupdate number: 1
> [    0.034513] liveupdate test: test-flb-v0: found flb data from the
> previous boot
> [    0.034517] liveupdate test: test-flb-v1: found flb data from the
> previous boot
> [    0.034518] liveupdate test: test-flb-v2: found flb data from the
> previous boot
> [    0.676891] liveupdate test: Registered 3 FLBs with file handler: [memfd-v1]
>
> Pasha
>
>> Best Regards,
>>
>> Yanjun.Zhu
>>
-- 
Best Regards,
Yanjun.Zhu

Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pratyush Yadav 1 month, 1 week ago
On Sun, Nov 09 2025, Zhu Yanjun wrote:

> 在 2025/11/8 10:13, Pasha Tatashin 写道:
>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>>>
>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>>>>>> Hi, Pasha
>>>>>>
>>>>>> In our previous discussion, we talked about counting the number of times
>>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
>>>>>> variable in debugfs to keep track of this count.
>>>>>> However, since debugfs is now optional, where would be an appropriate
>>>>>> place to store this variable?
>>>>> It is an optional config and can still be enabled if the live update
>>>>> reboot number value needs to be accessed through debugfs. However,
>>>>> given that debugfs does not guarantee a stable interface, tooling
>>>>> should not be built to require these interfaces.
>>>>>
>>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
>>>>> boot and also store it in the incoming LUO FDT tree, which can also be
>>>>> accessed through this optional debugfs interface.
>>>>>
>>>>> The pr_info message appears like this during boot:
>>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>>>>>
>>>>> Pasha
>>>> Forgot to add link to WIP LUOv5:
>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
>>>
>>> Thanks a lot. I’ve carefully read this commit:
>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
>>>
>>> To be honest, I’d like to run some tests with who/luo, including the
>>> selftest for kho/luo. Could you please share the steps with me?
>>>
>>> If the testing steps have already been documented somewhere, could you
>>> please share the link?
>> Currently the test performs in-kernel tests for FLB data, it creates a
>> number of FLB for every registered LUO file-handler, which at the
>> moment is only memfd.
>>
>> It works together with any of the kexec based live update tests. In
>> v5, I introduce two tests:
>> luo_kexec_simple
>> luo_multi_session
>>
>> For example, with luo_multi_session:
>
> Hi, Pasha
>
> I enabled "CONFIG_LIVEUPDATE=y"
>
> # ./luo_multi_session
> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?
>
> # ls /dev/liveupdate
> ls: cannot access '/dev/liveupdate': No such file or directory
>
> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
>
> I made tests on FC42. But /dev/liveupdate is missing.

You need to add liveupdate=1 to your kernel cmdline to enable LUO and
get /dev/liveupdate.

Pasha, your LUO series doesn't add the liveupdate parameter to
kernel-parameters.txt. I think it should be done in the next version to
this parameter is discoverable.

-- 
Regards,
Pratyush Yadav
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month, 1 week ago
On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav <pratyush@kernel.org> wrote:
>
> On Sun, Nov 09 2025, Zhu Yanjun wrote:
>
> > 在 2025/11/8 10:13, Pasha Tatashin 写道:
> >> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
> >>>
> >>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
> >>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
> >>>>>> Hi, Pasha
> >>>>>>
> >>>>>> In our previous discussion, we talked about counting the number of times
> >>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
> >>>>>> variable in debugfs to keep track of this count.
> >>>>>> However, since debugfs is now optional, where would be an appropriate
> >>>>>> place to store this variable?
> >>>>> It is an optional config and can still be enabled if the live update
> >>>>> reboot number value needs to be accessed through debugfs. However,
> >>>>> given that debugfs does not guarantee a stable interface, tooling
> >>>>> should not be built to require these interfaces.
> >>>>>
> >>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
> >>>>> boot and also store it in the incoming LUO FDT tree, which can also be
> >>>>> accessed through this optional debugfs interface.
> >>>>>
> >>>>> The pr_info message appears like this during boot:
> >>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
> >>>>>
> >>>>> Pasha
> >>>> Forgot to add link to WIP LUOv5:
> >>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
> >>>
> >>> Thanks a lot. I’ve carefully read this commit:
> >>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
> >>>
> >>> To be honest, I’d like to run some tests with who/luo, including the
> >>> selftest for kho/luo. Could you please share the steps with me?
> >>>
> >>> If the testing steps have already been documented somewhere, could you
> >>> please share the link?
> >> Currently the test performs in-kernel tests for FLB data, it creates a
> >> number of FLB for every registered LUO file-handler, which at the
> >> moment is only memfd.
> >>
> >> It works together with any of the kexec based live update tests. In
> >> v5, I introduce two tests:
> >> luo_kexec_simple
> >> luo_multi_session
> >>
> >> For example, with luo_multi_session:
> >
> > Hi, Pasha
> >
> > I enabled "CONFIG_LIVEUPDATE=y"
> >
> > # ./luo_multi_session
> > 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?
> >
> > # ls /dev/liveupdate
> > ls: cannot access '/dev/liveupdate': No such file or directory
> >
> > # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
> > /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
> > /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
> >
> > I made tests on FC42. But /dev/liveupdate is missing.
>
> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
> get /dev/liveupdate.

+1, kernel parameters require: kho=1 liveupdate=1

>
> Pasha, your LUO series doesn't add the liveupdate parameter to
> kernel-parameters.txt. I think it should be done in the next version to
> this parameter is discoverable.

Yeah, that is missing, I will update that in a standalone patch, or in
a next version.

Thanks,
Pasha
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Zhu Yanjun 1 month ago
In FC42, when I run "./luo_multi_session"

# ./luo_multi_session
# [STAGE 1] Starting pre-kexec setup for multi-session test...
# [STAGE 1] Creating state file for next stage (2)...
# [STAGE 1] Creating empty sessions 'multi-test-empty-1' and 
'multi-test-empty-2'...
# [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
# [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
# [STAGE 1] Executing kexec...

Then the system hang. And via virt-viewer, a calltrace will appear.

The call trace is in the attachment.

Yanjun.Zhu

在 2025/11/10 7:26, Pasha Tatashin 写道:
> On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav <pratyush@kernel.org> wrote:
>> On Sun, Nov 09 2025, Zhu Yanjun wrote:
>>
>>> 在 2025/11/8 10:13, Pasha Tatashin 写道:
>>>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>>>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
>>>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>>>>>>>> Hi, Pasha
>>>>>>>>
>>>>>>>> In our previous discussion, we talked about counting the number of times
>>>>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
>>>>>>>> variable in debugfs to keep track of this count.
>>>>>>>> However, since debugfs is now optional, where would be an appropriate
>>>>>>>> place to store this variable?
>>>>>>> It is an optional config and can still be enabled if the live update
>>>>>>> reboot number value needs to be accessed through debugfs. However,
>>>>>>> given that debugfs does not guarantee a stable interface, tooling
>>>>>>> should not be built to require these interfaces.
>>>>>>>
>>>>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
>>>>>>> boot and also store it in the incoming LUO FDT tree, which can also be
>>>>>>> accessed through this optional debugfs interface.
>>>>>>>
>>>>>>> The pr_info message appears like this during boot:
>>>>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>>>>>>>
>>>>>>> Pasha
>>>>>> Forgot to add link to WIP LUOv5:
>>>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
>>>>> Thanks a lot. I’ve carefully read this commit:
>>>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
>>>>>
>>>>> To be honest, I’d like to run some tests with who/luo, including the
>>>>> selftest for kho/luo. Could you please share the steps with me?
>>>>>
>>>>> If the testing steps have already been documented somewhere, could you
>>>>> please share the link?
>>>> Currently the test performs in-kernel tests for FLB data, it creates a
>>>> number of FLB for every registered LUO file-handler, which at the
>>>> moment is only memfd.
>>>>
>>>> It works together with any of the kexec based live update tests. In
>>>> v5, I introduce two tests:
>>>> luo_kexec_simple
>>>> luo_multi_session
>>>>
>>>> For example, with luo_multi_session:
>>> Hi, Pasha
>>>
>>> I enabled "CONFIG_LIVEUPDATE=y"
>>>
>>> # ./luo_multi_session
>>> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?
>>>
>>> # ls /dev/liveupdate
>>> ls: cannot access '/dev/liveupdate': No such file or directory
>>>
>>> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
>>> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
>>> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
>>>
>>> I made tests on FC42. But /dev/liveupdate is missing.
>> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
>> get /dev/liveupdate.
> +1, kernel parameters require: kho=1 liveupdate=1
>
>> Pasha, your LUO series doesn't add the liveupdate parameter to
>> kernel-parameters.txt. I think it should be done in the next version to
>> this parameter is discoverable.
> Yeah, that is missing, I will update that in a standalone patch, or in
> a next version.
>
> Thanks,
> Pasha

-- 
Best Regards,
Yanjun.Zhu
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month ago
On Mon, Nov 10, 2025 at 11:11 PM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>
> In FC42, when I run "./luo_multi_session"
>
> # ./luo_multi_session
> # [STAGE 1] Starting pre-kexec setup for multi-session test...
> # [STAGE 1] Creating state file for next stage (2)...
> # [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
> 'multi-test-empty-2'...
> # [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
> # [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
> # [STAGE 1] Executing kexec...
>
> Then the system hang. And via virt-viewer, a calltrace will appear.

Looks like mountroot fails, are you passing the same kernel parameters
as the during cold boot?
i.e. kexec -l -s --reuse-cmdline --initrd=[initramfs] [kernel]

Pasha

>
> The call trace is in the attachment.
>
> Yanjun.Zhu
>
> 在 2025/11/10 7:26, Pasha Tatashin 写道:
> > On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav <pratyush@kernel.org> wrote:
> >> On Sun, Nov 09 2025, Zhu Yanjun wrote:
> >>
> >>> 在 2025/11/8 10:13, Pasha Tatashin 写道:
> >>>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
> >>>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
> >>>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
> >>>>>>>> Hi, Pasha
> >>>>>>>>
> >>>>>>>> In our previous discussion, we talked about counting the number of times
> >>>>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
> >>>>>>>> variable in debugfs to keep track of this count.
> >>>>>>>> However, since debugfs is now optional, where would be an appropriate
> >>>>>>>> place to store this variable?
> >>>>>>> It is an optional config and can still be enabled if the live update
> >>>>>>> reboot number value needs to be accessed through debugfs. However,
> >>>>>>> given that debugfs does not guarantee a stable interface, tooling
> >>>>>>> should not be built to require these interfaces.
> >>>>>>>
> >>>>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
> >>>>>>> boot and also store it in the incoming LUO FDT tree, which can also be
> >>>>>>> accessed through this optional debugfs interface.
> >>>>>>>
> >>>>>>> The pr_info message appears like this during boot:
> >>>>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
> >>>>>>>
> >>>>>>> Pasha
> >>>>>> Forgot to add link to WIP LUOv5:
> >>>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
> >>>>> Thanks a lot. I’ve carefully read this commit:
> >>>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
> >>>>>
> >>>>> To be honest, I’d like to run some tests with who/luo, including the
> >>>>> selftest for kho/luo. Could you please share the steps with me?
> >>>>>
> >>>>> If the testing steps have already been documented somewhere, could you
> >>>>> please share the link?
> >>>> Currently the test performs in-kernel tests for FLB data, it creates a
> >>>> number of FLB for every registered LUO file-handler, which at the
> >>>> moment is only memfd.
> >>>>
> >>>> It works together with any of the kexec based live update tests. In
> >>>> v5, I introduce two tests:
> >>>> luo_kexec_simple
> >>>> luo_multi_session
> >>>>
> >>>> For example, with luo_multi_session:
> >>> Hi, Pasha
> >>>
> >>> I enabled "CONFIG_LIVEUPDATE=y"
> >>>
> >>> # ./luo_multi_session
> >>> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?
> >>>
> >>> # ls /dev/liveupdate
> >>> ls: cannot access '/dev/liveupdate': No such file or directory
> >>>
> >>> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
> >>> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
> >>> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
> >>>
> >>> I made tests on FC42. But /dev/liveupdate is missing.
> >> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
> >> get /dev/liveupdate.
> > +1, kernel parameters require: kho=1 liveupdate=1
> >
> >> Pasha, your LUO series doesn't add the liveupdate parameter to
> >> kernel-parameters.txt. I think it should be done in the next version to
> >> this parameter is discoverable.
> > Yeah, that is missing, I will update that in a standalone patch, or in
> > a next version.
> >
> > Thanks,
> > Pasha
>
> --
> Best Regards,
> Yanjun.Zhu
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Yanjun.Zhu 1 month ago
On 11/11/25 7:26 AM, Pasha Tatashin wrote:
> On Mon, Nov 10, 2025 at 11:11 PM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>> In FC42, when I run "./luo_multi_session"
>>
>> # ./luo_multi_session
>> # [STAGE 1] Starting pre-kexec setup for multi-session test...
>> # [STAGE 1] Creating state file for next stage (2)...
>> # [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
>> 'multi-test-empty-2'...
>> # [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
>> # [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
>> # [STAGE 1] Executing kexec...
>>
>> Then the system hang. And via virt-viewer, a calltrace will appear.
> Looks like mountroot fails, are you passing the same kernel parameters
> as the during cold boot?
> i.e. kexec -l -s --reuse-cmdline --initrd=[initramfs] [kernel]
>
> Pasha

Hi, Pasha

Following your advice, the following can work well.

I am not sure if we can merge this commit into selftests/liveupdate 
mainline?

commit 44764c48a658987b7729c5bc2be9fd87832cfbdf (HEAD -> linux-next/master)
Author: Zhu Yanjun <yanjun.zhu@linux.dev>
Date:   Thu Nov 13 11:45:21 2025 -0800

     selftests/liveupdate: Fix the error "Unable to mount root fs on 
unknown-block"

     If the initrd is not provide, the followings will appear.
     "
     Call Trace:
     <TASK>
     dump_stack_lvl+0x5d/0x80
     vpanic+0x118/8x320
     panic+0x6b/0x6b
     ? do_mount_root+0x115/0x130
      mount_root_generic+0x1cf/0x270
      prepare_namespace+0x1e1/0x230
      kernel_init_freeable+0x136/8x140
     ?_pfx_kernel_init+0x10/0x10
      kernel_init+0x1a/0x140
      ret_from_fork+0x130/0x1a8
      ?_pfx_kernel_init+0x10/0x10
      ret_from_fork_asm+0x1a/0x30
      </ TASK>
      Kernel Offset: 0x3000000 from Oxffffffff81000000
     "

     Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>

diff --git a/tools/testing/selftests/liveupdate/do_kexec.sh 
b/tools/testing/selftests/liveupdate/do_kexec.sh
index bb396a92c3b8..4ee59abd0dd4 100755
--- a/tools/testing/selftests/liveupdate/do_kexec.sh
+++ b/tools/testing/selftests/liveupdate/do_kexec.sh
@@ -2,5 +2,5 @@
  # SPDX-License-Identifier: GPL-2.0
  set -e

-kexec -l -s --reuse-cmdline /boot/bzImage
+kexec -l -s --reuse-cmdline /boot/bzImage --initrd 
/boot/initramfs-`uname -r`.img
  kexec -e

Thanks a lot.

Yanjun.Zhu

>> The call trace is in the attachment.
>>
>> Yanjun.Zhu
>>
>> 在 2025/11/10 7:26, Pasha Tatashin 写道:
>>> On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav <pratyush@kernel.org> wrote:
>>>> On Sun, Nov 09 2025, Zhu Yanjun wrote:
>>>>
>>>>> 在 2025/11/8 10:13, Pasha Tatashin 写道:
>>>>>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>>>>>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
>>>>>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>>>>>>>>>> Hi, Pasha
>>>>>>>>>>
>>>>>>>>>> In our previous discussion, we talked about counting the number of times
>>>>>>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
>>>>>>>>>> variable in debugfs to keep track of this count.
>>>>>>>>>> However, since debugfs is now optional, where would be an appropriate
>>>>>>>>>> place to store this variable?
>>>>>>>>> It is an optional config and can still be enabled if the live update
>>>>>>>>> reboot number value needs to be accessed through debugfs. However,
>>>>>>>>> given that debugfs does not guarantee a stable interface, tooling
>>>>>>>>> should not be built to require these interfaces.
>>>>>>>>>
>>>>>>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
>>>>>>>>> boot and also store it in the incoming LUO FDT tree, which can also be
>>>>>>>>> accessed through this optional debugfs interface.
>>>>>>>>>
>>>>>>>>> The pr_info message appears like this during boot:
>>>>>>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>>>>>>>>>
>>>>>>>>> Pasha
>>>>>>>> Forgot to add link to WIP LUOv5:
>>>>>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
>>>>>>> Thanks a lot. I’ve carefully read this commit:
>>>>>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
>>>>>>>
>>>>>>> To be honest, I’d like to run some tests with who/luo, including the
>>>>>>> selftest for kho/luo. Could you please share the steps with me?
>>>>>>>
>>>>>>> If the testing steps have already been documented somewhere, could you
>>>>>>> please share the link?
>>>>>> Currently the test performs in-kernel tests for FLB data, it creates a
>>>>>> number of FLB for every registered LUO file-handler, which at the
>>>>>> moment is only memfd.
>>>>>>
>>>>>> It works together with any of the kexec based live update tests. In
>>>>>> v5, I introduce two tests:
>>>>>> luo_kexec_simple
>>>>>> luo_multi_session
>>>>>>
>>>>>> For example, with luo_multi_session:
>>>>> Hi, Pasha
>>>>>
>>>>> I enabled "CONFIG_LIVEUPDATE=y"
>>>>>
>>>>> # ./luo_multi_session
>>>>> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?
>>>>>
>>>>> # ls /dev/liveupdate
>>>>> ls: cannot access '/dev/liveupdate': No such file or directory
>>>>>
>>>>> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
>>>>> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
>>>>> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
>>>>>
>>>>> I made tests on FC42. But /dev/liveupdate is missing.
>>>> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
>>>> get /dev/liveupdate.
>>> +1, kernel parameters require: kho=1 liveupdate=1
>>>
>>>> Pasha, your LUO series doesn't add the liveupdate parameter to
>>>> kernel-parameters.txt. I think it should be done in the next version to
>>>> this parameter is discoverable.
>>> Yeah, that is missing, I will update that in a standalone patch, or in
>>> a next version.
>>>
>>> Thanks,
>>> Pasha
>> --
>> Best Regards,
>> Yanjun.Zhu
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month ago
>   set -e
>
> -kexec -l -s --reuse-cmdline /boot/bzImage
> +kexec -l -s --reuse-cmdline /boot/bzImage --initrd
> /boot/initramfs-`uname -r`.img

Thank you for your suggestion, in the next version, I am going to add
initramfs optionally, I am thinking to update script to something like
this:

#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
set -e

# Use $KERNEL and $INITRAMFS to pass custom Kernel and optional initramfs

KERNEL="${KERNEL:-/boot/bzImage}"
set -- -l -s --reuse-cmdline "$KERNEL"

INITRAMFS="${INITRAMFS:-/boot/initramfs}"
if [ -f "$INITRAMFS" ]; then
    set -- "$@" --initrd="$INITRAMFS"
fi

kexec "$@"
kexec -e
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month ago
On Thu, Nov 13, 2025 at 3:10 PM Pasha Tatashin
<pasha.tatashin@soleen.com> wrote:
>
> >   set -e
> >
> > -kexec -l -s --reuse-cmdline /boot/bzImage
> > +kexec -l -s --reuse-cmdline /boot/bzImage --initrd
> > /boot/initramfs-`uname -r`.img
>
> Thank you for your suggestion, in the next version, I am going to add
> initramfs optionally, I am thinking to update script to something like

Optionally, because in some environments (like in mine), it is built
into bzImage.

> this:
>
> #!/bin/sh
> # SPDX-License-Identifier: GPL-2.0
> set -e
>
> # Use $KERNEL and $INITRAMFS to pass custom Kernel and optional initramfs
>
> KERNEL="${KERNEL:-/boot/bzImage}"
> set -- -l -s --reuse-cmdline "$KERNEL"
>
> INITRAMFS="${INITRAMFS:-/boot/initramfs}"
> if [ -f "$INITRAMFS" ]; then
>     set -- "$@" --initrd="$INITRAMFS"
> fi
>
> kexec "$@"
> kexec -e
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Yanjun.Zhu 1 month ago
On 11/13/25 12:13 PM, Pasha Tatashin wrote:
> On Thu, Nov 13, 2025 at 3:10 PM Pasha Tatashin
> <pasha.tatashin@soleen.com> wrote:
>>>    set -e
>>>
>>> -kexec -l -s --reuse-cmdline /boot/bzImage
>>> +kexec -l -s --reuse-cmdline /boot/bzImage --initrd
>>> /boot/initramfs-`uname -r`.img
>> Thank you for your suggestion, in the next version, I am going to add
>> initramfs optionally, I am thinking to update script to something like
> Optionally, because in some environments (like in mine), it is built
> into bzImage.

In my test hosts, the bzImage is vmlinuz-xxx. But with the help of "ln 
-sf ... ...",

this change can work well in my test environments, including x86_64 and 
arm64 hosts.

Br,

Yanjun.Zhu

>
>> this:
>>
>> #!/bin/sh
>> # SPDX-License-Identifier: GPL-2.0
>> set -e
>>
>> # Use $KERNEL and $INITRAMFS to pass custom Kernel and optional initramfs
>>
>> KERNEL="${KERNEL:-/boot/bzImage}"
>> set -- -l -s --reuse-cmdline "$KERNEL"
>>
>> INITRAMFS="${INITRAMFS:-/boot/initramfs}"
>> if [ -f "$INITRAMFS" ]; then
>>      set -- "$@" --initrd="$INITRAMFS"
>> fi
>>
>> kexec "$@"
>> kexec -e
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Yanjun.Zhu 1 month ago
On 11/11/25 7:26 AM, Pasha Tatashin wrote:
> On Mon, Nov 10, 2025 at 11:11 PM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>> In FC42, when I run "./luo_multi_session"
>>
>> # ./luo_multi_session
>> # [STAGE 1] Starting pre-kexec setup for multi-session test...
>> # [STAGE 1] Creating state file for next stage (2)...
>> # [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
>> 'multi-test-empty-2'...
>> # [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
>> # [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
>> # [STAGE 1] Executing kexec...
>>
>> Then the system hang. And via virt-viewer, a calltrace will appear.
> Looks like mountroot fails, are you passing the same kernel parameters
> as the during cold boot?
> i.e. kexec -l -s --reuse-cmdline --initrd=[initramfs] [kernel]


Thanks a lot. It can work now.  The logs are as below:

"

# [STAGE 2] Starting post-kexec verification...
# [STAGE 2] Retrieving all sessions...
# [STAGE 2] Verifying contents of session 'multi-test-files-1'...
# [STAGE 2] Verifying contents of session 'multi-test-files-2'...
# [STAGE 2] Test data verified successfully.
# [STAGE 2] Finalizing all test sessions...
# [STAGE 2] Finalizing state session...
#
--- MULTI-SESSION KEXEC TEST PASSED ---
"

Yanjun.Zhu

>
> Pasha
>
>> The call trace is in the attachment.
>>
>> Yanjun.Zhu
>>
>> 在 2025/11/10 7:26, Pasha Tatashin 写道:
>>> On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav <pratyush@kernel.org> wrote:
>>>> On Sun, Nov 09 2025, Zhu Yanjun wrote:
>>>>
>>>>> 在 2025/11/8 10:13, Pasha Tatashin 写道:
>>>>>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>>>>>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
>>>>>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
>>>>>>>>>> Hi, Pasha
>>>>>>>>>>
>>>>>>>>>> In our previous discussion, we talked about counting the number of times
>>>>>>>>>> the kernel is rebooted via kexec. At that time, you suggested adding a
>>>>>>>>>> variable in debugfs to keep track of this count.
>>>>>>>>>> However, since debugfs is now optional, where would be an appropriate
>>>>>>>>>> place to store this variable?
>>>>>>>>> It is an optional config and can still be enabled if the live update
>>>>>>>>> reboot number value needs to be accessed through debugfs. However,
>>>>>>>>> given that debugfs does not guarantee a stable interface, tooling
>>>>>>>>> should not be built to require these interfaces.
>>>>>>>>>
>>>>>>>>> In the WIP LUO [1] I have, I pr_info() the live update number during
>>>>>>>>> boot and also store it in the incoming LUO FDT tree, which can also be
>>>>>>>>> accessed through this optional debugfs interface.
>>>>>>>>>
>>>>>>>>> The pr_info message appears like this during boot:
>>>>>>>>> [    0.000000] luo: Retrieved live update data, liveupdate number: 17
>>>>>>>>>
>>>>>>>>> Pasha
>>>>>>>> Forgot to add link to WIP LUOv5:
>>>>>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
>>>>>>> Thanks a lot. I’ve carefully read this commit:
>>>>>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
>>>>>>>
>>>>>>> To be honest, I’d like to run some tests with who/luo, including the
>>>>>>> selftest for kho/luo. Could you please share the steps with me?
>>>>>>>
>>>>>>> If the testing steps have already been documented somewhere, could you
>>>>>>> please share the link?
>>>>>> Currently the test performs in-kernel tests for FLB data, it creates a
>>>>>> number of FLB for every registered LUO file-handler, which at the
>>>>>> moment is only memfd.
>>>>>>
>>>>>> It works together with any of the kexec based live update tests. In
>>>>>> v5, I introduce two tests:
>>>>>> luo_kexec_simple
>>>>>> luo_multi_session
>>>>>>
>>>>>> For example, with luo_multi_session:
>>>>> Hi, Pasha
>>>>>
>>>>> I enabled "CONFIG_LIVEUPDATE=y"
>>>>>
>>>>> # ./luo_multi_session
>>>>> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module loaded?
>>>>>
>>>>> # ls /dev/liveupdate
>>>>> ls: cannot access '/dev/liveupdate': No such file or directory
>>>>>
>>>>> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
>>>>> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
>>>>> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
>>>>>
>>>>> I made tests on FC42. But /dev/liveupdate is missing.
>>>> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
>>>> get /dev/liveupdate.
>>> +1, kernel parameters require: kho=1 liveupdate=1
>>>
>>>> Pasha, your LUO series doesn't add the liveupdate parameter to
>>>> kernel-parameters.txt. I think it should be done in the next version to
>>>> this parameter is discoverable.
>>> Yeah, that is missing, I will update that in a standalone patch, or in
>>> a next version.
>>>
>>> Thanks,
>>> Pasha
>> --
>> Best Regards,
>> Yanjun.Zhu
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Yanjun.Zhu 1 month ago
On 11/12/25 5:41 PM, Yanjun.Zhu wrote:
>
> On 11/11/25 7:26 AM, Pasha Tatashin wrote:
>> On Mon, Nov 10, 2025 at 11:11 PM Zhu Yanjun <yanjun.zhu@linux.dev> 
>> wrote:
>>> In FC42, when I run "./luo_multi_session"
>>>
>>> # ./luo_multi_session
>>> # [STAGE 1] Starting pre-kexec setup for multi-session test...
>>> # [STAGE 1] Creating state file for next stage (2)...
>>> # [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
>>> 'multi-test-empty-2'...
>>> # [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
>>> # [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
>>> # [STAGE 1] Executing kexec...
>>>
>>> Then the system hang. And via virt-viewer, a calltrace will appear.
>> Looks like mountroot fails, are you passing the same kernel parameters
>> as the during cold boot?
>> i.e. kexec -l -s --reuse-cmdline --initrd=[initramfs] [kernel]
>
>
> Thanks a lot. It can work now.  The logs are as below:
>
> "
>
> # [STAGE 2] Starting post-kexec verification...
> # [STAGE 2] Retrieving all sessions...
> # [STAGE 2] Verifying contents of session 'multi-test-files-1'...
> # [STAGE 2] Verifying contents of session 'multi-test-files-2'...
> # [STAGE 2] Test data verified successfully.
> # [STAGE 2] Finalizing all test sessions...
> # [STAGE 2] Finalizing state session...
> #
> --- MULTI-SESSION KEXEC TEST PASSED ---
> "
>
> Yanjun.Zhu


Hi, Pasha

In my tests, I found that luo_kexec_simple and luo_multi_session 
currently depend on the glibc-static library.
If this library is not installed, build errors occur.
By making the following changes, luo_kexec_simple and luo_multi_session 
would no longer depend on glibc-static, reducing external library 
dependencies.
I am not sure whether you agree with these proposed changes.

diff --git a/tools/testing/selftests/liveupdate/Makefile 
b/tools/testing/selftests/liveupdate/Makefile
index 6ee6efeec62d..b226b9976150 100644
--- a/tools/testing/selftests/liveupdate/Makefile
+++ b/tools/testing/selftests/liveupdate/Makefile
@@ -3,7 +3,6 @@
  KHDR_INCLUDES ?= -I../../../../usr/include
  CFLAGS += -Wall -O2 -Wno-unused-function
  CFLAGS += $(KHDR_INCLUDES)
-LDFLAGS += -static
  OUTPUT ?= .

  # --- Test Configuration (Edit this section when adding new tests) ---

Yanjun.Zhu

>
>
>>
>> Pasha
>>
>>> The call trace is in the attachment.
>>>
>>> Yanjun.Zhu
>>>
>>> 在 2025/11/10 7:26, Pasha Tatashin 写道:
>>>> On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav 
>>>> <pratyush@kernel.org> wrote:
>>>>> On Sun, Nov 09 2025, Zhu Yanjun wrote:
>>>>>
>>>>>> 在 2025/11/8 10:13, Pasha Tatashin 写道:
>>>>>>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev> 
>>>>>>> wrote:
>>>>>>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
>>>>>>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin 
>>>>>>>>> <pasha.tatashin@soleen.com> wrote:
>>>>>>>>>>> Hi, Pasha
>>>>>>>>>>>
>>>>>>>>>>> In our previous discussion, we talked about counting the 
>>>>>>>>>>> number of times
>>>>>>>>>>> the kernel is rebooted via kexec. At that time, you 
>>>>>>>>>>> suggested adding a
>>>>>>>>>>> variable in debugfs to keep track of this count.
>>>>>>>>>>> However, since debugfs is now optional, where would be an 
>>>>>>>>>>> appropriate
>>>>>>>>>>> place to store this variable?
>>>>>>>>>> It is an optional config and can still be enabled if the live 
>>>>>>>>>> update
>>>>>>>>>> reboot number value needs to be accessed through debugfs. 
>>>>>>>>>> However,
>>>>>>>>>> given that debugfs does not guarantee a stable interface, 
>>>>>>>>>> tooling
>>>>>>>>>> should not be built to require these interfaces.
>>>>>>>>>>
>>>>>>>>>> In the WIP LUO [1] I have, I pr_info() the live update number 
>>>>>>>>>> during
>>>>>>>>>> boot and also store it in the incoming LUO FDT tree, which 
>>>>>>>>>> can also be
>>>>>>>>>> accessed through this optional debugfs interface.
>>>>>>>>>>
>>>>>>>>>> The pr_info message appears like this during boot:
>>>>>>>>>> [    0.000000] luo: Retrieved live update data, liveupdate 
>>>>>>>>>> number: 17
>>>>>>>>>>
>>>>>>>>>> Pasha
>>>>>>>>> Forgot to add link to WIP LUOv5:
>>>>>>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
>>>>>>>> Thanks a lot. I’ve carefully read this commit:
>>>>>>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa. 
>>>>>>>>
>>>>>>>>
>>>>>>>> To be honest, I’d like to run some tests with who/luo, 
>>>>>>>> including the
>>>>>>>> selftest for kho/luo. Could you please share the steps with me?
>>>>>>>>
>>>>>>>> If the testing steps have already been documented somewhere, 
>>>>>>>> could you
>>>>>>>> please share the link?
>>>>>>> Currently the test performs in-kernel tests for FLB data, it 
>>>>>>> creates a
>>>>>>> number of FLB for every registered LUO file-handler, which at the
>>>>>>> moment is only memfd.
>>>>>>>
>>>>>>> It works together with any of the kexec based live update tests. In
>>>>>>> v5, I introduce two tests:
>>>>>>> luo_kexec_simple
>>>>>>> luo_multi_session
>>>>>>>
>>>>>>> For example, with luo_multi_session:
>>>>>> Hi, Pasha
>>>>>>
>>>>>> I enabled "CONFIG_LIVEUPDATE=y"
>>>>>>
>>>>>> # ./luo_multi_session
>>>>>> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module 
>>>>>> loaded?
>>>>>>
>>>>>> # ls /dev/liveupdate
>>>>>> ls: cannot access '/dev/liveupdate': No such file or directory
>>>>>>
>>>>>> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
>>>>>> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
>>>>>> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
>>>>>>
>>>>>> I made tests on FC42. But /dev/liveupdate is missing.
>>>>> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
>>>>> get /dev/liveupdate.
>>>> +1, kernel parameters require: kho=1 liveupdate=1
>>>>
>>>>> Pasha, your LUO series doesn't add the liveupdate parameter to
>>>>> kernel-parameters.txt. I think it should be done in the next 
>>>>> version to
>>>>> this parameter is discoverable.
>>>> Yeah, that is missing, I will update that in a standalone patch, or in
>>>> a next version.
>>>>
>>>> Thanks,
>>>> Pasha
>>> -- 
>>> Best Regards,
>>> Yanjun.Zhu
Re: [PATCH v9 1/9] kho: make debugfs interface optional
Posted by Pasha Tatashin 1 month ago
On Wed, Nov 12, 2025 at 9:11 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>
>
> On 11/12/25 5:41 PM, Yanjun.Zhu wrote:
> >
> > On 11/11/25 7:26 AM, Pasha Tatashin wrote:
> >> On Mon, Nov 10, 2025 at 11:11 PM Zhu Yanjun <yanjun.zhu@linux.dev>
> >> wrote:
> >>> In FC42, when I run "./luo_multi_session"
> >>>
> >>> # ./luo_multi_session
> >>> # [STAGE 1] Starting pre-kexec setup for multi-session test...
> >>> # [STAGE 1] Creating state file for next stage (2)...
> >>> # [STAGE 1] Creating empty sessions 'multi-test-empty-1' and
> >>> 'multi-test-empty-2'...
> >>> # [STAGE 1] Creating session 'multi-test-files-1' with one memfd...
> >>> # [STAGE 1] Creating session 'multi-test-files-2' with two memfds...
> >>> # [STAGE 1] Executing kexec...
> >>>
> >>> Then the system hang. And via virt-viewer, a calltrace will appear.
> >> Looks like mountroot fails, are you passing the same kernel parameters
> >> as the during cold boot?
> >> i.e. kexec -l -s --reuse-cmdline --initrd=[initramfs] [kernel]
> >
> >
> > Thanks a lot. It can work now.  The logs are as below:
> >
> > "
> >
> > # [STAGE 2] Starting post-kexec verification...
> > # [STAGE 2] Retrieving all sessions...
> > # [STAGE 2] Verifying contents of session 'multi-test-files-1'...
> > # [STAGE 2] Verifying contents of session 'multi-test-files-2'...
> > # [STAGE 2] Test data verified successfully.
> > # [STAGE 2] Finalizing all test sessions...
> > # [STAGE 2] Finalizing state session...
> > #
> > --- MULTI-SESSION KEXEC TEST PASSED ---
> > "
> >
> > Yanjun.Zhu
>
>
> Hi, Pasha
>
> In my tests, I found that luo_kexec_simple and luo_multi_session
> currently depend on the glibc-static library.
> If this library is not installed, build errors occur.
> By making the following changes, luo_kexec_simple and luo_multi_session
> would no longer depend on glibc-static, reducing external library
> dependencies.
> I am not sure whether you agree with these proposed changes.
>
> diff --git a/tools/testing/selftests/liveupdate/Makefile
> b/tools/testing/selftests/liveupdate/Makefile
> index 6ee6efeec62d..b226b9976150 100644
> --- a/tools/testing/selftests/liveupdate/Makefile
> +++ b/tools/testing/selftests/liveupdate/Makefile
> @@ -3,7 +3,6 @@
>   KHDR_INCLUDES ?= -I../../../../usr/include
>   CFLAGS += -Wall -O2 -Wno-unused-function
>   CFLAGS += $(KHDR_INCLUDES)
> -LDFLAGS += -static

Hi Yanjun,

Thank you for testing. I prefer to keep the '-static' flag because
these self-test files are not executed in the same environment where
they are compiled but in a VM which might have a different userspace.

Thank you,
Pasha

>   OUTPUT ?= .
>
>   # --- Test Configuration (Edit this section when adding new tests) ---
>
> Yanjun.Zhu
>
> >
> >
> >>
> >> Pasha
> >>
> >>> The call trace is in the attachment.
> >>>
> >>> Yanjun.Zhu
> >>>
> >>> 在 2025/11/10 7:26, Pasha Tatashin 写道:
> >>>> On Mon, Nov 10, 2025 at 8:16 AM Pratyush Yadav
> >>>> <pratyush@kernel.org> wrote:
> >>>>> On Sun, Nov 09 2025, Zhu Yanjun wrote:
> >>>>>
> >>>>>> 在 2025/11/8 10:13, Pasha Tatashin 写道:
> >>>>>>> On Fri, Nov 7, 2025 at 6:36 PM Yanjun.Zhu <yanjun.zhu@linux.dev>
> >>>>>>> wrote:
> >>>>>>>> On 11/7/25 4:02 AM, Pasha Tatashin wrote:
> >>>>>>>>> On Fri, Nov 7, 2025 at 7:00 AM Pasha Tatashin
> >>>>>>>>> <pasha.tatashin@soleen.com> wrote:
> >>>>>>>>>>> Hi, Pasha
> >>>>>>>>>>>
> >>>>>>>>>>> In our previous discussion, we talked about counting the
> >>>>>>>>>>> number of times
> >>>>>>>>>>> the kernel is rebooted via kexec. At that time, you
> >>>>>>>>>>> suggested adding a
> >>>>>>>>>>> variable in debugfs to keep track of this count.
> >>>>>>>>>>> However, since debugfs is now optional, where would be an
> >>>>>>>>>>> appropriate
> >>>>>>>>>>> place to store this variable?
> >>>>>>>>>> It is an optional config and can still be enabled if the live
> >>>>>>>>>> update
> >>>>>>>>>> reboot number value needs to be accessed through debugfs.
> >>>>>>>>>> However,
> >>>>>>>>>> given that debugfs does not guarantee a stable interface,
> >>>>>>>>>> tooling
> >>>>>>>>>> should not be built to require these interfaces.
> >>>>>>>>>>
> >>>>>>>>>> In the WIP LUO [1] I have, I pr_info() the live update number
> >>>>>>>>>> during
> >>>>>>>>>> boot and also store it in the incoming LUO FDT tree, which
> >>>>>>>>>> can also be
> >>>>>>>>>> accessed through this optional debugfs interface.
> >>>>>>>>>>
> >>>>>>>>>> The pr_info message appears like this during boot:
> >>>>>>>>>> [    0.000000] luo: Retrieved live update data, liveupdate
> >>>>>>>>>> number: 17
> >>>>>>>>>>
> >>>>>>>>>> Pasha
> >>>>>>>>> Forgot to add link to WIP LUOv5:
> >>>>>>>>> [1] https://github.com/soleen/linux/tree/luo/v5rc04
> >>>>>>>> Thanks a lot. I’ve carefully read this commit:
> >>>>>>>> https://github.com/soleen/linux/commit/60205b9a95c319dc9965f119303a1d83f0ff08fa.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> To be honest, I’d like to run some tests with who/luo,
> >>>>>>>> including the
> >>>>>>>> selftest for kho/luo. Could you please share the steps with me?
> >>>>>>>>
> >>>>>>>> If the testing steps have already been documented somewhere,
> >>>>>>>> could you
> >>>>>>>> please share the link?
> >>>>>>> Currently the test performs in-kernel tests for FLB data, it
> >>>>>>> creates a
> >>>>>>> number of FLB for every registered LUO file-handler, which at the
> >>>>>>> moment is only memfd.
> >>>>>>>
> >>>>>>> It works together with any of the kexec based live update tests. In
> >>>>>>> v5, I introduce two tests:
> >>>>>>> luo_kexec_simple
> >>>>>>> luo_multi_session
> >>>>>>>
> >>>>>>> For example, with luo_multi_session:
> >>>>>> Hi, Pasha
> >>>>>>
> >>>>>> I enabled "CONFIG_LIVEUPDATE=y"
> >>>>>>
> >>>>>> # ./luo_multi_session
> >>>>>> 1..0 # SKIP Failed to open /dev/liveupdate. Is the luo module
> >>>>>> loaded?
> >>>>>>
> >>>>>> # ls /dev/liveupdate
> >>>>>> ls: cannot access '/dev/liveupdate': No such file or directory
> >>>>>>
> >>>>>> # grep "LIVEUPDATE" -inrHI /boot/config-`uname -r`
> >>>>>> /boot/config-next-20251107-luo+:349:CONFIG_LIVEUPDATE=y
> >>>>>> /boot/config-next-20251107-luo+:11985:CONFIG_LIVEUPDATE_TEST=y
> >>>>>>
> >>>>>> I made tests on FC42. But /dev/liveupdate is missing.
> >>>>> You need to add liveupdate=1 to your kernel cmdline to enable LUO and
> >>>>> get /dev/liveupdate.
> >>>> +1, kernel parameters require: kho=1 liveupdate=1
> >>>>
> >>>>> Pasha, your LUO series doesn't add the liveupdate parameter to
> >>>>> kernel-parameters.txt. I think it should be done in the next
> >>>>> version to
> >>>>> this parameter is discoverable.
> >>>> Yeah, that is missing, I will update that in a standalone patch, or in
> >>>> a next version.
> >>>>
> >>>> Thanks,
> >>>> Pasha
> >>> --
> >>> Best Regards,
> >>> Yanjun.Zhu