[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200927161130.33172-1-zhouchengming@bytedance.com>
Date: Mon, 28 Sep 2020 00:11:29 +0800
From: Chengming Zhou <zhouchengming@...edance.com>
To: linux-kernel@...r.kernel.org, pmladek@...e.com,
sergey.senozhatsky@...il.com, rostedt@...dmis.org,
mingo@...hat.com, peterz@...radead.org, juri.lelli@...hat.com,
vincent.guittot@...aro.org, dietmar.eggemann@....com,
bsegall@...gle.com, mgorman@...e.de
Cc: zhouchengming@...edance.com, songmuchun@...edance.com
Subject: [PATCH 1/2] printk: Add printk_deferred_{enter, exit}
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 <zhouchengming@...edance.com>
Signed-off-by: MuChun Song <songmuchun@...edance.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
Powered by blists - more mailing lists