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