1efd4c9b6SSteve Lawrence /*
2efd4c9b6SSteve Lawrence  * CDDL HEADER START
3efd4c9b6SSteve Lawrence  *
4efd4c9b6SSteve Lawrence  * The contents of this file are subject to the terms of the
5efd4c9b6SSteve Lawrence  * Common Development and Distribution License (the "License").
6efd4c9b6SSteve Lawrence  * You may not use this file except in compliance with the License.
7efd4c9b6SSteve Lawrence  *
8efd4c9b6SSteve Lawrence  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9efd4c9b6SSteve Lawrence  * or http://www.opensolaris.org/os/licensing.
10efd4c9b6SSteve Lawrence  * See the License for the specific language governing permissions
11efd4c9b6SSteve Lawrence  * and limitations under the License.
12efd4c9b6SSteve Lawrence  *
13efd4c9b6SSteve Lawrence  * When distributing Covered Code, include this CDDL HEADER in each
14efd4c9b6SSteve Lawrence  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15efd4c9b6SSteve Lawrence  * If applicable, add the following below this CDDL HEADER, with the
16efd4c9b6SSteve Lawrence  * fields enclosed by brackets "[]" replaced with your own identifying
17efd4c9b6SSteve Lawrence  * information: Portions Copyright [yyyy] [name of copyright owner]
18efd4c9b6SSteve Lawrence  *
19efd4c9b6SSteve Lawrence  * CDDL HEADER END
20efd4c9b6SSteve Lawrence  */
21efd4c9b6SSteve Lawrence 
22efd4c9b6SSteve Lawrence /*
23efd4c9b6SSteve Lawrence  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24efd4c9b6SSteve Lawrence  */
25efd4c9b6SSteve Lawrence #include <alloca.h>
26efd4c9b6SSteve Lawrence #include <assert.h>
27efd4c9b6SSteve Lawrence #include <dirent.h>
28efd4c9b6SSteve Lawrence #include <dlfcn.h>
29efd4c9b6SSteve Lawrence #include <door.h>
30efd4c9b6SSteve Lawrence #include <errno.h>
31efd4c9b6SSteve Lawrence #include <exacct.h>
32efd4c9b6SSteve Lawrence #include <ctype.h>
33efd4c9b6SSteve Lawrence #include <fcntl.h>
34efd4c9b6SSteve Lawrence #include <kstat.h>
35efd4c9b6SSteve Lawrence #include <libcontract.h>
36efd4c9b6SSteve Lawrence #include <libintl.h>
37efd4c9b6SSteve Lawrence #include <libscf.h>
38efd4c9b6SSteve Lawrence #include <zonestat.h>
39efd4c9b6SSteve Lawrence #include <zonestat_impl.h>
40efd4c9b6SSteve Lawrence #include <limits.h>
41efd4c9b6SSteve Lawrence #include <pool.h>
42efd4c9b6SSteve Lawrence #include <procfs.h>
43efd4c9b6SSteve Lawrence #include <rctl.h>
44efd4c9b6SSteve Lawrence #include <thread.h>
45efd4c9b6SSteve Lawrence #include <signal.h>
46efd4c9b6SSteve Lawrence #include <stdarg.h>
47efd4c9b6SSteve Lawrence #include <stddef.h>
48efd4c9b6SSteve Lawrence #include <stdio.h>
49efd4c9b6SSteve Lawrence #include <stdlib.h>
50efd4c9b6SSteve Lawrence #include <strings.h>
51efd4c9b6SSteve Lawrence #include <synch.h>
52efd4c9b6SSteve Lawrence #include <sys/acctctl.h>
53efd4c9b6SSteve Lawrence #include <sys/contract/process.h>
54efd4c9b6SSteve Lawrence #include <sys/ctfs.h>
55efd4c9b6SSteve Lawrence #include <sys/fork.h>
56efd4c9b6SSteve Lawrence #include <sys/param.h>
57efd4c9b6SSteve Lawrence #include <sys/priocntl.h>
58efd4c9b6SSteve Lawrence #include <sys/fxpriocntl.h>
59efd4c9b6SSteve Lawrence #include <sys/processor.h>
60efd4c9b6SSteve Lawrence #include <sys/pset.h>
61efd4c9b6SSteve Lawrence #include <sys/socket.h>
62efd4c9b6SSteve Lawrence #include <sys/stat.h>
63efd4c9b6SSteve Lawrence #include <sys/statvfs.h>
64efd4c9b6SSteve Lawrence #include <sys/swap.h>
65efd4c9b6SSteve Lawrence #include <sys/systeminfo.h>
66efd4c9b6SSteve Lawrence #include <thread.h>
67efd4c9b6SSteve Lawrence #include <sys/list.h>
68efd4c9b6SSteve Lawrence #include <sys/time.h>
69efd4c9b6SSteve Lawrence #include <sys/types.h>
70efd4c9b6SSteve Lawrence #include <sys/vm_usage.h>
71efd4c9b6SSteve Lawrence #include <sys/wait.h>
72efd4c9b6SSteve Lawrence #include <sys/zone.h>
73efd4c9b6SSteve Lawrence #include <time.h>
74efd4c9b6SSteve Lawrence #include <ucred.h>
75efd4c9b6SSteve Lawrence #include <unistd.h>
76efd4c9b6SSteve Lawrence #include <vm/anon.h>
77efd4c9b6SSteve Lawrence #include <zone.h>
78efd4c9b6SSteve Lawrence #include <zonestat.h>
79efd4c9b6SSteve Lawrence 
80efd4c9b6SSteve Lawrence #define	MAX_PSET_NAME	1024	/* Taken from PV_NAME_MAX_LEN */
81efd4c9b6SSteve Lawrence #define	ZSD_PSET_UNLIMITED	UINT16_MAX
82efd4c9b6SSteve Lawrence #define	ZONESTAT_EXACCT_FILE	"/var/adm/exacct/zonestat-process"
83efd4c9b6SSteve Lawrence 
84efd4c9b6SSteve Lawrence /*
85efd4c9b6SSteve Lawrence  * zonestatd implements gathering cpu and memory utilization data for
86efd4c9b6SSteve Lawrence  * running zones.  It has these components:
87efd4c9b6SSteve Lawrence  *
88efd4c9b6SSteve Lawrence  * zsd_server:
89efd4c9b6SSteve Lawrence  *	Door server to respond to client connections.  Each client
90efd4c9b6SSteve Lawrence  *	will connect using libzonestat.so, which will open and
91efd4c9b6SSteve Lawrence  *	call /var/tmp/.zonestat_door.  Each connecting client is given
92efd4c9b6SSteve Lawrence  *	a file descriptor to the stat server.
93efd4c9b6SSteve Lawrence  *
94efd4c9b6SSteve Lawrence  *	The zsd_server also responds to zoneadmd, which reports when a
95efd4c9b6SSteve Lawrence  *	new zone is booted.  This is used to fattach the zsd_server door
96efd4c9b6SSteve Lawrence  *	into the new zone.
97efd4c9b6SSteve Lawrence  *
98efd4c9b6SSteve Lawrence  * zsd_stat_server:
99efd4c9b6SSteve Lawrence  *	Receives client requests for the current utilization data.  Each
100efd4c9b6SSteve Lawrence  *	client request will cause zonestatd to update the current utilization
101efd4c9b6SSteve Lawrence  *	data by kicking the stat_thread.
102efd4c9b6SSteve Lawrence  *
103efd4c9b6SSteve Lawrence  *	If the client is in a non-global zone, the utilization data will
104efd4c9b6SSteve Lawrence  *	be filtered to only show the given zone.  The usage by all other zones
105efd4c9b6SSteve Lawrence  *	will be added to the system utilization.
106efd4c9b6SSteve Lawrence  *
107efd4c9b6SSteve Lawrence  * stat_thread:
108efd4c9b6SSteve Lawrence  *	The stat thread implements querying the system to determine the
109efd4c9b6SSteve Lawrence  *	current utilization data for each running zone.  This includes
110efd4c9b6SSteve Lawrence  *	inspecting the system's processor set configuration, as well as details
111efd4c9b6SSteve Lawrence  *	of each zone, such as their configured limits, and which processor
112efd4c9b6SSteve Lawrence  *	sets they are running in.
113efd4c9b6SSteve Lawrence  *
114efd4c9b6SSteve Lawrence  *	The stat_thread will only update memory utilization data as often as
115efd4c9b6SSteve Lawrence  *	the configured config/sample_interval on the zones-monitoring service.
116efd4c9b6SSteve Lawrence  */
117efd4c9b6SSteve Lawrence 
118efd4c9b6SSteve Lawrence /*
119efd4c9b6SSteve Lawrence  * The private vmusage structure unfortunately uses size_t types, and assumes
120efd4c9b6SSteve Lawrence  * the caller's bitness matches the kernel's bitness.  Since the getvmusage()
121efd4c9b6SSteve Lawrence  * system call is contracted, and zonestatd is 32 bit, the following structures
122efd4c9b6SSteve Lawrence  * are used to interact with a 32bit or 64 bit kernel.
123efd4c9b6SSteve Lawrence  */
124efd4c9b6SSteve Lawrence typedef struct zsd_vmusage32 {
125efd4c9b6SSteve Lawrence 	id_t vmu_zoneid;
126efd4c9b6SSteve Lawrence 	uint_t vmu_type;
127efd4c9b6SSteve Lawrence 	id_t vmu_id;
128efd4c9b6SSteve Lawrence 
129efd4c9b6SSteve Lawrence 	uint32_t vmu_rss_all;
130efd4c9b6SSteve Lawrence 	uint32_t vmu_rss_private;
131efd4c9b6SSteve Lawrence 	uint32_t vmu_rss_shared;
132efd4c9b6SSteve Lawrence 	uint32_t vmu_swap_all;
133efd4c9b6SSteve Lawrence 	uint32_t vmu_swap_private;
134efd4c9b6SSteve Lawrence 	uint32_t vmu_swap_shared;
135efd4c9b6SSteve Lawrence } zsd_vmusage32_t;
136efd4c9b6SSteve Lawrence 
137efd4c9b6SSteve Lawrence typedef struct zsd_vmusage64 {
138efd4c9b6SSteve Lawrence 	id_t vmu_zoneid;
139efd4c9b6SSteve Lawrence 	uint_t vmu_type;
140efd4c9b6SSteve Lawrence 	id_t vmu_id;
141efd4c9b6SSteve Lawrence 	/*
142efd4c9b6SSteve Lawrence 	 * An amd64 kernel will align the following uint64_t members, but a
143efd4c9b6SSteve Lawrence 	 * 32bit i386 process will not without help.
144efd4c9b6SSteve Lawrence 	 */
145efd4c9b6SSteve Lawrence 	int vmu_align_next_members_on_8_bytes;
146efd4c9b6SSteve Lawrence 	uint64_t vmu_rss_all;
147efd4c9b6SSteve Lawrence 	uint64_t vmu_rss_private;
148efd4c9b6SSteve Lawrence 	uint64_t vmu_rss_shared;
149efd4c9b6SSteve Lawrence 	uint64_t vmu_swap_all;
150efd4c9b6SSteve Lawrence 	uint64_t vmu_swap_private;
151efd4c9b6SSteve Lawrence 	uint64_t vmu_swap_shared;
152efd4c9b6SSteve Lawrence } zsd_vmusage64_t;
153efd4c9b6SSteve Lawrence 
154efd4c9b6SSteve Lawrence struct zsd_zone;
155efd4c9b6SSteve Lawrence 
156efd4c9b6SSteve Lawrence /* Used to store a zone's usage of a pset */
157efd4c9b6SSteve Lawrence typedef struct zsd_pset_usage {
158efd4c9b6SSteve Lawrence 	struct zsd_zone	*zsu_zone;
159efd4c9b6SSteve Lawrence 	struct zsd_pset	*zsu_pset;
160efd4c9b6SSteve Lawrence 
161efd4c9b6SSteve Lawrence 	list_node_t	zsu_next;
162efd4c9b6SSteve Lawrence 
163efd4c9b6SSteve Lawrence 	zoneid_t	zsu_zoneid;
164efd4c9b6SSteve Lawrence 	boolean_t	zsu_found;	/* zone bound at end of interval */
165efd4c9b6SSteve Lawrence 	boolean_t	zsu_active;	/* zone was bound during interval */
166efd4c9b6SSteve Lawrence 	boolean_t	zsu_new;	/* zone newly bound in this interval */
167efd4c9b6SSteve Lawrence 	boolean_t	zsu_deleted;	/* zone was unbound in this interval */
168efd4c9b6SSteve Lawrence 	boolean_t	zsu_empty;	/* no procs in pset in this interval */
169efd4c9b6SSteve Lawrence 	time_t		zsu_start;	/* time when zone was found in pset */
170efd4c9b6SSteve Lawrence 	hrtime_t	zsu_hrstart;	/* time when zone  was found in pset */
171efd4c9b6SSteve Lawrence 	uint64_t	zsu_cpu_shares;
172efd4c9b6SSteve Lawrence 	uint_t		zsu_scheds;	/* schedulers found in this pass */
173efd4c9b6SSteve Lawrence 	timestruc_t	zsu_cpu_usage;	/* cpu time used */
174efd4c9b6SSteve Lawrence } zsd_pset_usage_t;
175efd4c9b6SSteve Lawrence 
176efd4c9b6SSteve Lawrence /* Used to store a pset's utilization */
177efd4c9b6SSteve Lawrence typedef struct zsd_pset {
178efd4c9b6SSteve Lawrence 	psetid_t	zsp_id;
179efd4c9b6SSteve Lawrence 	list_node_t	zsp_next;
180efd4c9b6SSteve Lawrence 	char		zsp_name[ZS_PSETNAME_MAX];
181efd4c9b6SSteve Lawrence 
182efd4c9b6SSteve Lawrence 	uint_t		zsp_cputype;	/* default, dedicated or shared */
183efd4c9b6SSteve Lawrence 	boolean_t	zsp_found;	/* pset found at end of interval */
184efd4c9b6SSteve Lawrence 	boolean_t	zsp_new;	/* pset new in this interval */
185efd4c9b6SSteve Lawrence 	boolean_t	zsp_deleted;	/* pset deleted in this interval */
186efd4c9b6SSteve Lawrence 	boolean_t	zsp_active;	/* pset existed during interval */
187efd4c9b6SSteve Lawrence 	boolean_t	zsp_empty;	/* no processes in pset */
188efd4c9b6SSteve Lawrence 	time_t		zsp_start;
189efd4c9b6SSteve Lawrence 	hrtime_t	zsp_hrstart;
190efd4c9b6SSteve Lawrence 
191efd4c9b6SSteve Lawrence 	uint64_t	zsp_online;	/* online cpus in interval */
192efd4c9b6SSteve Lawrence 	uint64_t	zsp_size;	/* size in this interval */
193efd4c9b6SSteve Lawrence 	uint64_t	zsp_min;	/* configured min in this interval */
194efd4c9b6SSteve Lawrence 	uint64_t	zsp_max;	/* configured max in this interval */
195efd4c9b6SSteve Lawrence 	int64_t		zsp_importance;	/* configured max in this interval */
196efd4c9b6SSteve Lawrence 
197efd4c9b6SSteve Lawrence 	uint_t		zsp_scheds;	/* scheds of processes found in pset */
198efd4c9b6SSteve Lawrence 	uint64_t	zsp_cpu_shares;	/* total shares in this interval */
199efd4c9b6SSteve Lawrence 
200efd4c9b6SSteve Lawrence 	timestruc_t	zsp_total_time;
201efd4c9b6SSteve Lawrence 	timestruc_t	zsp_usage_kern;
202efd4c9b6SSteve Lawrence 	timestruc_t	zsp_usage_zones;
203efd4c9b6SSteve Lawrence 
204efd4c9b6SSteve Lawrence 	/* Individual zone usages of pset */
205efd4c9b6SSteve Lawrence 	list_t		zsp_usage_list;
206efd4c9b6SSteve Lawrence 	int		zsp_nusage;
207efd4c9b6SSteve Lawrence 
208efd4c9b6SSteve Lawrence 	/* Summed kstat values from individual cpus in pset */
209efd4c9b6SSteve Lawrence 	timestruc_t	zsp_idle;
210efd4c9b6SSteve Lawrence 	timestruc_t	zsp_intr;
211efd4c9b6SSteve Lawrence 	timestruc_t	zsp_kern;
212efd4c9b6SSteve Lawrence 	timestruc_t	zsp_user;
213efd4c9b6SSteve Lawrence 
214efd4c9b6SSteve Lawrence } zsd_pset_t;
215efd4c9b6SSteve Lawrence 
216efd4c9b6SSteve Lawrence /* Used to track an individual cpu's utilization as reported by kstats */
217efd4c9b6SSteve Lawrence typedef struct zsd_cpu {
218efd4c9b6SSteve Lawrence 	processorid_t	zsc_id;
219efd4c9b6SSteve Lawrence 	list_node_t	zsc_next;
220efd4c9b6SSteve Lawrence 	psetid_t	zsc_psetid;
221efd4c9b6SSteve Lawrence 	psetid_t	zsc_psetid_prev;
222efd4c9b6SSteve Lawrence 	zsd_pset_t	*zsc_pset;
223efd4c9b6SSteve Lawrence 
224efd4c9b6SSteve Lawrence 	boolean_t	zsc_found;	/* cpu online in this interval */
225efd4c9b6SSteve Lawrence 	boolean_t	zsc_onlined;	/* cpu onlined during this interval */
226efd4c9b6SSteve Lawrence 	boolean_t	zsc_offlined;	/* cpu offlined during this interval */
227efd4c9b6SSteve Lawrence 	boolean_t	zsc_active;	/* cpu online during this interval */
228efd4c9b6SSteve Lawrence 	boolean_t	zsc_allocated;	/* True if cpu has ever been found */
229efd4c9b6SSteve Lawrence 
230efd4c9b6SSteve Lawrence 	/* kstats this interval */
231efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_idle;
232efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_intr;
233efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_kern;
234efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_user;
235efd4c9b6SSteve Lawrence 
236efd4c9b6SSteve Lawrence 	/* kstats in most recent interval */
237efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_idle_prev;
238efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_intr_prev;
239efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_kern_prev;
240efd4c9b6SSteve Lawrence 	uint64_t	zsc_nsec_user_prev;
241efd4c9b6SSteve Lawrence 
242efd4c9b6SSteve Lawrence 	/* Total kstat increases since zonestatd started reading kstats */
243efd4c9b6SSteve Lawrence 	timestruc_t	zsc_idle;
244efd4c9b6SSteve Lawrence 	timestruc_t	zsc_intr;
245efd4c9b6SSteve Lawrence 	timestruc_t	zsc_kern;
246efd4c9b6SSteve Lawrence 	timestruc_t	zsc_user;
247efd4c9b6SSteve Lawrence 
248efd4c9b6SSteve Lawrence } zsd_cpu_t;
249efd4c9b6SSteve Lawrence 
250efd4c9b6SSteve Lawrence /* Used to describe an individual zone and its utilization */
251efd4c9b6SSteve Lawrence typedef struct zsd_zone {
252efd4c9b6SSteve Lawrence 	zoneid_t	zsz_id;
253efd4c9b6SSteve Lawrence 	list_node_t	zsz_next;
254efd4c9b6SSteve Lawrence 	char		zsz_name[ZS_ZONENAME_MAX];
255efd4c9b6SSteve Lawrence 	uint_t		zsz_cputype;
256efd4c9b6SSteve Lawrence 	uint_t		zsz_iptype;
257efd4c9b6SSteve Lawrence 	time_t		zsz_start;
258efd4c9b6SSteve Lawrence 	hrtime_t	zsz_hrstart;
259efd4c9b6SSteve Lawrence 
260efd4c9b6SSteve Lawrence 	char		zsz_pool[ZS_POOLNAME_MAX];
261efd4c9b6SSteve Lawrence 	char		zsz_pset[ZS_PSETNAME_MAX];
262efd4c9b6SSteve Lawrence 	int		zsz_default_sched;
263efd4c9b6SSteve Lawrence 	/* These are deduced by inspecting processes */
264efd4c9b6SSteve Lawrence 	psetid_t	zsz_psetid;
265efd4c9b6SSteve Lawrence 	uint_t		zsz_scheds;
266efd4c9b6SSteve Lawrence 
267efd4c9b6SSteve Lawrence 	boolean_t	zsz_new;	/* zone booted during this interval */
268efd4c9b6SSteve Lawrence 	boolean_t	zsz_deleted;	/* halted during this interval */
269efd4c9b6SSteve Lawrence 	boolean_t	zsz_active;	/* running in this interval */
270efd4c9b6SSteve Lawrence 	boolean_t	zsz_empty;	/* no processes in this interval */
271efd4c9b6SSteve Lawrence 	boolean_t	zsz_gone;	/* not installed in this interval */
272efd4c9b6SSteve Lawrence 	boolean_t	zsz_found;	/* Running at end of this interval */
273efd4c9b6SSteve Lawrence 
274efd4c9b6SSteve Lawrence 	uint64_t	zsz_cpu_shares;
275efd4c9b6SSteve Lawrence 	uint64_t	zsz_cpu_cap;
276efd4c9b6SSteve Lawrence 	uint64_t	zsz_ram_cap;
277efd4c9b6SSteve Lawrence 	uint64_t	zsz_locked_cap;
278efd4c9b6SSteve Lawrence 	uint64_t	zsz_vm_cap;
279efd4c9b6SSteve Lawrence 
280efd4c9b6SSteve Lawrence 	uint64_t	zsz_cpus_online;
281efd4c9b6SSteve Lawrence 	timestruc_t	zsz_cpu_usage;	/* cpu time of cpu cap */
282efd4c9b6SSteve Lawrence 	timestruc_t	zsz_cap_time;	/* cpu time of cpu cap */
283efd4c9b6SSteve Lawrence 	timestruc_t	zsz_share_time; /* cpu time of share of cpu */
284efd4c9b6SSteve Lawrence 	timestruc_t	zsz_pset_time;  /* time of all psets zone is bound to */
285efd4c9b6SSteve Lawrence 
286efd4c9b6SSteve Lawrence 	uint64_t	zsz_usage_ram;
287efd4c9b6SSteve Lawrence 	uint64_t	zsz_usage_locked;
288efd4c9b6SSteve Lawrence 	uint64_t	zsz_usage_vm;
289efd4c9b6SSteve Lawrence 
290efd4c9b6SSteve Lawrence 	uint64_t	zsz_processes_cap;
291efd4c9b6SSteve Lawrence 	uint64_t	zsz_lwps_cap;
292efd4c9b6SSteve Lawrence 	uint64_t	zsz_shm_cap;
293efd4c9b6SSteve Lawrence 	uint64_t	zsz_shmids_cap;
294efd4c9b6SSteve Lawrence 	uint64_t	zsz_semids_cap;
295efd4c9b6SSteve Lawrence 	uint64_t	zsz_msgids_cap;
296efd4c9b6SSteve Lawrence 	uint64_t	zsz_lofi_cap;
297efd4c9b6SSteve Lawrence 
298efd4c9b6SSteve Lawrence 	uint64_t	zsz_processes;
299efd4c9b6SSteve Lawrence 	uint64_t	zsz_lwps;
300efd4c9b6SSteve Lawrence 	uint64_t	zsz_shm;
301efd4c9b6SSteve Lawrence 	uint64_t	zsz_shmids;
302efd4c9b6SSteve Lawrence 	uint64_t	zsz_semids;
303efd4c9b6SSteve Lawrence 	uint64_t	zsz_msgids;
304efd4c9b6SSteve Lawrence 	uint64_t	zsz_lofi;
305efd4c9b6SSteve Lawrence 
306efd4c9b6SSteve Lawrence } zsd_zone_t;
307efd4c9b6SSteve Lawrence 
308efd4c9b6SSteve Lawrence /*
309efd4c9b6SSteve Lawrence  * Used to track the cpu usage of an individual processes.
310efd4c9b6SSteve Lawrence  *
311efd4c9b6SSteve Lawrence  * zonestatd sweeps /proc each interval and charges the cpu usage of processes.
312efd4c9b6SSteve Lawrence  * to their zone.  As processes exit, their extended accounting records are
313efd4c9b6SSteve Lawrence  * read and the difference of their total and known usage is charged to their
314efd4c9b6SSteve Lawrence  * zone.
315efd4c9b6SSteve Lawrence  *
316efd4c9b6SSteve Lawrence  * If a process is never seen in /proc, the total usage on its extended
317efd4c9b6SSteve Lawrence  * accounting record will be charged to its zone.
318efd4c9b6SSteve Lawrence  */
319efd4c9b6SSteve Lawrence typedef struct zsd_proc {
320efd4c9b6SSteve Lawrence 	list_node_t	zspr_next;
321efd4c9b6SSteve Lawrence 	pid_t		zspr_ppid;
322efd4c9b6SSteve Lawrence 	psetid_t	zspr_psetid;
323efd4c9b6SSteve Lawrence 	zoneid_t	zspr_zoneid;
324efd4c9b6SSteve Lawrence 	int		zspr_sched;
325efd4c9b6SSteve Lawrence 	timestruc_t	zspr_usage;
326efd4c9b6SSteve Lawrence } zsd_proc_t;
327efd4c9b6SSteve Lawrence 
328efd4c9b6SSteve Lawrence /* Used to track the overall resource usage of the system */
329efd4c9b6SSteve Lawrence typedef struct zsd_system {
330efd4c9b6SSteve Lawrence 
331efd4c9b6SSteve Lawrence 	uint64_t zss_ram_total;
332efd4c9b6SSteve Lawrence 	uint64_t zss_ram_kern;
333efd4c9b6SSteve Lawrence 	uint64_t zss_ram_zones;
334efd4c9b6SSteve Lawrence 
335efd4c9b6SSteve Lawrence 	uint64_t zss_locked_kern;
336efd4c9b6SSteve Lawrence 	uint64_t zss_locked_zones;
337efd4c9b6SSteve Lawrence 
338efd4c9b6SSteve Lawrence 	uint64_t zss_vm_total;
339efd4c9b6SSteve Lawrence 	uint64_t zss_vm_kern;
340efd4c9b6SSteve Lawrence 	uint64_t zss_vm_zones;
341efd4c9b6SSteve Lawrence 
342efd4c9b6SSteve Lawrence 	uint64_t zss_swap_total;
343efd4c9b6SSteve Lawrence 	uint64_t zss_swap_used;
344efd4c9b6SSteve Lawrence 
345efd4c9b6SSteve Lawrence 	timestruc_t zss_idle;
346efd4c9b6SSteve Lawrence 	timestruc_t zss_intr;
347efd4c9b6SSteve Lawrence 	timestruc_t zss_kern;
348efd4c9b6SSteve Lawrence 	timestruc_t zss_user;
349efd4c9b6SSteve Lawrence 
350efd4c9b6SSteve Lawrence 	timestruc_t zss_cpu_total_time;
351efd4c9b6SSteve Lawrence 	timestruc_t zss_cpu_usage_kern;
352efd4c9b6SSteve Lawrence 	timestruc_t zss_cpu_usage_zones;
353efd4c9b6SSteve Lawrence 
354efd4c9b6SSteve Lawrence 	uint64_t zss_maxpid;
355efd4c9b6SSteve Lawrence 	uint64_t zss_processes_max;
356efd4c9b6SSteve Lawrence 	uint64_t zss_lwps_max;
357efd4c9b6SSteve Lawrence 	uint64_t zss_shm_max;
358efd4c9b6SSteve Lawrence 	uint64_t zss_shmids_max;
359efd4c9b6SSteve Lawrence 	uint64_t zss_semids_max;
360efd4c9b6SSteve Lawrence 	uint64_t zss_msgids_max;
361efd4c9b6SSteve Lawrence 	uint64_t zss_lofi_max;
362efd4c9b6SSteve Lawrence 
363efd4c9b6SSteve Lawrence 	uint64_t zss_processes;
364efd4c9b6SSteve Lawrence 	uint64_t zss_lwps;
365efd4c9b6SSteve Lawrence 	uint64_t zss_shm;
366efd4c9b6SSteve Lawrence 	uint64_t zss_shmids;
367efd4c9b6SSteve Lawrence 	uint64_t zss_semids;
368efd4c9b6SSteve Lawrence 	uint64_t zss_msgids;
369efd4c9b6SSteve Lawrence 	uint64_t zss_lofi;
370efd4c9b6SSteve Lawrence 
371efd4c9b6SSteve Lawrence 	uint64_t zss_ncpus;
372efd4c9b6SSteve Lawrence 	uint64_t zss_ncpus_online;
373efd4c9b6SSteve Lawrence 
374efd4c9b6SSteve Lawrence } zsd_system_t;
375efd4c9b6SSteve Lawrence 
376efd4c9b6SSteve Lawrence /*
377efd4c9b6SSteve Lawrence  * A dumping ground for various information and structures used to compute
378efd4c9b6SSteve Lawrence  * utilization.
379efd4c9b6SSteve Lawrence  *
380efd4c9b6SSteve Lawrence  * This structure is used to track the system while clients are connected.
381efd4c9b6SSteve Lawrence  * When The first client connects, a zsd_ctl is allocated and configured by
382efd4c9b6SSteve Lawrence  * zsd_open().  When all clients disconnect, the zsd_ctl is closed.
383efd4c9b6SSteve Lawrence  */
384efd4c9b6SSteve Lawrence typedef struct zsd_ctl {
385efd4c9b6SSteve Lawrence 	kstat_ctl_t	*zsctl_kstat_ctl;
386efd4c9b6SSteve Lawrence 
387efd4c9b6SSteve Lawrence 	/* To track extended accounting */
388efd4c9b6SSteve Lawrence 	int		zsctl_proc_fd;		/* Log currently being used */
389efd4c9b6SSteve Lawrence 	ea_file_t	zsctl_proc_eaf;
390efd4c9b6SSteve Lawrence 	struct stat64	zsctl_proc_stat;
391efd4c9b6SSteve Lawrence 	int		zsctl_proc_open;
392efd4c9b6SSteve Lawrence 	int		zsctl_proc_fd_next;	/* Log file to use next */
393efd4c9b6SSteve Lawrence 	ea_file_t	zsctl_proc_eaf_next;
394efd4c9b6SSteve Lawrence 	struct stat64	zsctl_proc_stat_next;
395efd4c9b6SSteve Lawrence 	int		zsctl_proc_open_next;
396efd4c9b6SSteve Lawrence 
397efd4c9b6SSteve Lawrence 	/* pool configuration handle */
398efd4c9b6SSteve Lawrence 	pool_conf_t	*zsctl_pool_conf;
399efd4c9b6SSteve Lawrence 	int		zsctl_pool_status;
400efd4c9b6SSteve Lawrence 	int		zsctl_pool_changed;
401efd4c9b6SSteve Lawrence 
402efd4c9b6SSteve Lawrence 	/* The above usage tacking structures */
403efd4c9b6SSteve Lawrence 	zsd_system_t	*zsctl_system;
404efd4c9b6SSteve Lawrence 	list_t		zsctl_zones;
405efd4c9b6SSteve Lawrence 	list_t		zsctl_psets;
406efd4c9b6SSteve Lawrence 	list_t		zsctl_cpus;
407efd4c9b6SSteve Lawrence 	zsd_cpu_t	*zsctl_cpu_array;
408efd4c9b6SSteve Lawrence 	zsd_proc_t	*zsctl_proc_array;
409efd4c9b6SSteve Lawrence 
410efd4c9b6SSteve Lawrence 	/* Various system info */
411efd4c9b6SSteve Lawrence 	uint64_t	zsctl_maxcpuid;
412efd4c9b6SSteve Lawrence 	uint64_t	zsctl_maxproc;
413efd4c9b6SSteve Lawrence 	uint64_t	zsctl_kern_bits;
414efd4c9b6SSteve Lawrence 	uint64_t	zsctl_pagesize;
415efd4c9b6SSteve Lawrence 
416efd4c9b6SSteve Lawrence 	/* Used to track time available under a cpu cap. */
417efd4c9b6SSteve Lawrence 	uint64_t	zsctl_hrtime;
418efd4c9b6SSteve Lawrence 	uint64_t	zsctl_hrtime_prev;
419efd4c9b6SSteve Lawrence 	timestruc_t	zsctl_hrtime_total;
420efd4c9b6SSteve Lawrence 
421efd4c9b6SSteve Lawrence 	struct timeval	zsctl_timeofday;
422efd4c9b6SSteve Lawrence 
423efd4c9b6SSteve Lawrence 	/* Caches for arrays allocated for use by various system calls */
424efd4c9b6SSteve Lawrence 	psetid_t	*zsctl_pset_cache;
425efd4c9b6SSteve Lawrence 	uint_t		zsctl_pset_ncache;
426efd4c9b6SSteve Lawrence 	processorid_t	*zsctl_cpu_cache;
427efd4c9b6SSteve Lawrence 	uint_t		zsctl_cpu_ncache;
428efd4c9b6SSteve Lawrence 	zoneid_t	*zsctl_zone_cache;
429efd4c9b6SSteve Lawrence 	uint_t		zsctl_zone_ncache;
430efd4c9b6SSteve Lawrence 	struct swaptable *zsctl_swap_cache;
431efd4c9b6SSteve Lawrence 	uint64_t	zsctl_swap_cache_size;
432efd4c9b6SSteve Lawrence 	uint64_t	zsctl_swap_cache_num;
433efd4c9b6SSteve Lawrence 	zsd_vmusage64_t	*zsctl_vmusage_cache;
434efd4c9b6SSteve Lawrence 	uint64_t	zsctl_vmusage_cache_num;
435efd4c9b6SSteve Lawrence 
436efd4c9b6SSteve Lawrence 	/* Info about procfs for scanning /proc */
437efd4c9b6SSteve Lawrence 	pool_value_t	*zsctl_pool_vals[3];
438efd4c9b6SSteve Lawrence 
439efd4c9b6SSteve Lawrence 	/* Counts on tracked entities */
440efd4c9b6SSteve Lawrence 	uint_t		zsctl_nzones;
441efd4c9b6SSteve Lawrence 	uint_t		zsctl_npsets;
442efd4c9b6SSteve Lawrence 	uint_t		zsctl_npset_usages;
443efd4c9b6SSteve Lawrence } zsd_ctl_t;
444efd4c9b6SSteve Lawrence 
445efd4c9b6SSteve Lawrence zsd_ctl_t		*g_ctl;
446efd4c9b6SSteve Lawrence boolean_t		g_open;		/* True if g_ctl is open */
447efd4c9b6SSteve Lawrence int			g_hasclient;	/* True if any clients are connected */
448efd4c9b6SSteve Lawrence 
449efd4c9b6SSteve Lawrence /*
450efd4c9b6SSteve Lawrence  * The usage cache is updated by the stat_thread, and copied to clients by
451efd4c9b6SSteve Lawrence  * the zsd_stat_server.  Mutex and cond are to synchronize between the
452efd4c9b6SSteve Lawrence  * stat_thread and the stat_server.
453efd4c9b6SSteve Lawrence  */
454efd4c9b6SSteve Lawrence zs_usage_cache_t	*g_usage_cache;
455efd4c9b6SSteve Lawrence mutex_t			g_usage_cache_lock;
456efd4c9b6SSteve Lawrence cond_t			g_usage_cache_kick;
457efd4c9b6SSteve Lawrence uint_t			g_usage_cache_kickers;
458efd4c9b6SSteve Lawrence cond_t			g_usage_cache_wait;
459efd4c9b6SSteve Lawrence char			*g_usage_cache_buf;
460efd4c9b6SSteve Lawrence uint_t			g_usage_cache_bufsz;
461efd4c9b6SSteve Lawrence uint64_t		g_gen_next;
462efd4c9b6SSteve Lawrence 
463efd4c9b6SSteve Lawrence /* fds of door servers */
464efd4c9b6SSteve Lawrence int			g_server_door;
465efd4c9b6SSteve Lawrence int			g_stat_door;
466efd4c9b6SSteve Lawrence 
467efd4c9b6SSteve Lawrence /*
468efd4c9b6SSteve Lawrence  * Starting and current time.  Used to throttle memory calculation, and to
469efd4c9b6SSteve Lawrence  * mark new zones and psets with their boot and creation time.
470efd4c9b6SSteve Lawrence  */
471efd4c9b6SSteve Lawrence time_t			g_now;
472efd4c9b6SSteve Lawrence time_t			g_start;
473efd4c9b6SSteve Lawrence hrtime_t		g_hrnow;
474efd4c9b6SSteve Lawrence hrtime_t		g_hrstart;
475efd4c9b6SSteve Lawrence uint64_t		g_interval;
476efd4c9b6SSteve Lawrence 
477efd4c9b6SSteve Lawrence /*
478efd4c9b6SSteve Lawrence  * main() thread.
479efd4c9b6SSteve Lawrence  */
480efd4c9b6SSteve Lawrence thread_t		g_main;
481efd4c9b6SSteve Lawrence 
482efd4c9b6SSteve Lawrence /* PRINTFLIKE1 */
483efd4c9b6SSteve Lawrence static void
zsd_warn(const char * fmt,...)484efd4c9b6SSteve Lawrence zsd_warn(const char *fmt, ...)
485efd4c9b6SSteve Lawrence {
486efd4c9b6SSteve Lawrence 	va_list alist;
487efd4c9b6SSteve Lawrence 
488efd4c9b6SSteve Lawrence 	va_start(alist, fmt);
489efd4c9b6SSteve Lawrence 
490efd4c9b6SSteve Lawrence 	(void) fprintf(stderr, gettext("zonestat: Warning: "));
491efd4c9b6SSteve Lawrence 	(void) vfprintf(stderr, fmt, alist);
492efd4c9b6SSteve Lawrence 	(void) fprintf(stderr, "\n");
493efd4c9b6SSteve Lawrence 	va_end(alist);
494efd4c9b6SSteve Lawrence }
495efd4c9b6SSteve Lawrence 
496efd4c9b6SSteve Lawrence /* PRINTFLIKE1 */
497efd4c9b6SSteve Lawrence static void
zsd_error(const char * fmt,...)498efd4c9b6SSteve Lawrence zsd_error(const char *fmt, ...)
499efd4c9b6SSteve Lawrence {
500efd4c9b6SSteve Lawrence 	va_list alist;
501efd4c9b6SSteve Lawrence 
502efd4c9b6SSteve Lawrence 	va_start(alist, fmt);
503efd4c9b6SSteve Lawrence 
504efd4c9b6SSteve Lawrence 	(void) fprintf(stderr, gettext("zonestat: Error: "));
505efd4c9b6SSteve Lawrence 	(void) vfprintf(stderr, fmt, alist);
506efd4c9b6SSteve Lawrence 	(void) fprintf(stderr, "\n");
507efd4c9b6SSteve Lawrence 	va_end(alist);
508efd4c9b6SSteve Lawrence 	exit(1);
509efd4c9b6SSteve Lawrence }
510efd4c9b6SSteve Lawrence 
511efd4c9b6SSteve Lawrence /* Turns on extended accounting if not configured externally */
512efd4c9b6SSteve Lawrence int
zsd_enable_cpu_stats()513efd4c9b6SSteve Lawrence zsd_enable_cpu_stats()
514efd4c9b6SSteve Lawrence {
515efd4c9b6SSteve Lawrence 	char *path = ZONESTAT_EXACCT_FILE;
516efd4c9b6SSteve Lawrence 	char oldfile[MAXPATHLEN];
517efd4c9b6SSteve Lawrence 	int ret, state = AC_ON;
518efd4c9b6SSteve Lawrence 	ac_res_t res[6];
519efd4c9b6SSteve Lawrence 
520efd4c9b6SSteve Lawrence 	/*
521efd4c9b6SSteve Lawrence 	 * Start a new accounting file  if accounting not configured
522efd4c9b6SSteve Lawrence 	 * externally.
523efd4c9b6SSteve Lawrence 	 */
524efd4c9b6SSteve Lawrence 
525efd4c9b6SSteve Lawrence 	res[0].ar_id = AC_PROC_PID;
526efd4c9b6SSteve Lawrence 	res[0].ar_state = AC_ON;
527efd4c9b6SSteve Lawrence 	res[1].ar_id = AC_PROC_ANCPID;
528efd4c9b6SSteve Lawrence 	res[1].ar_state = AC_ON;
529efd4c9b6SSteve Lawrence 	res[2].ar_id = AC_PROC_CPU;
530efd4c9b6SSteve Lawrence 	res[2].ar_state = AC_ON;
531efd4c9b6SSteve Lawrence 	res[3].ar_id = AC_PROC_TIME;
532efd4c9b6SSteve Lawrence 	res[3].ar_state = AC_ON;
533efd4c9b6SSteve Lawrence 	res[4].ar_id = AC_PROC_ZONENAME;
534efd4c9b6SSteve Lawrence 	res[4].ar_state = AC_ON;
535efd4c9b6SSteve Lawrence 	res[5].ar_id = AC_NONE;
536efd4c9b6SSteve Lawrence 	res[5].ar_state = AC_ON;
537efd4c9b6SSteve Lawrence 	if (acctctl(AC_PROC | AC_RES_SET, res, sizeof (res)) != 0) {
538efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to set accounting resources"));
539efd4c9b6SSteve Lawrence 		return (-1);
540efd4c9b6SSteve Lawrence 	}
541efd4c9b6SSteve Lawrence 	/* Only set accounting file if none is configured */
542efd4c9b6SSteve Lawrence 	ret = acctctl(AC_PROC | AC_FILE_GET, oldfile, sizeof (oldfile));
543efd4c9b6SSteve Lawrence 	if (ret < 0) {
544efd4c9b6SSteve Lawrence 
545efd4c9b6SSteve Lawrence 		(void) unlink(path);
546efd4c9b6SSteve Lawrence 		if (acctctl(AC_PROC | AC_FILE_SET, path, strlen(path) + 1)
547efd4c9b6SSteve Lawrence 		    == -1) {
548efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Unable to set accounting file"));
549efd4c9b6SSteve Lawrence 			return (-1);
550efd4c9b6SSteve Lawrence 		}
551efd4c9b6SSteve Lawrence 	}
552efd4c9b6SSteve Lawrence 	if (acctctl(AC_PROC | AC_STATE_SET, &state, sizeof (state)) == -1) {
553efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to enable accounting"));
554efd4c9b6SSteve Lawrence 		return (-1);
555efd4c9b6SSteve Lawrence 	}
556efd4c9b6SSteve Lawrence 	return (0);
557efd4c9b6SSteve Lawrence }
558efd4c9b6SSteve Lawrence 
559efd4c9b6SSteve Lawrence /* Turns off extended accounting if not configured externally */
560efd4c9b6SSteve Lawrence int
zsd_disable_cpu_stats()561efd4c9b6SSteve Lawrence zsd_disable_cpu_stats()
562efd4c9b6SSteve Lawrence {
563efd4c9b6SSteve Lawrence 	char *path = ZONESTAT_EXACCT_FILE;
564efd4c9b6SSteve Lawrence 	int ret, state = AC_OFF;
565efd4c9b6SSteve Lawrence 	ac_res_t res[6];
566efd4c9b6SSteve Lawrence 	char oldfile[MAXPATHLEN];
567efd4c9b6SSteve Lawrence 
568efd4c9b6SSteve Lawrence 	/* If accounting file is externally configured, leave it alone */
569efd4c9b6SSteve Lawrence 	ret = acctctl(AC_PROC | AC_FILE_GET, oldfile, sizeof (oldfile));
570efd4c9b6SSteve Lawrence 	if (ret == 0 && strcmp(oldfile, path) != 0)
571efd4c9b6SSteve Lawrence 		return (0);
572efd4c9b6SSteve Lawrence 
573efd4c9b6SSteve Lawrence 	res[0].ar_id = AC_PROC_PID;
574efd4c9b6SSteve Lawrence 	res[0].ar_state = AC_OFF;
575efd4c9b6SSteve Lawrence 	res[1].ar_id = AC_PROC_ANCPID;
576efd4c9b6SSteve Lawrence 	res[1].ar_state = AC_OFF;
577efd4c9b6SSteve Lawrence 	res[2].ar_id = AC_PROC_CPU;
578efd4c9b6SSteve Lawrence 	res[2].ar_state = AC_OFF;
579efd4c9b6SSteve Lawrence 	res[3].ar_id = AC_PROC_TIME;
580efd4c9b6SSteve Lawrence 	res[3].ar_state = AC_OFF;
581efd4c9b6SSteve Lawrence 	res[4].ar_id = AC_PROC_ZONENAME;
582efd4c9b6SSteve Lawrence 	res[4].ar_state = AC_OFF;
583efd4c9b6SSteve Lawrence 	res[5].ar_id = AC_NONE;
584efd4c9b6SSteve Lawrence 	res[5].ar_state = AC_OFF;
585efd4c9b6SSteve Lawrence 	if (acctctl(AC_PROC | AC_RES_SET, res, sizeof (res)) != 0) {
586efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to clear accounting resources"));
587efd4c9b6SSteve Lawrence 		return (-1);
588efd4c9b6SSteve Lawrence 	}
589efd4c9b6SSteve Lawrence 	if (acctctl(AC_PROC | AC_FILE_SET, NULL, 0) == -1) {
590efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to clear accounting file"));
591efd4c9b6SSteve Lawrence 		return (-1);
592efd4c9b6SSteve Lawrence 	}
593efd4c9b6SSteve Lawrence 	if (acctctl(AC_PROC | AC_STATE_SET, &state, sizeof (state)) == -1) {
594efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to diable accounting"));
595efd4c9b6SSteve Lawrence 		return (-1);
596efd4c9b6SSteve Lawrence 	}
597efd4c9b6SSteve Lawrence 
598efd4c9b6SSteve Lawrence 	(void) unlink(path);
599efd4c9b6SSteve Lawrence 	return (0);
600efd4c9b6SSteve Lawrence }
601efd4c9b6SSteve Lawrence 
602efd4c9b6SSteve Lawrence /*
603efd4c9b6SSteve Lawrence  * If not configured externally, deletes the current extended accounting file
604efd4c9b6SSteve Lawrence  * and starts a new one.
605efd4c9b6SSteve Lawrence  *
606efd4c9b6SSteve Lawrence  * Since the stat_thread holds an open handle to the accounting file, it will
607efd4c9b6SSteve Lawrence  * read all remaining entries from the old file before switching to
608efd4c9b6SSteve Lawrence  * read the new one.
609efd4c9b6SSteve Lawrence  */
610efd4c9b6SSteve Lawrence int
zsd_roll_exacct(void)611efd4c9b6SSteve Lawrence zsd_roll_exacct(void)
612efd4c9b6SSteve Lawrence {
613efd4c9b6SSteve Lawrence 	int ret;
614efd4c9b6SSteve Lawrence 	char *path = ZONESTAT_EXACCT_FILE;
615efd4c9b6SSteve Lawrence 	char oldfile[MAXPATHLEN];
616efd4c9b6SSteve Lawrence 
617efd4c9b6SSteve Lawrence 	/* If accounting file is externally configured, leave it alone */
618efd4c9b6SSteve Lawrence 	ret = acctctl(AC_PROC | AC_FILE_GET, oldfile, sizeof (oldfile));
619efd4c9b6SSteve Lawrence 	if (ret == 0 && strcmp(oldfile, path) != 0)
620efd4c9b6SSteve Lawrence 		return (0);
621efd4c9b6SSteve Lawrence 
622efd4c9b6SSteve Lawrence 	if (unlink(path) != 0)
623efd4c9b6SSteve Lawrence 		/* Roll it next time */
624efd4c9b6SSteve Lawrence 		return (0);
625efd4c9b6SSteve Lawrence 
626efd4c9b6SSteve Lawrence 	if (acctctl(AC_PROC | AC_FILE_SET, path, strlen(path) + 1) == -1) {
627efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to set accounting file"));
628efd4c9b6SSteve Lawrence 		return (-1);
629efd4c9b6SSteve Lawrence 	}
630efd4c9b6SSteve Lawrence 	return (0);
631efd4c9b6SSteve Lawrence }
632efd4c9b6SSteve Lawrence 
633efd4c9b6SSteve Lawrence /* Contract stuff for zone_enter() */
634efd4c9b6SSteve Lawrence int
init_template(void)635efd4c9b6SSteve Lawrence init_template(void)
636efd4c9b6SSteve Lawrence {
637efd4c9b6SSteve Lawrence 	int fd;
638efd4c9b6SSteve Lawrence 	int err = 0;
639efd4c9b6SSteve Lawrence 
640efd4c9b6SSteve Lawrence 	fd = open64(CTFS_ROOT "/process/template", O_RDWR);
641efd4c9b6SSteve Lawrence 	if (fd == -1)
642efd4c9b6SSteve Lawrence 		return (-1);
643efd4c9b6SSteve Lawrence 
644efd4c9b6SSteve Lawrence 	/*
645efd4c9b6SSteve Lawrence 	 * For now, zoneadmd doesn't do anything with the contract.
646efd4c9b6SSteve Lawrence 	 * Deliver no events, don't inherit, and allow it to be orphaned.
647efd4c9b6SSteve Lawrence 	 */
648efd4c9b6SSteve Lawrence 	err |= ct_tmpl_set_critical(fd, 0);
649efd4c9b6SSteve Lawrence 	err |= ct_tmpl_set_informative(fd, 0);
650efd4c9b6SSteve Lawrence 	err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
651efd4c9b6SSteve Lawrence 	err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
652efd4c9b6SSteve Lawrence 	if (err || ct_tmpl_activate(fd)) {
653efd4c9b6SSteve Lawrence 		(void) close(fd);
654efd4c9b6SSteve Lawrence 		return (-1);
655efd4c9b6SSteve Lawrence 	}
656efd4c9b6SSteve Lawrence 
657efd4c9b6SSteve Lawrence 	return (fd);
658efd4c9b6SSteve Lawrence }
659efd4c9b6SSteve Lawrence 
660efd4c9b6SSteve Lawrence /*
661efd4c9b6SSteve Lawrence  * Contract stuff for zone_enter()
662efd4c9b6SSteve Lawrence  */
663efd4c9b6SSteve Lawrence int
contract_latest(ctid_t * id)664efd4c9b6SSteve Lawrence contract_latest(ctid_t *id)
665efd4c9b6SSteve Lawrence {
666efd4c9b6SSteve Lawrence 	int cfd, r;
667efd4c9b6SSteve Lawrence 	ct_stathdl_t st;
668efd4c9b6SSteve Lawrence 	ctid_t result;
669efd4c9b6SSteve Lawrence 
670efd4c9b6SSteve Lawrence 	if ((cfd = open64(CTFS_ROOT "/process/latest", O_RDONLY)) == -1)
671efd4c9b6SSteve Lawrence 		return (errno);
672efd4c9b6SSteve Lawrence 
673efd4c9b6SSteve Lawrence 	if ((r = ct_status_read(cfd, CTD_COMMON, &st)) != 0) {
674efd4c9b6SSteve Lawrence 		(void) close(cfd);
675efd4c9b6SSteve Lawrence 		return (r);
676efd4c9b6SSteve Lawrence 	}
677efd4c9b6SSteve Lawrence 
678efd4c9b6SSteve Lawrence 	result = ct_status_get_id(st);
679efd4c9b6SSteve Lawrence 	ct_status_free(st);
680efd4c9b6SSteve Lawrence 	(void) close(cfd);
681efd4c9b6SSteve Lawrence 
682efd4c9b6SSteve Lawrence 	*id = result;
683efd4c9b6SSteve Lawrence 	return (0);
684efd4c9b6SSteve Lawrence }
685efd4c9b6SSteve Lawrence 
686efd4c9b6SSteve Lawrence static int
close_on_exec(int fd)687efd4c9b6SSteve Lawrence close_on_exec(int fd)
688efd4c9b6SSteve Lawrence {
689efd4c9b6SSteve Lawrence 	int flags = fcntl(fd, F_GETFD, 0);
690efd4c9b6SSteve Lawrence 	if ((flags != -1) && (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1))
691efd4c9b6SSteve Lawrence 		return (0);
692efd4c9b6SSteve Lawrence 	return (-1);
693efd4c9b6SSteve Lawrence }
694efd4c9b6SSteve Lawrence 
695efd4c9b6SSteve Lawrence int
contract_open(ctid_t ctid,const char * type,const char * file,int oflag)696efd4c9b6SSteve Lawrence contract_open(ctid_t ctid, const char *type, const char *file, int oflag)
697efd4c9b6SSteve Lawrence {
698efd4c9b6SSteve Lawrence 	char path[PATH_MAX];
699efd4c9b6SSteve Lawrence 	int n, fd;
700efd4c9b6SSteve Lawrence 
701efd4c9b6SSteve Lawrence 	if (type == NULL)
702efd4c9b6SSteve Lawrence 		type = "all";
703efd4c9b6SSteve Lawrence 
704efd4c9b6SSteve Lawrence 	n = snprintf(path, PATH_MAX, CTFS_ROOT "/%s/%ld/%s", type, ctid, file);
705efd4c9b6SSteve Lawrence 	if (n >= sizeof (path)) {
706efd4c9b6SSteve Lawrence 		errno = ENAMETOOLONG;
707efd4c9b6SSteve Lawrence 		return (-1);
708efd4c9b6SSteve Lawrence 	}
709efd4c9b6SSteve Lawrence 
710efd4c9b6SSteve Lawrence 	fd = open64(path, oflag);
711efd4c9b6SSteve Lawrence 	if (fd != -1) {
712efd4c9b6SSteve Lawrence 		if (close_on_exec(fd) == -1) {
713efd4c9b6SSteve Lawrence 			int err = errno;
714efd4c9b6SSteve Lawrence 			(void) close(fd);
715efd4c9b6SSteve Lawrence 			errno = err;
716efd4c9b6SSteve Lawrence 			return (-1);
717efd4c9b6SSteve Lawrence 		}
718efd4c9b6SSteve Lawrence 	}
719efd4c9b6SSteve Lawrence 	return (fd);
720efd4c9b6SSteve Lawrence }
721efd4c9b6SSteve Lawrence 
722efd4c9b6SSteve Lawrence int
contract_abandon_id(ctid_t ctid)723efd4c9b6SSteve Lawrence contract_abandon_id(ctid_t ctid)
724efd4c9b6SSteve Lawrence {
725efd4c9b6SSteve Lawrence 	int fd, err;
726efd4c9b6SSteve Lawrence 
727efd4c9b6SSteve Lawrence 	fd = contract_open(ctid, "all", "ctl", O_WRONLY);
728efd4c9b6SSteve Lawrence 	if (fd == -1)
729efd4c9b6SSteve Lawrence 		return (errno);
730efd4c9b6SSteve Lawrence 
731efd4c9b6SSteve Lawrence 	err = ct_ctl_abandon(fd);
732efd4c9b6SSteve Lawrence 	(void) close(fd);
733efd4c9b6SSteve Lawrence 
734efd4c9b6SSteve Lawrence 	return (err);
735efd4c9b6SSteve Lawrence }
736efd4c9b6SSteve Lawrence /*
737efd4c9b6SSteve Lawrence  * Attach the zsd_server to a zone.  Called for each zone when zonestatd
738efd4c9b6SSteve Lawrence  * starts, and for each newly booted zone when zoneadmd contacts the zsd_server
739efd4c9b6SSteve Lawrence  *
740efd4c9b6SSteve Lawrence  * Zone_enter is used to avoid reaching into zone to fattach door.
741efd4c9b6SSteve Lawrence  */
742efd4c9b6SSteve Lawrence static void
zsd_fattach_zone(zoneid_t zid,int door,boolean_t detach_only)743efd4c9b6SSteve Lawrence zsd_fattach_zone(zoneid_t zid, int door, boolean_t detach_only)
744efd4c9b6SSteve Lawrence {
745efd4c9b6SSteve Lawrence 	char *path = ZS_DOOR_PATH;
746efd4c9b6SSteve Lawrence 	int fd, pid, stat, tmpl_fd;
747efd4c9b6SSteve Lawrence 	ctid_t ct;
748efd4c9b6SSteve Lawrence 
749efd4c9b6SSteve Lawrence 	if ((tmpl_fd = init_template()) == -1) {
750efd4c9b6SSteve Lawrence 		zsd_warn("Unable to init template");
751efd4c9b6SSteve Lawrence 		return;
752efd4c9b6SSteve Lawrence 	}
753efd4c9b6SSteve Lawrence 
754efd4c9b6SSteve Lawrence 	pid = forkx(0);
755efd4c9b6SSteve Lawrence 	if (pid < 0) {
756efd4c9b6SSteve Lawrence 		(void) ct_tmpl_clear(tmpl_fd);
757efd4c9b6SSteve Lawrence 		zsd_warn(gettext(
758efd4c9b6SSteve Lawrence 		    "Unable to fork to add zonestat to zoneid %d\n"), zid);
759efd4c9b6SSteve Lawrence 		return;
760efd4c9b6SSteve Lawrence 	}
761efd4c9b6SSteve Lawrence 
762efd4c9b6SSteve Lawrence 	if (pid == 0) {
763efd4c9b6SSteve Lawrence 		(void) ct_tmpl_clear(tmpl_fd);
764efd4c9b6SSteve Lawrence 		(void) close(tmpl_fd);
765efd4c9b6SSteve Lawrence 		if (zid != 0 && zone_enter(zid) != 0) {
766efd4c9b6SSteve Lawrence 			if (errno == EINVAL) {
767efd4c9b6SSteve Lawrence 				_exit(0);
768efd4c9b6SSteve Lawrence 			}
769efd4c9b6SSteve Lawrence 			_exit(1);
770efd4c9b6SSteve Lawrence 		}
771efd4c9b6SSteve Lawrence 		(void) fdetach(path);
772efd4c9b6SSteve Lawrence 		(void) unlink(path);
773efd4c9b6SSteve Lawrence 		if (detach_only)
774efd4c9b6SSteve Lawrence 			_exit(0);
775efd4c9b6SSteve Lawrence 		fd = open(path, O_CREAT|O_RDWR, 0644);
776efd4c9b6SSteve Lawrence 		if (fd < 0)
777efd4c9b6SSteve Lawrence 			_exit(2);
778efd4c9b6SSteve Lawrence 		if (fattach(door, path) != 0)
779efd4c9b6SSteve Lawrence 			_exit(3);
780efd4c9b6SSteve Lawrence 		_exit(0);
781efd4c9b6SSteve Lawrence 	}
782efd4c9b6SSteve Lawrence 	if (contract_latest(&ct) == -1)
783efd4c9b6SSteve Lawrence 		ct = -1;
784efd4c9b6SSteve Lawrence 	(void) ct_tmpl_clear(tmpl_fd);
785efd4c9b6SSteve Lawrence 	(void) close(tmpl_fd);
786efd4c9b6SSteve Lawrence 	(void) contract_abandon_id(ct);
787efd4c9b6SSteve Lawrence 	while (waitpid(pid, &stat, 0) != pid)
788efd4c9b6SSteve Lawrence 		;
789efd4c9b6SSteve Lawrence 	if (WIFEXITED(stat) && WEXITSTATUS(stat) == 0)
790efd4c9b6SSteve Lawrence 		return;
791efd4c9b6SSteve Lawrence 
792efd4c9b6SSteve Lawrence 	zsd_warn(gettext("Unable to attach door to zoneid: %d"), zid);
793efd4c9b6SSteve Lawrence 
794efd4c9b6SSteve Lawrence 	if (WEXITSTATUS(stat) == 1)
795efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Cannot entering zone"));
796efd4c9b6SSteve Lawrence 	else if (WEXITSTATUS(stat) == 2)
797efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to create door file: %s"), path);
798efd4c9b6SSteve Lawrence 	else if (WEXITSTATUS(stat) == 3)
799efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to fattach file: %s"), path);
800efd4c9b6SSteve Lawrence 
801efd4c9b6SSteve Lawrence 	zsd_warn(gettext("Internal error entering zone: %d"), zid);
802efd4c9b6SSteve Lawrence }
803efd4c9b6SSteve Lawrence 
804efd4c9b6SSteve Lawrence /*
805efd4c9b6SSteve Lawrence  * Zone lookup and allocation functions to manage list of currently running
806efd4c9b6SSteve Lawrence  * zones.
807efd4c9b6SSteve Lawrence  */
808efd4c9b6SSteve Lawrence static zsd_zone_t *
zsd_lookup_zone(zsd_ctl_t * ctl,char * zonename,zoneid_t zoneid)809efd4c9b6SSteve Lawrence zsd_lookup_zone(zsd_ctl_t *ctl, char *zonename, zoneid_t zoneid)
810efd4c9b6SSteve Lawrence {
811efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
812efd4c9b6SSteve Lawrence 
813efd4c9b6SSteve Lawrence 	for (zone = list_head(&ctl->zsctl_zones); zone != NULL;
814efd4c9b6SSteve Lawrence 	    zone = list_next(&ctl->zsctl_zones, zone)) {
815efd4c9b6SSteve Lawrence 		if (strcmp(zone->zsz_name, zonename) == 0) {
816efd4c9b6SSteve Lawrence 			if (zoneid != -1)
817efd4c9b6SSteve Lawrence 				zone->zsz_id = zoneid;
818efd4c9b6SSteve Lawrence 			return (zone);
819efd4c9b6SSteve Lawrence 		}
820efd4c9b6SSteve Lawrence 	}
821efd4c9b6SSteve Lawrence 	return (NULL);
822efd4c9b6SSteve Lawrence }
823efd4c9b6SSteve Lawrence 
824efd4c9b6SSteve Lawrence static zsd_zone_t *
zsd_lookup_zone_byid(zsd_ctl_t * ctl,zoneid_t zoneid)825efd4c9b6SSteve Lawrence zsd_lookup_zone_byid(zsd_ctl_t *ctl, zoneid_t zoneid)
826efd4c9b6SSteve Lawrence {
827efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
828efd4c9b6SSteve Lawrence 
829efd4c9b6SSteve Lawrence 	for (zone = list_head(&ctl->zsctl_zones); zone != NULL;
830efd4c9b6SSteve Lawrence 	    zone = list_next(&ctl->zsctl_zones, zone)) {
831efd4c9b6SSteve Lawrence 		if (zone->zsz_id == zoneid)
832efd4c9b6SSteve Lawrence 			return (zone);
833efd4c9b6SSteve Lawrence 	}
834efd4c9b6SSteve Lawrence 	return (NULL);
835efd4c9b6SSteve Lawrence }
836efd4c9b6SSteve Lawrence 
837efd4c9b6SSteve Lawrence static zsd_zone_t *
zsd_allocate_zone(zsd_ctl_t * ctl,char * zonename,zoneid_t zoneid)838efd4c9b6SSteve Lawrence zsd_allocate_zone(zsd_ctl_t *ctl, char *zonename, zoneid_t zoneid)
839efd4c9b6SSteve Lawrence {
840efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
841efd4c9b6SSteve Lawrence 
842efd4c9b6SSteve Lawrence 	if ((zone = (zsd_zone_t *)calloc(1, sizeof (zsd_zone_t))) == NULL)
843efd4c9b6SSteve Lawrence 		return (NULL);
844efd4c9b6SSteve Lawrence 
845efd4c9b6SSteve Lawrence 	(void) strlcpy(zone->zsz_name, zonename, sizeof (zone->zsz_name));
846efd4c9b6SSteve Lawrence 	zone->zsz_id = zoneid;
847efd4c9b6SSteve Lawrence 	zone->zsz_found = B_FALSE;
848efd4c9b6SSteve Lawrence 
849efd4c9b6SSteve Lawrence 	/*
850efd4c9b6SSteve Lawrence 	 * Allocate as deleted so if not found in first pass, zone is deleted
851efd4c9b6SSteve Lawrence 	 * from list.  This can happen if zone is returned by zone_list, but
852efd4c9b6SSteve Lawrence 	 * exits before first attempt to fetch zone details.
853efd4c9b6SSteve Lawrence 	 */
854efd4c9b6SSteve Lawrence 	zone->zsz_start = g_now;
855efd4c9b6SSteve Lawrence 	zone->zsz_hrstart = g_hrnow;
856efd4c9b6SSteve Lawrence 	zone->zsz_deleted = B_TRUE;
857efd4c9b6SSteve Lawrence 
858efd4c9b6SSteve Lawrence 	zone->zsz_cpu_shares = ZS_LIMIT_NONE;
859efd4c9b6SSteve Lawrence 	zone->zsz_cpu_cap = ZS_LIMIT_NONE;
860efd4c9b6SSteve Lawrence 	zone->zsz_ram_cap = ZS_LIMIT_NONE;
861efd4c9b6SSteve Lawrence 	zone->zsz_locked_cap = ZS_LIMIT_NONE;
862efd4c9b6SSteve Lawrence 	zone->zsz_vm_cap = ZS_LIMIT_NONE;
863efd4c9b6SSteve Lawrence 
864efd4c9b6SSteve Lawrence 	zone->zsz_processes_cap = ZS_LIMIT_NONE;
865efd4c9b6SSteve Lawrence 	zone->zsz_lwps_cap = ZS_LIMIT_NONE;
866efd4c9b6SSteve Lawrence 	zone->zsz_shm_cap = ZS_LIMIT_NONE;
867efd4c9b6SSteve Lawrence 	zone->zsz_shmids_cap = ZS_LIMIT_NONE;
868efd4c9b6SSteve Lawrence 	zone->zsz_semids_cap = ZS_LIMIT_NONE;
869efd4c9b6SSteve Lawrence 	zone->zsz_msgids_cap = ZS_LIMIT_NONE;
870efd4c9b6SSteve Lawrence 	zone->zsz_lofi_cap = ZS_LIMIT_NONE;
871efd4c9b6SSteve Lawrence 
872efd4c9b6SSteve Lawrence 	ctl->zsctl_nzones++;
873efd4c9b6SSteve Lawrence 
874efd4c9b6SSteve Lawrence 	return (zone);
875efd4c9b6SSteve Lawrence }
876efd4c9b6SSteve Lawrence 
877efd4c9b6SSteve Lawrence static zsd_zone_t *
zsd_lookup_insert_zone(zsd_ctl_t * ctl,char * zonename,zoneid_t zoneid)878efd4c9b6SSteve Lawrence zsd_lookup_insert_zone(zsd_ctl_t *ctl, char *zonename, zoneid_t zoneid)
879efd4c9b6SSteve Lawrence {
880efd4c9b6SSteve Lawrence 	zsd_zone_t *zone, *tmp;
881efd4c9b6SSteve Lawrence 
882efd4c9b6SSteve Lawrence 	if ((zone = zsd_lookup_zone(ctl, zonename, zoneid)) != NULL)
883efd4c9b6SSteve Lawrence 		return (zone);
884efd4c9b6SSteve Lawrence 
885efd4c9b6SSteve Lawrence 	if ((zone = zsd_allocate_zone(ctl, zonename, zoneid)) == NULL)
886efd4c9b6SSteve Lawrence 		return (NULL);
887efd4c9b6SSteve Lawrence 
888efd4c9b6SSteve Lawrence 	/* Insert sorted by zonename */
889efd4c9b6SSteve Lawrence 	tmp = list_head(&ctl->zsctl_zones);
890efd4c9b6SSteve Lawrence 	while (tmp != NULL && strcmp(zonename, tmp->zsz_name) > 0)
891efd4c9b6SSteve Lawrence 		tmp = list_next(&ctl->zsctl_zones, tmp);
892efd4c9b6SSteve Lawrence 
893efd4c9b6SSteve Lawrence 	list_insert_before(&ctl->zsctl_zones, tmp, zone);
894efd4c9b6SSteve Lawrence 	return (zone);
895efd4c9b6SSteve Lawrence }
896efd4c9b6SSteve Lawrence 
897efd4c9b6SSteve Lawrence /*
898efd4c9b6SSteve Lawrence  * Mark all zones as not existing.  As zones are found, they will
899efd4c9b6SSteve Lawrence  * be marked as existing.  If a zone is not found, then it must have
900efd4c9b6SSteve Lawrence  * halted.
901efd4c9b6SSteve Lawrence  */
902efd4c9b6SSteve Lawrence static void
zsd_mark_zones_start(zsd_ctl_t * ctl)903efd4c9b6SSteve Lawrence zsd_mark_zones_start(zsd_ctl_t *ctl)
904efd4c9b6SSteve Lawrence {
905efd4c9b6SSteve Lawrence 
906efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
907efd4c9b6SSteve Lawrence 
908efd4c9b6SSteve Lawrence 	for (zone = list_head(&ctl->zsctl_zones); zone != NULL;
909efd4c9b6SSteve Lawrence 	    zone = list_next(&ctl->zsctl_zones, zone)) {
910efd4c9b6SSteve Lawrence 		zone->zsz_found = B_FALSE;
911efd4c9b6SSteve Lawrence 	}
912efd4c9b6SSteve Lawrence }
913efd4c9b6SSteve Lawrence 
914efd4c9b6SSteve Lawrence /*
915efd4c9b6SSteve Lawrence  * Mark each zone as not using pset.  If processes are found using the
916efd4c9b6SSteve Lawrence  * pset, the zone will remain bound to the pset.  If none of a zones
917efd4c9b6SSteve Lawrence  * processes are bound to the pset, the zone's usage of the pset will
918efd4c9b6SSteve Lawrence  * be deleted.
919efd4c9b6SSteve Lawrence  *
920efd4c9b6SSteve Lawrence  */
921efd4c9b6SSteve Lawrence static void
zsd_mark_pset_usage_start(zsd_pset_t * pset)922efd4c9b6SSteve Lawrence zsd_mark_pset_usage_start(zsd_pset_t *pset)
923efd4c9b6SSteve Lawrence {
924efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage;
925efd4c9b6SSteve Lawrence 
926efd4c9b6SSteve Lawrence 	for (usage = list_head(&pset->zsp_usage_list);
927efd4c9b6SSteve Lawrence 	    usage != NULL;
928efd4c9b6SSteve Lawrence 	    usage = list_next(&pset->zsp_usage_list, usage)) {
929efd4c9b6SSteve Lawrence 		usage->zsu_found = B_FALSE;
930efd4c9b6SSteve Lawrence 		usage->zsu_empty = B_TRUE;
931efd4c9b6SSteve Lawrence 	}
932efd4c9b6SSteve Lawrence }
933efd4c9b6SSteve Lawrence 
934efd4c9b6SSteve Lawrence /*
935efd4c9b6SSteve Lawrence  * Mark each pset as not existing.  If a pset is found, it will be marked
936efd4c9b6SSteve Lawrence  * as existing.  If a pset is not found, it wil be deleted.
937efd4c9b6SSteve Lawrence  */
938efd4c9b6SSteve Lawrence static void
zsd_mark_psets_start(zsd_ctl_t * ctl)939efd4c9b6SSteve Lawrence zsd_mark_psets_start(zsd_ctl_t *ctl)
940efd4c9b6SSteve Lawrence {
941efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
942efd4c9b6SSteve Lawrence 
943efd4c9b6SSteve Lawrence 	for (pset = list_head(&ctl->zsctl_psets); pset != NULL;
944efd4c9b6SSteve Lawrence 	    pset = list_next(&ctl->zsctl_psets, pset)) {
945efd4c9b6SSteve Lawrence 		pset->zsp_found = B_FALSE;
946efd4c9b6SSteve Lawrence 		zsd_mark_pset_usage_start(pset);
947efd4c9b6SSteve Lawrence 	}
948efd4c9b6SSteve Lawrence }
949efd4c9b6SSteve Lawrence 
950efd4c9b6SSteve Lawrence /*
951efd4c9b6SSteve Lawrence  * A pset was found.  Update its information
952efd4c9b6SSteve Lawrence  */
953efd4c9b6SSteve Lawrence static void
zsd_mark_pset_found(zsd_pset_t * pset,uint_t type,uint64_t online,uint64_t size,uint64_t min,uint64_t max,int64_t importance)954efd4c9b6SSteve Lawrence zsd_mark_pset_found(zsd_pset_t *pset, uint_t type, uint64_t online,
955efd4c9b6SSteve Lawrence     uint64_t size, uint64_t min, uint64_t max, int64_t importance)
956efd4c9b6SSteve Lawrence {
957efd4c9b6SSteve Lawrence 	pset->zsp_empty = B_TRUE;
958efd4c9b6SSteve Lawrence 	pset->zsp_deleted = B_FALSE;
959efd4c9b6SSteve Lawrence 
960efd4c9b6SSteve Lawrence 	assert(pset->zsp_found == B_FALSE);
961efd4c9b6SSteve Lawrence 
962efd4c9b6SSteve Lawrence 	/* update pset flags */
963efd4c9b6SSteve Lawrence 	if (pset->zsp_active == B_FALSE)
964efd4c9b6SSteve Lawrence 		/* pset not seen on previous interval.  It is new. */
965efd4c9b6SSteve Lawrence 		pset->zsp_new = B_TRUE;
966efd4c9b6SSteve Lawrence 	else
967efd4c9b6SSteve Lawrence 		pset->zsp_new = B_FALSE;
968efd4c9b6SSteve Lawrence 
969efd4c9b6SSteve Lawrence 	pset->zsp_found = B_TRUE;
970efd4c9b6SSteve Lawrence 	pset->zsp_cputype = type;
971efd4c9b6SSteve Lawrence 	pset->zsp_online = online;
972efd4c9b6SSteve Lawrence 	pset->zsp_size = size;
973efd4c9b6SSteve Lawrence 	pset->zsp_min = min;
974efd4c9b6SSteve Lawrence 	pset->zsp_max = max;
975efd4c9b6SSteve Lawrence 	pset->zsp_importance = importance;
976efd4c9b6SSteve Lawrence 	pset->zsp_cpu_shares = 0;
977efd4c9b6SSteve Lawrence 	pset->zsp_scheds = 0;
978efd4c9b6SSteve Lawrence 	pset->zsp_active = B_TRUE;
979efd4c9b6SSteve Lawrence }
980efd4c9b6SSteve Lawrence 
981efd4c9b6SSteve Lawrence /*
982efd4c9b6SSteve Lawrence  * A zone's process was found using a pset. Charge the process to the pset and
983efd4c9b6SSteve Lawrence  * the per-zone data for the pset.
984efd4c9b6SSteve Lawrence  */
985efd4c9b6SSteve Lawrence static void
zsd_mark_pset_usage_found(zsd_pset_usage_t * usage,uint_t sched)986efd4c9b6SSteve Lawrence zsd_mark_pset_usage_found(zsd_pset_usage_t *usage, uint_t sched)
987efd4c9b6SSteve Lawrence {
988efd4c9b6SSteve Lawrence 	zsd_zone_t *zone = usage->zsu_zone;
989efd4c9b6SSteve Lawrence 	zsd_pset_t *pset = usage->zsu_pset;
990efd4c9b6SSteve Lawrence 
991efd4c9b6SSteve Lawrence 	/* Nothing to do if already found */
992efd4c9b6SSteve Lawrence 	if (usage->zsu_found == B_TRUE)
993efd4c9b6SSteve Lawrence 		goto add_stats;
994efd4c9b6SSteve Lawrence 
995efd4c9b6SSteve Lawrence 	usage->zsu_found = B_TRUE;
996efd4c9b6SSteve Lawrence 	usage->zsu_empty = B_FALSE;
997efd4c9b6SSteve Lawrence 
998efd4c9b6SSteve Lawrence 	usage->zsu_deleted = B_FALSE;
999efd4c9b6SSteve Lawrence 	/* update usage flags */
1000efd4c9b6SSteve Lawrence 	if (usage->zsu_active == B_FALSE)
1001efd4c9b6SSteve Lawrence 		usage->zsu_new = B_TRUE;
1002efd4c9b6SSteve Lawrence 	else
1003efd4c9b6SSteve Lawrence 		usage->zsu_new = B_FALSE;
1004efd4c9b6SSteve Lawrence 
1005efd4c9b6SSteve Lawrence 	usage->zsu_scheds = 0;
1006efd4c9b6SSteve Lawrence 	usage->zsu_cpu_shares = ZS_LIMIT_NONE;
1007efd4c9b6SSteve Lawrence 	usage->zsu_active = B_TRUE;
1008efd4c9b6SSteve Lawrence 	pset->zsp_empty = B_FALSE;
1009efd4c9b6SSteve Lawrence 	zone->zsz_empty = B_FALSE;
1010efd4c9b6SSteve Lawrence 
1011efd4c9b6SSteve Lawrence add_stats:
1012efd4c9b6SSteve Lawrence 	/* Detect zone's pset id, and if it is bound to multiple psets */
1013efd4c9b6SSteve Lawrence 	if (zone->zsz_psetid == ZS_PSET_ERROR)
1014efd4c9b6SSteve Lawrence 		zone->zsz_psetid = pset->zsp_id;
1015efd4c9b6SSteve Lawrence 	else if (zone->zsz_psetid != pset->zsp_id)
1016efd4c9b6SSteve Lawrence 		zone->zsz_psetid = ZS_PSET_MULTI;
1017efd4c9b6SSteve Lawrence 
1018efd4c9b6SSteve Lawrence 	usage->zsu_scheds |= sched;
1019efd4c9b6SSteve Lawrence 	pset->zsp_scheds |= sched;
1020efd4c9b6SSteve Lawrence 	zone->zsz_scheds |= sched;
1021efd4c9b6SSteve Lawrence 
1022efd4c9b6SSteve Lawrence 	/* Record if FSS is co-habitating with conflicting scheduler */
1023efd4c9b6SSteve Lawrence 	if ((pset->zsp_scheds & ZS_SCHED_FSS) &&
1024efd4c9b6SSteve Lawrence 	    usage->zsu_scheds & (
1025efd4c9b6SSteve Lawrence 	    ZS_SCHED_TS | ZS_SCHED_IA | ZS_SCHED_FX)) {
1026efd4c9b6SSteve Lawrence 		usage->zsu_scheds |= ZS_SCHED_CONFLICT;
1027efd4c9b6SSteve Lawrence 
1028efd4c9b6SSteve Lawrence 		pset->zsp_scheds |= ZS_SCHED_CONFLICT;
1029efd4c9b6SSteve Lawrence 	}
1030efd4c9b6SSteve Lawrence 
1031efd4c9b6SSteve Lawrence }
1032efd4c9b6SSteve Lawrence 
1033efd4c9b6SSteve Lawrence /* Add cpu time for a process to a pset, zone, and system totals */
1034efd4c9b6SSteve Lawrence static void
zsd_add_usage(zsd_ctl_t * ctl,zsd_pset_usage_t * usage,timestruc_t * delta)1035efd4c9b6SSteve Lawrence zsd_add_usage(zsd_ctl_t *ctl, zsd_pset_usage_t *usage, timestruc_t *delta)
1036efd4c9b6SSteve Lawrence {
1037efd4c9b6SSteve Lawrence 	zsd_system_t *system = ctl->zsctl_system;
1038efd4c9b6SSteve Lawrence 	zsd_zone_t *zone = usage->zsu_zone;
1039efd4c9b6SSteve Lawrence 	zsd_pset_t *pset = usage->zsu_pset;
1040efd4c9b6SSteve Lawrence 
1041efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(usage->zsu_cpu_usage, *delta);
1042efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(pset->zsp_usage_zones, *delta);
1043efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(zone->zsz_cpu_usage, *delta);
1044efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(system->zss_cpu_usage_zones, *delta);
1045efd4c9b6SSteve Lawrence }
1046efd4c9b6SSteve Lawrence 
1047efd4c9b6SSteve Lawrence /* Determine which processor sets have been deleted */
1048efd4c9b6SSteve Lawrence static void
zsd_mark_psets_end(zsd_ctl_t * ctl)1049efd4c9b6SSteve Lawrence zsd_mark_psets_end(zsd_ctl_t *ctl)
1050efd4c9b6SSteve Lawrence {
1051efd4c9b6SSteve Lawrence 	zsd_pset_t *pset, *tmp;
1052efd4c9b6SSteve Lawrence 
1053efd4c9b6SSteve Lawrence 	/*
1054efd4c9b6SSteve Lawrence 	 * Mark pset as not exists, and deleted if it existed
1055efd4c9b6SSteve Lawrence 	 * previous interval.
1056efd4c9b6SSteve Lawrence 	 */
1057efd4c9b6SSteve Lawrence 	pset = list_head(&ctl->zsctl_psets);
1058efd4c9b6SSteve Lawrence 	while (pset != NULL) {
1059efd4c9b6SSteve Lawrence 		if (pset->zsp_found == B_FALSE) {
1060efd4c9b6SSteve Lawrence 			pset->zsp_empty = B_TRUE;
1061efd4c9b6SSteve Lawrence 			if (pset->zsp_deleted == B_TRUE) {
1062efd4c9b6SSteve Lawrence 				tmp = pset;
1063efd4c9b6SSteve Lawrence 				pset = list_next(&ctl->zsctl_psets, pset);
1064efd4c9b6SSteve Lawrence 				list_remove(&ctl->zsctl_psets, tmp);
1065efd4c9b6SSteve Lawrence 				free(tmp);
1066efd4c9b6SSteve Lawrence 				ctl->zsctl_npsets--;
1067efd4c9b6SSteve Lawrence 				continue;
1068efd4c9b6SSteve Lawrence 			} else {
1069efd4c9b6SSteve Lawrence 				/* Pset vanished during this interval */
1070efd4c9b6SSteve Lawrence 				pset->zsp_new = B_FALSE;
1071efd4c9b6SSteve Lawrence 				pset->zsp_deleted = B_TRUE;
1072efd4c9b6SSteve Lawrence 				pset->zsp_active = B_TRUE;
1073efd4c9b6SSteve Lawrence 			}
1074efd4c9b6SSteve Lawrence 		}
1075efd4c9b6SSteve Lawrence 		pset = list_next(&ctl->zsctl_psets, pset);
1076efd4c9b6SSteve Lawrence 	}
1077efd4c9b6SSteve Lawrence }
1078efd4c9b6SSteve Lawrence 
1079efd4c9b6SSteve Lawrence /* Determine which zones are no longer bound to processor sets */
1080efd4c9b6SSteve Lawrence static void
zsd_mark_pset_usages_end(zsd_ctl_t * ctl)1081efd4c9b6SSteve Lawrence zsd_mark_pset_usages_end(zsd_ctl_t *ctl)
1082efd4c9b6SSteve Lawrence {
1083efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
1084efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
1085efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage, *tmp;
1086efd4c9b6SSteve Lawrence 
1087efd4c9b6SSteve Lawrence 	/*
1088efd4c9b6SSteve Lawrence 	 * Mark pset as not exists, and deleted if it existed previous
1089efd4c9b6SSteve Lawrence 	 * interval.
1090efd4c9b6SSteve Lawrence 	 */
1091efd4c9b6SSteve Lawrence 	for (pset = list_head(&ctl->zsctl_psets); pset != NULL;
1092efd4c9b6SSteve Lawrence 	    pset = list_next(&ctl->zsctl_psets, pset)) {
1093efd4c9b6SSteve Lawrence 		usage = list_head(&pset->zsp_usage_list);
1094efd4c9b6SSteve Lawrence 		while (usage != NULL) {
1095efd4c9b6SSteve Lawrence 			/*
1096efd4c9b6SSteve Lawrence 			 * Mark pset as not exists, and deleted if it existed
1097efd4c9b6SSteve Lawrence 			 * previous interval.
1098efd4c9b6SSteve Lawrence 			 */
1099efd4c9b6SSteve Lawrence 			if (usage->zsu_found == B_FALSE ||
1100efd4c9b6SSteve Lawrence 			    usage->zsu_zone->zsz_deleted == B_TRUE ||
1101efd4c9b6SSteve Lawrence 			    usage->zsu_pset->zsp_deleted == B_TRUE) {
1102efd4c9b6SSteve Lawrence 				tmp = usage;
1103efd4c9b6SSteve Lawrence 				usage = list_next(&pset->zsp_usage_list,
1104efd4c9b6SSteve Lawrence 				    usage);
1105efd4c9b6SSteve Lawrence 				list_remove(&pset->zsp_usage_list, tmp);
1106efd4c9b6SSteve Lawrence 				free(tmp);
1107efd4c9b6SSteve Lawrence 				pset->zsp_nusage--;
1108efd4c9b6SSteve Lawrence 				ctl->zsctl_npset_usages--;
1109efd4c9b6SSteve Lawrence 				continue;
1110efd4c9b6SSteve Lawrence 			} else {
1111efd4c9b6SSteve Lawrence 				usage->zsu_new = B_FALSE;
1112efd4c9b6SSteve Lawrence 				usage->zsu_deleted = B_TRUE;
1113efd4c9b6SSteve Lawrence 				usage->zsu_active = B_TRUE;
1114efd4c9b6SSteve Lawrence 			}
1115efd4c9b6SSteve Lawrence 			/* Add cpu shares for usages that are in FSS */
1116efd4c9b6SSteve Lawrence 			zone = usage->zsu_zone;
1117efd4c9b6SSteve Lawrence 			if (usage->zsu_scheds & ZS_SCHED_FSS &&
1118efd4c9b6SSteve Lawrence 			    zone->zsz_cpu_shares != ZS_SHARES_UNLIMITED &&
1119efd4c9b6SSteve Lawrence 			    zone->zsz_cpu_shares != 0) {
1120efd4c9b6SSteve Lawrence 				zone = usage->zsu_zone;
1121efd4c9b6SSteve Lawrence 				usage->zsu_cpu_shares = zone->zsz_cpu_shares;
1122efd4c9b6SSteve Lawrence 				pset->zsp_cpu_shares += zone->zsz_cpu_shares;
1123efd4c9b6SSteve Lawrence 			}
1124efd4c9b6SSteve Lawrence 			usage = list_next(&pset->zsp_usage_list,
1125efd4c9b6SSteve Lawrence 			    usage);
1126efd4c9b6SSteve Lawrence 		}
1127efd4c9b6SSteve Lawrence 	}
1128efd4c9b6SSteve Lawrence }
1129efd4c9b6SSteve Lawrence 
1130efd4c9b6SSteve Lawrence /* A zone has been found.  Update its information */
1131efd4c9b6SSteve Lawrence static void
zsd_mark_zone_found(zsd_ctl_t * ctl,zsd_zone_t * zone,uint64_t cpu_shares,uint64_t cpu_cap,uint64_t ram_cap,uint64_t locked_cap,uint64_t vm_cap,uint64_t processes_cap,uint64_t processes,uint64_t lwps_cap,uint64_t lwps,uint64_t shm_cap,uint64_t shm,uint64_t shmids_cap,uint64_t shmids,uint64_t semids_cap,uint64_t semids,uint64_t msgids_cap,uint64_t msgids,uint64_t lofi_cap,uint64_t lofi,char * poolname,char * psetname,uint_t sched,uint_t cputype,uint_t iptype)1132efd4c9b6SSteve Lawrence zsd_mark_zone_found(zsd_ctl_t *ctl, zsd_zone_t *zone, uint64_t cpu_shares,
1133efd4c9b6SSteve Lawrence     uint64_t cpu_cap, uint64_t ram_cap, uint64_t locked_cap,
1134efd4c9b6SSteve Lawrence     uint64_t vm_cap, uint64_t processes_cap, uint64_t processes,
1135efd4c9b6SSteve Lawrence     uint64_t lwps_cap, uint64_t lwps, uint64_t shm_cap, uint64_t shm,
1136efd4c9b6SSteve Lawrence     uint64_t shmids_cap, uint64_t shmids, uint64_t semids_cap,
1137efd4c9b6SSteve Lawrence     uint64_t semids, uint64_t msgids_cap, uint64_t msgids, uint64_t lofi_cap,
1138efd4c9b6SSteve Lawrence     uint64_t lofi, char *poolname, char *psetname, uint_t sched, uint_t cputype,
1139efd4c9b6SSteve Lawrence     uint_t iptype)
1140efd4c9b6SSteve Lawrence {
1141efd4c9b6SSteve Lawrence 	zsd_system_t *sys = ctl->zsctl_system;
1142efd4c9b6SSteve Lawrence 
1143efd4c9b6SSteve Lawrence 	assert(zone->zsz_found == B_FALSE);
1144efd4c9b6SSteve Lawrence 
1145efd4c9b6SSteve Lawrence 	/*
1146efd4c9b6SSteve Lawrence 	 * Mark zone as exists, and new if it did not exist in previous
1147efd4c9b6SSteve Lawrence 	 * interval.
1148efd4c9b6SSteve Lawrence 	 */
1149efd4c9b6SSteve Lawrence 	zone->zsz_found = B_TRUE;
1150efd4c9b6SSteve Lawrence 	zone->zsz_empty = B_TRUE;
1151efd4c9b6SSteve Lawrence 	zone->zsz_deleted = B_FALSE;
1152efd4c9b6SSteve Lawrence 
1153efd4c9b6SSteve Lawrence 	/*
1154efd4c9b6SSteve Lawrence 	 * Zone is new.  Assume zone's properties are the same over entire
1155efd4c9b6SSteve Lawrence 	 * interval.
1156efd4c9b6SSteve Lawrence 	 */
1157efd4c9b6SSteve Lawrence 	if (zone->zsz_active == B_FALSE)
1158efd4c9b6SSteve Lawrence 		zone->zsz_new = B_TRUE;
1159efd4c9b6SSteve Lawrence 	else
1160efd4c9b6SSteve Lawrence 		zone->zsz_new = B_FALSE;
1161efd4c9b6SSteve Lawrence 
1162efd4c9b6SSteve Lawrence 	(void) strlcpy(zone->zsz_pool, poolname, sizeof (zone->zsz_pool));
1163efd4c9b6SSteve Lawrence 	(void) strlcpy(zone->zsz_pset, psetname, sizeof (zone->zsz_pset));
1164efd4c9b6SSteve Lawrence 	zone->zsz_default_sched = sched;
1165efd4c9b6SSteve Lawrence 
1166efd4c9b6SSteve Lawrence 	/* Schedulers updated later as processes are found */
1167efd4c9b6SSteve Lawrence 	zone->zsz_scheds = 0;
1168efd4c9b6SSteve Lawrence 
1169efd4c9b6SSteve Lawrence 	/* Cpus updated later as psets bound are identified */
1170efd4c9b6SSteve Lawrence 	zone->zsz_cpus_online = 0;
1171efd4c9b6SSteve Lawrence 
1172efd4c9b6SSteve Lawrence 	zone->zsz_cputype = cputype;
1173efd4c9b6SSteve Lawrence 	zone->zsz_iptype = iptype;
1174efd4c9b6SSteve Lawrence 	zone->zsz_psetid = ZS_PSET_ERROR;
1175efd4c9b6SSteve Lawrence 	zone->zsz_cpu_cap = cpu_cap;
1176efd4c9b6SSteve Lawrence 	zone->zsz_cpu_shares = cpu_shares;
1177efd4c9b6SSteve Lawrence 	zone->zsz_ram_cap = ram_cap;
1178efd4c9b6SSteve Lawrence 	zone->zsz_locked_cap = locked_cap;
1179efd4c9b6SSteve Lawrence 	zone->zsz_vm_cap = vm_cap;
1180efd4c9b6SSteve Lawrence 	zone->zsz_processes_cap = processes_cap;
1181efd4c9b6SSteve Lawrence 	zone->zsz_processes = processes;
1182efd4c9b6SSteve Lawrence 	zone->zsz_lwps_cap = lwps_cap;
1183efd4c9b6SSteve Lawrence 	zone->zsz_lwps = lwps;
1184efd4c9b6SSteve Lawrence 	zone->zsz_shm_cap = shm_cap;
1185efd4c9b6SSteve Lawrence 	zone->zsz_shm = shm;
1186efd4c9b6SSteve Lawrence 	zone->zsz_shmids_cap = shmids_cap;
1187efd4c9b6SSteve Lawrence 	zone->zsz_shmids = shmids;
1188efd4c9b6SSteve Lawrence 	zone->zsz_semids_cap = semids_cap;
1189efd4c9b6SSteve Lawrence 	zone->zsz_semids = semids;
1190efd4c9b6SSteve Lawrence 	zone->zsz_msgids_cap = msgids_cap;
1191efd4c9b6SSteve Lawrence 	zone->zsz_msgids = msgids;
1192efd4c9b6SSteve Lawrence 	zone->zsz_lofi_cap = lofi_cap;
1193efd4c9b6SSteve Lawrence 	zone->zsz_lofi = lofi;
1194efd4c9b6SSteve Lawrence 
1195efd4c9b6SSteve Lawrence 	sys->zss_processes += processes;
1196efd4c9b6SSteve Lawrence 	sys->zss_lwps += lwps;
1197efd4c9b6SSteve Lawrence 	sys->zss_shm += shm;
1198efd4c9b6SSteve Lawrence 	sys->zss_shmids += shmids;
1199efd4c9b6SSteve Lawrence 	sys->zss_semids += semids;
1200efd4c9b6SSteve Lawrence 	sys->zss_msgids += msgids;
1201efd4c9b6SSteve Lawrence 	sys->zss_lofi += lofi;
1202efd4c9b6SSteve Lawrence 	zone->zsz_active = B_TRUE;
1203efd4c9b6SSteve Lawrence }
1204efd4c9b6SSteve Lawrence 
1205efd4c9b6SSteve Lawrence 
1206efd4c9b6SSteve Lawrence /* Determine which zones have halted */
1207efd4c9b6SSteve Lawrence static void
zsd_mark_zones_end(zsd_ctl_t * ctl)1208efd4c9b6SSteve Lawrence zsd_mark_zones_end(zsd_ctl_t *ctl)
1209efd4c9b6SSteve Lawrence {
1210efd4c9b6SSteve Lawrence 	zsd_zone_t *zone, *tmp;
1211efd4c9b6SSteve Lawrence 
1212efd4c9b6SSteve Lawrence 	/*
1213efd4c9b6SSteve Lawrence 	 * Mark zone as not existing, or delete if it did not exist in
1214efd4c9b6SSteve Lawrence 	 * previous interval.
1215efd4c9b6SSteve Lawrence 	 */
1216efd4c9b6SSteve Lawrence 	zone = list_head(&ctl->zsctl_zones);
1217efd4c9b6SSteve Lawrence 	while (zone != NULL) {
1218efd4c9b6SSteve Lawrence 		if (zone->zsz_found == B_FALSE) {
1219efd4c9b6SSteve Lawrence 			zone->zsz_empty = B_TRUE;
1220efd4c9b6SSteve Lawrence 			if (zone->zsz_deleted == B_TRUE) {
1221efd4c9b6SSteve Lawrence 				/*
1222efd4c9b6SSteve Lawrence 				 * Zone deleted in prior interval,
1223efd4c9b6SSteve Lawrence 				 * so it no longer exists.
1224efd4c9b6SSteve Lawrence 				 */
1225efd4c9b6SSteve Lawrence 				tmp = zone;
1226efd4c9b6SSteve Lawrence 				zone = list_next(&ctl->zsctl_zones, zone);
1227efd4c9b6SSteve Lawrence 				list_remove(&ctl->zsctl_zones, tmp);
1228efd4c9b6SSteve Lawrence 				free(tmp);
1229efd4c9b6SSteve Lawrence 				ctl->zsctl_nzones--;
1230efd4c9b6SSteve Lawrence 				continue;
1231efd4c9b6SSteve Lawrence 			} else {
1232efd4c9b6SSteve Lawrence 				zone->zsz_new = B_FALSE;
1233efd4c9b6SSteve Lawrence 				zone->zsz_deleted = B_TRUE;
1234efd4c9b6SSteve Lawrence 				zone->zsz_active = B_TRUE;
1235efd4c9b6SSteve Lawrence 			}
1236efd4c9b6SSteve Lawrence 		}
1237efd4c9b6SSteve Lawrence 		zone = list_next(&ctl->zsctl_zones, zone);
1238efd4c9b6SSteve Lawrence 	}
1239efd4c9b6SSteve Lawrence }
1240efd4c9b6SSteve Lawrence 
1241efd4c9b6SSteve Lawrence /*
1242efd4c9b6SSteve Lawrence  * Mark cpus as not existing.  If a cpu is found, it will be updated.  If
1243efd4c9b6SSteve Lawrence  * a cpu is not found, then it must have gone offline, so it will be
1244efd4c9b6SSteve Lawrence  * deleted.
1245efd4c9b6SSteve Lawrence  *
1246efd4c9b6SSteve Lawrence  * The kstat tracking data is rolled so that the usage since the previous
1247efd4c9b6SSteve Lawrence  * interval can be determined.
1248efd4c9b6SSteve Lawrence  */
1249efd4c9b6SSteve Lawrence static void
zsd_mark_cpus_start(zsd_ctl_t * ctl,boolean_t roll)1250efd4c9b6SSteve Lawrence zsd_mark_cpus_start(zsd_ctl_t *ctl, boolean_t roll)
1251efd4c9b6SSteve Lawrence {
1252efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu;
1253efd4c9b6SSteve Lawrence 
1254efd4c9b6SSteve Lawrence 	/*
1255efd4c9b6SSteve Lawrence 	 * Mark all cpus as not existing.  As cpus are found, they will
1256efd4c9b6SSteve Lawrence 	 * be marked as existing.
1257efd4c9b6SSteve Lawrence 	 */
1258efd4c9b6SSteve Lawrence 	for (cpu = list_head(&ctl->zsctl_cpus); cpu != NULL;
1259efd4c9b6SSteve Lawrence 	    cpu = list_next(&ctl->zsctl_cpus, cpu)) {
1260efd4c9b6SSteve Lawrence 		cpu->zsc_found = B_FALSE;
1261efd4c9b6SSteve Lawrence 		if (cpu->zsc_active == B_TRUE && roll) {
1262efd4c9b6SSteve Lawrence 			cpu->zsc_psetid_prev = cpu->zsc_psetid;
1263efd4c9b6SSteve Lawrence 			cpu->zsc_nsec_idle_prev = cpu->zsc_nsec_idle;
1264efd4c9b6SSteve Lawrence 			cpu->zsc_nsec_intr_prev = cpu->zsc_nsec_intr;
1265efd4c9b6SSteve Lawrence 			cpu->zsc_nsec_kern_prev = cpu->zsc_nsec_kern;
1266efd4c9b6SSteve Lawrence 			cpu->zsc_nsec_user_prev = cpu->zsc_nsec_user;
1267efd4c9b6SSteve Lawrence 		}
1268efd4c9b6SSteve Lawrence 	}
1269efd4c9b6SSteve Lawrence }
1270efd4c9b6SSteve Lawrence 
1271efd4c9b6SSteve Lawrence /*
1272efd4c9b6SSteve Lawrence  * An array the size of the maximum number of cpus is kept.  Within this array
1273efd4c9b6SSteve Lawrence  * a list of the online cpus is maintained.
1274efd4c9b6SSteve Lawrence  */
1275efd4c9b6SSteve Lawrence zsd_cpu_t *
zsd_lookup_insert_cpu(zsd_ctl_t * ctl,processorid_t cpuid)1276efd4c9b6SSteve Lawrence zsd_lookup_insert_cpu(zsd_ctl_t *ctl, processorid_t cpuid)
1277efd4c9b6SSteve Lawrence {
1278efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu;
1279efd4c9b6SSteve Lawrence 
1280efd4c9b6SSteve Lawrence 	assert(cpuid < ctl->zsctl_maxcpuid);
1281efd4c9b6SSteve Lawrence 	cpu = &(ctl->zsctl_cpu_array[cpuid]);
1282efd4c9b6SSteve Lawrence 	assert(cpuid == cpu->zsc_id);
1283efd4c9b6SSteve Lawrence 
1284efd4c9b6SSteve Lawrence 	if (cpu->zsc_allocated == B_FALSE) {
1285efd4c9b6SSteve Lawrence 		cpu->zsc_allocated = B_TRUE;
1286efd4c9b6SSteve Lawrence 		list_insert_tail(&ctl->zsctl_cpus, cpu);
1287efd4c9b6SSteve Lawrence 	}
1288efd4c9b6SSteve Lawrence 	return (cpu);
1289efd4c9b6SSteve Lawrence }
1290efd4c9b6SSteve Lawrence 
1291efd4c9b6SSteve Lawrence /* A cpu has been found.  Update its information */
1292efd4c9b6SSteve Lawrence static void
zsd_mark_cpu_found(zsd_cpu_t * cpu,zsd_pset_t * pset,psetid_t psetid)1293efd4c9b6SSteve Lawrence zsd_mark_cpu_found(zsd_cpu_t *cpu, zsd_pset_t *pset, psetid_t psetid)
1294efd4c9b6SSteve Lawrence {
1295efd4c9b6SSteve Lawrence 	/*
1296efd4c9b6SSteve Lawrence 	 * legacy processor sets, the cpu may move while zonestatd is
1297efd4c9b6SSteve Lawrence 	 * inspecting, causing it to be found twice.  In this case, just
1298efd4c9b6SSteve Lawrence 	 * leave cpu in the first processor set in which it was found.
1299efd4c9b6SSteve Lawrence 	 */
1300efd4c9b6SSteve Lawrence 	if (cpu->zsc_found == B_TRUE)
1301efd4c9b6SSteve Lawrence 		return;
1302efd4c9b6SSteve Lawrence 
1303efd4c9b6SSteve Lawrence 	/* Mark cpu as online */
1304efd4c9b6SSteve Lawrence 	cpu->zsc_found = B_TRUE;
1305efd4c9b6SSteve Lawrence 	cpu->zsc_offlined = B_FALSE;
1306efd4c9b6SSteve Lawrence 	cpu->zsc_pset = pset;
1307efd4c9b6SSteve Lawrence 	/*
1308efd4c9b6SSteve Lawrence 	 * cpu is newly online.
1309efd4c9b6SSteve Lawrence 	 */
1310efd4c9b6SSteve Lawrence 	if (cpu->zsc_active == B_FALSE) {
1311efd4c9b6SSteve Lawrence 		/*
1312efd4c9b6SSteve Lawrence 		 * Cpu is newly online.
1313efd4c9b6SSteve Lawrence 		 */
1314efd4c9b6SSteve Lawrence 		cpu->zsc_onlined = B_TRUE;
1315efd4c9b6SSteve Lawrence 		cpu->zsc_psetid = psetid;
1316efd4c9b6SSteve Lawrence 		cpu->zsc_psetid_prev = psetid;
1317efd4c9b6SSteve Lawrence 	} else {
1318efd4c9b6SSteve Lawrence 		/*
1319efd4c9b6SSteve Lawrence 		 * cpu online during previous interval.  Save properties at
1320efd4c9b6SSteve Lawrence 		 * start of interval
1321efd4c9b6SSteve Lawrence 		 */
1322efd4c9b6SSteve Lawrence 		cpu->zsc_onlined = B_FALSE;
1323efd4c9b6SSteve Lawrence 		cpu->zsc_psetid = psetid;
1324efd4c9b6SSteve Lawrence 
1325efd4c9b6SSteve Lawrence 	}
1326efd4c9b6SSteve Lawrence 	cpu->zsc_active = B_TRUE;
1327efd4c9b6SSteve Lawrence }
1328efd4c9b6SSteve Lawrence 
1329efd4c9b6SSteve Lawrence /* Remove all offlined cpus from the list of tracked cpus */
1330efd4c9b6SSteve Lawrence static void
zsd_mark_cpus_end(zsd_ctl_t * ctl)1331efd4c9b6SSteve Lawrence zsd_mark_cpus_end(zsd_ctl_t *ctl)
1332efd4c9b6SSteve Lawrence {
1333efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu, *tmp;
1334efd4c9b6SSteve Lawrence 	int id;
1335efd4c9b6SSteve Lawrence 
1336efd4c9b6SSteve Lawrence 	/* Mark cpu as online or offline */
1337efd4c9b6SSteve Lawrence 	cpu = list_head(&ctl->zsctl_cpus);
1338efd4c9b6SSteve Lawrence 	while (cpu != NULL) {
1339efd4c9b6SSteve Lawrence 		if (cpu->zsc_found == B_FALSE) {
1340efd4c9b6SSteve Lawrence 			if (cpu->zsc_offlined == B_TRUE) {
1341efd4c9b6SSteve Lawrence 				/*
1342efd4c9b6SSteve Lawrence 				 * cpu offlined in prior interval. It is gone.
1343efd4c9b6SSteve Lawrence 				 */
1344efd4c9b6SSteve Lawrence 				tmp = cpu;
1345efd4c9b6SSteve Lawrence 				cpu = list_next(&ctl->zsctl_cpus, cpu);
1346efd4c9b6SSteve Lawrence 				list_remove(&ctl->zsctl_cpus, tmp);
1347efd4c9b6SSteve Lawrence 				/* Clear structure for future use */
1348efd4c9b6SSteve Lawrence 				id = tmp->zsc_id;
1349efd4c9b6SSteve Lawrence 				bzero(tmp, sizeof (zsd_cpu_t));
1350efd4c9b6SSteve Lawrence 				tmp->zsc_id = id;
1351efd4c9b6SSteve Lawrence 				tmp->zsc_allocated = B_FALSE;
1352efd4c9b6SSteve Lawrence 				tmp->zsc_psetid = ZS_PSET_ERROR;
1353efd4c9b6SSteve Lawrence 				tmp->zsc_psetid_prev = ZS_PSET_ERROR;
1354efd4c9b6SSteve Lawrence 
1355efd4c9b6SSteve Lawrence 			} else {
1356efd4c9b6SSteve Lawrence 				/*
1357efd4c9b6SSteve Lawrence 				 * cpu online at start of interval.  Treat
1358efd4c9b6SSteve Lawrence 				 * as still online, since it was online for
1359efd4c9b6SSteve Lawrence 				 * some portion of the interval.
1360efd4c9b6SSteve Lawrence 				 */
1361efd4c9b6SSteve Lawrence 				cpu->zsc_offlined = B_TRUE;
1362efd4c9b6SSteve Lawrence 				cpu->zsc_onlined = B_FALSE;
1363efd4c9b6SSteve Lawrence 				cpu->zsc_active = B_TRUE;
1364efd4c9b6SSteve Lawrence 				cpu->zsc_psetid = cpu->zsc_psetid_prev;
1365efd4c9b6SSteve Lawrence 				cpu->zsc_pset = NULL;
1366efd4c9b6SSteve Lawrence 			}
1367efd4c9b6SSteve Lawrence 		}
1368efd4c9b6SSteve Lawrence 		cpu = list_next(&ctl->zsctl_cpus, cpu);
1369efd4c9b6SSteve Lawrence 	}
1370efd4c9b6SSteve Lawrence }
1371efd4c9b6SSteve Lawrence 
1372efd4c9b6SSteve Lawrence /* Some utility functions for managing the list of processor sets */
1373efd4c9b6SSteve Lawrence static zsd_pset_t *
zsd_lookup_pset_byid(zsd_ctl_t * ctl,psetid_t psetid)1374efd4c9b6SSteve Lawrence zsd_lookup_pset_byid(zsd_ctl_t *ctl, psetid_t psetid)
1375efd4c9b6SSteve Lawrence {
1376efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
1377efd4c9b6SSteve Lawrence 
1378efd4c9b6SSteve Lawrence 	for (pset = list_head(&ctl->zsctl_psets); pset != NULL;
1379efd4c9b6SSteve Lawrence 	    pset = list_next(&ctl->zsctl_psets, pset)) {
1380efd4c9b6SSteve Lawrence 		if (pset->zsp_id == psetid)
1381efd4c9b6SSteve Lawrence 			return (pset);
1382efd4c9b6SSteve Lawrence 	}
1383efd4c9b6SSteve Lawrence 	return (NULL);
1384efd4c9b6SSteve Lawrence }
1385efd4c9b6SSteve Lawrence 
1386efd4c9b6SSteve Lawrence static zsd_pset_t *
zsd_lookup_pset(zsd_ctl_t * ctl,char * psetname,psetid_t psetid)1387efd4c9b6SSteve Lawrence zsd_lookup_pset(zsd_ctl_t *ctl, char *psetname, psetid_t psetid)
1388efd4c9b6SSteve Lawrence {
1389efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
1390efd4c9b6SSteve Lawrence 
1391efd4c9b6SSteve Lawrence 	for (pset = list_head(&ctl->zsctl_psets); pset != NULL;
1392efd4c9b6SSteve Lawrence 	    pset = list_next(&ctl->zsctl_psets, pset)) {
1393efd4c9b6SSteve Lawrence 		if (strcmp(pset->zsp_name, psetname) == 0) {
1394efd4c9b6SSteve Lawrence 			if (psetid != -1)
1395efd4c9b6SSteve Lawrence 				pset->zsp_id = psetid;
1396efd4c9b6SSteve Lawrence 			return (pset);
1397efd4c9b6SSteve Lawrence 		}
1398efd4c9b6SSteve Lawrence 	}
1399efd4c9b6SSteve Lawrence 	return (NULL);
1400efd4c9b6SSteve Lawrence }
1401efd4c9b6SSteve Lawrence 
1402efd4c9b6SSteve Lawrence static zsd_pset_t *
zsd_allocate_pset(zsd_ctl_t * ctl,char * psetname,psetid_t psetid)1403efd4c9b6SSteve Lawrence zsd_allocate_pset(zsd_ctl_t *ctl, char *psetname, psetid_t psetid)
1404efd4c9b6SSteve Lawrence {
1405efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
1406efd4c9b6SSteve Lawrence 
1407efd4c9b6SSteve Lawrence 	if ((pset = (zsd_pset_t *)calloc(1, sizeof (zsd_pset_t))) == NULL)
1408efd4c9b6SSteve Lawrence 		return (NULL);
1409efd4c9b6SSteve Lawrence 
1410efd4c9b6SSteve Lawrence 	(void) strlcpy(pset->zsp_name, psetname, sizeof (pset->zsp_name));
1411efd4c9b6SSteve Lawrence 	pset->zsp_id = psetid;
1412efd4c9b6SSteve Lawrence 	pset->zsp_found = B_FALSE;
1413efd4c9b6SSteve Lawrence 	/*
1414efd4c9b6SSteve Lawrence 	 * Allocate as deleted so if not found in first pass, pset is deleted
1415efd4c9b6SSteve Lawrence 	 * from list.  This can happen if pset is returned by pset_list, but
1416efd4c9b6SSteve Lawrence 	 * is destroyed before first attempt to fetch pset details.
1417efd4c9b6SSteve Lawrence 	 */
1418efd4c9b6SSteve Lawrence 	list_create(&pset->zsp_usage_list, sizeof (zsd_pset_usage_t),
1419efd4c9b6SSteve Lawrence 	    offsetof(zsd_pset_usage_t, zsu_next));
1420efd4c9b6SSteve Lawrence 
1421efd4c9b6SSteve Lawrence 	pset->zsp_hrstart = g_hrnow;
1422efd4c9b6SSteve Lawrence 	pset->zsp_deleted = B_TRUE;
1423efd4c9b6SSteve Lawrence 	pset->zsp_empty = B_TRUE;
1424efd4c9b6SSteve Lawrence 	ctl->zsctl_npsets++;
1425efd4c9b6SSteve Lawrence 
1426efd4c9b6SSteve Lawrence 	return (pset);
1427efd4c9b6SSteve Lawrence }
1428efd4c9b6SSteve Lawrence 
1429efd4c9b6SSteve Lawrence static zsd_pset_t *
zsd_lookup_insert_pset(zsd_ctl_t * ctl,char * psetname,psetid_t psetid)1430efd4c9b6SSteve Lawrence zsd_lookup_insert_pset(zsd_ctl_t *ctl, char *psetname, psetid_t psetid)
1431efd4c9b6SSteve Lawrence {
1432efd4c9b6SSteve Lawrence 	zsd_pset_t *pset, *tmp;
1433efd4c9b6SSteve Lawrence 
1434efd4c9b6SSteve Lawrence 	if ((pset = zsd_lookup_pset(ctl, psetname, psetid)) != NULL)
1435efd4c9b6SSteve Lawrence 		return (pset);
1436efd4c9b6SSteve Lawrence 
1437efd4c9b6SSteve Lawrence 	if ((pset = zsd_allocate_pset(ctl, psetname, psetid)) == NULL)
1438efd4c9b6SSteve Lawrence 		return (NULL);
1439efd4c9b6SSteve Lawrence 
1440efd4c9b6SSteve Lawrence 	/* Insert sorted by psetname */
1441efd4c9b6SSteve Lawrence 	tmp = list_head(&ctl->zsctl_psets);
1442efd4c9b6SSteve Lawrence 	while (tmp != NULL && strcmp(psetname, tmp->zsp_name) > 0)
1443efd4c9b6SSteve Lawrence 		tmp = list_next(&ctl->zsctl_psets, tmp);
1444efd4c9b6SSteve Lawrence 
1445efd4c9b6SSteve Lawrence 	list_insert_before(&ctl->zsctl_psets, tmp, pset);
1446efd4c9b6SSteve Lawrence 	return (pset);
1447efd4c9b6SSteve Lawrence }
1448efd4c9b6SSteve Lawrence 
1449efd4c9b6SSteve Lawrence /* Some utility functions for managing the list of zones using each pset */
1450efd4c9b6SSteve Lawrence static zsd_pset_usage_t *
zsd_lookup_usage(zsd_pset_t * pset,zsd_zone_t * zone)1451efd4c9b6SSteve Lawrence zsd_lookup_usage(zsd_pset_t *pset, zsd_zone_t *zone)
1452efd4c9b6SSteve Lawrence {
1453efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage;
1454efd4c9b6SSteve Lawrence 
1455efd4c9b6SSteve Lawrence 	for (usage = list_head(&pset->zsp_usage_list); usage != NULL;
1456efd4c9b6SSteve Lawrence 	    usage = list_next(&pset->zsp_usage_list, usage))
1457efd4c9b6SSteve Lawrence 		if (usage->zsu_zone == zone)
1458efd4c9b6SSteve Lawrence 			return (usage);
1459efd4c9b6SSteve Lawrence 
1460efd4c9b6SSteve Lawrence 	return (NULL);
1461efd4c9b6SSteve Lawrence }
1462efd4c9b6SSteve Lawrence 
1463efd4c9b6SSteve Lawrence static zsd_pset_usage_t *
zsd_allocate_pset_usage(zsd_ctl_t * ctl,zsd_pset_t * pset,zsd_zone_t * zone)1464efd4c9b6SSteve Lawrence zsd_allocate_pset_usage(zsd_ctl_t *ctl, zsd_pset_t *pset, zsd_zone_t *zone)
1465efd4c9b6SSteve Lawrence {
1466efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage;
1467efd4c9b6SSteve Lawrence 
1468efd4c9b6SSteve Lawrence 	if ((usage = (zsd_pset_usage_t *)calloc(1, sizeof (zsd_pset_usage_t)))
1469efd4c9b6SSteve Lawrence 	    == NULL)
1470efd4c9b6SSteve Lawrence 		return (NULL);
1471efd4c9b6SSteve Lawrence 
1472efd4c9b6SSteve Lawrence 	list_link_init(&usage->zsu_next);
1473efd4c9b6SSteve Lawrence 	usage->zsu_zone = zone;
1474efd4c9b6SSteve Lawrence 	usage->zsu_zoneid = zone->zsz_id;
1475efd4c9b6SSteve Lawrence 	usage->zsu_pset = pset;
1476efd4c9b6SSteve Lawrence 	usage->zsu_found = B_FALSE;
1477efd4c9b6SSteve Lawrence 	usage->zsu_active = B_FALSE;
1478efd4c9b6SSteve Lawrence 	usage->zsu_new = B_FALSE;
1479efd4c9b6SSteve Lawrence 	/*
1480efd4c9b6SSteve Lawrence 	 * Allocate as not deleted.  If a process is found in a pset for
1481efd4c9b6SSteve Lawrence 	 * a zone, the usage will not be deleted until at least the next
1482efd4c9b6SSteve Lawrence 	 * interval.
1483efd4c9b6SSteve Lawrence 	 */
1484efd4c9b6SSteve Lawrence 	usage->zsu_start = g_now;
1485efd4c9b6SSteve Lawrence 	usage->zsu_hrstart = g_hrnow;
1486efd4c9b6SSteve Lawrence 	usage->zsu_deleted = B_FALSE;
1487efd4c9b6SSteve Lawrence 	usage->zsu_empty = B_TRUE;
1488efd4c9b6SSteve Lawrence 	usage->zsu_scheds = 0;
1489efd4c9b6SSteve Lawrence 	usage->zsu_cpu_shares = ZS_LIMIT_NONE;
1490efd4c9b6SSteve Lawrence 
1491efd4c9b6SSteve Lawrence 	ctl->zsctl_npset_usages++;
1492efd4c9b6SSteve Lawrence 	pset->zsp_nusage++;
1493efd4c9b6SSteve Lawrence 
1494efd4c9b6SSteve Lawrence 	return (usage);
1495efd4c9b6SSteve Lawrence }
1496efd4c9b6SSteve Lawrence 
1497efd4c9b6SSteve Lawrence static zsd_pset_usage_t *
zsd_lookup_insert_usage(zsd_ctl_t * ctl,zsd_pset_t * pset,zsd_zone_t * zone)1498efd4c9b6SSteve Lawrence zsd_lookup_insert_usage(zsd_ctl_t *ctl, zsd_pset_t *pset, zsd_zone_t *zone)
1499efd4c9b6SSteve Lawrence {
1500efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage, *tmp;
1501efd4c9b6SSteve Lawrence 
1502efd4c9b6SSteve Lawrence 	if ((usage = zsd_lookup_usage(pset, zone))
1503efd4c9b6SSteve Lawrence 	    != NULL)
1504efd4c9b6SSteve Lawrence 		return (usage);
1505efd4c9b6SSteve Lawrence 
1506efd4c9b6SSteve Lawrence 	if ((usage = zsd_allocate_pset_usage(ctl, pset, zone)) == NULL)
1507efd4c9b6SSteve Lawrence 		return (NULL);
1508efd4c9b6SSteve Lawrence 
1509efd4c9b6SSteve Lawrence 	tmp = list_head(&pset->zsp_usage_list);
1510efd4c9b6SSteve Lawrence 	while (tmp != NULL && strcmp(zone->zsz_name, tmp->zsu_zone->zsz_name)
1511efd4c9b6SSteve Lawrence 	    > 0)
1512efd4c9b6SSteve Lawrence 		tmp = list_next(&pset->zsp_usage_list, tmp);
1513efd4c9b6SSteve Lawrence 
1514efd4c9b6SSteve Lawrence 	list_insert_before(&pset->zsp_usage_list, tmp, usage);
1515efd4c9b6SSteve Lawrence 	return (usage);
1516efd4c9b6SSteve Lawrence }
1517efd4c9b6SSteve Lawrence 
1518efd4c9b6SSteve Lawrence static void
zsd_refresh_system(zsd_ctl_t * ctl)1519efd4c9b6SSteve Lawrence zsd_refresh_system(zsd_ctl_t *ctl)
1520efd4c9b6SSteve Lawrence {
1521efd4c9b6SSteve Lawrence 	zsd_system_t *system = ctl->zsctl_system;
1522efd4c9b6SSteve Lawrence 
1523efd4c9b6SSteve Lawrence 	/* Re-count these values each interval */
1524efd4c9b6SSteve Lawrence 	system->zss_processes = 0;
1525efd4c9b6SSteve Lawrence 	system->zss_lwps = 0;
1526efd4c9b6SSteve Lawrence 	system->zss_shm = 0;
1527efd4c9b6SSteve Lawrence 	system->zss_shmids = 0;
1528efd4c9b6SSteve Lawrence 	system->zss_semids = 0;
1529efd4c9b6SSteve Lawrence 	system->zss_msgids = 0;
1530efd4c9b6SSteve Lawrence 	system->zss_lofi = 0;
1531efd4c9b6SSteve Lawrence }
1532efd4c9b6SSteve Lawrence 
1533efd4c9b6SSteve Lawrence 
1534efd4c9b6SSteve Lawrence /* Reads each cpu's kstats, and adds the usage to the cpu's pset */
1535efd4c9b6SSteve Lawrence static void
zsd_update_cpu_stats(zsd_ctl_t * ctl,zsd_cpu_t * cpu)1536efd4c9b6SSteve Lawrence zsd_update_cpu_stats(zsd_ctl_t *ctl, zsd_cpu_t *cpu)
1537efd4c9b6SSteve Lawrence {
1538efd4c9b6SSteve Lawrence 	zsd_system_t *sys;
1539efd4c9b6SSteve Lawrence 	processorid_t cpuid;
1540efd4c9b6SSteve Lawrence 	zsd_pset_t *pset_prev;
1541efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
1542efd4c9b6SSteve Lawrence 	kstat_t *kstat;
1543efd4c9b6SSteve Lawrence 	kstat_named_t *knp;
1544efd4c9b6SSteve Lawrence 	kid_t kid;
1545efd4c9b6SSteve Lawrence 	uint64_t idle, intr, kern, user;
1546efd4c9b6SSteve Lawrence 
1547efd4c9b6SSteve Lawrence 	sys = ctl->zsctl_system;
1548efd4c9b6SSteve Lawrence 	pset = cpu->zsc_pset;
1549efd4c9b6SSteve Lawrence 	knp = NULL;
1550efd4c9b6SSteve Lawrence 	kid = -1;
1551efd4c9b6SSteve Lawrence 	cpuid = cpu->zsc_id;
1552efd4c9b6SSteve Lawrence 
1553efd4c9b6SSteve Lawrence 	/* Get the cpu time totals for this cpu */
1554efd4c9b6SSteve Lawrence 	kstat = kstat_lookup(ctl->zsctl_kstat_ctl, "cpu", cpuid, "sys");
1555efd4c9b6SSteve Lawrence 	if (kstat == NULL)
1556efd4c9b6SSteve Lawrence 		return;
1557efd4c9b6SSteve Lawrence 
1558efd4c9b6SSteve Lawrence 	kid = kstat_read(ctl->zsctl_kstat_ctl, kstat, NULL);
1559efd4c9b6SSteve Lawrence 	if (kid == -1)
1560efd4c9b6SSteve Lawrence 		return;
1561efd4c9b6SSteve Lawrence 
1562efd4c9b6SSteve Lawrence 	knp = kstat_data_lookup(kstat, "cpu_nsec_idle");
1563efd4c9b6SSteve Lawrence 	if (knp == NULL || knp->data_type != KSTAT_DATA_UINT64)
1564efd4c9b6SSteve Lawrence 		return;
1565efd4c9b6SSteve Lawrence 
1566efd4c9b6SSteve Lawrence 	idle = knp->value.ui64;
1567efd4c9b6SSteve Lawrence 
1568efd4c9b6SSteve Lawrence 	knp = kstat_data_lookup(kstat, "cpu_nsec_kernel");
1569efd4c9b6SSteve Lawrence 	if (knp == NULL || knp->data_type != KSTAT_DATA_UINT64)
1570efd4c9b6SSteve Lawrence 		return;
1571efd4c9b6SSteve Lawrence 
1572efd4c9b6SSteve Lawrence 	kern = knp->value.ui64;
1573efd4c9b6SSteve Lawrence 
1574efd4c9b6SSteve Lawrence 	knp = kstat_data_lookup(kstat, "cpu_nsec_user");
1575efd4c9b6SSteve Lawrence 	if (knp == NULL || knp->data_type != KSTAT_DATA_UINT64)
1576efd4c9b6SSteve Lawrence 		return;
1577efd4c9b6SSteve Lawrence 
1578efd4c9b6SSteve Lawrence 	user = knp->value.ui64;
1579efd4c9b6SSteve Lawrence 
1580efd4c9b6SSteve Lawrence 	/*
1581efd4c9b6SSteve Lawrence 	 * Tracking intr time per cpu just exists for future enhancements.
1582efd4c9b6SSteve Lawrence 	 * The value is presently always zero.
1583efd4c9b6SSteve Lawrence 	 */
1584efd4c9b6SSteve Lawrence 	intr = 0;
1585efd4c9b6SSteve Lawrence 	cpu->zsc_nsec_idle = idle;
1586efd4c9b6SSteve Lawrence 	cpu->zsc_nsec_intr = intr;
1587efd4c9b6SSteve Lawrence 	cpu->zsc_nsec_kern = kern;
1588efd4c9b6SSteve Lawrence 	cpu->zsc_nsec_user = user;
1589efd4c9b6SSteve Lawrence 
1590efd4c9b6SSteve Lawrence 	if (cpu->zsc_onlined == B_TRUE) {
1591efd4c9b6SSteve Lawrence 		/*
1592efd4c9b6SSteve Lawrence 		 * cpu is newly online.  There is no reference value,
1593efd4c9b6SSteve Lawrence 		 * so just record its current stats for comparison
1594efd4c9b6SSteve Lawrence 		 * on next stat read.
1595efd4c9b6SSteve Lawrence 		 */
1596efd4c9b6SSteve Lawrence 		cpu->zsc_nsec_idle_prev = cpu->zsc_nsec_idle;
1597efd4c9b6SSteve Lawrence 		cpu->zsc_nsec_intr_prev = cpu->zsc_nsec_intr;
1598efd4c9b6SSteve Lawrence 		cpu->zsc_nsec_kern_prev = cpu->zsc_nsec_kern;
1599efd4c9b6SSteve Lawrence 		cpu->zsc_nsec_user_prev = cpu->zsc_nsec_user;
1600efd4c9b6SSteve Lawrence 		return;
1601efd4c9b6SSteve Lawrence 	}
1602efd4c9b6SSteve Lawrence 
1603efd4c9b6SSteve Lawrence 	/*
1604efd4c9b6SSteve Lawrence 	 * Calculate relative time since previous refresh.
1605efd4c9b6SSteve Lawrence 	 * Paranoia.  Don't let time  go backwards.
1606efd4c9b6SSteve Lawrence 	 */
1607efd4c9b6SSteve Lawrence 	idle = intr = kern = user = 0;
1608efd4c9b6SSteve Lawrence 	if (cpu->zsc_nsec_idle > cpu->zsc_nsec_idle_prev)
1609efd4c9b6SSteve Lawrence 		idle = cpu->zsc_nsec_idle - cpu->zsc_nsec_idle_prev;
1610efd4c9b6SSteve Lawrence 
1611efd4c9b6SSteve Lawrence 	if (cpu->zsc_nsec_intr > cpu->zsc_nsec_intr_prev)
1612efd4c9b6SSteve Lawrence 		intr = cpu->zsc_nsec_intr - cpu->zsc_nsec_intr_prev;
1613efd4c9b6SSteve Lawrence 
1614efd4c9b6SSteve Lawrence 	if (cpu->zsc_nsec_kern > cpu->zsc_nsec_kern_prev)
1615efd4c9b6SSteve Lawrence 		kern = cpu->zsc_nsec_kern - cpu->zsc_nsec_kern_prev;
1616efd4c9b6SSteve Lawrence 
1617efd4c9b6SSteve Lawrence 	if (cpu->zsc_nsec_user > cpu->zsc_nsec_user_prev)
1618efd4c9b6SSteve Lawrence 		user = cpu->zsc_nsec_user - cpu->zsc_nsec_user_prev;
1619efd4c9b6SSteve Lawrence 
1620efd4c9b6SSteve Lawrence 	/* Update totals for cpu usage */
1621efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(cpu->zsc_idle, idle);
1622efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(cpu->zsc_intr, intr);
1623efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(cpu->zsc_kern, kern);
1624efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(cpu->zsc_user, user);
1625efd4c9b6SSteve Lawrence 
1626efd4c9b6SSteve Lawrence 	/*
1627efd4c9b6SSteve Lawrence 	 * Add cpu's stats to its pset if it is known to be in
1628efd4c9b6SSteve Lawrence 	 * the pset since previous read.
1629efd4c9b6SSteve Lawrence 	 */
1630efd4c9b6SSteve Lawrence 	if (cpu->zsc_psetid == cpu->zsc_psetid_prev ||
1631efd4c9b6SSteve Lawrence 	    cpu->zsc_psetid_prev == ZS_PSET_ERROR ||
1632efd4c9b6SSteve Lawrence 	    (pset_prev = zsd_lookup_pset_byid(ctl,
1633efd4c9b6SSteve Lawrence 	    cpu->zsc_psetid_prev)) == NULL) {
1634efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_idle, idle);
1635efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_intr, intr);
1636efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_kern, kern);
1637efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_user, user);
1638efd4c9b6SSteve Lawrence 	} else {
1639efd4c9b6SSteve Lawrence 		/*
1640efd4c9b6SSteve Lawrence 		 * Last pset was different than current pset.
1641efd4c9b6SSteve Lawrence 		 * Best guess is to split usage between the two.
1642efd4c9b6SSteve Lawrence 		 */
1643efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset_prev->zsp_idle, idle / 2);
1644efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset_prev->zsp_intr, intr / 2);
1645efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset_prev->zsp_kern, kern / 2);
1646efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset_prev->zsp_user, user / 2);
1647efd4c9b6SSteve Lawrence 
1648efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_idle,
1649efd4c9b6SSteve Lawrence 		    (idle / 2) + (idle % 2));
1650efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_intr,
1651efd4c9b6SSteve Lawrence 		    (intr / 2) + (intr % 2));
1652efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_kern,
1653efd4c9b6SSteve Lawrence 		    (kern / 2) + (kern % 2));
1654efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_NANOSEC(pset->zsp_user,
1655efd4c9b6SSteve Lawrence 		    (user / 2) + (user % 2));
1656efd4c9b6SSteve Lawrence 	}
1657efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(sys->zss_idle, idle);
1658efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(sys->zss_intr, intr);
1659efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(sys->zss_kern, kern);
1660efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_NANOSEC(sys->zss_user, user);
1661efd4c9b6SSteve Lawrence }
1662efd4c9b6SSteve Lawrence 
1663efd4c9b6SSteve Lawrence /* Determine the details of a processor set by pset_id */
1664efd4c9b6SSteve Lawrence static int
zsd_get_pool_pset(zsd_ctl_t * ctl,psetid_t psetid,char * psetname,size_t namelen,uint_t * cputype,uint64_t * online,uint64_t * size,uint64_t * min,uint64_t * max,int64_t * importance)1665efd4c9b6SSteve Lawrence zsd_get_pool_pset(zsd_ctl_t *ctl, psetid_t psetid, char *psetname,
1666efd4c9b6SSteve Lawrence     size_t namelen, uint_t *cputype, uint64_t *online, uint64_t *size,
1667efd4c9b6SSteve Lawrence     uint64_t *min, uint64_t *max, int64_t *importance)
1668efd4c9b6SSteve Lawrence {
1669efd4c9b6SSteve Lawrence 	uint_t old, num;
1670efd4c9b6SSteve Lawrence 
1671efd4c9b6SSteve Lawrence 	pool_conf_t *conf = ctl->zsctl_pool_conf;
1672efd4c9b6SSteve Lawrence 	pool_value_t **vals = ctl->zsctl_pool_vals;
1673efd4c9b6SSteve Lawrence 	pool_resource_t **res_list = NULL;
1674efd4c9b6SSteve Lawrence 	pool_resource_t *pset;
1675efd4c9b6SSteve Lawrence 	pool_component_t **cpus = NULL;
1676efd4c9b6SSteve Lawrence 	processorid_t *cache;
1677efd4c9b6SSteve Lawrence 	const char *string;
1678efd4c9b6SSteve Lawrence 	uint64_t uint64;
1679efd4c9b6SSteve Lawrence 	int64_t int64;
1680efd4c9b6SSteve Lawrence 	int i, ret, type;
1681efd4c9b6SSteve Lawrence 
1682efd4c9b6SSteve Lawrence 	if (ctl->zsctl_pool_status == POOL_DISABLED) {
1683efd4c9b6SSteve Lawrence 
1684efd4c9b6SSteve Lawrence 		/*
1685efd4c9b6SSteve Lawrence 		 * Inspect legacy psets
1686efd4c9b6SSteve Lawrence 		 */
1687efd4c9b6SSteve Lawrence 		for (;;) {
1688efd4c9b6SSteve Lawrence 			old = num = ctl->zsctl_cpu_ncache;
1689efd4c9b6SSteve Lawrence 			ret = pset_info(psetid, &type, &num,
1690efd4c9b6SSteve Lawrence 			    ctl->zsctl_cpu_cache);
1691efd4c9b6SSteve Lawrence 			if (ret < 0) {
1692efd4c9b6SSteve Lawrence 				/* pset is gone.  Tell caller to retry */
1693efd4c9b6SSteve Lawrence 				errno = EINTR;
1694efd4c9b6SSteve Lawrence 				return (-1);
1695efd4c9b6SSteve Lawrence 			}
1696efd4c9b6SSteve Lawrence 			if (num <= old) {
1697efd4c9b6SSteve Lawrence 			/* Success */
1698efd4c9b6SSteve Lawrence 				break;
1699efd4c9b6SSteve Lawrence 			}
1700efd4c9b6SSteve Lawrence 			if ((cache = (processorid_t *)realloc(
1701efd4c9b6SSteve Lawrence 			    ctl->zsctl_cpu_cache, num *
1702efd4c9b6SSteve Lawrence 			    sizeof (processorid_t))) != NULL) {
1703efd4c9b6SSteve Lawrence 				ctl->zsctl_cpu_ncache = num;
1704efd4c9b6SSteve Lawrence 				ctl->zsctl_cpu_cache = cache;
1705efd4c9b6SSteve Lawrence 			} else {
1706efd4c9b6SSteve Lawrence 				/*
1707efd4c9b6SSteve Lawrence 				 * Could not allocate to get new cpu list.
1708efd4c9b6SSteve Lawrence 				 */
1709efd4c9b6SSteve Lawrence 				zsd_warn(gettext(
1710efd4c9b6SSteve Lawrence 				    "Could not allocate for cpu list"));
1711efd4c9b6SSteve Lawrence 				errno = ENOMEM;
1712efd4c9b6SSteve Lawrence 				return (-1);
1713efd4c9b6SSteve Lawrence 			}
1714efd4c9b6SSteve Lawrence 		}
1715efd4c9b6SSteve Lawrence 		/*
1716efd4c9b6SSteve Lawrence 		 * Old school pset.  Just make min and max equal
1717efd4c9b6SSteve Lawrence 		 * to its size
1718efd4c9b6SSteve Lawrence 		 */
1719efd4c9b6SSteve Lawrence 		if (psetid == ZS_PSET_DEFAULT) {
1720efd4c9b6SSteve Lawrence 			*cputype = ZS_CPUTYPE_DEFAULT_PSET;
1721efd4c9b6SSteve Lawrence 			(void) strlcpy(psetname, "pset_default", namelen);
1722efd4c9b6SSteve Lawrence 		} else {
1723efd4c9b6SSteve Lawrence 			*cputype = ZS_CPUTYPE_PSRSET_PSET;
1724efd4c9b6SSteve Lawrence 			(void) snprintf(psetname, namelen,
1725efd4c9b6SSteve Lawrence 			    "SUNWlegacy_pset_%d", psetid);
1726efd4c9b6SSteve Lawrence 		}
1727efd4c9b6SSteve Lawrence 
1728efd4c9b6SSteve Lawrence 		/*
1729efd4c9b6SSteve Lawrence 		 * Just treat legacy pset as a simple pool pset
1730efd4c9b6SSteve Lawrence 		 */
1731efd4c9b6SSteve Lawrence 		*online = num;
1732efd4c9b6SSteve Lawrence 		*size = num;
1733efd4c9b6SSteve Lawrence 		*min = num;
1734efd4c9b6SSteve Lawrence 		*max = num;
1735efd4c9b6SSteve Lawrence 		*importance = 1;
1736efd4c9b6SSteve Lawrence 
1737efd4c9b6SSteve Lawrence 		return (0);
1738efd4c9b6SSteve Lawrence 	}
1739efd4c9b6SSteve Lawrence 
1740efd4c9b6SSteve Lawrence 	/* Look up the pool pset using the pset id */
1741efd4c9b6SSteve Lawrence 	res_list = NULL;
1742efd4c9b6SSteve Lawrence 	pool_value_set_int64(vals[1], psetid);
1743efd4c9b6SSteve Lawrence 	if (pool_value_set_name(vals[1], "pset.sys_id")
1744efd4c9b6SSteve Lawrence 	    != PO_SUCCESS)
1745efd4c9b6SSteve Lawrence 		goto err;
1746efd4c9b6SSteve Lawrence 
1747efd4c9b6SSteve Lawrence 	if (pool_value_set_name(vals[0], "type") != PO_SUCCESS)
1748efd4c9b6SSteve Lawrence 		goto err;
1749efd4c9b6SSteve Lawrence 	if (pool_value_set_string(vals[0], "pset") != PO_SUCCESS)
1750efd4c9b6SSteve Lawrence 		goto err;
1751efd4c9b6SSteve Lawrence 	if ((res_list = pool_query_resources(conf, &num, vals)) == NULL)
1752efd4c9b6SSteve Lawrence 		goto err;
1753efd4c9b6SSteve Lawrence 	if (num != 1)
1754efd4c9b6SSteve Lawrence 		goto err;
1755efd4c9b6SSteve Lawrence 	pset = res_list[0];
1756efd4c9b6SSteve Lawrence 	free(res_list);
1757efd4c9b6SSteve Lawrence 	res_list = NULL;
1758efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf, pset),
1759efd4c9b6SSteve Lawrence 	    "pset.name", vals[0]) != POC_STRING ||
1760efd4c9b6SSteve Lawrence 	    pool_value_get_string(vals[0], &string) != PO_SUCCESS)
1761efd4c9b6SSteve Lawrence 		goto err;
1762efd4c9b6SSteve Lawrence 
1763efd4c9b6SSteve Lawrence 	(void) strlcpy(psetname, string, namelen);
1764efd4c9b6SSteve Lawrence 	if (strncmp(psetname, "SUNWtmp", strlen("SUNWtmp")) == 0)
1765efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_DEDICATED;
1766efd4c9b6SSteve Lawrence 	else if (psetid == ZS_PSET_DEFAULT)
1767efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_DEFAULT_PSET;
1768efd4c9b6SSteve Lawrence 	else
1769efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_POOL_PSET;
1770efd4c9b6SSteve Lawrence 
1771efd4c9b6SSteve Lawrence 	/* Get size, min, max, and importance */
1772efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf,
1773efd4c9b6SSteve Lawrence 	    pset), "pset.size", vals[0]) == POC_UINT &&
1774efd4c9b6SSteve Lawrence 	    pool_value_get_uint64(vals[0], &uint64) == PO_SUCCESS)
1775efd4c9b6SSteve Lawrence 		*size = uint64;
1776efd4c9b6SSteve Lawrence 	else
1777efd4c9b6SSteve Lawrence 		*size = 0;
1778efd4c9b6SSteve Lawrence 
1779efd4c9b6SSteve Lawrence 		/* Get size, min, max, and importance */
1780efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf,
1781efd4c9b6SSteve Lawrence 	    pset), "pset.min", vals[0]) == POC_UINT &&
1782efd4c9b6SSteve Lawrence 	    pool_value_get_uint64(vals[0], &uint64) == PO_SUCCESS)
1783efd4c9b6SSteve Lawrence 		*min = uint64;
1784efd4c9b6SSteve Lawrence 	else
1785efd4c9b6SSteve Lawrence 		*min = 0;
1786efd4c9b6SSteve Lawrence 	if (*min >= ZSD_PSET_UNLIMITED)
1787efd4c9b6SSteve Lawrence 		*min = ZS_LIMIT_NONE;
1788efd4c9b6SSteve Lawrence 
1789efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf,
1790efd4c9b6SSteve Lawrence 	    pset), "pset.max", vals[0]) == POC_UINT &&
1791efd4c9b6SSteve Lawrence 	    pool_value_get_uint64(vals[0], &uint64) == PO_SUCCESS)
1792efd4c9b6SSteve Lawrence 		*max = uint64;
1793efd4c9b6SSteve Lawrence 	else
1794efd4c9b6SSteve Lawrence 		*max = ZS_LIMIT_NONE;
1795efd4c9b6SSteve Lawrence 
1796efd4c9b6SSteve Lawrence 	if (*max >= ZSD_PSET_UNLIMITED)
1797efd4c9b6SSteve Lawrence 		*max = ZS_LIMIT_NONE;
1798efd4c9b6SSteve Lawrence 
1799efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf,
1800efd4c9b6SSteve Lawrence 	    pset), "pset.importance", vals[0]) == POC_INT &&
1801efd4c9b6SSteve Lawrence 	    pool_value_get_int64(vals[0], &int64) == PO_SUCCESS)
1802efd4c9b6SSteve Lawrence 		*importance = int64;
1803efd4c9b6SSteve Lawrence 	else
1804efd4c9b6SSteve Lawrence 		*importance = (uint64_t)1;
1805efd4c9b6SSteve Lawrence 
1806efd4c9b6SSteve Lawrence 	*online = 0;
1807efd4c9b6SSteve Lawrence 	if (*size == 0)
1808efd4c9b6SSteve Lawrence 		return (0);
1809efd4c9b6SSteve Lawrence 
1810efd4c9b6SSteve Lawrence 	/* get cpus */
1811efd4c9b6SSteve Lawrence 	cpus = pool_query_resource_components(conf, pset, &num, NULL);
1812efd4c9b6SSteve Lawrence 	if (cpus == NULL)
1813efd4c9b6SSteve Lawrence 		goto err;
1814efd4c9b6SSteve Lawrence 
1815efd4c9b6SSteve Lawrence 	/* Make sure there is space for cpu id list */
1816efd4c9b6SSteve Lawrence 	if (num > ctl->zsctl_cpu_ncache) {
1817efd4c9b6SSteve Lawrence 		if ((cache = (processorid_t *)realloc(
1818efd4c9b6SSteve Lawrence 		    ctl->zsctl_cpu_cache, num *
1819efd4c9b6SSteve Lawrence 		    sizeof (processorid_t))) != NULL) {
1820efd4c9b6SSteve Lawrence 			ctl->zsctl_cpu_ncache = num;
1821efd4c9b6SSteve Lawrence 			ctl->zsctl_cpu_cache = cache;
1822efd4c9b6SSteve Lawrence 		} else {
1823efd4c9b6SSteve Lawrence 			/*
1824efd4c9b6SSteve Lawrence 			 * Could not allocate to get new cpu list.
1825efd4c9b6SSteve Lawrence 			 */
1826efd4c9b6SSteve Lawrence 			zsd_warn(gettext(
1827efd4c9b6SSteve Lawrence 			    "Could not allocate for cpu list"));
1828efd4c9b6SSteve Lawrence 			goto err;
1829efd4c9b6SSteve Lawrence 		}
1830efd4c9b6SSteve Lawrence 	}
1831efd4c9b6SSteve Lawrence 
1832efd4c9b6SSteve Lawrence 	/* count the online cpus */
1833efd4c9b6SSteve Lawrence 	for (i = 0; i < num; i++) {
1834efd4c9b6SSteve Lawrence 		if (pool_get_property(conf, pool_component_to_elem(
1835efd4c9b6SSteve Lawrence 		    conf, cpus[i]), "cpu.status", vals[0]) != POC_STRING ||
1836efd4c9b6SSteve Lawrence 		    pool_value_get_string(vals[0], &string) != PO_SUCCESS)
1837efd4c9b6SSteve Lawrence 			goto err;
1838efd4c9b6SSteve Lawrence 
1839efd4c9b6SSteve Lawrence 		if (strcmp(string, "on-line") != 0 &&
1840efd4c9b6SSteve Lawrence 		    strcmp(string, "no-intr") != 0)
1841efd4c9b6SSteve Lawrence 			continue;
1842efd4c9b6SSteve Lawrence 
1843efd4c9b6SSteve Lawrence 		if (pool_get_property(conf, pool_component_to_elem(
1844efd4c9b6SSteve Lawrence 		    conf, cpus[i]), "cpu.sys_id", vals[0]) != POC_INT ||
1845efd4c9b6SSteve Lawrence 		    pool_value_get_int64(vals[0], &int64) != PO_SUCCESS)
1846efd4c9b6SSteve Lawrence 			goto err;
1847efd4c9b6SSteve Lawrence 
1848efd4c9b6SSteve Lawrence 		(*online)++;
1849efd4c9b6SSteve Lawrence 		ctl->zsctl_cpu_cache[i] = (psetid_t)int64;
1850efd4c9b6SSteve Lawrence 	}
1851efd4c9b6SSteve Lawrence 	free(cpus);
1852efd4c9b6SSteve Lawrence 	return (0);
1853efd4c9b6SSteve Lawrence err:
1854efd4c9b6SSteve Lawrence 	if (res_list != NULL)
1855efd4c9b6SSteve Lawrence 		free(res_list);
1856efd4c9b6SSteve Lawrence 	if (cpus != NULL)
1857efd4c9b6SSteve Lawrence 		free(cpus);
1858efd4c9b6SSteve Lawrence 
1859efd4c9b6SSteve Lawrence 	/*
1860efd4c9b6SSteve Lawrence 	 * The pools operations should succeed since the conf is a consistent
1861efd4c9b6SSteve Lawrence 	 * snapshot.  Tell caller there is no need to retry.
1862efd4c9b6SSteve Lawrence 	 */
1863efd4c9b6SSteve Lawrence 	errno = EINVAL;
1864efd4c9b6SSteve Lawrence 	return (-1);
1865efd4c9b6SSteve Lawrence }
1866efd4c9b6SSteve Lawrence 
1867efd4c9b6SSteve Lawrence /*
1868efd4c9b6SSteve Lawrence  * Update the current list of processor sets.
1869efd4c9b6SSteve Lawrence  * This also updates the list of online cpus, and each cpu's pset membership.
1870efd4c9b6SSteve Lawrence  */
1871efd4c9b6SSteve Lawrence static void
zsd_refresh_psets(zsd_ctl_t * ctl)1872efd4c9b6SSteve Lawrence zsd_refresh_psets(zsd_ctl_t *ctl)
1873efd4c9b6SSteve Lawrence {
1874efd4c9b6SSteve Lawrence 	int i, j, ret, state;
1875efd4c9b6SSteve Lawrence 	uint_t old, num;
1876efd4c9b6SSteve Lawrence 	uint_t cputype;
1877efd4c9b6SSteve Lawrence 	int64_t sys_id, importance;
1878efd4c9b6SSteve Lawrence 	uint64_t online, size, min, max;
1879efd4c9b6SSteve Lawrence 	zsd_system_t *system;
1880efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
1881efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu;
1882efd4c9b6SSteve Lawrence 	psetid_t *cache;
1883efd4c9b6SSteve Lawrence 	char psetname[ZS_PSETNAME_MAX];
1884efd4c9b6SSteve Lawrence 	processorid_t cpuid;
1885efd4c9b6SSteve Lawrence 	pool_value_t *pv_save = NULL;
1886efd4c9b6SSteve Lawrence 	pool_resource_t **res_list = NULL;
1887efd4c9b6SSteve Lawrence 	pool_resource_t *res;
1888efd4c9b6SSteve Lawrence 	pool_value_t **vals;
1889efd4c9b6SSteve Lawrence 	pool_conf_t *conf;
1890efd4c9b6SSteve Lawrence 	boolean_t roll_cpus = B_TRUE;
1891efd4c9b6SSteve Lawrence 
1892efd4c9b6SSteve Lawrence 	/* Zero cpu counters to recount them */
1893efd4c9b6SSteve Lawrence 	system = ctl->zsctl_system;
1894efd4c9b6SSteve Lawrence 	system->zss_ncpus = 0;
1895efd4c9b6SSteve Lawrence 	system->zss_ncpus_online = 0;
1896efd4c9b6SSteve Lawrence retry:
1897efd4c9b6SSteve Lawrence 	ret = pool_get_status(&state);
1898efd4c9b6SSteve Lawrence 	if (ret == 0 && state == POOL_ENABLED) {
1899efd4c9b6SSteve Lawrence 
1900efd4c9b6SSteve Lawrence 		conf = ctl->zsctl_pool_conf;
1901efd4c9b6SSteve Lawrence 		vals = ctl->zsctl_pool_vals;
1902efd4c9b6SSteve Lawrence 		pv_save = vals[1];
1903efd4c9b6SSteve Lawrence 		vals[1] = NULL;
1904efd4c9b6SSteve Lawrence 
1905efd4c9b6SSteve Lawrence 		if (ctl->zsctl_pool_status == POOL_DISABLED) {
1906efd4c9b6SSteve Lawrence 			if (pool_conf_open(ctl->zsctl_pool_conf,
1907efd4c9b6SSteve Lawrence 			    pool_dynamic_location(), PO_RDONLY) == 0) {
1908efd4c9b6SSteve Lawrence 				ctl->zsctl_pool_status = POOL_ENABLED;
1909efd4c9b6SSteve Lawrence 				ctl->zsctl_pool_changed = POU_PSET;
1910efd4c9b6SSteve Lawrence 			}
1911efd4c9b6SSteve Lawrence 		} else {
1912efd4c9b6SSteve Lawrence 			ctl->zsctl_pool_changed = 0;
1913efd4c9b6SSteve Lawrence 			ret = pool_conf_update(ctl->zsctl_pool_conf,
1914efd4c9b6SSteve Lawrence 			    &(ctl->zsctl_pool_changed));
1915efd4c9b6SSteve Lawrence 			if (ret < 0) {
1916efd4c9b6SSteve Lawrence 				/* Pools must have become disabled */
1917efd4c9b6SSteve Lawrence 				(void) pool_conf_close(ctl->zsctl_pool_conf);
1918efd4c9b6SSteve Lawrence 				ctl->zsctl_pool_status = POOL_DISABLED;
1919efd4c9b6SSteve Lawrence 				if (pool_error() == POE_SYSTEM && errno ==
1920efd4c9b6SSteve Lawrence 				    ENOTACTIVE)
1921efd4c9b6SSteve Lawrence 					goto retry;
1922efd4c9b6SSteve Lawrence 
1923efd4c9b6SSteve Lawrence 				zsd_warn(gettext(
1924efd4c9b6SSteve Lawrence 				    "Unable to update pool configuration"));
1925efd4c9b6SSteve Lawrence 				/* Not able to get pool info.  Don't update. */
1926efd4c9b6SSteve Lawrence 				goto err;
1927efd4c9b6SSteve Lawrence 			}
1928efd4c9b6SSteve Lawrence 		}
1929efd4c9b6SSteve Lawrence 		/* Get the list of psets using libpool */
1930efd4c9b6SSteve Lawrence 		if (pool_value_set_name(vals[0], "type") != PO_SUCCESS)
1931efd4c9b6SSteve Lawrence 			goto err;
1932efd4c9b6SSteve Lawrence 
1933efd4c9b6SSteve Lawrence 		if (pool_value_set_string(vals[0], "pset") != PO_SUCCESS)
1934efd4c9b6SSteve Lawrence 			goto err;
1935efd4c9b6SSteve Lawrence 		if ((res_list = pool_query_resources(conf, &num, vals))
1936efd4c9b6SSteve Lawrence 		    == NULL)
1937efd4c9b6SSteve Lawrence 			goto err;
1938efd4c9b6SSteve Lawrence 
1939efd4c9b6SSteve Lawrence 		if (num > ctl->zsctl_pset_ncache)  {
1940efd4c9b6SSteve Lawrence 			if ((cache = (psetid_t *)realloc(ctl->zsctl_pset_cache,
1941efd4c9b6SSteve Lawrence 			    (num) * sizeof (psetid_t))) == NULL) {
1942efd4c9b6SSteve Lawrence 				goto err;
1943efd4c9b6SSteve Lawrence 			}
1944efd4c9b6SSteve Lawrence 			ctl->zsctl_pset_ncache = num;
1945efd4c9b6SSteve Lawrence 			ctl->zsctl_pset_cache = cache;
1946efd4c9b6SSteve Lawrence 		}
1947efd4c9b6SSteve Lawrence 		/* Save the pset id of each pset */
1948efd4c9b6SSteve Lawrence 		for (i = 0; i < num; i++) {
1949efd4c9b6SSteve Lawrence 			res = res_list[i];
1950efd4c9b6SSteve Lawrence 			if (pool_get_property(conf, pool_resource_to_elem(conf,
1951efd4c9b6SSteve Lawrence 			    res), "pset.sys_id", vals[0]) != POC_INT ||
1952efd4c9b6SSteve Lawrence 			    pool_value_get_int64(vals[0], &sys_id)
1953efd4c9b6SSteve Lawrence 			    != PO_SUCCESS)
1954efd4c9b6SSteve Lawrence 				goto err;
1955efd4c9b6SSteve Lawrence 			ctl->zsctl_pset_cache[i] = (int)sys_id;
1956efd4c9b6SSteve Lawrence 		}
1957efd4c9b6SSteve Lawrence 		vals[1] = pv_save;
1958efd4c9b6SSteve Lawrence 		pv_save = NULL;
1959efd4c9b6SSteve Lawrence 	} else {
1960efd4c9b6SSteve Lawrence 		if (ctl->zsctl_pool_status == POOL_ENABLED) {
1961efd4c9b6SSteve Lawrence 			(void) pool_conf_close(ctl->zsctl_pool_conf);
1962efd4c9b6SSteve Lawrence 			ctl->zsctl_pool_status = POOL_DISABLED;
1963efd4c9b6SSteve Lawrence 		}
1964efd4c9b6SSteve Lawrence 		/* Get the pset list using legacy psets */
1965efd4c9b6SSteve Lawrence 		for (;;) {
1966efd4c9b6SSteve Lawrence 			old = num = ctl->zsctl_pset_ncache;
1967efd4c9b6SSteve Lawrence 			(void) pset_list(ctl->zsctl_pset_cache, &num);
1968efd4c9b6SSteve Lawrence 			if ((num + 1) <= old) {
1969efd4c9b6SSteve Lawrence 				break;
1970efd4c9b6SSteve Lawrence 			}
1971efd4c9b6SSteve Lawrence 			if ((cache = (psetid_t *)realloc(ctl->zsctl_pset_cache,
1972efd4c9b6SSteve Lawrence 			    (num + 1) * sizeof (psetid_t))) != NULL) {
1973efd4c9b6SSteve Lawrence 				ctl->zsctl_pset_ncache = num + 1;
1974efd4c9b6SSteve Lawrence 				ctl->zsctl_pset_cache = cache;
1975efd4c9b6SSteve Lawrence 			} else {
1976efd4c9b6SSteve Lawrence 				/*
1977efd4c9b6SSteve Lawrence 				 * Could not allocate to get new pset list.
1978efd4c9b6SSteve Lawrence 				 * Give up
1979efd4c9b6SSteve Lawrence 				 */
1980efd4c9b6SSteve Lawrence 				return;
1981efd4c9b6SSteve Lawrence 			}
1982efd4c9b6SSteve Lawrence 		}
1983efd4c9b6SSteve Lawrence 		/* Add the default pset to list */
1984efd4c9b6SSteve Lawrence 		ctl->zsctl_pset_cache[num] = ctl->zsctl_pset_cache[0];
1985efd4c9b6SSteve Lawrence 		ctl->zsctl_pset_cache[0] = ZS_PSET_DEFAULT;
1986efd4c9b6SSteve Lawrence 		num++;
1987efd4c9b6SSteve Lawrence 	}
1988efd4c9b6SSteve Lawrence psets_changed:
1989efd4c9b6SSteve Lawrence 	zsd_mark_cpus_start(ctl, roll_cpus);
1990efd4c9b6SSteve Lawrence 	zsd_mark_psets_start(ctl);
1991efd4c9b6SSteve Lawrence 	roll_cpus = B_FALSE;
1992efd4c9b6SSteve Lawrence 
1993efd4c9b6SSteve Lawrence 	/* Refresh cpu membership of all psets */
1994efd4c9b6SSteve Lawrence 	for (i = 0; i < num; i++) {
1995efd4c9b6SSteve Lawrence 
1996efd4c9b6SSteve Lawrence 		/* Get pool pset information */
1997efd4c9b6SSteve Lawrence 		sys_id = ctl->zsctl_pset_cache[i];
1998efd4c9b6SSteve Lawrence 		if (zsd_get_pool_pset(ctl, sys_id, psetname, sizeof (psetname),
1999efd4c9b6SSteve Lawrence 		    &cputype, &online, &size, &min, &max, &importance)
2000efd4c9b6SSteve Lawrence 		    != 0) {
2001efd4c9b6SSteve Lawrence 			if (errno == EINTR)
2002efd4c9b6SSteve Lawrence 				goto psets_changed;
2003efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Failed to get info for pset %d"),
2004efd4c9b6SSteve Lawrence 			    sys_id);
2005efd4c9b6SSteve Lawrence 			continue;
2006efd4c9b6SSteve Lawrence 		}
2007efd4c9b6SSteve Lawrence 
2008efd4c9b6SSteve Lawrence 		system->zss_ncpus += size;
2009efd4c9b6SSteve Lawrence 		system->zss_ncpus_online += online;
2010efd4c9b6SSteve Lawrence 
2011efd4c9b6SSteve Lawrence 		pset = zsd_lookup_insert_pset(ctl, psetname,
2012efd4c9b6SSteve Lawrence 		    ctl->zsctl_pset_cache[i]);
2013efd4c9b6SSteve Lawrence 
2014efd4c9b6SSteve Lawrence 		/* update pset info */
2015efd4c9b6SSteve Lawrence 		zsd_mark_pset_found(pset, cputype, online, size, min,
2016efd4c9b6SSteve Lawrence 		    max, importance);
2017efd4c9b6SSteve Lawrence 
2018efd4c9b6SSteve Lawrence 		/* update each cpu in pset */
2019efd4c9b6SSteve Lawrence 		for (j = 0; j < pset->zsp_online; j++) {
2020efd4c9b6SSteve Lawrence 			cpuid = ctl->zsctl_cpu_cache[j];
2021efd4c9b6SSteve Lawrence 			cpu = zsd_lookup_insert_cpu(ctl, cpuid);
2022efd4c9b6SSteve Lawrence 			zsd_mark_cpu_found(cpu, pset, sys_id);
2023efd4c9b6SSteve Lawrence 		}
2024efd4c9b6SSteve Lawrence 	}
2025efd4c9b6SSteve Lawrence err:
2026efd4c9b6SSteve Lawrence 	if (res_list != NULL)
2027efd4c9b6SSteve Lawrence 		free(res_list);
2028efd4c9b6SSteve Lawrence 	if (pv_save != NULL)
2029efd4c9b6SSteve Lawrence 		vals[1] = pv_save;
2030efd4c9b6SSteve Lawrence }
2031efd4c9b6SSteve Lawrence 
2032efd4c9b6SSteve Lawrence 
2033efd4c9b6SSteve Lawrence 
2034efd4c9b6SSteve Lawrence /*
2035efd4c9b6SSteve Lawrence  * Fetch the current pool and pset name for the given zone.
2036efd4c9b6SSteve Lawrence  */
2037efd4c9b6SSteve Lawrence static void
zsd_get_zone_pool_pset(zsd_ctl_t * ctl,zsd_zone_t * zone,char * pool,int poollen,char * pset,int psetlen,uint_t * cputype)2038efd4c9b6SSteve Lawrence zsd_get_zone_pool_pset(zsd_ctl_t *ctl, zsd_zone_t *zone,
2039efd4c9b6SSteve Lawrence     char *pool, int poollen, char *pset, int psetlen, uint_t *cputype)
2040efd4c9b6SSteve Lawrence {
2041efd4c9b6SSteve Lawrence 	poolid_t poolid;
2042efd4c9b6SSteve Lawrence 	pool_t **pools = NULL;
2043efd4c9b6SSteve Lawrence 	pool_resource_t **res_list = NULL;
2044efd4c9b6SSteve Lawrence 	char poolname[ZS_POOLNAME_MAX];
2045efd4c9b6SSteve Lawrence 	char psetname[ZS_PSETNAME_MAX];
2046efd4c9b6SSteve Lawrence 	pool_conf_t *conf = ctl->zsctl_pool_conf;
2047efd4c9b6SSteve Lawrence 	pool_value_t *pv_save = NULL;
2048efd4c9b6SSteve Lawrence 	pool_value_t **vals = ctl->zsctl_pool_vals;
2049efd4c9b6SSteve Lawrence 	const char *string;
2050efd4c9b6SSteve Lawrence 	int ret;
2051efd4c9b6SSteve Lawrence 	int64_t int64;
2052efd4c9b6SSteve Lawrence 	uint_t num;
2053efd4c9b6SSteve Lawrence 
2054efd4c9b6SSteve Lawrence 	ret = zone_getattr(zone->zsz_id, ZONE_ATTR_POOLID,
2055efd4c9b6SSteve Lawrence 	    &poolid, sizeof (poolid));
2056efd4c9b6SSteve Lawrence 	if (ret < 0)
2057efd4c9b6SSteve Lawrence 		goto lookup_done;
2058efd4c9b6SSteve Lawrence 
2059efd4c9b6SSteve Lawrence 	pv_save = vals[1];
2060efd4c9b6SSteve Lawrence 	vals[1] = NULL;
2061efd4c9b6SSteve Lawrence 	pools = NULL;
2062efd4c9b6SSteve Lawrence 	res_list = NULL;
2063efd4c9b6SSteve Lawrence 
2064efd4c9b6SSteve Lawrence 	/* Default values if lookup fails */
2065efd4c9b6SSteve Lawrence 	(void) strlcpy(poolname, "pool_default", sizeof (poolname));
2066efd4c9b6SSteve Lawrence 	(void) strlcpy(psetname, "pset_default", sizeof (poolname));
2067efd4c9b6SSteve Lawrence 	*cputype = ZS_CPUTYPE_DEFAULT_PSET;
2068efd4c9b6SSteve Lawrence 
2069efd4c9b6SSteve Lawrence 	/* no dedicated cpu if pools are disabled */
2070efd4c9b6SSteve Lawrence 	if (ctl->zsctl_pool_status == POOL_DISABLED)
2071efd4c9b6SSteve Lawrence 		goto lookup_done;
2072efd4c9b6SSteve Lawrence 
2073efd4c9b6SSteve Lawrence 	/* Get the pool name using the id */
2074efd4c9b6SSteve Lawrence 	pool_value_set_int64(vals[0], poolid);
2075efd4c9b6SSteve Lawrence 	if (pool_value_set_name(vals[0], "pool.sys_id") != PO_SUCCESS)
2076efd4c9b6SSteve Lawrence 		goto lookup_done;
2077efd4c9b6SSteve Lawrence 
2078efd4c9b6SSteve Lawrence 	if ((pools = pool_query_pools(conf, &num, vals)) == NULL)
2079efd4c9b6SSteve Lawrence 		goto lookup_done;
2080efd4c9b6SSteve Lawrence 
2081efd4c9b6SSteve Lawrence 	if (num != 1)
2082efd4c9b6SSteve Lawrence 		goto lookup_done;
2083efd4c9b6SSteve Lawrence 
2084efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_to_elem(conf, pools[0]),
2085efd4c9b6SSteve Lawrence 	    "pool.name", vals[0]) != POC_STRING ||
2086efd4c9b6SSteve Lawrence 	    pool_value_get_string(vals[0], &string) != PO_SUCCESS)
2087efd4c9b6SSteve Lawrence 		goto lookup_done;
2088efd4c9b6SSteve Lawrence 	(void) strlcpy(poolname, (char *)string, sizeof (poolname));
2089efd4c9b6SSteve Lawrence 
2090efd4c9b6SSteve Lawrence 	/* Get the name of the pset for the pool */
2091efd4c9b6SSteve Lawrence 	if (pool_value_set_name(vals[0], "type") != PO_SUCCESS)
2092efd4c9b6SSteve Lawrence 		goto lookup_done;
2093efd4c9b6SSteve Lawrence 
2094efd4c9b6SSteve Lawrence 	if (pool_value_set_string(vals[0], "pset") != PO_SUCCESS)
2095efd4c9b6SSteve Lawrence 		goto lookup_done;
2096efd4c9b6SSteve Lawrence 
2097efd4c9b6SSteve Lawrence 	if ((res_list = pool_query_pool_resources(conf, pools[0], &num, vals))
2098efd4c9b6SSteve Lawrence 	    == NULL)
2099efd4c9b6SSteve Lawrence 		goto lookup_done;
2100efd4c9b6SSteve Lawrence 
2101efd4c9b6SSteve Lawrence 	if (num != 1)
2102efd4c9b6SSteve Lawrence 		goto lookup_done;
2103efd4c9b6SSteve Lawrence 
2104efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf,
2105efd4c9b6SSteve Lawrence 	    res_list[0]), "pset.sys_id", vals[0]) != POC_INT ||
2106efd4c9b6SSteve Lawrence 	    pool_value_get_int64(vals[0], &int64) != PO_SUCCESS)
2107efd4c9b6SSteve Lawrence 		goto lookup_done;
2108efd4c9b6SSteve Lawrence 
2109efd4c9b6SSteve Lawrence 	if (int64 == ZS_PSET_DEFAULT)
2110efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_DEFAULT_PSET;
2111efd4c9b6SSteve Lawrence 
2112efd4c9b6SSteve Lawrence 	if (pool_get_property(conf, pool_resource_to_elem(conf,
2113efd4c9b6SSteve Lawrence 	    res_list[0]), "pset.name", vals[0]) != POC_STRING ||
2114efd4c9b6SSteve Lawrence 	    pool_value_get_string(vals[0], &string) != PO_SUCCESS)
2115efd4c9b6SSteve Lawrence 		goto lookup_done;
2116efd4c9b6SSteve Lawrence 
2117efd4c9b6SSteve Lawrence 	(void) strlcpy(psetname, (char *)string, sizeof (psetname));
2118efd4c9b6SSteve Lawrence 
2119efd4c9b6SSteve Lawrence 	if (strncmp(psetname, "SUNWtmp_", strlen("SUNWtmp_")) == 0)
2120efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_DEDICATED;
2121efd4c9b6SSteve Lawrence 	if (strncmp(psetname, "SUNW_legacy_", strlen("SUNW_legacy_")) == 0)
2122efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_PSRSET_PSET;
2123efd4c9b6SSteve Lawrence 	else
2124efd4c9b6SSteve Lawrence 		*cputype = ZS_CPUTYPE_POOL_PSET;
2125efd4c9b6SSteve Lawrence 
2126efd4c9b6SSteve Lawrence lookup_done:
2127efd4c9b6SSteve Lawrence 
2128efd4c9b6SSteve Lawrence 	if (pv_save != NULL)
2129efd4c9b6SSteve Lawrence 		vals[1] = pv_save;
2130efd4c9b6SSteve Lawrence 
2131efd4c9b6SSteve Lawrence 	if (res_list)
2132efd4c9b6SSteve Lawrence 		free(res_list);
2133efd4c9b6SSteve Lawrence 	if (pools)
2134efd4c9b6SSteve Lawrence 		free(pools);
2135efd4c9b6SSteve Lawrence 
2136efd4c9b6SSteve Lawrence 	(void) strlcpy(pool, poolname, poollen);
2137efd4c9b6SSteve Lawrence 	(void) strlcpy(pset, psetname, psetlen);
2138efd4c9b6SSteve Lawrence }
2139efd4c9b6SSteve Lawrence 
2140efd4c9b6SSteve Lawrence /* Convert scheduler names to ZS_* scheduler flags */
2141efd4c9b6SSteve Lawrence static uint_t
zsd_schedname2int(char * clname,int pri)2142efd4c9b6SSteve Lawrence zsd_schedname2int(char *clname, int pri)
2143efd4c9b6SSteve Lawrence {
2144efd4c9b6SSteve Lawrence 	uint_t sched = 0;
2145efd4c9b6SSteve Lawrence 
2146efd4c9b6SSteve Lawrence 	if (strcmp(clname, "TS") == 0) {
2147efd4c9b6SSteve Lawrence 		sched = ZS_SCHED_TS;
2148efd4c9b6SSteve Lawrence 	} else if (strcmp(clname, "IA") == 0) {
2149efd4c9b6SSteve Lawrence 		sched = ZS_SCHED_IA;
2150efd4c9b6SSteve Lawrence 	} else if (strcmp(clname, "FX") == 0) {
2151efd4c9b6SSteve Lawrence 		if (pri > 59) {
2152efd4c9b6SSteve Lawrence 			sched = ZS_SCHED_FX_60;
2153efd4c9b6SSteve Lawrence 		} else {
2154efd4c9b6SSteve Lawrence 			sched = ZS_SCHED_FX;
2155efd4c9b6SSteve Lawrence 		}
2156efd4c9b6SSteve Lawrence 	} else if (strcmp(clname, "RT") == 0) {
2157efd4c9b6SSteve Lawrence 		sched = ZS_SCHED_RT;
2158efd4c9b6SSteve Lawrence 
2159efd4c9b6SSteve Lawrence 	} else if (strcmp(clname, "FSS") == 0) {
2160efd4c9b6SSteve Lawrence 		sched = ZS_SCHED_FSS;
2161efd4c9b6SSteve Lawrence 	}
2162efd4c9b6SSteve Lawrence 	return (sched);
2163efd4c9b6SSteve Lawrence }
2164efd4c9b6SSteve Lawrence 
2165efd4c9b6SSteve Lawrence static uint64_t
zsd_get_zone_rctl_limit(char * name)2166efd4c9b6SSteve Lawrence zsd_get_zone_rctl_limit(char *name)
2167efd4c9b6SSteve Lawrence {
2168efd4c9b6SSteve Lawrence 	rctlblk_t *rblk;
2169efd4c9b6SSteve Lawrence 
2170efd4c9b6SSteve Lawrence 	rblk = (rctlblk_t *)alloca(rctlblk_size());
2171efd4c9b6SSteve Lawrence 	if (getrctl(name, NULL, rblk, RCTL_FIRST)
2172efd4c9b6SSteve Lawrence 	    != 0) {
2173efd4c9b6SSteve Lawrence 		return (ZS_LIMIT_NONE);
2174efd4c9b6SSteve Lawrence 	}
2175efd4c9b6SSteve Lawrence 	return (rctlblk_get_value(rblk));
2176efd4c9b6SSteve Lawrence }
2177efd4c9b6SSteve Lawrence 
2178efd4c9b6SSteve Lawrence static uint64_t
zsd_get_zone_rctl_usage(char * name)2179efd4c9b6SSteve Lawrence zsd_get_zone_rctl_usage(char *name)
2180efd4c9b6SSteve Lawrence {
2181efd4c9b6SSteve Lawrence 	rctlblk_t *rblk;
2182efd4c9b6SSteve Lawrence 
2183efd4c9b6SSteve Lawrence 	rblk = (rctlblk_t *)alloca(rctlblk_size());
2184efd4c9b6SSteve Lawrence 	if (getrctl(name, NULL, rblk, RCTL_USAGE)
2185efd4c9b6SSteve Lawrence 	    != 0) {
2186efd4c9b6SSteve Lawrence 		return (0);
2187efd4c9b6SSteve Lawrence 	}
2188efd4c9b6SSteve Lawrence 	return (rctlblk_get_value(rblk));
2189efd4c9b6SSteve Lawrence }
2190efd4c9b6SSteve Lawrence 
2191efd4c9b6SSteve Lawrence #define	ZSD_NUM_RCTL_VALS 19
2192efd4c9b6SSteve Lawrence 
2193efd4c9b6SSteve Lawrence /*
2194efd4c9b6SSteve Lawrence  * Fetch the limit information for a zone.  This uses zone_enter() as the
2195efd4c9b6SSteve Lawrence  * getrctl(2) system call only returns rctl information for the zone of
2196efd4c9b6SSteve Lawrence  * the caller.
2197efd4c9b6SSteve Lawrence  */
2198efd4c9b6SSteve Lawrence static int
zsd_get_zone_caps(zsd_ctl_t * ctl,zsd_zone_t * zone,uint64_t * cpu_shares,uint64_t * cpu_cap,uint64_t * ram_cap,uint64_t * locked_cap,uint64_t * vm_cap,uint64_t * processes_cap,uint64_t * processes,uint64_t * lwps_cap,uint64_t * lwps,uint64_t * shm_cap,uint64_t * shm,uint64_t * shmids_cap,uint64_t * shmids,uint64_t * semids_cap,uint64_t * semids,uint64_t * msgids_cap,uint64_t * msgids,uint64_t * lofi_cap,uint64_t * lofi,uint_t * sched)2199efd4c9b6SSteve Lawrence zsd_get_zone_caps(zsd_ctl_t *ctl, zsd_zone_t *zone, uint64_t *cpu_shares,
2200efd4c9b6SSteve Lawrence     uint64_t *cpu_cap, uint64_t *ram_cap, uint64_t *locked_cap,
2201efd4c9b6SSteve Lawrence     uint64_t *vm_cap, uint64_t *processes_cap, uint64_t *processes,
2202efd4c9b6SSteve Lawrence     uint64_t *lwps_cap, uint64_t *lwps, uint64_t *shm_cap, uint64_t *shm,
2203efd4c9b6SSteve Lawrence     uint64_t *shmids_cap, uint64_t *shmids, uint64_t *semids_cap,
2204efd4c9b6SSteve Lawrence     uint64_t *semids, uint64_t *msgids_cap, uint64_t *msgids,
2205efd4c9b6SSteve Lawrence     uint64_t *lofi_cap, uint64_t *lofi, uint_t *sched)
2206efd4c9b6SSteve Lawrence {
2207efd4c9b6SSteve Lawrence 	int p[2], pid, tmpl_fd, ret;
2208efd4c9b6SSteve Lawrence 	ctid_t ct;
2209efd4c9b6SSteve Lawrence 	char class[PC_CLNMSZ];
2210efd4c9b6SSteve Lawrence 	uint64_t vals[ZSD_NUM_RCTL_VALS];
2211efd4c9b6SSteve Lawrence 	zsd_system_t *sys = ctl->zsctl_system;
2212efd4c9b6SSteve Lawrence 	int i = 0;
2213efd4c9b6SSteve Lawrence 	int res = 0;
2214efd4c9b6SSteve Lawrence 
2215efd4c9b6SSteve Lawrence 	/* Treat all caps as no cap on error */
2216efd4c9b6SSteve Lawrence 	*cpu_shares = ZS_LIMIT_NONE;
2217efd4c9b6SSteve Lawrence 	*cpu_cap = ZS_LIMIT_NONE;
2218efd4c9b6SSteve Lawrence 	*ram_cap = ZS_LIMIT_NONE;
2219efd4c9b6SSteve Lawrence 	*locked_cap = ZS_LIMIT_NONE;
2220efd4c9b6SSteve Lawrence 	*vm_cap = ZS_LIMIT_NONE;
2221efd4c9b6SSteve Lawrence 
2222efd4c9b6SSteve Lawrence 	*processes_cap = ZS_LIMIT_NONE;
2223efd4c9b6SSteve Lawrence 	*lwps_cap = ZS_LIMIT_NONE;
2224efd4c9b6SSteve Lawrence 	*shm_cap = ZS_LIMIT_NONE;
2225efd4c9b6SSteve Lawrence 	*shmids_cap = ZS_LIMIT_NONE;
2226efd4c9b6SSteve Lawrence 	*semids_cap = ZS_LIMIT_NONE;
2227efd4c9b6SSteve Lawrence 	*msgids_cap = ZS_LIMIT_NONE;
2228efd4c9b6SSteve Lawrence 	*lofi_cap = ZS_LIMIT_NONE;
2229efd4c9b6SSteve Lawrence 
2230efd4c9b6SSteve Lawrence 	*processes = 0;
2231efd4c9b6SSteve Lawrence 	*lwps = 0;
2232efd4c9b6SSteve Lawrence 	*shm = 0;
2233efd4c9b6SSteve Lawrence 	*shmids = 0;
2234efd4c9b6SSteve Lawrence 	*semids = 0;
2235efd4c9b6SSteve Lawrence 	*msgids = 0;
2236efd4c9b6SSteve Lawrence 	*lofi = 0;
2237efd4c9b6SSteve Lawrence 
2238efd4c9b6SSteve Lawrence 	/* Get the ram cap first since it is a zone attr */
2239efd4c9b6SSteve Lawrence 	ret = zone_getattr(zone->zsz_id, ZONE_ATTR_PHYS_MCAP,
2240efd4c9b6SSteve Lawrence 	    ram_cap, sizeof (*ram_cap));
2241efd4c9b6SSteve Lawrence 	if (ret < 0 || *ram_cap == 0)
2242efd4c9b6SSteve Lawrence 		*ram_cap = ZS_LIMIT_NONE;
2243efd4c9b6SSteve Lawrence 
2244efd4c9b6SSteve Lawrence 	/* Get the zone's default scheduling class */
2245efd4c9b6SSteve Lawrence 	ret = zone_getattr(zone->zsz_id, ZONE_ATTR_SCHED_CLASS,
2246efd4c9b6SSteve Lawrence 	    class, sizeof (class));
2247efd4c9b6SSteve Lawrence 	if (ret < 0)
2248efd4c9b6SSteve Lawrence 		return (-1);
2249efd4c9b6SSteve Lawrence 
2250efd4c9b6SSteve Lawrence 	*sched = zsd_schedname2int(class, 0);
2251efd4c9b6SSteve Lawrence 
2252efd4c9b6SSteve Lawrence 	/* rctl caps must be fetched from within the zone */
2253efd4c9b6SSteve Lawrence 	if (pipe(p) != 0)
2254efd4c9b6SSteve Lawrence 		return (-1);
2255efd4c9b6SSteve Lawrence 
2256efd4c9b6SSteve Lawrence 	if ((tmpl_fd = init_template()) == -1) {
2257efd4c9b6SSteve Lawrence 		(void) close(p[0]);
2258efd4c9b6SSteve Lawrence 		(void) close(p[1]);
2259efd4c9b6SSteve Lawrence 		return (-1);
2260efd4c9b6SSteve Lawrence 	}
2261efd4c9b6SSteve Lawrence 	pid = forkx(0);
2262efd4c9b6SSteve Lawrence 	if (pid < 0) {
2263efd4c9b6SSteve Lawrence 		(void) ct_tmpl_clear(tmpl_fd);
2264efd4c9b6SSteve Lawrence 		(void) close(p[0]);
2265efd4c9b6SSteve Lawrence 		(void) close(p[1]);
2266efd4c9b6SSteve Lawrence 		return (-1);
2267efd4c9b6SSteve Lawrence 	}
2268efd4c9b6SSteve Lawrence 	if (pid == 0) {
2269efd4c9b6SSteve Lawrence 
2270efd4c9b6SSteve Lawrence 		(void) ct_tmpl_clear(tmpl_fd);
2271efd4c9b6SSteve Lawrence 		(void) close(tmpl_fd);
2272efd4c9b6SSteve Lawrence 		(void) close(p[0]);
2273efd4c9b6SSteve Lawrence 		if (zone->zsz_id != getzoneid()) {
2274efd4c9b6SSteve Lawrence 			if (zone_enter(zone->zsz_id) < 0) {
2275efd4c9b6SSteve Lawrence 				(void) close(p[1]);
2276efd4c9b6SSteve Lawrence 				_exit(0);
2277efd4c9b6SSteve Lawrence 			}
2278efd4c9b6SSteve Lawrence 		}
2279efd4c9b6SSteve Lawrence 
2280efd4c9b6SSteve Lawrence 		/* Get caps for zone, and write them to zonestatd parent. */
2281efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.cpu-shares");
2282efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.cpu-cap");
2283efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-locked-memory");
2284efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-swap");
2285efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-processes");
2286efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-processes");
2287efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-lwps");
2288efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-lwps");
2289efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-shm-memory");
2290efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-shm-memory");
2291efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-shm-ids");
2292efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-shm-ids");
2293efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-sem-ids");
2294efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-sem-ids");
2295efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-msg-ids");
2296efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-msg-ids");
2297efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_limit("zone.max-lofi");
2298efd4c9b6SSteve Lawrence 		vals[i++] = zsd_get_zone_rctl_usage("zone.max-lofi");
2299efd4c9b6SSteve Lawrence 
2300efd4c9b6SSteve Lawrence 		if (write(p[1], vals, ZSD_NUM_RCTL_VALS * sizeof (uint64_t)) !=
2301efd4c9b6SSteve Lawrence 		    ZSD_NUM_RCTL_VALS * sizeof (uint64_t)) {
2302efd4c9b6SSteve Lawrence 			(void) close(p[1]);
2303efd4c9b6SSteve Lawrence 			_exit(1);
2304efd4c9b6SSteve Lawrence 		}
2305efd4c9b6SSteve Lawrence 
2306efd4c9b6SSteve Lawrence 		(void) close(p[1]);
2307efd4c9b6SSteve Lawrence 		_exit(0);
2308efd4c9b6SSteve Lawrence 	}
2309efd4c9b6SSteve Lawrence 	if (contract_latest(&ct) == -1)
2310efd4c9b6SSteve Lawrence 		ct = -1;
2311efd4c9b6SSteve Lawrence 
2312efd4c9b6SSteve Lawrence 	(void) ct_tmpl_clear(tmpl_fd);
2313efd4c9b6SSteve Lawrence 	(void) close(tmpl_fd);
2314efd4c9b6SSteve Lawrence 	(void) close(p[1]);
2315efd4c9b6SSteve Lawrence 	while (waitpid(pid, NULL, 0) != pid)
2316efd4c9b6SSteve Lawrence 		;
2317efd4c9b6SSteve Lawrence 
2318efd4c9b6SSteve Lawrence 	/* Read cap from child in zone */
2319efd4c9b6SSteve Lawrence 	if (read(p[0], vals, ZSD_NUM_RCTL_VALS * sizeof (uint64_t)) !=
2320efd4c9b6SSteve Lawrence 	    ZSD_NUM_RCTL_VALS * sizeof (uint64_t)) {
2321efd4c9b6SSteve Lawrence 		res = -1;
2322efd4c9b6SSteve Lawrence 		goto cleanup;
2323efd4c9b6SSteve Lawrence 	}
2324efd4c9b6SSteve Lawrence 	i = 0;
2325efd4c9b6SSteve Lawrence 	*cpu_shares = vals[i++];
2326efd4c9b6SSteve Lawrence 	*cpu_cap = vals[i++];
2327efd4c9b6SSteve Lawrence 	*locked_cap = vals[i++];
2328efd4c9b6SSteve Lawrence 	*vm_cap = vals[i++];
2329efd4c9b6SSteve Lawrence 	*processes_cap = vals[i++];
2330efd4c9b6SSteve Lawrence 	*processes = vals[i++];
2331efd4c9b6SSteve Lawrence 	*lwps_cap = vals[i++];
2332efd4c9b6SSteve Lawrence 	*lwps = vals[i++];
2333efd4c9b6SSteve Lawrence 	*shm_cap = vals[i++];
2334efd4c9b6SSteve Lawrence 	*shm = vals[i++];
2335efd4c9b6SSteve Lawrence 	*shmids_cap = vals[i++];
2336efd4c9b6SSteve Lawrence 	*shmids = vals[i++];
2337efd4c9b6SSteve Lawrence 	*semids_cap = vals[i++];
2338efd4c9b6SSteve Lawrence 	*semids = vals[i++];
2339efd4c9b6SSteve Lawrence 	*msgids_cap = vals[i++];
2340efd4c9b6SSteve Lawrence 	*msgids = vals[i++];
2341efd4c9b6SSteve Lawrence 	*lofi_cap = vals[i++];
2342efd4c9b6SSteve Lawrence 	*lofi = vals[i++];
2343efd4c9b6SSteve Lawrence 
2344efd4c9b6SSteve Lawrence 	/* Interpret maximum values as no cap */
2345efd4c9b6SSteve Lawrence 	if (*cpu_cap == UINT32_MAX || *cpu_cap == 0)
2346efd4c9b6SSteve Lawrence 		*cpu_cap = ZS_LIMIT_NONE;
2347efd4c9b6SSteve Lawrence 	if (*processes_cap == sys->zss_processes_max)
2348efd4c9b6SSteve Lawrence 		*processes_cap = ZS_LIMIT_NONE;
2349efd4c9b6SSteve Lawrence 	if (*lwps_cap == sys->zss_lwps_max)
2350efd4c9b6SSteve Lawrence 		*lwps_cap = ZS_LIMIT_NONE;
2351efd4c9b6SSteve Lawrence 	if (*shm_cap == sys->zss_shm_max)
2352efd4c9b6SSteve Lawrence 		*shm_cap = ZS_LIMIT_NONE;
2353efd4c9b6SSteve Lawrence 	if (*shmids_cap == sys->zss_shmids_max)
2354efd4c9b6SSteve Lawrence 		*shmids_cap = ZS_LIMIT_NONE;
2355efd4c9b6SSteve Lawrence 	if (*semids_cap == sys->zss_semids_max)
2356efd4c9b6SSteve Lawrence 		*semids_cap = ZS_LIMIT_NONE;
2357efd4c9b6SSteve Lawrence 	if (*msgids_cap == sys->zss_msgids_max)
2358efd4c9b6SSteve Lawrence 		*msgids_cap = ZS_LIMIT_NONE;
2359efd4c9b6SSteve Lawrence 	if (*lofi_cap == sys->zss_lofi_max)
2360efd4c9b6SSteve Lawrence 		*lofi_cap = ZS_LIMIT_NONE;
2361efd4c9b6SSteve Lawrence 
2362efd4c9b6SSteve Lawrence 
2363efd4c9b6SSteve Lawrence cleanup:
2364efd4c9b6SSteve Lawrence 	(void) close(p[0]);
2365efd4c9b6SSteve Lawrence 	(void) ct_tmpl_clear(tmpl_fd);
2366efd4c9b6SSteve Lawrence 	(void) close(tmpl_fd);
2367efd4c9b6SSteve Lawrence 	(void) contract_abandon_id(ct);
2368efd4c9b6SSteve Lawrence 
2369efd4c9b6SSteve Lawrence 	return (res);
2370efd4c9b6SSteve Lawrence }
2371efd4c9b6SSteve Lawrence 
2372efd4c9b6SSteve Lawrence /* Update the current list of running zones */
2373efd4c9b6SSteve Lawrence static void
zsd_refresh_zones(zsd_ctl_t * ctl)2374efd4c9b6SSteve Lawrence zsd_refresh_zones(zsd_ctl_t *ctl)
2375efd4c9b6SSteve Lawrence {
2376efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
2377efd4c9b6SSteve Lawrence 	uint_t old, num;
2378efd4c9b6SSteve Lawrence 	ushort_t flags;
2379efd4c9b6SSteve Lawrence 	int i, ret;
2380efd4c9b6SSteve Lawrence 	zoneid_t *cache;
2381efd4c9b6SSteve Lawrence 	uint64_t cpu_shares;
2382efd4c9b6SSteve Lawrence 	uint64_t cpu_cap;
2383efd4c9b6SSteve Lawrence 	uint64_t ram_cap;
2384efd4c9b6SSteve Lawrence 	uint64_t locked_cap;
2385efd4c9b6SSteve Lawrence 	uint64_t vm_cap;
2386efd4c9b6SSteve Lawrence 	uint64_t processes_cap;
2387efd4c9b6SSteve Lawrence 	uint64_t processes;
2388efd4c9b6SSteve Lawrence 	uint64_t lwps_cap;
2389efd4c9b6SSteve Lawrence 	uint64_t lwps;
2390efd4c9b6SSteve Lawrence 	uint64_t shm_cap;
2391efd4c9b6SSteve Lawrence 	uint64_t shm;
2392efd4c9b6SSteve Lawrence 	uint64_t shmids_cap;
2393efd4c9b6SSteve Lawrence 	uint64_t shmids;
2394efd4c9b6SSteve Lawrence 	uint64_t semids_cap;
2395efd4c9b6SSteve Lawrence 	uint64_t semids;
2396efd4c9b6SSteve Lawrence 	uint64_t msgids_cap;
2397efd4c9b6SSteve Lawrence 	uint64_t msgids;
2398efd4c9b6SSteve Lawrence 	uint64_t lofi_cap;
2399efd4c9b6SSteve Lawrence 	uint64_t lofi;
2400efd4c9b6SSteve Lawrence 
2401efd4c9b6SSteve Lawrence 	char zonename[ZS_ZONENAME_MAX];
2402efd4c9b6SSteve Lawrence 	char poolname[ZS_POOLNAME_MAX];
2403efd4c9b6SSteve Lawrence 	char psetname[ZS_PSETNAME_MAX];
2404efd4c9b6SSteve Lawrence 	uint_t sched;
2405efd4c9b6SSteve Lawrence 	uint_t cputype;
2406efd4c9b6SSteve Lawrence 	uint_t iptype;
2407efd4c9b6SSteve Lawrence 
2408efd4c9b6SSteve Lawrence 	/* Get the current list of running zones */
2409efd4c9b6SSteve Lawrence 	for (;;) {
2410efd4c9b6SSteve Lawrence 		old = num = ctl->zsctl_zone_ncache;
2411efd4c9b6SSteve Lawrence 		(void) zone_list(ctl->zsctl_zone_cache, &num);
2412efd4c9b6SSteve Lawrence 		if (num <= old)
2413efd4c9b6SSteve Lawrence 			break;
2414efd4c9b6SSteve Lawrence 		if ((cache = (zoneid_t *)realloc(ctl->zsctl_zone_cache,
2415efd4c9b6SSteve Lawrence 		    (num) * sizeof (zoneid_t))) != NULL) {
2416efd4c9b6SSteve Lawrence 			ctl->zsctl_zone_ncache = num;
2417efd4c9b6SSteve Lawrence 			ctl->zsctl_zone_cache = cache;
2418efd4c9b6SSteve Lawrence 		} else {
2419efd4c9b6SSteve Lawrence 			/* Could not allocate to get new zone list.  Give up */
2420efd4c9b6SSteve Lawrence 			return;
2421efd4c9b6SSteve Lawrence 		}
2422efd4c9b6SSteve Lawrence 	}
2423efd4c9b6SSteve Lawrence 
2424efd4c9b6SSteve Lawrence 	zsd_mark_zones_start(ctl);
2425efd4c9b6SSteve Lawrence 
2426efd4c9b6SSteve Lawrence 	for (i = 0; i < num; i++) {
2427efd4c9b6SSteve Lawrence 
2428efd4c9b6SSteve Lawrence 		ret = getzonenamebyid(ctl->zsctl_zone_cache[i],
2429efd4c9b6SSteve Lawrence 		    zonename, sizeof (zonename));
2430efd4c9b6SSteve Lawrence 		if (ret < 0)
2431efd4c9b6SSteve Lawrence 			continue;
2432efd4c9b6SSteve Lawrence 
2433efd4c9b6SSteve Lawrence 		zone = zsd_lookup_insert_zone(ctl, zonename,
2434efd4c9b6SSteve Lawrence 		    ctl->zsctl_zone_cache[i]);
2435efd4c9b6SSteve Lawrence 
2436efd4c9b6SSteve Lawrence 		ret = zone_getattr(ctl->zsctl_zone_cache[i], ZONE_ATTR_FLAGS,
2437efd4c9b6SSteve Lawrence 		    &flags, sizeof (flags));
2438efd4c9b6SSteve Lawrence 		if (ret < 0)
2439efd4c9b6SSteve Lawrence 			continue;
2440efd4c9b6SSteve Lawrence 
2441efd4c9b6SSteve Lawrence 		if (flags & ZF_NET_EXCL)
2442efd4c9b6SSteve Lawrence 			iptype = ZS_IPTYPE_EXCLUSIVE;
2443efd4c9b6SSteve Lawrence 		else
2444efd4c9b6SSteve Lawrence 			iptype = ZS_IPTYPE_SHARED;
2445efd4c9b6SSteve Lawrence 
2446efd4c9b6SSteve Lawrence 		zsd_get_zone_pool_pset(ctl, zone, poolname, sizeof (poolname),
2447efd4c9b6SSteve Lawrence 		    psetname, sizeof (psetname), &cputype);
2448efd4c9b6SSteve Lawrence 
2449efd4c9b6SSteve Lawrence 		if (zsd_get_zone_caps(ctl, zone, &cpu_shares, &cpu_cap,
2450efd4c9b6SSteve Lawrence 		    &ram_cap, &locked_cap, &vm_cap, &processes_cap, &processes,
2451efd4c9b6SSteve Lawrence 		    &lwps_cap, &lwps, &shm_cap, &shm, &shmids_cap, &shmids,
2452efd4c9b6SSteve Lawrence 		    &semids_cap, &semids, &msgids_cap, &msgids, &lofi_cap,
2453efd4c9b6SSteve Lawrence 		    &lofi, &sched) != 0)
2454efd4c9b6SSteve Lawrence 			continue;
2455efd4c9b6SSteve Lawrence 
2456efd4c9b6SSteve Lawrence 		zsd_mark_zone_found(ctl, zone, cpu_shares, cpu_cap, ram_cap,
2457efd4c9b6SSteve Lawrence 		    locked_cap, vm_cap, processes_cap, processes, lwps_cap,
2458efd4c9b6SSteve Lawrence 		    lwps, shm_cap, shm, shmids_cap, shmids, semids_cap,
2459efd4c9b6SSteve Lawrence 		    semids, msgids_cap, msgids, lofi_cap, lofi, poolname,
2460efd4c9b6SSteve Lawrence 		    psetname, sched, cputype, iptype);
2461efd4c9b6SSteve Lawrence 	}
2462efd4c9b6SSteve Lawrence }
2463efd4c9b6SSteve Lawrence 
2464efd4c9b6SSteve Lawrence /* Fetch the details of a process from its psinfo_t */
2465efd4c9b6SSteve Lawrence static void
zsd_get_proc_info(zsd_ctl_t * ctl,psinfo_t * psinfo,psetid_t * psetid,psetid_t * prev_psetid,zoneid_t * zoneid,zoneid_t * prev_zoneid,timestruc_t * delta,uint_t * sched)2466efd4c9b6SSteve Lawrence zsd_get_proc_info(zsd_ctl_t *ctl, psinfo_t *psinfo, psetid_t *psetid,
2467efd4c9b6SSteve Lawrence     psetid_t *prev_psetid, zoneid_t *zoneid, zoneid_t *prev_zoneid,
2468efd4c9b6SSteve Lawrence     timestruc_t *delta, uint_t *sched)
2469efd4c9b6SSteve Lawrence {
2470efd4c9b6SSteve Lawrence 	timestruc_t d;
2471efd4c9b6SSteve Lawrence 	zsd_proc_t *proc;
2472efd4c9b6SSteve Lawrence 
2473efd4c9b6SSteve Lawrence 	/* Get cached data for proc */
2474efd4c9b6SSteve Lawrence 	proc = &(ctl->zsctl_proc_array[psinfo->pr_pid]);
2475efd4c9b6SSteve Lawrence 	*psetid = psinfo->pr_lwp.pr_bindpset;
2476efd4c9b6SSteve Lawrence 
2477efd4c9b6SSteve Lawrence 	if (proc->zspr_psetid == ZS_PSET_ERROR)
2478efd4c9b6SSteve Lawrence 		*prev_psetid = *psetid;
2479efd4c9b6SSteve Lawrence 	else
2480efd4c9b6SSteve Lawrence 		*prev_psetid = proc->zspr_psetid;
2481efd4c9b6SSteve Lawrence 
2482efd4c9b6SSteve Lawrence 	*zoneid = psinfo->pr_zoneid;
2483efd4c9b6SSteve Lawrence 	if (proc->zspr_zoneid == -1)
2484efd4c9b6SSteve Lawrence 		*prev_zoneid = *zoneid;
2485efd4c9b6SSteve Lawrence 	else
2486efd4c9b6SSteve Lawrence 		*prev_zoneid = proc->zspr_zoneid;
2487efd4c9b6SSteve Lawrence 
2488efd4c9b6SSteve Lawrence 	TIMESTRUC_DELTA(d, psinfo->pr_time, proc->zspr_usage);
2489efd4c9b6SSteve Lawrence 	*delta = d;
2490efd4c9b6SSteve Lawrence 
2491efd4c9b6SSteve Lawrence 	*sched = zsd_schedname2int(psinfo->pr_lwp.pr_clname,
2492efd4c9b6SSteve Lawrence 	    psinfo->pr_lwp.pr_pri);
2493efd4c9b6SSteve Lawrence 
2494efd4c9b6SSteve Lawrence 	/* Update cached data for proc */
2495efd4c9b6SSteve Lawrence 	proc->zspr_psetid = psinfo->pr_lwp.pr_bindpset;
2496efd4c9b6SSteve Lawrence 	proc->zspr_zoneid = psinfo->pr_zoneid;
2497efd4c9b6SSteve Lawrence 	proc->zspr_sched = *sched;
2498efd4c9b6SSteve Lawrence 	proc->zspr_usage.tv_sec = psinfo->pr_time.tv_sec;
2499efd4c9b6SSteve Lawrence 	proc->zspr_usage.tv_nsec = psinfo->pr_time.tv_nsec;
2500efd4c9b6SSteve Lawrence 	proc->zspr_ppid = psinfo->pr_ppid;
2501efd4c9b6SSteve Lawrence }
2502efd4c9b6SSteve Lawrence 
2503efd4c9b6SSteve Lawrence /*
2504efd4c9b6SSteve Lawrence  * Reset the known cpu usage of a process. This is done after a process
2505efd4c9b6SSteve Lawrence  * exits so that if the pid is recycled, data from its previous life is
2506efd4c9b6SSteve Lawrence  * not reused
2507efd4c9b6SSteve Lawrence  */
2508efd4c9b6SSteve Lawrence static void
zsd_flush_proc_info(zsd_proc_t * proc)2509efd4c9b6SSteve Lawrence zsd_flush_proc_info(zsd_proc_t *proc)
2510efd4c9b6SSteve Lawrence {
2511efd4c9b6SSteve Lawrence 	proc->zspr_usage.tv_sec = 0;
2512efd4c9b6SSteve Lawrence 	proc->zspr_usage.tv_nsec = 0;
2513efd4c9b6SSteve Lawrence }
2514efd4c9b6SSteve Lawrence 
2515efd4c9b6SSteve Lawrence /*
2516efd4c9b6SSteve Lawrence  * Open the current extended accounting file.  On initialization, open the
2517efd4c9b6SSteve Lawrence  * file as the current file to be used.  Otherwise, open the file as the
2518efd4c9b6SSteve Lawrence  * next file to use of the current file reaches EOF.
2519efd4c9b6SSteve Lawrence  */
2520efd4c9b6SSteve Lawrence static int
zsd_open_exacct(zsd_ctl_t * ctl,boolean_t init)2521efd4c9b6SSteve Lawrence zsd_open_exacct(zsd_ctl_t *ctl, boolean_t init)
2522efd4c9b6SSteve Lawrence {
2523efd4c9b6SSteve Lawrence 	int ret, oret, state, trys = 0, flags;
2524efd4c9b6SSteve Lawrence 	int *fd, *open;
2525efd4c9b6SSteve Lawrence 	ea_file_t *eaf;
2526efd4c9b6SSteve Lawrence 	struct stat64 *stat;
2527efd4c9b6SSteve Lawrence 	char path[MAXPATHLEN];
2528efd4c9b6SSteve Lawrence 
2529efd4c9b6SSteve Lawrence 	/*
2530efd4c9b6SSteve Lawrence 	 * The accounting file is first opened at the tail.  Following
2531efd4c9b6SSteve Lawrence 	 * opens to new accounting files are opened at the head.
2532efd4c9b6SSteve Lawrence 	 */
2533efd4c9b6SSteve Lawrence 	if (init == B_TRUE) {
2534efd4c9b6SSteve Lawrence 		flags = EO_NO_VALID_HDR | EO_TAIL;
2535efd4c9b6SSteve Lawrence 		fd = &ctl->zsctl_proc_fd;
2536efd4c9b6SSteve Lawrence 		eaf = &ctl->zsctl_proc_eaf;
2537efd4c9b6SSteve Lawrence 		stat = &ctl->zsctl_proc_stat;
2538efd4c9b6SSteve Lawrence 		open = &ctl->zsctl_proc_open;
2539efd4c9b6SSteve Lawrence 	} else {
2540efd4c9b6SSteve Lawrence 		flags = EO_NO_VALID_HDR | EO_HEAD;
2541efd4c9b6SSteve Lawrence 		fd = &ctl->zsctl_proc_fd_next;
2542efd4c9b6SSteve Lawrence 		eaf = &ctl->zsctl_proc_eaf_next;
2543efd4c9b6SSteve Lawrence 		stat = &ctl->zsctl_proc_stat_next;
2544efd4c9b6SSteve Lawrence 		open = &ctl->zsctl_proc_open_next;
2545efd4c9b6SSteve Lawrence 	}
2546efd4c9b6SSteve Lawrence 
2547efd4c9b6SSteve Lawrence 	*fd = -1;
2548efd4c9b6SSteve Lawrence 	*open = 0;
2549efd4c9b6SSteve Lawrence retry:
2550efd4c9b6SSteve Lawrence 	/* open accounting files for cpu consumption */
2551efd4c9b6SSteve Lawrence 	ret = acctctl(AC_STATE_GET | AC_PROC, &state, sizeof (state));
2552efd4c9b6SSteve Lawrence 	if (ret != 0) {
2553efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to get process accounting state"));
2554efd4c9b6SSteve Lawrence 		goto err;
2555efd4c9b6SSteve Lawrence 	}
2556efd4c9b6SSteve Lawrence 	if (state != AC_ON) {
2557efd4c9b6SSteve Lawrence 		if (trys > 0) {
2558efd4c9b6SSteve Lawrence 			zsd_warn(gettext(
2559efd4c9b6SSteve Lawrence 			    "Unable to enable process accounting"));
2560efd4c9b6SSteve Lawrence 			goto err;
2561efd4c9b6SSteve Lawrence 		}
2562efd4c9b6SSteve Lawrence 		(void) zsd_enable_cpu_stats();
2563efd4c9b6SSteve Lawrence 		trys++;
2564efd4c9b6SSteve Lawrence 		goto retry;
2565efd4c9b6SSteve Lawrence 	}
2566efd4c9b6SSteve Lawrence 
2567efd4c9b6SSteve Lawrence 	ret = acctctl(AC_FILE_GET | AC_PROC, path, sizeof (path));
2568efd4c9b6SSteve Lawrence 	if (ret != 0) {
2569efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to get process accounting file"));
2570efd4c9b6SSteve Lawrence 		goto err;
2571efd4c9b6SSteve Lawrence 	}
2572efd4c9b6SSteve Lawrence 
2573efd4c9b6SSteve Lawrence 	if ((*fd = open64(path, O_RDONLY, 0)) >= 0 &&
2574efd4c9b6SSteve Lawrence 	    (oret = ea_fdopen(eaf, *fd, NULL, flags, O_RDONLY)) == 0)
2575efd4c9b6SSteve Lawrence 		ret = fstat64(*fd, stat);
2576efd4c9b6SSteve Lawrence 
2577efd4c9b6SSteve Lawrence 	if (*fd < 0 || oret < 0 || ret < 0) {
2578efd4c9b6SSteve Lawrence 		struct timespec ts;
2579efd4c9b6SSteve Lawrence 
2580efd4c9b6SSteve Lawrence 		/*
2581efd4c9b6SSteve Lawrence 		 * It is possible the accounting file is momentarily unavailable
2582efd4c9b6SSteve Lawrence 		 * because it is being rolled.  Try for up to half a second.
2583efd4c9b6SSteve Lawrence 		 *
2584efd4c9b6SSteve Lawrence 		 * If failure to open accounting file persists, give up.
2585efd4c9b6SSteve Lawrence 		 */
2586efd4c9b6SSteve Lawrence 		if (oret == 0)
2587efd4c9b6SSteve Lawrence 			(void) ea_close(eaf);
2588efd4c9b6SSteve Lawrence 		else if (*fd >= 0)
2589efd4c9b6SSteve Lawrence 			(void) close(*fd);
2590efd4c9b6SSteve Lawrence 		if (trys > 500) {
2591efd4c9b6SSteve Lawrence 			zsd_warn(gettext(
2592efd4c9b6SSteve Lawrence 			    "Unable to open process accounting file"));
2593efd4c9b6SSteve Lawrence 			goto err;
2594efd4c9b6SSteve Lawrence 		}
2595efd4c9b6SSteve Lawrence 		/* wait one millisecond */
2596efd4c9b6SSteve Lawrence 		ts.tv_sec = 0;
2597efd4c9b6SSteve Lawrence 		ts.tv_nsec = NANOSEC / 1000;
2598efd4c9b6SSteve Lawrence 		(void) nanosleep(&ts, NULL);
2599efd4c9b6SSteve Lawrence 		goto retry;
2600efd4c9b6SSteve Lawrence 	}
2601efd4c9b6SSteve Lawrence 	*open = 1;
2602efd4c9b6SSteve Lawrence 	return (0);
2603efd4c9b6SSteve Lawrence err:
2604efd4c9b6SSteve Lawrence 	if (*fd >= 0)
2605efd4c9b6SSteve Lawrence 		(void) close(*fd);
2606efd4c9b6SSteve Lawrence 	*open = 0;
2607efd4c9b6SSteve Lawrence 	*fd = -1;
2608efd4c9b6SSteve Lawrence 	return (-1);
2609efd4c9b6SSteve Lawrence }
2610efd4c9b6SSteve Lawrence 
2611efd4c9b6SSteve Lawrence /*
2612efd4c9b6SSteve Lawrence  * Walk /proc and charge each process to its zone and processor set.
2613efd4c9b6SSteve Lawrence  * Then read exacct data for exited processes, and charge them as well.
2614efd4c9b6SSteve Lawrence  */
2615efd4c9b6SSteve Lawrence static void
zsd_refresh_procs(zsd_ctl_t * ctl,boolean_t init)2616efd4c9b6SSteve Lawrence zsd_refresh_procs(zsd_ctl_t *ctl, boolean_t init)
2617efd4c9b6SSteve Lawrence {
2618efd4c9b6SSteve Lawrence 	DIR *dir;
2619efd4c9b6SSteve Lawrence 	struct dirent *dent;
2620efd4c9b6SSteve Lawrence 	psinfo_t psinfo;
2621efd4c9b6SSteve Lawrence 	int fd, ret;
2622efd4c9b6SSteve Lawrence 	zsd_proc_t *proc, *pproc, *tmp, *next;
2623efd4c9b6SSteve Lawrence 	list_t pplist, plist;
2624efd4c9b6SSteve Lawrence 	zsd_zone_t *zone, *prev_zone;
2625efd4c9b6SSteve Lawrence 	zsd_pset_t *pset, *prev_pset;
2626efd4c9b6SSteve Lawrence 	psetid_t psetid, prev_psetid;
2627efd4c9b6SSteve Lawrence 	zoneid_t zoneid, prev_zoneid;
2628efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage, *prev_usage;
2629efd4c9b6SSteve Lawrence 	char path[MAXPATHLEN];
2630efd4c9b6SSteve Lawrence 
2631efd4c9b6SSteve Lawrence 	ea_object_t object;
2632efd4c9b6SSteve Lawrence 	ea_object_t pobject;
2633efd4c9b6SSteve Lawrence 	boolean_t hrtime_expired = B_FALSE;
2634efd4c9b6SSteve Lawrence 	struct timeval interval_end;
2635efd4c9b6SSteve Lawrence 
2636efd4c9b6SSteve Lawrence 	timestruc_t delta, d1, d2;
2637efd4c9b6SSteve Lawrence 	uint_t sched = 0;
2638efd4c9b6SSteve Lawrence 
2639efd4c9b6SSteve Lawrence 	/*
2640efd4c9b6SSteve Lawrence 	 * Get the current accounting file.  The current accounting file
2641efd4c9b6SSteve Lawrence 	 * may be different than the file in use, as the accounting file
2642efd4c9b6SSteve Lawrence 	 * may have been rolled, or manually changed by an admin.
2643efd4c9b6SSteve Lawrence 	 */
2644efd4c9b6SSteve Lawrence 	ret = zsd_open_exacct(ctl, init);
2645efd4c9b6SSteve Lawrence 	if (ret != 0) {
2646efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to track process accounting"));
2647efd4c9b6SSteve Lawrence 		return;
2648efd4c9b6SSteve Lawrence 	}
2649efd4c9b6SSteve Lawrence 
2650efd4c9b6SSteve Lawrence 	/*
2651efd4c9b6SSteve Lawrence 	 * Mark the current time as the interval end time.  Don't track
2652efd4c9b6SSteve Lawrence 	 * processes that exit after this time.
2653efd4c9b6SSteve Lawrence 	 */
2654efd4c9b6SSteve Lawrence 	(void) gettimeofday(&interval_end, NULL);
2655efd4c9b6SSteve Lawrence 
2656efd4c9b6SSteve Lawrence 	dir = opendir("/proc");
2657efd4c9b6SSteve Lawrence 	if (dir == NULL) {
2658efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to open /proc"));
2659efd4c9b6SSteve Lawrence 		return;
2660efd4c9b6SSteve Lawrence 	}
2661efd4c9b6SSteve Lawrence 
2662efd4c9b6SSteve Lawrence 	/* Walk all processes and compute each zone's usage on each pset. */
26632a690de6SMarco van Wieringen 	while ((dent = readdir(dir)) != NULL) {
2664efd4c9b6SSteve Lawrence 
2665efd4c9b6SSteve Lawrence 		if (strcmp(dent->d_name, ".") == 0 ||
2666efd4c9b6SSteve Lawrence 		    strcmp(dent->d_name, "..") == 0)
2667efd4c9b6SSteve Lawrence 			continue;
2668efd4c9b6SSteve Lawrence 
2669efd4c9b6SSteve Lawrence 		(void) snprintf(path, sizeof (path), "/proc/%s/psinfo",
2670efd4c9b6SSteve Lawrence 		    dent->d_name);
2671efd4c9b6SSteve Lawrence 
2672efd4c9b6SSteve Lawrence 		fd = open(path, O_RDONLY);
2673efd4c9b6SSteve Lawrence 		if (fd < 0)
2674efd4c9b6SSteve Lawrence 			continue;
2675efd4c9b6SSteve Lawrence 
2676efd4c9b6SSteve Lawrence 		if (read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) {
2677efd4c9b6SSteve Lawrence 			(void) close(fd);
2678efd4c9b6SSteve Lawrence 			continue;
2679efd4c9b6SSteve Lawrence 		}
2680efd4c9b6SSteve Lawrence 		(void) close(fd);
2681efd4c9b6SSteve Lawrence 
2682efd4c9b6SSteve Lawrence 		zsd_get_proc_info(ctl, &psinfo, &psetid, &prev_psetid,
2683efd4c9b6SSteve Lawrence 		    &zoneid, &prev_zoneid, &delta, &sched);
2684efd4c9b6SSteve Lawrence 
2685efd4c9b6SSteve Lawrence 		d1.tv_sec = delta.tv_sec / 2;
2686efd4c9b6SSteve Lawrence 		d1.tv_nsec = delta.tv_nsec / 2;
2687efd4c9b6SSteve Lawrence 		d2.tv_sec = (delta.tv_sec / 2) + (delta.tv_sec % 2);
2688efd4c9b6SSteve Lawrence 		d2.tv_nsec = (delta.tv_nsec / 2) + (delta.tv_nsec % 2);
2689efd4c9b6SSteve Lawrence 
2690efd4c9b6SSteve Lawrence 		/* Get the zone and pset this process is running in */
2691efd4c9b6SSteve Lawrence 		zone = zsd_lookup_zone_byid(ctl, zoneid);
2692efd4c9b6SSteve Lawrence 		if (zone == NULL)
2693efd4c9b6SSteve Lawrence 			continue;
2694efd4c9b6SSteve Lawrence 		pset = zsd_lookup_pset_byid(ctl, psetid);
2695efd4c9b6SSteve Lawrence 		if (pset == NULL)
2696efd4c9b6SSteve Lawrence 			continue;
2697efd4c9b6SSteve Lawrence 		usage = zsd_lookup_insert_usage(ctl, pset, zone);
2698efd4c9b6SSteve Lawrence 		if (usage == NULL)
2699efd4c9b6SSteve Lawrence 			continue;
2700efd4c9b6SSteve Lawrence 
2701efd4c9b6SSteve Lawrence 		/*
2702efd4c9b6SSteve Lawrence 		 * Get the usage of the previous zone and pset if they were
2703efd4c9b6SSteve Lawrence 		 * different.
2704efd4c9b6SSteve Lawrence 		 */
2705efd4c9b6SSteve Lawrence 		if (zoneid != prev_zoneid)
2706efd4c9b6SSteve Lawrence 			prev_zone = zsd_lookup_zone_byid(ctl, prev_zoneid);
2707efd4c9b6SSteve Lawrence 		else
2708efd4c9b6SSteve Lawrence 			prev_zone = NULL;
2709efd4c9b6SSteve Lawrence 
2710efd4c9b6SSteve Lawrence 		if (psetid != prev_psetid)
2711efd4c9b6SSteve Lawrence 			prev_pset = zsd_lookup_pset_byid(ctl, prev_psetid);
2712efd4c9b6SSteve Lawrence 		else
2713efd4c9b6SSteve Lawrence 			prev_pset = NULL;
2714efd4c9b6SSteve Lawrence 
2715efd4c9b6SSteve Lawrence 		prev_usage = NULL;
2716efd4c9b6SSteve Lawrence 		if (prev_zone != NULL || prev_pset != NULL) {
2717efd4c9b6SSteve Lawrence 			if (prev_zone == NULL)
2718efd4c9b6SSteve Lawrence 				prev_zone = zone;
2719efd4c9b6SSteve Lawrence 			if (prev_pset == NULL)
2720efd4c9b6SSteve Lawrence 				prev_pset = pset;
2721efd4c9b6SSteve Lawrence 
2722efd4c9b6SSteve Lawrence 			prev_usage = zsd_lookup_insert_usage(ctl, prev_pset,
2723efd4c9b6SSteve Lawrence 			    prev_zone);
2724efd4c9b6SSteve Lawrence 		}
2725efd4c9b6SSteve Lawrence 
2726efd4c9b6SSteve Lawrence 		/* Update the usage with the processes info */
2727efd4c9b6SSteve Lawrence 		if (prev_usage == NULL) {
2728efd4c9b6SSteve Lawrence 			zsd_mark_pset_usage_found(usage, sched);
2729efd4c9b6SSteve Lawrence 		} else {
2730efd4c9b6SSteve Lawrence 			zsd_mark_pset_usage_found(usage, sched);
2731efd4c9b6SSteve Lawrence 			zsd_mark_pset_usage_found(prev_usage, sched);
2732efd4c9b6SSteve Lawrence 		}
2733efd4c9b6SSteve Lawrence 
2734efd4c9b6SSteve Lawrence 		/*
2735efd4c9b6SSteve Lawrence 		 * First time around is just to get a starting point.  All
2736efd4c9b6SSteve Lawrence 		 * usages will be zero.
2737efd4c9b6SSteve Lawrence 		 */
2738efd4c9b6SSteve Lawrence 		if (init == B_TRUE)
2739efd4c9b6SSteve Lawrence 			continue;
2740efd4c9b6SSteve Lawrence 
2741efd4c9b6SSteve Lawrence 		if (prev_usage == NULL) {
2742efd4c9b6SSteve Lawrence 			zsd_add_usage(ctl, usage, &delta);
2743efd4c9b6SSteve Lawrence 		} else {
2744efd4c9b6SSteve Lawrence 			zsd_add_usage(ctl, usage, &d1);
2745efd4c9b6SSteve Lawrence 			zsd_add_usage(ctl, prev_usage, &d2);
2746efd4c9b6SSteve Lawrence 		}
2747efd4c9b6SSteve Lawrence 	}
2748efd4c9b6SSteve Lawrence 	(void) closedir(dir);
2749efd4c9b6SSteve Lawrence 
2750efd4c9b6SSteve Lawrence 	/*
2751efd4c9b6SSteve Lawrence 	 * No need to collect exited proc data on initialization.  Just
2752efd4c9b6SSteve Lawrence 	 * caching the usage of the known processes to get a zero starting
2753efd4c9b6SSteve Lawrence 	 * point.
2754efd4c9b6SSteve Lawrence 	 */
2755efd4c9b6SSteve Lawrence 	if (init == B_TRUE)
2756efd4c9b6SSteve Lawrence 		return;
2757efd4c9b6SSteve Lawrence 
2758efd4c9b6SSteve Lawrence 	/*
2759efd4c9b6SSteve Lawrence 	 * Add accounting records to account for processes which have
2760efd4c9b6SSteve Lawrence 	 * exited.
2761efd4c9b6SSteve Lawrence 	 */
2762efd4c9b6SSteve Lawrence 	list_create(&plist, sizeof (zsd_proc_t),
2763efd4c9b6SSteve Lawrence 	    offsetof(zsd_proc_t, zspr_next));
2764efd4c9b6SSteve Lawrence 	list_create(&pplist, sizeof (zsd_proc_t),
2765efd4c9b6SSteve Lawrence 	    offsetof(zsd_proc_t, zspr_next));
2766efd4c9b6SSteve Lawrence 
2767efd4c9b6SSteve Lawrence 	for (;;) {
2768efd4c9b6SSteve Lawrence 		pid_t pid;
2769efd4c9b6SSteve Lawrence 		pid_t ppid;
2770efd4c9b6SSteve Lawrence 		timestruc_t user, sys, proc_usage;
2771efd4c9b6SSteve Lawrence 		timestruc_t finish;
2772efd4c9b6SSteve Lawrence 		int numfound = 0;
2773efd4c9b6SSteve Lawrence 
2774efd4c9b6SSteve Lawrence 		bzero(&object, sizeof (object));
2775efd4c9b6SSteve Lawrence 		proc = NULL;
2776efd4c9b6SSteve Lawrence 		zone = NULL;
2777efd4c9b6SSteve Lawrence 		pset = NULL;
2778efd4c9b6SSteve Lawrence 		usage = NULL;
2779efd4c9b6SSteve Lawrence 		ret = ea_get_object(&ctl->zsctl_proc_eaf, &object);
2780efd4c9b6SSteve Lawrence 		if (ret == EO_ERROR) {
2781efd4c9b6SSteve Lawrence 			if (ea_error() == EXR_EOF) {
2782efd4c9b6SSteve Lawrence 
2783efd4c9b6SSteve Lawrence 				struct stat64 *stat;
2784efd4c9b6SSteve Lawrence 				struct stat64 *stat_next;
2785efd4c9b6SSteve Lawrence 
2786efd4c9b6SSteve Lawrence 				/*
2787efd4c9b6SSteve Lawrence 				 * See if the next accounting file is the
2788efd4c9b6SSteve Lawrence 				 * same as the current accounting file.
2789efd4c9b6SSteve Lawrence 				 */
2790efd4c9b6SSteve Lawrence 				stat = &(ctl->zsctl_proc_stat);
2791efd4c9b6SSteve Lawrence 				stat_next = &(ctl->zsctl_proc_stat_next);
2792efd4c9b6SSteve Lawrence 				if (stat->st_ino == stat_next->st_ino &&
2793efd4c9b6SSteve Lawrence 				    stat->st_dev == stat_next->st_dev) {
2794efd4c9b6SSteve Lawrence 					/*
2795efd4c9b6SSteve Lawrence 					 * End of current accounting file is
2796efd4c9b6SSteve Lawrence 					 * reached, so finished.  Clear EOF
2797efd4c9b6SSteve Lawrence 					 * bit for next time around.
2798efd4c9b6SSteve Lawrence 					 */
2799efd4c9b6SSteve Lawrence 					ea_clear(&ctl->zsctl_proc_eaf);
2800efd4c9b6SSteve Lawrence 					break;
2801efd4c9b6SSteve Lawrence 				} else {
2802efd4c9b6SSteve Lawrence 					/*
2803efd4c9b6SSteve Lawrence 					 * Accounting file has changed.  Move
2804efd4c9b6SSteve Lawrence 					 * to current accounting file.
2805efd4c9b6SSteve Lawrence 					 */
2806efd4c9b6SSteve Lawrence 					(void) ea_close(&ctl->zsctl_proc_eaf);
2807efd4c9b6SSteve Lawrence 
2808efd4c9b6SSteve Lawrence 					ctl->zsctl_proc_fd =
2809efd4c9b6SSteve Lawrence 					    ctl->zsctl_proc_fd_next;
2810efd4c9b6SSteve Lawrence 					ctl->zsctl_proc_eaf =
2811efd4c9b6SSteve Lawrence 					    ctl->zsctl_proc_eaf_next;
2812efd4c9b6SSteve Lawrence 					ctl->zsctl_proc_stat =
2813efd4c9b6SSteve Lawrence 					    ctl->zsctl_proc_stat_next;
2814efd4c9b6SSteve Lawrence 
2815efd4c9b6SSteve Lawrence 					ctl->zsctl_proc_fd_next = -1;
2816efd4c9b6SSteve Lawrence 					ctl->zsctl_proc_open_next = 0;
2817efd4c9b6SSteve Lawrence 					continue;
2818efd4c9b6SSteve Lawrence 				}
2819efd4c9b6SSteve Lawrence 			} else {
2820efd4c9b6SSteve Lawrence 				/*
2821efd4c9b6SSteve Lawrence 				 * Other accounting error.  Give up on
2822efd4c9b6SSteve Lawrence 				 * accounting.
2823efd4c9b6SSteve Lawrence 				 */
2824efd4c9b6SSteve Lawrence 				goto ea_err;
2825efd4c9b6SSteve Lawrence 			}
2826efd4c9b6SSteve Lawrence 		}
2827efd4c9b6SSteve Lawrence 		/* Skip if not a process group */
2828efd4c9b6SSteve Lawrence 		if ((object.eo_catalog & EXT_TYPE_MASK) != EXT_GROUP ||
2829efd4c9b6SSteve Lawrence 		    (object.eo_catalog & EXD_DATA_MASK) != EXD_GROUP_PROC) {
2830efd4c9b6SSteve Lawrence 			(void) ea_free_item(&object, EUP_ALLOC);
2831efd4c9b6SSteve Lawrence 			continue;
2832efd4c9b6SSteve Lawrence 		}
2833efd4c9b6SSteve Lawrence 
2834efd4c9b6SSteve Lawrence 		/* The process group entry should be complete */
2835efd4c9b6SSteve Lawrence 		while (numfound < 9) {
2836efd4c9b6SSteve Lawrence 			bzero(&pobject, sizeof (pobject));
2837efd4c9b6SSteve Lawrence 			ret = ea_get_object(&ctl->zsctl_proc_eaf,
2838efd4c9b6SSteve Lawrence 			    &pobject);
2839efd4c9b6SSteve Lawrence 			if (ret < 0) {
2840efd4c9b6SSteve Lawrence 				(void) ea_free_item(&object, EUP_ALLOC);
2841efd4c9b6SSteve Lawrence 				zsd_warn(
2842efd4c9b6SSteve Lawrence 				    "unable to get process accounting data");
2843efd4c9b6SSteve Lawrence 				goto ea_err;
2844efd4c9b6SSteve Lawrence 			}
2845efd4c9b6SSteve Lawrence 			/* Next entries should be process data */
2846efd4c9b6SSteve Lawrence 			if ((pobject.eo_catalog & EXT_TYPE_MASK) ==
2847efd4c9b6SSteve Lawrence 			    EXT_GROUP) {
2848efd4c9b6SSteve Lawrence 				(void) ea_free_item(&object, EUP_ALLOC);
2849efd4c9b6SSteve Lawrence 				(void) ea_free_item(&pobject, EUP_ALLOC);
2850efd4c9b6SSteve Lawrence 				zsd_warn(
2851efd4c9b6SSteve Lawrence 				    "process data of wrong type");
2852efd4c9b6SSteve Lawrence 				goto ea_err;
2853efd4c9b6SSteve Lawrence 			}
2854efd4c9b6SSteve Lawrence 			switch (pobject.eo_catalog & EXD_DATA_MASK) {
2855efd4c9b6SSteve Lawrence 			case EXD_PROC_PID:
2856efd4c9b6SSteve Lawrence 				pid = pobject.eo_item.ei_uint32;
2857efd4c9b6SSteve Lawrence 				proc = &(ctl->zsctl_proc_array[pid]);
2858efd4c9b6SSteve Lawrence 				/*
2859efd4c9b6SSteve Lawrence 				 * This process should not be currently in
2860efd4c9b6SSteve Lawrence 				 * the list of processes to process.
2861efd4c9b6SSteve Lawrence 				 */
2862efd4c9b6SSteve Lawrence 				assert(!list_link_active(&proc->zspr_next));
2863efd4c9b6SSteve Lawrence 				numfound++;
2864efd4c9b6SSteve Lawrence 				break;
2865efd4c9b6SSteve Lawrence 			case EXD_PROC_ANCPID:
2866efd4c9b6SSteve Lawrence 				ppid = pobject.eo_item.ei_uint32;
2867efd4c9b6SSteve Lawrence 				pproc = &(ctl->zsctl_proc_array[ppid]);
2868efd4c9b6SSteve Lawrence 				numfound++;
2869efd4c9b6SSteve Lawrence 				break;
2870efd4c9b6SSteve Lawrence 			case EXD_PROC_ZONENAME:
2871efd4c9b6SSteve Lawrence 				zone = zsd_lookup_zone(ctl,
2872efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_string, -1);
2873efd4c9b6SSteve Lawrence 				numfound++;
2874efd4c9b6SSteve Lawrence 				break;
2875efd4c9b6SSteve Lawrence 			case EXD_PROC_CPU_USER_SEC:
2876efd4c9b6SSteve Lawrence 				user.tv_sec =
2877efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_uint64;
2878efd4c9b6SSteve Lawrence 				numfound++;
2879efd4c9b6SSteve Lawrence 				break;
2880efd4c9b6SSteve Lawrence 			case EXD_PROC_CPU_USER_NSEC:
2881efd4c9b6SSteve Lawrence 				user.tv_nsec =
2882efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_uint64;
2883efd4c9b6SSteve Lawrence 				numfound++;
2884efd4c9b6SSteve Lawrence 				break;
2885efd4c9b6SSteve Lawrence 			case EXD_PROC_CPU_SYS_SEC:
2886efd4c9b6SSteve Lawrence 				sys.tv_sec =
2887efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_uint64;
2888efd4c9b6SSteve Lawrence 				numfound++;
2889efd4c9b6SSteve Lawrence 				break;
2890efd4c9b6SSteve Lawrence 			case EXD_PROC_CPU_SYS_NSEC:
2891efd4c9b6SSteve Lawrence 				sys.tv_nsec =
2892efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_uint64;
2893efd4c9b6SSteve Lawrence 				numfound++;
2894efd4c9b6SSteve Lawrence 				break;
2895efd4c9b6SSteve Lawrence 			case EXD_PROC_FINISH_SEC:
2896efd4c9b6SSteve Lawrence 				finish.tv_sec =
2897efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_uint64;
2898efd4c9b6SSteve Lawrence 				numfound++;
2899efd4c9b6SSteve Lawrence 				break;
2900efd4c9b6SSteve Lawrence 			case EXD_PROC_FINISH_NSEC:
2901efd4c9b6SSteve Lawrence 				finish.tv_nsec =
2902efd4c9b6SSteve Lawrence 				    pobject.eo_item.ei_uint64;
2903efd4c9b6SSteve Lawrence 				numfound++;
2904efd4c9b6SSteve Lawrence 				break;
2905efd4c9b6SSteve Lawrence 			}
2906efd4c9b6SSteve Lawrence 			(void) ea_free_item(&pobject, EUP_ALLOC);
2907efd4c9b6SSteve Lawrence 		}
2908efd4c9b6SSteve Lawrence 		(void) ea_free_item(&object, EUP_ALLOC);
2909efd4c9b6SSteve Lawrence 		if (numfound != 9) {
2910efd4c9b6SSteve Lawrence 			zsd_warn(gettext(
2911efd4c9b6SSteve Lawrence 			    "Malformed process accounting entry found"));
2912efd4c9b6SSteve Lawrence 			goto proc_done;
2913efd4c9b6SSteve Lawrence 		}
2914efd4c9b6SSteve Lawrence 
2915efd4c9b6SSteve Lawrence 		if (finish.tv_sec > interval_end.tv_sec ||
2916efd4c9b6SSteve Lawrence 		    (finish.tv_sec == interval_end.tv_sec &&
2917efd4c9b6SSteve Lawrence 		    finish.tv_nsec > (interval_end.tv_usec * 1000)))
2918efd4c9b6SSteve Lawrence 			hrtime_expired = B_TRUE;
2919efd4c9b6SSteve Lawrence 
2920efd4c9b6SSteve Lawrence 		/*
2921efd4c9b6SSteve Lawrence 		 * Try to identify the zone and pset to which this
2922efd4c9b6SSteve Lawrence 		 * exited process belongs.
2923efd4c9b6SSteve Lawrence 		 */
2924efd4c9b6SSteve Lawrence 		if (zone == NULL)
2925efd4c9b6SSteve Lawrence 			goto proc_done;
2926efd4c9b6SSteve Lawrence 
2927efd4c9b6SSteve Lawrence 		/* Save proc info */
2928efd4c9b6SSteve Lawrence 		proc->zspr_ppid = ppid;
2929efd4c9b6SSteve Lawrence 		proc->zspr_zoneid = zone->zsz_id;
2930efd4c9b6SSteve Lawrence 
2931efd4c9b6SSteve Lawrence 		prev_psetid = ZS_PSET_ERROR;
2932efd4c9b6SSteve Lawrence 		sched = 0;
2933efd4c9b6SSteve Lawrence 
2934efd4c9b6SSteve Lawrence 		/*
2935efd4c9b6SSteve Lawrence 		 * The following tries to deduce the processes pset.
2936efd4c9b6SSteve Lawrence 		 *
2937efd4c9b6SSteve Lawrence 		 * First choose pset and sched using cached value from the
2938efd4c9b6SSteve Lawrence 		 * most recent time the process has been seen.
2939efd4c9b6SSteve Lawrence 		 *
2940efd4c9b6SSteve Lawrence 		 * pset and sched can change across zone_enter, so make sure
2941efd4c9b6SSteve Lawrence 		 * most recent sighting of this process was in the same
2942efd4c9b6SSteve Lawrence 		 * zone before using most recent known value.
2943efd4c9b6SSteve Lawrence 		 *
2944efd4c9b6SSteve Lawrence 		 * If there is no known value, use value of processes
2945efd4c9b6SSteve Lawrence 		 * parent.  If parent is unknown, walk parents until a known
2946efd4c9b6SSteve Lawrence 		 * parent is found.
2947efd4c9b6SSteve Lawrence 		 *
2948efd4c9b6SSteve Lawrence 		 * If no parent in the zone is found, use the zone's default
2949efd4c9b6SSteve Lawrence 		 * pset and scheduling class.
2950efd4c9b6SSteve Lawrence 		 */
2951efd4c9b6SSteve Lawrence 		if (proc->zspr_psetid != ZS_PSET_ERROR) {
2952efd4c9b6SSteve Lawrence 			prev_psetid = proc->zspr_psetid;
2953efd4c9b6SSteve Lawrence 			pset = zsd_lookup_pset_byid(ctl, prev_psetid);
2954efd4c9b6SSteve Lawrence 			sched = proc->zspr_sched;
2955efd4c9b6SSteve Lawrence 		} else if (pproc->zspr_zoneid == zone->zsz_id &&
2956efd4c9b6SSteve Lawrence 		    pproc->zspr_psetid != ZS_PSET_ERROR) {
2957efd4c9b6SSteve Lawrence 			prev_psetid = pproc->zspr_psetid;
2958efd4c9b6SSteve Lawrence 			pset = zsd_lookup_pset_byid(ctl, prev_psetid);
2959efd4c9b6SSteve Lawrence 			sched = pproc->zspr_sched;
2960efd4c9b6SSteve Lawrence 		}
2961efd4c9b6SSteve Lawrence 
2962efd4c9b6SSteve Lawrence 		if (pset == NULL) {
2963efd4c9b6SSteve Lawrence 			/*
2964efd4c9b6SSteve Lawrence 			 * Process or processes parent has never been seen.
2965efd4c9b6SSteve Lawrence 			 * Save to deduce a known parent later.
2966efd4c9b6SSteve Lawrence 			 */
2967efd4c9b6SSteve Lawrence 			proc_usage = sys;
2968efd4c9b6SSteve Lawrence 			TIMESTRUC_ADD_TIMESTRUC(proc_usage, user);
2969efd4c9b6SSteve Lawrence 			TIMESTRUC_DELTA(delta, proc_usage,
2970efd4c9b6SSteve Lawrence 			    proc->zspr_usage);
2971efd4c9b6SSteve Lawrence 			proc->zspr_usage = delta;
2972efd4c9b6SSteve Lawrence 			list_insert_tail(&plist, proc);
2973efd4c9b6SSteve Lawrence 			continue;
2974efd4c9b6SSteve Lawrence 		}
2975efd4c9b6SSteve Lawrence 
2976efd4c9b6SSteve Lawrence 		/* Add the zone's usage to the pset */
2977efd4c9b6SSteve Lawrence 		usage = zsd_lookup_insert_usage(ctl, pset, zone);
2978efd4c9b6SSteve Lawrence 		if (usage == NULL)
2979efd4c9b6SSteve Lawrence 			goto proc_done;
2980efd4c9b6SSteve Lawrence 
2981efd4c9b6SSteve Lawrence 		zsd_mark_pset_usage_found(usage, sched);
2982efd4c9b6SSteve Lawrence 
2983efd4c9b6SSteve Lawrence 		/* compute the usage to add for the exited proc */
2984efd4c9b6SSteve Lawrence 		proc_usage = sys;
2985efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_TIMESTRUC(proc_usage, user);
2986efd4c9b6SSteve Lawrence 		TIMESTRUC_DELTA(delta, proc_usage,
2987efd4c9b6SSteve Lawrence 		    proc->zspr_usage);
2988efd4c9b6SSteve Lawrence 
2989efd4c9b6SSteve Lawrence 		zsd_add_usage(ctl, usage, &delta);
2990efd4c9b6SSteve Lawrence proc_done:
2991efd4c9b6SSteve Lawrence 		zsd_flush_proc_info(proc);
2992efd4c9b6SSteve Lawrence 
2993efd4c9b6SSteve Lawrence 		if (hrtime_expired == B_TRUE)
2994efd4c9b6SSteve Lawrence 			break;
2995efd4c9b6SSteve Lawrence 	}
2996efd4c9b6SSteve Lawrence 	/*
2997efd4c9b6SSteve Lawrence 	 * close next accounting file.
2998efd4c9b6SSteve Lawrence 	 */
2999efd4c9b6SSteve Lawrence 	if (ctl->zsctl_proc_open_next) {
3000efd4c9b6SSteve Lawrence 		(void) ea_close(
3001efd4c9b6SSteve Lawrence 		    &ctl->zsctl_proc_eaf_next);
3002efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_open_next = 0;
3003efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_fd_next = -1;
3004efd4c9b6SSteve Lawrence 	}
3005efd4c9b6SSteve Lawrence 
3006efd4c9b6SSteve Lawrence 	/* For the remaining processes, use pset and sched of a known parent */
3007efd4c9b6SSteve Lawrence 	proc = list_head(&plist);
3008efd4c9b6SSteve Lawrence 	while (proc != NULL) {
3009efd4c9b6SSteve Lawrence 		next = proc;
3010efd4c9b6SSteve Lawrence 		for (;;) {
3011efd4c9b6SSteve Lawrence 			if (next->zspr_ppid == 0 || next->zspr_ppid == -1) {
3012efd4c9b6SSteve Lawrence 				/*
3013efd4c9b6SSteve Lawrence 				 * Kernel process, or parent is unknown, skip
3014efd4c9b6SSteve Lawrence 				 * process, remove from process list.
3015efd4c9b6SSteve Lawrence 				 */
3016efd4c9b6SSteve Lawrence 				tmp = proc;
3017efd4c9b6SSteve Lawrence 				proc = list_next(&plist, proc);
3018efd4c9b6SSteve Lawrence 				list_link_init(&tmp->zspr_next);
3019efd4c9b6SSteve Lawrence 				break;
3020efd4c9b6SSteve Lawrence 			}
3021efd4c9b6SSteve Lawrence 			pproc = &(ctl->zsctl_proc_array[next->zspr_ppid]);
3022efd4c9b6SSteve Lawrence 			if (pproc->zspr_zoneid != proc->zspr_zoneid) {
3023efd4c9b6SSteve Lawrence 				/*
3024efd4c9b6SSteve Lawrence 				 * Parent in different zone.  Save process and
3025efd4c9b6SSteve Lawrence 				 * use zone's default pset and sched below
3026efd4c9b6SSteve Lawrence 				 */
3027efd4c9b6SSteve Lawrence 				tmp = proc;
3028efd4c9b6SSteve Lawrence 				proc = list_next(&plist, proc);
3029efd4c9b6SSteve Lawrence 				list_remove(&plist, tmp);
3030efd4c9b6SSteve Lawrence 				list_insert_tail(&pplist, tmp);
3031efd4c9b6SSteve Lawrence 				break;
3032efd4c9b6SSteve Lawrence 			}
3033efd4c9b6SSteve Lawrence 			/* Parent has unknown pset, Search parent's parent  */
3034efd4c9b6SSteve Lawrence 			if (pproc->zspr_psetid == ZS_PSET_ERROR) {
3035efd4c9b6SSteve Lawrence 				next = pproc;
3036efd4c9b6SSteve Lawrence 				continue;
3037efd4c9b6SSteve Lawrence 			}
3038efd4c9b6SSteve Lawrence 			/* Found parent with known pset.  Use its info */
3039efd4c9b6SSteve Lawrence 			proc->zspr_psetid = pproc->zspr_psetid;
3040efd4c9b6SSteve Lawrence 			proc->zspr_sched = pproc->zspr_sched;
3041efd4c9b6SSteve Lawrence 			next->zspr_psetid = pproc->zspr_psetid;
3042efd4c9b6SSteve Lawrence 			next->zspr_sched = pproc->zspr_sched;
3043efd4c9b6SSteve Lawrence 			zone = zsd_lookup_zone_byid(ctl,
3044efd4c9b6SSteve Lawrence 			    proc->zspr_zoneid);
3045efd4c9b6SSteve Lawrence 			if (zone == NULL) {
3046efd4c9b6SSteve Lawrence 				tmp = proc;
3047efd4c9b6SSteve Lawrence 				proc = list_next(&plist, proc);
3048efd4c9b6SSteve Lawrence 				list_remove(&plist, tmp);
3049efd4c9b6SSteve Lawrence 				list_link_init(&tmp->zspr_next);
3050efd4c9b6SSteve Lawrence 				break;
3051efd4c9b6SSteve Lawrence 			}
3052efd4c9b6SSteve Lawrence 			pset = zsd_lookup_pset_byid(ctl,
3053efd4c9b6SSteve Lawrence 			    proc->zspr_psetid);
3054efd4c9b6SSteve Lawrence 			if (pset == NULL) {
3055efd4c9b6SSteve Lawrence 				tmp = proc;
3056efd4c9b6SSteve Lawrence 				proc = list_next(&plist, proc);
3057efd4c9b6SSteve Lawrence 				list_remove(&plist, tmp);
3058efd4c9b6SSteve Lawrence 				list_link_init(&tmp->zspr_next);
3059efd4c9b6SSteve Lawrence 				break;
3060efd4c9b6SSteve Lawrence 			}
3061efd4c9b6SSteve Lawrence 			/* Add the zone's usage to the pset */
3062efd4c9b6SSteve Lawrence 			usage = zsd_lookup_insert_usage(ctl, pset, zone);
3063efd4c9b6SSteve Lawrence 			if (usage == NULL) {
3064efd4c9b6SSteve Lawrence 				tmp = proc;
3065efd4c9b6SSteve Lawrence 				proc = list_next(&plist, proc);
3066efd4c9b6SSteve Lawrence 				list_remove(&plist, tmp);
3067efd4c9b6SSteve Lawrence 				list_link_init(&tmp->zspr_next);
3068efd4c9b6SSteve Lawrence 				break;
3069efd4c9b6SSteve Lawrence 			}
3070efd4c9b6SSteve Lawrence 			zsd_mark_pset_usage_found(usage, proc->zspr_sched);
3071efd4c9b6SSteve Lawrence 			zsd_add_usage(ctl, usage, &proc->zspr_usage);
3072efd4c9b6SSteve Lawrence 			zsd_flush_proc_info(proc);
3073efd4c9b6SSteve Lawrence 			tmp = proc;
3074efd4c9b6SSteve Lawrence 			proc = list_next(&plist, proc);
3075efd4c9b6SSteve Lawrence 			list_remove(&plist, tmp);
3076efd4c9b6SSteve Lawrence 			list_link_init(&tmp->zspr_next);
3077efd4c9b6SSteve Lawrence 			break;
3078efd4c9b6SSteve Lawrence 		}
3079efd4c9b6SSteve Lawrence 	}
3080efd4c9b6SSteve Lawrence 	/*
3081efd4c9b6SSteve Lawrence 	 * Process has never been seen.  Using zone info to
3082efd4c9b6SSteve Lawrence 	 * determine pset and scheduling class.
3083efd4c9b6SSteve Lawrence 	 */
3084efd4c9b6SSteve Lawrence 	proc = list_head(&pplist);
3085efd4c9b6SSteve Lawrence 	while (proc != NULL) {
3086efd4c9b6SSteve Lawrence 
3087efd4c9b6SSteve Lawrence 		zone = zsd_lookup_zone_byid(ctl, proc->zspr_zoneid);
3088efd4c9b6SSteve Lawrence 		if (zone == NULL)
3089efd4c9b6SSteve Lawrence 			goto next;
3090efd4c9b6SSteve Lawrence 		if (zone->zsz_psetid != ZS_PSET_ERROR &&
3091efd4c9b6SSteve Lawrence 		    zone->zsz_psetid != ZS_PSET_MULTI) {
3092efd4c9b6SSteve Lawrence 			prev_psetid = zone->zsz_psetid;
3093efd4c9b6SSteve Lawrence 			pset = zsd_lookup_pset_byid(ctl, prev_psetid);
3094efd4c9b6SSteve Lawrence 		} else {
3095efd4c9b6SSteve Lawrence 			pset = zsd_lookup_pset(ctl, zone->zsz_pset, -1);
3096efd4c9b6SSteve Lawrence 			if (pset != NULL)
3097efd4c9b6SSteve Lawrence 				prev_psetid = pset->zsp_id;
3098efd4c9b6SSteve Lawrence 		}
3099efd4c9b6SSteve Lawrence 		if (pset == NULL)
3100efd4c9b6SSteve Lawrence 			goto next;
3101efd4c9b6SSteve Lawrence 
3102efd4c9b6SSteve Lawrence 		sched = zone->zsz_scheds;
3103efd4c9b6SSteve Lawrence 		/*
3104efd4c9b6SSteve Lawrence 		 * Ignore FX high scheduling class if it is not the
3105efd4c9b6SSteve Lawrence 		 * only scheduling class in the zone.
3106efd4c9b6SSteve Lawrence 		 */
3107efd4c9b6SSteve Lawrence 		if (sched != ZS_SCHED_FX_60)
3108efd4c9b6SSteve Lawrence 			sched &= (~ZS_SCHED_FX_60);
3109efd4c9b6SSteve Lawrence 		/*
3110efd4c9b6SSteve Lawrence 		 * If more than one scheduling class has been found
3111efd4c9b6SSteve Lawrence 		 * in the zone, use zone's default scheduling class for
3112efd4c9b6SSteve Lawrence 		 * this process.
3113efd4c9b6SSteve Lawrence 		 */
3114efd4c9b6SSteve Lawrence 		if ((sched & (sched - 1)) != 0)
3115efd4c9b6SSteve Lawrence 			sched = zone->zsz_default_sched;
3116efd4c9b6SSteve Lawrence 
3117efd4c9b6SSteve Lawrence 		/* Add the zone's usage to the pset */
3118efd4c9b6SSteve Lawrence 		usage = zsd_lookup_insert_usage(ctl, pset, zone);
3119efd4c9b6SSteve Lawrence 		if (usage == NULL)
3120efd4c9b6SSteve Lawrence 			goto next;
3121efd4c9b6SSteve Lawrence 
3122efd4c9b6SSteve Lawrence 		zsd_mark_pset_usage_found(usage, sched);
3123efd4c9b6SSteve Lawrence 		zsd_add_usage(ctl, usage, &proc->zspr_usage);
3124efd4c9b6SSteve Lawrence next:
3125efd4c9b6SSteve Lawrence 		tmp = proc;
3126efd4c9b6SSteve Lawrence 		proc = list_next(&pplist, proc);
3127efd4c9b6SSteve Lawrence 		zsd_flush_proc_info(tmp);
3128efd4c9b6SSteve Lawrence 		list_link_init(&tmp->zspr_next);
3129efd4c9b6SSteve Lawrence 	}
3130efd4c9b6SSteve Lawrence 	return;
3131efd4c9b6SSteve Lawrence ea_err:
3132efd4c9b6SSteve Lawrence 	/*
3133efd4c9b6SSteve Lawrence 	 * Close the next accounting file if we have not transitioned to it
3134efd4c9b6SSteve Lawrence 	 * yet.
3135efd4c9b6SSteve Lawrence 	 */
3136efd4c9b6SSteve Lawrence 	if (ctl->zsctl_proc_open_next) {
3137efd4c9b6SSteve Lawrence 		(void) ea_close(&ctl->zsctl_proc_eaf_next);
3138efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_open_next = 0;
3139efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_fd_next = -1;
3140efd4c9b6SSteve Lawrence 	}
3141efd4c9b6SSteve Lawrence }
3142efd4c9b6SSteve Lawrence 
3143efd4c9b6SSteve Lawrence /*
3144efd4c9b6SSteve Lawrence  * getvmusage(2) uses size_t's in the passwd data structure, which differ
3145efd4c9b6SSteve Lawrence  * in size for 32bit and 64 bit kernels.  Since this is a contracted interface,
3146efd4c9b6SSteve Lawrence  * and zonestatd does not necessarily match the kernel's bitness, marshal
3147efd4c9b6SSteve Lawrence  * results appropriately.
3148efd4c9b6SSteve Lawrence  */
3149efd4c9b6SSteve Lawrence static int
zsd_getvmusage(zsd_ctl_t * ctl,uint_t flags,time_t age,zsd_vmusage64_t * buf,uint64_t * nres)3150efd4c9b6SSteve Lawrence zsd_getvmusage(zsd_ctl_t *ctl, uint_t flags, time_t age, zsd_vmusage64_t *buf,
3151efd4c9b6SSteve Lawrence     uint64_t *nres)
3152efd4c9b6SSteve Lawrence {
3153efd4c9b6SSteve Lawrence 	zsd_vmusage32_t *vmu32;
3154efd4c9b6SSteve Lawrence 	zsd_vmusage64_t *vmu64;
3155efd4c9b6SSteve Lawrence 	uint32_t nres32;
3156efd4c9b6SSteve Lawrence 	int i;
3157efd4c9b6SSteve Lawrence 	int ret;
3158efd4c9b6SSteve Lawrence 
3159efd4c9b6SSteve Lawrence 	if (ctl->zsctl_kern_bits == 32)  {
3160efd4c9b6SSteve Lawrence 		nres32 = *nres;
3161efd4c9b6SSteve Lawrence 		ret = syscall(SYS_rusagesys, _RUSAGESYS_GETVMUSAGE,
3162efd4c9b6SSteve Lawrence 		    flags, age, (uintptr_t)buf, (uintptr_t)&nres32);
3163efd4c9b6SSteve Lawrence 		*nres = nres32;
3164efd4c9b6SSteve Lawrence 		if (ret == 0 && buf != NULL) {
3165efd4c9b6SSteve Lawrence 			/*
3166efd4c9b6SSteve Lawrence 			 * An array of vmusage32_t's has been returned.
3167efd4c9b6SSteve Lawrence 			 * Convert it to an array of vmusage64_t's.
3168efd4c9b6SSteve Lawrence 			 */
3169efd4c9b6SSteve Lawrence 			vmu32 = (zsd_vmusage32_t *)buf;
3170efd4c9b6SSteve Lawrence 			vmu64 = (zsd_vmusage64_t *)buf;
3171efd4c9b6SSteve Lawrence 			for (i = nres32 - 1; i >= 0; i--) {
3172efd4c9b6SSteve Lawrence 
3173efd4c9b6SSteve Lawrence 				vmu64[i].vmu_zoneid = vmu32[i].vmu_zoneid;
3174efd4c9b6SSteve Lawrence 				vmu64[i].vmu_type = vmu32[i].vmu_type;
3175efd4c9b6SSteve Lawrence 				vmu64[i].vmu_type = vmu32[i].vmu_type;
3176efd4c9b6SSteve Lawrence 				vmu64[i].vmu_rss_all = vmu32[i].vmu_rss_all;
3177efd4c9b6SSteve Lawrence 				vmu64[i].vmu_rss_private =
3178efd4c9b6SSteve Lawrence 				    vmu32[i].vmu_rss_private;
3179efd4c9b6SSteve Lawrence 				vmu64[i].vmu_rss_shared =
3180efd4c9b6SSteve Lawrence 				    vmu32[i].vmu_rss_shared;
3181efd4c9b6SSteve Lawrence 				vmu64[i].vmu_swap_all = vmu32[i].vmu_swap_all;
3182efd4c9b6SSteve Lawrence 				vmu64[i].vmu_swap_private =
3183efd4c9b6SSteve Lawrence 				    vmu32[i].vmu_swap_private;
3184efd4c9b6SSteve Lawrence 				vmu64[i].vmu_swap_shared =
3185efd4c9b6SSteve Lawrence 				    vmu32[i].vmu_swap_shared;
3186efd4c9b6SSteve Lawrence 			}
3187efd4c9b6SSteve Lawrence 		}
3188efd4c9b6SSteve Lawrence 		return (ret);
3189efd4c9b6SSteve Lawrence 	} else {
3190efd4c9b6SSteve Lawrence 		/*
3191efd4c9b6SSteve Lawrence 		 * kernel is 64 bit, so use 64 bit structures as zonestat
3192efd4c9b6SSteve Lawrence 		 * expects.
3193efd4c9b6SSteve Lawrence 		 */
3194efd4c9b6SSteve Lawrence 		return (syscall(SYS_rusagesys, _RUSAGESYS_GETVMUSAGE,
3195efd4c9b6SSteve Lawrence 		    flags, age, (uintptr_t)buf, (uintptr_t)nres));
3196efd4c9b6SSteve Lawrence 
3197efd4c9b6SSteve Lawrence 	}
3198efd4c9b6SSteve Lawrence }
3199efd4c9b6SSteve Lawrence 
3200efd4c9b6SSteve Lawrence /*
3201efd4c9b6SSteve Lawrence  * Update the current physical, virtual, and locked memory usage of the
3202efd4c9b6SSteve Lawrence  * running zones.
3203efd4c9b6SSteve Lawrence  */
3204efd4c9b6SSteve Lawrence static void
zsd_refresh_memory(zsd_ctl_t * ctl,boolean_t init)3205efd4c9b6SSteve Lawrence zsd_refresh_memory(zsd_ctl_t *ctl, boolean_t init)
3206efd4c9b6SSteve Lawrence {
3207efd4c9b6SSteve Lawrence 
3208efd4c9b6SSteve Lawrence 	uint64_t phys_total;
3209efd4c9b6SSteve Lawrence 	uint64_t phys_used;
3210efd4c9b6SSteve Lawrence 	uint64_t phys_zones;
3211efd4c9b6SSteve Lawrence 	uint64_t phys_zones_overcount;
3212efd4c9b6SSteve Lawrence 	uint64_t phys_zones_extra;
3213efd4c9b6SSteve Lawrence 	uint64_t phys_zones_credit;
3214efd4c9b6SSteve Lawrence 
3215efd4c9b6SSteve Lawrence 	uint64_t vm_free;
3216efd4c9b6SSteve Lawrence 	uint64_t vm_used;
3217efd4c9b6SSteve Lawrence 
3218efd4c9b6SSteve Lawrence 	uint64_t disk_swap_total;
3219efd4c9b6SSteve Lawrence 	uint64_t disk_swap_used;	/* disk swap with contents */
3220efd4c9b6SSteve Lawrence 
3221efd4c9b6SSteve Lawrence 	uint64_t physmem;
3222efd4c9b6SSteve Lawrence 	uint64_t pp_kernel;
3223efd4c9b6SSteve Lawrence 	uint64_t arc_size = 0;
3224efd4c9b6SSteve Lawrence 	struct anoninfo ani;
3225efd4c9b6SSteve Lawrence 
3226efd4c9b6SSteve Lawrence 	int num_swap_devices;
3227efd4c9b6SSteve Lawrence 	struct swaptable *swt;
3228efd4c9b6SSteve Lawrence 	struct swapent *swent;
3229efd4c9b6SSteve Lawrence 	size_t swt_size;
3230efd4c9b6SSteve Lawrence 	char *path;
3231efd4c9b6SSteve Lawrence 
3232efd4c9b6SSteve Lawrence 	zsd_vmusage64_t *vmusage;
3233efd4c9b6SSteve Lawrence 	uint64_t num_vmusage;
3234efd4c9b6SSteve Lawrence 
3235efd4c9b6SSteve Lawrence 	int i, ret;
3236efd4c9b6SSteve Lawrence 
3237efd4c9b6SSteve Lawrence 	zsd_system_t *sys;
3238efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
3239efd4c9b6SSteve Lawrence 	int vmu_nzones;
3240efd4c9b6SSteve Lawrence 
3241efd4c9b6SSteve Lawrence 	kstat_t *kstat;
3242efd4c9b6SSteve Lawrence 	char kstat_name[KSTAT_STRLEN];
3243efd4c9b6SSteve Lawrence 	kstat_named_t *knp;
3244efd4c9b6SSteve Lawrence 	kid_t kid;
3245efd4c9b6SSteve Lawrence 
3246efd4c9b6SSteve Lawrence 	if (init)
3247efd4c9b6SSteve Lawrence 		return;
3248efd4c9b6SSteve Lawrence 
3249efd4c9b6SSteve Lawrence 	sys = ctl->zsctl_system;
3250efd4c9b6SSteve Lawrence 
3251efd4c9b6SSteve Lawrence 	/* interrogate swap devices to find the amount of disk swap */
3252efd4c9b6SSteve Lawrence disk_swap_again:
3253efd4c9b6SSteve Lawrence 	num_swap_devices = swapctl(SC_GETNSWP, NULL);
3254efd4c9b6SSteve Lawrence 
3255efd4c9b6SSteve Lawrence 	if (num_swap_devices == 0) {
3256efd4c9b6SSteve Lawrence 		sys->zss_swap_total = disk_swap_total = 0;
3257efd4c9b6SSteve Lawrence 		sys->zss_swap_used = disk_swap_used = 0;
3258efd4c9b6SSteve Lawrence 		/* No disk swap */
3259efd4c9b6SSteve Lawrence 		goto disk_swap_done;
3260efd4c9b6SSteve Lawrence 	}
3261efd4c9b6SSteve Lawrence 	/* see if swap table needs to be larger */
3262efd4c9b6SSteve Lawrence 	if (num_swap_devices > ctl->zsctl_swap_cache_num) {
3263efd4c9b6SSteve Lawrence 		swt_size = sizeof (int) +
3264efd4c9b6SSteve Lawrence 		    (num_swap_devices * sizeof (struct swapent)) +
3265efd4c9b6SSteve Lawrence 		    (num_swap_devices * MAXPATHLEN);
3266efd4c9b6SSteve Lawrence 		if (ctl->zsctl_swap_cache != NULL)
3267efd4c9b6SSteve Lawrence 			free(ctl->zsctl_swap_cache);
3268efd4c9b6SSteve Lawrence 
3269efd4c9b6SSteve Lawrence 		swt = (struct swaptable *)malloc(swt_size);
3270efd4c9b6SSteve Lawrence 		if (swt == NULL) {
3271efd4c9b6SSteve Lawrence 			/*
3272efd4c9b6SSteve Lawrence 			 * Could not allocate to get list of swap devices.
3273efd4c9b6SSteve Lawrence 			 * Just use data from the most recent read, which will
3274efd4c9b6SSteve Lawrence 			 * be zero if this is the first read.
3275efd4c9b6SSteve Lawrence 			 */
3276efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Unable to allocate to determine "
3277efd4c9b6SSteve Lawrence 			    "virtual memory"));
3278efd4c9b6SSteve Lawrence 			disk_swap_total = sys->zss_swap_total;
3279efd4c9b6SSteve Lawrence 			disk_swap_used = sys->zss_swap_used;
3280efd4c9b6SSteve Lawrence 			goto disk_swap_done;
3281efd4c9b6SSteve Lawrence 		}
3282efd4c9b6SSteve Lawrence 		swent = swt->swt_ent;
3283efd4c9b6SSteve Lawrence 		path = (char *)swt + (sizeof (int) +
3284efd4c9b6SSteve Lawrence 		    num_swap_devices * sizeof (swapent_t));
3285efd4c9b6SSteve Lawrence 		for (i = 0; i < num_swap_devices; i++, swent++) {
3286efd4c9b6SSteve Lawrence 			swent->ste_path = path;
3287efd4c9b6SSteve Lawrence 			path += MAXPATHLEN;
3288efd4c9b6SSteve Lawrence 		}
3289efd4c9b6SSteve Lawrence 		swt->swt_n = num_swap_devices;
3290efd4c9b6SSteve Lawrence 		ctl->zsctl_swap_cache = swt;
3291efd4c9b6SSteve Lawrence 		ctl->zsctl_swap_cache_size = swt_size;
3292efd4c9b6SSteve Lawrence 		ctl->zsctl_swap_cache_num = num_swap_devices;
3293efd4c9b6SSteve Lawrence 	}
3294efd4c9b6SSteve Lawrence 	num_swap_devices = swapctl(SC_LIST, ctl->zsctl_swap_cache);
3295efd4c9b6SSteve Lawrence 	if (num_swap_devices < 0) {
3296efd4c9b6SSteve Lawrence 		/* More swap devices have arrived */
3297efd4c9b6SSteve Lawrence 		if (errno == ENOMEM)
3298efd4c9b6SSteve Lawrence 			goto disk_swap_again;
3299efd4c9b6SSteve Lawrence 
3300efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to determine disk swap devices"));
3301efd4c9b6SSteve Lawrence 		/* Unexpected error.  Use existing data */
3302efd4c9b6SSteve Lawrence 		disk_swap_total = sys->zss_swap_total;
3303efd4c9b6SSteve Lawrence 		disk_swap_used = sys->zss_swap_used;
3304efd4c9b6SSteve Lawrence 		goto disk_swap_done;
3305efd4c9b6SSteve Lawrence 	}
3306efd4c9b6SSteve Lawrence 
3307efd4c9b6SSteve Lawrence 	/* add up the disk swap */
3308efd4c9b6SSteve Lawrence 	disk_swap_total = 0;
3309efd4c9b6SSteve Lawrence 	disk_swap_used = 0;
3310efd4c9b6SSteve Lawrence 	swent = ctl->zsctl_swap_cache->swt_ent;
3311efd4c9b6SSteve Lawrence 	for (i = 0; i < num_swap_devices; i++, swent++) {
3312efd4c9b6SSteve Lawrence 		disk_swap_total += swent->ste_pages;
3313efd4c9b6SSteve Lawrence 		disk_swap_used += (swent->ste_pages - swent->ste_free);
3314efd4c9b6SSteve Lawrence 	}
3315efd4c9b6SSteve Lawrence 	disk_swap_total *= ctl->zsctl_pagesize;
3316efd4c9b6SSteve Lawrence 	disk_swap_used *= ctl->zsctl_pagesize;
3317efd4c9b6SSteve Lawrence 
3318efd4c9b6SSteve Lawrence 	sys->zss_swap_total = disk_swap_total;
3319efd4c9b6SSteve Lawrence 	sys->zss_swap_used = disk_swap_used;
3320efd4c9b6SSteve Lawrence 
3321efd4c9b6SSteve Lawrence disk_swap_done:
3322efd4c9b6SSteve Lawrence 
3323efd4c9b6SSteve Lawrence 	/* get system pages kstat */
3324efd4c9b6SSteve Lawrence 	kid = -1;
3325efd4c9b6SSteve Lawrence 	kstat = kstat_lookup(ctl->zsctl_kstat_ctl, "unix", 0, "system_pages");
3326efd4c9b6SSteve Lawrence 	if (kstat == NULL)
3327efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to lookup system pages kstat"));
3328efd4c9b6SSteve Lawrence 	else
3329efd4c9b6SSteve Lawrence 		kid = kstat_read(ctl->zsctl_kstat_ctl, kstat, NULL);
3330efd4c9b6SSteve Lawrence 
3331efd4c9b6SSteve Lawrence 	if (kid == -1) {
3332efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to read system pages kstat"));
3333efd4c9b6SSteve Lawrence 		return;
3334efd4c9b6SSteve Lawrence 	} else {
3335efd4c9b6SSteve Lawrence 		knp = kstat_data_lookup(kstat, "physmem");
3336efd4c9b6SSteve Lawrence 		if (knp == NULL) {
3337efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Unable to read physmem"));
3338efd4c9b6SSteve Lawrence 		} else {
3339efd4c9b6SSteve Lawrence 			if (knp->data_type == KSTAT_DATA_UINT64)
3340efd4c9b6SSteve Lawrence 				physmem = knp->value.ui64;
3341efd4c9b6SSteve Lawrence 			else if (knp->data_type == KSTAT_DATA_UINT32)
3342efd4c9b6SSteve Lawrence 				physmem = knp->value.ui32;
3343efd4c9b6SSteve Lawrence 			else
3344efd4c9b6SSteve Lawrence 				return;
3345efd4c9b6SSteve Lawrence 		}
3346efd4c9b6SSteve Lawrence 		knp = kstat_data_lookup(kstat, "pp_kernel");
3347efd4c9b6SSteve Lawrence 		if (knp == NULL) {
3348efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Unable to read pp_kernel"));
3349efd4c9b6SSteve Lawrence 		} else {
3350efd4c9b6SSteve Lawrence 			if (knp->data_type == KSTAT_DATA_UINT64)
3351efd4c9b6SSteve Lawrence 				pp_kernel = knp->value.ui64;
3352efd4c9b6SSteve Lawrence 			else if (knp->data_type == KSTAT_DATA_UINT32)
3353efd4c9b6SSteve Lawrence 				pp_kernel = knp->value.ui32;
3354efd4c9b6SSteve Lawrence 			else
3355efd4c9b6SSteve Lawrence 				return;
3356efd4c9b6SSteve Lawrence 		}
3357efd4c9b6SSteve Lawrence 	}
3358efd4c9b6SSteve Lawrence 	physmem *= ctl->zsctl_pagesize;
3359efd4c9b6SSteve Lawrence 	pp_kernel *= ctl->zsctl_pagesize;
3360efd4c9b6SSteve Lawrence 
3361efd4c9b6SSteve Lawrence 	/* get the zfs arc size if available */
3362efd4c9b6SSteve Lawrence 	arc_size = 0;
3363efd4c9b6SSteve Lawrence 	kid = -1;
3364efd4c9b6SSteve Lawrence 	kstat = kstat_lookup(ctl->zsctl_kstat_ctl, "zfs", 0, "arcstats");
3365efd4c9b6SSteve Lawrence 	if (kstat != NULL)
3366efd4c9b6SSteve Lawrence 		kid = kstat_read(ctl->zsctl_kstat_ctl, kstat, NULL);
3367efd4c9b6SSteve Lawrence 	if (kid != -1) {
3368efd4c9b6SSteve Lawrence 		knp = kstat_data_lookup(kstat, "size");
3369efd4c9b6SSteve Lawrence 		if (knp != NULL)
3370efd4c9b6SSteve Lawrence 			if (knp->data_type == KSTAT_DATA_UINT64)
3371efd4c9b6SSteve Lawrence 				arc_size = knp->value.ui64;
3372efd4c9b6SSteve Lawrence 	}
3373efd4c9b6SSteve Lawrence 
3374efd4c9b6SSteve Lawrence 	/* Try to get swap information */
3375efd4c9b6SSteve Lawrence 	if (swapctl(SC_AINFO, &ani) < 0) {
3376efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to get swap info"));
3377efd4c9b6SSteve Lawrence 		return;
3378efd4c9b6SSteve Lawrence 	}
3379efd4c9b6SSteve Lawrence 
3380efd4c9b6SSteve Lawrence vmusage_again:
3381efd4c9b6SSteve Lawrence 	/* getvmusage to get physical memory usage */
3382efd4c9b6SSteve Lawrence 	vmusage = ctl->zsctl_vmusage_cache;
3383efd4c9b6SSteve Lawrence 	num_vmusage = ctl->zsctl_vmusage_cache_num;
3384efd4c9b6SSteve Lawrence 
3385efd4c9b6SSteve Lawrence 	ret = zsd_getvmusage(ctl, VMUSAGE_SYSTEM | VMUSAGE_ALL_ZONES, 0,
3386efd4c9b6SSteve Lawrence 	    vmusage, &num_vmusage);
3387efd4c9b6SSteve Lawrence 
3388efd4c9b6SSteve Lawrence 	if (ret != 0) {
3389efd4c9b6SSteve Lawrence 		/* Unexpected error.  Use existing data */
3390efd4c9b6SSteve Lawrence 		if (errno != EOVERFLOW) {
3391efd4c9b6SSteve Lawrence 			zsd_warn(gettext(
3392efd4c9b6SSteve Lawrence 			    "Unable to read physical memory usage"));
3393efd4c9b6SSteve Lawrence 			phys_zones = sys->zss_ram_zones;
3394efd4c9b6SSteve Lawrence 			goto vmusage_done;
3395efd4c9b6SSteve Lawrence 		}
3396efd4c9b6SSteve Lawrence 	}
3397efd4c9b6SSteve Lawrence 	/* vmusage results cache too small */
3398efd4c9b6SSteve Lawrence 	if (num_vmusage > ctl->zsctl_vmusage_cache_num) {
3399efd4c9b6SSteve Lawrence 
3400efd4c9b6SSteve Lawrence 		size_t size = sizeof (zsd_vmusage64_t) * num_vmusage;
3401efd4c9b6SSteve Lawrence 
3402efd4c9b6SSteve Lawrence 		if (ctl->zsctl_vmusage_cache != NULL)
3403efd4c9b6SSteve Lawrence 			free(ctl->zsctl_vmusage_cache);
3404efd4c9b6SSteve Lawrence 		vmusage = (zsd_vmusage64_t *)malloc(size);
3405efd4c9b6SSteve Lawrence 		if (vmusage == NULL) {
3406efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Unable to alloc to determine "
3407efd4c9b6SSteve Lawrence 			    "physical memory usage"));
3408efd4c9b6SSteve Lawrence 			phys_zones = sys->zss_ram_zones;
3409efd4c9b6SSteve Lawrence 			goto vmusage_done;
3410efd4c9b6SSteve Lawrence 		}
3411efd4c9b6SSteve Lawrence 		ctl->zsctl_vmusage_cache = vmusage;
3412efd4c9b6SSteve Lawrence 		ctl->zsctl_vmusage_cache_num = num_vmusage;
3413efd4c9b6SSteve Lawrence 		goto vmusage_again;
3414efd4c9b6SSteve Lawrence 	}
3415efd4c9b6SSteve Lawrence 
3416efd4c9b6SSteve Lawrence 	phys_zones_overcount = 0;
3417efd4c9b6SSteve Lawrence 	vmu_nzones = 0;
3418efd4c9b6SSteve Lawrence 	for (i = 0; i < num_vmusage; i++) {
3419efd4c9b6SSteve Lawrence 		switch (vmusage[i].vmu_type) {
3420efd4c9b6SSteve Lawrence 		case VMUSAGE_SYSTEM:
3421efd4c9b6SSteve Lawrence 			/* total pages backing user process mappings */
3422efd4c9b6SSteve Lawrence 			phys_zones = sys->zss_ram_zones =
3423efd4c9b6SSteve Lawrence 			    vmusage[i].vmu_rss_all;
3424efd4c9b6SSteve Lawrence 			break;
3425efd4c9b6SSteve Lawrence 		case VMUSAGE_ZONE:
3426efd4c9b6SSteve Lawrence 			vmu_nzones++;
3427efd4c9b6SSteve Lawrence 			phys_zones_overcount += vmusage[i].vmu_rss_all;
3428efd4c9b6SSteve Lawrence 			zone = zsd_lookup_zone_byid(ctl, vmusage[i].vmu_id);
3429efd4c9b6SSteve Lawrence 			if (zone != NULL)
3430efd4c9b6SSteve Lawrence 				zone->zsz_usage_ram = vmusage[i].vmu_rss_all;
3431efd4c9b6SSteve Lawrence 			break;
3432efd4c9b6SSteve Lawrence 		default:
3433efd4c9b6SSteve Lawrence 			break;
3434efd4c9b6SSteve Lawrence 		}
3435efd4c9b6SSteve Lawrence 	}
3436efd4c9b6SSteve Lawrence 	/*
3437efd4c9b6SSteve Lawrence 	 * Figure how much memory was double counted due to text sharing
3438efd4c9b6SSteve Lawrence 	 * between zones.  Credit this back so that the sum of the zones
3439efd4c9b6SSteve Lawrence 	 * equals the total zone ram usage;
3440efd4c9b6SSteve Lawrence 	 */
3441efd4c9b6SSteve Lawrence 	phys_zones_extra = phys_zones_overcount - phys_zones;
3442efd4c9b6SSteve Lawrence 	phys_zones_credit = phys_zones_extra / vmu_nzones;
3443efd4c9b6SSteve Lawrence 
3444efd4c9b6SSteve Lawrence vmusage_done:
3445efd4c9b6SSteve Lawrence 
3446efd4c9b6SSteve Lawrence 	/* walk the zones to get swap and locked kstats.  Fetch ram cap. */
3447efd4c9b6SSteve Lawrence 	sys->zss_locked_zones = 0;
3448efd4c9b6SSteve Lawrence 	sys->zss_vm_zones = 0;
3449efd4c9b6SSteve Lawrence 	for (zone = list_head(&ctl->zsctl_zones); zone != NULL;
3450efd4c9b6SSteve Lawrence 	    zone = list_next(&ctl->zsctl_zones, zone)) {
3451efd4c9b6SSteve Lawrence 
3452efd4c9b6SSteve Lawrence 		/* If zone halted during interval, show memory usage as none */
3453efd4c9b6SSteve Lawrence 		if (zone->zsz_active == B_FALSE ||
3454efd4c9b6SSteve Lawrence 		    zone->zsz_deleted == B_TRUE) {
3455efd4c9b6SSteve Lawrence 			zone->zsz_usage_ram = 0;
3456efd4c9b6SSteve Lawrence 			zone->zsz_usage_vm = 0;
3457efd4c9b6SSteve Lawrence 			zone->zsz_usage_locked = 0;
3458efd4c9b6SSteve Lawrence 			continue;
3459efd4c9b6SSteve Lawrence 		}
3460efd4c9b6SSteve Lawrence 
3461efd4c9b6SSteve Lawrence 		if (phys_zones_credit > 0) {
3462efd4c9b6SSteve Lawrence 			if (zone->zsz_usage_ram > phys_zones_credit) {
3463efd4c9b6SSteve Lawrence 				zone->zsz_usage_ram -= phys_zones_credit;
3464efd4c9b6SSteve Lawrence 			}
3465efd4c9b6SSteve Lawrence 		}
3466efd4c9b6SSteve Lawrence 		/*
3467efd4c9b6SSteve Lawrence 		 * Get zone's swap usage.  Since zone could have halted,
3468efd4c9b6SSteve Lawrence 		 * treats as zero if cannot read
3469efd4c9b6SSteve Lawrence 		 */
3470efd4c9b6SSteve Lawrence 		zone->zsz_usage_vm = 0;
3471efd4c9b6SSteve Lawrence 		(void) snprintf(kstat_name, sizeof (kstat_name),
3472efd4c9b6SSteve Lawrence 		    "swapresv_zone_%d", zone->zsz_id);
3473efd4c9b6SSteve Lawrence 		kid = -1;
3474efd4c9b6SSteve Lawrence 		kstat = kstat_lookup(ctl->zsctl_kstat_ctl, "caps",
3475efd4c9b6SSteve Lawrence 		    zone->zsz_id, kstat_name);
3476efd4c9b6SSteve Lawrence 		if (kstat != NULL)
3477efd4c9b6SSteve Lawrence 			kid = kstat_read(ctl->zsctl_kstat_ctl, kstat, NULL);
3478efd4c9b6SSteve Lawrence 		if (kid != -1) {
3479efd4c9b6SSteve Lawrence 			knp = kstat_data_lookup(kstat, "usage");
3480efd4c9b6SSteve Lawrence 			if (knp != NULL &&
3481efd4c9b6SSteve Lawrence 			    knp->data_type == KSTAT_DATA_UINT64) {
3482efd4c9b6SSteve Lawrence 				zone->zsz_usage_vm = knp->value.ui64;
3483efd4c9b6SSteve Lawrence 				sys->zss_vm_zones += knp->value.ui64;
3484efd4c9b6SSteve Lawrence 			}
3485efd4c9b6SSteve Lawrence 		}
3486efd4c9b6SSteve Lawrence 		/*
3487efd4c9b6SSteve Lawrence 		 * Get zone's locked usage.  Since zone could have halted,
3488efd4c9b6SSteve Lawrence 		 * treats as zero if cannot read
3489efd4c9b6SSteve Lawrence 		 */
3490efd4c9b6SSteve Lawrence 		zone->zsz_usage_locked = 0;
3491efd4c9b6SSteve Lawrence 		(void) snprintf(kstat_name, sizeof (kstat_name),
3492efd4c9b6SSteve Lawrence 		    "lockedmem_zone_%d", zone->zsz_id);
3493efd4c9b6SSteve Lawrence 		kid = -1;
3494efd4c9b6SSteve Lawrence 		kstat = kstat_lookup(ctl->zsctl_kstat_ctl, "caps",
3495efd4c9b6SSteve Lawrence 		    zone->zsz_id, kstat_name);
3496efd4c9b6SSteve Lawrence 		if (kstat != NULL)
3497efd4c9b6SSteve Lawrence 			kid = kstat_read(ctl->zsctl_kstat_ctl, kstat, NULL);
3498efd4c9b6SSteve Lawrence 		if (kid != -1) {
3499efd4c9b6SSteve Lawrence 			knp = kstat_data_lookup(kstat, "usage");
3500efd4c9b6SSteve Lawrence 			if (knp != NULL &&
3501efd4c9b6SSteve Lawrence 			    knp->data_type == KSTAT_DATA_UINT64) {
3502efd4c9b6SSteve Lawrence 				zone->zsz_usage_locked = knp->value.ui64;
3503efd4c9b6SSteve Lawrence 				/*
3504efd4c9b6SSteve Lawrence 				 * Since locked memory accounting for zones
3505efd4c9b6SSteve Lawrence 				 * can double count ddi locked memory, cap each
3506efd4c9b6SSteve Lawrence 				 * zone's locked usage at its ram usage.
3507efd4c9b6SSteve Lawrence 				 */
3508efd4c9b6SSteve Lawrence 				if (zone->zsz_usage_locked >
3509efd4c9b6SSteve Lawrence 				    zone->zsz_usage_ram)
3510efd4c9b6SSteve Lawrence 					zone->zsz_usage_locked =
3511efd4c9b6SSteve Lawrence 					    zone->zsz_usage_ram;
3512efd4c9b6SSteve Lawrence 				sys->zss_locked_zones +=
3513efd4c9b6SSteve Lawrence 				    zone->zsz_usage_locked;
3514efd4c9b6SSteve Lawrence 			}
3515efd4c9b6SSteve Lawrence 		}
3516efd4c9b6SSteve Lawrence 	}
3517efd4c9b6SSteve Lawrence 
3518efd4c9b6SSteve Lawrence 	phys_total =
3519efd4c9b6SSteve Lawrence 	    sysconf(_SC_PHYS_PAGES) * ctl->zsctl_pagesize;
3520efd4c9b6SSteve Lawrence 
3521efd4c9b6SSteve Lawrence 	phys_used = (sysconf(_SC_PHYS_PAGES) - sysconf(_SC_AVPHYS_PAGES))
3522efd4c9b6SSteve Lawrence 	    * ctl->zsctl_pagesize;
3523efd4c9b6SSteve Lawrence 
3524efd4c9b6SSteve Lawrence 	/* Compute remaining statistics */
3525efd4c9b6SSteve Lawrence 	sys->zss_ram_total = phys_total;
3526efd4c9b6SSteve Lawrence 	sys->zss_ram_zones = phys_zones;
3527efd4c9b6SSteve Lawrence 	sys->zss_ram_kern = phys_used - phys_zones - arc_size;
3528efd4c9b6SSteve Lawrence 
3529efd4c9b6SSteve Lawrence 	/*
3530efd4c9b6SSteve Lawrence 	 * The total for kernel locked memory should include
3531efd4c9b6SSteve Lawrence 	 * segkp locked pages, but oh well.  The arc size is subtracted,
3532efd4c9b6SSteve Lawrence 	 * as that physical memory is reclaimable.
3533efd4c9b6SSteve Lawrence 	 */
3534efd4c9b6SSteve Lawrence 	sys->zss_locked_kern = pp_kernel - arc_size;
3535efd4c9b6SSteve Lawrence 	/* Add memory used by kernel startup and obp to kernel locked */
3536efd4c9b6SSteve Lawrence 	if ((phys_total - physmem) > 0)
3537efd4c9b6SSteve Lawrence 		sys->zss_locked_kern += phys_total - physmem;
3538efd4c9b6SSteve Lawrence 
3539efd4c9b6SSteve Lawrence 	/*
3540efd4c9b6SSteve Lawrence 	 * Add in the portion of (RAM+DISK) that is not available as swap,
3541efd4c9b6SSteve Lawrence 	 * and consider it swap used by the kernel.
3542efd4c9b6SSteve Lawrence 	 */
3543efd4c9b6SSteve Lawrence 	sys->zss_vm_total = phys_total + disk_swap_total;
3544efd4c9b6SSteve Lawrence 	vm_free = (ani.ani_max - ani.ani_resv) * ctl->zsctl_pagesize;
3545efd4c9b6SSteve Lawrence 	vm_used = sys->zss_vm_total - vm_free;
3546efd4c9b6SSteve Lawrence 	sys->zss_vm_kern = vm_used - sys->zss_vm_zones - arc_size;
3547efd4c9b6SSteve Lawrence }
3548efd4c9b6SSteve Lawrence 
3549efd4c9b6SSteve Lawrence /*
3550efd4c9b6SSteve Lawrence  * Charge each cpu's usage to its processor sets.  Also add the cpu's total
3551efd4c9b6SSteve Lawrence  * time to each zone using the processor set.  This tracks the maximum
3552efd4c9b6SSteve Lawrence  * amount of cpu time that a zone could have used.
3553efd4c9b6SSteve Lawrence  */
3554efd4c9b6SSteve Lawrence static void
zsd_refresh_cpu_stats(zsd_ctl_t * ctl,boolean_t init)3555efd4c9b6SSteve Lawrence zsd_refresh_cpu_stats(zsd_ctl_t *ctl, boolean_t init)
3556efd4c9b6SSteve Lawrence {
3557efd4c9b6SSteve Lawrence 	zsd_system_t *sys;
3558efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
3559efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage;
3560efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu;
3561efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu_next;
3562efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
3563efd4c9b6SSteve Lawrence 	timestruc_t ts;
3564efd4c9b6SSteve Lawrence 	uint64_t hrtime;
3565efd4c9b6SSteve Lawrence 	timestruc_t delta;
3566efd4c9b6SSteve Lawrence 
3567efd4c9b6SSteve Lawrence 	/* Update the per-cpu kstat data */
3568efd4c9b6SSteve Lawrence 	cpu_next = list_head(&ctl->zsctl_cpus);
3569efd4c9b6SSteve Lawrence 	while (cpu_next != NULL) {
3570efd4c9b6SSteve Lawrence 		cpu = cpu_next;
3571efd4c9b6SSteve Lawrence 		cpu_next = list_next(&ctl->zsctl_cpus, cpu);
3572efd4c9b6SSteve Lawrence 		zsd_update_cpu_stats(ctl, cpu);
3573efd4c9b6SSteve Lawrence 	}
3574efd4c9b6SSteve Lawrence 	/* Update the elapsed real time */
3575efd4c9b6SSteve Lawrence 	hrtime = gethrtime();
3576efd4c9b6SSteve Lawrence 	if (init) {
3577efd4c9b6SSteve Lawrence 		/* first time around, store hrtime for future comparision */
3578efd4c9b6SSteve Lawrence 		ctl->zsctl_hrtime = hrtime;
3579efd4c9b6SSteve Lawrence 		ctl->zsctl_hrtime_prev = hrtime;
3580efd4c9b6SSteve Lawrence 
3581efd4c9b6SSteve Lawrence 	} else {
3582efd4c9b6SSteve Lawrence 		/* Compute increase in hrtime since the most recent read */
3583efd4c9b6SSteve Lawrence 		ctl->zsctl_hrtime_prev = ctl->zsctl_hrtime;
3584efd4c9b6SSteve Lawrence 		ctl->zsctl_hrtime = hrtime;
3585efd4c9b6SSteve Lawrence 		if ((hrtime = hrtime - ctl->zsctl_hrtime_prev) > 0)
3586efd4c9b6SSteve Lawrence 			TIMESTRUC_ADD_NANOSEC(ctl->zsctl_hrtime_total, hrtime);
3587efd4c9b6SSteve Lawrence 	}
3588efd4c9b6SSteve Lawrence 
3589efd4c9b6SSteve Lawrence 	/* On initialization, all psets have zero time  */
3590efd4c9b6SSteve Lawrence 	if (init)
3591efd4c9b6SSteve Lawrence 		return;
3592efd4c9b6SSteve Lawrence 
3593efd4c9b6SSteve Lawrence 	for (pset = list_head(&ctl->zsctl_psets); pset != NULL;
3594efd4c9b6SSteve Lawrence 	    pset = list_next(&ctl->zsctl_psets, pset)) {
3595efd4c9b6SSteve Lawrence 
3596efd4c9b6SSteve Lawrence 		if (pset->zsp_active == B_FALSE) {
3597efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Internal error,inactive pset found"));
3598efd4c9b6SSteve Lawrence 			continue;
3599efd4c9b6SSteve Lawrence 		}
3600efd4c9b6SSteve Lawrence 
3601efd4c9b6SSteve Lawrence 		/* sum total used time for pset */
3602efd4c9b6SSteve Lawrence 		ts.tv_sec = 0;
3603efd4c9b6SSteve Lawrence 		ts.tv_nsec = 0;
3604efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_TIMESTRUC(ts, pset->zsp_intr);
3605efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_TIMESTRUC(ts, pset->zsp_kern);
3606efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_TIMESTRUC(ts, pset->zsp_user);
3607efd4c9b6SSteve Lawrence 		/* kernel time in pset is total time minus zone time */
3608efd4c9b6SSteve Lawrence 		TIMESTRUC_DELTA(pset->zsp_usage_kern, ts,
3609efd4c9b6SSteve Lawrence 		    pset->zsp_usage_zones);
3610efd4c9b6SSteve Lawrence 		if (pset->zsp_usage_kern.tv_sec < 0 ||
3611efd4c9b6SSteve Lawrence 		    pset->zsp_usage_kern.tv_nsec < 0) {
3612efd4c9b6SSteve Lawrence 			pset->zsp_usage_kern.tv_sec = 0;
3613efd4c9b6SSteve Lawrence 			pset->zsp_usage_kern.tv_nsec = 0;
3614efd4c9b6SSteve Lawrence 		}
3615efd4c9b6SSteve Lawrence 		/* Total pset elapsed time is used time plus idle time */
3616efd4c9b6SSteve Lawrence 		TIMESTRUC_ADD_TIMESTRUC(ts, pset->zsp_idle);
3617efd4c9b6SSteve Lawrence 
3618efd4c9b6SSteve Lawrence 		TIMESTRUC_DELTA(delta, ts, pset->zsp_total_time);
3619efd4c9b6SSteve Lawrence 
3620efd4c9b6SSteve Lawrence 		for (usage = list_head(&pset->zsp_usage_list); usage != NULL;
3621efd4c9b6SSteve Lawrence 		    usage = list_next(&pset->zsp_usage_list, usage)) {
3622efd4c9b6SSteve Lawrence 
3623efd4c9b6SSteve Lawrence 			zone = usage->zsu_zone;
3624efd4c9b6SSteve Lawrence 			if (usage->zsu_cpu_shares != ZS_LIMIT_NONE &&
3625efd4c9b6SSteve Lawrence 			    usage->zsu_cpu_shares != ZS_SHARES_UNLIMITED &&
3626efd4c9b6SSteve Lawrence 			    usage->zsu_cpu_shares != 0) {
3627efd4c9b6SSteve Lawrence 				/*
3628efd4c9b6SSteve Lawrence 				 * Figure out how many nanoseconds of share time
3629efd4c9b6SSteve Lawrence 				 * to give to the zone
3630efd4c9b6SSteve Lawrence 				 */
3631efd4c9b6SSteve Lawrence 				hrtime = delta.tv_sec;
3632efd4c9b6SSteve Lawrence 				hrtime *= NANOSEC;
3633efd4c9b6SSteve Lawrence 				hrtime += delta.tv_nsec;
3634efd4c9b6SSteve Lawrence 				hrtime *= usage->zsu_cpu_shares;
3635efd4c9b6SSteve Lawrence 				hrtime /= pset->zsp_cpu_shares;
3636efd4c9b6SSteve Lawrence 				TIMESTRUC_ADD_NANOSEC(zone->zsz_share_time,
3637efd4c9b6SSteve Lawrence 				    hrtime);
3638efd4c9b6SSteve Lawrence 			}
3639efd4c9b6SSteve Lawrence 			/* Add pset time to each zone using pset */
3640efd4c9b6SSteve Lawrence 			TIMESTRUC_ADD_TIMESTRUC(zone->zsz_pset_time, delta);
3641efd4c9b6SSteve Lawrence 
3642efd4c9b6SSteve Lawrence 			zone->zsz_cpus_online += pset->zsp_online;
3643efd4c9b6SSteve Lawrence 		}
3644efd4c9b6SSteve Lawrence 		pset->zsp_total_time = ts;
3645efd4c9b6SSteve Lawrence 	}
3646efd4c9b6SSteve Lawrence 
3647efd4c9b6SSteve Lawrence 	for (zone = list_head(&ctl->zsctl_zones); zone != NULL;
3648efd4c9b6SSteve Lawrence 	    zone = list_next(&ctl->zsctl_zones, zone)) {
3649efd4c9b6SSteve Lawrence 
3650efd4c9b6SSteve Lawrence 		/* update cpu cap tracking if the zone has a cpu cap */
3651efd4c9b6SSteve Lawrence 		if (zone->zsz_cpu_cap != ZS_LIMIT_NONE) {
3652efd4c9b6SSteve Lawrence 			uint64_t elapsed;
3653efd4c9b6SSteve Lawrence 
3654efd4c9b6SSteve Lawrence 			elapsed = ctl->zsctl_hrtime - ctl->zsctl_hrtime_prev;
3655efd4c9b6SSteve Lawrence 			elapsed *= zone->zsz_cpu_cap;
3656efd4c9b6SSteve Lawrence 			elapsed = elapsed / 100;
3657efd4c9b6SSteve Lawrence 			TIMESTRUC_ADD_NANOSEC(zone->zsz_cap_time, elapsed);
3658efd4c9b6SSteve Lawrence 		}
3659efd4c9b6SSteve Lawrence 	}
3660efd4c9b6SSteve Lawrence 	sys = ctl->zsctl_system;
3661efd4c9b6SSteve Lawrence 	ts.tv_sec = 0;
3662efd4c9b6SSteve Lawrence 	ts.tv_nsec = 0;
3663efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(ts, sys->zss_intr);
3664efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(ts, sys->zss_kern);
3665efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(ts, sys->zss_user);
3666efd4c9b6SSteve Lawrence 
3667efd4c9b6SSteve Lawrence 	/* kernel time in pset is total time minus zone time */
3668efd4c9b6SSteve Lawrence 	TIMESTRUC_DELTA(sys->zss_cpu_usage_kern, ts,
3669efd4c9b6SSteve Lawrence 	    sys->zss_cpu_usage_zones);
3670efd4c9b6SSteve Lawrence 	if (sys->zss_cpu_usage_kern.tv_sec < 0 ||
3671efd4c9b6SSteve Lawrence 	    sys->zss_cpu_usage_kern.tv_nsec < 0) {
3672efd4c9b6SSteve Lawrence 		sys->zss_cpu_usage_kern.tv_sec = 0;
3673efd4c9b6SSteve Lawrence 		sys->zss_cpu_usage_kern.tv_nsec = 0;
3674efd4c9b6SSteve Lawrence 	}
3675efd4c9b6SSteve Lawrence 	/* Total pset elapsed time is used time plus idle time */
3676efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(ts, sys->zss_idle);
3677efd4c9b6SSteve Lawrence 	sys->zss_cpu_total_time = ts;
3678efd4c9b6SSteve Lawrence }
3679efd4c9b6SSteve Lawrence 
3680efd4c9b6SSteve Lawrence /*
3681efd4c9b6SSteve Lawrence  * Saves current usage data to a cache that is read by libzonestat when
3682efd4c9b6SSteve Lawrence  * calling zs_usage_read().
3683efd4c9b6SSteve Lawrence  *
3684efd4c9b6SSteve Lawrence  * All pointers in the cached data structure are set to NULL.  When
3685efd4c9b6SSteve Lawrence  * libzonestat reads the cached data, it will set the pointers relative to
3686efd4c9b6SSteve Lawrence  * its address space.
3687efd4c9b6SSteve Lawrence  */
3688efd4c9b6SSteve Lawrence static void
zsd_usage_cache_update(zsd_ctl_t * ctl)3689efd4c9b6SSteve Lawrence zsd_usage_cache_update(zsd_ctl_t *ctl)
3690efd4c9b6SSteve Lawrence {
3691efd4c9b6SSteve Lawrence 	zs_usage_cache_t *cache;
3692efd4c9b6SSteve Lawrence 	zs_usage_cache_t *old;
3693efd4c9b6SSteve Lawrence 	zs_usage_t *usage;
3694efd4c9b6SSteve Lawrence 
3695efd4c9b6SSteve Lawrence 	zs_system_t *sys;
3696efd4c9b6SSteve Lawrence 	zsd_system_t *dsys;
3697efd4c9b6SSteve Lawrence 	zs_zone_t *zone = NULL;
3698efd4c9b6SSteve Lawrence 	zsd_zone_t *dzone;
3699efd4c9b6SSteve Lawrence 	zs_pset_t *pset = NULL;
3700efd4c9b6SSteve Lawrence 	zsd_pset_t *dpset;
3701efd4c9b6SSteve Lawrence 	zs_pset_zone_t *pusage;
3702efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *dpusage;
3703efd4c9b6SSteve Lawrence 
3704efd4c9b6SSteve Lawrence 	char *next;
3705efd4c9b6SSteve Lawrence 	uint_t size, i, j;
3706efd4c9b6SSteve Lawrence 
3707efd4c9b6SSteve Lawrence 	size =
3708efd4c9b6SSteve Lawrence 	    sizeof (zs_usage_cache_t) +
3709efd4c9b6SSteve Lawrence 	    sizeof (zs_usage_t) +
3710efd4c9b6SSteve Lawrence 	    sizeof (zs_system_t) +
3711efd4c9b6SSteve Lawrence 	    sizeof (zs_zone_t) * ctl->zsctl_nzones +
3712efd4c9b6SSteve Lawrence 	    sizeof (zs_pset_t) *  ctl->zsctl_npsets +
3713efd4c9b6SSteve Lawrence 	    sizeof (zs_pset_zone_t) * ctl->zsctl_npset_usages;
3714efd4c9b6SSteve Lawrence 
3715efd4c9b6SSteve Lawrence 	cache = (zs_usage_cache_t *)malloc(size);
3716efd4c9b6SSteve Lawrence 	if (cache == NULL) {
3717efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to allocate usage cache\n"));
3718efd4c9b6SSteve Lawrence 		return;
3719efd4c9b6SSteve Lawrence 	}
3720efd4c9b6SSteve Lawrence 
3721efd4c9b6SSteve Lawrence 	next = (char *)cache;
3722efd4c9b6SSteve Lawrence 	cache->zsuc_size = size - sizeof (zs_usage_cache_t);
3723efd4c9b6SSteve Lawrence 	next += sizeof (zs_usage_cache_t);
3724efd4c9b6SSteve Lawrence 
3725efd4c9b6SSteve Lawrence 	/* LINTED */
3726efd4c9b6SSteve Lawrence 	usage = cache->zsuc_usage = (zs_usage_t *)next;
3727efd4c9b6SSteve Lawrence 	next += sizeof (zs_usage_t);
3728efd4c9b6SSteve Lawrence 	usage->zsu_start = g_start;
3729efd4c9b6SSteve Lawrence 	usage->zsu_hrstart = g_hrstart;
3730efd4c9b6SSteve Lawrence 	usage->zsu_time = g_now;
3731efd4c9b6SSteve Lawrence 	usage->zsu_hrtime = g_hrnow;
3732efd4c9b6SSteve Lawrence 	usage->zsu_nzones = ctl->zsctl_nzones;
3733efd4c9b6SSteve Lawrence 	usage->zsu_npsets = ctl->zsctl_npsets;
3734efd4c9b6SSteve Lawrence 	usage->zsu_system = NULL;
3735efd4c9b6SSteve Lawrence 
3736efd4c9b6SSteve Lawrence 	/* LINTED */
3737efd4c9b6SSteve Lawrence 	sys = (zs_system_t *)next;
3738efd4c9b6SSteve Lawrence 	next += sizeof (zs_system_t);
3739efd4c9b6SSteve Lawrence 	dsys = ctl->zsctl_system;
3740efd4c9b6SSteve Lawrence 	sys->zss_ram_total = dsys->zss_ram_total;
3741efd4c9b6SSteve Lawrence 	sys->zss_ram_kern = dsys->zss_ram_kern;
3742efd4c9b6SSteve Lawrence 	sys->zss_ram_zones = dsys->zss_ram_zones;
3743efd4c9b6SSteve Lawrence 	sys->zss_locked_kern = dsys->zss_locked_kern;
3744efd4c9b6SSteve Lawrence 	sys->zss_locked_zones = dsys->zss_locked_zones;
3745efd4c9b6SSteve Lawrence 	sys->zss_vm_total = dsys->zss_vm_total;
3746efd4c9b6SSteve Lawrence 	sys->zss_vm_kern = dsys->zss_vm_kern;
3747efd4c9b6SSteve Lawrence 	sys->zss_vm_zones = dsys->zss_vm_zones;
3748efd4c9b6SSteve Lawrence 	sys->zss_swap_total = dsys->zss_swap_total;
3749efd4c9b6SSteve Lawrence 	sys->zss_swap_used = dsys->zss_swap_used;
3750efd4c9b6SSteve Lawrence 	sys->zss_ncpus = dsys->zss_ncpus;
3751efd4c9b6SSteve Lawrence 	sys->zss_ncpus_online = dsys->zss_ncpus_online;
3752efd4c9b6SSteve Lawrence 
3753efd4c9b6SSteve Lawrence 	sys->zss_processes_max = dsys->zss_maxpid;
3754efd4c9b6SSteve Lawrence 	sys->zss_lwps_max = dsys->zss_lwps_max;
3755efd4c9b6SSteve Lawrence 	sys->zss_shm_max = dsys->zss_shm_max;
3756efd4c9b6SSteve Lawrence 	sys->zss_shmids_max = dsys->zss_shmids_max;
3757efd4c9b6SSteve Lawrence 	sys->zss_semids_max = dsys->zss_semids_max;
3758efd4c9b6SSteve Lawrence 	sys->zss_msgids_max = dsys->zss_msgids_max;
3759efd4c9b6SSteve Lawrence 	sys->zss_lofi_max = dsys->zss_lofi_max;
3760efd4c9b6SSteve Lawrence 
3761efd4c9b6SSteve Lawrence 	sys->zss_processes = dsys->zss_processes;
3762efd4c9b6SSteve Lawrence 	sys->zss_lwps = dsys->zss_lwps;
3763efd4c9b6SSteve Lawrence 	sys->zss_shm = dsys->zss_shm;
3764efd4c9b6SSteve Lawrence 	sys->zss_shmids = dsys->zss_shmids;
3765efd4c9b6SSteve Lawrence 	sys->zss_semids = dsys->zss_semids;
3766efd4c9b6SSteve Lawrence 	sys->zss_msgids = dsys->zss_msgids;
3767efd4c9b6SSteve Lawrence 	sys->zss_lofi = dsys->zss_lofi;
3768efd4c9b6SSteve Lawrence 
3769efd4c9b6SSteve Lawrence 	sys->zss_cpu_total_time = dsys->zss_cpu_total_time;
3770efd4c9b6SSteve Lawrence 	sys->zss_cpu_usage_zones = dsys->zss_cpu_usage_zones;
3771efd4c9b6SSteve Lawrence 	sys->zss_cpu_usage_kern = dsys->zss_cpu_usage_kern;
3772efd4c9b6SSteve Lawrence 
3773efd4c9b6SSteve Lawrence 	for (i = 0, dzone = list_head(&ctl->zsctl_zones);
3774efd4c9b6SSteve Lawrence 	    i < ctl->zsctl_nzones;
3775efd4c9b6SSteve Lawrence 	    i++, dzone = list_next(&ctl->zsctl_zones, dzone)) {
3776efd4c9b6SSteve Lawrence 		/* LINTED */
3777efd4c9b6SSteve Lawrence 		zone = (zs_zone_t *)next;
3778efd4c9b6SSteve Lawrence 		next += sizeof (zs_zone_t);
3779efd4c9b6SSteve Lawrence 		list_link_init(&zone->zsz_next);
3780efd4c9b6SSteve Lawrence 		zone->zsz_system = NULL;
3781efd4c9b6SSteve Lawrence 
3782efd4c9b6SSteve Lawrence 		(void) strlcpy(zone->zsz_name, dzone->zsz_name,
3783efd4c9b6SSteve Lawrence 		    sizeof (zone->zsz_name));
3784efd4c9b6SSteve Lawrence 		(void) strlcpy(zone->zsz_pool, dzone->zsz_pool,
3785efd4c9b6SSteve Lawrence 		    sizeof (zone->zsz_pool));
3786efd4c9b6SSteve Lawrence 		(void) strlcpy(zone->zsz_pset, dzone->zsz_pset,
3787efd4c9b6SSteve Lawrence 		    sizeof (zone->zsz_pset));
3788efd4c9b6SSteve Lawrence 		zone->zsz_id = dzone->zsz_id;
3789efd4c9b6SSteve Lawrence 		zone->zsz_cputype = dzone->zsz_cputype;
3790efd4c9b6SSteve Lawrence 		zone->zsz_iptype = dzone->zsz_iptype;
3791efd4c9b6SSteve Lawrence 		zone->zsz_start = dzone->zsz_start;
3792efd4c9b6SSteve Lawrence 		zone->zsz_hrstart = dzone->zsz_hrstart;
3793efd4c9b6SSteve Lawrence 		zone->zsz_scheds = dzone->zsz_scheds;
3794efd4c9b6SSteve Lawrence 		zone->zsz_cpu_shares = dzone->zsz_cpu_shares;
3795efd4c9b6SSteve Lawrence 		zone->zsz_cpu_cap = dzone->zsz_cpu_cap;
3796efd4c9b6SSteve Lawrence 		zone->zsz_ram_cap = dzone->zsz_ram_cap;
3797efd4c9b6SSteve Lawrence 		zone->zsz_vm_cap = dzone->zsz_vm_cap;
3798efd4c9b6SSteve Lawrence 		zone->zsz_locked_cap = dzone->zsz_locked_cap;
3799efd4c9b6SSteve Lawrence 		zone->zsz_cpu_usage = dzone->zsz_cpu_usage;
3800efd4c9b6SSteve Lawrence 		zone->zsz_cpus_online = dzone->zsz_cpus_online;
3801efd4c9b6SSteve Lawrence 		zone->zsz_pset_time = dzone->zsz_pset_time;
3802efd4c9b6SSteve Lawrence 		zone->zsz_cap_time = dzone->zsz_cap_time;
3803efd4c9b6SSteve Lawrence 		zone->zsz_share_time = dzone->zsz_share_time;
3804efd4c9b6SSteve Lawrence 		zone->zsz_usage_ram = dzone->zsz_usage_ram;
3805efd4c9b6SSteve Lawrence 		zone->zsz_usage_locked = dzone->zsz_usage_locked;
3806efd4c9b6SSteve Lawrence 		zone->zsz_usage_vm = dzone->zsz_usage_vm;
3807efd4c9b6SSteve Lawrence 
3808efd4c9b6SSteve Lawrence 		zone->zsz_processes_cap = dzone->zsz_processes_cap;
3809efd4c9b6SSteve Lawrence 		zone->zsz_lwps_cap = dzone->zsz_lwps_cap;
3810efd4c9b6SSteve Lawrence 		zone->zsz_shm_cap = dzone->zsz_shm_cap;
3811efd4c9b6SSteve Lawrence 		zone->zsz_shmids_cap = dzone->zsz_shmids_cap;
3812efd4c9b6SSteve Lawrence 		zone->zsz_semids_cap = dzone->zsz_semids_cap;
3813efd4c9b6SSteve Lawrence 		zone->zsz_msgids_cap = dzone->zsz_msgids_cap;
3814efd4c9b6SSteve Lawrence 		zone->zsz_lofi_cap = dzone->zsz_lofi_cap;
3815efd4c9b6SSteve Lawrence 
3816efd4c9b6SSteve Lawrence 		zone->zsz_processes = dzone->zsz_processes;
3817efd4c9b6SSteve Lawrence 		zone->zsz_lwps = dzone->zsz_lwps;
3818efd4c9b6SSteve Lawrence 		zone->zsz_shm = dzone->zsz_shm;
3819efd4c9b6SSteve Lawrence 		zone->zsz_shmids = dzone->zsz_shmids;
3820efd4c9b6SSteve Lawrence 		zone->zsz_semids = dzone->zsz_semids;
3821efd4c9b6SSteve Lawrence 		zone->zsz_msgids = dzone->zsz_msgids;
3822efd4c9b6SSteve Lawrence 		zone->zsz_lofi = dzone->zsz_lofi;
3823efd4c9b6SSteve Lawrence 	}
3824efd4c9b6SSteve Lawrence 
3825efd4c9b6SSteve Lawrence 	for (i = 0, dpset = list_head(&ctl->zsctl_psets);
3826efd4c9b6SSteve Lawrence 	    i < ctl->zsctl_npsets;
3827efd4c9b6SSteve Lawrence 	    i++, dpset = list_next(&ctl->zsctl_psets, dpset)) {
3828efd4c9b6SSteve Lawrence 		/* LINTED */
3829efd4c9b6SSteve Lawrence 		pset = (zs_pset_t *)next;
3830efd4c9b6SSteve Lawrence 		next += sizeof (zs_pset_t);
3831efd4c9b6SSteve Lawrence 		list_link_init(&pset->zsp_next);
3832efd4c9b6SSteve Lawrence 		(void) strlcpy(pset->zsp_name, dpset->zsp_name,
3833efd4c9b6SSteve Lawrence 		    sizeof (pset->zsp_name));
3834efd4c9b6SSteve Lawrence 		pset->zsp_id = dpset->zsp_id;
3835efd4c9b6SSteve Lawrence 		pset->zsp_cputype = dpset->zsp_cputype;
3836efd4c9b6SSteve Lawrence 		pset->zsp_start = dpset->zsp_start;
3837efd4c9b6SSteve Lawrence 		pset->zsp_hrstart = dpset->zsp_hrstart;
3838efd4c9b6SSteve Lawrence 		pset->zsp_online = dpset->zsp_online;
3839efd4c9b6SSteve Lawrence 		pset->zsp_size = dpset->zsp_size;
3840efd4c9b6SSteve Lawrence 		pset->zsp_min = dpset->zsp_min;
3841efd4c9b6SSteve Lawrence 		pset->zsp_max = dpset->zsp_max;
3842efd4c9b6SSteve Lawrence 		pset->zsp_importance = dpset->zsp_importance;
3843efd4c9b6SSteve Lawrence 		pset->zsp_scheds = dpset->zsp_scheds;
3844efd4c9b6SSteve Lawrence 		pset->zsp_cpu_shares = dpset->zsp_cpu_shares;
3845efd4c9b6SSteve Lawrence 		pset->zsp_total_time = dpset->zsp_total_time;
3846efd4c9b6SSteve Lawrence 		pset->zsp_usage_kern = dpset->zsp_usage_kern;
3847efd4c9b6SSteve Lawrence 		pset->zsp_usage_zones = dpset->zsp_usage_zones;
3848efd4c9b6SSteve Lawrence 		pset->zsp_nusage = dpset->zsp_nusage;
3849efd4c9b6SSteve Lawrence 		/* Add pset usages for pset */
3850efd4c9b6SSteve Lawrence 		for (j = 0, dpusage = list_head(&dpset->zsp_usage_list);
3851efd4c9b6SSteve Lawrence 		    j < dpset->zsp_nusage;
3852efd4c9b6SSteve Lawrence 		    j++, dpusage = list_next(&dpset->zsp_usage_list, dpusage)) {
3853efd4c9b6SSteve Lawrence 			/* LINTED */
3854efd4c9b6SSteve Lawrence 			pusage = (zs_pset_zone_t *)next;
3855efd4c9b6SSteve Lawrence 			next += sizeof (zs_pset_zone_t);
3856efd4c9b6SSteve Lawrence 			/* pointers are computed by client */
3857efd4c9b6SSteve Lawrence 			pusage->zspz_pset = NULL;
3858efd4c9b6SSteve Lawrence 			pusage->zspz_zone = NULL;
3859efd4c9b6SSteve Lawrence 			list_link_init(&pusage->zspz_next);
3860efd4c9b6SSteve Lawrence 			pusage->zspz_zoneid = dpusage->zsu_zone->zsz_id;
3861efd4c9b6SSteve Lawrence 			pusage->zspz_start = dpusage->zsu_start;
3862efd4c9b6SSteve Lawrence 			pusage->zspz_hrstart = dpusage->zsu_hrstart;
3863efd4c9b6SSteve Lawrence 			pusage->zspz_hrstart = dpusage->zsu_hrstart;
3864efd4c9b6SSteve Lawrence 			pusage->zspz_cpu_shares = dpusage->zsu_cpu_shares;
3865efd4c9b6SSteve Lawrence 			pusage->zspz_scheds = dpusage->zsu_scheds;
3866efd4c9b6SSteve Lawrence 			pusage->zspz_cpu_usage = dpusage->zsu_cpu_usage;
3867efd4c9b6SSteve Lawrence 		}
3868efd4c9b6SSteve Lawrence 	}
3869efd4c9b6SSteve Lawrence 
3870efd4c9b6SSteve Lawrence 	/* Update the current cache pointer */
3871efd4c9b6SSteve Lawrence 	(void) mutex_lock(&g_usage_cache_lock);
38728c4f1486SMarcel Telka 	old = g_usage_cache;
38738c4f1486SMarcel Telka 	cache->zsuc_ref = 1;
38748c4f1486SMarcel Telka 	cache->zsuc_gen = g_gen_next;
38758c4f1486SMarcel Telka 	usage->zsu_gen = g_gen_next;
38768c4f1486SMarcel Telka 	usage->zsu_size = size;
38778c4f1486SMarcel Telka 	g_usage_cache = cache;
38788c4f1486SMarcel Telka 	if (old != NULL) {
38798c4f1486SMarcel Telka 		old->zsuc_ref--;
38808c4f1486SMarcel Telka 		if (old->zsuc_ref == 0)
38818c4f1486SMarcel Telka 			free(old);
38828c4f1486SMarcel Telka 	}
38838c4f1486SMarcel Telka 	g_gen_next++;
3884efd4c9b6SSteve Lawrence 	/* Wake up any clients that are waiting for this calculation */
3885efd4c9b6SSteve Lawrence 	if (g_usage_cache_kickers > 0) {
3886efd4c9b6SSteve Lawrence 		(void) cond_broadcast(&g_usage_cache_wait);
3887efd4c9b6SSteve Lawrence 	}
3888efd4c9b6SSteve Lawrence 	(void) mutex_unlock(&g_usage_cache_lock);
3889efd4c9b6SSteve Lawrence }
3890efd4c9b6SSteve Lawrence 
3891efd4c9b6SSteve Lawrence static zs_usage_cache_t *
zsd_usage_cache_hold_locked()3892efd4c9b6SSteve Lawrence zsd_usage_cache_hold_locked()
3893efd4c9b6SSteve Lawrence {
3894efd4c9b6SSteve Lawrence 	zs_usage_cache_t *ret;
3895efd4c9b6SSteve Lawrence 
3896efd4c9b6SSteve Lawrence 	ret = g_usage_cache;
3897efd4c9b6SSteve Lawrence 	ret->zsuc_ref++;
3898efd4c9b6SSteve Lawrence 	return (ret);
3899efd4c9b6SSteve Lawrence }
3900efd4c9b6SSteve Lawrence 
3901efd4c9b6SSteve Lawrence void
zsd_usage_cache_rele(zs_usage_cache_t * cache)3902efd4c9b6SSteve Lawrence zsd_usage_cache_rele(zs_usage_cache_t *cache)
3903efd4c9b6SSteve Lawrence {
3904efd4c9b6SSteve Lawrence 	(void) mutex_lock(&g_usage_cache_lock);
3905efd4c9b6SSteve Lawrence 	cache->zsuc_ref--;
3906efd4c9b6SSteve Lawrence 	if (cache->zsuc_ref == 0)
3907efd4c9b6SSteve Lawrence 		free(cache);
3908efd4c9b6SSteve Lawrence 	(void) mutex_unlock(&g_usage_cache_lock);
3909efd4c9b6SSteve Lawrence }
3910efd4c9b6SSteve Lawrence 
3911efd4c9b6SSteve Lawrence /* Close the handles held by zsd_open() */
3912efd4c9b6SSteve Lawrence void
zsd_close(zsd_ctl_t * ctl)3913efd4c9b6SSteve Lawrence zsd_close(zsd_ctl_t *ctl)
3914efd4c9b6SSteve Lawrence {
3915efd4c9b6SSteve Lawrence 	zsd_zone_t *zone;
3916efd4c9b6SSteve Lawrence 	zsd_pset_t *pset;
3917efd4c9b6SSteve Lawrence 	zsd_pset_usage_t *usage;
3918efd4c9b6SSteve Lawrence 	zsd_cpu_t *cpu;
3919efd4c9b6SSteve Lawrence 	int id;
3920efd4c9b6SSteve Lawrence 
3921efd4c9b6SSteve Lawrence 	if (ctl->zsctl_kstat_ctl) {
3922efd4c9b6SSteve Lawrence 		(void) kstat_close(ctl->zsctl_kstat_ctl);
3923efd4c9b6SSteve Lawrence 		ctl->zsctl_kstat_ctl = NULL;
3924efd4c9b6SSteve Lawrence 	}
3925efd4c9b6SSteve Lawrence 	if (ctl->zsctl_proc_open) {
3926efd4c9b6SSteve Lawrence 		(void) ea_close(&ctl->zsctl_proc_eaf);
3927efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_open = 0;
3928efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_fd = -1;
3929efd4c9b6SSteve Lawrence 	}
3930efd4c9b6SSteve Lawrence 	if (ctl->zsctl_pool_conf) {
3931efd4c9b6SSteve Lawrence 		if (ctl->zsctl_pool_status == POOL_ENABLED)
3932efd4c9b6SSteve Lawrence 			(void) pool_conf_close(ctl->zsctl_pool_conf);
3933efd4c9b6SSteve Lawrence 		ctl->zsctl_pool_status = POOL_DISABLED;
3934efd4c9b6SSteve Lawrence 	}
3935efd4c9b6SSteve Lawrence 
3936efd4c9b6SSteve Lawrence 	while ((zone = list_head(&ctl->zsctl_zones)) != NULL) {
3937efd4c9b6SSteve Lawrence 		list_remove(&ctl->zsctl_zones, zone);
3938efd4c9b6SSteve Lawrence 		free(zone);
3939efd4c9b6SSteve Lawrence 		ctl->zsctl_nzones--;
3940efd4c9b6SSteve Lawrence 	}
3941efd4c9b6SSteve Lawrence 
3942efd4c9b6SSteve Lawrence 	while ((pset = list_head(&ctl->zsctl_psets)) != NULL) {
3943efd4c9b6SSteve Lawrence 		while ((usage = list_head(&pset->zsp_usage_list))
3944efd4c9b6SSteve Lawrence 		    != NULL) {
3945efd4c9b6SSteve Lawrence 			list_remove(&pset->zsp_usage_list, usage);
3946efd4c9b6SSteve Lawrence 			ctl->zsctl_npset_usages--;
3947efd4c9b6SSteve Lawrence 			free(usage);
3948efd4c9b6SSteve Lawrence 		}
3949efd4c9b6SSteve Lawrence 		list_remove(&ctl->zsctl_psets, pset);
3950efd4c9b6SSteve Lawrence 		free(pset);
3951efd4c9b6SSteve Lawrence 		ctl->zsctl_npsets--;
3952efd4c9b6SSteve Lawrence 	}
3953efd4c9b6SSteve Lawrence 
3954efd4c9b6SSteve Lawrence 	/* Release all cpus being tracked */
3955efd4c9b6SSteve Lawrence 	while (cpu = list_head(&ctl->zsctl_cpus)) {
3956efd4c9b6SSteve Lawrence 		list_remove(&ctl->zsctl_cpus, cpu);
3957efd4c9b6SSteve Lawrence 		id = cpu->zsc_id;
3958efd4c9b6SSteve Lawrence 		bzero(cpu, sizeof (zsd_cpu_t));
3959efd4c9b6SSteve Lawrence 		cpu->zsc_id = id;
3960efd4c9b6SSteve Lawrence 		cpu->zsc_allocated = B_FALSE;
3961efd4c9b6SSteve Lawrence 		cpu->zsc_psetid = ZS_PSET_ERROR;
3962efd4c9b6SSteve Lawrence 		cpu->zsc_psetid_prev = ZS_PSET_ERROR;
3963efd4c9b6SSteve Lawrence 	}
3964efd4c9b6SSteve Lawrence 
3965efd4c9b6SSteve Lawrence 	assert(ctl->zsctl_npset_usages == 0);
3966efd4c9b6SSteve Lawrence 	assert(ctl->zsctl_npsets == 0);
3967efd4c9b6SSteve Lawrence 	assert(ctl->zsctl_nzones == 0);
3968efd4c9b6SSteve Lawrence 	(void) zsd_disable_cpu_stats();
3969efd4c9b6SSteve Lawrence }
3970efd4c9b6SSteve Lawrence 
3971efd4c9b6SSteve Lawrence 
3972efd4c9b6SSteve Lawrence /*
3973efd4c9b6SSteve Lawrence  * Update the utilization data for all zones and processor sets.
3974efd4c9b6SSteve Lawrence  */
3975efd4c9b6SSteve Lawrence static int
zsd_read(zsd_ctl_t * ctl,boolean_t init,boolean_t do_memory)3976efd4c9b6SSteve Lawrence zsd_read(zsd_ctl_t *ctl, boolean_t init, boolean_t do_memory)
3977efd4c9b6SSteve Lawrence {
3978efd4c9b6SSteve Lawrence 	(void) kstat_chain_update(ctl->zsctl_kstat_ctl);
3979efd4c9b6SSteve Lawrence 	(void) gettimeofday(&(ctl->zsctl_timeofday), NULL);
3980efd4c9b6SSteve Lawrence 
3981efd4c9b6SSteve Lawrence 	zsd_refresh_system(ctl);
3982efd4c9b6SSteve Lawrence 
3983efd4c9b6SSteve Lawrence 	/*
3984efd4c9b6SSteve Lawrence 	 * Memory calculation is expensive.  Only update it on sample
3985efd4c9b6SSteve Lawrence 	 * intervals.
3986efd4c9b6SSteve Lawrence 	 */
3987efd4c9b6SSteve Lawrence 	if (do_memory == B_TRUE)
3988efd4c9b6SSteve Lawrence 		zsd_refresh_memory(ctl, init);
3989efd4c9b6SSteve Lawrence 	zsd_refresh_zones(ctl);
3990efd4c9b6SSteve Lawrence 	zsd_refresh_psets(ctl);
3991efd4c9b6SSteve Lawrence 	zsd_refresh_procs(ctl, init);
3992efd4c9b6SSteve Lawrence 	zsd_refresh_cpu_stats(ctl, init);
3993efd4c9b6SSteve Lawrence 
3994efd4c9b6SSteve Lawrence 	/*
3995efd4c9b6SSteve Lawrence 	 * Delete objects that no longer exist.
3996efd4c9b6SSteve Lawrence 	 * Pset usages must be deleted first as they point to zone and
3997efd4c9b6SSteve Lawrence 	 * pset objects.
3998efd4c9b6SSteve Lawrence 	 */
3999efd4c9b6SSteve Lawrence 	zsd_mark_pset_usages_end(ctl);
4000efd4c9b6SSteve Lawrence 	zsd_mark_psets_end(ctl);
4001efd4c9b6SSteve Lawrence 	zsd_mark_cpus_end(ctl);
4002efd4c9b6SSteve Lawrence 	zsd_mark_zones_end(ctl);
4003efd4c9b6SSteve Lawrence 
4004efd4c9b6SSteve Lawrence 	/*
4005efd4c9b6SSteve Lawrence 	 * Save results for clients.
4006efd4c9b6SSteve Lawrence 	 */
4007efd4c9b6SSteve Lawrence 	zsd_usage_cache_update(ctl);
4008efd4c9b6SSteve Lawrence 
4009efd4c9b6SSteve Lawrence 	/*
4010efd4c9b6SSteve Lawrence 	 * Roll process accounting file.
4011efd4c9b6SSteve Lawrence 	 */
4012efd4c9b6SSteve Lawrence 	(void) zsd_roll_exacct();
4013efd4c9b6SSteve Lawrence 	return (0);
4014efd4c9b6SSteve Lawrence }
4015efd4c9b6SSteve Lawrence 
4016efd4c9b6SSteve Lawrence /*
4017efd4c9b6SSteve Lawrence  * Get the system rctl, which is the upper most limit
4018efd4c9b6SSteve Lawrence  */
4019efd4c9b6SSteve Lawrence static uint64_t
zsd_get_system_rctl(char * name)4020efd4c9b6SSteve Lawrence zsd_get_system_rctl(char *name)
4021efd4c9b6SSteve Lawrence {
4022efd4c9b6SSteve Lawrence 	rctlblk_t *rblk, *rblk_last;
4023efd4c9b6SSteve Lawrence 
4024efd4c9b6SSteve Lawrence 	rblk = (rctlblk_t *)alloca(rctlblk_size());
4025efd4c9b6SSteve Lawrence 	rblk_last = (rctlblk_t *)alloca(rctlblk_size());
4026efd4c9b6SSteve Lawrence 
4027efd4c9b6SSteve Lawrence 	if (getrctl(name, NULL, rblk_last, RCTL_FIRST) != 0)
4028efd4c9b6SSteve Lawrence 		return (ZS_LIMIT_NONE);
4029efd4c9b6SSteve Lawrence 
4030efd4c9b6SSteve Lawrence 	while (getrctl(name, rblk_last, rblk, RCTL_NEXT) == 0)
4031efd4c9b6SSteve Lawrence 		(void) bcopy(rblk, rblk_last, rctlblk_size());
4032efd4c9b6SSteve Lawrence 
4033efd4c9b6SSteve Lawrence 	return (rctlblk_get_value(rblk_last));
4034efd4c9b6SSteve Lawrence }
4035efd4c9b6SSteve Lawrence 
4036efd4c9b6SSteve Lawrence /*
4037efd4c9b6SSteve Lawrence  * Open any necessary subsystems for collecting utilization data,
4038efd4c9b6SSteve Lawrence  * allocate and initialize data structures, and get initial utilization.
4039efd4c9b6SSteve Lawrence  *
4040efd4c9b6SSteve Lawrence  * Errors:
4041efd4c9b6SSteve Lawrence  *	ENOMEM	out of memory
4042efd4c9b6SSteve Lawrence  *	EINVAL  other error
4043efd4c9b6SSteve Lawrence  */
4044efd4c9b6SSteve Lawrence static zsd_ctl_t *
zsd_open(zsd_ctl_t * ctl)4045efd4c9b6SSteve Lawrence zsd_open(zsd_ctl_t *ctl)
4046efd4c9b6SSteve Lawrence {
4047efd4c9b6SSteve Lawrence 	zsd_system_t *system;
4048efd4c9b6SSteve Lawrence 
4049efd4c9b6SSteve Lawrence 	char path[MAXPATHLEN];
4050efd4c9b6SSteve Lawrence 	struct statvfs svfs;
4051efd4c9b6SSteve Lawrence 	int ret;
4052efd4c9b6SSteve Lawrence 	int i;
4053efd4c9b6SSteve Lawrence 	size_t size;
4054efd4c9b6SSteve Lawrence 	int err;
4055efd4c9b6SSteve Lawrence 
4056efd4c9b6SSteve Lawrence 	if (ctl == NULL && (ctl = (zsd_ctl_t *)calloc(1,
4057efd4c9b6SSteve Lawrence 	    sizeof (zsd_ctl_t))) == NULL) {
4058efd4c9b6SSteve Lawrence 			zsd_warn(gettext("Out of Memory"));
4059efd4c9b6SSteve Lawrence 			errno = ENOMEM;
4060efd4c9b6SSteve Lawrence 			goto err;
4061efd4c9b6SSteve Lawrence 	}
4062efd4c9b6SSteve Lawrence 	ctl->zsctl_proc_fd = -1;
4063efd4c9b6SSteve Lawrence 
4064efd4c9b6SSteve Lawrence 	/* open kstats */
4065efd4c9b6SSteve Lawrence 	if (ctl->zsctl_kstat_ctl == NULL &&
4066efd4c9b6SSteve Lawrence 	    (ctl->zsctl_kstat_ctl = kstat_open()) == NULL) {
4067efd4c9b6SSteve Lawrence 		err = errno;
4068efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to open kstats"));
4069efd4c9b6SSteve Lawrence 		errno = err;
4070efd4c9b6SSteve Lawrence 		if (errno != ENOMEM)
4071efd4c9b6SSteve Lawrence 			errno = EAGAIN;
4072efd4c9b6SSteve Lawrence 		goto err;
4073efd4c9b6SSteve Lawrence 	}
4074efd4c9b6SSteve Lawrence 
4075efd4c9b6SSteve Lawrence 	/*
4076efd4c9b6SSteve Lawrence 	 * These are set when the accounting file is opened by
4077efd4c9b6SSteve Lawrence 	 * zsd_update_procs()
4078efd4c9b6SSteve Lawrence 	 */
4079efd4c9b6SSteve Lawrence 	ctl->zsctl_proc_fd = -1;
4080efd4c9b6SSteve Lawrence 	ctl->zsctl_proc_fd_next = -1;
4081efd4c9b6SSteve Lawrence 	ctl->zsctl_proc_open = 0;
4082efd4c9b6SSteve Lawrence 	ctl->zsctl_proc_open_next = 0;
4083efd4c9b6SSteve Lawrence 
4084efd4c9b6SSteve Lawrence check_exacct:
4085efd4c9b6SSteve Lawrence 	(void) zsd_enable_cpu_stats();
4086efd4c9b6SSteve Lawrence 
4087efd4c9b6SSteve Lawrence 	/* Create structures to track usage */
4088efd4c9b6SSteve Lawrence 	if (ctl->zsctl_system == NULL && (ctl->zsctl_system = (zsd_system_t *)
4089efd4c9b6SSteve Lawrence 	    calloc(1, sizeof (zsd_system_t))) == NULL) {
4090efd4c9b6SSteve Lawrence 		ret = -1;
4091efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Out of Memory"));
4092efd4c9b6SSteve Lawrence 		errno = ENOMEM;
4093efd4c9b6SSteve Lawrence 		goto err;
4094efd4c9b6SSteve Lawrence 	}
4095efd4c9b6SSteve Lawrence 	system = ctl->zsctl_system;
4096efd4c9b6SSteve Lawrence 	/* get the kernel bitness to know structure layout for getvmusage */
4097efd4c9b6SSteve Lawrence 	ret = sysinfo(SI_ARCHITECTURE_64, path, sizeof (path));
4098efd4c9b6SSteve Lawrence 	if (ret < 0)
4099efd4c9b6SSteve Lawrence 		ctl->zsctl_kern_bits = 32;
4100efd4c9b6SSteve Lawrence 	else
4101efd4c9b6SSteve Lawrence 		ctl->zsctl_kern_bits = 64;
4102efd4c9b6SSteve Lawrence 	ctl->zsctl_pagesize = sysconf(_SC_PAGESIZE);
4103efd4c9b6SSteve Lawrence 
4104efd4c9b6SSteve Lawrence 	size = sysconf(_SC_CPUID_MAX);
4105efd4c9b6SSteve Lawrence 	ctl->zsctl_maxcpuid = size;
4106efd4c9b6SSteve Lawrence 	if (ctl->zsctl_cpu_array == NULL && (ctl->zsctl_cpu_array =
4107efd4c9b6SSteve Lawrence 	    (zsd_cpu_t *)calloc(size + 1, sizeof (zsd_cpu_t))) == NULL) {
4108efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Out of Memory"));
4109efd4c9b6SSteve Lawrence 		errno = ENOMEM;
4110efd4c9b6SSteve Lawrence 		goto err;
4111efd4c9b6SSteve Lawrence 	}
4112efd4c9b6SSteve Lawrence 	for (i = 0; i <= ctl->zsctl_maxcpuid; i++) {
4113efd4c9b6SSteve Lawrence 		ctl->zsctl_cpu_array[i].zsc_id = i;
4114efd4c9b6SSteve Lawrence 		ctl->zsctl_cpu_array[i].zsc_allocated = B_FALSE;
4115efd4c9b6SSteve Lawrence 		ctl->zsctl_cpu_array[i].zsc_psetid = ZS_PSET_ERROR;
4116efd4c9b6SSteve Lawrence 		ctl->zsctl_cpu_array[i].zsc_psetid_prev = ZS_PSET_ERROR;
4117efd4c9b6SSteve Lawrence 	}
4118efd4c9b6SSteve Lawrence 	if (statvfs("/proc", &svfs) != 0 ||
4119efd4c9b6SSteve Lawrence 	    strcmp("/proc", svfs.f_fstr) != 0) {
4120efd4c9b6SSteve Lawrence 		zsd_warn(gettext("/proc not a procfs filesystem"));
4121efd4c9b6SSteve Lawrence 		errno = EINVAL;
4122efd4c9b6SSteve Lawrence 		goto err;
4123efd4c9b6SSteve Lawrence 	}
4124efd4c9b6SSteve Lawrence 
4125efd4c9b6SSteve Lawrence 	size = sysconf(_SC_MAXPID) + 1;
4126efd4c9b6SSteve Lawrence 	ctl->zsctl_maxproc = size;
4127efd4c9b6SSteve Lawrence 	if (ctl->zsctl_proc_array == NULL &&
4128efd4c9b6SSteve Lawrence 	    (ctl->zsctl_proc_array = (zsd_proc_t *)calloc(size,
4129efd4c9b6SSteve Lawrence 	    sizeof (zsd_proc_t))) == NULL) {
4130efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Out of Memory"));
4131efd4c9b6SSteve Lawrence 		errno = ENOMEM;
4132efd4c9b6SSteve Lawrence 		goto err;
4133efd4c9b6SSteve Lawrence 	}
4134efd4c9b6SSteve Lawrence 	for (i = 0; i <= ctl->zsctl_maxproc; i++) {
4135efd4c9b6SSteve Lawrence 		list_link_init(&(ctl->zsctl_proc_array[i].zspr_next));
4136efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_array[i].zspr_psetid = ZS_PSET_ERROR;
4137efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_array[i].zspr_zoneid = -1;
4138efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_array[i].zspr_usage.tv_sec = 0;
4139efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_array[i].zspr_usage.tv_nsec = 0;
4140efd4c9b6SSteve Lawrence 		ctl->zsctl_proc_array[i].zspr_ppid = -1;
4141efd4c9b6SSteve Lawrence 	}
4142efd4c9b6SSteve Lawrence 
4143efd4c9b6SSteve Lawrence 	list_create(&ctl->zsctl_zones, sizeof (zsd_zone_t),
4144efd4c9b6SSteve Lawrence 	    offsetof(zsd_zone_t, zsz_next));
4145efd4c9b6SSteve Lawrence 
4146efd4c9b6SSteve Lawrence 	list_create(&ctl->zsctl_psets, sizeof (zsd_pset_t),
4147efd4c9b6SSteve Lawrence 	    offsetof(zsd_pset_t, zsp_next));
4148efd4c9b6SSteve Lawrence 
4149efd4c9b6SSteve Lawrence 	list_create(&ctl->zsctl_cpus, sizeof (zsd_cpu_t),
4150efd4c9b6SSteve Lawrence 	    offsetof(zsd_cpu_t, zsc_next));
4151efd4c9b6SSteve Lawrence 
4152efd4c9b6SSteve Lawrence 	if (ctl->zsctl_pool_conf == NULL &&
4153efd4c9b6SSteve Lawrence 	    (ctl->zsctl_pool_conf = pool_conf_alloc()) == NULL) {
4154efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Out of Memory"));
4155efd4c9b6SSteve Lawrence 		errno = ENOMEM;
4156efd4c9b6SSteve Lawrence 		goto err;
4157efd4c9b6SSteve Lawrence 	}
4158efd4c9b6SSteve Lawrence 	ctl->zsctl_pool_status = POOL_DISABLED;
4159efd4c9b6SSteve Lawrence 	ctl->zsctl_pool_changed = 0;
4160efd4c9b6SSteve Lawrence 
4161efd4c9b6SSteve Lawrence 	if (ctl->zsctl_pool_vals[0] == NULL &&
4162efd4c9b6SSteve Lawrence 	    (ctl->zsctl_pool_vals[0] = pool_value_alloc()) == NULL) {
4163efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Out of Memory"));
4164efd4c9b6SSteve Lawrence 		errno = ENOMEM;
4165efd4c9b6SSteve Lawrence 		goto err;
4166efd4c9b6SSteve Lawrence 	}
4167efd4c9b6SSteve Lawrence 	if (ctl->zsctl_pool_vals[1] == NULL &&
4168efd4c9b6SSteve Lawrence 	    (ctl->zsctl_pool_vals[1] = pool_value_alloc()) == NULL) {
4169efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Out of Memory"));
4170efd4c9b6SSteve Lawrence 		errno = ENOMEM;
4171efd4c9b6SSteve Lawrence 		goto err;
4172efd4c9b6SSteve Lawrence 	}
4173efd4c9b6SSteve Lawrence 	ctl->zsctl_pool_vals[2] = NULL;
4174efd4c9b6SSteve Lawrence 
4175efd4c9b6SSteve Lawrence 	/*
4176efd4c9b6SSteve Lawrence 	 * get system limits
4177efd4c9b6SSteve Lawrence 	 */
4178efd4c9b6SSteve Lawrence 	system->zss_maxpid = size = sysconf(_SC_MAXPID);
4179efd4c9b6SSteve Lawrence 	system->zss_processes_max = zsd_get_system_rctl("zone.max-processes");
4180efd4c9b6SSteve Lawrence 	system->zss_lwps_max = zsd_get_system_rctl("zone.max-lwps");
4181efd4c9b6SSteve Lawrence 	system->zss_shm_max = zsd_get_system_rctl("zone.max-shm-memory");
4182efd4c9b6SSteve Lawrence 	system->zss_shmids_max = zsd_get_system_rctl("zone.max-shm-ids");
4183efd4c9b6SSteve Lawrence 	system->zss_semids_max = zsd_get_system_rctl("zone.max-sem-ids");
4184efd4c9b6SSteve Lawrence 	system->zss_msgids_max = zsd_get_system_rctl("zone.max-msg-ids");
4185efd4c9b6SSteve Lawrence 	system->zss_lofi_max = zsd_get_system_rctl("zone.max-lofi");
4186efd4c9b6SSteve Lawrence 
4187efd4c9b6SSteve Lawrence 	g_gen_next = 1;
4188efd4c9b6SSteve Lawrence 
4189efd4c9b6SSteve Lawrence 	if (zsd_read(ctl, B_TRUE, B_FALSE) != 0)
4190efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Reading zone statistics failed"));
4191efd4c9b6SSteve Lawrence 
4192efd4c9b6SSteve Lawrence 	return (ctl);
4193efd4c9b6SSteve Lawrence err:
4194efd4c9b6SSteve Lawrence 	if (ctl)
4195efd4c9b6SSteve Lawrence 		zsd_close(ctl);
4196efd4c9b6SSteve Lawrence 
4197efd4c9b6SSteve Lawrence 	return (NULL);
4198efd4c9b6SSteve Lawrence }
4199efd4c9b6SSteve Lawrence 
4200efd4c9b6SSteve Lawrence /* Copy utilization data to buffer, filtering data if non-global zone. */
4201efd4c9b6SSteve Lawrence static void
zsd_usage_filter(zoneid_t zid,zs_usage_cache_t * cache,zs_usage_t * usage,boolean_t is_gz)4202efd4c9b6SSteve Lawrence zsd_usage_filter(zoneid_t zid, zs_usage_cache_t *cache, zs_usage_t *usage,
4203efd4c9b6SSteve Lawrence     boolean_t is_gz)
4204efd4c9b6SSteve Lawrence {
4205efd4c9b6SSteve Lawrence 	zs_usage_t *cusage;
4206efd4c9b6SSteve Lawrence 	zs_system_t *sys, *csys;
4207efd4c9b6SSteve Lawrence 	zs_zone_t *zone, *czone;
4208efd4c9b6SSteve Lawrence 	zs_pset_t *pset, *cpset;
4209efd4c9b6SSteve Lawrence 	zs_pset_zone_t *pz, *cpz, *foundpz;
4210efd4c9b6SSteve Lawrence 	size_t size = 0, csize = 0;
4211efd4c9b6SSteve Lawrence 	char *start, *cstart;
4212efd4c9b6SSteve Lawrence 	int i, j;
4213efd4c9b6SSteve Lawrence 	timestruc_t delta;
4214efd4c9b6SSteve Lawrence 
4215efd4c9b6SSteve Lawrence 	/* Privileged users in the global zone get everything */
4216efd4c9b6SSteve Lawrence 	if (is_gz) {
4217efd4c9b6SSteve Lawrence 		cusage = cache->zsuc_usage;
4218efd4c9b6SSteve Lawrence 		(void) bcopy(cusage, usage, cusage->zsu_size);
4219efd4c9b6SSteve Lawrence 		return;
4220efd4c9b6SSteve Lawrence 	}
4221efd4c9b6SSteve Lawrence 
4222efd4c9b6SSteve Lawrence 	/* Zones just get their own usage */
4223efd4c9b6SSteve Lawrence 	cusage = cache->zsuc_usage;
4224efd4c9b6SSteve Lawrence 
4225efd4c9b6SSteve Lawrence 	start = (char *)usage;
4226efd4c9b6SSteve Lawrence 	cstart = (char *)cusage;
4227efd4c9b6SSteve Lawrence 	size += sizeof (zs_usage_t);
4228efd4c9b6SSteve Lawrence 	csize += sizeof (zs_usage_t);
4229efd4c9b6SSteve Lawrence 
4230efd4c9b6SSteve Lawrence 	usage->zsu_start = cusage->zsu_start;
4231efd4c9b6SSteve Lawrence 	usage->zsu_hrstart = cusage->zsu_hrstart;
4232efd4c9b6SSteve Lawrence 	usage->zsu_time = cusage->zsu_time;
4233efd4c9b6SSteve Lawrence 	usage->zsu_hrtime = cusage->zsu_hrtime;
4234efd4c9b6SSteve Lawrence 	usage->zsu_gen = cusage->zsu_gen;
4235efd4c9b6SSteve Lawrence 	usage->zsu_nzones = 1;
4236efd4c9b6SSteve Lawrence 	usage->zsu_npsets = 0;
4237efd4c9b6SSteve Lawrence 
4238efd4c9b6SSteve Lawrence 	/* LINTED */
4239efd4c9b6SSteve Lawrence 	sys = (zs_system_t *)(start + size);
4240efd4c9b6SSteve Lawrence 	/* LINTED */
4241efd4c9b6SSteve Lawrence 	csys = (zs_system_t *)(cstart + csize);
4242efd4c9b6SSteve Lawrence 	size += sizeof (zs_system_t);
4243efd4c9b6SSteve Lawrence 	csize += sizeof (zs_system_t);
4244efd4c9b6SSteve Lawrence 
4245efd4c9b6SSteve Lawrence 	/* Save system limits but not usage */
4246efd4c9b6SSteve Lawrence 	*sys = *csys;
4247efd4c9b6SSteve Lawrence 	sys->zss_ncpus = 0;
4248efd4c9b6SSteve Lawrence 	sys->zss_ncpus_online = 0;
4249efd4c9b6SSteve Lawrence 
4250efd4c9b6SSteve Lawrence 	/* LINTED */
4251efd4c9b6SSteve Lawrence 	zone = (zs_zone_t *)(start + size);
4252efd4c9b6SSteve Lawrence 	/* LINTED */
4253efd4c9b6SSteve Lawrence 	czone = (zs_zone_t *)(cstart + csize);
4254efd4c9b6SSteve Lawrence 	/* Find the matching zone */
4255efd4c9b6SSteve Lawrence 	for (i = 0; i < cusage->zsu_nzones; i++) {
4256efd4c9b6SSteve Lawrence 		if (czone->zsz_id == zid) {
4257efd4c9b6SSteve Lawrence 			*zone = *czone;
4258efd4c9b6SSteve Lawrence 			size += sizeof (zs_zone_t);
4259efd4c9b6SSteve Lawrence 		}
4260efd4c9b6SSteve Lawrence 		csize += sizeof (zs_zone_t);
4261efd4c9b6SSteve Lawrence 		/* LINTED */
4262efd4c9b6SSteve Lawrence 		czone = (zs_zone_t *)(cstart + csize);
4263efd4c9b6SSteve Lawrence 	}
4264efd4c9b6SSteve Lawrence 	sys->zss_ram_kern += (sys->zss_ram_zones - zone->zsz_usage_ram);
4265efd4c9b6SSteve Lawrence 	sys->zss_ram_zones = zone->zsz_usage_ram;
4266efd4c9b6SSteve Lawrence 
4267efd4c9b6SSteve Lawrence 	sys->zss_vm_kern += (sys->zss_vm_zones - zone->zsz_usage_vm);
4268efd4c9b6SSteve Lawrence 	sys->zss_vm_zones = zone->zsz_usage_vm;
4269efd4c9b6SSteve Lawrence 
4270efd4c9b6SSteve Lawrence 	sys->zss_locked_kern += (sys->zss_locked_zones -
4271efd4c9b6SSteve Lawrence 	    zone->zsz_usage_locked);
4272efd4c9b6SSteve Lawrence 	sys->zss_locked_zones = zone->zsz_usage_locked;
4273efd4c9b6SSteve Lawrence 
4274efd4c9b6SSteve Lawrence 	TIMESTRUC_DELTA(delta, sys->zss_cpu_usage_zones, zone->zsz_cpu_usage);
4275efd4c9b6SSteve Lawrence 	TIMESTRUC_ADD_TIMESTRUC(sys->zss_cpu_usage_kern, delta);
4276efd4c9b6SSteve Lawrence 	sys->zss_cpu_usage_zones = zone->zsz_cpu_usage;
4277efd4c9b6SSteve Lawrence 
4278efd4c9b6SSteve Lawrence 	/* LINTED */
4279efd4c9b6SSteve Lawrence 	pset = (zs_pset_t *)(start + size);
4280efd4c9b6SSteve Lawrence 	/* LINTED */
4281efd4c9b6SSteve Lawrence 	cpset = (zs_pset_t *)(cstart + csize);
4282efd4c9b6SSteve Lawrence 	for (i = 0; i < cusage->zsu_npsets; i++) {
4283efd4c9b6SSteve Lawrence 		csize += sizeof (zs_pset_t);
4284efd4c9b6SSteve Lawrence 		/* LINTED */
4285efd4c9b6SSteve Lawrence 		cpz = (zs_pset_zone_t *)(csize + cstart);
4286efd4c9b6SSteve Lawrence 		foundpz = NULL;
4287efd4c9b6SSteve Lawrence 		for (j = 0; j < cpset->zsp_nusage; j++) {
4288efd4c9b6SSteve Lawrence 			if (cpz->zspz_zoneid == zid)
4289efd4c9b6SSteve Lawrence 				foundpz = cpz;
4290efd4c9b6SSteve Lawrence 
4291efd4c9b6SSteve Lawrence 			csize += sizeof (zs_pset_zone_t);
4292efd4c9b6SSteve Lawrence 			/* LINTED */
4293efd4c9b6SSteve Lawrence 			cpz = (zs_pset_zone_t *)(csize + cstart);
4294efd4c9b6SSteve Lawrence 		}
4295efd4c9b6SSteve Lawrence 		if (foundpz != NULL) {
4296efd4c9b6SSteve Lawrence 			size += sizeof (zs_pset_t);
4297efd4c9b6SSteve Lawrence 			/* LINTED */
4298efd4c9b6SSteve Lawrence 			pz = (zs_pset_zone_t *)(start + size);
4299efd4c9b6SSteve Lawrence 			size += sizeof (zs_pset_zone_t);
4300efd4c9b6SSteve Lawrence 
4301efd4c9b6SSteve Lawrence 			*pset = *cpset;
4302efd4c9b6SSteve Lawrence 			*pz = *foundpz;
4303efd4c9b6SSteve Lawrence 
4304efd4c9b6SSteve Lawrence 			TIMESTRUC_DELTA(delta, pset->zsp_usage_zones,
4305efd4c9b6SSteve Lawrence 			    pz->zspz_cpu_usage);
4306efd4c9b6SSteve Lawrence 			TIMESTRUC_ADD_TIMESTRUC(pset->zsp_usage_kern, delta);
4307efd4c9b6SSteve Lawrence 			pset->zsp_usage_zones = pz->zspz_cpu_usage;
4308efd4c9b6SSteve Lawrence 			pset->zsp_nusage = 1;
4309efd4c9b6SSteve Lawrence 			usage->zsu_npsets++;
4310efd4c9b6SSteve Lawrence 			sys->zss_ncpus += pset->zsp_size;
4311efd4c9b6SSteve Lawrence 			sys->zss_ncpus_online += pset->zsp_online;
4312efd4c9b6SSteve Lawrence 		}
4313efd4c9b6SSteve Lawrence 		/* LINTED */
4314efd4c9b6SSteve Lawrence 		cpset = (zs_pset_t *)(cstart + csize);
4315efd4c9b6SSteve Lawrence 	}
4316efd4c9b6SSteve Lawrence 	usage->zsu_size = size;
4317efd4c9b6SSteve Lawrence }
4318efd4c9b6SSteve Lawrence 
4319efd4c9b6SSteve Lawrence /*
4320efd4c9b6SSteve Lawrence  * Respond to new connections from libzonestat.so.  Also respond to zoneadmd,
4321efd4c9b6SSteve Lawrence  * which reports new zones.
4322efd4c9b6SSteve Lawrence  */
4323efd4c9b6SSteve Lawrence /* ARGSUSED */
4324efd4c9b6SSteve Lawrence static void
zsd_server(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)4325efd4c9b6SSteve Lawrence zsd_server(void *cookie, char *argp, size_t arg_size,
4326efd4c9b6SSteve Lawrence     door_desc_t *dp, uint_t n_desc)
4327efd4c9b6SSteve Lawrence {
4328efd4c9b6SSteve Lawrence 	int *args, cmd;
4329efd4c9b6SSteve Lawrence 	door_desc_t door;
4330efd4c9b6SSteve Lawrence 	ucred_t *ucred;
4331efd4c9b6SSteve Lawrence 	const priv_set_t *eset;
4332efd4c9b6SSteve Lawrence 
4333efd4c9b6SSteve Lawrence 	if (argp == DOOR_UNREF_DATA) {
4334efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4335efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4336efd4c9b6SSteve Lawrence 	}
4337efd4c9b6SSteve Lawrence 
4338efd4c9b6SSteve Lawrence 	if (arg_size != sizeof (cmd) * 2) {
4339efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4340efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4341efd4c9b6SSteve Lawrence 	}
4342efd4c9b6SSteve Lawrence 
4343efd4c9b6SSteve Lawrence 	/* LINTED */
4344efd4c9b6SSteve Lawrence 	args = (int *)argp;
4345efd4c9b6SSteve Lawrence 	cmd = args[0];
4346efd4c9b6SSteve Lawrence 
4347efd4c9b6SSteve Lawrence 	/* If connection, return door to stat server */
4348efd4c9b6SSteve Lawrence 	if (cmd == ZSD_CMD_CONNECT) {
4349efd4c9b6SSteve Lawrence 
4350efd4c9b6SSteve Lawrence 		/* Verify client compilation version */
4351efd4c9b6SSteve Lawrence 		if (args[1] != ZS_VERSION) {
4352efd4c9b6SSteve Lawrence 			args[1] = ZSD_STATUS_VERSION_MISMATCH;
4353efd4c9b6SSteve Lawrence 			(void) door_return(argp, sizeof (cmd) * 2, NULL, 0);
4354efd4c9b6SSteve Lawrence 			thr_exit(NULL);
4355efd4c9b6SSteve Lawrence 		}
4356efd4c9b6SSteve Lawrence 		ucred = alloca(ucred_size());
4357efd4c9b6SSteve Lawrence 		/* Verify client permission */
4358efd4c9b6SSteve Lawrence 		if (door_ucred(&ucred) != 0) {
4359efd4c9b6SSteve Lawrence 			args[1] = ZSD_STATUS_INTERNAL_ERROR;
4360efd4c9b6SSteve Lawrence 			(void) door_return(argp, sizeof (cmd) * 2, NULL, 0);
4361efd4c9b6SSteve Lawrence 			thr_exit(NULL);
4362efd4c9b6SSteve Lawrence 		}
4363efd4c9b6SSteve Lawrence 
4364efd4c9b6SSteve Lawrence 		eset = ucred_getprivset(ucred, PRIV_EFFECTIVE);
4365efd4c9b6SSteve Lawrence 		if (eset == NULL) {
4366efd4c9b6SSteve Lawrence 			args[1] = ZSD_STATUS_INTERNAL_ERROR;
4367efd4c9b6SSteve Lawrence 			(void) door_return(argp, sizeof (cmd) * 2, NULL, 0);
4368efd4c9b6SSteve Lawrence 			thr_exit(NULL);
4369efd4c9b6SSteve Lawrence 		}
4370efd4c9b6SSteve Lawrence 		if (!priv_ismember(eset, PRIV_PROC_INFO)) {
4371efd4c9b6SSteve Lawrence 			args[1] = ZSD_STATUS_PERMISSION;
4372efd4c9b6SSteve Lawrence 			(void) door_return(argp, sizeof (cmd) * 2, NULL, 0);
4373efd4c9b6SSteve Lawrence 			thr_exit(NULL);
4374efd4c9b6SSteve Lawrence 		}
4375efd4c9b6SSteve Lawrence 
4376efd4c9b6SSteve Lawrence 		/* Return stat server door */
4377efd4c9b6SSteve Lawrence 		args[1] = ZSD_STATUS_OK;
4378efd4c9b6SSteve Lawrence 		door.d_attributes = DOOR_DESCRIPTOR;
4379efd4c9b6SSteve Lawrence 		door.d_data.d_desc.d_descriptor = g_stat_door;
4380efd4c9b6SSteve Lawrence 		(void) door_return(argp, sizeof (cmd) * 2, &door, 1);
4381efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4382efd4c9b6SSteve Lawrence 	}
4383efd4c9b6SSteve Lawrence 
4384efd4c9b6SSteve Lawrence 	/* Respond to zoneadmd informing zonestatd of a new zone */
4385efd4c9b6SSteve Lawrence 	if (cmd == ZSD_CMD_NEW_ZONE) {
4386efd4c9b6SSteve Lawrence 		zsd_fattach_zone(args[1], g_server_door, B_FALSE);
4387efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4388efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4389efd4c9b6SSteve Lawrence 	}
4390efd4c9b6SSteve Lawrence 
4391efd4c9b6SSteve Lawrence 	args[1] = ZSD_STATUS_INTERNAL_ERROR;
4392efd4c9b6SSteve Lawrence 	(void) door_return(argp, sizeof (cmd) * 2, NULL, 0);
4393efd4c9b6SSteve Lawrence 	thr_exit(NULL);
4394efd4c9b6SSteve Lawrence }
4395efd4c9b6SSteve Lawrence 
4396efd4c9b6SSteve Lawrence /*
4397efd4c9b6SSteve Lawrence  * Respond to libzonestat.so clients with the current utlilzation data.
4398efd4c9b6SSteve Lawrence  */
4399efd4c9b6SSteve Lawrence /* ARGSUSED */
4400efd4c9b6SSteve Lawrence static void
zsd_stat_server(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)4401efd4c9b6SSteve Lawrence zsd_stat_server(void *cookie, char *argp, size_t arg_size,
4402efd4c9b6SSteve Lawrence     door_desc_t *dp, uint_t n_desc)
4403efd4c9b6SSteve Lawrence {
4404efd4c9b6SSteve Lawrence 	uint64_t *args, cmd;
4405efd4c9b6SSteve Lawrence 	zs_usage_cache_t *cache;
4406efd4c9b6SSteve Lawrence 	int ret;
4407efd4c9b6SSteve Lawrence 	char *rvalp;
4408efd4c9b6SSteve Lawrence 	size_t rvals;
4409efd4c9b6SSteve Lawrence 	zs_usage_t *usage;
4410efd4c9b6SSteve Lawrence 	ucred_t *ucred;
4411efd4c9b6SSteve Lawrence 	zoneid_t zoneid;
4412efd4c9b6SSteve Lawrence 	const priv_set_t *eset;
4413efd4c9b6SSteve Lawrence 	boolean_t is_gz = B_FALSE;
4414efd4c9b6SSteve Lawrence 
4415efd4c9b6SSteve Lawrence 	/* Tell stat thread there are no more clients */
4416efd4c9b6SSteve Lawrence 	if (argp == DOOR_UNREF_DATA) {
4417efd4c9b6SSteve Lawrence 		(void) mutex_lock(&g_usage_cache_lock);
4418efd4c9b6SSteve Lawrence 		g_hasclient = B_FALSE;
4419efd4c9b6SSteve Lawrence 		(void) cond_signal(&g_usage_cache_kick);
4420efd4c9b6SSteve Lawrence 		(void) mutex_unlock(&g_usage_cache_lock);
4421efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4422efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4423efd4c9b6SSteve Lawrence 	}
4424efd4c9b6SSteve Lawrence 	if (arg_size != sizeof (cmd) * 2) {
4425efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4426efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4427efd4c9b6SSteve Lawrence 	}
4428efd4c9b6SSteve Lawrence 	/* LINTED */
4429efd4c9b6SSteve Lawrence 	args = (uint64_t *)argp;
4430efd4c9b6SSteve Lawrence 	cmd = args[0];
4431efd4c9b6SSteve Lawrence 	if (cmd != ZSD_CMD_READ) {
4432efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4433efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4434efd4c9b6SSteve Lawrence 	}
4435efd4c9b6SSteve Lawrence 	ucred = alloca(ucred_size());
4436efd4c9b6SSteve Lawrence 	if (door_ucred(&ucred) != 0) {
4437efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4438efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4439efd4c9b6SSteve Lawrence 	}
4440efd4c9b6SSteve Lawrence 	zoneid = ucred_getzoneid(ucred);
4441efd4c9b6SSteve Lawrence 
4442efd4c9b6SSteve Lawrence 	if (zoneid == GLOBAL_ZONEID)
4443efd4c9b6SSteve Lawrence 		is_gz = B_TRUE;
4444efd4c9b6SSteve Lawrence 
4445efd4c9b6SSteve Lawrence 	eset = ucred_getprivset(ucred, PRIV_EFFECTIVE);
4446efd4c9b6SSteve Lawrence 	if (eset == NULL) {
4447efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4448efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4449efd4c9b6SSteve Lawrence 	}
4450efd4c9b6SSteve Lawrence 	if (!priv_ismember(eset, PRIV_PROC_INFO)) {
4451efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4452efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4453efd4c9b6SSteve Lawrence 	}
4454efd4c9b6SSteve Lawrence 	(void) mutex_lock(&g_usage_cache_lock);
4455efd4c9b6SSteve Lawrence 	g_hasclient = B_TRUE;
4456efd4c9b6SSteve Lawrence 
4457efd4c9b6SSteve Lawrence 	/*
4458efd4c9b6SSteve Lawrence 	 * Force a new cpu calculation for client.  This will force a
4459efd4c9b6SSteve Lawrence 	 * new memory calculation if the memory data is older than the
4460efd4c9b6SSteve Lawrence 	 * sample period.
4461efd4c9b6SSteve Lawrence 	 */
4462efd4c9b6SSteve Lawrence 	g_usage_cache_kickers++;
4463efd4c9b6SSteve Lawrence 	(void) cond_signal(&g_usage_cache_kick);
4464efd4c9b6SSteve Lawrence 	ret = cond_wait(&g_usage_cache_wait, &g_usage_cache_lock);
4465efd4c9b6SSteve Lawrence 	g_usage_cache_kickers--;
4466efd4c9b6SSteve Lawrence 	if (ret != 0 && errno == EINTR) {
4467efd4c9b6SSteve Lawrence 		(void) mutex_unlock(&g_usage_cache_lock);
4468efd4c9b6SSteve Lawrence 		zsd_warn(gettext(
4469efd4c9b6SSteve Lawrence 		    "Interrupted before writing usage size to client\n"));
4470efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4471efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4472efd4c9b6SSteve Lawrence 	}
4473efd4c9b6SSteve Lawrence 	cache = zsd_usage_cache_hold_locked();
4474efd4c9b6SSteve Lawrence 	if (cache == NULL) {
4475efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Usage cache empty.\n"));
4476efd4c9b6SSteve Lawrence 		(void) door_return(NULL, 0, NULL, 0);
4477efd4c9b6SSteve Lawrence 		thr_exit(NULL);
4478efd4c9b6SSteve Lawrence 	}
4479efd4c9b6SSteve Lawrence 	(void) mutex_unlock(&g_usage_cache_lock);
4480efd4c9b6SSteve Lawrence 
4481efd4c9b6SSteve Lawrence 	/* Copy current usage data to stack to send to client */
4482efd4c9b6SSteve Lawrence 	usage = (zs_usage_t *)alloca(cache->zsuc_size);
4483efd4c9b6SSteve Lawrence 
4484efd4c9b6SSteve Lawrence 	/* Filter out results if caller is non-global zone */
4485efd4c9b6SSteve Lawrence 	zsd_usage_filter(zoneid, cache, usage, is_gz);
4486efd4c9b6SSteve Lawrence 
4487efd4c9b6SSteve Lawrence 	rvalp = (void *)usage;
4488efd4c9b6SSteve Lawrence 	rvals = usage->zsu_size;
4489efd4c9b6SSteve Lawrence 	zsd_usage_cache_rele(cache);
4490efd4c9b6SSteve Lawrence 
44911e88dc67SToomas Soome 	(void) door_return(rvalp, rvals, NULL, 0);
4492efd4c9b6SSteve Lawrence 	thr_exit(NULL);
4493efd4c9b6SSteve Lawrence }
4494efd4c9b6SSteve Lawrence 
4495efd4c9b6SSteve Lawrence static volatile boolean_t g_quit;
4496efd4c9b6SSteve Lawrence 
4497efd4c9b6SSteve Lawrence /* ARGSUSED */
4498efd4c9b6SSteve Lawrence static void
zonestat_quithandler(int sig)4499efd4c9b6SSteve Lawrence zonestat_quithandler(int sig)
4500efd4c9b6SSteve Lawrence {
4501efd4c9b6SSteve Lawrence 	g_quit = B_TRUE;
4502efd4c9b6SSteve Lawrence }
4503efd4c9b6SSteve Lawrence 
4504efd4c9b6SSteve Lawrence /*
4505efd4c9b6SSteve Lawrence  * The stat thread generates new utilization data when clients request
4506efd4c9b6SSteve Lawrence  * it.  It also manages opening and closing the subsystems used to gather
4507efd4c9b6SSteve Lawrence  * data depending on if clients exist.
4508efd4c9b6SSteve Lawrence  */
4509efd4c9b6SSteve Lawrence /* ARGSUSED */
4510efd4c9b6SSteve Lawrence void *
stat_thread(void * arg)4511efd4c9b6SSteve Lawrence stat_thread(void *arg)
4512efd4c9b6SSteve Lawrence {
4513efd4c9b6SSteve Lawrence 	time_t start;
4514efd4c9b6SSteve Lawrence 	time_t now;
4515efd4c9b6SSteve Lawrence 	time_t next_memory;
4516efd4c9b6SSteve Lawrence 	boolean_t do_memory;
4517efd4c9b6SSteve Lawrence 	boolean_t do_read;
4518efd4c9b6SSteve Lawrence 	boolean_t do_close;
4519efd4c9b6SSteve Lawrence 
4520efd4c9b6SSteve Lawrence 	start = time(NULL);
4521efd4c9b6SSteve Lawrence 	if (start < 0) {
4522efd4c9b6SSteve Lawrence 		if (g_quit == B_TRUE)
4523efd4c9b6SSteve Lawrence 			goto quit;
4524efd4c9b6SSteve Lawrence 		zsd_warn(gettext("Unable to fetch current time"));
4525efd4c9b6SSteve Lawrence 		g_quit = B_TRUE;
4526efd4c9b6SSteve Lawrence 		goto quit;
4527efd4c9b6SSteve Lawrence 	}
4528efd4c9b6SSteve Lawrence 
4529efd4c9b6SSteve Lawrence 	next_memory = start;
4530efd4c9b6SSteve Lawrence 	while (g_quit == B_FALSE) {
4531efd4c9b6SSteve Lawrence 		for (;;) {
4532efd4c9b6SSteve Lawrence 			/*
4533efd4c9b6SSteve Lawrence 			 * These are used to decide if the most recent memory
4534efd4c9b6SSteve Lawrence 			 * calculation was within a sample interval,
4535efd4c9b6SSteve Lawrence 			 * and weather or not the usage collection needs to
4536efd4c9b6SSteve Lawrence 			 * be opened or closed.
4537efd4c9b6SSteve Lawrence 			 */
4538efd4c9b6SSteve Lawrence 			do_memory = B_FALSE;
4539efd4c9b6SSteve Lawrence 			do_read = B_FALSE;
4540efd4c9b6SSteve Lawrence 			do_close = B_FALSE;
4541efd4c9b6SSteve Lawrence 
4542efd4c9b6SSteve Lawrence 			/*
4543efd4c9b6SSteve Lawrence 			 * If all clients have gone, close usage collecting
4544efd4c9b6SSteve Lawrence 			 */
4545efd4c9b6SSteve Lawrence 			(void) mutex_lock(&g_usage_cache_lock);
4546efd4c9b6SSteve Lawrence 			if (!g_hasclient && g_open == B_TRUE) {
4547efd4c9b6SSteve Lawrence 				do_close = B_TRUE;
4548efd4c9b6SSteve Lawrence 				(void) mutex_unlock(&g_usage_cache_lock);
4549efd4c9b6SSteve Lawrence 				break;
4550efd4c9b6SSteve Lawrence 			}
4551efd4c9b6SSteve Lawrence 			if (g_quit == B_TRUE) {
4552efd4c9b6SSteve Lawrence 				(void) mutex_unlock(
4553efd4c9b6SSteve Lawrence 				    &g_usage_cache_lock);
4554efd4c9b6SSteve Lawrence 				break;
4555efd4c9b6SSteve Lawrence 			}
4556efd4c9b6SSteve Lawrence 			/*
4557efd4c9b6SSteve Lawrence 			 * Wait for a usage data request
4558efd4c9b6SSteve Lawrence 			 */
4559efd4c9b6SSteve Lawrence 			if (g_usage_cache_kickers == 0) {
4560efd4c9b6SSteve Lawrence 				(void) cond_wait(&g_usage_cache_kick,
4561efd4c9b6SSteve Lawrence 				    &g_usage_cache_lock);
4562efd4c9b6SSteve Lawrence 			}
4563efd4c9b6SSteve Lawrence 			now = time(NULL);
4564efd4c9b6SSteve Lawrence 			if (now < 0) {
4565efd4c9b6SSteve Lawrence 				if (g_quit == B_TRUE) {
4566efd4c9b6SSteve Lawrence 					(void) mutex_unlock(
4567efd4c9b6SSteve Lawrence 					    &g_usage_cache_lock);
4568efd4c9b6SSteve Lawrence 					goto quit;
4569efd4c9b6SSteve Lawrence 				}
4570efd4c9b6SSteve Lawrence 				g_quit = B_TRUE;
4571efd4c9b6SSteve Lawrence 				(void) mutex_unlock(&g_usage_cache_lock);
4572efd4c9b6SSteve Lawrence 				zsd_warn(gettext(
4573efd4c9b6SSteve Lawrence 				    "Unable to fetch current time"));
4574efd4c9b6SSteve Lawrence 				goto quit;
4575efd4c9b6SSteve Lawrence 			}
4576efd4c9b6SSteve Lawrence 			if (g_hasclient) {
4577efd4c9b6SSteve Lawrence 				do_read = B_TRUE;
4578efd4c9b6SSteve Lawrence 				if (now >= next_memory) {
4579efd4c9b6SSteve Lawrence 					do_memory = B_TRUE;
4580efd4c9b6SSteve Lawrence 					next_memory = now + g_interval;
4581efd4c9b6SSteve Lawrence 				}
4582efd4c9b6SSteve Lawrence 			} else {
4583efd4c9b6SSteve Lawrence 				do_close = B_TRUE;
4584efd4c9b6SSteve Lawrence 			}
4585efd4c9b6SSteve Lawrence 			(void) mutex_unlock(&g_usage_cache_lock);
4586efd4c9b6SSteve Lawrence 			if (do_read || do_close)
4587efd4c9b6SSteve Lawrence 				break;
4588efd4c9b6SSteve Lawrence 		}
4589efd4c9b6SSteve Lawrence 		g_now = now;
4590efd4c9b6SSteve Lawrence 		g_hrnow = gethrtime();
4591efd4c9b6SSteve Lawrence 		if (g_hasclient && g_open == B_FALSE) {
4592efd4c9b6SSteve Lawrence 			g_start = g_now;
4593efd4c9b6SSteve Lawrence 			g_hrstart = g_hrnow;
4594efd4c9b6SSteve Lawrence 			g_ctl = zsd_open(g_ctl);
4595efd4c9b6SSteve Lawrence 			if (g_ctl == NULL)
4596efd4c9b6SSteve Lawrence 				zsd_warn(gettext(
4597efd4c9b6SSteve Lawrence 				    "Unable to open zone statistics"));
4598efd4c9b6SSteve Lawrence 			else
4599efd4c9b6SSteve Lawrence 				g_open = B_TRUE;
4600efd4c9b6SSteve Lawrence 		}
4601efd4c9b6SSteve Lawrence 		if (do_read && g_ctl) {
4602efd4c9b6SSteve Lawrence 			if (zsd_read(g_ctl, B_FALSE, do_memory) != 0) {
4603efd4c9b6SSteve Lawrence 				zsd_warn(gettext(
4604efd4c9b6SSteve Lawrence 				    "Unable to read zone statistics"));
4605efd4c9b6SSteve Lawrence 				g_quit = B_TRUE;
4606efd4c9b6SSteve Lawrence 				return (NULL);
4607efd4c9b6SSteve Lawrence 			}
4608efd4c9b6SSteve Lawrence 		}
4609efd4c9b6SSteve Lawrence 		(void) mutex_lock(&g_usage_cache_lock);
4610efd4c9b6SSteve Lawrence 		if (!g_hasclient && g_open == B_TRUE && g_ctl) {
4611efd4c9b6SSteve Lawrence 			(void) mutex_unlock(&g_usage_cache_lock);
4612efd4c9b6SSteve Lawrence 			zsd_close(g_ctl);
4613efd4c9b6SSteve Lawrence 			g_open = B_FALSE;
4614efd4c9b6SSteve Lawrence 		} else {
4615efd4c9b6SSteve Lawrence 			(void) mutex_unlock(&g_usage_cache_lock);
4616efd4c9b6SSteve Lawrence 		}
4617efd4c9b6SSteve Lawrence 	}
4618efd4c9b6SSteve Lawrence quit:
4619efd4c9b6SSteve Lawrence 	if (g_open)
4620efd4c9b6SSteve Lawrence 		zsd_close(g_ctl);
4621efd4c9b6SSteve Lawrence 
4622efd4c9b6SSteve Lawrence 	(void) thr_kill(g_main, SIGINT);
4623efd4c9b6SSteve Lawrence 	thr_exit(NULL);
4624efd4c9b6SSteve Lawrence 	return (NULL);
4625efd4c9b6SSteve Lawrence }
4626efd4c9b6SSteve Lawrence 
4627efd4c9b6SSteve Lawrence void
zsd_set_fx()4628efd4c9b6SSteve Lawrence zsd_set_fx()
4629efd4c9b6SSteve Lawrence {
4630efd4c9b6SSteve Lawrence 	pcinfo_t pcinfo;
4631efd4c9b6SSteve Lawrence 	pcparms_t pcparms;
4632efd4c9b6SSteve Lawrence 
4633efd4c9b6SSteve Lawrence 	(void) strlcpy(pcinfo.pc_clname, "FX", sizeof (pcinfo.pc_clname));
4634efd4c9b6SSteve Lawrence 	if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) {
4635efd4c9b6SSteve Lawrence 		zsd_warn(gettext("cannot get FX class parameters"));
4636efd4c9b6SSteve Lawrence 		return;
4637efd4c9b6SSteve Lawrence 	}
4638efd4c9b6SSteve Lawrence 	pcparms.pc_cid = pcinfo.pc_cid;
4639efd4c9b6SSteve Lawrence 	((fxparms_t *)pcparms.pc_clparms)->fx_upri = 60;
4640efd4c9b6SSteve Lawrence 	((fxparms_t *)pcparms.pc_clparms)->fx_uprilim = 60;
4641efd4c9b6SSteve Lawrence 	((fxparms_t *)pcparms.pc_clparms)->fx_tqsecs = 0;
4642efd4c9b6SSteve Lawrence 	((fxparms_t *)pcparms.pc_clparms)->fx_tqnsecs = FX_NOCHANGE;
4643efd4c9b6SSteve Lawrence 	if (priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms) == -1)
4644efd4c9b6SSteve Lawrence 		zsd_warn(gettext("cannot enter the FX class"));
4645efd4c9b6SSteve Lawrence }
4646efd4c9b6SSteve Lawrence 
4647efd4c9b6SSteve Lawrence static int pipe_fd;
4648efd4c9b6SSteve Lawrence 
4649efd4c9b6SSteve Lawrence static void
daemonize_ready(char status)4650efd4c9b6SSteve Lawrence daemonize_ready(char status)
4651efd4c9b6SSteve Lawrence {
4652efd4c9b6SSteve Lawrence 	/*
4653efd4c9b6SSteve Lawrence 	 * wake the parent with a clue
4654efd4c9b6SSteve Lawrence 	 */
4655efd4c9b6SSteve Lawrence 	(void) write(pipe_fd, &status, 1);
4656efd4c9b6SSteve Lawrence 	(void) close(pipe_fd);
4657efd4c9b6SSteve Lawrence }
4658efd4c9b6SSteve Lawrence 
4659efd4c9b6SSteve Lawrence static int
daemonize_start(void)4660efd4c9b6SSteve Lawrence daemonize_start(void)
4661efd4c9b6SSteve Lawrence {
4662efd4c9b6SSteve Lawrence 	char data;
4663efd4c9b6SSteve Lawrence 	int status;
4664efd4c9b6SSteve Lawrence 
4665efd4c9b6SSteve Lawrence 	int filedes[2];
4666efd4c9b6SSteve Lawrence 	pid_t pid;
4667efd4c9b6SSteve Lawrence 
4668efd4c9b6SSteve Lawrence 	(void) close(0);
4669efd4c9b6SSteve Lawrence 	(void) dup2(2, 1);
4670efd4c9b6SSteve Lawrence 
4671efd4c9b6SSteve Lawrence 	if (pipe(filedes) < 0)
4672efd4c9b6SSteve Lawrence 		return (-1);
4673efd4c9b6SSteve Lawrence 
4674efd4c9b6SSteve Lawrence 	(void) fflush(NULL);
4675efd4c9b6SSteve Lawrence 
4676efd4c9b6SSteve Lawrence 	if ((pid = fork1()) < 0)
4677efd4c9b6SSteve Lawrence 		return (-1);
4678efd4c9b6SSteve Lawrence 
4679efd4c9b6SSteve Lawrence 	if (pid != 0) {
4680efd4c9b6SSteve Lawrence 		/*
4681efd4c9b6SSteve Lawrence 		 * parent
4682efd4c9b6SSteve Lawrence 		 */
4683efd4c9b6SSteve Lawrence 		struct sigaction act;
4684efd4c9b6SSteve Lawrence 
4685*30699046SRichard Lowe 		act.sa_handler = SIG_DFL;
4686efd4c9b6SSteve Lawrence 		(void) sigemptyset(&act.sa_mask);
4687efd4c9b6SSteve Lawrence 		act.sa_flags = 0;
4688efd4c9b6SSteve Lawrence 
4689efd4c9b6SSteve Lawrence 		(void) sigaction(SIGPIPE, &act, NULL);  /* ignore SIGPIPE */
4690efd4c9b6SSteve Lawrence 
4691efd4c9b6SSteve Lawrence 		(void) close(filedes[1]);
4692efd4c9b6SSteve Lawrence 		if (read(filedes[0], &data, 1) == 1) {
4693efd4c9b6SSteve Lawrence 			/* forward ready code via exit status */
4694efd4c9b6SSteve Lawrence 			exit(data);
4695efd4c9b6SSteve Lawrence 		}
4696efd4c9b6SSteve Lawrence 		status = -1;
4697efd4c9b6SSteve Lawrence 		(void) wait4(pid, &status, 0, NULL);
4698efd4c9b6SSteve Lawrence 		/* daemon process exited before becoming ready */
4699efd4c9b6SSteve Lawrence 		if (WIFEXITED(status)) {
4700efd4c9b6SSteve Lawrence 			/* assume daemon process printed useful message */
4701efd4c9b6SSteve Lawrence 			exit(WEXITSTATUS(status));
4702efd4c9b6SSteve Lawrence 		} else {
4703efd4c9b6SSteve Lawrence 			zsd_warn(gettext("daemon process killed or died"));
4704efd4c9b6SSteve Lawrence 			exit(1);
4705efd4c9b6SSteve Lawrence 		}
4706efd4c9b6SSteve Lawrence 	}
4707efd4c9b6SSteve Lawrence 
4708efd4c9b6SSteve Lawrence 	/*
4709efd4c9b6SSteve Lawrence 	 * child
4710efd4c9b6SSteve Lawrence 	 */
4711efd4c9b6SSteve Lawrence 	pipe_fd = filedes[1];
4712efd4c9b6SSteve Lawrence 	(void) close(filedes[0]);
4713efd4c9b6SSteve Lawrence 
4714efd4c9b6SSteve Lawrence 	/*
4715efd4c9b6SSteve Lawrence 	 * generic Unix setup
4716efd4c9b6SSteve Lawrence 	 */
4717efd4c9b6SSteve Lawrence 	(void) setsid();
4718efd4c9b6SSteve Lawrence 	(void) umask(0000);
4719efd4c9b6SSteve Lawrence 
4720efd4c9b6SSteve Lawrence 	return (0);
4721efd4c9b6SSteve Lawrence }
4722efd4c9b6SSteve Lawrence 
4723efd4c9b6SSteve Lawrence static void
fattach_all_zones(boolean_t detach_only)4724efd4c9b6SSteve Lawrence fattach_all_zones(boolean_t detach_only)
4725efd4c9b6SSteve Lawrence {
4726efd4c9b6SSteve Lawrence 	zoneid_t *zids;
4727efd4c9b6SSteve Lawrence 	uint_t nzids, nzids_last;
4728efd4c9b6SSteve Lawrence 	int i;
4729efd4c9b6SSteve Lawrence 
4730efd4c9b6SSteve Lawrence again:
4731efd4c9b6SSteve Lawrence 	(void) zone_list(NULL, &nzids);
4732efd4c9b6SSteve Lawrence 	nzids_last = nzids;
4733efd4c9b6SSteve Lawrence 	zids = (zoneid_t *)malloc(sizeof (zoneid_t) * nzids_last);
4734efd4c9b6SSteve Lawrence 	if (zids == NULL)
4735efd4c9b6SSteve Lawrence 		zsd_error(gettext("Out of memory"));
4736efd4c9b6SSteve Lawrence 
4737efd4c9b6SSteve Lawrence 	(void) zone_list(zids, &nzids);
4738efd4c9b6SSteve Lawrence 	if (nzids > nzids_last) {
4739efd4c9b6SSteve Lawrence 		free(zids);
4740efd4c9b6SSteve Lawrence 		goto again;
4741efd4c9b6SSteve Lawrence 	}
4742efd4c9b6SSteve Lawrence 	for (i = 0; i < nzids; i++)
4743efd4c9b6SSteve Lawrence 		zsd_fattach_zone(zids[i], g_server_door, detach_only);
4744efd4c9b6SSteve Lawrence 
4745efd4c9b6SSteve Lawrence 	free(zids);
4746efd4c9b6SSteve Lawrence }
4747efd4c9b6SSteve Lawrence 
4748efd4c9b6SSteve Lawrence int
main(int argc,char * argv[])4749efd4c9b6SSteve Lawrence main(int argc, char *argv[])
4750efd4c9b6SSteve Lawrence {
4751efd4c9b6SSteve Lawrence 
4752efd4c9b6SSteve Lawrence 	int arg;
4753efd4c9b6SSteve Lawrence 	thread_t tid;
4754efd4c9b6SSteve Lawrence 	scf_simple_prop_t *prop;
4755efd4c9b6SSteve Lawrence 	uint64_t *intervalp;
4756efd4c9b6SSteve Lawrence 	boolean_t opt_cleanup = B_FALSE;
4757efd4c9b6SSteve Lawrence 
4758efd4c9b6SSteve Lawrence 	g_main = thr_self();
4759efd4c9b6SSteve Lawrence 	g_quit = B_FALSE;
4760efd4c9b6SSteve Lawrence 	(void) signal(SIGINT, zonestat_quithandler);
4761efd4c9b6SSteve Lawrence 	(void) signal(SIGTERM, zonestat_quithandler);
4762efd4c9b6SSteve Lawrence 	(void) signal(SIGHUP, zonestat_quithandler);
4763efd4c9b6SSteve Lawrence /*	(void) sigignore(SIGCHLD); */
4764efd4c9b6SSteve Lawrence 	(void) sigignore(SIGPIPE);
4765efd4c9b6SSteve Lawrence 
4766efd4c9b6SSteve Lawrence 	if (getzoneid() != GLOBAL_ZONEID)
4767efd4c9b6SSteve Lawrence 		zsd_error(gettext("Must be run from global zone only"));
4768efd4c9b6SSteve Lawrence 
4769efd4c9b6SSteve Lawrence 	while ((arg = getopt(argc, argv, "c"))
4770efd4c9b6SSteve Lawrence 	    != EOF) {
4771efd4c9b6SSteve Lawrence 		switch (arg) {
4772efd4c9b6SSteve Lawrence 		case 'c':
4773efd4c9b6SSteve Lawrence 			opt_cleanup = B_TRUE;
4774efd4c9b6SSteve Lawrence 			break;
4775efd4c9b6SSteve Lawrence 		default:
4776efd4c9b6SSteve Lawrence 			zsd_error(gettext("Invalid option"));
4777efd4c9b6SSteve Lawrence 		}
4778efd4c9b6SSteve Lawrence 	}
4779efd4c9b6SSteve Lawrence 
4780efd4c9b6SSteve Lawrence 	if (opt_cleanup) {
4781efd4c9b6SSteve Lawrence 		if (zsd_disable_cpu_stats() != 0)
4782efd4c9b6SSteve Lawrence 			exit(1);
4783efd4c9b6SSteve Lawrence 		else
4784efd4c9b6SSteve Lawrence 			exit(0);
4785efd4c9b6SSteve Lawrence 	}
4786efd4c9b6SSteve Lawrence 
4787efd4c9b6SSteve Lawrence 	/* Get the configured sample interval */
4788efd4c9b6SSteve Lawrence 	prop = scf_simple_prop_get(NULL, "svc:/system/zones-monitoring:default",
4789efd4c9b6SSteve Lawrence 	    "config", "sample_interval");
4790efd4c9b6SSteve Lawrence 	if (prop == NULL)
4791efd4c9b6SSteve Lawrence 		zsd_error(gettext("Unable to fetch SMF property "
4792efd4c9b6SSteve Lawrence 		    "\"config/sample_interval\""));
4793efd4c9b6SSteve Lawrence 
4794efd4c9b6SSteve Lawrence 	if (scf_simple_prop_type(prop) != SCF_TYPE_COUNT)
4795efd4c9b6SSteve Lawrence 		zsd_error(gettext("Malformed SMF property "
4796efd4c9b6SSteve Lawrence 		    "\"config/sample_interval\".  Must be of type \"count\""));
4797efd4c9b6SSteve Lawrence 
4798efd4c9b6SSteve Lawrence 	intervalp = scf_simple_prop_next_count(prop);
4799efd4c9b6SSteve Lawrence 	g_interval = *intervalp;
4800efd4c9b6SSteve Lawrence 	if (g_interval == 0)
4801efd4c9b6SSteve Lawrence 		zsd_error(gettext("Malformed SMF property "
4802efd4c9b6SSteve Lawrence 		    "\"config/sample_interval\".  Must be greater than zero"));
4803efd4c9b6SSteve Lawrence 
4804efd4c9b6SSteve Lawrence 	scf_simple_prop_free(prop);
4805efd4c9b6SSteve Lawrence 
4806efd4c9b6SSteve Lawrence 	if (daemonize_start() < 0)
4807efd4c9b6SSteve Lawrence 		zsd_error(gettext("Unable to start daemon\n"));
4808efd4c9b6SSteve Lawrence 
4809efd4c9b6SSteve Lawrence 	/* Run at high priority */
4810efd4c9b6SSteve Lawrence 	zsd_set_fx();
4811efd4c9b6SSteve Lawrence 
4812efd4c9b6SSteve Lawrence 	(void) mutex_init(&g_usage_cache_lock, USYNC_THREAD, NULL);
4813efd4c9b6SSteve Lawrence 	(void) cond_init(&g_usage_cache_kick, USYNC_THREAD, NULL);
4814efd4c9b6SSteve Lawrence 	(void) cond_init(&g_usage_cache_wait, USYNC_THREAD, NULL);
4815efd4c9b6SSteve Lawrence 
4816efd4c9b6SSteve Lawrence 	g_server_door = door_create(zsd_server, NULL,
4817efd4c9b6SSteve Lawrence 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
4818efd4c9b6SSteve Lawrence 	if (g_server_door < 0)
4819efd4c9b6SSteve Lawrence 		zsd_error(gettext("Unable to create server door\n"));
4820efd4c9b6SSteve Lawrence 
4821efd4c9b6SSteve Lawrence 
4822efd4c9b6SSteve Lawrence 	g_stat_door = door_create(zsd_stat_server, NULL, DOOR_UNREF_MULTI |
4823efd4c9b6SSteve Lawrence 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
4824efd4c9b6SSteve Lawrence 	if (g_stat_door < 0)
4825efd4c9b6SSteve Lawrence 		zsd_error(gettext("Unable to create statistics door\n"));
4826efd4c9b6SSteve Lawrence 
4827efd4c9b6SSteve Lawrence 	fattach_all_zones(B_FALSE);
4828efd4c9b6SSteve Lawrence 
4829efd4c9b6SSteve Lawrence 	if (thr_create(NULL, 0, stat_thread, NULL, 0, &tid) != 0)
4830efd4c9b6SSteve Lawrence 		zsd_error(gettext("Unable to create statistics thread\n"));
4831efd4c9b6SSteve Lawrence 
4832efd4c9b6SSteve Lawrence 	daemonize_ready(0);
4833efd4c9b6SSteve Lawrence 
4834efd4c9b6SSteve Lawrence 	/* Wait for signal to quit */
4835efd4c9b6SSteve Lawrence 	while (g_quit == B_FALSE)
4836efd4c9b6SSteve Lawrence 		(void) pause();
4837efd4c9b6SSteve Lawrence 
4838efd4c9b6SSteve Lawrence 	/* detach doors */
4839efd4c9b6SSteve Lawrence 	fattach_all_zones(B_TRUE);
4840efd4c9b6SSteve Lawrence 
4841efd4c9b6SSteve Lawrence 	(void) door_revoke(g_server_door);
4842efd4c9b6SSteve Lawrence 	(void) door_revoke(g_stat_door);
4843efd4c9b6SSteve Lawrence 
4844efd4c9b6SSteve Lawrence 	/* kick stat thread and wait for it to close the statistics */
4845efd4c9b6SSteve Lawrence 	(void) mutex_lock(&g_usage_cache_lock);
4846efd4c9b6SSteve Lawrence 	g_quit = B_TRUE;
4847efd4c9b6SSteve Lawrence 	(void) cond_signal(&g_usage_cache_kick);
4848efd4c9b6SSteve Lawrence 	(void) mutex_unlock(&g_usage_cache_lock);
4849efd4c9b6SSteve Lawrence end:
4850efd4c9b6SSteve Lawrence 	(void) thr_join(tid, NULL, NULL);
4851efd4c9b6SSteve Lawrence 	return (0);
4852efd4c9b6SSteve Lawrence }
4853