diff --git a/sys/kern/kern_cons.c b/sys/kern/kern_cons.c index 5f4bf63bed0..780fce00387 100644 --- a/sys/kern/kern_cons.c +++ b/sys/kern/kern_cons.c @@ -105,8 +105,10 @@ static u_char console_pausing; /* pause after each line during probe */ static const char console_pausestr[] = ""; struct tty *constty; /* pointer to console "window" tty */ +static struct mtx constty_mtx; /* Mutex for constty assignment. */ +MTX_SYSINIT(constty_mtx, &constty_mtx, "constty_mtx", MTX_DEF); static struct mtx cnputs_mtx; /* Mutex for cnputs(). */ -static int use_cnputs_mtx = 0; /* != 0 if cnputs_mtx locking reqd. */ +MTX_SYSINIT(cnputs_mtx, &cnputs_mtx, "cnputs_mtx", MTX_SPIN | MTX_NOWITNESS); static void constty_timeout(void *arg); @@ -538,8 +540,8 @@ cnputsn(const char *p, size_t n) size_t i; int unlock_reqd = 0; - if (use_cnputs_mtx) { - /* + if (mtx_initialized(&cnputs_mtx)) { + /* * NOTE: Debug prints and/or witness printouts in * console driver clients can cause the "cnputs_mtx" * mutex to recurse. Simply return if that happens. @@ -563,49 +565,72 @@ cnputs(const char *p) cnputsn(p, strlen(p)); } -static int consmsgbuf_size = 8192; -SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, - "Console tty buffer size"); +static unsigned int consmsgbuf_size = 65536; +SYSCTL_UINT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RWTUN, &consmsgbuf_size, + 0, "Console tty buffer size"); /* * Redirect console output to a tty. */ -void +int constty_set(struct tty *tp) { - int size; + int size = consmsgbuf_size; + void *buf = NULL; + + tty_assert_locked(tp); + if (constty == tp) + return (0); + if (constty != NULL) + return (EBUSY); - KASSERT(tp != NULL, ("constty_set: NULL tp")); if (consbuf == NULL) { - size = consmsgbuf_size; - consbuf = malloc(size, M_TTYCONS, M_WAITOK); - msgbuf_init(&consmsgbuf, consbuf, size); - callout_init(&conscallout, 0); + tty_unlock(tp); + buf = malloc(size, M_TTYCONS, M_WAITOK); + tty_lock(tp); } + mtx_lock(&constty_mtx); + if (constty != NULL) { + mtx_unlock(&constty_mtx); + free(buf, M_TTYCONS); + return (EBUSY); + } + if (consbuf == NULL) { + consbuf = buf; + msgbuf_init(&consmsgbuf, buf, size); + } else + free(buf, M_TTYCONS); constty = tp; - constty_timeout(NULL); + mtx_unlock(&constty_mtx); + + callout_init_mtx(&conscallout, tty_getlock(tp), 0); + constty_timeout(tp); + return (0); } /* * Disable console redirection to a tty. */ -void -constty_clear(void) +int +constty_clear(struct tty *tp) { int c; - constty = NULL; - if (consbuf == NULL) - return; + tty_assert_locked(tp); + if (constty != tp) + return (ENXIO); callout_stop(&conscallout); + mtx_lock(&constty_mtx); + constty = NULL; + mtx_unlock(&constty_mtx); while ((c = msgbuf_getchar(&consmsgbuf)) != -1) cnputc(c); - free(consbuf, M_TTYCONS); - consbuf = NULL; + /* We never free consbuf because it can still be in use. */ + return (0); } /* Times per second to check for pending console tty messages. */ -static int constty_wakeups_per_second = 5; +static int constty_wakeups_per_second = 15; SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, &constty_wakeups_per_second, 0, "Times per second to check for pending console tty messages"); @@ -613,40 +638,20 @@ SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, static void constty_timeout(void *arg) { + struct tty *tp = arg; int c; - if (constty != NULL) { - tty_lock(constty); - while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { - if (tty_putchar(constty, c) < 0) { - tty_unlock(constty); - constty = NULL; - break; - } + tty_assert_locked(tp); + while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { + if (tty_putchar(tp, c) < 0) { + constty_clear(tp); + return; } - - if (constty != NULL) - tty_unlock(constty); - } - if (constty != NULL) { - callout_reset(&conscallout, hz / constty_wakeups_per_second, - constty_timeout, NULL); - } else { - /* Deallocate the constty buffer memory. */ - constty_clear(); } + callout_reset_sbt(&conscallout, SBT_1S / constty_wakeups_per_second, + 0, constty_timeout, tp, C_PREL(1)); } -static void -cn_drvinit(void *unused) -{ - - mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS); - use_cnputs_mtx = 1; -} - -SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL); - /* * Sysbeep(), if we have hardware for it */ diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 8700eb8f9ef..8dfe5e93780 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -241,8 +241,7 @@ ttydev_leave(struct tty *tp) tp->t_flags |= TF_OPENCLOSE; /* Remove console TTY. */ - if (constty == tp) - constty_clear(); + constty_clear(tp); /* Drain any output. */ if (!tty_gone(tp)) @@ -1920,24 +1919,11 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, error = priv_check(td, PRIV_TTY_CONSOLE); if (error) return (error); - - /* - * XXX: constty should really need to be locked! - * XXX: allow disconnected constty's to be stolen! - */ - - if (constty == tp) - return (0); - if (constty != NULL) - return (EBUSY); - - tty_unlock(tp); - constty_set(tp); - tty_lock(tp); - } else if (constty == tp) { - constty_clear(); + error = constty_set(tp); + } else { + error = constty_clear(tp); } - return (0); + return (error); case TIOCGWINSZ: /* Obtain window size. */ *(struct winsize*)data = tp->t_winsize; diff --git a/sys/sys/cons.h b/sys/sys/cons.h index 779f365f6e9..ad73b258df6 100644 --- a/sys/sys/cons.h +++ b/sys/sys/cons.h @@ -139,8 +139,8 @@ void cnputc(int); void cnputs(const char *); void cnputsn(const char *, size_t); int cnunavailable(void); -void constty_set(struct tty *tp); -void constty_clear(void); +int constty_set(struct tty *tp); +int constty_clear(struct tty *tp); /* sc(4) / vt(4) coexistence shim */ #define VTY_SC 0x01