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
This commit is contained in:
parent
2f21ec0129
commit
a6f63533a7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=312077
@ -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. */
|
||||
|
@ -112,7 +112,7 @@ static uma_zone_t ttyinq_zone;
|
||||
TTYINQ_INSERT_TAIL(ti, tib); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
int
|
||||
ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t size)
|
||||
{
|
||||
struct ttyinq_block *tib;
|
||||
@ -134,8 +134,14 @@ ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t size)
|
||||
tib = uma_zalloc(ttyinq_zone, M_WAITOK);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp)) {
|
||||
uma_zfree(ttyinq_zone, tib);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
TTYINQ_INSERT_TAIL(ti, tib);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -89,7 +89,7 @@ ttyoutq_flush(struct ttyoutq *to)
|
||||
to->to_end = 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size)
|
||||
{
|
||||
struct ttyoutq_block *tob;
|
||||
@ -111,8 +111,14 @@ ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size)
|
||||
tob = uma_zalloc(ttyoutq_zone, M_WAITOK);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp)) {
|
||||
uma_zfree(ttyoutq_zone, tob);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
TTYOUTQ_INSERT_TAIL(to, tob);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -69,7 +69,7 @@ struct ttyoutq {
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* Input queue handling routines. */
|
||||
void ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t len);
|
||||
int ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t len);
|
||||
void ttyinq_free(struct ttyinq *ti);
|
||||
int ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio,
|
||||
size_t readlen, size_t flushlen);
|
||||
@ -136,7 +136,7 @@ void ttyinq_line_iterate_from_reprintpos(struct ttyinq *ti,
|
||||
|
||||
/* Output queue handling routines. */
|
||||
void ttyoutq_flush(struct ttyoutq *to);
|
||||
void ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t len);
|
||||
int ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t len);
|
||||
void ttyoutq_free(struct ttyoutq *to);
|
||||
size_t ttyoutq_read(struct ttyoutq *to, void *buf, size_t len);
|
||||
int ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio);
|
||||
|
Loading…
Reference in New Issue
Block a user