diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c index 6c66ddd..776016a 100644 --- a/sys/net/bridgestp.c +++ b/sys/net/bridgestp.c @@ -341,8 +341,7 @@ bstp_config_bpdu_generation(struct bridge_softc *sc) { struct bridge_iflist *bif; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bstp_designated_port(sc, bif) && @@ -416,8 +415,7 @@ bstp_root_selection(struct bridge_softc *sc) { struct bridge_iflist *root_port = NULL, *bif; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bstp_designated_port(sc, bif)) @@ -475,8 +473,7 @@ bstp_designated_port_selection(struct bridge_softc *sc) { struct bridge_iflist *bif; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bstp_designated_port(sc, bif)) @@ -515,8 +512,7 @@ bstp_port_state_selection(struct bridge_softc *sc) { struct bridge_iflist *bif; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bif == sc->sc_root_port) { @@ -793,8 +789,7 @@ bstp_designated_for_some_port(struct bridge_softc *sc) struct bridge_iflist *bif; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bif->bif_designated_bridge == sc->sc_bridge_id) @@ -833,8 +828,7 @@ bstp_initialization(struct bridge_softc *sc) BRIDGE_LOCK(sc); - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bif->bif_ifp->if_type != IFT_ETHER) @@ -888,8 +882,7 @@ bstp_initialization(struct bridge_softc *sc) BRIDGE_LOCK(sc); - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if (bif->bif_flags & IFBIF_STP) bstp_enable_port(sc, bif); else @@ -909,8 +902,7 @@ bstp_stop(struct bridge_softc *sc) struct bridge_iflist *bif; BRIDGE_LOCK(sc); - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED); bstp_timer_stop(&bif->bif_hold_timer); bstp_timer_stop(&bif->bif_message_age_timer); @@ -982,8 +974,7 @@ bstp_set_bridge_priority(struct bridge_softc *sc, uint64_t new_bridge_id) root = bstp_root_bridge(sc); - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bstp_designated_port(sc, bif)) @@ -1076,8 +1067,7 @@ bstp_tick(void *arg) s = splnet(); BRIDGE_LOCK(sc); - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; /* @@ -1100,8 +1090,7 @@ bstp_tick(void *arg) sc->sc_topology_change_time)) bstp_topology_change_timer_expiry(sc); - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bstp_timer_expired(&bif->bif_message_age_timer, @@ -1109,8 +1098,7 @@ bstp_tick(void *arg) bstp_message_age_timer_expiry(sc, bif); } - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { if ((bif->bif_flags & IFBIF_STP) == 0) continue; if (bstp_timer_expired(&bif->bif_forward_delay_timer, diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 6023061..a7397b6 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -197,21 +197,25 @@ __CTASSERT(offsetof(struct ifbifconf, ifbic_buf) == offsetof(struct ifbaconf, if #ifdef NET_MPSAFE -#define ACQUIRE_GLOBAL_LOCKS(s) do { s = 0; } while (0) -#define RELEASE_GLOBAL_LOCKS(s) do { (void)s; } while (0) +#define DECLARE_LOCK_VARIABLE +#define ACQUIRE_GLOBAL_LOCKS() do { } while (0) +#define RELEASE_GLOBAL_LOCKS() do { } while (0) #else -#define ACQUIRE_GLOBAL_LOCKS(s) do { \ +#define DECLARE_LOCK_VARIABLE int __s +#define ACQUIRE_GLOBAL_LOCKS() do { \ KERNEL_LOCK(1, NULL); \ mutex_enter(softnet_lock); \ - s = splnet(); \ + __s = splnet(); \ } while (0) -#define RELEASE_GLOBAL_LOCKS(s) do { \ - splx(s); \ +#define RELEASE_GLOBAL_LOCKS() do { \ + splx(__s); \ mutex_exit(softnet_lock); \ KERNEL_UNLOCK_ONE(NULL); \ } while (0) #endif +struct psref_class *bridge_psref_class __read_mostly; + int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; static struct pool bridge_rtnode_pool; @@ -254,13 +258,18 @@ static void bridge_rtnode_remove(struct bridge_softc *, static void bridge_rtnode_destroy(struct bridge_rtnode *); static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, - const char *name); + const char *name, + struct psref *); static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, - struct ifnet *ifp); -static void bridge_release_member(struct bridge_softc *, struct bridge_iflist *); + struct ifnet *ifp, + struct psref *); +static void bridge_release_member(struct bridge_softc *, struct bridge_iflist *, + struct psref *); static void bridge_delete_member(struct bridge_softc *, struct bridge_iflist *); -static struct bridge_iflist *bridge_try_hold_bif(struct bridge_iflist *); +static void bridge_acquire_member(struct bridge_softc *sc, + struct bridge_iflist *, + struct psref *); static int bridge_ioctl_add(struct bridge_softc *, void *); static int bridge_ioctl_del(struct bridge_softc *, void *); @@ -369,6 +378,8 @@ bridgeattach(int n) pool_init(&bridge_rtnode_pool, sizeof(struct bridge_rtnode), 0, 0, 0, "brtpl", NULL, IPL_NET); + bridge_psref_class = psref_class_create("bridge", IPL_SOFTNET); + if_clone_attach(&bridge_cloner); } @@ -407,10 +418,9 @@ bridge_clone_create(struct if_clone *ifc, int unit) callout_init(&sc->sc_brcallout, 0); callout_init(&sc->sc_bstpcallout, 0); - PSLIST_INIT(&sc->sc_iflist); - sc->sc_iflist_psz = pserialize_create(); - sc->sc_iflist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET); - cv_init(&sc->sc_iflist_cv, "if_bridge_cv"); + mutex_init(&sc->sc_iflist_psref.bip_lock, MUTEX_DEFAULT, IPL_NONE); + PSLIST_INIT(&sc->sc_iflist_psref.bip_iflist); + sc->sc_iflist_psref.bip_psz = pserialize_create(); if_initname(ifp, ifc->ifc_name, unit); ifp->if_softc = sc; @@ -451,13 +461,13 @@ bridge_clone_destroy(struct ifnet *ifp) BRIDGE_LOCK(sc); for (;;) { - bif = PSLIST_WRITER_FIRST(&sc->sc_iflist, struct bridge_iflist, + bif = PSLIST_WRITER_FIRST(&sc->sc_iflist_psref.bip_iflist, struct bridge_iflist, bif_next); if (bif == NULL) break; bridge_delete_member(sc, bif); } - PSLIST_DESTROY(&sc->sc_iflist); + PSLIST_DESTROY(&sc->sc_iflist_psref.bip_iflist); BRIDGE_UNLOCK(sc); splx(s); @@ -467,12 +477,8 @@ bridge_clone_destroy(struct ifnet *ifp) /* Tear down the routing table. */ bridge_rtable_fini(sc); - cv_destroy(&sc->sc_iflist_cv); - - if (sc->sc_iflist_psz) - pserialize_destroy(sc->sc_iflist_psz); - if (sc->sc_iflist_lock) - mutex_obj_free(sc->sc_iflist_lock); + pserialize_destroy(sc->sc_iflist_psref.bip_psz); + mutex_destroy(&sc->sc_iflist_psref.bip_lock); workqueue_destroy(sc->sc_rtage_wq); @@ -620,7 +626,7 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data) * Lookup a bridge member interface. */ static struct bridge_iflist * -bridge_lookup_member(struct bridge_softc *sc, const char *name) +bridge_lookup_member(struct bridge_softc *sc, const char *name, struct psref *psref) { struct bridge_iflist *bif; struct ifnet *ifp; @@ -628,13 +634,13 @@ bridge_lookup_member(struct bridge_softc *sc, const char *name) BRIDGE_PSZ_RENTER(s); - PSLIST_READER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_READER_FOREACH(bif, sc) { ifp = bif->bif_ifp; if (strcmp(ifp->if_xname, name) == 0) break; } - bif = bridge_try_hold_bif(bif); + if (bif != NULL) + bridge_acquire_member(sc, bif, psref); BRIDGE_PSZ_REXIT(s); @@ -647,7 +653,8 @@ bridge_lookup_member(struct bridge_softc *sc, const char *name) * Lookup a bridge member interface by ifnet*. */ static struct bridge_iflist * -bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) +bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp, + struct psref *psref) { struct bridge_iflist *bif; int s; @@ -655,42 +662,35 @@ bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) BRIDGE_PSZ_RENTER(s); bif = member_ifp->if_bridgeif; - bif = bridge_try_hold_bif(bif); - - BRIDGE_PSZ_REXIT(s); - - return bif; -} - -static struct bridge_iflist * -bridge_try_hold_bif(struct bridge_iflist *bif) -{ - if (bif != NULL) { - if (bif->bif_waiting) - bif = NULL; - else - atomic_inc_32(&bif->bif_refs); + psref_acquire(psref, &bif->bif_psref, + bridge_psref_class); } + + BRIDGE_PSZ_REXIT(s); + return bif; } +static void +bridge_acquire_member(struct bridge_softc *sc, struct bridge_iflist *bif, + struct psref *psref) +{ + + psref_acquire(psref, &bif->bif_psref, bridge_psref_class); +} + /* * bridge_release_member: * * Release the specified member interface. */ static void -bridge_release_member(struct bridge_softc *sc, struct bridge_iflist *bif) +bridge_release_member(struct bridge_softc *sc, struct bridge_iflist *bif, + struct psref *psref) { - uint32_t refs; - refs = atomic_dec_uint_nv(&bif->bif_refs); - if (__predict_false(refs == 0 && bif->bif_waiting)) { - BRIDGE_LOCK(sc); - cv_broadcast(&sc->sc_iflist_cv); - BRIDGE_UNLOCK(sc); - } + psref_release(psref, &bif->bif_psref, bridge_psref_class); } /* @@ -711,16 +711,10 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) PSLIST_WRITER_REMOVE(bif, bif_next); BRIDGE_PSZ_PERFORM(sc); - - bif->bif_waiting = true; - membar_sync(); - while (bif->bif_refs > 0) { - aprint_debug("%s: cv_wait on iflist\n", __func__); - cv_wait(&sc->sc_iflist_cv, sc->sc_iflist_lock); - } - bif->bif_waiting = false; BRIDGE_UNLOCK(sc); + psref_target_destroy(&bif->bif_psref, bridge_psref_class); + PSLIST_ENTRY_DESTROY(bif, bif_next); kmem_free(bif, sizeof(*bif)); @@ -777,15 +771,14 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY; bif->bif_path_cost = BSTP_DEFAULT_PATH_COST; - bif->bif_refs = 0; - bif->bif_waiting = false; PSLIST_ENTRY_INIT(bif, bif_next); + psref_target_init(&bif->bif_psref, bridge_psref_class); BRIDGE_LOCK(sc); ifs->if_bridge = sc; ifs->if_bridgeif = bif; - PSLIST_WRITER_INSERT_HEAD(&sc->sc_iflist, bif, bif_next); + PSLIST_WRITER_INSERT_HEAD(&sc->sc_iflist_psref.bip_iflist, bif, bif_next); ifs->_if_input = bridge_input; BRIDGE_UNLOCK(sc); @@ -817,8 +810,7 @@ bridge_ioctl_del(struct bridge_softc *sc, void *arg) * Don't use bridge_lookup_member. We want to get a member * with bif_refs == 0. */ - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { ifs = bif->bif_ifp; if (strcmp(ifs->if_xname, name) == 0) break; @@ -862,8 +854,9 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; + struct psref psref; - bif = bridge_lookup_member(sc, req->ifbr_ifsname); + bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); if (bif == NULL) return (ENOENT); @@ -873,7 +866,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) req->ifbr_path_cost = bif->bif_path_cost; req->ifbr_portno = bif->bif_ifp->if_index & 0xff; - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (0); } @@ -883,8 +876,9 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; + struct psref psref; - bif = bridge_lookup_member(sc, req->ifbr_ifsname); + bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); if (bif == NULL) return (ENOENT); @@ -896,14 +890,14 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) default: /* Nothing else can. */ - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (EINVAL); } } bif->bif_flags = req->ifbr_ifsflags; - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); if (sc->sc_if.if_flags & IFF_RUNNING) bstp_initialization(sc); @@ -943,8 +937,7 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) retry: BRIDGE_LOCK(sc); count = 0; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) count++; BRIDGE_UNLOCK(sc); @@ -964,8 +957,7 @@ retry: BRIDGE_LOCK(sc); i = 0; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) i++; if (i > count) { /* @@ -978,8 +970,7 @@ retry: } i = 0; - PSLIST_WRITER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { + BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { struct ifbreq *breq = &breqs[i++]; memset(breq, 0, sizeof(*breq)); @@ -1053,15 +1044,16 @@ bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) struct ifbareq *req = arg; struct bridge_iflist *bif; int error; + struct psref psref; - bif = bridge_lookup_member(sc, req->ifba_ifsname); + bif = bridge_lookup_member(sc, req->ifba_ifsname, &psref); if (bif == NULL) return (ENOENT); error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1, req->ifba_flags); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (error); } @@ -1207,8 +1199,9 @@ bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; + struct psref psref; - bif = bridge_lookup_member(sc, req->ifbr_ifsname); + bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); if (bif == NULL) return (ENOENT); @@ -1217,7 +1210,7 @@ bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) if (sc->sc_if.if_flags & IFF_RUNNING) bstp_initialization(sc); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (0); } @@ -1265,8 +1258,9 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; + struct psref psref; - bif = bridge_lookup_member(sc, req->ifbr_ifsname); + bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); if (bif == NULL) return (ENOENT); @@ -1275,7 +1269,7 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) if (sc->sc_if.if_flags & IFF_RUNNING) bstp_initialization(sc); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (0); } @@ -1463,11 +1457,10 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, int used = 0; BRIDGE_PSZ_RENTER(s); - PSLIST_READER_FOREACH(bif, &sc->sc_iflist, - struct bridge_iflist, bif_next) { - bif = bridge_try_hold_bif(bif); - if (bif == NULL) - continue; + BRIDGE_IFLIST_READER_FOREACH(bif, sc) { + struct psref psref; + + bridge_acquire_member(sc, bif, &psref); BRIDGE_PSZ_REXIT(s); dst_if = bif->bif_ifp; @@ -1510,8 +1503,8 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, splx(s); #endif next: - bridge_release_member(sc, bif); BRIDGE_PSZ_RENTER(s); + bridge_release_member(sc, bif, &psref); } BRIDGE_PSZ_REXIT(s); @@ -1566,7 +1559,8 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) struct bridge_iflist *bif; struct ifnet *src_if, *dst_if; struct ether_header *eh; - int s; + struct psref psref; + DECLARE_LOCK_VARIABLE; if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) return; @@ -1579,7 +1573,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) /* * Look up the bridge_iflist. */ - bif = bridge_lookup_member_if(sc, src_if); + bif = bridge_lookup_member_if(sc, src_if, &psref); if (bif == NULL) { /* Interface is not a bridge member (anymore?) */ m_freem(m); @@ -1592,7 +1586,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) case BSTP_IFSTATE_LISTENING: case BSTP_IFSTATE_DISABLED: m_freem(m); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); goto out; } } @@ -1619,11 +1613,11 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) if ((bif->bif_flags & IFBIF_STP) != 0 && bif->bif_state == BSTP_IFSTATE_LEARNING) { m_freem(m); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); goto out; } - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); /* * At this point, the port either doesn't participate @@ -1669,7 +1663,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) goto out; } - bif = bridge_lookup_member_if(sc, dst_if); + bif = bridge_lookup_member_if(sc, dst_if, &psref); if (bif == NULL) { /* Not a member of the bridge (anymore?) */ m_freem(m); @@ -1681,16 +1675,16 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) case BSTP_IFSTATE_DISABLED: case BSTP_IFSTATE_BLOCKING: m_freem(m); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); goto out; } } - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); - ACQUIRE_GLOBAL_LOCKS(s); + ACQUIRE_GLOBAL_LOCKS(); bridge_enqueue(sc, dst_if, m, 1); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); out: /* XXX gcc */ return; @@ -1739,22 +1733,24 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) struct bridge_iflist *bif; struct ether_header *eh; int s; + struct psref psref; + DECLARE_LOCK_VARIABLE; KASSERT(!cpu_intr_p()); if (__predict_false(sc == NULL) || (sc->sc_if.if_flags & IFF_RUNNING) == 0) { - ACQUIRE_GLOBAL_LOCKS(s); + ACQUIRE_GLOBAL_LOCKS(); ether_input(ifp, m); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); return; } - bif = bridge_lookup_member_if(sc, ifp); + bif = bridge_lookup_member_if(sc, ifp, &psref); if (bif == NULL) { - ACQUIRE_GLOBAL_LOCKS(s); + ACQUIRE_GLOBAL_LOCKS(); ether_input(ifp, m); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); return; } @@ -1776,13 +1772,13 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) !bstp_state_before_learning(bif)) { struct bridge_iflist *_bif; struct ifnet *_ifp = NULL; + struct psref _psref; BRIDGE_PSZ_RENTER(s); - PSLIST_READER_FOREACH(_bif, &sc->sc_iflist, - struct bridge_iflist, bif_next) { + BRIDGE_IFLIST_READER_FOREACH(_bif, sc) { /* It is destined for us. */ if (bridge_ourether(_bif, eh, 0)) { - _bif = bridge_try_hold_bif(_bif); + bridge_acquire_member(sc, _bif, &_psref); BRIDGE_PSZ_REXIT(s); if (_bif == NULL) goto out; @@ -1790,7 +1786,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) (void) bridge_rtupdate(sc, eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); _ifp = m->m_pkthdr.rcvif = _bif->bif_ifp; - bridge_release_member(sc, _bif); + bridge_release_member(sc, _bif, &_psref); goto out; } @@ -1802,12 +1798,12 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) out: if (_bif != NULL) { - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); if (_ifp != NULL) { m->m_flags &= ~M_PROMISC; - ACQUIRE_GLOBAL_LOCKS(s); + ACQUIRE_GLOBAL_LOCKS(); ether_input(_ifp, m); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); } else m_freem(m); return; @@ -1818,7 +1814,7 @@ out: if (bif->bif_flags & IFBIF_STP && memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) { bstp_input(sc, bif, m); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return; } @@ -1827,14 +1823,14 @@ out: * we've done historically. This also prevents some obnoxious behaviour. */ if (bstp_state_before_learning(bif)) { - bridge_release_member(sc, bif); - ACQUIRE_GLOBAL_LOCKS(s); + bridge_release_member(sc, bif, &psref); + ACQUIRE_GLOBAL_LOCKS(); ether_input(ifp, m); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); return; } - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); bridge_forward(sc, m); } @@ -1855,15 +1851,15 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, struct ifnet *dst_if; bool bmcast; int s; + DECLARE_LOCK_VARIABLE; bmcast = m->m_flags & (M_BCAST|M_MCAST); BRIDGE_PSZ_RENTER(s); - PSLIST_READER_FOREACH(bif, &sc->sc_iflist, struct bridge_iflist, - bif_next) { - bif = bridge_try_hold_bif(bif); - if (bif == NULL) - continue; + BRIDGE_IFLIST_READER_FOREACH(bif, sc) { + struct psref psref; + + bridge_acquire_member(sc, bif, &psref); BRIDGE_PSZ_REXIT(s); dst_if = bif->bif_ifp; @@ -1888,9 +1884,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, sc->sc_if.if_oerrors++; goto next; } - ACQUIRE_GLOBAL_LOCKS(s); + ACQUIRE_GLOBAL_LOCKS(); bridge_enqueue(sc, dst_if, mc, 1); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); } if (bmcast) { @@ -1903,13 +1899,13 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, mc->m_pkthdr.rcvif = dst_if; mc->m_flags &= ~M_PROMISC; - ACQUIRE_GLOBAL_LOCKS(s); + ACQUIRE_GLOBAL_LOCKS(); ether_input(dst_if, mc); - RELEASE_GLOBAL_LOCKS(s); + RELEASE_GLOBAL_LOCKS(); } next: - bridge_release_member(sc, bif); BRIDGE_PSZ_RENTER(s); + bridge_release_member(sc, bif, &psref); } BRIDGE_PSZ_REXIT(s); diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h index aa6bb98..9fba1ff 100644 --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -215,6 +215,7 @@ struct ifbrparam { #include #include +#include #include #include @@ -267,8 +268,7 @@ struct bridge_iflist { uint8_t bif_priority; struct ifnet *bif_ifp; /* member if */ uint32_t bif_flags; /* member if flags */ - uint32_t bif_refs; /* reference count */ - bool bif_waiting; /* waiting for released */ + struct psref_target bif_psref; }; /* @@ -283,6 +283,12 @@ struct bridge_rtnode { uint8_t brt_addr[ETHER_ADDR_LEN]; }; +struct bridge_iflist_psref { + struct pslist_head bip_iflist; /* member interface list */ + kmutex_t bip_lock; + pserialize_t bip_psz; +}; + /* * Software state for each bridge. */ @@ -312,10 +318,7 @@ struct bridge_softc { uint32_t sc_brttimeout; /* rt timeout in seconds */ callout_t sc_brcallout; /* bridge callout */ callout_t sc_bstpcallout; /* STP callout */ - struct pslist_head sc_iflist; /* member interface list */ - kcondvar_t sc_iflist_cv; - pserialize_t sc_iflist_psz; - kmutex_t *sc_iflist_lock; + struct bridge_iflist_psref sc_iflist_psref; LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ kmutex_t *sc_rtlist_lock; @@ -340,13 +343,20 @@ void bstp_input(struct bridge_softc *, struct bridge_iflist *, struct mbuf *); void bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *, int); -#define BRIDGE_LOCK(_sc) mutex_enter((_sc)->sc_iflist_lock) -#define BRIDGE_UNLOCK(_sc) mutex_exit((_sc)->sc_iflist_lock) -#define BRIDGE_LOCKED(_sc) mutex_owned((_sc)->sc_iflist_lock) +#define BRIDGE_LOCK(_sc) mutex_enter(&(_sc)->sc_iflist_psref.bip_lock) +#define BRIDGE_UNLOCK(_sc) mutex_exit(&(_sc)->sc_iflist_psref.bip_lock) +#define BRIDGE_LOCKED(_sc) mutex_owned(&(_sc)->sc_iflist_psref.bip_lock) #define BRIDGE_PSZ_RENTER(__s) do { __s = pserialize_read_enter(); } while (0) #define BRIDGE_PSZ_REXIT(__s) do { pserialize_read_exit(__s); } while (0) -#define BRIDGE_PSZ_PERFORM(_sc) pserialize_perform((_sc)->sc_iflist_psz) +#define BRIDGE_PSZ_PERFORM(_sc) pserialize_perform((_sc)->sc_iflist_psref.bip_psz) + +#define BRIDGE_IFLIST_READER_FOREACH(_bif, _sc) \ + PSLIST_READER_FOREACH((_bif), &((_sc)->sc_iflist_psref.bip_iflist), \ + struct bridge_iflist, bif_next) +#define BRIDGE_IFLIST_WRITER_FOREACH(_bif, _sc) \ + PSLIST_WRITER_FOREACH((_bif), &((_sc)->sc_iflist_psref.bip_iflist), \ + struct bridge_iflist, bif_next) /* * Locking notes: