mirror of
https://github.com/torvalds/linux.git
synced 2026-10-07 05:31:08 -04:00
serial: pl011: Fix lockdep splat when handling magic-sysrq interrupt
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]> Link: https://lore.kernel.org/r/20200811101313.GA6970@willie-the-truck Signed-off-by: Peter Zijlstra <[email protected]> Tested-by: Will Deacon <[email protected]> Signed-off-by: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
This commit is contained in:
1 parent
29788ab1d2
commit
534cf755d9
1 file changed
+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;
|
||||
|
||||
Reference in new issue
Block a user