Skip to content

Commit f8747d4

Browse files
peterhurleygregkh
authored andcommitted
tty: Fix pty master read() after slave closes
Commit f95499c, n_tty: Don't wait for buffer work in read() loop creates a race window which can cause a pty master read() to miss the last pty slave write(s) and return -EIO instead, thus signalling the pty slave is closed. This can happen when the pty slave is written and immediately closed but before the tty buffer i/o loop receives the new input; the pty master read() is scheduled, sees its read buffer is empty and the pty slave has been closed, and exits. Because tty_flush_to_ldisc() has significant performance impact for parallel i/o, rather than revert the commit, special case this condition (ie., when the read buffer is empty and the 'other' pty has been closed) and, only then, wait for buffer work to complete before re-testing if the read buffer is still empty. As before, subsequent pty master reads return any available data until no more data is available, and then returns -EIO to indicate the pty slave has closed. Reported-by: Mikael Pettersson <[email protected]> Signed-off-by: Peter Hurley <[email protected]> Tested-by: Mikael Pettersson <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 15c03dd commit f8747d4

File tree

1 file changed

+26
-20
lines changed

1 file changed

+26
-20
lines changed

drivers/tty/n_tty.c

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,28 +2183,34 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
21832183

21842184
if (!input_available_p(tty, 0)) {
21852185
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
2186-
retval = -EIO;
2187-
break;
2188-
}
2189-
if (tty_hung_up_p(file))
2190-
break;
2191-
if (!timeout)
2192-
break;
2193-
if (file->f_flags & O_NONBLOCK) {
2194-
retval = -EAGAIN;
2195-
break;
2196-
}
2197-
if (signal_pending(current)) {
2198-
retval = -ERESTARTSYS;
2199-
break;
2200-
}
2201-
n_tty_set_room(tty);
2202-
up_read(&tty->termios_rwsem);
2186+
up_read(&tty->termios_rwsem);
2187+
tty_flush_to_ldisc(tty);
2188+
down_read(&tty->termios_rwsem);
2189+
if (!input_available_p(tty, 0)) {
2190+
retval = -EIO;
2191+
break;
2192+
}
2193+
} else {
2194+
if (tty_hung_up_p(file))
2195+
break;
2196+
if (!timeout)
2197+
break;
2198+
if (file->f_flags & O_NONBLOCK) {
2199+
retval = -EAGAIN;
2200+
break;
2201+
}
2202+
if (signal_pending(current)) {
2203+
retval = -ERESTARTSYS;
2204+
break;
2205+
}
2206+
n_tty_set_room(tty);
2207+
up_read(&tty->termios_rwsem);
22032208

2204-
timeout = schedule_timeout(timeout);
2209+
timeout = schedule_timeout(timeout);
22052210

2206-
down_read(&tty->termios_rwsem);
2207-
continue;
2211+
down_read(&tty->termios_rwsem);
2212+
continue;
2213+
}
22082214
}
22092215
__set_current_state(TASK_RUNNING);
22102216

0 commit comments

Comments
 (0)