185 lines
5.9 KiB
Diff
185 lines
5.9 KiB
Diff
|
From: John Ogness <john.ogness@linutronix.de>
|
||
|
Date: Tue, 20 Aug 2024 08:35:55 +0206
|
||
|
Subject: [PATCH 29/54] printk: Coordinate direct printing in panic
|
||
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.11/older/patches-6.11-rt7.tar.xz
|
||
|
|
||
|
If legacy and nbcon consoles are registered and the nbcon
|
||
|
consoles are allowed to flush (i.e. no boot consoles
|
||
|
registered), the legacy consoles will no longer perform
|
||
|
direct printing on the panic CPU until after the backtrace
|
||
|
has been stored. This will give the safe nbcon consoles a
|
||
|
chance to print the panic messages before allowing the
|
||
|
unsafe legacy consoles to print.
|
||
|
|
||
|
If no nbcon consoles are registered or they are not allowed
|
||
|
to flush because boot consoles are registered, there is no
|
||
|
change in behavior (i.e. legacy consoles will always attempt
|
||
|
to print from the printk() caller context).
|
||
|
|
||
|
Signed-off-by: John Ogness <john.ogness@linutronix.de>
|
||
|
Reviewed-by: Petr Mladek <pmladek@suse.com>
|
||
|
Link: https://lore.kernel.org/r/20240820063001.36405-30-john.ogness@linutronix.de
|
||
|
Signed-off-by: Petr Mladek <pmladek@suse.com>
|
||
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||
|
---
|
||
|
include/linux/printk.h | 5 ++++
|
||
|
kernel/panic.c | 2 +
|
||
|
kernel/printk/internal.h | 1
|
||
|
kernel/printk/printk.c | 55 +++++++++++++++++++++++++++++++++++++++++------
|
||
|
4 files changed, 56 insertions(+), 7 deletions(-)
|
||
|
|
||
|
--- a/include/linux/printk.h
|
||
|
+++ b/include/linux/printk.h
|
||
|
@@ -200,6 +200,7 @@ extern asmlinkage void dump_stack_lvl(co
|
||
|
extern asmlinkage void dump_stack(void) __cold;
|
||
|
void printk_trigger_flush(void);
|
||
|
void console_try_replay_all(void);
|
||
|
+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);
|
||
|
@@ -286,6 +287,10 @@ static inline void console_try_replay_al
|
||
|
{
|
||
|
}
|
||
|
|
||
|
+static inline void printk_legacy_allow_panic_sync(void)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
static inline bool nbcon_device_try_acquire(struct console *con)
|
||
|
{
|
||
|
return false;
|
||
|
--- a/kernel/panic.c
|
||
|
+++ b/kernel/panic.c
|
||
|
@@ -374,6 +374,8 @@ void panic(const char *fmt, ...)
|
||
|
|
||
|
panic_other_cpus_shutdown(_crash_kexec_post_notifiers);
|
||
|
|
||
|
+ printk_legacy_allow_panic_sync();
|
||
|
+
|
||
|
/*
|
||
|
* Run any panic handlers, including those that might need to
|
||
|
* add information to the kmsg dump output.
|
||
|
--- a/kernel/printk/internal.h
|
||
|
+++ b/kernel/printk/internal.h
|
||
|
@@ -154,6 +154,7 @@ static inline bool console_is_usable(str
|
||
|
#endif /* CONFIG_PRINTK */
|
||
|
|
||
|
extern bool have_boot_console;
|
||
|
+extern bool legacy_allow_panic_sync;
|
||
|
|
||
|
extern struct printk_buffers printk_shared_pbufs;
|
||
|
|
||
|
--- a/kernel/printk/printk.c
|
||
|
+++ b/kernel/printk/printk.c
|
||
|
@@ -471,7 +471,9 @@ static DEFINE_MUTEX(syslog_lock);
|
||
|
static bool have_legacy_console;
|
||
|
|
||
|
/*
|
||
|
- * Specifies if an nbcon console is registered.
|
||
|
+ * Specifies if an nbcon console is registered. If nbcon consoles are present,
|
||
|
+ * synchronous printing of legacy consoles will not occur during panic until
|
||
|
+ * the backtrace has been stored to the ringbuffer.
|
||
|
*/
|
||
|
static bool have_nbcon_console;
|
||
|
|
||
|
@@ -483,6 +485,9 @@ static bool have_nbcon_console;
|
||
|
*/
|
||
|
bool have_boot_console;
|
||
|
|
||
|
+/* See printk_legacy_allow_panic_sync() for details. */
|
||
|
+bool legacy_allow_panic_sync;
|
||
|
+
|
||
|
/*
|
||
|
* Specifies if the console lock/unlock dance is needed for console
|
||
|
* printing. If @have_boot_console is true, the nbcon consoles will
|
||
|
@@ -2330,12 +2335,28 @@ int vprintk_store(int facility, int leve
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * This acts as a one-way switch to allow legacy consoles to print from
|
||
|
+ * the printk() caller context on a panic CPU. It also attempts to flush
|
||
|
+ * the legacy consoles in this context.
|
||
|
+ */
|
||
|
+void printk_legacy_allow_panic_sync(void)
|
||
|
+{
|
||
|
+ legacy_allow_panic_sync = true;
|
||
|
+
|
||
|
+ if (printing_via_unlock && !is_printk_legacy_deferred()) {
|
||
|
+ if (console_trylock())
|
||
|
+ console_unlock();
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
asmlinkage int vprintk_emit(int facility, int level,
|
||
|
const struct dev_printk_info *dev_info,
|
||
|
const char *fmt, va_list args)
|
||
|
{
|
||
|
+ bool do_trylock_unlock = printing_via_unlock;
|
||
|
+ bool defer_legacy = false;
|
||
|
int printed_len;
|
||
|
- bool in_sched = false;
|
||
|
|
||
|
/* Suppress unimportant messages after panic happens */
|
||
|
if (unlikely(suppress_printk))
|
||
|
@@ -2349,17 +2370,35 @@ asmlinkage int vprintk_emit(int facility
|
||
|
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
|
||
|
return 0;
|
||
|
|
||
|
+ /* If called from the scheduler, we can not call up(). */
|
||
|
if (level == LOGLEVEL_SCHED) {
|
||
|
level = LOGLEVEL_DEFAULT;
|
||
|
- in_sched = true;
|
||
|
+ defer_legacy = do_trylock_unlock;
|
||
|
+ do_trylock_unlock = false;
|
||
|
}
|
||
|
|
||
|
printk_delay(level);
|
||
|
|
||
|
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
|
||
|
|
||
|
- /* If called from the scheduler, we can not call up(). */
|
||
|
- if (!in_sched && printing_via_unlock) {
|
||
|
+ if (have_nbcon_console && !have_boot_console) {
|
||
|
+ nbcon_atomic_flush_pending();
|
||
|
+
|
||
|
+ /*
|
||
|
+ * In panic, the legacy consoles are not allowed to print from
|
||
|
+ * the printk calling context unless explicitly allowed. This
|
||
|
+ * gives the safe nbcon consoles a chance to print out all the
|
||
|
+ * panic messages first. This restriction only applies if
|
||
|
+ * there are nbcon consoles registered and they are allowed to
|
||
|
+ * flush.
|
||
|
+ */
|
||
|
+ if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
|
||
|
+ do_trylock_unlock = false;
|
||
|
+ defer_legacy = false;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (do_trylock_unlock) {
|
||
|
/*
|
||
|
* The caller may be holding system-critical or
|
||
|
* timing-sensitive locks. Disable preemption during
|
||
|
@@ -2379,7 +2418,7 @@ asmlinkage int vprintk_emit(int facility
|
||
|
preempt_enable();
|
||
|
}
|
||
|
|
||
|
- if (in_sched && printing_via_unlock)
|
||
|
+ if (defer_legacy)
|
||
|
defer_console_output();
|
||
|
else
|
||
|
wake_up_klogd();
|
||
|
@@ -3293,7 +3332,9 @@ void console_flush_on_panic(enum con_flu
|
||
|
if (!have_boot_console)
|
||
|
nbcon_atomic_flush_pending();
|
||
|
|
||
|
- console_flush_all(false, &next_seq, &handover);
|
||
|
+ /* Flush legacy consoles once allowed, even when dangerous. */
|
||
|
+ if (legacy_allow_panic_sync)
|
||
|
+ console_flush_all(false, &next_seq, &handover);
|
||
|
}
|
||
|
|
||
|
/*
|