diff options
author | Philippe Rétornaz <philippe.retornaz@epfl.ch> | 2010-10-27 11:13:21 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-09 18:05:50 -0500 |
commit | 1c95ba1e1de7edffc0c4e275e147f1a9eb1f81ae (patch) | |
tree | 9c0db77569313d05ac0e7298984897f9c003da95 /drivers/tty | |
parent | 100eeae2c5ce23b4db93ff320ee330ef1d740151 (diff) |
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>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/tty_ldisc.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 5bbf33ad49f1..d8e96b005023 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -743,9 +743,12 @@ static void tty_reset_termios(struct tty_struct *tty) | |||
743 | * state closed | 743 | * state closed |
744 | */ | 744 | */ |
745 | 745 | ||
746 | static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc) | 746 | static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) |
747 | { | 747 | { |
748 | struct tty_ldisc *ld; | 748 | struct tty_ldisc *ld = tty_ldisc_get(ldisc); |
749 | |||
750 | if (IS_ERR(ld)) | ||
751 | return -1; | ||
749 | 752 | ||
750 | tty_ldisc_close(tty, tty->ldisc); | 753 | tty_ldisc_close(tty, tty->ldisc); |
751 | tty_ldisc_put(tty->ldisc); | 754 | tty_ldisc_put(tty->ldisc); |
@@ -753,10 +756,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc) | |||
753 | /* | 756 | /* |
754 | * Switch the line discipline back | 757 | * Switch the line discipline back |
755 | */ | 758 | */ |
756 | ld = tty_ldisc_get(ldisc); | ||
757 | BUG_ON(IS_ERR(ld)); | ||
758 | tty_ldisc_assign(tty, ld); | 759 | tty_ldisc_assign(tty, ld); |
759 | tty_set_termios_ldisc(tty, ldisc); | 760 | tty_set_termios_ldisc(tty, ldisc); |
761 | |||
762 | return 0; | ||
760 | } | 763 | } |
761 | 764 | ||
762 | /** | 765 | /** |
@@ -831,13 +834,16 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
831 | a FIXME */ | 834 | a FIXME */ |
832 | if (tty->ldisc) { /* Not yet closed */ | 835 | if (tty->ldisc) { /* Not yet closed */ |
833 | if (reset == 0) { | 836 | if (reset == 0) { |
834 | tty_ldisc_reinit(tty, tty->termios->c_line); | 837 | |
835 | err = tty_ldisc_open(tty, tty->ldisc); | 838 | if (!tty_ldisc_reinit(tty, tty->termios->c_line)) |
839 | err = tty_ldisc_open(tty, tty->ldisc); | ||
840 | else | ||
841 | err = 1; | ||
836 | } | 842 | } |
837 | /* If the re-open fails or we reset then go to N_TTY. The | 843 | /* If the re-open fails or we reset then go to N_TTY. The |
838 | N_TTY open cannot fail */ | 844 | N_TTY open cannot fail */ |
839 | if (reset || err) { | 845 | if (reset || err) { |
840 | tty_ldisc_reinit(tty, N_TTY); | 846 | BUG_ON(tty_ldisc_reinit(tty, N_TTY)); |
841 | WARN_ON(tty_ldisc_open(tty, tty->ldisc)); | 847 | WARN_ON(tty_ldisc_open(tty, tty->ldisc)); |
842 | } | 848 | } |
843 | tty_ldisc_enable(tty); | 849 | tty_ldisc_enable(tty); |