Re: Serial Driver Bug?? (and patch!)

Tom Grigg (st588@bayou.uh.edu)
Sun, 28 Apr 1996 10:08:59 -0500 (CDT)


On Fri, 26 Apr 1996, Theodore Y. Ts'o wrote:

> I haven't seen any of these symptoms on my machine, and neither has any
> of the other people whom I'm familiar with who have tried using the
> modular serial driver.

I hadn't seen any of them either (except an occasional 'couldn't get a
free page' message, which I didn't attribute to the serial driver) until
I started playing around with the things he mentioned.

> Do any of these problems (cat /proc/ioports causing system crashes,
> etc.) happen *before* the first time the serial driver is loaded?

No. In fact, they only happen after ther serial driver has been loaded
and then unloaded (and possibly loaded again). The problem seems to be
that 'release_region' is never called at module unload time, and so the
kernel's resource tables contain wild pointers.

Below is a patch that I send to Andrew yesterday; it fixes the problem
for me. It also adds a KERN_INFO priority to some of the printk()s
(so my console doesn't get littered by them when kerneld loads the
module). Comments welcome.

Index: linux/drivers/char/serial.c
===================================================================
RCS file: /usr/local/cvsroot/linux/drivers/char/serial.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 serial.c
--- serial.c 1996/04/18 20:36:08 1.1.1.4
+++ serial.c 1996/04/27 09:27:41
@@ -2448,7 +2448,7 @@
*/
static void show_serial_version(void)
{
- printk("%s version %s with", serial_name, serial_version);
+ printk(KERN_INFO "%s version %s with", serial_name, serial_version);
#ifdef CONFIG_HUB6
printk(" HUB-6");
#define SERIAL_OPT
@@ -2797,7 +2797,7 @@
autoconfig(info);
if (info->type == PORT_UNKNOWN)
continue;
- printk("tty%02d%s at 0x%04x (irq = %d)", info->line,
+ printk(KERN_INFO "tty%02d%s at 0x%04x (irq = %d)", info->line,
(info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
info->port, info->irq);
switch (info->type) {
@@ -2867,7 +2867,7 @@
printk("register_serial(): autoconfig failed\n");
return -1;
}
- printk("tty%02d at 0x%04x (irq = %d)", info->line,
+ printk(KERN_INFO "tty%02d at 0x%04x (irq = %d)", info->line,
info->port, info->irq);
switch (info->type) {
case PORT_8250:
@@ -2895,7 +2895,7 @@
if (info->tty)
tty_hangup(info->tty);
info->type = PORT_UNKNOWN;
- printk("tty%02d unloaded\n", info->line);
+ printk(KERN_INFO "tty%02d unloaded\n", info->line);
restore_flags(flags);
}

@@ -2909,6 +2909,7 @@
{
unsigned long flags;
int e1, e2;
+ int i;

/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
save_flags(flags);
@@ -2923,5 +2924,10 @@
printk("SERIAL: failed to unregister callout driver (%d)\n",
e2);
restore_flags(flags);
+
+ for (i = 0; i < NR_PORTS; i++) {
+ if (rs_table[i].type != PORT_UNKNOWN)
+ release_region(rs_table[i].port, 8);
+ }
}
#endif /* MODULE */

--
Tom Grigg
st588@jetson.uh.edu
http://www.egr.uh.edu/~eac64750/tom/