diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-10-16 23:33:29 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-11-06 03:34:36 +0300 |
commit | 1aa1bf1115272d22fc4c758ee8769b73d8079a79 (patch) | |
tree | 880cd64a703772ce11bae136ac50ed2330a10803 /drivers/tty/n_tty.c | |
parent | 4ed60fc257185dbb0daea7cd3e4289d1658b11f6 (diff) | |
download | linux-1aa1bf1115272d22fc4c758ee8769b73d8079a79.tar.xz |
tty: Fix missed wakeup from packet mode status update
The pty master read() can miss the wake up for a packet mode
status change. For example,
CPU 0 | CPU 1
n_tty_read() | n_tty_packet_mode_flush()
... | .
if (packet & link->ctrl_status) { | .
/* no new ctrl_status ATM */ | .
| spin_lock
| ctrl_status |= TIOCPKT_FLUSHREAD
| spin_unlock
| wake_up(link->read_wait)
} |
set_current_state(TASK_INTERRUPTIBLE) |
... |
The pty master read() will now sleep (assuming there is no input) having
missed the read_wait wakeup.
Set the task state before the condition test.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Reviewed-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cd725cc6e21e..7f134b977c36 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2168,6 +2168,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, add_wait_queue(&tty->read_wait, &wait); while (nr) { + /* This statement must be first before checking for input + so that any interrupt will set the state back to + TASK_RUNNING. */ + set_current_state(TASK_INTERRUPTIBLE); + /* First test for status change. */ if (packet && tty->link->ctrl_status) { unsigned char cs; @@ -2185,10 +2190,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, nr--; break; } - /* This statement must be first before checking for input - so that any interrupt will set the state back to - TASK_RUNNING. */ - set_current_state(TASK_INTERRUPTIBLE); if (((minimum - (b - buf)) < ldata->minimum_to_wake) && ((minimum - (b - buf)) >= 1)) |