Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2025

kernel-2.6.18-238.el5.src.rpm

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);
 	}