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