xref: /onnv-gate/usr/src/uts/common/os/kstat_fr.c (revision 12982:a2d5e2db1c76)
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 /*
2212607Sjohn.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
kstat_zone_find(kstat_t * k,zoneid_t zoneid)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
kstat_zone_remove(kstat_t * k,zoneid_t zoneid)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
kstat_zone_add(kstat_t * k,zoneid_t zoneid)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
kstat_zone_compare(ekstat_t * e1,ekstat_t * e2)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
kstat_compare_bykid(const void * a1,const void * a2)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
kstat_compare_byname(const void * a1,const void * a2)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 *
kstat_hold(avl_tree_t * t,ekstat_t * template)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
kstat_rele(kstat_t * ksp)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 *
kstat_hold_bykid(kid_t kid,zoneid_t zoneid)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 *
kstat_hold_byname(const char * ks_module,int ks_instance,const char * ks_name,zoneid_t ks_zoneid)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 *
kstat_alloc(size_t size)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
kstat_free(ekstat_t * e)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
kstat_init(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
kstat_named_setstr(kstat_named_t * knp,const char * src)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
kstat_set_string(char * dst,const char * src)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
kstat_named_init(kstat_named_t * knp,const char * name,uchar_t data_type)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
kstat_timer_init(kstat_timer_t * ktp,const char * name)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
default_kstat_update(kstat_t * ksp,int rw)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
default_kstat_snapshot(kstat_t * ksp,void * buf,int rw)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
header_kstat_update(kstat_t * header_ksp,int rw)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
header_kstat_snapshot(kstat_t * header_ksp,void * buf,int rw)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
system_misc_kstat_update(kstat_t * ksp,int rw)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;
810*12982SVamsi.Krishna@Sun.COM 	size_t zone_nproc;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
8130Sstevel@tonic-gate 		return (EACCES);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	if (!INGLOBALZONE(curproc)) {
8160Sstevel@tonic-gate 		/*
8170Sstevel@tonic-gate 		 * Here we grab cpu_lock which is OK as long as no-one in the
8180Sstevel@tonic-gate 		 * future attempts to lookup this particular kstat
8190Sstevel@tonic-gate 		 * (unix:0:system_misc) while holding cpu_lock.
8200Sstevel@tonic-gate 		 */
8210Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
8220Sstevel@tonic-gate 		if (pool_pset_enabled()) {
8230Sstevel@tonic-gate 			psetid_t mypsid = zone_pset_get(curproc->p_zone);
8240Sstevel@tonic-gate 			int error;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 			myncpus = zone_ncpus_get(curproc->p_zone);
8270Sstevel@tonic-gate 			ASSERT(myncpus > 0);
8280Sstevel@tonic-gate 			error = cpupart_get_loadavg(mypsid, &loadavg[0],
8290Sstevel@tonic-gate 			    LOADAVG_NSTATS);
8300Sstevel@tonic-gate 			ASSERT(error == 0);
8310Sstevel@tonic-gate 			loadavgp = &loadavg[0];
8320Sstevel@tonic-gate 		}
8330Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
836*12982SVamsi.Krishna@Sun.COM 	if (INGLOBALZONE(curproc)) {
8378798SDhanaraj.M@Sun.COM 		zone_boot_time = boot_time;
83811066Srafael.vanoni@sun.com 		zone_lbolt = ddi_get_lbolt();
839*12982SVamsi.Krishna@Sun.COM 		zone_nproc = nproc;
8408798SDhanaraj.M@Sun.COM 	} else {
8418798SDhanaraj.M@Sun.COM 		struct timeval tvp;
8428798SDhanaraj.M@Sun.COM 		hrt2tv(curproc->p_zone->zone_zsched->p_mstart, &tvp);
8438798SDhanaraj.M@Sun.COM 		zone_boot_time = tvp.tv_sec;
8448798SDhanaraj.M@Sun.COM 
8458798SDhanaraj.M@Sun.COM 		zone_hrtime = gethrtime();
8468798SDhanaraj.M@Sun.COM 		zone_lbolt = (clock_t)(NSEC_TO_TICK(zone_hrtime) -
8478798SDhanaraj.M@Sun.COM 		    NSEC_TO_TICK(curproc->p_zone->zone_zsched->p_mstart));
848*12982SVamsi.Krishna@Sun.COM 		mutex_enter(&curproc->p_zone->zone_nlwps_lock);
849*12982SVamsi.Krishna@Sun.COM 		zone_nproc = curproc->p_zone->zone_nprocs;
850*12982SVamsi.Krishna@Sun.COM 		mutex_exit(&curproc->p_zone->zone_nlwps_lock);
8518798SDhanaraj.M@Sun.COM 	}
8528798SDhanaraj.M@Sun.COM 
8530Sstevel@tonic-gate 	system_misc_kstat.ncpus.value.ui32		= (uint32_t)myncpus;
8548798SDhanaraj.M@Sun.COM 	system_misc_kstat.lbolt.value.ui32		= (uint32_t)zone_lbolt;
8550Sstevel@tonic-gate 	system_misc_kstat.deficit.value.ui32		= (uint32_t)deficit;
8568798SDhanaraj.M@Sun.COM 	system_misc_kstat.clk_intr.value.ui32		= (uint32_t)zone_lbolt;
8570Sstevel@tonic-gate 	system_misc_kstat.vac.value.ui32		= (uint32_t)vac;
858*12982SVamsi.Krishna@Sun.COM 	system_misc_kstat.nproc.value.ui32		= (uint32_t)zone_nproc;
8590Sstevel@tonic-gate 	system_misc_kstat.avenrun_1min.value.ui32	= (uint32_t)loadavgp[0];
8600Sstevel@tonic-gate 	system_misc_kstat.avenrun_5min.value.ui32	= (uint32_t)loadavgp[1];
8610Sstevel@tonic-gate 	system_misc_kstat.avenrun_15min.value.ui32	= (uint32_t)loadavgp[2];
8628798SDhanaraj.M@Sun.COM 	system_misc_kstat.boot_time.value.ui32		= (uint32_t)
8638798SDhanaraj.M@Sun.COM 	    zone_boot_time;
8640Sstevel@tonic-gate 	return (0);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate #ifdef	__sparc
8680Sstevel@tonic-gate extern caddr_t	econtig32;
8690Sstevel@tonic-gate #else	/* !__sparc */
8700Sstevel@tonic-gate extern caddr_t	econtig;
8710Sstevel@tonic-gate #endif	/* __sparc */
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate /* ARGSUSED */
8740Sstevel@tonic-gate static int
system_pages_kstat_update(kstat_t * ksp,int rw)8750Sstevel@tonic-gate system_pages_kstat_update(kstat_t *ksp, int rw)
8760Sstevel@tonic-gate {
8770Sstevel@tonic-gate 	kobj_stat_t kobj_stat;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
8800Sstevel@tonic-gate 		return (EACCES);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	kobj_stat_get(&kobj_stat);
8840Sstevel@tonic-gate 	system_pages_kstat.physmem.value.ul	= (ulong_t)physmem;
8850Sstevel@tonic-gate 	system_pages_kstat.nalloc.value.ul	= kobj_stat.nalloc;
8860Sstevel@tonic-gate 	system_pages_kstat.nfree.value.ul	= kobj_stat.nfree;
8870Sstevel@tonic-gate 	system_pages_kstat.nalloc_calls.value.ul = kobj_stat.nalloc_calls;
8880Sstevel@tonic-gate 	system_pages_kstat.nfree_calls.value.ul	= kobj_stat.nfree_calls;
8890Sstevel@tonic-gate 	system_pages_kstat.kernelbase.value.ul	= (ulong_t)KERNELBASE;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate #ifdef	__sparc
8920Sstevel@tonic-gate 	/*
8930Sstevel@tonic-gate 	 * kstat should REALLY be modified to also report kmem64_base and
8940Sstevel@tonic-gate 	 * kmem64_end (see sun4u/os/startup.c), as the virtual address range
8950Sstevel@tonic-gate 	 * [ kernelbase .. econtig ] no longer is truly reflective of the
8960Sstevel@tonic-gate 	 * kernel's vallocs...
8970Sstevel@tonic-gate 	 */
8980Sstevel@tonic-gate 	system_pages_kstat.econtig.value.ul	= (ulong_t)econtig32;
8990Sstevel@tonic-gate #else	/* !__sparc */
9000Sstevel@tonic-gate 	system_pages_kstat.econtig.value.ul	= (ulong_t)econtig;
9010Sstevel@tonic-gate #endif	/* __sparc */
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	system_pages_kstat.freemem.value.ul	= (ulong_t)freemem;
9040Sstevel@tonic-gate 	system_pages_kstat.availrmem.value.ul	= (ulong_t)availrmem;
9050Sstevel@tonic-gate 	system_pages_kstat.lotsfree.value.ul	= (ulong_t)lotsfree;
9060Sstevel@tonic-gate 	system_pages_kstat.desfree.value.ul	= (ulong_t)desfree;
9070Sstevel@tonic-gate 	system_pages_kstat.minfree.value.ul	= (ulong_t)minfree;
9080Sstevel@tonic-gate 	system_pages_kstat.fastscan.value.ul	= (ulong_t)fastscan;
9090Sstevel@tonic-gate 	system_pages_kstat.slowscan.value.ul	= (ulong_t)slowscan;
9100Sstevel@tonic-gate 	system_pages_kstat.nscan.value.ul	= (ulong_t)nscan;
9110Sstevel@tonic-gate 	system_pages_kstat.desscan.value.ul	= (ulong_t)desscan;
9120Sstevel@tonic-gate 	system_pages_kstat.pagesfree.value.ul	= (ulong_t)freemem;
9130Sstevel@tonic-gate 	system_pages_kstat.pageslocked.value.ul	= (ulong_t)(availrmem_initial -
9140Sstevel@tonic-gate 	    availrmem);
9150Sstevel@tonic-gate 	system_pages_kstat.pagestotal.value.ul	= (ulong_t)total_pages;
9160Sstevel@tonic-gate 	/*
9170Sstevel@tonic-gate 	 * pp_kernel represents total pages used by the kernel since the
9180Sstevel@tonic-gate 	 * startup. This formula takes into account the boottime kernel
9190Sstevel@tonic-gate 	 * footprint and also considers the availrmem changes because of
9200Sstevel@tonic-gate 	 * user explicit page locking.
9210Sstevel@tonic-gate 	 */
9220Sstevel@tonic-gate 	system_pages_kstat.pp_kernel.value.ul   = (ulong_t)(physinstalled -
9236695Saguzovsk 	    obp_pages - availrmem - k_anoninfo.ani_mem_resv -
9246695Saguzovsk 	    anon_segkp_pages_locked - pages_locked -
9256695Saguzovsk 	    pages_claimed - pages_useclaim);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	return (0);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate kstat_t *
kstat_create(const char * ks_module,int ks_instance,const char * ks_name,const char * ks_class,uchar_t ks_type,uint_t ks_ndata,uchar_t ks_flags)9312951Selowe kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
9322951Selowe     const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags)
9330Sstevel@tonic-gate {
9340Sstevel@tonic-gate 	return (kstat_create_zone(ks_module, ks_instance, ks_name, ks_class,
9356695Saguzovsk 	    ks_type, ks_ndata, ks_flags, ALL_ZONES));
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate /*
9390Sstevel@tonic-gate  * Allocate and initialize a kstat structure.  Or, if a dormant kstat with
9400Sstevel@tonic-gate  * the specified name exists, reactivate it.  Returns a pointer to the kstat
9410Sstevel@tonic-gate  * on success, NULL on failure.  The kstat will not be visible to the
9420Sstevel@tonic-gate  * kstat driver until kstat_install().
9430Sstevel@tonic-gate  */
9440Sstevel@tonic-gate kstat_t *
kstat_create_zone(const char * ks_module,int ks_instance,const char * ks_name,const char * ks_class,uchar_t ks_type,uint_t ks_ndata,uchar_t ks_flags,zoneid_t ks_zoneid)9452951Selowe kstat_create_zone(const char *ks_module, int ks_instance, const char *ks_name,
9462951Selowe     const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
9470Sstevel@tonic-gate     zoneid_t ks_zoneid)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate 	size_t ks_data_size;
9500Sstevel@tonic-gate 	kstat_t *ksp;
9510Sstevel@tonic-gate 	ekstat_t *e;
9520Sstevel@tonic-gate 	avl_index_t where;
9530Sstevel@tonic-gate 	char namebuf[KSTAT_STRLEN + 16];
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	if (avl_numnodes(&kstat_avl_bykid) == 0) {
9560Sstevel@tonic-gate 		avl_create(&kstat_avl_bykid, kstat_compare_bykid,
9570Sstevel@tonic-gate 		    sizeof (ekstat_t), offsetof(struct ekstat, e_avl_bykid));
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 		avl_create(&kstat_avl_byname, kstat_compare_byname,
9600Sstevel@tonic-gate 		    sizeof (ekstat_t), offsetof(struct ekstat, e_avl_byname));
9610Sstevel@tonic-gate 	}
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	/*
9640Sstevel@tonic-gate 	 * If ks_name == NULL, set the ks_name to <module><instance>.
9650Sstevel@tonic-gate 	 */
9660Sstevel@tonic-gate 	if (ks_name == NULL) {
9670Sstevel@tonic-gate 		char buf[KSTAT_STRLEN];
9680Sstevel@tonic-gate 		kstat_set_string(buf, ks_module);
9690Sstevel@tonic-gate 		(void) sprintf(namebuf, "%s%d", buf, ks_instance);
9700Sstevel@tonic-gate 		ks_name = namebuf;
9710Sstevel@tonic-gate 	}
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	/*
9740Sstevel@tonic-gate 	 * Make sure it's a valid kstat data type
9750Sstevel@tonic-gate 	 */
9760Sstevel@tonic-gate 	if (ks_type >= KSTAT_NUM_TYPES) {
9770Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
9786695Saguzovsk 		    "invalid kstat type %d",
9796695Saguzovsk 		    ks_module, ks_instance, ks_name, ks_type);
9800Sstevel@tonic-gate 		return (NULL);
9810Sstevel@tonic-gate 	}
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	/*
9840Sstevel@tonic-gate 	 * Don't allow persistent virtual kstats -- it makes no sense.
9850Sstevel@tonic-gate 	 * ks_data points to garbage when the client goes away.
9860Sstevel@tonic-gate 	 */
9870Sstevel@tonic-gate 	if ((ks_flags & KSTAT_FLAG_PERSISTENT) &&
9880Sstevel@tonic-gate 	    (ks_flags & KSTAT_FLAG_VIRTUAL)) {
9890Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
9906695Saguzovsk 		    "cannot create persistent virtual kstat",
9916695Saguzovsk 		    ks_module, ks_instance, ks_name);
9920Sstevel@tonic-gate 		return (NULL);
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/*
9960Sstevel@tonic-gate 	 * Don't allow variable-size physical kstats, since the framework's
9970Sstevel@tonic-gate 	 * memory allocation for physical kstat data is fixed at creation time.
9980Sstevel@tonic-gate 	 */
9990Sstevel@tonic-gate 	if ((ks_flags & KSTAT_FLAG_VAR_SIZE) &&
10000Sstevel@tonic-gate 	    !(ks_flags & KSTAT_FLAG_VIRTUAL)) {
10010Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
10026695Saguzovsk 		    "cannot create variable-size physical kstat",
10036695Saguzovsk 		    ks_module, ks_instance, ks_name);
10040Sstevel@tonic-gate 		return (NULL);
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	/*
10080Sstevel@tonic-gate 	 * Make sure the number of data fields is within legal range
10090Sstevel@tonic-gate 	 */
10100Sstevel@tonic-gate 	if (ks_ndata < kstat_data_type[ks_type].min_ndata ||
10110Sstevel@tonic-gate 	    ks_ndata > kstat_data_type[ks_type].max_ndata) {
10120Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
10136695Saguzovsk 		    "ks_ndata=%d out of range [%d, %d]",
10146695Saguzovsk 		    ks_module, ks_instance, ks_name, (int)ks_ndata,
10156695Saguzovsk 		    kstat_data_type[ks_type].min_ndata,
10166695Saguzovsk 		    kstat_data_type[ks_type].max_ndata);
10170Sstevel@tonic-gate 		return (NULL);
10180Sstevel@tonic-gate 	}
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	ks_data_size = kstat_data_type[ks_type].size * ks_ndata;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	/*
10230Sstevel@tonic-gate 	 * If the named kstat already exists and is dormant, reactivate it.
10240Sstevel@tonic-gate 	 */
10250Sstevel@tonic-gate 	ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid);
10260Sstevel@tonic-gate 	if (ksp != NULL) {
10270Sstevel@tonic-gate 		if (!(ksp->ks_flags & KSTAT_FLAG_DORMANT)) {
10280Sstevel@tonic-gate 			/*
10290Sstevel@tonic-gate 			 * The named kstat exists but is not dormant --
10300Sstevel@tonic-gate 			 * this is a kstat namespace collision.
10310Sstevel@tonic-gate 			 */
10320Sstevel@tonic-gate 			kstat_rele(ksp);
10330Sstevel@tonic-gate 			cmn_err(CE_WARN,
10340Sstevel@tonic-gate 			    "kstat_create('%s', %d, '%s'): namespace collision",
10350Sstevel@tonic-gate 			    ks_module, ks_instance, ks_name);
10360Sstevel@tonic-gate 			return (NULL);
10370Sstevel@tonic-gate 		}
10380Sstevel@tonic-gate 		if ((strcmp(ksp->ks_class, ks_class) != 0) ||
10390Sstevel@tonic-gate 		    (ksp->ks_type != ks_type) ||
10400Sstevel@tonic-gate 		    (ksp->ks_ndata != ks_ndata) ||
10410Sstevel@tonic-gate 		    (ks_flags & KSTAT_FLAG_VIRTUAL)) {
10420Sstevel@tonic-gate 			/*
10430Sstevel@tonic-gate 			 * The name is the same, but the other key parameters
10440Sstevel@tonic-gate 			 * differ from those of the dormant kstat -- bogus.
10450Sstevel@tonic-gate 			 */
10460Sstevel@tonic-gate 			kstat_rele(ksp);
10470Sstevel@tonic-gate 			cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
10486695Saguzovsk 			    "invalid reactivation of dormant kstat",
10496695Saguzovsk 			    ks_module, ks_instance, ks_name);
10500Sstevel@tonic-gate 			return (NULL);
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 		/*
10530Sstevel@tonic-gate 		 * Return dormant kstat pointer to caller.  As usual,
10540Sstevel@tonic-gate 		 * the kstat is marked invalid until kstat_install().
10550Sstevel@tonic-gate 		 */
10560Sstevel@tonic-gate 		ksp->ks_flags |= KSTAT_FLAG_INVALID;
10570Sstevel@tonic-gate 		kstat_rele(ksp);
10580Sstevel@tonic-gate 		return (ksp);
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/*
10620Sstevel@tonic-gate 	 * Allocate memory for the new kstat header and, if this is a physical
10630Sstevel@tonic-gate 	 * kstat, the data section.
10640Sstevel@tonic-gate 	 */
10650Sstevel@tonic-gate 	e = kstat_alloc(ks_flags & KSTAT_FLAG_VIRTUAL ? 0 : ks_data_size);
10660Sstevel@tonic-gate 	if (e == NULL) {
10670Sstevel@tonic-gate 		cmn_err(CE_NOTE, "kstat_create('%s', %d, '%s'): "
10686695Saguzovsk 		    "insufficient kernel memory",
10696695Saguzovsk 		    ks_module, ks_instance, ks_name);
10700Sstevel@tonic-gate 		return (NULL);
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/*
10740Sstevel@tonic-gate 	 * Initialize as many fields as we can.  The caller may reset
10750Sstevel@tonic-gate 	 * ks_lock, ks_update, ks_private, and ks_snapshot as necessary.
10760Sstevel@tonic-gate 	 * Creators of virtual kstats may also reset ks_data.  It is
10770Sstevel@tonic-gate 	 * also up to the caller to initialize the kstat data section,
10780Sstevel@tonic-gate 	 * if necessary.  All initialization must be complete before
10790Sstevel@tonic-gate 	 * calling kstat_install().
10800Sstevel@tonic-gate 	 */
10810Sstevel@tonic-gate 	e->e_zone.zoneid = ks_zoneid;
10820Sstevel@tonic-gate 	e->e_zone.next = NULL;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	ksp = &e->e_ks;
10850Sstevel@tonic-gate 	ksp->ks_crtime		= gethrtime();
10860Sstevel@tonic-gate 	kstat_set_string(ksp->ks_module, ks_module);
10870Sstevel@tonic-gate 	ksp->ks_instance	= ks_instance;
10880Sstevel@tonic-gate 	kstat_set_string(ksp->ks_name, ks_name);
10890Sstevel@tonic-gate 	ksp->ks_type		= ks_type;
10900Sstevel@tonic-gate 	kstat_set_string(ksp->ks_class, ks_class);
10910Sstevel@tonic-gate 	ksp->ks_flags		= ks_flags | KSTAT_FLAG_INVALID;
10920Sstevel@tonic-gate 	if (ks_flags & KSTAT_FLAG_VIRTUAL)
10930Sstevel@tonic-gate 		ksp->ks_data	= NULL;
10940Sstevel@tonic-gate 	else
10950Sstevel@tonic-gate 		ksp->ks_data	= (void *)(e + 1);
10960Sstevel@tonic-gate 	ksp->ks_ndata		= ks_ndata;
10970Sstevel@tonic-gate 	ksp->ks_data_size	= ks_data_size;
10980Sstevel@tonic-gate 	ksp->ks_snaptime	= ksp->ks_crtime;
10990Sstevel@tonic-gate 	ksp->ks_update		= default_kstat_update;
11000Sstevel@tonic-gate 	ksp->ks_private		= NULL;
11010Sstevel@tonic-gate 	ksp->ks_snapshot	= default_kstat_snapshot;
11020Sstevel@tonic-gate 	ksp->ks_lock		= NULL;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	/*
11070Sstevel@tonic-gate 	 * Add our kstat to the AVL trees.
11080Sstevel@tonic-gate 	 */
11090Sstevel@tonic-gate 	if (avl_find(&kstat_avl_byname, e, &where) != NULL) {
11100Sstevel@tonic-gate 		mutex_exit(&kstat_chain_lock);
11110Sstevel@tonic-gate 		cmn_err(CE_WARN,
11120Sstevel@tonic-gate 		    "kstat_create('%s', %d, '%s'): namespace collision",
11130Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name);
11140Sstevel@tonic-gate 		kstat_free(e);
11150Sstevel@tonic-gate 		return (NULL);
11160Sstevel@tonic-gate 	}
11170Sstevel@tonic-gate 	avl_insert(&kstat_avl_byname, e, where);
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/*
11200Sstevel@tonic-gate 	 * Loop around until we find an unused KID.
11210Sstevel@tonic-gate 	 */
11220Sstevel@tonic-gate 	do {
11230Sstevel@tonic-gate 		ksp->ks_kid = kstat_chain_id++;
11240Sstevel@tonic-gate 	} while (avl_find(&kstat_avl_bykid, e, &where) != NULL);
11250Sstevel@tonic-gate 	avl_insert(&kstat_avl_bykid, e, where);
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	return (ksp);
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate /*
11330Sstevel@tonic-gate  * Activate a fully initialized kstat and make it visible to /dev/kstat.
11340Sstevel@tonic-gate  */
11350Sstevel@tonic-gate void
kstat_install(kstat_t * ksp)11360Sstevel@tonic-gate kstat_install(kstat_t *ksp)
11370Sstevel@tonic-gate {
11380Sstevel@tonic-gate 	zoneid_t zoneid = ((ekstat_t *)ksp)->e_zone.zoneid;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	/*
11410Sstevel@tonic-gate 	 * If this is a variable-size kstat, it MUST provide kstat data locking
11420Sstevel@tonic-gate 	 * to prevent data-size races with kstat readers.
11430Sstevel@tonic-gate 	 */
11440Sstevel@tonic-gate 	if ((ksp->ks_flags & KSTAT_FLAG_VAR_SIZE) && ksp->ks_lock == NULL) {
11450Sstevel@tonic-gate 		panic("kstat_install('%s', %d, '%s'): "
11460Sstevel@tonic-gate 		    "cannot create variable-size kstat without data lock",
11470Sstevel@tonic-gate 		    ksp->ks_module, ksp->ks_instance, ksp->ks_name);
11480Sstevel@tonic-gate 	}
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) {
11510Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_install(%p): does not exist",
11520Sstevel@tonic-gate 		    (void *)ksp);
11530Sstevel@tonic-gate 		return;
11540Sstevel@tonic-gate 	}
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data != NULL) {
11570Sstevel@tonic-gate 		int has_long_strings = 0;
11580Sstevel@tonic-gate 		uint_t i;
11590Sstevel@tonic-gate 		kstat_named_t *knp = KSTAT_NAMED_PTR(ksp);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		for (i = 0; i < ksp->ks_ndata; i++, knp++) {
11620Sstevel@tonic-gate 			if (knp->data_type == KSTAT_DATA_STRING) {
11630Sstevel@tonic-gate 				has_long_strings = 1;
11640Sstevel@tonic-gate 				break;
11650Sstevel@tonic-gate 			}
11660Sstevel@tonic-gate 		}
11670Sstevel@tonic-gate 		/*
11680Sstevel@tonic-gate 		 * It is an error for a named kstat with fields of
11690Sstevel@tonic-gate 		 * KSTAT_DATA_STRING to be non-virtual.
11700Sstevel@tonic-gate 		 */
11710Sstevel@tonic-gate 		if (has_long_strings && !(ksp->ks_flags & KSTAT_FLAG_VIRTUAL)) {
11720Sstevel@tonic-gate 			panic("kstat_install('%s', %d, '%s'): "
11730Sstevel@tonic-gate 			    "named kstat containing KSTAT_DATA_STRING "
11740Sstevel@tonic-gate 			    "is not virtual",
11750Sstevel@tonic-gate 			    ksp->ks_module, ksp->ks_instance,
11760Sstevel@tonic-gate 			    ksp->ks_name);
11770Sstevel@tonic-gate 		}
11780Sstevel@tonic-gate 		/*
11790Sstevel@tonic-gate 		 * The default snapshot routine does not handle KSTAT_WRITE
11800Sstevel@tonic-gate 		 * for long strings.
11810Sstevel@tonic-gate 		 */
11820Sstevel@tonic-gate 		if (has_long_strings && (ksp->ks_flags & KSTAT_FLAG_WRITABLE) &&
11830Sstevel@tonic-gate 		    (ksp->ks_snapshot == default_kstat_snapshot)) {
11840Sstevel@tonic-gate 			panic("kstat_install('%s', %d, '%s'): "
11850Sstevel@tonic-gate 			    "named kstat containing KSTAT_DATA_STRING "
11860Sstevel@tonic-gate 			    "is writable but uses default snapshot routine",
11870Sstevel@tonic-gate 			    ksp->ks_module, ksp->ks_instance, ksp->ks_name);
11880Sstevel@tonic-gate 		}
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	if (ksp->ks_flags & KSTAT_FLAG_DORMANT) {
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 		/*
11940Sstevel@tonic-gate 		 * We are reactivating a dormant kstat.  Initialize the
11950Sstevel@tonic-gate 		 * caller's underlying data to the value it had when the
11960Sstevel@tonic-gate 		 * kstat went dormant, and mark the kstat as active.
11970Sstevel@tonic-gate 		 * Grab the provider's kstat lock if it's not already held.
11980Sstevel@tonic-gate 		 */
11990Sstevel@tonic-gate 		kmutex_t *lp = ksp->ks_lock;
12000Sstevel@tonic-gate 		if (lp != NULL && MUTEX_NOT_HELD(lp)) {
12010Sstevel@tonic-gate 			mutex_enter(lp);
12020Sstevel@tonic-gate 			(void) KSTAT_UPDATE(ksp, KSTAT_WRITE);
12030Sstevel@tonic-gate 			mutex_exit(lp);
12040Sstevel@tonic-gate 		} else {
12050Sstevel@tonic-gate 			(void) KSTAT_UPDATE(ksp, KSTAT_WRITE);
12060Sstevel@tonic-gate 		}
12070Sstevel@tonic-gate 		ksp->ks_flags &= ~KSTAT_FLAG_DORMANT;
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	/*
12110Sstevel@tonic-gate 	 * Now that the kstat is active, make it visible to the kstat driver.
12120Sstevel@tonic-gate 	 */
12130Sstevel@tonic-gate 	ksp->ks_flags &= ~KSTAT_FLAG_INVALID;
12140Sstevel@tonic-gate 	kstat_rele(ksp);
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate /*
12180Sstevel@tonic-gate  * Remove a kstat from the system.  Or, if it's a persistent kstat,
12190Sstevel@tonic-gate  * just update the data and mark it as dormant.
12200Sstevel@tonic-gate  */
12210Sstevel@tonic-gate void
kstat_delete(kstat_t * ksp)12220Sstevel@tonic-gate kstat_delete(kstat_t *ksp)
12230Sstevel@tonic-gate {
12240Sstevel@tonic-gate 	kmutex_t *lp;
12250Sstevel@tonic-gate 	ekstat_t *e = (ekstat_t *)ksp;
122611438SFrank.Batschulat@Sun.COM 	zoneid_t zoneid;
12270Sstevel@tonic-gate 	kstat_zone_t *kz;
12280Sstevel@tonic-gate 
122911438SFrank.Batschulat@Sun.COM 	ASSERT(ksp != NULL);
123011438SFrank.Batschulat@Sun.COM 
12310Sstevel@tonic-gate 	if (ksp == NULL)
12320Sstevel@tonic-gate 		return;
12330Sstevel@tonic-gate 
123411438SFrank.Batschulat@Sun.COM 	zoneid = e->e_zone.zoneid;
123511438SFrank.Batschulat@Sun.COM 
12360Sstevel@tonic-gate 	lp = ksp->ks_lock;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	if (lp != NULL && MUTEX_HELD(lp)) {
12390Sstevel@tonic-gate 		panic("kstat_delete(%p): caller holds data lock %p",
12400Sstevel@tonic-gate 		    (void *)ksp, (void *)lp);
12410Sstevel@tonic-gate 	}
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) {
12440Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_delete(%p): does not exist",
12450Sstevel@tonic-gate 		    (void *)ksp);
12460Sstevel@tonic-gate 		return;
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	if (ksp->ks_flags & KSTAT_FLAG_PERSISTENT) {
12500Sstevel@tonic-gate 		/*
12510Sstevel@tonic-gate 		 * Update the data one last time, so that all activity
12520Sstevel@tonic-gate 		 * prior to going dormant has been accounted for.
12530Sstevel@tonic-gate 		 */
12540Sstevel@tonic-gate 		KSTAT_ENTER(ksp);
12550Sstevel@tonic-gate 		(void) KSTAT_UPDATE(ksp, KSTAT_READ);
12560Sstevel@tonic-gate 		KSTAT_EXIT(ksp);
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 		/*
12590Sstevel@tonic-gate 		 * Mark the kstat as dormant and restore caller-modifiable
12600Sstevel@tonic-gate 		 * fields to default values, so the kstat is readable during
12610Sstevel@tonic-gate 		 * the dormant phase.
12620Sstevel@tonic-gate 		 */
12630Sstevel@tonic-gate 		ksp->ks_flags |= KSTAT_FLAG_DORMANT;
12640Sstevel@tonic-gate 		ksp->ks_lock = NULL;
12650Sstevel@tonic-gate 		ksp->ks_update = default_kstat_update;
12660Sstevel@tonic-gate 		ksp->ks_private = NULL;
12670Sstevel@tonic-gate 		ksp->ks_snapshot = default_kstat_snapshot;
12680Sstevel@tonic-gate 		kstat_rele(ksp);
12690Sstevel@tonic-gate 		return;
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	/*
12730Sstevel@tonic-gate 	 * Remove the kstat from the framework's AVL trees,
12740Sstevel@tonic-gate 	 * free the allocated memory, and increment kstat_chain_id so
12750Sstevel@tonic-gate 	 * /dev/kstat clients can detect the event.
12760Sstevel@tonic-gate 	 */
12770Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
12780Sstevel@tonic-gate 	avl_remove(&kstat_avl_bykid, e);
12790Sstevel@tonic-gate 	avl_remove(&kstat_avl_byname, e);
12800Sstevel@tonic-gate 	kstat_chain_id++;
12810Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	kz = e->e_zone.next;
12840Sstevel@tonic-gate 	while (kz != NULL) {
12850Sstevel@tonic-gate 		kstat_zone_t *t = kz;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 		kz = kz->next;
12880Sstevel@tonic-gate 		kmem_free(t, sizeof (*t));
12890Sstevel@tonic-gate 	}
12900Sstevel@tonic-gate 	kstat_rele(ksp);
12910Sstevel@tonic-gate 	kstat_free(e);
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate void
kstat_delete_byname_zone(const char * ks_module,int ks_instance,const char * ks_name,zoneid_t ks_zoneid)12952951Selowe kstat_delete_byname_zone(const char *ks_module, int ks_instance,
12962951Selowe     const char *ks_name, zoneid_t ks_zoneid)
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate 	kstat_t *ksp;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid);
13010Sstevel@tonic-gate 	if (ksp != NULL) {
13020Sstevel@tonic-gate 		kstat_rele(ksp);
13030Sstevel@tonic-gate 		kstat_delete(ksp);
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate void
kstat_delete_byname(const char * ks_module,int ks_instance,const char * ks_name)13082951Selowe kstat_delete_byname(const char *ks_module, int ks_instance, const char *ks_name)
13090Sstevel@tonic-gate {
13100Sstevel@tonic-gate 	kstat_delete_byname_zone(ks_module, ks_instance, ks_name, ALL_ZONES);
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate /*
13140Sstevel@tonic-gate  * The sparc V9 versions of these routines can be much cheaper than
13150Sstevel@tonic-gate  * the poor 32-bit compiler can comprehend, so they're in sparcv9_subr.s.
13160Sstevel@tonic-gate  * For simplicity, however, we always feed the C versions to lint.
13170Sstevel@tonic-gate  */
13180Sstevel@tonic-gate #if !defined(__sparc) || defined(lint) || defined(__lint)
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate void
kstat_waitq_enter(kstat_io_t * kiop)13210Sstevel@tonic-gate kstat_waitq_enter(kstat_io_t *kiop)
13220Sstevel@tonic-gate {
13230Sstevel@tonic-gate 	hrtime_t new, delta;
13240Sstevel@tonic-gate 	ulong_t wcnt;
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	new = gethrtime_unscaled();
13270Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
13280Sstevel@tonic-gate 	kiop->wlastupdate = new;
13290Sstevel@tonic-gate 	wcnt = kiop->wcnt++;
13300Sstevel@tonic-gate 	if (wcnt != 0) {
13310Sstevel@tonic-gate 		kiop->wlentime += delta * wcnt;
13320Sstevel@tonic-gate 		kiop->wtime += delta;
13330Sstevel@tonic-gate 	}
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate void
kstat_waitq_exit(kstat_io_t * kiop)13370Sstevel@tonic-gate kstat_waitq_exit(kstat_io_t *kiop)
13380Sstevel@tonic-gate {
13390Sstevel@tonic-gate 	hrtime_t new, delta;
13400Sstevel@tonic-gate 	ulong_t wcnt;
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	new = gethrtime_unscaled();
13430Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
13440Sstevel@tonic-gate 	kiop->wlastupdate = new;
13450Sstevel@tonic-gate 	wcnt = kiop->wcnt--;
13460Sstevel@tonic-gate 	ASSERT((int)wcnt > 0);
13470Sstevel@tonic-gate 	kiop->wlentime += delta * wcnt;
13480Sstevel@tonic-gate 	kiop->wtime += delta;
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate void
kstat_runq_enter(kstat_io_t * kiop)13520Sstevel@tonic-gate kstat_runq_enter(kstat_io_t *kiop)
13530Sstevel@tonic-gate {
13540Sstevel@tonic-gate 	hrtime_t new, delta;
13550Sstevel@tonic-gate 	ulong_t rcnt;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	new = gethrtime_unscaled();
13580Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
13590Sstevel@tonic-gate 	kiop->rlastupdate = new;
13600Sstevel@tonic-gate 	rcnt = kiop->rcnt++;
13610Sstevel@tonic-gate 	if (rcnt != 0) {
13620Sstevel@tonic-gate 		kiop->rlentime += delta * rcnt;
13630Sstevel@tonic-gate 		kiop->rtime += delta;
13640Sstevel@tonic-gate 	}
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate void
kstat_runq_exit(kstat_io_t * kiop)13680Sstevel@tonic-gate kstat_runq_exit(kstat_io_t *kiop)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate 	hrtime_t new, delta;
13710Sstevel@tonic-gate 	ulong_t rcnt;
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	new = gethrtime_unscaled();
13740Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
13750Sstevel@tonic-gate 	kiop->rlastupdate = new;
13760Sstevel@tonic-gate 	rcnt = kiop->rcnt--;
13770Sstevel@tonic-gate 	ASSERT((int)rcnt > 0);
13780Sstevel@tonic-gate 	kiop->rlentime += delta * rcnt;
13790Sstevel@tonic-gate 	kiop->rtime += delta;
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate void
kstat_waitq_to_runq(kstat_io_t * kiop)13830Sstevel@tonic-gate kstat_waitq_to_runq(kstat_io_t *kiop)
13840Sstevel@tonic-gate {
13850Sstevel@tonic-gate 	hrtime_t new, delta;
13860Sstevel@tonic-gate 	ulong_t wcnt, rcnt;
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	new = gethrtime_unscaled();
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
13910Sstevel@tonic-gate 	kiop->wlastupdate = new;
13920Sstevel@tonic-gate 	wcnt = kiop->wcnt--;
13930Sstevel@tonic-gate 	ASSERT((int)wcnt > 0);
13940Sstevel@tonic-gate 	kiop->wlentime += delta * wcnt;
13950Sstevel@tonic-gate 	kiop->wtime += delta;
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
13980Sstevel@tonic-gate 	kiop->rlastupdate = new;
13990Sstevel@tonic-gate 	rcnt = kiop->rcnt++;
14000Sstevel@tonic-gate 	if (rcnt != 0) {
14010Sstevel@tonic-gate 		kiop->rlentime += delta * rcnt;
14020Sstevel@tonic-gate 		kiop->rtime += delta;
14030Sstevel@tonic-gate 	}
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate void
kstat_runq_back_to_waitq(kstat_io_t * kiop)14070Sstevel@tonic-gate kstat_runq_back_to_waitq(kstat_io_t *kiop)
14080Sstevel@tonic-gate {
14090Sstevel@tonic-gate 	hrtime_t new, delta;
14100Sstevel@tonic-gate 	ulong_t wcnt, rcnt;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	new = gethrtime_unscaled();
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
14150Sstevel@tonic-gate 	kiop->rlastupdate = new;
14160Sstevel@tonic-gate 	rcnt = kiop->rcnt--;
14170Sstevel@tonic-gate 	ASSERT((int)rcnt > 0);
14180Sstevel@tonic-gate 	kiop->rlentime += delta * rcnt;
14190Sstevel@tonic-gate 	kiop->rtime += delta;
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
14220Sstevel@tonic-gate 	kiop->wlastupdate = new;
14230Sstevel@tonic-gate 	wcnt = kiop->wcnt++;
14240Sstevel@tonic-gate 	if (wcnt != 0) {
14250Sstevel@tonic-gate 		kiop->wlentime += delta * wcnt;
14260Sstevel@tonic-gate 		kiop->wtime += delta;
14270Sstevel@tonic-gate 	}
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate #endif
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate void
kstat_timer_start(kstat_timer_t * ktp)14330Sstevel@tonic-gate kstat_timer_start(kstat_timer_t *ktp)
14340Sstevel@tonic-gate {
14350Sstevel@tonic-gate 	ktp->start_time = gethrtime();
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate void
kstat_timer_stop(kstat_timer_t * ktp)14390Sstevel@tonic-gate kstat_timer_stop(kstat_timer_t *ktp)
14400Sstevel@tonic-gate {
14410Sstevel@tonic-gate 	hrtime_t	etime;
14420Sstevel@tonic-gate 	u_longlong_t	num_events;
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	ktp->stop_time = etime = gethrtime();
14450Sstevel@tonic-gate 	etime -= ktp->start_time;
14460Sstevel@tonic-gate 	num_events = ktp->num_events;
14470Sstevel@tonic-gate 	if (etime < ktp->min_time || num_events == 0)
14480Sstevel@tonic-gate 		ktp->min_time = etime;
14490Sstevel@tonic-gate 	if (etime > ktp->max_time)
14500Sstevel@tonic-gate 		ktp->max_time = etime;
14510Sstevel@tonic-gate 	ktp->elapsed_time += etime;
14520Sstevel@tonic-gate 	ktp->num_events = num_events + 1;
14530Sstevel@tonic-gate }
1454