/* * It might happen that the administrator used ifconfig to externally destroy * the interface. In that case, tap_fops_close will be called while * tap_detach is already happening. If we called it again from here, we * would dead lock. TAP_GOING ensures that this situation doesn't happen. */ static int tap_fops_close(file_t *fp) { int unit = fp->f_devunit; struct tap_softc *sc; int error; sc = device_lookup_private(&tap_cd, unit); if (sc == NULL) return (ENXIO); /* tap_dev_close currently always succeeds, but it might not * always be the case. */ KERNEL_LOCK(1, NULL); if ((error = tap_dev_close(sc)) != 0) { KERNEL_UNLOCK_ONE(NULL); return (error); } /* Destroy the device now that it is no longer useful, * unless it's already being destroyed. */ if ((sc->sc_flags & TAP_GOING) != 0) { KERNEL_UNLOCK_ONE(NULL); return (0); } error = tap_clone_destroyer(sc->sc_dev); KERNEL_UNLOCK_ONE(NULL); return error; }
/* * The clean design of if_clone and autoconf(9) makes that part * really straightforward. The second argument of config_detach * means neither QUIET nor FORCED. */ static int tap_clone_destroy(struct ifnet *ifp) { struct tap_softc *sc = ifp->if_softc; return tap_clone_destroyer(sc->sc_dev); }
/* * The clean design of if_clone and autoconf(9) makes that part * really straightforward. The second argument of config_detach * means neither QUIET nor FORCED. */ static int tap_clone_destroy(struct ifnet *ifp) { struct tap_softc *sc = ifp->if_softc; int error = tap_clone_destroyer(sc->sc_dev); if (error == 0) atomic_dec_uint(&tap_count); return error; }