We use printk_deferred in scheduler code when rq lock held because calling printk can cause deadlock. It's a nice solution but a little hard to use when we want to mark the printk_deferred danger areas. Currently, the use of WARN_ON or WARN_ON_ONCE in scheduler with rq lock held can cause deadlock when warn condition met. If we can mark the printk_deferred area when rq lock held using pintk_deferred_{enter, exit}, all console output in that area will be deferred.
Signed-off-by: Chengming Zhou <zhouchengm...@bytedance.com> Signed-off-by: MuChun Song <songmuc...@bytedance.com> --- include/linux/printk.h | 8 ++++++++ kernel/printk/internal.h | 3 ++- kernel/printk/printk_safe.c | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index 34c1a7be3e01..96ab252f529a 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -147,6 +147,14 @@ static inline __printf(1, 2) __cold void early_printk(const char *s, ...) { } #endif +#ifdef CONFIG_PRINTK +extern void printk_deferred_enter(void); +extern void printk_deferred_exit(void); +#else +static inline void printk_deferred_enter(void) { } +static inline void printk_deferred_exit(void) { } +#endif + #ifdef CONFIG_PRINTK_NMI extern void printk_nmi_enter(void); extern void printk_nmi_exit(void); diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 660f9a6bf73a..b2ede46b7460 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -6,7 +6,8 @@ #ifdef CONFIG_PRINTK -#define PRINTK_SAFE_CONTEXT_MASK 0x007ffffff +#define PRINTK_SAFE_CONTEXT_MASK 0x003ffffff +#define PRINTK_DEFERRED_CONTEXT_MASK 0x004000000 #define PRINTK_NMI_DIRECT_CONTEXT_MASK 0x008000000 #define PRINTK_NMI_CONTEXT_MASK 0xff0000000 diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index 50aeae770434..f77c6880f59f 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c @@ -335,6 +335,16 @@ static __printf(1, 0) int vprintk_nmi(const char *fmt, va_list args) #endif /* CONFIG_PRINTK_NMI */ +void printk_deferred_enter(void) +{ + __this_cpu_or(printk_context, PRINTK_DEFERRED_CONTEXT_MASK); +} + +void printk_deferred_exit(void) +{ + __this_cpu_and(printk_context, ~PRINTK_DEFERRED_CONTEXT_MASK); +} + /* * Lock-less printk(), to avoid deadlocks should the printk() recurse * into itself. It uses a per-CPU buffer to store the message, just like @@ -385,6 +395,14 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args) if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK) return vprintk_nmi(fmt, args); + if (this_cpu_read(printk_context) & PRINTK_DEFERRED_CONTEXT_MASK) { + int len; + + len = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); + defer_console_output(); + return len; + } + /* Use extra buffer to prevent a recursion deadlock in safe mode. */ if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) return vprintk_safe(fmt, args); -- 2.11.0