We're at the stage where we want to run multiple parts of the Network Stack in parallel. sashan@ is trying to get multiple network threads running to exercise parallelism in pf_test() and tb@ is trying to push the NET_LOCK() further down in ioctl(2) path.
However we want to be able to gradually select which code paths can be executed in parallel as the rest of the stack. So the way to move forward is to introduce a read version of the NET_LOCK(), NET_RLOCK() and change code paths on a case-by-case basis. Diff below does that for the input processing path. Note that the 3 tasks below cannot run in parallel because they are scheduled on the same taskq. Regarding assert macros, NET_ASSERT_LOCK() now required either a read or write lock. I also introduced a NET_ASSERT_WLOCK() to put in paths that are not ready to be run in parallel of the rest of the stack. Once that's in we can slowly convert existing NET_LOCK() to NET_WLOCK() to be explicit. Ok? Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.523 diff -u -p -r1.523 if.c --- net/if.c 4 Nov 2017 16:58:46 -0000 1.523 +++ net/if.c 8 Nov 2017 09:01:12 -0000 @@ -905,7 +905,7 @@ if_input_process(void *xifidx) * to PF globals, pipex globals, unicast and multicast addresses * lists. */ - NET_LOCK(); + NET_RLOCK(); s = splnet(); while ((m = ml_dequeue(&ml)) != NULL) { /* @@ -922,7 +922,7 @@ if_input_process(void *xifidx) m_freem(m); } splx(s); - NET_UNLOCK(); + NET_RUNLOCK(); out: if_put(ifp); } Index: netinet/ip_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.329 diff -u -p -r1.329 ip_input.c --- netinet/ip_input.c 5 Nov 2017 13:19:59 -0000 1.329 +++ netinet/ip_input.c 8 Nov 2017 09:06:57 -0000 @@ -1814,11 +1814,11 @@ ip_send_dispatch(void *xmq) if (ml_empty(&ml)) return; - NET_LOCK(); + NET_RLOCK(); while ((m = ml_dequeue(&ml)) != NULL) { ip_output(m, NULL, NULL, 0, NULL, NULL, 0); } - NET_UNLOCK(); + NET_RUNLOCK(); } void Index: netinet6/ip6_input.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.207 diff -u -p -r1.207 ip6_input.c --- netinet6/ip6_input.c 1 Nov 2017 06:35:38 -0000 1.207 +++ netinet6/ip6_input.c 8 Nov 2017 09:07:16 -0000 @@ -1459,7 +1459,7 @@ ip6_send_dispatch(void *xmq) if (ml_empty(&ml)) return; - NET_LOCK(); + NET_RLOCK(); while ((m = ml_dequeue(&ml)) != NULL) { /* * To avoid a "too big" situation at an intermediate router and @@ -1470,7 +1470,7 @@ ip6_send_dispatch(void *xmq) */ ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL); } - NET_UNLOCK(); + NET_RUNLOCK(); } void Index: sys/systm.h =================================================================== RCS file: /cvs/src/sys/sys/systm.h,v retrieving revision 1.133 diff -u -p -r1.133 systm.h --- sys/systm.h 11 Aug 2017 21:24:20 -0000 1.133 +++ sys/systm.h 8 Nov 2017 09:21:51 -0000 @@ -296,26 +296,34 @@ int uiomove(void *, size_t, struct uio * extern struct rwlock netlock; -#define NET_LOCK() \ -do { \ - rw_enter_write(&netlock); \ -} while (0) +#define NET_LOCK() NET_WLOCK() +#define NET_UNLOCK() NET_WUNLOCK() -#define NET_UNLOCK() \ +#define NET_WLOCK() do { rw_enter_write(&netlock); } while (0) +#define NET_WUNLOCK() do { rw_exit_write(&netlock); } while (0) + +#define NET_ASSERT_WLOCKED() \ do { \ - rw_exit_write(&netlock); \ + int _s = rw_status(&netlock); \ + if (_s != RW_WRITE) \ + splassert_fail(RW_WRITE, _s, __func__); \ } while (0) +#define NET_RLOCK() do { rw_enter_read(&netlock); } while (0) +#define NET_RUNLOCK() do { rw_exit_read(&netlock); } while (0) + #define NET_ASSERT_LOCKED() \ do { \ - if (rw_status(&netlock) != RW_WRITE) \ - splassert_fail(RW_WRITE, rw_status(&netlock), __func__);\ + int _s = rw_status(&netlock); \ + if (_s != RW_WRITE && _s != RW_READ) \ + splassert_fail(RW_READ, _s, __func__); \ } while (0) #define NET_ASSERT_UNLOCKED() \ do { \ - if (rw_status(&netlock) == RW_WRITE) \ - splassert_fail(0, rw_status(&netlock), __func__); \ + int _s = rw_status(&netlock); \ + if (_s == RW_WRITE || _s == RW_READ) \ + splassert_fail(0, _s, __func__); \ } while (0) __returns_twice int setjmp(label_t *);