History

PM: Fix suspend_console and resume_console to use only one semaphore

This fixes a race where a thread acquires the console while the console is suspended, and the console is resumed before this thread releases it. In this case, the secondary console semaphore would be left locked, and the primary semaphore would be released twice. This in turn would cause the console switch on suspend or resume to hang forever. Note that suspend_console does not actually lock the console for clients that use acquire_console_sem, it only locks it for clients that use try_acquire_console_sem. If we change suspend_console to fully lock the console, then the kernel may deadlock on suspend. One client of try_acquire_console_sem is acquire_console_semaphore_for_printk, which uses it to prevent printk from using the console while it is suspended.

Arve Hjønnevåg committed 17 years ago

Commit 403f3071 parent b090f9f1 file · +9 −6Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/printk.c+9−6
@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress); · 72 unmodified lines
7373 * driver system.
7474 */
7575 static DECLARE_MUTEX(console_sem);
76−static DECLARE_MUTEX(secondary_console_sem);
7776 struct console *console_drivers;
7877 EXPORT_SYMBOL_GPL(console_drivers);
7978
@@ -891,12 +890,14 @@ void suspend_console(void) · 811 unmodified lines
891890 printk("Suspending console(s) (use no_console_suspend to debug)\n");
892891 acquire_console_sem();
893892 console_suspended = 1;
893+ up(&console_sem);
894894 }
895895
896896 void resume_console(void)
897897 {
898898 if (!console_suspend_enabled)
899899 return;
900+ down(&console_sem);
900901 console_suspended = 0;
901902 release_console_sem();
902903 }
@@ -912,11 +913,9 @@ void resume_console(void) · 9 unmodified lines
912913 void acquire_console_sem(void)
913914 {
914915 BUG_ON(in_interrupt());
915− if (console_suspended) {
916− down(&secondary_console_sem);
917− return;
918− }
919916 down(&console_sem);
917+ if (console_suspended)
918+ return;
920919 console_locked = 1;
921920 console_may_schedule = 1;
922921 }
@@ -926,6 +925,10 @@ int try_acquire_console_sem(void) · 3 unmodified lines
926925 {
927926 if (down_trylock(&console_sem))
928927 return -1;
928+ if (console_suspended) {
929+ up(&console_sem);
930+ return -1;
931+ }
929932 console_locked = 1;
930933 console_may_schedule = 0;
931934 return 0;
@@ -979,7 +982,7 @@ void release_console_sem(void) · 47 unmodified lines
979982 unsigned wake_klogd = 0;
980983
981984 if (console_suspended) {
982− up(&secondary_console_sem);
985+ up(&console_sem);
983986 return;
984987 }
985988