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

Changed files
+30 -75
drivers
acpi
tty
+1 -1
drivers/acpi/spcr.c
··· 30 return true; 31 32 if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && 33 - h->oem_revision == 0) 34 return true; 35 36 return false;
··· 30 return true; 31 32 if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && 33 + h->oem_revision == 1) 34 return true; 35 36 return false;
+7 -2
drivers/tty/serial/8250/8250_dw.c
··· 257 { 258 unsigned int baud = tty_termios_baud_rate(termios); 259 struct dw8250_data *d = p->private_data; 260 - unsigned int rate; 261 int ret; 262 263 if (IS_ERR(d->clk) || !old) ··· 265 266 clk_disable_unprepare(d->clk); 267 rate = clk_round_rate(d->clk, baud * 16); 268 - ret = clk_set_rate(d->clk, rate); 269 clk_prepare_enable(d->clk); 270 271 if (!ret)
··· 257 { 258 unsigned int baud = tty_termios_baud_rate(termios); 259 struct dw8250_data *d = p->private_data; 260 + long rate; 261 int ret; 262 263 if (IS_ERR(d->clk) || !old) ··· 265 266 clk_disable_unprepare(d->clk); 267 rate = clk_round_rate(d->clk, baud * 16); 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); 274 clk_prepare_enable(d->clk); 275 276 if (!ret)
+1 -1
drivers/tty/serial/amba-pl011.c
··· 2373 if (strcmp(name, "qdf2400_e44") == 0) { 2374 pr_info_once("UART: Working around QDF2400 SoC erratum 44"); 2375 qdf2400_e44_present = true; 2376 - } else if (strcmp(name, "pl011") != 0 || strcmp(name, "ttyAMA") != 0) { 2377 return -ENODEV; 2378 } 2379
··· 2373 if (strcmp(name, "qdf2400_e44") == 0) { 2374 pr_info_once("UART: Working around QDF2400 SoC erratum 44"); 2375 qdf2400_e44_present = true; 2376 + } else if (strcmp(name, "pl011") != 0) { 2377 return -ENODEV; 2378 } 2379
+21 -71
drivers/tty/tty_ldisc.c
··· 271 272 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 273 { 274 ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); 275 - if (!tty->ldisc) 276 ldsem_up_read(&tty->ldisc_sem); 277 - return tty->ldisc; 278 } 279 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 280 ··· 492 } 493 494 /** 495 - * tty_ldisc_restore - helper for tty ldisc change 496 - * @tty: tty to recover 497 - * @old: previous ldisc 498 - * 499 - * Restore the previous line discipline or N_TTY when a line discipline 500 - * change fails due to an open error 501 - */ 502 - 503 - static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) 504 - { 505 - struct tty_ldisc *new_ldisc; 506 - int r; 507 - 508 - /* There is an outstanding reference here so this is safe */ 509 - old = tty_ldisc_get(tty, old->ops->num); 510 - WARN_ON(IS_ERR(old)); 511 - tty->ldisc = old; 512 - tty_set_termios_ldisc(tty, old->ops->num); 513 - if (tty_ldisc_open(tty, old) < 0) { 514 - tty_ldisc_put(old); 515 - /* This driver is always present */ 516 - new_ldisc = tty_ldisc_get(tty, N_TTY); 517 - if (IS_ERR(new_ldisc)) 518 - panic("n_tty: get"); 519 - tty->ldisc = new_ldisc; 520 - tty_set_termios_ldisc(tty, N_TTY); 521 - r = tty_ldisc_open(tty, new_ldisc); 522 - if (r < 0) 523 - panic("Couldn't open N_TTY ldisc for " 524 - "%s --- error %d.", 525 - tty_name(tty), r); 526 - } 527 - } 528 - 529 - /** 530 * tty_set_ldisc - set line discipline 531 * @tty: the terminal to set 532 * @ldisc: the line discipline ··· 504 505 int tty_set_ldisc(struct tty_struct *tty, int disc) 506 { 507 - int retval; 508 - struct tty_ldisc *old_ldisc, *new_ldisc; 509 - 510 - new_ldisc = tty_ldisc_get(tty, disc); 511 - if (IS_ERR(new_ldisc)) 512 - return PTR_ERR(new_ldisc); 513 514 tty_lock(tty); 515 retval = tty_ldisc_lock(tty, 5 * HZ); ··· 517 } 518 519 /* Check the no-op case */ 520 - if (tty->ldisc->ops->num == disc) 521 goto out; 522 523 if (test_bit(TTY_HUPPED, &tty->flags)) { ··· 527 goto out; 528 } 529 530 - old_ldisc = tty->ldisc; 531 - 532 - /* Shutdown the old discipline. */ 533 - tty_ldisc_close(tty, old_ldisc); 534 - 535 - /* Now set up the new line discipline. */ 536 - tty->ldisc = new_ldisc; 537 - tty_set_termios_ldisc(tty, disc); 538 - 539 - retval = tty_ldisc_open(tty, new_ldisc); 540 if (retval < 0) { 541 /* Back to the old one or N_TTY if we can't */ 542 - tty_ldisc_put(new_ldisc); 543 - tty_ldisc_restore(tty, old_ldisc); 544 } 545 546 - if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) { 547 down_read(&tty->termios_rwsem); 548 tty->ops->set_ldisc(tty); 549 up_read(&tty->termios_rwsem); 550 } 551 552 - /* At this point we hold a reference to the new ldisc and a 553 - reference to the old ldisc, or we hold two references to 554 - the old ldisc (if it was restored as part of error cleanup 555 - above). In either case, releasing a single reference from 556 - the old ldisc is correct. */ 557 - new_ldisc = old_ldisc; 558 out: 559 tty_ldisc_unlock(tty); 560 ··· 553 already running */ 554 tty_buffer_restart_work(tty->port); 555 err: 556 - tty_ldisc_put(new_ldisc); /* drop the extra reference */ 557 tty_unlock(tty); 558 return retval; 559 } ··· 613 int retval; 614 615 ld = tty_ldisc_get(tty, disc); 616 - if (IS_ERR(ld)) { 617 - BUG_ON(disc == N_TTY); 618 return PTR_ERR(ld); 619 - } 620 621 if (tty->ldisc) { 622 tty_ldisc_close(tty, tty->ldisc); ··· 626 tty_set_termios_ldisc(tty, disc); 627 retval = tty_ldisc_open(tty, tty->ldisc); 628 if (retval) { 629 - if (!WARN_ON(disc == N_TTY)) { 630 - tty_ldisc_put(tty->ldisc); 631 - tty->ldisc = NULL; 632 - } 633 } 634 return retval; 635 }
··· 271 272 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 273 { 274 + struct tty_ldisc *ld; 275 + 276 ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); 277 + ld = tty->ldisc; 278 + if (!ld) 279 ldsem_up_read(&tty->ldisc_sem); 280 + return ld; 281 } 282 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 283 ··· 489 } 490 491 /** 492 * tty_set_ldisc - set line discipline 493 * @tty: the terminal to set 494 * @ldisc: the line discipline ··· 536 537 int tty_set_ldisc(struct tty_struct *tty, int disc) 538 { 539 + int retval, old_disc; 540 541 tty_lock(tty); 542 retval = tty_ldisc_lock(tty, 5 * HZ); ··· 554 } 555 556 /* Check the no-op case */ 557 + old_disc = tty->ldisc->ops->num; 558 + if (old_disc == disc) 559 goto out; 560 561 if (test_bit(TTY_HUPPED, &tty->flags)) { ··· 563 goto out; 564 } 565 566 + retval = tty_ldisc_reinit(tty, disc); 567 if (retval < 0) { 568 /* Back to the old one or N_TTY if we can't */ 569 + if (tty_ldisc_reinit(tty, old_disc) < 0) { 570 + pr_err("tty: TIOCSETD failed, reinitializing N_TTY\n"); 571 + if (tty_ldisc_reinit(tty, N_TTY) < 0) { 572 + /* At this point we have tty->ldisc == NULL. */ 573 + pr_err("tty: reinitializing N_TTY failed\n"); 574 + } 575 + } 576 } 577 578 + if (tty->ldisc && tty->ldisc->ops->num != old_disc && 579 + tty->ops->set_ldisc) { 580 down_read(&tty->termios_rwsem); 581 tty->ops->set_ldisc(tty); 582 up_read(&tty->termios_rwsem); 583 } 584 585 out: 586 tty_ldisc_unlock(tty); 587 ··· 598 already running */ 599 tty_buffer_restart_work(tty->port); 600 err: 601 tty_unlock(tty); 602 return retval; 603 } ··· 659 int retval; 660 661 ld = tty_ldisc_get(tty, disc); 662 + if (IS_ERR(ld)) 663 return PTR_ERR(ld); 664 665 if (tty->ldisc) { 666 tty_ldisc_close(tty, tty->ldisc); ··· 674 tty_set_termios_ldisc(tty, disc); 675 retval = tty_ldisc_open(tty, tty->ldisc); 676 if (retval) { 677 + tty_ldisc_put(tty->ldisc); 678 + tty->ldisc = NULL; 679 } 680 return retval; 681 }