Commit c8d50041 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

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: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a3ca86ae
...@@ -790,17 +790,20 @@ void tty_ldisc_hangup(struct tty_struct *tty) ...@@ -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);
/* Switch back to N_TTY */ if (tty->ldisc) { /* Not yet closed */
tty_ldisc_halt(tty); /* Switch back to N_TTY */
tty_ldisc_wait_idle(tty); tty_ldisc_halt(tty);
tty_ldisc_reinit(tty); tty_ldisc_wait_idle(tty);
/* At this point we have a closed ldisc and we want to tty_ldisc_reinit(tty);
reopen it. We could defer this to the next open but /* At this point we have a closed ldisc and we want to
it means auditing a lot of other paths so this is a FIXME */ reopen it. We could defer this to the next open but
WARN_ON(tty_ldisc_open(tty, tty->ldisc)); it means auditing a lot of other paths so this is
tty_ldisc_enable(tty); a FIXME */
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
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) ...@@ -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) ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment