xref: /illumos-gate/usr/src/uts/common/os/kstat_fr.c (revision 338664df3f3bc1f21029a55383e932d9e58190ef)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a08731ecScth  * Common Development and Distribution License (the "License").
6a08731ecScth  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2244c4f64bSJohn Levon  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23c9bbee95SJerry Jelinek  * Copyright 2014, Joyent, Inc. All rights reserved.
24c0e96d86SHans Rosenfeld  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Kernel statistics framework
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/time.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
357c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/errno.h>
387c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
417c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
437c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
447c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
457c478bd9Sstevel@tonic-gate #include <sys/flock.h>
467c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
477c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
487c478bd9Sstevel@tonic-gate #include <sys/dnlc.h>
497c478bd9Sstevel@tonic-gate #include <sys/var.h>
507c478bd9Sstevel@tonic-gate #include <sys/debug.h>
517c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
527c478bd9Sstevel@tonic-gate #include <sys/avl.h>
537c478bd9Sstevel@tonic-gate #include <sys/pool_pset.h>
547c478bd9Sstevel@tonic-gate #include <sys/cpupart.h>
557c478bd9Sstevel@tonic-gate #include <sys/zone.h>
567c478bd9Sstevel@tonic-gate #include <sys/loadavg.h>
577c478bd9Sstevel@tonic-gate #include <vm/page.h>
587c478bd9Sstevel@tonic-gate #include <vm/anon.h>
597c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * Global lock to protect the AVL trees and kstat_chain_id.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate static kmutex_t kstat_chain_lock;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * Every install/delete kstat bumps kstat_chain_id.  This is used by:
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * (1)	/dev/kstat, to detect changes in the kstat chain across ioctls;
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * (2)	kstat_create(), to assign a KID (kstat ID) to each new kstat.
727c478bd9Sstevel@tonic-gate  *	/dev/kstat uses the KID as a cookie for kstat lookups.
737c478bd9Sstevel@tonic-gate  *
747c478bd9Sstevel@tonic-gate  * We reserve the first two IDs because some kstats are created before
757c478bd9Sstevel@tonic-gate  * the well-known ones (kstat_headers = 0, kstat_types = 1).
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * We also bump the kstat_chain_id if a zone is gaining or losing visibility
787c478bd9Sstevel@tonic-gate  * into a particular kstat, which is logically equivalent to a kstat being
797c478bd9Sstevel@tonic-gate  * installed/deleted.
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate kid_t kstat_chain_id = 2;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * As far as zones are concerned, there are 3 types of kstat:
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  * 1) Those which have a well-known name, and which should return per-zone data
887c478bd9Sstevel@tonic-gate  * depending on which zone is doing the kstat_read().  sockfs:0:sock_unix_list
897c478bd9Sstevel@tonic-gate  * is an example of this type of kstat.
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * 2) Those which should only be exported to a particular list of zones.
927c478bd9Sstevel@tonic-gate  * For example, in the case of nfs:*:mntinfo, we don't want zone A to be
937c478bd9Sstevel@tonic-gate  * able to see NFS mounts associated with zone B, while we want the
947c478bd9Sstevel@tonic-gate  * global zone to be able to see all mounts on the system.
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  * 3) Those that can be exported to all zones.  Most system-related
977c478bd9Sstevel@tonic-gate  * kstats fall within this category.
987c478bd9Sstevel@tonic-gate  *
997c478bd9Sstevel@tonic-gate  * An ekstat_t thus contains a list of kstats that the zone is to be
1007c478bd9Sstevel@tonic-gate  * exported to.  The lookup of a name:instance:module thus translates to a
1017c478bd9Sstevel@tonic-gate  * lookup of name:instance:module:myzone; if the kstat is not exported
1027c478bd9Sstevel@tonic-gate  * to all zones, and does not have the caller's zoneid explicitly
1037c478bd9Sstevel@tonic-gate  * enumerated in the list of zones to be exported to, it is the same as
1047c478bd9Sstevel@tonic-gate  * if the kstat didn't exist.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Writing to kstats is currently disallowed from within a non-global
1077c478bd9Sstevel@tonic-gate  * zone, although this restriction could be removed in the future.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate typedef struct kstat_zone {
1107c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
1117c478bd9Sstevel@tonic-gate 	struct kstat_zone *next;
1127c478bd9Sstevel@tonic-gate } kstat_zone_t;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * Extended kstat structure -- for internal use only.
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate typedef struct ekstat {
1187c478bd9Sstevel@tonic-gate 	kstat_t		e_ks;		/* the kstat itself */
1197c478bd9Sstevel@tonic-gate 	size_t		e_size;		/* total allocation size */
1207c478bd9Sstevel@tonic-gate 	kthread_t	*e_owner;	/* thread holding this kstat */
1217c478bd9Sstevel@tonic-gate 	kcondvar_t	e_cv;		/* wait for owner == NULL */
1227c478bd9Sstevel@tonic-gate 	avl_node_t	e_avl_bykid;	/* AVL tree to sort by KID */
1237c478bd9Sstevel@tonic-gate 	avl_node_t	e_avl_byname;	/* AVL tree to sort by name */
1247c478bd9Sstevel@tonic-gate 	kstat_zone_t	e_zone;		/* zone to export stats to */
1257c478bd9Sstevel@tonic-gate } ekstat_t;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static uint64_t kstat_initial[8192];
1287c478bd9Sstevel@tonic-gate static void *kstat_initial_ptr = kstat_initial;
1297c478bd9Sstevel@tonic-gate static size_t kstat_initial_avail = sizeof (kstat_initial);
1307c478bd9Sstevel@tonic-gate static vmem_t *kstat_arena;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate #define	KSTAT_ALIGN	(sizeof (uint64_t))
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static avl_tree_t kstat_avl_bykid;
1357c478bd9Sstevel@tonic-gate static avl_tree_t kstat_avl_byname;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * Various pointers we need to create kstats at boot time in kstat_init()
1397c478bd9Sstevel@tonic-gate  */
1407c478bd9Sstevel@tonic-gate extern	kstat_named_t	*segmapcnt_ptr;
1417c478bd9Sstevel@tonic-gate extern	uint_t		segmapcnt_ndata;
1427c478bd9Sstevel@tonic-gate extern	int		segmap_kstat_update(kstat_t *, int);
1437c478bd9Sstevel@tonic-gate extern	kstat_named_t	*biostats_ptr;
1447c478bd9Sstevel@tonic-gate extern	uint_t		biostats_ndata;
1457c478bd9Sstevel@tonic-gate extern	kstat_named_t	*pollstats_ptr;
1467c478bd9Sstevel@tonic-gate extern	uint_t		pollstats_ndata;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate extern	int	vac;
1497c478bd9Sstevel@tonic-gate extern	uint_t	nproc;
1507c478bd9Sstevel@tonic-gate extern	time_t	boot_time;
1517c478bd9Sstevel@tonic-gate extern	sysinfo_t	sysinfo;
1527c478bd9Sstevel@tonic-gate extern	vminfo_t	vminfo;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate struct {
1557c478bd9Sstevel@tonic-gate 	kstat_named_t ncpus;
1567c478bd9Sstevel@tonic-gate 	kstat_named_t lbolt;
1577c478bd9Sstevel@tonic-gate 	kstat_named_t deficit;
1587c478bd9Sstevel@tonic-gate 	kstat_named_t clk_intr;
1597c478bd9Sstevel@tonic-gate 	kstat_named_t vac;
1607c478bd9Sstevel@tonic-gate 	kstat_named_t nproc;
1617c478bd9Sstevel@tonic-gate 	kstat_named_t avenrun_1min;
1627c478bd9Sstevel@tonic-gate 	kstat_named_t avenrun_5min;
1637c478bd9Sstevel@tonic-gate 	kstat_named_t avenrun_15min;
1647c478bd9Sstevel@tonic-gate 	kstat_named_t boot_time;
165482a7749SJerry Jelinek 	kstat_named_t nsec_per_tick;
1667c478bd9Sstevel@tonic-gate } system_misc_kstat = {
1677c478bd9Sstevel@tonic-gate 	{ "ncpus",		KSTAT_DATA_UINT32 },
1687c478bd9Sstevel@tonic-gate 	{ "lbolt",		KSTAT_DATA_UINT32 },
1697c478bd9Sstevel@tonic-gate 	{ "deficit",		KSTAT_DATA_UINT32 },
1707c478bd9Sstevel@tonic-gate 	{ "clk_intr",		KSTAT_DATA_UINT32 },
1717c478bd9Sstevel@tonic-gate 	{ "vac",		KSTAT_DATA_UINT32 },
1727c478bd9Sstevel@tonic-gate 	{ "nproc",		KSTAT_DATA_UINT32 },
1737c478bd9Sstevel@tonic-gate 	{ "avenrun_1min",	KSTAT_DATA_UINT32 },
1747c478bd9Sstevel@tonic-gate 	{ "avenrun_5min",	KSTAT_DATA_UINT32 },
1757c478bd9Sstevel@tonic-gate 	{ "avenrun_15min",	KSTAT_DATA_UINT32 },
1767c478bd9Sstevel@tonic-gate 	{ "boot_time",		KSTAT_DATA_UINT32 },
177482a7749SJerry Jelinek 	{ "nsec_per_tick",	KSTAT_DATA_UINT32 },
1787c478bd9Sstevel@tonic-gate };
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate struct {
1817c478bd9Sstevel@tonic-gate 	kstat_named_t physmem;
1827c478bd9Sstevel@tonic-gate 	kstat_named_t nalloc;
1837c478bd9Sstevel@tonic-gate 	kstat_named_t nfree;
1847c478bd9Sstevel@tonic-gate 	kstat_named_t nalloc_calls;
1857c478bd9Sstevel@tonic-gate 	kstat_named_t nfree_calls;
1867c478bd9Sstevel@tonic-gate 	kstat_named_t kernelbase;
1877c478bd9Sstevel@tonic-gate 	kstat_named_t econtig;
1887c478bd9Sstevel@tonic-gate 	kstat_named_t freemem;
1897c478bd9Sstevel@tonic-gate 	kstat_named_t availrmem;
1907c478bd9Sstevel@tonic-gate 	kstat_named_t lotsfree;
1917c478bd9Sstevel@tonic-gate 	kstat_named_t desfree;
1927c478bd9Sstevel@tonic-gate 	kstat_named_t minfree;
1937c478bd9Sstevel@tonic-gate 	kstat_named_t fastscan;
1947c478bd9Sstevel@tonic-gate 	kstat_named_t slowscan;
1957c478bd9Sstevel@tonic-gate 	kstat_named_t nscan;
1967c478bd9Sstevel@tonic-gate 	kstat_named_t desscan;
1977c478bd9Sstevel@tonic-gate 	kstat_named_t pp_kernel;
1987c478bd9Sstevel@tonic-gate 	kstat_named_t pagesfree;
1997c478bd9Sstevel@tonic-gate 	kstat_named_t pageslocked;
2007c478bd9Sstevel@tonic-gate 	kstat_named_t pagestotal;
201*338664dfSAndy Fiddaman 	kstat_named_t lowmemscan;
202*338664dfSAndy Fiddaman 	kstat_named_t nthrottle;
2037c478bd9Sstevel@tonic-gate } system_pages_kstat = {
2047c478bd9Sstevel@tonic-gate 	{ "physmem",		KSTAT_DATA_ULONG },
2057c478bd9Sstevel@tonic-gate 	{ "nalloc",		KSTAT_DATA_ULONG },
2067c478bd9Sstevel@tonic-gate 	{ "nfree",		KSTAT_DATA_ULONG },
2077c478bd9Sstevel@tonic-gate 	{ "nalloc_calls",	KSTAT_DATA_ULONG },
2087c478bd9Sstevel@tonic-gate 	{ "nfree_calls",	KSTAT_DATA_ULONG },
2097c478bd9Sstevel@tonic-gate 	{ "kernelbase",		KSTAT_DATA_ULONG },
2107c478bd9Sstevel@tonic-gate 	{ "econtig",		KSTAT_DATA_ULONG },
2117c478bd9Sstevel@tonic-gate 	{ "freemem",		KSTAT_DATA_ULONG },
2127c478bd9Sstevel@tonic-gate 	{ "availrmem",		KSTAT_DATA_ULONG },
2137c478bd9Sstevel@tonic-gate 	{ "lotsfree",		KSTAT_DATA_ULONG },
2147c478bd9Sstevel@tonic-gate 	{ "desfree",		KSTAT_DATA_ULONG },
2157c478bd9Sstevel@tonic-gate 	{ "minfree",		KSTAT_DATA_ULONG },
2167c478bd9Sstevel@tonic-gate 	{ "fastscan",		KSTAT_DATA_ULONG },
2177c478bd9Sstevel@tonic-gate 	{ "slowscan",		KSTAT_DATA_ULONG },
2187c478bd9Sstevel@tonic-gate 	{ "nscan",		KSTAT_DATA_ULONG },
2197c478bd9Sstevel@tonic-gate 	{ "desscan",		KSTAT_DATA_ULONG },
2207c478bd9Sstevel@tonic-gate 	{ "pp_kernel",		KSTAT_DATA_ULONG },
2217c478bd9Sstevel@tonic-gate 	{ "pagesfree",		KSTAT_DATA_ULONG },
2227c478bd9Sstevel@tonic-gate 	{ "pageslocked",	KSTAT_DATA_ULONG },
2237c478bd9Sstevel@tonic-gate 	{ "pagestotal",		KSTAT_DATA_ULONG },
224*338664dfSAndy Fiddaman 	{ "low_mem_scan",	KSTAT_DATA_ULONG },
225*338664dfSAndy Fiddaman 	{ "n_throttle",		KSTAT_DATA_ULONG },
2267c478bd9Sstevel@tonic-gate };
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate static int header_kstat_update(kstat_t *, int);
2297c478bd9Sstevel@tonic-gate static int header_kstat_snapshot(kstat_t *, void *, int);
2307c478bd9Sstevel@tonic-gate static int system_misc_kstat_update(kstat_t *, int);
2317c478bd9Sstevel@tonic-gate static int system_pages_kstat_update(kstat_t *, int);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static struct {
2347c478bd9Sstevel@tonic-gate 	char	name[KSTAT_STRLEN];
2357c478bd9Sstevel@tonic-gate 	size_t	size;
2367c478bd9Sstevel@tonic-gate 	uint_t	min_ndata;
2377c478bd9Sstevel@tonic-gate 	uint_t	max_ndata;
2387c478bd9Sstevel@tonic-gate } kstat_data_type[KSTAT_NUM_TYPES] = {
2397c478bd9Sstevel@tonic-gate 	{ "raw",		1,			0,	INT_MAX	},
2407c478bd9Sstevel@tonic-gate 	{ "name=value",		sizeof (kstat_named_t),	0,	INT_MAX	},
2417c478bd9Sstevel@tonic-gate 	{ "interrupt",		sizeof (kstat_intr_t),	1,	1	},
2427c478bd9Sstevel@tonic-gate 	{ "i/o",		sizeof (kstat_io_t),	1,	1	},
2437c478bd9Sstevel@tonic-gate 	{ "event_timer",	sizeof (kstat_timer_t),	0,	INT_MAX	},
2447c478bd9Sstevel@tonic-gate };
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate int
kstat_zone_find(kstat_t * k,zoneid_t zoneid)2477c478bd9Sstevel@tonic-gate kstat_zone_find(kstat_t *k, zoneid_t zoneid)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	ekstat_t *e = (ekstat_t *)k;
2507c478bd9Sstevel@tonic-gate 	kstat_zone_t *kz;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&kstat_chain_lock));
2537c478bd9Sstevel@tonic-gate 	for (kz = &e->e_zone; kz != NULL; kz = kz->next) {
2547c478bd9Sstevel@tonic-gate 		if (zoneid == ALL_ZONES || kz->zoneid == ALL_ZONES)
2557c478bd9Sstevel@tonic-gate 			return (1);
2567c478bd9Sstevel@tonic-gate 		if (zoneid == kz->zoneid)
2577c478bd9Sstevel@tonic-gate 			return (1);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	return (0);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate void
kstat_zone_remove(kstat_t * k,zoneid_t zoneid)2637c478bd9Sstevel@tonic-gate kstat_zone_remove(kstat_t *k, zoneid_t zoneid)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate 	ekstat_t *e = (ekstat_t *)k;
2667c478bd9Sstevel@tonic-gate 	kstat_zone_t *kz, *t = NULL;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
2697c478bd9Sstevel@tonic-gate 	if (zoneid == e->e_zone.zoneid) {
2707c478bd9Sstevel@tonic-gate 		kz = e->e_zone.next;
2717c478bd9Sstevel@tonic-gate 		ASSERT(kz != NULL);
2727c478bd9Sstevel@tonic-gate 		e->e_zone.zoneid = kz->zoneid;
2737c478bd9Sstevel@tonic-gate 		e->e_zone.next = kz->next;
2747c478bd9Sstevel@tonic-gate 		goto out;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 	for (kz = &e->e_zone; kz->next != NULL; kz = kz->next) {
2777c478bd9Sstevel@tonic-gate 		if (kz->next->zoneid == zoneid) {
2787c478bd9Sstevel@tonic-gate 			t = kz->next;
2797c478bd9Sstevel@tonic-gate 			kz->next = t->next;
2807c478bd9Sstevel@tonic-gate 			break;
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);	/* we removed something */
2847c478bd9Sstevel@tonic-gate 	kz = t;
2857c478bd9Sstevel@tonic-gate out:
2867c478bd9Sstevel@tonic-gate 	kstat_chain_id++;
2877c478bd9Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
2887c478bd9Sstevel@tonic-gate 	kmem_free(kz, sizeof (*kz));
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate void
kstat_zone_add(kstat_t * k,zoneid_t zoneid)2927c478bd9Sstevel@tonic-gate kstat_zone_add(kstat_t *k, zoneid_t zoneid)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	ekstat_t *e = (ekstat_t *)k;
2957c478bd9Sstevel@tonic-gate 	kstat_zone_t *kz;
2967c478bd9Sstevel@tonic-gate 
297c97ad5cdSakolb 	kz = kmem_alloc(sizeof (*kz), KM_NOSLEEP);
298c97ad5cdSakolb 	if (kz == NULL)
299c97ad5cdSakolb 		return;
3007c478bd9Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
3017c478bd9Sstevel@tonic-gate 	kz->zoneid = zoneid;
3027c478bd9Sstevel@tonic-gate 	kz->next = e->e_zone.next;
3037c478bd9Sstevel@tonic-gate 	e->e_zone.next = kz;
3047c478bd9Sstevel@tonic-gate 	kstat_chain_id++;
3057c478bd9Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate  * Compare the list of zones for the given kstats, returning 0 if they match
3107c478bd9Sstevel@tonic-gate  * (ie, one list contains ALL_ZONES or both lists contain the same zoneid).
3117c478bd9Sstevel@tonic-gate  * In practice, this is called indirectly by kstat_hold_byname(), so one of the
3127c478bd9Sstevel@tonic-gate  * two lists always has one element, and this is an O(n) operation rather than
3137c478bd9Sstevel@tonic-gate  * O(n^2).
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate static int
kstat_zone_compare(ekstat_t * e1,ekstat_t * e2)3167c478bd9Sstevel@tonic-gate kstat_zone_compare(ekstat_t *e1, ekstat_t *e2)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	kstat_zone_t *kz1, *kz2;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&kstat_chain_lock));
3217c478bd9Sstevel@tonic-gate 	for (kz1 = &e1->e_zone; kz1 != NULL; kz1 = kz1->next) {
3227c478bd9Sstevel@tonic-gate 		for (kz2 = &e2->e_zone; kz2 != NULL; kz2 = kz2->next) {
3237c478bd9Sstevel@tonic-gate 			if (kz1->zoneid == ALL_ZONES ||
3247c478bd9Sstevel@tonic-gate 			    kz2->zoneid == ALL_ZONES)
3257c478bd9Sstevel@tonic-gate 				return (0);
3267c478bd9Sstevel@tonic-gate 			if (kz1->zoneid == kz2->zoneid)
3277c478bd9Sstevel@tonic-gate 				return (0);
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 	return (e1->e_zone.zoneid < e2->e_zone.zoneid ? -1 : 1);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate /*
3347c478bd9Sstevel@tonic-gate  * Support for keeping kstats sorted in AVL trees for fast lookups.
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate static int
kstat_compare_bykid(const void * a1,const void * a2)3377c478bd9Sstevel@tonic-gate kstat_compare_bykid(const void *a1, const void *a2)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	const kstat_t *k1 = a1;
3407c478bd9Sstevel@tonic-gate 	const kstat_t *k2 = a2;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if (k1->ks_kid < k2->ks_kid)
3437c478bd9Sstevel@tonic-gate 		return (-1);
3447c478bd9Sstevel@tonic-gate 	if (k1->ks_kid > k2->ks_kid)
3457c478bd9Sstevel@tonic-gate 		return (1);
3467c478bd9Sstevel@tonic-gate 	return (kstat_zone_compare((ekstat_t *)k1, (ekstat_t *)k2));
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate static int
kstat_compare_byname(const void * a1,const void * a2)3507c478bd9Sstevel@tonic-gate kstat_compare_byname(const void *a1, const void *a2)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	const kstat_t *k1 = a1;
3537c478bd9Sstevel@tonic-gate 	const kstat_t *k2 = a2;
3547c478bd9Sstevel@tonic-gate 	int s;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	s = strcmp(k1->ks_module, k2->ks_module);
3577c478bd9Sstevel@tonic-gate 	if (s > 0)
3587c478bd9Sstevel@tonic-gate 		return (1);
3597c478bd9Sstevel@tonic-gate 	if (s < 0)
3607c478bd9Sstevel@tonic-gate 		return (-1);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (k1->ks_instance < k2->ks_instance)
3637c478bd9Sstevel@tonic-gate 		return (-1);
3647c478bd9Sstevel@tonic-gate 	if (k1->ks_instance > k2->ks_instance)
3657c478bd9Sstevel@tonic-gate 		return (1);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	s = strcmp(k1->ks_name, k2->ks_name);
3687c478bd9Sstevel@tonic-gate 	if (s > 0)
3697c478bd9Sstevel@tonic-gate 		return (1);
3707c478bd9Sstevel@tonic-gate 	if (s < 0)
3717c478bd9Sstevel@tonic-gate 		return (-1);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	return (kstat_zone_compare((ekstat_t *)k1, (ekstat_t *)k2));
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate static kstat_t *
kstat_hold(avl_tree_t * t,ekstat_t * template)3777c478bd9Sstevel@tonic-gate kstat_hold(avl_tree_t *t, ekstat_t *template)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
3807c478bd9Sstevel@tonic-gate 	ekstat_t *e;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
3837c478bd9Sstevel@tonic-gate 	for (;;) {
3847c478bd9Sstevel@tonic-gate 		ksp = avl_find(t, template, NULL);
3857c478bd9Sstevel@tonic-gate 		if (ksp == NULL)
3867c478bd9Sstevel@tonic-gate 			break;
3877c478bd9Sstevel@tonic-gate 		e = (ekstat_t *)ksp;
3887c478bd9Sstevel@tonic-gate 		if (e->e_owner == NULL) {
3897c478bd9Sstevel@tonic-gate 			e->e_owner = curthread;
3907c478bd9Sstevel@tonic-gate 			break;
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 		cv_wait(&e->e_cv, &kstat_chain_lock);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
3957c478bd9Sstevel@tonic-gate 	return (ksp);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate void
kstat_rele(kstat_t * ksp)3997c478bd9Sstevel@tonic-gate kstat_rele(kstat_t *ksp)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	ekstat_t *e = (ekstat_t *)ksp;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
4047c478bd9Sstevel@tonic-gate 	ASSERT(e->e_owner == curthread);
4057c478bd9Sstevel@tonic-gate 	e->e_owner = NULL;
4067c478bd9Sstevel@tonic-gate 	cv_broadcast(&e->e_cv);
4077c478bd9Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate kstat_t *
kstat_hold_bykid(kid_t kid,zoneid_t zoneid)4117c478bd9Sstevel@tonic-gate kstat_hold_bykid(kid_t kid, zoneid_t zoneid)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	ekstat_t e;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	e.e_ks.ks_kid = kid;
4167c478bd9Sstevel@tonic-gate 	e.e_zone.zoneid = zoneid;
4177c478bd9Sstevel@tonic-gate 	e.e_zone.next = NULL;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	return (kstat_hold(&kstat_avl_bykid, &e));
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate kstat_t *
kstat_hold_byname(const char * ks_module,int ks_instance,const char * ks_name,zoneid_t ks_zoneid)423d624471bSelowe kstat_hold_byname(const char *ks_module, int ks_instance, const char *ks_name,
4247c478bd9Sstevel@tonic-gate     zoneid_t ks_zoneid)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	ekstat_t e;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	kstat_set_string(e.e_ks.ks_module, ks_module);
4297c478bd9Sstevel@tonic-gate 	e.e_ks.ks_instance = ks_instance;
4307c478bd9Sstevel@tonic-gate 	kstat_set_string(e.e_ks.ks_name, ks_name);
4317c478bd9Sstevel@tonic-gate 	e.e_zone.zoneid = ks_zoneid;
4327c478bd9Sstevel@tonic-gate 	e.e_zone.next = NULL;
4337c478bd9Sstevel@tonic-gate 	return (kstat_hold(&kstat_avl_byname, &e));
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate static ekstat_t *
kstat_alloc(size_t size)4377c478bd9Sstevel@tonic-gate kstat_alloc(size_t size)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	ekstat_t *e = NULL;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	size = P2ROUNDUP(sizeof (ekstat_t) + size, KSTAT_ALIGN);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	if (kstat_arena == NULL) {
4447c478bd9Sstevel@tonic-gate 		if (size <= kstat_initial_avail) {
4457c478bd9Sstevel@tonic-gate 			e = kstat_initial_ptr;
4467c478bd9Sstevel@tonic-gate 			kstat_initial_ptr = (char *)kstat_initial_ptr + size;
4477c478bd9Sstevel@tonic-gate 			kstat_initial_avail -= size;
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	} else {
4507c478bd9Sstevel@tonic-gate 		e = vmem_alloc(kstat_arena, size, VM_NOSLEEP);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if (e != NULL) {
4547c478bd9Sstevel@tonic-gate 		bzero(e, size);
4557c478bd9Sstevel@tonic-gate 		e->e_size = size;
4567c478bd9Sstevel@tonic-gate 		cv_init(&e->e_cv, NULL, CV_DEFAULT, NULL);
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	return (e);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static void
kstat_free(ekstat_t * e)4637c478bd9Sstevel@tonic-gate kstat_free(ekstat_t *e)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	cv_destroy(&e->e_cv);
4667c478bd9Sstevel@tonic-gate 	vmem_free(kstat_arena, e, e->e_size);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * Create various system kstats.
4717c478bd9Sstevel@tonic-gate  */
4727c478bd9Sstevel@tonic-gate void
kstat_init(void)4737c478bd9Sstevel@tonic-gate kstat_init(void)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
4767c478bd9Sstevel@tonic-gate 	ekstat_t *e;
4777c478bd9Sstevel@tonic-gate 	avl_tree_t *t = &kstat_avl_bykid;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/*
4807c478bd9Sstevel@tonic-gate 	 * Set up the kstat vmem arena.
4817c478bd9Sstevel@tonic-gate 	 */
4827c478bd9Sstevel@tonic-gate 	kstat_arena = vmem_create("kstat",
4837c478bd9Sstevel@tonic-gate 	    kstat_initial, sizeof (kstat_initial), KSTAT_ALIGN,
4847c478bd9Sstevel@tonic-gate 	    segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * Make initial kstats appear as though they were allocated.
4887c478bd9Sstevel@tonic-gate 	 */
4897c478bd9Sstevel@tonic-gate 	for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER))
4907c478bd9Sstevel@tonic-gate 		(void) vmem_xalloc(kstat_arena, e->e_size, KSTAT_ALIGN,
4917c478bd9Sstevel@tonic-gate 		    0, 0, e, (char *)e + e->e_size,
4927c478bd9Sstevel@tonic-gate 		    VM_NOSLEEP | VM_BESTFIT | VM_PANIC);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	/*
4957c478bd9Sstevel@tonic-gate 	 * The mother of all kstats.  The first kstat in the system, which
4967c478bd9Sstevel@tonic-gate 	 * always has KID 0, has the headers for all kstats (including itself)
4977c478bd9Sstevel@tonic-gate 	 * as its data.  Thus, the kstat driver does not need any special
4987c478bd9Sstevel@tonic-gate 	 * interface to extract the kstat chain.
4997c478bd9Sstevel@tonic-gate 	 */
5007c478bd9Sstevel@tonic-gate 	kstat_chain_id = 0;
5017c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "kstat_headers", "kstat", KSTAT_TYPE_RAW,
5027c478bd9Sstevel@tonic-gate 	    0, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
5037c478bd9Sstevel@tonic-gate 	if (ksp) {
5047c478bd9Sstevel@tonic-gate 		ksp->ks_lock = &kstat_chain_lock;
5057c478bd9Sstevel@tonic-gate 		ksp->ks_update = header_kstat_update;
5067c478bd9Sstevel@tonic-gate 		ksp->ks_snapshot = header_kstat_snapshot;
5077c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5087c478bd9Sstevel@tonic-gate 	} else {
5097c478bd9Sstevel@tonic-gate 		panic("cannot create kstat 'kstat_headers'");
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "kstat_types", "kstat",
5137c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, KSTAT_NUM_TYPES, 0);
5147c478bd9Sstevel@tonic-gate 	if (ksp) {
5157c478bd9Sstevel@tonic-gate 		int i;
5167c478bd9Sstevel@tonic-gate 		kstat_named_t *kn = KSTAT_NAMED_PTR(ksp);
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		for (i = 0; i < KSTAT_NUM_TYPES; i++) {
5197c478bd9Sstevel@tonic-gate 			kstat_named_init(&kn[i], kstat_data_type[i].name,
5207c478bd9Sstevel@tonic-gate 			    KSTAT_DATA_ULONG);
5217c478bd9Sstevel@tonic-gate 			kn[i].value.ul = i;
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "sysinfo", "misc", KSTAT_TYPE_RAW,
5277c478bd9Sstevel@tonic-gate 	    sizeof (sysinfo_t), KSTAT_FLAG_VIRTUAL);
5287c478bd9Sstevel@tonic-gate 	if (ksp) {
5297c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) &sysinfo;
5307c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "vminfo", "vm", KSTAT_TYPE_RAW,
5347c478bd9Sstevel@tonic-gate 	    sizeof (vminfo_t), KSTAT_FLAG_VIRTUAL);
5357c478bd9Sstevel@tonic-gate 	if (ksp) {
5367c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) &vminfo;
5377c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "segmap", "vm", KSTAT_TYPE_NAMED,
5417c478bd9Sstevel@tonic-gate 	    segmapcnt_ndata, KSTAT_FLAG_VIRTUAL);
5427c478bd9Sstevel@tonic-gate 	if (ksp) {
5437c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) segmapcnt_ptr;
5447c478bd9Sstevel@tonic-gate 		ksp->ks_update = segmap_kstat_update;
5457c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "biostats", "misc", KSTAT_TYPE_NAMED,
5497c478bd9Sstevel@tonic-gate 	    biostats_ndata, KSTAT_FLAG_VIRTUAL);
5507c478bd9Sstevel@tonic-gate 	if (ksp) {
5517c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) biostats_ptr;
5527c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "var", "misc", KSTAT_TYPE_RAW,
5567c478bd9Sstevel@tonic-gate 	    sizeof (struct var), KSTAT_FLAG_VIRTUAL);
5577c478bd9Sstevel@tonic-gate 	if (ksp) {
5587c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) &v;
5597c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "system_misc", "misc", KSTAT_TYPE_NAMED,
5637c478bd9Sstevel@tonic-gate 	    sizeof (system_misc_kstat) / sizeof (kstat_named_t),
5647c478bd9Sstevel@tonic-gate 	    KSTAT_FLAG_VIRTUAL);
5657c478bd9Sstevel@tonic-gate 	if (ksp) {
5667c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) &system_misc_kstat;
5677c478bd9Sstevel@tonic-gate 		ksp->ks_update = system_misc_kstat_update;
5687c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	ksp = kstat_create("unix", 0, "system_pages", "pages", KSTAT_TYPE_NAMED,
5727c478bd9Sstevel@tonic-gate 	    sizeof (system_pages_kstat) / sizeof (kstat_named_t),
5737c478bd9Sstevel@tonic-gate 	    KSTAT_FLAG_VIRTUAL);
5747c478bd9Sstevel@tonic-gate 	if (ksp) {
5757c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) &system_pages_kstat;
5767c478bd9Sstevel@tonic-gate 		ksp->ks_update = system_pages_kstat_update;
5777c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	ksp = kstat_create("poll", 0, "pollstats", "misc", KSTAT_TYPE_NAMED,
5817c478bd9Sstevel@tonic-gate 	    pollstats_ndata, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if (ksp) {
5847c478bd9Sstevel@tonic-gate 		ksp->ks_data = pollstats_ptr;
5857c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * Caller of this should ensure that the string pointed by src
5917c478bd9Sstevel@tonic-gate  * doesn't change while kstat's lock is held. Not doing so defeats
5927c478bd9Sstevel@tonic-gate  * kstat's snapshot strategy as explained in <sys/kstat.h>
5937c478bd9Sstevel@tonic-gate  */
5947c478bd9Sstevel@tonic-gate void
kstat_named_setstr(kstat_named_t * knp,const char * src)5957c478bd9Sstevel@tonic-gate kstat_named_setstr(kstat_named_t *knp, const char *src)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	if (knp->data_type != KSTAT_DATA_STRING)
5987c478bd9Sstevel@tonic-gate 		panic("kstat_named_setstr('%p', '%p'): "
599903a11ebSrh87107 		    "named kstat is not of type KSTAT_DATA_STRING",
600903a11ebSrh87107 		    (void *)knp, (void *)src);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	KSTAT_NAMED_STR_PTR(knp) = (char *)src;
6037c478bd9Sstevel@tonic-gate 	if (src != NULL)
6047c478bd9Sstevel@tonic-gate 		KSTAT_NAMED_STR_BUFLEN(knp) = strlen(src) + 1;
6057c478bd9Sstevel@tonic-gate 	else
6067c478bd9Sstevel@tonic-gate 		KSTAT_NAMED_STR_BUFLEN(knp) = 0;
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate void
kstat_set_string(char * dst,const char * src)610d624471bSelowe kstat_set_string(char *dst, const char *src)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate 	bzero(dst, KSTAT_STRLEN);
6137c478bd9Sstevel@tonic-gate 	(void) strncpy(dst, src, KSTAT_STRLEN - 1);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate void
kstat_named_init(kstat_named_t * knp,const char * name,uchar_t data_type)617d624471bSelowe kstat_named_init(kstat_named_t *knp, const char *name, uchar_t data_type)
6187c478bd9Sstevel@tonic-gate {
6197c478bd9Sstevel@tonic-gate 	kstat_set_string(knp->name, name);
6207c478bd9Sstevel@tonic-gate 	knp->data_type = data_type;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (data_type == KSTAT_DATA_STRING)
6237c478bd9Sstevel@tonic-gate 		kstat_named_setstr(knp, NULL);
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate void
kstat_timer_init(kstat_timer_t * ktp,const char * name)627d624471bSelowe kstat_timer_init(kstat_timer_t *ktp, const char *name)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate 	kstat_set_string(ktp->name, name);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate /* ARGSUSED */
6337c478bd9Sstevel@tonic-gate static int
default_kstat_update(kstat_t * ksp,int rw)6347c478bd9Sstevel@tonic-gate default_kstat_update(kstat_t *ksp, int rw)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	uint_t i;
6377c478bd9Sstevel@tonic-gate 	size_t len = 0;
6387c478bd9Sstevel@tonic-gate 	kstat_named_t *knp;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	/*
6417c478bd9Sstevel@tonic-gate 	 * Named kstats with variable-length long strings have a standard
6427c478bd9Sstevel@tonic-gate 	 * way of determining how much space is needed to hold the snapshot:
6437c478bd9Sstevel@tonic-gate 	 */
6447c478bd9Sstevel@tonic-gate 	if (ksp->ks_data != NULL && ksp->ks_type == KSTAT_TYPE_NAMED &&
645c0e96d86SHans Rosenfeld 	    (ksp->ks_flags & (KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_LONGSTRINGS))) {
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		/*
6487c478bd9Sstevel@tonic-gate 		 * Add in the space required for the strings
6497c478bd9Sstevel@tonic-gate 		 */
6507c478bd9Sstevel@tonic-gate 		knp = KSTAT_NAMED_PTR(ksp);
6517c478bd9Sstevel@tonic-gate 		for (i = 0; i < ksp->ks_ndata; i++, knp++) {
6527c478bd9Sstevel@tonic-gate 			if (knp->data_type == KSTAT_DATA_STRING)
6537c478bd9Sstevel@tonic-gate 				len += KSTAT_NAMED_STR_BUFLEN(knp);
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 		ksp->ks_data_size =
6567c478bd9Sstevel@tonic-gate 		    ksp->ks_ndata * sizeof (kstat_named_t) + len;
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 	return (0);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate static int
default_kstat_snapshot(kstat_t * ksp,void * buf,int rw)6627c478bd9Sstevel@tonic-gate default_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate 	kstat_io_t *kiop;
6657c478bd9Sstevel@tonic-gate 	hrtime_t cur_time;
6667c478bd9Sstevel@tonic-gate 	size_t	namedsz;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	ksp->ks_snaptime = cur_time = gethrtime();
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
6717c478bd9Sstevel@tonic-gate 		if (!(ksp->ks_flags & KSTAT_FLAG_WRITABLE))
6727c478bd9Sstevel@tonic-gate 			return (EACCES);
6737c478bd9Sstevel@tonic-gate 		bcopy(buf, ksp->ks_data, ksp->ks_data_size);
6747c478bd9Sstevel@tonic-gate 		return (0);
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	/*
6787c478bd9Sstevel@tonic-gate 	 * KSTAT_TYPE_NAMED kstats are defined to have ks_ndata
6797c478bd9Sstevel@tonic-gate 	 * number of kstat_named_t structures, followed by an optional
6807c478bd9Sstevel@tonic-gate 	 * string segment. The ks_data generally holds only the
6817c478bd9Sstevel@tonic-gate 	 * kstat_named_t structures. So we copy it first. The strings,
6827c478bd9Sstevel@tonic-gate 	 * if any, are copied below. For other kstat types, ks_data holds the
6837c478bd9Sstevel@tonic-gate 	 * entire buffer.
6847c478bd9Sstevel@tonic-gate 	 */
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	namedsz = sizeof (kstat_named_t) * ksp->ks_ndata;
6877c478bd9Sstevel@tonic-gate 	if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data_size > namedsz)
6887c478bd9Sstevel@tonic-gate 		bcopy(ksp->ks_data, buf, namedsz);
6897c478bd9Sstevel@tonic-gate 	else
6907c478bd9Sstevel@tonic-gate 		bcopy(ksp->ks_data, buf, ksp->ks_data_size);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	/*
6937c478bd9Sstevel@tonic-gate 	 * Apply kstat type-specific data massaging
6947c478bd9Sstevel@tonic-gate 	 */
6957c478bd9Sstevel@tonic-gate 	switch (ksp->ks_type) {
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	case KSTAT_TYPE_IO:
6987c478bd9Sstevel@tonic-gate 		/*
6997c478bd9Sstevel@tonic-gate 		 * Normalize time units and deal with incomplete transactions
7007c478bd9Sstevel@tonic-gate 		 */
7017c478bd9Sstevel@tonic-gate 		kiop = (kstat_io_t *)buf;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		scalehrtime(&kiop->wtime);
7047c478bd9Sstevel@tonic-gate 		scalehrtime(&kiop->wlentime);
7057c478bd9Sstevel@tonic-gate 		scalehrtime(&kiop->wlastupdate);
7067c478bd9Sstevel@tonic-gate 		scalehrtime(&kiop->rtime);
7077c478bd9Sstevel@tonic-gate 		scalehrtime(&kiop->rlentime);
7087c478bd9Sstevel@tonic-gate 		scalehrtime(&kiop->rlastupdate);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 		if (kiop->wcnt != 0) {
711a08731ecScth 			/* like kstat_waitq_exit */
7127c478bd9Sstevel@tonic-gate 			hrtime_t wfix = cur_time - kiop->wlastupdate;
7137c478bd9Sstevel@tonic-gate 			kiop->wlastupdate = cur_time;
714a08731ecScth 			kiop->wlentime += kiop->wcnt * wfix;
715a08731ecScth 			kiop->wtime += wfix;
7167c478bd9Sstevel@tonic-gate 		}
717a08731ecScth 
718a08731ecScth 		if (kiop->rcnt != 0) {
719a08731ecScth 			/* like kstat_runq_exit */
720a08731ecScth 			hrtime_t rfix = cur_time - kiop->rlastupdate;
7217c478bd9Sstevel@tonic-gate 			kiop->rlastupdate = cur_time;
722a08731ecScth 			kiop->rlentime += kiop->rcnt * rfix;
723a08731ecScth 			kiop->rtime += rfix;
724a08731ecScth 		}
7257c478bd9Sstevel@tonic-gate 		break;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	case KSTAT_TYPE_NAMED:
7287c478bd9Sstevel@tonic-gate 		/*
7297c478bd9Sstevel@tonic-gate 		 * Massage any long strings in at the end of the buffer
7307c478bd9Sstevel@tonic-gate 		 */
7317c478bd9Sstevel@tonic-gate 		if (ksp->ks_data_size > namedsz) {
7327c478bd9Sstevel@tonic-gate 			uint_t i;
7337c478bd9Sstevel@tonic-gate 			kstat_named_t *knp = buf;
7347c478bd9Sstevel@tonic-gate 			char *dst = (char *)(knp + ksp->ks_ndata);
7357c478bd9Sstevel@tonic-gate 			/*
7367c478bd9Sstevel@tonic-gate 			 * Copy strings and update pointers
7377c478bd9Sstevel@tonic-gate 			 */
7387c478bd9Sstevel@tonic-gate 			for (i = 0; i < ksp->ks_ndata; i++, knp++) {
7397c478bd9Sstevel@tonic-gate 				if (knp->data_type == KSTAT_DATA_STRING &&
7407c478bd9Sstevel@tonic-gate 				    KSTAT_NAMED_STR_PTR(knp) != NULL) {
7417c478bd9Sstevel@tonic-gate 					bcopy(KSTAT_NAMED_STR_PTR(knp), dst,
7427c478bd9Sstevel@tonic-gate 					    KSTAT_NAMED_STR_BUFLEN(knp));
7437c478bd9Sstevel@tonic-gate 					KSTAT_NAMED_STR_PTR(knp) = dst;
7447c478bd9Sstevel@tonic-gate 					dst += KSTAT_NAMED_STR_BUFLEN(knp);
7457c478bd9Sstevel@tonic-gate 				}
7467c478bd9Sstevel@tonic-gate 			}
7477c478bd9Sstevel@tonic-gate 			ASSERT(dst <= ((char *)buf + ksp->ks_data_size));
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 		break;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	return (0);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate static int
header_kstat_update(kstat_t * header_ksp,int rw)7557c478bd9Sstevel@tonic-gate header_kstat_update(kstat_t *header_ksp, int rw)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate 	int nkstats = 0;
7587c478bd9Sstevel@tonic-gate 	ekstat_t *e;
7597c478bd9Sstevel@tonic-gate 	avl_tree_t *t = &kstat_avl_bykid;
7607c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
7637c478bd9Sstevel@tonic-gate 		return (EACCES);
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&kstat_chain_lock));
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	zoneid = getzoneid();
7687c478bd9Sstevel@tonic-gate 	for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) {
769dc9df478SJerry Jelinek 		if (kstat_zone_find((kstat_t *)e, zoneid) &&
770dc9df478SJerry Jelinek 		    (e->e_ks.ks_flags & KSTAT_FLAG_INVALID) == 0) {
7717c478bd9Sstevel@tonic-gate 			nkstats++;
7727c478bd9Sstevel@tonic-gate 		}
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 	header_ksp->ks_ndata = nkstats;
7757c478bd9Sstevel@tonic-gate 	header_ksp->ks_data_size = nkstats * sizeof (kstat_t);
7767c478bd9Sstevel@tonic-gate 	return (0);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate /*
7807c478bd9Sstevel@tonic-gate  * Copy out the data section of kstat 0, which consists of the list
7817c478bd9Sstevel@tonic-gate  * of all kstat headers.  By specification, these headers must be
7827c478bd9Sstevel@tonic-gate  * copied out in order of increasing KID.
7837c478bd9Sstevel@tonic-gate  */
7847c478bd9Sstevel@tonic-gate static int
header_kstat_snapshot(kstat_t * header_ksp,void * buf,int rw)7857c478bd9Sstevel@tonic-gate header_kstat_snapshot(kstat_t *header_ksp, void *buf, int rw)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate 	ekstat_t *e;
7887c478bd9Sstevel@tonic-gate 	avl_tree_t *t = &kstat_avl_bykid;
7897c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	header_ksp->ks_snaptime = gethrtime();
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
7947c478bd9Sstevel@tonic-gate 		return (EACCES);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&kstat_chain_lock));
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	zoneid = getzoneid();
7997c478bd9Sstevel@tonic-gate 	for (e = avl_first(t); e != NULL; e = avl_walk(t, e, AVL_AFTER)) {
800dc9df478SJerry Jelinek 		if (kstat_zone_find((kstat_t *)e, zoneid) &&
801dc9df478SJerry Jelinek 		    (e->e_ks.ks_flags & KSTAT_FLAG_INVALID) == 0) {
8027c478bd9Sstevel@tonic-gate 			bcopy(&e->e_ks, buf, sizeof (kstat_t));
8037c478bd9Sstevel@tonic-gate 			buf = (char *)buf + sizeof (kstat_t);
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	return (0);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /* ARGSUSED */
8117c478bd9Sstevel@tonic-gate static int
system_misc_kstat_update(kstat_t * ksp,int rw)8127c478bd9Sstevel@tonic-gate system_misc_kstat_update(kstat_t *ksp, int rw)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate 	int myncpus = ncpus;
8157c478bd9Sstevel@tonic-gate 	int *loadavgp = &avenrun[0];
816a34e7eeaSDhanaraj M 	time_t zone_boot_time;
817a34e7eeaSDhanaraj M 	clock_t zone_lbolt;
818a34e7eeaSDhanaraj M 	hrtime_t zone_hrtime;
8198cb09440SVamsi Nagineni 	size_t zone_nproc;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
8227c478bd9Sstevel@tonic-gate 		return (EACCES);
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	if (!INGLOBALZONE(curproc)) {
8257c478bd9Sstevel@tonic-gate 		/*
8267c478bd9Sstevel@tonic-gate 		 * Here we grab cpu_lock which is OK as long as no-one in the
8277c478bd9Sstevel@tonic-gate 		 * future attempts to lookup this particular kstat
8287c478bd9Sstevel@tonic-gate 		 * (unix:0:system_misc) while holding cpu_lock.
8297c478bd9Sstevel@tonic-gate 		 */
8307c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
8317c478bd9Sstevel@tonic-gate 		if (pool_pset_enabled()) {
8327c478bd9Sstevel@tonic-gate 			myncpus = zone_ncpus_get(curproc->p_zone);
8337c478bd9Sstevel@tonic-gate 			ASSERT(myncpus > 0);
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
83681d43577SJerry Jelinek 		loadavgp = &curproc->p_zone->zone_avenrun[0];
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8398cb09440SVamsi Nagineni 	if (INGLOBALZONE(curproc)) {
840a34e7eeaSDhanaraj M 		zone_boot_time = boot_time;
841d3d50737SRafael Vanoni 		zone_lbolt = ddi_get_lbolt();
8428cb09440SVamsi Nagineni 		zone_nproc = nproc;
843a34e7eeaSDhanaraj M 	} else {
84486ad481cSJerry Jelinek 		zone_boot_time = curproc->p_zone->zone_boot_time;
845a34e7eeaSDhanaraj M 
846a34e7eeaSDhanaraj M 		zone_hrtime = gethrtime();
847a34e7eeaSDhanaraj M 		zone_lbolt = (clock_t)(NSEC_TO_TICK(zone_hrtime) -
848a34e7eeaSDhanaraj M 		    NSEC_TO_TICK(curproc->p_zone->zone_zsched->p_mstart));
8498cb09440SVamsi Nagineni 		mutex_enter(&curproc->p_zone->zone_nlwps_lock);
8508cb09440SVamsi Nagineni 		zone_nproc = curproc->p_zone->zone_nprocs;
8518cb09440SVamsi Nagineni 		mutex_exit(&curproc->p_zone->zone_nlwps_lock);
852a34e7eeaSDhanaraj M 	}
853a34e7eeaSDhanaraj M 
8547c478bd9Sstevel@tonic-gate 	system_misc_kstat.ncpus.value.ui32		= (uint32_t)myncpus;
855a34e7eeaSDhanaraj M 	system_misc_kstat.lbolt.value.ui32		= (uint32_t)zone_lbolt;
8567c478bd9Sstevel@tonic-gate 	system_misc_kstat.deficit.value.ui32		= (uint32_t)deficit;
857a34e7eeaSDhanaraj M 	system_misc_kstat.clk_intr.value.ui32		= (uint32_t)zone_lbolt;
8587c478bd9Sstevel@tonic-gate 	system_misc_kstat.vac.value.ui32		= (uint32_t)vac;
8598cb09440SVamsi Nagineni 	system_misc_kstat.nproc.value.ui32		= (uint32_t)zone_nproc;
8607c478bd9Sstevel@tonic-gate 	system_misc_kstat.avenrun_1min.value.ui32	= (uint32_t)loadavgp[0];
8617c478bd9Sstevel@tonic-gate 	system_misc_kstat.avenrun_5min.value.ui32	= (uint32_t)loadavgp[1];
8627c478bd9Sstevel@tonic-gate 	system_misc_kstat.avenrun_15min.value.ui32	= (uint32_t)loadavgp[2];
863a34e7eeaSDhanaraj M 	system_misc_kstat.boot_time.value.ui32		= (uint32_t)
864a34e7eeaSDhanaraj M 	    zone_boot_time;
865482a7749SJerry Jelinek 	system_misc_kstat.nsec_per_tick.value.ui32	= (uint32_t)
866482a7749SJerry Jelinek 	    nsec_per_tick;
8677c478bd9Sstevel@tonic-gate 	return (0);
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate #ifdef	__sparc
8717c478bd9Sstevel@tonic-gate extern caddr_t	econtig32;
8727c478bd9Sstevel@tonic-gate #else	/* !__sparc */
8737c478bd9Sstevel@tonic-gate extern caddr_t	econtig;
8747c478bd9Sstevel@tonic-gate #endif	/* __sparc */
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate /* ARGSUSED */
8777c478bd9Sstevel@tonic-gate static int
system_pages_kstat_update(kstat_t * ksp,int rw)8787c478bd9Sstevel@tonic-gate system_pages_kstat_update(kstat_t *ksp, int rw)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	kobj_stat_t kobj_stat;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
8837c478bd9Sstevel@tonic-gate 		return (EACCES);
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	kobj_stat_get(&kobj_stat);
8877c478bd9Sstevel@tonic-gate 	system_pages_kstat.physmem.value.ul	= (ulong_t)physmem;
8887c478bd9Sstevel@tonic-gate 	system_pages_kstat.nalloc.value.ul	= kobj_stat.nalloc;
8897c478bd9Sstevel@tonic-gate 	system_pages_kstat.nfree.value.ul	= kobj_stat.nfree;
8907c478bd9Sstevel@tonic-gate 	system_pages_kstat.nalloc_calls.value.ul = kobj_stat.nalloc_calls;
8917c478bd9Sstevel@tonic-gate 	system_pages_kstat.nfree_calls.value.ul	= kobj_stat.nfree_calls;
8927c478bd9Sstevel@tonic-gate 	system_pages_kstat.kernelbase.value.ul	= (ulong_t)KERNELBASE;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate #ifdef	__sparc
8957c478bd9Sstevel@tonic-gate 	/*
8967c478bd9Sstevel@tonic-gate 	 * kstat should REALLY be modified to also report kmem64_base and
8977c478bd9Sstevel@tonic-gate 	 * kmem64_end (see sun4u/os/startup.c), as the virtual address range
8987c478bd9Sstevel@tonic-gate 	 * [ kernelbase .. econtig ] no longer is truly reflective of the
8997c478bd9Sstevel@tonic-gate 	 * kernel's vallocs...
9007c478bd9Sstevel@tonic-gate 	 */
9017c478bd9Sstevel@tonic-gate 	system_pages_kstat.econtig.value.ul	= (ulong_t)econtig32;
9027c478bd9Sstevel@tonic-gate #else	/* !__sparc */
9037c478bd9Sstevel@tonic-gate 	system_pages_kstat.econtig.value.ul	= (ulong_t)econtig;
9047c478bd9Sstevel@tonic-gate #endif	/* __sparc */
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	system_pages_kstat.freemem.value.ul	= (ulong_t)freemem;
9077c478bd9Sstevel@tonic-gate 	system_pages_kstat.availrmem.value.ul	= (ulong_t)availrmem;
9087c478bd9Sstevel@tonic-gate 	system_pages_kstat.lotsfree.value.ul	= (ulong_t)lotsfree;
9097c478bd9Sstevel@tonic-gate 	system_pages_kstat.desfree.value.ul	= (ulong_t)desfree;
9107c478bd9Sstevel@tonic-gate 	system_pages_kstat.minfree.value.ul	= (ulong_t)minfree;
9117c478bd9Sstevel@tonic-gate 	system_pages_kstat.fastscan.value.ul	= (ulong_t)fastscan;
9127c478bd9Sstevel@tonic-gate 	system_pages_kstat.slowscan.value.ul	= (ulong_t)slowscan;
9137c478bd9Sstevel@tonic-gate 	system_pages_kstat.nscan.value.ul	= (ulong_t)nscan;
9147c478bd9Sstevel@tonic-gate 	system_pages_kstat.desscan.value.ul	= (ulong_t)desscan;
9157c478bd9Sstevel@tonic-gate 	system_pages_kstat.pagesfree.value.ul	= (ulong_t)freemem;
9167c478bd9Sstevel@tonic-gate 	system_pages_kstat.pageslocked.value.ul	= (ulong_t)(availrmem_initial -
9177c478bd9Sstevel@tonic-gate 	    availrmem);
9187c478bd9Sstevel@tonic-gate 	system_pages_kstat.pagestotal.value.ul	= (ulong_t)total_pages;
919*338664dfSAndy Fiddaman 	system_pages_kstat.lowmemscan.value.ul	= (ulong_t)low_mem_scan;
920*338664dfSAndy Fiddaman 	system_pages_kstat.nthrottle.value.ul	= (ulong_t)n_throttle;
9217c478bd9Sstevel@tonic-gate 	/*
9227c478bd9Sstevel@tonic-gate 	 * pp_kernel represents total pages used by the kernel since the
9237c478bd9Sstevel@tonic-gate 	 * startup. This formula takes into account the boottime kernel
9247c478bd9Sstevel@tonic-gate 	 * footprint and also considers the availrmem changes because of
9257c478bd9Sstevel@tonic-gate 	 * user explicit page locking.
9267c478bd9Sstevel@tonic-gate 	 */
9277c478bd9Sstevel@tonic-gate 	system_pages_kstat.pp_kernel.value.ul   = (ulong_t)(physinstalled -
9287c478bd9Sstevel@tonic-gate 	    obp_pages - availrmem - k_anoninfo.ani_mem_resv -
929a98e9dbfSaguzovsk 	    anon_segkp_pages_locked - pages_locked -
930a98e9dbfSaguzovsk 	    pages_claimed - pages_useclaim);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	return (0);
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@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)936d624471bSelowe kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
937d624471bSelowe     const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	return (kstat_create_zone(ks_module, ks_instance, ks_name, ks_class,
9407c478bd9Sstevel@tonic-gate 	    ks_type, ks_ndata, ks_flags, ALL_ZONES));
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate  * Allocate and initialize a kstat structure.  Or, if a dormant kstat with
9457c478bd9Sstevel@tonic-gate  * the specified name exists, reactivate it.  Returns a pointer to the kstat
9467c478bd9Sstevel@tonic-gate  * on success, NULL on failure.  The kstat will not be visible to the
9477c478bd9Sstevel@tonic-gate  * kstat driver until kstat_install().
9487c478bd9Sstevel@tonic-gate  */
9497c478bd9Sstevel@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)950d624471bSelowe kstat_create_zone(const char *ks_module, int ks_instance, const char *ks_name,
951d624471bSelowe     const char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
9527c478bd9Sstevel@tonic-gate     zoneid_t ks_zoneid)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	size_t ks_data_size;
9557c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
9567c478bd9Sstevel@tonic-gate 	ekstat_t *e;
9577c478bd9Sstevel@tonic-gate 	avl_index_t where;
9587c478bd9Sstevel@tonic-gate 	char namebuf[KSTAT_STRLEN + 16];
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	if (avl_numnodes(&kstat_avl_bykid) == 0) {
9617c478bd9Sstevel@tonic-gate 		avl_create(&kstat_avl_bykid, kstat_compare_bykid,
9627c478bd9Sstevel@tonic-gate 		    sizeof (ekstat_t), offsetof(struct ekstat, e_avl_bykid));
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 		avl_create(&kstat_avl_byname, kstat_compare_byname,
9657c478bd9Sstevel@tonic-gate 		    sizeof (ekstat_t), offsetof(struct ekstat, e_avl_byname));
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/*
9697c478bd9Sstevel@tonic-gate 	 * If ks_name == NULL, set the ks_name to <module><instance>.
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	if (ks_name == NULL) {
9727c478bd9Sstevel@tonic-gate 		char buf[KSTAT_STRLEN];
9737c478bd9Sstevel@tonic-gate 		kstat_set_string(buf, ks_module);
9747c478bd9Sstevel@tonic-gate 		(void) sprintf(namebuf, "%s%d", buf, ks_instance);
9757c478bd9Sstevel@tonic-gate 		ks_name = namebuf;
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	/*
9797c478bd9Sstevel@tonic-gate 	 * Make sure it's a valid kstat data type
9807c478bd9Sstevel@tonic-gate 	 */
9817c478bd9Sstevel@tonic-gate 	if (ks_type >= KSTAT_NUM_TYPES) {
9827c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
9837c478bd9Sstevel@tonic-gate 		    "invalid kstat type %d",
9847c478bd9Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name, ks_type);
9857c478bd9Sstevel@tonic-gate 		return (NULL);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/*
9897c478bd9Sstevel@tonic-gate 	 * Don't allow persistent virtual kstats -- it makes no sense.
9907c478bd9Sstevel@tonic-gate 	 * ks_data points to garbage when the client goes away.
9917c478bd9Sstevel@tonic-gate 	 */
9927c478bd9Sstevel@tonic-gate 	if ((ks_flags & KSTAT_FLAG_PERSISTENT) &&
9937c478bd9Sstevel@tonic-gate 	    (ks_flags & KSTAT_FLAG_VIRTUAL)) {
9947c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
9957c478bd9Sstevel@tonic-gate 		    "cannot create persistent virtual kstat",
9967c478bd9Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name);
9977c478bd9Sstevel@tonic-gate 		return (NULL);
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	/*
10017c478bd9Sstevel@tonic-gate 	 * Don't allow variable-size physical kstats, since the framework's
10027c478bd9Sstevel@tonic-gate 	 * memory allocation for physical kstat data is fixed at creation time.
10037c478bd9Sstevel@tonic-gate 	 */
10047c478bd9Sstevel@tonic-gate 	if ((ks_flags & KSTAT_FLAG_VAR_SIZE) &&
10057c478bd9Sstevel@tonic-gate 	    !(ks_flags & KSTAT_FLAG_VIRTUAL)) {
10067c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
10077c478bd9Sstevel@tonic-gate 		    "cannot create variable-size physical kstat",
10087c478bd9Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name);
10097c478bd9Sstevel@tonic-gate 		return (NULL);
10107c478bd9Sstevel@tonic-gate 	}
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	/*
10137c478bd9Sstevel@tonic-gate 	 * Make sure the number of data fields is within legal range
10147c478bd9Sstevel@tonic-gate 	 */
10157c478bd9Sstevel@tonic-gate 	if (ks_ndata < kstat_data_type[ks_type].min_ndata ||
10167c478bd9Sstevel@tonic-gate 	    ks_ndata > kstat_data_type[ks_type].max_ndata) {
10177c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
10187c478bd9Sstevel@tonic-gate 		    "ks_ndata=%d out of range [%d, %d]",
10197c478bd9Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name, (int)ks_ndata,
10207c478bd9Sstevel@tonic-gate 		    kstat_data_type[ks_type].min_ndata,
10217c478bd9Sstevel@tonic-gate 		    kstat_data_type[ks_type].max_ndata);
10227c478bd9Sstevel@tonic-gate 		return (NULL);
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	ks_data_size = kstat_data_type[ks_type].size * ks_ndata;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	/*
10287c478bd9Sstevel@tonic-gate 	 * If the named kstat already exists and is dormant, reactivate it.
10297c478bd9Sstevel@tonic-gate 	 */
10307c478bd9Sstevel@tonic-gate 	ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid);
10317c478bd9Sstevel@tonic-gate 	if (ksp != NULL) {
10327c478bd9Sstevel@tonic-gate 		if (!(ksp->ks_flags & KSTAT_FLAG_DORMANT)) {
10337c478bd9Sstevel@tonic-gate 			/*
10347c478bd9Sstevel@tonic-gate 			 * The named kstat exists but is not dormant --
10357c478bd9Sstevel@tonic-gate 			 * this is a kstat namespace collision.
10367c478bd9Sstevel@tonic-gate 			 */
10377c478bd9Sstevel@tonic-gate 			kstat_rele(ksp);
10387c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
10397c478bd9Sstevel@tonic-gate 			    "kstat_create('%s', %d, '%s'): namespace collision",
10407c478bd9Sstevel@tonic-gate 			    ks_module, ks_instance, ks_name);
10417c478bd9Sstevel@tonic-gate 			return (NULL);
10427c478bd9Sstevel@tonic-gate 		}
10437c478bd9Sstevel@tonic-gate 		if ((strcmp(ksp->ks_class, ks_class) != 0) ||
10447c478bd9Sstevel@tonic-gate 		    (ksp->ks_type != ks_type) ||
10457c478bd9Sstevel@tonic-gate 		    (ksp->ks_ndata != ks_ndata) ||
10467c478bd9Sstevel@tonic-gate 		    (ks_flags & KSTAT_FLAG_VIRTUAL)) {
10477c478bd9Sstevel@tonic-gate 			/*
10487c478bd9Sstevel@tonic-gate 			 * The name is the same, but the other key parameters
10497c478bd9Sstevel@tonic-gate 			 * differ from those of the dormant kstat -- bogus.
10507c478bd9Sstevel@tonic-gate 			 */
10517c478bd9Sstevel@tonic-gate 			kstat_rele(ksp);
10527c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "kstat_create('%s', %d, '%s'): "
10537c478bd9Sstevel@tonic-gate 			    "invalid reactivation of dormant kstat",
10547c478bd9Sstevel@tonic-gate 			    ks_module, ks_instance, ks_name);
10557c478bd9Sstevel@tonic-gate 			return (NULL);
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 		/*
10587c478bd9Sstevel@tonic-gate 		 * Return dormant kstat pointer to caller.  As usual,
10597c478bd9Sstevel@tonic-gate 		 * the kstat is marked invalid until kstat_install().
10607c478bd9Sstevel@tonic-gate 		 */
10617c478bd9Sstevel@tonic-gate 		ksp->ks_flags |= KSTAT_FLAG_INVALID;
10627c478bd9Sstevel@tonic-gate 		kstat_rele(ksp);
10637c478bd9Sstevel@tonic-gate 		return (ksp);
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	/*
10677c478bd9Sstevel@tonic-gate 	 * Allocate memory for the new kstat header and, if this is a physical
10687c478bd9Sstevel@tonic-gate 	 * kstat, the data section.
10697c478bd9Sstevel@tonic-gate 	 */
10707c478bd9Sstevel@tonic-gate 	e = kstat_alloc(ks_flags & KSTAT_FLAG_VIRTUAL ? 0 : ks_data_size);
10717c478bd9Sstevel@tonic-gate 	if (e == NULL) {
10727c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "kstat_create('%s', %d, '%s'): "
10737c478bd9Sstevel@tonic-gate 		    "insufficient kernel memory",
10747c478bd9Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name);
10757c478bd9Sstevel@tonic-gate 		return (NULL);
10767c478bd9Sstevel@tonic-gate 	}
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	/*
10797c478bd9Sstevel@tonic-gate 	 * Initialize as many fields as we can.  The caller may reset
10807c478bd9Sstevel@tonic-gate 	 * ks_lock, ks_update, ks_private, and ks_snapshot as necessary.
10817c478bd9Sstevel@tonic-gate 	 * Creators of virtual kstats may also reset ks_data.  It is
10827c478bd9Sstevel@tonic-gate 	 * also up to the caller to initialize the kstat data section,
10837c478bd9Sstevel@tonic-gate 	 * if necessary.  All initialization must be complete before
10847c478bd9Sstevel@tonic-gate 	 * calling kstat_install().
10857c478bd9Sstevel@tonic-gate 	 */
10867c478bd9Sstevel@tonic-gate 	e->e_zone.zoneid = ks_zoneid;
10877c478bd9Sstevel@tonic-gate 	e->e_zone.next = NULL;
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	ksp = &e->e_ks;
10907c478bd9Sstevel@tonic-gate 	ksp->ks_crtime		= gethrtime();
10917c478bd9Sstevel@tonic-gate 	kstat_set_string(ksp->ks_module, ks_module);
10927c478bd9Sstevel@tonic-gate 	ksp->ks_instance	= ks_instance;
10937c478bd9Sstevel@tonic-gate 	kstat_set_string(ksp->ks_name, ks_name);
10947c478bd9Sstevel@tonic-gate 	ksp->ks_type		= ks_type;
10957c478bd9Sstevel@tonic-gate 	kstat_set_string(ksp->ks_class, ks_class);
10967c478bd9Sstevel@tonic-gate 	ksp->ks_flags		= ks_flags | KSTAT_FLAG_INVALID;
10977c478bd9Sstevel@tonic-gate 	if (ks_flags & KSTAT_FLAG_VIRTUAL)
10987c478bd9Sstevel@tonic-gate 		ksp->ks_data	= NULL;
10997c478bd9Sstevel@tonic-gate 	else
11007c478bd9Sstevel@tonic-gate 		ksp->ks_data	= (void *)(e + 1);
11017c478bd9Sstevel@tonic-gate 	ksp->ks_ndata		= ks_ndata;
11027c478bd9Sstevel@tonic-gate 	ksp->ks_data_size	= ks_data_size;
11037c478bd9Sstevel@tonic-gate 	ksp->ks_snaptime	= ksp->ks_crtime;
11047c478bd9Sstevel@tonic-gate 	ksp->ks_update		= default_kstat_update;
11057c478bd9Sstevel@tonic-gate 	ksp->ks_private		= NULL;
11067c478bd9Sstevel@tonic-gate 	ksp->ks_snapshot	= default_kstat_snapshot;
11077c478bd9Sstevel@tonic-gate 	ksp->ks_lock		= NULL;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	/*
11127c478bd9Sstevel@tonic-gate 	 * Add our kstat to the AVL trees.
11137c478bd9Sstevel@tonic-gate 	 */
11147c478bd9Sstevel@tonic-gate 	if (avl_find(&kstat_avl_byname, e, &where) != NULL) {
11157c478bd9Sstevel@tonic-gate 		mutex_exit(&kstat_chain_lock);
11167c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
11177c478bd9Sstevel@tonic-gate 		    "kstat_create('%s', %d, '%s'): namespace collision",
11187c478bd9Sstevel@tonic-gate 		    ks_module, ks_instance, ks_name);
11197c478bd9Sstevel@tonic-gate 		kstat_free(e);
11207c478bd9Sstevel@tonic-gate 		return (NULL);
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 	avl_insert(&kstat_avl_byname, e, where);
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	/*
11257c478bd9Sstevel@tonic-gate 	 * Loop around until we find an unused KID.
11267c478bd9Sstevel@tonic-gate 	 */
11277c478bd9Sstevel@tonic-gate 	do {
11287c478bd9Sstevel@tonic-gate 		ksp->ks_kid = kstat_chain_id++;
11297c478bd9Sstevel@tonic-gate 	} while (avl_find(&kstat_avl_bykid, e, &where) != NULL);
11307c478bd9Sstevel@tonic-gate 	avl_insert(&kstat_avl_bykid, e, where);
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	return (ksp);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate /*
11387c478bd9Sstevel@tonic-gate  * Activate a fully initialized kstat and make it visible to /dev/kstat.
11397c478bd9Sstevel@tonic-gate  */
11407c478bd9Sstevel@tonic-gate void
kstat_install(kstat_t * ksp)11417c478bd9Sstevel@tonic-gate kstat_install(kstat_t *ksp)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	zoneid_t zoneid = ((ekstat_t *)ksp)->e_zone.zoneid;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	/*
11467c478bd9Sstevel@tonic-gate 	 * If this is a variable-size kstat, it MUST provide kstat data locking
11477c478bd9Sstevel@tonic-gate 	 * to prevent data-size races with kstat readers.
11487c478bd9Sstevel@tonic-gate 	 */
11497c478bd9Sstevel@tonic-gate 	if ((ksp->ks_flags & KSTAT_FLAG_VAR_SIZE) && ksp->ks_lock == NULL) {
11507c478bd9Sstevel@tonic-gate 		panic("kstat_install('%s', %d, '%s'): "
11517c478bd9Sstevel@tonic-gate 		    "cannot create variable-size kstat without data lock",
11527c478bd9Sstevel@tonic-gate 		    ksp->ks_module, ksp->ks_instance, ksp->ks_name);
11537c478bd9Sstevel@tonic-gate 	}
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) {
11567c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_install(%p): does not exist",
11577c478bd9Sstevel@tonic-gate 		    (void *)ksp);
11587c478bd9Sstevel@tonic-gate 		return;
11597c478bd9Sstevel@tonic-gate 	}
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	if (ksp->ks_type == KSTAT_TYPE_NAMED && ksp->ks_data != NULL) {
11627c478bd9Sstevel@tonic-gate 		uint_t i;
11637c478bd9Sstevel@tonic-gate 		kstat_named_t *knp = KSTAT_NAMED_PTR(ksp);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 		for (i = 0; i < ksp->ks_ndata; i++, knp++) {
11667c478bd9Sstevel@tonic-gate 			if (knp->data_type == KSTAT_DATA_STRING) {
1167c0e96d86SHans Rosenfeld 				ksp->ks_flags |= KSTAT_FLAG_LONGSTRINGS;
11687c478bd9Sstevel@tonic-gate 				break;
11697c478bd9Sstevel@tonic-gate 			}
11707c478bd9Sstevel@tonic-gate 		}
11717c478bd9Sstevel@tonic-gate 		/*
11727c478bd9Sstevel@tonic-gate 		 * The default snapshot routine does not handle KSTAT_WRITE
11737c478bd9Sstevel@tonic-gate 		 * for long strings.
11747c478bd9Sstevel@tonic-gate 		 */
1175c0e96d86SHans Rosenfeld 		if ((ksp->ks_flags & KSTAT_FLAG_LONGSTRINGS) &&
1176c0e96d86SHans Rosenfeld 		    (ksp->ks_flags & KSTAT_FLAG_WRITABLE) &&
11777c478bd9Sstevel@tonic-gate 		    (ksp->ks_snapshot == default_kstat_snapshot)) {
11787c478bd9Sstevel@tonic-gate 			panic("kstat_install('%s', %d, '%s'): "
11797c478bd9Sstevel@tonic-gate 			    "named kstat containing KSTAT_DATA_STRING "
11807c478bd9Sstevel@tonic-gate 			    "is writable but uses default snapshot routine",
11817c478bd9Sstevel@tonic-gate 			    ksp->ks_module, ksp->ks_instance, ksp->ks_name);
11827c478bd9Sstevel@tonic-gate 		}
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (ksp->ks_flags & KSTAT_FLAG_DORMANT) {
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 		/*
11887c478bd9Sstevel@tonic-gate 		 * We are reactivating a dormant kstat.  Initialize the
11897c478bd9Sstevel@tonic-gate 		 * caller's underlying data to the value it had when the
11907c478bd9Sstevel@tonic-gate 		 * kstat went dormant, and mark the kstat as active.
11917c478bd9Sstevel@tonic-gate 		 * Grab the provider's kstat lock if it's not already held.
11927c478bd9Sstevel@tonic-gate 		 */
11937c478bd9Sstevel@tonic-gate 		kmutex_t *lp = ksp->ks_lock;
11947c478bd9Sstevel@tonic-gate 		if (lp != NULL && MUTEX_NOT_HELD(lp)) {
11957c478bd9Sstevel@tonic-gate 			mutex_enter(lp);
11967c478bd9Sstevel@tonic-gate 			(void) KSTAT_UPDATE(ksp, KSTAT_WRITE);
11977c478bd9Sstevel@tonic-gate 			mutex_exit(lp);
11987c478bd9Sstevel@tonic-gate 		} else {
11997c478bd9Sstevel@tonic-gate 			(void) KSTAT_UPDATE(ksp, KSTAT_WRITE);
12007c478bd9Sstevel@tonic-gate 		}
12017c478bd9Sstevel@tonic-gate 		ksp->ks_flags &= ~KSTAT_FLAG_DORMANT;
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	/*
12057c478bd9Sstevel@tonic-gate 	 * Now that the kstat is active, make it visible to the kstat driver.
1206c9bbee95SJerry Jelinek 	 * When copying out kstats the count is determined in
1207c9bbee95SJerry Jelinek 	 * header_kstat_update() and actually copied into kbuf in
1208c9bbee95SJerry Jelinek 	 * header_kstat_snapshot(). kstat_chain_lock is held across the two
1209c9bbee95SJerry Jelinek 	 * calls to ensure that this list doesn't change. Thus, we need to
1210c9bbee95SJerry Jelinek 	 * also take the lock to ensure that the we don't copy the new kstat
1211c9bbee95SJerry Jelinek 	 * in the 2nd pass and overrun the buf.
12127c478bd9Sstevel@tonic-gate 	 */
1213c9bbee95SJerry Jelinek 	mutex_enter(&kstat_chain_lock);
12147c478bd9Sstevel@tonic-gate 	ksp->ks_flags &= ~KSTAT_FLAG_INVALID;
1215c9bbee95SJerry Jelinek 	mutex_exit(&kstat_chain_lock);
12167c478bd9Sstevel@tonic-gate 	kstat_rele(ksp);
12177c478bd9Sstevel@tonic-gate }
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate /*
12207c478bd9Sstevel@tonic-gate  * Remove a kstat from the system.  Or, if it's a persistent kstat,
12217c478bd9Sstevel@tonic-gate  * just update the data and mark it as dormant.
12227c478bd9Sstevel@tonic-gate  */
12237c478bd9Sstevel@tonic-gate void
kstat_delete(kstat_t * ksp)12247c478bd9Sstevel@tonic-gate kstat_delete(kstat_t *ksp)
12257c478bd9Sstevel@tonic-gate {
12267c478bd9Sstevel@tonic-gate 	kmutex_t *lp;
12277c478bd9Sstevel@tonic-gate 	ekstat_t *e = (ekstat_t *)ksp;
12283c5c7d01Sbatschul 	zoneid_t zoneid;
12297c478bd9Sstevel@tonic-gate 	kstat_zone_t *kz;
12307c478bd9Sstevel@tonic-gate 
12313c5c7d01Sbatschul 	ASSERT(ksp != NULL);
12323c5c7d01Sbatschul 
12337c478bd9Sstevel@tonic-gate 	if (ksp == NULL)
12347c478bd9Sstevel@tonic-gate 		return;
12357c478bd9Sstevel@tonic-gate 
12363c5c7d01Sbatschul 	zoneid = e->e_zone.zoneid;
12373c5c7d01Sbatschul 
12387c478bd9Sstevel@tonic-gate 	lp = ksp->ks_lock;
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (lp != NULL && MUTEX_HELD(lp)) {
12417c478bd9Sstevel@tonic-gate 		panic("kstat_delete(%p): caller holds data lock %p",
12427c478bd9Sstevel@tonic-gate 		    (void *)ksp, (void *)lp);
12437c478bd9Sstevel@tonic-gate 	}
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	if (kstat_hold_bykid(ksp->ks_kid, zoneid) != ksp) {
12467c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kstat_delete(%p): does not exist",
12477c478bd9Sstevel@tonic-gate 		    (void *)ksp);
12487c478bd9Sstevel@tonic-gate 		return;
12497c478bd9Sstevel@tonic-gate 	}
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	if (ksp->ks_flags & KSTAT_FLAG_PERSISTENT) {
12527c478bd9Sstevel@tonic-gate 		/*
12537c478bd9Sstevel@tonic-gate 		 * Update the data one last time, so that all activity
12547c478bd9Sstevel@tonic-gate 		 * prior to going dormant has been accounted for.
12557c478bd9Sstevel@tonic-gate 		 */
12567c478bd9Sstevel@tonic-gate 		KSTAT_ENTER(ksp);
12577c478bd9Sstevel@tonic-gate 		(void) KSTAT_UPDATE(ksp, KSTAT_READ);
12587c478bd9Sstevel@tonic-gate 		KSTAT_EXIT(ksp);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 		/*
12617c478bd9Sstevel@tonic-gate 		 * Mark the kstat as dormant and restore caller-modifiable
12627c478bd9Sstevel@tonic-gate 		 * fields to default values, so the kstat is readable during
12637c478bd9Sstevel@tonic-gate 		 * the dormant phase.
12647c478bd9Sstevel@tonic-gate 		 */
12657c478bd9Sstevel@tonic-gate 		ksp->ks_flags |= KSTAT_FLAG_DORMANT;
12667c478bd9Sstevel@tonic-gate 		ksp->ks_lock = NULL;
12677c478bd9Sstevel@tonic-gate 		ksp->ks_update = default_kstat_update;
12687c478bd9Sstevel@tonic-gate 		ksp->ks_private = NULL;
12697c478bd9Sstevel@tonic-gate 		ksp->ks_snapshot = default_kstat_snapshot;
12707c478bd9Sstevel@tonic-gate 		kstat_rele(ksp);
12717c478bd9Sstevel@tonic-gate 		return;
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	/*
12757c478bd9Sstevel@tonic-gate 	 * Remove the kstat from the framework's AVL trees,
12767c478bd9Sstevel@tonic-gate 	 * free the allocated memory, and increment kstat_chain_id so
12777c478bd9Sstevel@tonic-gate 	 * /dev/kstat clients can detect the event.
12787c478bd9Sstevel@tonic-gate 	 */
12797c478bd9Sstevel@tonic-gate 	mutex_enter(&kstat_chain_lock);
12807c478bd9Sstevel@tonic-gate 	avl_remove(&kstat_avl_bykid, e);
12817c478bd9Sstevel@tonic-gate 	avl_remove(&kstat_avl_byname, e);
12827c478bd9Sstevel@tonic-gate 	kstat_chain_id++;
12837c478bd9Sstevel@tonic-gate 	mutex_exit(&kstat_chain_lock);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	kz = e->e_zone.next;
12867c478bd9Sstevel@tonic-gate 	while (kz != NULL) {
12877c478bd9Sstevel@tonic-gate 		kstat_zone_t *t = kz;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 		kz = kz->next;
12907c478bd9Sstevel@tonic-gate 		kmem_free(t, sizeof (*t));
12917c478bd9Sstevel@tonic-gate 	}
12927c478bd9Sstevel@tonic-gate 	kstat_rele(ksp);
12937c478bd9Sstevel@tonic-gate 	kstat_free(e);
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate void
kstat_delete_byname_zone(const char * ks_module,int ks_instance,const char * ks_name,zoneid_t ks_zoneid)1297d624471bSelowe kstat_delete_byname_zone(const char *ks_module, int ks_instance,
1298d624471bSelowe     const char *ks_name, zoneid_t ks_zoneid)
12997c478bd9Sstevel@tonic-gate {
13007c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	ksp = kstat_hold_byname(ks_module, ks_instance, ks_name, ks_zoneid);
13037c478bd9Sstevel@tonic-gate 	if (ksp != NULL) {
13047c478bd9Sstevel@tonic-gate 		kstat_rele(ksp);
13057c478bd9Sstevel@tonic-gate 		kstat_delete(ksp);
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate void
kstat_delete_byname(const char * ks_module,int ks_instance,const char * ks_name)1310d624471bSelowe kstat_delete_byname(const char *ks_module, int ks_instance, const char *ks_name)
13117c478bd9Sstevel@tonic-gate {
13127c478bd9Sstevel@tonic-gate 	kstat_delete_byname_zone(ks_module, ks_instance, ks_name, ALL_ZONES);
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate /*
13167c478bd9Sstevel@tonic-gate  * The sparc V9 versions of these routines can be much cheaper than
13177c478bd9Sstevel@tonic-gate  * the poor 32-bit compiler can comprehend, so they're in sparcv9_subr.s.
13187c478bd9Sstevel@tonic-gate  * For simplicity, however, we always feed the C versions to lint.
13197c478bd9Sstevel@tonic-gate  */
13207c478bd9Sstevel@tonic-gate #if !defined(__sparc) || defined(lint) || defined(__lint)
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate void
kstat_waitq_enter(kstat_io_t * kiop)13237c478bd9Sstevel@tonic-gate kstat_waitq_enter(kstat_io_t *kiop)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate 	hrtime_t new, delta;
13267c478bd9Sstevel@tonic-gate 	ulong_t wcnt;
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 	new = gethrtime_unscaled();
13297c478bd9Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
13307c478bd9Sstevel@tonic-gate 	kiop->wlastupdate = new;
13317c478bd9Sstevel@tonic-gate 	wcnt = kiop->wcnt++;
13327c478bd9Sstevel@tonic-gate 	if (wcnt != 0) {
13337c478bd9Sstevel@tonic-gate 		kiop->wlentime += delta * wcnt;
13347c478bd9Sstevel@tonic-gate 		kiop->wtime += delta;
13357c478bd9Sstevel@tonic-gate 	}
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate void
kstat_waitq_exit(kstat_io_t * kiop)13397c478bd9Sstevel@tonic-gate kstat_waitq_exit(kstat_io_t *kiop)
13407c478bd9Sstevel@tonic-gate {
13417c478bd9Sstevel@tonic-gate 	hrtime_t new, delta;
13427c478bd9Sstevel@tonic-gate 	ulong_t wcnt;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	new = gethrtime_unscaled();
13457c478bd9Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
13467c478bd9Sstevel@tonic-gate 	kiop->wlastupdate = new;
13477c478bd9Sstevel@tonic-gate 	wcnt = kiop->wcnt--;
13487c478bd9Sstevel@tonic-gate 	ASSERT((int)wcnt > 0);
13497c478bd9Sstevel@tonic-gate 	kiop->wlentime += delta * wcnt;
13507c478bd9Sstevel@tonic-gate 	kiop->wtime += delta;
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate void
kstat_runq_enter(kstat_io_t * kiop)13547c478bd9Sstevel@tonic-gate kstat_runq_enter(kstat_io_t *kiop)
13557c478bd9Sstevel@tonic-gate {
13567c478bd9Sstevel@tonic-gate 	hrtime_t new, delta;
13577c478bd9Sstevel@tonic-gate 	ulong_t rcnt;
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	new = gethrtime_unscaled();
13607c478bd9Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
13617c478bd9Sstevel@tonic-gate 	kiop->rlastupdate = new;
13627c478bd9Sstevel@tonic-gate 	rcnt = kiop->rcnt++;
13637c478bd9Sstevel@tonic-gate 	if (rcnt != 0) {
13647c478bd9Sstevel@tonic-gate 		kiop->rlentime += delta * rcnt;
13657c478bd9Sstevel@tonic-gate 		kiop->rtime += delta;
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate void
kstat_runq_exit(kstat_io_t * kiop)13707c478bd9Sstevel@tonic-gate kstat_runq_exit(kstat_io_t *kiop)
13717c478bd9Sstevel@tonic-gate {
13727c478bd9Sstevel@tonic-gate 	hrtime_t new, delta;
13737c478bd9Sstevel@tonic-gate 	ulong_t rcnt;
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	new = gethrtime_unscaled();
13767c478bd9Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
13777c478bd9Sstevel@tonic-gate 	kiop->rlastupdate = new;
13787c478bd9Sstevel@tonic-gate 	rcnt = kiop->rcnt--;
13797c478bd9Sstevel@tonic-gate 	ASSERT((int)rcnt > 0);
13807c478bd9Sstevel@tonic-gate 	kiop->rlentime += delta * rcnt;
13817c478bd9Sstevel@tonic-gate 	kiop->rtime += delta;
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate void
kstat_waitq_to_runq(kstat_io_t * kiop)13857c478bd9Sstevel@tonic-gate kstat_waitq_to_runq(kstat_io_t *kiop)
13867c478bd9Sstevel@tonic-gate {
13877c478bd9Sstevel@tonic-gate 	hrtime_t new, delta;
13887c478bd9Sstevel@tonic-gate 	ulong_t wcnt, rcnt;
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	new = gethrtime_unscaled();
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
13937c478bd9Sstevel@tonic-gate 	kiop->wlastupdate = new;
13947c478bd9Sstevel@tonic-gate 	wcnt = kiop->wcnt--;
13957c478bd9Sstevel@tonic-gate 	ASSERT((int)wcnt > 0);
13967c478bd9Sstevel@tonic-gate 	kiop->wlentime += delta * wcnt;
13977c478bd9Sstevel@tonic-gate 	kiop->wtime += delta;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
14007c478bd9Sstevel@tonic-gate 	kiop->rlastupdate = new;
14017c478bd9Sstevel@tonic-gate 	rcnt = kiop->rcnt++;
14027c478bd9Sstevel@tonic-gate 	if (rcnt != 0) {
14037c478bd9Sstevel@tonic-gate 		kiop->rlentime += delta * rcnt;
14047c478bd9Sstevel@tonic-gate 		kiop->rtime += delta;
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate void
kstat_runq_back_to_waitq(kstat_io_t * kiop)14097c478bd9Sstevel@tonic-gate kstat_runq_back_to_waitq(kstat_io_t *kiop)
14107c478bd9Sstevel@tonic-gate {
14117c478bd9Sstevel@tonic-gate 	hrtime_t new, delta;
14127c478bd9Sstevel@tonic-gate 	ulong_t wcnt, rcnt;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	new = gethrtime_unscaled();
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	delta = new - kiop->rlastupdate;
14177c478bd9Sstevel@tonic-gate 	kiop->rlastupdate = new;
14187c478bd9Sstevel@tonic-gate 	rcnt = kiop->rcnt--;
14197c478bd9Sstevel@tonic-gate 	ASSERT((int)rcnt > 0);
14207c478bd9Sstevel@tonic-gate 	kiop->rlentime += delta * rcnt;
14217c478bd9Sstevel@tonic-gate 	kiop->rtime += delta;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	delta = new - kiop->wlastupdate;
14247c478bd9Sstevel@tonic-gate 	kiop->wlastupdate = new;
14257c478bd9Sstevel@tonic-gate 	wcnt = kiop->wcnt++;
14267c478bd9Sstevel@tonic-gate 	if (wcnt != 0) {
14277c478bd9Sstevel@tonic-gate 		kiop->wlentime += delta * wcnt;
14287c478bd9Sstevel@tonic-gate 		kiop->wtime += delta;
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate #endif
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate void
kstat_timer_start(kstat_timer_t * ktp)14357c478bd9Sstevel@tonic-gate kstat_timer_start(kstat_timer_t *ktp)
14367c478bd9Sstevel@tonic-gate {
14377c478bd9Sstevel@tonic-gate 	ktp->start_time = gethrtime();
14387c478bd9Sstevel@tonic-gate }
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate void
kstat_timer_stop(kstat_timer_t * ktp)14417c478bd9Sstevel@tonic-gate kstat_timer_stop(kstat_timer_t *ktp)
14427c478bd9Sstevel@tonic-gate {
14437c478bd9Sstevel@tonic-gate 	hrtime_t	etime;
14447c478bd9Sstevel@tonic-gate 	u_longlong_t	num_events;
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	ktp->stop_time = etime = gethrtime();
14477c478bd9Sstevel@tonic-gate 	etime -= ktp->start_time;
14487c478bd9Sstevel@tonic-gate 	num_events = ktp->num_events;
14497c478bd9Sstevel@tonic-gate 	if (etime < ktp->min_time || num_events == 0)
14507c478bd9Sstevel@tonic-gate 		ktp->min_time = etime;
14517c478bd9Sstevel@tonic-gate 	if (etime > ktp->max_time)
14527c478bd9Sstevel@tonic-gate 		ktp->max_time = etime;
14537c478bd9Sstevel@tonic-gate 	ktp->elapsed_time += etime;
14547c478bd9Sstevel@tonic-gate 	ktp->num_events = num_events + 1;
14557c478bd9Sstevel@tonic-gate }
1456