Page MenuHomeFreeBSD

D24459.diff
No OneTemporary

D24459.diff

diff --git a/sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c b/sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c
--- a/sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c
+++ b/sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c
@@ -263,7 +263,7 @@
{
int c;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
AJU_LOCK_ASSERT(sc);
while (aju_readable(sc)) {
@@ -295,7 +295,7 @@
uint32_t v;
uint8_t ch;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
AJU_LOCK_ASSERT(sc);
AJU_UNLOCK(sc);
@@ -361,7 +361,7 @@
{
struct altera_jtag_uart_softc *sc = tty_softc(tp);
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
AJU_LOCK(sc);
aju_handle_output(sc, tp);
@@ -374,7 +374,6 @@
struct altera_jtag_uart_softc *sc = arg;
struct tty *tp = sc->ajus_ttyp;
- tty_lock(tp);
AJU_LOCK(sc);
/*
@@ -396,7 +395,6 @@
callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
aju_io_callout, sc);
AJU_UNLOCK(sc);
- tty_unlock(tp);
}
static void
@@ -406,7 +404,6 @@
struct tty *tp = sc->ajus_ttyp;
uint32_t v;
- tty_lock(tp);
AJU_LOCK(sc);
v = aju_control_read(sc);
if (v & ALTERA_JTAG_UART_CONTROL_AC) {
@@ -436,7 +433,6 @@
callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
aju_ac_callout, sc);
AJU_UNLOCK(sc);
- tty_unlock(tp);
}
static void
@@ -446,7 +442,7 @@
struct tty *tp = sc->ajus_ttyp;
uint32_t v;
- tty_lock(tp);
+ ttydisc_lock(tp);
AJU_LOCK(sc);
v = aju_control_read(sc);
if (v & ALTERA_JTAG_UART_CONTROL_RI) {
@@ -458,7 +454,7 @@
aju_handle_output(sc, tp);
}
AJU_UNLOCK(sc);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
int
@@ -515,6 +511,8 @@
tty_init_console(tp, 0);
}
tty_makedev(tp, NULL, "%s%d", AJU_TTYNAME, sc->ajus_unit);
+ /* Grab the lock now for callout work. */
+ ttydisc_lock(tp);
/*
* If we will be using interrupts, enable them now; otherwise, start
@@ -525,13 +523,14 @@
aju_intr_readable_enable(sc);
AJU_UNLOCK(sc);
} else {
- callout_init(&sc->ajus_io_callout, 1);
+ callout_init_mtx(&sc->ajus_io_callout, ttydisc_getlock(tp), 0);
callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
aju_io_callout, sc);
}
- callout_init(&sc->ajus_ac_callout, 1);
+ callout_init_mtx(&sc->ajus_ac_callout, ttydisc_getlock(tp), 0);
callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
aju_ac_callout, sc);
+ ttydisc_unlock(tp);
return (0);
}
@@ -542,8 +541,11 @@
/*
* If we're using interrupts, disable and release the interrupt
- * handler now. Otherwise drain the polling timeout.
+ * handler now. Otherwise drain the polling timeout. Grab the tty
+ * lock early to block any requests from userland until we've finished
+ * detaching.
*/
+ tty_lock(tp);
if (sc->ajus_irq_res != NULL) {
AJU_LOCK(sc);
aju_intr_disable(sc);
@@ -555,7 +557,7 @@
callout_drain(&sc->ajus_ac_callout);
if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
aju_cons_sc = NULL;
- tty_lock(tp);
+ ttydisc_lock(tp);
tty_rel_gone(tp);
AJU_LOCK_DESTROY(sc);
}
diff --git a/sys/dev/cfe/cfe_console.c b/sys/dev/cfe/cfe_console.c
--- a/sys/dev/cfe/cfe_console.c
+++ b/sys/dev/cfe/cfe_console.c
@@ -87,7 +87,7 @@
if (cfe_consdev.cn_pri != CN_DEAD &&
cfe_consdev.cn_name[0] != '\0') {
tp = tty_alloc(&cfe_ttydevsw, NULL);
- callout_init_mtx(&cfe_timer, tty_getlock(tp), 0);
+ callout_init_mtx(&cfe_timer, ttydisc_getlock(tp), 0);
tty_makedev(tp, NULL, "cfecons");
}
}
@@ -95,6 +95,8 @@
static int
cfe_tty_open(struct tty *tp)
{
+
+ ttydisc_assert_locked(tp);
polltime = hz / CFECONS_POLL_HZ;
if (polltime < 1)
polltime = 1;
@@ -107,6 +109,7 @@
cfe_tty_close(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
callout_stop(&cfe_timer);
}
@@ -139,7 +142,7 @@
tp = (struct tty *)v;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
while ((c = cfe_cngetc(NULL)) != -1)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
diff --git a/sys/dev/dcons/dcons_os.c b/sys/dev/dcons/dcons_os.c
--- a/sys/dev/dcons/dcons_os.c
+++ b/sys/dev/dcons/dcons_os.c
@@ -233,13 +233,13 @@
dc = &sc[i];
tp = dc->tty;
- tty_lock(tp);
+ ttydisc_lock(tp);
while ((c = dcons_os_checkc_nopoll(dc)) != -1) {
ttydisc_rint(tp, c, 0);
poll_idle = 0;
}
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
poll_idle++;
polltime = hz;
diff --git a/sys/dev/nmdm/nmdm.c b/sys/dev/nmdm/nmdm.c
--- a/sys/dev/nmdm/nmdm.c
+++ b/sys/dev/nmdm/nmdm.c
@@ -106,6 +106,7 @@
struct nmdmpart *onp;
struct tty *otp;
+ ttydisc_assert_locked(tp);
np = tty_softc(tp);
onp = np->np_other;
otp = onp->np_tty;
@@ -118,13 +119,14 @@
tty_rel_gone(tp);
/* Shut down second part. */
- tty_lock(tp);
+ tty_lock(otp);
onp = np->np_other;
if (onp == NULL)
return;
otp = onp->np_tty;
tty_rel_gone(otp);
tty_lock(tp);
+ ttydisc_lock(tp);
}
static void
@@ -189,7 +191,10 @@
TASK_INIT(&ns->ns_part2.np_task, 0, nmdm_task_tty, &ns->ns_part2);
callout_init_mtx(&ns->ns_part2.np_callout, &ns->ns_mtx, 0);
- /* Create device nodes. */
+ /*
+ * Create device nodes. Both sides can have distinct tty locks, as
+ * long as they share a ttydisc lock.
+ */
tp = ns->ns_part1.np_tty = tty_alloc_mutex(&nmdm_class, &ns->ns_part1,
&ns->ns_mtx);
*end = 'A';
@@ -254,12 +259,16 @@
char c;
tp = np->np_tty;
- tty_lock(tp);
+ ttydisc_lock(tp);
if (tty_gone(tp)) {
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return;
}
+ /*
+ * We'll be operating on otp while maintaining the tp ttydisc lock; this
+ * is OK, since they share the same ttydisc lock.
+ */
otp = np->np_other->np_tty;
KASSERT(otp != NULL, ("NULL otp in nmdmstart"));
KASSERT(otp != tp, ("NULL otp == tp nmdmstart"));
@@ -277,7 +286,7 @@
/* This may happen when we are in detach process. */
if (tty_gone(otp)) {
- tty_unlock(otp);
+ ttydisc_unlock(tp);
return;
}
@@ -291,8 +300,7 @@
}
ttydisc_rint_done(otp);
-
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
static int
@@ -322,6 +330,8 @@
struct tty *tp2;
int bpc, rate, speed, i;
+ /* Must be true for callout manipulation down below. */
+ ttydisc_assert_locked(tp);
tp2 = np->np_other->np_tty;
if (!((t->c_cflag | tp2->t_termios.c_cflag) & CDSR_OFLOW)) {
@@ -379,6 +389,7 @@
struct nmdmpart *np = tty_softc(tp);
int i = 0;
+ ttydisc_assert_locked(tp);
if (sigon || sigoff) {
if (sigon & SER_DTR)
np->np_other->np_dcd = 1;
@@ -386,14 +397,12 @@
np->np_other->np_dcd = 0;
ttydisc_modem(np->np_other->np_tty, np->np_other->np_dcd);
-
return (0);
} else {
if (np->np_dcd)
i |= SER_DCD;
if (np->np_other->np_dcd)
i |= SER_DTR;
-
return (i);
}
}
diff --git a/sys/dev/ofw/ofw_console.c b/sys/dev/ofw/ofw_console.c
--- a/sys/dev/ofw/ofw_console.c
+++ b/sys/dev/ofw/ofw_console.c
@@ -100,7 +100,7 @@
return;
if (strlen(output) > 0)
tty_makealias(tp, "%s", output);
- callout_init_mtx(&ofw_timer, tty_getlock(tp), 0);
+ callout_init_mtx(&ofw_timer, ttydisc_getlock(tp), 0);
}
}
@@ -112,6 +112,8 @@
static int
ofwtty_open(struct tty *tp)
{
+
+ ttydisc_assert_locked(tp);
polltime = hz / OFWCONS_POLL_HZ;
if (polltime < 1)
polltime = 1;
@@ -125,6 +127,7 @@
ofwtty_close(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
callout_stop(&ofw_timer);
}
@@ -134,6 +137,7 @@
int len;
u_char buf[OFBURSTLEN];
+ ttydisc_assert_locked(tp);
for (;;) {
len = ttydisc_getc(tp, buf, sizeof buf);
if (len == 0)
@@ -150,7 +154,7 @@
tp = (struct tty *)v;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
while ((c = ofw_cngetc(NULL)) != -1)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c
--- a/sys/dev/snp/snp.c
+++ b/sys/dev/snp/snp.c
@@ -162,10 +162,14 @@
return (error);
tp = ss->snp_tty;
- if (tp == NULL || tty_gone(tp))
+ if (tp == NULL)
+ return (EIO);
+ ttydisc_lock(tp);
+ if (tty_gone(tp)) {
+ ttydisc_unlock(tp);
return (EIO);
+ }
- tty_lock(tp);
for (;;) {
error = ttyoutq_read_uio(&ss->snp_outq, tp, uio);
if (error != 0 || uio->uio_resid != oresid)
@@ -176,7 +180,7 @@
error = EWOULDBLOCK;
break;
}
- error = cv_wait_sig(&ss->snp_outwait, tty_getlock(tp));
+ error = cv_wait_sig(&ss->snp_outwait, ttydisc_getlock(tp));
if (error != 0)
break;
if (tty_gone(tp)) {
@@ -184,7 +188,7 @@
break;
}
}
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (error);
}
@@ -212,11 +216,11 @@
if (error != 0)
return (error);
- tty_lock(tp);
+ ttydisc_lock(tp);
/* Driver could have abandoned the TTY in the mean time. */
if (tty_gone(tp)) {
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (ENXIO);
}
@@ -228,7 +232,7 @@
ttydisc_rint_simple(tp, in, len);
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
return (0);
@@ -276,7 +280,9 @@
/* Now that went okay, allocate a buffer for the queue. */
tp = ss->snp_tty;
tty_lock(tp);
+ ttydisc_lock(tp);
ttyoutq_setsize(&ss->snp_outq, tp, SNP_OUTPUT_BUFSIZE);
+ ttydisc_unlock(tp);
tty_unlock(tp);
return (0);
diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c
--- a/sys/dev/syscons/syscons.c
+++ b/sys/dev/syscons/syscons.c
@@ -408,6 +408,7 @@
u_char buf[PCBURST];
scr_stat *scp = sc_get_stat(tp);
+ ttydisc_assert_locked(tp);
if (scp->status & SLKED ||
(scp == scp->sc->cur_scp && scp->sc->blink_in_progress))
return;
@@ -746,7 +747,16 @@
scp = sc_get_stat(tp);
if (scp == NULL) {
+ /*
+ * ttydisc lock isn't sleepable like Giant, so we must go ahead
+ * and drop it. The tty lock is still held, but that's Giant at
+ * the moment as it was before the ttydisc lock became distinct.
+ * This is still likely unsafe, but something to revisit once
+ * this particular tty device isn't Giant locked anymore.
+ */
+ ttydisc_unlock(tp);
scp = SC_STAT(tp) = alloc_scp(sc, SC_VTY(tp));
+ ttydisc_lock(tp);
if (ISGRAPHSC(scp))
sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8);
}
@@ -846,9 +856,12 @@
cur_tty = SC_DEV(sc, sc->cur_scp->index);
if (!tty_opened_ns(cur_tty))
continue;
+ ttydisc_lock(cur_tty);
- if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty))
+ if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty)) {
+ ttydisc_unlock(cur_tty);
continue;
+ }
switch (KEYFLAGS(c)) {
case 0x0000: /* normal key */
@@ -874,8 +887,8 @@
}
ttydisc_rint_done(cur_tty);
+ ttydisc_unlock(cur_tty);
}
-
sc->cur_scp->status |= MOUSE_HIDDEN;
done:
@@ -4239,10 +4252,12 @@
tp = SC_DEV(scp->sc, scp->sc->cur_scp->index);
if (!tty_opened_ns(tp))
return;
+ ttydisc_lock(tp);
rmap = scp->sc->scr_rmap;
for (; count > 0; --count)
ttydisc_rint(tp, rmap[*p++], 0);
ttydisc_rint_done(tp);
+ ttydisc_unlock(tp);
}
void
@@ -4253,11 +4268,13 @@
tp = SC_DEV(scp->sc, scp->sc->cur_scp->index);
if (!tty_opened_ns(tp))
return;
+ ttydisc_lock(tp);
ttydisc_rint_simple(tp, p, count);
if (wakeup) {
/* XXX: we can't always call ttydisc_rint_done() here! */
ttydisc_rint_done(tp);
}
+ ttydisc_unlock(tp);
}
/*
diff --git a/sys/dev/syscons/sysmouse.c b/sys/dev/syscons/sysmouse.c
--- a/sys/dev/syscons/sysmouse.c
+++ b/sys/dev/syscons/sysmouse.c
@@ -260,7 +260,7 @@
int x, y, z;
int i, flags = 0;
- tty_lock(sysmouse_tty);
+ ttydisc_lock(sysmouse_tty);
switch (info->operation) {
case MOUSE_ACTION:
@@ -323,7 +323,7 @@
}
ttydisc_rint_done(sysmouse_tty);
-done: tty_unlock(sysmouse_tty);
+done: ttydisc_unlock(sysmouse_tty);
return (flags);
}
diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c
--- a/sys/dev/uart/uart_tty.c
+++ b/sys/dev/uart/uart_tty.c
@@ -330,7 +330,7 @@
return;
tp = sc->sc_u.u_tty.tp;
- tty_lock(tp);
+ ttydisc_lock(tp);
if (pend & SER_INT_RXREADY) {
while (!uart_rx_empty(sc) && !sc->sc_isquelch) {
@@ -366,7 +366,7 @@
if (pend & SER_INT_TXIDLE)
uart_tty_outwakeup(tp);
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
static void
@@ -459,7 +459,7 @@
{
if (sc->sc_u.u_tty.tp != NULL)
- return (tty_getlock(sc->sc_u.u_tty.tp));
+ return (ttydisc_getlock(sc->sc_u.u_tty.tp));
else
return (NULL);
}
diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c
--- a/sys/dev/usb/serial/usb_serial.c
+++ b/sys/dev/usb/serial/usb_serial.c
@@ -526,6 +526,7 @@
mtx_unlock(&ucom_mtx);
tty_lock(tp);
+ ttydisc_lock(tp);
ucom_close(tp); /* close, if any */
@@ -626,10 +627,12 @@
task->termios_copy = *pt;
/*
- * Closing or opening the device should be synchronous.
+ * The tty lock is sleepable and the ttydisc lock is shared with the USB
+ * parts. We can now asychronously do the USB parts while making sure
+ * that we're not violation termios guarantees about the state of the
+ * hardware when we return.
*/
- if (fn == ucom_cfg_close || fn == ucom_cfg_open)
- usb_proc_mwait(&ssc->sc_tq, t0, t1);
+ usb_proc_mwait(&ssc->sc_tq, t0, t1);
/*
* In case of multiple configure requests,
diff --git a/sys/dev/virtio/console/virtio_console.c b/sys/dev/virtio/console/virtio_console.c
--- a/sys/dev/virtio/console/virtio_console.c
+++ b/sys/dev/virtio/console/virtio_console.c
@@ -92,6 +92,7 @@
#define VTCON_PORT_LOCK(_port) mtx_lock(&(_port)->vtcport_mtx)
#define VTCON_PORT_UNLOCK(_port) mtx_unlock(&(_port)->vtcport_mtx)
+#define VTCON_PORT_ASSERT(_port, ma) mtx_assert(&(_port)->vtcport_mtx, (ma))
struct vtcon_softc_port {
struct vtcon_softc *vcsp_sc;
@@ -1306,6 +1307,8 @@
uint32_t len;
int i, deq;
+ /* Effectively the ttydisc lock. */
+ VTCON_PORT_ASSERT(port, MA_OWNED);
tp = port->vtcport_tty;
vq = port->vtcport_invq;
@@ -1396,13 +1399,14 @@
{
struct vtcon_port *port;
+ /* Effectively VTCON_PORT_LOCK. */
+ ttydisc_assert_locked(tp);
port = tty_softc(tp);
-
- if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
+ if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) {
return (ENXIO);
+ }
vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
return (0);
}
@@ -1411,8 +1415,9 @@
{
struct vtcon_port *port;
+ /* Effectively VTCON_PORT_LOCK. */
+ ttydisc_assert_locked(tp);
port = tty_softc(tp);
-
if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
return;
@@ -1426,6 +1431,8 @@
char buf[VTCON_BULK_BUFSZ];
int len;
+ /* Effectively VTCON_PORT_LOCK. */
+ ttydisc_assert_locked(tp);
port = tty_softc(tp);
if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
diff --git a/sys/dev/xen/console/xen_console.c b/sys/dev/xen/console/xen_console.c
--- a/sys/dev/xen/console/xen_console.c
+++ b/sys/dev/xen/console/xen_console.c
@@ -517,7 +517,7 @@
cons = tty_softc(tp);
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
/*
* Don't transmit any character if the buffer is full. Otherwise,
@@ -557,7 +557,7 @@
xencons_rx(cons);
- tty_lock(tp);
+ ttydisc_lock(tp);
while ((ret = xencons_getc(cons)) != -1) {
#ifdef KDB
kdb_alt_break(ret, &cons->altbrk);
@@ -565,7 +565,7 @@
ttydisc_rint(tp, ret, 0);
}
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
/* Try to flush remaining characters if necessary */
xencons_tx_flush(cons, 0);
@@ -684,6 +684,7 @@
struct xencons_priv *cons;
cons = tty_softc(tp);
+ ttydisc_assert_locked(tp);
callout_stop(&cons->callout);
@@ -736,7 +737,7 @@
tty_makedev(tp, NULL, "%s%r", driver_name, 0);
device_set_softc(dev, tp);
- callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
+ callout_init_mtx(&cons->callout, ttydisc_getlock(tp), 0);
err = cons->ops->init(dev, tp, xencons_intr);
if (err != 0) {
diff --git a/sys/kern/kern_cons.c b/sys/kern/kern_cons.c
--- a/sys/kern/kern_cons.c
+++ b/sys/kern/kern_cons.c
@@ -603,16 +603,16 @@
int size = consmsgbuf_size;
void *buf = NULL;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (constty == tp)
return (0);
if (constty != NULL)
return (EBUSY);
if (consbuf == NULL) {
- tty_unlock(tp);
+ ttydisc_unlock(tp);
buf = malloc(size, M_TTYCONS, M_WAITOK);
- tty_lock(tp);
+ ttydisc_lock(tp);
}
mtx_lock(&constty_mtx);
if (constty != NULL) {
@@ -628,7 +628,7 @@
constty = tp;
mtx_unlock(&constty_mtx);
- callout_init_mtx(&conscallout, tty_getlock(tp), 0);
+ callout_init_mtx(&conscallout, ttydisc_getlock(tp), 0);
constty_timeout(tp);
return (0);
}
@@ -641,7 +641,7 @@
{
int c;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (constty != tp)
return (ENXIO);
callout_stop(&conscallout);
@@ -666,7 +666,7 @@
struct tty *tp = arg;
int c;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
while ((c = msgbuf_getchar(&consmsgbuf)) != -1) {
if (tty_putchar(tp, c) < 0) {
constty_clear(tp);
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -945,10 +945,10 @@
*/
if (tp != NULL) {
- tty_lock(tp);
+ ttydisc_lock(tp);
if (tp->t_session == sp)
tty_signal_pgrp(tp, SIGHUP);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
if (ttyvp != NULL) {
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -205,10 +205,10 @@
pca.flags = TOTTY;
pca.p_bufr = NULL;
va_start(ap, fmt);
- tty_lock(pca.tty);
+ ttydisc_lock(pca.tty);
sx_sunlock(&proctree_lock);
retval = kvprintf(fmt, putchar, &pca, 10, ap);
- tty_unlock(pca.tty);
+ ttydisc_unlock(pca.tty);
va_end(ap);
return (retval);
}
diff --git a/sys/kern/subr_terminal.c b/sys/kern/subr_terminal.c
--- a/sys/kern/subr_terminal.c
+++ b/sys/kern/subr_terminal.c
@@ -317,7 +317,7 @@
return;
c = TCHAR_CHARACTER(c);
- tty_lock(tp);
+ ttydisc_lock(tp);
/*
* Conversion to UTF-8.
*/
@@ -349,7 +349,7 @@
ttydisc_rint_simple(tp, str, sizeof str);
}
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
void
@@ -361,10 +361,10 @@
if (tp == NULL)
return;
- tty_lock(tp);
+ ttydisc_lock(tp);
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
void
@@ -381,10 +381,10 @@
if (str == NULL)
return;
- tty_lock(tp);
+ ttydisc_lock(tp);
ttydisc_rint_simple(tp, str, strlen(str));
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
/*
@@ -416,6 +416,7 @@
size_t olen;
unsigned int flags = 0;
+ ttydisc_assert_locked(tp);
while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
TERMINAL_LOCK_TTY(tm);
if (!(tm->tm_flags & TF_MUTE)) {
@@ -473,9 +474,11 @@
* deallocate TTYs. This means it's safe to temporarily unlock
* the TTY when handling ioctls.
*/
+ ttydisc_unlock(tp);
tty_unlock(tp);
error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
tty_lock(tp);
+ ttydisc_lock(tp);
if ((error == 0) && (cmd == CONS_CLRHIST)) {
/*
* Scrollback history has been successfully cleared,
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -126,12 +126,14 @@
size_t bs = 0;
int error;
+ tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
/* Provide an input buffer for 2 seconds of data. */
if (tp->t_termios.c_cflag & CREAD)
bs = MIN(tp->t_termios.c_ispeed / 5, TTYBUF_MAX);
error = ttyinq_setsize(&tp->t_inq, tp, bs);
if (error != 0)
- return (error);
+ goto out;
/* Set low watermark at 10% (when 90% is available). */
tp->t_inlow = (ttyinq_getallocatedsize(&tp->t_inq) * 9) / 10;
@@ -140,12 +142,13 @@
bs = MIN(tp->t_termios.c_ospeed / 5, TTYBUF_MAX);
error = ttyoutq_setsize(&tp->t_outq, tp, bs);
if (error != 0)
- return (error);
+ goto out;
/* Set low watermark at 10% (when 90% is available). */
tp->t_outlow = (ttyoutq_getallocatedsize(&tp->t_outq) * 9) / 10;
- return (0);
+out:
+ return (error);
}
static int
@@ -155,6 +158,7 @@
size_t bytes;
int error;
+ ttydisc_assert_locked(tp);
if (ttyhook_hashook(tp, getc_inject))
/* buffer is inaccessible */
return (0);
@@ -229,20 +233,31 @@
ttydev_leave(struct tty *tp)
{
+ /*
+ * The locking in this function, like elsewhere, is also a nightmare
+ * that will be corrected when the tty lock gets converted to a
+ * sleepable lock.
+ */
tty_assert_locked(tp);
if (tty_opened(tp) || tp->t_flags & TF_OPENCLOSE) {
/* Device is still opened somewhere. */
+ if (ttydisc_lock_owned(tp))
+ ttydisc_unlock(tp);
tty_unlock(tp);
return;
}
-
+ if (!ttydisc_lock_owned(tp))
+ ttydisc_lock(tp);
tp->t_flags |= TF_OPENCLOSE;
/* Remove console TTY. */
constty_clear(tp);
- /* Drain any output. */
+ /*
+ * Drain any output. Pick up ttydisc_lock in advance of tty_drain,
+ * which will perhaps want to sleep and can't handle having both locks.
+ */
if (!tty_gone(tp))
tty_drain(tp, 1);
@@ -259,6 +274,7 @@
tp->t_flags &= ~TF_OPENCLOSE;
cv_broadcast(&tp->t_dcdwait);
+ ttydisc_unlock(tp);
tty_rel_free(tp);
}
@@ -285,6 +301,7 @@
* Block when other processes are currently opening or closing
* the TTY.
*/
+ ttydisc_lock(tp);
while (tp->t_flags & TF_OPENCLOSE) {
error = tty_wait(tp, &tp->t_dcdwait);
if (error != 0) {
@@ -293,6 +310,7 @@
}
}
tp->t_flags |= TF_OPENCLOSE;
+ ttydisc_unlock(tp);
/*
* Make sure the "tty" and "cua" device cannot be opened at the
@@ -316,11 +334,15 @@
}
if (!tty_opened(tp)) {
- /* Set proper termios flags. */
+ /*
+ * Set proper termios flags. Further mutations of t_termios
+ * will require the ttydisc lock.
+ */
if (TTY_CALLOUT(tp, dev))
tp->t_termios = tp->t_termios_init_out;
else
tp->t_termios = tp->t_termios_init_in;
+ ttydisc_lock(tp);
ttydevsw_param(tp, &tp->t_termios);
/* Prevent modem control on callout devices and /dev/console. */
if (TTY_CALLOUT(tp, dev) || dev == dev_console)
@@ -335,8 +357,11 @@
ttydisc_open(tp);
error = tty_watermarks(tp);
+ /* tty_watermarks dropped the ttydisc lock. */
if (error != 0)
goto done;
+ } else {
+ ttydisc_lock(tp);
}
/* Wait for Carrier Detect. */
@@ -358,7 +383,10 @@
MPASS((tp->t_flags & (TF_OPENED_CONS | TF_OPENED_IN)) == 0 ||
(tp->t_flags & TF_OPENED_OUT) == 0);
-done: tp->t_flags &= ~TF_OPENCLOSE;
+done:
+ if (!ttydisc_lock_owned(tp))
+ ttydisc_lock(tp);
+ tp->t_flags &= ~TF_OPENCLOSE;
cv_broadcast(&tp->t_dcdwait);
ttydev_leave(tp);
@@ -372,6 +400,7 @@
struct tty *tp = dev->si_drv1;
tty_lock(tp);
+ ttydisc_lock(tp);
/*
* Don't actually close the device if it is being used as the
@@ -385,6 +414,7 @@
tp->t_flags &= ~(TF_OPENED_IN|TF_OPENED_OUT);
if (tp->t_flags & TF_OPENED) {
+ ttydisc_unlock(tp);
tty_unlock(tp);
return (0);
}
@@ -413,8 +443,8 @@
tty_is_ctty(struct tty *tp, struct proc *p)
{
- tty_assert_locked(tp);
-
+ KASSERT(tty_lock_owned(tp) || ttydisc_lock_owned(tp),
+ ("neither ttymtx nor ttydiscmtx owned"));
return (p->p_session == tp->t_session && p->p_flag & P_CONTROLT);
}
@@ -427,7 +457,7 @@
int error;
MPASS(sig == SIGTTIN || sig == SIGTTOU);
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
p = td->td_proc;
for (;;) {
@@ -504,10 +534,18 @@
struct tty *tp = dev->si_drv1;
int error;
+ /*
+ * We'll pick up the tty lock just long enough to ensure we're alive and
+ * well, then we'll pick up the ttydisc lock and drop the tty lock -- we
+ * won't be needing it for the rest of this as we serialize I/O on the
+ * ttydisc lock.
+ */
error = ttydev_enter(tp);
if (error)
goto done;
+ ttydisc_lock(tp);
error = ttydisc_read(tp, uio, ioflag);
+ ttydisc_unlock(tp);
tty_unlock(tp);
/*
@@ -528,6 +566,7 @@
error = ttydev_enter(tp);
if (error)
return (error);
+ ttydisc_lock(tp);
if (tp->t_termios.c_lflag & TOSTOP) {
error = tty_wait_background(tp, curthread, SIGTTOU);
@@ -554,7 +593,8 @@
cv_signal(&tp->t_outserwait);
}
-done: tty_unlock(tp);
+done: ttydisc_unlock(tp);
+ tty_unlock(tp);
return (error);
}
@@ -605,7 +645,9 @@
* If the ioctl() causes the TTY to be modified, let it
* wait in the background.
*/
+ ttydisc_lock(tp);
error = tty_wait_background(tp, curthread, SIGTTOU);
+ ttydisc_unlock(tp);
if (error)
goto done;
}
@@ -654,6 +696,7 @@
if (error)
return ((events & (POLLIN|POLLRDNORM)) | POLLHUP);
+ ttydisc_lock(tp);
if (events & (POLLIN|POLLRDNORM)) {
/* See if we can read something. */
if (ttydisc_read_poll(tp) > 0)
@@ -668,6 +711,7 @@
if (ttydisc_write_poll(tp) > 0)
revents |= events & (POLLOUT|POLLWRNORM);
}
+ ttydisc_unlock(tp);
if (revents == 0) {
if (events & (POLLIN|POLLRDNORM))
@@ -716,7 +760,7 @@
{
struct tty *tp = kn->kn_hook;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tty_gone(tp) || tp->t_flags & TF_ZOMBIE) {
kn->kn_flags |= EV_EOF;
@@ -740,7 +784,7 @@
{
struct tty *tp = kn->kn_hook;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tty_gone(tp)) {
kn->kn_flags |= EV_EOF;
@@ -777,12 +821,16 @@
case EVFILT_READ:
kn->kn_hook = tp;
kn->kn_fop = &tty_kqops_read;
+ ttydisc_lock(tp);
knlist_add(&tp->t_inpoll.si_note, kn, 1);
+ ttydisc_unlock(tp);
break;
case EVFILT_WRITE:
kn->kn_hook = tp;
kn->kn_fop = &tty_kqops_write;
+ ttydisc_lock(tp);
knlist_add(&tp->t_outpoll.si_note, kn, 1);
+ ttydisc_unlock(tp);
break;
default:
error = EINVAL;
@@ -1052,7 +1100,7 @@
}
struct tty *
-tty_alloc_mutex(struct ttydevsw *tsw, void *sc, struct mtx *mutex)
+tty_alloc_mutex(struct ttydevsw *tsw, void *sc, struct mtx *discmtx)
{
struct tty *tp;
@@ -1091,16 +1139,30 @@
cv_init(&tp->t_bgwait, "ttybg");
cv_init(&tp->t_dcdwait, "ttydcd");
- /* Allow drivers to use a custom mutex to lock the TTY. */
- if (mutex != NULL) {
- tp->t_mtx = mutex;
+ if (discmtx == &Giant) {
+ /*
+ * This should go away when the syscons/Giant problem is
+ * resolved. For now, we still have the one driver locked by
+ * Giant, so we have to special-case it and maintain the old
+ * behavior. It will get a separate discmtx and maintain Giant
+ * as the main tty lock.
+ */
+
+ tp->t_mtx = discmtx;
+ discmtx = NULL;
+ } else {
+ sx_init(&tp->t_sxobj, "ttysx");
+ }
+
+ if (discmtx != NULL) {
+ tp->t_discmtx = discmtx;
} else {
- tp->t_mtx = &tp->t_mtxobj;
- mtx_init(&tp->t_mtxobj, "ttymtx", NULL, MTX_DEF);
+ tp->t_discmtx = &tp->t_discmtxobj;
+ mtx_init(&tp->t_discmtxobj, "ttydiscmtx", NULL, MTX_DEF);
}
- knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx);
- knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx);
+ knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_discmtx);
+ knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_discmtx);
return (tp);
}
@@ -1132,8 +1194,11 @@
cv_destroy(&tp->t_dcdwait);
cv_destroy(&tp->t_outserwait);
- if (tp->t_mtx == &tp->t_mtxobj)
- mtx_destroy(&tp->t_mtxobj);
+ /* We didn't bother initializing the sx if we were given Giant. */
+ if (tp->t_mtx == NULL)
+ sx_destroy(&tp->t_sxobj);
+ if (tp->t_discmtx == &tp->t_discmtxobj)
+ mtx_destroy(&tp->t_discmtxobj);
ttydevsw_free(tp);
free(tp, M_TTY);
}
@@ -1176,9 +1241,11 @@
MPASS(tp->t_sessioncnt > 0);
tty_assert_locked(tp);
+ ttydisc_lock(tp);
if (tp->t_pgrp == pg)
tp->t_pgrp = NULL;
+ ttydisc_unlock(tp);
tty_unlock(tp);
}
@@ -1186,14 +1253,17 @@
tty_rel_sess(struct tty *tp, struct session *sess)
{
+ tty_assert_locked(tp);
MPASS(tp->t_sessioncnt > 0);
+ ttydisc_lock(tp);
/* Current session has left. */
if (tp->t_session == sess) {
tp->t_session = NULL;
MPASS(tp->t_pgrp == NULL);
}
tp->t_sessioncnt--;
+ ttydisc_unlock(tp);
tty_rel_free(tp);
}
@@ -1204,6 +1274,8 @@
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
+ if (!ttydisc_lock_owned(tp))
+ ttydisc_lock(tp);
/* Simulate carrier removal. */
ttydisc_modem(tp, 0);
@@ -1213,6 +1285,7 @@
cv_broadcast(&tp->t_dcdwait);
tp->t_flags |= TF_GONE;
+ ttydisc_unlock(tp);
tty_rel_free(tp);
}
@@ -1254,6 +1327,9 @@
return (EPERM);
}
+ ttydisc_lock(tp);
+ tp->t_sessioncnt--;
+ ttydisc_unlock(tp);
PROC_LOCK(p);
SESS_LOCK(session);
vp = session->s_ttyvp;
@@ -1262,7 +1338,6 @@
session->s_ttydp = NULL;
SESS_UNLOCK(session);
- tp->t_sessioncnt--;
p->p_flag &= ~P_CONTROLT;
PROC_UNLOCK(p);
sx_xunlock(&proctree_lock);
@@ -1501,7 +1576,7 @@
struct proc *p;
struct session *s;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(sig >= 1 && sig < NSIG);
/* Make signals start output again. */
@@ -1527,7 +1602,7 @@
{
ksiginfo_t ksi;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(sig >= 1 && sig < NSIG);
/* Make signals start output again. */
@@ -1550,6 +1625,7 @@
tty_wakeup(struct tty *tp, int flags)
{
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_ASYNC && tp->t_sigio != NULL)
pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL));
@@ -1570,11 +1646,21 @@
{
int error;
int revokecnt = tp->t_revokecnt;
+ bool locktty;
- tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED);
+ ttydisc_lock_assert(tp, MA_OWNED | MA_NOTRECURSED);
MPASS(!tty_gone(tp));
- error = cv_wait_sig(cv, tp->t_mtx);
+ locktty = tty_lock_owned(tp);
+ if (locktty)
+ tty_unlock(tp);
+ error = cv_wait_sig(cv, ttydisc_getlock(tp));
+ /* If we had the tty lock coming in, relock it. */
+ if (locktty) {
+ ttydisc_unlock(tp);
+ tty_lock(tp);
+ ttydisc_lock(tp);
+ }
/* Bail out when the device slipped away. */
if (tty_gone(tp))
@@ -1592,11 +1678,21 @@
{
int error;
int revokecnt = tp->t_revokecnt;
+ bool locktty;
- tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED);
+ ttydisc_lock_assert(tp, MA_OWNED | MA_NOTRECURSED);
MPASS(!tty_gone(tp));
- error = cv_timedwait_sig(cv, tp->t_mtx, hz);
+ locktty = tty_lock_owned(tp);
+ if (locktty)
+ tty_unlock(tp);
+ error = cv_timedwait_sig(cv, ttydisc_getlock(tp), hz);
+ /* If we had the tty lock coming in, relock it. */
+ if (locktty) {
+ ttydisc_unlock(tp);
+ tty_lock(tp);
+ ttydisc_lock(tp);
+ }
/* Bail out when the device slipped away. */
if (tty_gone(tp))
@@ -1613,6 +1709,7 @@
tty_flush(struct tty *tp, int flags)
{
+ ttydisc_assert_locked(tp);
if (flags & FWRITE) {
tp->t_flags &= ~TF_HIWAT_OUT;
ttyoutq_flush(&tp->t_outq);
@@ -1637,10 +1734,14 @@
tty_set_winsize(struct tty *tp, const struct winsize *wsz)
{
+ ttydisc_assert_unlocked(tp);
+ tty_assert_locked(tp);
if (memcmp(&tp->t_winsize, wsz, sizeof(*wsz)) == 0)
return;
tp->t_winsize = *wsz;
+ ttydisc_lock(tp);
tty_signal_pgrp(tp, SIGWINCH);
+ ttydisc_unlock(tp);
}
static int
@@ -1656,30 +1757,42 @@
* shifted. I don't know why.
*/
case TIOCSDTR:
+ ttydisc_lock(tp);
ttydevsw_modem(tp, SER_DTR, 0);
+ ttydisc_unlock(tp);
return (0);
case TIOCCDTR:
+ ttydisc_lock(tp);
ttydevsw_modem(tp, 0, SER_DTR);
+ ttydisc_unlock(tp);
return (0);
case TIOCMSET: {
int bits = *(int *)data;
+ ttydisc_lock(tp);
ttydevsw_modem(tp,
(bits & (TIOCM_DTR | TIOCM_RTS)) >> 1,
((~bits) & (TIOCM_DTR | TIOCM_RTS)) >> 1);
+ ttydisc_unlock(tp);
return (0);
}
case TIOCMBIS: {
int bits = *(int *)data;
+ ttydisc_lock(tp);
ttydevsw_modem(tp, (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1, 0);
+ ttydisc_unlock(tp);
return (0);
}
case TIOCMBIC: {
int bits = *(int *)data;
+ ttydisc_lock(tp);
ttydevsw_modem(tp, 0, (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1);
+ ttydisc_unlock(tp);
return (0);
}
case TIOCMGET:
+ ttydisc_lock(tp);
*(int *)data = TIOCM_LE + (ttydevsw_modem(tp, 0, 0) << 1);
+ ttydisc_unlock(tp);
return (0);
case FIOASYNC:
@@ -1726,6 +1839,7 @@
struct termios *t = data;
bool canonicalize = false;
+ ttydisc_lock(tp);
/*
* Who makes up these funny rules? According to POSIX,
* input baud rate is set equal to the output baud rate
@@ -1743,8 +1857,10 @@
/* Set terminal flags through tcsetattr(). */
if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
error = tty_drain(tp, 0);
- if (error)
+ if (error) {
+ ttydisc_unlock(tp);
return (error);
+ }
if (cmd == TIOCSETAF)
tty_flush(tp, FREAD);
}
@@ -1759,8 +1875,10 @@
tp->t_termios.c_ispeed != t->c_ispeed ||
tp->t_termios.c_ospeed != t->c_ospeed)) {
error = ttydevsw_param(tp, t);
- if (error)
+ if (error) {
+ ttydisc_unlock(tp);
return (error);
+ }
/* XXX: CLOCAL? */
@@ -1770,8 +1888,10 @@
/* Baud rate has changed - update watermarks. */
error = tty_watermarks(tp);
- if (error)
+ if (error) {
+ ttydisc_unlock(tp);
return (error);
+ }
}
/*
@@ -1817,6 +1937,7 @@
ttydevsw_pktnotify(tp, TIOCPKT_DOSTOP);
else
ttydevsw_pktnotify(tp, TIOCPKT_NOSTOP);
+ ttydisc_unlock(tp);
return (0);
}
case TIOCGETD:
@@ -1880,12 +2001,15 @@
}
/* Connect the session to the TTY. */
+ ttydisc_lock(tp);
tp->t_session = p->p_session;
tp->t_session->s_ttyp = tp;
tp->t_sessioncnt++;
/* Assign foreground process group. */
tp->t_pgrp = p->p_pgrp;
+ ttydisc_unlock(tp);
+
PROC_LOCK(p);
p->p_flag |= P_CONTROLT;
PROC_UNLOCK(p);
@@ -1921,7 +2045,9 @@
sx_sunlock(&proctree_lock);
return (ENOTTY);
}
+ ttydisc_lock(tp);
tp->t_pgrp = pg;
+ ttydisc_unlock(tp);
sx_sunlock(&proctree_lock);
/* Wake up the background process groups. */
@@ -1935,14 +2061,21 @@
flags = (FREAD|FWRITE);
else
flags &= (FREAD|FWRITE);
+ ttydisc_lock(tp);
tty_flush(tp, flags);
+ ttydisc_unlock(tp);
return (0);
}
case TIOCDRAIN:
/* Drain TTY output. */
- return tty_drain(tp, 0);
+ ttydisc_lock(tp);
+ error = tty_drain(tp, 0);
+ ttydisc_unlock(tp);
+ return (error);
case TIOCGDRAINWAIT:
+ ttydisc_lock(tp);
*(int *)data = tp->t_drainwait;
+ ttydisc_unlock(tp);
return (0);
case TIOCSDRAINWAIT:
error = priv_check(td, PRIV_TTY_DRAINWAIT);
@@ -1969,23 +2102,33 @@
tty_set_winsize(tp, data);
return (0);
case TIOCEXCL:
+ ttydisc_lock(tp);
tp->t_flags |= TF_EXCLUDE;
+ ttydisc_unlock(tp);
return (0);
case TIOCNXCL:
+ ttydisc_lock(tp);
tp->t_flags &= ~TF_EXCLUDE;
+ ttydisc_unlock(tp);
return (0);
case TIOCSTOP:
+ ttydisc_lock(tp);
tp->t_flags |= TF_STOPPED;
ttydevsw_pktnotify(tp, TIOCPKT_STOP);
+ ttydisc_unlock(tp);
return (0);
case TIOCSTART:
+ ttydisc_lock(tp);
tp->t_flags &= ~TF_STOPPED;
tp->t_termios.c_lflag &= ~FLUSHO;
ttydevsw_outwakeup(tp);
ttydevsw_pktnotify(tp, TIOCPKT_START);
+ ttydisc_unlock(tp);
return (0);
case TIOCSTAT:
+ ttydisc_lock(tp);
tty_info(tp);
+ ttydisc_unlock(tp);
return (0);
case TIOCSTI:
if ((fflag & FREAD) == 0 && priv_check(td, PRIV_TTY_STI))
@@ -1993,8 +2136,10 @@
if (!tty_is_ctty(tp, td->td_proc) &&
priv_check(td, PRIV_TTY_STI))
return (EACCES);
+ ttydisc_lock(tp);
ttydisc_rint(tp, *(char *)data, 0);
ttydisc_rint_done(tp);
+ ttydisc_unlock(tp);
return (0);
}
@@ -2015,7 +2160,10 @@
if (tty_gone(tp))
return (ENXIO);
+ /* tty device driver may change parameters related to I/O. */
+ ttydisc_lock(tp);
error = ttydevsw_ioctl(tp, cmd, data, td);
+ ttydisc_unlock(tp);
if (error == ENOIOCTL)
error = tty_generic_ioctl(tp, cmd, data, fflag, td);
@@ -2036,6 +2184,7 @@
tty_checkoutq(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
/* 256 bytes should be enough to print a log message. */
return (ttyoutq_bytesleft(&tp->t_outq) >= 256);
}
@@ -2044,6 +2193,7 @@
tty_hiwat_in_block(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
if ((tp->t_flags & TF_HIWAT_IN) == 0 &&
tp->t_termios.c_iflag & IXOFF &&
tp->t_termios.c_cc[VSTOP] != _POSIX_VDISABLE) {
@@ -2064,6 +2214,7 @@
tty_hiwat_in_unblock(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_HIWAT_IN &&
tp->t_termios.c_iflag & IXOFF &&
tp->t_termios.c_cc[VSTART] != _POSIX_VDISABLE) {
@@ -2163,6 +2314,7 @@
if (tp->t_flags & TF_HOOK)
goto done3;
+ ttydisc_lock(tp);
tp->t_flags |= TF_HOOK;
tp->t_hook = th;
tp->t_hooksoftc = softc;
@@ -2176,6 +2328,7 @@
if (!ttyhook_hashook(tp, rint) && ttyhook_hashook(tp, rint_bypass))
th->th_rint = ttyhook_defrint;
+ ttydisc_unlock(tp);
done3: tty_unlock(tp);
done2: dev_relthread(dev, ref);
done1: fdrop(fp, curthread);
@@ -2190,11 +2343,13 @@
MPASS(tp->t_flags & TF_HOOK);
/* Disconnect the hook. */
+ ttydisc_lock(tp);
tp->t_flags &= ~TF_HOOK;
tp->t_hook = NULL;
/* Maybe we need to leave bypass mode. */
ttydisc_optimize(tp);
+ ttydisc_unlock(tp);
/* Maybe deallocate the TTY as well. */
tty_rel_free(tp);
diff --git a/sys/kern/tty_info.c b/sys/kern/tty_info.c
--- a/sys/kern/tty_info.c
+++ b/sys/kern/tty_info.c
@@ -295,7 +295,8 @@
char comm[MAXCOMLEN + 1];
struct rusage ru;
- tty_assert_locked(tp);
+ /* ttydisc lock is sufficient for everything we're doing here */
+ ttydisc_assert_locked(tp);
if (tty_checkoutq(tp) == 0)
return;
diff --git a/sys/kern/tty_inq.c b/sys/kern/tty_inq.c
--- a/sys/kern/tty_inq.c
+++ b/sys/kern/tty_inq.c
@@ -116,6 +116,8 @@
{
struct ttyinq_block *tib;
+ tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
ti->ti_quota = howmany(size, TTYINQ_DATASIZE);
while (ti->ti_quota > ti->ti_nblocks) {
@@ -123,15 +125,12 @@
* List is getting bigger.
* Add new blocks to the tail of the list.
*
- * We must unlock the TTY temporarily, because we need
- * to allocate memory. This won't be a problem, because
- * in the worst case, another thread ends up here, which
- * may cause us to allocate too many blocks, but this
- * will be caught by the loop below.
+ * We must unlock the ttydisc, but we're still holding on to
+ * the tty lock so we should avoid problems.
*/
- tty_unlock(tp);
+ ttydisc_unlock(tp);
tib = uma_zalloc(ttyinq_zone, M_WAITOK);
- tty_lock(tp);
+ ttydisc_lock(tp);
if (tty_gone(tp)) {
uma_zfree(ttyinq_zone, tib);
@@ -164,6 +163,7 @@
size_t rlen, size_t flen)
{
+ ttydisc_assert_locked(tp);
/* rlen includes flen, flen bytes will be trimmed from the end. */
MPASS(rlen - flen <= uio->uio_resid);
@@ -235,10 +235,10 @@
* userspace. We may need to flush trailing
* bytes, like EOF characters.
*/
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = uiomove(tib->tib_data + cbegin,
clen - flen, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
/* Block can now be readded to the list. */
TTYINQ_RECYCLE(ti, tib);
@@ -253,9 +253,9 @@
MPASS(ti->ti_begin < TTYINQ_DATASIZE);
/* Temporary unlock and copy the data to userspace. */
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = uiomove(ob, clen - flen, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
}
if (error != 0)
diff --git a/sys/kern/tty_outq.c b/sys/kern/tty_outq.c
--- a/sys/kern/tty_outq.c
+++ b/sys/kern/tty_outq.c
@@ -93,6 +93,8 @@
{
struct ttyoutq_block *tob;
+ tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
to->to_quota = howmany(size, TTYOUTQ_DATASIZE);
while (to->to_quota > to->to_nblocks) {
@@ -100,20 +102,12 @@
* List is getting bigger.
* Add new blocks to the tail of the list.
*
- * We must unlock the TTY temporarily, because we need
- * to allocate memory. This won't be a problem, because
- * in the worst case, another thread ends up here, which
- * may cause us to allocate too many blocks, but this
- * will be caught by the loop below.
+ * We must unlock the ttydisc, but we're still holding on to
+ * the tty lock so we should avoid problems.
*/
- tty_unlock(tp);
+ ttydisc_unlock(tp);
tob = uma_zalloc(ttyoutq_zone, M_WAITOK);
- tty_lock(tp);
-
- if (tty_gone(tp)) {
- uma_zfree(ttyoutq_zone, tob);
- return (ENXIO);
- }
+ ttydisc_lock(tp);
TTYOUTQ_INSERT_TAIL(to, tob);
}
@@ -201,6 +195,7 @@
ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio)
{
+ ttydisc_assert_locked(tp);
while (uio->uio_resid > 0) {
int error;
struct ttyoutq_block *tob;
@@ -244,9 +239,9 @@
to->to_end -= TTYOUTQ_DATASIZE;
/* Temporary unlock and copy the data to userspace. */
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = uiomove(tob->tob_data + cbegin, clen, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
/* Block can now be readded to the list. */
TTYOUTQ_RECYCLE(to, tob);
@@ -261,9 +256,9 @@
MPASS(to->to_begin < TTYOUTQ_DATASIZE);
/* Temporary unlock and copy the data to userspace. */
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = uiomove(ob, clen, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
}
if (error != 0)
diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c
--- a/sys/kern/tty_pts.c
+++ b/sys/kern/tty_pts.c
@@ -81,20 +81,20 @@
* Per-PTS structure.
*
* List of locks
- * (t) locked by tty_lock()
+ * (d) locked by ttydisc_lock()
* (c) const until freeing
*/
struct pts_softc {
int pts_unit; /* (c) Device unit number. */
- unsigned int pts_flags; /* (t) Device flags. */
+ unsigned int pts_flags; /* (d) Device flags. */
#define PTS_PKT 0x1 /* Packet mode. */
#define PTS_FINISHED 0x2 /* Return errors on read()/write(). */
- char pts_pkt; /* (t) Unread packet mode data. */
+ char pts_pkt; /* (d) Unread packet mode data. */
- struct cv pts_inwait; /* (t) Blocking write() on master. */
- struct selinfo pts_inpoll; /* (t) Select queue for write(). */
- struct cv pts_outwait; /* (t) Blocking read() on master. */
- struct selinfo pts_outpoll; /* (t) Select queue for read(). */
+ struct cv pts_inwait; /* (d) Blocking write() on master. */
+ struct selinfo pts_inpoll; /* (d) Select queue for write(). */
+ struct cv pts_outwait; /* (d) Blocking read() on master. */
+ struct selinfo pts_outpoll; /* (d) Select queue for read(). */
#ifdef PTS_EXTERNAL
struct cdev *pts_cdev; /* (c) Master device node. */
@@ -119,7 +119,7 @@
if (uio->uio_resid == 0)
return (0);
- tty_lock(tp);
+ ttydisc_lock(tp);
for (;;) {
/*
@@ -130,7 +130,7 @@
if (psc->pts_flags & PTS_PKT && psc->pts_pkt) {
pkt = psc->pts_pkt;
psc->pts_pkt = 0;
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = ureadc(pkt, uio);
return (error);
@@ -151,11 +151,11 @@
* consumers aren't multithreaded.
*/
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = ureadc(TIOCPKT_DATA, uio);
if (error)
return (error);
- tty_lock(tp);
+ ttydisc_lock(tp);
}
error = ttydisc_getc_uio(tp, uio);
@@ -171,12 +171,12 @@
error = EWOULDBLOCK;
break;
}
- error = cv_wait_sig(&psc->pts_outwait, tp->t_mtx);
+ error = cv_wait_sig(&psc->pts_outwait, ttydisc_getlock(tp));
if (error != 0)
break;
}
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (error);
}
@@ -199,7 +199,7 @@
iblen = MIN(uio->uio_resid, sizeof ib);
error = uiomove(ib, iblen, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
if (error != 0) {
iblen = 0;
goto done;
@@ -233,18 +233,19 @@
/* Wake up users on the slave side. */
ttydisc_rint_done(tp);
- error = cv_wait_sig(&psc->pts_inwait, tp->t_mtx);
+ error = cv_wait_sig(&psc->pts_inwait,
+ ttydisc_getlock(tp));
if (error != 0)
goto done;
} while (iblen > 0);
if (uio->uio_resid == 0)
break;
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
done: ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
/*
* Don't account for the part of the buffer that we couldn't
@@ -270,9 +271,9 @@
/* This device supports non-blocking operation. */
return (0);
case FIONREAD:
- tty_lock(tp);
+ ttydisc_lock(tp);
*(int *)data = ttydisc_getc_poll(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (0);
case FIODGNAME:
#ifdef COMPAT_FREEBSD32
@@ -304,9 +305,9 @@
#ifdef PTS_LINUX
case TIOCGETA:
/* Obtain terminal flags through tcgetattr(). */
- tty_lock(tp);
+ ttydisc_lock(tp);
*(struct termios*)data = tp->t_termios;
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (0);
#endif /* PTS_LINUX */
case TIOCSETAF:
@@ -331,21 +332,21 @@
#endif /* PTS_COMPAT || PTS_LINUX */
case TIOCGPGRP:
/* Get the foreground process group ID. */
- tty_lock(tp);
+ ttydisc_lock(tp);
if (tp->t_pgrp != NULL)
*(int *)data = tp->t_pgrp->pg_id;
else
*(int *)data = NO_PID;
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (0);
case TIOCGSID:
/* Get the session leader process ID. */
- tty_lock(tp);
+ ttydisc_lock(tp);
if (tp->t_session == NULL)
error = ENOTTY;
else
*(int *)data = tp->t_session->s_sid;
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (error);
case TIOCPTMASTER:
/* Yes, we are a pseudo-terminal master. */
@@ -356,18 +357,18 @@
if (sig < 1 || sig >= NSIG)
return (EINVAL);
- tty_lock(tp);
+ ttydisc_lock(tp);
tty_signal_pgrp(tp, sig);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (0);
case TIOCPKT:
/* Enable/disable packet mode. */
- tty_lock(tp);
+ ttydisc_lock(tp);
if (*(int *)data)
psc->pts_flags |= PTS_PKT;
else
psc->pts_flags &= ~PTS_PKT;
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (0);
}
@@ -389,11 +390,11 @@
struct pts_softc *psc = tty_softc(tp);
int revents = 0;
- tty_lock(tp);
+ ttydisc_lock(tp);
if (psc->pts_flags & PTS_FINISHED) {
/* Slave device is not opened. */
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return ((events & (POLLIN|POLLRDNORM)) | POLLHUP);
}
@@ -427,7 +428,7 @@
selrecord(td, &psc->pts_inpoll);
}
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (revents);
}
@@ -768,8 +769,8 @@
psc->pts_cred = crhold(cred);
tp = tty_alloc(&pts_class, psc);
- knlist_init_mtx(&psc->pts_inpoll.si_note, tp->t_mtx);
- knlist_init_mtx(&psc->pts_outpoll.si_note, tp->t_mtx);
+ knlist_init_mtx(&psc->pts_inpoll.si_note, ttydisc_getlock(tp));
+ knlist_init_mtx(&psc->pts_outpoll.si_note, ttydisc_getlock(tp));
/* Expose the slave device as well. */
tty_makedev(tp, td->td_ucred, "pts/%u", psc->pts_unit);
@@ -815,8 +816,8 @@
psc->pts_cred = crhold(cred);
tp = tty_alloc(&pts_class, psc);
- knlist_init_mtx(&psc->pts_inpoll.si_note, tp->t_mtx);
- knlist_init_mtx(&psc->pts_outpoll.si_note, tp->t_mtx);
+ knlist_init_mtx(&psc->pts_inpoll.si_note, ttydisc_getlock(tp));
+ knlist_init_mtx(&psc->pts_outpoll.si_note, ttydisc_getlock(tp));
/* Expose the slave device as well. */
tty_makedev(tp, td->td_ucred, "%s", name);
diff --git a/sys/kern/tty_ttydisc.c b/sys/kern/tty_ttydisc.c
--- a/sys/kern/tty_ttydisc.c
+++ b/sys/kern/tty_ttydisc.c
@@ -98,6 +98,7 @@
ttydisc_close(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
/* Clean up our flags when leaving the discipline. */
tp->t_flags &= ~(TF_STOPPED|TF_HIWAT|TF_ZOMBIE);
tp->t_termios.c_lflag &= ~FLUSHO;
@@ -411,6 +412,7 @@
int error;
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (uio->uio_resid == 0)
return (0);
@@ -543,6 +545,7 @@
unsigned int oblen = 0;
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_ZOMBIE)
return (EIO);
@@ -567,18 +570,13 @@
/* Step 1: read data. */
obstart = ob;
nlen = MIN(uio->uio_resid, sizeof ob);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = uiomove(ob, nlen, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
if (error != 0)
break;
oblen = nlen;
- if (tty_gone(tp)) {
- error = ENXIO;
- break;
- }
-
MPASS(oblen > 0);
/* Step 2: process data. */
@@ -669,7 +667,7 @@
void
ttydisc_optimize(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (ttyhook_hashook(tp, rint_bypass)) {
tp->t_flags |= TF_BYPASS;
@@ -690,7 +688,7 @@
ttydisc_modem(struct tty *tp, int open)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (open)
cv_broadcast(&tp->t_dcdwait);
@@ -1015,7 +1013,7 @@
char ob[3] = { 0xff, 0x00 };
size_t ol;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
atomic_add_long(&tty_nin, 1);
@@ -1272,7 +1270,7 @@
{
size_t ret;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(tp->t_flags & TF_BYPASS);
@@ -1293,7 +1291,7 @@
ttydisc_rint_done(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (ttyhook_hashook(tp, rint_done))
ttyhook_rint_done(tp);
@@ -1309,7 +1307,7 @@
{
size_t l;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (ttyhook_hashook(tp, rint_poll))
return ttyhook_rint_poll(tp);
@@ -1352,7 +1350,7 @@
ttydisc_getc(struct tty *tp, void *buf, size_t len)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_STOPPED)
return (0);
@@ -1379,7 +1377,7 @@
size_t len;
char buf[TTY_STACKBUF];
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_STOPPED)
return (0);
@@ -1399,9 +1397,9 @@
break;
/* Copy to userspace. */
- tty_unlock(tp);
+ ttydisc_unlock(tp);
error = uiomove(buf, len, uio);
- tty_lock(tp);
+ ttydisc_lock(tp);
if (error != 0)
break;
@@ -1420,7 +1418,7 @@
ttydisc_getc_poll(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_STOPPED)
return (0);
@@ -1442,7 +1440,7 @@
{
size_t i;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tty_gone(tp))
return (-1);
diff --git a/sys/netgraph/ng_tty.c b/sys/netgraph/ng_tty.c
--- a/sys/netgraph/ng_tty.c
+++ b/sys/netgraph/ng_tty.c
@@ -336,8 +336,10 @@
/* notify the TTY that data is ready */
tty_lock(tp);
+ ttydisc_lock(tp);
if (!tty_gone(tp))
ttydevsw_outwakeup(tp);
+ ttydisc_unlock(tp);
tty_unlock(tp);
return (0);
@@ -410,7 +412,7 @@
size_t total = 0;
int error = 0, length;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (sc->hook == NULL)
return (0);
@@ -457,7 +459,7 @@
struct mbuf *m;
int error = 0;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (sc->hook == NULL)
return (0);
diff --git a/sys/powerpc/mambo/mambo_console.c b/sys/powerpc/mambo/mambo_console.c
--- a/sys/powerpc/mambo/mambo_console.c
+++ b/sys/powerpc/mambo/mambo_console.c
@@ -88,8 +88,10 @@
polltime = 1;
- callout_init(&mambo_callout, 1);
+ callout_init_mtx(&mambo_callout, ttydisc_getlock(tp), 0);
+ ttydisc_lock(tp);
callout_reset(&mambo_callout, polltime, mambo_timeout, NULL);
+ ttydisc_unlock(tp);
}
}
@@ -114,11 +116,9 @@
{
int c;
- tty_lock(tp);
while ((c = mambo_cngetc(NULL)) != -1)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
- tty_unlock(tp);
callout_reset(&mambo_callout, polltime, mambo_timeout, NULL);
}
diff --git a/sys/powerpc/powernv/opal_console.c b/sys/powerpc/powernv/opal_console.c
--- a/sys/powerpc/powernv/opal_console.c
+++ b/sys/powerpc/powernv/opal_console.c
@@ -528,11 +528,11 @@
struct tty *tp = sc->tp;
int c;
- tty_lock(tp);
+ ttydisc_lock(tp);
while ((c = uart_opal_getc(sc)) > 0)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
opal_call(OPAL_POLL_EVENTS, NULL);
diff --git a/sys/powerpc/pseries/phyp_console.c b/sys/powerpc/pseries/phyp_console.c
--- a/sys/powerpc/pseries/phyp_console.c
+++ b/sys/powerpc/pseries/phyp_console.c
@@ -447,11 +447,11 @@
unsigned char c;
int len;
- tty_lock(tp);
+ ttydisc_lock(tp);
while ((len = uart_phyp_get(sc, &c, 1)) > 0)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
if (sc->irqres == NULL)
callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc);
diff --git a/sys/riscv/riscv/riscv_console.c b/sys/riscv/riscv/riscv_console.c
--- a/sys/riscv/riscv/riscv_console.c
+++ b/sys/riscv/riscv/riscv_console.c
@@ -126,8 +126,10 @@
polltime = 1;
- callout_init(&riscv_callout, 1);
+ callout_init_mtx(&riscv_callout, ttydisc_getlock(tp), 0);
+ ttydisc_lock(tp);
callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
+ ttydisc_unlock(tp);
}
}
@@ -157,11 +159,9 @@
{
int c;
- tty_lock(tp);
while ((c = riscv_cngetc(NULL)) != -1)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
- tty_unlock(tp);
callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
}
diff --git a/sys/sys/tty.h b/sys/sys/tty.h
--- a/sys/sys/tty.h
+++ b/sys/sys/tty.h
@@ -36,6 +36,7 @@
#include <sys/queue.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sx.h>
#include <sys/condvar.h>
#include <sys/selinfo.h>
#include <sys/_termios.h>
@@ -53,64 +54,89 @@
/*
* Per-TTY structure, containing buffers, etc.
*
+ * Under the new locking model, the ttylock is mostly internal to ^/sys/kern.
+ * It must be acquired when calling tty_rel_gone(), but for the most part
+ * drivers will not touch it. It is especially wrong for a driver to drop the
+ * tty lock when entered via ttydevsw methods; it is sleepable so that drivers
+ * do not need to drop it, keeping entry to tty methods from userland properly
+ * blocked while the driver is operating.
+ *
+ * The lock that drivers may supply is now called the ttydisc lock, which
+ * replaces most traditional usage of the ttylock in drivers. As the name
+ * implies, it must be held when calling ttydisc_* methods. The exception is
+ * when &Giant is passed to tty_alloc_mutex(); this is currently a special hack
+ * put in place so that syscons can continue operating without the tty layer
+ * attempting to acquire this sx before Giant. syscons will become properly
+ * locked in due time, but this is a more complicated feat.
+ *
* List of locks
- * (t) locked by t_mtx
+ * (t) locked by ttylock
+ * (d) locked by ttydisc lock
* (l) locked by tty_list_sx
* (c) const until freeing
- */
+ * (d+t) both locks must be held to write
+ *
+ * (d*) locking for tf_flags is more complex. It is generally locked by the
+ * ttydisc lock, but both locks must be held to mark some flags so that we
+ * can do some unlocked reads safely with just one or the other. Those flags
+ * are annotated with a (t) to indicate that they require the ttylock as well.
+*/
struct tty {
- struct mtx *t_mtx; /* TTY lock. */
- struct mtx t_mtxobj; /* Per-TTY lock (when not borrowing). */
+ struct mtx *t_mtx; /* Deprecated TTY lock (Giant). */
+ struct sx t_sxobj; /* TTY lock (when not borrowing). */
+ struct mtx *t_discmtx; /* TTY discipline lock. */
+ /* Per-TTY discipline lock (when not borrowing). */
+ struct mtx t_discmtxobj;
TAILQ_ENTRY(tty) t_list; /* (l) TTY list entry. */
- int t_drainwait; /* (t) TIOCDRAIN timeout seconds. */
- unsigned int t_flags; /* (t) Terminal option flags. */
+ int t_drainwait; /* (d) TIOCDRAIN timeout seconds. */
+ unsigned int t_flags; /* (d*) Terminal option flags. */
/* Keep flags in sync with db_show_tty and pstat(8). */
#define TF_NOPREFIX 0x00001 /* Don't prepend "tty" to device name. */
#define TF_INITLOCK 0x00002 /* Create init/lock state devices. */
#define TF_CALLOUT 0x00004 /* Create "cua" devices. */
-#define TF_OPENED_IN 0x00008 /* "tty" node is in use. */
-#define TF_OPENED_OUT 0x00010 /* "cua" node is in use. */
-#define TF_OPENED_CONS 0x00020 /* Device in use as console. */
+#define TF_OPENED_IN 0x00008 /* (t) "tty" node is in use. */
+#define TF_OPENED_OUT 0x00010 /* (t) "cua" node is in use. */
+#define TF_OPENED_CONS 0x00020 /* (t) Device in use as console. */
#define TF_OPENED (TF_OPENED_IN|TF_OPENED_OUT|TF_OPENED_CONS)
-#define TF_GONE 0x00040 /* Device node is gone. */
-#define TF_OPENCLOSE 0x00080 /* Device is in open()/close(). */
-#define TF_ASYNC 0x00100 /* Asynchronous I/O enabled. */
+#define TF_GONE 0x00040 /* (t) Device node is gone. */
+#define TF_OPENCLOSE 0x00080 /* (t) Device is in open()/close(). */
+#define TF_ASYNC 0x00100 /* (t) Asynchronous I/O enabled. */
#define TF_LITERAL 0x00200 /* Accept the next character literally. */
#define TF_HIWAT_IN 0x00400 /* We've reached the input watermark. */
#define TF_HIWAT_OUT 0x00800 /* We've reached the output watermark. */
#define TF_HIWAT (TF_HIWAT_IN|TF_HIWAT_OUT)
#define TF_STOPPED 0x01000 /* Output flow control - stopped. */
-#define TF_EXCLUDE 0x02000 /* Exclusive access. */
+#define TF_EXCLUDE 0x02000 /* (t) Exclusive access. */
#define TF_BYPASS 0x04000 /* Optimized input path. */
#define TF_ZOMBIE 0x08000 /* Modem disconnect received. */
-#define TF_HOOK 0x10000 /* TTY has hook attached. */
-#define TF_BUSY_IN 0x20000 /* Process busy in read() -- not supported. */
-#define TF_BUSY_OUT 0x40000 /* Process busy in write(). */
+#define TF_HOOK 0x10000 /* (t) TTY has hook attached. */
+#define TF_BUSY_IN 0x20000 /* (t) Process busy in read(); not supported. */
+#define TF_BUSY_OUT 0x40000 /* (Process busy in write(). */
#define TF_BUSY (TF_BUSY_IN|TF_BUSY_OUT)
- unsigned int t_revokecnt; /* (t) revoke() count. */
+ unsigned int t_revokecnt; /* (d+t) revoke() count. */
/* Buffering mechanisms. */
- struct ttyinq t_inq; /* (t) Input queue. */
- size_t t_inlow; /* (t) Input low watermark. */
- struct ttyoutq t_outq; /* (t) Output queue. */
- size_t t_outlow; /* (t) Output low watermark. */
+ struct ttyinq t_inq; /* (d) Input queue. */
+ size_t t_inlow; /* (d) Input low watermark. */
+ struct ttyoutq t_outq; /* (d) Output queue. */
+ size_t t_outlow; /* (d) Output low watermark. */
/* Sleeping mechanisms. */
- struct cv t_inwait; /* (t) Input wait queue. */
- struct cv t_outwait; /* (t) Output wait queue. */
- struct cv t_outserwait; /* (t) Serial output wait queue. */
- struct cv t_bgwait; /* (t) Background wait queue. */
- struct cv t_dcdwait; /* (t) Carrier Detect wait queue. */
+ struct cv t_inwait; /* (d) Input wait queue. */
+ struct cv t_outwait; /* (d) Output wait queue. */
+ struct cv t_outserwait; /* (d) Serial output wait queue. */
+ struct cv t_bgwait; /* (d) Background wait queue. */
+ struct cv t_dcdwait; /* (d) Carrier Detect wait queue. */
/* Polling mechanisms. */
struct selinfo t_inpoll; /* (t) Input poll queue. */
struct selinfo t_outpoll; /* (t) Output poll queue. */
struct sigio *t_sigio; /* (t) Asynchronous I/O. */
- struct termios t_termios; /* (t) I/O processing flags. */
+ struct termios t_termios; /* (d+t) I/O processing flags. */
struct winsize t_winsize; /* (t) Window size. */
- unsigned int t_column; /* (t) Current cursor position. */
- unsigned int t_writepos; /* (t) Where input was interrupted. */
+ unsigned int t_column; /* (d) Current cursor position. */
+ unsigned int t_writepos; /* (d) Where input was interrupted. */
int t_compatflags; /* (t) COMPAT_43TTY flags. */
/* Init/lock-state devices. */
@@ -123,16 +149,16 @@
struct ttyhook *t_hook; /* (t) Capture/inject hook. */
/* Process signal delivery. */
- struct pgrp *t_pgrp; /* (t) Foreground process group. */
- struct session *t_session; /* (t) Associated session. */
- unsigned int t_sessioncnt; /* (t) Backpointing sessions. */
+ struct pgrp *t_pgrp; /* (d+t) Foreground process group. */
+ struct session *t_session; /* (d+t) Associated session. */
+ unsigned int t_sessioncnt; /* (d+t) Backpointing sessions. */
void *t_devswsoftc; /* (c) Soft config, for drivers. */
void *t_hooksoftc; /* (t) Soft config, for hooks. */
struct cdev *t_dev; /* (c) Primary character device. */
- size_t t_prbufsz; /* (t) SIGINFO buffer size. */
- char t_prbuf[]; /* (t) SIGINFO buffer. */
+ size_t t_prbufsz; /* (d) SIGINFO buffer size. */
+ char t_prbuf[]; /* (d) SIGINFO buffer. */
};
/*
@@ -162,20 +188,91 @@
#define TTYUNIT_CALLOUT 0x4
/* Allocation and deallocation. */
+/*
+ * - tty_alloc: allocate a TTY with internal TTY/discipline locks
+ * - tty_alloc_mutex: allocate a TTY with a given mutex as the ttydisc lock.
+ * The exception is if the mutex specified is Giant, it will be used as
+ * the TTY lock instead and an internal discipline lock will be allocated.
+ */
struct tty *tty_alloc(struct ttydevsw *tsw, void *softc);
struct tty *tty_alloc_mutex(struct ttydevsw *tsw, void *softc, struct mtx *mtx);
void tty_rel_pgrp(struct tty *tp, struct pgrp *pgrp);
void tty_rel_sess(struct tty *tp, struct session *sess);
void tty_rel_gone(struct tty *tp);
-#define tty_lock(tp) mtx_lock((tp)->t_mtx)
-#define tty_unlock(tp) mtx_unlock((tp)->t_mtx)
-#define tty_lock_owned(tp) mtx_owned((tp)->t_mtx)
-#define tty_assert_locked(tp) mtx_assert((tp)->t_mtx, MA_OWNED)
-#define tty_getlock(tp) ((tp)->t_mtx)
+/*
+ * These will get turned back into macros after the syscons/Giant locking
+ * situation is resolved. For now, we have to support both kinds of tty lock
+ * for this one case.
+ */
+static __inline void
+_tty_lock(struct tty *tp)
+{
+
+ if (tp->t_mtx != NULL)
+ mtx_lock(tp->t_mtx);
+ else
+ sx_xlock(&tp->t_sxobj);
+}
+
+static __inline void
+_tty_unlock(struct tty *tp)
+{
+
+ if (tp->t_mtx != NULL)
+ mtx_unlock(tp->t_mtx);
+ else
+ sx_xunlock(&tp->t_sxobj);
+}
+
+static __inline int
+_tty_lock_owned(struct tty *tp)
+{
+
+ if (tp->t_mtx != NULL)
+ return (mtx_owned(tp->t_mtx));
+ else
+ return (sx_xlocked(&tp->t_sxobj));
+}
+
+#if defined(INVARIANTS) || defined(INVARIANTS_SUPPORT)
+/* XXX This should go away when the Giant special-case is removed. */
+static __inline void
+tty_assert_locked(struct tty *tp)
+{
+
+ if (tp->t_mtx != NULL)
+ mtx_assert(tp->t_mtx, MA_OWNED);
+ else
+ sx_assert(&tp->t_sxobj, SA_XLOCKED);
+}
+
+#else
+
+#define tty_assert_locked(tp)
+
+#endif /* defined(INVARIANTS) || defined(INVARIANTS_SUPPORT */
+
+#define tty_lock(tp) _tty_lock(tp)
+#define tty_unlock(tp) _tty_unlock(tp)
+#define tty_lock_owned(tp) _tty_lock_owned(tp)
+
+/*
+ * XXX This one is technically wrong as long as syscons is still Giant-locked.
+ * However, neither the internal tty infrastructure nor syscons will attempt to
+ * tty_getlock, so we leave it as-is.
+ */
+#define tty_getlock(tp) (&(tp)->t_sxobj)
+
+#define ttydisc_lock(tp) mtx_lock((tp)->t_discmtx)
+#define ttydisc_unlock(tp) mtx_unlock((tp)->t_discmtx)
+#define ttydisc_lock_owned(tp) mtx_owned((tp)->t_discmtx)
+#define ttydisc_assert_locked(tp) mtx_assert((tp)->t_discmtx, MA_OWNED)
+#define ttydisc_assert_unlocked(tp) mtx_assert((tp)->t_discmtx, MA_NOTOWNED)
+#define ttydisc_getlock(tp) ((tp)->t_discmtx)
-/* XXX Should migrate users to tty_assert_locked! */
-#define tty_lock_assert(tp, ma) mtx_assert((tp)->t_mtx, (ma))
+/* Internal to tty, preferably... */
+#define ttydisc_lock_assert(tp, ma) mtx_assert((tp)->t_discmtx, (ma))
/* Device node creation. */
int tty_makedevf(struct tty *tp, struct ucred *cred, int flags,
diff --git a/sys/sys/ttydevsw.h b/sys/sys/ttydevsw.h
--- a/sys/sys/ttydevsw.h
+++ b/sys/sys/ttydevsw.h
@@ -85,6 +85,7 @@
{
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_open(tp));
@@ -95,6 +96,7 @@
{
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_devsw->tsw_close(tp);
@@ -104,7 +106,8 @@
ttydevsw_outwakeup(struct tty *tp)
{
- tty_assert_locked(tp);
+ /* We may or may not have the tty lock. */
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
/* Prevent spurious wakeups. */
@@ -118,7 +121,8 @@
ttydevsw_inwakeup(struct tty *tp)
{
- tty_assert_locked(tp);
+ /* We may or may not have the tty lock. */
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
/* Prevent spurious wakeups. */
@@ -133,6 +137,7 @@
{
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_ioctl(tp, cmd, data, td));
@@ -153,6 +158,8 @@
ttydevsw_param(struct tty *tp, struct termios *t)
{
+ tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_param(tp, t));
@@ -162,6 +169,8 @@
ttydevsw_modem(struct tty *tp, int sigon, int sigoff)
{
+ tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_modem(tp, sigon, sigoff));
@@ -181,7 +190,7 @@
ttydevsw_pktnotify(struct tty *tp, char event)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_devsw->tsw_pktnotify(tp, event);
@@ -191,6 +200,7 @@
ttydevsw_free(struct tty *tp)
{
+ /* Locks are destroyed at this point. */
MPASS(tty_gone(tp));
tp->t_devsw->tsw_free(tty_softc(tp));
@@ -200,7 +210,8 @@
ttydevsw_busy(struct tty *tp)
{
- tty_assert_locked(tp);
+ /* We may or may not have the tty lock. */
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_busy(tp));
diff --git a/sys/sys/ttydisc.h b/sys/sys/ttydisc.h
--- a/sys/sys/ttydisc.h
+++ b/sys/sys/ttydisc.h
@@ -72,7 +72,7 @@
ttydisc_read_poll(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
return ttyinq_bytescanonicalized(&tp->t_inq);
}
@@ -81,7 +81,7 @@
ttydisc_write_poll(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
return ttyoutq_bytesleft(&tp->t_outq);
}
diff --git a/sys/sys/ttyhook.h b/sys/sys/ttyhook.h
--- a/sys/sys/ttyhook.h
+++ b/sys/sys/ttyhook.h
@@ -76,7 +76,7 @@
static __inline int
ttyhook_rint(struct tty *tp, char c, int flags)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return tp->t_hook->th_rint(tp, c, flags);
@@ -85,7 +85,7 @@
static __inline size_t
ttyhook_rint_bypass(struct tty *tp, const void *buf, size_t len)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return tp->t_hook->th_rint_bypass(tp, buf, len);
@@ -94,7 +94,7 @@
static __inline void
ttyhook_rint_done(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_hook->th_rint_done(tp);
@@ -103,7 +103,7 @@
static __inline size_t
ttyhook_rint_poll(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return tp->t_hook->th_rint_poll(tp);
@@ -112,7 +112,7 @@
static __inline size_t
ttyhook_getc_inject(struct tty *tp, void *buf, size_t len)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return tp->t_hook->th_getc_inject(tp, buf, len);
@@ -121,7 +121,7 @@
static __inline void
ttyhook_getc_capture(struct tty *tp, const void *buf, size_t len)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_hook->th_getc_capture(tp, buf, len);
@@ -130,7 +130,7 @@
static __inline size_t
ttyhook_getc_poll(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return tp->t_hook->th_getc_poll(tp);
@@ -139,7 +139,7 @@
static __inline void
ttyhook_close(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
tp->t_hook->th_close(tp);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Jan 19, 9:53 PM (20 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15961719
Default Alt Text
D24459.diff (64 KB)

Event Timeline