if_bridge(4): Fix module teardown
bridge_rtnode_zone still has outstanding allocations at the time of destruction in the current model because all of the interface teardown happens in a VNET_SYSUNINIT, -after- the MOD_UNLOAD has already been processed. The SYSUNINIT triggers destruction of the interfaces, which then attempts to free the memory from the zone that's already been destroyed, and we hit a panic. Solve this by virtualizing the uma_zone we allocate the rtnodes from to fix the ordering. bridge_rtable_fini should also take care to flush any remaining routes that weren't taken care of when dynamic routes were flushed in bridge_stop. Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D19578
This commit is contained in:
parent
0204d1c793
commit
a87407ff85
@ -235,7 +235,8 @@ static eventhandler_tag bridge_detach_cookie;
|
|||||||
|
|
||||||
int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
|
int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
|
||||||
|
|
||||||
uma_zone_t bridge_rtnode_zone;
|
VNET_DEFINE_STATIC(uma_zone_t, bridge_rtnode_zone);
|
||||||
|
#define V_bridge_rtnode_zone VNET(bridge_rtnode_zone)
|
||||||
|
|
||||||
static int bridge_clone_create(struct if_clone *, int, caddr_t);
|
static int bridge_clone_create(struct if_clone *, int, caddr_t);
|
||||||
static void bridge_clone_destroy(struct ifnet *);
|
static void bridge_clone_destroy(struct ifnet *);
|
||||||
@ -527,6 +528,9 @@ static void
|
|||||||
vnet_bridge_init(const void *unused __unused)
|
vnet_bridge_init(const void *unused __unused)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
V_bridge_rtnode_zone = uma_zcreate("bridge_rtnode",
|
||||||
|
sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL,
|
||||||
|
UMA_ALIGN_PTR, 0);
|
||||||
BRIDGE_LIST_LOCK_INIT();
|
BRIDGE_LIST_LOCK_INIT();
|
||||||
LIST_INIT(&V_bridge_list);
|
LIST_INIT(&V_bridge_list);
|
||||||
V_bridge_cloner = if_clone_simple(bridge_name,
|
V_bridge_cloner = if_clone_simple(bridge_name,
|
||||||
@ -542,6 +546,7 @@ vnet_bridge_uninit(const void *unused __unused)
|
|||||||
if_clone_detach(V_bridge_cloner);
|
if_clone_detach(V_bridge_cloner);
|
||||||
V_bridge_cloner = NULL;
|
V_bridge_cloner = NULL;
|
||||||
BRIDGE_LIST_LOCK_DESTROY();
|
BRIDGE_LIST_LOCK_DESTROY();
|
||||||
|
uma_zdestroy(V_bridge_rtnode_zone);
|
||||||
}
|
}
|
||||||
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
|
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
|
||||||
vnet_bridge_uninit, NULL);
|
vnet_bridge_uninit, NULL);
|
||||||
@ -552,9 +557,6 @@ bridge_modevent(module_t mod, int type, void *data)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MOD_LOAD:
|
case MOD_LOAD:
|
||||||
bridge_rtnode_zone = uma_zcreate("bridge_rtnode",
|
|
||||||
sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL,
|
|
||||||
UMA_ALIGN_PTR, 0);
|
|
||||||
bridge_dn_p = bridge_dummynet;
|
bridge_dn_p = bridge_dummynet;
|
||||||
bridge_detach_cookie = EVENTHANDLER_REGISTER(
|
bridge_detach_cookie = EVENTHANDLER_REGISTER(
|
||||||
ifnet_departure_event, bridge_ifdetach, NULL,
|
ifnet_departure_event, bridge_ifdetach, NULL,
|
||||||
@ -563,7 +565,6 @@ bridge_modevent(module_t mod, int type, void *data)
|
|||||||
case MOD_UNLOAD:
|
case MOD_UNLOAD:
|
||||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
|
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
|
||||||
bridge_detach_cookie);
|
bridge_detach_cookie);
|
||||||
uma_zdestroy(bridge_rtnode_zone);
|
|
||||||
bridge_dn_p = NULL;
|
bridge_dn_p = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -730,6 +731,9 @@ bridge_clone_destroy(struct ifnet *ifp)
|
|||||||
bridge_delete_span(sc, bif);
|
bridge_delete_span(sc, bif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tear down the routing table. */
|
||||||
|
bridge_rtable_fini(sc);
|
||||||
|
|
||||||
BRIDGE_UNLOCK(sc);
|
BRIDGE_UNLOCK(sc);
|
||||||
|
|
||||||
callout_drain(&sc->sc_brcallout);
|
callout_drain(&sc->sc_brcallout);
|
||||||
@ -742,9 +746,6 @@ bridge_clone_destroy(struct ifnet *ifp)
|
|||||||
ether_ifdetach(ifp);
|
ether_ifdetach(ifp);
|
||||||
if_free(ifp);
|
if_free(ifp);
|
||||||
|
|
||||||
/* Tear down the routing table. */
|
|
||||||
bridge_rtable_fini(sc);
|
|
||||||
|
|
||||||
BRIDGE_LOCK_DESTROY(sc);
|
BRIDGE_LOCK_DESTROY(sc);
|
||||||
free(sc, M_DEVBUF);
|
free(sc, M_DEVBUF);
|
||||||
}
|
}
|
||||||
@ -2669,7 +2670,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
|
|||||||
* initialize the expiration time and Ethernet
|
* initialize the expiration time and Ethernet
|
||||||
* address.
|
* address.
|
||||||
*/
|
*/
|
||||||
brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO);
|
brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO);
|
||||||
if (brt == NULL)
|
if (brt == NULL)
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
|
|
||||||
@ -2682,7 +2683,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
|
|||||||
brt->brt_vlan = vlan;
|
brt->brt_vlan = vlan;
|
||||||
|
|
||||||
if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
|
if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
|
||||||
uma_zfree(bridge_rtnode_zone, brt);
|
uma_zfree(V_bridge_rtnode_zone, brt);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
brt->brt_dst = bif;
|
brt->brt_dst = bif;
|
||||||
@ -2766,11 +2767,14 @@ bridge_timer(void *arg)
|
|||||||
|
|
||||||
BRIDGE_LOCK_ASSERT(sc);
|
BRIDGE_LOCK_ASSERT(sc);
|
||||||
|
|
||||||
|
/* Destruction of rtnodes requires a proper vnet context */
|
||||||
|
CURVNET_SET(sc->sc_ifp->if_vnet);
|
||||||
bridge_rtage(sc);
|
bridge_rtage(sc);
|
||||||
|
|
||||||
if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
|
if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||||
callout_reset(&sc->sc_brcallout,
|
callout_reset(&sc->sc_brcallout,
|
||||||
bridge_rtable_prune_period * hz, bridge_timer, sc);
|
bridge_rtable_prune_period * hz, bridge_timer, sc);
|
||||||
|
CURVNET_RESTORE();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2886,6 +2890,7 @@ bridge_rtable_fini(struct bridge_softc *sc)
|
|||||||
|
|
||||||
KASSERT(sc->sc_brtcnt == 0,
|
KASSERT(sc->sc_brtcnt == 0,
|
||||||
("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt));
|
("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt));
|
||||||
|
bridge_rtflush(sc, 1);
|
||||||
free(sc->sc_rthash, M_DEVBUF);
|
free(sc->sc_rthash, M_DEVBUF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3028,7 +3033,7 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
|
|||||||
LIST_REMOVE(brt, brt_list);
|
LIST_REMOVE(brt, brt_list);
|
||||||
sc->sc_brtcnt--;
|
sc->sc_brtcnt--;
|
||||||
brt->brt_dst->bif_addrcnt--;
|
brt->brt_dst->bif_addrcnt--;
|
||||||
uma_zfree(bridge_rtnode_zone, brt);
|
uma_zfree(V_bridge_rtnode_zone, brt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user