diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 35185392173f..37dff3429adb 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -782,7 +782,7 @@ static inline int can_use_console(unsigned int cpu) | |||
782 | static int console_trylock_for_printk(unsigned int cpu) | 782 | static int console_trylock_for_printk(unsigned int cpu) |
783 | __releases(&logbuf_lock) | 783 | __releases(&logbuf_lock) |
784 | { | 784 | { |
785 | int retval = 0; | 785 | int retval = 0, wake = 0; |
786 | 786 | ||
787 | if (console_trylock()) { | 787 | if (console_trylock()) { |
788 | retval = 1; | 788 | retval = 1; |
@@ -795,12 +795,14 @@ static int console_trylock_for_printk(unsigned int cpu) | |||
795 | */ | 795 | */ |
796 | if (!can_use_console(cpu)) { | 796 | if (!can_use_console(cpu)) { |
797 | console_locked = 0; | 797 | console_locked = 0; |
798 | up(&console_sem); | 798 | wake = 1; |
799 | retval = 0; | 799 | retval = 0; |
800 | } | 800 | } |
801 | } | 801 | } |
802 | printk_cpu = UINT_MAX; | 802 | printk_cpu = UINT_MAX; |
803 | spin_unlock(&logbuf_lock); | 803 | spin_unlock(&logbuf_lock); |
804 | if (wake) | ||
805 | up(&console_sem); | ||
804 | return retval; | 806 | return retval; |
805 | } | 807 | } |
806 | static const char recursion_bug_msg [] = | 808 | static const char recursion_bug_msg [] = |
@@ -1242,7 +1244,7 @@ void console_unlock(void) | |||
1242 | { | 1244 | { |
1243 | unsigned long flags; | 1245 | unsigned long flags; |
1244 | unsigned _con_start, _log_end; | 1246 | unsigned _con_start, _log_end; |
1245 | unsigned wake_klogd = 0; | 1247 | unsigned wake_klogd = 0, retry = 0; |
1246 | 1248 | ||
1247 | if (console_suspended) { | 1249 | if (console_suspended) { |
1248 | up(&console_sem); | 1250 | up(&console_sem); |
@@ -1251,6 +1253,7 @@ void console_unlock(void) | |||
1251 | 1253 | ||
1252 | console_may_schedule = 0; | 1254 | console_may_schedule = 0; |
1253 | 1255 | ||
1256 | again: | ||
1254 | for ( ; ; ) { | 1257 | for ( ; ; ) { |
1255 | spin_lock_irqsave(&logbuf_lock, flags); | 1258 | spin_lock_irqsave(&logbuf_lock, flags); |
1256 | wake_klogd |= log_start - log_end; | 1259 | wake_klogd |= log_start - log_end; |
@@ -1271,8 +1274,23 @@ void console_unlock(void) | |||
1271 | if (unlikely(exclusive_console)) | 1274 | if (unlikely(exclusive_console)) |
1272 | exclusive_console = NULL; | 1275 | exclusive_console = NULL; |
1273 | 1276 | ||
1277 | spin_unlock(&logbuf_lock); | ||
1278 | |||
1274 | up(&console_sem); | 1279 | up(&console_sem); |
1280 | |||
1281 | /* | ||
1282 | * Someone could have filled up the buffer again, so re-check if there's | ||
1283 | * something to flush. In case we cannot trylock the console_sem again, | ||
1284 | * there's a new owner and the console_unlock() from them will do the | ||
1285 | * flush, no worries. | ||
1286 | */ | ||
1287 | spin_lock(&logbuf_lock); | ||
1288 | if (con_start != log_end) | ||
1289 | retry = 1; | ||
1275 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1290 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1291 | if (retry && console_trylock()) | ||
1292 | goto again; | ||
1293 | |||
1276 | if (wake_klogd) | 1294 | if (wake_klogd) |
1277 | wake_up_klogd(); | 1295 | wake_up_klogd(); |
1278 | } | 1296 | } |