Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Oct 2008 15:43:28 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org
Subject:   svn commit: r184167 - in releng/6.4/sys: . kern
Message-ID:  <200810221543.m9MFhSwj032531@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200810221543.m9MFhSwj032531>