Commit 32a76006 authored by Ingo Molnar's avatar Ingo Molnar

printk: make printk more robust by not allowing recursion

make printk more robust by allowing recursion only if there's a crash
going on. Also add recursion detection.

I've tested it with an artificially injected printk recursion - instead
of a lockup or spontaneous reboot or other crash, the output was a well
controlled:

[   41.057335] SysRq : <2>BUG: recent printk recursion!
[   41.057335] loglevel0-8 reBoot Crashdump show-all-locks(D) tErm Full kIll saK showMem Nice powerOff showPc show-all-timers(Q) unRaw Sync showTasks Unmount shoW-blocked-tasks

also do all this printk-debug logic with irqs disabled.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Reviewed-by: default avatarNick Piggin <npiggin@suse.de>
parent b47711bf
...@@ -628,30 +628,57 @@ asmlinkage int printk(const char *fmt, ...) ...@@ -628,30 +628,57 @@ asmlinkage int printk(const char *fmt, ...)
/* cpu currently holding logbuf_lock */ /* cpu currently holding logbuf_lock */
static volatile unsigned int printk_cpu = UINT_MAX; static volatile unsigned int printk_cpu = UINT_MAX;
const char printk_recursion_bug_msg [] =
KERN_CRIT "BUG: recent printk recursion!\n";
static int printk_recursion_bug;
asmlinkage int vprintk(const char *fmt, va_list args) asmlinkage int vprintk(const char *fmt, va_list args)
{ {
static int log_level_unknown = 1;
static char printk_buf[1024];
unsigned long flags; unsigned long flags;
int printed_len; int printed_len = 0;
int this_cpu;
char *p; char *p;
static char printk_buf[1024];
static int log_level_unknown = 1;
boot_delay_msec(); boot_delay_msec();
preempt_disable(); preempt_disable();
if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
/* If a crash is occurring during printk() on this CPU,
* make sure we can't deadlock */
zap_locks();
/* This stops the holder of console_sem just where we want him */ /* This stops the holder of console_sem just where we want him */
raw_local_irq_save(flags); raw_local_irq_save(flags);
this_cpu = smp_processor_id();
/*
* Ouch, printk recursed into itself!
*/
if (unlikely(printk_cpu == this_cpu)) {
/*
* If a crash is occurring during printk() on this CPU,
* then try to get the crash message out but make sure
* we can't deadlock. Otherwise just return to avoid the
* recursion and return - but flag the recursion so that
* it can be printed at the next appropriate moment:
*/
if (!oops_in_progress) {
printk_recursion_bug = 1;
goto out_restore_irqs;
}
zap_locks();
}
lockdep_off(); lockdep_off();
spin_lock(&logbuf_lock); spin_lock(&logbuf_lock);
printk_cpu = smp_processor_id(); printk_cpu = this_cpu;
if (printk_recursion_bug) {
printk_recursion_bug = 0;
strcpy(printk_buf, printk_recursion_bug_msg);
printed_len = sizeof(printk_recursion_bug_msg);
}
/* Emit the output into the temporary buffer */ /* Emit the output into the temporary buffer */
printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf), fmt, args);
/* /*
* Copy the output into log_buf. If the caller didn't provide * Copy the output into log_buf. If the caller didn't provide
...@@ -744,6 +771,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) ...@@ -744,6 +771,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
printk_cpu = UINT_MAX; printk_cpu = UINT_MAX;
spin_unlock(&logbuf_lock); spin_unlock(&logbuf_lock);
lockdep_on(); lockdep_on();
out_restore_irqs:
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment