Sun Feb 27 14:16:12 2022 UTC ()
lockstat(4): Membar audit.

- Serialize updates to lockstat_enabled, lockstat_dev_enabled, and
  lockstat_dtrace_enabled with a new __cpu_simple_lock.

- Use xc_barrier to obviate any need for additional membars in
  lockstat_event.

- Use atomic_load/store_* for access that might not be serialized by
  lockstat_lock or lockstat_enabled_lock.


(riastradh)
diff -r1.10 -r1.11 src/external/cddl/osnet/dev/lockstat/lockstat.c
diff -r1.27 -r1.28 src/sys/dev/lockstat.c
diff -r1.14 -r1.15 src/sys/dev/lockstat.h

cvs diff -r1.10 -r1.11 src/external/cddl/osnet/dev/lockstat/lockstat.c (expand / switch to unified diff)

--- src/external/cddl/osnet/dev/lockstat/lockstat.c 2019/02/12 14:31:45 1.10
+++ src/external/cddl/osnet/dev/lockstat/lockstat.c 2022/02/27 14:16:12 1.11
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: lockstat.c,v 1.10 2019/02/12 14:31:45 rin Exp $ */ 1/* $NetBSD: lockstat.c,v 1.11 2022/02/27 14:16:12 riastradh Exp $ */
2 2
3/* 3/*
4 * CDDL HEADER START 4 * CDDL HEADER START
5 * 5 *
6 * The contents of this file are subject to the terms of the 6 * The contents of this file are subject to the terms of the
7 * Common Development and Distribution License (the "License"). 7 * Common Development and Distribution License (the "License").
8 * You may not use this file except in compliance with the License. 8 * You may not use this file except in compliance with the License.
9 * 9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing. 11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions 12 * See the License for the specific language governing permissions
13 * and limitations under the License. 13 * and limitations under the License.
14 * 14 *
@@ -16,27 +16,27 @@ @@ -16,27 +16,27 @@
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the 17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying 18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * 20 *
21 * CDDL HEADER END 21 * CDDL HEADER END
22 */ 22 */
23/* 23/*
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms. 25 * Use is subject to license terms.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.10 2019/02/12 14:31:45 rin Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.11 2022/02/27 14:16:12 riastradh Exp $");
30 30
31#include <sys/types.h> 31#include <sys/types.h>
32#include <sys/proc.h> 32#include <sys/proc.h>
33#include <sys/param.h> 33#include <sys/param.h>
34#include <sys/conf.h> 34#include <sys/conf.h>
35#include <sys/dtrace.h> 35#include <sys/dtrace.h>
36#include <sys/module.h> 36#include <sys/module.h>
37#include <sys/mutex.h> 37#include <sys/mutex.h>
38#include <sys/systm.h> 38#include <sys/systm.h>
39#include <sys/xcall.h> 39#include <sys/xcall.h>
40#include <sys/atomic.h> 40#include <sys/atomic.h>
41 41
42#define NLOCKSTAT 1 42#define NLOCKSTAT 1
@@ -62,49 +62,58 @@ lockstat_probe_t lockstat_probes[] = { @@ -62,49 +62,58 @@ lockstat_probe_t lockstat_probes[] = {
62}; 62};
63 63
64static dtrace_provider_id_t lockstat_id; 64static dtrace_provider_id_t lockstat_id;
65static size_t lockstat_dtrace_count; 65static size_t lockstat_dtrace_count;
66 66
67/*ARGSUSED*/ 67/*ARGSUSED*/
68static int 68static int
69lockstat_enable(void *arg, dtrace_id_t id, void *parg) 69lockstat_enable(void *arg, dtrace_id_t id, void *parg)
70{ 70{
71 lockstat_probe_t *probe = parg; 71 lockstat_probe_t *probe = parg;
72 72
73 ASSERT(!lockstat_probemap[LS_COMPRESS(probe->lsp_probe)]); 73 ASSERT(!lockstat_probemap[LS_COMPRESS(probe->lsp_probe)]);
74 74
75 lockstat_probemap[LS_COMPRESS(probe->lsp_probe)] = id; 
76 if (lockstat_dtrace_count++ == 0) { 75 if (lockstat_dtrace_count++ == 0) {
 76 LOCKSTAT_ENABLED_UPDATE_BEGIN();
77 lockstat_dtrace_enabled = LB_DTRACE; 77 lockstat_dtrace_enabled = LB_DTRACE;
78 LOCKSTAT_ENABLED_UPDATE(); 78 LOCKSTAT_ENABLED_UPDATE_END();
79 } 79 }
 80 atomic_store_relaxed(&lockstat_probemap[LS_COMPRESS(probe->lsp_probe)],
 81 id);
80 82
81 return 0; 83 return 0;
82} 84}
83 85
84/*ARGSUSED*/ 86/*ARGSUSED*/
85static void 87static void
86lockstat_disable(void *arg, dtrace_id_t id __unused, void *parg) 88lockstat_disable(void *arg, dtrace_id_t id __unused, void *parg)
87{ 89{
88 lockstat_probe_t *probe = parg; 90 lockstat_probe_t *probe = parg;
89 91
90 ASSERT(lockstat_probemap[LS_COMPRESS(probe->lsp_probe)]); 92 ASSERT(lockstat_probemap[LS_COMPRESS(probe->lsp_probe)]);
91 93
 94 atomic_store_relaxed(&lockstat_probemap[LS_COMPRESS(probe->lsp_probe)],
 95 0);
92 if (--lockstat_dtrace_count == 0) { 96 if (--lockstat_dtrace_count == 0) {
 97 LOCKSTAT_ENABLED_UPDATE_BEGIN();
93 lockstat_dtrace_enabled = 0; 98 lockstat_dtrace_enabled = 0;
94 LOCKSTAT_ENABLED_UPDATE(); 99 LOCKSTAT_ENABLED_UPDATE_END();
95 } 
96 100
97 lockstat_probemap[LS_COMPRESS(probe->lsp_probe)] = 0; 101 /*
 102 * Wait for all lockstat dtrace probe on all CPUs to
 103 * finish, now that they've been disabled.
 104 */
 105 xc_barrier(0);
 106 }
98} 107}
99 108
100/*ARGSUSED*/ 109/*ARGSUSED*/
101static void 110static void
102lockstat_provide(void *arg, dtrace_probedesc_t *desc) 111lockstat_provide(void *arg, dtrace_probedesc_t *desc)
103{ 112{
104 int i = 0; 113 int i = 0;
105 114
106 for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) { 115 for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) {
107 lockstat_probe_t *probe = &lockstat_probes[i]; 116 lockstat_probe_t *probe = &lockstat_probes[i];
108 117
109 if (dtrace_probe_lookup(lockstat_id, __UNCONST("kernel"), 118 if (dtrace_probe_lookup(lockstat_id, __UNCONST("kernel"),
110 __UNCONST(probe->lsp_func), __UNCONST(probe->lsp_name)) 119 __UNCONST(probe->lsp_func), __UNCONST(probe->lsp_name))
@@ -139,48 +148,47 @@ static dtrace_pattr_t lockstat_attr = { @@ -139,48 +148,47 @@ static dtrace_pattr_t lockstat_attr = {
139static dtrace_pops_t lockstat_pops = { 148static dtrace_pops_t lockstat_pops = {
140 lockstat_provide, 149 lockstat_provide,
141 NULL, 150 NULL,
142 lockstat_enable, 151 lockstat_enable,
143 lockstat_disable, 152 lockstat_disable,
144 NULL, 153 NULL,
145 NULL, 154 NULL,
146 NULL, 155 NULL,
147 NULL, 156 NULL,
148 NULL, 157 NULL,
149 lockstat_destroy 158 lockstat_destroy
150}; 159};
151 160
152static void 
153lockstat_barrier_xc(void *arg0 __unused, void *arg1 __unused) 
154{ 
155 
156 membar_consumer(); 
157} 
158 
159typedef void (*dtrace_probe_func_t)(dtrace_id_t, uintptr_t, uintptr_t, 161typedef void (*dtrace_probe_func_t)(dtrace_id_t, uintptr_t, uintptr_t,
160 uintptr_t, uintptr_t, uintptr_t); 162 uintptr_t, uintptr_t, uintptr_t);
161 163
162static bool 164static bool
163lockstat_cas_probe(dtrace_probe_func_t old, dtrace_probe_func_t new) 165lockstat_cas_probe(dtrace_probe_func_t old, dtrace_probe_func_t new)
164{ 166{
165 167
166 ASSERT(kernconfig_is_held()); 168 ASSERT(kernconfig_is_held());
167 169
168 if (lockstat_probe_func != old) 170 if (lockstat_probe_func != old)
169 return false; 171 return false;
170 172
171 lockstat_probe_func = new; 173 lockstat_probe_func = new;
172 membar_producer(); 174
173 xc_wait(xc_broadcast(0, lockstat_barrier_xc, NULL, NULL)); 175 /*
 176 * Make sure that the probe function is initialized on all CPUs
 177 * before we enable the lockstat probe by setting
 178 * lockstat_probemap[...].
 179 */
 180 xc_barrier(0);
 181
174 return true; 182 return true;
175} 183}
176 184
177static int 185static int
178lockstat_init(void) 186lockstat_init(void)
179{ 187{
180 int error; 188 int error;
181 bool ok; 189 bool ok;
182 190
183 /* Install the probe function. */ 191 /* Install the probe function. */
184 ok = lockstat_cas_probe(lockstat_probe_stub, dtrace_probe); 192 ok = lockstat_cas_probe(lockstat_probe_stub, dtrace_probe);
185 if (!ok) { 193 if (!ok) {
186 printf("dtrace_lockstat: lockstat probe already installed\n"); 194 printf("dtrace_lockstat: lockstat probe already installed\n");

cvs diff -r1.27 -r1.28 src/sys/dev/lockstat.c (expand / switch to unified diff)

--- src/sys/dev/lockstat.c 2020/05/23 23:42:42 1.27
+++ src/sys/dev/lockstat.c 2022/02/27 14:16:12 1.28
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: lockstat.c,v 1.27 2020/05/23 23:42:42 ad Exp $ */ 1/* $NetBSD: lockstat.c,v 1.28 2022/02/27 14:16:12 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2006, 2007, 2019 The NetBSD Foundation, Inc. 4 * Copyright (c) 2006, 2007, 2019 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran. 8 * by Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -31,39 +31,40 @@ @@ -31,39 +31,40 @@
31 31
32/* 32/*
33 * Lock statistics driver, providing kernel support for the lockstat(8) 33 * Lock statistics driver, providing kernel support for the lockstat(8)
34 * command. 34 * command.
35 * 35 *
36 * We use a global lock word (lockstat_lock) to track device opens. 36 * We use a global lock word (lockstat_lock) to track device opens.
37 * Only one thread can hold the device at a time, providing a global lock. 37 * Only one thread can hold the device at a time, providing a global lock.
38 * 38 *
39 * XXX Timings for contention on sleep locks are currently incorrect. 39 * XXX Timings for contention on sleep locks are currently incorrect.
40 * XXX Convert this to use timecounters! 40 * XXX Convert this to use timecounters!
41 */ 41 */
42 42
43#include <sys/cdefs.h> 43#include <sys/cdefs.h>
44__KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.27 2020/05/23 23:42:42 ad Exp $"); 44__KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.28 2022/02/27 14:16:12 riastradh Exp $");
45 45
46#include <sys/types.h> 46#include <sys/types.h>
47#include <sys/param.h> 47#include <sys/param.h>
48#include <sys/proc.h>  48#include <sys/proc.h>
49#include <sys/resourcevar.h> 49#include <sys/resourcevar.h>
50#include <sys/systm.h> 50#include <sys/systm.h>
51#include <sys/kernel.h> 51#include <sys/kernel.h>
52#include <sys/kmem.h> 52#include <sys/kmem.h>
53#include <sys/conf.h> 53#include <sys/conf.h>
54#include <sys/cpu.h> 54#include <sys/cpu.h>
55#include <sys/syslog.h> 55#include <sys/syslog.h>
56#include <sys/atomic.h> 56#include <sys/atomic.h>
 57#include <sys/xcall.h>
57 58
58#include <dev/lockstat.h> 59#include <dev/lockstat.h>
59 60
60#include <machine/lock.h> 61#include <machine/lock.h>
61 62
62#include "ioconf.h" 63#include "ioconf.h"
63 64
64#ifndef __HAVE_CPU_COUNTER 65#ifndef __HAVE_CPU_COUNTER
65#error CPU counters not available 66#error CPU counters not available
66#endif 67#endif
67 68
68#if LONG_BIT == 64 69#if LONG_BIT == 64
69#define LOCKSTAT_HASH_SHIFT 3 70#define LOCKSTAT_HASH_SHIFT 3
@@ -91,26 +92,27 @@ typedef struct lslist lslist_t; @@ -91,26 +92,27 @@ typedef struct lslist lslist_t;
91void lockstat_start(lsenable_t *); 92void lockstat_start(lsenable_t *);
92int lockstat_alloc(lsenable_t *); 93int lockstat_alloc(lsenable_t *);
93void lockstat_init_tables(lsenable_t *); 94void lockstat_init_tables(lsenable_t *);
94int lockstat_stop(lsdisable_t *); 95int lockstat_stop(lsdisable_t *);
95void lockstat_free(void); 96void lockstat_free(void);
96 97
97dev_type_open(lockstat_open); 98dev_type_open(lockstat_open);
98dev_type_close(lockstat_close); 99dev_type_close(lockstat_close);
99dev_type_read(lockstat_read); 100dev_type_read(lockstat_read);
100dev_type_ioctl(lockstat_ioctl); 101dev_type_ioctl(lockstat_ioctl);
101 102
102volatile u_int lockstat_enabled; 103volatile u_int lockstat_enabled;
103volatile u_int lockstat_dev_enabled; 104volatile u_int lockstat_dev_enabled;
 105__cpu_simple_lock_t lockstat_enabled_lock;
104uintptr_t lockstat_csstart; 106uintptr_t lockstat_csstart;
105uintptr_t lockstat_csend; 107uintptr_t lockstat_csend;
106uintptr_t lockstat_csmask; 108uintptr_t lockstat_csmask;
107uintptr_t lockstat_lamask; 109uintptr_t lockstat_lamask;
108uintptr_t lockstat_lockstart; 110uintptr_t lockstat_lockstart;
109uintptr_t lockstat_lockend; 111uintptr_t lockstat_lockend;
110__cpu_simple_lock_t lockstat_lock; 112__cpu_simple_lock_t lockstat_lock;
111lwp_t *lockstat_lwp; 113lwp_t *lockstat_lwp;
112lsbuf_t *lockstat_baseb; 114lsbuf_t *lockstat_baseb;
113size_t lockstat_sizeb; 115size_t lockstat_sizeb;
114int lockstat_busy; 116int lockstat_busy;
115struct timespec lockstat_stime; 117struct timespec lockstat_stime;
116 118
@@ -144,26 +146,27 @@ const struct cdevsw lockstat_cdevsw = { @@ -144,26 +146,27 @@ const struct cdevsw lockstat_cdevsw = {
144 .d_flag = D_OTHER | D_MPSAFE 146 .d_flag = D_OTHER | D_MPSAFE
145}; 147};
146 148
147/* 149/*
148 * Called when the pseudo-driver is attached. 150 * Called when the pseudo-driver is attached.
149 */ 151 */
150void 152void
151lockstatattach(int nunits) 153lockstatattach(int nunits)
152{ 154{
153 155
154 (void)nunits; 156 (void)nunits;
155 157
156 __cpu_simple_lock_init(&lockstat_lock); 158 __cpu_simple_lock_init(&lockstat_lock);
 159 __cpu_simple_lock_init(&lockstat_enabled_lock);
157} 160}
158 161
159/* 162/*
160 * Prepare the per-CPU tables for use, or clear down tables when tracing is 163 * Prepare the per-CPU tables for use, or clear down tables when tracing is
161 * stopped. 164 * stopped.
162 */ 165 */
163void 166void
164lockstat_init_tables(lsenable_t *le) 167lockstat_init_tables(lsenable_t *le)
165{ 168{
166 int i, per, slop, cpuno; 169 int i, per, slop, cpuno;
167 CPU_INFO_ITERATOR cii; 170 CPU_INFO_ITERATOR cii;
168 struct cpu_info *ci; 171 struct cpu_info *ci;
169 lscpu_t *lc; 172 lscpu_t *lc;
@@ -225,56 +228,72 @@ lockstat_start(lsenable_t *le) @@ -225,56 +228,72 @@ lockstat_start(lsenable_t *le)
225 else 228 else
226 lockstat_csmask = 0; 229 lockstat_csmask = 0;
227 230
228 if ((le->le_flags & LE_LOCK) != 0) 231 if ((le->le_flags & LE_LOCK) != 0)
229 lockstat_lamask = (uintptr_t)-1LL; 232 lockstat_lamask = (uintptr_t)-1LL;
230 else 233 else
231 lockstat_lamask = 0; 234 lockstat_lamask = 0;
232 235
233 lockstat_csstart = le->le_csstart; 236 lockstat_csstart = le->le_csstart;
234 lockstat_csend = le->le_csend; 237 lockstat_csend = le->le_csend;
235 lockstat_lockstart = le->le_lockstart; 238 lockstat_lockstart = le->le_lockstart;
236 lockstat_lockstart = le->le_lockstart; 239 lockstat_lockstart = le->le_lockstart;
237 lockstat_lockend = le->le_lockend; 240 lockstat_lockend = le->le_lockend;
238 membar_sync(); 241
 242 /*
 243 * Ensure everything is initialized on all CPUs, by issuing a
 244 * null xcall with the side effect of a release barrier on this
 245 * CPU and an acquire barrier on all other CPUs, before they
 246 * can witness any flags set in lockstat_dev_enabled -- this
 247 * way we don't need to add any barriers in lockstat_event.
 248 */
 249 xc_barrier(0);
 250
 251 /*
 252 * Start timing after the xcall, so we don't spuriously count
 253 * xcall communication time, but before flipping the switch, so
 254 * we don't dirty sample with locks taken in the timecounter.
 255 */
239 getnanotime(&lockstat_stime); 256 getnanotime(&lockstat_stime);
240 lockstat_dev_enabled = le->le_mask; 257
241 LOCKSTAT_ENABLED_UPDATE(); 258 LOCKSTAT_ENABLED_UPDATE_BEGIN();
 259 atomic_store_relaxed(&lockstat_dev_enabled, le->le_mask);
 260 LOCKSTAT_ENABLED_UPDATE_END();
242} 261}
243 262
244/* 263/*
245 * Stop collecting lock statistics. 264 * Stop collecting lock statistics.
246 */ 265 */
247int 266int
248lockstat_stop(lsdisable_t *ld) 267lockstat_stop(lsdisable_t *ld)
249{ 268{
250 CPU_INFO_ITERATOR cii; 269 CPU_INFO_ITERATOR cii;
251 struct cpu_info *ci; 270 struct cpu_info *ci;
252 u_int cpuno, overflow; 271 u_int cpuno, overflow;
253 struct timespec ts; 272 struct timespec ts;
254 int error; 273 int error;
255 lwp_t *l; 274 lwp_t *l;
256 275
257 /* coverity[assert_side_effect] */ 276 /* coverity[assert_side_effect] */
258 KASSERT(lockstat_dev_enabled); 277 KASSERT(lockstat_dev_enabled);
259 278
260 /* 279 /*
261 * Set enabled false, force a write barrier, and wait for other CPUs 280 * Disable and wait for other CPUs to exit lockstat_event().
262 * to exit lockstat_event(). 
263 */ 281 */
264 lockstat_dev_enabled = 0; 282 LOCKSTAT_ENABLED_UPDATE_BEGIN();
265 LOCKSTAT_ENABLED_UPDATE(); 283 atomic_store_relaxed(&lockstat_dev_enabled, 0);
 284 LOCKSTAT_ENABLED_UPDATE_END();
266 getnanotime(&ts); 285 getnanotime(&ts);
267 tsleep(&lockstat_stop, PPAUSE, "lockstat", mstohz(10)); 286 xc_barrier(0);
268 287
269 /* 288 /*
270 * Did we run out of buffers while tracing? 289 * Did we run out of buffers while tracing?
271 */ 290 */
272 overflow = 0; 291 overflow = 0;
273 for (CPU_INFO_FOREACH(cii, ci)) 292 for (CPU_INFO_FOREACH(cii, ci))
274 overflow += ((lscpu_t *)ci->ci_lockstat)->lc_overflow; 293 overflow += ((lscpu_t *)ci->ci_lockstat)->lc_overflow;
275 294
276 if (overflow != 0) { 295 if (overflow != 0) {
277 error = EOVERFLOW; 296 error = EOVERFLOW;
278 log(LOG_NOTICE, "lockstat: %d buffer allocations failed\n", 297 log(LOG_NOTICE, "lockstat: %d buffer allocations failed\n",
279 overflow); 298 overflow);
280 } else 299 } else
@@ -360,32 +379,34 @@ lockstat_free(void) @@ -360,32 +379,34 @@ lockstat_free(void)
360void 379void
361lockstat_event(uintptr_t lock, uintptr_t callsite, u_int flags, u_int count, 380lockstat_event(uintptr_t lock, uintptr_t callsite, u_int flags, u_int count,
362 uint64_t cycles) 381 uint64_t cycles)
363{ 382{
364 lslist_t *ll; 383 lslist_t *ll;
365 lscpu_t *lc; 384 lscpu_t *lc;
366 lsbuf_t *lb; 385 lsbuf_t *lb;
367 u_int event; 386 u_int event;
368 int s; 387 int s;
369 388
370#ifdef KDTRACE_HOOKS 389#ifdef KDTRACE_HOOKS
371 uint32_t id; 390 uint32_t id;
372 CTASSERT((LS_NPROBES & (LS_NPROBES - 1)) == 0); 391 CTASSERT((LS_NPROBES & (LS_NPROBES - 1)) == 0);
373 if ((id = lockstat_probemap[LS_COMPRESS(flags)]) != 0) 392 if ((id = atomic_load_relaxed(&lockstat_probemap[LS_COMPRESS(flags)]))
 393 != 0)
374 (*lockstat_probe_func)(id, lock, callsite, flags, count, 394 (*lockstat_probe_func)(id, lock, callsite, flags, count,
375 cycles); 395 cycles);
376#endif 396#endif
377 397
378 if ((flags & lockstat_dev_enabled) != flags || count == 0) 398 if ((flags & atomic_load_relaxed(&lockstat_dev_enabled)) != flags ||
 399 count == 0)
379 return; 400 return;
380 if (lock < lockstat_lockstart || lock > lockstat_lockend) 401 if (lock < lockstat_lockstart || lock > lockstat_lockend)
381 return; 402 return;
382 if (callsite < lockstat_csstart || callsite > lockstat_csend) 403 if (callsite < lockstat_csstart || callsite > lockstat_csend)
383 return; 404 return;
384 405
385 callsite &= lockstat_csmask; 406 callsite &= lockstat_csmask;
386 lock &= lockstat_lamask; 407 lock &= lockstat_lamask;
387 408
388 /* 409 /*
389 * Find the table for this lock+callsite pair, and try to locate a 410 * Find the table for this lock+callsite pair, and try to locate a
390 * buffer with the same key. 411 * buffer with the same key.
391 */ 412 */
@@ -477,27 +498,27 @@ lockstat_ioctl(dev_t dev, u_long cmd, vo @@ -477,27 +498,27 @@ lockstat_ioctl(dev_t dev, u_long cmd, vo
477 switch (cmd) { 498 switch (cmd) {
478 case IOC_LOCKSTAT_GVERSION: 499 case IOC_LOCKSTAT_GVERSION:
479 *(int *)data = LS_VERSION; 500 *(int *)data = LS_VERSION;
480 error = 0; 501 error = 0;
481 break; 502 break;
482 503
483 case IOC_LOCKSTAT_ENABLE: 504 case IOC_LOCKSTAT_ENABLE:
484 le = (lsenable_t *)data; 505 le = (lsenable_t *)data;
485 506
486 if (!cpu_hascounter()) { 507 if (!cpu_hascounter()) {
487 error = ENODEV; 508 error = ENODEV;
488 break; 509 break;
489 } 510 }
490 if (lockstat_dev_enabled) { 511 if (atomic_load_relaxed(&lockstat_dev_enabled)) {
491 error = EBUSY; 512 error = EBUSY;
492 break; 513 break;
493 } 514 }
494 515
495 /* 516 /*
496 * Sanitize the arguments passed in and set up filtering. 517 * Sanitize the arguments passed in and set up filtering.
497 */ 518 */
498 if (le->le_nbufs == 0) { 519 if (le->le_nbufs == 0) {
499 le->le_nbufs = MIN(LOCKSTAT_DEFBUFS * ncpu, 520 le->le_nbufs = MIN(LOCKSTAT_DEFBUFS * ncpu,
500 LOCKSTAT_MAXBUFS); 521 LOCKSTAT_MAXBUFS);
501 } else if (le->le_nbufs > LOCKSTAT_MAXBUFS || 522 } else if (le->le_nbufs > LOCKSTAT_MAXBUFS ||
502 le->le_nbufs < LOCKSTAT_MINBUFS) { 523 le->le_nbufs < LOCKSTAT_MINBUFS) {
503 error = EINVAL; 524 error = EINVAL;
@@ -514,27 +535,27 @@ lockstat_ioctl(dev_t dev, u_long cmd, vo @@ -514,27 +535,27 @@ lockstat_ioctl(dev_t dev, u_long cmd, vo
514 if ((le->le_mask & LB_EVENT_MASK) == 0) 535 if ((le->le_mask & LB_EVENT_MASK) == 0)
515 return EINVAL; 536 return EINVAL;
516 if ((le->le_mask & LB_LOCK_MASK) == 0) 537 if ((le->le_mask & LB_LOCK_MASK) == 0)
517 return EINVAL; 538 return EINVAL;
518 539
519 /* 540 /*
520 * Start tracing. 541 * Start tracing.
521 */ 542 */
522 if ((error = lockstat_alloc(le)) == 0) 543 if ((error = lockstat_alloc(le)) == 0)
523 lockstat_start(le); 544 lockstat_start(le);
524 break; 545 break;
525 546
526 case IOC_LOCKSTAT_DISABLE: 547 case IOC_LOCKSTAT_DISABLE:
527 if (!lockstat_dev_enabled) 548 if (!atomic_load_relaxed(&lockstat_dev_enabled))
528 error = EINVAL; 549 error = EINVAL;
529 else 550 else
530 error = lockstat_stop((lsdisable_t *)data); 551 error = lockstat_stop((lsdisable_t *)data);
531 break; 552 break;
532 553
533 default: 554 default:
534 error = ENOTTY; 555 error = ENOTTY;
535 break; 556 break;
536 } 557 }
537 558
538 return error; 559 return error;
539} 560}
540 561

cvs diff -r1.14 -r1.15 src/sys/dev/lockstat.h (expand / switch to unified diff)

--- src/sys/dev/lockstat.h 2016/01/24 01:01:11 1.14
+++ src/sys/dev/lockstat.h 2022/02/27 14:16:12 1.15
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: lockstat.h,v 1.14 2016/01/24 01:01:11 christos Exp $ */ 1/* $NetBSD: lockstat.h,v 1.15 2022/02/27 14:16:12 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran. 8 * by Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -28,27 +28,29 @@ @@ -28,27 +28,29 @@
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#ifndef _SYS_LOCKSTAT_H_ 32#ifndef _SYS_LOCKSTAT_H_
33#define _SYS_LOCKSTAT_H_ 33#define _SYS_LOCKSTAT_H_
34 34
35#ifdef _KERNEL_OPT 35#ifdef _KERNEL_OPT
36#include "opt_dtrace.h" 36#include "opt_dtrace.h"
37#include <lockstat.h> 37#include <lockstat.h>
38#endif 38#endif
39 39
40#include <sys/types.h> 40#include <sys/types.h>
 41
41#include <sys/ioccom.h> 42#include <sys/ioccom.h>
 43#include <sys/lock.h>
42#include <sys/queue.h> 44#include <sys/queue.h>
43#include <sys/time.h> 45#include <sys/time.h>
44 46
45#if defined(_KERNEL) && defined(__HAVE_CPU_COUNTER) 47#if defined(_KERNEL) && defined(__HAVE_CPU_COUNTER)
46#include <machine/cpu_counter.h> 48#include <machine/cpu_counter.h>
47#endif 49#endif
48 50
49/* 51/*
50 * Interface version. The interface is not designed to provide 52 * Interface version. The interface is not designed to provide
51 * compatibility across NetBSD releases. 53 * compatibility across NetBSD releases.
52 */ 54 */
53 55
54#define IOC_LOCKSTAT_GVERSION _IOR('L', 0, int) 56#define IOC_LOCKSTAT_GVERSION _IOR('L', 0, int)
@@ -149,27 +151,27 @@ do { \ @@ -149,27 +151,27 @@ do { \
149 (type), (count), (time)); \ 151 (type), (count), (time)); \
150} while (/* CONSTCOND */ 0); 152} while (/* CONSTCOND */ 0);
151 153
152#define LOCKSTAT_EVENT_RA(flag, lock, type, count, time, ra) \ 154#define LOCKSTAT_EVENT_RA(flag, lock, type, count, time, ra) \
153do { \ 155do { \
154 if (__predict_false(flag)) \ 156 if (__predict_false(flag)) \
155 lockstat_event((uintptr_t)(lock), (uintptr_t)ra, \ 157 lockstat_event((uintptr_t)(lock), (uintptr_t)ra, \
156 (type), (count), (time)); \ 158 (type), (count), (time)); \
157} while (/* CONSTCOND */ 0); 159} while (/* CONSTCOND */ 0);
158 160
159#define LOCKSTAT_TIMER(name) uint64_t name = 0 161#define LOCKSTAT_TIMER(name) uint64_t name = 0
160#define LOCKSTAT_COUNTER(name) uint64_t name = 0 162#define LOCKSTAT_COUNTER(name) uint64_t name = 0
161#define LOCKSTAT_FLAG(name) int name 163#define LOCKSTAT_FLAG(name) int name
162#define LOCKSTAT_ENTER(name) name = lockstat_enabled 164#define LOCKSTAT_ENTER(name) name = atomic_load_relaxed(&lockstat_enabled)
163#define LOCKSTAT_EXIT(name) 165#define LOCKSTAT_EXIT(name)
164 166
165#define LOCKSTAT_START_TIMER(flag, name) \ 167#define LOCKSTAT_START_TIMER(flag, name) \
166do { \ 168do { \
167 if (__predict_false(flag)) \ 169 if (__predict_false(flag)) \
168 (name) -= cpu_counter(); \ 170 (name) -= cpu_counter(); \
169} while (/* CONSTCOND */ 0) 171} while (/* CONSTCOND */ 0)
170 172
171#define LOCKSTAT_STOP_TIMER(flag, name) \ 173#define LOCKSTAT_STOP_TIMER(flag, name) \
172do { \ 174do { \
173 if (__predict_false(flag)) \ 175 if (__predict_false(flag)) \
174 (name) += cpu_counter(); \ 176 (name) += cpu_counter(); \
175} while (/* CONSTCOND */ 0) 177} while (/* CONSTCOND */ 0)
@@ -204,23 +206,32 @@ extern volatile u_int lockstat_dtrace_en @@ -204,23 +206,32 @@ extern volatile u_int lockstat_dtrace_en
204#define LS_NPROBES 0x20 /* 5 bits */ 206#define LS_NPROBES 0x20 /* 5 bits */
205 207
206extern uint32_t lockstat_probemap[]; 208extern uint32_t lockstat_probemap[];
207extern void (*lockstat_probe_func)(uint32_t, uintptr_t, uintptr_t, 209extern void (*lockstat_probe_func)(uint32_t, uintptr_t, uintptr_t,
208 uintptr_t, uintptr_t, uintptr_t); 210 uintptr_t, uintptr_t, uintptr_t);
209 211
210void lockstat_probe_stub(uint32_t, uintptr_t, uintptr_t, 212void lockstat_probe_stub(uint32_t, uintptr_t, uintptr_t,
211 uintptr_t, uintptr_t, uintptr_t); 213 uintptr_t, uintptr_t, uintptr_t);
212#else 214#else
213#define KDTRACE_LOCKSTAT_ENABLED 0 215#define KDTRACE_LOCKSTAT_ENABLED 0
214#endif 216#endif
215 217
216#if defined(_KERNEL) && NLOCKSTAT > 0 218#if defined(_KERNEL) && NLOCKSTAT > 0
 219extern __cpu_simple_lock_t lockstat_enabled_lock;
217extern volatile u_int lockstat_enabled; 220extern volatile u_int lockstat_enabled;
218extern volatile u_int lockstat_dev_enabled; 221extern volatile u_int lockstat_dev_enabled;
219 222
220#define LOCKSTAT_ENABLED_UPDATE() do { \ 223#define LOCKSTAT_ENABLED_UPDATE_BEGIN() do \
221 lockstat_enabled = lockstat_dev_enabled | KDTRACE_LOCKSTAT_ENABLED; \ 224{ \
222 membar_producer(); \ 225 __cpu_simple_lock(&lockstat_enabled_lock); \
223 } while (/*CONSTCOND*/0) 226} while (/*CONSTCOND*/0)
 227
 228#define LOCKSTAT_ENABLED_UPDATE_END() do \
 229{ \
 230 atomic_store_relaxed(&lockstat_enabled, \
 231 lockstat_dev_enabled | KDTRACE_LOCKSTAT_ENABLED); \
 232 __cpu_simple_unlock(&lockstat_enabled_lock); \
 233} while (/*CONSTCOND*/0)
 234
224#endif 235#endif
225 236
226#endif /* _SYS_LOCKSTAT_H_ */ 237#endif /* _SYS_LOCKSTAT_H_ */