Index: sys/net/if_lagg.h =================================================================== --- sys/net/if_lagg.h +++ sys/net/if_lagg.h @@ -206,6 +206,7 @@ struct ifnet *sc_ifp; /* virtual interface */ struct rmlock sc_mtx; struct sx sc_sx; + bool sc_slowpath; int sc_proto; /* lagg protocol */ u_int sc_count; /* number of ports */ u_int sc_active; /* active port count */ @@ -257,20 +258,59 @@ #define LAGG_LOCK_INIT(_sc) rm_init(&(_sc)->sc_mtx, "if_lagg rmlock") #define LAGG_LOCK_DESTROY(_sc) rm_destroy(&(_sc)->sc_mtx) -#define LAGG_RLOCK(_sc, _p) rm_rlock(&(_sc)->sc_mtx, (_p)) -#define LAGG_WLOCK(_sc) rm_wlock(&(_sc)->sc_mtx) +#define LAGG_RLOCK(_sc, _p) do { \ + rm_rlock(&(_sc)->sc_mtx, (_p)); \ + if ((_sc)->sc_slowpath == false) \ + break; \ + rm_runlock(&(_sc)->sc_mtx, (_p)); \ + DELAY(1); \ +} while(1) #define LAGG_RUNLOCK(_sc, _p) rm_runlock(&(_sc)->sc_mtx, (_p)) -#define LAGG_WUNLOCK(_sc) rm_wunlock(&(_sc)->sc_mtx) -#define LAGG_RLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_RLOCKED) -#define LAGG_WLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_WLOCKED) -#define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED) #define LAGG_SX_INIT(_sc) sx_init(&(_sc)->sc_sx, "if_lagg sx") #define LAGG_SX_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx) -#define LAGG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx) -#define LAGG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx) -#define LAGG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx) -#define LAGG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx) +#define LAGG_SLOCK(_sc) do { \ + do { \ + rm_wlock(&(_sc)->sc_mtx); \ + if ((_sc)->sc_slowpath == false) { \ + (_sc)->sc_slowpath = true; \ + rm_wunlock(&(_sc)->sc_mtx); \ + break; \ + } \ + DELAY(1); \ + rm_wunlock(&(_sc)->sc_mtx); \ + } while(1); \ + sx_slock(&(_sc)->sc_sx); \ +} while(0) + +#define LAGG_XLOCK(_sc) do { \ + do { \ + rm_wlock(&(_sc)->sc_mtx); \ + if ((_sc)->sc_slowpath == false) { \ + (_sc)->sc_slowpath = true; \ + rm_wunlock(&(_sc)->sc_mtx); \ + break; \ + } \ + DELAY(1); \ + rm_wunlock(&(_sc)->sc_mtx); \ + } while(1); \ + sx_xlock(&(_sc)->sc_sx); \ +} while(0) + +#define LAGG_SUNLOCK(_sc) do { \ + sx_sunlock(&(_sc)->sc_sx); \ + rm_wlock(&(_sc)->sc_mtx); \ + (_sc)->sc_slowpath = false; \ + rm_wunlock(&(_sc)->sc_mtx); \ +} while(0) + +#define LAGG_XUNLOCK(_sc) do { \ + sx_xunlock(&(_sc)->sc_sx); \ + rm_wlock(&(_sc)->sc_mtx); \ + (_sc)->sc_slowpath = false; \ + rm_wunlock(&(_sc)->sc_mtx); \ +} while(0) + #define LAGG_SXLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED) #define LAGG_SLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_SLOCKED) #define LAGG_XLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_XLOCKED) Index: sys/net/if_lagg.c =================================================================== --- sys/net/if_lagg.c +++ sys/net/if_lagg.c @@ -334,14 +334,11 @@ lagg_proto pr; LAGG_XLOCK_ASSERT(sc); - LAGG_WLOCK_ASSERT(sc); pr = sc->sc_proto; sc->sc_proto = LAGG_PROTO_NONE; if (lagg_protos[pr].pr_detach != NULL) lagg_protos[pr].pr_detach(sc); - else - LAGG_WUNLOCK(sc); } static int @@ -550,9 +547,7 @@ lagg_port_destroy(lp, 1); /* Unhook the aggregation protocol */ - LAGG_WLOCK(sc); lagg_proto_detach(sc); - LAGG_UNLOCK_ASSERT(sc); LAGG_XUNLOCK(sc); ifmedia_removeall(&sc->sc_media); @@ -564,7 +559,6 @@ LAGG_LIST_UNLOCK(); LAGG_SX_DESTROY(sc); - LAGG_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } @@ -689,17 +683,14 @@ bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); lp->lp_ifcapenable = ifp->if_capenable; if (SLIST_EMPTY(&sc->sc_ports)) { - LAGG_WLOCK(sc); bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); lagg_proto_lladdr(sc); - LAGG_WUNLOCK(sc); EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); } else { if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); } lagg_setflags(lp, 1); - LAGG_WLOCK(sc); if (SLIST_EMPTY(&sc->sc_ports)) sc->sc_primary = lp; @@ -738,13 +729,9 @@ lagg_setmulti(lp); - LAGG_WUNLOCK(sc); - if ((error = lagg_proto_addport(sc, lp)) != 0) { /* Remove the port, without calling pr_delport. */ - LAGG_WLOCK(sc); lagg_port_destroy(lp, 0); - LAGG_UNLOCK_ASSERT(sc); return (error); } @@ -786,11 +773,8 @@ LAGG_XLOCK_ASSERT(sc); - if (rundelport) { - LAGG_WLOCK(sc); + if (rundelport) lagg_proto_delport(sc, lp); - } else - LAGG_WLOCK_ASSERT(sc); if (lp->lp_detaching == 0) lagg_clrmulti(lp); @@ -824,10 +808,8 @@ if (sc->sc_destroying == 0) { bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); lagg_proto_lladdr(sc); - LAGG_WUNLOCK(sc); EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); - } else - LAGG_WUNLOCK(sc); + } /* * Update lladdr for each port (new primary needs update @@ -835,8 +817,7 @@ */ SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) if_setlladdr(lp_ptr->lp_ifp, lladdr, ETHER_ADDR_LEN); - } else - LAGG_WUNLOCK(sc); + } if (lp->lp_ifflags) if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); @@ -942,8 +923,8 @@ struct lagg_softc *sc; struct lagg_port *lp; struct ifnet *lpifp; - struct rm_priotracker tracker; uint64_t newval, oldval, vsum; + struct rm_priotracker tracker; /* Revise this when we've got non-generic counters. */ KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); @@ -1158,9 +1139,7 @@ } LAGG_XLOCK(sc); - LAGG_WLOCK(sc); lagg_proto_detach(sc); - LAGG_UNLOCK_ASSERT(sc); lagg_proto_attach(sc, ra->ra_proto); LAGG_XUNLOCK(sc); break; @@ -1430,12 +1409,12 @@ break; case SIOCADDMULTI: case SIOCDELMULTI: - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { lagg_clrmulti(lp); lagg_setmulti(lp); } - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); error = 0; break; case SIOCSIFMEDIA: @@ -1523,7 +1502,7 @@ struct ifmultiaddr *ifma; int error; - LAGG_WLOCK_ASSERT(sc); + LAGG_XLOCK_ASSERT(sc); IF_ADDR_WLOCK(scifp); TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) @@ -1554,7 +1533,7 @@ { struct lagg_mc *mc; - LAGG_WLOCK_ASSERT(lp->lp_softc); + LAGG_XLOCK_ASSERT(lp->lp_softc); while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); if (mc->mc_ifma && lp->lp_detaching == 0) @@ -2014,8 +1993,8 @@ { struct lagg_lb *lb; + LAGG_XLOCK_ASSERT(sc); lb = (struct lagg_lb *)sc->sc_psc; - LAGG_WUNLOCK(sc); if (lb != NULL) free(lb, M_DEVBUF); } @@ -2114,12 +2093,12 @@ struct lagg_port *lp; void *psc; + LAGG_XLOCK_ASSERT(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lacp_port_destroy(lp); psc = sc->sc_psc; sc->sc_psc = NULL; - LAGG_WUNLOCK(sc); lacp_detach(psc); }