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: Ingo Molnar <mingo@elte.hu> Reviewed-by: Nick Piggin <npiggin@suse.de>
This commit is contained in:
parent
b47711bfbc
commit
32a7600668
|
@ -628,30 +628,57 @@ asmlinkage int printk(const char *fmt, ...)
|
|||
/* cpu currently holding logbuf_lock */
|
||||
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)
|
||||
{
|
||||
unsigned long flags;
|
||||
int printed_len;
|
||||
char *p;
|
||||
static char printk_buf[1024];
|
||||
static int log_level_unknown = 1;
|
||||
static char printk_buf[1024];
|
||||
|
||||
unsigned long flags;
|
||||
int printed_len = 0;
|
||||
int this_cpu;
|
||||
char *p;
|
||||
|
||||
boot_delay_msec();
|
||||
|
||||
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 */
|
||||
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();
|
||||
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 */
|
||||
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
|
||||
|
@ -744,6 +771,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
|
|||
printk_cpu = UINT_MAX;
|
||||
spin_unlock(&logbuf_lock);
|
||||
lockdep_on();
|
||||
out_restore_irqs:
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue