diff options
-rw-r--r-- | include/linux/printk.h | 2 | ||||
-rw-r--r-- | kernel/panic.c | 2 | ||||
-rw-r--r-- | kernel/printk/printk.c | 53 |
3 files changed, 50 insertions, 7 deletions
diff --git a/include/linux/printk.h b/include/linux/printk.h index e26dcf63efb1..cf545b76131f 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -782,3 +782,5 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, print_hex_dump_debug(prefix_str, prefix_type, 16, 1, buf, len, true) #endif + +void printk_legacy_allow_panic_sync(void); diff --git a/kernel/panic.c b/kernel/panic.c index 219b69fbe829..f0e91a0c4001 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -366,6 +366,8 @@ void panic(const char *fmt, ...) */ atomic_notifier_call_chain(&panic_notifier_list, 0, buf); + printk_legacy_allow_panic_sync(); + panic_print_sys_info(false); kmsg_dump(KMSG_DUMP_PANIC); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index e84da28db173..9c2e26ce16f9 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2330,12 +2330,23 @@ out: return ret; } +static bool legacy_allow_panic_sync; + +/* + * This acts as a one-way switch to allow legacy consoles to print from + * the printk() caller context on a panic CPU. + */ +void printk_legacy_allow_panic_sync(void) +{ + legacy_allow_panic_sync = true; +} + 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; int printed_len; - bool in_sched = false; /* Suppress unimportant messages after panic happens */ if (unlikely(suppress_printk)) @@ -2351,15 +2362,43 @@ asmlinkage int vprintk_emit(int facility, int level, if (level == LOGLEVEL_SCHED) { level = LOGLEVEL_DEFAULT; - in_sched = true; + /* If called from the scheduler, we can not call up(). */ + 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_boot_console && have_nbcon_console) { + bool is_panic_context = this_cpu_in_panic(); + + /* + * 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. + */ + if (is_panic_context) + do_trylock_unlock &= legacy_allow_panic_sync; + + /* + * There are situations where nbcon atomic printing should + * happen in the printk() caller context: + * + * - When this CPU is in panic. + * + * Note that if boot consoles are registered, the + * console_lock/console_unlock dance must be relied upon + * instead because nbcon consoles cannot print simultaneously + * with boot consoles. + */ + if (is_panic_context) + nbcon_atomic_flush_all(); + } + + if (do_trylock_unlock) { /* * The caller may be holding system-critical or * timing-sensitive locks. Disable preemption during @@ -2379,10 +2418,10 @@ asmlinkage int vprintk_emit(int facility, int level, preempt_enable(); } - if (in_sched) - defer_console_output(); - else + if (do_trylock_unlock) wake_up_klogd(); + else + defer_console_output(); return printed_len; } |