commit ff2fd294dc292673f8fd8e69551b373c8adf28c2 Author: Ryota Ozaki Date: Tue Apr 12 19:08:45 2016 +0900 Use psref for bridge 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..86ca7c3 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -254,13 +254,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 struct bridge_iflist *bridge_try_hold_bif(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 *); @@ -395,6 +400,7 @@ bridge_clone_create(struct if_clone *ifc, int unit) sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY; sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME; sc->sc_filter_flags = 0; + sc->sc_dying = false; /* Initialize our routing table. */ bridge_rtable_init(sc); @@ -407,10 +413,14 @@ 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 (sc->sc_iflist_psref.bip_psz == NULL) + panic("%s: pserialize_create %d\n", __func__, error); + + sc->sc_iflist_psref.bip_class = + psref_class_create("if_bridge_cv", IPL_SOFTNET); if_initname(ifp, ifc->ifc_name, unit); ifp->if_softc = sc; @@ -447,17 +457,18 @@ bridge_clone_destroy(struct ifnet *ifp) s = splnet(); + sc->sc_dying = true; bridge_stop(ifp, 1); 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 +478,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 +627,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 +635,12 @@ 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); + bif = bridge_try_hold_bif(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,7 +662,10 @@ 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); + if (bif != NULL) { + psref_acquire(psref, &bif->bif_psref, + sc->sc_iflist_psref.bip_class); + } BRIDGE_PSZ_REXIT(s); @@ -663,14 +673,13 @@ bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) } static struct bridge_iflist * -bridge_try_hold_bif(struct bridge_iflist *bif) +bridge_try_hold_bif(struct bridge_softc *sc, struct bridge_iflist *bif, + struct psref *psref) { if (bif != NULL) { - if (bif->bif_waiting) - bif = NULL; - else - atomic_inc_32(&bif->bif_refs); + psref_acquire(psref, &bif->bif_psref, + sc->sc_iflist_psref.bip_class); } return bif; } @@ -681,16 +690,11 @@ bridge_try_hold_bif(struct bridge_iflist *bif) * 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, sc->sc_iflist_psref.bip_class); } /* @@ -711,16 +715,11 @@ 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, + sc->sc_iflist_psref.bip_class); + PSLIST_ENTRY_DESTROY(bif, bif_next); kmem_free(bif, sizeof(*bif)); @@ -735,6 +734,9 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) struct ifnet *ifs; int error = 0; + if (sc->sc_dying) + return ENOENT; + ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) return (ENOENT); @@ -777,15 +779,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, sc->sc_iflist_psref.bip_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 +818,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 +862,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 +874,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 +884,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 +898,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 +945,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 +965,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 +978,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 +1052,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 +1207,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 +1218,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 +1266,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 +1277,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,9 +1465,9 @@ 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); + BRIDGE_IFLIST_READER_FOREACH(bif, sc) { + struct psref psref; + bif = bridge_try_hold_bif(sc, bif, &psref); if (bif == NULL) continue; BRIDGE_PSZ_REXIT(s); @@ -1510,8 +1512,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); @@ -1567,6 +1569,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) struct ifnet *src_if, *dst_if; struct ether_header *eh; int s; + struct psref psref; if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) return; @@ -1579,7 +1582,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 +1595,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 +1622,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 +1672,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,12 +1684,12 @@ 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); bridge_enqueue(sc, dst_if, m, 1); @@ -1739,6 +1742,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) struct bridge_iflist *bif; struct ether_header *eh; int s; + struct psref psref; KASSERT(!cpu_intr_p()); @@ -1750,7 +1754,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) return; } - bif = bridge_lookup_member_if(sc, ifp); + bif = bridge_lookup_member_if(sc, ifp, &psref); if (bif == NULL) { ACQUIRE_GLOBAL_LOCKS(s); ether_input(ifp, m); @@ -1776,13 +1780,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); + _bif = bridge_try_hold_bif(sc, _bif, &_psref); BRIDGE_PSZ_REXIT(s); if (_bif == NULL) goto out; @@ -1790,7 +1794,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,7 +1806,7 @@ 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); @@ -1818,7 +1822,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 +1831,14 @@ out: * we've done historically. This also prevents some obnoxious behaviour. */ if (bstp_state_before_learning(bif)) { - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); ACQUIRE_GLOBAL_LOCKS(s); ether_input(ifp, m); RELEASE_GLOBAL_LOCKS(s); return; } - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); bridge_forward(sc, m); } @@ -1859,9 +1863,10 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, 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); + BRIDGE_IFLIST_READER_FOREACH(bif, sc) { + struct psref psref; + + bif = bridge_try_hold_bif(sc, bif, &psref); if (bif == NULL) continue; BRIDGE_PSZ_REXIT(s); @@ -1908,8 +1913,8 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, RELEASE_GLOBAL_LOCKS(s); } 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..7e8bb9c 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,13 @@ 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; + struct psref_class *bip_class; +}; + /* * Software state for each bridge. */ @@ -312,10 +319,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; @@ -324,6 +328,7 @@ struct bridge_softc { struct work sc_rtage_wk; uint32_t sc_rthash_key; /* key for hash */ uint32_t sc_filter_flags; /* ipf and flags */ + bool sc_dying; /* being destroyed */ }; extern const uint8_t bstp_etheraddr[]; @@ -340,13 +345,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: