1 From 1c95ba1e1de7edffc0c4e275e147f1a9eb1f81ae Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Philippe=20R=C3=A9tornaz?= <philippe.retornaz@epfl.ch>
3 Date: Wed, 27 Oct 2010 17:13:21 +0200
4 Subject: tty_ldisc: Fix BUG() on hangup
6 From: =?UTF-8?q?Philippe=20R=C3=A9tornaz?= <philippe.retornaz@epfl.ch>
8 commit 1c95ba1e1de7edffc0c4e275e147f1a9eb1f81ae upstream.
10 A kernel BUG when bluetooth rfcomm connection drop while the associated
11 serial port is open is sometime triggered.
13 It seems that the line discipline can disappear between the
14 tty_ldisc_put and tty_ldisc_get. This patch fall back to the N_TTY line
15 discipline if the previous discipline is not available anymore.
17 Signed-off-by: Philippe Retornaz <philippe.retornaz@epfl.ch>
18 Acked-by: Alan Cox <alan@linux.intel.com>
19 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
22 drivers/char/tty_ldisc.c | 20 +++++++++++++-------
23 1 file changed, 13 insertions(+), 7 deletions(-)
25 --- a/drivers/char/tty_ldisc.c
26 +++ b/drivers/char/tty_ldisc.c
27 @@ -743,9 +743,12 @@ static void tty_reset_termios(struct tty
31 -static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
32 +static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
34 - struct tty_ldisc *ld;
35 + struct tty_ldisc *ld = tty_ldisc_get(ldisc);
40 tty_ldisc_close(tty, tty->ldisc);
41 tty_ldisc_put(tty->ldisc);
42 @@ -753,10 +756,10 @@ static void tty_ldisc_reinit(struct tty_
44 * Switch the line discipline back
46 - ld = tty_ldisc_get(ldisc);
48 tty_ldisc_assign(tty, ld);
49 tty_set_termios_ldisc(tty, ldisc);
55 @@ -831,13 +834,16 @@ void tty_ldisc_hangup(struct tty_struct
57 if (tty->ldisc) { /* Not yet closed */
59 - tty_ldisc_reinit(tty, tty->termios->c_line);
60 - err = tty_ldisc_open(tty, tty->ldisc);
62 + if (!tty_ldisc_reinit(tty, tty->termios->c_line))
63 + err = tty_ldisc_open(tty, tty->ldisc);
67 /* If the re-open fails or we reset then go to N_TTY. The
68 N_TTY open cannot fail */
70 - tty_ldisc_reinit(tty, N_TTY);
71 + BUG_ON(tty_ldisc_reinit(tty, N_TTY));
72 WARN_ON(tty_ldisc_open(tty, tty->ldisc));
74 tty_ldisc_enable(tty);