--- a/sys/kern/tty_cons.c +++ b/sys/kern/tty_cons.c @@ -455,15 +455,38 @@ cnread(struct dev_read_args *ap) static int cnwrite(struct dev_write_args *ap) { struct uio *uio = ap->a_uio; + struct tty *tp; cdev_t dev; + int error; if (cn_tab == NULL || cn_fwd_ops == NULL) { uio->uio_resid = 0; /* dump the data */ return (0); } - if (constty) - dev = constty->t_dev; - else - dev = cn_tab->cn_dev; + /* + * Serialize against constty teardown. The teardown path + * (ttyclose() clearing constty, and pti_done() clearing + * tp->t_dev and destroy_dev()ing the cdev) runs under + * tp->t_token. Capture the cdev under the same token and + * hold the token across the forward so the cdev cannot be + * destroyed between the capture and dev_doperate(). + * (constty-capable ttys -- ptys and the console drivers -- + * have persistent struct tty storage, so the token itself + * stays valid.) + */ + tp = constty; + dev = NULL; + if (tp) { + lwkt_gettoken(&tp->t_token); + if (constty != tp || tp->t_dev == NULL) { + lwkt_reltoken(&tp->t_token); + tp = NULL; + } else { + dev = tp->t_dev; + } + } + if (dev == NULL) + dev = cn_tab->cn_dev; log_console(uio); ap->a_head.a_dev = dev; - return (dev_doperate(&ap->a_head)); + error = dev_doperate(&ap->a_head); + if (tp) + lwkt_reltoken(&tp->t_token); + return (error); }