aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-07-16 11:05:08 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-07-16 12:19:16 -0400
commitc8d50041734534e0a4b0ea13df36ed5857fccd56 (patch)
treec654fde94ba2fbf1eb936f017d687860aed0deed /drivers/char
parenta3ca86aea507904148870946d599e07a340b39bf (diff)
tty: fix close/hangup race
We can get a situation where a hangup occurs during or after a close. In that case the ldisc gets disposed of by the close and the hangup then explodes. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/tty_ldisc.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 0ef0dc97ba20..acd76b767d4c 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -790,17 +790,20 @@ void tty_ldisc_hangup(struct tty_struct *tty)
790 * N_TTY. 790 * N_TTY.
791 */ 791 */
792 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { 792 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
793 /* Avoid racing set_ldisc */ 793 /* Avoid racing set_ldisc or tty_ldisc_release */
794 mutex_lock(&tty->ldisc_mutex); 794 mutex_lock(&tty->ldisc_mutex);
795 /* Switch back to N_TTY */ 795 if (tty->ldisc) { /* Not yet closed */
796 tty_ldisc_halt(tty); 796 /* Switch back to N_TTY */
797 tty_ldisc_wait_idle(tty); 797 tty_ldisc_halt(tty);
798 tty_ldisc_reinit(tty); 798 tty_ldisc_wait_idle(tty);
799 /* At this point we have a closed ldisc and we want to 799 tty_ldisc_reinit(tty);
800 reopen it. We could defer this to the next open but 800 /* At this point we have a closed ldisc and we want to
801 it means auditing a lot of other paths so this is a FIXME */ 801 reopen it. We could defer this to the next open but
802 WARN_ON(tty_ldisc_open(tty, tty->ldisc)); 802 it means auditing a lot of other paths so this is
803 tty_ldisc_enable(tty); 803 a FIXME */
804 WARN_ON(tty_ldisc_open(tty, tty->ldisc));
805 tty_ldisc_enable(tty);
806 }
804 mutex_unlock(&tty->ldisc_mutex); 807 mutex_unlock(&tty->ldisc_mutex);
805 tty_reset_termios(tty); 808 tty_reset_termios(tty);
806 } 809 }
@@ -865,6 +868,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
865 868
866 tty_ldisc_wait_idle(tty); 869 tty_ldisc_wait_idle(tty);
867 870
871 mutex_lock(&tty->ldisc_mutex);
868 /* 872 /*
869 * Now kill off the ldisc 873 * Now kill off the ldisc
870 */ 874 */
@@ -875,6 +879,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
875 879
876 /* Ensure the next open requests the N_TTY ldisc */ 880 /* Ensure the next open requests the N_TTY ldisc */
877 tty_set_termios_ldisc(tty, N_TTY); 881 tty_set_termios_ldisc(tty, N_TTY);
882 mutex_unlock(&tty->ldisc_mutex);
878 883
879 /* This will need doing differently if we need to lock */ 884 /* This will need doing differently if we need to lock */
880 if (o_tty) 885 if (o_tty)