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