summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-11-05 12:13:05 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-05 18:50:42 -0800
commit52bce7f8d4fc633c9a9d0646eef58ba6ae9a3b73 (patch)
tree8d6586f5e62fcd0dbb4c54a64fe687939c79d1b6 /drivers/tty
parent1bb954153aa97702db4363c6746794d097d9c707 (diff)
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 <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/n_tty.c46
-rw-r--r--drivers/tty/pty.c1
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);