Author: kevans
Date: Fri Mar 15 13:19:52 2019
New Revision: 345180
URL: https://svnweb.freebsd.org/changeset/base/345180

Log:
  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

Modified:
  head/sys/net/if_bridge.c

Modified: head/sys/net/if_bridge.c
==============================================================================
--- head/sys/net/if_bridge.c    Fri Mar 15 11:49:46 2019        (r345179)
+++ head/sys/net/if_bridge.c    Fri Mar 15 13:19:52 2019        (r345180)
@@ -235,7 +235,8 @@ static eventhandler_tag bridge_detach_cookie;
 
 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 void    bridge_clone_destroy(struct ifnet *);
@@ -527,6 +528,9 @@ static void
 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();
        LIST_INIT(&V_bridge_list);
        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);
        V_bridge_cloner = NULL;
        BRIDGE_LIST_LOCK_DESTROY();
+       uma_zdestroy(V_bridge_rtnode_zone);
 }
 VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
     vnet_bridge_uninit, NULL);
@@ -552,9 +557,6 @@ bridge_modevent(module_t mod, int type, void *data)
 
        switch (type) {
        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_detach_cookie = EVENTHANDLER_REGISTER(
                    ifnet_departure_event, bridge_ifdetach, NULL,
@@ -563,7 +565,6 @@ bridge_modevent(module_t mod, int type, void *data)
        case MOD_UNLOAD:
                EVENTHANDLER_DEREGISTER(ifnet_departure_event,
                    bridge_detach_cookie);
-               uma_zdestroy(bridge_rtnode_zone);
                bridge_dn_p = NULL;
                break;
        default:
@@ -730,6 +731,9 @@ bridge_clone_destroy(struct ifnet *ifp)
                bridge_delete_span(sc, bif);
        }
 
+       /* Tear down the routing table. */
+       bridge_rtable_fini(sc);
+
        BRIDGE_UNLOCK(sc);
 
        callout_drain(&sc->sc_brcallout);
@@ -742,9 +746,6 @@ bridge_clone_destroy(struct ifnet *ifp)
        ether_ifdetach(ifp);
        if_free(ifp);
 
-       /* Tear down the routing table. */
-       bridge_rtable_fini(sc);
-
        BRIDGE_LOCK_DESTROY(sc);
        free(sc, M_DEVBUF);
 }
@@ -2669,7 +2670,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t
                 * initialize the expiration time and Ethernet
                 * 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)
                        return (ENOMEM);
 
@@ -2682,7 +2683,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t
                brt->brt_vlan = vlan;
 
                if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
-                       uma_zfree(bridge_rtnode_zone, brt);
+                       uma_zfree(V_bridge_rtnode_zone, brt);
                        return (error);
                }
                brt->brt_dst = bif;
@@ -2766,11 +2767,14 @@ bridge_timer(void *arg)
 
        BRIDGE_LOCK_ASSERT(sc);
 
+       /* Destruction of rtnodes requires a proper vnet context */
+       CURVNET_SET(sc->sc_ifp->if_vnet);
        bridge_rtage(sc);
 
        if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
                callout_reset(&sc->sc_brcallout,
                    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,
            ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt));
+       bridge_rtflush(sc, 1);
        free(sc->sc_rthash, M_DEVBUF);
 }
 
@@ -3028,7 +3033,7 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct 
        LIST_REMOVE(brt, brt_list);
        sc->sc_brtcnt--;
        brt->brt_dst->bif_addrcnt--;
-       uma_zfree(bridge_rtnode_zone, brt);
+       uma_zfree(V_bridge_rtnode_zone, brt);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to