Author: grehan
Date: Thu Sep 18 14:44:47 2014
New Revision: 271773
URL: http://svnweb.freebsd.org/changeset/base/271773

Log:
  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)

Modified:
  stable/10/sys/kern/tty.c
  stable/10/sys/sys/tty.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/kern/tty.c
==============================================================================
--- stable/10/sys/kern/tty.c    Thu Sep 18 14:43:23 2014        (r271772)
+++ stable/10/sys/kern/tty.c    Thu Sep 18 14:44:47 2014        (r271773)
@@ -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. */
@@ -1007,11 +1007,6 @@ tty_alloc_mutex(struct ttydevsw *tsw, vo
        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, CTLTY
  * 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
                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;
                }
        }
+
+       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);
 }
 
 /*

Modified: stable/10/sys/sys/tty.h
==============================================================================
--- stable/10/sys/sys/tty.h     Thu Sep 18 14:43:23 2014        (r271772)
+++ stable/10/sys/sys/tty.h     Thu Sep 18 14:44:47 2014        (r271773)
@@ -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__)
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to