Index: if_tun.c =================================================================== RCS file: /cvs/src/sys/net/if_tun.c,v retrieving revision 1.234 diff -u -p -r1.234 if_tun.c --- if_tun.c 16 Feb 2022 02:22:39 -0000 1.234 +++ if_tun.c 23 Feb 2022 13:44:33 -0000 @@ -78,6 +78,7 @@ #include struct tun_softc { + unsigned int sc_gen; struct arpcom sc_ac; /* ethernet common data */ #define sc_if sc_ac.ac_if struct selinfo sc_rsel; /* read select */ @@ -154,6 +155,58 @@ struct if_clone tun_cloner = struct if_clone tap_cloner = IF_CLONE_INITIALIZER("tap", tap_clone_create, tun_clone_destroy); +struct tun_log_entry { + unsigned int gen; + const char *func; + unsigned int line; + unsigned int seq; + pid_t thrid; + unsigned int cpuid; +}; + +unsigned int tun_log_seq = 0; +struct tun_log_entry tun_log_entries[128]; + +void +__tun_log(const char *func, unsigned int line, struct tun_softc *sc) +{ + unsigned int seq; + struct tun_log_entry *entry; + + KERNEL_ASSERT_LOCKED(); + + seq = tun_log_seq++; + entry = &tun_log_entries[seq % nitems(tun_log_entries)]; + + entry->gen = sc->sc_gen; + entry->func = func; + entry->line = line; + entry->seq = seq; + entry->thrid = curproc->p_tid; + entry->cpuid = curcpu()->ci_cpuid; +} + +#define tun_log(_sc) __tun_log(__func__, __LINE__, _sc) + +void +tun_log_dump(void) +{ + const struct tun_log_entry *entry; + unsigned int end = tun_log_seq % nitems(tun_log_entries); + unsigned int slot = end; /* the end is the beginning is the end */ + + do { + entry = &tun_log_entries[slot]; + + printf("sc: %3u, cpu: %d, tid: %6d, %s[%u]\n", + entry->gen, entry->cpuid, entry->thrid, + entry->func, entry->line); + + slot++; + slot %= nitems(tun_log_entries); + } while (slot != end); +} + void tunattach(int n) { @@ -200,6 +253,7 @@ tun_insert(struct tun_softc *sc) error = EEXIST; else { /* tun_name_lookup checks for the right lock already */ + tun_log(sc); SMR_LIST_INSERT_HEAD_LOCKED(&tun_devs_list, sc, sc_entry); } @@ -211,6 +265,7 @@ tun_create(struct if_clone *ifc, int uni { struct tun_softc *sc; struct ifnet *ifp; + static unsigned int gen; if (unit > minor(~0U)) return (ENXIO); @@ -218,6 +273,7 @@ tun_create(struct if_clone *ifc, int uni KERNEL_ASSERT_LOCKED(); sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); + sc->sc_gen = gen++; refcnt_init(&sc->sc_refs); ifp = &sc->sc_if; @@ -293,6 +349,7 @@ tun_clone_destroy(struct ifnet *ifp) if (ISSET(sc->sc_flags, TUN_DEAD)) return (ENXIO); + tun_log(sc); SET(sc->sc_flags, TUN_DEAD); /* kick userland off the device */ @@ -300,10 +357,20 @@ tun_clone_destroy(struct ifnet *ifp) if (dev) { struct vnode *vp; - if (vfinddev(dev, VCHR, &vp)) - VOP_REVOKE(vp, REVOKEALL); + tun_log(sc); + if (vfinddev(dev, VCHR, &vp)) { + int rv; + tun_log(sc); + rv = VOP_REVOKE(vp, REVOKEALL); + if (rv != 0) { + printf("%s: revoke %d\n", ifp->if_xname, rv); + uprintf("%s: revoke %d\n", ifp->if_xname, rv); + } + } else + tun_log(sc); - KASSERT(sc->sc_dev == 0); + while (sc->sc_dev != 0) + tsleep_nsec(&sc->sc_dev, PWAIT, "tunclose", INFSLP); } /* prevent userland from getting to the device again */ @@ -314,14 +381,16 @@ tun_clone_destroy(struct ifnet *ifp) if (sc->sc_reading) wakeup(&ifp->if_snd); - /* 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); + /* wait for device entrypoints to finish */ + refcnt_finalize(&sc->sc_refs, "tundtor"); + + tun_log(sc); + if (ISSET(sc->sc_flags, TUN_LAYER2)) ether_ifdetach(ifp); @@ -383,6 +452,7 @@ tun_dev_open(dev_t dev, const struct if_ /* let's find or make an interface to work with */ while ((sc = tun_name_lookup(name)) == NULL) { + stayup = 0; error = if_clone_create(name, rdomain); switch (error) { case 0: /* it's probably ours */ @@ -400,6 +470,7 @@ tun_dev_open(dev_t dev, const struct if_ /* wait for it to be fully constructed before we use it */ for (;;) { if (ISSET(sc->sc_flags, TUN_DEAD)) { + tun_log(sc); error = ENXIO; goto done; } @@ -415,11 +486,13 @@ tun_dev_open(dev_t dev, const struct if_ } if (sc->sc_dev != 0) { + tun_log(sc); /* aww, we lost */ error = EBUSY; goto done; } /* it's ours now */ + tun_log(sc); sc->sc_dev = dev; CLR(sc->sc_flags, stayup); @@ -431,6 +504,8 @@ tun_dev_open(dev_t dev, const struct if_ tun_link_state(ifp, LINK_STATE_FULL_DUPLEX); error = 0; + tun_log(sc); + done: tun_put(sc); return (error); @@ -462,8 +537,11 @@ tun_dev_close(dev_t dev, struct proc *p) int destroy = 0; sc = tun_get(dev); - if (sc == NULL) + if (sc == NULL) { + printf("%s[%u]: wat\n", __func__, __LINE__); return (ENXIO); + } + tun_log(sc); ifp = &sc->sc_if; @@ -473,24 +551,25 @@ tun_dev_close(dev_t dev, struct proc *p) NET_LOCK(); CLR(ifp->if_flags, IFF_UP | IFF_RUNNING); NET_UNLOCK(); + tun_link_state(ifp, LINK_STATE_DOWN); 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)) { + sc->sc_dev = 0; + + if (ISSET(sc->sc_flags, TUN_DEAD)) { + tun_log(sc); + wakeup(&sc->sc_dev); + } else if (!ISSET(sc->sc_flags, TUN_STAYUP)) { /* we can't hold a reference to sc before we start a dtor */ - if (!ISSET(sc->sc_flags, TUN_STAYUP)) { - destroy = 1; - strlcpy(name, ifp->if_xname, sizeof(name)); - } else { - tun_link_state(ifp, LINK_STATE_DOWN); - } + destroy = 1; + strlcpy(name, ifp->if_xname, sizeof(name)); } - sc->sc_dev = 0; - + tun_log(sc); tun_put(sc); if (destroy)