Skip to content

Commit e35a888

Browse files
jognesspmladek
authored andcommitted
printk: Coordinate direct printing in panic
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 <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Petr Mladek <[email protected]>
1 parent bebd87a commit e35a888

File tree

4 files changed

+56
-7
lines changed

4 files changed

+56
-7
lines changed

include/linux/printk.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
200200
extern asmlinkage void dump_stack(void) __cold;
201201
void printk_trigger_flush(void);
202202
void console_try_replay_all(void);
203+
void printk_legacy_allow_panic_sync(void);
203204
extern bool nbcon_device_try_acquire(struct console *con);
204205
extern void nbcon_device_release(struct console *con);
205206
void nbcon_atomic_flush_unsafe(void);
@@ -286,6 +287,10 @@ static inline void console_try_replay_all(void)
286287
{
287288
}
288289

290+
static inline void printk_legacy_allow_panic_sync(void)
291+
{
292+
}
293+
289294
static inline bool nbcon_device_try_acquire(struct console *con)
290295
{
291296
return false;

kernel/panic.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ void panic(const char *fmt, ...)
374374

375375
panic_other_cpus_shutdown(_crash_kexec_post_notifiers);
376376

377+
printk_legacy_allow_panic_sync();
378+
377379
/*
378380
* Run any panic handlers, including those that might need to
379381
* add information to the kmsg dump output.

kernel/printk/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ static inline bool console_is_usable(struct console *con, short flags) { return
154154
#endif /* CONFIG_PRINTK */
155155

156156
extern bool have_boot_console;
157+
extern bool legacy_allow_panic_sync;
157158

158159
extern struct printk_buffers printk_shared_pbufs;
159160

kernel/printk/printk.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,9 @@ static DEFINE_MUTEX(syslog_lock);
471471
static bool have_legacy_console;
472472

473473
/*
474-
* Specifies if an nbcon console is registered.
474+
* Specifies if an nbcon console is registered. If nbcon consoles are present,
475+
* synchronous printing of legacy consoles will not occur during panic until
476+
* the backtrace has been stored to the ringbuffer.
475477
*/
476478
static bool have_nbcon_console;
477479

@@ -483,6 +485,9 @@ static bool have_nbcon_console;
483485
*/
484486
bool have_boot_console;
485487

488+
/* See printk_legacy_allow_panic_sync() for details. */
489+
bool legacy_allow_panic_sync;
490+
486491
/*
487492
* Specifies if the console lock/unlock dance is needed for console
488493
* printing. If @have_boot_console is true, the nbcon consoles will
@@ -2330,12 +2335,28 @@ int vprintk_store(int facility, int level,
23302335
return ret;
23312336
}
23322337

2338+
/*
2339+
* This acts as a one-way switch to allow legacy consoles to print from
2340+
* the printk() caller context on a panic CPU. It also attempts to flush
2341+
* the legacy consoles in this context.
2342+
*/
2343+
void printk_legacy_allow_panic_sync(void)
2344+
{
2345+
legacy_allow_panic_sync = true;
2346+
2347+
if (printing_via_unlock && !is_printk_legacy_deferred()) {
2348+
if (console_trylock())
2349+
console_unlock();
2350+
}
2351+
}
2352+
23332353
asmlinkage int vprintk_emit(int facility, int level,
23342354
const struct dev_printk_info *dev_info,
23352355
const char *fmt, va_list args)
23362356
{
2357+
bool do_trylock_unlock = printing_via_unlock;
2358+
bool defer_legacy = false;
23372359
int printed_len;
2338-
bool in_sched = false;
23392360

23402361
/* Suppress unimportant messages after panic happens */
23412362
if (unlikely(suppress_printk))
@@ -2349,17 +2370,35 @@ asmlinkage int vprintk_emit(int facility, int level,
23492370
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
23502371
return 0;
23512372

2373+
/* If called from the scheduler, we can not call up(). */
23522374
if (level == LOGLEVEL_SCHED) {
23532375
level = LOGLEVEL_DEFAULT;
2354-
in_sched = true;
2376+
defer_legacy = do_trylock_unlock;
2377+
do_trylock_unlock = false;
23552378
}
23562379

23572380
printk_delay(level);
23582381

23592382
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
23602383

2361-
/* If called from the scheduler, we can not call up(). */
2362-
if (!in_sched && printing_via_unlock) {
2384+
if (have_nbcon_console && !have_boot_console) {
2385+
nbcon_atomic_flush_pending();
2386+
2387+
/*
2388+
* In panic, the legacy consoles are not allowed to print from
2389+
* the printk calling context unless explicitly allowed. This
2390+
* gives the safe nbcon consoles a chance to print out all the
2391+
* panic messages first. This restriction only applies if
2392+
* there are nbcon consoles registered and they are allowed to
2393+
* flush.
2394+
*/
2395+
if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
2396+
do_trylock_unlock = false;
2397+
defer_legacy = false;
2398+
}
2399+
}
2400+
2401+
if (do_trylock_unlock) {
23632402
/*
23642403
* The caller may be holding system-critical or
23652404
* timing-sensitive locks. Disable preemption during
@@ -2379,7 +2418,7 @@ asmlinkage int vprintk_emit(int facility, int level,
23792418
preempt_enable();
23802419
}
23812420

2382-
if (in_sched && printing_via_unlock)
2421+
if (defer_legacy)
23832422
defer_console_output();
23842423
else
23852424
wake_up_klogd();
@@ -3292,7 +3331,9 @@ void console_flush_on_panic(enum con_flush_mode mode)
32923331
if (!have_boot_console)
32933332
nbcon_atomic_flush_pending();
32943333

3295-
console_flush_all(false, &next_seq, &handover);
3334+
/* Flush legacy consoles once allowed, even when dangerous. */
3335+
if (legacy_allow_panic_sync)
3336+
console_flush_all(false, &next_seq, &handover);
32963337
}
32973338

32983339
/*

0 commit comments

Comments
 (0)