Skip to content

Commit afdc34a

Browse files
committed
printk: Add per_cpu printk func to allow printk to be diverted
Being able to divert printk to call another function besides the normal logging is useful for such things like NMI handling. If some functions are to be called from NMI that does printk() it is possible to lock up the box if the nmi handler triggers when another printk is happening. One example of this use is to perform a stack trace on all CPUs via NMI. But if the NMI is to do the printk() it can cause the system to lock up. By allowing the printk to be diverted to another function that can safely record the printk output and then print it when it in a safe context then NMIs will be safe to call these functions like show_regs(). Link: http://lkml.kernel.org/p/[email protected] Tested-by: Jiri Kosina <[email protected]> Acked-by: Jiri Kosina <[email protected]> Acked-by: Paul E. McKenney <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Steven Rostedt <[email protected]>
1 parent 8d58e99 commit afdc34a

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed

include/linux/percpu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,7 @@ extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
134134
(typeof(type) __percpu *)__alloc_percpu(sizeof(type), \
135135
__alignof__(type))
136136

137+
/* To avoid include hell, as printk can not declare this, we declare it here */
138+
DECLARE_PER_CPU(printk_func_t, printk_func);
139+
137140
#endif /* __LINUX_PERCPU_H */

include/linux/printk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ extern int kptr_restrict;
162162

163163
extern void wake_up_klogd(void);
164164

165+
typedef int(*printk_func_t)(const char *fmt, va_list args);
166+
165167
void log_buf_kexec_setup(void);
166168
void __init setup_log_buf(int early);
167169
void dump_stack_set_arch_desc(const char *fmt, ...);

kernel/printk/printk.c

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,30 @@ asmlinkage int printk_emit(int facility, int level,
18071807
}
18081808
EXPORT_SYMBOL(printk_emit);
18091809

1810+
int vprintk_default(const char *fmt, va_list args)
1811+
{
1812+
int r;
1813+
1814+
#ifdef CONFIG_KGDB_KDB
1815+
if (unlikely(kdb_trap_printk)) {
1816+
r = vkdb_printf(fmt, args);
1817+
return r;
1818+
}
1819+
#endif
1820+
r = vprintk_emit(0, -1, NULL, 0, fmt, args);
1821+
1822+
return r;
1823+
}
1824+
EXPORT_SYMBOL_GPL(vprintk_default);
1825+
1826+
/*
1827+
* This allows printk to be diverted to another function per cpu.
1828+
* This is useful for calling printk functions from within NMI
1829+
* without worrying about race conditions that can lock up the
1830+
* box.
1831+
*/
1832+
DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
1833+
18101834
/**
18111835
* printk - print a kernel message
18121836
* @fmt: format string
@@ -1830,19 +1854,15 @@ EXPORT_SYMBOL(printk_emit);
18301854
*/
18311855
asmlinkage __visible int printk(const char *fmt, ...)
18321856
{
1857+
printk_func_t vprintk_func;
18331858
va_list args;
18341859
int r;
18351860

1836-
#ifdef CONFIG_KGDB_KDB
1837-
if (unlikely(kdb_trap_printk)) {
1838-
va_start(args, fmt);
1839-
r = vkdb_printf(fmt, args);
1840-
va_end(args);
1841-
return r;
1842-
}
1843-
#endif
18441861
va_start(args, fmt);
1845-
r = vprintk_emit(0, -1, NULL, 0, fmt, args);
1862+
preempt_disable();
1863+
vprintk_func = this_cpu_read(printk_func);
1864+
r = vprintk_func(fmt, args);
1865+
preempt_enable();
18461866
va_end(args);
18471867

18481868
return r;

0 commit comments

Comments
 (0)