Index: sys/net/if_vlan.c =================================================================== --- sys/net/if_vlan.c +++ sys/net/if_vlan.c @@ -87,11 +87,15 @@ #define UP_AND_RUNNING(ifp) \ ((ifp)->if_flags & IFF_UP && (ifp)->if_drv_flags & IFF_DRV_RUNNING) -CK_SLIST_HEAD(ifvlanhead, ifvlan); +struct ifvlanhead { + CK_SLIST_HEAD(, ifvlan) head; + struct epoch_context epoch_ctx; +}; struct ifvlantrunk { struct ifnet *parent; /* parent interface of this trunk */ struct mtx lock; + struct epoch_context epoch_ctx; #ifdef VLAN_ARRAY #define VLAN_ARRAY_SIZE (EVL_VLID_MASK + 1) struct ifvlan *vlans[VLAN_ARRAY_SIZE]; /* static table */ @@ -117,7 +121,7 @@ struct ifvlan *_next; \ size_t _i; \ for (_i = 0; _i < (1 << (_trunk)->hwidth); _i++) \ - CK_SLIST_FOREACH_SAFE((_ifv), &(_trunk)->hash[_i], ifv_list, _next) + CK_SLIST_FOREACH_SAFE((_ifv), &(_trunk)->hash[_i].head, ifv_list, _next) #endif /* VLAN_ARRAY */ /* @@ -146,7 +150,7 @@ for (_i = 0; \ !(_cond) && _i < (1 << (_trunk)->hwidth); \ _i = (_touch && ((_trunk) != NULL) ? 0 : _i + 1), _touch = false) \ - if (((_ifv) = CK_SLIST_FIRST(&(_trunk)->hash[_i])) != NULL && \ + if (((_ifv) = CK_SLIST_FIRST(&(_trunk)->hash[_i].head)) != NULL && \ (_touch = true)) #endif /* VLAN_ARRAY */ @@ -275,7 +279,7 @@ static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid); #endif -static void trunk_destroy(struct ifvlantrunk *trunk); +static void vlan_trunk_destroy(struct epoch_context *); static void vlan_init(void *foo); static void vlan_input(struct ifnet *ifp, struct mbuf *m); @@ -324,6 +328,13 @@ free(mc, M_VLAN); } +static void +vlan_hash_free(struct epoch_context *ctx) +{ + struct ifvlanhead *hash = __containerof(ctx, struct ifvlanhead, epoch_ctx); + free(hash, M_VLAN); +} + static void vlan_inithash(struct ifvlantrunk *trunk) { @@ -343,7 +354,7 @@ trunk->hmask = n - 1; trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK); for (i = 0; i < n; i++) - CK_SLIST_INIT(&trunk->hash[i]); + CK_SLIST_INIT(&trunk->hash[i].head); } static void @@ -354,7 +365,7 @@ KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); for (i = 0; i < (1 << trunk->hwidth); i++) - KASSERT(CK_SLIST_EMPTY(&trunk->hash[i]), + KASSERT(CK_SLIST_EMPTY(&trunk->hash[i].head), ("%s: hash table not empty", __func__)); #endif free(trunk->hash, M_VLAN); @@ -373,9 +384,10 @@ b = 1 << trunk->hwidth; i = HASH(ifv->ifv_vid, trunk->hmask); - CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) + CK_SLIST_FOREACH(ifv2, &trunk->hash[i].head, ifv_list) { if (ifv->ifv_vid == ifv2->ifv_vid) return (EEXIST); + } /* * Grow the hash when the number of vlans exceeds half of the number of @@ -386,7 +398,7 @@ vlan_growhash(trunk, 1); i = HASH(ifv->ifv_vid, trunk->hmask); } - CK_SLIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list); + CK_SLIST_INSERT_HEAD(&trunk->hash[i].head, ifv, ifv_list); trunk->refcnt++; return (0); @@ -403,15 +415,15 @@ b = 1 << trunk->hwidth; i = HASH(ifv->ifv_vid, trunk->hmask); - CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) + CK_SLIST_FOREACH(ifv2, &trunk->hash[i].head, ifv_list) { if (ifv2 == ifv) { trunk->refcnt--; - CK_SLIST_REMOVE(&trunk->hash[i], ifv2, ifvlan, ifv_list); + CK_SLIST_REMOVE(&trunk->hash[i].head, ifv2, ifvlan, ifv_list); if (trunk->refcnt < (b * b) / 2) vlan_growhash(trunk, -1); return (0); } - + } panic("%s: vlan not found\n", __func__); return (ENOENT); /*NOTREACHED*/ } @@ -449,15 +461,15 @@ return; /* We can live with the old hash table */ } for (j = 0; j < n2; j++) - CK_SLIST_INIT(&hash2[j]); - for (i = 0; i < n; i++) - while ((ifv = CK_SLIST_FIRST(&trunk->hash[i])) != NULL) { - CK_SLIST_REMOVE(&trunk->hash[i], ifv, ifvlan, ifv_list); + CK_SLIST_INIT(&hash2[j].head); + for (i = 0; i < n; i++) { + while ((ifv = CK_SLIST_FIRST(&trunk->hash[i].head)) != NULL) { + CK_SLIST_REMOVE(&trunk->hash[i].head, ifv, ifvlan, ifv_list); j = HASH(ifv->ifv_vid, n2 - 1); - CK_SLIST_INSERT_HEAD(&hash2[j], ifv, ifv_list); + CK_SLIST_INSERT_HEAD(&hash2[j].head, ifv, ifv_list); } - NET_EPOCH_WAIT(); - free(trunk->hash, M_VLAN); + } + epoch_call(net_epoch_preempt, &trunk->hash->epoch_ctx, vlan_hash_free); trunk->hash = hash2; trunk->hwidth = hwidth2; trunk->hmask = n2 - 1; @@ -474,9 +486,10 @@ TRUNK_RLOCK_ASSERT(trunk); - CK_SLIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list) + CK_SLIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)].head, ifv_list) { if (ifv->ifv_vid == vid) return (ifv); + } return (NULL); } @@ -490,7 +503,7 @@ for (i = 0; i < (1 << trunk->hwidth); i++) { printf("%d: ", i); - CK_SLIST_FOREACH(ifv, &trunk->hash[i], ifv_list) + CK_SLIST_FOREACH(ifv, &trunk->hash[i].head, ifv_list) printf("%s ", ifv->ifv_ifp->if_xname); printf("\n"); } @@ -540,12 +553,11 @@ #endif /* !VLAN_ARRAY */ static void -trunk_destroy(struct ifvlantrunk *trunk) +vlan_trunk_destroy(struct epoch_context *ctx) { - VLAN_XLOCK_ASSERT(); + struct ifvlantrunk *trunk = __containerof(ctx, struct ifvlantrunk, epoch_ctx); vlan_freehash(trunk); - trunk->parent->if_vlantrunk = NULL; TRUNK_LOCK_DESTROY(trunk); if_rele(trunk->parent); free(trunk, M_VLAN); @@ -1505,8 +1517,7 @@ */ if (trunk->refcnt == 0) { parent->if_vlantrunk = NULL; - NET_EPOCH_WAIT(); - trunk_destroy(trunk); + epoch_call(net_epoch_preempt, &trunk->epoch_ctx, vlan_trunk_destroy); } }