Commit 7896f30d authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman

tty: Refactor tty_ldisc_reinit() for reuse

At tty hangup, the line discipline instance is reinitialized by
closing the current ldisc instance and opening a new instance.
This operation is complicated by error recovery: if the attempt
to reinit the current line discipline fails, the line discipline
is reset to N_TTY (which should not but can fail).

Re-purpose tty_ldisc_reinit() to return a valid, open line discipline
instance, or otherwise, an error.
Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c12da96f
...@@ -641,26 +641,41 @@ static void tty_reset_termios(struct tty_struct *tty) ...@@ -641,26 +641,41 @@ static void tty_reset_termios(struct tty_struct *tty)
* @tty: tty to reinit * @tty: tty to reinit
* @disc: line discipline to reinitialize * @disc: line discipline to reinitialize
* *
* Switch the tty to a line discipline and leave the ldisc * Completely reinitialize the line discipline state, by closing the
* state closed * current instance and opening a new instance. If an error occurs opening
* the new non-N_TTY instance, the instance is dropped and tty->ldisc reset
* to NULL. The caller can then retry with N_TTY instead.
*
* Returns 0 if successful, otherwise error code < 0
*/ */
static int tty_ldisc_reinit(struct tty_struct *tty, int disc) static int tty_ldisc_reinit(struct tty_struct *tty, int disc)
{ {
struct tty_ldisc *ld = tty_ldisc_get(tty, disc); struct tty_ldisc *ld;
int retval;
if (IS_ERR(ld)) ld = tty_ldisc_get(tty, disc);
return -1; if (IS_ERR(ld)) {
BUG_ON(disc == N_TTY);
return PTR_ERR(ld);
}
tty_ldisc_close(tty, tty->ldisc); if (tty->ldisc) {
tty_ldisc_put(tty->ldisc); tty_ldisc_close(tty, tty->ldisc);
/* tty_ldisc_put(tty->ldisc);
* Switch the line discipline back }
*/
/* switch the line discipline */
tty->ldisc = ld; tty->ldisc = ld;
tty_set_termios_ldisc(tty, disc); tty_set_termios_ldisc(tty, disc);
retval = tty_ldisc_open(tty, tty->ldisc);
return 0; if (retval) {
if (!WARN_ON(disc == N_TTY)) {
tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;
}
}
return retval;
} }
/** /**
...@@ -716,19 +731,13 @@ void tty_ldisc_hangup(struct tty_struct *tty) ...@@ -716,19 +731,13 @@ void tty_ldisc_hangup(struct tty_struct *tty)
reopen a new ldisc. We could defer the reopen to the next reopen a new ldisc. We could defer the reopen to the next
open but it means auditing a lot of other paths so this is open but it means auditing a lot of other paths so this is
a FIXME */ a FIXME */
if (reset == 0) { if (reset == 0)
err = tty_ldisc_reinit(tty, tty->termios.c_line);
if (!tty_ldisc_reinit(tty, tty->termios.c_line))
err = tty_ldisc_open(tty, tty->ldisc);
else
err = 1;
}
/* If the re-open fails or we reset then go to N_TTY. The /* If the re-open fails or we reset then go to N_TTY. The
N_TTY open cannot fail */ N_TTY open cannot fail */
if (reset || err) { if (reset || err < 0)
BUG_ON(tty_ldisc_reinit(tty, N_TTY)); tty_ldisc_reinit(tty, N_TTY);
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
}
} }
tty_ldisc_unlock(tty); tty_ldisc_unlock(tty);
if (reset) if (reset)
......
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