diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-01-25 15:07:58 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-25 15:07:58 -0500 |
commit | 32a76006683f7b28ae3cc491da37716e002f198e (patch) | |
tree | ab4bf487f675ab1a19b3ad0eac78a0e48f5144e9 /kernel | |
parent | b47711bfbcd4eb77ca61ef0162487b20e023ae55 (diff) |
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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/printk.c | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 89011bf8c106..e6c1f36d8c3a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -628,30 +628,57 @@ asmlinkage int printk(const char *fmt, ...) | |||
628 | /* cpu currently holding logbuf_lock */ | 628 | /* cpu currently holding logbuf_lock */ |
629 | static volatile unsigned int printk_cpu = UINT_MAX; | 629 | static volatile unsigned int printk_cpu = UINT_MAX; |
630 | 630 | ||
631 | const char printk_recursion_bug_msg [] = | ||
632 | KERN_CRIT "BUG: recent printk recursion!\n"; | ||
633 | static int printk_recursion_bug; | ||
634 | |||
631 | asmlinkage int vprintk(const char *fmt, va_list args) | 635 | asmlinkage int vprintk(const char *fmt, va_list args) |
632 | { | 636 | { |
637 | static int log_level_unknown = 1; | ||
638 | static char printk_buf[1024]; | ||
639 | |||
633 | unsigned long flags; | 640 | unsigned long flags; |
634 | int printed_len; | 641 | int printed_len = 0; |
642 | int this_cpu; | ||
635 | char *p; | 643 | char *p; |
636 | static char printk_buf[1024]; | ||
637 | static int log_level_unknown = 1; | ||
638 | 644 | ||
639 | boot_delay_msec(); | 645 | boot_delay_msec(); |
640 | 646 | ||
641 | preempt_disable(); | 647 | preempt_disable(); |
642 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) | ||
643 | /* If a crash is occurring during printk() on this CPU, | ||
644 | * make sure we can't deadlock */ | ||
645 | zap_locks(); | ||
646 | |||
647 | /* This stops the holder of console_sem just where we want him */ | 648 | /* This stops the holder of console_sem just where we want him */ |
648 | raw_local_irq_save(flags); | 649 | raw_local_irq_save(flags); |
650 | this_cpu = smp_processor_id(); | ||
651 | |||
652 | /* | ||
653 | * Ouch, printk recursed into itself! | ||
654 | */ | ||
655 | if (unlikely(printk_cpu == this_cpu)) { | ||
656 | /* | ||
657 | * If a crash is occurring during printk() on this CPU, | ||
658 | * then try to get the crash message out but make sure | ||
659 | * we can't deadlock. Otherwise just return to avoid the | ||
660 | * recursion and return - but flag the recursion so that | ||
661 | * it can be printed at the next appropriate moment: | ||
662 | */ | ||
663 | if (!oops_in_progress) { | ||
664 | printk_recursion_bug = 1; | ||
665 | goto out_restore_irqs; | ||
666 | } | ||
667 | zap_locks(); | ||
668 | } | ||
669 | |||
649 | lockdep_off(); | 670 | lockdep_off(); |
650 | spin_lock(&logbuf_lock); | 671 | spin_lock(&logbuf_lock); |
651 | printk_cpu = smp_processor_id(); | 672 | printk_cpu = this_cpu; |
652 | 673 | ||
674 | if (printk_recursion_bug) { | ||
675 | printk_recursion_bug = 0; | ||
676 | strcpy(printk_buf, printk_recursion_bug_msg); | ||
677 | printed_len = sizeof(printk_recursion_bug_msg); | ||
678 | } | ||
653 | /* Emit the output into the temporary buffer */ | 679 | /* Emit the output into the temporary buffer */ |
654 | printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); | 680 | printed_len += vscnprintf(printk_buf + printed_len, |
681 | sizeof(printk_buf), fmt, args); | ||
655 | 682 | ||
656 | /* | 683 | /* |
657 | * Copy the output into log_buf. If the caller didn't provide | 684 | * 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 | printk_cpu = UINT_MAX; | 771 | printk_cpu = UINT_MAX; |
745 | spin_unlock(&logbuf_lock); | 772 | spin_unlock(&logbuf_lock); |
746 | lockdep_on(); | 773 | lockdep_on(); |
774 | out_restore_irqs: | ||
747 | raw_local_irq_restore(flags); | 775 | raw_local_irq_restore(flags); |
748 | } | 776 | } |
749 | 777 | ||