[PATCH] Was: patch to drivers/char/serial.c to fix kernel lock-up

Theodore Y. Ts'o (tytso@mit.edu)
Sat, 5 Dec 1998 01:07:13 -0500


Ah, OK. I found the actual problem, which is a bug in set_serial_info.
Simply avoiding the IRQ chain would have only hidden the actual
problem, which was a one-line typo:

- info->flags = ((state->flags & ~ASYNC_USR_MASK) |
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |

This cleared ASYNC_INITIALIZED from info->flags and that's what caused
startup() to get called twice.

Linus, Alan, enclosed please find a patch which should get applied to
the 2.1 tree. It fixes the above-mentioned problem, and also fixes a
bug in the serial driver so that it properly refuses an baud rate that
it can't support by resetting the baud rate in the termios structure to
its previous value. Also, I added two additional line discpline
definitions which got requested a while back, but which never made it
into the tree.

- Ted

Patch generated: on Sat Dec 5 00:05:08 EST 1998 by tytso@rsts-11.mit.edu
against Linux version 2.1.130

===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c 1998/12/05 00:20:27 1.1
+++ drivers/char/serial.c 1998/12/05 02:12:54
@@ -154,7 +154,7 @@
#endif

static char *serial_name = "Serial driver";
-static char *serial_version = "4.26";
+static char *serial_version = "4.27";

static DECLARE_TASK_QUEUE(tq_serial);

@@ -180,7 +180,7 @@

static unsigned detect_uart_irq (struct serial_state * state);
static void autoconfig(struct serial_state * info);
-static void change_speed(struct async_struct *info);
+static void change_speed(struct async_struct *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);

/*
@@ -1110,7 +1110,7 @@
/*
* and set the speed of the serial port
*/
- change_speed(info);
+ change_speed(info, 0);

info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
@@ -1233,7 +1233,8 @@
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static void change_speed(struct async_struct *info)
+static void change_speed(struct async_struct *info,
+ struct termios *old_termios)
{
unsigned short port;
int quot = 0, baud_base, baud;
@@ -1284,7 +1285,25 @@
else if (baud)
quot = baud_base / baud;
}
- /* If the quotient is ever zero, default to 9600 bps */
+ /* If the quotient is zero refuse the change */
+ if (!quot && old_termios) {
+ info->tty->termios->c_cflag &= ~CBAUD;
+ info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600;
+ if (baud == 38400 &&
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ quot = info->state->custom_divisor;
+ else {
+ if (baud == 134)
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
+ quot = baud_base / baud;
+ }
+ }
+ /* As a last resort, if the quotient is zero, default to 9600 bps */
if (!quot)
quot = baud_base / 9600;
info->quot = quot;
@@ -1653,7 +1672,7 @@
return -EPERM;
state->flags = ((state->flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
- info->flags = ((state->flags & ~ASYNC_USR_MASK) |
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
(info->flags & ASYNC_USR_MASK));
state->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
@@ -1733,7 +1752,7 @@
info->tty->alt_speed = 230400;
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
- change_speed(info);
+ change_speed(info, 0);
}
} else
retval = startup(info);
@@ -2003,7 +2022,6 @@
"driver!!\n");
}
}
-
return 0;
}
#endif
@@ -2150,7 +2168,7 @@
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;

- change_speed(info);
+ change_speed(info, old_termios);

/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
@@ -2645,13 +2663,13 @@
*tty->termios = info->state->normal_termios;
else
*tty->termios = info->state->callout_termios;
- change_speed(info);
+ change_speed(info, 0);
}
#ifdef CONFIG_SERIAL_CONSOLE
if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0;
- change_speed(info);
+ change_speed(info, 0);
}
#endif
info->session = current->session;
===================================================================
RCS file: include/asm-i386/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-i386/termios.h
--- include/asm-i386/termios.h 1998/12/05 01:08:53 1.1
+++ include/asm-i386/termios.h 1998/12/05 02:24:02
@@ -50,6 +50,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

===================================================================
RCS file: include/asm-alpha/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-alpha/termios.h
--- include/asm-alpha/termios.h 1998/12/05 01:49:41 1.1
+++ include/asm-alpha/termios.h 1998/12/05 01:55:54
@@ -77,6 +77,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__
/* eof=^D eol=\0 eol2=\0 erase=del
===================================================================
RCS file: include/asm-arm/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-arm/termios.h
--- include/asm-arm/termios.h 1998/12/05 01:50:20 1.1
+++ include/asm-arm/termios.h 1998/12/05 01:57:01
@@ -58,6 +58,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

===================================================================
RCS file: include/asm-m68k/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-m68k/termios.h
--- include/asm-m68k/termios.h 1998/12/05 01:51:06 1.1
+++ include/asm-m68k/termios.h 1998/12/05 01:57:18
@@ -58,6 +58,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

===================================================================
RCS file: include/asm-mips/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-mips/termios.h
--- include/asm-mips/termios.h 1998/12/05 01:49:36 1.1
+++ include/asm-mips/termios.h 1998/12/05 01:57:33
@@ -96,6 +96,8 @@
#define N_MASC 8 /* Reserved fo Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

===================================================================
RCS file: include/asm-ppc/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-ppc/termios.h
--- include/asm-ppc/termios.h 1998/12/05 01:50:06 1.1
+++ include/asm-ppc/termios.h 1998/12/05 01:57:46
@@ -182,6 +182,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

===================================================================
RCS file: include/asm-sparc/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-sparc/termios.h
--- include/asm-sparc/termios.h 1998/12/05 01:49:46 1.1
+++ include/asm-sparc/termios.h 1998/12/05 01:57:55
@@ -66,6 +66,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

===================================================================
RCS file: include/asm-sparc64/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-sparc64/termios.h
--- include/asm-sparc64/termios.h 1998/12/05 01:49:52 1.1
+++ include/asm-sparc64/termios.h 1998/12/05 01:58:02
@@ -66,6 +66,8 @@
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */

#ifdef __KERNEL__

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/