OK, so my last attempt didn't fix it. Still, the problem is that con_close() can sleep, dropping bkl, permitting another task to come in and grab a tty->count ref while con_close() is in the process of tearing things down. We've always had this race with CONFIG_DEVFS=y, because vcs_remove_devfs()->devfs_remvoe() can sleep. The patch extends tty_sem coverage to release_dev(), as well as init_dev(), thus preventing the open-vs-close races. Judging by the comment over the tty_sem definition this was always intended. Mabe someone backed it out again because of some deadlock... --- 25-akpm/drivers/char/tty_io.c | 22 +++++++++++++--------- 1 files changed, 13 insertions(+), 9 deletions(-) diff -puN drivers/char/tty_io.c~tty-locking-again drivers/char/tty_io.c --- 25/drivers/char/tty_io.c~tty-locking-again 2004-03-27 16:25:08.265371360 -0800 +++ 25-akpm/drivers/char/tty_io.c 2004-03-27 16:25:40.840419200 -0800 @@ -1084,6 +1084,7 @@ static void release_dev(struct file * fi tty_fasync(-1, filp, 0); idx = tty->index; + down(&tty_sem); pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); o_tty = tty->link; @@ -1092,25 +1093,25 @@ static void release_dev(struct file * fi if (idx < 0 || idx >= tty->driver->num) { printk(KERN_DEBUG "release_dev: bad idx when trying to " "free (%s)\n", tty->name); - return; + goto out; } if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (tty != tty->driver->ttys[idx]) { printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); - return; + goto out; } if (tty->termios != tty->driver->termios[idx]) { printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, tty->name); - return; + goto out; } if (tty->termios_locked != tty->driver->termios_locked[idx]) { printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " "termios_locked for (%s)\n", idx, tty->name); - return; + goto out; } } #endif @@ -1127,24 +1128,24 @@ static void release_dev(struct file * fi printk(KERN_DEBUG "release_dev: other->table[%d] " "not o_tty for (%s)\n", idx, tty->name); - return; + goto out; } if (o_tty->termios != tty->driver->other->termios[idx]) { printk(KERN_DEBUG "release_dev: other->termios[%d] " "not o_termios for (%s)\n", idx, tty->name); - return; + goto out; } if (o_tty->termios_locked != tty->driver->other->termios_locked[idx]) { printk(KERN_DEBUG "release_dev: other->termios_locked[" "%d] not o_termios_locked for (%s)\n", idx, tty->name); - return; + goto out; } if (o_tty->link != tty) { printk(KERN_DEBUG "release_dev: bad pty pointers\n"); - return; + goto out; } } #endif @@ -1276,7 +1277,7 @@ static void release_dev(struct file * fi /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) - return; + goto out; #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "freeing tty structure..."); @@ -1316,6 +1317,9 @@ static void release_dev(struct file * fi * the slots and preserving the termios structure. */ release_mem(tty, idx); +out: + up(&tty_sem); + return; } /* _