On Fri, May 13, 2022 at 12:19:46PM +1000, David Gwynne wrote:
> On Thu, May 12, 2022 at 08:07:09PM +0200, Hrvoje Popovski wrote:
> > On 12.5.2022. 20:04, Hrvoje Popovski wrote:
> > > On 12.5.2022. 16:22, Hrvoje Popovski wrote:
> > >> On 12.5.2022. 14:48, Claudio Jeker wrote:
> > >>> I think the diff below may be enough to fix this issue. It drops the SMR
> > >>> critical secition around the enqueue operation but uses a reference on 
> > >>> the
> > >>> port insteadt to ensure that the device can't be removed during the
> > >>> enqueue. Once the enqueue is finished we enter the SMR critical section
> > >>> again and drop the reference.
> > >>>
> > >>> To make it clear that the SMR_TAILQ remains intact while a refcount is
> > >>> held I moved refcnt_finalize() above SMR_TAILQ_REMOVE_LOCKED(). This is
> > >>> not strictly needed since the next pointer remains valid up until the
> > >>> smr_barrier() call but I find this a bit easier to understand.
> > >>> First make sure nobody else holds a reference then remove the port from
> > >>> the list.
> > >>>
> > >>> I currently have no test setup to verify this but I hope someone else 
> > >>> can
> > >>> give this a spin.
> > >> Hi,
> > >>
> > >> for now veb seems stable and i can't panic box although it should, but
> > >> please give me few more hours to torture it properly.
> > > 
> > > 
> > > I can trigger panic in veb with this diff.
> > > 
> > > Thank you ..
> > > 
> > > 
> > 
> > I can't trigger ... :))) sorry ..
> 
> sorry i'm late to the party. can you try this diff?
> 
> this diff replaces the list of ports with an array/map of ports.
> the map takes references to all the ports, so the forwarding paths
> just have to hold a reference to the map to be able to use all the
> ports. the forwarding path uses smr to get hold of a map, takes a map
> ref, and then leaves the smr crit section before iterating over the map
> and pushing packets.
> 
> this means we should only take and release a single refcnt when
> we're pushing packets out any number of ports.
> 
> if no span ports are configured, then there's no span port map and
> we don't try and take a ref, we can just return early.
> 
> we also only take and release a single refcnt when we forward the
> actual packet. forwarding to a single port provided by an etherbridge
> lookup already takes/releases the single port ref. if it falls
> through that for unknown unicast or broadcast/multicast, then it's
> a single refcnt for the current map of all ports.

This is very smart and probably better since it uses less atomic
instructions per packet. Diff reads fine. OK claudio@
 
> Index: if_veb.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_veb.c,v
> retrieving revision 1.25
> diff -u -p -r1.25 if_veb.c
> --- if_veb.c  4 Jan 2022 06:32:39 -0000       1.25
> +++ if_veb.c  13 May 2022 02:01:43 -0000
> @@ -139,13 +139,13 @@ struct veb_port {
>       struct veb_rule_list             p_vr_list[2];
>  #define VEB_RULE_LIST_OUT                    0
>  #define VEB_RULE_LIST_IN                     1
> -
> -     SMR_TAILQ_ENTRY(veb_port)        p_entry;
>  };
>  
>  struct veb_ports {
> -     SMR_TAILQ_HEAD(, veb_port)       l_list;
> -     unsigned int                     l_count;
> +     struct refcnt                    m_refs;
> +     unsigned int                     m_count;
> +
> +     /* followed by an array of veb_port pointers */
>  };
>  
>  struct veb_softc {
> @@ -155,8 +155,8 @@ struct veb_softc {
>       struct etherbridge               sc_eb;
>  
>       struct rwlock                    sc_rule_lock;
> -     struct veb_ports                 sc_ports;
> -     struct veb_ports                 sc_spans;
> +     struct veb_ports                *sc_ports;
> +     struct veb_ports                *sc_spans;
>  };
>  
>  #define DPRINTF(_sc, fmt...)    do { \
> @@ -184,8 +184,25 @@ static int       veb_p_ioctl(struct ifnet *, u
>  static int   veb_p_output(struct ifnet *, struct mbuf *,
>                   struct sockaddr *, struct rtentry *);
>  
> -static void  veb_p_dtor(struct veb_softc *, struct veb_port *,
> -                 const char *);
> +static inline size_t
> +veb_ports_size(unsigned int n)
> +{
> +     /* use of _ALIGN is inspired by CMSGs */
> +     return _ALIGN(sizeof(struct veb_ports)) +
> +         n * sizeof(struct veb_port *);
> +}
> +
> +static inline struct veb_port **
> +veb_ports_array(struct veb_ports *m)
> +{
> +     return (struct veb_port **)((caddr_t)m + _ALIGN(sizeof(*m)));
> +}
> +
> +static void  veb_ports_free(struct veb_ports *);
> +
> +static void  veb_p_unlink(struct veb_softc *, struct veb_port *);
> +static void  veb_p_fini(struct veb_port *);
> +static void  veb_p_dtor(struct veb_softc *, struct veb_port *);
>  static int   veb_add_port(struct veb_softc *,
>                   const struct ifbreq *, unsigned int);
>  static int   veb_del_port(struct veb_softc *,
> @@ -271,8 +288,8 @@ veb_clone_create(struct if_clone *ifc, i
>               return (ENOMEM);
>  
>       rw_init(&sc->sc_rule_lock, "vebrlk");
> -     SMR_TAILQ_INIT(&sc->sc_ports.l_list);
> -     SMR_TAILQ_INIT(&sc->sc_spans.l_list);
> +     sc->sc_ports = NULL;
> +     sc->sc_spans = NULL;
>  
>       ifp = &sc->sc_if;
>  
> @@ -314,7 +331,10 @@ static int
>  veb_clone_destroy(struct ifnet *ifp)
>  {
>       struct veb_softc *sc = ifp->if_softc;
> -     struct veb_port *p, *np;
> +     struct veb_ports *mp, *ms;
> +     struct veb_port **ps;
> +     struct veb_port *p;
> +     unsigned int i;
>  
>       NET_LOCK();
>       sc->sc_dead = 1;
> @@ -326,10 +346,60 @@ veb_clone_destroy(struct ifnet *ifp)
>       if_detach(ifp);
>  
>       NET_LOCK();
> -     SMR_TAILQ_FOREACH_SAFE_LOCKED(p, &sc->sc_ports.l_list, p_entry, np)
> -             veb_p_dtor(sc, p, "destroy");
> -     SMR_TAILQ_FOREACH_SAFE_LOCKED(p, &sc->sc_spans.l_list, p_entry, np)
> -             veb_p_dtor(sc, p, "destroy");
> +
> +     /*
> +      * this is an upside down version of veb_p_dtor() and
> +      * veb_ports_destroy() to avoid a lot of malloc/free and
> +      * smr_barrier calls if we remove ports one by one.
> +      */
> +
> +     mp = SMR_PTR_GET_LOCKED(&sc->sc_ports);
> +     SMR_PTR_SET_LOCKED(&sc->sc_ports, NULL);
> +     if (mp != NULL) {
> +             ps = veb_ports_array(mp);
> +             for (i = 0; i < mp->m_count; i++) {
> +                     veb_p_unlink(sc, ps[i]);
> +             }
> +     }
> +
> +     ms = SMR_PTR_GET_LOCKED(&sc->sc_spans);
> +     SMR_PTR_SET_LOCKED(&sc->sc_spans, NULL);
> +     if (ms != NULL) {
> +             ps = veb_ports_array(ms);
> +             for (i = 0; i < ms->m_count; i++)
> +                     veb_p_unlink(sc, ps[i]);
> +     }
> +
> +     if (mp != NULL || ms != NULL) {
> +             smr_barrier(); /* everything everywhere all at once */
> +
> +             if (mp != NULL) {
> +                     refcnt_finalize(&mp->m_refs, "vebdtor");
> +
> +                     ps = veb_ports_array(mp);
> +                     for (i = 0; i < mp->m_count; i++) {
> +                             p = ps[i];
> +                             /* the ports map holds a port ref */
> +                             refcnt_rele(&p->p_refs);
> +                             /* now we can finalize the port */
> +                             veb_p_fini(p);
> +                     }
> +
> +                     veb_ports_free(mp);
> +             }
> +             if (ms != NULL) {
> +                     refcnt_finalize(&ms->m_refs, "vebdtor");
> +
> +                     ps = veb_ports_array(ms);
> +                     for (i = 0; i < ms->m_count; i++) {
> +                             p = ps[i];
> +                             refcnt_rele(&p->p_refs);
> +                             veb_p_fini(p);
> +                     }
> +
> +                     veb_ports_free(ms);
> +             }
> +     }
>       NET_UNLOCK();
>  
>       etherbridge_destroy(&sc->sc_eb);
> @@ -349,12 +419,25 @@ veb_span_input(struct ifnet *ifp0, struc
>  static void
>  veb_span(struct veb_softc *sc, struct mbuf *m0)
>  {
> +     struct veb_ports *sm;
> +     struct veb_port **ps;
>       struct veb_port *p;
>       struct ifnet *ifp0;
>       struct mbuf *m;
> +     unsigned int i;
>  
>       smr_read_enter();
> -     SMR_TAILQ_FOREACH(p, &sc->sc_spans.l_list, p_entry) {
> +     sm = SMR_PTR_GET(&sc->sc_spans);
> +     if (sm != NULL)
> +             refcnt_take(&sm->m_refs);
> +     smr_read_leave();
> +     if (sm == NULL)
> +             return;
> +
> +     ps = veb_ports_array(sm);
> +     for (i = 0; i < sm->m_count; i++) {
> +             p = ps[i];
> +
>               ifp0 = p->p_ifp0;
>               if (!ISSET(ifp0->if_flags, IFF_RUNNING))
>                       continue;
> @@ -367,7 +450,7 @@ veb_span(struct veb_softc *sc, struct mb
>  
>               if_enqueue(ifp0, m); /* XXX count error */
>       }
> -     smr_read_leave();
> +     refcnt_rele_wake(&sm->m_refs);
>  }
>  
>  static int
> @@ -847,9 +930,12 @@ veb_broadcast(struct veb_softc *sc, stru
>      uint64_t src, uint64_t dst)
>  {
>       struct ifnet *ifp = &sc->sc_if;
> +     struct veb_ports *pm;
> +     struct veb_port **ps;
>       struct veb_port *tp;
>       struct ifnet *ifp0;
>       struct mbuf *m;
> +     unsigned int i;
>  
>  #if NPF > 0
>       /*
> @@ -873,7 +959,17 @@ veb_broadcast(struct veb_softc *sc, stru
>           m0->m_pkthdr.len);
>  
>       smr_read_enter();
> -     SMR_TAILQ_FOREACH(tp, &sc->sc_ports.l_list, p_entry) {
> +     pm = SMR_PTR_GET(&sc->sc_ports);
> +     if (__predict_true(pm != NULL))
> +             refcnt_take(&pm->m_refs);
> +     smr_read_leave();
> +     if (__predict_false(pm == NULL))
> +             goto done;
> +
> +     ps = veb_ports_array(pm);
> +     for (i = 0; i < pm->m_count; i++) {
> +             tp = ps[i];
> +
>               if (rp == tp || (rp->p_protected & tp->p_protected)) {
>                       /*
>                        * don't let Ethernet packets hairpin or
> @@ -906,8 +1002,9 @@ veb_broadcast(struct veb_softc *sc, stru
>  
>               (*tp->p_enqueue)(ifp0, m); /* XXX count error */
>       }
> -     smr_read_leave();
> +     refcnt_rele_wake(&pm->m_refs);
>  
> +done:
>       m_freem(m0);
>  }
>  
> @@ -1241,12 +1338,99 @@ veb_ioctl(struct ifnet *ifp, u_long cmd,
>       return (error);
>  }
>  
> +static struct veb_ports *
> +veb_ports_insert(struct veb_ports *om, struct veb_port *p)
> +{
> +     struct veb_ports *nm;
> +     struct veb_port **nps, **ops;
> +     unsigned int ocount = om != NULL ? om->m_count : 0;
> +     unsigned int ncount = ocount + 1;
> +     unsigned int i;
> +
> +     nm = malloc(veb_ports_size(ncount), M_DEVBUF, M_WAITOK|M_ZERO);
> +
> +     refcnt_init(&nm->m_refs);
> +     nm->m_count = ncount;
> +
> +     nps = veb_ports_array(nm);
> +
> +     if (om != NULL) {
> +             ops = veb_ports_array(om);
> +             for (i = 0; i < ocount; i++) {
> +                     struct veb_port *op = ops[i];
> +                     refcnt_take(&op->p_refs);
> +                     nps[i] = op;
> +             }
> +     } else
> +             i = 0;
> +
> +     refcnt_take(&p->p_refs);
> +     nps[i] = p;
> +
> +     return (nm);
> +}
> +
> +static struct veb_ports *
> +veb_ports_remove(struct veb_ports *om, struct veb_port *p)
> +{
> +     struct veb_ports *nm;
> +     struct veb_port **nps, **ops;
> +     unsigned int ocount = om->m_count;
> +     unsigned int ncount = ocount - 1;
> +     unsigned int i, j;
> +
> +     if (ncount == 0)
> +             return (NULL);
> +
> +     nm = malloc(veb_ports_size(ncount), M_DEVBUF, M_WAITOK|M_ZERO);
> +
> +     refcnt_init(&nm->m_refs);
> +     nm->m_count = ncount;
> +
> +     nps = veb_ports_array(nm);
> +     j = 0;
> +
> +     ops = veb_ports_array(om);
> +     for (i = 0; i < ocount; i++) {
> +             struct veb_port *op = ops[i];
> +             if (op == p)
> +                     continue;
> +
> +             refcnt_take(&op->p_refs);
> +             nps[j++] = op;
> +     }
> +     KASSERT(j == ncount);
> +
> +     return (nm);
> +}
> +
> +static inline void
> +veb_ports_free(struct veb_ports *m)
> +{
> +     free(m, M_DEVBUF, veb_ports_size(m->m_count));
> +}
> +
> +static void
> +veb_ports_destroy(struct veb_ports *m)
> +{
> +     struct veb_port **ps = veb_ports_array(m);
> +     unsigned int i;
> +
> +     for (i = 0; i < m->m_count; i++) {
> +             struct veb_port *p = ps[i];
> +             refcnt_rele_wake(&p->p_refs);
> +     }
> +
> +     veb_ports_free(m);
> +}
> +
>  static int
>  veb_add_port(struct veb_softc *sc, const struct ifbreq *req, unsigned int 
> span)
>  {
>       struct ifnet *ifp = &sc->sc_if;
>       struct ifnet *ifp0;
> -     struct veb_ports *port_list;
> +     struct veb_ports **ports_ptr;
> +     struct veb_ports *om, *nm;
>       struct veb_port *p;
>       int isvport;
>       int error;
> @@ -1294,7 +1478,7 @@ veb_add_port(struct veb_softc *sc, const
>       p->p_output = ifp0->if_output;
>  
>       if (span) {
> -             port_list = &sc->sc_spans;
> +             ports_ptr = &sc->sc_spans;
>  
>               if (isvport) {
>                       error = EPROTONOSUPPORT;
> @@ -1304,7 +1488,7 @@ veb_add_port(struct veb_softc *sc, const
>               p->p_brport.eb_input = veb_span_input;
>               p->p_bif_flags = IFBIF_SPAN;
>       } else {
> -             port_list = &sc->sc_ports;
> +             ports_ptr = &sc->sc_ports;
>  
>               error = ifpromisc(ifp0, 1);
>               if (error != 0)
> @@ -1318,6 +1502,9 @@ veb_add_port(struct veb_softc *sc, const
>       p->p_brport.eb_port_take = veb_eb_brport_take;
>       p->p_brport.eb_port_rele = veb_eb_brport_rele;
>  
> +     om = SMR_PTR_GET_LOCKED(ports_ptr);
> +     nm = veb_ports_insert(om, p);
> +
>       /* this might have changed if we slept for malloc or ifpromisc */
>       error = ether_brport_isset(ifp0);
>       if (error != 0)
> @@ -1332,8 +1519,7 @@ veb_add_port(struct veb_softc *sc, const
>       p->p_brport.eb_port = p;
>  
>       /* commit */
> -     SMR_TAILQ_INSERT_TAIL_LOCKED(&port_list->l_list, p, p_entry);
> -     port_list->l_count++;
> +     SMR_PTR_SET_LOCKED(ports_ptr, nm);
>  
>       ether_brport_set(ifp0, &p->p_brport);
>       if (!isvport) { /* vport is special */
> @@ -1343,6 +1529,13 @@ veb_add_port(struct veb_softc *sc, const
>  
>       veb_p_linkch(p);
>  
> +     /* clean up the old veb_ports map */
> +     smr_barrier();
> +     if (om != NULL) {
> +             refcnt_finalize(&om->m_refs, "vebports");
> +             veb_ports_destroy(om);
> +     }
> +
>       return (0);
>  
>  unpromisc:
> @@ -1358,12 +1551,19 @@ put:
>  static struct veb_port *
>  veb_trunkport(struct veb_softc *sc, const char *name, unsigned int span)
>  {
> -     struct veb_ports *port_list;
> +     struct veb_ports *m;
> +     struct veb_port **ps;
>       struct veb_port *p;
> +     unsigned int i;
> +
> +     m = SMR_PTR_GET_LOCKED(span ? &sc->sc_spans : &sc->sc_ports);
> +     if (m == NULL)
> +             return (NULL);
>  
> -     port_list = span ? &sc->sc_spans : &sc->sc_ports;
> +     ps = veb_ports_array(m);
> +     for (i = 0; i < m->m_count; i++) {
> +             p = ps[i];
>  
> -     SMR_TAILQ_FOREACH_LOCKED(p, &port_list->l_list, p_entry) {
>               if (strcmp(p->p_ifp0->if_xname, name) == 0)
>                       return (p);
>       }
> @@ -1381,7 +1581,7 @@ veb_del_port(struct veb_softc *sc, const
>       if (p == NULL)
>               return (EINVAL);
>  
> -     veb_p_dtor(sc, p, "del");
> +     veb_p_dtor(sc, p);
>  
>       return (0);
>  }
> @@ -1389,20 +1589,31 @@ veb_del_port(struct veb_softc *sc, const
>  static struct veb_port *
>  veb_port_get(struct veb_softc *sc, const char *name)
>  {
> +     struct veb_ports *m;
> +     struct veb_port **ps;
>       struct veb_port *p;
> +     struct ifnet *ifp0;
> +     unsigned int i;
>  
>       NET_ASSERT_LOCKED();
>  
> -     SMR_TAILQ_FOREACH_LOCKED(p, &sc->sc_ports.l_list, p_entry) {
> -             struct ifnet *ifp0 = p->p_ifp0;
> +     m = SMR_PTR_GET_LOCKED(&sc->sc_ports);
> +     if (m == NULL)
> +             return (NULL);
> +
> +     ps = veb_ports_array(m);
> +     for (i = 0; i < m->m_count; i++) {
> +             p = ps[i];
> +             ifp0 = p->p_ifp0;
> +
>               if (strncmp(ifp0->if_xname, name,
>                   sizeof(ifp0->if_xname)) == 0) {
>                       refcnt_take(&p->p_refs);
> -                     break;
> +                     return (p);
>               }
>       }
>  
> -     return (p);
> +     return (NULL);
>  }
>  
>  static void
> @@ -1712,56 +1923,77 @@ static int
>  veb_port_list(struct veb_softc *sc, struct ifbifconf *bifc)
>  {
>       struct ifnet *ifp = &sc->sc_if;
> +     struct veb_ports *m;
> +     struct veb_port **ps;
>       struct veb_port *p;
>       struct ifnet *ifp0;
>       struct ifbreq breq;
>       int n = 0, error = 0;
> +     unsigned int i;
>  
>       NET_ASSERT_LOCKED();
>  
>       if (bifc->ifbic_len == 0) {
> -             n = sc->sc_ports.l_count + sc->sc_spans.l_count;
> +             m = SMR_PTR_GET_LOCKED(&sc->sc_ports);
> +             if (m != NULL)
> +                     n += m->m_count;
> +             m = SMR_PTR_GET_LOCKED(&sc->sc_spans);
> +             if (m != NULL)
> +                     n += m->m_count;
>               goto done;
>       }
>  
> -     SMR_TAILQ_FOREACH_LOCKED(p, &sc->sc_ports.l_list, p_entry) {
> -             if (bifc->ifbic_len < sizeof(breq))
> -                     break;
> +     m = SMR_PTR_GET_LOCKED(&sc->sc_ports);
> +     if (m != NULL) {
> +             ps = veb_ports_array(m);
> +             for (i = 0; i < m->m_count; i++) {
> +                     if (bifc->ifbic_len < sizeof(breq))
> +                             break;
>  
> -             memset(&breq, 0, sizeof(breq));
> +                     p = ps[i];
>  
> -             ifp0 = p->p_ifp0;
> +                     memset(&breq, 0, sizeof(breq));
> +
> +                     ifp0 = p->p_ifp0;
>  
> -             strlcpy(breq.ifbr_name, ifp->if_xname, IFNAMSIZ);
> -             strlcpy(breq.ifbr_ifsname, ifp0->if_xname, IFNAMSIZ);
> +                     strlcpy(breq.ifbr_name, ifp->if_xname, IFNAMSIZ);
> +                     strlcpy(breq.ifbr_ifsname, ifp0->if_xname, IFNAMSIZ);
>  
> -             breq.ifbr_ifsflags = p->p_bif_flags;
> -             breq.ifbr_portno = ifp0->if_index;
> -             breq.ifbr_protected = p->p_protected;
> -             if ((error = copyout(&breq, bifc->ifbic_req + n,
> -                 sizeof(breq))) != 0)
> -                     goto done;
> +                     breq.ifbr_ifsflags = p->p_bif_flags;
> +                     breq.ifbr_portno = ifp0->if_index;
> +                     breq.ifbr_protected = p->p_protected;
> +                     if ((error = copyout(&breq, bifc->ifbic_req + n,
> +                         sizeof(breq))) != 0)
> +                             goto done;
>  
> -             bifc->ifbic_len -= sizeof(breq);
> -             n++;
> +                     bifc->ifbic_len -= sizeof(breq);
> +                     n++;
> +             }
>       }
>  
> -     SMR_TAILQ_FOREACH_LOCKED(p, &sc->sc_spans.l_list, p_entry) {
> -             if (bifc->ifbic_len < sizeof(breq))
> -                     break;
> +     m = SMR_PTR_GET_LOCKED(&sc->sc_spans);
> +     if (m != NULL) {
> +             ps = veb_ports_array(m);
> +             for (i = 0; i < m->m_count; i++) {
> +                     if (bifc->ifbic_len < sizeof(breq))
> +                             break;
>  
> -             memset(&breq, 0, sizeof(breq));
> +                     p = ps[i];
>  
> -             strlcpy(breq.ifbr_name, ifp->if_xname, IFNAMSIZ);
> -             strlcpy(breq.ifbr_ifsname, p->p_ifp0->if_xname, IFNAMSIZ);
> +                     memset(&breq, 0, sizeof(breq));
>  
> -             breq.ifbr_ifsflags = p->p_bif_flags;
> -             if ((error = copyout(&breq, bifc->ifbic_req + n,
> -                 sizeof(breq))) != 0)
> -                     goto done;
> +                     strlcpy(breq.ifbr_name, ifp->if_xname, IFNAMSIZ);
> +                     strlcpy(breq.ifbr_ifsname, p->p_ifp0->if_xname,
> +                         IFNAMSIZ);
>  
> -             bifc->ifbic_len -= sizeof(breq);
> -             n++;
> +                     breq.ifbr_ifsflags = p->p_bif_flags;
> +                     if ((error = copyout(&breq, bifc->ifbic_req + n,
> +                         sizeof(breq))) != 0)
> +                             goto done;
> +
> +                     bifc->ifbic_len -= sizeof(breq);
> +                     n++;
> +             }
>       }
>  
>  done:
> @@ -1904,46 +2136,67 @@ veb_p_output(struct ifnet *ifp0, struct 
>       return ((*p_output)(ifp0, m, dst, rt));
>  }
>  
> +/*
> + * there must be an smr_barrier after ether_brport_clr() and before
> + * veb_port is freed in veb_p_fini()
> + */
> +
>  static void
> -veb_p_dtor(struct veb_softc *sc, struct veb_port *p, const char *op)
> +veb_p_unlink(struct veb_softc *sc, struct veb_port *p)
>  {
>       struct ifnet *ifp = &sc->sc_if;
>       struct ifnet *ifp0 = p->p_ifp0;
> -     struct veb_ports *port_list;
> -
> -     DPRINTF(sc, "%s %s: destroying port\n",
> -         ifp->if_xname, ifp0->if_xname);
>  
>       ifp0->if_ioctl = p->p_ioctl;
>       ifp0->if_output = p->p_output;
>  
> -     ether_brport_clr(ifp0);
> +     ether_brport_clr(ifp0); /* needs an smr_barrier */
>  
>       if_detachhook_del(ifp0, &p->p_dtask);
>       if_linkstatehook_del(ifp0, &p->p_ltask);
>  
> -     if (ISSET(p->p_bif_flags, IFBIF_SPAN)) {
> -             port_list = &sc->sc_spans;
> -     } else {
> +     if (!ISSET(p->p_bif_flags, IFBIF_SPAN)) {
>               if (ifpromisc(ifp0, 0) != 0) {
>                       log(LOG_WARNING, "%s %s: unable to disable promisc\n",
>                           ifp->if_xname, ifp0->if_xname);
>               }
>  
>               etherbridge_detach_port(&sc->sc_eb, p);
> -
> -             port_list = &sc->sc_ports;
>       }
> -     SMR_TAILQ_REMOVE_LOCKED(&port_list->l_list, p, p_entry);
> -     port_list->l_count--;
> +}
>  
> -     refcnt_finalize(&p->p_refs, "vebpdtor");
> -     smr_barrier();
> +static void
> +veb_p_fini(struct veb_port *p)
> +{
> +     struct ifnet *ifp0 = p->p_ifp0;
>  
> +     refcnt_finalize(&p->p_refs, "vebpdtor");
>       veb_rule_list_free(TAILQ_FIRST(&p->p_vrl));
>  
>       if_put(ifp0);
> -     free(p, M_DEVBUF, sizeof(*p));
> +     free(p, M_DEVBUF, sizeof(*p)); /* hope you didn't forget smr_barrier */
> +}
> +
> +static void
> +veb_p_dtor(struct veb_softc *sc, struct veb_port *p)
> +{
> +     struct veb_ports **ports_ptr;
> +     struct veb_ports *om, *nm;
> +
> +     ports_ptr = ISSET(p->p_bif_flags, IFBIF_SPAN) ?
> +         &sc->sc_spans : &sc->sc_ports;
> +
> +     om = SMR_PTR_GET_LOCKED(ports_ptr);
> +     nm = veb_ports_remove(om, p);
> +     SMR_PTR_SET_LOCKED(ports_ptr, nm);
> +
> +     veb_p_unlink(sc, p);
> +
> +     smr_barrier();
> +     refcnt_finalize(&om->m_refs, "vebports");
> +     veb_ports_destroy(om);
> +
> +     veb_p_fini(p);
>  }
>  
>  static void
> @@ -1952,7 +2205,7 @@ veb_p_detach(void *arg)
>       struct veb_port *p = arg;
>       struct veb_softc *sc = p->p_veb;
>  
> -     veb_p_dtor(sc, p, "detach");
> +     veb_p_dtor(sc, p);
>  
>       NET_ASSERT_LOCKED();
>  }

-- 
:wq Claudio

Reply via email to