visa@, mpi@, I'm asking you to review, because you are involved in the kevent(9) development.
Hrvoje, if you want to test this diff, you need to disable pipex(4) with "net.pipex.enable=0". Index: sys/net/if_pppx.c =================================================================== RCS file: /cvs/src/sys/net/if_pppx.c,v retrieving revision 1.124 diff -u -p -r1.124 if_pppx.c --- sys/net/if_pppx.c 26 Nov 2022 17:50:26 -0000 1.124 +++ sys/net/if_pppx.c 25 Jan 2023 19:30:51 -0000 @@ -56,7 +56,7 @@ #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/vnode.h> -#include <sys/selinfo.h> +#include <sys/event.h> #include <sys/refcnt.h> #include <net/if.h> @@ -125,10 +125,10 @@ struct pppx_dev { int pxd_unit; /* [I] */ /* kq shizz */ - struct selinfo pxd_rsel; - struct mutex pxd_rsel_mtx; - struct selinfo pxd_wsel; - struct mutex pxd_wsel_mtx; + struct klist pxd_rklist; + struct mutex pxd_rklist_mtx; + struct klist pxd_wklist; + struct mutex pxd_wklist_mtx; /* queue of packets for userland to service - protected by splnet */ struct mbuf_queue pxd_svcq; @@ -195,22 +195,40 @@ void pppxattach(int); void filt_pppx_rdetach(struct knote *); int filt_pppx_read(struct knote *, long); +int filt_pppx_rmodify(struct kevent *kev, struct knote *kn); +int filt_pppx_rprocess(struct knote *kn, struct kevent *kev); const struct filterops pppx_rd_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_pppx_rdetach, .f_event = filt_pppx_read, + .f_modify = filt_pppx_rmodify, + .f_process = filt_pppx_rprocess, }; void filt_pppx_wdetach(struct knote *); int filt_pppx_write(struct knote *, long); +int filt_pppx_wmodify(struct kevent *kev, struct knote *kn); +int filt_pppx_wprocess(struct knote *kn, struct kevent *kev); const struct filterops pppx_wr_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_pppx_wdetach, .f_event = filt_pppx_write, + .f_modify = filt_pppx_wmodify, + .f_process = filt_pppx_wprocess, +}; + +void klist_pppx_assertlk(void *); +int klist_pppx_lock(void *); +void klist_pppx_unlock(void *, int); + +const struct klistops pppx_klistops = { + .klo_assertlk = klist_pppx_assertlk, + .klo_lock = klist_pppx_lock, + .klo_unlock = klist_pppx_unlock, }; struct pppx_dev * @@ -257,8 +275,10 @@ pppxopen(dev_t dev, int flags, int mode, } pxd->pxd_unit = minor(dev); - mtx_init(&pxd->pxd_rsel_mtx, IPL_NET); - mtx_init(&pxd->pxd_wsel_mtx, IPL_NET); + mtx_init(&pxd->pxd_rklist_mtx, IPL_NET); + mtx_init(&pxd->pxd_wklist_mtx, IPL_NET); + klist_init(&pxd->pxd_rklist, &pppx_klistops, &pxd->pxd_rklist_mtx); + klist_init(&pxd->pxd_wklist, &pppx_klistops, &pxd->pxd_wklist_mtx); LIST_INIT(&pxd->pxd_pxis); mq_init(&pxd->pxd_svcq, 128, IPL_NET); @@ -458,13 +478,13 @@ pppxkqfilter(dev_t dev, struct knote *kn switch (kn->kn_filter) { case EVFILT_READ: - mtx = &pxd->pxd_rsel_mtx; - klist = &pxd->pxd_rsel.si_note; + mtx = &pxd->pxd_rklist_mtx; + klist = &pxd->pxd_rklist; kn->kn_fop = &pppx_rd_filtops; break; case EVFILT_WRITE: - mtx = &pxd->pxd_wsel_mtx; - klist = &pxd->pxd_wsel.si_note; + mtx = &pxd->pxd_wklist_mtx; + klist = &pxd->pxd_wklist; kn->kn_fop = &pppx_wr_filtops; break; default: @@ -484,11 +504,11 @@ void filt_pppx_rdetach(struct knote *kn) { struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook; - struct klist *klist = &pxd->pxd_rsel.si_note; + struct klist *klist = &pxd->pxd_rklist; - mtx_enter(&pxd->pxd_rsel_mtx); + mtx_enter(&pxd->pxd_rklist_mtx); klist_remove_locked(klist, kn); - mtx_leave(&pxd->pxd_rsel_mtx); + mtx_leave(&pxd->pxd_rklist_mtx); } int @@ -501,15 +521,41 @@ filt_pppx_read(struct knote *kn, long hi return (kn->kn_data > 0); } +int +filt_pppx_rmodify(struct kevent *kev, struct knote *kn) +{ + struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook; + int rv; + + mtx_enter(&pxd->pxd_rklist_mtx); + rv = knote_modify(kev, kn); + mtx_leave(&pxd->pxd_rklist_mtx); + + return (rv); +} + +int +filt_pppx_rprocess(struct knote *kn, struct kevent *kev) +{ + struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook; + int rv; + + mtx_enter(&pxd->pxd_rklist_mtx); + rv = knote_process(kn, kev); + mtx_leave(&pxd->pxd_rklist_mtx); + + return (rv); +} + void filt_pppx_wdetach(struct knote *kn) { struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook; - struct klist *klist = &pxd->pxd_wsel.si_note; + struct klist *klist = &pxd->pxd_wklist; - mtx_enter(&pxd->pxd_wsel_mtx); + mtx_enter(&pxd->pxd_wklist_mtx); klist_remove_locked(klist, kn); - mtx_leave(&pxd->pxd_wsel_mtx); + mtx_leave(&pxd->pxd_wklist_mtx); } int @@ -520,6 +566,57 @@ filt_pppx_write(struct knote *kn, long h } int +filt_pppx_wmodify(struct kevent *kev, struct knote *kn) +{ + struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook; + int rv; + + mtx_enter(&pxd->pxd_wklist_mtx); + rv = knote_modify(kev, kn); + mtx_leave(&pxd->pxd_wklist_mtx); + + return (rv); +} + +int +filt_pppx_wprocess(struct knote *kn, struct kevent *kev) +{ + struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook; + int rv; + + mtx_enter(&pxd->pxd_wklist_mtx); + rv = knote_process(kn, kev); + mtx_leave(&pxd->pxd_wklist_mtx); + + return (rv); +} + +void +klist_pppx_assertlk(void *arg) +{ + struct mutex *mtx = arg; + + MUTEX_ASSERT_LOCKED(mtx); +} + +int +klist_pppx_lock(void *arg) +{ + struct mutex *mtx = arg; + + mtx_enter(mtx); + return (1); +} + +void +klist_pppx_unlock(void *arg, int ls) +{ + struct mutex *mtx = arg; + + mtx_leave(mtx); +} + +int pppxclose(dev_t dev, int flags, int mode, struct proc *p) { struct pppx_dev *pxd; @@ -536,6 +633,9 @@ pppxclose(dev_t dev, int flags, int mode mq_purge(&pxd->pxd_svcq); + klist_free(&pxd->pxd_rklist); + klist_free(&pxd->pxd_rklist); + free(pxd, M_DEVBUF, sizeof(*pxd)); return (0); @@ -875,7 +975,9 @@ pppx_if_output(struct ifnet *ifp, struct wakeup((caddr_t)pxi->pxi_dev); pxi->pxi_dev->pxd_waiting = 0; } - selwakeup(&pxi->pxi_dev->pxd_rsel); + mtx_enter(&pxi->pxi_dev->pxd_rklist_mtx); + KNOTE(&pxi->pxi_dev->pxd_rklist, 0); + mtx_leave(&pxi->pxi_dev->pxd_rklist_mtx); } } @@ -928,10 +1030,10 @@ struct pppac_softc { LIST_ENTRY(pppac_softc) sc_entry; /* [K] */ - struct mutex sc_rsel_mtx; - struct selinfo sc_rsel; - struct mutex sc_wsel_mtx; - struct selinfo sc_wsel; + struct mutex sc_rklist_mtx; + struct klist sc_rklist; + struct mutex sc_wklist_mtx; + struct klist sc_wklist; struct pipex_session *sc_multicast_session; @@ -944,22 +1046,40 @@ LIST_HEAD(pppac_list, pppac_softc); /* [ static void filt_pppac_rdetach(struct knote *); static int filt_pppac_read(struct knote *, long); +int filt_pppac_rmodify(struct kevent *kev, struct knote *kn); +int filt_pppac_rprocess(struct knote *kn, struct kevent *kev); static const struct filterops pppac_rd_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_pppac_rdetach, - .f_event = filt_pppac_read + .f_event = filt_pppac_read, + .f_modify = filt_pppac_rmodify, + .f_process = filt_pppac_rprocess, }; static void filt_pppac_wdetach(struct knote *); static int filt_pppac_write(struct knote *, long); +int filt_pppac_wmodify(struct kevent *kev, struct knote *kn); +int filt_pppac_wprocess(struct knote *kn, struct kevent *kev); static const struct filterops pppac_wr_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_pppac_wdetach, - .f_event = filt_pppac_write + .f_event = filt_pppac_write, + .f_modify = filt_pppac_wmodify, + .f_process = filt_pppac_wprocess, +}; + +void klist_pppac_assertlk(void *); +int klist_pppac_lock(void *); +void klist_pppac_unlock(void *, int); + +const struct klistops pppac_klistops = { + .klo_assertlk = klist_pppac_assertlk, + .klo_lock = klist_pppac_lock, + .klo_unlock = klist_pppac_unlock, }; static struct pppac_list pppac_devs = LIST_HEAD_INITIALIZER(pppac_devs); @@ -1020,8 +1140,10 @@ pppacopen(dev_t dev, int flags, int mode session->ownersc = sc; sc->sc_multicast_session = session; - mtx_init(&sc->sc_rsel_mtx, IPL_SOFTNET); - mtx_init(&sc->sc_wsel_mtx, IPL_SOFTNET); + mtx_init(&sc->sc_rklist_mtx, IPL_SOFTNET); + mtx_init(&sc->sc_wklist_mtx, IPL_SOFTNET); + klist_init(&sc->sc_rklist, &pppac_klistops, &sc->sc_rklist_mtx); + klist_init(&sc->sc_wklist, &pppac_klistops, &sc->sc_wklist_mtx); mq_init(&sc->sc_mq, IFQ_MAXLEN, IPL_SOFTNET); ifp = &sc->sc_if; @@ -1210,13 +1332,13 @@ pppackqfilter(dev_t dev, struct knote *k switch (kn->kn_filter) { case EVFILT_READ: - mtx = &sc->sc_rsel_mtx; - klist = &sc->sc_rsel.si_note; + mtx = &sc->sc_rklist_mtx; + klist = &sc->sc_rklist; kn->kn_fop = &pppac_rd_filtops; break; case EVFILT_WRITE: - mtx = &sc->sc_wsel_mtx; - klist = &sc->sc_wsel.si_note; + mtx = &sc->sc_wklist_mtx; + klist = &sc->sc_wklist; kn->kn_fop = &pppac_wr_filtops; break; default: @@ -1236,11 +1358,11 @@ static void filt_pppac_rdetach(struct knote *kn) { struct pppac_softc *sc = kn->kn_hook; - struct klist *klist = &sc->sc_rsel.si_note; + struct klist *klist = &sc->sc_rklist; - mtx_enter(&sc->sc_rsel_mtx); + mtx_enter(&sc->sc_rklist_mtx); klist_remove_locked(klist, kn); - mtx_leave(&sc->sc_rsel_mtx); + mtx_leave(&sc->sc_rklist_mtx); } static int @@ -1253,15 +1375,41 @@ filt_pppac_read(struct knote *kn, long h return (kn->kn_data > 0); } +int +filt_pppac_rmodify(struct kevent *kev, struct knote *kn) +{ + struct pppac_softc *sc = kn->kn_hook; + int rv; + + mtx_enter(&sc->sc_rklist_mtx); + rv = knote_modify(kev, kn); + mtx_leave(&sc->sc_rklist_mtx); + + return (rv); +} + +int +filt_pppac_rprocess(struct knote *kn, struct kevent *kev) +{ + struct pppac_softc *sc = kn->kn_hook; + int rv; + + mtx_enter(&sc->sc_rklist_mtx); + rv = knote_process(kn, kev); + mtx_leave(&sc->sc_rklist_mtx); + + return (rv); +} + static void filt_pppac_wdetach(struct knote *kn) { struct pppac_softc *sc = kn->kn_hook; - struct klist *klist = &sc->sc_wsel.si_note; + struct klist *klist = &sc->sc_wklist; - mtx_enter(&sc->sc_wsel_mtx); + mtx_enter(&sc->sc_wklist_mtx); klist_remove_locked(klist, kn); - mtx_leave(&sc->sc_wsel_mtx); + mtx_leave(&sc->sc_wklist_mtx); } static int @@ -1272,11 +1420,61 @@ filt_pppac_write(struct knote *kn, long } int +filt_pppac_wmodify(struct kevent *kev, struct knote *kn) +{ + struct pppac_softc *sc = kn->kn_hook; + int rv; + + mtx_enter(&sc->sc_wklist_mtx); + rv = knote_modify(kev, kn); + mtx_leave(&sc->sc_wklist_mtx); + + return (rv); +} + +int +filt_pppac_wprocess(struct knote *kn, struct kevent *kev) +{ + struct pppac_softc *sc = kn->kn_hook; + int rv; + + mtx_enter(&sc->sc_wklist_mtx); + rv = knote_process(kn, kev); + mtx_leave(&sc->sc_wklist_mtx); + + return (rv); +} + +void +klist_pppac_assertlk(void *arg) +{ + struct mutex *mtx = arg; + + MUTEX_ASSERT_LOCKED(mtx); +} + +int +klist_pppac_lock(void *arg) +{ + struct mutex *mtx = arg; + + mtx_enter(mtx); + return (1); +} + +void +klist_pppac_unlock(void *arg, int ls) +{ + struct mutex *mtx = arg; + + mtx_leave(mtx); +} + +int pppacclose(dev_t dev, int flags, int mode, struct proc *p) { struct pppac_softc *sc = pppac_lookup(dev); struct ifnet *ifp = &sc->sc_if; - int s; sc->sc_ready = 0; @@ -1286,10 +1484,8 @@ pppacclose(dev_t dev, int flags, int mod if_detach(ifp); - s = splhigh(); - klist_invalidate(&sc->sc_rsel.si_note); - klist_invalidate(&sc->sc_wsel.si_note); - splx(s); + klist_free(&sc->sc_rklist); + klist_free(&sc->sc_wklist); pool_put(&pipex_session_pool, sc->sc_multicast_session); pipex_destroy_all_sessions(sc); @@ -1461,6 +1657,8 @@ bad: if (!mq_empty(&sc->sc_mq)) { wakeup(sc); - selwakeup(&sc->sc_rsel); + mtx_enter(&sc->sc_rklist_mtx); + KNOTE(&sc->sc_rklist, 0); + mtx_leave(&sc->sc_rklist_mtx); } }