[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20190926085855.debu7t46s7kgb26p@pathway.suse.cz>
Date: Thu, 26 Sep 2019 10:58:55 +0200
From: Petr Mladek <pmladek@...e.com>
To: Sergey Senozhatsky <sergey.senozhatsky.work@...il.com>
Cc: Uwe Kleine-König
<u.kleine-koenig@...gutronix.de>,
Sergey Senozhatsky <sergey.senozhatsky@...il.com>,
Steven Rostedt <rostedt@...dmis.org>,
Tetsuo Handa <penguin-kernel@...ove.sakura.ne.jp>,
linux-kernel@...r.kernel.org
Subject: Re: Regression in dbdda842fe96 ("printk: Add console owner and
waiter logic to load balance console writes") [Was: Regression in
fd5f7cde1b85 ("...")]
On Wed 2019-09-18 16:52:52, Sergey Senozhatsky wrote:
> On (09/18/19 09:11), Uwe Kleine-König wrote:
> > I rechecked and indeed fd5f7cde1b85's parent has the problem, too, so I
> > did a mistake during my bisection :-|
> >
> > Redoing the bisection (a bit quicker this time) points to
> >
> > dbdda842fe96 ("printk: Add console owner and waiter logic to load balance console writes")
> >
> > Sorry for the confusion.
>
> No worries!
>
> [..]
> > > So I'd say that lockdep is correct, but there are several hacks which
> > > prevent actual deadlock.
>
> The basic idea is to handle sysrq out of port->lock.
Great idea!
> I didn't test it all (not even sure if it compiles).
>
> ---
> drivers/tty/serial/imx.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> index 87c58f9f6390..f0dd807b52df 100644
> --- a/drivers/tty/serial/imx.c
> +++ b/drivers/tty/serial/imx.c
> @@ -731,9 +731,9 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
> struct imx_port *sport = dev_id;
> unsigned int rx, flg, ignored = 0;
> struct tty_port *port = &sport->port.state->port;
> + unsigned long flags;
>
> - spin_lock(&sport->port.lock);
> -
> + uart_port_lock_irqsave(&sport->port, flags);
uart_port_lock_irqsave() does not exist. Instead the current users
do:
spin_lock_irqsave(&port->lock, flags);
> while (imx_uart_readl(sport, USR2) & USR2_RDR) {
> u32 usr2;
>
> @@ -749,8 +749,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
> continue;
> }
>
> - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
> - continue;
> + if (uart_prepare_sysrq_char(&sport->port, (unsigned char)rx))
> + break;
>
> if (unlikely(rx & URXD_ERR)) {
> if (rx & URXD_BRK)
> @@ -792,7 +792,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
> }
>
> out:
> - spin_unlock(&sport->port.lock);
> + uart_unlock_and_check_sysrq(&sport->port, flags);
This API has been introduced for exactly this reason. See the commit
6e1935819db0c91ce4a5af ("serial: core: Allow processing sysrq at port
unlock time").
I like this approach. It allows to remove hacks with locks.
Well, Sergey's patch is nice example that the API is a bit confusing.
I would either make it symmetric and make a variant without saving
irq flags:
uart_lock(port);
uart_unlock_and_handle_sysrq(port);
uart_lock_irqsave(port, flags);
uart_unlock_irqrestore_and_handle_sysrq(port);
Or I would keep the locking as is and add some API
just for the sysrq handling:
int uart_store_sysrq_char(struct uart_port *port, unsigned int ch);
unsigned int uart_get_sysrq_char(struct uart_port *port);
And use it the following way:
int handle_irq()
{
unsined int sysrq, sysrq_ch;
spin_lock(&port->lock);
[...]
sysrq = uart_store_sysrq_char(port, ch);
if (!sysrq)
[...]
[...]
out:
sysrq_ch = uart_get_sysrq_char(port);
spin_unlock(&port->lock);
if (sysrq_ch)
handle_sysrq(sysrq_ch);
}
I prefer the 2nd option. It is more code. But it is more
self explanatory.
What do you think?
Best Regards,
Petr
Powered by blists - more mailing lists