Skip to content

Commit fedb576

Browse files
committed
serial: fix race between flush_to_ldisc and tty_open
There still is a race window after the commit b027e22 ("tty: fix data race between tty_init_dev and flush of buf"), and we encountered this crash issue if receive_buf call comes before tty initialization completes in tty_open and tty->driver_data may be NULL. CPU0 CPU1 ---- ---- tty_open tty_init_dev tty_ldisc_unlock schedule flush_to_ldisc receive_buf tty_port_default_receive_buf tty_ldisc_receive_buf n_tty_receive_buf_common __receive_buf uart_flush_chars uart_start /*tty->driver_data is NULL*/ tty->ops->open /*init tty->driver_data*/ it can be fixed by extending ldisc semaphore lock in tty_init_dev to driver_data initialized completely after tty->ops->open(), but this will lead to get lock on one function and unlock in some other function, and hard to maintain, so fix this race only by checking tty->driver_data when receiving, and return if tty->driver_data is NULL, and n_tty_receive_buf_common maybe calls uart_unthrottle, so add the same check. Because the tty layer knows nothing about the driver associated with the device, the tty layer can not do anything here, it is up to the tty driver itself to check for this type of race. Fix up the serial driver to correctly check to see if it is finished binding with the device when being called, and if not, abort the tty calls. [Description and problem report and testing from Li RongQing, I rewrote the patch to be in the serial layer, not in the tty core - gregkh] Reported-by: Li RongQing <lirongqing@baidu.com> Tested-by: Li RongQing <lirongqing@baidu.com> Signed-off-by: Wang Li <wangli39@baidu.com> Signed-off-by: Zhang Yu <zhangyu31@baidu.com> Signed-off-by: Li RongQing <lirongqing@baidu.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a1960e0 commit fedb576

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

drivers/tty/serial/serial_core.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ static void uart_start(struct tty_struct *tty)
130130
struct uart_port *port;
131131
unsigned long flags;
132132

133+
if (!state)
134+
return;
135+
133136
port = uart_port_lock(state, flags);
134137
__uart_start(tty);
135138
uart_port_unlock(port, flags);
@@ -727,6 +730,9 @@ static void uart_unthrottle(struct tty_struct *tty)
727730
upstat_t mask = UPSTAT_SYNC_FIFO;
728731
struct uart_port *port;
729732

733+
if (!state)
734+
return;
735+
730736
port = uart_port_ref(state);
731737
if (!port)
732738
return;

0 commit comments

Comments
 (0)