On Mon, Jan 27, 2020 at 12:48:49AM +0100, Alexandr Nedvedicky wrote:
> Hello,
> 
> </snip>
> > >     I'm not sure about your diff see below.
> > 
> > visa@ pointed out that PF_LOCK will introduce a potential sleep inside 
> > if_vinput(),
> > making this unsafe, so here's a less optimistic diff where only the vlan 
> > list
> > traversal is inside the SMR read section, and vlan_softcs are still 
> > refcounted.
> > I probably need to rework some other unsent SRP->SMR diffs now too.
> 
>     less optimistic variant looks better. Though I have one
>     question related to refcnt_finalize().
> 
> </snip>
> 
> > @@ -257,6 +239,7 @@ vlan_clone_destroy(struct ifnet *ifp)
> >  
> >     ether_ifdetach(ifp);
> >     if_detach(ifp);
> > +   smr_barrier();
> >     refcnt_finalize(&sc->sc_refcnt, "vlanrefs");
>     ^^^^
>     I think a protection should be added so there will be at most 1 thread
>     calling to refcnt_finalize(). I've noticed vlan_clone_destroy() does
>     ->sc_dead = 1; couple line earlier under protection of NET_LOCK(). Would 
> it
>     make sense to do if (->sc_dead == 1) first? We would just bail out if
>     ->sc_dead will be set already, because there is vlan_clone_destroy() in
>     progress already.
> 
>     Otherwise the change looks good.

I agree we should protect against that - if I add a sleep there, I can easily
cause a panic with 'ifconfig vlan10 destroy & ifconfig vlan10 destroy'.
I think that's a separate issue though, as the same window is present in
the existing code.

This fixes it, at least in my brief testing:

Index: if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.202
diff -u -p -u -p -r1.202 if_vlan.c
--- if_vlan.c   7 Nov 2019 07:36:32 -0000       1.202
+++ if_vlan.c   27 Jan 2020 03:47:24 -0000
@@ -249,6 +249,10 @@ vlan_clone_destroy(struct ifnet *ifp)
        struct vlan_softc *sc = ifp->if_softc;
 
        NET_LOCK();
+       if (sc->sc_dead != 0) {
+               NET_UNLOCK();
+               return (ENXIO);
+       }
        sc->sc_dead = 1;
 
        if (ISSET(ifp->if_flags, IFF_RUNNING))

Reply via email to