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 printk_force_console_enter(void)18void printk_force_console_enter(void) 19 { 20 atomic_inc(&force_con); 21 } 22 printk_force_console_exit(void)23void printk_force_console_exit(void) 24 { 25 atomic_dec(&force_con); 26 } 27 is_printk_force_console(void)28bool 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. */ __printk_safe_enter(void)36void __printk_safe_enter(void) 37 { 38 this_cpu_inc(printk_context); 39 } 40 41 /* Can be preempted by NMI. */ __printk_safe_exit(void)42void __printk_safe_exit(void) 43 { 44 this_cpu_dec(printk_context); 45 } 46 __printk_deferred_enter(void)47void __printk_deferred_enter(void) 48 { 49 cant_migrate(); 50 __printk_safe_enter(); 51 } 52 __printk_deferred_exit(void)53void __printk_deferred_exit(void) 54 { 55 cant_migrate(); 56 __printk_safe_exit(); 57 } 58 is_printk_legacy_deferred(void)59bool 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 * A context holding the printk_cpu_sync must not spin waiting for 66 * another CPU. For legacy printing, it could be the console_lock 67 * or the port lock. 68 */ 69 return (force_legacy_kthread() || 70 this_cpu_read(printk_context) || 71 in_nmi() || 72 is_printk_cpu_sync_owner()); 73 } 74 vprintk(const char * fmt,va_list args)75asmlinkage int vprintk(const char *fmt, va_list args) 76 { 77 #ifdef CONFIG_KGDB_KDB 78 /* Allow to pass printk() to kdb but avoid a recursion. */ 79 if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0)) 80 return vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args); 81 #endif 82 return vprintk_default(fmt, args); 83 } 84 EXPORT_SYMBOL(vprintk); 85