aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-01-25 15:07:58 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-25 15:07:58 -0500
commit32a76006683f7b28ae3cc491da37716e002f198e (patch)
treeab4bf487f675ab1a19b3ad0eac78a0e48f5144e9
parentb47711bfbcd4eb77ca61ef0162487b20e023ae55 (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>
-rw-r--r--kernel/printk.c48
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 */
629static volatile unsigned int printk_cpu = UINT_MAX; 629static volatile unsigned int printk_cpu = UINT_MAX;
630 630
631const char printk_recursion_bug_msg [] =
632 KERN_CRIT "BUG: recent printk recursion!\n";
633static int printk_recursion_bug;
634
631asmlinkage int vprintk(const char *fmt, va_list args) 635asmlinkage 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();
774out_restore_irqs:
747 raw_local_irq_restore(flags); 775 raw_local_irq_restore(flags);
748 } 776 }
749 777