svn commit: r184521 - in head/sys: conf kern sys

Ed Schouten ed at FreeBSD.org
Sat Nov 1 01:35:29 PDT 2008


Author: ed
Date: Sat Nov  1 08:35:28 2008
New Revision: 184521
URL: http://svn.freebsd.org/changeset/base/184521

Log:
  Reimplement the /dev/console device node.
  
  One of the pieces of code that I had left alone during the development
  of the MPSAFE TTY layer, was tty_cons.c. This file actually has two
  different functions:
  
  - It contains low-level console input/output routines (cnputc(), etc).
  
  - It creates /dev/console and wraps all its cdevsw calls to the
    appropriate TTY.
  
  This commit reimplements the second set of functions by moving it
  directly into the TTY layer. /dev/console is now a character device node
  that's basically a regular TTY, but does a lookup of `si_drv1' each time
  you open it. d_write has also been changed to call log_console().
  d_close() is not present, because we must make sure we don't revoke the
  TTY after writing a log message to it.
  
  Even though I'm not convinced this is in line with the future directions
  of our console code, it is a good move for now. It removes recursive
  locking from the top half of the TTY layer. The previous implementation
  called into the TTY layer with Giant held.
  
  I'm renaming tty_cons.c to kern_cons.c now. The code hardly contains any
  TTY related bits, so we'd better give it a less misleading name.
  
  Tested by:	Andrzej Tobola <ato iem pw edu pl>,
  		Carlos A.M. dos Santos <unixmania gmail com>,
  		Eygene Ryabinkin <rea-fbsd codelabs ru>

Added:
  head/sys/kern/kern_cons.c   (contents, props changed)
     - copied, changed from r184520, head/sys/kern/tty_cons.c
Deleted:
  head/sys/kern/tty_cons.c
Modified:
  head/sys/conf/files
  head/sys/kern/tty.c
  head/sys/sys/tty.h

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Sat Nov  1 08:07:02 2008	(r184520)
+++ head/sys/conf/files	Sat Nov  1 08:35:28 2008	(r184521)
@@ -1596,6 +1596,7 @@ kern/kern_alq.c			optional alq
 kern/kern_clock.c		standard
 kern/kern_condvar.c		standard
 kern/kern_conf.c		standard
+kern/kern_cons.c		standard
 kern/kern_cpu.c			standard
 kern/kern_cpuset.c		standard
 kern/kern_context.c		standard
@@ -1708,7 +1709,6 @@ kern/sysv_sem.c			optional sysvsem
 kern/sysv_shm.c			optional sysvshm
 kern/tty.c			standard
 kern/tty_compat.c		optional compat_43tty
-kern/tty_cons.c			standard
 kern/tty_info.c			standard
 kern/tty_inq.c			standard
 kern/tty_outq.c			standard

Copied and modified: head/sys/kern/kern_cons.c (from r184520, head/sys/kern/tty_cons.c)
==============================================================================
--- head/sys/kern/tty_cons.c	Sat Nov  1 08:07:02 2008	(r184520, copy source)
+++ head/sys/kern/kern_cons.c	Sat Nov  1 08:35:28 2008	(r184521)
@@ -68,30 +68,8 @@ __FBSDID("$FreeBSD$");
 
 static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling");
 
-static	d_open_t	cnopen;
-static	d_close_t	cnclose;
-static	d_read_t	cnread;
-static	d_write_t	cnwrite;
-static	d_ioctl_t	cnioctl;
-static	d_poll_t	cnpoll;
-static	d_kqfilter_t	cnkqfilter;
-
-static struct cdevsw cn_cdevsw = {
-	.d_version =	D_VERSION,
-	.d_open =	cnopen,
-	.d_close =	cnclose,
-	.d_read =	cnread,
-	.d_write =	cnwrite,
-	.d_ioctl =	cnioctl,
-	.d_poll =	cnpoll,
-	.d_name =	"console",
-	.d_flags =	D_TTY | D_NEEDGIANT,
-	.d_kqfilter =	cnkqfilter,
-};
-
 struct cn_device {
 	STAILQ_ENTRY(cn_device) cnd_next;
-	struct		vnode *cnd_vp;
 	struct		consdev *cnd_cn;
 };
 
@@ -101,22 +79,12 @@ static struct cn_device cn_devtab[CNDEVT
 static STAILQ_HEAD(, cn_device) cn_devlist =
     STAILQ_HEAD_INITIALIZER(cn_devlist);
 
-#define CND_INVALID(cnd, td) 						\
-	(cnd == NULL || cnd->cnd_vp == NULL ||				\
-	    (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1)))
-
-static dev_t	cn_udev_t;
-SYSCTL_OPAQUE(_machdep, OID_AUTO, consdev, CTLFLAG_RD,
-	&cn_udev_t, sizeof cn_udev_t, "T,struct cdev *", "");
-
 int	cons_avail_mask = 0;	/* Bit mask. Each registered low level console
 				 * which is currently unavailable for inpit
 				 * (i.e., if it is in graphics mode) will have
 				 * this bit cleared.
 				 */
 static int cn_mute;
-static int openflag;			/* how /dev/console was opened */
-static int cn_is_open;
 static char *consbuf;			/* buffer used by `consmsgbuf' */
 static struct callout conscallout;	/* callout for outputting to constty */
 struct msgbuf consmsgbuf;		/* message buffer for console tty */
@@ -214,6 +182,8 @@ cnadd(struct consdev *cn)
 		printf("WARNING: console at %p has no name\n", cn);
 	}
 	STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
+	if (STAILQ_FIRST(&cn_devlist) == cnd)
+		ttyconsdev_select(cnd->cnd_cn->cn_name);
 
 	/* Add device to the active mask. */
 	cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0);
@@ -230,10 +200,9 @@ cnremove(struct consdev *cn)
 	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
 		if (cnd->cnd_cn != cn)
 			continue;
+		if (STAILQ_FIRST(&cn_devlist) == cnd)
+			ttyconsdev_select(NULL);
 		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
-		if (cnd->cnd_vp != NULL)
-			vn_close(cnd->cnd_vp, openflag, NOCRED, NULL);
-		cnd->cnd_vp = NULL;
 		cnd->cnd_cn = NULL;
 
 		/* Remove this device from available mask. */
@@ -267,6 +236,7 @@ cnselect(struct consdev *cn)
 			return;
 		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
 		STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
+		ttyconsdev_select(cnd->cnd_cn->cn_name);
 		return;
 	}
 }
@@ -368,210 +338,12 @@ sysctl_kern_consmute(SYSCTL_HANDLER_ARGS
 	error = sysctl_handle_int(oidp, &cn_mute, 0, req);
 	if (error != 0 || req->newptr == NULL)
 		return (error);
-	if (ocn_mute && !cn_mute && cn_is_open)
-		error = cnopen(NULL, openflag, 0, curthread);
-	else if (!ocn_mute && cn_mute && cn_is_open) {
-		error = cnclose(NULL, openflag, 0, curthread);
-		cn_is_open = 1;		/* XXX hack */
-	}
 	return (error);
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
 	0, sizeof(cn_mute), sysctl_kern_consmute, "I", "");
 
-static int
-cn_devopen(struct cn_device *cnd, struct thread *td, int forceopen)
-{
-	char path[CNDEVPATHMAX];
-	struct nameidata nd;
-	struct vnode *vp;
-	struct cdev *dev;
-	struct cdevsw *csw;
-	int error;
-
-	if ((vp = cnd->cnd_vp) != NULL) {
-		if (!forceopen && vp->v_type != VBAD) {
-			dev = vp->v_rdev;
-			csw = dev_refthread(dev);
-			if (csw == NULL)
-				return (ENXIO);
-			error = (*csw->d_open)(dev, openflag, 0, td);
-			dev_relthread(dev);
-			return (error);
-		}
-		cnd->cnd_vp = NULL;
-		vn_close(vp, openflag, td->td_ucred, td);
-	}
-	snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_cn->cn_name);
-	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
-	error = vn_open(&nd, &openflag, 0, NULL);
-	if (error == 0) {
-		NDFREE(&nd, NDF_ONLY_PNBUF);
-		VOP_UNLOCK(nd.ni_vp, 0);
-		if (nd.ni_vp->v_type == VCHR)
-			cnd->cnd_vp = nd.ni_vp;
-		else
-			vn_close(nd.ni_vp, openflag, td->td_ucred, td);
-	}
-	return (cnd->cnd_vp != NULL);
-}
-
-static int
-cnopen(struct cdev *dev, int flag, int mode, struct thread *td)
-{
-	struct cn_device *cnd;
-
-	openflag = flag | FWRITE;	/* XXX */
-	cn_is_open = 1;			/* console is logically open */
-	if (cn_mute)
-		return (0);
-	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
-		cn_devopen(cnd, td, 0);
-	return (0);
-}
-
-static int
-cnclose(struct cdev *dev, int flag, int mode, struct thread *td)
-{
-	struct cn_device *cnd;
-	struct vnode *vp;
-
-	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
-		if ((vp = cnd->cnd_vp) == NULL)
-			continue; 
-		cnd->cnd_vp = NULL;
-		vn_close(vp, openflag, td->td_ucred, td);
-	}
-	cn_is_open = 0;
-	return (0);
-}
-
-static int
-cnread(struct cdev *dev, struct uio *uio, int flag)
-{
-	struct cn_device *cnd;
-	struct cdevsw *csw;
-	int error;
-
-	cnd = STAILQ_FIRST(&cn_devlist);
-	if (cn_mute || CND_INVALID(cnd, curthread))
-		return (0);
-	dev = cnd->cnd_vp->v_rdev;
-	csw = dev_refthread(dev);
-	if (csw == NULL)
-		return (ENXIO);
-	error = (csw->d_read)(dev, uio, flag);
-	dev_relthread(dev);
-	return (error);
-}
-
-static int
-cnwrite(struct cdev *dev, struct uio *uio, int flag)
-{
-	struct cn_device *cnd;
-	struct cdevsw *csw;
-	int error;
-
-	cnd = STAILQ_FIRST(&cn_devlist);
-	if (cn_mute || CND_INVALID(cnd, curthread))
-		goto done;
-	if (constty)
-		dev = constty->t_dev;
-	else
-		dev = cnd->cnd_vp->v_rdev;
-	if (dev != NULL) {
-		log_console(uio);
-		csw = dev_refthread(dev);
-		if (csw == NULL)
-			return (ENXIO);
-		error = (csw->d_write)(dev, uio, flag);
-		dev_relthread(dev);
-		return (error);
-	}
-done:
-	uio->uio_resid = 0; /* dump the data */
-	return (0);
-}
-
-static int
-cnioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
-{
-	struct cn_device *cnd;
-	struct cdevsw *csw;
-	int error;
-
-	cnd = STAILQ_FIRST(&cn_devlist);
-	if (cn_mute || CND_INVALID(cnd, td))
-		return (0);
-	/*
-	 * Superuser can always use this to wrest control of console
-	 * output from the "virtual" console.
-	 */
-	if (cmd == TIOCCONS && constty) {
-		error = priv_check(td, PRIV_TTY_CONSOLE);
-		if (error)
-			return (error);
-		constty = NULL;
-		return (0);
-	}
-	dev = cnd->cnd_vp->v_rdev;
-	if (dev == NULL)
-		return (0);	/* XXX : ENOTTY ? */
-	csw = dev_refthread(dev);
-	if (csw == NULL)
-		return (ENXIO);
-	error = (csw->d_ioctl)(dev, cmd, data, flag, td);
-	dev_relthread(dev);
-	return (error);
-}
-
-/*
- * XXX
- * poll/kqfilter do not appear to be correct
- */
-static int
-cnpoll(struct cdev *dev, int events, struct thread *td)
-{
-	struct cn_device *cnd;
-	struct cdevsw *csw;
-	int error;
-
-	cnd = STAILQ_FIRST(&cn_devlist);
-	if (cn_mute || CND_INVALID(cnd, td))
-		return (0);
-	dev = cnd->cnd_vp->v_rdev;
-	if (dev == NULL)
-		return (0);
-	csw = dev_refthread(dev);
-	if (csw == NULL)
-		return (ENXIO);
-	error = (csw->d_poll)(dev, events, td);
-	dev_relthread(dev);
-	return (error);
-}
-
-static int
-cnkqfilter(struct cdev *dev, struct knote *kn)
-{
-	struct cn_device *cnd;
-	struct cdevsw *csw;
-	int error;
-
-	cnd = STAILQ_FIRST(&cn_devlist);
-	if (cn_mute || CND_INVALID(cnd, curthread))
-		return (EINVAL);
-	dev = cnd->cnd_vp->v_rdev;
-	if (dev == NULL)
-		return (ENXIO);
-	csw = dev_refthread(dev);
-	if (csw == NULL)
-		return (ENXIO);
-	error = (csw->d_kqfilter)(dev, kn);
-	dev_relthread(dev);
-	return (error);
-}
-
 /*
  * Low level console routines.
  */
@@ -737,8 +509,6 @@ static void
 cn_drvinit(void *unused)
 {
 
-	make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "console");
-
 	mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS);
 	use_cnputs_mtx = 1;
 }

Modified: head/sys/kern/tty.c
==============================================================================
--- head/sys/kern/tty.c	Sat Nov  1 08:07:02 2008	(r184520)
+++ head/sys/kern/tty.c	Sat Nov  1 08:35:28 2008	(r184521)
@@ -73,6 +73,10 @@ static struct sx tty_list_sx;
 SX_SYSINIT(tty_list, &tty_list_sx, "tty list");
 static unsigned int tty_list_count = 0;
 
+/* Character device of /dev/console. */
+static struct cdev	*dev_console;
+static const char	*dev_console_filename;
+
 /*
  * Flags that are supported and stored by this implementation.
  */
@@ -86,7 +90,7 @@ static unsigned int tty_list_count = 0;
 			HUPCL|CLOCAL|CCTS_OFLOW|CRTS_IFLOW|CDTR_IFLOW|\
 			CDSR_OFLOW|CCAR_OFLOW)
 
-#define TTY_CALLOUT(tp,d) ((tp)->t_dev != (d))
+#define	TTY_CALLOUT(tp,d) ((d) != (tp)->t_dev && (d) != dev_console)
 
 /*
  * Set TTY buffer sizes.
@@ -1189,11 +1193,7 @@ tty_wait(struct tty *tp, struct cv *cv)
 	int error;
 	int revokecnt = tp->t_revokecnt;
 
-#if 0
-	/* XXX: /dev/console also picks up Giant. */
 	tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED);
-#endif
-	tty_lock_assert(tp, MA_OWNED);
 	MPASS(!tty_gone(tp));
 
 	error = cv_wait_sig(cv, tp->t_mtx);
@@ -1215,11 +1215,7 @@ tty_timedwait(struct tty *tp, struct cv 
 	int error;
 	int revokecnt = tp->t_revokecnt;
 
-#if 0
-	/* XXX: /dev/console also picks up Giant. */
 	tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED);
-#endif
-	tty_lock_assert(tp, MA_OWNED);
 	MPASS(!tty_gone(tp));
 
 	error = cv_timedwait_sig(cv, tp->t_mtx, hz);
@@ -1662,6 +1658,10 @@ tty_hiwat_in_unblock(struct tty *tp)
 		ttydevsw_inwakeup(tp);
 }
 
+/*
+ * TTY hooks interface.
+ */
+
 static int
 ttyhook_defrint(struct tty *tp, char c, int flags)
 {
@@ -1745,6 +1745,84 @@ ttyhook_unregister(struct tty *tp)
 	tty_rel_free(tp);
 }
 
+/*
+ * /dev/console handling.
+ */
+
+static int
+ttyconsdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+	struct tty *tp;
+
+	/* System has no console device. */
+	if (dev_console_filename == NULL)
+		return (ENXIO);
+
+	/* Look up corresponding TTY by device name. */
+	sx_slock(&tty_list_sx);
+	TAILQ_FOREACH(tp, &tty_list, t_list) {
+		if (strcmp(dev_console_filename, tty_devname(tp)) == 0) {
+			dev_console->si_drv1 = tp;
+			break;
+		}
+	}
+	sx_sunlock(&tty_list_sx);
+
+	/* System console has no TTY associated. */
+	if (dev_console->si_drv1 == NULL)
+		return (ENXIO);
+	
+	return (ttydev_open(dev, oflags, devtype, td));
+}
+
+static int
+ttyconsdev_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+
+	log_console(uio);
+
+	return (ttydev_write(dev, uio, ioflag));
+}
+
+/*
+ * /dev/console is a little different than normal TTY's. Unlike regular
+ * TTY device nodes, this device node will not revoke the entire TTY
+ * upon closure and all data written to it will be logged.
+ */
+static struct cdevsw ttyconsdev_cdevsw = {
+	.d_version	= D_VERSION,
+	.d_open		= ttyconsdev_open,
+	.d_read		= ttydev_read,
+	.d_write	= ttyconsdev_write,
+	.d_ioctl	= ttydev_ioctl,
+	.d_kqfilter	= ttydev_kqfilter,
+	.d_poll		= ttydev_poll,
+	.d_mmap		= ttydev_mmap,
+	.d_name		= "ttyconsdev",
+	.d_flags	= D_TTY,
+};
+
+static void
+ttyconsdev_init(void *unused)
+{
+
+	dev_console = make_dev(&ttyconsdev_cdevsw, 0, UID_ROOT, GID_WHEEL,
+	    0600, "console");
+}
+
+SYSINIT(tty, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyconsdev_init, NULL);
+
+void
+ttyconsdev_select(const char *name)
+{
+
+	dev_console_filename = name;
+}
+
+/*
+ * Debugging routines.
+ */
+
 #include "opt_ddb.h"
 #ifdef DDB
 #include <ddb/ddb.h>

Modified: head/sys/sys/tty.h
==============================================================================
--- head/sys/sys/tty.h	Sat Nov  1 08:07:02 2008	(r184520)
+++ head/sys/sys/tty.h	Sat Nov  1 08:35:28 2008	(r184521)
@@ -192,6 +192,9 @@ dev_t	tty_udev(struct tty *tp);
 /* Status line printing. */
 void	tty_info(struct tty *tp);
 
+/* /dev/console selection. */
+void	ttyconsdev_select(const char *name);
+
 /* Pseudo-terminal hooks. */
 int	pts_alloc_external(int fd, struct thread *td, struct file *fp,
     struct cdev *dev, const char *name);


More information about the svn-src-all mailing list