From: Neil Horman <nhorman@redhat.com> Date: Fri, 22 Aug 2008 14:20:49 -0400 Subject: [misc] make printk more robust against kexec shutdowns Message-id: 20080822182049.GK20093@hmsendeavour.rdu.redhat.com O-Subject: [RHEL 5.3 PATCH] kexec: make printk more robust to avoid hangs on kexec shutdown (bz 458368) Bugzilla: 458368 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> RH-Acked-by: Markus Armbruster <armbru@redhat.com> Hey- Backport of upstream comit 32a76006683f7b28ae3cc491da37716e002f198e. Makes printk more robust and tolerant of re-entry so as to prevent a few hangs on kexec shutdown. Solves bz 458368. Tested by the reporter successfully. Thanks to Guy Streeter for the backport work. Neil diff --git a/kernel/printk.c b/kernel/printk.c index 3605558..d1cb5ea 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -538,28 +538,54 @@ asmlinkage int printk(const char *fmt, ...) /* cpu currently holding logbuf_lock */ static volatile unsigned int printk_cpu = UINT_MAX; +static const char recursion_bug_msg [] = + KERN_CRIT "BUG: recent printk recursion!\n"; +static int 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; 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 */ 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) { + 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 (recursion_bug) { + recursion_bug = 0; + strcpy(printk_buf, recursion_bug_msg); + printed_len = sizeof(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) - printed_len, fmt, args); /* * Copy the output into log_buf. If the caller didn't provide @@ -652,6 +678,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) printk_cpu = UINT_MAX; spin_unlock(&logbuf_lock); lockdep_on(); +out_restore_irqs: local_irq_restore(flags); }