Page MenuHomeFreeBSD

D24459.id70715.diff
No OneTemporary

D24459.id70715.diff

Index: sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c
===================================================================
--- sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c
+++ sys/dev/altera/jtag_uart/altera_jtag_uart_tty.c
@@ -266,7 +266,7 @@
{
int c;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
AJU_LOCK_ASSERT(sc);
while (aju_readable(sc)) {
@@ -298,7 +298,7 @@
uint32_t v;
uint8_t ch;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
AJU_LOCK_ASSERT(sc);
AJU_UNLOCK(sc);
@@ -364,7 +364,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);
@@ -377,7 +377,6 @@
struct altera_jtag_uart_softc *sc = arg;
struct tty *tp = sc->ajus_ttyp;
- tty_lock(tp);
AJU_LOCK(sc);
/*
@@ -399,7 +398,6 @@
callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
aju_io_callout, sc);
AJU_UNLOCK(sc);
- tty_unlock(tp);
}
static void
@@ -409,7 +407,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) {
@@ -439,7 +436,6 @@
callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
aju_ac_callout, sc);
AJU_UNLOCK(sc);
- tty_unlock(tp);
}
static void
@@ -449,7 +445,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) {
@@ -461,7 +457,7 @@
aju_handle_output(sc, tp);
}
AJU_UNLOCK(sc);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
int
@@ -518,6 +514,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
@@ -528,13 +526,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);
}
@@ -545,8 +544,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);
@@ -558,7 +560,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);
}
Index: sys/dev/bvm/bvm_console.c
===================================================================
--- sys/dev/bvm/bvm_console.c
+++ sys/dev/bvm/bvm_console.c
@@ -110,7 +110,7 @@
if (bvm_consdev.cn_pri != CN_DEAD) {
tp = tty_alloc(&bvm_ttydevsw, NULL);
- callout_init_mtx(&bvm_timer, tty_getlock(tp), 0);
+ callout_init_mtx(&bvm_timer, ttydisc_getlock(tp), 0);
tty_makedev(tp, NULL, "bvmcons");
}
}
@@ -118,6 +118,8 @@
static int
bvm_tty_open(struct tty *tp)
{
+
+ ttydisc_assert_locked(tp);
polltime = hz / BVMCONS_POLL_HZ;
if (polltime < 1)
polltime = 1;
@@ -130,7 +132,7 @@
bvm_tty_close(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
callout_stop(&bvm_timer);
}
@@ -159,7 +161,7 @@
tp = (struct tty *)v;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
while ((c = bvm_cngetc(NULL)) != -1)
ttydisc_rint(tp, c, 0);
ttydisc_rint_done(tp);
Index: sys/dev/cfe/cfe_console.c
===================================================================
--- sys/dev/cfe/cfe_console.c
+++ sys/dev/cfe/cfe_console.c
@@ -90,7 +90,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");
}
}
@@ -98,6 +98,8 @@
static int
cfe_tty_open(struct tty *tp)
{
+
+ ttydisc_assert_locked(tp);
polltime = hz / CFECONS_POLL_HZ;
if (polltime < 1)
polltime = 1;
@@ -110,6 +112,7 @@
cfe_tty_close(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
callout_stop(&cfe_timer);
}
@@ -142,7 +145,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);
Index: sys/dev/dcons/dcons_os.c
===================================================================
--- sys/dev/dcons/dcons_os.c
+++ sys/dev/dcons/dcons_os.c
@@ -235,13 +235,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;
Index: sys/dev/gxemul/cons/gxemul_cons.c
===================================================================
--- sys/dev/gxemul/cons/gxemul_cons.c
+++ sys/dev/gxemul/cons/gxemul_cons.c
@@ -281,10 +281,11 @@
tp = tty_alloc(&gxemul_cons_ttydevsw, NULL);
tty_init_console(tp, 0);
tty_makedev(tp, NULL, "%s", "ttyu0");
- callout_init(&gxemul_cons_callout, 1);
+ callout_init_mtx(&gxemul_cons_callout, ttydisc_getlock(tp), 0);
+ ttydisc_lock(tp);
callout_reset(&gxemul_cons_callout, gxemul_cons_polltime,
gxemul_cons_timeout, tp);
-
+ ttydisc_unlock(tp);
}
SYSINIT(gxemul_cons_ttyinit, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE,
gxemul_cons_ttyinit, NULL);
@@ -316,7 +317,7 @@
int c;
tp = v;
- tty_lock(tp);
+ ttydisc_lock(tp);
GC_LOCK();
while (gxemul_cons_readable()) {
c = gxemul_cons_read();
@@ -329,7 +330,7 @@
}
GC_UNLOCK();
ttydisc_rint_done(tp);
- tty_unlock(tp);
callout_reset(&gxemul_cons_callout, gxemul_cons_polltime,
gxemul_cons_timeout, tp);
+ ttydisc_unlock(tp);
}
Index: sys/dev/nmdm/nmdm.c
===================================================================
--- sys/dev/nmdm/nmdm.c
+++ sys/dev/nmdm/nmdm.c
@@ -108,6 +108,7 @@
struct nmdmpart *onp;
struct tty *otp;
+ ttydisc_assert_locked(tp);
np = tty_softc(tp);
onp = np->np_other;
otp = onp->np_tty;
@@ -120,13 +121,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
@@ -191,7 +193,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';
@@ -256,12 +261,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"));
@@ -279,7 +288,7 @@
/* This may happen when we are in detach process. */
if (tty_gone(otp)) {
- tty_unlock(otp);
+ ttydisc_unlock(tp);
return;
}
@@ -294,7 +303,7 @@
ttydisc_rint_done(otp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
static int
@@ -324,6 +333,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)) {
@@ -381,6 +392,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;
Index: sys/dev/ofw/ofw_console.c
===================================================================
--- sys/dev/ofw/ofw_console.c
+++ sys/dev/ofw/ofw_console.c
@@ -102,7 +102,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);
}
}
@@ -114,6 +114,8 @@
static int
ofwtty_open(struct tty *tp)
{
+
+ ttydisc_assert_locked(tp);
polltime = hz / OFWCONS_POLL_HZ;
if (polltime < 1)
polltime = 1;
@@ -127,6 +129,7 @@
ofwtty_close(struct tty *tp)
{
+ ttydisc_assert_locked(tp);
callout_stop(&ofw_timer);
}
@@ -136,6 +139,7 @@
int len;
u_char buf[OFBURSTLEN];
+ ttydisc_assert_locked(tp);
for (;;) {
len = ttydisc_getc(tp, buf, sizeof buf);
if (len == 0)
@@ -152,7 +156,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);
Index: sys/dev/rp/rp.c
===================================================================
--- sys/dev/rp/rp.c
+++ sys/dev/rp/rp.c
@@ -596,7 +596,7 @@
FIFO one word at a time, pulling apart the character and
the status. Update error counters depending on status.
*/
- tty_lock(tp);
+ ttydisc_lock(tp);
if(ChanStatus & STATMODE) {
while(ToRecv) {
CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
@@ -630,7 +630,7 @@
}
}
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
static void rp_handle_port(struct rp_port *rp)
@@ -674,7 +674,7 @@
rp = arg;
tp = rp->rp_tty;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
ctl = rp->rp_ctlp;
CtlMask = ctl->ctlmask(ctl);
if (CtlMask & (1 << rp->rp_aiop)) {
@@ -742,7 +742,7 @@
num_chan = sGetAiopNumChan(ctlp, aiop);
for(chan=0; chan < num_chan; chan++, port++, rp++) {
rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
- callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0);
+ callout_init_mtx(&rp->rp_timer, ttydisc_getlock(tp), 0);
rp->rp_port = port;
rp->rp_ctlp = ctlp;
rp->rp_unit = unit;
@@ -848,7 +848,9 @@
IntMask = IntMask & rp->rp_intmask;
ChanStatus = sGetChanStatus(&rp->rp_channel);
+ ttydisc_lock(tp);
callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
+ ttydisc_unlock(tp);
device_busy(rp->rp_ctlp->dev);
return(0);
@@ -860,6 +862,7 @@
struct rp_port *rp;
rp = tty_softc(tp);
+ ttydisc_assert_locked(tp);
callout_stop(&rp->rp_timer);
rphardclose(tp);
device_unbusy(rp->rp_ctlp->dev);
Index: sys/dev/snp/snp.c
===================================================================
--- sys/dev/snp/snp.c
+++ sys/dev/snp/snp.c
@@ -164,10 +164,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)
@@ -178,7 +182,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)) {
@@ -186,7 +190,7 @@
break;
}
}
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (error);
}
Index: sys/dev/syscons/syscons.c
===================================================================
--- sys/dev/syscons/syscons.c
+++ sys/dev/syscons/syscons.c
@@ -410,6 +410,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;
@@ -748,7 +749,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);
}
@@ -849,9 +859,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 */
@@ -877,6 +890,7 @@
}
ttydisc_rint_done(cur_tty);
+ ttydisc_unlock(cur_tty);
}
sc->cur_scp->status |= MOUSE_HIDDEN;
@@ -4240,10 +4254,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
@@ -4254,11 +4270,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);
}
void
Index: sys/dev/syscons/sysmouse.c
===================================================================
--- sys/dev/syscons/sysmouse.c
+++ sys/dev/syscons/sysmouse.c
@@ -263,7 +263,7 @@
int x, y, z;
int i, flags = 0;
- tty_lock(sysmouse_tty);
+ ttydisc_lock(sysmouse_tty);
switch (info->operation) {
case MOUSE_ACTION:
@@ -324,7 +324,7 @@
}
ttydisc_rint_done(sysmouse_tty);
-done: tty_unlock(sysmouse_tty);
+done: ttydisc_unlock(sysmouse_tty);
return (flags);
}
Index: sys/dev/uart/uart_tty.c
===================================================================
--- sys/dev/uart/uart_tty.c
+++ 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
@@ -449,7 +449,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);
}
Index: sys/dev/usb/serial/usb_serial.c
===================================================================
--- sys/dev/usb/serial/usb_serial.c
+++ sys/dev/usb/serial/usb_serial.c
@@ -530,6 +530,7 @@
mtx_unlock(&ucom_mtx);
tty_lock(tp);
+ ttydisc_lock(tp);
ucom_close(tp); /* close, if any */
@@ -630,10 +631,11 @@
task->termios_copy = *pt;
/*
- * Closing the device should be synchronous.
+ * The tty lock is sleepable and the ttydisc lock is shared with the USB
+ * parts. We can now sychronously do the USB parts while making sure
+ * that we're cool from termios standpoint.
*/
- if (fn == ucom_cfg_close)
- usb_proc_mwait(&ssc->sc_tq, t0, t1);
+ usb_proc_mwait(&ssc->sc_tq, t0, t1);
/*
* In case of multiple configure requests,
Index: sys/dev/virtio/console/virtio_console.c
===================================================================
--- sys/dev/virtio/console/virtio_console.c
+++ sys/dev/virtio/console/virtio_console.c
@@ -95,6 +95,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;
@@ -1293,6 +1294,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;
@@ -1383,10 +1386,13 @@
{
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);
@@ -1398,6 +1404,8 @@
{
struct vtcon_port *port;
+ /* Effectively VTCON_PORT_LOCK. */
+ ttydisc_assert_locked(tp);
port = tty_softc(tp);
if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
@@ -1413,6 +1421,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)
Index: sys/dev/xen/console/xen_console.c
===================================================================
--- sys/dev/xen/console/xen_console.c
+++ sys/dev/xen/console/xen_console.c
@@ -515,7 +515,7 @@
cons = tty_softc(tp);
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
/*
* Don't transmit any character if the buffer is full. Otherwise,
@@ -555,7 +555,7 @@
xencons_rx(cons);
- tty_lock(tp);
+ ttydisc_lock(tp);
while ((ret = xencons_getc(cons)) != -1) {
#ifdef KDB
kdb_alt_break(ret, &cons->altbrk);
@@ -563,7 +563,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);
@@ -682,6 +682,7 @@
struct xencons_priv *cons;
cons = tty_softc(tp);
+ ttydisc_assert_locked(tp);
callout_stop(&cons->callout);
@@ -734,7 +735,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) {
Index: sys/kern/kern_cons.c
===================================================================
--- sys/kern/kern_cons.c
+++ sys/kern/kern_cons.c
@@ -632,17 +632,17 @@
int c;
if (constty != NULL) {
- tty_lock(constty);
+ ttydisc_lock(constty);
while ((c = msgbuf_getchar(&consmsgbuf)) != -1) {
if (tty_putchar(constty, c) < 0) {
- tty_unlock(constty);
+ ttydisc_unlock(constty);
constty = NULL;
break;
}
}
if (constty != NULL)
- tty_unlock(constty);
+ ttydisc_unlock(constty);
}
if (constty != NULL) {
callout_reset(&conscallout, hz / constty_wakeups_per_second,
Index: sys/kern/kern_proc.c
===================================================================
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -861,10 +861,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) {
Index: sys/kern/subr_prf.c
===================================================================
--- sys/kern/subr_prf.c
+++ sys/kern/subr_prf.c
@@ -198,10 +198,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);
}
Index: sys/kern/subr_terminal.c
===================================================================
--- sys/kern/subr_terminal.c
+++ sys/kern/subr_terminal.c
@@ -321,7 +321,7 @@
return;
c = TCHAR_CHARACTER(c);
- tty_lock(tp);
+ ttydisc_lock(tp);
/*
* Conversion to UTF-8.
*/
@@ -353,7 +353,7 @@
ttydisc_rint_simple(tp, str, sizeof str);
}
ttydisc_rint_done(tp);
- tty_unlock(tp);
+ ttydisc_unlock(tp);
}
void
@@ -365,10 +365,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
@@ -385,10 +385,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);
}
/*
@@ -420,6 +420,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)) {
@@ -478,8 +479,10 @@
* the TTY when handling ioctls.
*/
tty_unlock(tp);
+ ttydisc_unlock(tp);
error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
tty_lock(tp);
+ ttydisc_lock(tp);
return (error);
}
Index: sys/kern/tty.c
===================================================================
--- sys/kern/tty.c
+++ sys/kern/tty.c
@@ -125,12 +125,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;
@@ -139,12 +141,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
@@ -154,6 +157,7 @@
size_t bytes;
int error;
+ ttydisc_assert_locked(tp);
if (ttyhook_hashook(tp, getc_inject))
/* buffer is inaccessible */
return (0);
@@ -228,21 +232,33 @@
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. */
if (constty == tp)
constty_clear();
- /* 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);
@@ -262,6 +278,7 @@
tp->t_flags &= ~TF_OPENCLOSE;
cv_broadcast(&tp->t_dcdwait);
+ ttydisc_unlock(tp);
tty_rel_free(tp);
}
@@ -288,6 +305,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) {
@@ -296,6 +314,7 @@
}
}
tp->t_flags |= TF_OPENCLOSE;
+ ttydisc_unlock(tp);
/*
* Make sure the "tty" and "cua" device cannot be opened at the
@@ -319,11 +338,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)
@@ -338,8 +361,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. */
@@ -361,7 +387,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);
@@ -375,6 +404,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
@@ -388,6 +418,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 +444,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 +458,7 @@
int error;
MPASS(sig == SIGTTIN || sig == SIGTTOU);
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
for (;;) {
PROC_LOCK(p);
@@ -487,10 +518,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);
/*
@@ -511,6 +550,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);
@@ -535,7 +575,8 @@
cv_signal(&tp->t_outserwait);
}
-done: tty_unlock(tp);
+done: ttydisc_unlock(tp);
+ tty_unlock(tp);
return (error);
}
@@ -586,7 +627,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;
}
@@ -635,6 +678,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)
@@ -649,6 +693,7 @@
if (ttydisc_write_poll(tp) > 0)
revents |= events & (POLLOUT|POLLWRNORM);
}
+ ttydisc_unlock(tp);
if (revents == 0) {
if (events & (POLLIN|POLLRDNORM))
@@ -697,7 +742,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;
@@ -721,7 +766,7 @@
{
struct tty *tp = kn->kn_hook;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tty_gone(tp)) {
kn->kn_flags |= EV_EOF;
@@ -758,12 +803,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;
@@ -1033,7 +1082,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;
@@ -1072,16 +1121,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 {
- tp->t_mtx = &tp->t_mtxobj;
- mtx_init(&tp->t_mtxobj, "ttymtx", NULL, MTX_DEF);
+ sx_init(&tp->t_sxobj, "ttysx");
}
- knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx);
- knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx);
+ if (discmtx != NULL) {
+ tp->t_discmtx = discmtx;
+ } else {
+ 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_discmtx);
+ knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_discmtx);
return (tp);
}
@@ -1111,8 +1174,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);
}
@@ -1155,9 +1221,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);
}
@@ -1165,14 +1233,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);
}
@@ -1183,6 +1254,8 @@
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
+ if (!ttydisc_lock_owned(tp))
+ ttydisc_lock(tp);
/* Simulate carrier removal. */
ttydisc_modem(tp, 0);
@@ -1192,6 +1265,7 @@
cv_broadcast(&tp->t_dcdwait);
tp->t_flags |= TF_GONE;
+ ttydisc_unlock(tp);
tty_rel_free(tp);
}
@@ -1233,6 +1307,9 @@
return (EPERM);
}
+ ttydisc_lock(tp);
+ tp->t_sessioncnt--;
+ ttydisc_unlock(tp);
PROC_LOCK(p);
SESS_LOCK(session);
vp = session->s_ttyvp;
@@ -1241,7 +1318,6 @@
session->s_ttydp = NULL;
SESS_UNLOCK(session);
- tp->t_sessioncnt--;
p->p_flag &= ~P_CONTROLT;
PROC_UNLOCK(p);
sx_xunlock(&proctree_lock);
@@ -1460,7 +1536,7 @@
{
struct proc *p;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(sig >= 1 && sig < NSIG);
/* Make signals start output again. */
@@ -1479,7 +1555,7 @@
{
ksiginfo_t ksi;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(sig >= 1 && sig < NSIG);
/* Make signals start output again. */
@@ -1501,6 +1577,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));
@@ -1521,11 +1598,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))
@@ -1543,11 +1630,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))
@@ -1564,6 +1661,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);
@@ -1588,10 +1686,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
@@ -1607,30 +1709,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:
@@ -1676,6 +1790,7 @@
case TIOCSETAF: {
struct termios *t = data;
+ ttydisc_lock(tp);
/*
* Who makes up these funny rules? According to POSIX,
* input baud rate is set equal to the output baud rate
@@ -1693,8 +1808,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);
}
@@ -1709,8 +1826,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? */
@@ -1720,8 +1839,10 @@
/* Baud rate has changed - update watermarks. */
error = tty_watermarks(tp);
- if (error)
+ if (error) {
+ ttydisc_unlock(tp);
return (error);
+ }
}
/* Copy new non-device driver parameters. */
@@ -1752,6 +1873,7 @@
ttydevsw_pktnotify(tp, TIOCPKT_DOSTOP);
else
ttydevsw_pktnotify(tp, TIOCPKT_NOSTOP);
+ ttydisc_unlock(tp);
return (0);
}
case TIOCGETD:
@@ -1815,13 +1937,16 @@
}
/* Connect the session to the TTY. */
+ ttydisc_lock(tp);
tp->t_session = p->p_session;
tp->t_session->s_ttyp = tp;
tp->t_sessioncnt++;
- sx_xunlock(&proctree_lock);
/* Assign foreground process group. */
tp->t_pgrp = p->p_pgrp;
+ ttydisc_unlock(tp);
+ sx_xunlock(&proctree_lock);
+
PROC_LOCK(p);
p->p_flag |= P_CONTROLT;
PROC_UNLOCK(p);
@@ -1856,7 +1981,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. */
@@ -1870,14 +1997,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);
@@ -1917,22 +2051,32 @@
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;
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))
@@ -1940,8 +2084,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);
}
@@ -1962,7 +2108,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);
@@ -1983,6 +2132,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);
}
@@ -1991,6 +2141,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) {
@@ -2011,6 +2162,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) {
@@ -2101,6 +2253,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;
@@ -2114,6 +2267,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);
@@ -2128,11 +2282,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);
Index: sys/kern/tty_info.c
===================================================================
--- sys/kern/tty_info.c
+++ sys/kern/tty_info.c
@@ -266,7 +266,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;
Index: sys/kern/tty_inq.c
===================================================================
--- sys/kern/tty_inq.c
+++ sys/kern/tty_inq.c
@@ -119,6 +119,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) {
@@ -126,15 +128,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);
@@ -167,6 +166,7 @@
size_t rlen, size_t flen)
{
+ ttydisc_assert_locked(tp);
MPASS(rlen <= uio->uio_resid);
while (rlen > 0) {
@@ -229,10 +229,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);
@@ -247,9 +247,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)
Index: sys/kern/tty_outq.c
===================================================================
--- sys/kern/tty_outq.c
+++ sys/kern/tty_outq.c
@@ -96,6 +96,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) {
@@ -103,20 +105,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);
}
@@ -204,6 +198,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;
@@ -247,9 +242,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);
@@ -264,9 +259,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)
Index: sys/kern/tty_pts.c
===================================================================
--- sys/kern/tty_pts.c
+++ sys/kern/tty_pts.c
@@ -84,20 +84,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. */
@@ -122,7 +122,7 @@
if (uio->uio_resid == 0)
return (0);
- tty_lock(tp);
+ ttydisc_lock(tp);
for (;;) {
/*
@@ -133,7 +133,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);
@@ -154,11 +154,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);
@@ -174,12 +174,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);
}
@@ -202,7 +202,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;
@@ -236,18 +236,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
@@ -273,14 +274,14 @@
/* This device supports non-blocking operation. */
return (0);
case FIONREAD:
- tty_lock(tp);
+ ttydisc_lock(tp);
if (psc->pts_flags & PTS_FINISHED) {
/* Force read() to be called. */
*(int *)data = 1;
} else {
*(int *)data = ttydisc_getc_poll(tp);
}
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (0);
case FIODGNAME:
#ifdef COMPAT_FREEBSD32
@@ -312,9 +313,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:
@@ -339,21 +340,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. */
@@ -364,18 +365,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);
}
@@ -397,11 +398,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);
}
@@ -435,7 +436,7 @@
selrecord(td, &psc->pts_inpoll);
}
- tty_unlock(tp);
+ ttydisc_unlock(tp);
return (revents);
}
@@ -776,8 +777,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);
@@ -823,8 +824,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);
Index: sys/kern/tty_ttydisc.c
===================================================================
--- sys/kern/tty_ttydisc.c
+++ sys/kern/tty_ttydisc.c
@@ -93,6 +93,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);
@@ -327,6 +328,7 @@
int error;
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (uio->uio_resid == 0)
return (0);
@@ -459,6 +461,7 @@
unsigned int oblen = 0;
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_ZOMBIE)
return (EIO);
@@ -477,18 +480,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. */
@@ -573,7 +571,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;
@@ -594,7 +592,7 @@
ttydisc_modem(struct tty *tp, int open)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (open)
cv_broadcast(&tp->t_dcdwait);
@@ -842,7 +840,7 @@
char ob[3] = { 0xff, 0x00 };
size_t ol;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
atomic_add_long(&tty_nin, 1);
@@ -1085,7 +1083,7 @@
{
size_t ret;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(tp->t_flags & TF_BYPASS);
@@ -1106,7 +1104,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);
@@ -1122,7 +1120,7 @@
{
size_t l;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (ttyhook_hashook(tp, rint_poll))
return ttyhook_rint_poll(tp);
@@ -1165,7 +1163,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);
@@ -1192,7 +1190,7 @@
size_t len;
char buf[TTY_STACKBUF];
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_STOPPED)
return (0);
@@ -1212,9 +1210,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;
@@ -1233,7 +1231,7 @@
ttydisc_getc_poll(struct tty *tp)
{
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tp->t_flags & TF_STOPPED)
return (0);
@@ -1255,7 +1253,7 @@
{
size_t i;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (tty_gone(tp))
return (-1);
Index: sys/netgraph/ng_tty.c
===================================================================
--- sys/netgraph/ng_tty.c
+++ sys/netgraph/ng_tty.c
@@ -338,8 +338,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);
@@ -412,7 +414,7 @@
size_t total = 0;
int error = 0, length;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (sc->hook == NULL)
return (0);
@@ -459,7 +461,7 @@
struct mbuf *m;
int error = 0;
- tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
if (sc->hook == NULL)
return (0);
Index: sys/powerpc/mambo/mambo_console.c
===================================================================
--- sys/powerpc/mambo/mambo_console.c
+++ sys/powerpc/mambo/mambo_console.c
@@ -91,8 +91,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);
}
}
@@ -117,11 +119,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);
}
Index: sys/powerpc/powernv/opal_console.c
===================================================================
--- sys/powerpc/powernv/opal_console.c
+++ sys/powerpc/powernv/opal_console.c
@@ -489,11 +489,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);
Index: sys/powerpc/pseries/phyp_console.c
===================================================================
--- sys/powerpc/pseries/phyp_console.c
+++ sys/powerpc/pseries/phyp_console.c
@@ -444,11 +444,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);
Index: sys/riscv/riscv/riscv_console.c
===================================================================
--- sys/riscv/riscv/riscv_console.c
+++ sys/riscv/riscv/riscv_console.c
@@ -129,8 +129,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);
}
}
@@ -160,11 +162,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);
}
Index: sys/sys/tty.h
===================================================================
--- sys/sys/tty.h
+++ sys/sys/tty.h
@@ -38,6 +38,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>
@@ -56,63 +57,72 @@
* Per-TTY structure, containing buffers, etc.
*
* 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
+ *
+ * locking for tf_flags is more complex. It is generally locked by the
+ * discipline lock, but both locks must be held to mark some flags so that we
+ * can do some unlocked reads safely with just the TTY lock. Those flags are
+ * annotated as such.
*/
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;
+ /* 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. */
@@ -125,16 +135,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. */
};
/*
@@ -164,20 +174,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,
Index: sys/sys/ttydevsw.h
===================================================================
--- sys/sys/ttydevsw.h
+++ sys/sys/ttydevsw.h
@@ -87,6 +87,7 @@
{
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_open(tp));
@@ -97,6 +98,7 @@
{
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_devsw->tsw_close(tp);
@@ -106,7 +108,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. */
@@ -120,7 +123,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. */
@@ -135,6 +139,7 @@
{
tty_assert_locked(tp);
+ ttydisc_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_ioctl(tp, cmd, data, td));
@@ -155,6 +160,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));
@@ -164,6 +171,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));
@@ -183,7 +192,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);
@@ -193,6 +202,7 @@
ttydevsw_free(struct tty *tp)
{
+ /* Locks are destroyed at this point. */
MPASS(tty_gone(tp));
tp->t_devsw->tsw_free(tty_softc(tp));
@@ -202,7 +212,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));
Index: sys/sys/ttydisc.h
===================================================================
--- sys/sys/ttydisc.h
+++ 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);
}
Index: sys/sys/ttyhook.h
===================================================================
--- sys/sys/ttyhook.h
+++ sys/sys/ttyhook.h
@@ -78,7 +78,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);
@@ -87,7 +87,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);
@@ -96,7 +96,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);
@@ -105,7 +105,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);
@@ -114,7 +114,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);
@@ -123,7 +123,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);
@@ -132,7 +132,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);
@@ -141,7 +141,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
Thu, Mar 20, 5:48 AM (17 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17227059
Default Alt Text
D24459.id70715.diff (66 KB)

Event Timeline