From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

This patch removes the call to unblank() from printk, and avoids calling
unblank at irq() time _unless_ oops_in_progress is 1.  I also export
oops_in_progress() so drivers who care like radeonfb can test it and know
what to do.  I audited call sites of unblank_screen(), console_unblank(),
etc...  and I _hope_ I got them all, the patch includes a small patch to
the s390 bust_spinlocks code that sets oops_in_progress back to 0 _after_
unblanking for example.

I added a few might_sleep() to help us catch possible remaining callers.

I'll soon write a document explaining fbdev locking.  The current situation
after this patch is that:

- All callbacks have console_semaphore held (fbdev's are fully
  serialised).

- Everything is called in schedule'able context, except the cfb_*
  rendering operations and cursor operations, with the special case of
  unblank who can be called at any time when "oops_in_progress" is true.  A
  driver that needs to sleep in it's unblank implementation is welcome to
  test that variable and use a fallback path (or just do nothing if it's
  not simple).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/s390/mm/fault.c |    2 +-
 25-akpm/drivers/char/vt.c    |   18 +++++++++++++++---
 25-akpm/kernel/printk.c      |   18 +++++++++++++-----
 3 files changed, 29 insertions(+), 9 deletions(-)

diff -puN arch/s390/mm/fault.c~vt-dont-call-unblank-at-irq-time arch/s390/mm/fault.c
--- 25/arch/s390/mm/fault.c~vt-dont-call-unblank-at-irq-time	2005-03-10 22:06:02.000000000 -0800
+++ 25-akpm/arch/s390/mm/fault.c	2005-03-10 22:06:02.000000000 -0800
@@ -62,8 +62,8 @@ void bust_spinlocks(int yes)
 		oops_in_progress = 1;
 	} else {
 		int loglevel_save = console_loglevel;
-		oops_in_progress = 0;
 		console_unblank();
+		oops_in_progress = 0;
 		/*
 		 * OK, the message is on the console.  Now we call printk()
 		 * without oops_in_progress set so that printk will give klogd
diff -puN drivers/char/vt.c~vt-dont-call-unblank-at-irq-time drivers/char/vt.c
--- 25/drivers/char/vt.c~vt-dont-call-unblank-at-irq-time	2005-03-10 22:06:02.000000000 -0800
+++ 25-akpm/drivers/char/vt.c	2005-03-10 22:06:02.000000000 -0800
@@ -2220,9 +2220,6 @@ void vt_console_print(struct console *co
 	}
 	set_cursor(vc);
 
-	if (!oops_in_progress)
-		poke_blanked_console();
-
 quit:
 	clear_bit(0, &printing);
 }
@@ -2823,6 +2820,13 @@ void do_unblank_screen(int leaving_gfx)
 {
 	struct vc_data *vc;
 
+	/* This should now always be called from a "sane" (read: can schedule)
+	 * context for the sake of the low level drivers, except in the special
+	 * case of oops_in_progress
+	 */
+	if (!oops_in_progress)
+		might_sleep();
+
 	WARN_CONSOLE_UNLOCKED();
 
 	ignore_poke = 0;
@@ -2879,6 +2883,14 @@ void poke_blanked_console(void)
 {
 	WARN_CONSOLE_UNLOCKED();
 
+	/* Add this so we quickly catch whoever might call us in a non
+	 * safe context. Nowadays, unblank_screen() isn't to be called in
+	 * atomic contexts and is allowed to schedule (with the special case
+	 * of oops_in_progress, but that isn't of any concern for this
+	 * function. --BenH.
+	 */
+	might_sleep();
+
 	/* This isn't perfectly race free, but a race here would be mostly harmless,
 	 * at worse, we'll do a spurrious blank and it's unlikely
 	 */
diff -puN kernel/printk.c~vt-dont-call-unblank-at-irq-time kernel/printk.c
--- 25/kernel/printk.c~vt-dont-call-unblank-at-irq-time	2005-03-10 22:06:02.000000000 -0800
+++ 25-akpm/kernel/printk.c	2005-03-10 22:06:02.000000000 -0800
@@ -54,7 +54,12 @@ int console_printk[4] = {
 
 EXPORT_SYMBOL(console_printk);
 
+/*
+ * Low lever drivers may need that to know if they can schedule in
+ * their unblank() callback or not. So let's export it.
+ */
 int oops_in_progress;
+EXPORT_SYMBOL(oops_in_progress);
 
 /*
  * console_sem protects the console_drivers list, and also
@@ -749,12 +754,15 @@ void console_unblank(void)
 	struct console *c;
 
 	/*
-	 * Try to get the console semaphore. If someone else owns it
-	 * we have to return without unblanking because console_unblank
-	 * may be called in interrupt context.
+	 * console_unblank can no longer be called in interrupt context unless
+	 * oops_in_progress is set to 1..
 	 */
-	if (down_trylock(&console_sem) != 0)
-		return;
+	if (oops_in_progress) {
+		if (down_trylock(&console_sem) != 0)
+			return;
+	} else
+		acquire_console_sem();
+
 	console_locked = 1;
 	console_may_schedule = 0;
 	for (c = console_drivers; c != NULL; c = c->next)
_