diff options
-rw-r--r-- | include/linux/console.h | 1 | ||||
-rw-r--r-- | kernel/printk.c | 50 |
2 files changed, 34 insertions, 17 deletions
diff --git a/include/linux/console.h b/include/linux/console.h index 08734e660d41..d0f8a8009490 100644 --- a/include/linux/console.h +++ b/include/linux/console.h | |||
@@ -87,6 +87,7 @@ void give_up_console(const struct consw *sw); | |||
87 | #define CON_CONSDEV (2) /* Last on the command line */ | 87 | #define CON_CONSDEV (2) /* Last on the command line */ |
88 | #define CON_ENABLED (4) | 88 | #define CON_ENABLED (4) |
89 | #define CON_BOOT (8) | 89 | #define CON_BOOT (8) |
90 | #define CON_ANYTIME (16) /* Safe to call when cpu is offline */ | ||
90 | 91 | ||
91 | struct console | 92 | struct console |
92 | { | 93 | { |
diff --git a/kernel/printk.c b/kernel/printk.c index 19a955619294..6b89dd9d11b6 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -327,7 +327,9 @@ static void __call_console_drivers(unsigned long start, unsigned long end) | |||
327 | struct console *con; | 327 | struct console *con; |
328 | 328 | ||
329 | for (con = console_drivers; con; con = con->next) { | 329 | for (con = console_drivers; con; con = con->next) { |
330 | if ((con->flags & CON_ENABLED) && con->write) | 330 | if ((con->flags & CON_ENABLED) && con->write && |
331 | (cpu_online(smp_processor_id()) || | ||
332 | (con->flags & CON_ANYTIME))) | ||
331 | con->write(con, &LOG_BUF(start), end - start); | 333 | con->write(con, &LOG_BUF(start), end - start); |
332 | } | 334 | } |
333 | } | 335 | } |
@@ -453,6 +455,18 @@ __attribute__((weak)) unsigned long long printk_clock(void) | |||
453 | return sched_clock(); | 455 | return sched_clock(); |
454 | } | 456 | } |
455 | 457 | ||
458 | /* Check if we have any console registered that can be called early in boot. */ | ||
459 | static int have_callable_console(void) | ||
460 | { | ||
461 | struct console *con; | ||
462 | |||
463 | for (con = console_drivers; con; con = con->next) | ||
464 | if (con->flags & CON_ANYTIME) | ||
465 | return 1; | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
456 | /** | 470 | /** |
457 | * printk - print a kernel message | 471 | * printk - print a kernel message |
458 | * @fmt: format string | 472 | * @fmt: format string |
@@ -566,27 +580,29 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
566 | log_level_unknown = 1; | 580 | log_level_unknown = 1; |
567 | } | 581 | } |
568 | 582 | ||
569 | if (!cpu_online(smp_processor_id())) { | 583 | if (!down_trylock(&console_sem)) { |
570 | /* | 584 | /* |
571 | * Some console drivers may assume that per-cpu resources have | 585 | * We own the drivers. We can drop the spinlock and |
572 | * been allocated. So don't allow them to be called by this | 586 | * let release_console_sem() print the text, maybe ... |
573 | * CPU until it is officially up. We shouldn't be calling into | ||
574 | * random console drivers on a CPU which doesn't exist yet.. | ||
575 | */ | 587 | */ |
588 | console_locked = 1; | ||
576 | printk_cpu = UINT_MAX; | 589 | printk_cpu = UINT_MAX; |
577 | spin_unlock_irqrestore(&logbuf_lock, flags); | 590 | spin_unlock_irqrestore(&logbuf_lock, flags); |
578 | goto out; | 591 | |
579 | } | ||
580 | if (!down_trylock(&console_sem)) { | ||
581 | console_locked = 1; | ||
582 | /* | 592 | /* |
583 | * We own the drivers. We can drop the spinlock and let | 593 | * Console drivers may assume that per-cpu resources have |
584 | * release_console_sem() print the text | 594 | * been allocated. So unless they're explicitly marked as |
595 | * being able to cope (CON_ANYTIME) don't call them until | ||
596 | * this CPU is officially up. | ||
585 | */ | 597 | */ |
586 | printk_cpu = UINT_MAX; | 598 | if (cpu_online(smp_processor_id()) || have_callable_console()) { |
587 | spin_unlock_irqrestore(&logbuf_lock, flags); | 599 | console_may_schedule = 0; |
588 | console_may_schedule = 0; | 600 | release_console_sem(); |
589 | release_console_sem(); | 601 | } else { |
602 | /* Release by hand to avoid flushing the buffer. */ | ||
603 | console_locked = 0; | ||
604 | up(&console_sem); | ||
605 | } | ||
590 | } else { | 606 | } else { |
591 | /* | 607 | /* |
592 | * Someone else owns the drivers. We drop the spinlock, which | 608 | * Someone else owns the drivers. We drop the spinlock, which |
@@ -596,7 +612,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
596 | printk_cpu = UINT_MAX; | 612 | printk_cpu = UINT_MAX; |
597 | spin_unlock_irqrestore(&logbuf_lock, flags); | 613 | spin_unlock_irqrestore(&logbuf_lock, flags); |
598 | } | 614 | } |
599 | out: | 615 | |
600 | preempt_enable(); | 616 | preempt_enable(); |
601 | return printed_len; | 617 | return printed_len; |
602 | } | 618 | } |