Author: jhb
Date: Wed Oct 22 15:43:28 2008
New Revision: 184167
URL: http://svn.freebsd.org/changeset/base/184167

Log:
  MFC: Close a race in the kern.ttys sysctl handler that resulted in panics
  in dev2udev() when a tty was being detached concurrently with the sysctl
  handler.  One difference relative to 7.x+ is that we still leak tty
  objects in tty_free() since destroy_dev() in 6.x doesn't purge all
  threads.
  
  Approved by:  re (kib)

Modified:
  releng/6.4/sys/   (props changed)
  releng/6.4/sys/kern/tty.c

Modified: releng/6.4/sys/kern/tty.c
==============================================================================
--- releng/6.4/sys/kern/tty.c   Wed Oct 22 15:39:28 2008        (r184166)
+++ releng/6.4/sys/kern/tty.c   Wed Oct 22 15:43:28 2008        (r184167)
@@ -3024,16 +3024,19 @@ ttygone(struct tty *tp)
  *
  * XXX: This shall sleep until all threads have left the driver.
  */
- 
 void
 ttyfree(struct tty *tp)
 {
+       struct cdev *dev;
        u_int unit;
  
        mtx_assert(&Giant, MA_OWNED);
        ttygone(tp);
        unit = tp->t_devunit;
-       destroy_dev(tp->t_mdev);
+       dev = tp->t_mdev;
+       dev->si_tty = NULL;
+       tp->t_dev = NULL;
+       destroy_dev(dev);
        free_unr(tty_unit, unit);
 }
 
@@ -3049,8 +3052,9 @@ sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
        tp = TAILQ_FIRST(&tty_list);
        if (tp != NULL)
                ttyref(tp);
-       mtx_unlock(&tty_list_mutex);
        while (tp != NULL) {
+               if (tp->t_state & TS_GONE)
+                       goto nexttp;
                bzero(&xt, sizeof xt);
                xt.xt_size = sizeof xt;
 #define XT_COPY(field) xt.xt_##field = tp->t_##field
@@ -3058,6 +3062,18 @@ sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
                xt.xt_cancc = tp->t_canq.c_cc;
                xt.xt_outcc = tp->t_outq.c_cc;
                XT_COPY(line);
+
+               /*
+                * XXX: We hold the tty list lock while doing this to
+                * work around a race with pty/pts tty destruction.
+                * They set t_dev to NULL and then call ttyrel() to
+                * free the structure which will block on the list
+                * lock before they call destroy_dev() on the cdev
+                * backing t_dev.
+                *
+                * XXX: ttyfree() now does the same since it has been
+                * fixed to not leak ttys.
+                */
                if (tp->t_dev != NULL)
                        xt.xt_dev = dev2udev(tp->t_dev);
                XT_COPY(state);
@@ -3080,19 +3096,22 @@ sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
                XT_COPY(olowat);
                XT_COPY(ospeedwat);
 #undef XT_COPY
+               mtx_unlock(&tty_list_mutex);
                error = SYSCTL_OUT(req, &xt, sizeof xt);
                if (error != 0) {
                        ttyrel(tp);
                        return (error);
                }
                mtx_lock(&tty_list_mutex);
-               tp2 = TAILQ_NEXT(tp, t_list);
+nexttp:                tp2 = TAILQ_NEXT(tp, t_list);
                if (tp2 != NULL)
                        ttyref(tp2);
                mtx_unlock(&tty_list_mutex);
                ttyrel(tp);
                tp = tp2;
+               mtx_lock(&tty_list_mutex);
        }
+       mtx_unlock(&tty_list_mutex);
        return (0);
 }
 
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to