@@ -213,9 +213,11 @@ static void n_tty_kick_worker(const struct tty_struct *tty)
static ssize_t chars_in_buffer(const struct tty_struct *tty)
{
const struct n_tty_data *ldata = tty->disc_data;
- size_t head = ldata->icanon ? ldata->canon_head : ldata->commit_head;
+ size_t head = ldata->icanon ?
+ smp_load_acquire(&ldata->canon_head) :
+ smp_load_acquire(&ldata->commit_head);
- return head - ldata->read_tail;
+ return head - smp_load_acquire(&ldata->read_tail);
}
/**
@@ -1919,11 +1921,12 @@ static inline int input_available_p(const struct tty_struct *tty, int poll)
{
const struct n_tty_data *ldata = tty->disc_data;
int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
+ size_t tail = smp_load_acquire(&ldata->read_tail);
if (ldata->icanon && !L_EXTPROC(tty))
- return ldata->canon_head != ldata->read_tail;
+ return smp_load_acquire(&ldata->canon_head) != tail;
else
- return ldata->commit_head - ldata->read_tail >= amt;
+ return smp_load_acquire(&ldata->commit_head) - tail >= amt;
}
/**
When running anything causes an intense enough tty output, for example 'find /' on a tty console, KCSAN is likely to report a few data races around an internal routines which examines and manages the read buffer: BUG: KCSAN: data-race in n_tty_read / n_tty_receive_buf_common write (marked) to 0xffffc90003ae5008 of 8 bytes by task 100 on cpu 1: n_tty_receive_buf_common+0x710/0xc30 n_tty_receive_buf2+0x3d/0x60 tty_ldisc_receive_buf+0x6b/0x100 tty_port_default_receive_buf+0x63/0xa0 flush_to_ldisc+0x169/0x3c0 process_scheduled_works+0x6fe/0xf40 worker_thread+0x53b/0x7b0 kthread+0x4f8/0x590 ret_from_fork+0x28c/0x450 ret_from_fork_asm+0x1a/0x30 read to 0xffffc90003ae5008 of 8 bytes by task 5844 on cpu 4: n_tty_read+0x6b2/0xe00 tty_read+0x16f/0x490 vfs_read+0x595/0x600 ksys_read+0xe7/0x1b0 __x64_sys_read+0x4a/0x60 x64_sys_call+0x2ff1/0x32b0 do_syscall_64+0xfa/0x3b0 entry_SYSCALL_64_after_hwframe+0x77/0x7f BUG: KCSAN: data-race in n_tty_poll / n_tty_receive_buf_common write (marked) to 0xffffc90003ae5008 of 8 bytes by task 68 on cpu 6: n_tty_receive_buf_common+0x710/0xc30 n_tty_receive_buf2+0x3d/0x60 tty_ldisc_receive_buf+0x6b/0x100 tty_port_default_receive_buf+0x63/0xa0 flush_to_ldisc+0x169/0x3c0 process_scheduled_works+0x6fe/0xf40 worker_thread+0x53b/0x7b0 kthread+0x4f8/0x590 ret_from_fork+0x28c/0x450 ret_from_fork_asm+0x1a/0x30 read to 0xffffc90003ae5008 of 8 bytes by task 5844 on cpu 3: n_tty_poll+0x2fb/0x480 tty_poll+0x80/0x100 do_sys_poll+0x618/0xb30 __se_sys_ppoll+0x1c3/0x210 __x64_sys_ppoll+0x71/0x90 x64_sys_call+0x3079/0x32b0 do_syscall_64+0xfa/0x3b0 entry_SYSCALL_64_after_hwframe+0x77/0x7f BUG: KCSAN: data-race in n_tty_check_unthrottle / n_tty_receive_buf_common write (marked) to 0xffffc90003ae5008 of 8 bytes by task 68 on cpu 4: n_tty_receive_buf_common+0x710/0xc30 n_tty_receive_buf2+0x3d/0x60 tty_ldisc_receive_buf+0x6b/0x100 tty_port_default_receive_buf+0x63/0xa0 flush_to_ldisc+0x169/0x3c0 process_scheduled_works+0x6fe/0xf40 worker_thread+0x53b/0x7b0 kthread+0x4f8/0x590 ret_from_fork+0x28c/0x450 ret_from_fork_asm+0x1a/0x30 read to 0xffffc90003ae5008 of 8 bytes by task 5844 on cpu 5: n_tty_check_unthrottle+0x86/0x1d0 n_tty_read+0xb05/0xe00 tty_read+0x16f/0x490 vfs_read+0x595/0x600 ksys_read+0xe7/0x1b0 __x64_sys_read+0x4a/0x60 x64_sys_call+0x2ff1/0x32b0 do_syscall_64+0xfa/0x3b0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fix all of them by using smp_load_acquire() accessing buffer's head and tail marks in chars_in_buffer() and input_available_p(). Fixes: 70aca71f92ca ("n_tty: Fix unordered accesses to lockless read buffer") Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> --- drivers/tty/n_tty.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)