From: Breno Leitao <leitao@debian.org>
To: Petr Mladek <pmladek@suse.com>
Cc: John Ogness <john.ogness@linutronix.de>,
Ryan Roberts <ryan.roberts@arm.com>,
Andrew Morton <akpm@linux-foundation.org>,
Steven Rostedt <rostedt@goodmis.org>,
Sergey Senozhatsky <senozhatsky@chromium.org>,
Rio <rioo.tsukatsukii@gmail.com>,
linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH v1] panic: Flush unsafe consoles before panic reboot
Date: Fri, 30 Oct 2026 10:56:35 -0700 [thread overview]
Message-ID: <auTaBZlNbpm3jgvb@gmail.com> (raw)
In-Reply-To: <auNaD8LELWok3LOF@pathway>
On Thu, Oct 29, 2026 at 03:37:03PM +0100, Petr Mladek wrote:
> Another question is where to call it. I guess the it should be called
> in two code paths:
>
> + __crash_kexec() likely after stopping other CPUs
>
> + console_flush_on_panic() after flushing safe nbcon consoles
> the safe way
What about something like:
commit de57403441b601af01d92bc03bf0625338d39c80
Author: Breno Leitao <leitao@debian.org>
Date: Fri Oct 30 10:08:01 2026 -0700
panic: flush unsafe consoles before reboot and kdump
netconsole registers with CON_NBCON_ATOMIC_UNSAFE since commit
7eab73b18630 ("netconsole: convert to NBCON console infrastructure"), so
its write_atomic() only runs from nbcon_atomic_flush_unsafe(). vpanic()
calls that right before its final busy loop, after emergency_restart()
and after __crash_kexec().
A panic that reboots (panic_timeout != 0) or boots a crash kernel
therefore never reaches the netconsole target. Neither does an oops that
goes to kdump through crash_kexec(), which skips vpanic() entirely.
Before the conversion, netconsole was a legacy console, flushed by
console_flush_on_panic() ahead of the reboot.
Add nbcon_atomic_unsafe_only_flush(), which flushes only the
CON_NBCON_ATOMIC_UNSAFE consoles and allows unsafe takeovers on them.
Call it on the panic CPU once the other CPUs are stopped, leaving the
consoles with a safe write_atomic() alone.
In vpanic() it runs after the safe flush, when
panic_other_cpus_shutdown() has stopped the other CPUs. In
__crash_kexec() it runs after crash_smp_send_stop() and before
machine_crash_shutdown(), the order panic() already uses with
crash_kexec_post_notifiers.
The call does not go into console_flush_on_panic(), because kgdb_panic()
calls that before the other CPUs are stopped. It does not go after
machine_crash_shutdown() either: on TDX guests tdx_kexec_finish() zaps
the shared PTEs there, and netconsole on a virtio NIC would touch that
memory.
A write_atomic() that hangs now keeps the machine from rebooting or from
reaching the crash kernel.
Fixes: 187de7c212e5 ("printk: nbcon: Allow unsafe write_atomic() for panic")
Reported-by: Ryan Roberts <ryan.roberts@arm.com>
Closes: https://lore.kernel.org/all/20260915100140.3631650-1-ryan.roberts@arm.com/
Suggested-by: John Ogness <john.ogness@linutronix.de>
Suggested-by: Petr Mladek <pmladek@suse.com>
Cc: stable@vger.kernel.org
Signed-off-by: Breno Leitao <leitao@debian.org>
diff --git a/include/linux/console.h b/include/linux/console.h
index cb8be9ea4a767b..ebfa259633761a 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -183,7 +183,8 @@ static inline void con_debug_leave(void) { }
* @CON_NBCON: Console can operate outside of the legacy style console_lock
* constraints.
* @CON_NBCON_ATOMIC_UNSAFE: The write_atomic() callback is not safe and is
- * therefore only used by nbcon_atomic_flush_unsafe().
+ * therefore only used by nbcon_atomic_flush_unsafe() and
+ * nbcon_atomic_unsafe_only_flush().
*/
enum cons_flags {
CON_PRINTBUFFER = BIT(0),
diff --git a/include/linux/printk.h b/include/linux/printk.h
index f594c1266bfd41..95da3904c0d30e 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -208,6 +208,7 @@ void printk_legacy_allow_panic_sync(void);
extern bool nbcon_device_try_acquire(struct console *con);
extern void nbcon_device_release(struct console *con);
void nbcon_atomic_flush_unsafe(void);
+void nbcon_atomic_unsafe_only_flush(void);
bool pr_flush(int timeout_ms, bool reset_on_progress);
#else
static inline __printf(1, 0)
@@ -322,6 +323,10 @@ static inline void nbcon_atomic_flush_unsafe(void)
{
}
+static inline void nbcon_atomic_unsafe_only_flush(void)
+{
+}
+
static inline bool pr_flush(int timeout_ms, bool reset_on_progress)
{
return true;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index d0bd2d0cf8990b..d00a8ce5cb618c 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -140,6 +140,13 @@ void __noclone __crash_kexec(struct pt_regs *regs)
crash_setup_regs(&fixed_regs, regs);
crash_save_vmcoreinfo();
+ /*
+ * Flush the unsafe consoles with the other CPUs
+ * stopped, before machine_crash_shutdown() tears
+ * down what they may need.
+ */
+ crash_smp_send_stop();
+ nbcon_atomic_unsafe_only_flush();
machine_crash_shutdown(&fixed_regs);
crash_cma_clear_pending_dma();
machine_kexec(kexec_crash_image);
diff --git a/kernel/panic.c b/kernel/panic.c
index 91e48d33b7dbbd..e14b1b60828130 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -723,6 +723,9 @@ void vpanic(const char *fmt, va_list args)
panic_console_replay)
console_flush_on_panic(CONSOLE_REPLAY_ALL);
+ /* The other CPUs are stopped, flush the unsafe consoles too.
h /tmp/puf_post.sh kerneltest001.31.atn1 6791 atn1a &); (sh
/tmp/puf_post.sh kerneltest005.19.atn2 6792 atn2a &)
/
+ nbcon_atomic_unsafe_only_flush();
+
if (!panic_blink)
panic_blink = no_blink;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 5f8afaca886650..a43143eca1a015 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1653,8 +1653,9 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
* __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
* write_atomic() callback
* @stop_seq: Flush up until this record
+ * @unsafe_only: Flush only the CON_NBCON_ATOMIC_UNSAFE consoles
*/
-static void __nbcon_atomic_flush_pending(u64 stop_seq)
+static void __nbcon_atomic_flush_pending(u64 stop_seq, bool unsafe_only)
{
struct console *con;
int cookie;
@@ -1666,6 +1667,9 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
if (!(flags & CON_NBCON))
continue;
+ if (unsafe_only && !(flags & CON_NBCON_ATOMIC_UNSAFE))
+ continue;
+
if (!console_is_usable(con, flags, true))
continue;
@@ -1688,7 +1692,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
*/
void nbcon_atomic_flush_pending(void)
{
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
}
/**
@@ -1701,7 +1705,21 @@ void nbcon_atomic_flush_pending(void)
void nbcon_atomic_flush_unsafe(void)
{
panic_nbcon_allow_unsafe_takeover = true;
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
+ panic_nbcon_allow_unsafe_takeover = false;
+}
+
+/**
+ * nbcon_atomic_unsafe_only_flush - Flush only the CON_NBCON_ATOMIC_UNSAFE
+ * consoles, allowing unsafe hostile takeovers
+ *
+ * Like nbcon_atomic_flush_unsafe(), but consoles with a safe write_atomic()
+ * are left alone. Meant for the panic CPU once the other CPUs are stopped.
+ */
+void nbcon_atomic_unsafe_only_flush(void)
+{
+ panic_nbcon_allow_unsafe_takeover = true;
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
panic_nbcon_allow_unsafe_takeover = false;
}
prev parent reply other threads:[~2026-10-30 17:56 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-15 10:01 Ryan Roberts
2026-09-15 10:06 ` Ryan Roberts
2026-09-15 18:49 ` Bradley Morgan
2026-09-16 7:44 ` Ryan Roberts
2026-09-16 14:58 ` Bradley Morgan
2026-09-16 13:08 ` Petr Mladek
2026-10-22 20:35 ` Gustavo Luiz Duarte
2026-10-23 7:57 ` John Ogness
2026-10-23 10:36 ` Petr Mladek
2026-10-27 16:12 ` Breno Leitao
2026-10-27 17:43 ` Breno Leitao
2026-10-27 18:01 ` John Ogness
2026-10-28 11:24 ` Breno Leitao
2026-10-28 10:52 ` Breno Leitao
2026-10-28 14:37 ` John Ogness
2026-10-28 21:15 ` Breno Leitao
2026-10-29 9:20 ` John Ogness
2026-10-29 10:58 ` Breno Leitao
2026-10-29 13:53 ` John Ogness
2026-10-29 14:37 ` Petr Mladek
2026-10-30 17:56 ` Breno Leitao [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=auTaBZlNbpm3jgvb@gmail.com \
--to=leitao@debian.org \
--cc=akpm@linux-foundation.org \
--cc=john.ogness@linutronix.de \
--cc=linux-kernel@vger.kernel.org \
--cc=pmladek@suse.com \
--cc=rioo.tsukatsukii@gmail.com \
--cc=rostedt@goodmis.org \
--cc=ryan.roberts@arm.com \
--cc=senozhatsky@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®