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);

Reply via email to