lkml.org 
[lkml]   [2022]   [Apr]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 235/475] serial: 8250: Fix race condition in RTS-after-send handling
    Date
    From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

    [ Upstream commit dedab69fd650ea74710b2e626e63fd35584ef773 ]

    Set em485->active_timer = NULL isn't always enough to take out the stop
    timer. While there is a check that it acts in the right state (i.e.
    waiting for RTS-after-send to pass after sending some chars) but the
    following might happen:

    - CPU1: some chars send, shifter becomes empty, stop tx timer armed
    - CPU0: more chars send before RTS-after-send expired
    - CPU0: shifter empty irq, port lock taken
    - CPU1: tx timer triggers, waits for port lock
    - CPU0: em485->active_timer = &em485->stop_tx_timer, hrtimer_start(),
    releases lock()
    - CPU1: get lock, see em485->active_timer == &em485->stop_tx_timer,
    tear down RTS too early

    This fix bases on research done by Steffen Trumtrar.

    Fixes: b86f86e8e7c5 ("serial: 8250: fix potential deadlock in rs485-mode")
    Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    Link: https://lore.kernel.org/r/20220215160236.344236-1-u.kleine-koenig@pengutronix.de
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/tty/serial/8250/8250_port.c | 12 ++++++++++++
    1 file changed, 12 insertions(+)

    diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
    index 777ef1a9591c..87567515591e 100644
    --- a/drivers/tty/serial/8250/8250_port.c
    +++ b/drivers/tty/serial/8250/8250_port.c
    @@ -1545,6 +1545,18 @@ static inline void start_tx_rs485(struct uart_port *port)
    if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
    serial8250_stop_rx(&up->port);

    + /*
    + * While serial8250_em485_handle_stop_tx() is a noop if
    + * em485->active_timer != &em485->stop_tx_timer, it might happen that
    + * the timer is still armed and triggers only after the current bunch of
    + * chars is send and em485->active_timer == &em485->stop_tx_timer again.
    + * So cancel the timer. There is still a theoretical race condition if
    + * the timer is already running and only comes around to check for
    + * em485->active_timer when &em485->stop_tx_timer is armed again.
    + */
    + if (em485->active_timer == &em485->stop_tx_timer)
    + hrtimer_try_to_cancel(&em485->stop_tx_timer);
    +
    em485->active_timer = NULL;

    mcr = serial8250_in_MCR(up);
    --
    2.34.1


    \
     
     \ /
      Last update: 2022-04-14 16:42    [W:4.031 / U:0.092 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site