On 16/06/21(Wed) 14:26, David Gwynne wrote:
> 
> 
> > On 16 Jun 2021, at 00:39, Martin Pieuchot <[email protected]> wrote:
> > 
> > On 15/06/21(Tue) 22:52, David Gwynne wrote:
> >> On Mon, Jun 14, 2021 at 10:07:58AM +0200, Martin Pieuchot wrote:
> >>> On 10/06/21(Thu) 19:17, Alexander Bluhm wrote:
> >> [...] 
> >>>> The in6_ functions need netlock.  And driver SIOCSIFFLAGS ioctl
> >>>> must not have splnet().
> >>> 
> >>> Why not?  This is new since the introduction of intr_barrier() or this
> >>> is an old issue?
> >>> 
> >>>> Is reducing splnet() the correct aproach?
> >> 
> >> yes.
> >> 
> >>> I doubt it is possible to answer this question without defining who owns
> >>> `if_flags' and how can it be read/written to.
> >> 
> >> NET_LOCK is what "owns" updates to if_flags.
> > 
> > Why does reducing splnet() is the correct approach?  It isn't clear to
> > me.  What's splnet() protecting then?
> 
> splnet() and all the other splraise() variants only raise the IPL on the 
> current CPU. Unless you have some other lock to coordinate with other CPUs 
> (eg KERNEL_LOCK) it doesn't really prevent other code running. ixl in 
> particular has mpsafe interrupts, so unless your ioctl code is running on the 
> same CPU that ixl is interrupting, it's not helping.
> 
> splnet() with KERNEL_LOCK provides backward compat for with legacy drivers. 
> The reason it doesn't really help with the network stack is because the stack 
> runs from nettq under NET_LOCK without KERNEL_LOCK, it's no longer a softint 
> at an IPL lower than net.

The diff discussed in this thread reduces the scope of the splnet/splx()
dance to only surround the modification of `if_flags'.   How is this
related to what you said?  Is it because `if_flags' is read in interrupt
handlers and it isn't modified atomically?  Does that imply that every
modification of `if_flags' should be done at IPL_NET?  Does that mean
some love is needed to ensure reading `if_flags' is coherent?

Does that change also imply that it is safe to issue a SIOCSIFFLAGS on
a legacy drivers without blocking interrupts?  If the IPL needs to be
raised, this is left to the driver, right?

Was the current splnet/splx() dance an easy way to block packet reception
between multiple SIOCSIFFLAGS ioctls?  This might have been a way to not
receive packets on a DOWN interface.  This is no longer the case on MP
kernels as there's a window between the UP and DOWN ioctls.  Do we care?
Is this down/up/down dance fine for legacy a modern drivers?

> >>>> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
> >>>> retrieving revision 1.641
> >>>> diff -u -p -r1.641 if.c
> >>>> --- net/if.c     25 May 2021 22:45:09 -0000      1.641
> >>>> +++ net/if.c     10 Jun 2021 14:32:12 -0000
> >>>> @@ -3109,6 +3109,8 @@ ifnewlladdr(struct ifnet *ifp)
> >>>>  short up;
> >>>>  int s;
> >>>> 
> >>>> +        NET_ASSERT_LOCKED();
> >>>> +
> >>>>  s = splnet();
> >>>>  up = ifp->if_flags & IFF_UP;
> >>>> 
> >>>> @@ -3116,11 +3118,14 @@ ifnewlladdr(struct ifnet *ifp)
> >>>>          /* go down for a moment... */
> >>>>          ifp->if_flags &= ~IFF_UP;
> >>>>          ifrq.ifr_flags = ifp->if_flags;
> >>>> +                splx(s);
> >>>>          (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
> >>>> +                s = splnet();
> >>>>  }
> >>>> 
> >>>>  ifp->if_flags |= IFF_UP;
> >>>>  ifrq.ifr_flags = ifp->if_flags;
> >>>> +        splx(s);
> >>>>  (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
> >>>> 
> >>>> #ifdef INET6
> >>>> @@ -3139,11 +3144,12 @@ ifnewlladdr(struct ifnet *ifp)
> >>>> #endif
> >>>>  if (!up) {
> >>>>          /* go back down */
> >>>> +                s = splnet();
> >>>>          ifp->if_flags &= ~IFF_UP;
> >>>>          ifrq.ifr_flags = ifp->if_flags;
> >>>> +                splx(s);
> >>>>          (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
> >>>>  }
> >>>> -        splx(s);
> >>>> }
> >>>> 
> >>>> void
> >>>> 
> >>> 
> >> 
> 

Reply via email to