1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <limits.h>
29#include <pool.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <synch.h>
34#include <thread.h>
35
36#include <sys/loadavg.h>
37#include <sys/types.h>
38#include <sys/utsname.h>
39
40#include "dict.h"
41#include "pool_internal.h"
42#include "pool_impl.h"
43
44/*
45 * Atom structure, used to reference count string atoms.
46 */
47typedef struct {
48	char *a_string;				/* String atom */
49	uint_t a_count;				/* String reference count */
50} atom_t;
51
52/*
53 * The _internal_lock is used to lock the state of libpool during
54 * internal initialisation operations.
55 */
56mutex_t		_internal_lock;
57
58static int _libpool_debug = 0;			/* debugging messages */
59static dict_hdl_t *_pv_atoms;			/* pool_value_t atoms */
60static mutex_t _atom_lock;			/* atom table lock */
61static int _libpool_internal_initialised = PO_FALSE;
62
63/*
64 * Various useful constant strings which are often encountered
65 */
66const char *c_a_dtype = "a-dtype";
67const char *c_name = "name";
68const char *c_type = "type";
69const char *c_ref_id = "ref_id";
70const char *c_max_prop = "max";
71const char *c_min_prop = "min";
72const char *c_size_prop = "size";
73const char *c_sys_prop = "sys_id";
74
75/*
76 * prop_is_type() checks the supplied property and returns PO_TRUE if the
77 * property value is set for the property else PO_FALSE
78 */
79static int prop_is_type(int, const pool_prop_t *);
80static int resource_get_common(const pool_resource_t *, const char *,
81    uint64_t *);
82static int64_t elem_get_expected_int64(const pool_elem_t *, const char *);
83
84/*
85 * The following returns a malloc'ed string which must be free'd by the
86 * caller.
87 */
88static char *elem_get_expected_string(const pool_elem_t *, const char *);
89static int element_props_init(pool_prop_t *);
90
91/*
92 * Each element class/sub-class has a set of properties and behaviours
93 * which are used to create the element with appropriate property
94 * values and to ensure correct property manipulations. The details
95 * are all stored in the following arrays.
96 */
97
98static int elem_name_init(pool_prop_t *);
99static int elem_comment_init(pool_prop_t *);
100
101static int pool_importance_init(pool_prop_t *);
102static int pool_active_init(pool_prop_t *);
103
104static int res_max_init(pool_prop_t *);
105static int res_min_init(pool_prop_t *);
106static int res_size_init(pool_prop_t *);
107static int res_load_init(pool_prop_t *);
108
109static int pset_units_init(pool_prop_t *);
110
111static int cpu_status_init(pool_prop_t *);
112
113static int elem_no_set(pool_elem_t *, const pool_value_t *);
114static int elem_set_name(pool_elem_t *, const pool_value_t *);
115static int elem_get_type(const pool_elem_t *, pool_value_t *);
116static int elem_set_string(pool_elem_t *, const pool_value_t *);
117static int elem_set_bool(pool_elem_t *, const pool_value_t *);
118static int elem_set_uint(pool_elem_t *, const pool_value_t *);
119
120static int system_set_allocate(pool_elem_t *, const pool_value_t *);
121
122static int pool_set_scheduler(pool_elem_t *, const pool_value_t *);
123static int pool_set_active(pool_elem_t *, const pool_value_t *);
124
125static int res_set_max(pool_elem_t *, const pool_value_t *);
126static int res_set_min(pool_elem_t *, const pool_value_t *);
127
128static int cpu_set_status(pool_elem_t *, const pool_value_t *);
129
130static const char *pool_elem_class_name[] = {
131	"invalid",
132	"system",
133	"pool",
134	"component resource",
135	"aggregate resource",
136	"component"
137};
138
139/*
140 * This must be kept in sync with the pool_resource_elem_ctl array and
141 * the "enum pool_resource_elem_class" type.
142 */
143static const char *pool_resource_elem_class_name[] = {
144	"invalid",
145	"pset"
146};
147
148static const char *pool_component_elem_class_name[] = {
149	"invalid",
150	"cpu"
151};
152
153static pool_prop_t system_props[] = {
154	{ "system.name", POOL_VALUE_INITIALIZER, PP_STORED, NULL,
155	    { NULL, elem_set_name } },
156	{ "system.ref_id", POOL_VALUE_INITIALIZER,
157	    PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } },
158	{ "system.comment", POOL_VALUE_INITIALIZER, PP_STORED, NULL, NULL },
159	{ "system.version", POOL_VALUE_INITIALIZER,
160	    PP_STORED | PP_READ, NULL, NULL },
161	{ "system.bind-default", POOL_VALUE_INITIALIZER,
162	    PP_STORED, NULL, NULL },
163	{ "system.allocate-method", POOL_VALUE_INITIALIZER,
164	    PP_STORED | PP_OPTIONAL, NULL, { NULL, system_set_allocate } },
165	{ "system.poold.log-level", POOL_VALUE_INITIALIZER,
166	    PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } },
167	{ "system.poold.log-location", POOL_VALUE_INITIALIZER,
168	    PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } },
169	{ "system.poold.monitor-interval", POOL_VALUE_INITIALIZER,
170	    PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_uint } },
171	{ "system.poold.history-file", POOL_VALUE_INITIALIZER,
172	    PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } },
173	{ "system.poold.objectives", POOL_VALUE_INITIALIZER,
174	    PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } },
175	NULL
176};
177
178static pool_prop_t pool_props[] = {
179	{ "pool.sys_id", POOL_VALUE_INITIALIZER,
180	    PP_STORED | PP_READ, NULL, NULL },
181	{ "pool.name", POOL_VALUE_INITIALIZER,
182	    PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } },
183	{ "pool.res", POOL_VALUE_INITIALIZER,
184	    PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } },
185	{ "pool.ref_id", POOL_VALUE_INITIALIZER,
186	    PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } },
187	{ "pool.active", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT,
188	    pool_active_init, { NULL, pool_set_active } },
189	{ "pool.default", POOL_VALUE_INITIALIZER,
190	    PP_STORED | PP_READ, NULL, NULL },
191	{ "pool.scheduler", POOL_VALUE_INITIALIZER,
192	    PP_STORED | PP_OPTIONAL, NULL,
193	    { NULL, pool_set_scheduler } },
194	{ "pool.importance", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT,
195	    pool_importance_init, NULL },
196	{ "pool.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT,
197	    elem_comment_init, NULL },
198	NULL
199};
200
201static pool_prop_t pset_props[] = {
202	{ "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL,
203	    { elem_get_type, NULL }  },
204	{ "pset.sys_id", POOL_VALUE_INITIALIZER,
205	    PP_STORED | PP_READ, NULL, NULL },
206	{ "pset.name", POOL_VALUE_INITIALIZER,
207	    PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } },
208	{ "pset.ref_id", POOL_VALUE_INITIALIZER,
209	    PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } },
210	{ "pset.default", POOL_VALUE_INITIALIZER,
211	    PP_STORED | PP_READ, NULL, NULL },
212	{ "pset.min", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_min_init,
213	    { NULL, res_set_min } },
214	{ "pset.max", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_max_init,
215	    { NULL, res_set_max } },
216	{ "pset.units", POOL_VALUE_INITIALIZER,
217	    PP_STORED | PP_INIT, pset_units_init, NULL },
218	{ "pset.load", POOL_VALUE_INITIALIZER, PP_READ | PP_INIT,
219	    res_load_init, NULL },
220	{ "pset.size", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT | PP_READ,
221	    res_size_init, NULL },
222	{ "pset.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT,
223	    elem_comment_init, NULL },
224	{ "pset.poold.objectives", POOL_VALUE_INITIALIZER,
225	    PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } },
226	NULL
227};
228
229static pool_prop_t cpu_props[] = {
230	{ "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL,
231	    { elem_get_type, NULL }  },
232	{ "cpu.sys_id", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL,
233	    NULL },
234	{ "cpu.ref_id", POOL_VALUE_INITIALIZER,
235	    PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } },
236	{ "cpu.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT,
237	    elem_comment_init, NULL },
238	{ "cpu.status", POOL_VALUE_INITIALIZER, PP_INIT, cpu_status_init,
239	    { NULL, cpu_set_status } },
240	{ "cpu.pinned", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL,
241	    { NULL, elem_set_bool } },
242	NULL
243};
244
245static pool_prop_t *pool_elem_ctl[] = {
246	NULL,
247	system_props,
248	pool_props,
249	NULL,
250	NULL,
251	NULL
252};
253
254/*
255 * This must be kept in sync with the pool_resource_elem_class_name array and
256 * the "enum pool_resource_elem_class" type.
257 */
258static pool_prop_t *pool_resource_elem_ctl[] = {
259	NULL,
260	pset_props
261};
262
263static pool_prop_t *pool_component_elem_ctl[] = {
264	NULL,
265	cpu_props
266};
267
268static void
269atom_init(void)
270{
271	(void) mutex_lock(&_atom_lock);
272	/*
273	 * Initialize pool_value_t atom dictionary
274	 */
275	if (_pv_atoms == NULL)
276		if ((_pv_atoms = dict_new((int (*)(const void *, const void *))
277		    strcmp, (uint64_t (*)(const void *))hash_str)) == NULL)
278			abort();
279	(void) mutex_unlock(&_atom_lock);
280}
281
282/*
283 * Initializer, called when the library is initialized.
284 */
285void
286internal_init(void)
287{
288	(void) mutex_lock(&_internal_lock);
289	if (_libpool_internal_initialised == PO_TRUE) {
290		(void) mutex_unlock(&_internal_lock);
291		return;
292	}
293	atom_init();
294	/*
295	 * Initialize all available property arrays.
296	 */
297	if (element_props_init(system_props) == PO_FAIL)
298		abort();
299	if (element_props_init(pool_props) == PO_FAIL)
300		abort();
301	if (element_props_init(pset_props) == PO_FAIL)
302		abort();
303	if (element_props_init(cpu_props) == PO_FAIL)
304		abort();
305	_libpool_internal_initialised = PO_TRUE;
306	(void) mutex_unlock(&_internal_lock);
307
308}
309
310static int
311element_props_init(pool_prop_t *props)
312{
313	int i;
314
315	for (i = 0; props[i].pp_pname != NULL; i++) {
316		/*
317		 * Initialise each of the properties
318		 */
319		if (pool_value_set_name(&props[i].pp_value,
320		    props[i].pp_pname) != PO_SUCCESS) {
321			return (PO_FAIL);
322		}
323		if (props[i].pp_init &&
324		    props[i].pp_init(&props[i]) != PO_SUCCESS) {
325			return (PO_FAIL);
326		}
327	}
328	return (PO_SUCCESS);
329}
330
331
332/*
333 * These functions intialise the properties of this plugin. The only reason
334 * they exist is because the ability to perform the static initialisation of
335 * union members properly was only introduced in the C99 standard. i.e. if you
336 * could do {.f = 1.0} like in the proposed C99 standard then that would
337 * be the preferred way to do this as it keeps the data in the array and
338 * minimises the scope for errors. However, until that time these functions
339 * are the best way to minimise the scope for errors and to maximise
340 * maintainability.
341 *
342 * There is one function for each property, and the initial value for each
343 * property is hard-coded into each function.
344 */
345
346static int
347elem_name_init(pool_prop_t *prop)
348{
349	return (string_init(prop, "default"));
350}
351
352static int
353elem_comment_init(pool_prop_t *prop)
354{
355	return (string_init(prop, ""));
356}
357
358static int
359pool_importance_init(pool_prop_t *prop)
360{
361	return (int_init(prop, 1));
362}
363
364static int
365pool_active_init(pool_prop_t *prop)
366{
367	return (bool_init(prop, PO_TRUE));
368}
369
370static int
371res_max_init(pool_prop_t *prop)
372{
373	return (uint_init(prop, 0));
374}
375
376static int
377res_min_init(pool_prop_t *prop)
378{
379	return (uint_init(prop, 0));
380}
381
382static int
383res_size_init(pool_prop_t *prop)
384{
385	return (uint_init(prop, 0));
386}
387
388static int
389res_load_init(pool_prop_t *prop)
390{
391	return (uint_init(prop, 0));
392}
393
394static int
395pset_units_init(pool_prop_t *prop)
396{
397	return (string_init(prop, "population"));
398}
399
400static int
401cpu_status_init(pool_prop_t *prop)
402{
403	return (string_init(prop, PS_ONLINE));
404}
405
406/*
407 * Individual property manipulation routines for use by the generic
408 * get/put property routines
409 */
410
411/*
412 * Many properties cannot be modified. This function prevents property
413 * modification.
414 */
415/* ARGSUSED */
416static int
417elem_no_set(pool_elem_t *elem, const pool_value_t *pval)
418{
419	return (PO_FAIL);
420}
421
422/*
423 * Duplicate names for a pool or resource type are illegal.
424 */
425static int
426elem_set_name(pool_elem_t *elem, const pool_value_t *pval)
427{
428	const char *nm;
429	pool_t *pool;
430	pool_resource_t *res;
431
432	if (pool_value_get_string(pval, &nm) != PO_SUCCESS) {
433		return (PO_FAIL);
434	}
435	if (!is_valid_name(nm)) {
436		pool_seterror(POE_PUTPROP);
437		return (PO_FAIL);
438	}
439	switch (pool_elem_class(elem)) {
440	case PEC_SYSTEM:
441		break;
442	case PEC_POOL:
443		pool = pool_get_pool(TO_CONF(elem), nm);
444		if (pool != NULL && pool != pool_elem_pool(elem)) {
445			pool_seterror(POE_PUTPROP);
446			return (PO_FAIL);
447		}
448		break;
449	case PEC_RES_COMP:
450	case PEC_RES_AGG:
451		res = pool_get_resource(TO_CONF(elem),
452		    pool_elem_class_string(elem), nm);
453		if (res != NULL && res != pool_elem_res(elem)) {
454			pool_seterror(POE_PUTPROP);
455			return (PO_FAIL);
456		}
457		break;
458	default:
459		return (PO_FAIL);
460	}
461	return (PO_SUCCESS);
462}
463
464/*
465 * Ensure the type is a string.
466 */
467/* ARGSUSED */
468static int
469elem_set_string(pool_elem_t *elem, const pool_value_t *pval)
470{
471	if (pool_value_get_type(pval) == POC_STRING)
472		return (PO_SUCCESS);
473	else {
474		pool_seterror(POE_BADPARAM);
475		return (PO_FAIL);
476	}
477}
478
479/*
480 * Ensure the type is a boolean.
481 */
482/* ARGSUSED */
483static int
484elem_set_bool(pool_elem_t *elem, const pool_value_t *pval)
485{
486	if (pool_value_get_type(pval) == POC_BOOL)
487		return (PO_SUCCESS);
488	else {
489		pool_seterror(POE_BADPARAM);
490		return (PO_FAIL);
491	}
492}
493
494/*
495 * Ensure the type is an unsigned int.
496 */
497/* ARGSUSED */
498static int
499elem_set_uint(pool_elem_t *elem, const pool_value_t *pval)
500{
501	if (pool_value_get_type(pval) == POC_UINT)
502		return (PO_SUCCESS);
503	else {
504		pool_seterror(POE_BADPARAM);
505		return (PO_FAIL);
506	}
507}
508
509/* ARGSUSED */
510int
511system_set_allocate(pool_elem_t *elem, const pool_value_t *pval)
512{
513	const char *sval;
514
515	if (pool_value_get_string(pval, &sval) != PO_SUCCESS) {
516		pool_seterror(POE_PUTPROP);
517		return (PO_FAIL);
518	}
519	if (strcmp(POA_IMPORTANCE, sval) != 0 &&
520	    strcmp(POA_SURPLUS_TO_DEFAULT, sval) != 0) {
521			pool_seterror(POE_PUTPROP);
522			return (PO_FAIL);
523	}
524	return (PO_SUCCESS);
525}
526
527/* ARGSUSED */
528int
529pool_set_active(pool_elem_t *elem, const pool_value_t *pval)
530{
531	uchar_t bval;
532
533	if (pool_value_get_type(pval) != POC_BOOL) {
534		pool_seterror(POE_BADPARAM);
535		return (PO_FAIL);
536	}
537	(void) pool_value_get_bool(pval, &bval);
538	if (bval != 1) {
539		/*
540		 * "active" must be true on pools for
541		 * now.
542		 */
543		pool_seterror(POE_BADPARAM);
544		return (PO_FAIL);
545	}
546	return (PO_SUCCESS);
547}
548
549/* ARGSUSED */
550int
551pool_set_scheduler(pool_elem_t *elem, const pool_value_t *pval)
552{
553	pcinfo_t pcinfo;
554	const char *sched;
555
556	if (pool_value_get_string(pval, &sched) != 0) {
557		pool_seterror(POE_PUTPROP);
558		return (PO_FAIL);
559	}
560	(void) strncpy(pcinfo.pc_clname, sched, PC_CLNMSZ);
561	if (priocntl(0, 0, PC_GETCID, &pcinfo) == -1) {
562		pool_seterror(POE_PUTPROP);
563		return (PO_FAIL);
564	}
565	return (PO_SUCCESS);
566}
567
568static int
569res_set_max(pool_elem_t *elem, const pool_value_t *pval)
570{
571	uint64_t min, max;
572	pool_value_t val = POOL_VALUE_INITIALIZER;
573
574	/*
575	 * max must be a uint
576	 */
577	if (pool_value_get_uint64(pval, &max) != PO_SUCCESS) {
578		pool_seterror(POE_PUTPROP);
579		return (PO_FAIL);
580	}
581	/*
582	 * max can't be less than min (if it exists)
583	 */
584	if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL)
585		return (PO_SUCCESS);
586	if (pool_value_get_uint64(&val, &min) != PO_SUCCESS) {
587		pool_seterror(POE_PUTPROP);
588		return (PO_FAIL);
589	}
590	if (max < min) {
591		pool_seterror(POE_PUTPROP);
592		return (PO_FAIL);
593	}
594	/*
595	 * Ensure that changes to the max in a dynamic configuration
596	 * are still valid.
597	 */
598	if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) {
599		uint64_t oldmax;
600
601		if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) {
602			pool_seterror(POE_PUTPROP);
603			return (PO_FAIL);
604		}
605		if (pool_value_get_uint64(&val, &oldmax) != PO_SUCCESS) {
606			pool_seterror(POE_PUTPROP);
607			return (PO_FAIL);
608		}
609		if (max < oldmax) {
610			/*
611			 * Ensure that the modified total max is >= size
612			 * of all resources of this type
613			 */
614			return (pool_validate_resource(TO_CONF(elem),
615				pool_elem_class_string(elem), c_max_prop,
616				max - oldmax));
617		}
618	}
619	return (PO_SUCCESS);
620}
621
622static int
623res_set_min(pool_elem_t *elem, const pool_value_t *pval)
624{
625	uint64_t min, max;
626	pool_value_t val = POOL_VALUE_INITIALIZER;
627
628	/*
629	 * min must be a uint
630	 */
631	if (pool_value_get_uint64(pval, &min) != PO_SUCCESS) {
632		pool_seterror(POE_PUTPROP);
633		return (PO_FAIL);
634	}
635	/*
636	 * min can't be more than max (if it exists)
637	 */
638	if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL)
639		return (PO_SUCCESS);
640	if (pool_value_get_uint64(&val, &max) != PO_SUCCESS) {
641		pool_seterror(POE_PUTPROP);
642		return (PO_FAIL);
643	}
644	if (min > max) {
645		pool_seterror(POE_PUTPROP);
646		return (PO_FAIL);
647	}
648
649	switch (pool_resource_elem_class(elem)) {
650	case PREC_PSET:
651		if (resource_is_default(pool_elem_res(elem))) {
652			if (min < 1) {
653				pool_seterror(POE_PUTPROP);
654				return (PO_FAIL);
655			}
656		}
657		break;
658	default:
659		break;
660	}
661
662	/*
663	 * Ensure that changes to the min in a dynamic configuration
664	 * are still valid.
665	 */
666	if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) {
667		uint64_t oldmin;
668
669		if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) {
670			pool_seterror(POE_PUTPROP);
671			return (PO_FAIL);
672		}
673		if (pool_value_get_uint64(&val, &oldmin) != PO_SUCCESS) {
674			pool_seterror(POE_PUTPROP);
675			return (PO_FAIL);
676		}
677		if (min > oldmin) {
678			/*
679			 * Ensure that the modified total min is <= size
680			 * of all resources of this type
681			 */
682			return (pool_validate_resource(TO_CONF(elem),
683				pool_elem_class_string(elem), c_min_prop,
684				min - oldmin));
685		}
686	}
687	return (PO_SUCCESS);
688}
689
690/* ARGSUSED */
691int
692cpu_set_status(pool_elem_t *elem, const pool_value_t *pval)
693{
694	const char *status;
695
696	if (pool_value_get_string(pval, &status) != 0) {
697		pool_seterror(POE_PUTPROP);
698		return (PO_FAIL);
699	}
700
701	if (strcmp(PS_ONLINE, status) != 0 &&
702	    strcmp(PS_OFFLINE, status) != 0 &&
703	    strcmp(PS_NOINTR, status) != 0 &&
704	    strcmp(PS_SPARE, status) != 0 &&
705	    strcmp(PS_FAULTED, status) != 0) {
706		pool_seterror(POE_PUTPROP);
707		return (PO_FAIL);
708	}
709	return (PO_SUCCESS);
710}
711
712static int
713elem_get_type(const pool_elem_t *elem, pool_value_t *pval)
714{
715	if (pool_value_set_string(pval, pool_elem_class_string(elem)) ==
716	    PO_FAIL)
717		return (PO_FAIL);
718	return (PO_SUCCESS);
719}
720
721/*
722 * More general utilities
723 */
724/*
725 * Is the supplied configuration the dynamic configuration
726 * Return: PO_TRUE/PO_FALSE
727 */
728int
729conf_is_dynamic(const pool_conf_t *conf)
730{
731	if (strcmp(pool_conf_location(conf), pool_dynamic_location()) == 0)
732		return (PO_TRUE);
733	return (PO_FALSE);
734}
735
736/*
737 * uint_init() initialises the value of the supplied property with the
738 * supplied value.
739 * Returns PO_SUCCESS
740 */
741int
742uint_init(pool_prop_t *prop, uint64_t val)
743{
744	pool_value_set_uint64(&prop->pp_value, val);
745	return (PO_SUCCESS);
746}
747
748/*
749 * int_init() initialises the value of the supplied property with the
750 * supplied value.
751 * Returns PO_SUCCESS
752 */
753int
754int_init(pool_prop_t *prop, int64_t val)
755{
756	pool_value_set_int64(&prop->pp_value, val);
757	return (PO_SUCCESS);
758}
759
760/*
761 * double_init() initialises the value of the supplied property with the
762 * supplied value.
763 * Returns PO_SUCCESS
764 */
765int
766double_init(pool_prop_t *prop, double val)
767{
768	pool_value_set_double(&prop->pp_value, val);
769	return (PO_SUCCESS);
770}
771
772/*
773 * bool_init() initialises the value of the supplied property with the
774 * supplied value.
775 * Returns PO_SUCCESS
776 */
777int
778bool_init(pool_prop_t *prop, uchar_t val)
779{
780	pool_value_set_bool(&prop->pp_value, val);
781	return (PO_SUCCESS);
782}
783
784/*
785 * string_init() initialises the value of the supplied property with the
786 * supplied value.
787 * Returns PO_SUCCESS/PO_FAIL
788 */
789int
790string_init(pool_prop_t *prop, const char *val)
791{
792	return (pool_value_set_string(&prop->pp_value, val));
793}
794
795/*
796 * pool_get_provider_count() returns the count of registered providers.
797 *
798 * Returns count of registered providers
799 */
800uint_t
801pool_get_provider_count(void)
802{
803	uint_t count = 0;
804	int i;
805
806	for (i = 0; i < sizeof (pool_resource_elem_ctl) /
807	    sizeof (pool_resource_elem_ctl[0]); i++) {
808		if (pool_resource_elem_ctl[i] != NULL)
809			count++;
810	}
811	return (count);
812}
813
814/*
815 * Return all the props for a specified provider
816 */
817const pool_prop_t *
818provider_get_props(const pool_elem_t *elem)
819{
820	const pool_prop_t *prop_list = NULL;
821	pool_elem_class_t elem_class = pool_elem_class(elem);
822
823	switch (elem_class) {
824	case PEC_SYSTEM:
825	case PEC_POOL:
826		prop_list = pool_elem_ctl[elem_class];
827		break;
828	case PEC_RES_AGG:
829	case PEC_RES_COMP:
830		prop_list = pool_resource_elem_ctl
831		    [pool_resource_elem_class(elem)];
832		break;
833	case PEC_COMP:
834		prop_list = pool_component_elem_ctl
835		    [pool_component_elem_class(elem)];
836		break;
837	}
838	return (prop_list);
839}
840
841/*
842 * provider_get_prop() return the pool_prop_t structure which
843 * describes the supplied property name for the supplied provider.
844 *
845 * Returns the property description or NULL if it doesn't exist.
846 */
847const pool_prop_t *
848provider_get_prop(const pool_elem_t *elem, const char *name)
849{
850	int i;
851	const pool_prop_t *prop_list;
852
853	if ((prop_list = provider_get_props(elem)) == NULL)
854		return (NULL);
855
856	for (i = 0; prop_list[i].pp_pname != NULL; i++) {
857		if (strcmp(name, prop_list[i].pp_pname) == 0) {
858			return (&prop_list[i]);
859		}
860	}
861	return (NULL);
862}
863
864/*
865 * prop_is_type() checks the supplied property and returns PO_TRUE if the
866 * property value is 1 else PO_FALSE
867 */
868static int
869prop_is_type(int prop_type, const pool_prop_t *prop)
870{
871	return ((prop->pp_perms & prop_type) ? PO_TRUE : PO_FALSE);
872}
873
874/*
875 * prop_is_stored() returns PO_TRUE if the property is stored in the backing
876 * configuration and PO_FALSE else.
877 */
878int
879prop_is_stored(const pool_prop_t *prop)
880{
881	return (prop_is_type(PP_STORED, prop));
882}
883
884/*
885 * prop_is_readonly() returns PO_TRUE if the property is a read-only property
886 * and PO_FALSE else.
887 */
888int
889prop_is_readonly(const pool_prop_t *prop)
890{
891	return (prop_is_type(PP_READ, prop));
892}
893
894/*
895 * prop_is_init() returns PO_TRUE if the property should be
896 * initialised when an element of this type is created and PO_FALSE
897 * else.
898 */
899int
900prop_is_init(const pool_prop_t *prop)
901{
902	return (prop_is_type(PP_INIT, prop));
903}
904
905/*
906 * prop_is_hidden() returns PO_TRUE if the property should be hidden
907 * from access by the external property access mechanisms.
908 */
909int
910prop_is_hidden(const pool_prop_t *prop)
911{
912	return (prop_is_type(PP_HIDDEN, prop));
913}
914
915/*
916 * prop_is_optional() returns PO_TRUE if the property is optional and
917 * can be removed by external property access mechanisms.
918 */
919int
920prop_is_optional(const pool_prop_t *prop)
921{
922	return (prop_is_type(PP_OPTIONAL, prop));
923}
924
925int
926cpu_is_requested(pool_component_t *component)
927{
928	pool_value_t val = POOL_VALUE_INITIALIZER;
929	uchar_t requested;
930
931	if (pool_get_property(TO_CONF(TO_ELEM(component)), TO_ELEM(component),
932	    "cpu.requested", &val) != POC_BOOL) {
933		return (PO_FALSE);
934	}
935	if (pool_value_get_bool(&val, &requested) != PO_SUCCESS) {
936		return (PO_FALSE);
937	}
938	return ((int)requested);
939}
940
941/*
942 * Common code for various resource get functions
943 */
944static int
945resource_get_common(const pool_resource_t *res, const char *name,
946    uint64_t *uval)
947{
948	pool_value_t val = POOL_VALUE_INITIALIZER;
949	pool_value_class_t pvc;
950	int retval = PO_SUCCESS;
951
952	pvc = pool_get_ns_property(TO_ELEM(res), name, &val);
953	if (pvc == POC_INVAL) {
954		*uval = 0;
955#ifdef DEBUG
956		dprintf("can't retrieve %s\n");
957		pool_elem_dprintf(TO_ELEM(res));
958#endif	/* DEBUG */
959	} else if (pvc == POC_UINT) {
960		retval = pool_value_get_uint64(&val, uval);
961	}
962	return (retval);
963}
964
965/*
966 * resource_get_size() updates size with the size of the supplied resource.
967 *
968 * Returns PO_SUCCESS/PO_FAIL
969 */
970int
971resource_get_size(const pool_resource_t *res, uint64_t *size)
972{
973	return (resource_get_common(res, c_size_prop, size));
974}
975
976/*
977 * resource_get_pinned() updates pinned with the size of the
978 * pinned part of a supplied resource. Resource is not available for
979 * allocation if it is marked as "pinned".
980 *
981 * Returns PO_SUCCESS/PO_FAIL
982 */
983int
984resource_get_pinned(const pool_resource_t *res, uint64_t *pinned)
985{
986	pool_value_t *props[] = { NULL, NULL };
987	pool_value_t val = POOL_VALUE_INITIALIZER;
988	pool_component_t **cs = NULL;
989	uint_t ncompelem;
990
991	props[0] = &val;
992
993	pool_value_set_bool(props[0], PO_TRUE);
994	if (pool_value_set_name(props[0], "cpu.pinned") != PO_SUCCESS)
995		return (PO_FAIL);
996
997	if ((cs = pool_query_resource_components(TO_CONF(TO_ELEM(res)), res,
998	    &ncompelem, props)) != NULL) {
999		*pinned = ncompelem;
1000		free(cs);
1001	} else
1002		*pinned = 0;
1003	return (PO_SUCCESS);
1004}
1005
1006/*
1007 * resource_get_min() updates min with the minimum size of the supplied
1008 * resource.
1009 *
1010 * Returns PO_SUCCESS/PO_FAIL
1011 */
1012int
1013resource_get_min(const pool_resource_t *res, uint64_t *min)
1014{
1015	return (resource_get_common(res, c_min_prop, min));
1016}
1017
1018/*
1019 * resource_get_max() updates max with the maximum size of the supplied
1020 * resource.
1021 *
1022 * Returns PO_SUCCESS/PO_FAIL
1023 */
1024int
1025resource_get_max(const pool_resource_t *res, uint64_t *max)
1026{
1027	return (resource_get_common(res, c_max_prop, max));
1028}
1029
1030/*
1031 * TODO: This is pset specific
1032 *
1033 * get_default_resource() returns the default resource for type of the supplied
1034 * resource.
1035 *
1036 * Returns A pointer to the default resource of the same type as the supplied
1037 * resource.
1038 */
1039const pool_resource_t *
1040get_default_resource(const pool_resource_t *res)
1041{
1042	return (resource_by_sysid(TO_CONF(TO_ELEM(res)), PS_NONE,
1043	    pool_elem_class_string(TO_ELEM(res))));
1044}
1045
1046/*
1047 * resource_is_default() returns 1 if the supplied resource is the default
1048 * resource for it's type.
1049 */
1050int
1051resource_is_default(const pool_resource_t *res)
1052{
1053
1054	return (get_default_resource(res) == res);
1055}
1056
1057/*
1058 * resource_is_system() determines if the resource is a system resource.
1059 */
1060int
1061resource_is_system(const pool_resource_t *res)
1062{
1063	return (res->pr_is_system(res));
1064
1065}
1066
1067/*
1068 * resource_can_associate() determines if it is possible to associate
1069 * with the supplied resource.
1070 */
1071int
1072resource_can_associate(const pool_resource_t *res)
1073{
1074	return (res->pr_can_associate(res));
1075}
1076
1077/*
1078 * Common code to get an int64 property.
1079 * Unfortunately (-1) is a valid psetid, so we'll return (-2) in case of
1080 * error.
1081 */
1082static int64_t
1083elem_get_expected_int64(const pool_elem_t *elem, const char *name)
1084{
1085	int64_t val64;
1086	pool_value_t val = POOL_VALUE_INITIALIZER;
1087
1088	if (pool_get_ns_property(elem, name, &val) != POC_INT) {
1089		return (POOL_SYSID_BAD);
1090	}
1091	(void) pool_value_get_int64(&val, &val64);
1092
1093	return (val64);
1094}
1095
1096/*
1097 * The following returns a malloc'ed string which must be free'd by the
1098 * caller.
1099 */
1100static char *
1101elem_get_expected_string(const pool_elem_t *elem, const char *name)
1102{
1103	pool_value_t val = POOL_VALUE_INITIALIZER;
1104	char *retval;
1105
1106	if (pool_get_ns_property(elem, name, &val) != POC_STRING) {
1107		return (NULL);
1108	}
1109	(void) pool_value_get_string(&val, (const char **)&retval);
1110	retval = strdup(retval);
1111	return (retval);
1112}
1113
1114/*
1115 * elem_get_sysid() returns the sys_id for the supplied elem.
1116 */
1117id_t
1118elem_get_sysid(const pool_elem_t *elem)
1119{
1120	return ((id_t)elem_get_expected_int64(elem, c_sys_prop));
1121}
1122
1123/*
1124 * elem_get_name() returns the name for the supplied elem. Note that
1125 * it is the caller's responsibility to free this memory.
1126 */
1127char *
1128elem_get_name(const pool_elem_t *elem)
1129{
1130	return (elem_get_expected_string(elem, c_name));
1131}
1132
1133/*
1134 * elem_is_default() returns 1 if the supplied elem is the default
1135 * elem for it's type.
1136 */
1137int
1138elem_is_default(const pool_elem_t *res)
1139{
1140
1141	return (get_default_elem(res) == res);
1142}
1143
1144/*
1145 * Return B_TRUE if the element has the 'temporary' property set.
1146 */
1147boolean_t
1148elem_is_tmp(const pool_elem_t *elem)
1149{
1150	pool_value_t val = POOL_VALUE_INITIALIZER;
1151	uchar_t bval;
1152
1153	if (pool_get_ns_property(elem, "temporary", &val) != POC_BOOL)
1154		return (B_FALSE);
1155
1156	(void) pool_value_get_bool(&val, &bval);
1157
1158	return (bval != 0);
1159}
1160
1161/*
1162 * get_default_elem() returns the default elem for type of the supplied
1163 * elem.
1164 *
1165 * Returns A pointer to the default elem of the same type as the
1166 * supplied elem or NULL on error. Trying to access the default elem
1167 * for a type of element which doesn't support the notion of default
1168 * is an error.
1169 */
1170const pool_elem_t *
1171get_default_elem(const pool_elem_t *pe)
1172{
1173	pool_result_set_t *rs;
1174	pool_value_t *props[] = { NULL, NULL };
1175	pool_value_t val = POOL_VALUE_INITIALIZER;
1176	char_buf_t *cb;
1177	const pool_elem_t *pe_default;
1178
1179	props[0] = &val;
1180	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1181		return (NULL);
1182	}
1183	if (set_char_buf(cb, "%s.default", pool_elem_class_string(pe)) !=
1184	    PO_SUCCESS) {
1185		free_char_buf(cb);
1186		return (NULL);
1187	}
1188	if (pool_value_set_name(props[0], cb->cb_buf) != PO_SUCCESS) {
1189		free_char_buf(cb);
1190		return (NULL);
1191	}
1192	free_char_buf(cb);
1193	pool_value_set_bool(props[0], PO_TRUE);
1194
1195	if ((rs = pool_exec_query(TO_CONF(pe), NULL, NULL,
1196	    PEC_QRY_ELEM(pe), props)) == NULL) {
1197		pool_seterror(POE_INVALID_CONF);
1198		return (NULL);
1199	}
1200	if (pool_rs_count(rs) != 1) {
1201		(void) pool_rs_close(rs);
1202		pool_seterror(POE_INVALID_CONF);
1203		return (NULL);
1204	}
1205
1206	pe_default = rs->prs_next(rs);
1207	(void) pool_rs_close(rs);
1208	return (pe_default);
1209}
1210
1211/*
1212 * is_a_known_prefix() determines if the supplied prop_name is a known
1213 * name for the supplied class.
1214 *
1215 * Returns a pointer to the prefix if it is found or NULL
1216 */
1217const char *
1218is_a_known_prefix(pool_elem_class_t class, const char *prop_name)
1219{
1220	int i;
1221	int len;
1222
1223	switch (class) {
1224	case PEC_SYSTEM:
1225	case PEC_POOL:
1226		len = strlen(pool_elem_class_name[class]);
1227		if (strncmp(prop_name, pool_elem_class_name[class], len) == 0 &&
1228		    prop_name[len] == '.' || strcmp(prop_name, c_type) == 0)
1229			return (pool_elem_class_name[class]);
1230		break;
1231	case PEC_RES_COMP:
1232	case PEC_RES_AGG:
1233		for (i = 0; i < sizeof (pool_resource_elem_class_name) /
1234		    sizeof (pool_resource_elem_class_name[0]); i++) {
1235			len = strlen(pool_resource_elem_class_name[i]);
1236			if (strncmp(prop_name,
1237			    pool_resource_elem_class_name[i], len) == 0 &&
1238			    prop_name[len] == '.' ||
1239			    strcmp(prop_name, c_type) == 0)
1240				return (pool_resource_elem_class_name[i]);
1241		}
1242		break;
1243	case PEC_COMP:
1244		for (i = 0; i < sizeof (pool_component_elem_class_name) /
1245		    sizeof (pool_component_elem_class_name[0]); i++) {
1246			len = strlen(pool_component_elem_class_name[i]);
1247			if (strncmp(prop_name,
1248			    pool_component_elem_class_name[i], len) == 0 &&
1249			    prop_name[len] == '.' ||
1250			    strcmp(prop_name, c_type) == 0)
1251				return (pool_component_elem_class_name[i]);
1252		}
1253		break;
1254	default:
1255		break;
1256	}
1257	return (NULL);
1258}
1259
1260
1261const char *
1262pool_elem_class_string(const pool_elem_t *pe)
1263{
1264	switch (pool_elem_class(pe)) {
1265	case PEC_SYSTEM:
1266	case PEC_POOL:
1267		return (pool_elem_class_name[pool_elem_class(pe)]);
1268	case PEC_RES_COMP:
1269	case PEC_RES_AGG:
1270		return (pool_resource_elem_class_name
1271		    [pool_resource_elem_class(pe)]);
1272	case PEC_COMP:
1273		return (pool_component_elem_class_name
1274		    [pool_component_elem_class(pe)]);
1275	default:
1276		return (pool_elem_class_name[PEC_INVALID]);
1277	}
1278}
1279
1280const char *
1281pool_resource_type_string(pool_resource_elem_class_t type)
1282{
1283	return (pool_resource_elem_class_name[type]);
1284}
1285
1286const char *
1287pool_component_type_string(pool_component_elem_class_t type)
1288{
1289	return (pool_component_elem_class_name[type]);
1290}
1291
1292/*
1293 * resource_by_sysid() finds a resource from it's supplied sysid and type.
1294 *
1295 * Returns a pointer to the resource or NULL if it doesn't exist.
1296 */
1297pool_resource_t *
1298resource_by_sysid(const pool_conf_t *conf, id_t sysid, const char *type)
1299{
1300	pool_value_t *props[] = { NULL, NULL, NULL };
1301	pool_resource_t **resources = NULL;
1302	pool_resource_t *retval = NULL;
1303	uint_t nelem;
1304	char_buf_t *cb;
1305	pool_value_t val0 = POOL_VALUE_INITIALIZER;
1306	pool_value_t val1 = POOL_VALUE_INITIALIZER;
1307
1308	props[0] = &val0;
1309	props[1] = &val1;
1310
1311	if (pool_value_set_string(props[0], type) != PO_SUCCESS ||
1312	    pool_value_set_name(props[0], c_type) != PO_SUCCESS)
1313		return (NULL);
1314
1315	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1316		return (NULL);
1317	}
1318	if (set_char_buf(cb, "%s.sys_id", type) != PO_SUCCESS) {
1319		free_char_buf(cb);
1320		return (NULL);
1321	}
1322	if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) {
1323		free_char_buf(cb);
1324		return (NULL);
1325	}
1326	free_char_buf(cb);
1327	pool_value_set_int64(props[1], sysid);
1328
1329	resources = pool_query_resources(conf, &nelem, props);
1330
1331	if (resources != NULL) {
1332		retval = resources[0];
1333		free(resources);
1334	}
1335	return (retval);
1336}
1337
1338pool_elem_class_t
1339pool_elem_class_from_string(const char *type)
1340{
1341	int i;
1342
1343	for (i = 0; i < sizeof (pool_elem_class_name) /
1344	    sizeof (pool_elem_class_name[0]); i++) {
1345		if (strcmp(pool_elem_class_name[i], type) == 0)
1346			break;
1347	}
1348	if (i == sizeof (pool_elem_class_name) /
1349	    sizeof (pool_elem_class_name[0]))
1350		return (PEC_INVALID);
1351	return ((pool_elem_class_t)i);
1352}
1353
1354pool_resource_elem_class_t
1355pool_resource_elem_class_from_string(const char *type)
1356{
1357	int i;
1358
1359	for (i = 0; i < sizeof (pool_resource_elem_class_name) /
1360	    sizeof (pool_resource_elem_class_name[0]); i++) {
1361		if (strcmp(pool_resource_elem_class_name[i], type) == 0)
1362			break;
1363	}
1364	if (i == sizeof (pool_resource_elem_class_name) /
1365	    sizeof (pool_resource_elem_class_name[0]))
1366		return (PREC_INVALID);
1367	return ((pool_resource_elem_class_t)i);
1368}
1369
1370pool_component_elem_class_t
1371pool_component_elem_class_from_string(const char *type)
1372{
1373	int i;
1374
1375	for (i = 0; i < sizeof (pool_component_elem_class_name) /
1376	    sizeof (pool_component_elem_class_name[0]); i++) {
1377		if (strcmp(pool_component_elem_class_name[i], type) == 0)
1378			break;
1379	}
1380	if (i == sizeof (pool_component_elem_class_name) /
1381	    sizeof (pool_component_elem_class_name[0]))
1382		return (PCEC_INVALID);
1383	return ((pool_component_elem_class_t)i);
1384}
1385
1386/*
1387 * pool_resource_type_list() populates the supplied array of pointers
1388 * with the names of the available resource types on this system.
1389 */
1390int
1391pool_resource_type_list(const char **types, uint_t *numtypes)
1392{
1393	int i, j;
1394	uint_t maxnum = *numtypes;
1395
1396	*numtypes = pool_get_provider_count();
1397
1398	if (types) {
1399		for (i = 0, j = 0; i < sizeof (pool_resource_elem_ctl) /
1400		    sizeof (pool_resource_elem_ctl[0]) && j < maxnum; i++) {
1401			if (pool_resource_elem_ctl[i] != NULL)
1402				types[j++] = pool_resource_elem_class_name[i];
1403		}
1404	}
1405	return (PO_SUCCESS);
1406}
1407
1408/*
1409 * Return the system element for the supplied conf.
1410 * NULL is returned if an error is detected and the error code is updated
1411 * to indicate the cause of the error.
1412 */
1413pool_system_t *
1414pool_conf_system(const pool_conf_t *conf)
1415{
1416	pool_elem_t *system;
1417	pool_result_set_t *rs;
1418
1419	if ((rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_SYSTEM, NULL)) ==
1420	    NULL) {
1421		pool_seterror(POE_INVALID_CONF);
1422		return (NULL);
1423	}
1424	/* There should only be one system record */
1425	if (pool_rs_count(rs) != 1) {
1426		pool_seterror(POE_INVALID_CONF);
1427		(void) pool_rs_close(rs);
1428		return (NULL);
1429	}
1430	system = rs->prs_next(rs);
1431	(void) pool_rs_close(rs);
1432	return (pool_elem_system(system));
1433}
1434
1435pool_system_t *
1436pool_elem_system(const pool_elem_t *pe)
1437{
1438	if (pe->pe_class != PEC_SYSTEM) {
1439		pool_seterror(POE_BADPARAM);
1440		return (NULL);
1441	}
1442	return ((pool_system_t *)pe);
1443}
1444
1445pool_t *
1446pool_elem_pool(const pool_elem_t *pe)
1447{
1448	if (pe->pe_class != PEC_POOL) {
1449		pool_seterror(POE_BADPARAM);
1450		return (NULL);
1451	}
1452	return ((pool_t *)pe);
1453}
1454
1455pool_resource_t *
1456pool_elem_res(const pool_elem_t *pe)
1457{
1458	if (pe->pe_class != PEC_RES_COMP &&
1459	    pool_elem_class(pe) != PEC_RES_AGG) {
1460		pool_seterror(POE_BADPARAM);
1461		return (NULL);
1462	}
1463	return ((pool_resource_t *)pe);
1464}
1465
1466pool_component_t *
1467pool_elem_comp(const pool_elem_t *pe)
1468{
1469	if (pe->pe_class != PEC_COMP) {
1470		pool_seterror(POE_BADPARAM);
1471		return (NULL);
1472	}
1473	return ((pool_component_t *)pe);
1474}
1475
1476/*
1477 * qsort_elem_compare() is used for qsort elemement comparison.
1478 *
1479 * Returns see qsort(3c)
1480 */
1481int
1482qsort_elem_compare(const void *a, const void *b)
1483{
1484	const pool_elem_t *e1 = *(const pool_elem_t **)a;
1485	const pool_elem_t *e2 = *(const pool_elem_t **)b;
1486
1487	/*
1488	 * Special case for handling name changes on default elements
1489	 * If both elements are default elements then always return 0
1490	 */
1491	if (pool_elem_same_class(e1, e2) == PO_TRUE &&
1492	    (elem_is_default(e1) && elem_is_default(e2)))
1493			return (0);
1494	else
1495		return (pool_elem_compare_name(e1, e2));
1496}
1497
1498/*
1499 * Dynamic character buffers.
1500 */
1501
1502/*
1503 * Resize the supplied character buffer to the new size.
1504 */
1505static int
1506resize_char_buf(char_buf_t *cb, size_t size)
1507{
1508	char *re_cb = NULL;
1509
1510	if ((re_cb = realloc(cb->cb_buf, size)) == NULL) {
1511		pool_seterror(POE_SYSTEM);
1512		return (PO_FAIL);
1513	}
1514	/* If inital allocation, make sure buffer is zeroed */
1515	if (cb->cb_buf == NULL)
1516		(void) memset(re_cb, 0, sizeof (re_cb));
1517	/* If resized smaller, make sure buffer NULL terminated */
1518	if (size < cb->cb_size)
1519		re_cb[size] = 0;
1520	cb->cb_buf = re_cb;
1521	cb->cb_size = size;
1522	return (PO_SUCCESS);
1523}
1524
1525/*
1526 * Allocate a new char_buf_t structure. If there isn't enough memory, return
1527 * NULL. Initialise the new char_buf_t to 0 and then call resize_char_buf
1528 * to initialise the character buffer. Return a pointer to the new
1529 * char_buf_t if the operation succeeds.
1530 */
1531char_buf_t *
1532alloc_char_buf(size_t size)
1533{
1534	char_buf_t *cb;
1535
1536	if ((cb = malloc(sizeof (char_buf_t))) == NULL) {
1537		pool_seterror(POE_SYSTEM);
1538		return (NULL);
1539	}
1540	(void) memset(cb, 0, sizeof (char_buf_t));
1541
1542	if (resize_char_buf(cb, size + 1) == PO_FAIL) {
1543		free(cb);
1544		return (NULL);
1545	}
1546	return (cb);
1547}
1548
1549/*
1550 * Free the character buffer and then free the char_buf_t.
1551 */
1552void
1553free_char_buf(char_buf_t *cb)
1554{
1555	free((void *)cb->cb_buf);
1556	free(cb);
1557}
1558
1559/*
1560 * Set the character buffer to the supplied data. The user supplies a printf
1561 * like format string and then an appropriate number of parameters for the
1562 * specified format. The character buffer is automatically resized to fit
1563 * the data as determined by resize_char_buf.
1564 */
1565/*PRINTFLIKE2*/
1566int
1567set_char_buf(char_buf_t *cb, const char *fmt, ...)
1568{
1569	va_list ap;
1570	int new_size;
1571
1572	va_start(ap, fmt);
1573	if ((new_size = vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap)) >=
1574	    cb->cb_size) {
1575		if (resize_char_buf(cb, new_size + 1) != PO_SUCCESS) {
1576			pool_seterror(POE_SYSTEM);
1577			return (PO_FAIL);
1578		}
1579		(void) vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap);
1580	}
1581	va_end(ap);
1582	return (PO_SUCCESS);
1583}
1584
1585/*
1586 * Append the supplied data to the character buffer. The user supplies a printf
1587 * like format string and then an appropriate number of parameters for the
1588 * specified format. The character buffer is automatically resized to fit
1589 * the data as determined by resize_char_buf.
1590 */
1591/*PRINTFLIKE2*/
1592int
1593append_char_buf(char_buf_t *cb, const char *fmt, ...)
1594{
1595	va_list ap;
1596	int new_len;
1597	char size_buf[1];
1598	int old_len = 0;
1599
1600	if (cb->cb_buf != NULL)
1601		old_len = strlen(cb->cb_buf);
1602	va_start(ap, fmt);
1603	new_len = vsnprintf(size_buf, sizeof (size_buf), fmt, ap);
1604	if (new_len + old_len >= cb->cb_size) {
1605		if (resize_char_buf(cb, old_len + new_len + 1) !=
1606		    PO_SUCCESS) {
1607			pool_seterror(POE_SYSTEM);
1608			return (PO_FAIL);
1609		}
1610	}
1611	/*
1612	 * Resized the buffer to the right size, now append the new data
1613	 */
1614	(void) vsnprintf(&cb->cb_buf[old_len], cb->cb_size - old_len, fmt, ap);
1615	va_end(ap);
1616	return (PO_SUCCESS);
1617}
1618
1619/*
1620 * Return the class for the supplied elem.
1621 * If the return is PEC_INVALID, the error code will be set to reflect cause.
1622 */
1623pool_elem_class_t
1624pool_elem_class(const pool_elem_t *elem)
1625{
1626	return (elem->pe_class);
1627}
1628
1629
1630/*
1631 * Return the resource class for the supplied elem.
1632 */
1633pool_resource_elem_class_t
1634pool_resource_elem_class(const pool_elem_t *elem)
1635{
1636	return (elem->pe_resource_class);
1637}
1638
1639/*
1640 * Return the component class for the supplied elem.
1641 */
1642pool_component_elem_class_t
1643pool_component_elem_class(const pool_elem_t *elem)
1644{
1645	return (elem->pe_component_class);
1646}
1647
1648pool_elem_t *
1649pool_get_pair(const pool_elem_t *pe)
1650{
1651	return (pe->pe_pair);
1652}
1653
1654void
1655pool_set_pair(pool_elem_t *pe1, pool_elem_t *pe2)
1656{
1657	pe1->pe_pair = pe2;
1658}
1659
1660int
1661pool_validate_resource(const pool_conf_t *conf, const char *type,
1662    const char *prop, int64_t delta)
1663{
1664	pool_conf_t *dyn;
1665	uint_t nelem;
1666	uint64_t available, required, uval;
1667	int i;
1668	pool_resource_t **rl;
1669	pool_value_t val = POOL_VALUE_INITIALIZER;
1670	pool_value_t val1 = POOL_VALUE_INITIALIZER;
1671	pool_value_t *pvals[] = { NULL, NULL };
1672
1673	if (strcmp(prop, c_min_prop) && strcmp(prop, c_max_prop)) {
1674		pool_seterror(POE_BADPARAM);
1675		return (PO_FAIL);
1676	}
1677
1678	pvals[0] = &val;
1679	(void) pool_value_set_string(&val, type);
1680	(void) pool_value_set_name(&val, c_type);
1681
1682	/*
1683	 * Check that there are available resources on this
1684	 * system for this configuration to be applied. Find
1685	 * each resource type and then find all resources of
1686	 * each type and total ".min". Find all available
1687	 * resources and ensure >= total min.
1688	 */
1689
1690	available = 0;
1691	required = delta;
1692
1693	if ((rl = (pool_query_resources(conf, &nelem, pvals))) == NULL)
1694		return (PO_FAIL);
1695
1696	for (i = 0; i < nelem; i++) {
1697		if (pool_get_ns_property(TO_ELEM(rl[i]), prop,
1698		    &val1) == POC_INVAL ||
1699		    pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) {
1700			free(rl);
1701			return (PO_FAIL);
1702		}
1703		/*
1704		 * Watch out for overflow
1705		 */
1706		if (required + uval < required) {
1707			required = UINT64_MAX;
1708			break;
1709		} else
1710			required += uval;
1711	}
1712
1713	if (conf_is_dynamic(conf) == PO_TRUE) {
1714		dyn = (pool_conf_t *)conf;
1715	} else {
1716		free(rl);
1717		if ((dyn = pool_conf_alloc()) == NULL)
1718			return (PO_FAIL);
1719		if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDONLY) !=
1720		PO_SUCCESS) {
1721			pool_conf_free(dyn);
1722			return (PO_FAIL);
1723		}
1724		if ((rl = (pool_query_resources(dyn, &nelem, pvals))) ==
1725		    NULL) {
1726			(void) pool_conf_close(dyn);
1727			pool_conf_free(dyn);
1728			return (PO_FAIL);
1729		}
1730	}
1731	for (i = 0; i < nelem; i++) {
1732		if (pool_get_ns_property(TO_ELEM(rl[i]), c_size_prop,
1733		    &val1) == POC_INVAL ||
1734		    pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) {
1735			free(rl);
1736			if (conf != dyn) {
1737				(void) pool_conf_close(dyn);
1738				pool_conf_free(dyn);
1739			}
1740			return (PO_FAIL);
1741		}
1742		available += uval;
1743	}
1744	free(rl);
1745	if (conf != dyn) {
1746		(void) pool_conf_close(dyn);
1747		pool_conf_free(dyn);
1748	}
1749	if (strcmp(prop, c_min_prop) == 0) {
1750		if (available < required) {
1751			pool_seterror(POE_INVALID_CONF);
1752			return (PO_FAIL);
1753		}
1754	} else {
1755		if (available > required) {
1756			pool_seterror(POE_INVALID_CONF);
1757			return (PO_FAIL);
1758		}
1759	}
1760	return (PO_SUCCESS);
1761}
1762
1763/*
1764 * If _libpool_debug is set, printf the debug message to stderr with an
1765 * appropriate prefix in front of it.
1766 */
1767void
1768do_dprintf(const char *format, va_list ap)
1769{
1770	if (_libpool_debug) {
1771		(void) fputs("libpool DEBUG: ", stderr);
1772		(void) vfprintf(stderr, format, ap);
1773	}
1774}
1775
1776/*PRINTFLIKE1*/
1777void
1778dprintf(const char *format, ...)
1779{
1780	if (_libpool_debug) {
1781		va_list alist;
1782		va_start(alist, format);
1783		do_dprintf(format, alist);
1784		va_end(alist);
1785	}
1786}
1787
1788/*
1789 * log_alloc() allocates a new, empty transaction log.
1790 *
1791 * Returns a pointer to the new log or NULL on failure.
1792 */
1793log_t *
1794log_alloc(pool_conf_t *conf)
1795{
1796	log_t *l;
1797
1798	if ((l = calloc(1, sizeof (log_t))) == NULL) {
1799		pool_seterror(POE_SYSTEM);
1800		return (NULL);
1801	}
1802	l->l_state = LS_DO;
1803	l->l_conf = conf;
1804	if ((l->l_sentinel = log_item_alloc(l, 0, NULL))
1805	    == NULL) {
1806		free(l);
1807		pool_seterror(POE_SYSTEM);
1808		return (NULL);
1809	}
1810	l->l_sentinel->li_next = l->l_sentinel;
1811	l->l_sentinel->li_prev = l->l_sentinel;
1812
1813	return (l);
1814}
1815
1816/*
1817 * log_free() reclaims the resources associated with a transaction log.
1818 */
1819void
1820log_free(log_t *l)
1821{
1822	(void) log_walk(l, log_item_free);
1823	(void) log_item_free(l->l_sentinel);
1824	free(l);
1825}
1826/*
1827 * log_empty() removes all items from a transaction log. It is the
1828 * users responsibility to ensure that any resources associated with
1829 * an item are reclaimed before this function is invoked.
1830 */
1831void
1832log_empty(log_t *l)
1833{
1834	(void) log_walk(l, log_item_free);
1835}
1836
1837/*
1838 * log_walk() visits each log item in turn and executes the supplied action
1839 * using the item as a parameter. If no action is supplied, then the item
1840 * uses it's own stored action.
1841 *
1842 * Returns PO_SUCCESS/PO_FAIL
1843 */
1844int
1845log_walk(log_t *l, log_item_action_t action)
1846{
1847	log_item_t *li, *li_next;
1848
1849	li = l->l_sentinel->li_next;
1850	while (li != l->l_sentinel) {
1851		li_next = li->li_next;
1852		if ((action(li)) != PO_SUCCESS)
1853			return (PO_FAIL);
1854		li = li_next;
1855	}
1856	return (PO_SUCCESS);
1857}
1858
1859/*
1860 * log_reverse_walk() visits each log item in turn (in reverse order)
1861 * and executes the supplied action using the item as a parameter.
1862 *
1863 * Returns PO_SUCCESS/PO_FAIL
1864 */
1865int
1866log_reverse_walk(log_t *l, log_item_action_t action)
1867{
1868	log_item_t *li, *li_prev;
1869
1870	li = l->l_sentinel->li_prev;
1871	while (li != l->l_sentinel) {
1872		li_prev = li->li_prev;
1873		if ((action(li)) != PO_SUCCESS)
1874			return (PO_FAIL);
1875		li = li_prev;
1876	}
1877	return (PO_SUCCESS);
1878}
1879
1880/*
1881 * log_size() returns the size of the log, i.e. the number of items pending in
1882 * the log.
1883 */
1884uint_t
1885log_size(log_t *l)
1886{
1887	log_item_t *li;
1888	uint_t size = 0;
1889
1890	for (li = l->l_sentinel->li_next; li != l->l_sentinel; li = li->li_next)
1891		size++;
1892	return (size);
1893}
1894
1895/*
1896 * log_append() allocates a new log item to hold the supplied details and
1897 * appends the newly created item to the supplied log.
1898 *
1899 * Returns PO_SUCCESS/PO_FAIL
1900 */
1901int
1902log_append(log_t *l, int op, void *details)
1903{
1904	log_item_t *li;
1905
1906	if ((li = log_item_alloc(l, op, details)) == NULL) {
1907		l->l_state = LS_UNDO;
1908		return (PO_FAIL);
1909	}
1910	/*
1911	 * Link it in
1912	 */
1913	li->li_prev = l->l_sentinel->li_prev;
1914	li->li_next = l->l_sentinel;
1915	l->l_sentinel->li_prev->li_next = li;
1916	l->l_sentinel->li_prev = li;
1917	return (PO_SUCCESS);
1918}
1919
1920/*
1921 * log_item_alloc() allocates a new transaction log item. The item should be
1922 * used to store details about a transaction which may need to be undone if
1923 * commit processing fails.
1924 *
1925 * Returns a pointer to a new transaction log item or NULL.
1926 */
1927log_item_t *
1928log_item_alloc(log_t *l, int op, void *details)
1929{
1930	log_item_t *li;
1931
1932	if ((li = malloc(sizeof (log_item_t))) == NULL) {
1933		pool_seterror(POE_SYSTEM);
1934		return (NULL);
1935	}
1936
1937	(void) memset(li, 0, sizeof (log_item_t));
1938	li->li_log = l;
1939	li->li_op = op;
1940	li->li_details = details;
1941	li->li_state = LS_DO;
1942
1943	return (li);
1944}
1945
1946/*
1947 * log_item_free() reclaims the resources associated with a log_item_t.
1948 */
1949int
1950log_item_free(log_item_t *li)
1951{
1952	li->li_prev->li_next = li->li_next;
1953	li->li_next->li_prev = li->li_prev;
1954	free(li);
1955	return (PO_SUCCESS);
1956}
1957
1958/*
1959 * atom_string() checks the string table to see if a string is already
1960 * stored. If it is, return a pointer to it. If not, duplicate the
1961 * string and return a pointer to the duplicate.
1962 */
1963const char *
1964atom_string(const char *s)
1965{
1966	atom_t *atom;
1967
1968	/*
1969	 * atom_init() must have completed successfully
1970	 */
1971	atom_init();
1972	(void) mutex_lock(&_atom_lock);
1973	if ((atom = dict_get(_pv_atoms, s)) == NULL) {
1974		if ((atom = calloc(1, sizeof (atom_t))) == NULL) {
1975			pool_seterror(POE_SYSTEM);
1976			(void) mutex_unlock(&_atom_lock);
1977			return (NULL);
1978		}
1979		if ((atom->a_string = strdup(s)) == NULL) {
1980			(void) mutex_unlock(&_atom_lock);
1981			free(atom);
1982			pool_seterror(POE_SYSTEM);
1983			return (NULL);
1984		}
1985		(void) dict_put(_pv_atoms, atom->a_string, atom);
1986	}
1987	atom->a_count++;
1988	(void) mutex_unlock(&_atom_lock);
1989	return (atom->a_string);
1990}
1991
1992/*
1993 * atom_free() decrements the reference count for the supplied
1994 * string. If the reference count reaches zero, then the atom is
1995 * destroyed.
1996 */
1997void
1998atom_free(const char *s)
1999{
2000	atom_t *atom;
2001
2002	(void) mutex_lock(&_atom_lock);
2003	if ((atom = dict_get(_pv_atoms, s)) != NULL) {
2004		if (--atom->a_count == 0) {
2005			(void) dict_remove(_pv_atoms, s);
2006			free(atom->a_string);
2007			free(atom);
2008		}
2009	}
2010	(void) mutex_unlock(&_atom_lock);
2011}
2012
2013#ifdef DEBUG
2014/*
2015 * log_item_dprintf() prints the contents of the supplied log item using the
2016 * pools dprintf() trace mechanism.
2017 *
2018 * Returns PO_SUCCESS
2019 */
2020void
2021log_item_dprintf(log_item_t *li)
2022{
2023	dprintf("LOGDUMP: %d operation, %p\n", li->li_op, li->li_details);
2024}
2025
2026/*
2027 * log_item_dprintf() prints the contents of the supplied log item using the
2028 * pools dprintf() trace mechanism.
2029 *
2030 * Returns PO_SUCCESS
2031 */
2032void
2033pool_elem_dprintf(const pool_elem_t *pe)
2034{
2035	if (pool_elem_class(pe) != PEC_COMP) {
2036		const char *name = elem_get_name(pe);
2037		dprintf("element type: %s name: %s\n",
2038		    pool_elem_class_string(pe), name);
2039		free((void *)name);
2040	} else {
2041		id_t sys_id = elem_get_sysid(pe);
2042		dprintf("element type: %s sys_id: %d\n",
2043		    pool_elem_class_string(pe), sys_id);
2044	}
2045}
2046#endif	/* DEBUG */
2047