Print this page
Add boot_hrtime to global and zone kstats.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/kstat_fr.c
+++ new/usr/src/uts/common/os/kstat_fr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2014, Joyent, Inc. All rights reserved.
24 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 + * Copyright 2016 Garrett D'Amore
25 26 */
26 27
27 28 /*
28 29 * Kernel statistics framework
29 30 */
30 31
31 32 #include <sys/types.h>
32 33 #include <sys/time.h>
33 34 #include <sys/systm.h>
34 35 #include <sys/vmsystm.h>
35 36 #include <sys/t_lock.h>
36 37 #include <sys/param.h>
37 38 #include <sys/errno.h>
38 39 #include <sys/vmem.h>
39 40 #include <sys/sysmacros.h>
40 41 #include <sys/cmn_err.h>
41 42 #include <sys/kstat.h>
42 43 #include <sys/sysinfo.h>
43 44 #include <sys/cpuvar.h>
44 45 #include <sys/fcntl.h>
45 46 #include <sys/flock.h>
46 47 #include <sys/vnode.h>
47 48 #include <sys/vfs.h>
48 49 #include <sys/dnlc.h>
49 50 #include <sys/var.h>
50 51 #include <sys/debug.h>
51 52 #include <sys/kobj.h>
52 53 #include <sys/avl.h>
53 54 #include <sys/pool_pset.h>
54 55 #include <sys/cpupart.h>
55 56 #include <sys/zone.h>
56 57 #include <sys/loadavg.h>
57 58 #include <vm/page.h>
58 59 #include <vm/anon.h>
59 60 #include <vm/seg_kmem.h>
60 61
61 62 /*
62 63 * Global lock to protect the AVL trees and kstat_chain_id.
63 64 */
64 65 static kmutex_t kstat_chain_lock;
65 66
66 67 /*
67 68 * Every install/delete kstat bumps kstat_chain_id. This is used by:
68 69 *
69 70 * (1) /dev/kstat, to detect changes in the kstat chain across ioctls;
70 71 *
71 72 * (2) kstat_create(), to assign a KID (kstat ID) to each new kstat.
72 73 * /dev/kstat uses the KID as a cookie for kstat lookups.
73 74 *
74 75 * We reserve the first two IDs because some kstats are created before
75 76 * the well-known ones (kstat_headers = 0, kstat_types = 1).
76 77 *
77 78 * We also bump the kstat_chain_id if a zone is gaining or losing visibility
78 79 * into a particular kstat, which is logically equivalent to a kstat being
79 80 * installed/deleted.
80 81 */
81 82
82 83 kid_t kstat_chain_id = 2;
83 84
84 85 /*
85 86 * As far as zones are concerned, there are 3 types of kstat:
86 87 *
87 88 * 1) Those which have a well-known name, and which should return per-zone data
88 89 * depending on which zone is doing the kstat_read(). sockfs:0:sock_unix_list
89 90 * is an example of this type of kstat.
90 91 *
91 92 * 2) Those which should only be exported to a particular list of zones.
92 93 * For example, in the case of nfs:*:mntinfo, we don't want zone A to be
93 94 * able to see NFS mounts associated with zone B, while we want the
94 95 * global zone to be able to see all mounts on the system.
95 96 *
96 97 * 3) Those that can be exported to all zones. Most system-related
97 98 * kstats fall within this category.
98 99 *
99 100 * An ekstat_t thus contains a list of kstats that the zone is to be
100 101 * exported to. The lookup of a name:instance:module thus translates to a
101 102 * lookup of name:instance:module:myzone; if the kstat is not exported
102 103 * to all zones, and does not have the caller's zoneid explicitly
103 104 * enumerated in the list of zones to be exported to, it is the same as
104 105 * if the kstat didn't exist.
105 106 *
106 107 * Writing to kstats is currently disallowed from within a non-global
107 108 * zone, although this restriction could be removed in the future.
108 109 */
109 110 typedef struct kstat_zone {
110 111 zoneid_t zoneid;
111 112 struct kstat_zone *next;
112 113 } kstat_zone_t;
113 114
114 115 /*
115 116 * Extended kstat structure -- for internal use only.
116 117 */
117 118 typedef struct ekstat {
118 119 kstat_t e_ks; /* the kstat itself */
119 120 size_t e_size; /* total allocation size */
120 121 kthread_t *e_owner; /* thread holding this kstat */
121 122 kcondvar_t e_cv; /* wait for owner == NULL */
122 123 avl_node_t e_avl_bykid; /* AVL tree to sort by KID */
123 124 avl_node_t e_avl_byname; /* AVL tree to sort by name */
124 125 kstat_zone_t e_zone; /* zone to export stats to */
125 126 } ekstat_t;
126 127
127 128 static uint64_t kstat_initial[8192];
128 129 static void *kstat_initial_ptr = kstat_initial;
129 130 static size_t kstat_initial_avail = sizeof (kstat_initial);
130 131 static vmem_t *kstat_arena;
131 132
132 133 #define KSTAT_ALIGN (sizeof (uint64_t))
133 134
134 135 static avl_tree_t kstat_avl_bykid;
135 136 static avl_tree_t kstat_avl_byname;
136 137
137 138 /*
138 139 * Various pointers we need to create kstats at boot time in kstat_init()
139 140 */
140 141 extern kstat_named_t *segmapcnt_ptr;
↓ open down ↓ |
106 lines elided |
↑ open up ↑ |
141 142 extern uint_t segmapcnt_ndata;
142 143 extern int segmap_kstat_update(kstat_t *, int);
143 144 extern kstat_named_t *biostats_ptr;
144 145 extern uint_t biostats_ndata;
145 146 extern kstat_named_t *pollstats_ptr;
146 147 extern uint_t pollstats_ndata;
147 148
148 149 extern int vac;
149 150 extern uint_t nproc;
150 151 extern time_t boot_time;
152 +extern hrtime_t boot_hrtime;
151 153 extern sysinfo_t sysinfo;
152 154 extern vminfo_t vminfo;
153 155
154 156 struct {
155 157 kstat_named_t ncpus;
156 158 kstat_named_t lbolt;
157 159 kstat_named_t deficit;
158 160 kstat_named_t clk_intr;
159 161 kstat_named_t vac;
160 162 kstat_named_t nproc;
161 163 kstat_named_t avenrun_1min;
162 164 kstat_named_t avenrun_5min;
163 165 kstat_named_t avenrun_15min;
164 166 kstat_named_t boot_time;
167 + kstat_named_t boot_hrtime;
165 168 kstat_named_t nsec_per_tick;
166 169 } system_misc_kstat = {
167 170 { "ncpus", KSTAT_DATA_UINT32 },
168 171 { "lbolt", KSTAT_DATA_UINT32 },
169 172 { "deficit", KSTAT_DATA_UINT32 },
170 173 { "clk_intr", KSTAT_DATA_UINT32 },
171 174 { "vac", KSTAT_DATA_UINT32 },
172 175 { "nproc", KSTAT_DATA_UINT32 },
173 176 { "avenrun_1min", KSTAT_DATA_UINT32 },
174 177 { "avenrun_5min", KSTAT_DATA_UINT32 },
175 178 { "avenrun_15min", KSTAT_DATA_UINT32 },
176 179 { "boot_time", KSTAT_DATA_UINT32 },
180 + { "boot_hrtime", KSTAT_DATA_TIME },
177 181 { "nsec_per_tick", KSTAT_DATA_UINT32 },
178 182 };
179 183
180 184 struct {
181 185 kstat_named_t physmem;
182 186 kstat_named_t nalloc;
183 187 kstat_named_t nfree;
184 188 kstat_named_t nalloc_calls;
185 189 kstat_named_t nfree_calls;
186 190 kstat_named_t kernelbase;
187 191 kstat_named_t econtig;
188 192 kstat_named_t freemem;
189 193 kstat_named_t availrmem;
190 194 kstat_named_t lotsfree;
191 195 kstat_named_t desfree;
192 196 kstat_named_t minfree;
193 197 kstat_named_t fastscan;
194 198 kstat_named_t slowscan;
195 199 kstat_named_t nscan;
196 200 kstat_named_t desscan;
197 201 kstat_named_t pp_kernel;
198 202 kstat_named_t pagesfree;
199 203 kstat_named_t pageslocked;
200 204 kstat_named_t pagestotal;
201 205 } system_pages_kstat = {
202 206 { "physmem", KSTAT_DATA_ULONG },
203 207 { "nalloc", KSTAT_DATA_ULONG },
204 208 { "nfree", KSTAT_DATA_ULONG },
205 209 { "nalloc_calls", KSTAT_DATA_ULONG },
206 210 { "nfree_calls", KSTAT_DATA_ULONG },
207 211 { "kernelbase", KSTAT_DATA_ULONG },
208 212 { "econtig", KSTAT_DATA_ULONG },
209 213 { "freemem", KSTAT_DATA_ULONG },
210 214 { "availrmem", KSTAT_DATA_ULONG },
211 215 { "lotsfree", KSTAT_DATA_ULONG },
212 216 { "desfree", KSTAT_DATA_ULONG },
213 217 { "minfree", KSTAT_DATA_ULONG },
214 218 { "fastscan", KSTAT_DATA_ULONG },
215 219 { "slowscan", KSTAT_DATA_ULONG },
216 220 { "nscan", KSTAT_DATA_ULONG },
217 221 { "desscan", KSTAT_DATA_ULONG },
218 222 { "pp_kernel", KSTAT_DATA_ULONG },
219 223 { "pagesfree", KSTAT_DATA_ULONG },
220 224 { "pageslocked", KSTAT_DATA_ULONG },
221 225 { "pagestotal", KSTAT_DATA_ULONG },
222 226 };
223 227
224 228 static int header_kstat_update(kstat_t *, int);
225 229 static int header_kstat_snapshot(kstat_t *, void *, int);
226 230 static int system_misc_kstat_update(kstat_t *, int);
227 231 static int system_pages_kstat_update(kstat_t *, int);
228 232
229 233 static struct {
230 234 char name[KSTAT_STRLEN];
231 235 size_t size;
232 236 uint_t min_ndata;
233 237 uint_t max_ndata;
234 238 } kstat_data_type[KSTAT_NUM_TYPES] = {
235 239 { "raw", 1, 0, INT_MAX },
236 240 { "name=value", sizeof (kstat_named_t), 0, INT_MAX },
237 241 { "interrupt", sizeof (kstat_intr_t), 1, 1 },
238 242 { "i/o", sizeof (kstat_io_t), 1, 1 },
239 243 { "event_timer", sizeof (kstat_timer_t), 0, INT_MAX },
240 244 };
241 245
242 246 int
243 247 kstat_zone_find(kstat_t *k, zoneid_t zoneid)
244 248 {
245 249 ekstat_t *e = (ekstat_t *)k;
246 250 kstat_zone_t *kz;
247 251
248 252 ASSERT(MUTEX_HELD(&kstat_chain_lock));
249 253 for (kz = &e->e_zone; kz != NULL; kz = kz->next) {
250 254 if (zoneid == ALL_ZONES || kz->zoneid == ALL_ZONES)
251 255 return (1);
252 256 if (zoneid == kz->zoneid)
253 257 return (1);
254 258 }
255 259 return (0);
256 260 }
257 261
258 262 void
259 263 kstat_zone_remove(kstat_t *k, zoneid_t zoneid)
260 264 {
261 265 ekstat_t *e = (ekstat_t *)k;
262 266 kstat_zone_t *kz, *t = NULL;
263 267
264 268 mutex_enter(&kstat_chain_lock);
265 269 if (zoneid == e->e_zone.zoneid) {
266 270 kz = e->e_zone.next;
267 271 ASSERT(kz != NULL);
268 272 e->e_zone.zoneid = kz->zoneid;
269 273 e->e_zone.next = kz->next;
270 274 goto out;
271 275 }
272 276 for (kz = &e->e_zone; kz->next != NULL; kz = kz->next) {
273 277 if (kz->next->zoneid == zoneid) {
274 278 t = kz->next;
275 279 kz->next = t->next;
276 280 break;
277 281 }
278 282 }
279 283 ASSERT(t != NULL); /* we removed something */
280 284 kz = t;
281 285 out:
282 286 kstat_chain_id++;
283 287 mutex_exit(&kstat_chain_lock);
284 288 kmem_free(kz, sizeof (*kz));
285 289 }
286 290
287 291 void
288 292 kstat_zone_add(kstat_t *k, zoneid_t zoneid)
289 293 {
290 294 ekstat_t *e = (ekstat_t *)k;
291 295 kstat_zone_t *kz;
292 296
293 297 kz = kmem_alloc(sizeof (*kz), KM_NOSLEEP);
294 298 if (kz == NULL)
295 299 return;
296 300 mutex_enter(&kstat_chain_lock);
297 301 kz->zoneid = zoneid;
298 302 kz->next = e->e_zone.next;
299 303 e->e_zone.next = kz;
300 304 kstat_chain_id++;
301 305 mutex_exit(&kstat_chain_lock);
302 306 }
303 307
304 308 /*
305 309 * Compare the list of zones for the given kstats, returning 0 if they match
306 310 * (ie, one list contains ALL_ZONES or both lists contain the same zoneid).
307 311 * In practice, this is called indirectly by kstat_hold_byname(), so one of the
308 312 * two lists always has one element, and this is an O(n) operation rather than
309 313 * O(n^2).
310 314 */
311 315 static int
312 316 kstat_zone_compare(ekstat_t *e1, ekstat_t *e2)
313 317 {
314 318 kstat_zone_t *kz1, *kz2;
315 319
316 320 ASSERT(MUTEX_HELD(&kstat_chain_lock));
317 321 for (kz1 = &e1->e_zone; kz1 != NULL; kz1 = kz1->next) {
318 322 for (kz2 = &e2->e_zone; kz2 != NULL; kz2 = kz2->next) {
319 323 if (kz1->zoneid == ALL_ZONES ||
320 324 kz2->zoneid == ALL_ZONES)
321 325 return (0);
322 326 if (kz1->zoneid == kz2->zoneid)
323 327 return (0);
324 328 }
325 329 }
326 330 return (e1->e_zone.zoneid < e2->e_zone.zoneid ? -1 : 1);
327 331 }
328 332
329 333 /*
330 334 * Support for keeping kstats sorted in AVL trees for fast lookups.
331 335 */
332 336 static int
333 337 kstat_compare_bykid(const void *a1, const void *a2)
334 338 {
335 339 const kstat_t *k1 = a1;
336 340 const kstat_t *k2 = a2;
337 341
338 342 if (k1->ks_kid < k2->ks_kid)
339 343 return (-1);
340 344 if (k1->ks_kid > k2->ks_kid)
341 345 return (1);
342 346 return (kstat_zone_compare((ekstat_t *)k1, (ekstat_t *)k2));
343 347 }
344 348
345 349 static int
346 350 kstat_compare_byname(const void *a1, const void *a2)
347 351 {
348 352 const kstat_t *k1 = a1;
349 353 const kstat_t *k2 = a2;
350 354 int s;
351 355
352 356 s = strcmp(k1->ks_module, k2->ks_module);
353 357 if (s > 0)
354 358 return (1);
355 359 if (s < 0)
356 360 return (-1);
357 361
358 362 if (k1->ks_instance < k2->ks_instance)
359 363 return (-1);
360 364 if (k1->ks_instance > k2->ks_instance)
361 365 return (1);
362 366
363 367 s = strcmp(k1->ks_name, k2->ks_name);
364 368 if (s > 0)
365 369 return (1);
366 370 if (s < 0)
367 371 return (-1);
368 372
369 373 return (kstat_zone_compare((ekstat_t *)k1, (ekstat_t *)k2));
370 374 }
371 375
372 376 static kstat_t *
373 377 kstat_hold(avl_tree_t *t, ekstat_t *template)
374 378 {
375 379 kstat_t *ksp;
376 380 ekstat_t *e;
377 381
378 382 mutex_enter(&kstat_chain_lock);
379 383 for (;;) {
380 384 ksp = avl_find(t, template, NULL);
381 385 if (ksp == NULL)
382 386 break;
383 387 e = (ekstat_t *)ksp;
384 388 if (e->e_owner == NULL) {
385 389 e->e_owner = curthread;
386 390 break;
387 391 }
388 392 cv_wait(&e->e_cv, &kstat_chain_lock);
389 393 }
390 394 mutex_exit(&kstat_chain_lock);
391 395 return (ksp);
392 396 }
393 397
394 398 void
395 399 kstat_rele(kstat_t *ksp)
396 400 {
397 401 ekstat_t *e = (ekstat_t *)ksp;
398 402
399 403 mutex_enter(&kstat_chain_lock);
400 404 ASSERT(e->e_owner == curthread);
401 405 e->e_owner = NULL;
402 406 cv_broadcast(&e->e_cv);
403 407 mutex_exit(&kstat_chain_lock);
404 408 }
405 409
406 410 kstat_t *
407 411 kstat_hold_bykid(kid_t kid, zoneid_t zoneid)
408 412 {
409 413 ekstat_t e;
410 414
411 415 e.e_ks.ks_kid = kid;
412 416 e.e_zone.zoneid = zoneid;
413 417 e.e_zone.next = NULL;
414 418
415 419 return (kstat_hold(&kstat_avl_bykid, &e));
416 420 }
417 421
418 422 kstat_t *
419 423 kstat_hold_byname(const char *ks_module, int ks_instance, const char *ks_name,
420 424 zoneid_t ks_zoneid)
421 425 {
422 426 ekstat_t e;
423 427
424 428 kstat_set_string(e.e_ks.ks_module, ks_module);
425 429 e.e_ks.ks_instance = ks_instance;
426 430 kstat_set_string(e.e_ks.ks_name, ks_name);
427 431 e.e_zone.zoneid = ks_zoneid;
428 432 e.e_zone.next = NULL;
429 433 return (kstat_hold(&kstat_avl_byname, &e));
430 434 }
431 435
432 436 static ekstat_t *
433 437 kstat_alloc(size_t size)
434 438 {
435 439 ekstat_t *e = NULL;
436 440
437 441 size = P2ROUNDUP(sizeof (ekstat_t) + size, KSTAT_ALIGN);
438 442
439 443 if (kstat_arena == NULL) {
440 444 if (size <= kstat_initial_avail) {
441 445 e = kstat_initial_ptr;
442 446 kstat_initial_ptr = (char *)kstat_initial_ptr + size;
443 447 kstat_initial_avail -= size;
444 448 }
445 449 } else {
446 450 e = vmem_alloc(kstat_arena, size, VM_NOSLEEP);
447 451 }
448 452
449 453 if (e != NULL) {
450 454 bzero(e, size);
451 455 e->e_size = size;
452 456 cv_init(&e->e_cv, NULL, CV_DEFAULT, NULL);
453 457 }
454 458
455 459 return (e);
456 460 }
457 461
458 462 static void
459 463 kstat_free(ekstat_t *e)
460 464 {
461 465 cv_destroy(&e->e_cv);
462 466 vmem_free(kstat_arena, e, e->e_size);
463 467 }
464 468
465 469 /*
466 470 * Create various system kstats.
467 471 */
468 472 void
469 473 kstat_init(void)
470 474 {
471 475 kstat_t *ksp;
472 476 ekstat_t *e;
473 477 avl_tree_t *t = &kstat_avl_bykid;
474 478
475 479 /*
476 480 * Set up the kstat vmem arena.
477 481 */
478 482 kstat_arena = vmem_create("kstat",
479 483 kstat_initial, sizeof (kstat_initial), KSTAT_ALIGN,
480 484 segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
481 485
482 486 /*
483 487 * Make initial kstats appear as though they were allocated.
484 488 */
485 489 for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER))
486 490 (void) vmem_xalloc(kstat_arena, e->e_size, KSTAT_ALIGN,
487 491 0, 0, e, (char *)e + e->e_size,
488 492 VM_NOSLEEP | VM_BESTFIT | VM_PANIC);
489 493
490 494 /*
491 495 * The mother of all kstats. The first kstat in the system, which
492 496 * always has KID 0, has the headers for all kstats (including itself)
493 497 * as its data. Thus, the kstat driver does not need any special
494 498 * interface to extract the kstat chain.
495 499 */
496 500 kstat_chain_id = 0;
497 501 ksp = kstat_create("unix", 0, "kstat_headers", "kstat", KSTAT_TYPE_RAW,
498 502 0, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
499 503 if (ksp) {
500 504 ksp->ks_lock = &kstat_chain_lock;
501 505 ksp->ks_update = header_kstat_update;
502 506 ksp->ks_snapshot = header_kstat_snapshot;
503 507 kstat_install(ksp);
504 508 } else {
505 509 panic("cannot create kstat 'kstat_headers'");
506 510 }
507 511
508 512 ksp = kstat_create("unix", 0, "kstat_types", "kstat",
509 513 KSTAT_TYPE_NAMED, KSTAT_NUM_TYPES, 0);
510 514 if (ksp) {
511 515 int i;
512 516 kstat_named_t *kn = KSTAT_NAMED_PTR(ksp);
513 517
514 518 for (i = 0; i < KSTAT_NUM_TYPES; i++) {
515 519 kstat_named_init(&kn[i], kstat_data_type[i].name,
516 520 KSTAT_DATA_ULONG);
517 521 kn[i].value.ul = i;
518 522 }
519 523 kstat_install(ksp);
520 524 }
521 525
522 526 ksp = kstat_create("unix", 0, "sysinfo", "misc", KSTAT_TYPE_RAW,
523 527 sizeof (sysinfo_t), KSTAT_FLAG_VIRTUAL);
524 528 if (ksp) {
525 529 ksp->ks_data = (void *) &sysinfo;
526 530 kstat_install(ksp);
527 531 }
528 532
529 533 ksp = kstat_create("unix", 0, "vminfo", "vm", KSTAT_TYPE_RAW,
530 534 sizeof (vminfo_t), KSTAT_FLAG_VIRTUAL);
531 535 if (ksp) {
532 536 ksp->ks_data = (void *) &vminfo;
533 537 kstat_install(ksp);
534 538 }
535 539
536 540 ksp = kstat_create("unix", 0, "segmap", "vm", KSTAT_TYPE_NAMED,
537 541 segmapcnt_ndata, KSTAT_FLAG_VIRTUAL);
538 542 if (ksp) {
539 543 ksp->ks_data = (void *) segmapcnt_ptr;
540 544 ksp->ks_update = segmap_kstat_update;
541 545 kstat_install(ksp);
542 546 }
543 547
544 548 ksp = kstat_create("unix", 0, "biostats", "misc", KSTAT_TYPE_NAMED,
545 549 biostats_ndata, KSTAT_FLAG_VIRTUAL);
546 550 if (ksp) {
547 551 ksp->ks_data = (void *) biostats_ptr;
548 552 kstat_install(ksp);
549 553 }
550 554
551 555 ksp = kstat_create("unix", 0, "var", "misc", KSTAT_TYPE_RAW,
552 556 sizeof (struct var), KSTAT_FLAG_VIRTUAL);
553 557 if (ksp) {
554 558 ksp->ks_data = (void *) &v;
555 559 kstat_install(ksp);
556 560 }
557 561
558 562 ksp = kstat_create("unix", 0, "system_misc", "misc", KSTAT_TYPE_NAMED,
559 563 sizeof (system_misc_kstat) / sizeof (kstat_named_t),
560 564 KSTAT_FLAG_VIRTUAL);
561 565 if (ksp) {
562 566 ksp->ks_data = (void *) &system_misc_kstat;
563 567 ksp->ks_update = system_misc_kstat_update;
564 568 kstat_install(ksp);
565 569 }
566 570
567 571 ksp = kstat_create("unix", 0, "system_pages", "pages", KSTAT_TYPE_NAMED,
568 572 sizeof (system_pages_kstat) / sizeof (kstat_named_t),
569 573 KSTAT_FLAG_VIRTUAL);
570 574 if (ksp) {
571 575 ksp->ks_data = (void *) &system_pages_kstat;
572 576 ksp->ks_update = system_pages_kstat_update;
573 577 kstat_install(ksp);
574 578 }
575 579
576 580 ksp = kstat_create("poll", 0, "pollstats", "misc", KSTAT_TYPE_NAMED,
577 581 pollstats_ndata, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
578 582
579 583 if (ksp) {
580 584 ksp->ks_data = pollstats_ptr;
581 585 kstat_install(ksp);
582 586 }
583 587 }
584 588
585 589 /*
586 590 * Caller of this should ensure that the string pointed by src
587 591 * doesn't change while kstat's lock is held. Not doing so defeats
588 592 * kstat's snapshot strategy as explained in <sys/kstat.h>
589 593 */
590 594 void
591 595 kstat_named_setstr(kstat_named_t *knp, const char *src)
592 596 {
593 597 if (knp->data_type != KSTAT_DATA_STRING)
594 598 panic("kstat_named_setstr('%p', '%p'): "
595 599 "named kstat is not of type KSTAT_DATA_STRING",
596 600 (void *)knp, (void *)src);
597 601
598 602 KSTAT_NAMED_STR_PTR(knp) = (char *)src;
599 603 if (src != NULL)
600 604 KSTAT_NAMED_STR_BUFLEN(knp) = strlen(src) + 1;
601 605 else
602 606 KSTAT_NAMED_STR_BUFLEN(knp) = 0;
603 607 }
604 608
605 609 void
606 610 kstat_set_string(char *dst, const char *src)
607 611 {
608 612 bzero(dst, KSTAT_STRLEN);
609 613 (void) strncpy(dst, src, KSTAT_STRLEN - 1);
610 614 }
611 615
612 616 void
613 617 kstat_named_init(kstat_named_t *knp, const char *name, uchar_t data_type)
614 618 {
615 619 kstat_set_string(knp->name, name);
616 620 knp->data_type = data_type;
617 621
618 622 if (data_type == KSTAT_DATA_STRING)
619 623 kstat_named_setstr(knp, NULL);
620 624 }
621 625
622 626 void
623 627 kstat_timer_init(kstat_timer_t *ktp, const char *name)
624 628 {
625 629 kstat_set_string(ktp->name, name);
626 630 }
627 631
628 632 /* ARGSUSED */
629 633 static int
630 634 default_kstat_update(kstat_t *ksp, int rw)
631 635 {
632 636 uint_t i;
633 637 size_t len = 0;
634 638 kstat_named_t *knp;
635 639
636 640 /*
637 641 * Named kstats with variable-length long strings have a standard
638 642 * way of determining how much space is needed to hold the snapshot:
639 643 */
640 644 if (ksp->ks_data != NULL && ksp->ks_type == KSTAT_TYPE_NAMED &&
641 645 (ksp->ks_flags & (KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_LONGSTRINGS))) {
642 646
643 647 /*
644 648 * Add in the space required for the strings
645 649 */
646 650 knp = KSTAT_NAMED_PTR(ksp);
647 651 for (i = 0; i < ksp->ks_ndata; i++, knp++) {
648 652 if (knp->data_type == KSTAT_DATA_STRING)
649 653 len += KSTAT_NAMED_STR_BUFLEN(knp);
650 654 }
651 655 ksp->ks_data_size =
652 656 ksp->ks_ndata * sizeof (kstat_named_t) + len;
653 657 }
654 658 return (0);
655 659 }
656 660
657 661 static int
658 662 default_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
659 663 {
660 664 kstat_io_t *kiop;
661 665 hrtime_t cur_time;
662 666 size_t namedsz;
663 667
664 668 ksp->ks_snaptime = cur_time = gethrtime();
665 669
666 670 if (rw == KSTAT_WRITE) {
667 671 if (!(ksp->ks_flags & KSTAT_FLAG_WRITABLE))
668 672 return (EACCES);
669 673 bcopy(buf, ksp->ks_data, ksp->ks_data_size);
670 674 return (0);
671 675 }
672 676
673 677 /*
674 678 * KSTAT_TYPE_NAMED kstats are defined to have ks_ndata
675 679 * number of kstat_named_t structures, followed by an optional
676 680 * string segment. The ks_data generally holds only the
677 681 * kstat_named_t structures. So we copy it first. The strings,
678 682 * if any, are copied below. For other kstat types, ks_data holds the
679 683 * entire buffer.
680 684 */
681 685
682 686 namedsz = sizeof (kstat_named_t) * ksp->ks_ndata;
683 687 if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data_size > namedsz)
684 688 bcopy(ksp->ks_data, buf, namedsz);
685 689 else
686 690 bcopy(ksp->ks_data, buf, ksp->ks_data_size);
687 691
688 692 /*
689 693 * Apply kstat type-specific data massaging
690 694 */
691 695 switch (ksp->ks_type) {
692 696
693 697 case KSTAT_TYPE_IO:
694 698 /*
695 699 * Normalize time units and deal with incomplete transactions
696 700 */
697 701 kiop = (kstat_io_t *)buf;
698 702
699 703 scalehrtime(&kiop->wtime);
700 704 scalehrtime(&kiop->wlentime);
701 705 scalehrtime(&kiop->wlastupdate);
702 706 scalehrtime(&kiop->rtime);
703 707 scalehrtime(&kiop->rlentime);
704 708 scalehrtime(&kiop->rlastupdate);
705 709
706 710 if (kiop->wcnt != 0) {
707 711 /* like kstat_waitq_exit */
708 712 hrtime_t wfix = cur_time - kiop->wlastupdate;
709 713 kiop->wlastupdate = cur_time;
710 714 kiop->wlentime += kiop->wcnt * wfix;
711 715 kiop->wtime += wfix;
712 716 }
713 717
714 718 if (kiop->rcnt != 0) {
715 719 /* like kstat_runq_exit */
716 720 hrtime_t rfix = cur_time - kiop->rlastupdate;
717 721 kiop->rlastupdate = cur_time;
718 722 kiop->rlentime += kiop->rcnt * rfix;
719 723 kiop->rtime += rfix;
720 724 }
721 725 break;
722 726
723 727 case KSTAT_TYPE_NAMED:
724 728 /*
725 729 * Massage any long strings in at the end of the buffer
726 730 */
727 731 if (ksp->ks_data_size > namedsz) {
728 732 uint_t i;
729 733 kstat_named_t *knp = buf;
730 734 char *dst = (char *)(knp + ksp->ks_ndata);
731 735 /*
732 736 * Copy strings and update pointers
733 737 */
734 738 for (i = 0; i < ksp->ks_ndata; i++, knp++) {
735 739 if (knp->data_type == KSTAT_DATA_STRING &&
736 740 KSTAT_NAMED_STR_PTR(knp) != NULL) {
737 741 bcopy(KSTAT_NAMED_STR_PTR(knp), dst,
738 742 KSTAT_NAMED_STR_BUFLEN(knp));
739 743 KSTAT_NAMED_STR_PTR(knp) = dst;
740 744 dst += KSTAT_NAMED_STR_BUFLEN(knp);
741 745 }
742 746 }
743 747 ASSERT(dst <= ((char *)buf + ksp->ks_data_size));
744 748 }
745 749 break;
746 750 }
747 751 return (0);
748 752 }
749 753
750 754 static int
751 755 header_kstat_update(kstat_t *header_ksp, int rw)
752 756 {
753 757 int nkstats = 0;
754 758 ekstat_t *e;
755 759 avl_tree_t *t = &kstat_avl_bykid;
756 760 zoneid_t zoneid;
757 761
758 762 if (rw == KSTAT_WRITE)
759 763 return (EACCES);
760 764
761 765 ASSERT(MUTEX_HELD(&kstat_chain_lock));
762 766
763 767 zoneid = getzoneid();
764 768 for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) {
765 769 if (kstat_zone_find((kstat_t *)e, zoneid) &&
766 770 (e->e_ks.ks_flags & KSTAT_FLAG_INVALID) == 0) {
767 771 nkstats++;
768 772 }
769 773 }
770 774 header_ksp->ks_ndata = nkstats;
771 775 header_ksp->ks_data_size = nkstats * sizeof (kstat_t);
772 776 return (0);
773 777 }
774 778
775 779 /*
776 780 * Copy out the data section of kstat 0, which consists of the list
777 781 * of all kstat headers. By specification, these headers must be
778 782 * copied out in order of increasing KID.
779 783 */
780 784 static int
781 785 header_kstat_snapshot(kstat_t *header_ksp, void *buf, int rw)
782 786 {
783 787 ekstat_t *e;
784 788 avl_tree_t *t = &kstat_avl_bykid;
785 789 zoneid_t zoneid;
786 790
787 791 header_ksp->ks_snaptime = gethrtime();
788 792
789 793 if (rw == KSTAT_WRITE)
790 794 return (EACCES);
791 795
792 796 ASSERT(MUTEX_HELD(&kstat_chain_lock));
793 797
794 798 zoneid = getzoneid();
795 799 for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) {
796 800 if (kstat_zone_find((kstat_t *)e, zoneid) &&
797 801 (e->e_ks.ks_flags & KSTAT_FLAG_INVALID) == 0) {
798 802 bcopy(&e->e_ks, buf, sizeof (kstat_t));
799 803 buf = (char *)buf + sizeof (kstat_t);
800 804 }
801 805 }
802 806
↓ open down ↓ |
616 lines elided |
↑ open up ↑ |
803 807 return (0);
804 808 }
805 809
806 810 /* ARGSUSED */
807 811 static int
808 812 system_misc_kstat_update(kstat_t *ksp, int rw)
809 813 {
810 814 int myncpus = ncpus;
811 815 int *loadavgp = &avenrun[0];
812 816 time_t zone_boot_time;
817 + hrtime_t zone_boot_hrtime;
813 818 clock_t zone_lbolt;
814 819 hrtime_t zone_hrtime;
815 820 size_t zone_nproc;
816 821
817 822 if (rw == KSTAT_WRITE)
818 823 return (EACCES);
819 824
820 825 if (!INGLOBALZONE(curproc)) {
821 826 /*
822 827 * Here we grab cpu_lock which is OK as long as no-one in the
823 828 * future attempts to lookup this particular kstat
824 829 * (unix:0:system_misc) while holding cpu_lock.
825 830 */
826 831 mutex_enter(&cpu_lock);
827 832 if (pool_pset_enabled()) {
828 833 myncpus = zone_ncpus_get(curproc->p_zone);
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
829 834 ASSERT(myncpus > 0);
830 835 }
831 836 mutex_exit(&cpu_lock);
832 837 loadavgp = &curproc->p_zone->zone_avenrun[0];
833 838 }
834 839
835 840 if (INGLOBALZONE(curproc)) {
836 841 zone_boot_time = boot_time;
837 842 zone_lbolt = ddi_get_lbolt();
838 843 zone_nproc = nproc;
844 + zone_boot_hrtime = boot_hrtime;
839 845 } else {
840 846 zone_boot_time = curproc->p_zone->zone_boot_time;
847 + zone_boot_hrtime = curproc->p_zone->zone_boot_hrtime;
841 848
842 849 zone_hrtime = gethrtime();
843 850 zone_lbolt = (clock_t)(NSEC_TO_TICK(zone_hrtime) -
844 851 NSEC_TO_TICK(curproc->p_zone->zone_zsched->p_mstart));
845 852 mutex_enter(&curproc->p_zone->zone_nlwps_lock);
846 853 zone_nproc = curproc->p_zone->zone_nprocs;
847 854 mutex_exit(&curproc->p_zone->zone_nlwps_lock);
848 855 }
849 856
850 857 system_misc_kstat.ncpus.value.ui32 = (uint32_t)myncpus;
851 858 system_misc_kstat.lbolt.value.ui32 = (uint32_t)zone_lbolt;
852 859 system_misc_kstat.deficit.value.ui32 = (uint32_t)deficit;
853 860 system_misc_kstat.clk_intr.value.ui32 = (uint32_t)zone_lbolt;
854 861 system_misc_kstat.vac.value.ui32 = (uint32_t)vac;
855 862 system_misc_kstat.nproc.value.ui32 = (uint32_t)zone_nproc;
856 863 system_misc_kstat.avenrun_1min.value.ui32 = (uint32_t)loadavgp[0];
857 864 system_misc_kstat.avenrun_5min.value.ui32 = (uint32_t)loadavgp[1];
858 865 system_misc_kstat.avenrun_15min.value.ui32 = (uint32_t)loadavgp[2];
859 866 system_misc_kstat.boot_time.value.ui32 = (uint32_t)
860 867 zone_boot_time;
868 + system_misc_kstat.boot_hrtime.value.t = zone_boot_hrtime;
861 869 system_misc_kstat.nsec_per_tick.value.ui32 = (uint32_t)
862 870 nsec_per_tick;
863 871 return (0);
864 872 }
865 873
866 874 #ifdef __sparc
867 875 extern caddr_t econtig32;
868 876 #else /* !__sparc */
869 877 extern caddr_t econtig;
870 878 #endif /* __sparc */
871 879
872 880 /* ARGSUSED */
873 881 static int
874 882 system_pages_kstat_update(kstat_t *ksp, int rw)
875 883 {
876 884 kobj_stat_t kobj_stat;
877 885
878 886 if (rw == KSTAT_WRITE) {
879 887 return (EACCES);
880 888 }
881 889
882 890 kobj_stat_get(&kobj_stat);
883 891 system_pages_kstat.physmem.value.ul = (ulong_t)physmem;
884 892 system_pages_kstat.nalloc.value.ul = kobj_stat.nalloc;
885 893 system_pages_kstat.nfree.value.ul = kobj_stat.nfree;
886 894 system_pages_kstat.nalloc_calls.value.ul = kobj_stat.nalloc_calls;
887 895 system_pages_kstat.nfree_calls.value.ul = kobj_stat.nfree_calls;
888 896 system_pages_kstat.kernelbase.value.ul = (ulong_t)KERNELBASE;
889 897
890 898 #ifdef __sparc
891 899 /*
892 900 * kstat should REALLY be modified to also report kmem64_base and
893 901 * kmem64_end (see sun4u/os/startup.c), as the virtual address range
894 902 * [ kernelbase .. econtig ] no longer is truly reflective of the
895 903 * kernel's vallocs...
896 904 */
897 905 system_pages_kstat.econtig.value.ul = (ulong_t)econtig32;
898 906 #else /* !__sparc */
899 907 system_pages_kstat.econtig.value.ul = (ulong_t)econtig;
900 908 #endif /* __sparc */
901 909
902 910 system_pages_kstat.freemem.value.ul = (ulong_t)freemem;
903 911 system_pages_kstat.availrmem.value.ul = (ulong_t)availrmem;
904 912 system_pages_kstat.lotsfree.value.ul = (ulong_t)lotsfree;
905 913 system_pages_kstat.desfree.value.ul = (ulong_t)desfree;
906 914 system_pages_kstat.minfree.value.ul = (ulong_t)minfree;
907 915 system_pages_kstat.fastscan.value.ul = (ulong_t)fastscan;
908 916 system_pages_kstat.slowscan.value.ul = (ulong_t)slowscan;
909 917 system_pages_kstat.nscan.value.ul = (ulong_t)nscan;
910 918 system_pages_kstat.desscan.value.ul = (ulong_t)desscan;
911 919 system_pages_kstat.pagesfree.value.ul = (ulong_t)freemem;
912 920 system_pages_kstat.pageslocked.value.ul = (ulong_t)(availrmem_initial -
913 921 availrmem);
914 922 system_pages_kstat.pagestotal.value.ul = (ulong_t)total_pages;
915 923 /*
916 924 * pp_kernel represents total pages used by the kernel since the
917 925 * startup. This formula takes into account the boottime kernel
918 926 * footprint and also considers the availrmem changes because of
919 927 * user explicit page locking.
920 928 */
921 929 system_pages_kstat.pp_kernel.value.ul = (ulong_t)(physinstalled -
922 930 obp_pages - availrmem - k_anoninfo.ani_mem_resv -
923 931 anon_segkp_pages_locked - pages_locked -
924 932 pages_claimed - pages_useclaim);
925 933
926 934 return (0);
927 935 }
928 936
929 937 kstat_t *
930 938 kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
931 939 const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags)
932 940 {
933 941 return (kstat_create_zone(ks_module, ks_instance, ks_name, ks_class,
934 942 ks_type, ks_ndata, ks_flags, ALL_ZONES));
935 943 }
936 944
937 945 /*
938 946 * Allocate and initialize a kstat structure. Or, if a dormant kstat with
939 947 * the specified name exists, reactivate it. Returns a pointer to the kstat
940 948 * on success, NULL on failure. The kstat will not be visible to the
941 949 * kstat driver until kstat_install().
942 950 */
943 951 kstat_t *
944 952 kstat_create_zone(const char *ks_module, int ks_instance, const char *ks_name,
945 953 const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
946 954 zoneid_t ks_zoneid)
947 955 {
948 956 size_t ks_data_size;
949 957 kstat_t *ksp;
950 958 ekstat_t *e;
951 959 avl_index_t where;
952 960 char namebuf[KSTAT_STRLEN + 16];
953 961
954 962 if (avl_numnodes(&kstat_avl_bykid) == 0) {
955 963 avl_create(&kstat_avl_bykid, kstat_compare_bykid,
956 964 sizeof (ekstat_t), offsetof(struct ekstat, e_avl_bykid));
957 965
958 966 avl_create(&kstat_avl_byname, kstat_compare_byname,
959 967 sizeof (ekstat_t), offsetof(struct ekstat, e_avl_byname));
960 968 }
961 969
962 970 /*
963 971 * If ks_name == NULL, set the ks_name to <module><instance>.
964 972 */
965 973 if (ks_name == NULL) {
966 974 char buf[KSTAT_STRLEN];
967 975 kstat_set_string(buf, ks_module);
968 976 (void) sprintf(namebuf, "%s%d", buf, ks_instance);
969 977 ks_name = namebuf;
970 978 }
971 979
972 980 /*
973 981 * Make sure it's a valid kstat data type
974 982 */
975 983 if (ks_type >= KSTAT_NUM_TYPES) {
976 984 cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
977 985 "invalid kstat type %d",
978 986 ks_module, ks_instance, ks_name, ks_type);
979 987 return (NULL);
980 988 }
981 989
982 990 /*
983 991 * Don't allow persistent virtual kstats -- it makes no sense.
984 992 * ks_data points to garbage when the client goes away.
985 993 */
986 994 if ((ks_flags & KSTAT_FLAG_PERSISTENT) &&
987 995 (ks_flags & KSTAT_FLAG_VIRTUAL)) {
988 996 cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
989 997 "cannot create persistent virtual kstat",
990 998 ks_module, ks_instance, ks_name);
991 999 return (NULL);
992 1000 }
993 1001
994 1002 /*
995 1003 * Don't allow variable-size physical kstats, since the framework's
996 1004 * memory allocation for physical kstat data is fixed at creation time.
997 1005 */
998 1006 if ((ks_flags & KSTAT_FLAG_VAR_SIZE) &&
999 1007 !(ks_flags & KSTAT_FLAG_VIRTUAL)) {
1000 1008 cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
1001 1009 "cannot create variable-size physical kstat",
1002 1010 ks_module, ks_instance, ks_name);
1003 1011 return (NULL);
1004 1012 }
1005 1013
1006 1014 /*
1007 1015 * Make sure the number of data fields is within legal range
1008 1016 */
1009 1017 if (ks_ndata < kstat_data_type[ks_type].min_ndata ||
1010 1018 ks_ndata > kstat_data_type[ks_type].max_ndata) {
1011 1019 cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
1012 1020 "ks_ndata=%d out of range [%d, %d]",
1013 1021 ks_module, ks_instance, ks_name, (int)ks_ndata,
1014 1022 kstat_data_type[ks_type].min_ndata,
1015 1023 kstat_data_type[ks_type].max_ndata);
1016 1024 return (NULL);
1017 1025 }
1018 1026
1019 1027 ks_data_size = kstat_data_type[ks_type].size * ks_ndata;
1020 1028
1021 1029 /*
1022 1030 * If the named kstat already exists and is dormant, reactivate it.
1023 1031 */
1024 1032 ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid);
1025 1033 if (ksp != NULL) {
1026 1034 if (!(ksp->ks_flags & KSTAT_FLAG_DORMANT)) {
1027 1035 /*
1028 1036 * The named kstat exists but is not dormant --
1029 1037 * this is a kstat namespace collision.
1030 1038 */
1031 1039 kstat_rele(ksp);
1032 1040 cmn_err(CE_WARN,
1033 1041 "kstat_create('%s', %d, '%s'): namespace collision",
1034 1042 ks_module, ks_instance, ks_name);
1035 1043 return (NULL);
1036 1044 }
1037 1045 if ((strcmp(ksp->ks_class, ks_class) != 0) ||
1038 1046 (ksp->ks_type != ks_type) ||
1039 1047 (ksp->ks_ndata != ks_ndata) ||
1040 1048 (ks_flags & KSTAT_FLAG_VIRTUAL)) {
1041 1049 /*
1042 1050 * The name is the same, but the other key parameters
1043 1051 * differ from those of the dormant kstat -- bogus.
1044 1052 */
1045 1053 kstat_rele(ksp);
1046 1054 cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
1047 1055 "invalid reactivation of dormant kstat",
1048 1056 ks_module, ks_instance, ks_name);
1049 1057 return (NULL);
1050 1058 }
1051 1059 /*
1052 1060 * Return dormant kstat pointer to caller. As usual,
1053 1061 * the kstat is marked invalid until kstat_install().
1054 1062 */
1055 1063 ksp->ks_flags |= KSTAT_FLAG_INVALID;
1056 1064 kstat_rele(ksp);
1057 1065 return (ksp);
1058 1066 }
1059 1067
1060 1068 /*
1061 1069 * Allocate memory for the new kstat header and, if this is a physical
1062 1070 * kstat, the data section.
1063 1071 */
1064 1072 e = kstat_alloc(ks_flags & KSTAT_FLAG_VIRTUAL ? 0 : ks_data_size);
1065 1073 if (e == NULL) {
1066 1074 cmn_err(CE_NOTE, "kstat_create('%s', %d, '%s'): "
1067 1075 "insufficient kernel memory",
1068 1076 ks_module, ks_instance, ks_name);
1069 1077 return (NULL);
1070 1078 }
1071 1079
1072 1080 /*
1073 1081 * Initialize as many fields as we can. The caller may reset
1074 1082 * ks_lock, ks_update, ks_private, and ks_snapshot as necessary.
1075 1083 * Creators of virtual kstats may also reset ks_data. It is
1076 1084 * also up to the caller to initialize the kstat data section,
1077 1085 * if necessary. All initialization must be complete before
1078 1086 * calling kstat_install().
1079 1087 */
1080 1088 e->e_zone.zoneid = ks_zoneid;
1081 1089 e->e_zone.next = NULL;
1082 1090
1083 1091 ksp = &e->e_ks;
1084 1092 ksp->ks_crtime = gethrtime();
1085 1093 kstat_set_string(ksp->ks_module, ks_module);
1086 1094 ksp->ks_instance = ks_instance;
1087 1095 kstat_set_string(ksp->ks_name, ks_name);
1088 1096 ksp->ks_type = ks_type;
1089 1097 kstat_set_string(ksp->ks_class, ks_class);
1090 1098 ksp->ks_flags = ks_flags | KSTAT_FLAG_INVALID;
1091 1099 if (ks_flags & KSTAT_FLAG_VIRTUAL)
1092 1100 ksp->ks_data = NULL;
1093 1101 else
1094 1102 ksp->ks_data = (void *)(e + 1);
1095 1103 ksp->ks_ndata = ks_ndata;
1096 1104 ksp->ks_data_size = ks_data_size;
1097 1105 ksp->ks_snaptime = ksp->ks_crtime;
1098 1106 ksp->ks_update = default_kstat_update;
1099 1107 ksp->ks_private = NULL;
1100 1108 ksp->ks_snapshot = default_kstat_snapshot;
1101 1109 ksp->ks_lock = NULL;
1102 1110
1103 1111 mutex_enter(&kstat_chain_lock);
1104 1112
1105 1113 /*
1106 1114 * Add our kstat to the AVL trees.
1107 1115 */
1108 1116 if (avl_find(&kstat_avl_byname, e, &where) != NULL) {
1109 1117 mutex_exit(&kstat_chain_lock);
1110 1118 cmn_err(CE_WARN,
1111 1119 "kstat_create('%s', %d, '%s'): namespace collision",
1112 1120 ks_module, ks_instance, ks_name);
1113 1121 kstat_free(e);
1114 1122 return (NULL);
1115 1123 }
1116 1124 avl_insert(&kstat_avl_byname, e, where);
1117 1125
1118 1126 /*
1119 1127 * Loop around until we find an unused KID.
1120 1128 */
1121 1129 do {
1122 1130 ksp->ks_kid = kstat_chain_id++;
1123 1131 } while (avl_find(&kstat_avl_bykid, e, &where) != NULL);
1124 1132 avl_insert(&kstat_avl_bykid, e, where);
1125 1133
1126 1134 mutex_exit(&kstat_chain_lock);
1127 1135
1128 1136 return (ksp);
1129 1137 }
1130 1138
1131 1139 /*
1132 1140 * Activate a fully initialized kstat and make it visible to /dev/kstat.
1133 1141 */
1134 1142 void
1135 1143 kstat_install(kstat_t *ksp)
1136 1144 {
1137 1145 zoneid_t zoneid = ((ekstat_t *)ksp)->e_zone.zoneid;
1138 1146
1139 1147 /*
1140 1148 * If this is a variable-size kstat, it MUST provide kstat data locking
1141 1149 * to prevent data-size races with kstat readers.
1142 1150 */
1143 1151 if ((ksp->ks_flags & KSTAT_FLAG_VAR_SIZE) && ksp->ks_lock == NULL) {
1144 1152 panic("kstat_install('%s', %d, '%s'): "
1145 1153 "cannot create variable-size kstat without data lock",
1146 1154 ksp->ks_module, ksp->ks_instance, ksp->ks_name);
1147 1155 }
1148 1156
1149 1157 if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) {
1150 1158 cmn_err(CE_WARN, "kstat_install(%p): does not exist",
1151 1159 (void *)ksp);
1152 1160 return;
1153 1161 }
1154 1162
1155 1163 if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data != NULL) {
1156 1164 uint_t i;
1157 1165 kstat_named_t *knp = KSTAT_NAMED_PTR(ksp);
1158 1166
1159 1167 for (i = 0; i < ksp->ks_ndata; i++, knp++) {
1160 1168 if (knp->data_type == KSTAT_DATA_STRING) {
1161 1169 ksp->ks_flags |= KSTAT_FLAG_LONGSTRINGS;
1162 1170 break;
1163 1171 }
1164 1172 }
1165 1173 /*
1166 1174 * The default snapshot routine does not handle KSTAT_WRITE
1167 1175 * for long strings.
1168 1176 */
1169 1177 if ((ksp->ks_flags & KSTAT_FLAG_LONGSTRINGS) &&
1170 1178 (ksp->ks_flags & KSTAT_FLAG_WRITABLE) &&
1171 1179 (ksp->ks_snapshot == default_kstat_snapshot)) {
1172 1180 panic("kstat_install('%s', %d, '%s'): "
1173 1181 "named kstat containing KSTAT_DATA_STRING "
1174 1182 "is writable but uses default snapshot routine",
1175 1183 ksp->ks_module, ksp->ks_instance, ksp->ks_name);
1176 1184 }
1177 1185 }
1178 1186
1179 1187 if (ksp->ks_flags & KSTAT_FLAG_DORMANT) {
1180 1188
1181 1189 /*
1182 1190 * We are reactivating a dormant kstat. Initialize the
1183 1191 * caller's underlying data to the value it had when the
1184 1192 * kstat went dormant, and mark the kstat as active.
1185 1193 * Grab the provider's kstat lock if it's not already held.
1186 1194 */
1187 1195 kmutex_t *lp = ksp->ks_lock;
1188 1196 if (lp != NULL && MUTEX_NOT_HELD(lp)) {
1189 1197 mutex_enter(lp);
1190 1198 (void) KSTAT_UPDATE(ksp, KSTAT_WRITE);
1191 1199 mutex_exit(lp);
1192 1200 } else {
1193 1201 (void) KSTAT_UPDATE(ksp, KSTAT_WRITE);
1194 1202 }
1195 1203 ksp->ks_flags &= ~KSTAT_FLAG_DORMANT;
1196 1204 }
1197 1205
1198 1206 /*
1199 1207 * Now that the kstat is active, make it visible to the kstat driver.
1200 1208 * When copying out kstats the count is determined in
1201 1209 * header_kstat_update() and actually copied into kbuf in
1202 1210 * header_kstat_snapshot(). kstat_chain_lock is held across the two
1203 1211 * calls to ensure that this list doesn't change. Thus, we need to
1204 1212 * also take the lock to ensure that the we don't copy the new kstat
1205 1213 * in the 2nd pass and overrun the buf.
1206 1214 */
1207 1215 mutex_enter(&kstat_chain_lock);
1208 1216 ksp->ks_flags &= ~KSTAT_FLAG_INVALID;
1209 1217 mutex_exit(&kstat_chain_lock);
1210 1218 kstat_rele(ksp);
1211 1219 }
1212 1220
1213 1221 /*
1214 1222 * Remove a kstat from the system. Or, if it's a persistent kstat,
1215 1223 * just update the data and mark it as dormant.
1216 1224 */
1217 1225 void
1218 1226 kstat_delete(kstat_t *ksp)
1219 1227 {
1220 1228 kmutex_t *lp;
1221 1229 ekstat_t *e = (ekstat_t *)ksp;
1222 1230 zoneid_t zoneid;
1223 1231 kstat_zone_t *kz;
1224 1232
1225 1233 ASSERT(ksp != NULL);
1226 1234
1227 1235 if (ksp == NULL)
1228 1236 return;
1229 1237
1230 1238 zoneid = e->e_zone.zoneid;
1231 1239
1232 1240 lp = ksp->ks_lock;
1233 1241
1234 1242 if (lp != NULL && MUTEX_HELD(lp)) {
1235 1243 panic("kstat_delete(%p): caller holds data lock %p",
1236 1244 (void *)ksp, (void *)lp);
1237 1245 }
1238 1246
1239 1247 if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) {
1240 1248 cmn_err(CE_WARN, "kstat_delete(%p): does not exist",
1241 1249 (void *)ksp);
1242 1250 return;
1243 1251 }
1244 1252
1245 1253 if (ksp->ks_flags & KSTAT_FLAG_PERSISTENT) {
1246 1254 /*
1247 1255 * Update the data one last time, so that all activity
1248 1256 * prior to going dormant has been accounted for.
1249 1257 */
1250 1258 KSTAT_ENTER(ksp);
1251 1259 (void) KSTAT_UPDATE(ksp, KSTAT_READ);
1252 1260 KSTAT_EXIT(ksp);
1253 1261
1254 1262 /*
1255 1263 * Mark the kstat as dormant and restore caller-modifiable
1256 1264 * fields to default values, so the kstat is readable during
1257 1265 * the dormant phase.
1258 1266 */
1259 1267 ksp->ks_flags |= KSTAT_FLAG_DORMANT;
1260 1268 ksp->ks_lock = NULL;
1261 1269 ksp->ks_update = default_kstat_update;
1262 1270 ksp->ks_private = NULL;
1263 1271 ksp->ks_snapshot = default_kstat_snapshot;
1264 1272 kstat_rele(ksp);
1265 1273 return;
1266 1274 }
1267 1275
1268 1276 /*
1269 1277 * Remove the kstat from the framework's AVL trees,
1270 1278 * free the allocated memory, and increment kstat_chain_id so
1271 1279 * /dev/kstat clients can detect the event.
1272 1280 */
1273 1281 mutex_enter(&kstat_chain_lock);
1274 1282 avl_remove(&kstat_avl_bykid, e);
1275 1283 avl_remove(&kstat_avl_byname, e);
1276 1284 kstat_chain_id++;
1277 1285 mutex_exit(&kstat_chain_lock);
1278 1286
1279 1287 kz = e->e_zone.next;
1280 1288 while (kz != NULL) {
1281 1289 kstat_zone_t *t = kz;
1282 1290
1283 1291 kz = kz->next;
1284 1292 kmem_free(t, sizeof (*t));
1285 1293 }
1286 1294 kstat_rele(ksp);
1287 1295 kstat_free(e);
1288 1296 }
1289 1297
1290 1298 void
1291 1299 kstat_delete_byname_zone(const char *ks_module, int ks_instance,
1292 1300 const char *ks_name, zoneid_t ks_zoneid)
1293 1301 {
1294 1302 kstat_t *ksp;
1295 1303
1296 1304 ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid);
1297 1305 if (ksp != NULL) {
1298 1306 kstat_rele(ksp);
1299 1307 kstat_delete(ksp);
1300 1308 }
1301 1309 }
1302 1310
1303 1311 void
1304 1312 kstat_delete_byname(const char *ks_module, int ks_instance, const char *ks_name)
1305 1313 {
1306 1314 kstat_delete_byname_zone(ks_module, ks_instance, ks_name, ALL_ZONES);
1307 1315 }
1308 1316
1309 1317 /*
1310 1318 * The sparc V9 versions of these routines can be much cheaper than
1311 1319 * the poor 32-bit compiler can comprehend, so they're in sparcv9_subr.s.
1312 1320 * For simplicity, however, we always feed the C versions to lint.
1313 1321 */
1314 1322 #if !defined(__sparc) || defined(lint) || defined(__lint)
1315 1323
1316 1324 void
1317 1325 kstat_waitq_enter(kstat_io_t *kiop)
1318 1326 {
1319 1327 hrtime_t new, delta;
1320 1328 ulong_t wcnt;
1321 1329
1322 1330 new = gethrtime_unscaled();
1323 1331 delta = new - kiop->wlastupdate;
1324 1332 kiop->wlastupdate = new;
1325 1333 wcnt = kiop->wcnt++;
1326 1334 if (wcnt != 0) {
1327 1335 kiop->wlentime += delta * wcnt;
1328 1336 kiop->wtime += delta;
1329 1337 }
1330 1338 }
1331 1339
1332 1340 void
1333 1341 kstat_waitq_exit(kstat_io_t *kiop)
1334 1342 {
1335 1343 hrtime_t new, delta;
1336 1344 ulong_t wcnt;
1337 1345
1338 1346 new = gethrtime_unscaled();
1339 1347 delta = new - kiop->wlastupdate;
1340 1348 kiop->wlastupdate = new;
1341 1349 wcnt = kiop->wcnt--;
1342 1350 ASSERT((int)wcnt > 0);
1343 1351 kiop->wlentime += delta * wcnt;
1344 1352 kiop->wtime += delta;
1345 1353 }
1346 1354
1347 1355 void
1348 1356 kstat_runq_enter(kstat_io_t *kiop)
1349 1357 {
1350 1358 hrtime_t new, delta;
1351 1359 ulong_t rcnt;
1352 1360
1353 1361 new = gethrtime_unscaled();
1354 1362 delta = new - kiop->rlastupdate;
1355 1363 kiop->rlastupdate = new;
1356 1364 rcnt = kiop->rcnt++;
1357 1365 if (rcnt != 0) {
1358 1366 kiop->rlentime += delta * rcnt;
1359 1367 kiop->rtime += delta;
1360 1368 }
1361 1369 }
1362 1370
1363 1371 void
1364 1372 kstat_runq_exit(kstat_io_t *kiop)
1365 1373 {
1366 1374 hrtime_t new, delta;
1367 1375 ulong_t rcnt;
1368 1376
1369 1377 new = gethrtime_unscaled();
1370 1378 delta = new - kiop->rlastupdate;
1371 1379 kiop->rlastupdate = new;
1372 1380 rcnt = kiop->rcnt--;
1373 1381 ASSERT((int)rcnt > 0);
1374 1382 kiop->rlentime += delta * rcnt;
1375 1383 kiop->rtime += delta;
1376 1384 }
1377 1385
1378 1386 void
1379 1387 kstat_waitq_to_runq(kstat_io_t *kiop)
1380 1388 {
1381 1389 hrtime_t new, delta;
1382 1390 ulong_t wcnt, rcnt;
1383 1391
1384 1392 new = gethrtime_unscaled();
1385 1393
1386 1394 delta = new - kiop->wlastupdate;
1387 1395 kiop->wlastupdate = new;
1388 1396 wcnt = kiop->wcnt--;
1389 1397 ASSERT((int)wcnt > 0);
1390 1398 kiop->wlentime += delta * wcnt;
1391 1399 kiop->wtime += delta;
1392 1400
1393 1401 delta = new - kiop->rlastupdate;
1394 1402 kiop->rlastupdate = new;
1395 1403 rcnt = kiop->rcnt++;
1396 1404 if (rcnt != 0) {
1397 1405 kiop->rlentime += delta * rcnt;
1398 1406 kiop->rtime += delta;
1399 1407 }
1400 1408 }
1401 1409
1402 1410 void
1403 1411 kstat_runq_back_to_waitq(kstat_io_t *kiop)
1404 1412 {
1405 1413 hrtime_t new, delta;
1406 1414 ulong_t wcnt, rcnt;
1407 1415
1408 1416 new = gethrtime_unscaled();
1409 1417
1410 1418 delta = new - kiop->rlastupdate;
1411 1419 kiop->rlastupdate = new;
1412 1420 rcnt = kiop->rcnt--;
1413 1421 ASSERT((int)rcnt > 0);
1414 1422 kiop->rlentime += delta * rcnt;
1415 1423 kiop->rtime += delta;
1416 1424
1417 1425 delta = new - kiop->wlastupdate;
1418 1426 kiop->wlastupdate = new;
1419 1427 wcnt = kiop->wcnt++;
1420 1428 if (wcnt != 0) {
1421 1429 kiop->wlentime += delta * wcnt;
1422 1430 kiop->wtime += delta;
1423 1431 }
1424 1432 }
1425 1433
1426 1434 #endif
1427 1435
1428 1436 void
1429 1437 kstat_timer_start(kstat_timer_t *ktp)
1430 1438 {
1431 1439 ktp->start_time = gethrtime();
1432 1440 }
1433 1441
1434 1442 void
1435 1443 kstat_timer_stop(kstat_timer_t *ktp)
1436 1444 {
1437 1445 hrtime_t etime;
1438 1446 u_longlong_t num_events;
1439 1447
1440 1448 ktp->stop_time = etime = gethrtime();
1441 1449 etime -= ktp->start_time;
1442 1450 num_events = ktp->num_events;
1443 1451 if (etime < ktp->min_time || num_events == 0)
1444 1452 ktp->min_time = etime;
1445 1453 if (etime > ktp->max_time)
1446 1454 ktp->max_time = etime;
1447 1455 ktp->elapsed_time += etime;
1448 1456 ktp->num_events = num_events + 1;
1449 1457 }
↓ open down ↓ |
579 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX