* [PATCH 1/2] printk: nbcon: Flush unsafe consoles from printk() in panic
2026-11-02 18:14 [PATCH 0/2] panic: flush unsafe consoles before reboot and kdump Breno Leitao
@ 2026-11-02 18:14 ` Breno Leitao
2026-11-02 18:14 ` [PATCH 2/2] crash: Flush unsafe consoles before machine_crash_shutdown() Breno Leitao
1 sibling, 0 replies; 3+ messages in thread
From: Breno Leitao @ 2026-11-02 18:14 UTC (permalink / raw)
To: Petr Mladek, John Ogness, Kiryl Shutsemau
Cc: linux-kernel, printk, gustavold, samuelcrossley, ryan.roberts,
brads, x86, Breno Leitao, kernel-team, stable
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. Before the conversion,
netconsole was a legacy console and printk() wrote each panic message to
it as it was printed.
Flush the unsafe consoles from nbcon_atomic_flush_pending() as well,
right after the safe ones, when it runs on the panic CPU with
oops_in_progress set. Every printk() on the panic CPU then reaches
netconsole again, "Rebooting in" included.
An unsafe write_atomic() that hangs now stops the panic CPU at the first
message, before the other consoles print the rest and before the reboot
or the crash kernel. Getting the messages out is worth that.
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: Petr Mladek <pmladek@suse.com>
Cc: stable@vger.kernel.org
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/console.h | 7 ++++---
kernel/printk/nbcon.c | 24 ++++++++++++++++++------
2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index cb8be9ea4a767b..934fe72978b0e5 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 in panic, when unsafe takeovers
+ * are allowed.
*/
enum cons_flags {
CON_PRINTBUFFER = BIT(0),
@@ -246,8 +247,8 @@ static_assert(sizeof(struct nbcon_state) <= sizeof(int));
* @NBCON_PRIO_MAX: The number of priority levels
*
* A higher priority context can takeover the console when it is
- * in the safe state. The final attempt to flush consoles in panic()
- * can be allowed to do so even in an unsafe state (Hope and pray).
+ * in the safe state. The panic CPU can be allowed to do so even in
+ * an unsafe state (Hope and pray).
*/
enum nbcon_prio {
NBCON_PRIO_NONE = 0,
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 5f8afaca886650..19fa9f79cac3cb 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -84,8 +84,8 @@
* b) Gives up console ownership by clearing the 'prio' field.
*
* 3) Unsafe hostile takeover allows to take over the lock even when the
- * console is an unsafe state. It is used only in panic() by the final
- * attempt to flush consoles in a try and hope mode.
+ * console is an unsafe state. It is used only on the panic CPU, in a
+ * try and hope mode.
*
* Note that separate record buffers are used in panic(). As a result,
* the messages can be read and formatted without any risk even after
@@ -543,7 +543,7 @@ static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt,
* Acquire the console even in the unsafe state.
*
* It can be permitted by setting the 'allow_unsafe_takeover' field only
- * by the final attempt to flush messages in panic().
+ * on the panic CPU.
*
* Return: 0 on success. -EPERM when not allowed by the context.
*/
@@ -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,15 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
*/
void nbcon_atomic_flush_pending(void)
{
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ u64 stop_seq = prb_next_reserve_seq(prb);
+
+ __nbcon_atomic_flush_pending(stop_seq, false);
+
+ if (panic_on_this_cpu() && oops_in_progress) {
+ panic_nbcon_allow_unsafe_takeover = true;
+ __nbcon_atomic_flush_pending(stop_seq, true);
+ panic_nbcon_allow_unsafe_takeover = false;
+ }
}
/**
@@ -1701,7 +1713,7 @@ 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;
}
--
2.53.0-Meta
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] crash: Flush unsafe consoles before machine_crash_shutdown()
2026-11-02 18:14 [PATCH 0/2] panic: flush unsafe consoles before reboot and kdump Breno Leitao
2026-11-02 18:14 ` [PATCH 1/2] printk: nbcon: Flush unsafe consoles from printk() in panic Breno Leitao
@ 2026-11-02 18:14 ` Breno Leitao
1 sibling, 0 replies; 3+ messages in thread
From: Breno Leitao @ 2026-11-02 18:14 UTC (permalink / raw)
To: Petr Mladek, John Ogness, Kiryl Shutsemau
Cc: linux-kernel, printk, gustavold, samuelcrossley, ryan.roberts,
brads, x86, Breno Leitao, kernel-team, stable
On x86, an oops that goes to kdump never reaches netconsole. oops_end()
calls crash_kexec() after the oops is printed, before this CPU becomes
the panic CPU, so printk() skips the unsafe consoles for the whole
report. Unless something fails, nothing else is printed on the panic CPU
before machine_kexec().
Add nbcon_atomic_unsafe_only_flush(), which flushes only the
CON_NBCON_ATOMIC_UNSAFE consoles and allows unsafe takeovers on them.
Call it in __crash_kexec() before machine_crash_shutdown() tears down
what they may need, such as the shared memory of a TDX guest. As with
the legacy console, the other CPUs are still running at that point,
unless crash_kexec_post_notifiers is set.
When kdump comes from panic(), printk() has already flushed the unsafe
consoles and the call finds nothing pending.
Fixes: 187de7c212e5 ("printk: nbcon: Allow unsafe write_atomic() for panic")
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>
---
include/linux/printk.h | 5 +++++
kernel/crash_core.c | 1 +
kernel/printk/nbcon.c | 14 ++++++++++++++
3 files changed, 20 insertions(+)
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..6580eaa86685a9 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -140,6 +140,7 @@ void __noclone __crash_kexec(struct pt_regs *regs)
crash_setup_regs(&fixed_regs, regs);
crash_save_vmcoreinfo();
+ nbcon_atomic_unsafe_only_flush();
machine_crash_shutdown(&fixed_regs);
crash_cma_clear_pending_dma();
machine_kexec(kexec_crash_image);
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 19fa9f79cac3cb..c22175a33ce17e 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1717,6 +1717,20 @@ void nbcon_atomic_flush_unsafe(void)
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. Only effective on the panic CPU.
+ */
+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;
+}
+
/**
* nbcon_cpu_emergency_enter - Enter an emergency section where printk()
* messages for that CPU are flushed directly
--
2.53.0-Meta
^ permalink raw reply [flat|nested] 3+ messages in thread