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:

Reply via email to