diff options
author | rwatson <rwatson@FreeBSD.org> | 2004-03-29 18:42:51 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2004-03-29 18:42:51 +0000 |
commit | 1d1b2c7f35d1158639ebc40e2a97c5fdb1888f4c (patch) | |
tree | 453bb875a2c70c8c786e9408f7fb28d341c2ab69 /sys/net | |
parent | f758b08c5a4eaeddcb7827e76fe9c0a8903c0cca (diff) | |
download | FreeBSD-src-1d1b2c7f35d1158639ebc40e2a97c5fdb1888f4c.zip FreeBSD-src-1d1b2c7f35d1158639ebc40e2a97c5fdb1888f4c.tar.gz |
Lock down if_tun global variables using a new mutex, tunmtx. As with
other pseudo-interfaces, break out tear-down of a softc into a
separate tun_destroy() function, and invoke that from the module
unloader. Hold tunmtx across manipulations of the global softc list.
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_tun.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 2579b93..bda7bb1 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -87,6 +87,12 @@ struct tun_softc { #define TUNDEBUG if (tundebug) if_printf #define TUNNAME "tun" +/* + * All mutable global variables in if_tun are locked using tunmtx, with + * the exception of tundebug, which is used unlocked, and tunclones, + * which is static after setup. + */ +static struct mtx tunmtx; static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface"); static int tundebug = 0; static struct clonedevs *tunclones; @@ -147,15 +153,30 @@ tunclone(void *arg, char *name, int namelen, dev_t *dev) } } +static void +tun_destroy(struct tun_softc *tp) +{ + dev_t dev; + + KASSERT((tp->tun_flags & TUN_OPEN) == 0, + ("tununits is out of sync - unit %d", tp->tun_if.if_dunit)); + + dev = tp->tun_dev; + bpfdetach(&tp->tun_if); + if_detach(&tp->tun_if); + destroy_dev(dev); + free(tp, M_TUN); +} + static int tunmodevent(module_t mod, int type, void *data) { static eventhandler_tag tag; struct tun_softc *tp; - dev_t dev; switch (type) { case MOD_LOAD: + mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF); clone_setup(&tunclones); tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000); if (tag == NULL) @@ -164,19 +185,16 @@ tunmodevent(module_t mod, int type, void *data) case MOD_UNLOAD: EVENTHANDLER_DEREGISTER(dev_clone, tag); - while (!TAILQ_EMPTY(&tunhead)) { - tp = TAILQ_FIRST(&tunhead); - KASSERT((tp->tun_flags & TUN_OPEN) == 0, - ("tununits is out of sync - unit %d", - tp->tun_if.if_dunit)); + mtx_lock(&tunmtx); + while ((tp = TAILQ_FIRST(&tunhead)) != NULL) { TAILQ_REMOVE(&tunhead, tp, tun_list); - dev = tp->tun_dev; - bpfdetach(&tp->tun_if); - if_detach(&tp->tun_if); - destroy_dev(dev); - free(tp, M_TUN); + mtx_unlock(&tunmtx); + tun_destroy(tp); + mtx_lock(&tunmtx); } + mtx_unlock(&tunmtx); clone_cleanup(&tunclones); + mtx_destroy(&tunmtx); break; } return 0; @@ -215,7 +233,9 @@ tuncreate(dev_t dev) MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO); sc->tun_flags = TUN_INITED; sc->tun_dev = dev; + mtx_lock(&tunmtx); TAILQ_INSERT_TAIL(&tunhead, sc, tun_list); + mtx_unlock(&tunmtx); ifp = &sc->tun_if; if_initname(ifp, TUNNAME, dev2unit(dev)); |