Merge branch 'for-5.18-panic-deadlocks' into for-linus
This commit is contained in:
commit
1ccd85f5ac
|
@ -93,6 +93,12 @@ EXPORT_SYMBOL_GPL(console_drivers);
|
|||
*/
|
||||
int __read_mostly suppress_printk;
|
||||
|
||||
/*
|
||||
* During panic, heavy printk by other CPUs can delay the
|
||||
* panic and risk deadlock on console resources.
|
||||
*/
|
||||
static int __read_mostly suppress_panic_printk;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static struct lockdep_map console_lock_dep_map = {
|
||||
.name = "console_lock"
|
||||
|
@ -258,6 +264,11 @@ static void __up_console_sem(unsigned long ip)
|
|||
}
|
||||
#define up_console_sem() __up_console_sem(_RET_IP_)
|
||||
|
||||
static bool panic_in_progress(void)
|
||||
{
|
||||
return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used for debugging the mess that is the VT code by
|
||||
* keeping track if we have the console semaphore held. It's
|
||||
|
@ -1844,6 +1855,16 @@ static int console_trylock_spinning(void)
|
|||
if (console_trylock())
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* It's unsafe to spin once a panic has begun. If we are the
|
||||
* panic CPU, we may have already halted the owner of the
|
||||
* console_sem. If we are not the panic CPU, then we should
|
||||
* avoid taking console_sem, so the panic CPU has a better
|
||||
* chance of cleanly acquiring it later.
|
||||
*/
|
||||
if (panic_in_progress())
|
||||
return 0;
|
||||
|
||||
printk_safe_enter_irqsave(flags);
|
||||
|
||||
raw_spin_lock(&console_owner_lock);
|
||||
|
@ -2219,6 +2240,10 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|||
if (unlikely(suppress_printk))
|
||||
return 0;
|
||||
|
||||
if (unlikely(suppress_panic_printk) &&
|
||||
atomic_read(&panic_cpu) != raw_smp_processor_id())
|
||||
return 0;
|
||||
|
||||
if (level == LOGLEVEL_SCHED) {
|
||||
level = LOGLEVEL_DEFAULT;
|
||||
in_sched = true;
|
||||
|
@ -2586,6 +2611,25 @@ static int have_callable_console(void)
|
|||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* Can we actually use the console at this time on this cpu?
|
||||
*
|
||||
|
@ -2616,6 +2660,7 @@ void console_unlock(void)
|
|||
{
|
||||
static char ext_text[CONSOLE_EXT_LOG_MAX];
|
||||
static char text[CONSOLE_LOG_MAX];
|
||||
static int panic_console_dropped;
|
||||
unsigned long flags;
|
||||
bool do_cond_resched, retry;
|
||||
struct printk_info info;
|
||||
|
@ -2670,6 +2715,10 @@ skip:
|
|||
if (console_seq != r.info->seq) {
|
||||
console_dropped += r.info->seq - console_seq;
|
||||
console_seq = r.info->seq;
|
||||
if (panic_in_progress() && panic_console_dropped++ > 10) {
|
||||
suppress_panic_printk = 1;
|
||||
pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (suppress_message_printing(r.info->level)) {
|
||||
|
@ -2729,6 +2778,10 @@ skip:
|
|||
if (handover)
|
||||
return;
|
||||
|
||||
/* Allow panic_cpu to take over the consoles safely */
|
||||
if (abandon_console_lock_in_panic())
|
||||
break;
|
||||
|
||||
if (do_cond_resched)
|
||||
cond_resched();
|
||||
}
|
||||
|
@ -2746,7 +2799,7 @@ skip:
|
|||
* flush, no worries.
|
||||
*/
|
||||
retry = prb_read_valid(prb, next_seq, NULL);
|
||||
if (retry && console_trylock())
|
||||
if (retry && !abandon_console_lock_in_panic() && console_trylock())
|
||||
goto again;
|
||||
}
|
||||
EXPORT_SYMBOL(console_unlock);
|
||||
|
|
Loading…
Reference in New Issue