Expose the physical address of the outgoing KHO FDT via /sys/kernel/debug/kho/out/fdt_phys (analogous to bootmem_phys) so that userspace tooling can locate the root KHO FDT in physical memory.
Also add kho_debugfs_cleanup() and remove the KHO debugfs directory if kho_init() fails after initializing debugfs, ensuring fdt_phys does not retain a dangling pointer to a freed FDT. This is going to be used by the upcoming KHO read-only mode. Signed-off-by: Pasha Tatashin <[email protected]> --- Documentation/admin-guide/mm/kho.rst | 3 +++ kernel/liveupdate/kexec_handover.c | 10 ++++++---- kernel/liveupdate/kexec_handover_debugfs.c | 22 ++++++++++++++++++++- kernel/liveupdate/kexec_handover_internal.h | 7 +++++-- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Documentation/admin-guide/mm/kho.rst b/Documentation/admin-guide/mm/kho.rst index 902d171a780a..2ba884c620c5 100644 --- a/Documentation/admin-guide/mm/kho.rst +++ b/Documentation/admin-guide/mm/kho.rst @@ -96,6 +96,9 @@ stabilized. current KHO state in this file. Kexec user space tooling can use this as input file for the KHO payload image. +``/sys/kernel/debug/kho/out/fdt_phys`` + Physical address of the outgoing KHO FDT blob. + ``/sys/kernel/debug/kho/out/bootmem_len`` Lengths of KHO bootmem regions, which are physically contiguous memory regions that will always stay available for future kexec diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 6f1f55fe3181..ce5983abf181 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -1851,17 +1851,17 @@ static __init int kho_init(void) if (err) goto err_free_fdt; - err = kho_out_debugfs_init(&kho_out.dbg); + err = kho_out_debugfs_init(&kho_out.dbg, kho_out.fdt); if (err) - goto err_free_fdt; + goto err_cleanup_debugfs; err = kho_out_fdt_setup(); if (err) - goto err_free_fdt; + goto err_cleanup_debugfs; err = kho_kexec_metadata_init(fdt); if (err) - goto err_free_fdt; + goto err_cleanup_debugfs; if (fdt) { kho_in_debugfs_init(&kho_in.dbg, fdt); @@ -1893,6 +1893,8 @@ static __init int kho_init(void) return 0; +err_cleanup_debugfs: + kho_debugfs_cleanup(); err_free_fdt: kho_unpreserve_free(kho_out.fdt); err_free_kho_radix_tree: diff --git a/kernel/liveupdate/kexec_handover_debugfs.c b/kernel/liveupdate/kexec_handover_debugfs.c index 7d74477da0b7..db3830829398 100644 --- a/kernel/liveupdate/kexec_handover_debugfs.c +++ b/kernel/liveupdate/kexec_handover_debugfs.c @@ -95,6 +95,15 @@ static int bootmem_len_show(struct seq_file *m, void *v) } DEFINE_SHOW_ATTRIBUTE(bootmem_len); +static int fdt_phys_show(struct seq_file *m, void *v) +{ + void *fdt = m->private; + + seq_printf(m, "0x%llx\n", (unsigned long long)virt_to_phys(fdt)); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(fdt_phys); + __init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt) { struct dentry *dir, *sub_fdt_dir; @@ -172,7 +181,7 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt) } } -__init int kho_out_debugfs_init(struct kho_debugfs *dbg) +__init int kho_out_debugfs_init(struct kho_debugfs *dbg, const void *fdt) { struct dentry *dir, *f, *sub_fdt_dir; @@ -196,6 +205,11 @@ __init int kho_out_debugfs_init(struct kho_debugfs *dbg) if (IS_ERR(f)) goto err_rmdir; + f = debugfs_create_file("fdt_phys", 0400, dir, (void *)fdt, + &fdt_phys_fops); + if (IS_ERR(f)) + goto err_rmdir; + dbg->dir = dir; dbg->sub_fdt_dir = sub_fdt_dir; return 0; @@ -212,3 +226,9 @@ __init int kho_debugfs_init(void) return -ENOENT; return 0; } + +__init void kho_debugfs_cleanup(void) +{ + debugfs_remove_recursive(debugfs_root); + debugfs_root = NULL; +} diff --git a/kernel/liveupdate/kexec_handover_internal.h b/kernel/liveupdate/kexec_handover_internal.h index e9685e1ef6d7..38181076f603 100644 --- a/kernel/liveupdate/kexec_handover_internal.h +++ b/kernel/liveupdate/kexec_handover_internal.h @@ -24,16 +24,19 @@ extern unsigned int kho_bootmem_cnt; #ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS int kho_debugfs_init(void); +void kho_debugfs_cleanup(void); void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt); -int kho_out_debugfs_init(struct kho_debugfs *dbg); +int kho_out_debugfs_init(struct kho_debugfs *dbg, const void *fdt); int kho_debugfs_blob_add(struct kho_debugfs *dbg, const char *name, const void *blob, size_t size, bool root); void kho_debugfs_blob_remove(struct kho_debugfs *dbg, void *blob); #else static inline int kho_debugfs_init(void) { return 0; } +static inline void kho_debugfs_cleanup(void) { } 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_out_debugfs_init(struct kho_debugfs *dbg, + const void *fdt) { return 0; } static inline int kho_debugfs_blob_add(struct kho_debugfs *dbg, const char *name, const void *blob, size_t size, bool root) { return 0; } -- 2.56.0.176.g3575e65682-goog

