diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 83 |
1 files changed, 48 insertions, 35 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 9adc2a473e6e..c46a20a19a15 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -616,6 +616,40 @@ asmlinkage int printk(const char *fmt, ...) | |||
616 | /* cpu currently holding logbuf_lock */ | 616 | /* cpu currently holding logbuf_lock */ |
617 | static volatile unsigned int printk_cpu = UINT_MAX; | 617 | static volatile unsigned int printk_cpu = UINT_MAX; |
618 | 618 | ||
619 | /* | ||
620 | * Can we actually use the console at this time on this cpu? | ||
621 | * | ||
622 | * Console drivers may assume that per-cpu resources have | ||
623 | * been allocated. So unless they're explicitly marked as | ||
624 | * being able to cope (CON_ANYTIME) don't call them until | ||
625 | * this CPU is officially up. | ||
626 | */ | ||
627 | static inline int can_use_console(unsigned int cpu) | ||
628 | { | ||
629 | return cpu_online(cpu) || have_callable_console(); | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * Try to get console ownership to actually show the kernel | ||
634 | * messages from a 'printk'. Return true (and with the | ||
635 | * console_semaphore held, and 'console_locked' set) if it | ||
636 | * is successful, false otherwise. | ||
637 | * | ||
638 | * This gets called with the 'logbuf_lock' spinlock held and | ||
639 | * interrupts disabled. It should return with 'lockbuf_lock' | ||
640 | * released but interrupts still disabled. | ||
641 | */ | ||
642 | static int acquire_console_semaphore_for_printk(unsigned int cpu) | ||
643 | { | ||
644 | int retval = 0; | ||
645 | |||
646 | if (can_use_console(cpu)) | ||
647 | retval = !try_acquire_console_sem(); | ||
648 | printk_cpu = UINT_MAX; | ||
649 | spin_unlock(&logbuf_lock); | ||
650 | return retval; | ||
651 | } | ||
652 | |||
619 | const char printk_recursion_bug_msg [] = | 653 | const char printk_recursion_bug_msg [] = |
620 | KERN_CRIT "BUG: recent printk recursion!\n"; | 654 | KERN_CRIT "BUG: recent printk recursion!\n"; |
621 | static int printk_recursion_bug; | 655 | static int printk_recursion_bug; |
@@ -725,43 +759,22 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
725 | log_level_unknown = 1; | 759 | log_level_unknown = 1; |
726 | } | 760 | } |
727 | 761 | ||
728 | if (!down_trylock(&console_sem)) { | 762 | /* |
729 | /* | 763 | * Try to acquire and then immediately release the |
730 | * We own the drivers. We can drop the spinlock and | 764 | * console semaphore. The release will do all the |
731 | * let release_console_sem() print the text, maybe ... | 765 | * actual magic (print out buffers, wake up klogd, |
732 | */ | 766 | * etc). |
733 | console_locked = 1; | 767 | * |
734 | printk_cpu = UINT_MAX; | 768 | * The acquire_console_semaphore_for_printk() function |
735 | spin_unlock(&logbuf_lock); | 769 | * will release 'logbuf_lock' regardless of whether it |
770 | * actually gets the semaphore or not. | ||
771 | */ | ||
772 | if (acquire_console_semaphore_for_printk(this_cpu)) | ||
773 | release_console_sem(); | ||
736 | 774 | ||
737 | /* | 775 | lockdep_on(); |
738 | * Console drivers may assume that per-cpu resources have | ||
739 | * been allocated. So unless they're explicitly marked as | ||
740 | * being able to cope (CON_ANYTIME) don't call them until | ||
741 | * this CPU is officially up. | ||
742 | */ | ||
743 | if (cpu_online(smp_processor_id()) || have_callable_console()) { | ||
744 | console_may_schedule = 0; | ||
745 | release_console_sem(); | ||
746 | } else { | ||
747 | /* Release by hand to avoid flushing the buffer. */ | ||
748 | console_locked = 0; | ||
749 | up(&console_sem); | ||
750 | } | ||
751 | lockdep_on(); | ||
752 | raw_local_irq_restore(flags); | ||
753 | } else { | ||
754 | /* | ||
755 | * Someone else owns the drivers. We drop the spinlock, which | ||
756 | * allows the semaphore holder to proceed and to call the | ||
757 | * console drivers with the output which we just produced. | ||
758 | */ | ||
759 | printk_cpu = UINT_MAX; | ||
760 | spin_unlock(&logbuf_lock); | ||
761 | lockdep_on(); | ||
762 | out_restore_irqs: | 776 | out_restore_irqs: |
763 | raw_local_irq_restore(flags); | 777 | raw_local_irq_restore(flags); |
764 | } | ||
765 | 778 | ||
766 | preempt_enable(); | 779 | preempt_enable(); |
767 | return printed_len; | 780 | return printed_len; |