| From: Pasha Tatashin <pasha.tatashin@soleen.com> |
| Subject: kho: make debugfs interface optional |
| Date: Tue, 7 Oct 2025 03:30:55 +0000 |
| |
| 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. |
| |
| Link: https://lkml.kernel.org/r/20251007033100.836886-3-pasha.tatashin@soleen.com |
| 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> |
| Cc: Alexander Graf <graf@amazon.com> |
| Cc: Christian Brauner <brauner@kernel.org> |
| Cc: Jason Gunthorpe <jgg@nvidia.com> |
| Cc: Jason Gunthorpe <jgg@ziepe.ca> |
| Cc: Jonathan Corbet <corbet@lwn.net> |
| Cc: Masahiro Yamada <masahiroy@kernel.org> |
| Cc: Miguel Ojeda <ojeda@kernel.org> |
| Cc: Pratyush Yadav <pratyush@kernel.org> |
| Cc: Randy Dunlap <rdunlap@infradead.org> |
| Cc: Tejun Heo <tj@kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| MAINTAINERS | 3 |
| kernel/Kconfig.kexec | 10 + |
| kernel/Makefile | 1 |
| kernel/kexec_handover.c | 223 ++---------------------- |
| kernel/kexec_handover_debug.c | 213 ++++++++++++++++++++++ |
| kernel/kexec_handover_internal.h | 44 ++++ |
| tools/testing/selftests/kho/vmtest.sh | 1 |
| 7 files changed, 290 insertions(+), 205 deletions(-) |
| |
| --- a/kernel/Kconfig.kexec~kho-make-debugfs-interface-optional |
| +++ a/kernel/Kconfig.kexec |
| @@ -109,6 +109,16 @@ config KEXEC_HANDOVER |
| to keep data or state alive across the kexec. For this to work, |
| both source and target kernels need to have this option enabled. |
| |
| +config KEXEC_HANDOVER_DEBUGFS |
| + bool "kexec handover debugfs interface" |
| + depends on KEXEC_HANDOVER |
| + depends on 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 |
| --- a/kernel/kexec_handover.c~kho-make-debugfs-interface-optional |
| +++ a/kernel/kexec_handover.c |
| @@ -10,7 +10,6 @@ |
| |
| #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> |
| @@ -28,6 +27,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" |
| @@ -101,8 +101,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; |
| @@ -110,20 +108,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), |
| }, |
| @@ -465,8 +459,8 @@ static void __init kho_mem_deserialize(c |
| * 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 |
| @@ -662,37 +656,6 @@ err_disable_kho: |
| 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. |
| @@ -704,7 +667,8 @@ static int kho_debugfs_fdt_add(struct li |
| * 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 |
| */ |
| @@ -721,7 +685,7 @@ int kho_add_subtree(struct kho_serializa |
| 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); |
| |
| @@ -1044,29 +1008,6 @@ err_free_pages_array: |
| } |
| 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) |
| { |
| int err; |
| @@ -1116,8 +1057,9 @@ int kho_abort(void) |
| return ret; |
| |
| kho_out.finalized = false; |
| + kho_debugfs_cleanup(&kho_out.dbg); |
| |
| - return kho_out_update_debugfs_fdt(); |
| + return 0; |
| } |
| |
| static int __kho_finalize(void) |
| @@ -1186,89 +1128,23 @@ int kho_finalize(void) |
| |
| kho_out.finalized = true; |
| |
| - return kho_out_update_debugfs_fdt(); |
| -} |
| - |
| -static int kho_out_finalize_get(void *data, u64 *val) |
| -{ |
| - 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) |
| -{ |
| - return (!!_val) ? kho_finalize() : kho_abort(); |
| + return kho_debugfs_fdt_add(&kho_out.dbg, "fdt", |
| + page_to_virt(kho_out.ser.fdt), true); |
| } |
| |
| -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) |
| +bool kho_finalized(void) |
| { |
| - 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); |
| - |
| -static __init int kho_out_debugfs_init(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) |
| @@ -1332,56 +1208,6 @@ int kho_retrieve_subtree(const char *nam |
| } |
| 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; |
| @@ -1396,27 +1222,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_debug.c a/kernel/kexec_handover_debug.c |
| new file mode 100644 |
| --- /dev/null |
| +++ a/kernel/kexec_handover_debug.c |
| @@ -0,0 +1,213 @@ |
| +// SPDX-License-Identifier: GPL-2.0-only |
| +/* |
| + * kexec_handover.c - kexec handover metadata processing |
| + * 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) |
| +{ |
| + return (!!_val) ? kho_finalize() : 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 a/kernel/kexec_handover_internal.h |
| new file mode 100644 |
| --- /dev/null |
| +++ a/kernel/kexec_handover_internal.h |
| @@ -0,0 +1,44 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +#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); |
| + |
| +#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 */ |
| + |
| +#endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */ |
| --- a/kernel/Makefile~kho-make-debugfs-interface-optional |
| +++ a/kernel/Makefile |
| @@ -83,6 +83,7 @@ obj-$(CONFIG_KEXEC) += kexec.o |
| 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_DEBUGFS) += kexec_handover_debug.o |
| obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o |
| obj-$(CONFIG_COMPAT) += compat.o |
| obj-$(CONFIG_CGROUPS) += cgroup/ |
| --- a/MAINTAINERS~kho-make-debugfs-interface-optional |
| +++ a/MAINTAINERS |
| @@ -13774,13 +13774,14 @@ KEXEC HANDOVER (KHO) |
| M: Alexander Graf <graf@amazon.com> |
| M: Mike Rapoport <rppt@kernel.org> |
| M: Changyuan Lyu <changyuanl@google.com> |
| +M: Pasha Tatashin <pasha.tatashin@soleen.com> |
| L: kexec@lists.infradead.org |
| L: linux-mm@kvack.org |
| 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 |
| --- a/tools/testing/selftests/kho/vmtest.sh~kho-make-debugfs-interface-optional |
| +++ a/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 |
| _ |