Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+30 -75
+1 -1
drivers/acpi/spcr.c
··· 30 30 return true; 31 31 32 32 if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && 33 - h->oem_revision == 0) 33 + h->oem_revision == 1) 34 34 return true; 35 35 36 36 return false;
+7 -2
drivers/tty/serial/8250/8250_dw.c
··· 257 257 { 258 258 unsigned int baud = tty_termios_baud_rate(termios); 259 259 struct dw8250_data *d = p->private_data; 260 - unsigned int rate; 260 + long rate; 261 261 int ret; 262 262 263 263 if (IS_ERR(d->clk) || !old) ··· 265 265 266 266 clk_disable_unprepare(d->clk); 267 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 274 clk_prepare_enable(d->clk); 270 275 271 276 if (!ret)
+1 -1
drivers/tty/serial/amba-pl011.c
··· 2373 2373 if (strcmp(name, "qdf2400_e44") == 0) { 2374 2374 pr_info_once("UART: Working around QDF2400 SoC erratum 44"); 2375 2375 qdf2400_e44_present = true; 2376 - } else if (strcmp(name, "pl011") != 0 || strcmp(name, "ttyAMA") != 0) { 2376 + } else if (strcmp(name, "pl011") != 0) { 2377 2377 return -ENODEV; 2378 2378 } 2379 2379
+21 -71
drivers/tty/tty_ldisc.c
··· 271 271 272 272 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 273 273 { 274 + struct tty_ldisc *ld; 275 + 274 276 ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); 275 - if (!tty->ldisc) 277 + ld = tty->ldisc; 278 + if (!ld) 276 279 ldsem_up_read(&tty->ldisc_sem); 277 - return tty->ldisc; 280 + return ld; 278 281 } 279 282 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 280 283 ··· 492 489 } 493 490 494 491 /** 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 492 * tty_set_ldisc - set line discipline 531 493 * @tty: the terminal to set 532 494 * @ldisc: the line discipline ··· 504 536 505 537 int tty_set_ldisc(struct tty_struct *tty, int disc) 506 538 { 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); 539 + int retval, old_disc; 513 540 514 541 tty_lock(tty); 515 542 retval = tty_ldisc_lock(tty, 5 * HZ); ··· 517 554 } 518 555 519 556 /* Check the no-op case */ 520 - if (tty->ldisc->ops->num == disc) 557 + old_disc = tty->ldisc->ops->num; 558 + if (old_disc == disc) 521 559 goto out; 522 560 523 561 if (test_bit(TTY_HUPPED, &tty->flags)) { ··· 527 563 goto out; 528 564 } 529 565 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); 566 + retval = tty_ldisc_reinit(tty, disc); 540 567 if (retval < 0) { 541 568 /* 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); 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 + } 544 576 } 545 577 546 - if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) { 578 + if (tty->ldisc && tty->ldisc->ops->num != old_disc && 579 + tty->ops->set_ldisc) { 547 580 down_read(&tty->termios_rwsem); 548 581 tty->ops->set_ldisc(tty); 549 582 up_read(&tty->termios_rwsem); 550 583 } 551 584 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 585 out: 559 586 tty_ldisc_unlock(tty); 560 587 ··· 553 598 already running */ 554 599 tty_buffer_restart_work(tty->port); 555 600 err: 556 - tty_ldisc_put(new_ldisc); /* drop the extra reference */ 557 601 tty_unlock(tty); 558 602 return retval; 559 603 } ··· 613 659 int retval; 614 660 615 661 ld = tty_ldisc_get(tty, disc); 616 - if (IS_ERR(ld)) { 617 - BUG_ON(disc == N_TTY); 662 + if (IS_ERR(ld)) 618 663 return PTR_ERR(ld); 619 - } 620 664 621 665 if (tty->ldisc) { 622 666 tty_ldisc_close(tty, tty->ldisc); ··· 626 674 tty_set_termios_ldisc(tty, disc); 627 675 retval = tty_ldisc_open(tty, tty->ldisc); 628 676 if (retval) { 629 - if (!WARN_ON(disc == N_TTY)) { 630 - tty_ldisc_put(tty->ldisc); 631 - tty->ldisc = NULL; 632 - } 677 + tty_ldisc_put(tty->ldisc); 678 + tty->ldisc = NULL; 633 679 } 634 680 return retval; 635 681 }