tty(4) uses custom code for revoking knotes. It should be changed to use
klist_invalidate() to handle the revocation in one place. The following
diff does that.
In addition, the patch makes the code store the tty context pointer
in kn_hook directly. This simplifies the code.
Unlike ttkqflush(), klist_invalidate() can sleep. However, that should
not be a problem because the callers of ttyfree() call vdevgone() that
can sleep as well.
It would be good to have this tested in various setups. Originally,
ttkqflush() was added to prevent crashing when a ucom(4) device is
detached while still in use by a kqueue-enabled program such as cu(1).
OK?
Index: kern/tty.c
===================================================================
RCS file: src/sys/kern/tty.c,v
retrieving revision 1.151
diff -u -p -r1.151 tty.c
--- kern/tty.c 9 Jan 2020 14:35:20 -0000 1.151
+++ kern/tty.c 2 Feb 2020 09:38:17 -0000
@@ -75,7 +75,6 @@ static void ttyblock(struct tty *);
void ttyunblock(struct tty *);
static void ttyecho(int, struct tty *);
static void ttyrubo(struct tty *, int);
-void ttkqflush(struct klist *klist);
int filt_ttyread(struct knote *kn, long hint);
void filt_ttyrdetach(struct knote *kn);
int filt_ttywrite(struct knote *kn, long hint);
@@ -1124,7 +1123,7 @@ ttkqfilter(dev_t dev, struct knote *kn)
return (EINVAL);
}
- kn->kn_hook = (caddr_t)((u_long)dev);
+ kn->kn_hook = tp;
s = spltty();
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
@@ -1134,29 +1133,11 @@ ttkqfilter(dev_t dev, struct knote *kn)
}
void
-ttkqflush(struct klist *klist)
-{
- struct knote *kn, *kn1;
-
- SLIST_FOREACH_SAFE(kn, klist, kn_selnext, kn1) {
- SLIST_REMOVE(klist, kn, knote, kn_selnext);
- kn->kn_hook = (caddr_t)((u_long)NODEV);
- kn->kn_flags |= EV_EOF;
- knote_activate(kn);
- }
-}
-
-void
filt_ttyrdetach(struct knote *kn)
{
- dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp;
+ struct tty *tp = kn->kn_hook;
int s;
- if (dev == NODEV)
- return;
- tp = (*cdevsw[major(dev)].d_tty)(dev);
-
s = spltty();
SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
splx(s);
@@ -1165,16 +1146,9 @@ filt_ttyrdetach(struct knote *kn)
int
filt_ttyread(struct knote *kn, long hint)
{
- dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp;
+ struct tty *tp = kn->kn_hook;
int s;
- if (dev == NODEV) {
- kn->kn_flags |= EV_EOF;
- return (1);
- }
- tp = (*cdevsw[major(dev)].d_tty)(dev);
-
s = spltty();
kn->kn_data = ttnread(tp);
splx(s);
@@ -1188,14 +1162,9 @@ filt_ttyread(struct knote *kn, long hint
void
filt_ttywdetach(struct knote *kn)
{
- dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp;
+ struct tty *tp = kn->kn_hook;
int s;
- if (dev == NODEV)
- return;
- tp = (*cdevsw[major(dev)].d_tty)(dev);
-
s = spltty();
SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
splx(s);
@@ -1204,16 +1173,9 @@ filt_ttywdetach(struct knote *kn)
int
filt_ttywrite(struct knote *kn, long hint)
{
- dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp;
+ struct tty *tp = kn->kn_hook;
int canwrite, s;
- if (dev == NODEV) {
- kn->kn_flags |= EV_EOF;
- return (1);
- }
- tp = (*cdevsw[major(dev)].d_tty)(dev);
-
s = spltty();
kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc;
canwrite = (tp->t_outq.c_cc <= tp->t_lowat);
@@ -2378,6 +2340,7 @@ ttymalloc(int baud)
void
ttyfree(struct tty *tp)
{
+ int s;
--tty_count;
#ifdef DIAGNOSTIC
@@ -2386,8 +2349,10 @@ ttyfree(struct tty *tp)
#endif
TAILQ_REMOVE(&ttylist, tp, tty_link);
- ttkqflush(&tp->t_rsel.si_note);
- ttkqflush(&tp->t_wsel.si_note);
+ s = spltty();
+ klist_invalidate(&tp->t_rsel.si_note);
+ klist_invalidate(&tp->t_wsel.si_note);
+ splx(s);
clfree(&tp->t_rawq);
clfree(&tp->t_canq);