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 /* Context where printk messages are never suppressed */ 16 static atomic_t force_con; 17 18 void printk_force_console_enter(void) 19 { 20 atomic_inc(&force_con); 21 } 22 23 void printk_force_console_exit(void) 24 { 25 atomic_dec(&force_con); 26 } 27 28 bool is_printk_force_console(void) 29 { 30 return atomic_read(&force_con); 31 } 32 33 static DEFINE_PER_CPU(int, printk_context); 34 35 /* Can be preempted by NMI. */ 36 void __printk_safe_enter(void) 37 { 38 this_cpu_inc(printk_context); 39 } 40 41 /* Can be preempted by NMI. */ 42 void __printk_safe_exit(void) 43 { 44 this_cpu_dec(printk_context); 45 } 46 47 void __printk_deferred_enter(void) 48 { 49 cant_migrate(); 50 __printk_safe_enter(); 51 } 52 53 void __printk_deferred_exit(void) 54 { 55 cant_migrate(); 56 __printk_safe_exit(); 57 } 58 59 bool is_printk_legacy_deferred(void) 60 { 61 /* 62 * The per-CPU variable @printk_context can be read safely in any 63 * context. CPU migration is always disabled when set. 64 */ 65 return (force_legacy_kthread() || 66 this_cpu_read(printk_context) || 67 in_nmi()); 68 } 69 70 asmlinkage int vprintk(const char *fmt, va_list args) 71 { 72 #ifdef CONFIG_KGDB_KDB 73 /* Allow to pass printk() to kdb but avoid a recursion. */ 74 if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0)) 75 return vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args); 76 #endif 77 78 /* 79 * Use the main logbuf even in NMI. But avoid calling console 80 * drivers that might have their own locks. 81 */ 82 if (is_printk_legacy_deferred()) 83 return vprintk_deferred(fmt, args); 84 85 /* No obstacles. */ 86 return vprintk_default(fmt, args); 87 } 88 EXPORT_SYMBOL(vprintk); 89