Skip to content

Commit daeed15

Browse files
jognesspmladek
authored andcommitted
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>
1 parent 1529bbb commit daeed15

File tree

1 file changed

+63
-20
lines changed

1 file changed

+63
-20
lines changed

kernel/printk/printk.c

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2981,6 +2981,34 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
29812981
return true;
29822982
}
29832983

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+
29843012
/*
29853013
* Used as the printk buffers for non-panic, serialized console printing.
29863014
* This is for legacy (!CON_NBCON) as well as all boot (CON_BOOT) consoles.
@@ -3030,31 +3058,46 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
30303058
con->dropped = 0;
30313059
}
30323060

3033-
/*
3034-
* While actively printing out messages, if another printk()
3035-
* were to occur on another CPU, it may wait for this one to
3036-
* finish. This task can not be preempted if there is a
3037-
* waiter waiting to take over.
3038-
*
3039-
* Interrupts are disabled because the hand over to a waiter
3040-
* must not be interrupted until the hand over is completed
3041-
* (@console_waiter is cleared).
3042-
*/
3043-
printk_safe_enter_irqsave(flags);
3044-
console_lock_spinning_enable();
3061+
/* Write everything out to the hardware. */
30453062

3046-
/* Do not trace print latency. */
3047-
stop_critical_timings();
3063+
if (force_legacy_kthread() && !panic_in_progress()) {
3064+
/*
3065+
* With forced threading this function is in a task context
3066+
* (either legacy kthread or get_init_console_seq()). There
3067+
* is no need for concern about printk reentrance, handovers,
3068+
* or lockdep complaints.
3069+
*/
30483070

3049-
/* Write everything out to the hardware. */
3050-
con->write(con, outbuf, pmsg.outbuf_len);
3071+
con->write(con, outbuf, pmsg.outbuf_len);
3072+
con->seq = pmsg.seq + 1;
3073+
} else {
3074+
/*
3075+
* While actively printing out messages, if another printk()
3076+
* were to occur on another CPU, it may wait for this one to
3077+
* finish. This task can not be preempted if there is a
3078+
* waiter waiting to take over.
3079+
*
3080+
* Interrupts are disabled because the hand over to a waiter
3081+
* must not be interrupted until the hand over is completed
3082+
* (@console_waiter is cleared).
3083+
*/
3084+
printk_safe_enter_irqsave(flags);
3085+
console_lock_spinning_enable();
30513086

3052-
start_critical_timings();
3087+
/* Do not trace print latency. */
3088+
stop_critical_timings();
30533089

3054-
con->seq = pmsg.seq + 1;
3090+
printk_legacy_allow_spinlock_enter();
3091+
con->write(con, outbuf, pmsg.outbuf_len);
3092+
printk_legacy_allow_spinlock_exit();
30553093

3056-
*handover = console_lock_spinning_disable_and_check(cookie);
3057-
printk_safe_exit_irqrestore(flags);
3094+
start_critical_timings();
3095+
3096+
con->seq = pmsg.seq + 1;
3097+
3098+
*handover = console_lock_spinning_disable_and_check(cookie);
3099+
printk_safe_exit_irqrestore(flags);
3100+
}
30583101
skip:
30593102
return true;
30603103
}

0 commit comments

Comments
 (0)