diff options
author | Andrew Johnson <ajohnson@intrinsyc.com> | 2007-03-16 17:38:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-16 22:25:05 -0400 |
commit | b257bc051f06607beb3004d9a1c297085e728bec (patch) | |
tree | 2eeb60429d92b683e9593d2fcde2f22ae40a1bf4 | |
parent | 1174cf730179d8f029b9e93cb9a4d5bfb08d1202 (diff) |
[PATCH] swsusp: fix suspend when console is in VT_AUTO+KD_GRAPHICS mode
When the console is in VT_AUTO+KD_GRAPHICS mode, switching to the
SUSPEND_CONSOLE fails, resulting in vt_waitactive() waiting indefinitely or
until the task is interrupted. This patch tests if a console switch can
occur in set_console() and returns early if a console switch is not
possible.
[akpm@linux-foundation.org: cleanup]
Signed-off-by: Andrew Johnson <ajohnson@intrinsyc.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/char/vt.c | 20 | ||||
-rw-r--r-- | drivers/char/vt_ioctl.c | 2 | ||||
-rw-r--r-- | include/linux/kbd_kern.h | 2 | ||||
-rw-r--r-- | include/linux/vt_kern.h | 1 | ||||
-rw-r--r-- | kernel/power/console.c | 10 |
5 files changed, 31 insertions, 4 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index c3f8e383933b..0fefe2a28055 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -2185,10 +2185,28 @@ static void console_callback(struct work_struct *ignored) | |||
2185 | release_console_sem(); | 2185 | release_console_sem(); |
2186 | } | 2186 | } |
2187 | 2187 | ||
2188 | void set_console(int nr) | 2188 | int set_console(int nr) |
2189 | { | 2189 | { |
2190 | struct vc_data *vc = vc_cons[fg_console].d; | ||
2191 | |||
2192 | if (!vc_cons_allocated(nr) || vt_dont_switch || | ||
2193 | (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) { | ||
2194 | |||
2195 | /* | ||
2196 | * Console switch will fail in console_callback() or | ||
2197 | * change_console() so there is no point scheduling | ||
2198 | * the callback | ||
2199 | * | ||
2200 | * Existing set_console() users don't check the return | ||
2201 | * value so this shouldn't break anything | ||
2202 | */ | ||
2203 | return -EINVAL; | ||
2204 | } | ||
2205 | |||
2190 | want_console = nr; | 2206 | want_console = nr; |
2191 | schedule_console_callback(); | 2207 | schedule_console_callback(); |
2208 | |||
2209 | return 0; | ||
2192 | } | 2210 | } |
2193 | 2211 | ||
2194 | struct tty_driver *console_driver; | 2212 | struct tty_driver *console_driver; |
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 3a5d301e783b..1fa2da8f4fbe 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/kbd_diacr.h> | 34 | #include <linux/kbd_diacr.h> |
35 | #include <linux/selection.h> | 35 | #include <linux/selection.h> |
36 | 36 | ||
37 | static char vt_dont_switch; | 37 | char vt_dont_switch; |
38 | extern struct tty_driver *console_driver; | 38 | extern struct tty_driver *console_driver; |
39 | 39 | ||
40 | #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) | 40 | #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) |
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index 06c58c423fe1..506ad20c18f8 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h | |||
@@ -75,7 +75,7 @@ extern int do_poke_blanked_console; | |||
75 | 75 | ||
76 | extern void (*kbd_ledfunc)(unsigned int led); | 76 | extern void (*kbd_ledfunc)(unsigned int led); |
77 | 77 | ||
78 | extern void set_console(int nr); | 78 | extern int set_console(int nr); |
79 | extern void schedule_console_callback(void); | 79 | extern void schedule_console_callback(void); |
80 | 80 | ||
81 | static inline void set_leds(void) | 81 | static inline void set_leds(void) |
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 37a1a41f5b65..e0db669998f3 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h | |||
@@ -83,6 +83,7 @@ void reset_vc(struct vc_data *vc); | |||
83 | #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) | 83 | #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) |
84 | extern char con_buf[CON_BUF_SIZE]; | 84 | extern char con_buf[CON_BUF_SIZE]; |
85 | extern struct semaphore con_buf_sem; | 85 | extern struct semaphore con_buf_sem; |
86 | extern char vt_dont_switch; | ||
86 | 87 | ||
87 | struct vt_spawn_console { | 88 | struct vt_spawn_console { |
88 | spinlock_t lock; | 89 | spinlock_t lock; |
diff --git a/kernel/power/console.c b/kernel/power/console.c index 623786d44159..89bcf4973ee5 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c | |||
@@ -27,7 +27,15 @@ int pm_prepare_console(void) | |||
27 | return 1; | 27 | return 1; |
28 | } | 28 | } |
29 | 29 | ||
30 | set_console(SUSPEND_CONSOLE); | 30 | if (set_console(SUSPEND_CONSOLE)) { |
31 | /* | ||
32 | * We're unable to switch to the SUSPEND_CONSOLE. | ||
33 | * Let the calling function know so it can decide | ||
34 | * what to do. | ||
35 | */ | ||
36 | release_console_sem(); | ||
37 | return 1; | ||
38 | } | ||
31 | release_console_sem(); | 39 | release_console_sem(); |
32 | 40 | ||
33 | if (vt_waitactive(SUSPEND_CONSOLE)) { | 41 | if (vt_waitactive(SUSPEND_CONSOLE)) { |