aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorPhilippe Rétornaz <philippe.retornaz@epfl.ch>2010-10-27 11:13:21 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-11-09 18:05:50 -0500
commit1c95ba1e1de7edffc0c4e275e147f1a9eb1f81ae (patch)
tree9c0db77569313d05ac0e7298984897f9c003da95 /drivers/tty
parent100eeae2c5ce23b4db93ff320ee330ef1d740151 (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.c20
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
746static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc) 746static 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);