Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -411,7 +411,7 @@ #define NET_EPOCH_ENTER_ET(et) epoch_enter_preempt(net_epoch_preempt, &(et)) #define NET_EPOCH_EXIT() epoch_exit_preempt(net_epoch_preempt, &nep_et) #define NET_EPOCH_EXIT_ET(et) epoch_exit_preempt(net_epoch_preempt, &(et)) - +#define NET_EPOCH_WAIT() epoch_wait_preempt(net_epoch_preempt) /* * Function variations on locking macros intended to be used by loadable Index: sys/net/if_vlan.c =================================================================== --- sys/net/if_vlan.c +++ sys/net/if_vlan.c @@ -87,11 +87,11 @@ #define UP_AND_RUNNING(ifp) \ ((ifp)->if_flags & IFF_UP && (ifp)->if_drv_flags & IFF_DRV_RUNNING) -LIST_HEAD(ifvlanhead, ifvlan); +CK_SLIST_HEAD(ifvlanhead, ifvlan); struct ifvlantrunk { struct ifnet *parent; /* parent interface of this trunk */ - struct rmlock lock; + struct mtx lock; #ifdef VLAN_ARRAY #define VLAN_ARRAY_SIZE (EVL_VLID_MASK + 1) struct ifvlan *vlans[VLAN_ARRAY_SIZE]; /* static table */ @@ -117,7 +117,7 @@ struct ifvlan *_next; \ size_t _i; \ for (_i = 0; _i < (1 << (_trunk)->hwidth); _i++) \ - LIST_FOREACH_SAFE((_ifv), &(_trunk)->hash[_i], ifv_list, _next) + CK_SLIST_FOREACH_SAFE((_ifv), &(_trunk)->hash[_i], ifv_list, _next) #endif /* VLAN_ARRAY */ /* @@ -146,13 +146,13 @@ for (_i = 0; \ !(_cond) && _i < (1 << (_trunk)->hwidth); \ _i = (_touch && ((_trunk) != NULL) ? 0 : _i + 1), _touch = false) \ - if (((_ifv) = LIST_FIRST(&(_trunk)->hash[_i])) != NULL && \ + if (((_ifv) = CK_SLIST_FIRST(&(_trunk)->hash[_i])) != NULL && \ (_touch = true)) #endif /* VLAN_ARRAY */ struct vlan_mc_entry { struct sockaddr_dl mc_addr; - SLIST_ENTRY(vlan_mc_entry) mc_entries; + CK_SLIST_ENTRY(vlan_mc_entry) mc_entries; }; struct ifvlan { @@ -173,9 +173,9 @@ uint8_t ifvm_pcp; /* Priority Code Point (PCP). */ } ifv_mib; struct task lladdr_task; - SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; + CK_SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; #ifndef VLAN_ARRAY - LIST_ENTRY(ifvlan) ifv_list; + CK_SLIST_ENTRY(ifvlan) ifv_list; #endif }; #define ifv_proto ifv_mib.ifvm_proto @@ -229,31 +229,19 @@ * freed/reused when the tx/rx functions are called by the stack. This can only * be fixed by addressing ifnet's lifetime issues. */ -#define _VLAN_RM_ID ifv_rm_lock #define _VLAN_SX_ID ifv_sx -static struct rmlock _VLAN_RM_ID; static struct sx _VLAN_SX_ID; #define VLAN_LOCKING_INIT() \ - rm_init(&_VLAN_RM_ID, "vlan_rm"); \ sx_init(&_VLAN_SX_ID, "vlan_sx") #define VLAN_LOCKING_DESTROY() \ - rm_destroy(&_VLAN_RM_ID); \ sx_destroy(&_VLAN_SX_ID) -#define _VLAN_RM_TRACKER _vlan_rm_tracker -#define VLAN_RLOCK() rm_rlock(&_VLAN_RM_ID, \ - &_VLAN_RM_TRACKER) -#define VLAN_RUNLOCK() rm_runlock(&_VLAN_RM_ID, \ - &_VLAN_RM_TRACKER) -#define VLAN_WLOCK() rm_wlock(&_VLAN_RM_ID) -#define VLAN_WUNLOCK() rm_wunlock(&_VLAN_RM_ID) -#define VLAN_RLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_RLOCKED) -#define VLAN_WLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_WLOCKED) -#define VLAN_RWLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_LOCKED) -#define VLAN_LOCK_READER struct rm_priotracker _VLAN_RM_TRACKER +#define VLAN_RLOCK() NET_EPOCH_ENTER(); +#define VLAN_RUNLOCK() NET_EPOCH_EXIT(); +#define VLAN_RLOCK_ASSERT() MPASS(in_epoch(net_epoch_preempt)) #define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) #define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) @@ -271,19 +259,15 @@ * via VLAN_SLOCK or VLAN_RLOCK. Thus, an exclusive lock on the global locks * makes a call to TRUNK_RLOCK/TRUNK_WLOCK technically superfluous. */ -#define _TRUNK_RM_TRACKER _trunk_rm_tracker -#define TRUNK_LOCK_INIT(trunk) rm_init(&(trunk)->lock, vlanname) -#define TRUNK_LOCK_DESTROY(trunk) rm_destroy(&(trunk)->lock) -#define TRUNK_RLOCK(trunk) rm_rlock(&(trunk)->lock, \ - &_TRUNK_RM_TRACKER) -#define TRUNK_WLOCK(trunk) rm_wlock(&(trunk)->lock) -#define TRUNK_RUNLOCK(trunk) rm_runlock(&(trunk)->lock, \ - &_TRUNK_RM_TRACKER) -#define TRUNK_WUNLOCK(trunk) rm_wunlock(&(trunk)->lock) -#define TRUNK_RLOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_RLOCKED) -#define TRUNK_LOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_LOCKED) -#define TRUNK_WLOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_WLOCKED) -#define TRUNK_LOCK_READER struct rm_priotracker _TRUNK_RM_TRACKER +#define TRUNK_LOCK_INIT(trunk) mtx_init(&(trunk)->lock, vlanname, NULL, MTX_DEF) +#define TRUNK_LOCK_DESTROY(trunk) mtx_destroy(&(trunk)->lock) +#define TRUNK_RLOCK(trunk) NET_EPOCH_ENTER() +#define TRUNK_WLOCK(trunk) mtx_lock(&(trunk)->lock) +#define TRUNK_RUNLOCK(trunk) NET_EPOCH_EXIT(); +#define TRUNK_WUNLOCK(trunk) mtx_unlock(&(trunk)->lock) +#define TRUNK_RLOCK_ASSERT(trunk) MPASS(in_epoch(net_epoch_preempt)) +#define TRUNK_LOCK_ASSERT(trunk) MPASS(in_epoch(net_epoch_preempt) || mtx_owned(&(trunk)->lock)) +#define TRUNK_WLOCK_ASSERT(trunk) mtx_assert(&(trunk)->lock, MA_OWNED); /* * The VLAN_ARRAY substitutes the dynamic hash with a static array @@ -361,7 +345,7 @@ trunk->hmask = n - 1; trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK); for (i = 0; i < n; i++) - LIST_INIT(&trunk->hash[i]); + CK_SLIST_INIT(&trunk->hash[i]); } static void @@ -372,7 +356,7 @@ KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); for (i = 0; i < (1 << trunk->hwidth); i++) - KASSERT(LIST_EMPTY(&trunk->hash[i]), + KASSERT(CK_SLIST_EMPTY(&trunk->hash[i]), ("%s: hash table not empty", __func__)); #endif free(trunk->hash, M_VLAN); @@ -391,7 +375,7 @@ b = 1 << trunk->hwidth; i = HASH(ifv->ifv_vid, trunk->hmask); - LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) + CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) if (ifv->ifv_vid == ifv2->ifv_vid) return (EEXIST); @@ -404,7 +388,7 @@ vlan_growhash(trunk, 1); i = HASH(ifv->ifv_vid, trunk->hmask); } - LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list); + CK_SLIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list); trunk->refcnt++; return (0); @@ -421,10 +405,10 @@ b = 1 << trunk->hwidth; i = HASH(ifv->ifv_vid, trunk->hmask); - LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) + CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) if (ifv2 == ifv) { trunk->refcnt--; - LIST_REMOVE(ifv2, ifv_list); + CK_SLIST_REMOVE(&trunk->hash[i], ifv2, ifvlan, ifv_list); if (trunk->refcnt < (b * b) / 2) vlan_growhash(trunk, -1); return (0); @@ -468,13 +452,14 @@ return; /* We can live with the old hash table */ } for (j = 0; j < n2; j++) - LIST_INIT(&hash2[j]); + CK_SLIST_INIT(&hash2[j]); for (i = 0; i < n; i++) - while ((ifv = LIST_FIRST(&trunk->hash[i])) != NULL) { - LIST_REMOVE(ifv, ifv_list); + while ((ifv = CK_SLIST_FIRST(&trunk->hash[i])) != NULL) { + CK_SLIST_REMOVE(&trunk->hash[i], ifv, ifvlan, ifv_list); j = HASH(ifv->ifv_vid, n2 - 1); - LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list); + CK_SLIST_INSERT_HEAD(&hash2[j], ifv, ifv_list); } + NET_EPOCH_WAIT(); free(trunk->hash, M_VLAN); trunk->hash = hash2; trunk->hwidth = hwidth2; @@ -492,7 +477,7 @@ TRUNK_RLOCK_ASSERT(trunk); - LIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list) + CK_SLIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list) if (ifv->ifv_vid == vid) return (ifv); return (NULL); @@ -508,7 +493,7 @@ for (i = 0; i < (1 << trunk->hwidth); i++) { printf("%d: ", i); - LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) + CK_SLIST_FOREACH(ifv, &trunk->hash[i], ifv_list) printf("%s ", ifv->ifv_ifp->if_xname); printf("\n"); } @@ -561,7 +546,6 @@ trunk_destroy(struct ifvlantrunk *trunk) { VLAN_XLOCK_ASSERT(); - VLAN_WLOCK_ASSERT(); vlan_freehash(trunk); trunk->parent->if_vlantrunk = NULL; @@ -591,19 +575,19 @@ * XXX This stupidly needs the rmlock to avoid sleeping while holding * the in6_multi_mtx (see in6_mc_join_locked). */ - VLAN_RWLOCK_ASSERT(); + VLAN_XLOCK_ASSERT(); /* Find the parent. */ sc = ifp->if_softc; - TRUNK_WLOCK_ASSERT(TRUNK(sc)); ifp_p = PARENT(sc); CURVNET_SET_QUIET(ifp_p->if_vnet); /* First, remove any existing filter entries. */ - while ((mc = SLIST_FIRST(&sc->vlan_mc_listhead)) != NULL) { - SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); + while ((mc = CK_SLIST_FIRST(&sc->vlan_mc_listhead)) != NULL) { + CK_SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); (void)if_delmulti(ifp_p, (struct sockaddr *)&mc->mc_addr); + NET_EPOCH_WAIT(); free(mc, M_VLAN); } @@ -619,10 +603,10 @@ } bcopy(ifma->ifma_addr, &mc->mc_addr, ifma->ifma_addr->sa_len); mc->mc_addr.sdl_index = ifp_p->if_index; - SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); + CK_SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); } IF_ADDR_WUNLOCK(ifp); - SLIST_FOREACH (mc, &sc->vlan_mc_listhead, mc_entries) { + CK_SLIST_FOREACH (mc, &sc->vlan_mc_listhead, mc_entries) { error = if_addmulti(ifp_p, (struct sockaddr *)&mc->mc_addr, NULL); if (error) @@ -645,7 +629,6 @@ struct ifnet *ifv_ifp; struct ifvlantrunk *trunk; struct sockaddr_dl *sdl; - VLAN_LOCK_READER; /* Need the rmlock since this is run on taskqueue_swi. */ VLAN_RLOCK(); @@ -724,7 +707,6 @@ vlan_trunkdev(struct ifnet *ifp) { struct ifvlan *ifv; - VLAN_LOCK_READER; if (ifp->if_type != IFT_L2VLAN) return (NULL); @@ -809,8 +791,6 @@ { struct ifvlantrunk *trunk; struct ifvlan *ifv; - VLAN_LOCK_READER; - TRUNK_LOCK_READER; /* Not clear if callers are sleepable, so acquire the rmlock. */ VLAN_RLOCK(); @@ -820,11 +800,9 @@ return (NULL); } ifp = NULL; - TRUNK_RLOCK(trunk); ifv = vlan_gethash(trunk, vid); if (ifv) ifp = ifv->ifv_ifp; - TRUNK_RUNLOCK(trunk); VLAN_RUNLOCK(); return (ifp); } @@ -1076,7 +1054,7 @@ if_rele(p); return (ENOSPC); } - SLIST_INIT(&ifv->vlan_mc_listhead); + CK_SLIST_INIT(&ifv->vlan_mc_listhead); ifp->if_softc = ifv; /* * Set the name manually rather than using if_initname because @@ -1167,7 +1145,6 @@ struct ifvlan *ifv; struct ifnet *p; int error, len, mcast; - VLAN_LOCK_READER; VLAN_RLOCK(); ifv = ifp->if_softc; @@ -1227,8 +1204,6 @@ { struct ifvlantrunk *trunk; struct ifvlan *ifv; - VLAN_LOCK_READER; - TRUNK_LOCK_READER; struct m_tag *mtag; uint16_t vid, tag; @@ -1289,16 +1264,13 @@ vid = EVL_VLANOFTAG(tag); - TRUNK_RLOCK(trunk); ifv = vlan_gethash(trunk, vid); if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) { - TRUNK_RUNLOCK(trunk); - if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); VLAN_RUNLOCK(); + if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); m_freem(m); return; } - TRUNK_RUNLOCK(trunk); if (vlan_mtag_pcp) { /* @@ -1376,13 +1348,11 @@ M_VLAN, M_WAITOK | M_ZERO); vlan_inithash(trunk); TRUNK_LOCK_INIT(trunk); - VLAN_WLOCK(); TRUNK_WLOCK(trunk); p->if_vlantrunk = trunk; trunk->parent = p; if_ref(trunk->parent); } else { - VLAN_WLOCK(); trunk = p->if_vlantrunk; TRUNK_WLOCK(trunk); } @@ -1391,8 +1361,10 @@ ifv->ifv_pcp = 0; /* Default: best effort delivery. */ vlan_tag_recalculate(ifv); error = vlan_inshash(trunk, ifv); - if (error) + if (error) { + TRUNK_WUNLOCK(trunk); goto done; + } ifv->ifv_proto = ETHERTYPE_VLAN; ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; ifv->ifv_mintu = ETHERMIN; @@ -1458,12 +1430,6 @@ ((struct sockaddr_dl *)ifp->if_addr->ifa_addr)->sdl_alen = p->if_addrlen; - /* - * Configure multicast addresses that may already be - * joined on the vlan device. - */ - (void)vlan_setmulti(ifp); - TASK_INIT(&ifv->lladdr_task, 0, vlan_lladdr_fn, ifv); /* We are ready for operation now. */ @@ -1471,13 +1437,14 @@ /* Update flags on the parent, if necessary. */ vlan_setflags(ifp, 1); -done: + TRUNK_WUNLOCK(trunk); /* - * We need to drop the non-sleepable rmlock so that the underlying - * devices can sleep in their vlan_config hooks. + * Configure multicast addresses that may already be + * joined on the vlan device. */ - TRUNK_WUNLOCK(trunk); - VLAN_WUNLOCK(); + (void)vlan_setmulti(ifp); + +done: if (error == 0) EVENTHANDLER_INVOKE(vlan_config, p, ifv->ifv_vid); VLAN_XUNLOCK(); @@ -1516,7 +1483,6 @@ * an exclusive lock here to prevent them from using bad * ifvlans. */ - VLAN_WLOCK(); parent = trunk->parent; /* @@ -1524,7 +1490,7 @@ * empty the list of multicast groups that we may have joined * while we were alive from the parent's list. */ - while ((mc = SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { + while ((mc = CK_SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { /* * If the parent interface is being detached, * all its multicast addresses have already @@ -1541,7 +1507,7 @@ "Failed to delete multicast address from parent: %d\n", error); } - SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); + CK_SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); free(mc, M_VLAN); } @@ -1561,9 +1527,9 @@ */ if (trunk->refcnt == 0) { parent->if_vlantrunk = NULL; + NET_EPOCH_WAIT(); trunk_destroy(trunk); } - VLAN_WUNLOCK(); } /* Disconnect from parent. */ @@ -1640,7 +1606,6 @@ { struct ifvlantrunk *trunk; struct ifvlan *ifv; - VLAN_LOCK_READER; /* Called from a taskqueue_swi task, so we cannot sleep. */ VLAN_RLOCK(); @@ -1789,7 +1754,6 @@ struct ifvlantrunk *trunk; struct vlanreq vlr; int error = 0; - VLAN_LOCK_READER; ifr = (struct ifreq *)data; ifa = (struct ifaddr *) data; @@ -1925,16 +1889,13 @@ * XXX We need the rmlock here to avoid sleeping while * holding in6_multi_mtx. */ - VLAN_RLOCK(); + VLAN_XLOCK(); trunk = TRUNK(ifv); - if (trunk != NULL) { - TRUNK_WLOCK(trunk); + if (trunk != NULL) error = vlan_setmulti(ifp); - TRUNK_WUNLOCK(trunk); - } - VLAN_RUNLOCK(); - break; + VLAN_XUNLOCK(); + break; case SIOCGVLANPCP: #ifdef VIMAGE if (ifp->if_vnet != ifp->if_home_vnet) {