tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bridge(4): BRIDGE_MPSAFE by default and applying psref(9)



   Date: Thu, 14 Apr 2016 15:55:45 +0900
   From: Ryota Ozaki <ozaki-r%netbsd.org@localhost>

   I prepared two patches for bridge(4):
     http://www.netbsd.org/~ozaki-r/remove-BRIDGE_MPSAFE.diff
     http://www.netbsd.org/~ozaki-r/psref-bridge.diff

   The former removes BRIDGE_MPSAFE switch and enables the
   MP-safe code by default. After introducing softint-based
   if_input, bridge can run in parallel even without NET_MPSAFE,
   so I think we need to always enable it.

Nice!  Some comments on the patch below.

   The latter applies psref(9) to bridge. I confirmed the new
   implementation survives load test, which includes repeating
   bridge creations/deletions and member interface
   additions/removals, over several hours.

One test it would be nice to see is something that fails due to the
bug of attempting to use a list element after bridge_release_member,
outside a pserialize read section, and then does not fail with psref.
Maybe you could add a busy-wait delay after the bridge_release_member
to exacerbate it.  (However, it may be hard to actually cause this to
happen, so I won't demand that you do it before committing!)

   Note that I notice that we need to tweak shmif of the
   rump kernel because it seems that the interrupt handler
   of shmif can migration between CPUs and so the behavior
   violates a contract of psref. We can fix it by applying
   if_percpuq to shmif, but I'm not sure that's the way
   to go. (I'll ask pooka about the issue.)

You could make (e.g.) bridge_input always satisfy the contract by
doing

	int bound = curlwp->l_pflag & LP_BOUND;
	curlwp->l_pflag |= LP_BOUND;
	...
	curlwp->l_pflag ^= bound ^ LP_BOUND;

if you can't guarantee that every caller will be in a softint.

   diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
   index 6023061..86ca7c3 100644
   --- a/sys/net/if_bridge.c
   +++ b/sys/net/if_bridge.c
   @@ -395,6 +400,7 @@ bridge_clone_create(struct if_clone *ifc, int unit)
           sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
           sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME;
           sc->sc_filter_flags = 0;
   +       sc->sc_dying = false;

Why do you add a dying flag here?  If there's a problem of
coordinating *_clone_destroy and *_ioctl, it seems to me that that's
something that should be handled higher up.

And this protocol seems fishy to me -- what stops bridge_clone_destroy
from freeing a bridge while another CPU is in the middle of
bridge_ioctl_add, after the sc_dying check?

   @@ -407,10 +413,14 @@ bridge_clone_create(struct if_clone *ifc, int unit)
   [...]
   +       sc->sc_iflist_psref.bip_class =
   +           psref_class_create("if_bridge_cv", IPL_SOFTNET);

The wmesg here should be only 8 characters long (and preferably make
the first 5 or 6 the important ones).  Maybe just `bridge' or
`bridgeif'.

Also, I would suggest that you make the psref class be global, not
per-bridge.  The main reason for having different psref classes in the
first place is for different IPLs.  There is conceivably a tiny
performance benefit for destruction -- but not likely to matter much.

bridge_try_hold_bif should perhaps be renamed now that it never fails,
say to bridge_acquire_member -- or maybe we can just remove
bridge_try_hold_bif and bridge_release_member altogether, since
they're just psref_acquire and psref_release.


Home | Main Index | Thread Index | Old Index