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

Unified · Split

kernel/printk.c+9−6
@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress); · 72 unmodified lines
73 * driver system.73 * driver system.
74 */74 */
75static DECLARE_MUTEX(console_sem);75static DECLARE_MUTEX(console_sem);
76static DECLARE_MUTEX(secondary_console_sem);
77struct console *console_drivers;76struct console *console_drivers;
78EXPORT_SYMBOL_GPL(console_drivers);77EXPORT_SYMBOL_GPL(console_drivers);
79 78
@@ -891,12 +890,14 @@ void suspend_console(void) · 811 unmodified lines
891 printk("Suspending console(s) (use no_console_suspend to debug)\n");890 printk("Suspending console(s) (use no_console_suspend to debug)\n");
892 acquire_console_sem();891 acquire_console_sem();
893 console_suspended = 1;892 console_suspended = 1;
893 up(&console_sem);
894}894}
895 895
896void resume_console(void)896void resume_console(void)
897{897{
898 if (!console_suspend_enabled)898 if (!console_suspend_enabled)
899 return;899 return;
900 down(&console_sem);
900 console_suspended = 0;901 console_suspended = 0;
901 release_console_sem();902 release_console_sem();
902}903}
@@ -912,11 +913,9 @@ void resume_console(void) · 9 unmodified lines
912void acquire_console_sem(void)913void acquire_console_sem(void)
913{914{
914 BUG_ON(in_interrupt());915 BUG_ON(in_interrupt());
915 if (console_suspended) {
916 down(&secondary_console_sem);
917 return;
918 }
919 down(&console_sem);916 down(&console_sem);
917 if (console_suspended)
918 return;
920 console_locked = 1;919 console_locked = 1;
921 console_may_schedule = 1;920 console_may_schedule = 1;
922}921}
@@ -926,6 +925,10 @@ int try_acquire_console_sem(void) · 3 unmodified lines
926{925{
927 if (down_trylock(&console_sem))926 if (down_trylock(&console_sem))
928 return -1;927 return -1;
928 if (console_suspended) {
929 up(&console_sem);
930 return -1;
931 }
929 console_locked = 1;932 console_locked = 1;
930 console_may_schedule = 0;933 console_may_schedule = 0;
931 return 0;934 return 0;
@@ -979,7 +982,7 @@ void release_console_sem(void) · 47 unmodified lines
979 unsigned wake_klogd = 0;982 unsigned wake_klogd = 0;
980 983
981 if (console_suspended) {984 if (console_suspended) {
982 up(&secondary_console_sem);985 up(&console_sem);
983 return;986 return;
984 }987 }
985 988