From a09e3660685d853a4df332437f7aee9222b1ab7f Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Wed, 29 Jan 2020 16:46:10 +0000 Subject: [PATCH] Fix lockstat setup and teardown synchronization. Use xc_barrier() to enforce memory ordering on all CPUs so there's no need for membar_producer or atomic_load_acquire. Avoid bodgy tsleep. Omit needless membars. --- external/cddl/osnet/dev/lockstat/lockstat.c | 15 ++++------ sys/dev/lockstat.c | 33 ++++++++++++++------- sys/dev/lockstat.h | 11 +++---- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/external/cddl/osnet/dev/lockstat/lockstat.c b/external/cddl/osnet/dev/lockstat/lockstat.c index 53e6997e0236..21ce216ec2f8 100644 --- a/external/cddl/osnet/dev/lockstat/lockstat.c +++ b/external/cddl/osnet/dev/lockstat/lockstat.c @@ -149,13 +149,6 @@ static dtrace_pops_t lockstat_pops = { lockstat_destroy }; -static void -lockstat_barrier_xc(void *arg0 __unused, void *arg1 __unused) -{ - - membar_consumer(); -} - typedef void (*dtrace_probe_func_t)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); @@ -168,9 +161,13 @@ lockstat_cas_probe(dtrace_probe_func_t old, dtrace_probe_func_t new) if (lockstat_probe_func != old) return false; + /* Set the probe func. */ lockstat_probe_func = new; - membar_producer(); - xc_wait(xc_broadcast(0, lockstat_barrier_xc, NULL, NULL)); + + /* Wait until all CPUs have witnessed the new probe func. */ + xc_barrier(0); + + /* Success! */ return true; } diff --git a/sys/dev/lockstat.c b/sys/dev/lockstat.c index b2db655caa9c..7ea34501d107 100644 --- a/sys/dev/lockstat.c +++ b/sys/dev/lockstat.c @@ -53,7 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.26 2019/11/23 17:32:10 ad Exp $"); #include #include #include -#include +#include #include @@ -235,7 +235,6 @@ lockstat_start(lsenable_t *le) lockstat_lockstart = le->le_lockstart; lockstat_lockstart = le->le_lockstart; lockstat_lockend = le->le_lockend; - membar_sync(); getnanotime(&lockstat_stime); lockstat_dev_enabled = le->le_mask; LOCKSTAT_ENABLED_UPDATE(); @@ -257,14 +256,10 @@ lockstat_stop(lsdisable_t *ld) /* coverity[assert_side_effect] */ KASSERT(lockstat_dev_enabled); - /* - * Set enabled false, force a write barrier, and wait for other CPUs - * to exit lockstat_event(). - */ + /* Disable it and wait for it to settle. */ lockstat_dev_enabled = 0; LOCKSTAT_ENABLED_UPDATE(); getnanotime(&ts); - tsleep(&lockstat_stop, PPAUSE, "lockstat", mstohz(10)); /* * Did we run out of buffers while tracing? @@ -312,6 +307,20 @@ lockstat_stop(lsdisable_t *ld) return error; } +void +lockstat_enabled_update(u_int dtrace_enabled) +{ + + /* + * Wait until all CPUs see the setup if we're setting it up, + * kick it off, and wait until all CPUs are done using it if + * we're tearing it down. + */ + xc_barrier(0); + lockstat_enabled = lockstat_dev_enabled | dtrace_enabled; + xc_barrier(0); +} + /* * Allocate buffers for lockstat_start(). */ @@ -367,6 +376,9 @@ lockstat_event(uintptr_t lock, uintptr_t callsite, u_int flags, u_int count, u_int event; int s; + /* Lock out xc_barrier. */ + kpreempt_disable(); + #ifdef KDTRACE_HOOKS uint32_t id; CTASSERT((LS_NPROBES & (LS_NPROBES - 1)) == 0); @@ -376,11 +388,11 @@ lockstat_event(uintptr_t lock, uintptr_t callsite, u_int flags, u_int count, #endif if ((flags & lockstat_dev_enabled) != flags || count == 0) - return; + goto out; if (lock < lockstat_lockstart || lock > lockstat_lockend) - return; + goto out; if (callsite < lockstat_csstart || callsite > lockstat_csend) - return; + goto out; callsite &= lockstat_csmask; lock &= lockstat_lamask; @@ -431,6 +443,7 @@ lockstat_event(uintptr_t lock, uintptr_t callsite, u_int flags, u_int count, } splx(s); +out: kpreempt_enable(); } /* diff --git a/sys/dev/lockstat.h b/sys/dev/lockstat.h index 80e94f254433..e4ea6ca232c7 100644 --- a/sys/dev/lockstat.h +++ b/sys/dev/lockstat.h @@ -214,13 +214,10 @@ void lockstat_probe_stub(uint32_t, uintptr_t, uintptr_t, #endif #if defined(_KERNEL) && NLOCKSTAT > 0 -extern volatile u_int lockstat_enabled; -extern volatile u_int lockstat_dev_enabled; - -#define LOCKSTAT_ENABLED_UPDATE() do { \ - lockstat_enabled = lockstat_dev_enabled | KDTRACE_LOCKSTAT_ENABLED; \ - membar_producer(); \ - } while (/*CONSTCOND*/0) +extern volatile u_int lockstat_enabled; +void lockstat_enabled_update(u_int); +#define LOCKSTAT_ENABLED_UPDATE() \ + lockstat_enabled_update(KDTRACE_LOCKSTAT_ENABLED) #endif #endif /* _SYS_LOCKSTAT_H_ */