aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/serial/tty.txt3
-rw-r--r--drivers/tty/n_hdlc.c4
-rw-r--r--drivers/tty/n_tty.c22
-rw-r--r--drivers/tty/pty.c5
-rw-r--r--drivers/tty/tty_buffer.c41
-rw-r--r--include/linux/tty.h2
6 files changed, 54 insertions, 23 deletions
diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt
index 1e52d67d0abf..dbe6623fed1c 100644
--- a/Documentation/serial/tty.txt
+++ b/Documentation/serial/tty.txt
@@ -198,6 +198,9 @@ TTY_IO_ERROR If set, causes all subsequent userspace read/write
198 198
199TTY_OTHER_CLOSED Device is a pty and the other side has closed. 199TTY_OTHER_CLOSED Device is a pty and the other side has closed.
200 200
201TTY_OTHER_DONE Device is a pty and the other side has closed and
202 all pending input processing has been completed.
203
201TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into 204TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into
202 smaller chunks. 205 smaller chunks.
203 206
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 644ddb841d9f..bbc4ce66c2c1 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -600,7 +600,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
600 add_wait_queue(&tty->read_wait, &wait); 600 add_wait_queue(&tty->read_wait, &wait);
601 601
602 for (;;) { 602 for (;;) {
603 if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { 603 if (test_bit(TTY_OTHER_DONE, &tty->flags)) {
604 ret = -EIO; 604 ret = -EIO;
605 break; 605 break;
606 } 606 }
@@ -828,7 +828,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
828 /* set bits for operations that won't block */ 828 /* set bits for operations that won't block */
829 if (n_hdlc->rx_buf_list.head) 829 if (n_hdlc->rx_buf_list.head)
830 mask |= POLLIN | POLLRDNORM; /* readable */ 830 mask |= POLLIN | POLLRDNORM; /* readable */
831 if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) 831 if (test_bit(TTY_OTHER_DONE, &tty->flags))
832 mask |= POLLHUP; 832 mask |= POLLHUP;
833 if (tty_hung_up_p(filp)) 833 if (tty_hung_up_p(filp))
834 mask |= POLLHUP; 834 mask |= POLLHUP;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index cf6e0f2e1331..cc57a3a6b02b 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1949,6 +1949,18 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
1949 return ldata->commit_head - ldata->read_tail >= amt; 1949 return ldata->commit_head - ldata->read_tail >= amt;
1950} 1950}
1951 1951
1952static inline int check_other_done(struct tty_struct *tty)
1953{
1954 int done = test_bit(TTY_OTHER_DONE, &tty->flags);
1955 if (done) {
1956 /* paired with cmpxchg() in check_other_closed(); ensures
1957 * read buffer head index is not stale
1958 */
1959 smp_mb__after_atomic();
1960 }
1961 return done;
1962}
1963
1952/** 1964/**
1953 * copy_from_read_buf - copy read data directly 1965 * copy_from_read_buf - copy read data directly
1954 * @tty: terminal device 1966 * @tty: terminal device
@@ -2167,7 +2179,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2167 struct n_tty_data *ldata = tty->disc_data; 2179 struct n_tty_data *ldata = tty->disc_data;
2168 unsigned char __user *b = buf; 2180 unsigned char __user *b = buf;
2169 DEFINE_WAIT_FUNC(wait, woken_wake_function); 2181 DEFINE_WAIT_FUNC(wait, woken_wake_function);
2170 int c; 2182 int c, done;
2171 int minimum, time; 2183 int minimum, time;
2172 ssize_t retval = 0; 2184 ssize_t retval = 0;
2173 long timeout; 2185 long timeout;
@@ -2235,8 +2247,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2235 ((minimum - (b - buf)) >= 1)) 2247 ((minimum - (b - buf)) >= 1))
2236 ldata->minimum_to_wake = (minimum - (b - buf)); 2248 ldata->minimum_to_wake = (minimum - (b - buf));
2237 2249
2250 done = check_other_done(tty);
2251
2238 if (!input_available_p(tty, 0)) { 2252 if (!input_available_p(tty, 0)) {
2239 if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { 2253 if (done) {
2240 retval = -EIO; 2254 retval = -EIO;
2241 break; 2255 break;
2242 } 2256 }
@@ -2443,12 +2457,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
2443 2457
2444 poll_wait(file, &tty->read_wait, wait); 2458 poll_wait(file, &tty->read_wait, wait);
2445 poll_wait(file, &tty->write_wait, wait); 2459 poll_wait(file, &tty->write_wait, wait);
2460 if (check_other_done(tty))
2461 mask |= POLLHUP;
2446 if (input_available_p(tty, 1)) 2462 if (input_available_p(tty, 1))
2447 mask |= POLLIN | POLLRDNORM; 2463 mask |= POLLIN | POLLRDNORM;
2448 if (tty->packet && tty->link->ctrl_status) 2464 if (tty->packet && tty->link->ctrl_status)
2449 mask |= POLLPRI | POLLIN | POLLRDNORM; 2465 mask |= POLLPRI | POLLIN | POLLRDNORM;
2450 if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
2451 mask |= POLLHUP;
2452 if (tty_hung_up_p(file)) 2466 if (tty_hung_up_p(file))
2453 mask |= POLLHUP; 2467 mask |= POLLHUP;
2454 if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { 2468 if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index e72ee629cead..4d5e8409769c 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -53,9 +53,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
53 /* Review - krefs on tty_link ?? */ 53 /* Review - krefs on tty_link ?? */
54 if (!tty->link) 54 if (!tty->link)
55 return; 55 return;
56 tty_flush_to_ldisc(tty->link);
57 set_bit(TTY_OTHER_CLOSED, &tty->link->flags); 56 set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
58 wake_up_interruptible(&tty->link->read_wait); 57 tty_flip_buffer_push(tty->link->port);
59 wake_up_interruptible(&tty->link->write_wait); 58 wake_up_interruptible(&tty->link->write_wait);
60 if (tty->driver->subtype == PTY_TYPE_MASTER) { 59 if (tty->driver->subtype == PTY_TYPE_MASTER) {
61 set_bit(TTY_OTHER_CLOSED, &tty->flags); 60 set_bit(TTY_OTHER_CLOSED, &tty->flags);
@@ -243,7 +242,9 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
243 goto out; 242 goto out;
244 243
245 clear_bit(TTY_IO_ERROR, &tty->flags); 244 clear_bit(TTY_IO_ERROR, &tty->flags);
245 /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
246 clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); 246 clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
247 clear_bit(TTY_OTHER_DONE, &tty->link->flags);
247 set_bit(TTY_THROTTLED, &tty->flags); 248 set_bit(TTY_THROTTLED, &tty->flags);
248 return 0; 249 return 0;
249 250
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 75661641f5fe..2f78b77f0f81 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -37,6 +37,28 @@
37 37
38#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) 38#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
39 39
40/*
41 * If all tty flip buffers have been processed by flush_to_ldisc() or
42 * dropped by tty_buffer_flush(), check if the linked pty has been closed.
43 * If so, wake the reader/poll to process
44 */
45static inline void check_other_closed(struct tty_struct *tty)
46{
47 unsigned long flags, old;
48
49 /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */
50 for (flags = ACCESS_ONCE(tty->flags);
51 test_bit(TTY_OTHER_CLOSED, &flags);
52 ) {
53 old = flags;
54 __set_bit(TTY_OTHER_DONE, &flags);
55 flags = cmpxchg(&tty->flags, old, flags);
56 if (old == flags) {
57 wake_up_interruptible(&tty->read_wait);
58 break;
59 }
60 }
61}
40 62
41/** 63/**
42 * tty_buffer_lock_exclusive - gain exclusive access to buffer 64 * tty_buffer_lock_exclusive - gain exclusive access to buffer
@@ -229,6 +251,8 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
229 if (ld && ld->ops->flush_buffer) 251 if (ld && ld->ops->flush_buffer)
230 ld->ops->flush_buffer(tty); 252 ld->ops->flush_buffer(tty);
231 253
254 check_other_closed(tty);
255
232 atomic_dec(&buf->priority); 256 atomic_dec(&buf->priority);
233 mutex_unlock(&buf->lock); 257 mutex_unlock(&buf->lock);
234} 258}
@@ -471,8 +495,10 @@ static void flush_to_ldisc(struct work_struct *work)
471 smp_rmb(); 495 smp_rmb();
472 count = head->commit - head->read; 496 count = head->commit - head->read;
473 if (!count) { 497 if (!count) {
474 if (next == NULL) 498 if (next == NULL) {
499 check_other_closed(tty);
475 break; 500 break;
501 }
476 buf->head = next; 502 buf->head = next;
477 tty_buffer_free(port, head); 503 tty_buffer_free(port, head);
478 continue; 504 continue;
@@ -489,19 +515,6 @@ static void flush_to_ldisc(struct work_struct *work)
489} 515}
490 516
491/** 517/**
492 * tty_flush_to_ldisc
493 * @tty: tty to push
494 *
495 * Push the terminal flip buffers to the line discipline.
496 *
497 * Must not be called from IRQ context.
498 */
499void tty_flush_to_ldisc(struct tty_struct *tty)
500{
501 flush_work(&tty->port->buf.work);
502}
503
504/**
505 * tty_flip_buffer_push - terminal 518 * tty_flip_buffer_push - terminal
506 * @port: tty port to push 519 * @port: tty port to push
507 * 520 *
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fe5623c9af71..d76631f615c2 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -339,6 +339,7 @@ struct tty_file_private {
339#define TTY_EXCLUSIVE 3 /* Exclusive open mode */ 339#define TTY_EXCLUSIVE 3 /* Exclusive open mode */
340#define TTY_DEBUG 4 /* Debugging */ 340#define TTY_DEBUG 4 /* Debugging */
341#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ 341#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */
342#define TTY_OTHER_DONE 6 /* Closed pty has completed input processing */
342#define TTY_LDISC_OPEN 11 /* Line discipline is open */ 343#define TTY_LDISC_OPEN 11 /* Line discipline is open */
343#define TTY_PTY_LOCK 16 /* pty private */ 344#define TTY_PTY_LOCK 16 /* pty private */
344#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ 345#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
@@ -462,7 +463,6 @@ extern int tty_hung_up_p(struct file *filp);
462extern void do_SAK(struct tty_struct *tty); 463extern void do_SAK(struct tty_struct *tty);
463extern void __do_SAK(struct tty_struct *tty); 464extern void __do_SAK(struct tty_struct *tty);
464extern void no_tty(void); 465extern void no_tty(void);
465extern void tty_flush_to_ldisc(struct tty_struct *tty);
466extern void tty_buffer_free_all(struct tty_port *port); 466extern void tty_buffer_free_all(struct tty_port *port);
467extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); 467extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
468extern void tty_buffer_init(struct tty_port *port); 468extern void tty_buffer_init(struct tty_port *port);