diff options
| -rw-r--r-- | drivers/char/tty_ldisc.c | 50 |
1 files changed, 30 insertions, 20 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 3f653f7d849f..500e740ec5e4 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
| @@ -706,12 +706,13 @@ static void tty_reset_termios(struct tty_struct *tty) | |||
| 706 | /** | 706 | /** |
| 707 | * tty_ldisc_reinit - reinitialise the tty ldisc | 707 | * tty_ldisc_reinit - reinitialise the tty ldisc |
| 708 | * @tty: tty to reinit | 708 | * @tty: tty to reinit |
| 709 | * @ldisc: line discipline to reinitialize | ||
| 709 | * | 710 | * |
| 710 | * Switch the tty back to N_TTY line discipline and leave the | 711 | * Switch the tty to a line discipline and leave the ldisc |
| 711 | * ldisc state closed | 712 | * state closed |
| 712 | */ | 713 | */ |
| 713 | 714 | ||
| 714 | static void tty_ldisc_reinit(struct tty_struct *tty) | 715 | static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc) |
| 715 | { | 716 | { |
| 716 | struct tty_ldisc *ld; | 717 | struct tty_ldisc *ld; |
| 717 | 718 | ||
| @@ -721,10 +722,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty) | |||
| 721 | /* | 722 | /* |
| 722 | * Switch the line discipline back | 723 | * Switch the line discipline back |
| 723 | */ | 724 | */ |
| 724 | ld = tty_ldisc_get(N_TTY); | 725 | ld = tty_ldisc_get(ldisc); |
| 725 | BUG_ON(IS_ERR(ld)); | 726 | BUG_ON(IS_ERR(ld)); |
| 726 | tty_ldisc_assign(tty, ld); | 727 | tty_ldisc_assign(tty, ld); |
| 727 | tty_set_termios_ldisc(tty, N_TTY); | 728 | tty_set_termios_ldisc(tty, ldisc); |
| 728 | } | 729 | } |
| 729 | 730 | ||
| 730 | /** | 731 | /** |
| @@ -745,6 +746,8 @@ static void tty_ldisc_reinit(struct tty_struct *tty) | |||
| 745 | void tty_ldisc_hangup(struct tty_struct *tty) | 746 | void tty_ldisc_hangup(struct tty_struct *tty) |
| 746 | { | 747 | { |
| 747 | struct tty_ldisc *ld; | 748 | struct tty_ldisc *ld; |
| 749 | int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; | ||
| 750 | int err = 0; | ||
| 748 | 751 | ||
| 749 | /* | 752 | /* |
| 750 | * FIXME! What are the locking issues here? This may me overdoing | 753 | * FIXME! What are the locking issues here? This may me overdoing |
| @@ -772,25 +775,32 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
| 772 | wake_up_interruptible_poll(&tty->read_wait, POLLIN); | 775 | wake_up_interruptible_poll(&tty->read_wait, POLLIN); |
| 773 | /* | 776 | /* |
| 774 | * Shutdown the current line discipline, and reset it to | 777 | * Shutdown the current line discipline, and reset it to |
| 775 | * N_TTY. | 778 | * N_TTY if need be. |
| 779 | * | ||
| 780 | * Avoid racing set_ldisc or tty_ldisc_release | ||
| 776 | */ | 781 | */ |
| 777 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { | 782 | mutex_lock(&tty->ldisc_mutex); |
| 778 | /* Avoid racing set_ldisc or tty_ldisc_release */ | 783 | tty_ldisc_halt(tty); |
| 779 | mutex_lock(&tty->ldisc_mutex); | 784 | /* At this point we have a closed ldisc and we want to |
| 780 | tty_ldisc_halt(tty); | 785 | reopen it. We could defer this to the next open but |
| 781 | if (tty->ldisc) { /* Not yet closed */ | 786 | it means auditing a lot of other paths so this is |
| 782 | /* Switch back to N_TTY */ | 787 | a FIXME */ |
| 783 | tty_ldisc_reinit(tty); | 788 | if (tty->ldisc) { /* Not yet closed */ |
| 784 | /* At this point we have a closed ldisc and we want to | 789 | if (reset == 0) { |
| 785 | reopen it. We could defer this to the next open but | 790 | tty_ldisc_reinit(tty, tty->termios->c_line); |
| 786 | it means auditing a lot of other paths so this is | 791 | err = tty_ldisc_open(tty, tty->ldisc); |
| 787 | a FIXME */ | 792 | } |
| 793 | /* If the re-open fails or we reset then go to N_TTY. The | ||
| 794 | N_TTY open cannot fail */ | ||
| 795 | if (reset || err) { | ||
| 796 | tty_ldisc_reinit(tty, N_TTY); | ||
| 788 | WARN_ON(tty_ldisc_open(tty, tty->ldisc)); | 797 | WARN_ON(tty_ldisc_open(tty, tty->ldisc)); |
| 789 | tty_ldisc_enable(tty); | ||
| 790 | } | 798 | } |
| 791 | mutex_unlock(&tty->ldisc_mutex); | 799 | tty_ldisc_enable(tty); |
| 792 | tty_reset_termios(tty); | ||
| 793 | } | 800 | } |
| 801 | mutex_unlock(&tty->ldisc_mutex); | ||
| 802 | if (reset) | ||
| 803 | tty_reset_termios(tty); | ||
| 794 | } | 804 | } |
| 795 | 805 | ||
| 796 | /** | 806 | /** |
