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 14 Feb 2022 06:55:45 -0000 @@ -92,6 +92,7 @@ struct tun_softc { dev_t sc_dev; struct refcnt sc_refs; unsigned int sc_reading; + struct task sc_wakeup; }; #ifdef TUN_DEBUG @@ -124,8 +125,9 @@ int tap_clone_create(struct if_clone *, int tun_create(struct if_clone *, int, int); int tun_clone_destroy(struct ifnet *); void tun_wakeup(struct tun_softc *); +void tun_wakeup_cb(void *); int tun_init(struct tun_softc *); -void tun_start(struct ifnet *); +void tun_start(struct ifqueue *); int filt_tunread(struct knote *, long); int filt_tunwrite(struct knote *, long); void filt_tunrdetach(struct knote *); @@ -230,9 +232,10 @@ tun_create(struct if_clone *ifc, int uni /* build the interface */ + ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE; ifp->if_ioctl = tun_ioctl; ifp->if_enqueue = tun_enqueue; - ifp->if_start = tun_start; + ifp->if_qstart = tun_start; ifp->if_hardmtu = TUNMRU; ifp->if_link_state = LINK_STATE_DOWN; @@ -268,6 +271,7 @@ tun_create(struct if_clone *ifc, int uni sigio_init(&sc->sc_sigio); refcnt_init(&sc->sc_refs); + task_set(&sc->sc_wakeup, tun_wakeup_cb, sc); /* tell tun_dev_open we're initialised */ @@ -331,6 +335,12 @@ tun_clone_destroy(struct ifnet *ifp) return (0); } +static inline void +tun_ref(struct tun_softc *sc) +{ + refcnt_take(&sc->sc_refs); +} + static struct tun_softc * tun_get(dev_t dev) { @@ -339,7 +349,7 @@ tun_get(dev_t dev) smr_read_enter(); SMR_LIST_FOREACH(sc, &tun_devs_list, sc_entry) { if (sc->sc_dev == dev) { - refcnt_take(&sc->sc_refs); + tun_ref(sc); break; } } @@ -621,15 +631,35 @@ tun_enqueue(struct ifnet *ifp, struct mb return (0); } +/* + * If there are processes sleeping on this descriptor, wake them up. + */ + void tun_wakeup(struct tun_softc *sc) { if (sc->sc_reading) wakeup(&sc->sc_if.if_snd); + if (ISSET(sc->sc_flags, TUN_ASYNC) || + !klist_empty(&sc->sc_rsel.si_note) || + sc->sc_rsel.si_seltid != 0) { + tun_ref(sc); + if (!task_add(systq, &sc->sc_wakeup)) + tun_put(sc); + } +} + +void +tun_wakeup_cb(void *arg) +{ + struct tun_softc *sc = arg; + selwakeup(&sc->sc_rsel); if (sc->sc_flags & TUN_ASYNC) pgsigio(&sc->sc_sigio, SIGIO, 0); + + tun_put(sc); } /* @@ -815,13 +845,25 @@ put: int tunwrite(dev_t dev, struct uio *uio, int ioflag) { - return (tun_dev_write(dev, uio, ioflag, 0)); + int rv; + + KERNEL_UNLOCK(); + rv = tun_dev_write(dev, uio, ioflag, 0); + KERNEL_LOCK(); + + return (rv); } int tapwrite(dev_t dev, struct uio *uio, int ioflag) { - return (tun_dev_write(dev, uio, ioflag, ETHER_ALIGN)); + int rv; + + KERNEL_UNLOCK(); + rv = tun_dev_write(dev, uio, ioflag, ETHER_ALIGN); + KERNEL_LOCK(); + + return (rv); } int @@ -830,6 +872,7 @@ tun_dev_write(dev_t dev, struct uio *uio struct tun_softc *sc; struct ifnet *ifp; struct mbuf *m0; + struct mbuf_list ml = MBUF_LIST_INITIALIZER(); int error = 0; size_t mlen; @@ -869,9 +912,8 @@ tun_dev_write(dev_t dev, struct uio *uio if (error != 0) goto drop; - NET_LOCK(); - if_vinput(ifp, m0); - NET_UNLOCK(); + ml_enqueue(&ml, m0); + if_input(ifp, &ml); tun_put(sc); return (0); @@ -1055,14 +1097,12 @@ filt_tunwrite(struct knote *kn, long hin } void -tun_start(struct ifnet *ifp) +tun_start(struct ifqueue *ifq) { + struct ifnet *ifp = ifq->ifq_if; struct tun_softc *sc = ifp->if_softc; - splassert(IPL_NET); - - if (ifq_len(&ifp->if_snd)) - tun_wakeup(sc); + tun_wakeup(sc); } void