diff options
author | Alan Cox <alan@linux.intel.com> | 2009-07-16 11:05:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-07-16 12:19:16 -0400 |
commit | c8d50041734534e0a4b0ea13df36ed5857fccd56 (patch) | |
tree | c654fde94ba2fbf1eb936f017d687860aed0deed /drivers/char | |
parent | a3ca86aea507904148870946d599e07a340b39bf (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.c | 25 |
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) |