aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/tty_ldisc.c50
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
714static void tty_ldisc_reinit(struct tty_struct *tty) 715static 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)
745void tty_ldisc_hangup(struct tty_struct *tty) 746void 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/**