[PATCH 2/2] Fix console handling during suspend/resume

Linus Torvalds
2006-06-13T21:40:01Z

The old code was terminally broken, and would do extremely bad things if
you used netconsole, for example. Like sending out packets when the device
had already been suspended etc.

The new version may not be perfect either, but it seems fundamentally like
a better design: we just hold on to the primary console semaphore over the
whole suspend event, forcing printk() to just buffer up its data until we
can show it again. The code is also much simpler and more obvious.

This can potentially make debugging harder when something goes wrong at
suspend time and a visible printk would have given us a hint _what_ went
wrong, but on the other hand, it makes fewer things go wrong. Oopses will
punch through the semaphore anyway, so serious problems aren't affected by
this.

Adding a debug thing to say "don't get the console semaphore" might be a
good idea.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

diff --git a/kernel/power/console.c b/kernel/power/console.c
index 623786d..9110371 100644
--- a/kernel/power/console.c
+++ b/kernel/power/console.c
@@ -9,42 +9,20 @@ #include <linux/kbd_kern.h>
#include <linux/console.h>
#include "power.h"

-#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
-#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
-
-static int orig_fgconsole, orig_kmsg;
+extern int console_suspended;

int pm_prepare_console(void)
{
acquire_console_sem();
-
- orig_fgconsole = fg_console;
-
- if (vc_allocate(SUSPEND_CONSOLE)) {
- /* we can't have a free VC for now. Too bad,
- * we don't want to mess the screen for now. */
- release_console_sem();
- return 1;
- }
-
- set_console(SUSPEND_CONSOLE);
- release_console_sem();
-
- if (vt_waitactive(SUSPEND_CONSOLE)) {
- pr_debug("Suspend: Can't switch VCs.");
- return 1;
- }
- orig_kmsg = kmsg_redirect;
- kmsg_redirect = SUSPEND_CONSOLE;
+ console_suspended = 1;
+ system_state = SYSTEM_BOOTING;
return 0;
}

void pm_restore_console(void)
{
- acquire_console_sem();
- set_console(orig_fgconsole);
+ console_suspended = 0;
+ system_state = SYSTEM_BOOTING;
release_console_sem();
- kmsg_redirect = orig_kmsg;
return;
}
-#endif
diff --git a/kernel/printk.c b/kernel/printk.c
index c056f33..8adb9ed 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -67,6 +67,7 @@ EXPORT_SYMBOL(oops_in_progress);
* driver system.
*/
static DECLARE_MUTEX(console_sem);
+static DECLARE_MUTEX(secondary_console_sem);
struct console *console_drivers;
/*
* This is used for debugging the mess that is the VT code by
@@ -77,6 +78,7 @@ struct console *console_drivers;
* locked without the console sempahore held
*/
static int console_locked;
+int console_suspended;

/*
* logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
@@ -707,6 +709,11 @@ int __init add_preferred_console(char *n
*/
void acquire_console_sem(void)
{
+ if (console_suspended) {
+ down(&secondary_console_sem);
+ return;
+ }
+
BUG_ON(in_interrupt());
down(&console_sem);
console_locked = 1;
@@ -750,6 +757,11 @@ void release_console_sem(void)
unsigned long _con_start, _log_end;
unsigned long wake_klogd = 0;

+ if (console_suspended) {
+ up(&secondary_console_sem);
+ return;
+ }
+
for ( ; ; ) {
spin_lock_irqsave(&logbuf_lock, flags);
wake_klogd |= log_start - log_end;