From d80c43e26e21de4b6782959d2608f5f39c1a6aa6 Mon Sep 17 00:00:00 2001 From: grehan Date: Thu, 18 Sep 2014 14:44:47 +0000 Subject: [PATCH] MFC tty fixes, r259549 and r259663 Keep tty_makedev as a function to preserve the KBI on 10-stable (it is a macro in CURRENT). The changes for this are direct commits to 10-stable. r259549 (glebius): - Rename tty_makedev() into tty_makedevf() and make it capable to fail and return error. - Use make_dev_p() in tty_makedevf() instead of make_dev_cred(). - Always pass MAKEDEV_CHECKNAME flag. - Optionally pass MAKEDEV_REF flag. - Provide macro for compatibility with old API. This fixes races with simultaneous creation and desctruction of ttys, and makes it possible to call tty_makedevf() from device cloners. A race in tty_watermarks() still exist, since the latter drops lock for M_WAITOK allocation. This will be addressed in separate commit. r259663 (glebius): Move list of ttys handling from the allocating procedures, to the device creation stage. A device creation can fail, and in that case an entry already on the list will be freed. KBI issue pointed out by: kib Reviewed by: kib (KBI addition) Approved by: re (kib) git-svn-id: svn://svn.freebsd.org/base/stable/10@271773 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/kern/tty.c | 156 +++++++++++++++++++++++++++++++++---------------- sys/sys/tty.h | 3 + 2 files changed, 110 insertions(+), 49 deletions(-) diff --git a/sys/kern/tty.c b/sys/kern/tty.c index e181d1e62..b3968c586 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -289,7 +289,7 @@ ttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) goto done; ttydisc_open(tp); - tty_watermarks(tp); + tty_watermarks(tp); /* XXXGL: drops lock */ } /* Wait for Carrier Detect. */ @@ -1007,11 +1007,6 @@ tty_alloc_mutex(struct ttydevsw *tsw, void *sc, struct mtx *mutex) knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx); knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx); - sx_xlock(&tty_list_sx); - TAILQ_INSERT_TAIL(&tty_list, tp, t_list); - tty_list_count++; - sx_xunlock(&tty_list_sx); - return (tp); } @@ -1020,11 +1015,6 @@ tty_dealloc(void *arg) { struct tty *tp = arg; - sx_xlock(&tty_list_sx); - TAILQ_REMOVE(&tty_list, tp, t_list); - tty_list_count--; - sx_xunlock(&tty_list_sx); - /* Make sure we haven't leaked buffers. */ MPASS(ttyinq_getsize(&tp->t_inq) == 0); MPASS(ttyoutq_getsize(&tp->t_outq) == 0); @@ -1065,6 +1055,11 @@ tty_rel_free(struct tty *tp) tp->t_dev = NULL; tty_unlock(tp); + sx_xlock(&tty_list_sx); + TAILQ_REMOVE(&tty_list, tp, t_list); + tty_list_count--; + sx_xunlock(&tty_list_sx); + if (dev != NULL) destroy_dev_sched_cb(dev, tty_dealloc, tp); } @@ -1174,24 +1169,23 @@ SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_MPSAFE, * the user. */ -void -tty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...) +static int +tty_vmakedevf(struct tty *tp, struct ucred *cred, int flags, + const char *fmt, va_list ap) { - va_list ap; - struct cdev *dev; + struct cdev *dev, *init, *lock, *cua, *cinit, *clock; const char *prefix = "tty"; char name[SPECNAMELEN - 3]; /* for "tty" and "cua". */ uid_t uid; gid_t gid; mode_t mode; + int error; /* Remove "tty" prefix from devices like PTY's. */ if (tp->t_flags & TF_NOPREFIX) prefix = ""; - va_start(ap, fmt); vsnrprintf(name, sizeof name, 32, fmt, ap); - va_end(ap); if (cred == NULL) { /* System device. */ @@ -1205,57 +1199,121 @@ tty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...) mode = S_IRUSR|S_IWUSR|S_IWGRP; } + flags = flags & TTYMK_CLONING ? MAKEDEV_REF : 0; + flags |= MAKEDEV_CHECKNAME; + /* Master call-in device. */ - dev = make_dev_cred(&ttydev_cdevsw, 0, cred, - uid, gid, mode, "%s%s", prefix, name); + error = make_dev_p(flags, &dev, &ttydev_cdevsw, cred, uid, gid, mode, + "%s%s", prefix, name); + if (error) + return (error); dev->si_drv1 = tp; wakeup(&dev->si_drv1); tp->t_dev = dev; + init = lock = cua = cinit = clock = NULL; + /* Slave call-in devices. */ if (tp->t_flags & TF_INITLOCK) { - dev = make_dev_cred(&ttyil_cdevsw, TTYUNIT_INIT, cred, - uid, gid, mode, "%s%s.init", prefix, name); - dev_depends(tp->t_dev, dev); - dev->si_drv1 = tp; - wakeup(&dev->si_drv1); - dev->si_drv2 = &tp->t_termios_init_in; - - dev = make_dev_cred(&ttyil_cdevsw, TTYUNIT_LOCK, cred, - uid, gid, mode, "%s%s.lock", prefix, name); - dev_depends(tp->t_dev, dev); - dev->si_drv1 = tp; - wakeup(&dev->si_drv1); - dev->si_drv2 = &tp->t_termios_lock_in; + error = make_dev_p(flags, &init, &ttyil_cdevsw, cred, uid, + gid, mode, "%s%s.init", prefix, name); + if (error) + goto fail; + dev_depends(dev, init); + dev2unit(init) = TTYUNIT_INIT; + init->si_drv1 = tp; + wakeup(&init->si_drv1); + init->si_drv2 = &tp->t_termios_init_in; + + error = make_dev_p(flags, &lock, &ttyil_cdevsw, cred, uid, + gid, mode, "%s%s.lock", prefix, name); + if (error) + goto fail; + dev_depends(dev, lock); + dev2unit(lock) = TTYUNIT_LOCK; + lock->si_drv1 = tp; + wakeup(&lock->si_drv1); + lock->si_drv2 = &tp->t_termios_lock_in; } /* Call-out devices. */ if (tp->t_flags & TF_CALLOUT) { - dev = make_dev_cred(&ttydev_cdevsw, TTYUNIT_CALLOUT, cred, + error = make_dev_p(flags, &cua, &ttydev_cdevsw, cred, UID_UUCP, GID_DIALER, 0660, "cua%s", name); - dev_depends(tp->t_dev, dev); - dev->si_drv1 = tp; - wakeup(&dev->si_drv1); + if (error) + goto fail; + dev_depends(dev, cua); + dev2unit(cua) = TTYUNIT_CALLOUT; + cua->si_drv1 = tp; + wakeup(&cua->si_drv1); /* Slave call-out devices. */ if (tp->t_flags & TF_INITLOCK) { - dev = make_dev_cred(&ttyil_cdevsw, - TTYUNIT_CALLOUT | TTYUNIT_INIT, cred, + error = make_dev_p(flags, &cinit, &ttyil_cdevsw, cred, UID_UUCP, GID_DIALER, 0660, "cua%s.init", name); - dev_depends(tp->t_dev, dev); - dev->si_drv1 = tp; - wakeup(&dev->si_drv1); - dev->si_drv2 = &tp->t_termios_init_out; - - dev = make_dev_cred(&ttyil_cdevsw, - TTYUNIT_CALLOUT | TTYUNIT_LOCK, cred, + if (error) + goto fail; + dev_depends(dev, cinit); + dev2unit(cinit) = TTYUNIT_CALLOUT | TTYUNIT_INIT; + cinit->si_drv1 = tp; + wakeup(&cinit->si_drv1); + cinit->si_drv2 = &tp->t_termios_init_out; + + error = make_dev_p(flags, &clock, &ttyil_cdevsw, cred, UID_UUCP, GID_DIALER, 0660, "cua%s.lock", name); - dev_depends(tp->t_dev, dev); - dev->si_drv1 = tp; - wakeup(&dev->si_drv1); - dev->si_drv2 = &tp->t_termios_lock_out; + if (error) + goto fail; + dev_depends(dev, clock); + dev2unit(clock) = TTYUNIT_CALLOUT | TTYUNIT_LOCK; + clock->si_drv1 = tp; + wakeup(&clock->si_drv1); + clock->si_drv2 = &tp->t_termios_lock_out; } } + + sx_xlock(&tty_list_sx); + TAILQ_INSERT_TAIL(&tty_list, tp, t_list); + tty_list_count++; + sx_xunlock(&tty_list_sx); + + return (0); + +fail: + destroy_dev(dev); + if (init) + destroy_dev(init); + if (lock) + destroy_dev(lock); + if (cinit) + destroy_dev(cinit); + if (clock) + destroy_dev(clock); + + return (error); +} + +int +tty_makedevf(struct tty *tp, struct ucred *cred, int flags, + const char *fmt, ...) +{ + va_list ap; + int error; + + va_start(ap, fmt); + error = tty_vmakedevf(tp, cred, flags, fmt, ap); + va_end(ap); + + return (error); +} + +void +tty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void) tty_vmakedevf(tp, cred, 0, fmt, ap); + va_end(ap); } /* diff --git a/sys/sys/tty.h b/sys/sys/tty.h index b9552186d..8d9547a01 100644 --- a/sys/sys/tty.h +++ b/sys/sys/tty.h @@ -173,6 +173,9 @@ void tty_rel_gone(struct tty *tp); /* Device node creation. */ void tty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...) __printflike(3, 4); +int tty_makedevf(struct tty *tp, struct ucred *cred, int flags, + const char *fmt, ...) __printflike(4, 5); +#define TTYMK_CLONING 0x1 #define tty_makealias(tp,fmt,...) \ make_dev_alias((tp)->t_dev, fmt, ## __VA_ARGS__) -- 2.45.0