diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-26 14:03:42 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-26 14:03:42 -0400 |
| commit | f1638fc65ee23875cf4021e342e8a564debe33e4 (patch) | |
| tree | af091401ed9d05c93a9b9545f963fcc566e6d4d9 | |
| parent | 53b4d5911d6adef3f543e1ad23643068c5c343ac (diff) | |
| parent | a4a3e061149f09c075f108b6f1cf04d9739a6bc2 (diff) | |
Merge tag 'tty-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver fixes from Greg KH:
"Here are some tty and serial driver fixes for 4.11-rc4.
One of these fix a long-standing issue in the ldisc code that was
found by Dmitry Vyukov with his great fuzzing work. The other fixes
resolve other reported issues, and there is one revert of a patch in
4.11-rc1 that wasn't correct.
All of these have been in linux-next for a while with no reported
issues"
* tag 'tty-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
tty: fix data race in tty_ldisc_ref_wait()
tty: don't panic on OOM in tty_set_ldisc()
Revert "tty: serial: pl011: add ttyAMA for matching pl011 console"
tty: acpi/spcr: QDF2400 E44 checks for wrong OEM revision
serial: 8250_dw: Fix breakage when HAVE_CLK=n
serial: 8250_dw: Honor clk_round_rate errors in dw8250_set_termios
| -rw-r--r-- | drivers/acpi/spcr.c | 2 | ||||
| -rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 9 | ||||
| -rw-r--r-- | drivers/tty/serial/amba-pl011.c | 2 | ||||
| -rw-r--r-- | drivers/tty/tty_ldisc.c | 92 |
4 files changed, 30 insertions, 75 deletions
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 01c94669a2b0..3afa8c1fa127 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c | |||
| @@ -30,7 +30,7 @@ static bool qdf2400_erratum_44_present(struct acpi_table_header *h) | |||
| 30 | return true; | 30 | return true; |
| 31 | 31 | ||
| 32 | if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && | 32 | if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && |
| 33 | h->oem_revision == 0) | 33 | h->oem_revision == 1) |
| 34 | return true; | 34 | return true; |
| 35 | 35 | ||
| 36 | return false; | 36 | return false; |
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 6ee55a2d47bb..e65808c482f1 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c | |||
| @@ -257,7 +257,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, | |||
| 257 | { | 257 | { |
| 258 | unsigned int baud = tty_termios_baud_rate(termios); | 258 | unsigned int baud = tty_termios_baud_rate(termios); |
| 259 | struct dw8250_data *d = p->private_data; | 259 | struct dw8250_data *d = p->private_data; |
| 260 | unsigned int rate; | 260 | long rate; |
| 261 | int ret; | 261 | int ret; |
| 262 | 262 | ||
| 263 | if (IS_ERR(d->clk) || !old) | 263 | if (IS_ERR(d->clk) || !old) |
| @@ -265,7 +265,12 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, | |||
| 265 | 265 | ||
| 266 | clk_disable_unprepare(d->clk); | 266 | clk_disable_unprepare(d->clk); |
| 267 | rate = clk_round_rate(d->clk, baud * 16); | 267 | rate = clk_round_rate(d->clk, baud * 16); |
| 268 | ret = clk_set_rate(d->clk, rate); | 268 | if (rate < 0) |
| 269 | ret = rate; | ||
| 270 | else if (rate == 0) | ||
| 271 | ret = -ENOENT; | ||
| 272 | else | ||
| 273 | ret = clk_set_rate(d->clk, rate); | ||
| 269 | clk_prepare_enable(d->clk); | 274 | clk_prepare_enable(d->clk); |
| 270 | 275 | ||
| 271 | if (!ret) | 276 | if (!ret) |
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8789ea423ccf..56f92d7348bf 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
| @@ -2373,7 +2373,7 @@ static int __init pl011_console_match(struct console *co, char *name, int idx, | |||
| 2373 | if (strcmp(name, "qdf2400_e44") == 0) { | 2373 | if (strcmp(name, "qdf2400_e44") == 0) { |
| 2374 | pr_info_once("UART: Working around QDF2400 SoC erratum 44"); | 2374 | pr_info_once("UART: Working around QDF2400 SoC erratum 44"); |
| 2375 | qdf2400_e44_present = true; | 2375 | qdf2400_e44_present = true; |
| 2376 | } else if (strcmp(name, "pl011") != 0 || strcmp(name, "ttyAMA") != 0) { | 2376 | } else if (strcmp(name, "pl011") != 0) { |
| 2377 | return -ENODEV; | 2377 | return -ENODEV; |
| 2378 | } | 2378 | } |
| 2379 | 2379 | ||
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 68947f6de5ad..b0500a0a87b8 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
| @@ -271,10 +271,13 @@ const struct file_operations tty_ldiscs_proc_fops = { | |||
| 271 | 271 | ||
| 272 | struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) | 272 | struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) |
| 273 | { | 273 | { |
| 274 | struct tty_ldisc *ld; | ||
| 275 | |||
| 274 | ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); | 276 | ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); |
| 275 | if (!tty->ldisc) | 277 | ld = tty->ldisc; |
| 278 | if (!ld) | ||
| 276 | ldsem_up_read(&tty->ldisc_sem); | 279 | ldsem_up_read(&tty->ldisc_sem); |
| 277 | return tty->ldisc; | 280 | return ld; |
| 278 | } | 281 | } |
| 279 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | 282 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); |
| 280 | 283 | ||
| @@ -489,41 +492,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) | |||
| 489 | } | 492 | } |
| 490 | 493 | ||
| 491 | /** | 494 | /** |
| 492 | * tty_ldisc_restore - helper for tty ldisc change | ||
| 493 | * @tty: tty to recover | ||
| 494 | * @old: previous ldisc | ||
| 495 | * | ||
| 496 | * Restore the previous line discipline or N_TTY when a line discipline | ||
| 497 | * change fails due to an open error | ||
| 498 | */ | ||
| 499 | |||
| 500 | static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | ||
| 501 | { | ||
| 502 | struct tty_ldisc *new_ldisc; | ||
| 503 | int r; | ||
| 504 | |||
| 505 | /* There is an outstanding reference here so this is safe */ | ||
| 506 | old = tty_ldisc_get(tty, old->ops->num); | ||
| 507 | WARN_ON(IS_ERR(old)); | ||
| 508 | tty->ldisc = old; | ||
| 509 | tty_set_termios_ldisc(tty, old->ops->num); | ||
| 510 | if (tty_ldisc_open(tty, old) < 0) { | ||
| 511 | tty_ldisc_put(old); | ||
| 512 | /* This driver is always present */ | ||
| 513 | new_ldisc = tty_ldisc_get(tty, N_TTY); | ||
| 514 | if (IS_ERR(new_ldisc)) | ||
| 515 | panic("n_tty: get"); | ||
| 516 | tty->ldisc = new_ldisc; | ||
| 517 | tty_set_termios_ldisc(tty, N_TTY); | ||
| 518 | r = tty_ldisc_open(tty, new_ldisc); | ||
| 519 | if (r < 0) | ||
| 520 | panic("Couldn't open N_TTY ldisc for " | ||
| 521 | "%s --- error %d.", | ||
| 522 | tty_name(tty), r); | ||
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 526 | /** | ||
| 527 | * tty_set_ldisc - set line discipline | 495 | * tty_set_ldisc - set line discipline |
| 528 | * @tty: the terminal to set | 496 | * @tty: the terminal to set |
| 529 | * @ldisc: the line discipline | 497 | * @ldisc: the line discipline |
| @@ -536,12 +504,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | |||
| 536 | 504 | ||
| 537 | int tty_set_ldisc(struct tty_struct *tty, int disc) | 505 | int tty_set_ldisc(struct tty_struct *tty, int disc) |
| 538 | { | 506 | { |
| 539 | int retval; | 507 | int retval, old_disc; |
| 540 | struct tty_ldisc *old_ldisc, *new_ldisc; | ||
| 541 | |||
| 542 | new_ldisc = tty_ldisc_get(tty, disc); | ||
| 543 | if (IS_ERR(new_ldisc)) | ||
| 544 | return PTR_ERR(new_ldisc); | ||
| 545 | 508 | ||
| 546 | tty_lock(tty); | 509 | tty_lock(tty); |
| 547 | retval = tty_ldisc_lock(tty, 5 * HZ); | 510 | retval = tty_ldisc_lock(tty, 5 * HZ); |
| @@ -554,7 +517,8 @@ int tty_set_ldisc(struct tty_struct *tty, int disc) | |||
| 554 | } | 517 | } |
| 555 | 518 | ||
| 556 | /* Check the no-op case */ | 519 | /* Check the no-op case */ |
| 557 | if (tty->ldisc->ops->num == disc) | 520 | old_disc = tty->ldisc->ops->num; |
| 521 | if (old_disc == disc) | ||
| 558 | goto out; | 522 | goto out; |
| 559 | 523 | ||
| 560 | if (test_bit(TTY_HUPPED, &tty->flags)) { | 524 | if (test_bit(TTY_HUPPED, &tty->flags)) { |
| @@ -563,34 +527,25 @@ int tty_set_ldisc(struct tty_struct *tty, int disc) | |||
| 563 | goto out; | 527 | goto out; |
| 564 | } | 528 | } |
| 565 | 529 | ||
| 566 | old_ldisc = tty->ldisc; | 530 | retval = tty_ldisc_reinit(tty, disc); |
| 567 | |||
| 568 | /* Shutdown the old discipline. */ | ||
| 569 | tty_ldisc_close(tty, old_ldisc); | ||
| 570 | |||
| 571 | /* Now set up the new line discipline. */ | ||
| 572 | tty->ldisc = new_ldisc; | ||
| 573 | tty_set_termios_ldisc(tty, disc); | ||
| 574 | |||
| 575 | retval = tty_ldisc_open(tty, new_ldisc); | ||
| 576 | if (retval < 0) { | 531 | if (retval < 0) { |
| 577 | /* Back to the old one or N_TTY if we can't */ | 532 | /* Back to the old one or N_TTY if we can't */ |
| 578 | tty_ldisc_put(new_ldisc); | 533 | if (tty_ldisc_reinit(tty, old_disc) < 0) { |
| 579 | tty_ldisc_restore(tty, old_ldisc); | 534 | pr_err("tty: TIOCSETD failed, reinitializing N_TTY\n"); |
| 535 | if (tty_ldisc_reinit(tty, N_TTY) < 0) { | ||
| 536 | /* At this point we have tty->ldisc == NULL. */ | ||
| 537 | pr_err("tty: reinitializing N_TTY failed\n"); | ||
| 538 | } | ||
| 539 | } | ||
| 580 | } | 540 | } |
| 581 | 541 | ||
| 582 | if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) { | 542 | if (tty->ldisc && tty->ldisc->ops->num != old_disc && |
| 543 | tty->ops->set_ldisc) { | ||
| 583 | down_read(&tty->termios_rwsem); | 544 | down_read(&tty->termios_rwsem); |
| 584 | tty->ops->set_ldisc(tty); | 545 | tty->ops->set_ldisc(tty); |
| 585 | up_read(&tty->termios_rwsem); | 546 | up_read(&tty->termios_rwsem); |
| 586 | } | 547 | } |
| 587 | 548 | ||
| 588 | /* At this point we hold a reference to the new ldisc and a | ||
| 589 | reference to the old ldisc, or we hold two references to | ||
| 590 | the old ldisc (if it was restored as part of error cleanup | ||
| 591 | above). In either case, releasing a single reference from | ||
| 592 | the old ldisc is correct. */ | ||
| 593 | new_ldisc = old_ldisc; | ||
| 594 | out: | 549 | out: |
| 595 | tty_ldisc_unlock(tty); | 550 | tty_ldisc_unlock(tty); |
| 596 | 551 | ||
| @@ -598,7 +553,6 @@ out: | |||
