printk: Keep non-panic-CPUs out of console lock

When in a panic situation, non-panic CPUs should avoid holding the
console lock so as not to contend with the panic CPU. This is already
implemented with abandon_console_lock_in_panic(), which is checked
after each printed line. However, non-panic CPUs should also avoid
trying to acquire the console lock during a panic.

Modify console_trylock() to fail and console_lock() to block() when
called from a non-panic CPU during a panic.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20230717194607.145135-4-john.ogness@linutronix.de
This commit is contained in:
John Ogness 2023-07-17 21:52:03 +02:06 committed by Petr Mladek
parent 7b23a66db5
commit 51a1d258e5
1 changed files with 26 additions and 19 deletions

View File

@ -2583,6 +2583,25 @@ static int console_cpu_notify(unsigned int cpu)
return 0; return 0;
} }
/*
* Return true when this CPU should unlock console_sem without pushing all
* messages to the console. This reduces the chance that the console is
* locked when the panic CPU tries to use it.
*/
static bool abandon_console_lock_in_panic(void)
{
if (!panic_in_progress())
return false;
/*
* We can use raw_smp_processor_id() here because it is impossible for
* the task to be migrated to the panic_cpu, or away from it. If
* panic_cpu has already been set, and we're not currently executing on
* that CPU, then we never will be.
*/
return atomic_read(&panic_cpu) != raw_smp_processor_id();
}
/** /**
* console_lock - block the console subsystem from printing * console_lock - block the console subsystem from printing
* *
@ -2595,6 +2614,10 @@ void console_lock(void)
{ {
might_sleep(); might_sleep();
/* On panic, the console_lock must be left to the panic cpu. */
while (abandon_console_lock_in_panic())
msleep(1000);
down_console_sem(); down_console_sem();
if (console_suspended) if (console_suspended)
return; return;
@ -2613,6 +2636,9 @@ EXPORT_SYMBOL(console_lock);
*/ */
int console_trylock(void) int console_trylock(void)
{ {
/* On panic, the console_lock must be left to the panic cpu. */
if (abandon_console_lock_in_panic())
return 0;
if (down_trylock_console_sem()) if (down_trylock_console_sem())
return 0; return 0;
if (console_suspended) { if (console_suspended) {
@ -2631,25 +2657,6 @@ int is_console_locked(void)
} }
EXPORT_SYMBOL(is_console_locked); EXPORT_SYMBOL(is_console_locked);
/*
* Return true when this CPU should unlock console_sem without pushing all
* messages to the console. This reduces the chance that the console is
* locked when the panic CPU tries to use it.
*/
static bool abandon_console_lock_in_panic(void)
{
if (!panic_in_progress())
return false;
/*
* We can use raw_smp_processor_id() here because it is impossible for
* the task to be migrated to the panic_cpu, or away from it. If
* panic_cpu has already been set, and we're not currently executing on
* that CPU, then we never will be.
*/
return atomic_read(&panic_cpu) != raw_smp_processor_id();
}
/* /*
* Check if the given console is currently capable and allowed to print * Check if the given console is currently capable and allowed to print
* records. * records.