patch "Fix OpenSSH pty regression on close" added to tty-next
Subsystems (3)
This is a note to let you know that I've just added the patch titled
Fix OpenSSH pty regression on close
to my tty git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
in the tty-next branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will also be merged in the next major kernel release during the merge window.
If you have any questions about this process, please let me know.
Quoted 1 line
From
0f40fbbcc34e093255a2b2d70b6b0fb48c3f39aaMon Sep 17 00:00:00 2001
From: Brian Bloniarz <[email protected]>
Date: Sun, 6 Mar 2016 13:16:30 -0800
Subject: Fix OpenSSH pty regression on close
OpenSSH expects the (non-blocking) read() of pty master to return EAGAIN only if it has received all of the slave-side output after it has received SIGCHLD. This used to work on pre-3.12 kernels.
This fix effectively forces non-blocking read() and poll() to block for parallel i/o to complete for all ttys. It also unwinds these changes:
1) f8747d4a466ab2cafe56112c51b3379f9fdb7a12
tty: Fix pty master read() after slave closes
2) 52bce7f8d4fc633c9a9d0646eef58ba6ae9a3b73 pty, n_tty: Simplify input processing on final close
3) 1a48632ffed61352a7810ce089dc5a8bcd505a60
pty: Fix input race when closing
Inspired by analysis and patch from Marc Aurele La France <[email protected]>
--- Documentation/serial/tty.txt | 3 -- drivers/tty/n_hdlc.c | 4 +-- drivers/tty/n_tty.c | 70 +++++++++++++++++++++----------------------- drivers/tty/pty.c | 4 +-- drivers/tty/tty_buffer.c | 34 ++++----------------- include/linux/tty.h | 2 +- 6 files changed, 43 insertions(+), 74 deletions(-)
Documentation/serial/tty.txt +0 -3
@@ -210,9 +210,6 @@ TTY_IO_ERROR If set, causes all subsequent userspace read/write TTY_OTHER_CLOSED Device is a pty and the other side has closed. -TTY_OTHER_DONE Device is a pty and the other side has closed and - all pending input processing has been completed. - TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into smaller chunks.
drivers/tty/n_hdlc.c +2 -2
@@ -599,7 +599,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,add_wait_queue (&tty->read_wait, &wait);for (;;) { -if (test_bit (TTY_OTHER_DONE , &tty->flags)) { +if (test_bit (TTY_OTHER_CLOSED , &tty->flags)) { ret = -EIO ;break ; }
@@ -827,7 +827,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,/* set bits for operations that won't block */ if (n_hdlc->rx_buf_list.head) mask |=POLLIN |POLLRDNORM ;/* readable */ -if (test_bit (TTY_OTHER_DONE , &tty->flags)) +if (test_bit (TTY_OTHER_CLOSED , &tty->flags)) mask |=POLLHUP ;if (tty_hung_up_p (filp)) mask |=POLLHUP ;
drivers/tty/n_tty.c +33 -37
102 lines not on this page · raw message
drivers/tty/pty.c +1 -3
@@ -59,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)if (!tty->link)return ;set_bit (TTY_OTHER_CLOSED , &tty->link->flags); -tty_flip_buffer_push (tty->link->port); +wake_up_interruptible (&tty->link->read_wait);wake_up_interruptible (&tty->link->write_wait);if (tty->driver->subtype ==PTY_TYPE_MASTER ) {set_bit (TTY_OTHER_CLOSED , &tty->flags);
@@ -247,9 +247,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp) goto out;clear_bit (TTY_IO_ERROR , &tty->flags); -/* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */ clear_bit (TTY_OTHER_CLOSED , &tty->link->flags); -clear_bit (TTY_OTHER_DONE , &tty->link->flags);set_bit (TTY_THROTTLED , &tty->flags);return 0 ;
drivers/tty/tty_buffer.c +6 -28
@@ -37,29 +37,6 @@#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) -/* -* If all tty flip buffers have been processed by flush_to_ldisc() or -* dropped by tty_buffer_flush(), check if the linked pty has been closed. -* If so, wake the reader/poll to process -*/ -static inline void check_other_closed (struct tty_struct *tty) -{ -unsigned long flags, old; - -/* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */ -for (flags =ACCESS_ONCE (tty->flags); -test_bit (TTY_OTHER_CLOSED , &flags); - ) { - old = flags; -__set_bit (TTY_OTHER_DONE , &flags); - flags =cmpxchg (&tty->flags, old, flags); -if (old == flags) { -wake_up_interruptible (&tty->read_wait); -break ; - } - } -} -/** * tty_buffer_lock_exclusive - gain exclusive access to buffer * tty_buffer_unlock_exclusive - release exclusive access
@@ -254,8 +231,6 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer (tty); -check_other_closed (tty); -atomic_dec (&buf->priority);mutex_unlock (&buf->lock); }
@@ -522,10 +497,8 @@ static void flush_to_ldisc(struct work_struct *work)*/ count =smp_load_acquire (&head->commit) - head->read;if (!count) { -if (next ==NULL ) { -check_other_closed (tty); +if (next ==NULL )break ; - } buf->head = next;tty_buffer_free (port, head);continue ;
@@ -614,3 +587,8 @@ bool tty_buffer_cancel_work(struct tty_port *port) {return cancel_work_sync (&port->buf.work); } + +void tty_buffer_flush_work (struct tty_port *port) +{ +flush_work (&port->buf.work); +}
include/linux/tty.h +1 -1
@@ -351,7 +351,6 @@ struct tty_file_private {#define TTY_OTHER_CLOSED 2/* Other side (if any) has closed */ #define TTY_EXCLUSIVE 3/* Exclusive open mode */ #define TTY_DO_WRITE_WAKEUP 5/* Call write_wakeup after queuing new */ -#define TTY_OTHER_DONE 6/* Closed pty has completed input processing */ #define TTY_LDISC_OPEN 11/* Line discipline is open */ #define TTY_PTY_LOCK 16/* pty private */ #define TTY_NO_WRITE_SPLIT 17/* Preserve write boundaries to driver */
@@ -480,6 +479,7 @@ extern void tty_buffer_init(struct tty_port *port);extern void tty_buffer_set_lock_subclass (struct tty_port *port);extern bool tty_buffer_restart_work (struct tty_port *port);extern bool tty_buffer_cancel_work (struct tty_port *port); +extern void tty_buffer_flush_work (struct tty_port *port);extern speed_t tty_termios_baud_rate (struct ktermios *termios);extern speed_t tty_termios_input_baud_rate (struct ktermios *termios); extern void tty_termios_encode_baud_rate(struct ktermios *termios,
Signature · 1 line
2.8.2