aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_ldisc.c
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2016-01-10 22:41:05 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-01-27 15:01:44 -0800
commit7896f30d6fc602f02198999acca4840620288990 (patch)
tree96f385ae7c987248ac90a01cc323c1c72e2f47c1 /drivers/tty/tty_ldisc.c
parenttty: Use 'disc' for line discipline index name (diff)
downloadlinux-dev-7896f30d6fc602f02198999acca4840620288990.tar.xz
linux-dev-7896f30d6fc602f02198999acca4840620288990.zip
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: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-rw-r--r--drivers/tty/tty_ldisc.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 45aa31b923e5..e18c8e864110 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -641,26 +641,41 @@ static void tty_reset_termios(struct tty_struct *tty)
* @tty: tty to reinit
* @disc: line discipline to reinitialize
*
- * Switch the tty to a line discipline and leave the ldisc
- * state closed
+ * Completely reinitialize the line discipline state, by closing the
+ * 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)
{
- struct tty_ldisc *ld = tty_ldisc_get(tty, disc);
+ struct tty_ldisc *ld;
+ int retval;
- if (IS_ERR(ld))
- return -1;
+ ld = tty_ldisc_get(tty, disc);
+ if (IS_ERR(ld)) {
+ BUG_ON(disc == N_TTY);
+ return PTR_ERR(ld);
+ }
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /*
- * Switch the line discipline back
- */
+ if (tty->ldisc) {
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ }
+
+ /* switch the line discipline */
tty->ldisc = ld;
tty_set_termios_ldisc(tty, disc);
-
- return 0;
+ retval = tty_ldisc_open(tty, tty->ldisc);
+ 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)
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
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
N_TTY open cannot fail */
- if (reset || err) {
- BUG_ON(tty_ldisc_reinit(tty, N_TTY));
- WARN_ON(tty_ldisc_open(tty, tty->ldisc));
- }
+ if (reset || err < 0)
+ tty_ldisc_reinit(tty, N_TTY);
}
tty_ldisc_unlock(tty);
if (reset)