tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: vlan(4) mpsafe
> Date: Fri, 26 May 2017 18:27:16 +0900
> From: Shoichi Yamaguchi <s-yamaguchi%iij.ad.jp@localhost>
>
> Hi, I implement vlan(4) MP-ify code.
Cool, thanks for working on this!
> Here is a patch:
> https://gist.githubusercontent.com/s-ymgch228/02bb360cfd4e95eb1f64a66c28b30ab2/raw/97221fcc103a796020ea3c48f0ffdbb7bc845d38/vlan_mpsafe.patch
I don't have time for a detailed review right now, but here are some
quick comments from a cursory glance. First, this change introduces
several new locks -- struct ifvlan::ifv_lock, ifv_list.lock, and
ifv_hash.lock. Can you write down a lock order for them?
It looks like ifv_list.lock ---> struct ifvlan::ifv_lock is one
ordering relation, based on vlan_ifdetach, but I'm not sure about the
others.
@@ -115,6 +122,21 @@ __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.96 2017/03/15 09:51:08 ozaki-r Exp $")
#include "ioconf.h"
+#ifdef NET_MPSAFE
+#define VLAN_MPSAFE 1
+#define DECLARE_LOCK_VARIABLE
+#define ACQUIRE_GLOBAL_LOCKS() do { } while (0)
+#define RELEASE_GLOBAL_LOCKS() do { } while (0)
+#else
+#define DECLARE_LOCK_VARIABLE int __s
+#define ACQUIRE_GLOBAL_LOCKS() do { \
+ __s = splnet(); \
+ } while (0)
+#define RELEASE_GLOBAL_LOCKS() do { \
+ splx(__s); \
+ } while (0)
+#endif
Is this necessary? Can we just eliminate the splnet altogether yet?
The name `global locks' is confusing -- splnet only blocks interrupts
on the current CPU.
+vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag)
{
...
+ mutex_enter(&ifv->ifv_lock);
...
+ nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
+ *nmib = *omib;
Using kmem_* under a lock is not generally allowed. You should
preallocate the structure, and then acquire the lock. In the error
branch this may require you to free it immediately, but that's OK.
@@ -370,33 +484,67 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p)
...
+ vlan_linkmib_update(ifv, nmib);
+ nmib = NULL;
+ kmem_free(omib, sizeof(*omib));
+
+done:
+ if (nmib) {
+ psref_target_destroy(&nmib->ifvm_psref, ifvm_psref_class);
+ kmem_free(nmib, sizeof(*nmib));
+ }
+ mutex_exit(&ifv->ifv_lock);
Similarly, kmem_free isn't allowed under a lock either. Release the
lock first; then psref_target_destroy and kmem_free.
+vlan_unconfig_locked(struct ifnet *ifp)
+{
...
+ KASSERT(mutex_owned(&ifv->ifv_lock));
...
+ nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
Same here. This may require a little restructuring -- e.g., maybe you
need to pass a preallocated struct ifvlan_linkmib as another parameter
to vlan_unconfig_locked.
@@ -370,33 +484,67 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p)
* to participate in bridges of that type.
*/
ifv->ifv_if.if_type = p->if_type;
+ membar_producer();
- return (0);
+ idx = tag_hash_func(tag, ifv_hash.mask);
+
+ mutex_enter(&ifv_hash.lock);
+ PSLIST_WRITER_INSERT_HEAD(&ifv_hash.lists[idx], ifv, ifv_hash);
+ mutex_exit(&ifv_hash.lock);
+
+ vlan_linkmib_update(ifv, nmib);
+ nmib = NULL;
+ kmem_free(omib, sizeof(*omib));
This change is a little confusing. I think you added the
membar_producer here so that the content of nmib would be published
before vlan_linkmib_update publishes the nmib pointer with
ifv->ifv_mib = nmib. In this case, the membar_producer is not
*strictly* necessary because PSLIST_WRITER_INSERT_HEAD already issues
one.
But membars should generally come in pairs -- pretty much every
membar_(datadep_)consumer should be paired with a corresponding
membar_producer -- so it's best to make it very clear which ones match
up. So I would suggest that you either
(a) add a comment saying that this membar_producer corresponds to the
membar_datadep_consumer issued after reading ifv->ifv_mib; or
(b) omit the membar_producer, and add a comment explaining that the
membar_producer implied by PSLIST_WRITER_INSERT_HEAD works to match
the membar_datadep_consumer; or
(c) move the explicit membar_producer into vlan_linkmib_update.
It took me about three readings to realize what was going on here, so
the added clarity of any one of these options will make it easier to
audit!
@@ -419,21 +567,145 @@ vlan_unconfig(struct ifnet *ifp)
#endif
}
- ifv->ifv_p = NULL;
+ nmib->ifvm_p = NULL;
ifv->ifv_if.if_mtu = 0;
ifv->ifv_flags = 0;
+ membar_producer();
+
+ mutex_enter(&ifv_hash.lock);
+ PSLIST_WRITER_REMOVE(ifv, ifv_hash);
+ pserialize_perform(vlan_psz);
+ mutex_exit(&ifv_hash.lock);
+
+ vlan_linkmib_update(ifv, nmib);
+ kmem_free(omib, sizeof(*omib));
Same issue here -- pserialize_perform effectively issues a
membar_producer (and much more).
Home |
Main Index |
Thread Index |
Old Index