svn commit: r184165 - in stable/6/sys: . kern

John Baldwin jhb at FreeBSD.org
Wed Oct 22 15:28:00 UTC 2008


Author: jhb
Date: Wed Oct 22 15:27:59 2008
New Revision: 184165
URL: http://svn.freebsd.org/changeset/base/184165

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:
  stable/6/sys/   (props changed)
  stable/6/sys/kern/tty.c

Modified: stable/6/sys/kern/tty.c
==============================================================================
--- stable/6/sys/kern/tty.c	Wed Oct 22 15:00:22 2008	(r184164)
+++ stable/6/sys/kern/tty.c	Wed Oct 22 15:27:59 2008	(r184165)
@@ -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);
 }
 


More information about the svn-src-all mailing list