i did this yesterday, but havent had a chance to beat on it properly
yet.

if anyone would like to give it a go it would be much appreciated.
im particularly interested in stability while carp configuration
is made or changed. if it happens to keep handling packets, thats
great, but not blowing up when you run ifconfig is the important
bit atm.

Index: ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.271
diff -u -p -r1.271 ip_carp.c
--- ip_carp.c   12 Sep 2015 20:51:35 -0000      1.271
+++ ip_carp.c   12 Sep 2015 21:07:42 -0000
@@ -48,6 +48,7 @@
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
+#include <sys/refcnt.h>
 
 #include <net/if.h>
 #include <net/if_var.h>
@@ -93,7 +94,9 @@ struct carp_mc_entry {
 enum { HMAC_ORIG=0, HMAC_NOV6LL=1, HMAC_MAX=2 };
 
 struct carp_vhost_entry {
-       LIST_ENTRY(carp_vhost_entry)    vhost_entries;
+       struct srpl_entry vhost_entries;
+       struct refcnt vhost_refcnt;
+
        struct carp_softc *parent_sc;
        int vhe_leader;
        int vhid;
@@ -114,6 +117,12 @@ struct carp_vhost_entry {
        struct sockaddr_dl vhe_sdl;     /* for IPv6 ndp balancing */
 };
 
+void   carp_vh_ref(void *, void *);
+void   carp_vh_unref(void *, void *);
+
+struct srpl_rc carp_vh_rc =
+    SRPL_RC_INITIALIZER(carp_vh_ref, carp_vh_unref, NULL);
+
 struct carp_softc {
        struct arpcom sc_ac;
 #define        sc_if           sc_ac.ac_if
@@ -124,7 +133,9 @@ struct carp_softc {
 #ifdef INET6
        struct ip6_moptions sc_im6o;
 #endif /* INET6 */
-       TAILQ_ENTRY(carp_softc) sc_list;
+
+       struct srpl_entry sc_list;
+       struct refcnt sc_refcnt;
 
        int sc_suppress;
        int sc_bow_out;
@@ -137,7 +148,7 @@ struct carp_softc {
 
        char sc_curlladdr[ETHER_ADDR_LEN];
 
-       LIST_HEAD(__carp_vhosthead, carp_vhost_entry)   carp_vhosts;
+       struct srpl carp_vhosts;
        int sc_vhe_count;
        u_int8_t sc_vhids[CARP_MAXNODES];
        u_int8_t sc_advskews[CARP_MAXNODES];
@@ -162,13 +173,19 @@ struct carp_softc {
        struct carp_vhost_entry *cur_vhe; /* current active vhe */
 };
 
+void   carp_sc_ref(void *, void *);
+void   carp_sc_unref(void *, void *);
+
+struct srpl_rc carp_sc_rc =
+    SRPL_RC_INITIALIZER(carp_sc_ref, carp_sc_unref, NULL);
+
 int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, LOG_CRIT };  /* XXX for now */
 struct carpstats carpstats;
 
 int    carp_send_all_recur = 0;
 
 struct carp_if {
-       TAILQ_HEAD(, carp_softc) vhif_vrs;
+       struct srpl vhif_vrs;
 };
 
 #define        CARP_LOG(l, sc, s)                                              
\
@@ -250,7 +267,9 @@ carp_hmac_prepare(struct carp_softc *sc)
        struct carp_vhost_entry *vhe;
        u_int8_t i;
 
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                for (i = 0; i < HMAC_MAX; i++) {
                        carp_hmac_prepare_ctx(vhe, i);
                }
@@ -579,11 +598,12 @@ carp_proto_input_c(struct ifnet *ifp, st
        else
                cif = (struct carp_if *)ifp->if_carp;
 
-       TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs + carp_vhosts */
+       SRPL_FOREACH_LOCKED(sc, &cif->vhif_vrs, sc_list) {
                if (af == AF_INET &&
                    ismulti != IN_MULTICAST(sc->sc_peer.s_addr))
                        continue;
-               LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+               SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                        if (vhe->vhid == ch->carp_vhid)
                                goto found;
                }
@@ -749,7 +769,9 @@ carp_clone_create(struct if_clone *ifc, 
        if (!sc)
                return (ENOMEM);
 
-       LIST_INIT(&sc->carp_vhosts);
+       refcnt_init(&sc->sc_refcnt);
+       
+       SRPL_INIT(&sc->carp_vhosts);
        sc->sc_vhe_count = 0;
        if (carp_new_vhost(sc, 0, 0)) {
                free(sc, M_DEVBUF, sizeof(*sc));
@@ -801,6 +823,8 @@ carp_new_vhost(struct carp_softc *sc, in
        if (vhe == NULL)
                return (ENOMEM);
 
+       refcnt_init(&vhe->vhost_refcnt);
+       carp_sc_ref(NULL, sc); /* give a sc ref to the vhe */
        vhe->parent_sc = sc;
        vhe->vhid = vhid;
        vhe->advskew = advskew;
@@ -809,18 +833,23 @@ carp_new_vhost(struct carp_softc *sc, in
        timeout_set(&vhe->md_tmo, carp_master_down, vhe);
        timeout_set(&vhe->md6_tmo, carp_master_down, vhe);
 
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+
        /* mark the first vhe as leader */
-       if (LIST_EMPTY(&sc->carp_vhosts)) {
+       if (SRPL_EMPTY_LOCKED(&sc->carp_vhosts)) {
                vhe->vhe_leader = 1;
-               LIST_INSERT_HEAD(&sc->carp_vhosts, vhe, vhost_entries);
+               SRPL_INSERT_HEAD_LOCKED(&carp_vh_rc, &sc->carp_vhosts,
+                   vhe, vhost_entries);
                sc->sc_vhe_count = 1;
                return (0);
        }
 
-       LIST_FOREACH(vhe0, &sc->carp_vhosts, vhost_entries)
-               if (LIST_NEXT(vhe0, vhost_entries) == NULL)
+       SRPL_FOREACH_LOCKED(vhe0, &sc->carp_vhosts, vhost_entries) {
+               if (SRPL_NEXT_LOCKED(vhe0, vhost_entries) == NULL)
                        break;
-       LIST_INSERT_AFTER(vhe0, vhe, vhost_entries);
+       }
+
+       SRPL_INSERT_AFTER_LOCKED(&carp_vh_rc, vhe0, vhe, vhost_entries);
        sc->sc_vhe_count++;
 
        return (0);
@@ -835,9 +864,9 @@ carp_clone_destroy(struct ifnet *ifp)
        ether_ifdetach(ifp);
        if_detach(ifp);
        carp_destroy_vhosts(ifp->if_softc);
+       refcnt_finalize(&sc->sc_refcnt, "carpdtor");
        free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
        free(sc, M_DEVBUF, sizeof(*sc));
-
        return (0);
 }
 
@@ -846,7 +875,8 @@ carp_del_all_timeouts(struct carp_softc 
 {
        struct carp_vhost_entry *vhe;
 
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                timeout_del(&vhe->ad_tmo);
                timeout_del(&vhe->md_tmo);
                timeout_del(&vhe->md6_tmo);
@@ -879,16 +909,20 @@ carpdetach(struct carp_softc *sc)
        if (ifp0 == NULL)
                return;
 
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */
+
+       cif = (struct carp_if *)ifp0->if_carp;
+
        /* Restore previous input handler. */
-       if_ih_remove(ifp0, carp_input, NULL);
+       if_ih_remove(ifp0, carp_input, cif);
 
        s = splnet();
        if (sc->lh_cookie != NULL)
-               hook_disestablish(ifp0->if_linkstatehooks,
-                   sc->lh_cookie);
-       cif = (struct carp_if *)ifp0->if_carp;
-       TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
-       if (TAILQ_EMPTY(&cif->vhif_vrs)) {
+               hook_disestablish(ifp0->if_linkstatehooks, sc->lh_cookie);
+
+       SRPL_REMOVE_LOCKED(&carp_sc_rc, &cif->vhif_vrs, sc,
+           carp_softc, sc_list);
+       if (SRPL_EMPTY_LOCKED(&cif->vhif_vrs)) {
                ifpromisc(ifp0, 0);
                ifp0->if_carp = NULL;
                free(cif, M_IFADDR, sizeof(*cif));
@@ -904,9 +938,12 @@ carp_ifdetach(struct ifnet *ifp0)
        struct carp_softc *sc, *nextsc;
        struct carp_if *cif = (struct carp_if *)ifp0->if_carp;
 
-       for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) {
-               nextsc = TAILQ_NEXT(sc, sc_list);
-               carpdetach(sc);
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */
+
+       for (sc = SRPL_FIRST_LOCKED(&cif->vhif_vrs); sc != NULL; sc = nextsc) {
+               nextsc = SRPL_NEXT_LOCKED(sc, sc_list);
+
+               carpdetach(sc); /* this can free cif */
        }
 }
 
@@ -914,13 +951,15 @@ void
 carp_destroy_vhosts(struct carp_softc *sc)
 {
        /* XXX bow out? */
-       struct carp_vhost_entry *vhe, *nvhe;
+       struct carp_vhost_entry *vhe;
 
-       for (vhe = LIST_FIRST(&sc->carp_vhosts); vhe != NULL; vhe = nvhe) {
-               nvhe = LIST_NEXT(vhe, vhost_entries);
-               free(vhe, M_DEVBUF, sizeof(*vhe));
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+
+       while ((vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts)) != NULL) {
+               SRPL_REMOVE_LOCKED(&carp_vh_rc, &sc->carp_vhosts, vhe,
+                   carp_vhost_entry, vhost_entries);
+               carp_vh_unref(NULL, vhe); /* drop last ref */
        }
-       LIST_INIT(&sc->carp_vhosts);
        sc->sc_vhe_count = 0;
 }
 
@@ -952,6 +991,8 @@ carp_send_ad_all(void)
        struct carp_if *cif;
        struct carp_softc *vh;
 
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */
+
        if (carp_send_all_recur > 0)
                return;
        ++carp_send_all_recur;
@@ -960,7 +1001,7 @@ carp_send_ad_all(void)
                        continue;
 
                cif = (struct carp_if *)ifp0->if_carp;
-               TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+               SRPL_FOREACH_LOCKED(vh, &cif->vhif_vrs, sc_list) {
                        if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
                            (IFF_UP|IFF_RUNNING)) {
                                carp_vhe_send_ad_all(vh);
@@ -975,7 +1016,9 @@ carp_vhe_send_ad_all(struct carp_softc *
 {
        struct carp_vhost_entry *vhe;
 
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                if (vhe->state == MASTER)
                        carp_send_ad(vhe);
        }
@@ -1302,7 +1345,8 @@ carp_update_lsmask(struct carp_softc *sc
        sc->sc_lsmask = 0;
        count = 0;
 
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                if (vhe->state == MASTER && count < sizeof(sc->sc_lsmask) * 8)
                        sc->sc_lsmask |= 1 << count;
                count++;
@@ -1316,7 +1360,9 @@ carp_iamatch(struct in_ifaddr *ia, u_cha
     u_int8_t **ether_shost)
 {
        struct carp_softc *sc = ia->ia_ifp->if_softc;
-       struct carp_vhost_entry *vhe = LIST_FIRST(&sc->carp_vhosts);
+       struct carp_vhost_entry *vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts);
+
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
 
        if (sc->sc_balancing == CARP_BAL_ARP) {
                int lshash;
@@ -1332,7 +1378,8 @@ carp_iamatch(struct in_ifaddr *ia, u_cha
                lshash = carp_hash(sc, src) % sc->sc_lscount;
                if ((1 << lshash) & sc->sc_lsmask) {
                        int i = 0;
-                       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+                       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts,
+                           vhost_entries) {
                                if (i++ == lshash)
                                        break;
                        }
@@ -1361,7 +1408,9 @@ int
 carp_iamatch6(struct ifnet *ifp, u_char *src, struct sockaddr_dl **sdl)
 {
        struct carp_softc *sc = ifp->if_softc;
-       struct carp_vhost_entry *vhe = LIST_FIRST(&sc->carp_vhosts);
+       struct carp_vhost_entry *vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts);
+
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
 
        if (sc->sc_balancing == CARP_BAL_ARP) {
                int lshash;
@@ -1380,7 +1429,8 @@ carp_iamatch6(struct ifnet *ifp, u_char 
                lshash = carp_hash(sc, src) % sc->sc_lscount;
                if ((1 << lshash) & sc->sc_lsmask) {
                        int i = 0;
-                       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+                       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts,
+                           vhost_entries) {
                                if (i++ == lshash)
                                        break;
                        }
@@ -1404,19 +1454,22 @@ carp_ourether(void *v, u_int8_t *ena)
        struct carp_if *cif = (struct carp_if *)v;
        struct carp_softc *vh;
 
-       TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs + carp_vhosts */
+
+       SRPL_FOREACH_LOCKED(vh, &cif->vhif_vrs, sc_list) {
                struct carp_vhost_entry *vhe;
                if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
                    (IFF_UP|IFF_RUNNING))
                        continue;
                if (vh->sc_balancing == CARP_BAL_ARP) {
-                       LIST_FOREACH(vhe, &vh->carp_vhosts, vhost_entries)
+                       SRPL_FOREACH_LOCKED(vhe, &vh->carp_vhosts,
+                           vhost_entries)
                                if (vhe->state == MASTER &&
                                    !memcmp(ena, vhe->vhe_enaddr,
                                    ETHER_ADDR_LEN))
                                        return (&vh->sc_if);
                } else {
-                       vhe = LIST_FIRST(&vh->carp_vhosts);
+                       vhe = SRPL_FIRST_LOCKED(&vh->carp_vhosts);
                        if ((vhe->state == MASTER ||
                            vh->sc_balancing >= CARP_BAL_IP) &&
                            !memcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
@@ -1427,32 +1480,70 @@ carp_ourether(void *v, u_int8_t *ena)
 }
 
 int
+carp_vhe_match(struct carp_softc *sc, uint8_t *ena)
+{
+       struct carp_vhost_entry *vhe;
+       struct srpl_iter i;
+       int match;
+
+       if (sc->sc_balancing == CARP_BAL_ARP) {
+               SRPL_FOREACH(vhe, &sc->carp_vhosts, &i, vhost_entries) {
+                       if (vhe->state == MASTER &&
+                           !memcmp(ena, vhe->vhe_enaddr, ETHER_ADDR_LEN)) {
+                               match = 1;
+                               break;
+                       }
+               }
+               SRPL_LEAVE(&i, vhe);
+       } else {
+               vhe = SRPL_ENTER(&sc->carp_vhosts, &i); /* head */
+               match = (vhe->state == MASTER ||
+                   sc->sc_balancing >= CARP_BAL_IP) &&
+                   !memcmp(ena, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
+               SRPL_LEAVE(&i, vhe);
+       }
+
+       return (match);
+}
+
+int
 carp_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
 {
-       struct carp_softc *sc;
        struct ether_header *eh;
        struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct carp_if *cif;
-       struct ifnet *ifp;
+       struct carp_softc *sc;
+       struct srpl_iter i;
 
        eh = mtod(m, struct ether_header *);
-       cif = (struct carp_if *)ifp0->if_carp;
+       cif = (struct carp_if *)cookie;
+       KASSERT(cif == (struct carp_if *)ifp0->if_carp);
 
-       ifp = carp_ourether(cif, eh->ether_dhost);
-       if (ifp == NULL && !ETHER_IS_MULTICAST(eh->ether_dhost))
-               return (0);
+       SRPL_FOREACH(sc, &cif->vhif_vrs, &i, sc_list) {
+               if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
+                   (IFF_UP|IFF_RUNNING))
+                       continue;
 
-       if (ifp == NULL) {
-               struct carp_softc *vh;
-               struct mbuf *m0;
+               if (carp_vhe_match(sc, eh->ether_dhost))
+                       break;
+       }
+
+       if (sc == NULL) {
+               SRPL_LEAVE(&i, sc);
+
+               if (!ETHER_IS_MULTICAST(eh->ether_dhost))
+                       return (0);
 
                /*
                 * XXX Should really check the list of multicast addresses
                 * for each CARP interface _before_ copying.
                 */
-               TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
-                       if (!(vh->sc_if.if_flags & IFF_UP))
+               SRPL_FOREACH(sc, &cif->vhif_vrs, &i, sc_list) {
+                       struct mbuf *m0;
+
+                       if (!(sc->sc_if.if_flags & IFF_UP))
                                continue;
+
                        m0 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
                        if (m0 == NULL)
                                continue;
@@ -1460,8 +1551,9 @@ carp_input(struct ifnet *ifp0, struct mb
                        ml_init(&ml);
                        ml_enqueue(&ml, m0);
 
-                       if_input(&vh->sc_if, &ml);
+                       if_input(&sc->sc_if, &ml);
                }
+               SRPL_LEAVE(&i, sc);
 
                return (0);
        }
@@ -1469,15 +1561,14 @@ carp_input(struct ifnet *ifp0, struct mb
        /*
         * Clear mcast if received on a carp IP balanced address.
         */
-       sc = ifp->if_softc;
        if (sc->sc_balancing == CARP_BAL_IP &&
            ETHER_IS_MULTICAST(eh->ether_dhost))
                *(eh->ether_dhost) &= ~0x01;
 
-
        ml_enqueue(&ml, m);
+       if_input(&sc->sc_if, &ml);
+       SRPL_LEAVE(&i, sc);
 
-       if_input(ifp, &ml);
        return (1);
 }
 
@@ -1554,7 +1645,9 @@ void
 carp_setrun_all(struct carp_softc *sc, sa_family_t af)
 {
        struct carp_vhost_entry *vhe;
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhost */
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                carp_setrun(vhe, af);
        }
 }
@@ -1671,7 +1764,7 @@ int
 carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp0)
 {
        struct carp_if *cif, *ncif = NULL;
-       struct carp_softc *vr, *after = NULL;
+       struct carp_softc *vr, *last = NULL, *after = NULL;
        int myself = 0, error = 0;
        int s;
 
@@ -1693,7 +1786,7 @@ carp_set_ifp(struct carp_softc *sc, stru
                        return (error);
                }
 
-               TAILQ_INIT(&ncif->vhif_vrs);
+               SRPL_INIT(&ncif->vhif_vrs);
        } else {
                cif = (struct carp_if *)ifp0->if_carp;
                if (carp_check_dup_vhids(sc, cif, NULL))
@@ -1711,20 +1804,29 @@ carp_set_ifp(struct carp_softc *sc, stru
        sc->sc_if.if_capabilities = ifp0->if_capabilities &
            IFCAP_CSUM_MASK;
        cif = (struct carp_if *)ifp0->if_carp;
-       TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
+       SRPL_FOREACH_LOCKED(vr, &cif->vhif_vrs, sc_list) {
+               struct carp_vhost_entry *vrhead, *schead;
+               last = vr;
+
                if (vr == sc)
                        myself = 1;
-               if (LIST_FIRST(&vr->carp_vhosts)->vhid <
-                   LIST_FIRST(&sc->carp_vhosts)->vhid)
+
+               vrhead = SRPL_FIRST_LOCKED(&vr->carp_vhosts);
+               schead = SRPL_FIRST_LOCKED(&sc->carp_vhosts);
+               if (vrhead->vhid < schead->vhid)
                        after = vr;
        }
 
        if (!myself) {
                /* We're trying to keep things in order */
-               if (after == NULL) {
-                       TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
+               if (last == NULL) {
+                       SRPL_INSERT_HEAD_LOCKED(&carp_sc_rc, &cif->vhif_vrs,
+                           sc, sc_list);
+               } else if (after == NULL) {
+                       SRPL_INSERT_AFTER_LOCKED(&carp_sc_rc, last,
+                           sc, sc_list);
                } else {
-                       TAILQ_INSERT_AFTER(&cif->vhif_vrs, after,
+                       SRPL_INSERT_AFTER_LOCKED(&carp_sc_rc, after,
                            sc, sc_list);
                }
        }
@@ -1736,7 +1838,7 @@ carp_set_ifp(struct carp_softc *sc, stru
            carp_carpdev_state, ifp0);
 
        /* Change input handler of the physical interface. */
-       if_ih_insert(ifp0, carp_input, NULL);
+       if_ih_insert(ifp0, carp_input, cif);
 
        s = splnet();
        carp_carpdev_state(ifp0);
@@ -1773,10 +1875,11 @@ carp_set_enaddr(struct carp_softc *sc)
 {
        struct carp_vhost_entry *vhe;
 
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries)
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries)
                carp_set_vhe_enaddr(vhe);
 
-       vhe = LIST_FIRST(&sc->carp_vhosts);
+       vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts);
 
        /*
         * Use the carp lladdr if the running one isn't manually set.
@@ -2009,7 +2112,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
                break;
 
        case SIOCSIFFLAGS:
-               vhe = LIST_FIRST(&sc->carp_vhosts);
+               KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+               vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts);
                if (vhe->state != INIT && !(ifr->ifr_flags & IFF_UP)) {
                        carp_del_all_timeouts(sc);
 
@@ -2029,7 +2133,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
                break;
 
        case SIOCSVH:
-               vhe = LIST_FIRST(&sc->carp_vhosts);
+               KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+               vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts);
                if ((error = suser(p, 0)) != 0)
                        break;
                if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr)))
@@ -2052,7 +2157,9 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
                                carp_setrun_all(sc, 0);
                                break;
                        case MASTER:
-                               LIST_FOREACH(vhe, &sc->carp_vhosts,
+                               KERNEL_ASSERT_LOCKED();
+                               /* touching carp_vhosts */
+                               SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts,
                                    vhost_entries)
                                        carp_master_down(vhe);
                                break;
@@ -2073,7 +2180,9 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
                if (memcmp(sc->sc_advskews, carpr.carpr_advskews,
                    sizeof(sc->sc_advskews))) {
                        i = 0;
-                       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries)
+                       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+                       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts,
+                           vhost_entries)
                                vhe->advskew = carpr.carpr_advskews[i++];
                        bcopy(carpr.carpr_advskews, sc->sc_advskews,
                            sizeof(sc->sc_advskews));
@@ -2103,7 +2212,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
                        strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname,
                            IFNAMSIZ);
                i = 0;
-               LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+               KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+               SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                        carpr.carpr_vhids[i] = vhe->vhid;
                        carpr.carpr_advskews[i] = vhe->advskew;
                        carpr.carpr_states[i] = vhe->state;
@@ -2150,17 +2260,20 @@ carp_check_dup_vhids(struct carp_softc *
        struct carp_vhost_entry *vhe, *vhe0;
        int i;
 
-       TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs + carp_vhosts */
+
+       SRPL_FOREACH_LOCKED(vr, &cif->vhif_vrs, sc_list) {
                if (vr == sc)
                        continue;
-               LIST_FOREACH(vhe, &vr->carp_vhosts, vhost_entries) {
+               SRPL_FOREACH_LOCKED(vhe, &vr->carp_vhosts, vhost_entries) {
                        if (carpr) {
                                for (i = 0; carpr->carpr_vhids[i]; i++) {
                                        if (vhe->vhid == carpr->carpr_vhids[i])
                                                return (EINVAL);
                                }
                        }
-                       LIST_FOREACH(vhe0, &sc->carp_vhosts, vhost_entries) {
+                       SRPL_FOREACH_LOCKED(vhe0, &sc->carp_vhosts,
+                           vhost_entries) {
                                if (vhe->vhid == vhe0->vhid)
                                        return (EINVAL);
                        }
@@ -2312,7 +2425,9 @@ carp_output(struct ifnet *ifp, struct mb
        struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc);
        struct carp_vhost_entry *vhe;
 
-       vhe = sc->cur_vhe ? sc->cur_vhe : LIST_FIRST(&sc->carp_vhosts);
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+
+       vhe = sc->cur_vhe ? sc->cur_vhe : SRPL_FIRST_LOCKED(&sc->carp_vhosts);
 
        if ((sc->sc_carpdev == NULL) ||
            (!sc->sc_balancing && vhe->state != MASTER)) {
@@ -2328,7 +2443,9 @@ carp_set_state_all(struct carp_softc *sc
 {
        struct carp_vhost_entry *vhe;
 
-       LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
+
+       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) {
                if (vhe->state == state)
                        continue;
 
@@ -2444,7 +2561,9 @@ carp_carpdev_state(void *v)
 
        cif = (struct carp_if *)ifp0->if_carp;
 
-       TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
+       KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */
+
+       SRPL_FOREACH_LOCKED(sc, &cif->vhif_vrs, sc_list) {
                int suppressed = sc->sc_suppress;
 
                if (sc->sc_carpdev->if_link_state == LINK_STATE_DOWN ||
@@ -2590,4 +2709,39 @@ carp_ether_purgemulti(struct carp_softc 
                LIST_REMOVE(mc, mc_entries);
                free(mc, M_DEVBUF, sizeof(*mc));
        }
+}
+
+void
+carp_vh_ref(void *null, void *v)
+{
+       struct carp_vhost_entry *vhe = v;
+
+       refcnt_take(&vhe->vhost_refcnt);
+}
+
+void
+carp_vh_unref(void *null, void *v)
+{
+       struct carp_vhost_entry *vhe = v;
+
+       if (refcnt_rele(&vhe->vhost_refcnt)) {
+               carp_sc_unref(NULL, vhe->parent_sc);
+               free(vhe, M_DEVBUF, sizeof(*vhe));
+       }
+}
+
+void
+carp_sc_ref(void *null, void *s)
+{
+       struct carp_softc *sc = s;
+
+       refcnt_take(&sc->sc_refcnt);
+}
+
+void
+carp_sc_unref(void *null, void *s)
+{
+       struct carp_softc *sc = s;
+
+       refcnt_rele_wake(&sc->sc_refcnt);
 }

Reply via email to