From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id B15B2C2D0CD for ; Thu, 15 May 2025 18:23:35 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 046B76B00AB; Thu, 15 May 2025 14:23:32 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id F2AAB6B00AE; Thu, 15 May 2025 14:23:31 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A98386B00AC; Thu, 15 May 2025 14:23:31 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 7F46C6B00AB for ; Thu, 15 May 2025 14:23:31 -0400 (EDT) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id D2ED859185 for ; Thu, 15 May 2025 18:23:30 +0000 (UTC) X-FDA: 83445964980.14.ACB464B Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) by imf04.hostedemail.com (Postfix) with ESMTP id 03FC64000A for ; Thu, 15 May 2025 18:23:28 +0000 (UTC) Authentication-Results: imf04.hostedemail.com; dkim=pass header.d=soleen-com.20230601.gappssmtp.com header.s=20230601 header.b=As3xWiNp; spf=pass (imf04.hostedemail.com: domain of pasha.tatashin@soleen.com designates 209.85.222.172 as permitted sender) smtp.mailfrom=pasha.tatashin@soleen.com; dmarc=pass (policy=none) header.from=soleen.com ARC-Authentication-Results: i=1; imf04.hostedemail.com; dkim=pass header.d=soleen-com.20230601.gappssmtp.com header.s=20230601 header.b=As3xWiNp; spf=pass (imf04.hostedemail.com: domain of pasha.tatashin@soleen.com designates 209.85.222.172 as permitted sender) smtp.mailfrom=pasha.tatashin@soleen.com; dmarc=pass (policy=none) header.from=soleen.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1747333409; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=OA6MgJ6M49mplY2qbuxPQY2uALRjdw04ISOceScmNg8=; b=1S2J/y5SWhhjsBTpUt7SpUn1UaFEk73EYa9+8jbh3WamVNJosb/zzbYhnNu1V5yR7sVUH5 p+JZJfcnvt8u2OykJrc1knxCwxZLRsuE47Vv1rTg3E257htKTp0ZrscmOjbXvs3SzKdW+u L48EQ1iU9a6v3idJOTtTMCjjarLx29U= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1747333409; a=rsa-sha256; cv=none; b=iwWARfXjLyHcIohe44t5raMpgYjluou8IF6TxqIX44kzL0LJfHXCQrtrB1cn5tEVewLRyq VZ+5hHSIpGERXClCoKS68Ybg83FthQLuWijg3emjY7wJYPe1MlnEbF5OxWcGUo+UJ4yF22 ylE77o3fBCUetFbjHRQq+6xnshPhv9E= Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-7c9376c4bddso142068485a.3 for ; Thu, 15 May 2025 11:23:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen-com.20230601.gappssmtp.com; s=20230601; t=1747333408; x=1747938208; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=OA6MgJ6M49mplY2qbuxPQY2uALRjdw04ISOceScmNg8=; b=As3xWiNpMxgDU/k8k2TMqaErKpmkE8wtOpnEkXod3IB2RguOJO5GJxqY5X7HupbTxl 5xVqkVcXoXARPVMDI0vsHnep51vWMbd15UzSrAu60KxNu96yfRL2fCMJAF/k5L67lHZZ aIYF7Nma1cCyja5zEAiyebM6d42GjIrfj/JONq/pEn5AJnhcxPLaSMl8IRP8VBkXM/5C FZAnevMPeVyvoJakLxobeHgy417rvAZtBgl+7m2sMYbAKL5C3U7aD9naA7FHpA112SnT uSwSlL29CKqfwo1j6AnwBzExe/Rj+VRwYT09vVx72AVL9jiHZlR3fk5uPfMXmOPMr1CL KG1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747333408; x=1747938208; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OA6MgJ6M49mplY2qbuxPQY2uALRjdw04ISOceScmNg8=; b=DXWokPLcikZ3EXYtbvEasRzxb1PX1GlfP51D2ArDpvKInbeBfWPfLA0YZ6SRnI8yBG S0qVEwHH+KuI0Q7JNGM4BbxBvq4ramXN+js+lqw3STxkUIJacCPhlO9MTti5u+wJI8yh mVBCyqQkynO65Hc/lS7nXXvop9VBCG9p6alz+ls+1VgYnGmy01ZLw5gw7ZR9s+M5HHQy SCEly/LZZLKDjWLAVCaaK0Cp2NZAkVFFlpL/40Q7BPCruEjuC86HOJFQ9MAHWhh9mt15 BF4vUhMpk9BN4TUSNgkagqjfZ+VHZ6K8wR8MaMy+0hIqc77vv84aZFpiPZ+xT50eJ5Bs 4mzA== X-Forwarded-Encrypted: i=1; AJvYcCWEsUWn5GQchoEQuv5Bbg4S65wii1buwDbZOzdTA8brzUmKiBnB2Qo1Rnr0XQcnafqDqasuFXLG8Q==@kvack.org X-Gm-Message-State: AOJu0YyyhGf90AzEeyxeGOB7njNC5I2KqMnMY7tPHeoVM7KwrLzxbTsw ynohAW/wAPxhVxGKqf7sbUrJbTHN0bZEii4wiXk/4ltPB6rmch15WiHLgHHADj5jABU= X-Gm-Gg: ASbGncue4XrvrfF/zFPzEA63Ax2FnBj4VXaqFKqooUh890BM7RNAR2/DPP9b72yy3Zn ftc6MOc+i4iIyMz+qpQdQZ2efd5uOnmNXUySnWNEuiqMmHb0cvl74yaeWQBbsnWSce8hSKwvFnf 8w6N5RyHeS8tz2xh4Srg7PjjPKKMIWI9fyUbQgm3SPor1E2PQaGRuSbyrr3mUuKHLgk33Osd71Q zbqs/hzy1QkVGRuEly073/cwjqRkNdIJfubNhaMn/Lu6jMQt6obuxk091HvezFy9tsepAVUhBrx ZZihED2pwiETccWa56peeIuyqyLCButy8YHlr89WXz5KW/NpexWGrhkPm+WR2rt+7yD8YpkI93s 9jeSQbRnitEv4YvDEiY34qbnp4gMbDf2NwmrcGGu62t4k9W6APY4P2WA= X-Google-Smtp-Source: AGHT+IFwPiSy57KtfJPs+U7xuV9rBNdEF5m1qAdIOcGOHbCQUN56mz0k2pGRILRAf8vp0yD020I1uw== X-Received: by 2002:a05:620a:2847:b0:7ca:f04b:3fa2 with SMTP id af79cd13be357-7cd4679cf74mr76951285a.38.1747333407852; Thu, 15 May 2025 11:23:27 -0700 (PDT) Received: from soleen.c.googlers.com.com (138.200.150.34.bc.googleusercontent.com. [34.150.200.138]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7cd466fc2afsm18218685a.0.2025.05.15.11.23.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 May 2025 11:23:27 -0700 (PDT) From: Pasha Tatashin To: pratyush@kernel.org, jasonmiu@google.com, graf@amazon.com, changyuanl@google.com, pasha.tatashin@soleen.com, rppt@kernel.org, dmatlack@google.com, rientjes@google.com, corbet@lwn.net, rdunlap@infradead.org, ilpo.jarvinen@linux.intel.com, kanie@linux.alibaba.com, ojeda@kernel.org, aliceryhl@google.com, masahiroy@kernel.org, akpm@linux-foundation.org, tj@kernel.org, yoann.congal@smile.fr, mmaurer@google.com, roman.gushchin@linux.dev, chenridong@huawei.com, axboe@kernel.dk, mark.rutland@arm.com, jannh@google.com, vincent.guittot@linaro.org, hannes@cmpxchg.org, dan.j.williams@intel.com, david@redhat.com, joel.granados@kernel.org, rostedt@goodmis.org, anna.schumaker@oracle.com, song@kernel.org, zhangguopeng@kylinos.cn, linux@weissschuh.net, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-mm@kvack.org, gregkh@linuxfoundation.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com, rafael@kernel.org, dakr@kernel.org, bartosz.golaszewski@linaro.org, cw00.choi@samsung.com, myungjoo.ham@samsung.com, yesanishhere@gmail.com, Jonathan.Cameron@huawei.com, quic_zijuhu@quicinc.com, aleksander.lobakin@intel.com, ira.weiny@intel.com, andriy.shevchenko@linux.intel.com, leon@kernel.org, lukas@wunner.de, bhelgaas@google.com, wagi@kernel.org, djeffery@redhat.com, stuart.w.hayes@gmail.com, ptyadav@amazon.de Subject: [RFC v2 01/16] kho: make debugfs interface optional Date: Thu, 15 May 2025 18:23:05 +0000 Message-ID: <20250515182322.117840-2-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.49.0.1101.gccaa498523-goog In-Reply-To: <20250515182322.117840-1-pasha.tatashin@soleen.com> References: <20250515182322.117840-1-pasha.tatashin@soleen.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: 03FC64000A X-Stat-Signature: ocoyep3ikpcgoy8j88uj9kkdqgg3nqes X-Rspam-User: X-HE-Tag: 1747333408-773451 X-HE-Meta: U2FsdGVkX19Wqc/TIQ4QlBm51fuKOmWL5DefiRC/uNtHTbEMfD4kK8Fbui2p77NXiNKXwMTCJIoLdrr/xPTe0Da2Yc1k/k8nl9ktFeqnUxzSrUI9ssvb9YkdiU/Fy4PEs1WAUiEIJXYhWwP2ouAI1SBAMCn6QeRAohiKDDBV3ISaeYLNopDv+bnBU655dOs9kOpt2l7KO1R6/cD+Od+1H+viOAHPex3l9k2A1Dfu62iqF4sym+qB/AxebJrqlp2IXS7af+hDSvnSjHgmSC1ZTWyGXAl6FHFhIDLkavVRF+k2gS25JSorMCbUcQpyt2TW+pqkZeDfVSfQOSCbOPo0mu96Q3vhi/gWmXB6R2RIRJc+CpZEhKi27abDTFsB1yRrp8+bOhHW6nbgqRwnwbR4rPu+86NDW8lWdGg2EWq8ZuubTMIA9YS1ZuUMzlPFD9+Q9l/pAaQSabPDbuB34+0Ior0wYPpm+4sLXzb+jTqLqsaGlWFb+ipGbVAYnPaZGfTl5UhMVJ2lSkPXTRilG+ire0ddDoQlRuVLP8Dsik0XUiWAl+iEBvSf/PPZg0VTPdrkSnGzBwlyIZMU7BsQs8kwoii4NUEDTuan3xZA/IbGV9936R+DfY9TTHQ6Is7JVmF1KRTCDZ8LBqe8joYpI1KFy1js3WsUosC6mj9jRgtnkmbJt3i6YqKfE3JlFQcb5pDd0ZKtXTJNNzBmjIroQJgi84vE8JV/3hbE4FRP0ApX8Lcqb+G+GerOtNQRjrpDUqHmciJUKODOMPnwYvy/Bpzdl6Btm7rTer7SyyIa2pqljs8PJAddbsHfT8BgKaDb21JF8i2z1Fe3DKt+qU2zUoCLGzJ3ji2cmsrppBLodv6RJUVrV7bQ7T9j8X5AKu7+H5eoUEJ3wij13MelA+w+01umsC6RHjBb2uDHEw0ihIHFpX4bzVkwRP3WtDmlA6J4MtXw7fdbnr/lbRwV4zb48ju bH5TGOUP qqtH2xx+lfkbqoY5bZICxrjaQPxljcVcMqEqHtrdq1je/u4fnjW59kBUxtE3A92B5ykojII6uVSszkxJcJ8O0EMarv4maK45n023gS7Ng1/xxT6ruBJjzODFQpEPNTzR4h8+W998NE8iRE3MbBisz9bsmTU7O/UIjbtce59ftGlOQ15cUx9tOZO+vbLdC+3JuEnEkuopVSvduQJFt4VuJdlGUiM2tlcN3aYqCDpOHegEpDYx7pqBPpwi4iyobkYIhjwDOuVSOsIOhc5lS7skaWefyA9fCU4sRKWC4+n1O9QOHAMfhta1a5TBGcWI8OqntL7dko4S/X9JlvRBvi7t4SAD3DyxxL7QjQMqlMzYvYPL26QfAxcX99AFW5h5CO95qPhEUonk7mM7xt0YUnSzEDmWfKyg/KJHyK2tod9pxmEqSoKSGQirMGVB1c+EFUXMNthXV/xLO+/0xKDUAL5mgNkayJxofCwbpsjDAHZjTNW/BpWZ/A63rb0PRhFPVuHBor3e7I+wi5/uB7Num5DoauLgH/Hsr6wKSDecCMxo8hnFsEvlaaAx701VC5dzy7nyQbYasru9enBk5w2b8Kh96n4EYE2bUUFy5yhWleZb2zcnPRto= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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_DEBUG that enables the debugfs interface, and allows to inspect the tree. Move all debufs related code to a new file to keep the .c files clear of ifdefs. Signed-off-by: Pasha Tatashin --- MAINTAINERS | 3 +- kernel/Kconfig.kexec | 10 ++ kernel/Makefile | 1 + kernel/kexec_handover.c | 271 ++----------------------------- kernel/kexec_handover_debug.c | 237 +++++++++++++++++++++++++++ kernel/kexec_handover_internal.h | 72 ++++++++ 6 files changed, 336 insertions(+), 258 deletions(-) create mode 100644 kernel/kexec_handover_debug.c create mode 100644 kernel/kexec_handover_internal.h diff --git a/MAINTAINERS b/MAINTAINERS index bdea634d63a9..4fc28b6674bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13143,12 +13143,13 @@ KEXEC HANDOVER (KHO) M: Alexander Graf M: Mike Rapoport M: Changyuan Lyu +M: Pasha Tatashin L: kexec@lists.infradead.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* KEYS-ENCRYPTED M: Mimi Zohar diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec index 4fa212909d69..44f9ac67ecbc 100644 --- a/kernel/Kconfig.kexec +++ b/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_DEBUG + bool "kexec handover debug interface" + 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 97c09847db42..ae44877c0300 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -81,6 +81,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_DEBUG) += kexec_handover_debug.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 69b953551677..5b65970e9746 100644 --- a/kernel/kexec_handover.c +++ b/kernel/kexec_handover.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,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" @@ -75,22 +75,8 @@ struct kho_mem_phys { struct xarray phys_bits; }; -struct kho_mem_track { - /* Points to kho_mem_phys, each order gets its own bitmap tree */ - struct xarray orders; -}; - 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; -}; - static void *xa_load_or_alloc(struct xarray *xa, unsigned long index, size_t sz) { void *elm, *res; @@ -355,8 +341,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 @@ -542,37 +528,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. @@ -584,7 +539,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_DEBUG * * Return: 0 on success, error code on failure */ @@ -601,22 +557,11 @@ 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(ser, name, fdt); } EXPORT_SYMBOL_GPL(kho_add_subtree); -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; -}; - -static struct kho_out kho_out = { +struct kho_out kho_out = { .chain_head = BLOCKING_NOTIFIER_INIT(kho_out.chain_head), .lock = __MUTEX_INITIALIZER(kho_out.lock), .ser = { @@ -707,30 +652,7 @@ int kho_preserve_phys(phys_addr_t phys, size_t size) } EXPORT_SYMBOL_GPL(kho_preserve_phys); -/* 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 __kho_abort(void) { int err; unsigned long order; @@ -763,7 +685,7 @@ static int kho_abort(void) return err; } -static int kho_finalize(void) +int __kho_finalize(void) { int err = 0; u64 *preserved_mem_map; @@ -806,117 +728,13 @@ 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) -{ - 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); - - if (val == kho_out.finalized) { - if (kho_out.finalized) - ret = -EEXIST; - else - ret = -ENOENT; - goto unlock; - } - - if (val) - ret = kho_finalize(); - else - ret = kho_abort(); - - 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); - -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; -} - -struct kho_in { - struct dentry *dir; - phys_addr_t fdt_phys; - phys_addr_t scratch_phys; - struct list_head fdt_list; -}; - -static struct kho_in kho_in = { +struct kho_in kho_in = { .fdt_list = LIST_HEAD_INIT(kho_in.fdt_list), }; @@ -961,56 +779,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; @@ -1025,27 +793,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(); 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(fdt); return 0; } diff --git a/kernel/kexec_handover_debug.c b/kernel/kexec_handover_debug.c new file mode 100644 index 000000000000..696131a3480f --- /dev/null +++ b/kernel/kexec_handover_debug.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * kexec_handover.c - kexec handover metadata processing + * Copyright (C) 2023 Alexander Graf + * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport + * Copyright (C) 2025 Google LLC, Changyuan Lyu + * Copyright (C) 2025 Google LLC, Pasha Tatashin + */ + +#define pr_fmt(fmt) "KHO: " fmt + +#include +#include +#include +#include +#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_serialization *ser, const char *name, + const void *fdt) +{ + return __kho_debugfs_fdt_add(&ser->fdt_list, ser->sub_fdt_dir, name, + fdt); +} + +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_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) +{ + int ret = 0; + bool val = !!_val; + + mutex_lock(&kho_out.lock); + + if (val == kho_out.finalized) { + if (kho_out.finalized) + ret = -EEXIST; + else + ret = -ENOENT; + goto unlock; + } + + if (val) + ret = __kho_finalize(); + else + ret = __kho_abort(); + + 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); + +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(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)) { + err = PTR_ERR(kho_in.dir); + goto err_out; + } + + 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; +err_rmdir: + debugfs_remove_recursive(kho_in.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(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; +} + +__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 new file mode 100644 index 000000000000..65ff0f651192 --- /dev/null +++ b/kernel/kexec_handover_internal.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_KEXEC_HANDOVER_INTERNAL_H +#define LINUX_KEXEC_HANDOVER_INTERNAL_H + +#include +#include +#include + +#ifdef CONFIG_KEXEC_HANDOVER_DEBUG +#include +#endif + +struct kho_mem_track { + /* Points to kho_mem_phys, each order gets its own bitmap tree */ + struct xarray orders; +}; + +struct kho_serialization { + struct page *fdt; + struct list_head fdt_list; + struct kho_mem_track track; + /* First chunk of serialized preserved memory map */ + struct khoser_mem_chunk *preserved_mem_map; +#ifdef CONFIG_KEXEC_HANDOVER_DEBUG + struct dentry *sub_fdt_dir; +#endif +}; + +struct kho_in { + phys_addr_t fdt_phys; + phys_addr_t scratch_phys; + struct list_head fdt_list; +#ifdef CONFIG_KEXEC_HANDOVER_DEBUG + struct dentry *dir; +#endif +}; + +struct kho_out { + struct blocking_notifier_head chain_head; + struct mutex lock; /* protects KHO FDT finalization */ + struct kho_serialization ser; + bool finalized; +#ifdef CONFIG_KEXEC_HANDOVER_DEBUG + struct dentry *dir; +#endif +}; + +extern struct kho_in kho_in; +extern struct kho_out kho_out; + +extern struct kho_scratch *kho_scratch; +extern unsigned int kho_scratch_cnt; + +int __kho_finalize(void); +int __kho_abort(void); + +#ifdef CONFIG_KEXEC_HANDOVER_DEBUG +int kho_debugfs_init(void); +void kho_in_debugfs_init(const void *fdt); +int kho_out_debugfs_init(void); +int kho_debugfs_fdt_add(struct kho_serialization *ser, const char *name, + const void *fdt); +#else +static inline int kho_debugfs_init(void) { return 0; } +static inline void kho_in_debugfs_init(const void *fdt) { } +static inline int kho_out_debugfs_init(void) { return 0; } +static inline int kho_debugfs_fdt_add(struct kho_serialization *ser, + const char *name, + const void *fdt) { return 0; } +#endif /* CONFIG_KEXEC_HANDOVER_DEBUG */ + +#endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */ -- 2.49.0.1101.gccaa498523-goog