Index: if_tun.c =================================================================== RCS file: /cvs/src/sys/net/if_tun.c,v retrieving revision 1.231 diff -u -p -r1.231 if_tun.c --- if_tun.c 9 Mar 2021 20:05:14 -0000 1.231 +++ if_tun.c 16 Jan 2022 06:53:11 -0000 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ struct tun_softc { struct arpcom sc_ac; /* ethernet common data */ #define sc_if sc_ac.ac_if + struct mutex sc_selmtx; /* protect read/write select */ struct selinfo sc_rsel; /* read select */ struct selinfo sc_wsel; /* write select (not used) */ SMR_LIST_ENTRY(tun_softc) @@ -128,22 +130,28 @@ int tun_init(struct tun_softc *); void tun_start(struct ifnet *); int filt_tunread(struct knote *, long); int filt_tunwrite(struct knote *, long); +int filt_tunmodify(struct kevent *, struct knote *); +int filt_tunprocess(struct knote *, struct kevent *); void filt_tunrdetach(struct knote *); void filt_tunwdetach(struct knote *); void tun_link_state(struct tun_softc *, int); const struct filterops tunread_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_tunrdetach, .f_event = filt_tunread, + .f_modify = filt_tunmodify, + .f_process = filt_tunprocess, }; const struct filterops tunwrite_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_tunwdetach, .f_event = filt_tunwrite, + .f_modify = filt_tunmodify, + .f_process = filt_tunprocess, }; SMR_LIST_HEAD(tun_list, tun_softc); @@ -221,6 +229,9 @@ tun_create(struct if_clone *ifc, int uni ifp = &sc->sc_if; snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", ifc->ifc_name, unit); + mtx_init(&sc->sc_selmtx, IPL_SOFTNET); + klist_init_mutex(&sc->sc_rsel.si_note, &sc->sc_selmtx); + klist_init_mutex(&sc->sc_wsel.si_note, &sc->sc_selmtx); ifp->if_softc = sc; /* this is enough state for tun_dev_open to work with */ @@ -277,6 +288,8 @@ tun_create(struct if_clone *ifc, int uni return (0); exists: + klist_free(&sc->sc_rsel.si_note); + klist_free(&sc->sc_wsel.si_note); free(sc, M_DEVBUF, sizeof(*sc)); return (EEXIST); } @@ -286,7 +299,6 @@ tun_clone_destroy(struct ifnet *ifp) { struct tun_softc *sc = ifp->if_softc; dev_t dev; - int s; KERNEL_ASSERT_LOCKED(); @@ -313,13 +325,17 @@ tun_clone_destroy(struct ifnet *ifp) if (sc->sc_reading) wakeup(&ifp->if_snd); + klist_invalidate(&sc->sc_rsel.si_note); + klist_invalidate(&sc->sc_wsel.si_note); + + /* the klist is empty, don't need sc_selmtx */ + selwakeup(&sc->sc_rsel); + /* wait for device entrypoints to finish */ refcnt_finalize(&sc->sc_refs, "tundtor"); - s = splhigh(); - klist_invalidate(&sc->sc_rsel.si_note); - klist_invalidate(&sc->sc_wsel.si_note); - splx(s); + klist_free(&sc->sc_rsel.si_note); + klist_free(&sc->sc_wsel.si_note); if (ISSET(sc->sc_flags, TUN_LAYER2)) ether_ifdetach(ifp); @@ -460,7 +476,6 @@ tun_dev_close(dev_t dev, struct proc *p) ifq_purge(&ifp->if_snd); CLR(sc->sc_flags, TUN_ASYNC); - selwakeup(&sc->sc_rsel); sigio_free(&sc->sc_sigio); if (!ISSET(sc->sc_flags, TUN_DEAD)) { @@ -977,7 +992,6 @@ tun_dev_kqfilter(dev_t dev, struct knote struct ifnet *ifp; struct klist *klist; int error = 0; - int s; sc = tun_get(dev); if (sc == NULL) @@ -1001,9 +1015,9 @@ tun_dev_kqfilter(dev_t dev, struct knote kn->kn_hook = (caddr_t)sc; /* XXX give the sc_ref to the hook? */ - s = splhigh(); - klist_insert_locked(klist, kn); - splx(s); + mtx_enter(&sc->sc_selmtx); + klist_insert(klist, kn); + mtx_leave(&sc->sc_selmtx); put: tun_put(sc); @@ -1013,12 +1027,9 @@ put: void filt_tunrdetach(struct knote *kn) { - int s; struct tun_softc *sc = kn->kn_hook; - s = splhigh(); - klist_remove_locked(&sc->sc_rsel.si_note, kn); - splx(s); + klist_remove(&sc->sc_rsel.si_note, kn); } int @@ -1035,12 +1046,9 @@ filt_tunread(struct knote *kn, long hint void filt_tunwdetach(struct knote *kn) { - int s; struct tun_softc *sc = kn->kn_hook; - s = splhigh(); - klist_remove_locked(&sc->sc_wsel.si_note, kn); - splx(s); + klist_remove(&sc->sc_wsel.si_note, kn); } int @@ -1052,6 +1060,39 @@ filt_tunwrite(struct knote *kn, long hin kn->kn_data = ifp->if_hdrlen + ifp->if_hardmtu; return (1); +} + +int +filt_tunmodify(struct kevent *kev, struct knote *kn) +{ + struct tun_softc *sc = kn->kn_hook; + int active; + kn->kn_fop = &tunwrite_filtops; + + mtx_enter(&sc->sc_selmtx); + knote_modify(kev, kn); + active = (*kn->kn_fop->f_event)(kn, 0); + mtx_leave(&sc->sc_selmtx); + + return (active); +} + +int +filt_tunprocess(struct knote *kn, struct kevent *kev) +{ + struct tun_softc *sc = kn->kn_hook; + int active; + + mtx_enter(&sc->sc_selmtx); + if (kev != NULL && ISSET(kn->kn_flags, EV_ONESHOT)) + active = 1; + else + active = (*kn->kn_fop->f_event)(kn, 0); + if (active) + knote_submit(kn, kev); + mtx_leave(&sc->sc_selmtx); + + return (active); } void