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