diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-05-17 00:10:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-05-17 00:10:05 -0400 |
commit | dd8edd7e97bdc5d4b96e9f13c2fab3fdc6c9ca1f (patch) | |
tree | 0aed219030fb430b033ad8dcd9db08dcd534fa6e | |
parent | 3f4741b1d863f624e8632b3283af5eabe35c2fca (diff) | |
parent | 1a48632ffed61352a7810ce089dc5a8bcd505a60 (diff) |
Merge tag 'tty-4.1-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial fixes from Greg KH:
"Here's some TTY and serial driver fixes for reported issues.
All of these have been in linux-next successfully"
* tag 'tty-4.1-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
pty: Fix input race when closing
tty/n_gsm.c: fix a memory leak when gsmtty is removed
Revert "serial/amba-pl011: Leave the TX IRQ alone when the UART is not open"
serial: omap: Fix error handling in probe
earlycon: Revert log warnings
-rw-r--r-- | Documentation/serial/tty.txt | 3 | ||||
-rw-r--r-- | drivers/tty/n_gsm.c | 5 | ||||
-rw-r--r-- | drivers/tty/n_hdlc.c | 4 | ||||
-rw-r--r-- | drivers/tty/n_tty.c | 22 | ||||
-rw-r--r-- | drivers/tty/pty.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/earlycon.c | 9 | ||||
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 2 | ||||
-rw-r--r-- | drivers/tty/tty_buffer.c | 41 | ||||
-rw-r--r-- | include/linux/tty.h | 2 |
10 files changed, 64 insertions, 34 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 | ||
199 | TTY_OTHER_CLOSED Device is a pty and the other side has closed. | 199 | TTY_OTHER_CLOSED Device is a pty and the other side has closed. |
200 | 200 | ||
201 | TTY_OTHER_DONE Device is a pty and the other side has closed and | ||
202 | all pending input processing has been completed. | ||
203 | |||
201 | TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into | 204 | TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into |
202 | smaller chunks. | 205 | smaller chunks. |
203 | 206 | ||
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 91abc00aa833..2c34c3249972 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c | |||
@@ -3170,7 +3170,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) | |||
3170 | return gsmtty_modem_update(dlci, encode); | 3170 | return gsmtty_modem_update(dlci, encode); |
3171 | } | 3171 | } |
3172 | 3172 | ||
3173 | static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) | 3173 | static void gsmtty_cleanup(struct tty_struct *tty) |
3174 | { | 3174 | { |
3175 | struct gsm_dlci *dlci = tty->driver_data; | 3175 | struct gsm_dlci *dlci = tty->driver_data; |
3176 | struct gsm_mux *gsm = dlci->gsm; | 3176 | struct gsm_mux *gsm = dlci->gsm; |
@@ -3178,7 +3178,6 @@ static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) | |||
3178 | dlci_put(dlci); | 3178 | dlci_put(dlci); |
3179 | dlci_put(gsm->dlci[0]); | 3179 | dlci_put(gsm->dlci[0]); |
3180 | mux_put(gsm); | 3180 | mux_put(gsm); |
3181 | driver->ttys[tty->index] = NULL; | ||
3182 | } | 3181 | } |
3183 | 3182 | ||
3184 | /* Virtual ttys for the demux */ | 3183 | /* Virtual ttys for the demux */ |
@@ -3199,7 +3198,7 @@ static const struct tty_operations gsmtty_ops = { | |||
3199 | .tiocmget = gsmtty_tiocmget, | 3198 | .tiocmget = gsmtty_tiocmget, |
3200 | .tiocmset = gsmtty_tiocmset, | 3199 | .tiocmset = gsmtty_tiocmset, |
3201 | .break_ctl = gsmtty_break_ctl, | 3200 | .break_ctl = gsmtty_break_ctl, |
3202 | .remove = gsmtty_remove, | 3201 | .cleanup = gsmtty_cleanup, |
3203 | }; | 3202 | }; |
3204 | 3203 | ||
3205 | 3204 | ||
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 | ||
1952 | static 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/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 5a4e9d579585..6f5a0720a8c8 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -1639,6 +1639,9 @@ static int pl011_startup(struct uart_port *port) | |||
1639 | 1639 | ||
1640 | writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); | 1640 | writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); |
1641 | 1641 | ||
1642 | /* Assume that TX IRQ doesn't work until we see one: */ | ||
1643 | uap->tx_irq_seen = 0; | ||
1644 | |||
1642 | spin_lock_irq(&uap->port.lock); | 1645 | spin_lock_irq(&uap->port.lock); |
1643 | 1646 | ||
1644 | /* restore RTS and DTR */ | 1647 | /* restore RTS and DTR */ |
@@ -1702,7 +1705,7 @@ static void pl011_shutdown(struct uart_port *port) | |||
1702 | spin_lock_irq(&uap->port.lock); | 1705 | spin_lock_irq(&uap->port.lock); |
1703 | uap->im = 0; | 1706 | uap->im = 0; |
1704 | writew(uap->im, uap->port.membase + UART011_IMSC); | 1707 | writew(uap->im, uap->port.membase + UART011_IMSC); |
1705 | writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR); | 1708 | writew(0xffff, uap->port.membase + UART011_ICR); |
1706 | spin_unlock_irq(&uap->port.lock); | 1709 | spin_unlock_irq(&uap->port.lock); |
1707 | 1710 | ||
1708 | pl011_dma_shutdown(uap); | 1711 | pl011_dma_shutdown(uap); |
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 5fdc9f3ecd64..6dc471e30e79 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c | |||
@@ -187,13 +187,8 @@ static int __init param_setup_earlycon(char *buf) | |||
187 | return 0; | 187 | return 0; |
188 | 188 | ||
189 | err = setup_earlycon(buf); | 189 | err = setup_earlycon(buf); |
190 | if (err == -ENOENT) { | 190 | if (err == -ENOENT || err == -EALREADY) |
191 | pr_warn("no match for %s\n", buf); | 191 | return 0; |
192 | err = 0; | ||
193 | } else if (err == -EALREADY) { | ||
194 | pr_warn("already registered\n"); | ||
195 | err = 0; | ||
196 | } | ||
197 | return err; | 192 | return err; |
198 | } | 193 | } |
199 | early_param("earlycon", param_setup_earlycon); | 194 | early_param("earlycon", param_setup_earlycon); |
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 211479aa34bb..7f49172ccd86 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c | |||
@@ -1735,6 +1735,8 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1735 | err_add_port: | 1735 | err_add_port: |
1736 | pm_runtime_put(&pdev->dev); | 1736 | pm_runtime_put(&pdev->dev); |
1737 | pm_runtime_disable(&pdev->dev); | 1737 | pm_runtime_disable(&pdev->dev); |
1738 | pm_qos_remove_request(&up->pm_qos_request); | ||
1739 | device_init_wakeup(up->dev, false); | ||
1738 | err_rs485: | 1740 | err_rs485: |
1739 | err_port_line: | 1741 | err_port_line: |
1740 | return ret; | 1742 | return ret; |
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 | */ | ||
45 | static 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 | */ | ||
499 | void 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); | |||
462 | extern void do_SAK(struct tty_struct *tty); | 463 | extern void do_SAK(struct tty_struct *tty); |
463 | extern void __do_SAK(struct tty_struct *tty); | 464 | extern void __do_SAK(struct tty_struct *tty); |
464 | extern void no_tty(void); | 465 | extern void no_tty(void); |
465 | extern void tty_flush_to_ldisc(struct tty_struct *tty); | ||
466 | extern void tty_buffer_free_all(struct tty_port *port); | 466 | extern void tty_buffer_free_all(struct tty_port *port); |
467 | extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); | 467 | extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); |
468 | extern void tty_buffer_init(struct tty_port *port); | 468 | extern void tty_buffer_init(struct tty_port *port); |