serial: pl011: Fix lockdep splat when handling magic-sysrq interrupt
PATCH 1/1 serial: pl011: Fix lockdep splat when handling magic-sysrq interrupt
From: Peter Zijlstra <[email protected]>
Issuing a magic-sysrq via the PL011 causes the following lockdep splat, which is easily reproducible under QEMU:
| sysrq: Changing Loglevel
| sysrq: Loglevel set to 9
|
| ======================================================
| WARNING: possible circular locking dependency detected
| 5.9.0-rc7 #1 Not tainted
| ------------------------------------------------------
| systemd-journal/138 is trying to acquire lock:
| ffffab133ad950c0 (console_owner){-.-.}-{0:0}, at: console_lock_spinning_enable+0x34/0x70
|
| but task is already holding lock:
| ffff0001fd47b098 (&port_lock_key){-.-.}-{2:2}, at: pl011_int+0x40/0x488
|
| which lock already depends on the new lock.[...]
| Possible unsafe locking scenario: | | CPU0 CPU1 | ---- ---- | lock(&port_lock_key); | lock(console_owner); | lock(&port_lock_key); | lock(console_owner); | | *** DEADLOCK ***
The issue being that CPU0 takes 'port_lock' on the irq path in pl011_int() before taking 'console_owner' on the printk() path, whereas CPU1 takes the two locks in the opposite order on the printk() path due to setting the "console_owner" prior to calling into into the actual console driver.
Fix this in the same way as the msm-serial driver by dropping 'port_lock' before handling the sysrq.
Cc <[email protected]> # 4.19+
Cc Russell King <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Signed-off-by Peter Zijlstra <[email protected]>
Tested-by Will Deacon <[email protected]>
Signed-off-by Will Deacon <[email protected]>
--- drivers/tty/serial/amba-pl011.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/tty/serial/amba-pl011.c +7 -4
@@ -308,8 +308,9 @@ static void pl011_write(unsigned int val, const struct uart_amba_port *uap,*/ static int pl011_fifo_to_tty (struct uart_amba_port *uap) { -u16 status;unsigned int ch, flag, fifotaken; +int sysrq; +u16 status;for (fifotaken =0 ; fifotaken !=256 ; fifotaken++) { status =pl011_read (uap,REG_FR );
@@ -344,10 +345,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) flag =TTY_FRAME ; } -if (uart_handle_sysrq_char (&uap->port, ch &255 )) -continue ; +spin_unlock (&uap->port.lock); + sysrq =uart_handle_sysrq_char (&uap->port, ch &255 ); +spin_lock (&uap->port.lock); -uart_insert_char (&uap->port, ch,UART011_DR_OE , ch, flag); +if (!sysrq) +uart_insert_char (&uap->port, ch,UART011_DR_OE , ch, flag); }return fifotaken;
Signature · 1 line
2.28.0.709.gb0816b6eb0-goog