From 52bce7f8d4fc633c9a9d0646eef58ba6ae9a3b73 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:13:05 -0500 Subject: [PATCH] pty, n_tty: Simplify input processing on final close When releasing one end of a pty pair, that end may just have written to the other, which the input processing worker, flush_to_ldisc(), is still working on but has not completed the copy to the other end's read buffer. So input may not appear to be available to a waiting reader but yet TTY_OTHER_CLOSED is now observed. The n_tty line discipline has worked around this by waiting for input processing to complete and then re-checking if input is available before exiting with -EIO. Since the tty/ldisc lock reordering, the wait for input processing to complete can now occur during final close before setting TTY_OTHER_CLOSED. In this way, a waiting reader is guaranteed to see input available (if any) before observing TTY_OTHER_CLOSED. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 46 ++++++++++++++++++++------------------------- drivers/tty/pty.c | 1 + 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 0cb0e12f87c7..112eda7c56bc 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2197,34 +2197,28 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, if (!input_available_p(tty, 0)) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { - up_read(&tty->termios_rwsem); - tty_flush_to_ldisc(tty); - down_read(&tty->termios_rwsem); - if (!input_available_p(tty, 0)) { - retval = -EIO; - break; - } - } else { - if (tty_hung_up_p(file)) - break; - if (!timeout) - break; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - n_tty_set_room(tty); - up_read(&tty->termios_rwsem); + retval = -EIO; + break; + } + if (tty_hung_up_p(file)) + break; + if (!timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + n_tty_set_room(tty); + up_read(&tty->termios_rwsem); - timeout = schedule_timeout(timeout); + timeout = schedule_timeout(timeout); - down_read(&tty->termios_rwsem); - continue; - } + down_read(&tty->termios_rwsem); + continue; } __set_current_state(TASK_RUNNING); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index bee9776730fd..a9d256d6e909 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -53,6 +53,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) /* Review - krefs on tty_link ?? */ if (!tty->link) return; + tty_flush_to_ldisc(tty->link); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); -- 2.20.1