linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls
@ 2016-12-21 14:35 Sergey Senozhatsky
  2016-12-21 14:35 ` [PATCHv6 1/7] printk: use vprintk_func in vprintk() Sergey Senozhatsky
                   ` (6 more replies)
  0 siblings, 7 replies; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:35 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

Hello,

        This patch set extends a lock-less NMI per-cpu buffers idea to
handle recursive printk() calls. The basic mechanism is pretty much the
same -- at the beginning of a deadlock-prone section we switch to lock-less
printk callback, and return back to a default printk implementation at the
end; the messages are getting flushed to a logbuf buffer from a safer
context.

Deadlock scenarios that printk_safe can handle:

a) printk recursion from logbuf_lock spin_lock section in printk()
  printk()
    raw_spin_lock(&logbuf_lock);
    WARN_ON(1);
    raw_spin_unlock(&logbuf_lock);

b) printk from sem->lock spin_lock section
  printk()
    console_trylock()
      down_trylock()
        raw_spin_lock_irqsave(&sem->lock, flags);
        WARN_ON(1);
        raw_spin_unlock_irqrestore(&sem->lock, flags);

c) printk from logbuf_lock spin_lock section in console_unlock()
  printk()
    console_unlock()
      raw_spin_lock(&logbuf_lock);
      WARN_ON(1);
      raw_spin_unlock(&logbuf_lock);

d) printk from ->pi_lock from semaphore up
  printk()
    console_unlock()
      up()
        try_to_wake_up()
          raw_spin_lock_irqsave(&p->pi_lock, flags);
          WARN_ON(1);
          raw_spin_unlock_irqrestore(&p->pi_lock, flags);

e) printk from console_cont_flush() /*and down the call chain */
  printk()
    console_unlock()
      call_console_drivers()
       ...
          WARN_ON(1);

v6:
-- re-based
-- addressed Petr's review (added comments; moved lost accounting to seq buf)

v5:
-- some style clean-ups and renamings (Petr)
-- use deferred printk when flush nmi/safe messages (Petr)

v4:
-- addressed Steven's review points
-- use printk_safe in console_cont_flush()

v3: (review by Petr)
-- renamed to printk_safe
-- !NMI config build fix
-- report lost messages for both printk_sae and printk_nmi
-- dropped recursion reporting patch
-- etc.

v2:
-- fix build error on !NMI configs, reported by Fengguang
-- reworked the series based on Petr's feedback
-- added a new patch to drop zap_locks()

Sergey Senozhatsky (7):
  printk: use vprintk_func in vprintk()
  printk: rename nmi.c and exported api
  printk: introduce per-cpu safe_print seq buffer
  printk: always use deferred printk when flush printk_safe lines
  printk: report lost messages in printk safe/nmi contexts
  printk: use printk_safe buffers in printk
  printk: remove zap_locks() function

 arch/arm/kernel/smp.c                  |   4 +-
 include/linux/hardirq.h                |   4 +-
 include/linux/printk.h                 |  29 +++--
 init/Kconfig                           |  16 +--
 init/main.c                            |   2 +-
 kernel/kexec_core.c                    |   2 +-
 kernel/panic.c                         |   4 +-
 kernel/printk/Makefile                 |   2 +-
 kernel/printk/internal.h               |  63 +++++-----
 kernel/printk/printk.c                 | 116 +++++-------------
 kernel/printk/{nmi.c => printk_safe.c} | 216 +++++++++++++++++++++++----------
 lib/nmi_backtrace.c                    |   2 +-
 12 files changed, 245 insertions(+), 215 deletions(-)
 rename kernel/printk/{nmi.c => printk_safe.c} (53%)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 1/7] printk: use vprintk_func in vprintk()
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
@ 2016-12-21 14:35 ` Sergey Senozhatsky
  2016-12-21 14:36 ` [PATCHv6 2/7] printk: rename nmi.c and exported api Sergey Senozhatsky
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:35 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

vprintk(), just like printk(), better be using per-cpu printk_func
instead of direct vprintk_emit() call. Just in case if vprintk()
will ever be called from NMI, or from any other context that can
deadlock in printk().

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e2cdd87e7a63..265e815730f9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1803,7 +1803,7 @@ EXPORT_SYMBOL(vprintk_emit);
 
 asmlinkage int vprintk(const char *fmt, va_list args)
 {
-	return vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
+	return vprintk_func(fmt, args);
 }
 EXPORT_SYMBOL(vprintk);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 2/7] printk: rename nmi.c and exported api
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
  2016-12-21 14:35 ` [PATCHv6 1/7] printk: use vprintk_func in vprintk() Sergey Senozhatsky
@ 2016-12-21 14:36 ` Sergey Senozhatsky
  2016-12-21 19:45   ` Linus Torvalds
  2016-12-21 14:36 ` [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer Sergey Senozhatsky
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

A preparation patch for printk_safe work. No functional change.
- rename nmi.c to print_safe.c
- rename exported functions to have a `printk_safe' prefix.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 arch/arm/kernel/smp.c                  |  4 +-
 include/linux/hardirq.h                |  4 +-
 include/linux/printk.h                 | 20 +++++-----
 init/Kconfig                           | 16 ++++----
 init/main.c                            |  2 +-
 kernel/kexec_core.c                    |  2 +-
 kernel/panic.c                         |  4 +-
 kernel/printk/Makefile                 |  2 +-
 kernel/printk/{nmi.c => printk_safe.c} | 72 +++++++++++++++++-----------------
 lib/nmi_backtrace.c                    |  2 +-
 10 files changed, 65 insertions(+), 63 deletions(-)
 rename kernel/printk/{nmi.c => printk_safe.c} (77%)

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 7dd14e8395e6..8b056e14158e 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -644,11 +644,11 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		break;
 
 	case IPI_CPU_BACKTRACE:
-		printk_nmi_enter();
+		printk_safe_nmi_enter();
 		irq_enter();
 		nmi_cpu_backtrace(regs);
 		irq_exit();
-		printk_nmi_exit();
+		printk_safe_nmi_exit();
 		break;
 
 	default:
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index c683996110b1..14840aafce3f 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -61,7 +61,7 @@ extern void irq_exit(void);
 
 #define nmi_enter()						\
 	do {							\
-		printk_nmi_enter();				\
+		printk_safe_nmi_enter();			\
 		lockdep_off();					\
 		ftrace_nmi_enter();				\
 		BUG_ON(in_nmi());				\
@@ -78,7 +78,7 @@ extern void irq_exit(void);
 		preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET);	\
 		ftrace_nmi_exit();				\
 		lockdep_on();					\
-		printk_nmi_exit();				\
+		printk_safe_nmi_exit();				\
 	} while (0)
 
 #endif /* LINUX_HARDIRQ_H */
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 3472cc6b7a60..67df41eca51c 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -147,17 +147,17 @@ void early_printk(const char *s, ...) { }
 #endif
 
 #ifdef CONFIG_PRINTK_NMI
-extern void printk_nmi_init(void);
-extern void printk_nmi_enter(void);
-extern void printk_nmi_exit(void);
-extern void printk_nmi_flush(void);
-extern void printk_nmi_flush_on_panic(void);
+extern void printk_safe_init(void);
+extern void printk_safe_nmi_enter(void);
+extern void printk_safe_nmi_exit(void);
+extern void printk_safe_flush(void);
+extern void printk_safe_flush_on_panic(void);
 #else
-static inline void printk_nmi_init(void) { }
-static inline void printk_nmi_enter(void) { }
-static inline void printk_nmi_exit(void) { }
-static inline void printk_nmi_flush(void) { }
-static inline void printk_nmi_flush_on_panic(void) { }
+static inline void printk_safe_init(void) { }
+static inline void printk_safe_nmi_enter(void) { }
+static inline void printk_safe_nmi_exit(void) { }
+static inline void printk_safe_flush(void) { }
+static inline void printk_safe_flush_on_panic(void) { }
 #endif /* PRINTK_NMI */
 
 #ifdef CONFIG_PRINTK
diff --git a/init/Kconfig b/init/Kconfig
index 223b734abccd..760b7d0bc9d7 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -875,17 +875,19 @@ config LOG_CPU_MAX_BUF_SHIFT
 		     13 =>   8 KB for each CPU
 		     12 =>   4 KB for each CPU
 
-config NMI_LOG_BUF_SHIFT
-	int "Temporary per-CPU NMI log buffer size (12 => 4KB, 13 => 8KB)"
+config PRINTK_SAFE_LOG_BUF_SHIFT
+	int "Temporary per-CPU printk log buffer size (12 => 4KB, 13 => 8KB)"
 	range 10 21
 	default 13
-	depends on PRINTK_NMI
+	depends on PRINTK
 	help
-	  Select the size of a per-CPU buffer where NMI messages are temporary
-	  stored. They are copied to the main log buffer in a safe context
-	  to avoid a deadlock. The value defines the size as a power of 2.
+	  Select the size of an alternate printk per-CPU buffer where messages
+	  printed from usafe contexts are temporary stored. One example would
+	  be NMI messages, another one - printk recursion. The messages are
+	  copied to the main log buffer in a safe context to avoid a deadlock.
+	  The value defines the size as a power of 2.
 
-	  NMI messages are rare and limited. The largest one is when
+	  Those messages are rare and limited. The largest one is when
 	  a backtrace is printed. It usually fits into 4KB. Select
 	  8KB if you want to be on the safe side.
 
diff --git a/init/main.c b/init/main.c
index b8f88013462d..b08305a7138c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -579,7 +579,7 @@ asmlinkage __visible void __init start_kernel(void)
 	timekeeping_init();
 	time_init();
 	sched_clock_postinit();
-	printk_nmi_init();
+	printk_safe_init();
 	perf_event_init();
 	profile_init();
 	call_function_init();
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 5617cc412444..14bb9eb76665 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -916,7 +916,7 @@ void crash_kexec(struct pt_regs *regs)
 	old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
 	if (old_cpu == PANIC_CPU_INVALID) {
 		/* This is the 1st CPU which comes here, so go ahead. */
-		printk_nmi_flush_on_panic();
+		printk_safe_flush_on_panic();
 		__crash_kexec(regs);
 
 		/*
diff --git a/kernel/panic.c b/kernel/panic.c
index c51edaa04fce..8c8efcd310e7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -188,7 +188,7 @@ void panic(const char *fmt, ...)
 	 * Bypass the panic_cpu check and call __crash_kexec directly.
 	 */
 	if (!_crash_kexec_post_notifiers) {
-		printk_nmi_flush_on_panic();
+		printk_safe_flush_on_panic();
 		__crash_kexec(NULL);
 
 		/*
@@ -213,7 +213,7 @@ void panic(const char *fmt, ...)
 	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
 
 	/* Call flush even twice. It tries harder with a single online CPU */
-	printk_nmi_flush_on_panic();
+	printk_safe_flush_on_panic();
 	kmsg_dump(KMSG_DUMP_PANIC);
 
 	/*
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
index abb0042a427b..607928119f26 100644
--- a/kernel/printk/Makefile
+++ b/kernel/printk/Makefile
@@ -1,3 +1,3 @@
 obj-y	= printk.o
-obj-$(CONFIG_PRINTK_NMI)		+= nmi.o
+obj-$(CONFIG_PRINTK_NMI)		+= printk_safe.o
 obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)	+= braille.o
diff --git a/kernel/printk/nmi.c b/kernel/printk/printk_safe.c
similarity index 77%
rename from kernel/printk/nmi.c
rename to kernel/printk/printk_safe.c
index f011aaef583c..09e5552f5b58 100644
--- a/kernel/printk/nmi.c
+++ b/kernel/printk/printk_safe.c
@@ -1,5 +1,5 @@
 /*
- * nmi.c - Safe printk in NMI context
+ * printk_safe.c - Safe printk in NMI context
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -39,18 +39,18 @@
  * were handled or when IRQs are blocked.
  */
 DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
-static int printk_nmi_irq_ready;
+static int printk_safe_irq_ready;
 atomic_t nmi_message_lost;
 
-#define NMI_LOG_BUF_LEN ((1 << CONFIG_NMI_LOG_BUF_SHIFT) -		\
+#define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -	\
 			 sizeof(atomic_t) - sizeof(struct irq_work))
 
-struct nmi_seq_buf {
+struct printk_safe_seq_buf {
 	atomic_t		len;	/* length of written data */
 	struct irq_work		work;	/* IRQ work that flushes the buffer */
-	unsigned char		buffer[NMI_LOG_BUF_LEN];
+	unsigned char		buffer[SAFE_LOG_BUF_LEN];
 };
-static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq);
+static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
 
 /*
  * Safe printk() for NMI context. It uses a per-CPU buffer to
@@ -58,9 +58,9 @@ static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq);
  * one writer running. But the buffer might get flushed from another
  * CPU, so we need to be careful.
  */
-static int vprintk_nmi(const char *fmt, va_list args)
+static int vprintk_safe_nmi(const char *fmt, va_list args)
 {
-	struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
+	struct printk_safe_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
 	int add = 0;
 	size_t len;
 
@@ -91,7 +91,7 @@ static int vprintk_nmi(const char *fmt, va_list args)
 		goto again;
 
 	/* Get flushed in a more safe context. */
-	if (add && printk_nmi_irq_ready) {
+	if (add && printk_safe_irq_ready) {
 		/* Make sure that IRQ work is really initialized. */
 		smp_rmb();
 		irq_work_queue(&s->work);
@@ -100,7 +100,7 @@ static int vprintk_nmi(const char *fmt, va_list args)
 	return add;
 }
 
-static void printk_nmi_flush_line(const char *text, int len)
+static void printk_safe_flush_line(const char *text, int len)
 {
 	/*
 	 * The buffers are flushed in NMI only on panic.  The messages must
@@ -111,11 +111,10 @@ static void printk_nmi_flush_line(const char *text, int len)
 		printk_deferred("%.*s", len, text);
 	else
 		printk("%.*s", len, text);
-
 }
 
 /* printk part of the temporary buffer line by line */
-static int printk_nmi_flush_buffer(const char *start, size_t len)
+static int printk_safe_flush_buffer(const char *start, size_t len)
 {
 	const char *c, *end;
 	bool header;
@@ -127,7 +126,7 @@ static int printk_nmi_flush_buffer(const char *start, size_t len)
 	/* Print line by line. */
 	while (c < end) {
 		if (*c == '\n') {
-			printk_nmi_flush_line(start, c - start + 1);
+			printk_safe_flush_line(start, c - start + 1);
 			start = ++c;
 			header = true;
 			continue;
@@ -140,7 +139,7 @@ static int printk_nmi_flush_buffer(const char *start, size_t len)
 				continue;
 			}
 
-			printk_nmi_flush_line(start, c - start);
+			printk_safe_flush_line(start, c - start);
 			start = c++;
 			header = true;
 			continue;
@@ -154,8 +153,8 @@ static int printk_nmi_flush_buffer(const char *start, size_t len)
 	if (start < end && !header) {
 		static const char newline[] = KERN_CONT "\n";
 
-		printk_nmi_flush_line(start, end - start);
-		printk_nmi_flush_line(newline, strlen(newline));
+		printk_safe_flush_line(start, end - start);
+		printk_safe_flush_line(newline, strlen(newline));
 	}
 
 	return len;
@@ -165,11 +164,12 @@ static int printk_nmi_flush_buffer(const char *start, size_t len)
  * Flush data from the associated per_CPU buffer. The function
  * can be called either via IRQ work or independently.
  */
-static void __printk_nmi_flush(struct irq_work *work)
+static void __printk_safe_flush(struct irq_work *work)
 {
 	static raw_spinlock_t read_lock =
 		__RAW_SPIN_LOCK_INITIALIZER(read_lock);
-	struct nmi_seq_buf *s = container_of(work, struct nmi_seq_buf, work);
+	struct printk_safe_seq_buf *s =
+		container_of(work, struct printk_safe_seq_buf, work);
 	unsigned long flags;
 	size_t len;
 	int i;
@@ -194,9 +194,9 @@ static void __printk_nmi_flush(struct irq_work *work)
 	 * buffer size.
 	 */
 	if ((i && i >= len) || len > sizeof(s->buffer)) {
-		const char *msg = "printk_nmi_flush: internal error\n";
+		const char *msg = "printk_safe_flush: internal error\n";
 
-		printk_nmi_flush_line(msg, strlen(msg));
+		printk_safe_flush_line(msg, strlen(msg));
 		len = 0;
 	}
 
@@ -205,7 +205,7 @@ static void __printk_nmi_flush(struct irq_work *work)
 
 	/* Make sure that data has been written up to the @len */
 	smp_rmb();
-	i += printk_nmi_flush_buffer(s->buffer + i, len - i);
+	i += printk_safe_flush_buffer(s->buffer + i, len - i);
 
 	/*
 	 * Check that nothing has got added in the meantime and truncate
@@ -221,31 +221,31 @@ static void __printk_nmi_flush(struct irq_work *work)
 }
 
 /**
- * printk_nmi_flush - flush all per-cpu nmi buffers.
+ * printk_safe_flush - flush all per-cpu nmi buffers.
  *
  * The buffers are flushed automatically via IRQ work. This function
  * is useful only when someone wants to be sure that all buffers have
  * been flushed at some point.
  */
-void printk_nmi_flush(void)
+void printk_safe_flush(void)
 {
 	int cpu;
 
 	for_each_possible_cpu(cpu)
-		__printk_nmi_flush(&per_cpu(nmi_print_seq, cpu).work);
+		__printk_safe_flush(&per_cpu(nmi_print_seq, cpu).work);
 }
 
 /**
- * printk_nmi_flush_on_panic - flush all per-cpu nmi buffers when the system
+ * printk_safe_flush_on_panic - flush all per-cpu nmi buffers when the system
  *	goes down.
  *
- * Similar to printk_nmi_flush() but it can be called even in NMI context when
+ * Similar to printk_safe_flush() but it can be called even in NMI context when
  * the system goes down. It does the best effort to get NMI messages into
  * the main ring buffer.
  *
  * Note that it could try harder when there is only one CPU online.
  */
-void printk_nmi_flush_on_panic(void)
+void printk_safe_flush_on_panic(void)
 {
 	/*
 	 * Make sure that we could access the main ring buffer.
@@ -259,33 +259,33 @@ void printk_nmi_flush_on_panic(void)
 		raw_spin_lock_init(&logbuf_lock);
 	}
 
-	printk_nmi_flush();
+	printk_safe_flush();
 }
 
-void __init printk_nmi_init(void)
+void __init printk_safe_init(void)
 {
 	int cpu;
 
 	for_each_possible_cpu(cpu) {
-		struct nmi_seq_buf *s = &per_cpu(nmi_print_seq, cpu);
+		struct printk_safe_seq_buf *s = &per_cpu(nmi_print_seq, cpu);
 
-		init_irq_work(&s->work, __printk_nmi_flush);
+		init_irq_work(&s->work, __printk_safe_flush);
 	}
 
 	/* Make sure that IRQ works are initialized before enabling. */
 	smp_wmb();
-	printk_nmi_irq_ready = 1;
+	printk_safe_irq_ready = 1;
 
 	/* Flush pending messages that did not have scheduled IRQ works. */
-	printk_nmi_flush();
+	printk_safe_flush();
 }
 
-void printk_nmi_enter(void)
+void printk_safe_nmi_enter(void)
 {
-	this_cpu_write(printk_func, vprintk_nmi);
+	this_cpu_write(printk_func, vprintk_safe_nmi);
 }
 
-void printk_nmi_exit(void)
+void printk_safe_nmi_exit(void)
 {
 	this_cpu_write(printk_func, vprintk_default);
 }
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
index 75554754eadf..5f7999eacad5 100644
--- a/lib/nmi_backtrace.c
+++ b/lib/nmi_backtrace.c
@@ -77,7 +77,7 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
 	 * Force flush any remote buffers that might be stuck in IRQ context
 	 * and therefore could not run their irq_work.
 	 */
-	printk_nmi_flush();
+	printk_safe_flush();
 
 	clear_bit_unlock(0, &backtrace_flag);
 	put_cpu();
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
  2016-12-21 14:35 ` [PATCHv6 1/7] printk: use vprintk_func in vprintk() Sergey Senozhatsky
  2016-12-21 14:36 ` [PATCHv6 2/7] printk: rename nmi.c and exported api Sergey Senozhatsky
@ 2016-12-21 14:36 ` Sergey Senozhatsky
  2016-12-22  0:53   ` kbuild test robot
  2016-12-21 14:36 ` [PATCHv6 4/7] printk: always use deferred printk when flush printk_safe lines Sergey Senozhatsky
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

This patch extends the idea of NMI per-cpu buffers to regions
that may cause recursive printk() calls and possible deadlocks.
Namely, printk() can't handle printk calls from schedule code
or printk() calls from lock debugging code (spin_dump() for instance);
because those may be called with `sem->lock' already taken or any
other `critical' locks (p->pi_lock, etc.). An example of deadlock
can be

 vprintk_emit()
  console_unlock()
   up()                        << raw_spin_lock_irqsave(&sem->lock, flags);
    wake_up_process()
     try_to_wake_up()
      ttwu_queue()
       ttwu_activate()
        activate_task()
         enqueue_task()
          enqueue_task_fair()
           cfs_rq_of()
            task_of()
             WARN_ON_ONCE(!entity_is_task(se))
              vprintk_emit()
               console_trylock()
                down_trylock()
                 raw_spin_lock_irqsave(&sem->lock, flags)
                 ^^^^ deadlock

and some other cases.

Just like in NMI implementation, the solution uses a per-cpu
`printk_func' pointer to 'redirect' printk() calls to a 'safe'
callback, that store messages in a per-cpu buffer and flushes
them back to logbuf buffer later.

Usage example:

 printk()
  printk_safe_enter(flags)
  //
  //  any printk() call from here will endup in vprintk_safe(),
  //  that stores messages in a special per-CPU buffer.
  //
  printk_safe_exit(flags)

The 'redirection' mechanism, though, has been reworked, as suggested
by Petr Mladek. Instead of using a per-cpu @print_func callback we now
keep a per-cpu printk-context variable and call either default or nmi
vprintk function depending on its value. printk_nmi_entrer/exit and
printk_safe_enter/exit, thus, just set/celar corresponding bits in
printk-context functions.

The patch only adds printk_safe support, we don't use it yet.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
 include/linux/printk.h      |  21 +++++--
 kernel/printk/Makefile      |   2 +-
 kernel/printk/internal.h    |  56 +++++++++++--------
 kernel/printk/printk.c      |   3 -
 kernel/printk/printk_safe.c | 130 +++++++++++++++++++++++++++++++++++---------
 5 files changed, 153 insertions(+), 59 deletions(-)

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 67df41eca51c..f7d291cf61d9 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -147,17 +147,11 @@ void early_printk(const char *s, ...) { }
 #endif
 
 #ifdef CONFIG_PRINTK_NMI
-extern void printk_safe_init(void);
 extern void printk_safe_nmi_enter(void);
 extern void printk_safe_nmi_exit(void);
-extern void printk_safe_flush(void);
-extern void printk_safe_flush_on_panic(void);
 #else
-static inline void printk_safe_init(void) { }
 static inline void printk_safe_nmi_enter(void) { }
 static inline void printk_safe_nmi_exit(void) { }
-static inline void printk_safe_flush(void) { }
-static inline void printk_safe_flush_on_panic(void) { }
 #endif /* PRINTK_NMI */
 
 #ifdef CONFIG_PRINTK
@@ -209,6 +203,9 @@ void __init setup_log_buf(int early);
 __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
 void dump_stack_print_info(const char *log_lvl);
 void show_regs_print_info(const char *log_lvl);
+extern void printk_safe_init(void);
+extern void printk_safe_flush(void);
+extern void printk_safe_flush_on_panic(void);
 #else
 static inline __printf(1, 0)
 int vprintk(const char *s, va_list args)
@@ -268,6 +265,18 @@ static inline void dump_stack_print_info(const char *log_lvl)
 static inline void show_regs_print_info(const char *log_lvl)
 {
 }
+
+static inline void printk_safe_init(void)
+{
+}
+
+static inline void printk_safe_flush(void)
+{
+}
+
+static inline void printk_safe_flush_on_panic(void)
+{
+}
 #endif
 
 extern asmlinkage void dump_stack(void) __cold;
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
index 607928119f26..4a2ffc39eb95 100644
--- a/kernel/printk/Makefile
+++ b/kernel/printk/Makefile
@@ -1,3 +1,3 @@
 obj-y	= printk.o
-obj-$(CONFIG_PRINTK_NMI)		+= printk_safe.o
+obj-$(CONFIG_PRINTK)	+= printk_safe.o
 obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)	+= braille.o
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 7fd2838fa417..97cee4f482f4 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -16,26 +16,8 @@
  */
 #include <linux/percpu.h>
 
-typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args);
-
-int __printf(1, 0) vprintk_default(const char *fmt, va_list args);
-
 #ifdef CONFIG_PRINTK_NMI
 
-extern raw_spinlock_t logbuf_lock;
-
-/*
- * printk() could not take logbuf_lock in NMI context. Instead,
- * it temporary stores the strings into a per-CPU buffer.
- * The alternative implementation is chosen transparently
- * via per-CPU variable.
- */
-DECLARE_PER_CPU(printk_func_t, printk_func);
-static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
-{
-	return this_cpu_read(printk_func)(fmt, args);
-}
-
 extern atomic_t nmi_message_lost;
 static inline int get_nmi_message_lost(void)
 {
@@ -44,14 +26,42 @@ static inline int get_nmi_message_lost(void)
 
 #else /* CONFIG_PRINTK_NMI */
 
-static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
-{
-	return vprintk_default(fmt, args);
-}
-
 static inline int get_nmi_message_lost(void)
 {
 	return 0;
 }
 
 #endif /* CONFIG_PRINTK_NMI */
+
+#ifdef CONFIG_PRINTK
+
+#define PRINTK_SAFE_CONTEXT_MASK	0x7fffffff
+#define PRINTK_NMI_CONTEXT_MASK	0x80000000
+
+extern raw_spinlock_t logbuf_lock;
+
+__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
+__printf(1, 0) int vprintk_func(const char *fmt, va_list args);
+void __printk_safe_enter(void);
+void __printk_safe_exit(void);
+
+#define printk_safe_enter(flags)		\
+	do {					\
+		local_irq_save(flags);		\
+		__printk_safe_enter();		\
+	} while (0)
+
+#define printk_safe_exit(flags)		\
+	do {					\
+		__printk_safe_exit();		\
+		local_irq_restore(flags);	\
+	} while (0)
+
+#else
+
+__printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; }
+
+#define printk_safe_enter(f)	((void)(f))
+#define printk_safe_exit(f)	((void)(f))
+
+#endif /* CONFIG_PRINTK */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 265e815730f9..335b0fcb538e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1902,9 +1902,6 @@ static size_t msg_print_text(const struct printk_log *msg,
 			     bool syslog, char *buf, size_t size) { return 0; }
 static bool suppress_message_printing(int level) { return false; }
 
-/* Still needs to be defined for users */
-DEFINE_PER_CPU(printk_func_t, printk_func);
-
 #endif /* CONFIG_PRINTK */
 
 #ifdef CONFIG_EARLY_PRINTK
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 09e5552f5b58..a041927a127b 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -1,5 +1,5 @@
 /*
- * printk_safe.c - Safe printk in NMI context
+ * printk_safe.c - Safe printk for printk-deadlock-prone contexts
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -32,15 +32,14 @@
  * is later flushed into the main ring buffer via IRQ work.
  *
  * The alternative implementation is chosen transparently
- * via @printk_func per-CPU variable.
+ * by examinig current printk() context mask stored in @printk_context
+ * per-CPU variable.
  *
  * The implementation allows to flush the strings also from another CPU.
  * There are situations when we want to make sure that all buffers
  * were handled or when IRQs are blocked.
  */
-DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
 static int printk_safe_irq_ready;
-atomic_t nmi_message_lost;
 
 #define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -	\
 			 sizeof(atomic_t) - sizeof(struct irq_work))
@@ -50,18 +49,29 @@ struct printk_safe_seq_buf {
 	struct irq_work		work;	/* IRQ work that flushes the buffer */
 	unsigned char		buffer[SAFE_LOG_BUF_LEN];
 };
+
+static DEFINE_PER_CPU(struct printk_safe_seq_buf, safe_print_seq);
+static DEFINE_PER_CPU(int, printk_context);
+
+#ifdef CONFIG_PRINTK_NMI
 static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
+atomic_t nmi_message_lost;
+#endif
 
 /*
- * Safe printk() for NMI context. It uses a per-CPU buffer to
- * store the message. NMIs are not nested, so there is always only
- * one writer running. But the buffer might get flushed from another
- * CPU, so we need to be careful.
+ * Add a message to per-CPU context-dependent buffer. NMI and printk-safe
+ * have dedicated buffers, because otherwise printk-safe preempted by
+ * NMI-printk would have overwritten the NMI messages.
+ *
+ * The messages are fushed from irq work (of from panic()), possibly,
+ * from other CPU, concurrently with printk_safe_log_store(). Should this
+ * happen, printk_safe_log_store() will notice the buffer->len mismatch
+ * and repeat the write.
  */
-static int vprintk_safe_nmi(const char *fmt, va_list args)
+static int printk_safe_log_store(struct printk_safe_seq_buf *s,
+				 const char *fmt, va_list args)
 {
-	struct printk_safe_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
-	int add = 0;
+	int add;
 	size_t len;
 
 again:
@@ -74,8 +84,8 @@ static int vprintk_safe_nmi(const char *fmt, va_list args)
 	}
 
 	/*
-	 * Make sure that all old data have been read before the buffer was
-	 * reseted. This is not needed when we just append data.
+	 * Make sure that all old data have been read before the buffer
+	 * was reset. This is not needed when we just append data.
 	 */
 	if (!len)
 		smp_rmb();
@@ -161,7 +171,7 @@ static int printk_safe_flush_buffer(const char *start, size_t len)
 }
 
 /*
- * Flush data from the associated per_CPU buffer. The function
+ * Flush data from the associated per-CPU buffer. The function
  * can be called either via IRQ work or independently.
  */
 static void __printk_safe_flush(struct irq_work *work)
@@ -231,8 +241,12 @@ void printk_safe_flush(void)
 {
 	int cpu;
 
-	for_each_possible_cpu(cpu)
+	for_each_possible_cpu(cpu) {
+#ifdef CONFIG_PRINTK_NMI
 		__printk_safe_flush(&per_cpu(nmi_print_seq, cpu).work);
+#endif
+		__printk_safe_flush(&per_cpu(safe_print_seq, cpu).work);
+	}
 }
 
 /**
@@ -262,14 +276,88 @@ void printk_safe_flush_on_panic(void)
 	printk_safe_flush();
 }
 
+#ifdef CONFIG_PRINTK_NMI
+/*
+ * Safe printk() for NMI context. It uses a per-CPU buffer to
+ * store the message. NMIs are not nested, so there is always only
+ * one writer running. But the buffer might get flushed from another
+ * CPU, so we need to be careful.
+ */
+static int vprintk_safe_nmi(const char *fmt, va_list args)
+{
+	struct printk_safe_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
+
+	return printk_safe_log_store(s, fmt, args);
+}
+
+void printk_safe_nmi_enter(void)
+{
+	this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK);
+}
+
+void printk_safe_nmi_exit(void)
+{
+	this_cpu_and(printk_context, ~PRINTK_NMI_CONTEXT_MASK);
+}
+
+#else
+
+static int vprintk_safe_nmi(const char *fmt, va_list args)
+{
+	return 0;
+}
+
+#endif /* CONFIG_PRINTK_NMI */
+
+/*
+ * Lock-less printk(), to avoid deadlocks should the printk() recurse
+ * into itself. It uses a per-CPU buffer to store the message, just like
+ * NMI.
+ */
+static int vprintk_safe(const char *fmt, va_list args)
+{
+	struct printk_safe_seq_buf *s = this_cpu_ptr(&safe_print_seq);
+
+	return printk_safe_log_store(s, fmt, args);
+}
+
+/* Can be preempted by NMI. */
+void __printk_safe_enter(void)
+{
+	this_cpu_inc(printk_context);
+}
+
+/* Can be preempted by NMI. */
+void __printk_safe_exit(void)
+{
+	this_cpu_dec(printk_context);
+}
+
+__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
+{
+	if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK)
+		return vprintk_safe_nmi(fmt, args);
+
+	if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK)
+		return vprintk_safe(fmt, args);
+
+	return vprintk_default(fmt, args);
+}
+
 void __init printk_safe_init(void)
 {
 	int cpu;
 
 	for_each_possible_cpu(cpu) {
-		struct printk_safe_seq_buf *s = &per_cpu(nmi_print_seq, cpu);
+		struct printk_safe_seq_buf *s;
+
+		s = &per_cpu(safe_print_seq, cpu);
+		init_irq_work(&s->work, __printk_safe_flush);
 
+#ifdef CONFIG_PRINTK_NMI
+		s = &per_cpu(nmi_print_seq, cpu);
 		init_irq_work(&s->work, __printk_safe_flush);
+#endif
 	}
 
 	/* Make sure that IRQ works are initialized before enabling. */
@@ -279,13 +367,3 @@ void __init printk_safe_init(void)
 	/* Flush pending messages that did not have scheduled IRQ works. */
 	printk_safe_flush();
 }
-
-void printk_safe_nmi_enter(void)
-{
-	this_cpu_write(printk_func, vprintk_safe_nmi);
-}
-
-void printk_safe_nmi_exit(void)
-{
-	this_cpu_write(printk_func, vprintk_default);
-}
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 4/7] printk: always use deferred printk when flush printk_safe lines
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
                   ` (2 preceding siblings ...)
  2016-12-21 14:36 ` [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer Sergey Senozhatsky
@ 2016-12-21 14:36 ` Sergey Senozhatsky
  2016-12-21 14:36 ` [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts Sergey Senozhatsky
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

Always use printk_deferred() in printk_safe_flush_line().
Flushing can be done from NMI or printk_safe contexts (when
we are in panic), so we can't call console drivers, yet still
want to store the messages in the logbuf buffer. Therefore we
use a deferred printk version.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Suggested-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk_safe.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index a041927a127b..9e8ef6a2070c 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -113,14 +113,12 @@ static int printk_safe_log_store(struct printk_safe_seq_buf *s,
 static void printk_safe_flush_line(const char *text, int len)
 {
 	/*
-	 * The buffers are flushed in NMI only on panic.  The messages must
-	 * go only into the ring buffer at this stage.  Consoles will get
-	 * explicitly called later when a crashdump is not generated.
+	 * Avoid any console drivers calls from here, because we may be
+	 * in NMI or printk_safe context (when in panic). The messages
+	 * must go only into the ring buffer at this stage.  Consoles will
+	 * get explicitly called later when a crashdump is not generated.
 	 */
-	if (in_nmi())
-		printk_deferred("%.*s", len, text);
-	else
-		printk("%.*s", len, text);
+	printk_deferred("%.*s", len, text);
 }
 
 /* printk part of the temporary buffer line by line */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
                   ` (3 preceding siblings ...)
  2016-12-21 14:36 ` [PATCHv6 4/7] printk: always use deferred printk when flush printk_safe lines Sergey Senozhatsky
@ 2016-12-21 14:36 ` Sergey Senozhatsky
  2016-12-23 10:54   ` Petr Mladek
  2016-12-21 14:36 ` [PATCHv6 6/7] printk: use printk_safe buffers in printk Sergey Senozhatsky
  2016-12-21 14:36 ` [PATCHv6 7/7] printk: remove zap_locks() function Sergey Senozhatsky
  6 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

Account lost messages in pritk-safe and printk-safe-nmi
contexts and report those numbers during printk_safe_flush().

The patch also moves lost message counter to struct
`printk_safe_seq_buf' instead of having dedicated static
counters - this simplifies the code.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/internal.h    | 17 -----------------
 kernel/printk/printk.c      | 10 ----------
 kernel/printk/printk_safe.c | 18 +++++++++++++++---
 3 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 97cee4f482f4..d2456020120c 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -16,23 +16,6 @@
  */
 #include <linux/percpu.h>
 
-#ifdef CONFIG_PRINTK_NMI
-
-extern atomic_t nmi_message_lost;
-static inline int get_nmi_message_lost(void)
-{
-	return atomic_xchg(&nmi_message_lost, 0);
-}
-
-#else /* CONFIG_PRINTK_NMI */
-
-static inline int get_nmi_message_lost(void)
-{
-	return 0;
-}
-
-#endif /* CONFIG_PRINTK_NMI */
-
 #ifdef CONFIG_PRINTK
 
 #define PRINTK_SAFE_CONTEXT_MASK	0x7fffffff
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 335b0fcb538e..6ec61ae0d122 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1677,7 +1677,6 @@ asmlinkage int vprintk_emit(int facility, int level,
 	unsigned long flags;
 	int this_cpu;
 	int printed_len = 0;
-	int nmi_message_lost;
 	bool in_sched = false;
 	/* cpu currently holding logbuf_lock in this function */
 	static unsigned int logbuf_cpu = UINT_MAX;
@@ -1728,15 +1727,6 @@ asmlinkage int vprintk_emit(int facility, int level,
 					 strlen(recursion_msg));
 	}
 
-	nmi_message_lost = get_nmi_message_lost();
-	if (unlikely(nmi_message_lost)) {
-		text_len = scnprintf(textbuf, sizeof(textbuf),
-				     "BAD LUCK: lost %d message(s) from NMI context!",
-				     nmi_message_lost);
-		printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
-					 NULL, 0, textbuf, text_len);
-	}
-
 	/*
 	 * The printf needs to come first; we need the syslog
 	 * prefix which might be passed-in as a parameter.
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 9e8ef6a2070c..cd5160112374 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -42,10 +42,13 @@
 static int printk_safe_irq_ready;
 
 #define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -	\
-			 sizeof(atomic_t) - sizeof(struct irq_work))
+				sizeof(atomic_t) -			\
+				sizeof(atomic_t) -			\
+				sizeof(struct irq_work))
 
 struct printk_safe_seq_buf {
 	atomic_t		len;	/* length of written data */
+	atomic_t		message_lost;
 	struct irq_work		work;	/* IRQ work that flushes the buffer */
 	unsigned char		buffer[SAFE_LOG_BUF_LEN];
 };
@@ -55,7 +58,6 @@ static DEFINE_PER_CPU(int, printk_context);
 
 #ifdef CONFIG_PRINTK_NMI
 static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
-atomic_t nmi_message_lost;
 #endif
 
 /*
@@ -79,7 +81,7 @@ static int printk_safe_log_store(struct printk_safe_seq_buf *s,
 
 	/* The trailing '\0' is not counted into len. */
 	if (len >= sizeof(s->buffer) - 1) {
-		atomic_inc(&nmi_message_lost);
+		atomic_inc(&s->message_lost);
 		return 0;
 	}
 
@@ -168,6 +170,14 @@ static int printk_safe_flush_buffer(const char *start, size_t len)
 	return len;
 }
 
+static void report_message_lost(struct printk_safe_seq_buf *s)
+{
+	int lost = atomic_xchg(&s->message_lost, 0);
+
+	if (lost)
+		printk_deferred("Lost %d message(s)!\n", lost);
+}
+
 /*
  * Flush data from the associated per-CPU buffer. The function
  * can be called either via IRQ work or independently.
@@ -224,6 +234,8 @@ static void __printk_safe_flush(struct irq_work *work)
 	if (atomic_cmpxchg(&s->len, len, 0) != len)
 		goto more;
 
+	report_message_lost(s);
+
 out:
 	raw_spin_unlock_irqrestore(&read_lock, flags);
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 6/7] printk: use printk_safe buffers in printk
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
                   ` (4 preceding siblings ...)
  2016-12-21 14:36 ` [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts Sergey Senozhatsky
@ 2016-12-21 14:36 ` Sergey Senozhatsky
  2016-12-22  5:31   ` Sergey Senozhatsky
  2016-12-21 14:36 ` [PATCHv6 7/7] printk: remove zap_locks() function Sergey Senozhatsky
  6 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

Use printk_safe per-CPU buffers in printk recursion-prone blocks:
-- around logbuf_lock protected sections in vprintk_emit() and
   console_unlock()
-- around down_trylock_console_sem() and up_console_sem()

Note that this solution addresses deadlocks caused by printk()
recursive calls only. That is vprintk_emit() and console_unlock().

Another thing to note is that we now keep lockdep enabled in printk,
because we are protected against the printk recursion caused by lockdep
in vprintk_emit() by the printk-safe mechanism - we first switch to
per-CPU buffers and only then access the deadlock-prone locks.

Examples:

1) printk() from logbuf_lock spin_lock section

Assume the following code:
  printk()
    raw_spin_lock(&logbuf_lock);
    WARN_ON(1);
    raw_spin_unlock(&logbuf_lock);

which now produces:

 ------------[ cut here ]------------
 WARNING: CPU: 0 PID: 366 at kernel/printk/printk.c:1811 vprintk_emit+0x1cd/0x438
 CPU: 0 PID: 366 Comm: bash
 Call Trace:
  [<ffffffff81045658>] warn_slowpath_null+0x1d/0x1f
  [<ffffffff81091527>] vprintk_emit+0x1cd/0x438
  [<ffffffff810918fe>] vprintk_default+0x1d/0x1f
  [<ffffffff810fdf6a>] printk+0x48/0x50
  [..]
  [<ffffffff813caaaa>] entry_SYSCALL_64_fastpath+0x18/0xad
 ---[ end trace ]---

2) printk() from semaphore sem->lock spin_lock section

Assume the following code

  printk()
    console_trylock()
      down_trylock()
        raw_spin_lock_irqsave(&sem->lock, flags);
        WARN_ON(1);
        raw_spin_unlock_irqrestore(&sem->lock, flags);

which now produces:

 ------------[ cut here ]------------
 WARNING: CPU: 1 PID: 363 at kernel/locking/semaphore.c:141 down_trylock+0x3d/0x62
 CPU: 1 PID: 363 Comm: bash
 Call Trace:
  [<ffffffff81045658>] warn_slowpath_null+0x1d/0x1f
  [<ffffffff810838df>] down_trylock+0x3d/0x62
  [<ffffffff8109177e>] ? vprintk_emit+0x3f9/0x414
  [<ffffffff810905cb>] console_trylock+0x31/0xeb
  [<ffffffff8109177e>] vprintk_emit+0x3f9/0x414
  [<ffffffff81091905>] vprintk_default+0x1d/0x1f
  [<ffffffff810fdf71>] printk+0x48/0x50
  [..]
  [<ffffffff813caaaa>] entry_SYSCALL_64_fastpath+0x18/0xad
 ---[ end trace ]---

3) printk() from console_unlock()

Assume the following code:

  printk()
    console_unlock()
      raw_spin_lock(&logbuf_lock);
      WARN_ON(1);
      raw_spin_unlock(&logbuf_lock);

which now produces:

 ------------[ cut here ]------------
 WARNING: CPU: 1 PID: 329 at kernel/printk/printk.c:2384 console_unlock+0x12d/0x559
 CPU: 1 PID: 329 Comm: bash
 Call Trace:
  [<ffffffff8103d6ca>] warn_slowpath_null+0x18/0x1a
  [<ffffffff8107f917>] console_unlock+0x12d/0x559
  [<ffffffff810772c4>] ? trace_hardirqs_on_caller+0x16d/0x189
  [<ffffffff810772ed>] ? trace_hardirqs_on+0xd/0xf
  [<ffffffff810800a6>] vprintk_emit+0x363/0x374
  [<ffffffff81080219>] vprintk_default+0x18/0x1a
  [<ffffffff810c7f77>] printk+0x43/0x4b
  [..]
  [<ffffffff814c2d6a>] entry_SYSCALL_64_fastpath+0x18/0xad
 ---[ end trace ]---

4) printk() from try_to_wake_up()

Assume the following code:

  printk()
    console_unlock()
      up()
        try_to_wake_up()
          raw_spin_lock_irqsave(&p->pi_lock, flags);
          WARN_ON(1);
          raw_spin_unlock_irqrestore(&p->pi_lock, flags);

which now produces:

 ------------[ cut here ]------------
 WARNING: CPU: 3 PID: 363 at kernel/sched/core.c:2028 try_to_wake_up+0x7f/0x4f7
 CPU: 3 PID: 363 Comm: bash
 Call Trace:
  [<ffffffff81045658>] warn_slowpath_null+0x1d/0x1f
  [<ffffffff8106c8d0>] try_to_wake_up+0x7f/0x4f7
  [<ffffffff8106cd5d>] wake_up_process+0x15/0x17
  [<ffffffff813c82c6>] __up.isra.0+0x56/0x63
  [<ffffffff810839a3>] up+0x32/0x42
  [<ffffffff8108f624>] __up_console_sem+0x37/0x55
  [<ffffffff810910ff>] console_unlock+0x21e/0x4c2
  [<ffffffff810917bf>] vprintk_emit+0x41c/0x462
  [<ffffffff81091971>] vprintk_default+0x1d/0x1f
  [<ffffffff810fdfdd>] printk+0x48/0x50
  [..]
  [<ffffffff813cab2a>] entry_SYSCALL_64_fastpath+0x18/0xad
 ---[ end trace ]---

5) printk() from call_console_drivers()

Assume the following code:
  printk()
    console_unlock()
      call_console_drivers()
      ...
          WARN_ON(1);

which now produces:

 ------------[ cut here ]------------
 WARNING: CPU: 2 PID: 305 at kernel/printk/printk.c:1604 call_console_drivers+0x3a/0xb0
 CPU: 2 PID: 305 Comm: bash
 Call Trace:
  [<ffffffff810399c0>] warn_slowpath_null+0x18/0x1a
  [<ffffffff8106b218>] call_console_drivers.isra.6.constprop.16+0x3a/0xb0
  [<ffffffff8106cc46>] console_unlock+0x471/0x48e
  [<ffffffff8106ce57>] vprintk_emit+0x1f4/0x206
  [<ffffffff8106cfcb>] vprintk_default+0x18/0x1a
  [<ffffffff8106af66>] vprintk_func+0x6e/0x70
  [<ffffffff810abbe3>] printk+0x3e/0x46
[..]
  [<ffffffff8145a860>] entry_SYSCALL_64_fastpath+0x13/0x94
 ---[ end trace ]---

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 42 +++++++++++++++++++++++++++---------------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 6ec61ae0d122..c188219e596f 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -213,17 +213,31 @@ static int nr_ext_console_drivers;
 
 static int __down_trylock_console_sem(unsigned long ip)
 {
-	if (down_trylock(&console_sem))
+	int lock_failed;
+	unsigned long flags;
+
+	printk_safe_enter(flags);
+	lock_failed = down_trylock(&console_sem);
+	printk_safe_exit(flags);
+
+	if (lock_failed)
 		return 1;
 	mutex_acquire(&console_lock_dep_map, 0, 1, ip);
 	return 0;
 }
 #define down_trylock_console_sem() __down_trylock_console_sem(_RET_IP_)
 
-#define up_console_sem() do { \
-	mutex_release(&console_lock_dep_map, 1, _RET_IP_);\
-	up(&console_sem);\
-} while (0)
+static void __up_console_sem(unsigned long ip)
+{
+	unsigned long flags;
+
+	mutex_release(&console_lock_dep_map, 1, ip);
+
+	printk_safe_enter(flags);
+	up(&console_sem);
+	printk_safe_exit(flags);
+}
+#define up_console_sem() __up_console_sem(_RET_IP_)
 
 /*
  * This is used for debugging the mess that is the VT code by
@@ -1689,7 +1703,7 @@ asmlinkage int vprintk_emit(int facility, int level,
 	boot_delay_msec(level);
 	printk_delay();
 
-	local_irq_save(flags);
+	printk_safe_enter(flags);
 	this_cpu = smp_processor_id();
 
 	/*
@@ -1705,13 +1719,12 @@ asmlinkage int vprintk_emit(int facility, int level,
 		 */
 		if (!oops_in_progress && !lockdep_recursing(current)) {
 			recursion_bug = true;
-			local_irq_restore(flags);
+			printk_safe_exit(flags);
 			return 0;
 		}
 		zap_locks();
 	}
 
-	lockdep_off();
 	/* This stops the holder of console_sem just where we want him */
 	raw_spin_lock(&logbuf_lock);
 	logbuf_cpu = this_cpu;
@@ -1771,12 +1784,10 @@ asmlinkage int vprintk_emit(int facility, int level,
 
 	logbuf_cpu = UINT_MAX;
 	raw_spin_unlock(&logbuf_lock);
-	lockdep_on();
-	local_irq_restore(flags);
+	printk_safe_exit(flags);
 
 	/* If called from the scheduler, we can not call up(). */
 	if (!in_sched) {
-		lockdep_off();
 		/*
 		 * Try to acquire and then immediately release the console
 		 * semaphore.  The release will print out buffers and wake up
@@ -1784,7 +1795,6 @@ asmlinkage int vprintk_emit(int facility, int level,
 		 */
 		if (console_trylock())
 			console_unlock();
-		lockdep_on();
 	}
 
 	return printed_len;
@@ -2209,7 +2219,8 @@ void console_unlock(void)
 		size_t len;
 		int level;
 
-		raw_spin_lock_irqsave(&logbuf_lock, flags);
+		printk_safe_enter(flags);
+		raw_spin_lock(&logbuf_lock);
 		if (seen_seq != log_next_seq) {
 			wake_klogd = true;
 			seen_seq = log_next_seq;
@@ -2259,7 +2270,7 @@ void console_unlock(void)
 		stop_critical_timings();	/* don't trace print latency */
 		call_console_drivers(level, ext_text, ext_len, text, len);
 		start_critical_timings();
-		local_irq_restore(flags);
+		printk_safe_exit(flags);
 
 		if (do_cond_resched)
 			cond_resched();
@@ -2282,7 +2293,8 @@ void console_unlock(void)
 	 */
 	raw_spin_lock(&logbuf_lock);
 	retry = console_seq != log_next_seq;
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	raw_spin_unlock(&logbuf_lock);
+	printk_safe_exit(flags);
 
 	if (retry && console_trylock())
 		goto again;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv6 7/7] printk: remove zap_locks() function
  2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
                   ` (5 preceding siblings ...)
  2016-12-21 14:36 ` [PATCHv6 6/7] printk: use printk_safe buffers in printk Sergey Senozhatsky
@ 2016-12-21 14:36 ` Sergey Senozhatsky
  6 siblings, 0 replies; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-21 14:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky,
	Sergey Senozhatsky

We use printk-safe now which makes printk-recursion detection code
in vprintk_emit() unreachable. The tricky thing here is that, apart
from detecting and reporting printk recursions, that code also used
to zap_locks() in case of panic() from the same CPU. However,
zap_locks() does not look to be needed anymore:

1) Since commit 08d78658f393 ("panic: release stale console lock to
   always get the logbuf printed out") panic flushing of `logbuf' to
   console ignores the state of `console_sem' by doing
   	panic()
		console_trylock();
		console_unlock();

2) Since commit cf9b1106c81c ("printk/nmi: flush NMI messages on the
   system panic") panic attempts to zap the `logbuf_lock' spin_lock to
   successfully flush nmi messages to `logbuf'.

Basically, it seems that we either already do what zap_locks() used to
do but in other places or we ignore the state of the lock. The only
reaming difference is that we don't re-init the console semaphore in
printk_safe_flush_on_panic(), but this is not necessary because we
don't call console drivers from printk_safe_flush_on_panic() due to
the fact that we are using a deferred printk() version (as was
suggested by Petr Mladek).

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 61 --------------------------------------------------
 1 file changed, 61 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c188219e596f..128b4d2161fd 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1552,28 +1552,6 @@ static void call_console_drivers(int level,
 	}
 }
 
-/*
- * Zap console related locks when oopsing.
- * To leave time for slow consoles to print a full oops,
- * only zap at most once every 30 seconds.
- */
-static void zap_locks(void)
-{
-	static unsigned long oops_timestamp;
-
-	if (time_after_eq(jiffies, oops_timestamp) &&
-	    !time_after(jiffies, oops_timestamp + 30 * HZ))
-		return;
-
-	oops_timestamp = jiffies;
-
-	debug_locks_off();
-	/* If a crash is occurring, make sure we can't deadlock */
-	raw_spin_lock_init(&logbuf_lock);
-	/* And make sure that we print immediately */
-	sema_init(&console_sem, 1);
-}
-
 int printk_delay_msec __read_mostly;
 
 static inline void printk_delay(void)
@@ -1683,17 +1661,13 @@ asmlinkage int vprintk_emit(int facility, int level,
 			    const char *dict, size_t dictlen,
 			    const char *fmt, va_list args)
 {
-	static bool recursion_bug;
 	static char textbuf[LOG_LINE_MAX];
 	char *text = textbuf;
 	size_t text_len = 0;
 	enum log_flags lflags = 0;
 	unsigned long flags;
-	int this_cpu;
 	int printed_len = 0;
 	bool in_sched = false;
-	/* cpu currently holding logbuf_lock in this function */
-	static unsigned int logbuf_cpu = UINT_MAX;
 
 	if (level == LOGLEVEL_SCHED) {
 		level = LOGLEVEL_DEFAULT;
@@ -1704,42 +1678,8 @@ asmlinkage int vprintk_emit(int facility, int level,
 	printk_delay();
 
 	printk_safe_enter(flags);
-	this_cpu = smp_processor_id();
-
-	/*
-	 * Ouch, printk recursed into itself!
-	 */
-	if (unlikely(logbuf_cpu == this_cpu)) {
-		/*
-		 * If a crash is occurring during printk() on this CPU,
-		 * then try to get the crash message out but make sure
-		 * we can't deadlock. Otherwise just return to avoid the
-		 * recursion and return - but flag the recursion so that
-		 * it can be printed at the next appropriate moment:
-		 */
-		if (!oops_in_progress && !lockdep_recursing(current)) {
-			recursion_bug = true;
-			printk_safe_exit(flags);
-			return 0;
-		}
-		zap_locks();
-	}
-
 	/* This stops the holder of console_sem just where we want him */
 	raw_spin_lock(&logbuf_lock);
-	logbuf_cpu = this_cpu;
-
-	if (unlikely(recursion_bug)) {
-		static const char recursion_msg[] =
-			"BUG: recent printk recursion!";
-
-		recursion_bug = false;
-		/* emit KERN_CRIT message */
-		printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
-					 NULL, 0, recursion_msg,
-					 strlen(recursion_msg));
-	}
-
 	/*
 	 * The printf needs to come first; we need the syslog
 	 * prefix which might be passed-in as a parameter.
@@ -1782,7 +1722,6 @@ asmlinkage int vprintk_emit(int facility, int level,
 
 	printed_len += log_output(facility, level, lflags, dict, dictlen, text, text_len);
 
-	logbuf_cpu = UINT_MAX;
 	raw_spin_unlock(&logbuf_lock);
 	printk_safe_exit(flags);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 2/7] printk: rename nmi.c and exported api
  2016-12-21 14:36 ` [PATCHv6 2/7] printk: rename nmi.c and exported api Sergey Senozhatsky
@ 2016-12-21 19:45   ` Linus Torvalds
  2016-12-22  1:17     ` Sergey Senozhatsky
  0 siblings, 1 reply; 19+ messages in thread
From: Linus Torvalds @ 2016-12-21 19:45 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Andrew Morton, Petr Mladek, Jan Kara, Tejun Heo, Calvin Owens,
	Steven Rostedt, Ingo Molnar, Peter Zijlstra, Andy Lutomirski,
	Peter Hurley, Linux Kernel Mailing List, Sergey Senozhatsky

On Wed, Dec 21, 2016 at 6:36 AM, Sergey Senozhatsky
<sergey.senozhatsky@gmail.com> wrote:
> A preparation patch for printk_safe work. No functional change.
> - rename nmi.c to print_safe.c
> - rename exported functions to have a `printk_safe' prefix.

I dislike this patch.

It's _mostly_ ok, but the nmi naming is nasty.

Either "printk_nmi()" or "printk_safe" is fine, but doing *both* is
stupid and wrong. And you do both in a couple of places.

So please keep the printk_nmi_enter/exit() naming. Because
"printk_safe_nmi_enter/exit()" is just stupid.  It's about nmi entry.
The "safe" part is simply an implementation detail.

                Linus

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer
  2016-12-21 14:36 ` [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer Sergey Senozhatsky
@ 2016-12-22  0:53   ` kbuild test robot
  2016-12-22  1:18     ` Sergey Senozhatsky
  0 siblings, 1 reply; 19+ messages in thread
From: kbuild test robot @ 2016-12-22  0:53 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: kbuild-all, Andrew Morton, Petr Mladek, Jan Kara, Tejun Heo,
	Calvin Owens, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
	Andy Lutomirski, Linus Torvalds, Peter Hurley, linux-kernel,
	Sergey Senozhatsky, Sergey Senozhatsky

[-- Attachment #1: Type: text/plain, Size: 11567 bytes --]

Hi Sergey,

[auto build test ERROR on linus/master]
[also build test ERROR on next-20161221]
[cannot apply to v4.9]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Sergey-Senozhatsky/printk-use-vprintk_func-in-vprintk/20161222-075616
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

Note: the linux-review/Sergey-Senozhatsky/printk-use-vprintk_func-in-vprintk/20161222-075616 HEAD 43ffcdc67ed0e40d3cf6137a37fbe557bfee4fb7 builds fine.
      It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   In file included from arch/ia64/include/asm/intrinsics.h:10:0,
                    from arch/ia64/include/asm/bitops.h:18,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/list.h:8,
                    from include/linux/preempt.h:10,
                    from kernel/printk/printk_safe.c:18:
   kernel/printk/printk_safe.c: In function 'printk_safe_log_store':
>> kernel/printk/printk_safe.c:82:15: error: 'nmi_message_lost' undeclared (first use in this function)
      atomic_inc(&nmi_message_lost);
                  ^
   arch/ia64/include/uapi/asm/intrinsics.h:60:24: note: in definition of macro 'ia64_fetchadd'
     volatile __typeof__(*(v)) *_v = (v);      \
                           ^
>> arch/ia64/include/asm/atomic.h:75:5: note: in expansion of macro 'ia64_fetch_and_add'
      ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \
        ^~~~~~~~~~~~~~~~~~
>> arch/ia64/include/asm/atomic.h:316:33: note: in expansion of macro 'atomic_add_return'
    #define atomic_add(i,v)   (void)atomic_add_return((i), (v))
                                    ^~~~~~~~~~~~~~~~~
>> arch/ia64/include/asm/atomic.h:318:25: note: in expansion of macro 'atomic_add'
    #define atomic_inc(v)   atomic_add(1, (v))
                            ^~~~~~~~~~
>> kernel/printk/printk_safe.c:82:3: note: in expansion of macro 'atomic_inc'
      atomic_inc(&nmi_message_lost);
      ^~~~~~~~~~
   kernel/printk/printk_safe.c:82:15: note: each undeclared identifier is reported only once for each function it appears in
      atomic_inc(&nmi_message_lost);
                  ^
   arch/ia64/include/uapi/asm/intrinsics.h:60:24: note: in definition of macro 'ia64_fetchadd'
     volatile __typeof__(*(v)) *_v = (v);      \
                           ^
>> arch/ia64/include/asm/atomic.h:75:5: note: in expansion of macro 'ia64_fetch_and_add'
      ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \
        ^~~~~~~~~~~~~~~~~~
>> arch/ia64/include/asm/atomic.h:316:33: note: in expansion of macro 'atomic_add_return'
    #define atomic_add(i,v)   (void)atomic_add_return((i), (v))
                                    ^~~~~~~~~~~~~~~~~
>> arch/ia64/include/asm/atomic.h:318:25: note: in expansion of macro 'atomic_add'
    #define atomic_inc(v)   atomic_add(1, (v))
                            ^~~~~~~~~~
>> kernel/printk/printk_safe.c:82:3: note: in expansion of macro 'atomic_inc'
      atomic_inc(&nmi_message_lost);
      ^~~~~~~~~~

vim +/nmi_message_lost +82 kernel/printk/printk_safe.c

42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  12   * GNU General Public License for more details.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  13   *
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  14   * You should have received a copy of the GNU General Public License
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  15   * along with this program; if not, see <http://www.gnu.org/licenses/>.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  16   */
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  17  
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20 @18  #include <linux/preempt.h>
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  19  #include <linux/spinlock.h>
cf9b1106 kernel/printk/nmi.c         Petr Mladek        2016-05-20  20  #include <linux/debug_locks.h>
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  21  #include <linux/smp.h>
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  22  #include <linux/cpumask.h>
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  23  #include <linux/irq_work.h>
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  24  #include <linux/printk.h>
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  25  
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  26  #include "internal.h"
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  27  
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  28  /*
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  29   * printk() could not take logbuf_lock in NMI context. Instead,
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  30   * it uses an alternative implementation that temporary stores
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  31   * the strings into a per-CPU buffer. The content of the buffer
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  32   * is later flushed into the main ring buffer via IRQ work.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  33   *
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  34   * The alternative implementation is chosen transparently
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  35   * by examinig current printk() context mask stored in @printk_context
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  36   * per-CPU variable.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  37   *
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  38   * The implementation allows to flush the strings also from another CPU.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  39   * There are situations when we want to make sure that all buffers
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  40   * were handled or when IRQs are blocked.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  41   */
c178cb8a kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  42  static int printk_safe_irq_ready;
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  43  
c178cb8a kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  44  #define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -	\
427934b8 kernel/printk/nmi.c         Petr Mladek        2016-05-20  45  			 sizeof(atomic_t) - sizeof(struct irq_work))
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  46  
c178cb8a kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  47  struct printk_safe_seq_buf {
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  48  	atomic_t		len;	/* length of written data */
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  49  	struct irq_work		work;	/* IRQ work that flushes the buffer */
c178cb8a kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  50  	unsigned char		buffer[SAFE_LOG_BUF_LEN];
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  51  };
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  52  
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  53  static DEFINE_PER_CPU(struct printk_safe_seq_buf, safe_print_seq);
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  54  static DEFINE_PER_CPU(int, printk_context);
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  55  
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  56  #ifdef CONFIG_PRINTK_NMI
c178cb8a kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  57  static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  58  atomic_t nmi_message_lost;
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  59  #endif
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  60  
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  61  /*
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  62   * Add a message to per-CPU context-dependent buffer. NMI and printk-safe
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  63   * have dedicated buffers, because otherwise printk-safe preempted by
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  64   * NMI-printk would have overwritten the NMI messages.
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  65   *
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  66   * The messages are fushed from irq work (of from panic()), possibly,
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  67   * from other CPU, concurrently with printk_safe_log_store(). Should this
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  68   * happen, printk_safe_log_store() will notice the buffer->len mismatch
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  69   * and repeat the write.
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  70   */
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  71  static int printk_safe_log_store(struct printk_safe_seq_buf *s,
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  72  				 const char *fmt, va_list args)
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  73  {
927f128d kernel/printk/printk_safe.c Sergey Senozhatsky 2016-12-21  74  	int add;
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  75  	size_t len;
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  76  
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  77  again:
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  78  	len = atomic_read(&s->len);
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  79  
4a998e32 kernel/printk/nmi.c         Petr Mladek        2016-12-12  80  	/* The trailing '\0' is not counted into len. */
4a998e32 kernel/printk/nmi.c         Petr Mladek        2016-12-12  81  	if (len >= sizeof(s->buffer) - 1) {
b522deab kernel/printk/nmi.c         Petr Mladek        2016-05-20 @82  		atomic_inc(&nmi_message_lost);
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  83  		return 0;
b522deab kernel/printk/nmi.c         Petr Mladek        2016-05-20  84  	}
42a0bb3f kernel/printk/nmi.c         Petr Mladek        2016-05-20  85  

:::::: The code at line 82 was first introduced by commit
:::::: b522deabc6f18e4f938d93a84f345f2cbf3347d1 printk/nmi: warn when some message has been lost in NMI context

:::::: TO: Petr Mladek <pmladek@suse.com>
:::::: CC: Linus Torvalds <torvalds@linux-foundation.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 45847 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 2/7] printk: rename nmi.c and exported api
  2016-12-21 19:45   ` Linus Torvalds
@ 2016-12-22  1:17     ` Sergey Senozhatsky
  0 siblings, 0 replies; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-22  1:17 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Sergey Senozhatsky, Andrew Morton, Petr Mladek, Jan Kara,
	Tejun Heo, Calvin Owens, Steven Rostedt, Ingo Molnar,
	Peter Zijlstra, Andy Lutomirski, Peter Hurley,
	Linux Kernel Mailing List, Sergey Senozhatsky

On (12/21/16 11:45), Linus Torvalds wrote:
> On Wed, Dec 21, 2016 at 6:36 AM, Sergey Senozhatsky
> <sergey.senozhatsky@gmail.com> wrote:
> > A preparation patch for printk_safe work. No functional change.
> > - rename nmi.c to print_safe.c
> > - rename exported functions to have a `printk_safe' prefix.
> 
> I dislike this patch.
> 
> It's _mostly_ ok, but the nmi naming is nasty.

ok, will change. Petr complained about the nmi naming as well.

	-ss

> Either "printk_nmi()" or "printk_safe" is fine, but doing *both* is
> stupid and wrong. And you do both in a couple of places.
> 
> So please keep the printk_nmi_enter/exit() naming. Because
> "printk_safe_nmi_enter/exit()" is just stupid.  It's about nmi entry.
> The "safe" part is simply an implementation detail.
> 
>                 Linus
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer
  2016-12-22  0:53   ` kbuild test robot
@ 2016-12-22  1:18     ` Sergey Senozhatsky
  2016-12-22 16:36       ` Petr Mladek
  0 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-22  1:18 UTC (permalink / raw)
  To: kbuild test robot
  Cc: Sergey Senozhatsky, kbuild-all, Andrew Morton, Petr Mladek,
	Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt, Ingo Molnar,
	Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Peter Hurley,
	linux-kernel, Sergey Senozhatsky

On (12/22/16 08:53), kbuild test robot wrote:
> Hi Sergey,
> 
> [auto build test ERROR on linus/master]
> [also build test ERROR on next-20161221]
> [cannot apply to v4.9]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Sergey-Senozhatsky/printk-use-vprintk_func-in-vprintk/20161222-075616
> config: ia64-allmodconfig (attached as .config)
> compiler: ia64-linux-gcc (GCC) 6.2.0
> reproduce:
>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         make.cross ARCH=ia64 

last minute change...
thanks for the report.

	-ss

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 6/7] printk: use printk_safe buffers in printk
  2016-12-21 14:36 ` [PATCHv6 6/7] printk: use printk_safe buffers in printk Sergey Senozhatsky
@ 2016-12-22  5:31   ` Sergey Senozhatsky
  2016-12-22 17:10     ` Petr Mladek
  0 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-22  5:31 UTC (permalink / raw)
  To: Linus Torvalds, Petr Mladek
  Cc: Andrew Morton, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Peter Hurley,
	linux-kernel, Sergey Senozhatsky, Sergey Senozhatsky

Hello,

On (12/21/16 23:36), Sergey Senozhatsky wrote:
> Use printk_safe per-CPU buffers in printk recursion-prone blocks:
> -- around logbuf_lock protected sections in vprintk_emit() and
>    console_unlock()
> -- around down_trylock_console_sem() and up_console_sem()
> 
> Note that this solution addresses deadlocks caused by printk()
> recursive calls only. That is vprintk_emit() and console_unlock().

several questions.

so my plan was to introduce printk-safe and to switch vprintk_emit()
and console_sem related functions (like console_unlock(), etc.) to
printk-safe first. and switch the remaining logbuf_lock users, like
devkmsg_open()/syslog_print()/etc, in a followup, pretty much
mechanical "find logbuf_lock - add printk_safe", patch. but that
followup patch is bigger than I expected (still mechanical tho);
so I want to re-group.

there are
	9 raw_spin_lock_irq(&logbuf_lock)
	7 raw_spin_lock_irqsave(&logbuf_lock, flags)
and
	12 raw_spin_lock_irq(&logbuf_lock)
	8 raw_spin_unlock_irqrestore(&logbuf_lock, flags)

wrapping each one of them in printk_safe_enter()/printk_safe_enter_irq()
and printk_safe_exit()/printk_safe_exit_irq() is a bit boring. so I have
several options: one of them is to add printk_safe_{enter,exit}_irq() and,
along with it, a bunch of help macros (to printk.c):

(questions below)

/*
 * Helper macros to lock/unlock logbuf_lock in deadlock safe
 * manner (logbuf_lock may spin_dump() in lock/unlock).
 */
#define lock_logbuf(flags)			\
	do {					\
		printk_safe_enter(flags);	\
		raw_spin_lock(&logbuf_lock);	\
	} while (0)

#define unlock_logbuf(flags)			\
	do {					\
		raw_spin_unlock(&logbuf_lock);	\
		printk_safe_exit(flags);	\
	} while (0)

#define lock_logbuf_irq()			\
	do {					\
		printk_safe_enter_irq();	\
		raw_spin_lock(&logbuf_lock);	\
	} while (0)

#define unlock_logbuf_irq()			\
	do {					\
		raw_spin_unlock(&logbuf_lock);	\
		printk_safe_exit_irq();		\
	} while (0)


so this

	printk_safe_enter_irq();
	raw_spin_lock(&logbuf_lock);
	...
	raw_spin_unlock(&logbuf_lock);
	printk_safe_exit(flags);

or this

	printk_safe_enter_irq();
	raw_spin_lock(&logbuf_lock);
	...
	raw_spin_unlock(&logbuf_lock);
	printk_safe_exit_irq();


becomes this

	lock_logbuf(flags);
	...
	unlock_logbuf(flags);

and this

	lock_logbuf_irq();
	...
	unlock_logbuf_irq();


questions:

-- the approach
 another solution? switch those raw_spin_{lock,unlock}_irq to irqsave/irqrestore
 (?) and use the existing printk_safe_enter()/printk_safe_exit(),
 so *_irq() versions of lock_logbuf/printk_safe macros will not be needed?

-- the naming
 are lock_logbuf()/unlock_logbuf() and lock_logbuf_irq()/unlock_logbuf_irq()
 good enough? (if good at all)

	-ss

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer
  2016-12-22  1:18     ` Sergey Senozhatsky
@ 2016-12-22 16:36       ` Petr Mladek
  0 siblings, 0 replies; 19+ messages in thread
From: Petr Mladek @ 2016-12-22 16:36 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: kbuild test robot, Sergey Senozhatsky, kbuild-all, Andrew Morton,
	Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt, Ingo Molnar,
	Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Peter Hurley,
	linux-kernel

On Thu 2016-12-22 10:18:41, Sergey Senozhatsky wrote:
> On (12/22/16 08:53), kbuild test robot wrote:
> > Hi Sergey,
> > 
> > [auto build test ERROR on linus/master]
> > [also build test ERROR on next-20161221]
> > [cannot apply to v4.9]
> > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> > 
> > url:    https://github.com/0day-ci/linux/commits/Sergey-Senozhatsky/printk-use-vprintk_func-in-vprintk/20161222-075616
> > config: ia64-allmodconfig (attached as .config)
> > compiler: ia64-linux-gcc (GCC) 6.2.0
> > reproduce:
> >         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
> >         chmod +x ~/bin/make.cross
> >         # save the attached .config to linux build tree
> >         make.cross ARCH=ia64 
> 
> last minute change...
> thanks for the report.

I guess that it is caused by moving the error-handling change
into the 5th patch and solving it another way. I like this move.

The patch looks fine now except for the build error.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 6/7] printk: use printk_safe buffers in printk
  2016-12-22  5:31   ` Sergey Senozhatsky
@ 2016-12-22 17:10     ` Petr Mladek
  2016-12-23  1:46       ` Sergey Senozhatsky
  0 siblings, 1 reply; 19+ messages in thread
From: Petr Mladek @ 2016-12-22 17:10 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Linus Torvalds, Andrew Morton, Jan Kara, Tejun Heo, Calvin Owens,
	Steven Rostedt, Ingo Molnar, Peter Zijlstra, Andy Lutomirski,
	Peter Hurley, linux-kernel, Sergey Senozhatsky

On Thu 2016-12-22 14:31:19, Sergey Senozhatsky wrote:
> Hello,
> 
> On (12/21/16 23:36), Sergey Senozhatsky wrote:
> > Use printk_safe per-CPU buffers in printk recursion-prone blocks:
> > -- around logbuf_lock protected sections in vprintk_emit() and
> >    console_unlock()
> > -- around down_trylock_console_sem() and up_console_sem()
> > 
> > Note that this solution addresses deadlocks caused by printk()
> > recursive calls only. That is vprintk_emit() and console_unlock().
> 
> several questions.

Good questions!

> so my plan was to introduce printk-safe and to switch vprintk_emit()
> and console_sem related functions (like console_unlock(), etc.) to
> printk-safe first. and switch the remaining logbuf_lock users, like
> devkmsg_open()/syslog_print()/etc, in a followup, pretty much
> mechanical "find logbuf_lock - add printk_safe", patch. but that
> followup patch is bigger than I expected (still mechanical tho);
> so I want to re-group.
> 
> there are
> 	9 raw_spin_lock_irq(&logbuf_lock)
> 	7 raw_spin_lock_irqsave(&logbuf_lock, flags)
> and
> 	12 raw_spin_lock_irq(&logbuf_lock)
> 	8 raw_spin_unlock_irqrestore(&logbuf_lock, flags)

I see.

> wrapping each one of them in printk_safe_enter()/printk_safe_enter_irq()
> and printk_safe_exit()/printk_safe_exit_irq() is a bit boring. so I have
> several options: one of them is to add printk_safe_{enter,exit}_irq() and,
> along with it, a bunch of help macros (to printk.c):
> 
> (questions below)
> 
> /*
>  * Helper macros to lock/unlock logbuf_lock in deadlock safe
>  * manner (logbuf_lock may spin_dump() in lock/unlock).
>  */
> #define lock_logbuf(flags)			\
> 	do {					\
> 		printk_safe_enter(flags);	\
> 		raw_spin_lock(&logbuf_lock);	\
> 	} while (0)

There are many callers. I think that such wrappers make sense.
I would only like to keep naming scheme similar to the classic
locks. I mean:

printk_safe_enter_irq()
printk_safe_exit_irq()

printk_safe_enter_irqsave(flags)
printk_safe_exit_irqrestore(flags)

and

logbuf_lock_irq()
logbuf_unlock_irq()

logbuf_lock_irqsave(flags)
logbuf_lock_irqrestore(flags)

I actually like this change. It makes it clear that the operation
has a side effect (disables/enables irq) which was not visible
from the original name.


Well, I wonder how many times we need to call printk_save_enter/exit
standalone (ouside these macros).

The question is if we really need all the variants of
printk_safe_enter()/exit(). Alternative solution would be
to handle only the printk_context in pritnk_safe_enter()
and make sure that it is called with IRQs disabled.
I mean to define only __printk_safe_enter()/exit()
and do:

#define logbuf_lock_irqsave(flags)		\
	do {					\
		local_irq_save(flags)		\
		__printk_safe_enter();		\
		raw_spin_lock(&logbuf_lock);	\
	} while (0)


> -- the approach
>  another solution? switch those raw_spin_{lock,unlock}_irq to irqsave/irqrestore
>  (?) and use the existing printk_safe_enter()/printk_safe_exit(),
>  so *_irq() versions of lock_logbuf/printk_safe macros will not be needed?

This is bad idea. We should keep the information where the flags need
to be stored and where not. It helps to understand in which context
the function might be called.

Best Regards,
Petr

PS: I still think if we could come with a better name than
printk_safe() but I cannot find one.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 6/7] printk: use printk_safe buffers in printk
  2016-12-22 17:10     ` Petr Mladek
@ 2016-12-23  1:46       ` Sergey Senozhatsky
  2016-12-23  9:53         ` Petr Mladek
  0 siblings, 1 reply; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-23  1:46 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Linus Torvalds, Andrew Morton, Jan Kara,
	Tejun Heo, Calvin Owens, Steven Rostedt, Ingo Molnar,
	Peter Zijlstra, Andy Lutomirski, Peter Hurley, linux-kernel,
	Sergey Senozhatsky

On (12/22/16 18:10), Petr Mladek wrote:
...
> There are many callers. I think that such wrappers make sense.
> I would only like to keep naming scheme similar to the classic
> locks. I mean:
> 
> printk_safe_enter_irq()
> printk_safe_exit_irq()
> 
> printk_safe_enter_irqsave(flags)
> printk_safe_exit_irqrestore(flags)

sure.

> and
> 
> logbuf_lock_irq()
> logbuf_unlock_irq()
> 
> logbuf_lock_irqsave(flags)
> logbuf_lock_irqrestore(flags)

ok.

> I actually like this change. It makes it clear that the operation
> has a side effect (disables/enables irq) which was not visible
> from the original name.

agree.

> Well, I wonder how many times we need to call printk_save_enter/exit
> standalone (ouside these macros).

not every switch to printk_safe is "dictated" by logbuf_lock.
down_trylock_console_sem(), for instance, takes semaphore spin_lock
which already may be locked on the same CPU (*), so we need to be
in safe mode:

vprintk_emit()
 down_trylock()
  raw_spin_lock_irqsave(&sem->lock, flags);
  ...
  raw_spin_unlock_irqrestore(&sem->lock, flags);
   spin_dump()
    printk()
     vprintk_emit()
      down_trylock()
       raw_spin_lock_irqsave(&sem->lock, flags)   << deadlock


and so on. IOW, "printk_save_enter()" != "logbuf_lock is acquired".


> The question is if we really need all the variants of
> printk_safe_enter()/exit(). Alternative solution would be
> to handle only the printk_context in pritnk_safe_enter()
> and make sure that it is called with IRQs disabled.
> I mean to define only __printk_safe_enter()/exit()
> and do:
> 
> #define logbuf_lock_irqsave(flags)		\
> 	do {					\
> 		local_irq_save(flags)		\
> 		__printk_safe_enter();		\
> 		raw_spin_lock(&logbuf_lock);	\
> 	} while (0)

won't do the trick for console sem spin_lock.

[..]
> PS: I still think if we could come with a better name than
> printk_safe() but I cannot find one.

well, not that I'm the fan of printk_safe name, but can't think
of anything better. we make printk calls safe (deadlock safe) in
places where previously it was unsafe... quick-&-dirty name that
is implementation-specific -- printk_percpu_enter/exit, or
printk_pcpu_enter/exit... dunno.

	-ss

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 6/7] printk: use printk_safe buffers in printk
  2016-12-23  1:46       ` Sergey Senozhatsky
@ 2016-12-23  9:53         ` Petr Mladek
  0 siblings, 0 replies; 19+ messages in thread
From: Petr Mladek @ 2016-12-23  9:53 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Linus Torvalds, Andrew Morton, Jan Kara, Tejun Heo, Calvin Owens,
	Steven Rostedt, Ingo Molnar, Peter Zijlstra, Andy Lutomirski,
	Peter Hurley, linux-kernel, Sergey Senozhatsky

On Fri 2016-12-23 10:46:43, Sergey Senozhatsky wrote:
> not every switch to printk_safe is "dictated" by logbuf_lock.
> down_trylock_console_sem(), for instance, takes semaphore spin_lock
> which already may be locked on the same CPU (*), so we need to be
> in safe mode:
> 
> vprintk_emit()
>  down_trylock()
>   raw_spin_lock_irqsave(&sem->lock, flags);
>   ...
>   raw_spin_unlock_irqrestore(&sem->lock, flags);
>    spin_dump()
>     printk()
>      vprintk_emit()
>       down_trylock()
>        raw_spin_lock_irqsave(&sem->lock, flags)   << deadlock
> 
> 
> and so on. IOW, "printk_save_enter()" != "logbuf_lock is acquired".

You are right. It seems that the

printk_safe_enter_irq()
printk_safe_exit_irq()

printk_safe_enter_irqsave(flags)
printk_safe_exit_irqrestore(flags)

variants make sense and we will need them together with
the logbuf_lock_*() stuff.

> [..]
> > PS: I still think if we could come with a better name than
> > printk_safe() but I cannot find one.
> 
> well, not that I'm the fan of printk_safe name, but can't think
> of anything better. we make printk calls safe (deadlock safe) in
> places where previously it was unsafe... quick-&-dirty name that
> is implementation-specific -- printk_percpu_enter/exit, or
> printk_pcpu_enter/exit... dunno.

OK, let's stay with printk_safe :-)

Best Reagards,
Petr

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts
  2016-12-21 14:36 ` [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts Sergey Senozhatsky
@ 2016-12-23 10:54   ` Petr Mladek
  2016-12-23 15:08     ` Sergey Senozhatsky
  0 siblings, 1 reply; 19+ messages in thread
From: Petr Mladek @ 2016-12-23 10:54 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Andrew Morton, Jan Kara, Tejun Heo, Calvin Owens, Steven Rostedt,
	Ingo Molnar, Peter Zijlstra, Andy Lutomirski, Linus Torvalds,
	Peter Hurley, linux-kernel, Sergey Senozhatsky

On Wed 2016-12-21 23:36:03, Sergey Senozhatsky wrote:
> Account lost messages in pritk-safe and printk-safe-nmi
> contexts and report those numbers during printk_safe_flush().
> 
> The patch also moves lost message counter to struct
> `printk_safe_seq_buf' instead of having dedicated static
> counters - this simplifies the code.
> 
> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
> Reviewed-by: Petr Mladek <pmladek@suse.com>
> ---
>  kernel/printk/internal.h    | 17 -----------------
>  kernel/printk/printk.c      | 10 ----------
>  kernel/printk/printk_safe.c | 18 +++++++++++++++---
>  3 files changed, 15 insertions(+), 30 deletions(-)
> 
> diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
> index 97cee4f482f4..d2456020120c 100644
> --- a/kernel/printk/internal.h
> +++ b/kernel/printk/internal.h
> @@ -16,23 +16,6 @@
>   */
>  #include <linux/percpu.h>
>  
> -#ifdef CONFIG_PRINTK_NMI
> -
> -extern atomic_t nmi_message_lost;
> -static inline int get_nmi_message_lost(void)
> -{
> -	return atomic_xchg(&nmi_message_lost, 0);
> -}
> -
> -#else /* CONFIG_PRINTK_NMI */
> -
> -static inline int get_nmi_message_lost(void)
> -{
> -	return 0;
> -}
> -
> -#endif /* CONFIG_PRINTK_NMI */
> -
>  #ifdef CONFIG_PRINTK
>  
>  #define PRINTK_SAFE_CONTEXT_MASK	0x7fffffff
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 335b0fcb538e..6ec61ae0d122 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -1677,7 +1677,6 @@ asmlinkage int vprintk_emit(int facility, int level,
>  	unsigned long flags;
>  	int this_cpu;
>  	int printed_len = 0;
> -	int nmi_message_lost;
>  	bool in_sched = false;
>  	/* cpu currently holding logbuf_lock in this function */
>  	static unsigned int logbuf_cpu = UINT_MAX;
> @@ -1728,15 +1727,6 @@ asmlinkage int vprintk_emit(int facility, int level,
>  					 strlen(recursion_msg));
>  	}
>  
> -	nmi_message_lost = get_nmi_message_lost();
> -	if (unlikely(nmi_message_lost)) {
> -		text_len = scnprintf(textbuf, sizeof(textbuf),
> -				     "BAD LUCK: lost %d message(s) from NMI context!",
> -				     nmi_message_lost);
> -		printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
> -					 NULL, 0, textbuf, text_len);
> -	}
> -
>  	/*
>  	 * The printf needs to come first; we need the syslog
>  	 * prefix which might be passed-in as a parameter.
> diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
> index 9e8ef6a2070c..cd5160112374 100644
> --- a/kernel/printk/printk_safe.c
> +++ b/kernel/printk/printk_safe.c
> @@ -42,10 +42,13 @@
>  static int printk_safe_irq_ready;
>  
>  #define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -	\
> -			 sizeof(atomic_t) - sizeof(struct irq_work))
> +				sizeof(atomic_t) -			\
> +				sizeof(atomic_t) -			\
> +				sizeof(struct irq_work))
>  
>  struct printk_safe_seq_buf {
>  	atomic_t		len;	/* length of written data */
> +	atomic_t		message_lost;
>  	struct irq_work		work;	/* IRQ work that flushes the buffer */
>  	unsigned char		buffer[SAFE_LOG_BUF_LEN];
>  };
> @@ -55,7 +58,6 @@ static DEFINE_PER_CPU(int, printk_context);
>  
>  #ifdef CONFIG_PRINTK_NMI
>  static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
> -atomic_t nmi_message_lost;
>  #endif
>  
>  /*
> @@ -79,7 +81,7 @@ static int printk_safe_log_store(struct printk_safe_seq_buf *s,
>  
>  	/* The trailing '\0' is not counted into len. */
>  	if (len >= sizeof(s->buffer) - 1) {
> -		atomic_inc(&nmi_message_lost);
> +		atomic_inc(&s->message_lost);
>  		return 0;
>  	}
>  
> @@ -168,6 +170,14 @@ static int printk_safe_flush_buffer(const char *start, size_t len)
>  	return len;
>  }
>  
> +static void report_message_lost(struct printk_safe_seq_buf *s)
> +{
> +	int lost = atomic_xchg(&s->message_lost, 0);
> +
> +	if (lost)
> +		printk_deferred("Lost %d message(s)!\n", lost);
> +}
> +
>  /*
>   * Flush data from the associated per-CPU buffer. The function
>   * can be called either via IRQ work or independently.
> @@ -224,6 +234,8 @@ static void __printk_safe_flush(struct irq_work *work)
>  	if (atomic_cmpxchg(&s->len, len, 0) != len)
>  		goto more;
>  
> +	report_message_lost(s);

There is a potential race:

CPU0					CPU1

printk_safe_log_store()
  len = atomic_read(&s->len);

					__printk_save_flush()

					  atomic_cmpxchg(&s->len, len, 0)

					  report_message_lost(s);

   if (len >= sizeof(s->buffer) - 1) {
	atomic_inc(&s->message_lost);
		return 0;

We check the outdated len, account lost message, but it will not
be reported until some other message appears in the log buffer.

> +
>  out:

I would make sense to move report_message_lost(s) here, after
the out: label.

Also it would make sense to queue the irq_work also when we
bump s->message lost in printk_save_log_store().

It still will not be perfect because the "racy" warning about the lost
messages will not be printed together with the messages that fit
the buffer. Also there might appear new messages in the meantime.
But it is a real corner case. We do the best effort. I think
that it is not worth more complications than what I suggested above.
We still have much better results than the original code.
And the new code looks much better.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts
  2016-12-23 10:54   ` Petr Mladek
@ 2016-12-23 15:08     ` Sergey Senozhatsky
  0 siblings, 0 replies; 19+ messages in thread
From: Sergey Senozhatsky @ 2016-12-23 15:08 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Andrew Morton, Jan Kara, Tejun Heo,
	Calvin Owens, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
	Andy Lutomirski, Linus Torvalds, Peter Hurley, linux-kernel,
	Sergey Senozhatsky

Hello,

On (12/23/16 11:54), Petr Mladek wrote:
[..]
> There is a potential race:
> 
> CPU0					CPU1
> 
> printk_safe_log_store()
>   len = atomic_read(&s->len);
> 
> 					__printk_save_flush()
> 
> 					  atomic_cmpxchg(&s->len, len, 0)
> 
> 					  report_message_lost(s);
> 
>    if (len >= sizeof(s->buffer) - 1) {
> 	atomic_inc(&s->message_lost);
> 		return 0;
> 
> We check the outdated len, account lost message, but it will not
> be reported until some other message appears in the log buffer.
> 
> > +
> >  out:
> 
> I would make sense to move report_message_lost(s) here, after
> the out: label.

hm, ok. to flush from another CPU we first need to have printk-safe/nmi
messages on that CPU, then return from printk-safe/nmi on that CPU, execute
per-CPU irq_wor, and then have concurrent printk-safe/nmi messages on current
CPU, in addition happening frequent enough to hit this case. I may be wrong,
but that's quite unlikely. I can move report_message_lost() to `out' label,
no problem. thanks for the report.

at some point I was actually considering turning ->message_lost into
'bool' -- "we lost your messages, we are sorry". the precise number of
lost messages doesn't help that much: the messages are gone, go and
increment CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT; that's all we can say now.

and speaking of lost messages. I think I found a regression in
console_unlock(). so I'll send out a fix ahead of this series.

and, besides, the logs I had a pleasure to look at today contained numerous
"%d printk messages dropped" with very accurate numbers, but those numbers
meant pretty much nothing to me - the messages were lost.

	-ss

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2016-12-23 15:09 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-21 14:35 [PATCHv6 0/7] printk: use printk_safe to handle printk() recursive calls Sergey Senozhatsky
2016-12-21 14:35 ` [PATCHv6 1/7] printk: use vprintk_func in vprintk() Sergey Senozhatsky
2016-12-21 14:36 ` [PATCHv6 2/7] printk: rename nmi.c and exported api Sergey Senozhatsky
2016-12-21 19:45   ` Linus Torvalds
2016-12-22  1:17     ` Sergey Senozhatsky
2016-12-21 14:36 ` [PATCHv6 3/7] printk: introduce per-cpu safe_print seq buffer Sergey Senozhatsky
2016-12-22  0:53   ` kbuild test robot
2016-12-22  1:18     ` Sergey Senozhatsky
2016-12-22 16:36       ` Petr Mladek
2016-12-21 14:36 ` [PATCHv6 4/7] printk: always use deferred printk when flush printk_safe lines Sergey Senozhatsky
2016-12-21 14:36 ` [PATCHv6 5/7] printk: report lost messages in printk safe/nmi contexts Sergey Senozhatsky
2016-12-23 10:54   ` Petr Mladek
2016-12-23 15:08     ` Sergey Senozhatsky
2016-12-21 14:36 ` [PATCHv6 6/7] printk: use printk_safe buffers in printk Sergey Senozhatsky
2016-12-22  5:31   ` Sergey Senozhatsky
2016-12-22 17:10     ` Petr Mladek
2016-12-23  1:46       ` Sergey Senozhatsky
2016-12-23  9:53         ` Petr Mladek
2016-12-21 14:36 ` [PATCHv6 7/7] printk: remove zap_locks() function Sergey Senozhatsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).