Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

printk: Avoid false positive lockdep report for legacy printing

Legacy console printing from printk() caller context may invoke
the console driver from atomic context. This leads to a lockdep
splat because the console driver will acquire a sleeping lock
and the caller may already hold a spinning lock. This is noticed
by lockdep on !PREEMPT_RT configurations because it will lead to
a problem on PREEMPT_RT.

However, on PREEMPT_RT the printing path from atomic context is
always avoided and the console driver is always invoked from a
dedicated thread. Thus the lockdep splat on !PREEMPT_RT is a
false positive.

For !PREEMPT_RT override the lock-context before invoking the
console driver to avoid the false positive.

Do not override the lock-context for PREEMPT_RT in order to
allow lockdep to catch any real locking context issues related
to the write callback usage.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240904120536.115780-18-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>

authored by

John Ogness and committed by
Petr Mladek
daeed159 1529bbb6

+64 -21
+64 -21
kernel/printk/printk.c
··· 2982 2982 } 2983 2983 2984 2984 /* 2985 + * Legacy console printing from printk() caller context does not respect 2986 + * raw_spinlock/spinlock nesting. For !PREEMPT_RT the lockdep warning is a 2987 + * false positive. For PREEMPT_RT the false positive condition does not 2988 + * occur. 2989 + * 2990 + * This map is used to temporarily establish LD_WAIT_SLEEP context for the 2991 + * console write() callback when legacy printing to avoid false positive 2992 + * lockdep complaints, thus allowing lockdep to continue to function for 2993 + * real issues. 2994 + */ 2995 + #ifdef CONFIG_PREEMPT_RT 2996 + static inline void printk_legacy_allow_spinlock_enter(void) { } 2997 + static inline void printk_legacy_allow_spinlock_exit(void) { } 2998 + #else 2999 + static DEFINE_WAIT_OVERRIDE_MAP(printk_legacy_map, LD_WAIT_SLEEP); 3000 + 3001 + static inline void printk_legacy_allow_spinlock_enter(void) 3002 + { 3003 + lock_map_acquire_try(&printk_legacy_map); 3004 + } 3005 + 3006 + static inline void printk_legacy_allow_spinlock_exit(void) 3007 + { 3008 + lock_map_release(&printk_legacy_map); 3009 + } 3010 + #endif /* CONFIG_PREEMPT_RT */ 3011 + 3012 + /* 2985 3013 * Used as the printk buffers for non-panic, serialized console printing. 2986 3014 * This is for legacy (!CON_NBCON) as well as all boot (CON_BOOT) consoles. 2987 3015 * Its usage requires the console_lock held. ··· 3058 3030 con->dropped = 0; 3059 3031 } 3060 3032 3061 - /* 3062 - * While actively printing out messages, if another printk() 3063 - * were to occur on another CPU, it may wait for this one to 3064 - * finish. This task can not be preempted if there is a 3065 - * waiter waiting to take over. 3066 - * 3067 - * Interrupts are disabled because the hand over to a waiter 3068 - * must not be interrupted until the hand over is completed 3069 - * (@console_waiter is cleared). 3070 - */ 3071 - printk_safe_enter_irqsave(flags); 3072 - console_lock_spinning_enable(); 3073 - 3074 - /* Do not trace print latency. */ 3075 - stop_critical_timings(); 3076 - 3077 3033 /* Write everything out to the hardware. */ 3078 - con->write(con, outbuf, pmsg.outbuf_len); 3079 3034 3080 - start_critical_timings(); 3035 + if (force_legacy_kthread() && !panic_in_progress()) { 3036 + /* 3037 + * With forced threading this function is in a task context 3038 + * (either legacy kthread or get_init_console_seq()). There 3039 + * is no need for concern about printk reentrance, handovers, 3040 + * or lockdep complaints. 3041 + */ 3081 3042 3082 - con->seq = pmsg.seq + 1; 3043 + con->write(con, outbuf, pmsg.outbuf_len); 3044 + con->seq = pmsg.seq + 1; 3045 + } else { 3046 + /* 3047 + * While actively printing out messages, if another printk() 3048 + * were to occur on another CPU, it may wait for this one to 3049 + * finish. This task can not be preempted if there is a 3050 + * waiter waiting to take over. 3051 + * 3052 + * Interrupts are disabled because the hand over to a waiter 3053 + * must not be interrupted until the hand over is completed 3054 + * (@console_waiter is cleared). 3055 + */ 3056 + printk_safe_enter_irqsave(flags); 3057 + console_lock_spinning_enable(); 3083 3058 3084 - *handover = console_lock_spinning_disable_and_check(cookie); 3085 - printk_safe_exit_irqrestore(flags); 3059 + /* Do not trace print latency. */ 3060 + stop_critical_timings(); 3061 + 3062 + printk_legacy_allow_spinlock_enter(); 3063 + con->write(con, outbuf, pmsg.outbuf_len); 3064 + printk_legacy_allow_spinlock_exit(); 3065 + 3066 + start_critical_timings(); 3067 + 3068 + con->seq = pmsg.seq + 1; 3069 + 3070 + *handover = console_lock_spinning_disable_and_check(cookie); 3071 + printk_safe_exit_irqrestore(flags); 3072 + } 3086 3073 skip: 3087 3074 return true; 3088 3075 }