On 13/09/15(Sun) 18:34, David Gwynne wrote:
> 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.

I did not find any regression yet and things are still working for me.

I'm in favor of putting this now so we have some time to look for
smoke.

ok mpi@


> 
> 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