Blob Blame History Raw
From: Thomas Gleixner <tglx@linutronix.de>
Date: Wed, 19 Sep 2012 14:50:37 +0200
Subject: [PATCH 206/329] printk: Make rt aware
Patch-mainline: Not yet, still being discussed upstream
References: bsc#1174146

Drop the lock before calling the console driver and do not disable
interrupts while printing to a serial console.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c |   69 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 50 insertions(+), 19 deletions(-)

--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -247,10 +247,12 @@ static void __up_console_sem(unsigned lo
 }
 #define up_console_sem() __up_console_sem(_RET_IP_)
 
+#ifndef CONFIG_PREEMPT_RT
 static bool panic_in_progress(void)
 {
 	return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
 }
+#endif
 
 /*
  * This is used for debugging the mess that is the VT code by
@@ -1659,6 +1661,7 @@ SYSCALL_DEFINE3(syslog, int, type, char
 	return do_syslog(type, buf, len, SYSLOG_FROM_READER);
 }
 
+#ifndef CONFIG_PREEMPT_RT
 /*
  * Special console_lock variants that help to reduce the risk of soft-lockups.
  * They allow to pass console_lock to another printk() call using a busy wait.
@@ -1675,22 +1678,6 @@ static struct task_struct *console_owner
 static bool console_waiter;
 
 /**
- * printk_bust_locks - forcibly reset all printk-related locks
- *
- * This function can be used after CPUs were stopped using NMI.
- * It is especially useful in kdump_nmi_shootdown_cpus() that
- * uses NMI but it does not modify the online CPU mask.
- */
-void printk_bust_locks(void)
-{
-	debug_locks_off();
-	raw_spin_lock_init(&logbuf_lock);
-	raw_spin_lock_init(&console_owner_lock);
-	console_owner = NULL;
-	console_waiter = false;
-}
-
-/**
  * console_lock_spinning_enable - mark beginning of code where another
  *	thread might safely busy wait
  *
@@ -1825,6 +1812,33 @@ static int console_trylock_spinning(void
 	return 1;
 }
 
+#else
+
+static int console_trylock_spinning(void)
+{
+	return console_trylock();
+}
+
+#endif
+
+/**
+ * printk_bust_locks - forcibly reset all printk-related locks
+ *
+ * This function can be used after CPUs were stopped using NMI.
+ * It is especially useful in kdump_nmi_shootdown_cpus() that
+ * uses NMI but it does not modify the online CPU mask.
+ */
+void printk_bust_locks(void)
+{
+	debug_locks_off();
+	raw_spin_lock_init(&logbuf_lock);
+#ifndef CONFIG_PREEMPT_RT
+	raw_spin_lock_init(&console_owner_lock);
+	console_owner = NULL;
+	console_waiter = false;
+#endif
+}
+
 /*
  * Call the console drivers, asking them to write out
  * log_buf[start] to log_buf[end - 1].
@@ -1840,6 +1854,7 @@ static void call_console_drivers(const c
 	if (!console_drivers)
 		return;
 
+	migrate_disable();
 	for_each_console(con) {
 		if (exclusive_console && con != exclusive_console)
 			continue;
@@ -1855,6 +1870,7 @@ static void call_console_drivers(const c
 		else
 			con->write(con, text, len);
 	}
+	migrate_enable();
 }
 
 int printk_delay_msec __read_mostly;
@@ -2075,20 +2091,30 @@ asmlinkage int vprintk_emit(int facility
 			/* Offload printing to a schedulable context. */
 			defer_console_output();
 		} else {
+			int may_trylock = 1;
+
+#ifdef CONFIG_PREEMPT_RT
+			/*
+			 * we can't take a sleeping lock with IRQs or preeption disabled
+			 * so we can't print in these contexts
+			 */
+			if (!(preempt_count() == 0 && !irqs_disabled()))
+				may_trylock = 0;
+#endif
 			/*
 			 * Disable preemption to avoid being preempted while
 			 * holding console_sem which would prevent anyone
 			 * from printing to console
 			 */
-			preempt_disable();
+			migrate_disable();
 			/*
 			 * Try to acquire and then immediately release the
 			 * console semaphore.  The release will print out
 			 * buffers and wake up /dev/kmsg and syslog() users.
 			 */
-			if (console_trylock_spinning())
+			if (may_trylock && console_trylock_spinning())
 				console_unlock();
-			preempt_enable();
+			migrate_enable();
 		}
 	}
 
@@ -2583,6 +2609,10 @@ skip:
 		console_seq++;
 		raw_spin_unlock(&logbuf_lock);
 
+#ifdef CONFIG_PREEMPT_RT
+		printk_safe_exit_irqrestore(flags);
+		call_console_drivers(ext_text, ext_len, text, len);
+#else
 		/*
 		 * While actively printing out messages, if another printk()
 		 * were to occur on another CPU, it may wait for this one to
@@ -2601,6 +2631,7 @@ skip:
 		}
 
 		printk_safe_exit_irqrestore(flags);
+#endif
 
 		if (do_cond_resched)
 			cond_resched();