10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52723Scth * Common Development and Distribution License (the "License"). 62723Scth * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*12607Sjohn.levon@sun.com * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate /* 260Sstevel@tonic-gate * Kernel statistics framework 270Sstevel@tonic-gate */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/time.h> 310Sstevel@tonic-gate #include <sys/systm.h> 320Sstevel@tonic-gate #include <sys/vmsystm.h> 330Sstevel@tonic-gate #include <sys/t_lock.h> 340Sstevel@tonic-gate #include <sys/param.h> 350Sstevel@tonic-gate #include <sys/errno.h> 360Sstevel@tonic-gate #include <sys/vmem.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/cmn_err.h> 390Sstevel@tonic-gate #include <sys/kstat.h> 400Sstevel@tonic-gate #include <sys/sysinfo.h> 410Sstevel@tonic-gate #include <sys/cpuvar.h> 420Sstevel@tonic-gate #include <sys/fcntl.h> 430Sstevel@tonic-gate #include <sys/flock.h> 440Sstevel@tonic-gate #include <sys/vnode.h> 450Sstevel@tonic-gate #include <sys/vfs.h> 460Sstevel@tonic-gate #include <sys/dnlc.h> 470Sstevel@tonic-gate #include <sys/var.h> 480Sstevel@tonic-gate #include <sys/debug.h> 490Sstevel@tonic-gate #include <sys/kobj.h> 500Sstevel@tonic-gate #include <sys/avl.h> 510Sstevel@tonic-gate #include <sys/pool_pset.h> 520Sstevel@tonic-gate #include <sys/cpupart.h> 530Sstevel@tonic-gate #include <sys/zone.h> 540Sstevel@tonic-gate #include <sys/loadavg.h> 550Sstevel@tonic-gate #include <vm/page.h> 560Sstevel@tonic-gate #include <vm/anon.h> 570Sstevel@tonic-gate #include <vm/seg_kmem.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * Global lock to protect the AVL trees and kstat_chain_id. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate static kmutex_t kstat_chain_lock; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* 650Sstevel@tonic-gate * Every install/delete kstat bumps kstat_chain_id. This is used by: 660Sstevel@tonic-gate * 670Sstevel@tonic-gate * (1) /dev/kstat, to detect changes in the kstat chain across ioctls; 680Sstevel@tonic-gate * 690Sstevel@tonic-gate * (2) kstat_create(), to assign a KID (kstat ID) to each new kstat. 700Sstevel@tonic-gate * /dev/kstat uses the KID as a cookie for kstat lookups. 710Sstevel@tonic-gate * 720Sstevel@tonic-gate * We reserve the first two IDs because some kstats are created before 730Sstevel@tonic-gate * the well-known ones (kstat_headers = 0, kstat_types = 1). 740Sstevel@tonic-gate * 750Sstevel@tonic-gate * We also bump the kstat_chain_id if a zone is gaining or losing visibility 760Sstevel@tonic-gate * into a particular kstat, which is logically equivalent to a kstat being 770Sstevel@tonic-gate * installed/deleted. 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate 800Sstevel@tonic-gate kid_t kstat_chain_id = 2; 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * As far as zones are concerned, there are 3 types of kstat: 840Sstevel@tonic-gate * 850Sstevel@tonic-gate * 1) Those which have a well-known name, and which should return per-zone data 860Sstevel@tonic-gate * depending on which zone is doing the kstat_read(). sockfs:0:sock_unix_list 870Sstevel@tonic-gate * is an example of this type of kstat. 880Sstevel@tonic-gate * 890Sstevel@tonic-gate * 2) Those which should only be exported to a particular list of zones. 900Sstevel@tonic-gate * For example, in the case of nfs:*:mntinfo, we don't want zone A to be 910Sstevel@tonic-gate * able to see NFS mounts associated with zone B, while we want the 920Sstevel@tonic-gate * global zone to be able to see all mounts on the system. 930Sstevel@tonic-gate * 940Sstevel@tonic-gate * 3) Those that can be exported to all zones. Most system-related 950Sstevel@tonic-gate * kstats fall within this category. 960Sstevel@tonic-gate * 970Sstevel@tonic-gate * An ekstat_t thus contains a list of kstats that the zone is to be 980Sstevel@tonic-gate * exported to. The lookup of a name:instance:module thus translates to a 990Sstevel@tonic-gate * lookup of name:instance:module:myzone; if the kstat is not exported 1000Sstevel@tonic-gate * to all zones, and does not have the caller's zoneid explicitly 1010Sstevel@tonic-gate * enumerated in the list of zones to be exported to, it is the same as 1020Sstevel@tonic-gate * if the kstat didn't exist. 1030Sstevel@tonic-gate * 1040Sstevel@tonic-gate * Writing to kstats is currently disallowed from within a non-global 1050Sstevel@tonic-gate * zone, although this restriction could be removed in the future. 1060Sstevel@tonic-gate */ 1070Sstevel@tonic-gate typedef struct kstat_zone { 1080Sstevel@tonic-gate zoneid_t zoneid; 1090Sstevel@tonic-gate struct kstat_zone *next; 1100Sstevel@tonic-gate } kstat_zone_t; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * Extended kstat structure -- for internal use only. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate typedef struct ekstat { 1160Sstevel@tonic-gate kstat_t e_ks; /* the kstat itself */ 1170Sstevel@tonic-gate size_t e_size; /* total allocation size */ 1180Sstevel@tonic-gate kthread_t *e_owner; /* thread holding this kstat */ 1190Sstevel@tonic-gate kcondvar_t e_cv; /* wait for owner == NULL */ 1200Sstevel@tonic-gate avl_node_t e_avl_bykid; /* AVL tree to sort by KID */ 1210Sstevel@tonic-gate avl_node_t e_avl_byname; /* AVL tree to sort by name */ 1220Sstevel@tonic-gate kstat_zone_t e_zone; /* zone to export stats to */ 1230Sstevel@tonic-gate } ekstat_t; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate static uint64_t kstat_initial[8192]; 1260Sstevel@tonic-gate static void *kstat_initial_ptr = kstat_initial; 1270Sstevel@tonic-gate static size_t kstat_initial_avail = sizeof (kstat_initial); 1280Sstevel@tonic-gate static vmem_t *kstat_arena; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate #define KSTAT_ALIGN (sizeof (uint64_t)) 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate static avl_tree_t kstat_avl_bykid; 1330Sstevel@tonic-gate static avl_tree_t kstat_avl_byname; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * Various pointers we need to create kstats at boot time in kstat_init() 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate extern kstat_named_t *segmapcnt_ptr; 1390Sstevel@tonic-gate extern uint_t segmapcnt_ndata; 1400Sstevel@tonic-gate extern int segmap_kstat_update(kstat_t *, int); 1410Sstevel@tonic-gate extern kstat_named_t *biostats_ptr; 1420Sstevel@tonic-gate extern uint_t biostats_ndata; 1430Sstevel@tonic-gate extern kstat_named_t *pollstats_ptr; 1440Sstevel@tonic-gate extern uint_t pollstats_ndata; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate extern int vac; 1470Sstevel@tonic-gate extern uint_t nproc; 1480Sstevel@tonic-gate extern time_t boot_time; 1490Sstevel@tonic-gate extern sysinfo_t sysinfo; 1500Sstevel@tonic-gate extern vminfo_t vminfo; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate struct { 1530Sstevel@tonic-gate kstat_named_t ncpus; 1540Sstevel@tonic-gate kstat_named_t lbolt; 1550Sstevel@tonic-gate kstat_named_t deficit; 1560Sstevel@tonic-gate kstat_named_t clk_intr; 1570Sstevel@tonic-gate kstat_named_t vac; 1580Sstevel@tonic-gate kstat_named_t nproc; 1590Sstevel@tonic-gate kstat_named_t avenrun_1min; 1600Sstevel@tonic-gate kstat_named_t avenrun_5min; 1610Sstevel@tonic-gate kstat_named_t avenrun_15min; 1620Sstevel@tonic-gate kstat_named_t boot_time; 1630Sstevel@tonic-gate } system_misc_kstat = { 1640Sstevel@tonic-gate { "ncpus", KSTAT_DATA_UINT32 }, 1650Sstevel@tonic-gate { "lbolt", KSTAT_DATA_UINT32 }, 1660Sstevel@tonic-gate { "deficit", KSTAT_DATA_UINT32 }, 1670Sstevel@tonic-gate { "clk_intr", KSTAT_DATA_UINT32 }, 1680Sstevel@tonic-gate { "vac", KSTAT_DATA_UINT32 }, 1690Sstevel@tonic-gate { "nproc", KSTAT_DATA_UINT32 }, 1700Sstevel@tonic-gate { "avenrun_1min", KSTAT_DATA_UINT32 }, 1710Sstevel@tonic-gate { "avenrun_5min", KSTAT_DATA_UINT32 }, 1720Sstevel@tonic-gate { "avenrun_15min", KSTAT_DATA_UINT32 }, 1730Sstevel@tonic-gate { "boot_time", KSTAT_DATA_UINT32 }, 1740Sstevel@tonic-gate }; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate struct { 1770Sstevel@tonic-gate kstat_named_t physmem; 1780Sstevel@tonic-gate kstat_named_t nalloc; 1790Sstevel@tonic-gate kstat_named_t nfree; 1800Sstevel@tonic-gate kstat_named_t nalloc_calls; 1810Sstevel@tonic-gate kstat_named_t nfree_calls; 1820Sstevel@tonic-gate kstat_named_t kernelbase; 1830Sstevel@tonic-gate kstat_named_t econtig; 1840Sstevel@tonic-gate kstat_named_t freemem; 1850Sstevel@tonic-gate kstat_named_t availrmem; 1860Sstevel@tonic-gate kstat_named_t lotsfree; 1870Sstevel@tonic-gate kstat_named_t desfree; 1880Sstevel@tonic-gate kstat_named_t minfree; 1890Sstevel@tonic-gate kstat_named_t fastscan; 1900Sstevel@tonic-gate kstat_named_t slowscan; 1910Sstevel@tonic-gate kstat_named_t nscan; 1920Sstevel@tonic-gate kstat_named_t desscan; 1930Sstevel@tonic-gate kstat_named_t pp_kernel; 1940Sstevel@tonic-gate kstat_named_t pagesfree; 1950Sstevel@tonic-gate kstat_named_t pageslocked; 1960Sstevel@tonic-gate kstat_named_t pagestotal; 1970Sstevel@tonic-gate } system_pages_kstat = { 1980Sstevel@tonic-gate { "physmem", KSTAT_DATA_ULONG }, 1990Sstevel@tonic-gate { "nalloc", KSTAT_DATA_ULONG }, 2000Sstevel@tonic-gate { "nfree", KSTAT_DATA_ULONG }, 2010Sstevel@tonic-gate { "nalloc_calls", KSTAT_DATA_ULONG }, 2020Sstevel@tonic-gate { "nfree_calls", KSTAT_DATA_ULONG }, 2030Sstevel@tonic-gate { "kernelbase", KSTAT_DATA_ULONG }, 2040Sstevel@tonic-gate { "econtig", KSTAT_DATA_ULONG }, 2050Sstevel@tonic-gate { "freemem", KSTAT_DATA_ULONG }, 2060Sstevel@tonic-gate { "availrmem", KSTAT_DATA_ULONG }, 2070Sstevel@tonic-gate { "lotsfree", KSTAT_DATA_ULONG }, 2080Sstevel@tonic-gate { "desfree", KSTAT_DATA_ULONG }, 2090Sstevel@tonic-gate { "minfree", KSTAT_DATA_ULONG }, 2100Sstevel@tonic-gate { "fastscan", KSTAT_DATA_ULONG }, 2110Sstevel@tonic-gate { "slowscan", KSTAT_DATA_ULONG }, 2120Sstevel@tonic-gate { "nscan", KSTAT_DATA_ULONG }, 2130Sstevel@tonic-gate { "desscan", KSTAT_DATA_ULONG }, 2140Sstevel@tonic-gate { "pp_kernel", KSTAT_DATA_ULONG }, 2150Sstevel@tonic-gate { "pagesfree", KSTAT_DATA_ULONG }, 2160Sstevel@tonic-gate { "pageslocked", KSTAT_DATA_ULONG }, 2170Sstevel@tonic-gate { "pagestotal", KSTAT_DATA_ULONG }, 2180Sstevel@tonic-gate }; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate static int header_kstat_update(kstat_t *, int); 2210Sstevel@tonic-gate static int header_kstat_snapshot(kstat_t *, void *, int); 2220Sstevel@tonic-gate static int system_misc_kstat_update(kstat_t *, int); 2230Sstevel@tonic-gate static int system_pages_kstat_update(kstat_t *, int); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate static struct { 2260Sstevel@tonic-gate char name[KSTAT_STRLEN]; 2270Sstevel@tonic-gate size_t size; 2280Sstevel@tonic-gate uint_t min_ndata; 2290Sstevel@tonic-gate uint_t max_ndata; 2300Sstevel@tonic-gate } kstat_data_type[KSTAT_NUM_TYPES] = { 2310Sstevel@tonic-gate { "raw", 1, 0, INT_MAX }, 2320Sstevel@tonic-gate { "name=value", sizeof (kstat_named_t), 0, INT_MAX }, 2330Sstevel@tonic-gate { "interrupt", sizeof (kstat_intr_t), 1, 1 }, 2340Sstevel@tonic-gate { "i/o", sizeof (kstat_io_t), 1, 1 }, 2350Sstevel@tonic-gate { "event_timer", sizeof (kstat_timer_t), 0, INT_MAX }, 2360Sstevel@tonic-gate }; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate int 2390Sstevel@tonic-gate kstat_zone_find(kstat_t *k, zoneid_t zoneid) 2400Sstevel@tonic-gate { 2410Sstevel@tonic-gate ekstat_t *e = (ekstat_t *)k; 2420Sstevel@tonic-gate kstat_zone_t *kz; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate ASSERT(MUTEX_HELD(&kstat_chain_lock)); 2450Sstevel@tonic-gate for (kz = &e->e_zone; kz != NULL; kz = kz->next) { 2460Sstevel@tonic-gate if (zoneid == ALL_ZONES || kz->zoneid == ALL_ZONES) 2470Sstevel@tonic-gate return (1); 2480Sstevel@tonic-gate if (zoneid == kz->zoneid) 2490Sstevel@tonic-gate return (1); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate return (0); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate void 2550Sstevel@tonic-gate kstat_zone_remove(kstat_t *k, zoneid_t zoneid) 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate ekstat_t *e = (ekstat_t *)k; 2580Sstevel@tonic-gate kstat_zone_t *kz, *t = NULL; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate mutex_enter(&kstat_chain_lock); 2610Sstevel@tonic-gate if (zoneid == e->e_zone.zoneid) { 2620Sstevel@tonic-gate kz = e->e_zone.next; 2630Sstevel@tonic-gate ASSERT(kz != NULL); 2640Sstevel@tonic-gate e->e_zone.zoneid = kz->zoneid; 2650Sstevel@tonic-gate e->e_zone.next = kz->next; 2660Sstevel@tonic-gate goto out; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate for (kz = &e->e_zone; kz->next != NULL; kz = kz->next) { 2690Sstevel@tonic-gate if (kz->next->zoneid == zoneid) { 2700Sstevel@tonic-gate t = kz->next; 2710Sstevel@tonic-gate kz->next = t->next; 2720Sstevel@tonic-gate break; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate ASSERT(t != NULL); /* we removed something */ 2760Sstevel@tonic-gate kz = t; 2770Sstevel@tonic-gate out: 2780Sstevel@tonic-gate kstat_chain_id++; 2790Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 2800Sstevel@tonic-gate kmem_free(kz, sizeof (*kz)); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate void 2840Sstevel@tonic-gate kstat_zone_add(kstat_t *k, zoneid_t zoneid) 2850Sstevel@tonic-gate { 2860Sstevel@tonic-gate ekstat_t *e = (ekstat_t *)k; 2870Sstevel@tonic-gate kstat_zone_t *kz; 2880Sstevel@tonic-gate 2893792Sakolb kz = kmem_alloc(sizeof (*kz), KM_NOSLEEP); 2903792Sakolb if (kz == NULL) 2913792Sakolb return; 2920Sstevel@tonic-gate mutex_enter(&kstat_chain_lock); 2930Sstevel@tonic-gate kz->zoneid = zoneid; 2940Sstevel@tonic-gate kz->next = e->e_zone.next; 2950Sstevel@tonic-gate e->e_zone.next = kz; 2960Sstevel@tonic-gate kstat_chain_id++; 2970Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * Compare the list of zones for the given kstats, returning 0 if they match 3020Sstevel@tonic-gate * (ie, one list contains ALL_ZONES or both lists contain the same zoneid). 3030Sstevel@tonic-gate * In practice, this is called indirectly by kstat_hold_byname(), so one of the 3040Sstevel@tonic-gate * two lists always has one element, and this is an O(n) operation rather than 3050Sstevel@tonic-gate * O(n^2). 3060Sstevel@tonic-gate */ 3070Sstevel@tonic-gate static int 3080Sstevel@tonic-gate kstat_zone_compare(ekstat_t *e1, ekstat_t *e2) 3090Sstevel@tonic-gate { 3100Sstevel@tonic-gate kstat_zone_t *kz1, *kz2; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate ASSERT(MUTEX_HELD(&kstat_chain_lock)); 3130Sstevel@tonic-gate for (kz1 = &e1->e_zone; kz1 != NULL; kz1 = kz1->next) { 3140Sstevel@tonic-gate for (kz2 = &e2->e_zone; kz2 != NULL; kz2 = kz2->next) { 3150Sstevel@tonic-gate if (kz1->zoneid == ALL_ZONES || 3160Sstevel@tonic-gate kz2->zoneid == ALL_ZONES) 3170Sstevel@tonic-gate return (0); 3180Sstevel@tonic-gate if (kz1->zoneid == kz2->zoneid) 3190Sstevel@tonic-gate return (0); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate return (e1->e_zone.zoneid < e2->e_zone.zoneid ? -1 : 1); 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * Support for keeping kstats sorted in AVL trees for fast lookups. 3270Sstevel@tonic-gate */ 3280Sstevel@tonic-gate static int 3290Sstevel@tonic-gate kstat_compare_bykid(const void *a1, const void *a2) 3300Sstevel@tonic-gate { 3310Sstevel@tonic-gate const kstat_t *k1 = a1; 3320Sstevel@tonic-gate const kstat_t *k2 = a2; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (k1->ks_kid < k2->ks_kid) 3350Sstevel@tonic-gate return (-1); 3360Sstevel@tonic-gate if (k1->ks_kid > k2->ks_kid) 3370Sstevel@tonic-gate return (1); 3380Sstevel@tonic-gate return (kstat_zone_compare((ekstat_t *)k1, (ekstat_t *)k2)); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate static int 3420Sstevel@tonic-gate kstat_compare_byname(const void *a1, const void *a2) 3430Sstevel@tonic-gate { 3440Sstevel@tonic-gate const kstat_t *k1 = a1; 3450Sstevel@tonic-gate const kstat_t *k2 = a2; 3460Sstevel@tonic-gate int s; 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate s = strcmp(k1->ks_module, k2->ks_module); 3490Sstevel@tonic-gate if (s > 0) 3500Sstevel@tonic-gate return (1); 3510Sstevel@tonic-gate if (s < 0) 3520Sstevel@tonic-gate return (-1); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (k1->ks_instance < k2->ks_instance) 3550Sstevel@tonic-gate return (-1); 3560Sstevel@tonic-gate if (k1->ks_instance > k2->ks_instance) 3570Sstevel@tonic-gate return (1); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate s = strcmp(k1->ks_name, k2->ks_name); 3600Sstevel@tonic-gate if (s > 0) 3610Sstevel@tonic-gate return (1); 3620Sstevel@tonic-gate if (s < 0) 3630Sstevel@tonic-gate return (-1); 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate return (kstat_zone_compare((ekstat_t *)k1, (ekstat_t *)k2)); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate static kstat_t * 3690Sstevel@tonic-gate kstat_hold(avl_tree_t *t, ekstat_t *template) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate kstat_t *ksp; 3720Sstevel@tonic-gate ekstat_t *e; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate mutex_enter(&kstat_chain_lock); 3750Sstevel@tonic-gate for (;;) { 3760Sstevel@tonic-gate ksp = avl_find(t, template, NULL); 3770Sstevel@tonic-gate if (ksp == NULL) 3780Sstevel@tonic-gate break; 3790Sstevel@tonic-gate e = (ekstat_t *)ksp; 3800Sstevel@tonic-gate if (e->e_owner == NULL) { 3810Sstevel@tonic-gate e->e_owner = curthread; 3820Sstevel@tonic-gate break; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate cv_wait(&e->e_cv, &kstat_chain_lock); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 3870Sstevel@tonic-gate return (ksp); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate void 3910Sstevel@tonic-gate kstat_rele(kstat_t *ksp) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate ekstat_t *e = (ekstat_t *)ksp; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate mutex_enter(&kstat_chain_lock); 3960Sstevel@tonic-gate ASSERT(e->e_owner == curthread); 3970Sstevel@tonic-gate e->e_owner = NULL; 3980Sstevel@tonic-gate cv_broadcast(&e->e_cv); 3990Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate kstat_t * 4030Sstevel@tonic-gate kstat_hold_bykid(kid_t kid, zoneid_t zoneid) 4040Sstevel@tonic-gate { 4050Sstevel@tonic-gate ekstat_t e; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate e.e_ks.ks_kid = kid; 4080Sstevel@tonic-gate e.e_zone.zoneid = zoneid; 4090Sstevel@tonic-gate e.e_zone.next = NULL; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate return (kstat_hold(&kstat_avl_bykid, &e)); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate kstat_t * 4152951Selowe kstat_hold_byname(const char *ks_module, int ks_instance, const char *ks_name, 4160Sstevel@tonic-gate zoneid_t ks_zoneid) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate ekstat_t e; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate kstat_set_string(e.e_ks.ks_module, ks_module); 4210Sstevel@tonic-gate e.e_ks.ks_instance = ks_instance; 4220Sstevel@tonic-gate kstat_set_string(e.e_ks.ks_name, ks_name); 4230Sstevel@tonic-gate e.e_zone.zoneid = ks_zoneid; 4240Sstevel@tonic-gate e.e_zone.next = NULL; 4250Sstevel@tonic-gate return (kstat_hold(&kstat_avl_byname, &e)); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate static ekstat_t * 4290Sstevel@tonic-gate kstat_alloc(size_t size) 4300Sstevel@tonic-gate { 4310Sstevel@tonic-gate ekstat_t *e = NULL; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate size = P2ROUNDUP(sizeof (ekstat_t) + size, KSTAT_ALIGN); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (kstat_arena == NULL) { 4360Sstevel@tonic-gate if (size <= kstat_initial_avail) { 4370Sstevel@tonic-gate e = kstat_initial_ptr; 4380Sstevel@tonic-gate kstat_initial_ptr = (char *)kstat_initial_ptr + size; 4390Sstevel@tonic-gate kstat_initial_avail -= size; 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate } else { 4420Sstevel@tonic-gate e = vmem_alloc(kstat_arena, size, VM_NOSLEEP); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (e != NULL) { 4460Sstevel@tonic-gate bzero(e, size); 4470Sstevel@tonic-gate e->e_size = size; 4480Sstevel@tonic-gate cv_init(&e->e_cv, NULL, CV_DEFAULT, NULL); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate return (e); 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate static void 4550Sstevel@tonic-gate kstat_free(ekstat_t *e) 4560Sstevel@tonic-gate { 4570Sstevel@tonic-gate cv_destroy(&e->e_cv); 4580Sstevel@tonic-gate vmem_free(kstat_arena, e, e->e_size); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * Create various system kstats. 4630Sstevel@tonic-gate */ 4640Sstevel@tonic-gate void 4650Sstevel@tonic-gate kstat_init(void) 4660Sstevel@tonic-gate { 4670Sstevel@tonic-gate kstat_t *ksp; 4680Sstevel@tonic-gate ekstat_t *e; 4690Sstevel@tonic-gate avl_tree_t *t = &kstat_avl_bykid; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * Set up the kstat vmem arena. 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate kstat_arena = vmem_create("kstat", 4750Sstevel@tonic-gate kstat_initial, sizeof (kstat_initial), KSTAT_ALIGN, 4760Sstevel@tonic-gate segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * Make initial kstats appear as though they were allocated. 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) 4820Sstevel@tonic-gate (void) vmem_xalloc(kstat_arena, e->e_size, KSTAT_ALIGN, 4830Sstevel@tonic-gate 0, 0, e, (char *)e + e->e_size, 4840Sstevel@tonic-gate VM_NOSLEEP | VM_BESTFIT | VM_PANIC); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * The mother of all kstats. The first kstat in the system, which 4880Sstevel@tonic-gate * always has KID 0, has the headers for all kstats (including itself) 4890Sstevel@tonic-gate * as its data. Thus, the kstat driver does not need any special 4900Sstevel@tonic-gate * interface to extract the kstat chain. 4910Sstevel@tonic-gate */ 4920Sstevel@tonic-gate kstat_chain_id = 0; 4930Sstevel@tonic-gate ksp = kstat_create("unix", 0, "kstat_headers", "kstat", KSTAT_TYPE_RAW, 4946695Saguzovsk 0, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE); 4950Sstevel@tonic-gate if (ksp) { 4960Sstevel@tonic-gate ksp->ks_lock = &kstat_chain_lock; 4970Sstevel@tonic-gate ksp->ks_update = header_kstat_update; 4980Sstevel@tonic-gate ksp->ks_snapshot = header_kstat_snapshot; 4990Sstevel@tonic-gate kstat_install(ksp); 5000Sstevel@tonic-gate } else { 5010Sstevel@tonic-gate panic("cannot create kstat 'kstat_headers'"); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate ksp = kstat_create("unix", 0, "kstat_types", "kstat", 5056695Saguzovsk KSTAT_TYPE_NAMED, KSTAT_NUM_TYPES, 0); 5060Sstevel@tonic-gate if (ksp) { 5070Sstevel@tonic-gate int i; 5080Sstevel@tonic-gate kstat_named_t *kn = KSTAT_NAMED_PTR(ksp); 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate for (i = 0; i < KSTAT_NUM_TYPES; i++) { 5110Sstevel@tonic-gate kstat_named_init(&kn[i], kstat_data_type[i].name, 5126695Saguzovsk KSTAT_DATA_ULONG); 5130Sstevel@tonic-gate kn[i].value.ul = i; 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate kstat_install(ksp); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate ksp = kstat_create("unix", 0, "sysinfo", "misc", KSTAT_TYPE_RAW, 5196695Saguzovsk sizeof (sysinfo_t), KSTAT_FLAG_VIRTUAL); 5200Sstevel@tonic-gate if (ksp) { 5210Sstevel@tonic-gate ksp->ks_data = (void *) &sysinfo; 5220Sstevel@tonic-gate kstat_install(ksp); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate ksp = kstat_create("unix", 0, "vminfo", "vm", KSTAT_TYPE_RAW, 5266695Saguzovsk sizeof (vminfo_t), KSTAT_FLAG_VIRTUAL); 5270Sstevel@tonic-gate if (ksp) { 5280Sstevel@tonic-gate ksp->ks_data = (void *) &vminfo; 5290Sstevel@tonic-gate kstat_install(ksp); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate ksp = kstat_create("unix", 0, "segmap", "vm", KSTAT_TYPE_NAMED, 5336695Saguzovsk segmapcnt_ndata, KSTAT_FLAG_VIRTUAL); 5340Sstevel@tonic-gate if (ksp) { 5350Sstevel@tonic-gate ksp->ks_data = (void *) segmapcnt_ptr; 5360Sstevel@tonic-gate ksp->ks_update = segmap_kstat_update; 5370Sstevel@tonic-gate kstat_install(ksp); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate ksp = kstat_create("unix", 0, "biostats", "misc", KSTAT_TYPE_NAMED, 5416695Saguzovsk biostats_ndata, KSTAT_FLAG_VIRTUAL); 5420Sstevel@tonic-gate if (ksp) { 5430Sstevel@tonic-gate ksp->ks_data = (void *) biostats_ptr; 5440Sstevel@tonic-gate kstat_install(ksp); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate ksp = kstat_create("unix", 0, "var", "misc", KSTAT_TYPE_RAW, 5486695Saguzovsk sizeof (struct var), KSTAT_FLAG_VIRTUAL); 5490Sstevel@tonic-gate if (ksp) { 5500Sstevel@tonic-gate ksp->ks_data = (void *) &v; 5510Sstevel@tonic-gate kstat_install(ksp); 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate ksp = kstat_create("unix", 0, "system_misc", "misc", KSTAT_TYPE_NAMED, 5556695Saguzovsk sizeof (system_misc_kstat) / sizeof (kstat_named_t), 5566695Saguzovsk KSTAT_FLAG_VIRTUAL); 5570Sstevel@tonic-gate if (ksp) { 5580Sstevel@tonic-gate ksp->ks_data = (void *) &system_misc_kstat; 5590Sstevel@tonic-gate ksp->ks_update = system_misc_kstat_update; 5600Sstevel@tonic-gate kstat_install(ksp); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate ksp = kstat_create("unix", 0, "system_pages", "pages", KSTAT_TYPE_NAMED, 5646695Saguzovsk sizeof (system_pages_kstat) / sizeof (kstat_named_t), 5656695Saguzovsk KSTAT_FLAG_VIRTUAL); 5660Sstevel@tonic-gate if (ksp) { 5670Sstevel@tonic-gate ksp->ks_data = (void *) &system_pages_kstat; 5680Sstevel@tonic-gate ksp->ks_update = system_pages_kstat_update; 5690Sstevel@tonic-gate kstat_install(ksp); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate ksp = kstat_create("poll", 0, "pollstats", "misc", KSTAT_TYPE_NAMED, 5730Sstevel@tonic-gate pollstats_ndata, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate if (ksp) { 5760Sstevel@tonic-gate ksp->ks_data = pollstats_ptr; 5770Sstevel@tonic-gate kstat_install(ksp); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * Caller of this should ensure that the string pointed by src 5830Sstevel@tonic-gate * doesn't change while kstat's lock is held. Not doing so defeats 5840Sstevel@tonic-gate * kstat's snapshot strategy as explained in <sys/kstat.h> 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate void 5870Sstevel@tonic-gate kstat_named_setstr(kstat_named_t *knp, const char *src) 5880Sstevel@tonic-gate { 5890Sstevel@tonic-gate if (knp->data_type != KSTAT_DATA_STRING) 5900Sstevel@tonic-gate panic("kstat_named_setstr('%p', '%p'): " 5917240Srh87107 "named kstat is not of type KSTAT_DATA_STRING", 5927240Srh87107 (void *)knp, (void *)src); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate KSTAT_NAMED_STR_PTR(knp) = (char *)src; 5950Sstevel@tonic-gate if (src != NULL) 5960Sstevel@tonic-gate KSTAT_NAMED_STR_BUFLEN(knp) = strlen(src) + 1; 5970Sstevel@tonic-gate else 5980Sstevel@tonic-gate KSTAT_NAMED_STR_BUFLEN(knp) = 0; 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate void 6022951Selowe kstat_set_string(char *dst, const char *src) 6030Sstevel@tonic-gate { 6040Sstevel@tonic-gate bzero(dst, KSTAT_STRLEN); 6050Sstevel@tonic-gate (void) strncpy(dst, src, KSTAT_STRLEN - 1); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate void 6092951Selowe kstat_named_init(kstat_named_t *knp, const char *name, uchar_t data_type) 6100Sstevel@tonic-gate { 6110Sstevel@tonic-gate kstat_set_string(knp->name, name); 6120Sstevel@tonic-gate knp->data_type = data_type; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if (data_type == KSTAT_DATA_STRING) 6150Sstevel@tonic-gate kstat_named_setstr(knp, NULL); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate void 6192951Selowe kstat_timer_init(kstat_timer_t *ktp, const char *name) 6200Sstevel@tonic-gate { 6210Sstevel@tonic-gate kstat_set_string(ktp->name, name); 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* ARGSUSED */ 6250Sstevel@tonic-gate static int 6260Sstevel@tonic-gate default_kstat_update(kstat_t *ksp, int rw) 6270Sstevel@tonic-gate { 6280Sstevel@tonic-gate uint_t i; 6290Sstevel@tonic-gate size_t len = 0; 6300Sstevel@tonic-gate kstat_named_t *knp; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* 6330Sstevel@tonic-gate * Named kstats with variable-length long strings have a standard 6340Sstevel@tonic-gate * way of determining how much space is needed to hold the snapshot: 6350Sstevel@tonic-gate */ 6360Sstevel@tonic-gate if (ksp->ks_data != NULL && ksp->ks_type == KSTAT_TYPE_NAMED && 6370Sstevel@tonic-gate (ksp->ks_flags & KSTAT_FLAG_VAR_SIZE)) { 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* 6400Sstevel@tonic-gate * Add in the space required for the strings 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate knp = KSTAT_NAMED_PTR(ksp); 6430Sstevel@tonic-gate for (i = 0; i < ksp->ks_ndata; i++, knp++) { 6440Sstevel@tonic-gate if (knp->data_type == KSTAT_DATA_STRING) 6450Sstevel@tonic-gate len += KSTAT_NAMED_STR_BUFLEN(knp); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate ksp->ks_data_size = 6480Sstevel@tonic-gate ksp->ks_ndata * sizeof (kstat_named_t) + len; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate return (0); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate static int 6540Sstevel@tonic-gate default_kstat_snapshot(kstat_t *ksp, void *buf, int rw) 6550Sstevel@tonic-gate { 6560Sstevel@tonic-gate kstat_io_t *kiop; 6570Sstevel@tonic-gate hrtime_t cur_time; 6580Sstevel@tonic-gate size_t namedsz; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate ksp->ks_snaptime = cur_time = gethrtime(); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if (rw == KSTAT_WRITE) { 6630Sstevel@tonic-gate if (!(ksp->ks_flags & KSTAT_FLAG_WRITABLE)) 6640Sstevel@tonic-gate return (EACCES); 6650Sstevel@tonic-gate bcopy(buf, ksp->ks_data, ksp->ks_data_size); 6660Sstevel@tonic-gate return (0); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * KSTAT_TYPE_NAMED kstats are defined to have ks_ndata 6710Sstevel@tonic-gate * number of kstat_named_t structures, followed by an optional 6720Sstevel@tonic-gate * string segment. The ks_data generally holds only the 6730Sstevel@tonic-gate * kstat_named_t structures. So we copy it first. The strings, 6740Sstevel@tonic-gate * if any, are copied below. For other kstat types, ks_data holds the 6750Sstevel@tonic-gate * entire buffer. 6760Sstevel@tonic-gate */ 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate namedsz = sizeof (kstat_named_t) * ksp->ks_ndata; 6790Sstevel@tonic-gate if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data_size > namedsz) 6800Sstevel@tonic-gate bcopy(ksp->ks_data, buf, namedsz); 6810Sstevel@tonic-gate else 6820Sstevel@tonic-gate bcopy(ksp->ks_data, buf, ksp->ks_data_size); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate /* 6850Sstevel@tonic-gate * Apply kstat type-specific data massaging 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate switch (ksp->ks_type) { 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate case KSTAT_TYPE_IO: 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * Normalize time units and deal with incomplete transactions 6920Sstevel@tonic-gate */ 6930Sstevel@tonic-gate kiop = (kstat_io_t *)buf; 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate scalehrtime(&kiop->wtime); 6960Sstevel@tonic-gate scalehrtime(&kiop->wlentime); 6970Sstevel@tonic-gate scalehrtime(&kiop->wlastupdate); 6980Sstevel@tonic-gate scalehrtime(&kiop->rtime); 6990Sstevel@tonic-gate scalehrtime(&kiop->rlentime); 7000Sstevel@tonic-gate scalehrtime(&kiop->rlastupdate); 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if (kiop->wcnt != 0) { 7032723Scth /* like kstat_waitq_exit */ 7040Sstevel@tonic-gate hrtime_t wfix = cur_time - kiop->wlastupdate; 7052723Scth kiop->wlastupdate = cur_time; 7060Sstevel@tonic-gate kiop->wlentime += kiop->wcnt * wfix; 7072723Scth kiop->wtime += wfix; 7080Sstevel@tonic-gate } 7092723Scth 7100Sstevel@tonic-gate if (kiop->rcnt != 0) { 7112723Scth /* like kstat_runq_exit */ 7120Sstevel@tonic-gate hrtime_t rfix = cur_time - kiop->rlastupdate; 7132723Scth kiop->rlastupdate = cur_time; 7140Sstevel@tonic-gate kiop->rlentime += kiop->rcnt * rfix; 7152723Scth kiop->rtime += rfix; 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate break; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate case KSTAT_TYPE_NAMED: 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * Massage any long strings in at the end of the buffer 7220Sstevel@tonic-gate */ 7230Sstevel@tonic-gate if (ksp->ks_data_size > namedsz) { 7240Sstevel@tonic-gate uint_t i; 7250Sstevel@tonic-gate kstat_named_t *knp = buf; 7260Sstevel@tonic-gate char *dst = (char *)(knp + ksp->ks_ndata); 7270Sstevel@tonic-gate /* 7280Sstevel@tonic-gate * Copy strings and update pointers 7290Sstevel@tonic-gate */ 7300Sstevel@tonic-gate for (i = 0; i < ksp->ks_ndata; i++, knp++) { 7310Sstevel@tonic-gate if (knp->data_type == KSTAT_DATA_STRING && 7320Sstevel@tonic-gate KSTAT_NAMED_STR_PTR(knp) != NULL) { 7330Sstevel@tonic-gate bcopy(KSTAT_NAMED_STR_PTR(knp), dst, 7340Sstevel@tonic-gate KSTAT_NAMED_STR_BUFLEN(knp)); 7350Sstevel@tonic-gate KSTAT_NAMED_STR_PTR(knp) = dst; 7360Sstevel@tonic-gate dst += KSTAT_NAMED_STR_BUFLEN(knp); 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate ASSERT(dst <= ((char *)buf + ksp->ks_data_size)); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate break; 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate return (0); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate static int 7470Sstevel@tonic-gate header_kstat_update(kstat_t *header_ksp, int rw) 7480Sstevel@tonic-gate { 7490Sstevel@tonic-gate int nkstats = 0; 7500Sstevel@tonic-gate ekstat_t *e; 7510Sstevel@tonic-gate avl_tree_t *t = &kstat_avl_bykid; 7520Sstevel@tonic-gate zoneid_t zoneid; 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate if (rw == KSTAT_WRITE) 7550Sstevel@tonic-gate return (EACCES); 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate ASSERT(MUTEX_HELD(&kstat_chain_lock)); 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate zoneid = getzoneid(); 7600Sstevel@tonic-gate for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) { 7610Sstevel@tonic-gate if (kstat_zone_find((kstat_t *)e, zoneid)) { 7620Sstevel@tonic-gate nkstats++; 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate header_ksp->ks_ndata = nkstats; 7660Sstevel@tonic-gate header_ksp->ks_data_size = nkstats * sizeof (kstat_t); 7670Sstevel@tonic-gate return (0); 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * Copy out the data section of kstat 0, which consists of the list 7720Sstevel@tonic-gate * of all kstat headers. By specification, these headers must be 7730Sstevel@tonic-gate * copied out in order of increasing KID. 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate static int 7760Sstevel@tonic-gate header_kstat_snapshot(kstat_t *header_ksp, void *buf, int rw) 7770Sstevel@tonic-gate { 7780Sstevel@tonic-gate ekstat_t *e; 7790Sstevel@tonic-gate avl_tree_t *t = &kstat_avl_bykid; 7800Sstevel@tonic-gate zoneid_t zoneid; 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate header_ksp->ks_snaptime = gethrtime(); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate if (rw == KSTAT_WRITE) 7850Sstevel@tonic-gate return (EACCES); 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate ASSERT(MUTEX_HELD(&kstat_chain_lock)); 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate zoneid = getzoneid(); 7900Sstevel@tonic-gate for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) { 7910Sstevel@tonic-gate if (kstat_zone_find((kstat_t *)e, zoneid)) { 7920Sstevel@tonic-gate bcopy(&e->e_ks, buf, sizeof (kstat_t)); 7930Sstevel@tonic-gate buf = (char *)buf + sizeof (kstat_t); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate return (0); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* ARGSUSED */ 8010Sstevel@tonic-gate static int 8020Sstevel@tonic-gate system_misc_kstat_update(kstat_t *ksp, int rw) 8030Sstevel@tonic-gate { 8040Sstevel@tonic-gate int myncpus = ncpus; 8050Sstevel@tonic-gate int *loadavgp = &avenrun[0]; 8060Sstevel@tonic-gate int loadavg[LOADAVG_NSTATS]; 8078798SDhanaraj.M@Sun.COM time_t zone_boot_time; 8088798SDhanaraj.M@Sun.COM clock_t zone_lbolt; 8098798SDhanaraj.M@Sun.COM hrtime_t zone_hrtime; 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate if (rw == KSTAT_WRITE) 8120Sstevel@tonic-gate return (EACCES); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate if (!INGLOBALZONE(curproc)) { 8150Sstevel@tonic-gate /* 8160Sstevel@tonic-gate * Here we grab cpu_lock which is OK as long as no-one in the 8170Sstevel@tonic-gate * future attempts to lookup this particular kstat 8180Sstevel@tonic-gate * (unix:0:system_misc) while holding cpu_lock. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate mutex_enter(&cpu_lock); 8210Sstevel@tonic-gate if (pool_pset_enabled()) { 8220Sstevel@tonic-gate psetid_t mypsid = zone_pset_get(curproc->p_zone); 8230Sstevel@tonic-gate int error; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate myncpus = zone_ncpus_get(curproc->p_zone); 8260Sstevel@tonic-gate ASSERT(myncpus > 0); 8270Sstevel@tonic-gate error = cpupart_get_loadavg(mypsid, &loadavg[0], 8280Sstevel@tonic-gate LOADAVG_NSTATS); 8290Sstevel@tonic-gate ASSERT(error == 0); 8300Sstevel@tonic-gate loadavgp = &loadavg[0]; 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate mutex_exit(&cpu_lock); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8358798SDhanaraj.M@Sun.COM if (curproc->p_zone->zone_id == 0) { 8368798SDhanaraj.M@Sun.COM zone_boot_time = boot_time; 83711066Srafael.vanoni@sun.com zone_lbolt = ddi_get_lbolt(); 8388798SDhanaraj.M@Sun.COM } else { 8398798SDhanaraj.M@Sun.COM struct timeval tvp; 8408798SDhanaraj.M@Sun.COM hrt2tv(curproc->p_zone->zone_zsched->p_mstart, &tvp); 8418798SDhanaraj.M@Sun.COM zone_boot_time = tvp.tv_sec; 8428798SDhanaraj.M@Sun.COM 8438798SDhanaraj.M@Sun.COM zone_hrtime = gethrtime(); 8448798SDhanaraj.M@Sun.COM zone_lbolt = (clock_t)(NSEC_TO_TICK(zone_hrtime) - 8458798SDhanaraj.M@Sun.COM NSEC_TO_TICK(curproc->p_zone->zone_zsched->p_mstart)); 8468798SDhanaraj.M@Sun.COM } 8478798SDhanaraj.M@Sun.COM 8480Sstevel@tonic-gate system_misc_kstat.ncpus.value.ui32 = (uint32_t)myncpus; 8498798SDhanaraj.M@Sun.COM system_misc_kstat.lbolt.value.ui32 = (uint32_t)zone_lbolt; 8500Sstevel@tonic-gate system_misc_kstat.deficit.value.ui32 = (uint32_t)deficit; 8518798SDhanaraj.M@Sun.COM system_misc_kstat.clk_intr.value.ui32 = (uint32_t)zone_lbolt; 8520Sstevel@tonic-gate system_misc_kstat.vac.value.ui32 = (uint32_t)vac; 8530Sstevel@tonic-gate system_misc_kstat.nproc.value.ui32 = (uint32_t)nproc; 8540Sstevel@tonic-gate system_misc_kstat.avenrun_1min.value.ui32 = (uint32_t)loadavgp[0]; 8550Sstevel@tonic-gate system_misc_kstat.avenrun_5min.value.ui32 = (uint32_t)loadavgp[1]; 8560Sstevel@tonic-gate system_misc_kstat.avenrun_15min.value.ui32 = (uint32_t)loadavgp[2]; 8578798SDhanaraj.M@Sun.COM system_misc_kstat.boot_time.value.ui32 = (uint32_t) 8588798SDhanaraj.M@Sun.COM zone_boot_time; 8590Sstevel@tonic-gate return (0); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate #ifdef __sparc 8630Sstevel@tonic-gate extern caddr_t econtig32; 8640Sstevel@tonic-gate #else /* !__sparc */ 8650Sstevel@tonic-gate extern caddr_t econtig; 8660Sstevel@tonic-gate #endif /* __sparc */ 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* ARGSUSED */ 8690Sstevel@tonic-gate static int 8700Sstevel@tonic-gate system_pages_kstat_update(kstat_t *ksp, int rw) 8710Sstevel@tonic-gate { 8720Sstevel@tonic-gate kobj_stat_t kobj_stat; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate if (rw == KSTAT_WRITE) { 8750Sstevel@tonic-gate return (EACCES); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate kobj_stat_get(&kobj_stat); 8790Sstevel@tonic-gate system_pages_kstat.physmem.value.ul = (ulong_t)physmem; 8800Sstevel@tonic-gate system_pages_kstat.nalloc.value.ul = kobj_stat.nalloc; 8810Sstevel@tonic-gate system_pages_kstat.nfree.value.ul = kobj_stat.nfree; 8820Sstevel@tonic-gate system_pages_kstat.nalloc_calls.value.ul = kobj_stat.nalloc_calls; 8830Sstevel@tonic-gate system_pages_kstat.nfree_calls.value.ul = kobj_stat.nfree_calls; 8840Sstevel@tonic-gate system_pages_kstat.kernelbase.value.ul = (ulong_t)KERNELBASE; 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate #ifdef __sparc 8870Sstevel@tonic-gate /* 8880Sstevel@tonic-gate * kstat should REALLY be modified to also report kmem64_base and 8890Sstevel@tonic-gate * kmem64_end (see sun4u/os/startup.c), as the virtual address range 8900Sstevel@tonic-gate * [ kernelbase .. econtig ] no longer is truly reflective of the 8910Sstevel@tonic-gate * kernel's vallocs... 8920Sstevel@tonic-gate */ 8930Sstevel@tonic-gate system_pages_kstat.econtig.value.ul = (ulong_t)econtig32; 8940Sstevel@tonic-gate #else /* !__sparc */ 8950Sstevel@tonic-gate system_pages_kstat.econtig.value.ul = (ulong_t)econtig; 8960Sstevel@tonic-gate #endif /* __sparc */ 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate system_pages_kstat.freemem.value.ul = (ulong_t)freemem; 8990Sstevel@tonic-gate system_pages_kstat.availrmem.value.ul = (ulong_t)availrmem; 9000Sstevel@tonic-gate system_pages_kstat.lotsfree.value.ul = (ulong_t)lotsfree; 9010Sstevel@tonic-gate system_pages_kstat.desfree.value.ul = (ulong_t)desfree; 9020Sstevel@tonic-gate system_pages_kstat.minfree.value.ul = (ulong_t)minfree; 9030Sstevel@tonic-gate system_pages_kstat.fastscan.value.ul = (ulong_t)fastscan; 9040Sstevel@tonic-gate system_pages_kstat.slowscan.value.ul = (ulong_t)slowscan; 9050Sstevel@tonic-gate system_pages_kstat.nscan.value.ul = (ulong_t)nscan; 9060Sstevel@tonic-gate system_pages_kstat.desscan.value.ul = (ulong_t)desscan; 9070Sstevel@tonic-gate system_pages_kstat.pagesfree.value.ul = (ulong_t)freemem; 9080Sstevel@tonic-gate system_pages_kstat.pageslocked.value.ul = (ulong_t)(availrmem_initial - 9090Sstevel@tonic-gate availrmem); 9100Sstevel@tonic-gate system_pages_kstat.pagestotal.value.ul = (ulong_t)total_pages; 9110Sstevel@tonic-gate /* 9120Sstevel@tonic-gate * pp_kernel represents total pages used by the kernel since the 9130Sstevel@tonic-gate * startup. This formula takes into account the boottime kernel 9140Sstevel@tonic-gate * footprint and also considers the availrmem changes because of 9150Sstevel@tonic-gate * user explicit page locking. 9160Sstevel@tonic-gate */ 9170Sstevel@tonic-gate system_pages_kstat.pp_kernel.value.ul = (ulong_t)(physinstalled - 9186695Saguzovsk obp_pages - availrmem - k_anoninfo.ani_mem_resv - 9196695Saguzovsk anon_segkp_pages_locked - pages_locked - 9206695Saguzovsk pages_claimed - pages_useclaim); 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate return (0); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate kstat_t * 9262951Selowe kstat_create(const char *ks_module, int ks_instance, const char *ks_name, 9272951Selowe const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate return (kstat_create_zone(ks_module, ks_instance, ks_name, ks_class, 9306695Saguzovsk ks_type, ks_ndata, ks_flags, ALL_ZONES)); 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Allocate and initialize a kstat structure. Or, if a dormant kstat with 9350Sstevel@tonic-gate * the specified name exists, reactivate it. Returns a pointer to the kstat 9360Sstevel@tonic-gate * on success, NULL on failure. The kstat will not be visible to the 9370Sstevel@tonic-gate * kstat driver until kstat_install(). 9380Sstevel@tonic-gate */ 9390Sstevel@tonic-gate kstat_t * 9402951Selowe kstat_create_zone(const char *ks_module, int ks_instance, const char *ks_name, 9412951Selowe const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags, 9420Sstevel@tonic-gate zoneid_t ks_zoneid) 9430Sstevel@tonic-gate { 9440Sstevel@tonic-gate size_t ks_data_size; 9450Sstevel@tonic-gate kstat_t *ksp; 9460Sstevel@tonic-gate ekstat_t *e; 9470Sstevel@tonic-gate avl_index_t where; 9480Sstevel@tonic-gate char namebuf[KSTAT_STRLEN + 16]; 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate if (avl_numnodes(&kstat_avl_bykid) == 0) { 9510Sstevel@tonic-gate avl_create(&kstat_avl_bykid, kstat_compare_bykid, 9520Sstevel@tonic-gate sizeof (ekstat_t), offsetof(struct ekstat, e_avl_bykid)); 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate avl_create(&kstat_avl_byname, kstat_compare_byname, 9550Sstevel@tonic-gate sizeof (ekstat_t), offsetof(struct ekstat, e_avl_byname)); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * If ks_name == NULL, set the ks_name to <module><instance>. 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate if (ks_name == NULL) { 9620Sstevel@tonic-gate char buf[KSTAT_STRLEN]; 9630Sstevel@tonic-gate kstat_set_string(buf, ks_module); 9640Sstevel@tonic-gate (void) sprintf(namebuf, "%s%d", buf, ks_instance); 9650Sstevel@tonic-gate ks_name = namebuf; 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate /* 9690Sstevel@tonic-gate * Make sure it's a valid kstat data type 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate if (ks_type >= KSTAT_NUM_TYPES) { 9720Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): " 9736695Saguzovsk "invalid kstat type %d", 9746695Saguzovsk ks_module, ks_instance, ks_name, ks_type); 9750Sstevel@tonic-gate return (NULL); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * Don't allow persistent virtual kstats -- it makes no sense. 9800Sstevel@tonic-gate * ks_data points to garbage when the client goes away. 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate if ((ks_flags & KSTAT_FLAG_PERSISTENT) && 9830Sstevel@tonic-gate (ks_flags & KSTAT_FLAG_VIRTUAL)) { 9840Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): " 9856695Saguzovsk "cannot create persistent virtual kstat", 9866695Saguzovsk ks_module, ks_instance, ks_name); 9870Sstevel@tonic-gate return (NULL); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate /* 9910Sstevel@tonic-gate * Don't allow variable-size physical kstats, since the framework's 9920Sstevel@tonic-gate * memory allocation for physical kstat data is fixed at creation time. 9930Sstevel@tonic-gate */ 9940Sstevel@tonic-gate if ((ks_flags & KSTAT_FLAG_VAR_SIZE) && 9950Sstevel@tonic-gate !(ks_flags & KSTAT_FLAG_VIRTUAL)) { 9960Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): " 9976695Saguzovsk "cannot create variable-size physical kstat", 9986695Saguzovsk ks_module, ks_instance, ks_name); 9990Sstevel@tonic-gate return (NULL); 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate /* 10030Sstevel@tonic-gate * Make sure the number of data fields is within legal range 10040Sstevel@tonic-gate */ 10050Sstevel@tonic-gate if (ks_ndata < kstat_data_type[ks_type].min_ndata || 10060Sstevel@tonic-gate ks_ndata > kstat_data_type[ks_type].max_ndata) { 10070Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): " 10086695Saguzovsk "ks_ndata=%d out of range [%d, %d]", 10096695Saguzovsk ks_module, ks_instance, ks_name, (int)ks_ndata, 10106695Saguzovsk kstat_data_type[ks_type].min_ndata, 10116695Saguzovsk kstat_data_type[ks_type].max_ndata); 10120Sstevel@tonic-gate return (NULL); 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate ks_data_size = kstat_data_type[ks_type].size * ks_ndata; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate /* 10180Sstevel@tonic-gate * If the named kstat already exists and is dormant, reactivate it. 10190Sstevel@tonic-gate */ 10200Sstevel@tonic-gate ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid); 10210Sstevel@tonic-gate if (ksp != NULL) { 10220Sstevel@tonic-gate if (!(ksp->ks_flags & KSTAT_FLAG_DORMANT)) { 10230Sstevel@tonic-gate /* 10240Sstevel@tonic-gate * The named kstat exists but is not dormant -- 10250Sstevel@tonic-gate * this is a kstat namespace collision. 10260Sstevel@tonic-gate */ 10270Sstevel@tonic-gate kstat_rele(ksp); 10280Sstevel@tonic-gate cmn_err(CE_WARN, 10290Sstevel@tonic-gate "kstat_create('%s', %d, '%s'): namespace collision", 10300Sstevel@tonic-gate ks_module, ks_instance, ks_name); 10310Sstevel@tonic-gate return (NULL); 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate if ((strcmp(ksp->ks_class, ks_class) != 0) || 10340Sstevel@tonic-gate (ksp->ks_type != ks_type) || 10350Sstevel@tonic-gate (ksp->ks_ndata != ks_ndata) || 10360Sstevel@tonic-gate (ks_flags & KSTAT_FLAG_VIRTUAL)) { 10370Sstevel@tonic-gate /* 10380Sstevel@tonic-gate * The name is the same, but the other key parameters 10390Sstevel@tonic-gate * differ from those of the dormant kstat -- bogus. 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate kstat_rele(ksp); 10420Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): " 10436695Saguzovsk "invalid reactivation of dormant kstat", 10446695Saguzovsk ks_module, ks_instance, ks_name); 10450Sstevel@tonic-gate return (NULL); 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate /* 10480Sstevel@tonic-gate * Return dormant kstat pointer to caller. As usual, 10490Sstevel@tonic-gate * the kstat is marked invalid until kstat_install(). 10500Sstevel@tonic-gate */ 10510Sstevel@tonic-gate ksp->ks_flags |= KSTAT_FLAG_INVALID; 10520Sstevel@tonic-gate kstat_rele(ksp); 10530Sstevel@tonic-gate return (ksp); 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate /* 10570Sstevel@tonic-gate * Allocate memory for the new kstat header and, if this is a physical 10580Sstevel@tonic-gate * kstat, the data section. 10590Sstevel@tonic-gate */ 10600Sstevel@tonic-gate e = kstat_alloc(ks_flags & KSTAT_FLAG_VIRTUAL ? 0 : ks_data_size); 10610Sstevel@tonic-gate if (e == NULL) { 10620Sstevel@tonic-gate cmn_err(CE_NOTE, "kstat_create('%s', %d, '%s'): " 10636695Saguzovsk "insufficient kernel memory", 10646695Saguzovsk ks_module, ks_instance, ks_name); 10650Sstevel@tonic-gate return (NULL); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate /* 10690Sstevel@tonic-gate * Initialize as many fields as we can. The caller may reset 10700Sstevel@tonic-gate * ks_lock, ks_update, ks_private, and ks_snapshot as necessary. 10710Sstevel@tonic-gate * Creators of virtual kstats may also reset ks_data. It is 10720Sstevel@tonic-gate * also up to the caller to initialize the kstat data section, 10730Sstevel@tonic-gate * if necessary. All initialization must be complete before 10740Sstevel@tonic-gate * calling kstat_install(). 10750Sstevel@tonic-gate */ 10760Sstevel@tonic-gate e->e_zone.zoneid = ks_zoneid; 10770Sstevel@tonic-gate e->e_zone.next = NULL; 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate ksp = &e->e_ks; 10800Sstevel@tonic-gate ksp->ks_crtime = gethrtime(); 10810Sstevel@tonic-gate kstat_set_string(ksp->ks_module, ks_module); 10820Sstevel@tonic-gate ksp->ks_instance = ks_instance; 10830Sstevel@tonic-gate kstat_set_string(ksp->ks_name, ks_name); 10840Sstevel@tonic-gate ksp->ks_type = ks_type; 10850Sstevel@tonic-gate kstat_set_string(ksp->ks_class, ks_class); 10860Sstevel@tonic-gate ksp->ks_flags = ks_flags | KSTAT_FLAG_INVALID; 10870Sstevel@tonic-gate if (ks_flags & KSTAT_FLAG_VIRTUAL) 10880Sstevel@tonic-gate ksp->ks_data = NULL; 10890Sstevel@tonic-gate else 10900Sstevel@tonic-gate ksp->ks_data = (void *)(e + 1); 10910Sstevel@tonic-gate ksp->ks_ndata = ks_ndata; 10920Sstevel@tonic-gate ksp->ks_data_size = ks_data_size; 10930Sstevel@tonic-gate ksp->ks_snaptime = ksp->ks_crtime; 10940Sstevel@tonic-gate ksp->ks_update = default_kstat_update; 10950Sstevel@tonic-gate ksp->ks_private = NULL; 10960Sstevel@tonic-gate ksp->ks_snapshot = default_kstat_snapshot; 10970Sstevel@tonic-gate ksp->ks_lock = NULL; 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate mutex_enter(&kstat_chain_lock); 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* 11020Sstevel@tonic-gate * Add our kstat to the AVL trees. 11030Sstevel@tonic-gate */ 11040Sstevel@tonic-gate if (avl_find(&kstat_avl_byname, e, &where) != NULL) { 11050Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 11060Sstevel@tonic-gate cmn_err(CE_WARN, 11070Sstevel@tonic-gate "kstat_create('%s', %d, '%s'): namespace collision", 11080Sstevel@tonic-gate ks_module, ks_instance, ks_name); 11090Sstevel@tonic-gate kstat_free(e); 11100Sstevel@tonic-gate return (NULL); 11110Sstevel@tonic-gate } 11120Sstevel@tonic-gate avl_insert(&kstat_avl_byname, e, where); 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * Loop around until we find an unused KID. 11160Sstevel@tonic-gate */ 11170Sstevel@tonic-gate do { 11180Sstevel@tonic-gate ksp->ks_kid = kstat_chain_id++; 11190Sstevel@tonic-gate } while (avl_find(&kstat_avl_bykid, e, &where) != NULL); 11200Sstevel@tonic-gate avl_insert(&kstat_avl_bykid, e, where); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate return (ksp); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate /* 11280Sstevel@tonic-gate * Activate a fully initialized kstat and make it visible to /dev/kstat. 11290Sstevel@tonic-gate */ 11300Sstevel@tonic-gate void 11310Sstevel@tonic-gate kstat_install(kstat_t *ksp) 11320Sstevel@tonic-gate { 11330Sstevel@tonic-gate zoneid_t zoneid = ((ekstat_t *)ksp)->e_zone.zoneid; 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate /* 11360Sstevel@tonic-gate * If this is a variable-size kstat, it MUST provide kstat data locking 11370Sstevel@tonic-gate * to prevent data-size races with kstat readers. 11380Sstevel@tonic-gate */ 11390Sstevel@tonic-gate if ((ksp->ks_flags & KSTAT_FLAG_VAR_SIZE) && ksp->ks_lock == NULL) { 11400Sstevel@tonic-gate panic("kstat_install('%s', %d, '%s'): " 11410Sstevel@tonic-gate "cannot create variable-size kstat without data lock", 11420Sstevel@tonic-gate ksp->ks_module, ksp->ks_instance, ksp->ks_name); 11430Sstevel@tonic-gate } 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) { 11460Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_install(%p): does not exist", 11470Sstevel@tonic-gate (void *)ksp); 11480Sstevel@tonic-gate return; 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data != NULL) { 11520Sstevel@tonic-gate int has_long_strings = 0; 11530Sstevel@tonic-gate uint_t i; 11540Sstevel@tonic-gate kstat_named_t *knp = KSTAT_NAMED_PTR(ksp); 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate for (i = 0; i < ksp->ks_ndata; i++, knp++) { 11570Sstevel@tonic-gate if (knp->data_type == KSTAT_DATA_STRING) { 11580Sstevel@tonic-gate has_long_strings = 1; 11590Sstevel@tonic-gate break; 11600Sstevel@tonic-gate } 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate /* 11630Sstevel@tonic-gate * It is an error for a named kstat with fields of 11640Sstevel@tonic-gate * KSTAT_DATA_STRING to be non-virtual. 11650Sstevel@tonic-gate */ 11660Sstevel@tonic-gate if (has_long_strings && !(ksp->ks_flags & KSTAT_FLAG_VIRTUAL)) { 11670Sstevel@tonic-gate panic("kstat_install('%s', %d, '%s'): " 11680Sstevel@tonic-gate "named kstat containing KSTAT_DATA_STRING " 11690Sstevel@tonic-gate "is not virtual", 11700Sstevel@tonic-gate ksp->ks_module, ksp->ks_instance, 11710Sstevel@tonic-gate ksp->ks_name); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate /* 11740Sstevel@tonic-gate * The default snapshot routine does not handle KSTAT_WRITE 11750Sstevel@tonic-gate * for long strings. 11760Sstevel@tonic-gate */ 11770Sstevel@tonic-gate if (has_long_strings && (ksp->ks_flags & KSTAT_FLAG_WRITABLE) && 11780Sstevel@tonic-gate (ksp->ks_snapshot == default_kstat_snapshot)) { 11790Sstevel@tonic-gate panic("kstat_install('%s', %d, '%s'): " 11800Sstevel@tonic-gate "named kstat containing KSTAT_DATA_STRING " 11810Sstevel@tonic-gate "is writable but uses default snapshot routine", 11820Sstevel@tonic-gate ksp->ks_module, ksp->ks_instance, ksp->ks_name); 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate if (ksp->ks_flags & KSTAT_FLAG_DORMANT) { 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate /* 11890Sstevel@tonic-gate * We are reactivating a dormant kstat. Initialize the 11900Sstevel@tonic-gate * caller's underlying data to the value it had when the 11910Sstevel@tonic-gate * kstat went dormant, and mark the kstat as active. 11920Sstevel@tonic-gate * Grab the provider's kstat lock if it's not already held. 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate kmutex_t *lp = ksp->ks_lock; 11950Sstevel@tonic-gate if (lp != NULL && MUTEX_NOT_HELD(lp)) { 11960Sstevel@tonic-gate mutex_enter(lp); 11970Sstevel@tonic-gate (void) KSTAT_UPDATE(ksp, KSTAT_WRITE); 11980Sstevel@tonic-gate mutex_exit(lp); 11990Sstevel@tonic-gate } else { 12000Sstevel@tonic-gate (void) KSTAT_UPDATE(ksp, KSTAT_WRITE); 12010Sstevel@tonic-gate } 12020Sstevel@tonic-gate ksp->ks_flags &= ~KSTAT_FLAG_DORMANT; 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate /* 12060Sstevel@tonic-gate * Now that the kstat is active, make it visible to the kstat driver. 12070Sstevel@tonic-gate */ 12080Sstevel@tonic-gate ksp->ks_flags &= ~KSTAT_FLAG_INVALID; 12090Sstevel@tonic-gate kstat_rele(ksp); 12100Sstevel@tonic-gate } 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate /* 12130Sstevel@tonic-gate * Remove a kstat from the system. Or, if it's a persistent kstat, 12140Sstevel@tonic-gate * just update the data and mark it as dormant. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate void 12170Sstevel@tonic-gate kstat_delete(kstat_t *ksp) 12180Sstevel@tonic-gate { 12190Sstevel@tonic-gate kmutex_t *lp; 12200Sstevel@tonic-gate ekstat_t *e = (ekstat_t *)ksp; 122111438SFrank.Batschulat@Sun.COM zoneid_t zoneid; 12220Sstevel@tonic-gate kstat_zone_t *kz; 12230Sstevel@tonic-gate 122411438SFrank.Batschulat@Sun.COM ASSERT(ksp != NULL); 122511438SFrank.Batschulat@Sun.COM 12260Sstevel@tonic-gate if (ksp == NULL) 12270Sstevel@tonic-gate return; 12280Sstevel@tonic-gate 122911438SFrank.Batschulat@Sun.COM zoneid = e->e_zone.zoneid; 123011438SFrank.Batschulat@Sun.COM 12310Sstevel@tonic-gate lp = ksp->ks_lock; 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate if (lp != NULL && MUTEX_HELD(lp)) { 12340Sstevel@tonic-gate panic("kstat_delete(%p): caller holds data lock %p", 12350Sstevel@tonic-gate (void *)ksp, (void *)lp); 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) { 12390Sstevel@tonic-gate cmn_err(CE_WARN, "kstat_delete(%p): does not exist", 12400Sstevel@tonic-gate (void *)ksp); 12410Sstevel@tonic-gate return; 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate if (ksp->ks_flags & KSTAT_FLAG_PERSISTENT) { 12450Sstevel@tonic-gate /* 12460Sstevel@tonic-gate * Update the data one last time, so that all activity 12470Sstevel@tonic-gate * prior to going dormant has been accounted for. 12480Sstevel@tonic-gate */ 12490Sstevel@tonic-gate KSTAT_ENTER(ksp); 12500Sstevel@tonic-gate (void) KSTAT_UPDATE(ksp, KSTAT_READ); 12510Sstevel@tonic-gate KSTAT_EXIT(ksp); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate /* 12540Sstevel@tonic-gate * Mark the kstat as dormant and restore caller-modifiable 12550Sstevel@tonic-gate * fields to default values, so the kstat is readable during 12560Sstevel@tonic-gate * the dormant phase. 12570Sstevel@tonic-gate */ 12580Sstevel@tonic-gate ksp->ks_flags |= KSTAT_FLAG_DORMANT; 12590Sstevel@tonic-gate ksp->ks_lock = NULL; 12600Sstevel@tonic-gate ksp->ks_update = default_kstat_update; 12610Sstevel@tonic-gate ksp->ks_private = NULL; 12620Sstevel@tonic-gate ksp->ks_snapshot = default_kstat_snapshot; 12630Sstevel@tonic-gate kstat_rele(ksp); 12640Sstevel@tonic-gate return; 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate /* 12680Sstevel@tonic-gate * Remove the kstat from the framework's AVL trees, 12690Sstevel@tonic-gate * free the allocated memory, and increment kstat_chain_id so 12700Sstevel@tonic-gate * /dev/kstat clients can detect the event. 12710Sstevel@tonic-gate */ 12720Sstevel@tonic-gate mutex_enter(&kstat_chain_lock); 12730Sstevel@tonic-gate avl_remove(&kstat_avl_bykid, e); 12740Sstevel@tonic-gate avl_remove(&kstat_avl_byname, e); 12750Sstevel@tonic-gate kstat_chain_id++; 12760Sstevel@tonic-gate mutex_exit(&kstat_chain_lock); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate kz = e->e_zone.next; 12790Sstevel@tonic-gate while (kz != NULL) { 12800Sstevel@tonic-gate kstat_zone_t *t = kz; 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate kz = kz->next; 12830Sstevel@tonic-gate kmem_free(t, sizeof (*t)); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate kstat_rele(ksp); 12860Sstevel@tonic-gate kstat_free(e); 12870Sstevel@tonic-gate } 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate void 12902951Selowe kstat_delete_byname_zone(const char *ks_module, int ks_instance, 12912951Selowe const char *ks_name, zoneid_t ks_zoneid) 12920Sstevel@tonic-gate { 12930Sstevel@tonic-gate kstat_t *ksp; 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid); 12960Sstevel@tonic-gate if (ksp != NULL) { 12970Sstevel@tonic-gate kstat_rele(ksp); 12980Sstevel@tonic-gate kstat_delete(ksp); 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate } 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate void 13032951Selowe kstat_delete_byname(const char *ks_module, int ks_instance, const char *ks_name) 13040Sstevel@tonic-gate { 13050Sstevel@tonic-gate kstat_delete_byname_zone(ks_module, ks_instance, ks_name, ALL_ZONES); 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate /* 13090Sstevel@tonic-gate * The sparc V9 versions of these routines can be much cheaper than 13100Sstevel@tonic-gate * the poor 32-bit compiler can comprehend, so they're in sparcv9_subr.s. 13110Sstevel@tonic-gate * For simplicity, however, we always feed the C versions to lint. 13120Sstevel@tonic-gate */ 13130Sstevel@tonic-gate #if !defined(__sparc) || defined(lint) || defined(__lint) 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate void 13160Sstevel@tonic-gate kstat_waitq_enter(kstat_io_t *kiop) 13170Sstevel@tonic-gate { 13180Sstevel@tonic-gate hrtime_t new, delta; 13190Sstevel@tonic-gate ulong_t wcnt; 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate new = gethrtime_unscaled(); 13220Sstevel@tonic-gate delta = new - kiop->wlastupdate; 13230Sstevel@tonic-gate kiop->wlastupdate = new; 13240Sstevel@tonic-gate wcnt = kiop->wcnt++; 13250Sstevel@tonic-gate if (wcnt != 0) { 13260Sstevel@tonic-gate kiop->wlentime += delta * wcnt; 13270Sstevel@tonic-gate kiop->wtime += delta; 13280Sstevel@tonic-gate } 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate void 13320Sstevel@tonic-gate kstat_waitq_exit(kstat_io_t *kiop) 13330Sstevel@tonic-gate { 13340Sstevel@tonic-gate hrtime_t new, delta; 13350Sstevel@tonic-gate ulong_t wcnt; 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate new = gethrtime_unscaled(); 13380Sstevel@tonic-gate delta = new - kiop->wlastupdate; 13390Sstevel@tonic-gate kiop->wlastupdate = new; 13400Sstevel@tonic-gate wcnt = kiop->wcnt--; 13410Sstevel@tonic-gate ASSERT((int)wcnt > 0); 13420Sstevel@tonic-gate kiop->wlentime += delta * wcnt; 13430Sstevel@tonic-gate kiop->wtime += delta; 13440Sstevel@tonic-gate } 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate void 13470Sstevel@tonic-gate kstat_runq_enter(kstat_io_t *kiop) 13480Sstevel@tonic-gate { 13490Sstevel@tonic-gate hrtime_t new, delta; 13500Sstevel@tonic-gate ulong_t rcnt; 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate new = gethrtime_unscaled(); 13530Sstevel@tonic-gate delta = new - kiop->rlastupdate; 13540Sstevel@tonic-gate kiop->rlastupdate = new; 13550Sstevel@tonic-gate rcnt = kiop->rcnt++; 13560Sstevel@tonic-gate if (rcnt != 0) { 13570Sstevel@tonic-gate kiop->rlentime += delta * rcnt; 13580Sstevel@tonic-gate kiop->rtime += delta; 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate void 13630Sstevel@tonic-gate kstat_runq_exit(kstat_io_t *kiop) 13640Sstevel@tonic-gate { 13650Sstevel@tonic-gate hrtime_t new, delta; 13660Sstevel@tonic-gate ulong_t rcnt; 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate new = gethrtime_unscaled(); 13690Sstevel@tonic-gate delta = new - kiop->rlastupdate; 13700Sstevel@tonic-gate kiop->rlastupdate = new; 13710Sstevel@tonic-gate rcnt = kiop->rcnt--; 13720Sstevel@tonic-gate ASSERT((int)rcnt > 0); 13730Sstevel@tonic-gate kiop->rlentime += delta * rcnt; 13740Sstevel@tonic-gate kiop->rtime += delta; 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate void 13780Sstevel@tonic-gate kstat_waitq_to_runq(kstat_io_t *kiop) 13790Sstevel@tonic-gate { 13800Sstevel@tonic-gate hrtime_t new, delta; 13810Sstevel@tonic-gate ulong_t wcnt, rcnt; 13820Sstevel@tonic-gate 13830Sstevel@tonic-gate new = gethrtime_unscaled(); 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate delta = new - kiop->wlastupdate; 13860Sstevel@tonic-gate kiop->wlastupdate = new; 13870Sstevel@tonic-gate wcnt = kiop->wcnt--; 13880Sstevel@tonic-gate ASSERT((int)wcnt > 0); 13890Sstevel@tonic-gate kiop->wlentime += delta * wcnt; 13900Sstevel@tonic-gate kiop->wtime += delta; 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate delta = new - kiop->rlastupdate; 13930Sstevel@tonic-gate kiop->rlastupdate = new; 13940Sstevel@tonic-gate rcnt = kiop->rcnt++; 13950Sstevel@tonic-gate if (rcnt != 0) { 13960Sstevel@tonic-gate kiop->rlentime += delta * rcnt; 13970Sstevel@tonic-gate kiop->rtime += delta; 13980Sstevel@tonic-gate } 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate void 14020Sstevel@tonic-gate kstat_runq_back_to_waitq(kstat_io_t *kiop) 14030Sstevel@tonic-gate { 14040Sstevel@tonic-gate hrtime_t new, delta; 14050Sstevel@tonic-gate ulong_t wcnt, rcnt; 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate new = gethrtime_unscaled(); 14080Sstevel@tonic-gate 14090Sstevel@tonic-gate delta = new - kiop->rlastupdate; 14100Sstevel@tonic-gate kiop->rlastupdate = new; 14110Sstevel@tonic-gate rcnt = kiop->rcnt--; 14120Sstevel@tonic-gate ASSERT((int)rcnt > 0); 14130Sstevel@tonic-gate kiop->rlentime += delta * rcnt; 14140Sstevel@tonic-gate kiop->rtime += delta; 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate delta = new - kiop->wlastupdate; 14170Sstevel@tonic-gate kiop->wlastupdate = new; 14180Sstevel@tonic-gate wcnt = kiop->wcnt++; 14190Sstevel@tonic-gate if (wcnt != 0) { 14200Sstevel@tonic-gate kiop->wlentime += delta * wcnt; 14210Sstevel@tonic-gate kiop->wtime += delta; 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate #endif 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate void 14280Sstevel@tonic-gate kstat_timer_start(kstat_timer_t *ktp) 14290Sstevel@tonic-gate { 14300Sstevel@tonic-gate ktp->start_time = gethrtime(); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate void 14340Sstevel@tonic-gate kstat_timer_stop(kstat_timer_t *ktp) 14350Sstevel@tonic-gate { 14360Sstevel@tonic-gate hrtime_t etime; 14370Sstevel@tonic-gate u_longlong_t num_events; 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate ktp->stop_time = etime = gethrtime(); 14400Sstevel@tonic-gate etime -= ktp->start_time; 14410Sstevel@tonic-gate num_events = ktp->num_events; 14420Sstevel@tonic-gate if (etime < ktp->min_time || num_events == 0) 14430Sstevel@tonic-gate ktp->min_time = etime; 14440Sstevel@tonic-gate if (etime > ktp->max_time) 14450Sstevel@tonic-gate ktp->max_time = etime; 14460Sstevel@tonic-gate ktp->elapsed_time += etime; 14470Sstevel@tonic-gate ktp->num_events = num_events + 1; 14480Sstevel@tonic-gate } 1449