Skip to content

Commit 7896f30

Browse files
peterhurleygregkh
authored andcommitted
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>
1 parent c12da96 commit 7896f30

File tree

1 file changed

+31
-22
lines changed

1 file changed

+31
-22
lines changed

drivers/tty/tty_ldisc.c

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -641,26 +641,41 @@ static void tty_reset_termios(struct tty_struct *tty)
641641
* @tty: tty to reinit
642642
* @disc: line discipline to reinitialize
643643
*
644-
* Switch the tty to a line discipline and leave the ldisc
645-
* state closed
644+
* Completely reinitialize the line discipline state, by closing the
645+
* current instance and opening a new instance. If an error occurs opening
646+
* the new non-N_TTY instance, the instance is dropped and tty->ldisc reset
647+
* to NULL. The caller can then retry with N_TTY instead.
648+
*
649+
* Returns 0 if successful, otherwise error code < 0
646650
*/
647651

648652
static int tty_ldisc_reinit(struct tty_struct *tty, int disc)
649653
{
650-
struct tty_ldisc *ld = tty_ldisc_get(tty, disc);
654+
struct tty_ldisc *ld;
655+
int retval;
651656

652-
if (IS_ERR(ld))
653-
return -1;
657+
ld = tty_ldisc_get(tty, disc);
658+
if (IS_ERR(ld)) {
659+
BUG_ON(disc == N_TTY);
660+
return PTR_ERR(ld);
661+
}
654662

655-
tty_ldisc_close(tty, tty->ldisc);
656-
tty_ldisc_put(tty->ldisc);
657-
/*
658-
* Switch the line discipline back
659-
*/
663+
if (tty->ldisc) {
664+
tty_ldisc_close(tty, tty->ldisc);
665+
tty_ldisc_put(tty->ldisc);
666+
}
667+
668+
/* switch the line discipline */
660669
tty->ldisc = ld;
661670
tty_set_termios_ldisc(tty, disc);
662-
663-
return 0;
671+
retval = tty_ldisc_open(tty, tty->ldisc);
672+
if (retval) {
673+
if (!WARN_ON(disc == N_TTY)) {
674+
tty_ldisc_put(tty->ldisc);
675+
tty->ldisc = NULL;
676+
}
677+
}
678+
return retval;
664679
}
665680

666681
/**
@@ -716,19 +731,13 @@ void tty_ldisc_hangup(struct tty_struct *tty)
716731
reopen a new ldisc. We could defer the reopen to the next
717732
open but it means auditing a lot of other paths so this is
718733
a FIXME */
719-
if (reset == 0) {
734+
if (reset == 0)
735+
err = tty_ldisc_reinit(tty, tty->termios.c_line);
720736

721-
if (!tty_ldisc_reinit(tty, tty->termios.c_line))
722-
err = tty_ldisc_open(tty, tty->ldisc);
723-
else
724-
err = 1;
725-
}
726737
/* If the re-open fails or we reset then go to N_TTY. The
727738
N_TTY open cannot fail */
728-
if (reset || err) {
729-
BUG_ON(tty_ldisc_reinit(tty, N_TTY));
730-
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
731-
}
739+
if (reset || err < 0)
740+
tty_ldisc_reinit(tty, N_TTY);
732741
}
733742
tty_ldisc_unlock(tty);
734743
if (reset)

0 commit comments

Comments
 (0)