Commit fe21773d authored by David Howells's avatar David Howells Committed by Linus Torvalds

[PATCH] Provide better printk() support for SMP machines

The attached patch prevents oopses interleaving with characters from
other printks on other CPUs by only breaking the lock if the oops is
happening on the machine holding the lock.

It might be better if the oops generator got the lock and then called an
inner vprintk routine that assumed the caller holds the lock, thus
making oops reports "atomic".
Signed-Off-By: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c3d8c141
...@@ -514,6 +514,9 @@ asmlinkage int printk(const char *fmt, ...) ...@@ -514,6 +514,9 @@ asmlinkage int printk(const char *fmt, ...)
return r; return r;
} }
/* cpu currently holding logbuf_lock */
static volatile unsigned int printk_cpu = UINT_MAX;
asmlinkage int vprintk(const char *fmt, va_list args) asmlinkage int vprintk(const char *fmt, va_list args)
{ {
unsigned long flags; unsigned long flags;
...@@ -522,11 +525,15 @@ asmlinkage int vprintk(const char *fmt, va_list args) ...@@ -522,11 +525,15 @@ asmlinkage int vprintk(const char *fmt, va_list args)
static char printk_buf[1024]; static char printk_buf[1024];
static int log_level_unknown = 1; static int log_level_unknown = 1;
if (unlikely(oops_in_progress)) 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(); 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 */
spin_lock_irqsave(&logbuf_lock, flags); spin_lock_irqsave(&logbuf_lock, flags);
printk_cpu = smp_processor_id();
/* 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, sizeof(printk_buf), fmt, args);
...@@ -595,6 +602,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) ...@@ -595,6 +602,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
* CPU until it is officially up. We shouldn't be calling into * CPU until it is officially up. We shouldn't be calling into
* random console drivers on a CPU which doesn't exist yet.. * random console drivers on a CPU which doesn't exist yet..
*/ */
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags); spin_unlock_irqrestore(&logbuf_lock, flags);
goto out; goto out;
} }
...@@ -604,6 +612,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) ...@@ -604,6 +612,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
* We own the drivers. We can drop the spinlock and let * We own the drivers. We can drop the spinlock and let
* release_console_sem() print the text * release_console_sem() print the text
*/ */
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags); spin_unlock_irqrestore(&logbuf_lock, flags);
console_may_schedule = 0; console_may_schedule = 0;
release_console_sem(); release_console_sem();
...@@ -613,9 +622,11 @@ asmlinkage int vprintk(const char *fmt, va_list args) ...@@ -613,9 +622,11 @@ asmlinkage int vprintk(const char *fmt, va_list args)
* allows the semaphore holder to proceed and to call the * allows the semaphore holder to proceed and to call the
* console drivers with the output which we just produced. * console drivers with the output which we just produced.
*/ */
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags); spin_unlock_irqrestore(&logbuf_lock, flags);
} }
out: out:
preempt_enable();
return printed_len; return printed_len;
} }
EXPORT_SYMBOL(printk); EXPORT_SYMBOL(printk);
......
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