xref: /titanic_51/usr/src/uts/common/os/pool_pset.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/pool.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/pool_impl.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/pool_pset.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/cpupart.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/fss.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/exacct.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/class.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/list.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate  * Processor set plugin for pools.
49*7c478bd9Sstevel@tonic-gate  *
50*7c478bd9Sstevel@tonic-gate  * This file contains various routines used by the common pools layer to create,
51*7c478bd9Sstevel@tonic-gate  * modify, and destroy processor sets.  All processor sets created by this
52*7c478bd9Sstevel@tonic-gate  * plug-in are stored in the pool_pset_list doubly-linked list, which is
53*7c478bd9Sstevel@tonic-gate  * guaranteed to always have an entry for the default processor set,
54*7c478bd9Sstevel@tonic-gate  * pool_pset_default.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * Interaction with zones:
57*7c478bd9Sstevel@tonic-gate  *
58*7c478bd9Sstevel@tonic-gate  * If pools are enabled, non-global zones only have visibility into the
59*7c478bd9Sstevel@tonic-gate  * pset of the pool to which they are bound.  This is accomplished by
60*7c478bd9Sstevel@tonic-gate  * changing the set of processors and processor sets which are visible
61*7c478bd9Sstevel@tonic-gate  * through both systemcall interfaces and system kstats.
62*7c478bd9Sstevel@tonic-gate  *
63*7c478bd9Sstevel@tonic-gate  * To avoid grabbing pool_lock() during cpu change operations, we cache
64*7c478bd9Sstevel@tonic-gate  * the pset the zone is currently bound to, and can read this value
65*7c478bd9Sstevel@tonic-gate  * while under cpu_lock.  The special psetid_t token ZONE_PS_INVAL means
66*7c478bd9Sstevel@tonic-gate  * that pools are disabled, and provides a mechanism for determining if the
67*7c478bd9Sstevel@tonic-gate  * status of pools without grabbing pool_lock().
68*7c478bd9Sstevel@tonic-gate  *
69*7c478bd9Sstevel@tonic-gate  * To avoid grabbing any locks to determine the instantaneous value of
70*7c478bd9Sstevel@tonic-gate  * the number of configured and online cpus in the zone, we also cache
71*7c478bd9Sstevel@tonic-gate  * these values in a zone_t.  If these values are zero, the pools
72*7c478bd9Sstevel@tonic-gate  * facility must be disabled, in which case relevant systemcall
73*7c478bd9Sstevel@tonic-gate  * interfaces will return the values for the system as a whole.
74*7c478bd9Sstevel@tonic-gate  *
75*7c478bd9Sstevel@tonic-gate  * The various kstat interfaces are dealt with as follows: if pools are
76*7c478bd9Sstevel@tonic-gate  * disabled all cpu-related kstats should be exported to all zones.
77*7c478bd9Sstevel@tonic-gate  * When pools are enabled we begin maintaining a list of "permitted
78*7c478bd9Sstevel@tonic-gate  * zones" on a per-kstat basis.  There are various hooks throughout the
79*7c478bd9Sstevel@tonic-gate  * code to update this list when certain pools- or cpu-related events
80*7c478bd9Sstevel@tonic-gate  * occur.
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate static list_t pool_pset_list;	/* doubly-linked list of psets */
84*7c478bd9Sstevel@tonic-gate pool_pset_t *pool_pset_default;	/* default pset */
85*7c478bd9Sstevel@tonic-gate hrtime_t pool_pset_mod;		/* last modification time for psets */
86*7c478bd9Sstevel@tonic-gate hrtime_t pool_cpu_mod;		/* last modification time for CPUs */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static pool_pset_t *
89*7c478bd9Sstevel@tonic-gate pool_lookup_pset_by_id(psetid_t psetid)
90*7c478bd9Sstevel@tonic-gate {
91*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset = pool_pset_default;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	for (pset = list_head(&pool_pset_list); pset;
96*7c478bd9Sstevel@tonic-gate 	    pset = list_next(&pool_pset_list, pset)) {
97*7c478bd9Sstevel@tonic-gate 		if (pset->pset_id == psetid)
98*7c478bd9Sstevel@tonic-gate 			return (pset);
99*7c478bd9Sstevel@tonic-gate 	}
100*7c478bd9Sstevel@tonic-gate 	return (NULL);
101*7c478bd9Sstevel@tonic-gate }
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate struct setup_arg {
104*7c478bd9Sstevel@tonic-gate 	psetid_t psetid;
105*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
106*7c478bd9Sstevel@tonic-gate 	cpu_setup_t what;
107*7c478bd9Sstevel@tonic-gate };
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /*
110*7c478bd9Sstevel@tonic-gate  * Callback function used to apply a cpu configuration event to a zone.
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate static int
113*7c478bd9Sstevel@tonic-gate pool_pset_setup_cb(zone_t *zone, void *arg)
114*7c478bd9Sstevel@tonic-gate {
115*7c478bd9Sstevel@tonic-gate 	struct setup_arg *sa = arg;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
118*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
119*7c478bd9Sstevel@tonic-gate 	ASSERT(zone != NULL);
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	if (zone == global_zone)
122*7c478bd9Sstevel@tonic-gate 		return (0);
123*7c478bd9Sstevel@tonic-gate 	if (zone_pset_get(zone) != sa->psetid)
124*7c478bd9Sstevel@tonic-gate 		return (0);	/* ignore */
125*7c478bd9Sstevel@tonic-gate 	switch (sa->what) {
126*7c478bd9Sstevel@tonic-gate 	case CPU_CONFIG:
127*7c478bd9Sstevel@tonic-gate 		cpu_visibility_configure(sa->cpu, zone);
128*7c478bd9Sstevel@tonic-gate 		break;
129*7c478bd9Sstevel@tonic-gate 	case CPU_UNCONFIG:
130*7c478bd9Sstevel@tonic-gate 		cpu_visibility_unconfigure(sa->cpu, zone);
131*7c478bd9Sstevel@tonic-gate 		break;
132*7c478bd9Sstevel@tonic-gate 	case CPU_ON:
133*7c478bd9Sstevel@tonic-gate 		cpu_visibility_online(sa->cpu, zone);
134*7c478bd9Sstevel@tonic-gate 		break;
135*7c478bd9Sstevel@tonic-gate 	case CPU_OFF:
136*7c478bd9Sstevel@tonic-gate 		cpu_visibility_offline(sa->cpu, zone);
137*7c478bd9Sstevel@tonic-gate 		break;
138*7c478bd9Sstevel@tonic-gate 	case CPU_CPUPART_IN:
139*7c478bd9Sstevel@tonic-gate 		cpu_visibility_add(sa->cpu, zone);
140*7c478bd9Sstevel@tonic-gate 		break;
141*7c478bd9Sstevel@tonic-gate 	case CPU_CPUPART_OUT:
142*7c478bd9Sstevel@tonic-gate 		cpu_visibility_remove(sa->cpu, zone);
143*7c478bd9Sstevel@tonic-gate 		break;
144*7c478bd9Sstevel@tonic-gate 	default:
145*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "invalid cpu_setup_t value %d", sa->what);
146*7c478bd9Sstevel@tonic-gate 	}
147*7c478bd9Sstevel@tonic-gate 	return (0);
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate /*
151*7c478bd9Sstevel@tonic-gate  * Callback function to be executed when a noteworthy cpu event takes
152*7c478bd9Sstevel@tonic-gate  * place.  Will ensure that the event is reflected by the zones which
153*7c478bd9Sstevel@tonic-gate  * were affected by it.
154*7c478bd9Sstevel@tonic-gate  */
155*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
156*7c478bd9Sstevel@tonic-gate static int
157*7c478bd9Sstevel@tonic-gate pool_pset_cpu_setup(cpu_setup_t what, int id, void *arg)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	processorid_t cpuid = id;
160*7c478bd9Sstevel@tonic-gate 	struct setup_arg sarg;
161*7c478bd9Sstevel@tonic-gate 	int error;
162*7c478bd9Sstevel@tonic-gate 	cpu_t *c;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
165*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	if (!pool_pset_enabled())
168*7c478bd9Sstevel@tonic-gate 		return (0);
169*7c478bd9Sstevel@tonic-gate 	if (what != CPU_CONFIG && what != CPU_UNCONFIG &&
170*7c478bd9Sstevel@tonic-gate 	    what != CPU_ON && what != CPU_OFF &&
171*7c478bd9Sstevel@tonic-gate 	    what != CPU_CPUPART_IN && what != CPU_CPUPART_OUT)
172*7c478bd9Sstevel@tonic-gate 		return (0);
173*7c478bd9Sstevel@tonic-gate 	c = cpu_get(cpuid);
174*7c478bd9Sstevel@tonic-gate 	ASSERT(c != NULL);
175*7c478bd9Sstevel@tonic-gate 	sarg.psetid = cpupart_query_cpu(c);
176*7c478bd9Sstevel@tonic-gate 	sarg.cpu = c;
177*7c478bd9Sstevel@tonic-gate 	sarg.what = what;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	error = zone_walk(pool_pset_setup_cb, &sarg);
180*7c478bd9Sstevel@tonic-gate 	ASSERT(error == 0);
181*7c478bd9Sstevel@tonic-gate 	return (0);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate /*
185*7c478bd9Sstevel@tonic-gate  * Initialize processor set plugin.  Called once at boot time.
186*7c478bd9Sstevel@tonic-gate  */
187*7c478bd9Sstevel@tonic-gate void
188*7c478bd9Sstevel@tonic-gate pool_pset_init(void)
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_pset_default == NULL);
191*7c478bd9Sstevel@tonic-gate 	pool_pset_default = kmem_zalloc(sizeof (pool_pset_t), KM_SLEEP);
192*7c478bd9Sstevel@tonic-gate 	pool_pset_default->pset_id = PS_NONE;
193*7c478bd9Sstevel@tonic-gate 	pool_pset_default->pset_npools = 1;	/* for pool_default */
194*7c478bd9Sstevel@tonic-gate 	pool_default->pool_pset = pool_pset_default;
195*7c478bd9Sstevel@tonic-gate 	list_create(&pool_pset_list, sizeof (pool_pset_t),
196*7c478bd9Sstevel@tonic-gate 	    offsetof(pool_pset_t, pset_link));
197*7c478bd9Sstevel@tonic-gate 	list_insert_head(&pool_pset_list, pool_pset_default);
198*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
199*7c478bd9Sstevel@tonic-gate 	register_cpu_setup_func(pool_pset_cpu_setup, NULL);
200*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
201*7c478bd9Sstevel@tonic-gate }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate  * Dummy wrapper function that returns 0 to satisfy zone_walk().
205*7c478bd9Sstevel@tonic-gate  */
206*7c478bd9Sstevel@tonic-gate static int
207*7c478bd9Sstevel@tonic-gate pool_pset_zone_pset_set(zone_t *zone, void *arg)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	psetid_t psetid = (psetid_t)(uintptr_t)arg;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
212*7c478bd9Sstevel@tonic-gate 	zone_pset_set(zone, psetid);
213*7c478bd9Sstevel@tonic-gate 	return (0);
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate /*
217*7c478bd9Sstevel@tonic-gate  * Enable processor set plugin.
218*7c478bd9Sstevel@tonic-gate  */
219*7c478bd9Sstevel@tonic-gate int
220*7c478bd9Sstevel@tonic-gate pool_pset_enable(void)
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	int error;
223*7c478bd9Sstevel@tonic-gate 	nvlist_t *props;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
226*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
227*7c478bd9Sstevel@tonic-gate 	/*
228*7c478bd9Sstevel@tonic-gate 	 * Can't enable pools if there are existing cpu partitions.
229*7c478bd9Sstevel@tonic-gate 	 */
230*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
231*7c478bd9Sstevel@tonic-gate 	if (cp_numparts > 1) {
232*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
233*7c478bd9Sstevel@tonic-gate 		return (EEXIST);
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * We want to switch things such that everything that was tagged with
238*7c478bd9Sstevel@tonic-gate 	 * the special ALL_ZONES token now is explicitly visible to all zones:
239*7c478bd9Sstevel@tonic-gate 	 * first add individual zones to the visibility list then remove the
240*7c478bd9Sstevel@tonic-gate 	 * special "ALL_ZONES" token.  There must only be the default pset
241*7c478bd9Sstevel@tonic-gate 	 * (PS_NONE) active if pools are being enabled, so we only need to
242*7c478bd9Sstevel@tonic-gate 	 * deal with it.
243*7c478bd9Sstevel@tonic-gate 	 *
244*7c478bd9Sstevel@tonic-gate 	 * We want to make pool_pset_enabled() start returning B_TRUE before
245*7c478bd9Sstevel@tonic-gate 	 * we call any of the visibility update functions.
246*7c478bd9Sstevel@tonic-gate 	 */
247*7c478bd9Sstevel@tonic-gate 	global_zone->zone_psetid = PS_NONE;
248*7c478bd9Sstevel@tonic-gate 	/*
249*7c478bd9Sstevel@tonic-gate 	 * We need to explicitly handle the global zone since
250*7c478bd9Sstevel@tonic-gate 	 * zone_pset_set() won't modify it.
251*7c478bd9Sstevel@tonic-gate 	 */
252*7c478bd9Sstevel@tonic-gate 	pool_pset_visibility_add(PS_NONE, global_zone);
253*7c478bd9Sstevel@tonic-gate 	/*
254*7c478bd9Sstevel@tonic-gate 	 * A NULL argument means the ALL_ZONES token.
255*7c478bd9Sstevel@tonic-gate 	 */
256*7c478bd9Sstevel@tonic-gate 	pool_pset_visibility_remove(PS_NONE, NULL);
257*7c478bd9Sstevel@tonic-gate 	error = zone_walk(pool_pset_zone_pset_set, (void *)PS_NONE);
258*7c478bd9Sstevel@tonic-gate 	ASSERT(error == 0);
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	/*
261*7c478bd9Sstevel@tonic-gate 	 * It is safe to drop cpu_lock here.  We're still
262*7c478bd9Sstevel@tonic-gate 	 * holding pool_lock so no new cpu partitions can
263*7c478bd9Sstevel@tonic-gate 	 * be created while we're here.
264*7c478bd9Sstevel@tonic-gate 	 */
265*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
266*7c478bd9Sstevel@tonic-gate 	(void) nvlist_alloc(&pool_pset_default->pset_props,
267*7c478bd9Sstevel@tonic-gate 	    NV_UNIQUE_NAME, KM_SLEEP);
268*7c478bd9Sstevel@tonic-gate 	props = pool_pset_default->pset_props;
269*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(props, "pset.name", "pset_default");
270*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(props, "pset.comment", "");
271*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_int64(props, "pset.sys_id", PS_NONE);
272*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(props, "pset.units", "population");
273*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_byte(props, "pset.default", 1);
274*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_uint64(props, "pset.max", 65536);
275*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_uint64(props, "pset.min", 1);
276*7c478bd9Sstevel@tonic-gate 	pool_pset_mod = pool_cpu_mod = gethrtime();
277*7c478bd9Sstevel@tonic-gate 	return (0);
278*7c478bd9Sstevel@tonic-gate }
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate /*
281*7c478bd9Sstevel@tonic-gate  * Disable processor set plugin.
282*7c478bd9Sstevel@tonic-gate  */
283*7c478bd9Sstevel@tonic-gate int
284*7c478bd9Sstevel@tonic-gate pool_pset_disable(void)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	processorid_t cpuid;
287*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
288*7c478bd9Sstevel@tonic-gate 	int error;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
291*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
294*7c478bd9Sstevel@tonic-gate 	if (cp_numparts > 1) {	/* make sure only default pset is left */
295*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
296*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 	/*
299*7c478bd9Sstevel@tonic-gate 	 * Remove all non-system CPU and processor set properties
300*7c478bd9Sstevel@tonic-gate 	 */
301*7c478bd9Sstevel@tonic-gate 	for (cpuid = 0; cpuid < NCPU; cpuid++) {
302*7c478bd9Sstevel@tonic-gate 		if ((cpu = cpu_get(cpuid)) == NULL)
303*7c478bd9Sstevel@tonic-gate 			continue;
304*7c478bd9Sstevel@tonic-gate 		if (cpu->cpu_props != NULL) {
305*7c478bd9Sstevel@tonic-gate 			(void) nvlist_free(cpu->cpu_props);
306*7c478bd9Sstevel@tonic-gate 			cpu->cpu_props = NULL;
307*7c478bd9Sstevel@tonic-gate 		}
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	/*
311*7c478bd9Sstevel@tonic-gate 	 * We want to switch things such that everything is now visible
312*7c478bd9Sstevel@tonic-gate 	 * to ALL_ZONES: first add the special "ALL_ZONES" token to the
313*7c478bd9Sstevel@tonic-gate 	 * visibility list then remove individual zones.  There must
314*7c478bd9Sstevel@tonic-gate 	 * only be the default pset active if pools are being disabled,
315*7c478bd9Sstevel@tonic-gate 	 * so we only need to deal with it.
316*7c478bd9Sstevel@tonic-gate 	 */
317*7c478bd9Sstevel@tonic-gate 	error = zone_walk(pool_pset_zone_pset_set, (void *)ZONE_PS_INVAL);
318*7c478bd9Sstevel@tonic-gate 	ASSERT(error == 0);
319*7c478bd9Sstevel@tonic-gate 	pool_pset_visibility_add(PS_NONE, NULL);
320*7c478bd9Sstevel@tonic-gate 	pool_pset_visibility_remove(PS_NONE, global_zone);
321*7c478bd9Sstevel@tonic-gate 	/*
322*7c478bd9Sstevel@tonic-gate 	 * pool_pset_enabled() will henceforth return B_FALSE.
323*7c478bd9Sstevel@tonic-gate 	 */
324*7c478bd9Sstevel@tonic-gate 	global_zone->zone_psetid = ZONE_PS_INVAL;
325*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
326*7c478bd9Sstevel@tonic-gate 	if (pool_pset_default->pset_props != NULL) {
327*7c478bd9Sstevel@tonic-gate 		nvlist_free(pool_pset_default->pset_props);
328*7c478bd9Sstevel@tonic-gate 		pool_pset_default->pset_props = NULL;
329*7c478bd9Sstevel@tonic-gate 	}
330*7c478bd9Sstevel@tonic-gate 	return (0);
331*7c478bd9Sstevel@tonic-gate }
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate /*
334*7c478bd9Sstevel@tonic-gate  * Create new processor set and give it a temporary name.
335*7c478bd9Sstevel@tonic-gate  */
336*7c478bd9Sstevel@tonic-gate int
337*7c478bd9Sstevel@tonic-gate pool_pset_create(psetid_t *id)
338*7c478bd9Sstevel@tonic-gate {
339*7c478bd9Sstevel@tonic-gate 	char pset_name[40];
340*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset;
341*7c478bd9Sstevel@tonic-gate 	psetid_t psetid;
342*7c478bd9Sstevel@tonic-gate 	int err;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
345*7c478bd9Sstevel@tonic-gate 	if ((err = cpupart_create(&psetid)) != 0)
346*7c478bd9Sstevel@tonic-gate 		return (err);
347*7c478bd9Sstevel@tonic-gate 	pset = kmem_alloc(sizeof (pool_pset_t), KM_SLEEP);
348*7c478bd9Sstevel@tonic-gate 	pset->pset_id = *id = psetid;
349*7c478bd9Sstevel@tonic-gate 	pset->pset_npools = 0;
350*7c478bd9Sstevel@tonic-gate 	(void) nvlist_alloc(&pset->pset_props, NV_UNIQUE_NAME, KM_SLEEP);
351*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_int64(pset->pset_props, "pset.sys_id", psetid);
352*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_byte(pset->pset_props, "pset.default", 0);
353*7c478bd9Sstevel@tonic-gate 	pool_pset_mod = gethrtime();
354*7c478bd9Sstevel@tonic-gate 	(void) snprintf(pset_name, sizeof (pset_name), "pset_%lld",
355*7c478bd9Sstevel@tonic-gate 	    pool_pset_mod);
356*7c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(pset->pset_props, "pset.name", pset_name);
357*7c478bd9Sstevel@tonic-gate 	list_insert_tail(&pool_pset_list, pset);
358*7c478bd9Sstevel@tonic-gate 	return (0);
359*7c478bd9Sstevel@tonic-gate }
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate /*
362*7c478bd9Sstevel@tonic-gate  * Destroy existing processor set.
363*7c478bd9Sstevel@tonic-gate  */
364*7c478bd9Sstevel@tonic-gate int
365*7c478bd9Sstevel@tonic-gate pool_pset_destroy(psetid_t psetid)
366*7c478bd9Sstevel@tonic-gate {
367*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset;
368*7c478bd9Sstevel@tonic-gate 	int ret;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	if (psetid == PS_NONE)
373*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
374*7c478bd9Sstevel@tonic-gate 	if ((pset = pool_lookup_pset_by_id(psetid)) == NULL)
375*7c478bd9Sstevel@tonic-gate 		return (ESRCH);
376*7c478bd9Sstevel@tonic-gate 	if (pset->pset_npools > 0) /* can't destroy associated psets */
377*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
378*7c478bd9Sstevel@tonic-gate 	if ((ret = cpupart_destroy(pset->pset_id)) != 0)
379*7c478bd9Sstevel@tonic-gate 		return (ret);
380*7c478bd9Sstevel@tonic-gate 	(void) nvlist_free(pset->pset_props);
381*7c478bd9Sstevel@tonic-gate 	list_remove(&pool_pset_list, pset);
382*7c478bd9Sstevel@tonic-gate 	pool_pset_mod = gethrtime();
383*7c478bd9Sstevel@tonic-gate 	kmem_free(pset, sizeof (pool_pset_t));
384*7c478bd9Sstevel@tonic-gate 	return (0);
385*7c478bd9Sstevel@tonic-gate }
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate /*
388*7c478bd9Sstevel@tonic-gate  * Change the visibility of a pset (and all contained cpus) in a zone.
389*7c478bd9Sstevel@tonic-gate  * A NULL zone argument implies the special ALL_ZONES token.
390*7c478bd9Sstevel@tonic-gate  */
391*7c478bd9Sstevel@tonic-gate static void
392*7c478bd9Sstevel@tonic-gate pool_pset_visibility_change(psetid_t psetid, zone_t *zone, boolean_t add)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid = zone ? zone->zone_id : ALL_ZONES;
395*7c478bd9Sstevel@tonic-gate 	cpupart_t *cp;
396*7c478bd9Sstevel@tonic-gate 	cpu_t *c;
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
399*7c478bd9Sstevel@tonic-gate 	ASSERT(psetid != ZONE_PS_INVAL);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	cp = cpupart_find(psetid);
402*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
403*7c478bd9Sstevel@tonic-gate 	if (cp->cp_kstat != NULL) {
404*7c478bd9Sstevel@tonic-gate 		if (add)
405*7c478bd9Sstevel@tonic-gate 			kstat_zone_add(cp->cp_kstat, zoneid);
406*7c478bd9Sstevel@tonic-gate 		else
407*7c478bd9Sstevel@tonic-gate 			kstat_zone_remove(cp->cp_kstat, zoneid);
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	c = cpu_list;
411*7c478bd9Sstevel@tonic-gate 	do {
412*7c478bd9Sstevel@tonic-gate 		ASSERT(c != NULL);
413*7c478bd9Sstevel@tonic-gate 		if (c->cpu_part == cp && !cpu_is_poweredoff(c)) {
414*7c478bd9Sstevel@tonic-gate 			if (add)
415*7c478bd9Sstevel@tonic-gate 				cpu_visibility_add(c, zone);
416*7c478bd9Sstevel@tonic-gate 			else
417*7c478bd9Sstevel@tonic-gate 				cpu_visibility_remove(c, zone);
418*7c478bd9Sstevel@tonic-gate 		}
419*7c478bd9Sstevel@tonic-gate 	} while ((c = c->cpu_next) != cpu_list);
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate /*
423*7c478bd9Sstevel@tonic-gate  * Make the processor set visible to the zone.  A NULL value for
424*7c478bd9Sstevel@tonic-gate  * the zone means that the special ALL_ZONES token should be added to
425*7c478bd9Sstevel@tonic-gate  * the visibility list.
426*7c478bd9Sstevel@tonic-gate  */
427*7c478bd9Sstevel@tonic-gate void
428*7c478bd9Sstevel@tonic-gate pool_pset_visibility_add(psetid_t psetid, zone_t *zone)
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate 	pool_pset_visibility_change(psetid, zone, B_TRUE);
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate /*
434*7c478bd9Sstevel@tonic-gate  * Remove zone's visibility into the processor set.  A NULL value for
435*7c478bd9Sstevel@tonic-gate  * the zone means that the special ALL_ZONES token should be removed
436*7c478bd9Sstevel@tonic-gate  * from the visibility list.
437*7c478bd9Sstevel@tonic-gate  */
438*7c478bd9Sstevel@tonic-gate void
439*7c478bd9Sstevel@tonic-gate pool_pset_visibility_remove(psetid_t psetid, zone_t *zone)
440*7c478bd9Sstevel@tonic-gate {
441*7c478bd9Sstevel@tonic-gate 	pool_pset_visibility_change(psetid, zone, B_FALSE);
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate /*
445*7c478bd9Sstevel@tonic-gate  * Quick way of seeing if pools are enabled (as far as processor sets are
446*7c478bd9Sstevel@tonic-gate  * concerned) without holding pool_lock().
447*7c478bd9Sstevel@tonic-gate  */
448*7c478bd9Sstevel@tonic-gate boolean_t
449*7c478bd9Sstevel@tonic-gate pool_pset_enabled(void)
450*7c478bd9Sstevel@tonic-gate {
451*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	return (zone_pset_get(global_zone) != ZONE_PS_INVAL);
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate struct assoc_zone_arg {
457*7c478bd9Sstevel@tonic-gate 	poolid_t poolid;
458*7c478bd9Sstevel@tonic-gate 	psetid_t newpsetid;
459*7c478bd9Sstevel@tonic-gate };
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate /*
462*7c478bd9Sstevel@tonic-gate  * Callback function to update a zone's processor set visibility when
463*7c478bd9Sstevel@tonic-gate  * a pool is associated with a processor set.
464*7c478bd9Sstevel@tonic-gate  */
465*7c478bd9Sstevel@tonic-gate static int
466*7c478bd9Sstevel@tonic-gate pool_pset_assoc_zone_cb(zone_t *zone, void *arg)
467*7c478bd9Sstevel@tonic-gate {
468*7c478bd9Sstevel@tonic-gate 	struct assoc_zone_arg *aza = arg;
469*7c478bd9Sstevel@tonic-gate 	pool_t *pool;
470*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid = zone->zone_id;
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
473*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	if (zoneid == GLOBAL_ZONEID)
476*7c478bd9Sstevel@tonic-gate 		return (0);
477*7c478bd9Sstevel@tonic-gate 	pool = zone_pool_get(zone);
478*7c478bd9Sstevel@tonic-gate 	if (pool->pool_id == aza->poolid)
479*7c478bd9Sstevel@tonic-gate 		zone_pset_set(zone, aza->newpsetid);
480*7c478bd9Sstevel@tonic-gate 	return (0);
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate /*
484*7c478bd9Sstevel@tonic-gate  * Associate pool with new processor set.
485*7c478bd9Sstevel@tonic-gate  */
486*7c478bd9Sstevel@tonic-gate int
487*7c478bd9Sstevel@tonic-gate pool_pset_assoc(poolid_t poolid, psetid_t psetid)
488*7c478bd9Sstevel@tonic-gate {
489*7c478bd9Sstevel@tonic-gate 	pool_t *pool;
490*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset, *oldpset;
491*7c478bd9Sstevel@tonic-gate 	int err = 0;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	if ((pool = pool_lookup_pool_by_id(poolid)) == NULL ||
496*7c478bd9Sstevel@tonic-gate 	    (pset = pool_lookup_pset_by_id(psetid)) == NULL) {
497*7c478bd9Sstevel@tonic-gate 		return (ESRCH);
498*7c478bd9Sstevel@tonic-gate 	}
499*7c478bd9Sstevel@tonic-gate 	if (pool->pool_pset->pset_id == psetid) {
500*7c478bd9Sstevel@tonic-gate 		/*
501*7c478bd9Sstevel@tonic-gate 		 * Already associated.
502*7c478bd9Sstevel@tonic-gate 		 */
503*7c478bd9Sstevel@tonic-gate 		return (0);
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	/*
507*7c478bd9Sstevel@tonic-gate 	 * Hang the new pset off the pool, and rebind all of the pool's
508*7c478bd9Sstevel@tonic-gate 	 * processes to it.  If pool_do_bind fails, all processes will remain
509*7c478bd9Sstevel@tonic-gate 	 * bound to the old set.
510*7c478bd9Sstevel@tonic-gate 	 */
511*7c478bd9Sstevel@tonic-gate 	oldpset = pool->pool_pset;
512*7c478bd9Sstevel@tonic-gate 	pool->pool_pset = pset;
513*7c478bd9Sstevel@tonic-gate 	err = pool_do_bind(pool, P_POOLID, poolid, POOL_BIND_PSET);
514*7c478bd9Sstevel@tonic-gate 	if (err) {
515*7c478bd9Sstevel@tonic-gate 		pool->pool_pset = oldpset;
516*7c478bd9Sstevel@tonic-gate 	} else {
517*7c478bd9Sstevel@tonic-gate 		struct assoc_zone_arg azarg;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		/*
520*7c478bd9Sstevel@tonic-gate 		 * Update zones' visibility to reflect changes.
521*7c478bd9Sstevel@tonic-gate 		 */
522*7c478bd9Sstevel@tonic-gate 		azarg.poolid = poolid;
523*7c478bd9Sstevel@tonic-gate 		azarg.newpsetid = pset->pset_id;
524*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
525*7c478bd9Sstevel@tonic-gate 		err = zone_walk(pool_pset_assoc_zone_cb, &azarg);
526*7c478bd9Sstevel@tonic-gate 		ASSERT(err == 0);
527*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 		oldpset->pset_npools--;
530*7c478bd9Sstevel@tonic-gate 		pset->pset_npools++;
531*7c478bd9Sstevel@tonic-gate 	}
532*7c478bd9Sstevel@tonic-gate 	return (err);
533*7c478bd9Sstevel@tonic-gate }
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate /*
536*7c478bd9Sstevel@tonic-gate  * Transfer specified CPUs between processor sets.
537*7c478bd9Sstevel@tonic-gate  */
538*7c478bd9Sstevel@tonic-gate int
539*7c478bd9Sstevel@tonic-gate pool_pset_xtransfer(psetid_t src, psetid_t dst, size_t size, id_t *ids)
540*7c478bd9Sstevel@tonic-gate {
541*7c478bd9Sstevel@tonic-gate 	struct cpu *cpu;
542*7c478bd9Sstevel@tonic-gate 	int ret = 0;
543*7c478bd9Sstevel@tonic-gate 	int id;
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
546*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	if (size == 0 || size > max_ncpus)	/* quick sanity check */
549*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
552*7c478bd9Sstevel@tonic-gate 	for (id = 0; id < size; id++) {
553*7c478bd9Sstevel@tonic-gate 		if ((cpu = cpu_get((processorid_t)ids[id])) == NULL ||
554*7c478bd9Sstevel@tonic-gate 		    cpupart_query_cpu(cpu) != src) {
555*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
556*7c478bd9Sstevel@tonic-gate 			break;
557*7c478bd9Sstevel@tonic-gate 		}
558*7c478bd9Sstevel@tonic-gate 		if ((ret = cpupart_attach_cpu(dst, cpu, 1)) != 0)
559*7c478bd9Sstevel@tonic-gate 			break;
560*7c478bd9Sstevel@tonic-gate 	}
561*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
562*7c478bd9Sstevel@tonic-gate 	if (ret == 0)
563*7c478bd9Sstevel@tonic-gate 		pool_pset_mod = gethrtime();
564*7c478bd9Sstevel@tonic-gate 	return (ret);
565*7c478bd9Sstevel@tonic-gate }
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate /*
568*7c478bd9Sstevel@tonic-gate  * Bind process to processor set.  This should never fail because
569*7c478bd9Sstevel@tonic-gate  * we should've done all preliminary checks before calling it.
570*7c478bd9Sstevel@tonic-gate  */
571*7c478bd9Sstevel@tonic-gate void
572*7c478bd9Sstevel@tonic-gate pool_pset_bind(proc_t *p, psetid_t psetid, void *projbuf, void *zonebuf)
573*7c478bd9Sstevel@tonic-gate {
574*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
575*7c478bd9Sstevel@tonic-gate 	int ret;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
578*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
579*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
580*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)
583*7c478bd9Sstevel@tonic-gate 		return;
584*7c478bd9Sstevel@tonic-gate 	do {
585*7c478bd9Sstevel@tonic-gate 		ret = cpupart_bind_thread(t, psetid, 0, projbuf, zonebuf);
586*7c478bd9Sstevel@tonic-gate 		ASSERT(ret == 0);
587*7c478bd9Sstevel@tonic-gate 		t->t_bind_pset = psetid;
588*7c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
589*7c478bd9Sstevel@tonic-gate }
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate /*
592*7c478bd9Sstevel@tonic-gate  * See the comment above pool_do_bind() for the semantics of the pset_bind_*()
593*7c478bd9Sstevel@tonic-gate  * functions.  These must be kept in sync with cpupart_move_thread, and
594*7c478bd9Sstevel@tonic-gate  * anything else that could fail a pool_pset_bind.
595*7c478bd9Sstevel@tonic-gate  *
596*7c478bd9Sstevel@tonic-gate  * Returns non-zero errno on failure and zero on success.
597*7c478bd9Sstevel@tonic-gate  * Iff successful, cpu_lock is held on return.
598*7c478bd9Sstevel@tonic-gate  */
599*7c478bd9Sstevel@tonic-gate int
600*7c478bd9Sstevel@tonic-gate pset_bind_start(proc_t **procs, pool_t *pool)
601*7c478bd9Sstevel@tonic-gate {
602*7c478bd9Sstevel@tonic-gate 	cred_t *pcred;
603*7c478bd9Sstevel@tonic-gate 	proc_t *p, **pp;
604*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
605*7c478bd9Sstevel@tonic-gate 	cpupart_t *newpp;
606*7c478bd9Sstevel@tonic-gate 	int ret;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	extern int cpupart_movable_thread(kthread_id_t, cpupart_t *, int);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
611*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
614*7c478bd9Sstevel@tonic-gate 	weakbinding_stop();
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	newpp = cpupart_find(pool->pool_pset->pset_id);
617*7c478bd9Sstevel@tonic-gate 	ASSERT(newpp != NULL);
618*7c478bd9Sstevel@tonic-gate 	if (newpp->cp_cpulist == NULL) {
619*7c478bd9Sstevel@tonic-gate 		weakbinding_start();
620*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
621*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
622*7c478bd9Sstevel@tonic-gate 	}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	pcred = crgetcred();
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	/*
627*7c478bd9Sstevel@tonic-gate 	 * Check for the PRIV_PROC_PRIOCNTL privilege that is required
628*7c478bd9Sstevel@tonic-gate 	 * to enter and exit scheduling classes.  If other privileges
629*7c478bd9Sstevel@tonic-gate 	 * are required by CL_ENTERCLASS/CL_CANEXIT types of routines
630*7c478bd9Sstevel@tonic-gate 	 * in the future, this code will have to be updated.
631*7c478bd9Sstevel@tonic-gate 	 */
632*7c478bd9Sstevel@tonic-gate 	if (secpolicy_setpriority(pcred) != 0) {
633*7c478bd9Sstevel@tonic-gate 		weakbinding_start();
634*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
635*7c478bd9Sstevel@tonic-gate 		crfree(pcred);
636*7c478bd9Sstevel@tonic-gate 		return (EPERM);
637*7c478bd9Sstevel@tonic-gate 	}
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	for (pp = procs; (p = *pp) != NULL; pp++) {
640*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
641*7c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) == NULL) {
642*7c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
643*7c478bd9Sstevel@tonic-gate 			continue;
644*7c478bd9Sstevel@tonic-gate 		}
645*7c478bd9Sstevel@tonic-gate 		/*
646*7c478bd9Sstevel@tonic-gate 		 * Check our basic permissions to control this process.
647*7c478bd9Sstevel@tonic-gate 		 */
648*7c478bd9Sstevel@tonic-gate 		if (!prochasprocperm(p, curproc, pcred)) {
649*7c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
650*7c478bd9Sstevel@tonic-gate 			weakbinding_start();
651*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
652*7c478bd9Sstevel@tonic-gate 			crfree(pcred);
653*7c478bd9Sstevel@tonic-gate 			return (EPERM);
654*7c478bd9Sstevel@tonic-gate 		}
655*7c478bd9Sstevel@tonic-gate 		do {
656*7c478bd9Sstevel@tonic-gate 			/*
657*7c478bd9Sstevel@tonic-gate 			 * Check that all threads can be moved to
658*7c478bd9Sstevel@tonic-gate 			 * a new processor set.
659*7c478bd9Sstevel@tonic-gate 			 */
660*7c478bd9Sstevel@tonic-gate 			thread_lock(t);
661*7c478bd9Sstevel@tonic-gate 			ret = cpupart_movable_thread(t, newpp, 0);
662*7c478bd9Sstevel@tonic-gate 			thread_unlock(t);
663*7c478bd9Sstevel@tonic-gate 			if (ret != 0) {
664*7c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
665*7c478bd9Sstevel@tonic-gate 				weakbinding_start();
666*7c478bd9Sstevel@tonic-gate 				mutex_exit(&cpu_lock);
667*7c478bd9Sstevel@tonic-gate 				crfree(pcred);
668*7c478bd9Sstevel@tonic-gate 				return (ret);
669*7c478bd9Sstevel@tonic-gate 			}
670*7c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
671*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
672*7c478bd9Sstevel@tonic-gate 	}
673*7c478bd9Sstevel@tonic-gate 	crfree(pcred);
674*7c478bd9Sstevel@tonic-gate 	return (0);	/* with cpu_lock held and weakbinding stopped */
675*7c478bd9Sstevel@tonic-gate }
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
678*7c478bd9Sstevel@tonic-gate void
679*7c478bd9Sstevel@tonic-gate pset_bind_abort(proc_t **procs, pool_t *pool)
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
682*7c478bd9Sstevel@tonic-gate }
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate void
685*7c478bd9Sstevel@tonic-gate pset_bind_finish(void)
686*7c478bd9Sstevel@tonic-gate {
687*7c478bd9Sstevel@tonic-gate 	weakbinding_start();
688*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
689*7c478bd9Sstevel@tonic-gate }
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate static pool_property_t pool_pset_props[] = {
692*7c478bd9Sstevel@tonic-gate 	{ "pset.name",			DATA_TYPE_STRING,	PP_RDWR },
693*7c478bd9Sstevel@tonic-gate 	{ "pset.comment",		DATA_TYPE_STRING,	PP_RDWR },
694*7c478bd9Sstevel@tonic-gate 	{ "pset.sys_id",		DATA_TYPE_UINT64,	PP_READ },
695*7c478bd9Sstevel@tonic-gate 	{ "pset.units",			DATA_TYPE_STRING,	PP_RDWR },
696*7c478bd9Sstevel@tonic-gate 	{ "pset.default",		DATA_TYPE_BYTE,		PP_READ },
697*7c478bd9Sstevel@tonic-gate 	{ "pset.min",			DATA_TYPE_UINT64,	PP_RDWR },
698*7c478bd9Sstevel@tonic-gate 	{ "pset.max",			DATA_TYPE_UINT64,	PP_RDWR },
699*7c478bd9Sstevel@tonic-gate 	{ "pset.size",			DATA_TYPE_UINT64,	PP_READ },
700*7c478bd9Sstevel@tonic-gate 	{ "pset.load",			DATA_TYPE_UINT64,	PP_READ },
701*7c478bd9Sstevel@tonic-gate 	{ "pset.poold.objectives",	DATA_TYPE_STRING,
702*7c478bd9Sstevel@tonic-gate 	    PP_RDWR | PP_OPTIONAL },
703*7c478bd9Sstevel@tonic-gate 	{ NULL,				0,			0 }
704*7c478bd9Sstevel@tonic-gate };
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate static pool_property_t pool_cpu_props[] = {
707*7c478bd9Sstevel@tonic-gate 	{ "cpu.sys_id",			DATA_TYPE_UINT64,	PP_READ },
708*7c478bd9Sstevel@tonic-gate 	{ "cpu.comment",		DATA_TYPE_STRING,	PP_RDWR },
709*7c478bd9Sstevel@tonic-gate 	{ "cpu.status",			DATA_TYPE_STRING,	PP_RDWR },
710*7c478bd9Sstevel@tonic-gate 	{ "cpu.pinned",			DATA_TYPE_BYTE,
711*7c478bd9Sstevel@tonic-gate 	    PP_RDWR | PP_OPTIONAL },
712*7c478bd9Sstevel@tonic-gate 	{ NULL,				0,			0 }
713*7c478bd9Sstevel@tonic-gate };
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate /*
716*7c478bd9Sstevel@tonic-gate  * Put property on the specified processor set.
717*7c478bd9Sstevel@tonic-gate  */
718*7c478bd9Sstevel@tonic-gate int
719*7c478bd9Sstevel@tonic-gate pool_pset_propput(psetid_t psetid, nvpair_t *pair)
720*7c478bd9Sstevel@tonic-gate {
721*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset;
722*7c478bd9Sstevel@tonic-gate 	int ret;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if ((pset = pool_lookup_pset_by_id(psetid)) == NULL)
727*7c478bd9Sstevel@tonic-gate 		return (ESRCH);
728*7c478bd9Sstevel@tonic-gate 	ret = pool_propput_common(pset->pset_props, pair, pool_pset_props);
729*7c478bd9Sstevel@tonic-gate 	if (ret == 0)
730*7c478bd9Sstevel@tonic-gate 		pool_pset_mod = gethrtime();
731*7c478bd9Sstevel@tonic-gate 	return (ret);
732*7c478bd9Sstevel@tonic-gate }
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate /*
735*7c478bd9Sstevel@tonic-gate  * Remove existing processor set property.
736*7c478bd9Sstevel@tonic-gate  */
737*7c478bd9Sstevel@tonic-gate int
738*7c478bd9Sstevel@tonic-gate pool_pset_proprm(psetid_t psetid, char *name)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset;
741*7c478bd9Sstevel@tonic-gate 	int ret;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	if ((pset = pool_lookup_pset_by_id(psetid)) == NULL)
746*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
747*7c478bd9Sstevel@tonic-gate 	ret = pool_proprm_common(pset->pset_props, name, pool_pset_props);
748*7c478bd9Sstevel@tonic-gate 	if (ret == 0)
749*7c478bd9Sstevel@tonic-gate 		pool_pset_mod = gethrtime();
750*7c478bd9Sstevel@tonic-gate 	return (ret);
751*7c478bd9Sstevel@tonic-gate }
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate /*
754*7c478bd9Sstevel@tonic-gate  * Put new CPU property.
755*7c478bd9Sstevel@tonic-gate  * Handle special case of "cpu.status".
756*7c478bd9Sstevel@tonic-gate  */
757*7c478bd9Sstevel@tonic-gate int
758*7c478bd9Sstevel@tonic-gate pool_cpu_propput(processorid_t cpuid, nvpair_t *pair)
759*7c478bd9Sstevel@tonic-gate {
760*7c478bd9Sstevel@tonic-gate 	int ret = 0;
761*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
764*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 	if (nvpair_type(pair) == DATA_TYPE_STRING &&
767*7c478bd9Sstevel@tonic-gate 	    strcmp(nvpair_name(pair), "cpu.status") == 0) {
768*7c478bd9Sstevel@tonic-gate 		char *val;
769*7c478bd9Sstevel@tonic-gate 		int status;
770*7c478bd9Sstevel@tonic-gate 		int old_status;
771*7c478bd9Sstevel@tonic-gate 		(void) nvpair_value_string(pair, &val);
772*7c478bd9Sstevel@tonic-gate 		if (strcmp(val, PS_OFFLINE) == 0)
773*7c478bd9Sstevel@tonic-gate 			status = P_OFFLINE;
774*7c478bd9Sstevel@tonic-gate 		else if (strcmp(val, PS_ONLINE) == 0)
775*7c478bd9Sstevel@tonic-gate 			status = P_ONLINE;
776*7c478bd9Sstevel@tonic-gate 		else if (strcmp(val, PS_NOINTR) == 0)
777*7c478bd9Sstevel@tonic-gate 			status = P_NOINTR;
778*7c478bd9Sstevel@tonic-gate 		else if (strcmp(val, PS_FAULTED) == 0)
779*7c478bd9Sstevel@tonic-gate 			status = P_FAULTED;
780*7c478bd9Sstevel@tonic-gate 		else if (strcmp(val, PS_SPARE) == 0)
781*7c478bd9Sstevel@tonic-gate 			status = P_SPARE;
782*7c478bd9Sstevel@tonic-gate 		else
783*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
784*7c478bd9Sstevel@tonic-gate 		ret = p_online_internal(cpuid, status, &old_status);
785*7c478bd9Sstevel@tonic-gate 	} else {
786*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
787*7c478bd9Sstevel@tonic-gate 		if ((cpu = cpu_get(cpuid)) == NULL)
788*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
789*7c478bd9Sstevel@tonic-gate 		if (cpu->cpu_props == NULL) {
790*7c478bd9Sstevel@tonic-gate 			(void) nvlist_alloc(&cpu->cpu_props,
791*7c478bd9Sstevel@tonic-gate 			    NV_UNIQUE_NAME, KM_SLEEP);
792*7c478bd9Sstevel@tonic-gate 			(void) nvlist_add_string(cpu->cpu_props,
793*7c478bd9Sstevel@tonic-gate 			    "cpu.comment", "");
794*7c478bd9Sstevel@tonic-gate 		}
795*7c478bd9Sstevel@tonic-gate 		ret = pool_propput_common(cpu->cpu_props, pair, pool_cpu_props);
796*7c478bd9Sstevel@tonic-gate 		if (ret == 0)
797*7c478bd9Sstevel@tonic-gate 			pool_cpu_mod = gethrtime();
798*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
799*7c478bd9Sstevel@tonic-gate 	}
800*7c478bd9Sstevel@tonic-gate 	return (ret);
801*7c478bd9Sstevel@tonic-gate }
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate /*
804*7c478bd9Sstevel@tonic-gate  * Remove existing CPU property.
805*7c478bd9Sstevel@tonic-gate  */
806*7c478bd9Sstevel@tonic-gate int
807*7c478bd9Sstevel@tonic-gate pool_cpu_proprm(processorid_t cpuid, char *name)
808*7c478bd9Sstevel@tonic-gate {
809*7c478bd9Sstevel@tonic-gate 	int ret;
810*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
813*7c478bd9Sstevel@tonic-gate 	ASSERT(INGLOBALZONE(curproc));
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
816*7c478bd9Sstevel@tonic-gate 	if ((cpu = cpu_get(cpuid)) == NULL || cpu_is_poweredoff(cpu)) {
817*7c478bd9Sstevel@tonic-gate 		ret = EINVAL;
818*7c478bd9Sstevel@tonic-gate 	} else {
819*7c478bd9Sstevel@tonic-gate 		if (cpu->cpu_props == NULL)
820*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
821*7c478bd9Sstevel@tonic-gate 		else
822*7c478bd9Sstevel@tonic-gate 			ret = pool_proprm_common(cpu->cpu_props, name,
823*7c478bd9Sstevel@tonic-gate 			    pool_cpu_props);
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 	if (ret == 0)
826*7c478bd9Sstevel@tonic-gate 		pool_cpu_mod = gethrtime();
827*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
828*7c478bd9Sstevel@tonic-gate 	return (ret);
829*7c478bd9Sstevel@tonic-gate }
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate /*
832*7c478bd9Sstevel@tonic-gate  * This macro returns load average multiplied by 1000 w/o losing precision
833*7c478bd9Sstevel@tonic-gate  */
834*7c478bd9Sstevel@tonic-gate #define	PSET_LOAD(f)	(((f >> 16) * 1000) + (((f & 0xffff) * 1000) / 0xffff))
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate /*
837*7c478bd9Sstevel@tonic-gate  * Take a snapshot of the current state of processor sets and CPUs,
838*7c478bd9Sstevel@tonic-gate  * pack it in the exacct format, and attach it to specified exacct record.
839*7c478bd9Sstevel@tonic-gate  */
840*7c478bd9Sstevel@tonic-gate int
841*7c478bd9Sstevel@tonic-gate pool_pset_pack(ea_object_t *eo_system)
842*7c478bd9Sstevel@tonic-gate {
843*7c478bd9Sstevel@tonic-gate 	ea_object_t *eo_pset, *eo_cpu;
844*7c478bd9Sstevel@tonic-gate 	cpupart_t *cpupart;
845*7c478bd9Sstevel@tonic-gate 	psetid_t mypsetid;
846*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset;
847*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
848*7c478bd9Sstevel@tonic-gate 	size_t bufsz;
849*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
850*7c478bd9Sstevel@tonic-gate 	char *buf;
851*7c478bd9Sstevel@tonic-gate 	int ncpu;
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
856*7c478bd9Sstevel@tonic-gate 	mypsetid = zone_pset_get(curproc->p_zone);
857*7c478bd9Sstevel@tonic-gate 	for (pset = list_head(&pool_pset_list); pset;
858*7c478bd9Sstevel@tonic-gate 	    pset = list_next(&pool_pset_list, pset)) {
859*7c478bd9Sstevel@tonic-gate 		psetid_t psetid = pset->pset_id;
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 		if (!INGLOBALZONE(curproc) && mypsetid != psetid)
862*7c478bd9Sstevel@tonic-gate 			continue;
863*7c478bd9Sstevel@tonic-gate 		cpupart = cpupart_find(psetid);
864*7c478bd9Sstevel@tonic-gate 		ASSERT(cpupart != NULL);
865*7c478bd9Sstevel@tonic-gate 		eo_pset = ea_alloc_group(EXT_GROUP |
866*7c478bd9Sstevel@tonic-gate 		    EXC_LOCAL | EXD_GROUP_PSET);
867*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(eo_pset, &psetid, sizeof (id_t),
868*7c478bd9Sstevel@tonic-gate 		    EXC_LOCAL | EXD_PSET_PSETID | EXT_UINT32);
869*7c478bd9Sstevel@tonic-gate 		/*
870*7c478bd9Sstevel@tonic-gate 		 * Pack info for all CPUs in this processor set.
871*7c478bd9Sstevel@tonic-gate 		 */
872*7c478bd9Sstevel@tonic-gate 		ncpu = 0;
873*7c478bd9Sstevel@tonic-gate 		cpu = cpu_list;
874*7c478bd9Sstevel@tonic-gate 		do {
875*7c478bd9Sstevel@tonic-gate 			if (cpu->cpu_part != cpupart)	/* not our pset */
876*7c478bd9Sstevel@tonic-gate 				continue;
877*7c478bd9Sstevel@tonic-gate 			ncpu++;
878*7c478bd9Sstevel@tonic-gate 			eo_cpu = ea_alloc_group(EXT_GROUP
879*7c478bd9Sstevel@tonic-gate 			    | EXC_LOCAL | EXD_GROUP_CPU);
880*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(eo_cpu, &cpu->cpu_id,
881*7c478bd9Sstevel@tonic-gate 			    sizeof (processorid_t),
882*7c478bd9Sstevel@tonic-gate 			    EXC_LOCAL | EXD_CPU_CPUID | EXT_UINT32);
883*7c478bd9Sstevel@tonic-gate 			if (cpu->cpu_props == NULL) {
884*7c478bd9Sstevel@tonic-gate 				(void) nvlist_alloc(&cpu->cpu_props,
885*7c478bd9Sstevel@tonic-gate 				    NV_UNIQUE_NAME, KM_SLEEP);
886*7c478bd9Sstevel@tonic-gate 				(void) nvlist_add_string(cpu->cpu_props,
887*7c478bd9Sstevel@tonic-gate 				    "cpu.comment", "");
888*7c478bd9Sstevel@tonic-gate 			}
889*7c478bd9Sstevel@tonic-gate 			(void) nvlist_dup(cpu->cpu_props, &nvl, KM_SLEEP);
890*7c478bd9Sstevel@tonic-gate 			(void) nvlist_add_int64(nvl, "cpu.sys_id", cpu->cpu_id);
891*7c478bd9Sstevel@tonic-gate 			(void) nvlist_add_string(nvl, "cpu.status",
892*7c478bd9Sstevel@tonic-gate 			    (char *)cpu_get_state_str(cpu));
893*7c478bd9Sstevel@tonic-gate 			buf = NULL;
894*7c478bd9Sstevel@tonic-gate 			bufsz = 0;
895*7c478bd9Sstevel@tonic-gate 			(void) nvlist_pack(nvl, &buf, &bufsz,
896*7c478bd9Sstevel@tonic-gate 			    NV_ENCODE_NATIVE, 0);
897*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(eo_cpu, buf, bufsz,
898*7c478bd9Sstevel@tonic-gate 			    EXC_LOCAL | EXD_CPU_PROP | EXT_RAW);
899*7c478bd9Sstevel@tonic-gate 			(void) nvlist_free(nvl);
900*7c478bd9Sstevel@tonic-gate 			kmem_free(buf, bufsz);
901*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_to_group(eo_pset, eo_cpu);
902*7c478bd9Sstevel@tonic-gate 		} while ((cpu = cpu->cpu_next) != cpu_list);
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 		(void) nvlist_dup(pset->pset_props, &nvl, KM_SLEEP);
905*7c478bd9Sstevel@tonic-gate 		(void) nvlist_add_uint64(nvl, "pset.size", ncpu);
906*7c478bd9Sstevel@tonic-gate 		(void) nvlist_add_uint64(nvl, "pset.load",
907*7c478bd9Sstevel@tonic-gate 		    (uint64_t)PSET_LOAD(cpupart->cp_hp_avenrun[0]));
908*7c478bd9Sstevel@tonic-gate 		buf = NULL;
909*7c478bd9Sstevel@tonic-gate 		bufsz = 0;
910*7c478bd9Sstevel@tonic-gate 		(void) nvlist_pack(nvl, &buf, &bufsz, NV_ENCODE_NATIVE, 0);
911*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(eo_pset, buf, bufsz,
912*7c478bd9Sstevel@tonic-gate 		    EXC_LOCAL | EXD_PSET_PROP | EXT_RAW);
913*7c478bd9Sstevel@tonic-gate 		(void) nvlist_free(nvl);
914*7c478bd9Sstevel@tonic-gate 		kmem_free(buf, bufsz);
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_to_group(eo_system, eo_pset);
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
919*7c478bd9Sstevel@tonic-gate 	return (0);
920*7c478bd9Sstevel@tonic-gate }
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate /*
923*7c478bd9Sstevel@tonic-gate  * Get dynamic property for processor sets.
924*7c478bd9Sstevel@tonic-gate  * The only dynamic property currently implemented is "pset.load".
925*7c478bd9Sstevel@tonic-gate  */
926*7c478bd9Sstevel@tonic-gate int
927*7c478bd9Sstevel@tonic-gate pool_pset_propget(psetid_t psetid, char *name, nvlist_t *nvl)
928*7c478bd9Sstevel@tonic-gate {
929*7c478bd9Sstevel@tonic-gate 	cpupart_t *cpupart;
930*7c478bd9Sstevel@tonic-gate 	pool_pset_t *pset;
931*7c478bd9Sstevel@tonic-gate 	int ret = ESRCH;
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
936*7c478bd9Sstevel@tonic-gate 	pset = pool_lookup_pset_by_id(psetid);
937*7c478bd9Sstevel@tonic-gate 	cpupart = cpupart_find(psetid);
938*7c478bd9Sstevel@tonic-gate 	if (cpupart == NULL || pset == NULL) {
939*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
940*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
941*7c478bd9Sstevel@tonic-gate 	}
942*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, "pset.load") == 0)
943*7c478bd9Sstevel@tonic-gate 		ret = nvlist_add_uint64(nvl, "pset.load",
944*7c478bd9Sstevel@tonic-gate 		    (uint64_t)PSET_LOAD(cpupart->cp_hp_avenrun[0]));
945*7c478bd9Sstevel@tonic-gate 	else
946*7c478bd9Sstevel@tonic-gate 		ret = EINVAL;
947*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
948*7c478bd9Sstevel@tonic-gate 	return (ret);
949*7c478bd9Sstevel@tonic-gate }
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate /*
952*7c478bd9Sstevel@tonic-gate  * Get dynamic property for CPUs.
953*7c478bd9Sstevel@tonic-gate  * The only dynamic property currently implemented is "cpu.status".
954*7c478bd9Sstevel@tonic-gate  */
955*7c478bd9Sstevel@tonic-gate int
956*7c478bd9Sstevel@tonic-gate pool_cpu_propget(processorid_t cpuid, char *name, nvlist_t *nvl)
957*7c478bd9Sstevel@tonic-gate {
958*7c478bd9Sstevel@tonic-gate 	int ret = ESRCH;
959*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	ASSERT(pool_lock_held());
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
964*7c478bd9Sstevel@tonic-gate 	if ((cpu = cpu_get(cpuid)) == NULL) {
965*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
966*7c478bd9Sstevel@tonic-gate 		return (ESRCH);
967*7c478bd9Sstevel@tonic-gate 	}
968*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, "cpu.status") == 0) {
969*7c478bd9Sstevel@tonic-gate 		ret = nvlist_add_string(nvl, "cpu.status",
970*7c478bd9Sstevel@tonic-gate 		    (char *)cpu_get_state_str(cpu));
971*7c478bd9Sstevel@tonic-gate 	} else {
972*7c478bd9Sstevel@tonic-gate 		ret = EINVAL;
973*7c478bd9Sstevel@tonic-gate 	}
974*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
975*7c478bd9Sstevel@tonic-gate 	return (ret);
976*7c478bd9Sstevel@tonic-gate }
977