slip: Fix deadlock in write_wakeup
Use schedule_work() to avoid potentially taking the spinlock in
interrupt context.
Commit
cc9fa74e2a ("slip/slcan: added locking in wakeup function") added
necessary locking to the wakeup function and
367525c8c2/
ddcde142be ("can:
slcan: Fix spinlock variant") converted it to spin_lock_bh() because the lock
is also taken in timers.
Disabling softirqs is not sufficient, however, as tty drivers may call
write_wakeup from interrupt context. This driver calls tty->ops->write() with
its spinlock held, which may immediately cause an interrupt on the same CPU and
subsequent spin_bug().
Simply converting to spin_lock_irq/irqsave() prevents this deadlock, but
causes lockdep to point out a possible circular locking dependency
between these locks:
(&(&sl->lock)->rlock){-.....}, at: slip_write_wakeup
(&port_lock_key){-.....}, at: serial8250_handle_irq.part.13
The slip transmit is holding the slip spinlock when calling the tty write.
This grabs the port lock. On an interrupt, the handler grabs the port
lock and calls write_wakeup which grabs the slip lock. This could be a
problem if a serial interrupt occurs on another CPU during the slip
transmit.
To deal with these issues, don't grab the lock in the wakeup function by
deferring the writeout to a workqueue. Also hold the lock during close
when de-assigning the tty pointer to safely disarm the worker and
timers.
This bug is easily reproducible on the first transmit when slip is
used with the standard 8250 serial driver.
[<
c0410b7c>] (spin_bug+0x0/0x38) from [<
c006109c>] (do_raw_spin_lock+0x60/0x1d0)
r5:
eab27000 r4:
ec02754c
[<
c006103c>] (do_raw_spin_lock+0x0/0x1d0) from [<
c04185c0>] (_raw_spin_lock+0x28/0x2c)
r10:
0000001f r9:
eabb814c r8:
eabb8140 r7:
40070193 r6:
ec02754c r5:
eab27000
r4:
ec02754c r3:
00000000
[<
c0418598>] (_raw_spin_lock+0x0/0x2c) from [<
bf3a0220>] (slip_write_wakeup+0x50/0xe0 [slip])
r4:
ec027540 r3:
00000003
[<
bf3a01d0>] (slip_write_wakeup+0x0/0xe0 [slip]) from [<
c026e420>] (tty_wakeup+0x48/0x68)
r6:
00000000 r5:
ea80c480 r4:
eab27000 r3:
bf3a01d0
[<
c026e3d8>] (tty_wakeup+0x0/0x68) from [<
c028a8ec>] (uart_write_wakeup+0x2c/0x30)
r5:
ed68ea90 r4:
c06790d8
[<
c028a8c0>] (uart_write_wakeup+0x0/0x30) from [<
c028dc44>] (serial8250_tx_chars+0x114/0x170)
[<
c028db30>] (serial8250_tx_chars+0x0/0x170) from [<
c028dffc>] (serial8250_handle_irq+0xa0/0xbc)
r6:
000000c2 r5:
00000060 r4:
c06790d8 r3:
00000000
[<
c028df5c>] (serial8250_handle_irq+0x0/0xbc) from [<
c02933a4>] (dw8250_handle_irq+0x38/0x64)
r7:
00000000 r6:
edd2f390 r5:
000000c2 r4:
c06790d8
[<
c029336c>] (dw8250_handle_irq+0x0/0x64) from [<
c028d2f4>] (serial8250_interrupt+0x44/0xc4)
r6:
00000000 r5:
00000000 r4:
c06791c4 r3:
c029336c
[<
c028d2b0>] (serial8250_interrupt+0x0/0xc4) from [<
c0067fe4>] (handle_irq_event_percpu+0xb4/0x2b0)
r10:
c06790d8 r9:
eab27000 r8:
00000000 r7:
00000000 r6:
0000001f r5:
edd52980
r4:
ec53b6c0 r3:
c028d2b0
[<
c0067f30>] (handle_irq_event_percpu+0x0/0x2b0) from [<
c006822c>] (handle_irq_event+0x4c/0x6c)
r10:
c06790d8 r9:
eab27000 r8:
c0673ae0 r7:
c05c2020 r6:
ec53b6c0 r5:
edd529d4
r4:
edd52980
[<
c00681e0>] (handle_irq_event+0x0/0x6c) from [<
c006b140>] (handle_level_irq+0xe8/0x100)
r6:
00000000 r5:
edd529d4 r4:
edd52980 r3:
00022000
[<
c006b058>] (handle_level_irq+0x0/0x100) from [<
c00676f8>] (generic_handle_irq+0x30/0x40)
r5:
0000001f r4:
0000001f
[<
c00676c8>] (generic_handle_irq+0x0/0x40) from [<
c000f57c>] (handle_IRQ+0xd0/0x13c)
r4:
ea997b18 r3:
000000e0
[<
c000f4ac>] (handle_IRQ+0x0/0x13c) from [<
c00086c4>] (armada_370_xp_handle_irq+0x4c/0x118)
r8:
000003ff r7:
ea997b18 r6:
ffffffff r5:
60070013 r4:
c0674dc0
[<
c0008678>] (armada_370_xp_handle_irq+0x0/0x118) from [<
c0013840>] (__irq_svc+0x40/0x70)
Exception stack(0xea997b18 to 0xea997b60)
7b00:
00000001 20070013
7b20:
00000000 0000000b 20070013 eab27000 20070013 00000000 ed10103e eab27000
7b40:
c06790d8 ea997b74 ea997b60 ea997b60 c04186c0 c04186c8 60070013 ffffffff
r9:
eab27000 r8:
ed10103e r7:
ea997b4c r6:
ffffffff r5:
60070013 r4:
c04186c8
[<
c04186a4>] (_raw_spin_unlock_irqrestore+0x0/0x54) from [<
c0288fc0>] (uart_start+0x40/0x44)
r4:
c06790d8 r3:
c028ddd8
[<
c0288f80>] (uart_start+0x0/0x44) from [<
c028982c>] (uart_write+0xe4/0xf4)
r6:
0000003e r5:
00000000 r4:
ed68ea90 r3:
0000003e
[<
c0289748>] (uart_write+0x0/0xf4) from [<
bf3a0d20>] (sl_xmit+0x1c4/0x228 [slip])
r10:
ed388e60 r9:
0000003c r8:
ffffffdd r7:
0000003e r6:
ec02754c r5:
ea717eb8
r4:
ec027000
[<
bf3a0b5c>] (sl_xmit+0x0/0x228 [slip]) from [<
c0368d74>] (dev_hard_start_xmit+0x39c/0x6d0)
r8:
eaf163c0 r7:
ec027000 r6:
ea717eb8 r5:
00000000 r4:
00000000
Signed-off-by: Tyler Hall <tylerwhall@gmail.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Andre Naujoks <nautsch2@gmail.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>