linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: Petr Mladek <pmladek@suse.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Daniel Wang <wonderfly@google.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Alan Cox <gnomes@lxorguk.ukuu.org.uk>,
	Jiri Slaby <jslaby@suse.com>, Peter Feiner <pfeiner@google.com>,
	linux-serial@vger.kernel.org,
	Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>,
	Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Subject: [RFC][PATCHv2 3/4] serial: introduce uart_port locking helpers
Date: Tue, 16 Oct 2018 14:04:27 +0900	[thread overview]
Message-ID: <20181016050428.17966-4-sergey.senozhatsky@gmail.com> (raw)
In-Reply-To: <20181016050428.17966-1-sergey.senozhatsky@gmail.com>

The patch introduces several macros which should make serial console
drivers less printk() deadlock prone.

There are several console driver entry points so we are looking at
several slightly different deadlock scenarios.

- The first entry point is console ->write() callback, which we call
  from printk(). A possible deadlock scenario there is:

  CPU0
	<NMI>
	spin_lock_irqsave(&port->lock, flags)      << deadlock
	serial_foo_write()
	call_console_drivers()
	console_unlock()
	console_flush_on_panic()
	panic()
	<NMI/>
	spin_lock_irqsave(&port->lock, flags)
	serial_foo_write()
	call_console_drivers()
	console_unlock()
	printk()
	...

  ->write() callback, generally speaking, must be re-entrant in two cases:
   1) sysrq
   2) panic (oops_in_progress)

  And this is what uart_port_lock_for_printk()/uart_port_unlock_after_printk()
  macros are for.

  Usage example:

	static serial_foo_write(...)
	{
		struct uart_port *port;
		unsigned long flags;
		bool locked;

		uart_port_lock_for_printk(port, flags, locked);
		uart_console_write(port, s, count, serial_foo_putchar);
		uart_port_unlock_after_printk(port, flags, locked);
	}

  Some of the serial drivers already use _some sort_ of
  uart_port_lock_for_printk(), some are not panic() re-entrant. This
  should address the issue.

- The rest (of entry points) requires a bit different handling.
  Let's take a look at the following backtrace:

  	CPU0
	<IRQ>
	spin_lock_irqsave(&port->lock, flags)      << deadlock
	serial_foo_write()
	call_console_drivers()
	console_unlock()
	printk()
	__queue_work()
	tty_flip_buffer_push()
	spin_lock_irqsave(&port->lock, flags)
	serial_foo_handle_IRQ()
	<IRQ/>

  Serial drivers invoke tons of core kernel functions - WQ, MM, etc. All
  of which may printk() in various cases. So we can't really just
  "remove those printk-s". The simples way to address this seems to be
  PRINTK_SAFE_CONTEXT_MASK.

  printk_safe() is a special printk() mode, which redirects recursive
  printk()-s to a secondary (per-CPU) buffer; so we don't re-enter
  printk() and serial console driver. The secondary (per-CPU) buffer is
  flushed and printed to the consoles later, from a safe context, when
  we know that we are not in printk()-recursion anymore.

  And this is what uart_port_lock_*()/uart_port_unlock_*() macros are
  for. With uart_port_lock_irqsave() the previous example would turn
  into:

	CPU0
	<IRQ>
	irq_work_queue()
	printk_safe_log_store()
	printk()
	__queue_work()
	tty_flip_buffer_push()
	uart_port_lock_irqsave(port, flags)
	serial_foo_handle_IRQ()
	<IRQ/>

  As of now, no consoles are re-entrant when printk() initiated by
  console's driver IRQ handler. This macro should address the issue.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
 include/linux/serial_core.h | 48 +++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 047fa67d039b..acc6966fea8e 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -266,6 +266,54 @@ struct uart_port {
 	void			*private_data;		/* generic platform data pointer */
 };
 
+#define uart_port_lock_irq(p)						\
+	do {								\
+		printk_safe_enter_irq();				\
+		spin_lock(&(p)->lock);					\
+	} while (0)
+
+#define uart_port_unlock_irq(p)					\
+	do {								\
+		spin_unlock(&(p)->lock);				\
+		printk_safe_exit_irq();					\
+	} while (0)
+
+#define uart_port_lock_irqsave(p, flags)				\
+	do {								\
+		printk_safe_enter_irqsave(flags);			\
+		spin_lock(&(p)->lock);					\
+	} while (0)
+
+#define uart_port_unlock_irqrestore(p, flags)				\
+	do {								\
+		spin_unlock(&(p)->lock);				\
+		printk_safe_exit_irqrestore(flags);			\
+	} while (0)
+
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
+#define uart_port_in_sysrq(p)		p->sysrq
+#else
+#define uart_port_in_sysrq(p)		0
+#endif
+
+#define uart_port_lock_for_printk(p, flags, locked)			\
+	do {								\
+		locked = true;						\
+		if (uart_port_in_sysrq(p))				\
+			locked = false;					\
+		else if (oops_in_progress)				\
+			locked = spin_trylock_irqsave(&(p)->lock,	\
+						      flags);		\
+		else							\
+			spin_lock_irqsave(&(p)->lock, flags);		\
+	} while (0)
+
+#define uart_port_unlock_after_printk(p, flags, locked)		\
+	do {								\
+		if (locked)						\
+			spin_unlock_irqrestore(&(p)->lock, flags);	\
+	} while (0)
+
 static inline int serial_port_in(struct uart_port *up, int offset)
 {
 	return up->serial_in(up, offset);
-- 
2.19.1


  parent reply	other threads:[~2018-10-16  5:05 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-16  5:04 [RFC][PATCHv2 0/4] less deadlock prone serial consoles Sergey Senozhatsky
2018-10-16  5:04 ` [RFC][PATCHv2 1/4] panic: avoid deadlocks in re-entrant console drivers Sergey Senozhatsky
2018-10-17  4:48   ` Sergey Senozhatsky
2018-10-23 11:07   ` Petr Mladek
2018-10-23 11:54     ` Sergey Senozhatsky
2018-10-23 12:04       ` Sergey Senozhatsky
2018-10-23 12:12         ` Sergey Senozhatsky
2018-10-25  9:06           ` Petr Mladek
2018-10-25  9:31             ` Sergey Senozhatsky
2018-10-25  8:29       ` Petr Mladek
2018-10-25  9:05         ` Sergey Senozhatsky
2018-10-25 10:10   ` [PATCHv3] " Sergey Senozhatsky
2018-10-25 10:51     ` kbuild test robot
2018-10-25 11:56       ` Sergey Senozhatsky
2018-10-31 12:27     ` Petr Mladek
2018-11-01  1:48       ` Sergey Senozhatsky
2018-11-01  8:08         ` Petr Mladek
2018-11-22 13:12           ` Petr Mladek
2018-12-12  0:53             ` Daniel Wang
2018-12-12  5:23               ` Sergey Senozhatsky
2018-12-12  5:59                 ` Daniel Wang
2018-12-12  6:06                   ` Sergey Senozhatsky
2018-12-12  6:09                     ` Daniel Wang
2018-10-16  5:04 ` [RFC][PATCHv2 2/4] printk: move printk_safe macros to printk header Sergey Senozhatsky
2018-10-16  7:27   ` Peter Zijlstra
2018-10-16 11:40     ` Petr Mladek
2018-10-16 12:17       ` Peter Zijlstra
2018-10-17 10:50         ` Petr Mladek
2018-10-17 14:00           ` Peter Zijlstra
2018-10-22 14:30             ` Petr Mladek
2018-10-16 12:27     ` Sergey Senozhatsky
2018-10-16 12:38       ` Peter Zijlstra
2018-10-16 12:54       ` Peter Zijlstra
2018-10-16 14:21         ` Peter Zijlstra
2018-10-17  4:32         ` Sergey Senozhatsky
2018-10-17  7:57           ` Peter Zijlstra
2018-10-17 13:36             ` Sergey Senozhatsky
2018-10-23  6:25         ` Sergey Senozhatsky
2018-10-16  5:04 ` Sergey Senozhatsky [this message]
2018-12-08  3:12   ` [RFC][PATCHv2 3/4] serial: introduce uart_port locking helpers Sergey Senozhatsky
2018-12-12 11:08     ` Greg Kroah-Hartman
2018-10-16  5:04 ` [RFC][PATCHv2 4/4] tty: 8250: switch to " Sergey Senozhatsky
2018-10-16  7:23 ` [RFC][PATCHv2 0/4] less deadlock prone serial consoles Peter Zijlstra
2018-10-16  8:12   ` Sergey Senozhatsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181016050428.17966-4-sergey.senozhatsky@gmail.com \
    --to=sergey.senozhatsky.work@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=gnomes@lxorguk.ukuu.org.uk \
    --cc=gregkh@linuxfoundation.org \
    --cc=jslaby@suse.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=peterz@infradead.org \
    --cc=pfeiner@google.com \
    --cc=pmladek@suse.com \
    --cc=rostedt@goodmis.org \
    --cc=sergey.senozhatsky@gmail.com \
    --cc=torvalds@linux-foundation.org \
    --cc=wonderfly@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).