Module Name: src Committed By: ozaki-r Date: Tue Apr 19 07:10:22 UTC 2016
Modified Files: src/sys/net: bridgestp.c if_bridge.c if_bridgevar.h Log Message: Apply psref(9) to bridge(4) Note that there is an issue that ioctls for an interface and a destruction of the interface can run in parallel and it causes race conditions on bridge as well (it rarely happens). The issue will be addressed in the interface common code (if.c). To generate a diff of this commit: cvs rdiff -u -r1.21 -r1.22 src/sys/net/bridgestp.c cvs rdiff -u -r1.114 -r1.115 src/sys/net/if_bridge.c cvs rdiff -u -r1.29 -r1.30 src/sys/net/if_bridgevar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/bridgestp.c diff -u src/sys/net/bridgestp.c:1.21 src/sys/net/bridgestp.c:1.22 --- src/sys/net/bridgestp.c:1.21 Mon Apr 11 05:40:47 2016 +++ src/sys/net/bridgestp.c Tue Apr 19 07:10:22 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: bridgestp.c,v 1.21 2016/04/11 05:40:47 ozaki-r Exp $ */ +/* $NetBSD: bridgestp.c,v 1.22 2016/04/19 07:10:22 ozaki-r Exp $ */ /* * Copyright (c) 2000 Jason L. Wright (ja...@thought.net) @@ -40,7 +40,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: bridgestp.c,v 1.21 2016/04/11 05:40:47 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: bridgestp.c,v 1.22 2016/04/19 07:10:22 ozaki-r Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -341,8 +341,7 @@ bstp_config_bpdu_generation(struct bridg { 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 { 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 br { 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_ { 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 bri 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 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 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_s 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, Index: src/sys/net/if_bridge.c diff -u src/sys/net/if_bridge.c:1.114 src/sys/net/if_bridge.c:1.115 --- src/sys/net/if_bridge.c:1.114 Tue Apr 19 07:03:12 2016 +++ src/sys/net/if_bridge.c Tue Apr 19 07:10:22 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bridge.c,v 1.114 2016/04/19 07:03:12 ozaki-r Exp $ */ +/* $NetBSD: if_bridge.c,v 1.115 2016/04/19 07:10:22 ozaki-r Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -80,7 +80,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.114 2016/04/19 07:03:12 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.115 2016/04/19 07:10:22 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_bridge_ipf.h" @@ -214,6 +214,8 @@ __CTASSERT(offsetof(struct ifbifconf, if } 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; @@ -256,13 +258,18 @@ static void bridge_rtnode_remove(struct 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 *); @@ -371,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); } @@ -409,10 +418,9 @@ bridge_clone_create(struct if_clone *ifc 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; @@ -453,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); @@ -469,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); @@ -622,7 +626,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c * 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; @@ -630,13 +634,13 @@ bridge_lookup_member(struct bridge_softc 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); @@ -649,7 +653,8 @@ bridge_lookup_member(struct bridge_softc * 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; @@ -657,24 +662,22 @@ bridge_lookup_member_if(struct bridge_so BRIDGE_PSZ_RENTER(s); bif = member_ifp->if_bridgeif; - bif = bridge_try_hold_bif(bif); + if (bif != NULL) { + psref_acquire(psref, &bif->bif_psref, + bridge_psref_class); + } BRIDGE_PSZ_REXIT(s); return bif; } -static struct bridge_iflist * -bridge_try_hold_bif(struct bridge_iflist *bif) +static void +bridge_acquire_member(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); - } - return bif; + psref_acquire(psref, &bif->bif_psref, bridge_psref_class); } /* @@ -683,16 +686,11 @@ bridge_try_hold_bif(struct bridge_iflist * 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); } /* @@ -713,16 +711,10 @@ bridge_delete_member(struct bridge_softc 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)); @@ -779,15 +771,14 @@ bridge_ioctl_add(struct bridge_softc *sc 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); @@ -819,8 +810,7 @@ bridge_ioctl_del(struct bridge_softc *sc * 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; @@ -864,8 +854,9 @@ bridge_ioctl_gifflags(struct bridge_soft { 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); @@ -875,7 +866,7 @@ bridge_ioctl_gifflags(struct bridge_soft 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); } @@ -885,8 +876,9 @@ bridge_ioctl_sifflags(struct bridge_soft { 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); @@ -898,14 +890,14 @@ bridge_ioctl_sifflags(struct bridge_soft 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); @@ -945,8 +937,7 @@ bridge_ioctl_gifs(struct bridge_softc *s 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); @@ -966,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) { /* @@ -980,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)); @@ -1055,15 +1044,16 @@ bridge_ioctl_saddr(struct bridge_softc * 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); } @@ -1209,8 +1199,9 @@ bridge_ioctl_sifprio(struct bridge_softc { 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); @@ -1219,7 +1210,7 @@ bridge_ioctl_sifprio(struct bridge_softc if (sc->sc_if.if_flags & IFF_RUNNING) bstp_initialization(sc); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (0); } @@ -1267,8 +1258,9 @@ bridge_ioctl_sifcost(struct bridge_softc { 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); @@ -1277,7 +1269,7 @@ bridge_ioctl_sifcost(struct bridge_softc if (sc->sc_if.if_flags & IFF_RUNNING) bstp_initialization(sc); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); return (0); } @@ -1465,11 +1457,10 @@ bridge_output(struct ifnet *ifp, struct 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; @@ -1512,8 +1503,8 @@ bridge_output(struct ifnet *ifp, struct splx(s); #endif next: - bridge_release_member(sc, bif); BRIDGE_PSZ_RENTER(s); + bridge_release_member(sc, bif, &psref); } BRIDGE_PSZ_REXIT(s); @@ -1568,6 +1559,7 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *bif; struct ifnet *src_if, *dst_if; struct ether_header *eh; + struct psref psref; DECLARE_LOCK_VARIABLE; if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) @@ -1581,7 +1573,7 @@ bridge_forward(struct bridge_softc *sc, /* * 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); @@ -1594,7 +1586,7 @@ bridge_forward(struct bridge_softc *sc, case BSTP_IFSTATE_LISTENING: case BSTP_IFSTATE_DISABLED: m_freem(m); - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); goto out; } } @@ -1621,11 +1613,11 @@ bridge_forward(struct bridge_softc *sc, 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 @@ -1671,7 +1663,7 @@ bridge_forward(struct bridge_softc *sc, 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); @@ -1683,12 +1675,12 @@ bridge_forward(struct bridge_softc *sc, 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(); bridge_enqueue(sc, dst_if, m, 1); @@ -1740,6 +1732,7 @@ bridge_input(struct ifnet *ifp, struct m struct bridge_softc *sc = ifp->if_bridge; struct bridge_iflist *bif; struct ether_header *eh; + struct psref psref; DECLARE_LOCK_VARIABLE; KASSERT(!cpu_intr_p()); @@ -1752,7 +1745,7 @@ bridge_input(struct ifnet *ifp, struct m return; } - bif = bridge_lookup_member_if(sc, ifp); + bif = bridge_lookup_member_if(sc, ifp, &psref); if (bif == NULL) { ACQUIRE_GLOBAL_LOCKS(); ether_input(ifp, m); @@ -1779,13 +1772,13 @@ bridge_input(struct ifnet *ifp, struct m struct bridge_iflist *_bif; struct ifnet *_ifp = NULL; int s; + 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; @@ -1793,7 +1786,7 @@ bridge_input(struct ifnet *ifp, struct 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; } @@ -1805,7 +1798,7 @@ bridge_input(struct ifnet *ifp, struct 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(); @@ -1821,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; } @@ -1830,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); + bridge_release_member(sc, bif, &psref); ACQUIRE_GLOBAL_LOCKS(); ether_input(ifp, m); RELEASE_GLOBAL_LOCKS(); return; } - bridge_release_member(sc, bif); + bridge_release_member(sc, bif, &psref); bridge_forward(sc, m); } @@ -1863,11 +1856,10 @@ bridge_broadcast(struct bridge_softc *sc 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; @@ -1912,8 +1904,8 @@ bridge_broadcast(struct bridge_softc *sc RELEASE_GLOBAL_LOCKS(); } next: - bridge_release_member(sc, bif); BRIDGE_PSZ_RENTER(s); + bridge_release_member(sc, bif, &psref); } BRIDGE_PSZ_REXIT(s); Index: src/sys/net/if_bridgevar.h diff -u src/sys/net/if_bridgevar.h:1.29 src/sys/net/if_bridgevar.h:1.30 --- src/sys/net/if_bridgevar.h:1.29 Tue Apr 19 07:03:12 2016 +++ src/sys/net/if_bridgevar.h Tue Apr 19 07:10:22 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bridgevar.h,v 1.29 2016/04/19 07:03:12 ozaki-r Exp $ */ +/* $NetBSD: if_bridgevar.h,v 1.30 2016/04/19 07:10:22 ozaki-r Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -215,6 +215,7 @@ struct ifbrparam { #include <sys/pserialize.h> #include <sys/pslist.h> +#include <sys/psref.h> #include <sys/workqueue.h> #include <net/pktqueue.h> @@ -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 *, s 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: