aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/tty.c
diff options
context:
space:
mode:
authorIan Lepore <ian@FreeBSD.org>2017-01-13 16:37:38 +0000
committerIan Lepore <ian@FreeBSD.org>2017-01-13 16:37:38 +0000
commita6f63533a7045d56ea46bd68a14cbf4053e63aa5 (patch)
tree2eca54863fed9f962b0c1ca85741ac42749b2c21 /sys/kern/tty.c
parent2f21ec0129dc3be555536d5177c5e0f4f8728f6b (diff)
downloadsrc-a6f63533a7045d56ea46bd68a14cbf4053e63aa5.tar.gz
src-a6f63533a7045d56ea46bd68a14cbf4053e63aa5.zip
Check tty_gone() after allocating IO buffers. The tty lock has to be
dropped then reacquired due to using M_WAITOK, which opens a window in which the tty device can disappear. Check for this and return ENXIO back up the call chain so that callers can cope. This closes a race where TF_GONE would get set while buffers were being allocated as part of ttydev_open(), causing a subsequent call to ttydevsw_modem() later in ttydev_open() to assert. Reported by: pho Reviewed by: kib
Notes
Notes: svn path=/head/; revision=312077
Diffstat (limited to 'sys/kern/tty.c')
-rw-r--r--sys/kern/tty.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 499bd13a38a4..9c2be5d18236 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -105,25 +105,38 @@ SYSCTL_INT(_kern, OID_AUTO, tty_drainwait, CTLFLAG_RWTUN,
#define TTYBUF_MAX 65536
-static void
+/*
+ * Allocate buffer space if necessary, and set low watermarks, based on speed.
+ * Note that the ttyxxxq_setsize() functions may drop and then reacquire the tty
+ * lock during memory allocation. They will return ENXIO if the tty disappears
+ * while unlocked.
+ */
+static int
tty_watermarks(struct tty *tp)
{
size_t bs = 0;
+ int error;
/* Provide an input buffer for 0.2 seconds of data. */
if (tp->t_termios.c_cflag & CREAD)
bs = MIN(tp->t_termios.c_ispeed / 5, TTYBUF_MAX);
- ttyinq_setsize(&tp->t_inq, tp, bs);
+ error = ttyinq_setsize(&tp->t_inq, tp, bs);
+ if (error != 0)
+ return (error);
/* Set low watermark at 10% (when 90% is available). */
tp->t_inlow = (ttyinq_getallocatedsize(&tp->t_inq) * 9) / 10;
/* Provide an output buffer for 0.2 seconds of data. */
bs = MIN(tp->t_termios.c_ospeed / 5, TTYBUF_MAX);
- ttyoutq_setsize(&tp->t_outq, tp, bs);
+ error = ttyoutq_setsize(&tp->t_outq, tp, bs);
+ if (error != 0)
+ return (error);
/* Set low watermark at 10% (when 90% is available). */
tp->t_outlow = (ttyoutq_getallocatedsize(&tp->t_outq) * 9) / 10;
+
+ return (0);
}
static int
@@ -318,7 +331,9 @@ ttydev_open(struct cdev *dev, int oflags, int devtype __unused,
goto done;
ttydisc_open(tp);
- tty_watermarks(tp); /* XXXGL: drops lock */
+ error = tty_watermarks(tp);
+ if (error != 0)
+ goto done;
}
/* Wait for Carrier Detect. */
@@ -1627,7 +1642,9 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag,
tp->t_termios.c_ospeed = t->c_ospeed;
/* Baud rate has changed - update watermarks. */
- tty_watermarks(tp);
+ error = tty_watermarks(tp);
+ if (error)
+ return (error);
}
/* Copy new non-device driver parameters. */