• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * printk_safe.c - Safe printk for printk-deadlock-prone contexts
4  */
5 
6 #include <linux/preempt.h>
7 #include <linux/kdb.h>
8 #include <linux/smp.h>
9 #include <linux/cpumask.h>
10 #include <linux/printk.h>
11 #include <linux/kprobes.h>
12 
13 #include "internal.h"
14 
15 static DEFINE_PER_CPU(int, printk_context);
16 
17 /* Can be preempted by NMI. */
__printk_safe_enter(void)18 void __printk_safe_enter(void)
19 {
20 	this_cpu_inc(printk_context);
21 }
22 
23 /* Can be preempted by NMI. */
__printk_safe_exit(void)24 void __printk_safe_exit(void)
25 {
26 	this_cpu_dec(printk_context);
27 }
28 
__printk_deferred_enter(void)29 void __printk_deferred_enter(void)
30 {
31 	cant_migrate();
32 	__printk_safe_enter();
33 }
34 
__printk_deferred_exit(void)35 void __printk_deferred_exit(void)
36 {
37 	cant_migrate();
38 	__printk_safe_exit();
39 }
40 
is_printk_legacy_deferred(void)41 bool is_printk_legacy_deferred(void)
42 {
43 	/*
44 	 * The per-CPU variable @printk_context can be read safely in any
45 	 * context. CPU migration is always disabled when set.
46 	 *
47 	 * A context holding the printk_cpu_sync must not spin waiting for
48 	 * another CPU. For legacy printing, it could be the console_lock
49 	 * or the port lock.
50 	 */
51 	return (force_legacy_kthread() ||
52 		this_cpu_read(printk_context) ||
53 		in_nmi() ||
54 		is_printk_cpu_sync_owner());
55 }
56 
vprintk(const char * fmt,va_list args)57 asmlinkage int vprintk(const char *fmt, va_list args)
58 {
59 #ifdef CONFIG_KGDB_KDB
60 	/* Allow to pass printk() to kdb but avoid a recursion. */
61 	if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0))
62 		return vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args);
63 #endif
64 
65 	/*
66 	 * Use the main logbuf even in NMI. But avoid calling console
67 	 * drivers that might have their own locks.
68 	 */
69 	if (is_printk_legacy_deferred())
70 		return vprintk_deferred(fmt, args);
71 
72 	/* No obstacles. */
73 	return vprintk_default(fmt, args);
74 }
75 EXPORT_SYMBOL(vprintk);
76