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>
This commit is contained in:
Alan Cox 2009-07-16 16:05:08 +01:00 committed by Linus Torvalds
parent a3ca86aea5
commit c8d5004173
1 changed files with 15 additions and 10 deletions

View File

@ -790,17 +790,20 @@ void tty_ldisc_hangup(struct tty_struct *tty)
* N_TTY. * N_TTY.
*/ */
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
/* Avoid racing set_ldisc */ /* Avoid racing set_ldisc or tty_ldisc_release */
mutex_lock(&tty->ldisc_mutex); mutex_lock(&tty->ldisc_mutex);
if (tty->ldisc) { /* Not yet closed */
/* Switch back to N_TTY */ /* Switch back to N_TTY */
tty_ldisc_halt(tty); tty_ldisc_halt(tty);
tty_ldisc_wait_idle(tty); tty_ldisc_wait_idle(tty);
tty_ldisc_reinit(tty); tty_ldisc_reinit(tty);
/* At this point we have a closed ldisc and we want to /* At this point we have a closed ldisc and we want to
reopen it. We could defer this to the next open but reopen it. We could defer this to the next open but
it means auditing a lot of other paths so this is a FIXME */ it means auditing a lot of other paths so this is
a FIXME */
WARN_ON(tty_ldisc_open(tty, tty->ldisc)); WARN_ON(tty_ldisc_open(tty, tty->ldisc));
tty_ldisc_enable(tty); tty_ldisc_enable(tty);
}
mutex_unlock(&tty->ldisc_mutex); mutex_unlock(&tty->ldisc_mutex);
tty_reset_termios(tty); tty_reset_termios(tty);
} }
@ -865,6 +868,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_wait_idle(tty); tty_ldisc_wait_idle(tty);
mutex_lock(&tty->ldisc_mutex);
/* /*
* Now kill off the ldisc * Now kill off the ldisc
*/ */
@ -875,6 +879,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
/* Ensure the next open requests the N_TTY ldisc */ /* Ensure the next open requests the N_TTY ldisc */
tty_set_termios_ldisc(tty, N_TTY); tty_set_termios_ldisc(tty, N_TTY);
mutex_unlock(&tty->ldisc_mutex);
/* This will need doing differently if we need to lock */ /* This will need doing differently if we need to lock */
if (o_tty) if (o_tty)