Finally nailed this sucker.
con_close() checks the tty->count and then sleeps in acquire_console_sem().
But another process can come in and grab a ref against the tty while
con_close() dropped the BKL. But con_close() then proceeds to deallocate the
tty->driver_data anyway, even though the tty now has ->count == 2.
Fix that by moving the check for ->tty_count inside console_sem.
return 0;
}
-static void con_close(struct tty_struct *tty, struct file * filp)
+static void con_close(struct tty_struct *tty, struct file *filp)
{
- struct vt_struct *vt;
-
- if (!tty || tty->count != 1)
- return;
-
- vcs_remove_devfs(tty);
acquire_console_sem();
- vt = (struct vt_struct*)tty->driver_data;
- if (vt)
- vc_cons[vt->vc_num].d->vc_tty = NULL;
- tty->driver_data = 0;
+ if (tty && tty->count == 1) {
+ struct vt_struct *vt;
+
+ vcs_remove_devfs(tty);
+ vt = tty->driver_data;
+ if (vt)
+ vc_cons[vt->vc_num].d->vc_tty = NULL;
+ tty->driver_data = 0;
+ }
release_console_sem();
}