xref: /illumos-gate/usr/src/lib/libpool/common/pool_internal.c (revision 797f979d1fe26bfb1cdeb3e7a86ed24c0b654200)
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  */
47 typedef 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  */
56 mutex_t		_internal_lock;
57 
58 static int _libpool_debug = 0;			/* debugging messages */
59 static dict_hdl_t *_pv_atoms;			/* pool_value_t atoms */
60 static mutex_t _atom_lock;			/* atom table lock */
61 static int _libpool_internal_initialised = PO_FALSE;
62 
63 /*
64  * Various useful constant strings which are often encountered
65  */
66 const char *c_a_dtype = "a-dtype";
67 const char *c_name = "name";
68 const char *c_type = "type";
69 const char *c_ref_id = "ref_id";
70 const char *c_max_prop = "max";
71 const char *c_min_prop = "min";
72 const char *c_size_prop = "size";
73 const 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  */
79 static int prop_is_type(int, const pool_prop_t *);
80 static int resource_get_common(const pool_resource_t *, const char *,
81     uint64_t *);
82 static 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  */
88 static char *elem_get_expected_string(const pool_elem_t *, const char *);
89 static 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 
98 static int elem_name_init(pool_prop_t *);
99 static int elem_comment_init(pool_prop_t *);
100 
101 static int pool_importance_init(pool_prop_t *);
102 static int pool_active_init(pool_prop_t *);
103 
104 static int res_max_init(pool_prop_t *);
105 static int res_min_init(pool_prop_t *);
106 static int res_size_init(pool_prop_t *);
107 static int res_load_init(pool_prop_t *);
108 
109 static int pset_units_init(pool_prop_t *);
110 
111 static int cpu_status_init(pool_prop_t *);
112 
113 static int elem_no_set(pool_elem_t *, const pool_value_t *);
114 static int elem_set_name(pool_elem_t *, const pool_value_t *);
115 static int elem_get_type(const pool_elem_t *, pool_value_t *);
116 static int elem_set_string(pool_elem_t *, const pool_value_t *);
117 static int elem_set_bool(pool_elem_t *, const pool_value_t *);
118 static int elem_set_uint(pool_elem_t *, const pool_value_t *);
119 
120 static int system_set_allocate(pool_elem_t *, const pool_value_t *);
121 
122 static int pool_set_scheduler(pool_elem_t *, const pool_value_t *);
123 static int pool_set_active(pool_elem_t *, const pool_value_t *);
124 
125 static int res_set_max(pool_elem_t *, const pool_value_t *);
126 static int res_set_min(pool_elem_t *, const pool_value_t *);
127 
128 static int cpu_set_status(pool_elem_t *, const pool_value_t *);
129 
130 static 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  */
143 static const char *pool_resource_elem_class_name[] = {
144 	"invalid",
145 	"pset"
146 };
147 
148 static const char *pool_component_elem_class_name[] = {
149 	"invalid",
150 	"cpu"
151 };
152 
153 static 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 
178 static 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 
201 static 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 
229 static 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 
245 static 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  */
258 static pool_prop_t *pool_resource_elem_ctl[] = {
259 	NULL,
260 	pset_props
261 };
262 
263 static pool_prop_t *pool_component_elem_ctl[] = {
264 	NULL,
265 	cpu_props
266 };
267 
268 static void
269 atom_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  */
285 void
286 internal_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 
310 static int
311 element_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 
346 static int
347 elem_name_init(pool_prop_t *prop)
348 {
349 	return (string_init(prop, "default"));
350 }
351 
352 static int
353 elem_comment_init(pool_prop_t *prop)
354 {
355 	return (string_init(prop, ""));
356 }
357 
358 static int
359 pool_importance_init(pool_prop_t *prop)
360 {
361 	return (int_init(prop, 1));
362 }
363 
364 static int
365 pool_active_init(pool_prop_t *prop)
366 {
367 	return (bool_init(prop, PO_TRUE));
368 }
369 
370 static int
371 res_max_init(pool_prop_t *prop)
372 {
373 	return (uint_init(prop, 0));
374 }
375 
376 static int
377 res_min_init(pool_prop_t *prop)
378 {
379 	return (uint_init(prop, 0));
380 }
381 
382 static int
383 res_size_init(pool_prop_t *prop)
384 {
385 	return (uint_init(prop, 0));
386 }
387 
388 static int
389 res_load_init(pool_prop_t *prop)
390 {
391 	return (uint_init(prop, 0));
392 }
393 
394 static int
395 pset_units_init(pool_prop_t *prop)
396 {
397 	return (string_init(prop, "population"));
398 }
399 
400 static int
401 cpu_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 */
416 static int
417 elem_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  */
425 static int
426 elem_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 */
468 static int
469 elem_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 */
483 static int
484 elem_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 */
498 static int
499 elem_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 */
510 int
511 system_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 */
528 int
529 pool_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 */
550 int
551 pool_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 
568 static int
569 res_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 
622 static int
623 res_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 */
691 int
692 cpu_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 
712 static int
713 elem_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  */
728 int
729 conf_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  */
741 int
742 uint_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  */
753 int
754 int_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  */
765 int
766 double_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  */
777 int
778 bool_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  */
789 int
790 string_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  */
800 uint_t
801 pool_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  */
817 const pool_prop_t *
818 provider_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  */
847 const pool_prop_t *
848 provider_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  */
868 static int
869 prop_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  */
878 int
879 prop_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  */
888 int
889 prop_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  */
899 int
900 prop_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  */
909 int
910 prop_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  */
919 int
920 prop_is_optional(const pool_prop_t *prop)
921 {
922 	return (prop_is_type(PP_OPTIONAL, prop));
923 }
924 
925 int
926 cpu_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  */
944 static int
945 resource_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  */
970 int
971 resource_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  */
983 int
984 resource_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  */
1012 int
1013 resource_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  */
1024 int
1025 resource_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  */
1039 const pool_resource_t *
1040 get_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  */
1050 int
1051 resource_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  */
1060 int
1061 resource_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  */
1071 int
1072 resource_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  */
1082 static int64_t
1083 elem_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  */
1100 static char *
1101 elem_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  */
1117 id_t
1118 elem_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  */
1127 char *
1128 elem_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  */
1137 int
1138 elem_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  */
1147 boolean_t
1148 elem_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  */
1170 const pool_elem_t *
1171 get_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  */
1217 const char *
1218 is_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 
1261 const char *
1262 pool_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 
1280 const char *
1281 pool_resource_type_string(pool_resource_elem_class_t type)
1282 {
1283 	return (pool_resource_elem_class_name[type]);
1284 }
1285 
1286 const char *
1287 pool_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  */
1297 pool_resource_t *
1298 resource_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 
1338 pool_elem_class_t
1339 pool_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 
1354 pool_resource_elem_class_t
1355 pool_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 
1370 pool_component_elem_class_t
1371 pool_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  */
1390 int
1391 pool_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  */
1413 pool_system_t *
1414 pool_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 
1435 pool_system_t *
1436 pool_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 
1445 pool_t *
1446 pool_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 
1455 pool_resource_t *
1456 pool_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 
1466 pool_component_t *
1467 pool_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  */
1481 int
1482 qsort_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  */
1505 static int
1506 resize_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  */
1531 char_buf_t *
1532 alloc_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  */
1552 void
1553 free_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*/
1566 int
1567 set_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*/
1592 int
1593 append_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  */
1623 pool_elem_class_t
1624 pool_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  */
1633 pool_resource_elem_class_t
1634 pool_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  */
1642 pool_component_elem_class_t
1643 pool_component_elem_class(const pool_elem_t *elem)
1644 {
1645 	return (elem->pe_component_class);
1646 }
1647 
1648 pool_elem_t *
1649 pool_get_pair(const pool_elem_t *pe)
1650 {
1651 	return (pe->pe_pair);
1652 }
1653 
1654 void
1655 pool_set_pair(pool_elem_t *pe1, pool_elem_t *pe2)
1656 {
1657 	pe1->pe_pair = pe2;
1658 }
1659 
1660 int
1661 pool_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  */
1767 void
1768 do_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*/
1777 void
1778 dprintf(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  */
1793 log_t *
1794 log_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  */
1819 void
1820 log_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  */
1831 void
1832 log_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  */
1844 int
1845 log_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  */
1865 int
1866 log_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  */
1884 uint_t
1885 log_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  */
1901 int
1902 log_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  */
1927 log_item_t *
1928 log_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  */
1949 int
1950 log_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  */
1963 const char *
1964 atom_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  */
1997 void
1998 atom_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  */
2020 void
2021 log_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  */
2032 void
2033 pool_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