Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -602,10 +602,14 @@ static void if_free_internal(struct ifnet *ifp) { + void *softc; + if_freed_fn_t freed_fn; KASSERT((ifp->if_flags & IFF_DYING), ("if_free_internal: interface not dying")); + softc = ifp->if_softc; + freed_fn = ifp->if_freed; if (if_com_free[ifp->if_alloctype] != NULL) if_com_free[ifp->if_alloctype](ifp->if_l2com, ifp->if_alloctype); @@ -626,6 +630,8 @@ free(ifp, M_IFNET); else free_domain(ifp, M_IFNET); + if (freed_fn != NULL) + freed_fn(softc); } static void Index: sys/net/if_tuntap.c =================================================================== --- sys/net/if_tuntap.c +++ sys/net/if_tuntap.c @@ -190,9 +190,6 @@ static TAILQ_HEAD(,tuntap_softc) tunhead = TAILQ_HEAD_INITIALIZER(tunhead); SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); -static struct sx tun_ioctl_sx; -SX_SYSINIT(tun_ioctl_sx, &tun_ioctl_sx, "tun_ioctl"); - SYSCTL_DECL(_net_link); /* tun */ static SYSCTL_NODE(_net_link, OID_AUTO, tun, CTLFLAG_RW, 0, @@ -217,6 +214,7 @@ static void tun_unbusy_locked(struct tuntap_softc *tp); static int tun_busy(struct tuntap_softc *tp); static void tun_unbusy(struct tuntap_softc *tp); +static void tunifdtor(void *softc); static int tuntap_name2info(const char *name, int *unit, int *flags); static void tunclone(void *arg, struct ucred *cred, char *name, @@ -617,6 +615,17 @@ CURVNET_RESTORE(); } +static void +tunifdtor(void *softc) +{ + struct tuntap_softc *tp; + + tp = softc; + mtx_destroy(&tp->tun_mtx); + cv_destroy(&tp->tun_cv); + free(tp, M_TUN); +} + static void tun_destroy(struct tuntap_softc *tp) { @@ -641,14 +650,9 @@ bpfdetach(TUN2IFP(tp)); if_detach(TUN2IFP(tp)); } - sx_xlock(&tun_ioctl_sx); - TUN2IFP(tp)->if_softc = NULL; - sx_xunlock(&tun_ioctl_sx); free_unr(tp->tun_drv->unrhdr, TUN2IFP(tp)->if_dunit); if_free(TUN2IFP(tp)); - mtx_destroy(&tp->tun_mtx); - cv_destroy(&tp->tun_cv); - free(tp, M_TUN); + /* softc cleanup deferred to tunifdtor. */ CURVNET_RESTORE(); } @@ -959,6 +963,7 @@ ifp->if_softc = tp; if_initname(ifp, drv->cdevsw.d_name, dev2unit(dev)); ifp->if_ioctl = tunifioctl; + ifp->if_freed = tunifdtor; ifp->if_flags = iflags; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_capabilities |= IFCAP_LINKSTATE; @@ -1011,14 +1016,11 @@ * from dying until we've created the alias (that will then be * subsequently destroyed). */ - sx_xlock(&tun_ioctl_sx); tp = ifp->if_softc; if (tp == NULL) { - sx_xunlock(&tun_ioctl_sx); return; } error = tun_busy(tp); - sx_xunlock(&tun_ioctl_sx); if (error != 0) return; if (tp->tun_alias != NULL) { @@ -1324,12 +1326,7 @@ bool l2tun; ifmr = NULL; - sx_xlock(&tun_ioctl_sx); tp = ifp->if_softc; - if (tp == NULL) { - error = ENXIO; - goto bad; - } l2tun = (tp->tun_flags & TUN_L2) != 0; switch(cmd) { case SIOCGIFSTATUS: @@ -1391,8 +1388,6 @@ error = EINVAL; } } -bad: - sx_xunlock(&tun_ioctl_sx); return (error); } Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -133,6 +133,7 @@ typedef int (*if_ioctl_fn_t)(if_t, u_long, caddr_t); typedef void (*if_init_fn_t)(void *); typedef void (*if_qflush_fn_t)(if_t); +typedef void (*if_freed_fn_t)(void *); typedef int (*if_transmit_fn_t)(if_t, struct mbuf *); typedef uint64_t (*if_get_counter_t)(if_t, ift_counter); @@ -368,6 +369,7 @@ if_start_fn_t if_start; /* initiate output routine */ if_ioctl_fn_t if_ioctl; /* ioctl routine */ if_init_fn_t if_init; /* Init routine */ + if_freed_fn_t if_freed; /* Post-free cleanup routine */ int (*if_resolvemulti) /* validate/resolve multicast */ (struct ifnet *, struct sockaddr **, struct sockaddr *); if_qflush_fn_t if_qflush; /* flush any queue */