tty_ldisc: Fix BUG() on hangup
A kernel BUG when bluetooth rfcomm connection drop while the associated serial port is open is sometime triggered. It seems that the line discipline can disappear between the tty_ldisc_put and tty_ldisc_get. This patch fall back to the N_TTY line discipline if the previous discipline is not available anymore. Signed-off-by: Philippe Retornaz <philippe.retornaz@epfl.ch> Acked-by: Alan Cox <alan@linux.intel.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
100eeae2c5
Коммит
1c95ba1e1d
|
@ -743,9 +743,12 @@ static void tty_reset_termios(struct tty_struct *tty)
|
|||
* state closed
|
||||
*/
|
||||
|
||||
static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
||||
static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
struct tty_ldisc *ld = tty_ldisc_get(ldisc);
|
||||
|
||||
if (IS_ERR(ld))
|
||||
return -1;
|
||||
|
||||
tty_ldisc_close(tty, tty->ldisc);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
|
@ -753,10 +756,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
|||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
ld = tty_ldisc_get(ldisc);
|
||||
BUG_ON(IS_ERR(ld));
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -831,13 +834,16 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||
a FIXME */
|
||||
if (tty->ldisc) { /* Not yet closed */
|
||||
if (reset == 0) {
|
||||
tty_ldisc_reinit(tty, tty->termios->c_line);
|
||||
err = tty_ldisc_open(tty, tty->ldisc);
|
||||
|
||||
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) {
|
||||
tty_ldisc_reinit(tty, N_TTY);
|
||||
BUG_ON(tty_ldisc_reinit(tty, N_TTY));
|
||||
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
|
||||
}
|
||||
tty_ldisc_enable(tty);
|
||||
|
|
Загрузка…
Ссылка в новой задаче