From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from confino.investici.org (confino.investici.org [93.190.126.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 73975632 for ; Sat, 11 Jul 2026 00:23:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.190.126.19 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783729385; cv=none; b=TajxyipoDaLKmEj91AC2YAZ3q4/wB1QBoJ24qKQznEWsO/8fpPXdw672A+mdX35DWivelNMenHwhrGh3pdA6Rfrm7dq7gMwsV2o8QgmMlnBmINZYSPGy1bp16VcsR0T8J/Q88Iwb6HtgwR+4jpv9f2qjl1TyyFEefxHKgp15eBw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783729385; c=relaxed/simple; bh=lEJjpmR0m6xLSnhl4oY9V2LAPJYH2qQbUxhRDP93YAI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ht0xxN+KeudVFI0e0EkjNCQJuitLnX6oVGTIv1OtTQX7bTUZAyWQTfdO1ROUq4CjrRudJjntChG7X2OLMLf/ZO1eDrIRHkWrS41GA/3RJ2feukdPD4QE4Jf19/u4+QBi+nIWbxNtecLXPkT6CD44ySlxvXf7Qg0dX1yF2x32HDs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net; spf=pass smtp.mailfrom=grrlz.net; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b=YMA3n1tZ; arc=none smtp.client-ip=93.190.126.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grrlz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b="YMA3n1tZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grrlz.net; s=stigmate; t=1783729373; bh=68s0RYnGpn0IUjFXbD1EK6m8KysWyV+WA560sE1DG4s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YMA3n1tZzGcqmx/qHaOfqw1qHiTSR1xarwZHJtAunkTXOx1IHC/1Kq3J/XkpXQpTS /e4yoy/riwS0j8UU6ntIjzCXS39TuqbhEi3d1Tx3NmBFadj1Rb+w2kB+PcVoMWhqDe A1VUzaDWdpUCSRbqPQL/cscSzvFNNv8FV7v/wshE= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4gxqCx6Jlpz114G; Sat, 11 Jul 2026 00:22:53 +0000 (UTC) Received: by mx1.investici.org (Postfix) id 4gxqCx0VSjz113X; Sat, 11 Jul 2026 00:22:53 +0000 (UTC) From: Bradley Morgan To: akpm@linux-foundation.org Cc: baoquan.he@linux.dev, pmladek@suse.com, feng.tang@linux.alibaba.com, gregkh@linuxfoundation.org, arnd@arndb.de, corbet@lwn.net, rdunlap@infradead.org, gpiccoli@igalia.com, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, include@grrlz.net Subject: [RFC PATCH 1/4] panic: add a pre kdump notifier list Date: Sat, 11 Jul 2026 00:22:50 +0000 Message-ID: <20260711002253.1115-2-include@grrlz.net> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260711002253.1115-1-include@grrlz.net> References: <20260711002253.1115-1-include@grrlz.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit When a crash kernel is loaded, panic() jumps to it before the panic notifiers run. A hypervisor or firmware therefore never learns that the guest panicked: the Hyper-V host never receives the crash registers, a Google gsmi firmware log entry is dropped, a pvpanic device never signals the host, and an AMD SEV-SNP guest skips the firmware and IOMMU shutdown. Fleet alerting, availability tracking, and crash logging all miss the event. The only escape hatch today is crash_kexec_post_notifiers, but it runs the entire legacy notifier list before the kdump. That list carries slow callbacks, IPMI being the obvious one because it talks to a BMC, so enabling it delays every crash dump on the machine. Hyper-V forces it on anyway and penalizes every kdump for the sake of one upcall; this series also removes the forcing that SEV-SNP added for the same reason, giving SNP hosts the normal early crash kexec back. Add a small dedicated list that always runs before crash kexec. The list head stays private and registration goes through a function, because the callbacks on this list have a strict contract and an API is how you enforce one. The list lives in its own file, not in panic.c, so the contract can carry a MAINTAINERS entry and the existing panic code does not have to move. Priorities order the list like any atomic notifier chain. The header documents that they are reserved for callbacks that must run last, for example because they may not return or because they tear down a transport that other callbacks still need. The notify path walks the chain by hand and names each callback on the console before invoking it. Running anything before the crash kexec is a reliability trade, if an upcall hangs or faults and costs us the crash dump, the console identifies the culprit instead of leaving a machine that silently never rebooted into the kdump kernel. Callback return values are deliberately ignored, and a nested panic resumes the walk after the callback that was running instead of refaulting on it. Signed-off-by: Bradley Morgan --- include/linux/panic_notifier.h | 18 ++++++++++ kernel/Makefile | 2 +- kernel/panic_notifiers.c | 65 ++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 kernel/panic_notifiers.c diff --git a/include/linux/panic_notifier.h b/include/linux/panic_notifier.h index 41e32483d7a7..1e99de3a8a6a 100644 --- a/include/linux/panic_notifier.h +++ b/include/linux/panic_notifier.h @@ -7,6 +7,24 @@ extern struct atomic_notifier_head panic_notifier_list; +/* + * The pre kdump list runs on every panic, before a potential crash + * kexec, so a hypervisor or firmware learns of the panic even when a + * crash kernel is loaded. A callback: + * + * - must not take locks, allocate memory or sleep + * - must not assume other CPUs have been stopped + * - must tolerate being entered again if the panic path panics + * + * One that cannot belongs on the legacy panic_notifier_list instead. + * Reserve low priorities for callbacks that must run last, for + * example because they do not return. Return values are ignored: the + * whole list always runs. + */ +int panic_notifier_register_pre_kdump(struct notifier_block *nb); +int panic_notifier_unregister_pre_kdump(struct notifier_block *nb); +void panic_pre_kdump_notify(const char *buf); + extern bool crash_kexec_post_notifiers; #endif /* _LINUX_PANIC_NOTIFIERS_H */ diff --git a/kernel/Makefile b/kernel/Makefile index 1e1a31673577..7add98a5acc2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -obj-y = fork.o exec_domain.o exec_state.o panic.o \ +obj-y = fork.o exec_domain.o exec_state.o panic.o panic_notifiers.o \ cpu.o exit.o softirq.o resource.o \ sysctl.o capability.o ptrace.o user.o \ signal.o sys.o umh.o workqueue.o pid.o task_work.o \ diff --git a/kernel/panic_notifiers.c b/kernel/panic_notifiers.c new file mode 100644 index 000000000000..31f15f84662e --- /dev/null +++ b/kernel/panic_notifiers.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* The pre kdump panic notifier list. See include/linux/panic_notifier.h. */ +#include +#include +#include +#include +#include +#include + +static ATOMIC_NOTIFIER_HEAD(panic_pre_kdump_list); + +/* The callback must satisfy the contract in include/linux/panic_notifier.h. */ +int panic_notifier_register_pre_kdump(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&panic_pre_kdump_list, nb); +} +EXPORT_SYMBOL_GPL(panic_notifier_register_pre_kdump); + +/* Synchronizes RCU and may block; must not be called from the panic path. */ +int panic_notifier_unregister_pre_kdump(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&panic_pre_kdump_list, nb); +} +EXPORT_SYMBOL_GPL(panic_notifier_unregister_pre_kdump); + +/* + * Called from panic() only, right before a potential crash kexec. Callbacks + * are named on the console first and their return values ignored. + */ +void panic_pre_kdump_notify(const char *buf) +{ + static struct notifier_block *cursor; + struct notifier_block *nb, *resume_after; + + /* No locking: panic_cpu serializes; a nested panic just runs again. */ + resume_after = cursor; + + rcu_read_lock(); + for (nb = rcu_dereference(panic_pre_kdump_list.head); nb; + nb = rcu_dereference(nb->next)) { + /* + * On a nested panic, skip past the callback that was + * running when it hit: that one is the likely culprit. + */ + if (resume_after) { + if (nb == resume_after) + resume_after = NULL; + continue; + } + +#ifdef CONFIG_DEBUG_NOTIFIERS + if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) { + WARN(1, "Invalid pre kdump notifier!"); + continue; + } +#endif + cursor = nb; + pr_emerg("pre kdump notifier: calling %ps\n", + nb->notifier_call); + /* The zero action mirrors the legacy panic_notifier_list. */ + nb->notifier_call(nb, 0, (void *)buf); + } + rcu_read_unlock(); + cursor = NULL; +} -- 2.53.0