svn commit: r259549 - in head/sys: kern sys

Gleb Smirnoff glebius at FreeBSD.org
Wed Dec 18 12:50:44 UTC 2013


Author: glebius
Date: Wed Dec 18 12:50:43 2013
New Revision: 259549
URL: http://svnweb.freebsd.org/changeset/base/259549

Log:
  - 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.
  
  Reviewed by:	kib
  Sponsored by:	Nginx, Inc.

Modified:
  head/sys/kern/tty.c
  head/sys/sys/tty.h

Modified: head/sys/kern/tty.c
==============================================================================
--- head/sys/kern/tty.c	Wed Dec 18 12:18:17 2013	(r259548)
+++ head/sys/kern/tty.c	Wed Dec 18 12:50:43 2013	(r259549)
@@ -289,7 +289,7 @@ ttydev_open(struct cdev *dev, int oflags
 			goto done;
 
 		ttydisc_open(tp);
-		tty_watermarks(tp);
+		tty_watermarks(tp); /* XXXGL: drops lock */
 	}
 
 	/* Wait for Carrier Detect. */
@@ -1174,16 +1174,18 @@ SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTY
  * the user.
  */
 
-void
-tty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...)
+int
+tty_makedevf(struct tty *tp, struct ucred *cred, int flags,
+    const char *fmt, ...)
 {
 	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)
@@ -1205,57 +1207,92 @@ tty_makedev(struct tty *tp, struct ucred
 		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;
+			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;
 
-			dev = make_dev_cred(&ttyil_cdevsw,
-			    TTYUNIT_CALLOUT | TTYUNIT_LOCK, cred,
+			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;
 		}
 	}
+
+	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);
 }
 
 /*

Modified: head/sys/sys/tty.h
==============================================================================
--- head/sys/sys/tty.h	Wed Dec 18 12:18:17 2013	(r259548)
+++ head/sys/sys/tty.h	Wed Dec 18 12:50:43 2013	(r259549)
@@ -171,8 +171,11 @@ void	tty_rel_gone(struct tty *tp);
 #define	tty_getlock(tp)		((tp)->t_mtx)
 
 /* 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_makedev(tp, cred, fmt, ...) \
+	(void )tty_makedevf((tp), (cred), 0, (fmt), ## __VA_ARGS__)
 #define	tty_makealias(tp,fmt,...) \
 	make_dev_alias((tp)->t_dev, fmt, ## __VA_ARGS__)
 


More information about the svn-src-all mailing list