Merge tag 'tty-4.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty fix from Greg KH:
"Here is a single tty core revert for a patch that was reported to
cause problems.

The original issue is one that we have lived with for decades, so
trying to scramble to fix the fix in time for 4.11-final does not make
sense due to the fragility of the tty ldisc layer. Just reverting it
makes sense for now"

* tag 'tty-4.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
Revert "tty: don't panic on OOM in tty_set_ldisc()"

Changed files
+69 -16
drivers
+69 -16
drivers/tty/tty_ldisc.c
··· 492 } 493 494 /** 495 * tty_set_ldisc - set line discipline 496 * @tty: the terminal to set 497 * @ldisc: the line discipline ··· 539 540 int tty_set_ldisc(struct tty_struct *tty, int disc) 541 { 542 - int retval, old_disc; 543 544 tty_lock(tty); 545 retval = tty_ldisc_lock(tty, 5 * HZ); ··· 557 } 558 559 /* Check the no-op case */ 560 - old_disc = tty->ldisc->ops->num; 561 - if (old_disc == disc) 562 goto out; 563 564 if (test_bit(TTY_HUPPED, &tty->flags)) { ··· 566 goto out; 567 } 568 569 - retval = tty_ldisc_reinit(tty, disc); 570 if (retval < 0) { 571 /* Back to the old one or N_TTY if we can't */ 572 - if (tty_ldisc_reinit(tty, old_disc) < 0) { 573 - pr_err("tty: TIOCSETD failed, reinitializing N_TTY\n"); 574 - if (tty_ldisc_reinit(tty, N_TTY) < 0) { 575 - /* At this point we have tty->ldisc == NULL. */ 576 - pr_err("tty: reinitializing N_TTY failed\n"); 577 - } 578 - } 579 } 580 581 - if (tty->ldisc && tty->ldisc->ops->num != old_disc && 582 - tty->ops->set_ldisc) { 583 down_read(&tty->termios_rwsem); 584 tty->ops->set_ldisc(tty); 585 up_read(&tty->termios_rwsem); 586 } 587 588 out: 589 tty_ldisc_unlock(tty); 590 ··· 601 already running */ 602 tty_buffer_restart_work(tty->port); 603 err: 604 tty_unlock(tty); 605 return retval; 606 } ··· 662 int retval; 663 664 ld = tty_ldisc_get(tty, disc); 665 - if (IS_ERR(ld)) 666 return PTR_ERR(ld); 667 668 if (tty->ldisc) { 669 tty_ldisc_close(tty, tty->ldisc); ··· 677 tty_set_termios_ldisc(tty, disc); 678 retval = tty_ldisc_open(tty, tty->ldisc); 679 if (retval) { 680 - tty_ldisc_put(tty->ldisc); 681 - tty->ldisc = NULL; 682 } 683 return retval; 684 }
··· 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 }