aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/console.h1
-rw-r--r--kernel/printk.c50
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
91struct console 92struct 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. */
459static 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 }
599out: 615
600 preempt_enable(); 616 preempt_enable();
601 return printed_len; 617 return printed_len;
602} 618}