diff options
Diffstat (limited to 'kernel/printk')
-rw-r--r-- | kernel/printk/printk.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index ced2b84b1cb7..f7b723f98cb9 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1807,6 +1807,30 @@ asmlinkage int printk_emit(int facility, int level, } EXPORT_SYMBOL(printk_emit); +int vprintk_default(const char *fmt, va_list args) +{ + int r; + +#ifdef CONFIG_KGDB_KDB + if (unlikely(kdb_trap_printk)) { + r = vkdb_printf(fmt, args); + return r; + } +#endif + r = vprintk_emit(0, -1, NULL, 0, fmt, args); + + return r; +} +EXPORT_SYMBOL_GPL(vprintk_default); + +/* + * This allows printk to be diverted to another function per cpu. + * This is useful for calling printk functions from within NMI + * without worrying about race conditions that can lock up the + * box. + */ +DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default; + /** * printk - print a kernel message * @fmt: format string @@ -1830,19 +1854,15 @@ EXPORT_SYMBOL(printk_emit); */ asmlinkage __visible int printk(const char *fmt, ...) { + printk_func_t vprintk_func; va_list args; int r; -#ifdef CONFIG_KGDB_KDB - if (unlikely(kdb_trap_printk)) { - va_start(args, fmt); - r = vkdb_printf(fmt, args); - va_end(args); - return r; - } -#endif va_start(args, fmt); - r = vprintk_emit(0, -1, NULL, 0, fmt, args); + preempt_disable(); + vprintk_func = this_cpu_read(printk_func); + r = vprintk_func(fmt, args); + preempt_enable(); va_end(args); return r; |