[PATCH] memory leaks: serial module & tty code, kernel 2.2.5 & 2.0.36

Armin Groesslinger (groessli@fmi.uni-passau.de)
Mon, 12 Apr 1999 10:06:31 +0200 (MET DST)


Hello!
I think I have discovered two memory leaks in kernel 2.2.5, one of which is
also existent in 2.0.36. It only happens when the serial driver is compiled as
a MODULE. I did (with 2.2.5) something like
while true; do insmod serial; echo >/dev/ttyS0; rmmod serial; done

Watching the process with "cat /proc/slabinfo" I discovered that with each
iteration there was an increase of 1 for "size-256" and of 2 for "size-64".
After 23000 interations my system (i486,16 MB RAM) was unrecoverably out of
memory and completely useless.

Looking at the sources I found two problems:
1. When the serial module is removed, it does not free the rs_table[?].info
async_struct's and they get lost. (applies to 2.2.5 only)
2. When tty_unregister_driver is called, it does not free the structures
driver->termios[?] and driver->termios_locked[?] and they also get lost.
(applies to both 2.2.5 and 2.0.36)

I have written some patches to fix these problems:
Patch for Problem 1 (2.2.5 only):

diff -ur 2.2.5/drivers/char/serial.c linux/drivers/char/serial.c
--- 2.2.5/drivers/char/serial.c Thu Apr 8 21:24:12 1999
+++ linux/drivers/char/serial.c Sun Apr 11 19:02:27 1999
@@ -3307,6 +3307,8 @@
for (i = 0; i < NR_PORTS; i++) {
if (rs_table[i].type != PORT_UNKNOWN)
release_region(rs_table[i].port, 8);
+ if (rs_table[i].info != NULL)
+ kfree(rs_table[i].info);
}
if (tmp_buf) {
free_page((unsigned long) tmp_buf);

Patch against 2.2.5 for Problem 2:

diff -ur 2.2.5/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- 2.2.5/drivers/char/tty_io.c Thu Apr 8 21:24:13 1999
+++ linux/drivers/char/tty_io.c Sun Apr 11 19:26:02 1999
@@ -1979,8 +1979,9 @@
{
int retval;
struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
const char *othername = NULL;
+ struct termios *tp;

if (*driver->refcount)
return -EBUSY;
@@ -2011,6 +2012,18 @@
driver->next->prev = driver->prev;

proc_tty_unregister_driver(driver);
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios[i] = NULL;
+ }
+ tp = driver->termios_locked[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios_locked[i] = NULL;
+ }
+ }
return 0;
}

Patch against 2.0.36 for Problem 2:

--- 2.0.36/drivers/char/tty_io.c Mon Apr 12 01:39:19 1999
+++ linux/drivers/char/tty_io.c Mon Apr 12 02:48:40 1999
@@ -1926,8 +1926,9 @@
{
int retval;
struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
const char *othername = NULL;
+ struct termios *tp;

if (*driver->refcount)
return -EBUSY;
@@ -1957,6 +1958,18 @@
if (driver->next)
driver->next->prev = driver->prev;

+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios[i] = NULL;
+ }
+ tp = driver->termios_locked[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios_locked[i] = NULL;
+ }
+ }
return 0;
}

Note: Although I could not try it myself, I think that problem 2 is existent as
well for other tty* drivers (e.g. ttyI* for ISDN) when they are compiled
as modules. Could someone check this?

I am looking forward to getting your responses to my suggestions.

Yours,
Armin Groesslinger.

PS: As I am not subscribed to the mailing list, could you please CC any reply
to my personal mail address (groessli@fmi.uni-passau.de), please? Thanks.

-
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/