diff options
Diffstat (limited to 'drivers')
-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 | /** |