|
@@ -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)
|
|
|
{
|
|
|
+ static int log_level_unknown = 1;
|
|
|
+ static char printk_buf[1024];
|
|
|
+
|
|
|
unsigned long flags;
|
|
|
- int printed_len;
|
|
|
+ int printed_len = 0;
|
|
|
+ int this_cpu;
|
|
|
char *p;
|
|
|
- static char printk_buf[1024];
|
|
|
- static int log_level_unknown = 1;
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|