Date: Sat, 1 Nov 2008 08:35:28 +0000 (UTC) From: Ed Schouten <ed@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r184521 - in head/sys: conf kern sys Message-ID: <200811010835.mA18ZSrZ003531@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200811010835.mA18ZSrZ003531>