xref: /titanic_50/usr/src/lib/libpool/common/pool.c (revision 46ae6f1e3494358cbcad951902b491d6826ebd75)
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 /*
23  * Copyright 2006 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 <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <thread.h>
34 #include <synch.h>
35 #include <unistd.h>
36 #include <stropts.h>
37 #include <fcntl.h>
38 #include <note.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <libintl.h>
42 #include <pool.h>
43 #include <signal.h>
44 
45 #include <sys/pool.h>
46 #include <sys/priocntl.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/wait.h>
50 
51 #include "pool_internal.h"
52 #include "pool_impl.h"
53 
54 /*
55  * libpool Interface Routines
56  *
57  * pool.c implements (most of) the external interface to libpool
58  * users. Some of the interface is implemented in pool_internal.c for
59  * reasons of internal code organisation.  The core requirements for
60  * pool.c are:
61  *
62  * Data Abstraction
63  *
64  * The abstraction of the actual datastore so that no details of the
65  * underlying data representation mechanism are revealed to users of
66  * the library. For instance, the fact that we use the kernel or files
67  * to store our configurations is completely abstracted via the
68  * various libpool APIs.
69  *
70  * External Interaction
71  *
72  * libpool users manipulate configuration components via the API
73  * defined in pool.h. Most functions in this file act as interceptors,
74  * validating parameters before redirecting the request into a
75  * specific datastore implementation for the actual work to be done.
76  *
77  * These main sets of requirements have driven the design so that it
78  * is possible to replace the entire datastore type without having to
79  * modify the external (or internal provider) APIs. It is possible to
80  * modify the storage technology used by libpool by implementing a new
81  * set of datastore provider operations. Simply modify the
82  * pool_conf_open() routine to establish a new datastore as the
83  * provider for a configuration.
84  *
85  * The key components in a libpool configuration are :
86  * pool_conf_t - This represents a complete configuration instance
87  * pool_t - A pool inside a configuration
88  * pool_resource_t - A resource inside a configuration
89  * pool_component_t - A component of a resource
90  *
91  */
92 
93 /*
94  * Used to control transfer setup.
95  */
96 #define	XFER_FAIL	PO_FAIL
97 #define	XFER_SUCCESS	PO_SUCCESS
98 #define	XFER_CONTINUE	1
99 
100 #define	SMF_SVC_INSTANCE	"svc:/system/pools:default"
101 #define	E_ERROR		1		/* Exit status for error */
102 
103 #ifndef	TEXT_DOMAIN
104 #define	TEXT_DOMAIN	"SYS_TEST"
105 #endif	/* TEXT_DOMAIN */
106 
107 const char pool_info_location[] =  "/dev/pool";
108 
109 /*
110  * Static data
111  */
112 static const char static_location[] = "/etc/pooladm.conf";
113 static const char dynamic_location[] =  "/dev/poolctl";
114 static mutex_t		keylock;
115 static thread_key_t	errkey;
116 static int		keyonce = 0;
117 
118 /*
119  * libpool error code
120  */
121 static int pool_errval = POE_OK;
122 
123 /*
124  * libpool version
125  */
126 static uint_t pool_workver = POOL_VER_CURRENT;
127 
128 static const char *data_type_tags[] = {
129 	"uint",
130 	"int",
131 	"float",
132 	"boolean",
133 	"string"
134 };
135 
136 /*
137  * static functions
138  */
139 static int pool_elem_remove(pool_elem_t *);
140 static int is_valid_prop_name(const char *);
141 static int prop_buf_build_cb(pool_conf_t *, pool_elem_t *, const char *,
142     pool_value_t *, void *);
143 static char *pool_base_info(const pool_elem_t *, char_buf_t *, int);
144 static int choose_components(pool_resource_t *, pool_resource_t *, uint64_t);
145 static int pool_conf_check(const pool_conf_t *);
146 static void free_value_list(int, pool_value_t **);
147 static int setup_transfer(pool_conf_t *, pool_resource_t *, pool_resource_t *,
148     uint64_t, uint64_t *, uint64_t *);
149 
150 /*
151  * Return the "static" location string for libpool.
152  */
153 const char *
154 pool_static_location(void)
155 {
156 	return (static_location);
157 }
158 
159 /*
160  * Return the "dynamic" location string for libpool.
161  */
162 const char *
163 pool_dynamic_location(void)
164 {
165 	return (dynamic_location);
166 }
167 
168 /*
169  * Return the status for a configuration. If the configuration has
170  * been successfully opened, then the status will be POF_VALID or
171  * POF_DESTROY.  If the configuration failed to open properly or has
172  * been closed or removed, then the status will be POF_INVALID.
173  */
174 pool_conf_state_t
175 pool_conf_status(const pool_conf_t *conf)
176 {
177 	return (conf->pc_state);
178 }
179 
180 /*
181  * Bind idtype id to the pool name.
182  */
183 int
184 pool_set_binding(const char *pool_name, idtype_t idtype, id_t id)
185 {
186 	pool_conf_t *conf;
187 	int result;
188 
189 	if ((conf = pool_conf_alloc()) == NULL)
190 		return (PO_FAIL);
191 
192 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
193 		pool_conf_free(conf);
194 		pool_seterror(POE_INVALID_CONF);
195 		return (PO_FAIL);
196 	}
197 
198 	result = conf->pc_prov->pc_set_binding(conf, pool_name, idtype, id);
199 
200 	(void) pool_conf_close(conf);
201 	pool_conf_free(conf);
202 	return (result);
203 }
204 
205 /*
206  * pool_get_resource_binding() returns the binding for a pid to the supplied
207  * type of resource. If a binding cannot be determined, NULL is returned.
208  */
209 char *
210 pool_get_resource_binding(const char *sz_type, pid_t pid)
211 {
212 	pool_conf_t *conf;
213 	char *result;
214 	pool_resource_elem_class_t type;
215 
216 	if ((type = pool_resource_elem_class_from_string(sz_type)) ==
217 	    PREC_INVALID) {
218 		pool_seterror(POE_BADPARAM);
219 		return (NULL);
220 	}
221 
222 	if ((conf = pool_conf_alloc()) == NULL)
223 		return (NULL);
224 
225 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)
226 	    != PO_SUCCESS) {
227 		pool_seterror(POE_INVALID_CONF);
228 		pool_conf_free(conf);
229 		return (NULL);
230 	}
231 	result = conf->pc_prov->pc_get_resource_binding(conf, type, pid);
232 	(void) pool_conf_close(conf);
233 	pool_conf_free(conf);
234 	return (result);
235 }
236 
237 /*
238  * pool_get_binding() returns the binding for a pid to a pool. If a
239  * binding cannot be determined, NULL is returned.
240  */
241 char *
242 pool_get_binding(pid_t pid)
243 {
244 	pool_conf_t *conf;
245 	char *result;
246 
247 	if ((conf = pool_conf_alloc()) == NULL)
248 		return (NULL);
249 
250 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)
251 	    != PO_SUCCESS) {
252 		pool_seterror(POE_INVALID_CONF);
253 		pool_conf_free(conf);
254 		return (NULL);
255 	}
256 	result = conf->pc_prov->pc_get_binding(conf, pid);
257 	(void) pool_conf_close(conf);
258 	pool_conf_free(conf);
259 	return (result);
260 }
261 
262 /*ARGSUSED*/
263 int
264 prop_buf_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name,
265     pool_value_t *pval, void *user)
266 {
267 	uint64_t u;
268 	int64_t i;
269 	uchar_t bool;
270 	const char *str;
271 	double d;
272 	char_buf_t *cb = (char_buf_t *)user;
273 	int type = pool_value_get_type(pval);
274 
275 	/*
276 	 * Ignore "type" and "<type>.name" properties as these are not
277 	 * to be displayed by this function
278 	 */
279 	if (strcmp(name, c_type) == 0 ||
280 	    strcmp(property_name_minus_ns(pe, name), c_name) == 0)
281 		return (PO_SUCCESS);
282 	if (append_char_buf(cb, "\n%s\t%s\t%s ", cb->cb_tab_buf,
283 	    data_type_tags[type], name) == PO_FAIL)
284 		return (PO_FAIL);
285 	switch (type) {
286 	case POC_UINT:
287 		(void) pool_value_get_uint64(pval, &u);
288 		if (append_char_buf(cb, "%llu", (u_longlong_t)u) == PO_FAIL)
289 			return (PO_FAIL);
290 		break;
291 	case POC_INT:
292 		(void) pool_value_get_int64(pval, &i);
293 		if (append_char_buf(cb, "%lld", (longlong_t)i) == PO_FAIL)
294 			return (PO_FAIL);
295 		break;
296 	case POC_STRING:
297 		(void) pool_value_get_string(pval, &str);
298 		if (append_char_buf(cb, "%s", str) == PO_FAIL)
299 			return (PO_FAIL);
300 		break;
301 	case POC_BOOL:
302 		(void) pool_value_get_bool(pval, &bool);
303 		if (bool == 0) {
304 			if (append_char_buf(cb, "%s", "false") == PO_FAIL)
305 				return (PO_FAIL);
306 		} else {
307 			if (append_char_buf(cb, "%s", "true") == PO_FAIL)
308 				return (PO_FAIL);
309 		}
310 		break;
311 	case POC_DOUBLE:
312 		(void) pool_value_get_double(pval, &d);
313 		if (append_char_buf(cb, "%g", d) == PO_FAIL)
314 			return (PO_FAIL);
315 		break;
316 	case POC_INVAL: /* Do nothing */
317 		break;
318 	default:
319 		return (PO_FAIL);
320 	}
321 	return (PO_SUCCESS);
322 }
323 
324 /*
325  * Return a buffer which describes the element
326  * pe is a pointer to the element
327  * deep is PO_TRUE/PO_FALSE to indicate whether children should be included
328  */
329 char *
330 pool_base_info(const pool_elem_t *pe, char_buf_t *cb, int deep)
331 {
332 	const char *sres;
333 	uint_t i;
334 	uint_t nelem;
335 
336 	pool_value_t val = POOL_VALUE_INITIALIZER;
337 	pool_resource_t **rs;
338 	pool_elem_t *elem;
339 	pool_conf_t *conf = TO_CONF(pe);
340 
341 	if (cb == NULL) {
342 		char *ret = NULL;
343 
344 		if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
345 			return (NULL);
346 
347 		/*
348 		 * Populate the buffer with element details
349 		 */
350 		(void) pool_base_info(pe, cb, deep);
351 		if (cb->cb_buf)
352 			ret = strdup(cb->cb_buf);
353 		free_char_buf(cb);
354 		return (ret);
355 	}
356 
357 	if (append_char_buf(cb, "\n%s%s", cb->cb_tab_buf,
358 		pool_elem_class_string(pe)) == PO_FAIL) {
359 		return (NULL);
360 	}
361 
362 	if (pool_get_ns_property(pe, c_name, &val) == POC_STRING) {
363 		(void) pool_value_get_string(&val, &sres);
364 		if (append_char_buf(cb, " %s", sres) == PO_FAIL) {
365 			return (NULL);
366 		}
367 	}
368 
369 	/*
370 	 * Add in some details about the element
371 	 */
372 	if (pool_walk_properties(conf, (pool_elem_t *)pe, cb,
373 	    prop_buf_build_cb) == PO_FAIL) {
374 		(void) append_char_buf(cb, "\n%s%s\n", cb->cb_tab_buf,
375 		    "Cannot access the properties of this element.");
376 		return (NULL);
377 	}
378 	if (append_char_buf(cb, "%s", "\n") == PO_FAIL)
379 		return (NULL);
380 
381 	if (pe->pe_class == PEC_POOL) {
382 		/*
383 		 * A shallow display of a pool only lists the resources by name
384 		 */
385 
386 		if ((rs = pool_query_pool_resources(conf, pool_elem_pool(pe),
387 		    &nelem, NULL)) == NULL) {
388 			return (NULL);
389 		}
390 
391 		for (i = 0; i < nelem; i++) {
392 			const char *str;
393 
394 			elem = TO_ELEM(rs[i]);
395 
396 			if (append_char_buf(cb, "\t%s%s", cb->cb_tab_buf,
397 			    pool_elem_class_string(elem)) == PO_FAIL) {
398 				free(rs);
399 				return (NULL);
400 			}
401 
402 			if (pool_get_ns_property(elem, c_name, &val) !=
403 			    POC_STRING) {
404 				free(rs);
405 				pool_seterror(POE_INVALID_CONF);
406 				return (NULL);
407 			}
408 			(void) pool_value_get_string(&val, &str);
409 			if (append_char_buf(cb, "\t%s\n", str) == PO_FAIL) {
410 				free(rs);
411 				return (NULL);
412 			}
413 		}
414 		free(rs);
415 	}
416 	if (deep == PO_TRUE) {
417 		pool_t **ps;
418 		pool_component_t **cs;
419 
420 		if (strlcat(cb->cb_tab_buf, "\t", CB_TAB_BUF_SIZE)
421 		    >= CB_TAB_BUF_SIZE) {
422 			pool_seterror(POE_SYSTEM);
423 			return (NULL);
424 		}
425 		switch (pe->pe_class) {
426 		case PEC_SYSTEM:
427 			if ((ps = pool_query_pools(conf, &nelem, NULL)) !=
428 			    NULL) { /* process the pools */
429 				for (i = 0; i < nelem; i++) {
430 					elem = TO_ELEM(ps[i]);
431 					if (pool_base_info(elem, cb,
432 					    PO_FALSE) == NULL) {
433 						free(ps);
434 						return (NULL);
435 					}
436 				}
437 				free(ps);
438 			}
439 			if ((rs = pool_query_resources(conf, &nelem, NULL)) !=
440 			    NULL) {
441 				for (i = 0; i < nelem; i++) {
442 					elem = TO_ELEM(rs[i]);
443 					if (pool_base_info(elem, cb,
444 					    PO_TRUE) == NULL) {
445 						free(rs);
446 						return (NULL);
447 					}
448 				}
449 				free(rs);
450 			}
451 			break;
452 		case PEC_POOL:
453 			if ((rs = pool_query_pool_resources(conf,
454 			    pool_elem_pool(pe), &nelem, NULL)) == NULL)
455 				return (NULL);
456 			for (i = 0; i < nelem; i++) {
457 				elem = TO_ELEM(rs[i]);
458 				if (pool_base_info(elem, cb, PO_TRUE) == NULL) {
459 					free(rs);
460 					return (NULL);
461 				}
462 			}
463 			free(rs);
464 			break;
465 		case PEC_RES_COMP:
466 			if ((cs = pool_query_resource_components(conf,
467 			    pool_elem_res(pe), &nelem, NULL)) != NULL) {
468 				for (i = 0; i < nelem; i++) {
469 					elem = TO_ELEM(cs[i]);
470 					if (pool_base_info(elem, cb,
471 					    PO_FALSE) == NULL) {
472 						free(cs);
473 						return (NULL);
474 					}
475 				}
476 				free(cs);
477 			}
478 			break;
479 		case PEC_RES_AGG:
480 		case PEC_COMP:
481 			break;
482 		default:
483 			/*NOTREACHED*/
484 			break;
485 		}
486 		if (cb->cb_tab_buf[0] != 0)
487 			cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0;
488 	}
489 	return (cb->cb_buf);
490 }
491 
492 /*
493  * Returns	The information on the specified pool or NULL.
494  *
495  * Errors	If the status of the conf is INVALID or the supplied
496  *		value of deep is illegal, POE_BADPARAM.
497  *
498  * The caller is responsible for free(3c)ing the string returned.
499  */
500 char *
501 pool_info(const pool_conf_t *conf, const pool_t *pool, int deep)
502 {
503 	pool_elem_t *pe;
504 
505 	pe = TO_ELEM(pool);
506 
507 	if (TO_CONF(pe) != conf) {
508 		pool_seterror(POE_BADPARAM);
509 		return (NULL);
510 	}
511 
512 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
513 		pool_seterror(POE_BADPARAM);
514 		return (NULL);
515 	}
516 
517 	return (pool_base_info(pe, NULL, deep));
518 }
519 
520 /*
521  * Returns	The information on the specified resource or NULL.
522  *
523  * Errors	If the status of the conf is INVALID or the supplied
524  *		value of deep is illegal, POE_BADPARAM.
525  *
526  * The caller is responsible for free(3c)ing the string returned.
527  */
528 char *
529 pool_resource_info(const pool_conf_t *conf, const pool_resource_t *res,
530     int deep)
531 {
532 	pool_elem_t *pe;
533 
534 	pe = TO_ELEM(res);
535 
536 	if (TO_CONF(pe) != conf) {
537 		pool_seterror(POE_BADPARAM);
538 		return (NULL);
539 	}
540 
541 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
542 		pool_seterror(POE_BADPARAM);
543 		return (NULL);
544 	}
545 
546 	return (pool_base_info(pe, NULL, deep));
547 }
548 
549 /*
550  * Returns	The information on the specified component or NULL.
551  *
552  * Errors	If the status of the conf is INVALID or the supplied
553  *		value of deep is illegal, POE_BADPARAM.
554  *
555  * The caller is responsible for free(3c)ing the string returned.
556  */
557 char *
558 pool_component_info(const pool_conf_t *conf, const pool_component_t *comp,
559     int deep)
560 {
561 	pool_elem_t *pe;
562 
563 	pe = TO_ELEM(comp);
564 
565 	if (TO_CONF(pe) != conf) {
566 		pool_seterror(POE_BADPARAM);
567 		return (NULL);
568 	}
569 
570 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
571 		pool_seterror(POE_BADPARAM);
572 		return (NULL);
573 	}
574 
575 	return (pool_base_info(pe, NULL, deep));
576 }
577 
578 /*
579  * Returns	The information on the specified conf or NULL.
580  *
581  * Errors	If the status of the conf is INVALID or the supplied
582  *		value of deep is illegal, POE_BADPARAM.
583  *
584  * The caller is responsible for free(3c)ing the string returned.
585  */
586 char *
587 pool_conf_info(const pool_conf_t *conf, int deep)
588 {
589 	pool_elem_t *pe;
590 
591 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
592 		pool_seterror(POE_BADPARAM);
593 		return (NULL);
594 	}
595 	if ((pe = pool_conf_to_elem(conf)) == NULL) {
596 		pool_seterror(POE_BADPARAM);
597 		return (NULL);
598 	}
599 	return (pool_base_info(pe, NULL, deep));
600 }
601 
602 
603 /*
604  * Set the thread specific error value.
605  */
606 void
607 pool_seterror(int errval)
608 {
609 	if (thr_main()) {
610 		pool_errval = errval;
611 		return;
612 	}
613 	if (keyonce == 0) {
614 		(void) mutex_lock(&keylock);
615 		if (keyonce == 0) {
616 			(void) thr_keycreate(&errkey, 0);
617 			keyonce++;
618 		}
619 		(void) mutex_unlock(&keylock);
620 	}
621 	(void) thr_setspecific(errkey, (void *)(intptr_t)errval);
622 }
623 
624 /*
625  * Return the current value of the error code.
626  * Returns: int error code
627  */
628 int
629 pool_error(void)
630 {
631 	void *errval;
632 
633 	if (thr_main())
634 		return (pool_errval);
635 	if (keyonce == 0)
636 		return (POE_OK);
637 	(void) thr_getspecific(errkey, &errval);
638 	return ((intptr_t)errval);
639 }
640 
641 /*
642  * Return the text represenation for the current value of the error code.
643  * Returns: const char * error string
644  */
645 const char *
646 pool_strerror(int error)
647 {
648 	char *str;
649 
650 	switch (error) {
651 	case POE_OK:
652 		str = dgettext(TEXT_DOMAIN, "Operation successful");
653 		break;
654 	case POE_BAD_PROP_TYPE:
655 		str = dgettext(TEXT_DOMAIN,
656 		    "Attempted to retrieve the wrong property type");
657 		break;
658 	case POE_INVALID_CONF:
659 		str = dgettext(TEXT_DOMAIN, "Invalid configuration");
660 		break;
661 	case POE_NOTSUP:
662 		str = dgettext(TEXT_DOMAIN, "Operation is not supported");
663 		break;
664 	case POE_INVALID_SEARCH:
665 		str = dgettext(TEXT_DOMAIN, "Invalid search");
666 		break;
667 	case POE_BADPARAM:
668 		str = dgettext(TEXT_DOMAIN, "Bad parameter supplied");
669 		break;
670 	case POE_PUTPROP:
671 		str = dgettext(TEXT_DOMAIN, "Error putting property");
672 		break;
673 	case POE_DATASTORE:
674 		str = dgettext(TEXT_DOMAIN, "Pools repository error");
675 		break;
676 	case POE_SYSTEM:
677 		str = dgettext(TEXT_DOMAIN, "System error");
678 		break;
679 	case POE_ACCESS:
680 		str = dgettext(TEXT_DOMAIN, "Permission denied");
681 		break;
682 	default:
683 		errno = ESRCH;
684 		str = NULL;
685 	}
686 	return (str);
687 }
688 
689 int
690 pool_get_status(int *state)
691 {
692 	int fd;
693 	pool_status_t status;
694 
695 	if ((fd = open(pool_info_location, O_RDONLY)) < 0) {
696 		pool_seterror(POE_SYSTEM);
697 		return (PO_FAIL);
698 	}
699 	if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
700 		(void) close(fd);
701 		pool_seterror(POE_SYSTEM);
702 		return (PO_FAIL);
703 	}
704 	(void) close(fd);
705 
706 	*state = status.ps_io_state;
707 
708 	return (PO_SUCCESS);
709 }
710 
711 int
712 pool_set_status(int state)
713 {
714 	int old_state;
715 
716 	if (pool_get_status(&old_state) != PO_SUCCESS) {
717 		pool_seterror(POE_SYSTEM);
718 		return (PO_FAIL);
719 	}
720 
721 	if (old_state != state) {
722 		int fd;
723 		pool_status_t status;
724 
725 		/*
726 		 * Changing the status of pools is performed by enabling
727 		 * or disabling the pools service instance. If this
728 		 * function has not been invoked by startd then we simply
729 		 * enable/disable the service and return success.
730 		 *
731 		 * There is no way to specify that state changes must be
732 		 * synchronous using the library API as yet, so we use
733 		 * the -s option provided by svcadm.
734 		 */
735 		if (getenv("SMF_FMRI") == NULL) {
736 			FILE *p;
737 			char *cmd;
738 
739 			if (state) {
740 				cmd = "/usr/sbin/svcadm enable -s " \
741 				    SMF_SVC_INSTANCE;
742 			} else {
743 				cmd = "/usr/sbin/svcadm disable -s " \
744 				    SMF_SVC_INSTANCE;
745 			}
746 			if ((p = popen(cmd, "wF")) == NULL || pclose(p) != 0) {
747 				pool_seterror(POE_SYSTEM);
748 				return (PO_FAIL);
749 			}
750 			return (PO_SUCCESS);
751 		}
752 
753 		if ((fd = open(pool_dynamic_location(), O_RDWR | O_EXCL)) < 0) {
754 			pool_seterror(POE_SYSTEM);
755 			return (PO_FAIL);
756 		}
757 
758 		status.ps_io_state = state;
759 
760 		if (ioctl(fd, POOL_STATUS, &status) < 0) {
761 			(void) close(fd);
762 			pool_seterror(POE_SYSTEM);
763 			return (PO_FAIL);
764 		}
765 
766 		(void) close(fd);
767 
768 	}
769 	return (PO_SUCCESS);
770 }
771 
772 /*
773  * General Data Provider Independent Access Methods
774  */
775 
776 /*
777  * Property manipulation code.
778  *
779  * The pool_(get|rm|set)_property() functions consult the plugins before
780  * looking at the actual configuration. This allows plugins to provide
781  * "virtual" properties that may not exist in the configuration file per se,
782  * but behave like regular properties. This also allows plugins to reserve
783  * certain properties as read-only, non-removable, etc.
784  *
785  * A negative value returned from the plugin denotes error, 0 means that the
786  * property request should be forwarded to the backend, and 1 means the request
787  * was satisfied by the plugin and should not be processed further.
788  *
789  * The (get|rm|set)_property() functions bypass the plugin layer completely,
790  * and hence should not be generally used.
791  */
792 
793 /*
794  * Return true if the string passed in matches the pattern
795  * [A-Za-z][A-Za-z0-9,._-]*
796  */
797 int
798 is_valid_name(const char *name)
799 {
800 	int i;
801 	char c;
802 
803 	if (name == NULL)
804 		return (PO_FALSE);
805 	if (!isalpha(name[0]))
806 		return (PO_FALSE);
807 	for (i = 1; (c = name[i]) != '\0'; i++) {
808 		if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-')
809 			return (PO_FALSE);
810 	}
811 	return (PO_TRUE);
812 }
813 
814 /*
815  * Return true if the string passed in matches the pattern
816  * [A-Za-z_][A-Za-z0-9,._-]*
817  * A property name starting with a '_' is an "invisible" property that does not
818  * show up in a property walk.
819  */
820 int
821 is_valid_prop_name(const char *prop_name)
822 {
823 	int i;
824 	char c;
825 
826 	if (prop_name == NULL)
827 		return (PO_FALSE);
828 	if (!isalpha(prop_name[0]) && prop_name[0] != '_')
829 		return (PO_FALSE);
830 	for (i = 1; (c = prop_name[i]) != '\0'; i++) {
831 		if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-')
832 			return (PO_FALSE);
833 	}
834 	return (PO_TRUE);
835 }
836 
837 /*
838  * Return the specified property value.
839  *
840  * POC_INVAL is returned if an error is detected and the error code is updated
841  * to indicate the cause of the error.
842  */
843 pool_value_class_t
844 pool_get_property(const pool_conf_t *conf, const pool_elem_t *pe,
845     const char *name, pool_value_t *val)
846 {
847 	const pool_prop_t *prop_info;
848 
849 	if (pool_conf_status(conf) == POF_INVALID) {
850 		pool_seterror(POE_BADPARAM);
851 		return (POC_INVAL);
852 	}
853 	if (pool_value_set_name(val, name) != PO_SUCCESS) {
854 		return (POC_INVAL);
855 	}
856 	/*
857 	 * Check to see if this is a property we are managing. If it
858 	 * is and it has an interceptor installed for property
859 	 * retrieval, use it.
860 	 */
861 	if ((prop_info = provider_get_prop(pe, name)) != NULL &&
862 	    prop_info->pp_op.ppo_get_value != NULL) {
863 		if (prop_info->pp_op.ppo_get_value(pe, val) == PO_FAIL)
864 			return (POC_INVAL);
865 		else
866 			return (pool_value_get_type(val));
867 	}
868 	return (pe->pe_get_prop(pe, name, val));
869 }
870 
871 /*
872  * Return the specified property value with the namespace prepended.
873  * e.g. If this function is used to get the property "name" on a pool, it will
874  * attempt to retrieve "pool.name".
875  *
876  * POC_INVAL is returned if an error is detected and the error code is updated
877  * to indicate the cause of the error.
878  */
879 pool_value_class_t
880 pool_get_ns_property(const pool_elem_t *pe, const char *name, pool_value_t *val)
881 {
882 	int ret;
883 	char_buf_t *cb;
884 
885 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
886 		return (POC_INVAL);
887 	if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
888 	    PO_FAIL) {
889 		free_char_buf(cb);
890 		return (POC_INVAL);
891 	}
892 	ret = pool_get_property(TO_CONF(pe), pe, cb->cb_buf, val);
893 	free_char_buf(cb);
894 	return (ret);
895 }
896 
897 /*
898  * Update the specified property value.
899  *
900  * PO_FAIL is returned if an error is detected and the error code is updated
901  * to indicate the cause of the error.
902  */
903 int
904 pool_put_property(pool_conf_t *conf, pool_elem_t *pe, const char *name,
905     const pool_value_t *val)
906 {
907 	const pool_prop_t *prop_info;
908 
909 	if (pool_conf_check(conf) != PO_SUCCESS)
910 		return (PO_FAIL);
911 
912 	if (TO_CONF(pe) != conf) {
913 		pool_seterror(POE_BADPARAM);
914 		return (NULL);
915 	}
916 
917 	/* Don't allow (re)setting of the "temporary" property */
918 	if (!is_valid_prop_name(name) || strstr(name, ".temporary") != NULL) {
919 		pool_seterror(POE_BADPARAM);
920 		return (PO_FAIL);
921 	}
922 
923 	/* Don't allow rename of temporary pools/resources */
924 	if (strstr(name, ".name") != NULL && elem_is_tmp(pe)) {
925 		boolean_t rename = B_TRUE;
926 		pool_value_t *pv = pool_value_alloc();
927 
928 		if (pe->pe_get_prop(pe, name, pv) != POC_INVAL) {
929 			const char *s1 = NULL;
930 			const char *s2 = NULL;
931 
932 			(void) pool_value_get_string(pv, &s1);
933 			(void) pool_value_get_string(val, &s2);
934 			if (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0)
935 				rename = B_FALSE;
936 		}
937 		pool_value_free(pv);
938 
939 		if (rename) {
940 			pool_seterror(POE_BADPARAM);
941 			return (PO_FAIL);
942 		}
943 	}
944 
945 	/*
946 	 * Check to see if this is a property we are managing. If it is,
947 	 * ensure that we are happy with what the user is doing.
948 	 */
949 	if ((prop_info = provider_get_prop(pe, name)) != NULL) {
950 		if (prop_is_readonly(prop_info) == PO_TRUE) {
951 			pool_seterror(POE_BADPARAM);
952 			return (PO_FAIL);
953 		}
954 		if (prop_info->pp_op.ppo_set_value &&
955 		    prop_info->pp_op.ppo_set_value(pe, val) == PO_FAIL)
956 			return (PO_FAIL);
957 	}
958 
959 	return (pe->pe_put_prop(pe, name, val));
960 }
961 
962 /*
963  * Set temporary property to flag as a temporary element.
964  *
965  * PO_FAIL is returned if an error is detected and the error code is updated
966  * to indicate the cause of the error.
967  */
968 int
969 pool_set_temporary(pool_conf_t *conf, pool_elem_t *pe)
970 {
971 	int res;
972 	char name[128];
973 	pool_value_t *val;
974 
975 	if (pool_conf_check(conf) != PO_SUCCESS)
976 		return (PO_FAIL);
977 
978 	if (TO_CONF(pe) != conf) {
979 		pool_seterror(POE_BADPARAM);
980 		return (PO_FAIL);
981 	}
982 
983 	/* create property name based on element type */
984 	if (snprintf(name, sizeof (name), "%s.temporary",
985 	    pool_elem_class_string(pe)) > sizeof (name)) {
986 		pool_seterror(POE_SYSTEM);
987 		return (PO_FAIL);
988 	}
989 
990 	if ((val = pool_value_alloc()) == NULL)
991 		return (PO_FAIL);
992 
993 	pool_value_set_bool(val, (uchar_t)1);
994 
995 	res = pe->pe_put_prop(pe, name, val);
996 
997 	pool_value_free(val);
998 
999 	return (res);
1000 }
1001 
1002 /*
1003  * Update the specified property value with the namespace prepended.
1004  * e.g. If this function is used to update the property "name" on a pool, it
1005  * will attempt to update "pool.name".
1006  *
1007  * PO_FAIL is returned if an error is detected and the error code is updated
1008  * to indicate the cause of the error.
1009  */
1010 int
1011 pool_put_ns_property(pool_elem_t *pe, const char *name,
1012     const pool_value_t *val)
1013 {
1014 	char_buf_t *cb;
1015 	int ret;
1016 
1017 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
1018 		return (PO_FAIL);
1019 	if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
1020 	    PO_FAIL) {
1021 		free_char_buf(cb);
1022 		return (PO_FAIL);
1023 	}
1024 	ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val);
1025 	free_char_buf(cb);
1026 	return (ret);
1027 }
1028 
1029 /*
1030  * Update the specified property value. Do not use the property
1031  * protection mechanism. This function should only be used for cases
1032  * where the library must bypass the normal property protection
1033  * mechanism. The only known use is to update properties in the static
1034  * configuration when performing a commit.
1035  *
1036  * PO_FAIL is returned if an error is detected and the error code is
1037  * updated to indicate the cause of the error.
1038  */
1039 int
1040 pool_put_any_property(pool_elem_t *pe, const char *name,
1041     const pool_value_t *val)
1042 {
1043 	if (!is_valid_prop_name(name)) {
1044 		pool_seterror(POE_BADPARAM);
1045 		return (PO_FAIL);
1046 	}
1047 
1048 	return (pe->pe_put_prop(pe, name, val));
1049 }
1050 
1051 /*
1052  * Update the specified property value with the namespace prepended.
1053  * e.g. If this function is used to update the property "name" on a pool, it
1054  * will attempt to update "pool.name".
1055  *
1056  * PO_FAIL is returned if an error is detected and the error code is updated
1057  * to indicate the cause of the error.
1058  */
1059 int
1060 pool_put_any_ns_property(pool_elem_t *pe, const char *name,
1061     const pool_value_t *val)
1062 {
1063 	char_buf_t *cb;
1064 	int ret;
1065 
1066 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
1067 		return (PO_FAIL);
1068 	if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
1069 	    PO_FAIL) {
1070 		free_char_buf(cb);
1071 		return (PO_FAIL);
1072 	}
1073 	ret = pool_put_any_property(pe, cb->cb_buf, val);
1074 	free_char_buf(cb);
1075 	return (ret);
1076 }
1077 
1078 /*
1079  * Remove the specified property value. Note that some properties are
1080  * mandatory and thus failure to remove these properties is inevitable.
1081  * PO_FAIL is returned if an error is detected and the error code is updated
1082  * to indicate the cause of the error.
1083  */
1084 int
1085 pool_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name)
1086 {
1087 	const pool_prop_t *prop_info;
1088 
1089 	if (pool_conf_check(conf) != PO_SUCCESS)
1090 		return (PO_FAIL);
1091 
1092 	if (TO_CONF(pe) != conf) {
1093 		pool_seterror(POE_BADPARAM);
1094 		return (NULL);
1095 	}
1096 
1097 	/* Don't allow removal of the "temporary" property */
1098 	if (strstr(name, ".temporary") != NULL) {
1099 		pool_seterror(POE_BADPARAM);
1100 		return (PO_FAIL);
1101 	}
1102 
1103 	/*
1104 	 * Check to see if this is a property we are managing. If it is,
1105 	 * ensure that we are happy with what the user is doing.
1106 	 */
1107 	if ((prop_info = provider_get_prop(pe, name)) != NULL) {
1108 		if (prop_is_optional(prop_info) == PO_FALSE) {
1109 			pool_seterror(POE_BADPARAM);
1110 			return (PO_FAIL);
1111 		}
1112 	}
1113 	return (pe->pe_rm_prop(pe, name));
1114 }
1115 
1116 /*
1117  * Check if the supplied name is a namespace protected property for the supplied
1118  * element, pe. If it is, return the prefix, otherwise just return NULL.
1119  */
1120 const char *
1121 is_ns_property(const pool_elem_t *pe, const char *name)
1122 {
1123 	const char *prefix;
1124 
1125 	if ((prefix = pool_elem_class_string(pe)) != NULL) {
1126 		if (strncmp(name, prefix, strlen(prefix)) == 0)
1127 			return (prefix);
1128 	}
1129 	return (NULL);
1130 }
1131 
1132 /*
1133  * Check if the supplied name is a namespace protected property for the supplied
1134  * element, pe. If it is, return the property name with the namespace stripped,
1135  * otherwise just return the name.
1136  */
1137 const char *
1138 property_name_minus_ns(const pool_elem_t *pe, const char *name)
1139 {
1140 	const char *prefix;
1141 	if ((prefix = is_ns_property(pe, name)) != NULL) {
1142 		return (name + strlen(prefix) + 1);
1143 	}
1144 	return (name);
1145 }
1146 
1147 /*
1148  * Create an element to represent a pool and add it to the supplied
1149  * configuration.
1150  */
1151 pool_t *
1152 pool_create(pool_conf_t *conf, const char *name)
1153 {
1154 	pool_elem_t *pe;
1155 	pool_value_t val = POOL_VALUE_INITIALIZER;
1156 	const pool_prop_t *default_props;
1157 
1158 	if (pool_conf_check(conf) != PO_SUCCESS)
1159 		return (NULL);
1160 
1161 	if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) {
1162 		/*
1163 		 * A pool with the same name exists. Reject.
1164 		 */
1165 		pool_seterror(POE_BADPARAM);
1166 		return (NULL);
1167 	}
1168 	if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_POOL, PREC_INVALID,
1169 	    PCEC_INVALID)) == NULL) {
1170 		pool_seterror(POE_INVALID_CONF);
1171 		return (NULL);
1172 	}
1173 	if ((default_props = provider_get_props(pe)) != NULL) {
1174 		int i;
1175 		for (i = 0; default_props[i].pp_pname != NULL; i++) {
1176 			if (prop_is_init(&default_props[i]) &&
1177 			    (pool_put_any_property(pe,
1178 			    default_props[i].pp_pname,
1179 			    &default_props[i].pp_value) == PO_FAIL)) {
1180 				(void) pool_destroy(conf, pool_elem_pool(pe));
1181 				return (NULL);
1182 			}
1183 		}
1184 	}
1185 	if (pool_value_set_string(&val, name) != PO_SUCCESS) {
1186 		(void) pool_destroy(conf, pool_elem_pool(pe));
1187 		pool_seterror(POE_SYSTEM);
1188 		return (NULL);
1189 	}
1190 	if (pool_put_property(conf, pe, "pool.name", &val) == PO_FAIL) {
1191 		(void) pool_destroy(conf, pool_elem_pool(pe));
1192 		pool_seterror(POE_PUTPROP);
1193 		return (NULL);
1194 	}
1195 
1196 	/*
1197 	 * If we are creating a temporary pool configuration, flag the pool.
1198 	 */
1199 	if (conf->pc_prov->pc_oflags & PO_TEMP) {
1200 		if (pool_set_temporary(conf, pe) == PO_FAIL) {
1201 			(void) pool_destroy(conf, pool_elem_pool(pe));
1202 			return (NULL);
1203 		}
1204 	}
1205 
1206 	return (pool_elem_pool(pe));
1207 }
1208 
1209 /*
1210  * Create an element to represent a res.
1211  */
1212 pool_resource_t *
1213 pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name)
1214 {
1215 	pool_elem_t *pe;
1216 	pool_value_t val = POOL_VALUE_INITIALIZER;
1217 	const pool_prop_t *default_props;
1218 	pool_resource_t **resources;
1219 	int is_default = 0;
1220 	uint_t nelem;
1221 	pool_elem_class_t elem_class;
1222 	pool_resource_elem_class_t type;
1223 	pool_value_t *props[] = { NULL, NULL };
1224 
1225 	if (pool_conf_check(conf) != PO_SUCCESS)
1226 		return (NULL);
1227 
1228 	if ((type = pool_resource_elem_class_from_string(sz_type)) ==
1229 	    PREC_INVALID) {
1230 		pool_seterror(POE_BADPARAM);
1231 		return (NULL);
1232 	}
1233 
1234 	if (strcmp(sz_type, "pset") != 0) {
1235 		pool_seterror(POE_BADPARAM);
1236 		return (NULL);
1237 	}
1238 
1239 	if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) !=
1240 	    NULL) {
1241 		/*
1242 		 * Resources must be unique by name+type.
1243 		 */
1244 		pool_seterror(POE_BADPARAM);
1245 		return (NULL);
1246 	}
1247 
1248 	props[0] = &val;
1249 
1250 	if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS ||
1251 	    pool_value_set_name(props[0], c_type) != PO_SUCCESS) {
1252 		return (NULL);
1253 	}
1254 
1255 	if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) {
1256 		/*
1257 		 * This is the first representative of this type; when it's
1258 		 * created it should be created with 'default' = 'true'.
1259 		 */
1260 		is_default = 1;
1261 	} else {
1262 		free(resources);
1263 	}
1264 	/*
1265 	 * TODO: If Additional PEC_RES_COMP types are added to
1266 	 * pool_impl.h, this would need to be extended.
1267 	 */
1268 	switch (type) {
1269 	case PREC_PSET:
1270 		elem_class = PEC_RES_COMP;
1271 		break;
1272 	default:
1273 		elem_class = PEC_RES_AGG;
1274 		break;
1275 	}
1276 	if ((pe = conf->pc_prov->pc_elem_create(conf, elem_class, type,
1277 	    PCEC_INVALID)) == NULL) {
1278 		pool_seterror(POE_INVALID_CONF);
1279 		return (NULL);
1280 	}
1281 
1282 	/*
1283 	 * The plugins contain a list of default properties and their values
1284 	 * for resources. The resource returned, hence, is fully initialized.
1285 	 */
1286 	if ((default_props = provider_get_props(pe)) != NULL) {
1287 		int i;
1288 		for (i = 0; default_props[i].pp_pname != NULL; i++) {
1289 			if (prop_is_init(&default_props[i]) &&
1290 			    pool_put_any_property(pe, default_props[i].pp_pname,
1291 			    &default_props[i].pp_value) == PO_FAIL) {
1292 				(void) pool_resource_destroy(conf,
1293 				    pool_elem_res(pe));
1294 				return (NULL);
1295 			}
1296 		}
1297 	}
1298 	if (pool_value_set_string(&val, name) != PO_SUCCESS ||
1299 	    pool_put_ns_property(pe, "name", &val) != PO_SUCCESS) {
1300 		(void) pool_resource_destroy(conf, pool_elem_res(pe));
1301 		return (NULL);
1302 	}
1303 	if (is_default) {
1304 		pool_value_set_bool(&val, PO_TRUE);
1305 		if (pool_put_any_ns_property(pe, "default", &val) !=
1306 		    PO_SUCCESS) {
1307 			(void) pool_resource_destroy(conf, pool_elem_res(pe));
1308 			return (NULL);
1309 		}
1310 	}
1311 
1312 	/*
1313 	 * If we are creating a temporary pool configuration, flag the resource.
1314 	 */
1315 	if (conf->pc_prov->pc_oflags & PO_TEMP) {
1316 		if (pool_set_temporary(conf, pe) != PO_SUCCESS) {
1317 			(void) pool_resource_destroy(conf, pool_elem_res(pe));
1318 			return (NULL);
1319 		}
1320 	}
1321 
1322 	return (pool_elem_res(pe));
1323 }
1324 
1325 /*
1326  * Create an element to represent a resource component.
1327  */
1328 pool_component_t *
1329 pool_component_create(pool_conf_t *conf, const pool_resource_t *res,
1330     int64_t sys_id)
1331 {
1332 	pool_elem_t *pe;
1333 	pool_value_t val = POOL_VALUE_INITIALIZER;
1334 	const pool_prop_t *default_props;
1335 	char refbuf[KEY_BUFFER_SIZE];
1336 
1337 	if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_COMP,
1338 	    PREC_INVALID, PCEC_CPU)) == NULL) {
1339 		pool_seterror(POE_INVALID_CONF);
1340 		return (NULL);
1341 	}
1342 	/*
1343 	 * TODO: If additional PEC_COMP types are added in pool_impl.h,
1344 	 * this would need to be extended.
1345 	 */
1346 	pe->pe_component_class = PCEC_CPU;
1347 	/* Now set the container for this comp */
1348 	if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) {
1349 		(void) pool_component_destroy(pool_elem_comp(pe));
1350 		return (NULL);
1351 	}
1352 	/*
1353 	 * The plugins contain a list of default properties and their values
1354 	 * for resources. The resource returned, hence, is fully initialized.
1355 	 */
1356 	if ((default_props = provider_get_props(pe)) != NULL) {
1357 		int i;
1358 		for (i = 0; default_props[i].pp_pname != NULL; i++) {
1359 			if (prop_is_init(&default_props[i]) &&
1360 			    pool_put_any_property(pe,
1361 			    default_props[i].pp_pname,
1362 			    &default_props[i].pp_value) == PO_FAIL) {
1363 				(void) pool_component_destroy(
1364 				    pool_elem_comp(pe));
1365 				return (NULL);
1366 			}
1367 		}
1368 	}
1369 	/*
1370 	 * Set additional attributes/properties on component.
1371 	 */
1372 	pool_value_set_int64(&val, sys_id);
1373 	if (pool_put_any_ns_property(pe, c_sys_prop, &val) != PO_SUCCESS) {
1374 		(void) pool_component_destroy(pool_elem_comp(pe));
1375 		return (NULL);
1376 	}
1377 	if (snprintf(refbuf, KEY_BUFFER_SIZE, "%s_%lld",
1378 	    pool_elem_class_string(pe), sys_id) > KEY_BUFFER_SIZE) {
1379 		(void) pool_component_destroy(pool_elem_comp(pe));
1380 		return (NULL);
1381 	}
1382 	if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) {
1383 		(void) pool_component_destroy(pool_elem_comp(pe));
1384 		return (NULL);
1385 	}
1386 	if (pool_put_any_ns_property(pe, c_ref_id, &val) != PO_SUCCESS) {
1387 		(void) pool_component_destroy(pool_elem_comp(pe));
1388 		return (NULL);
1389 	}
1390 	return (pool_elem_comp(pe));
1391 }
1392 
1393 /*
1394  * Return the location of a configuration.
1395  */
1396 const char *
1397 pool_conf_location(const pool_conf_t *conf)
1398 {
1399 	if (pool_conf_status(conf) == POF_INVALID) {
1400 		pool_seterror(POE_BADPARAM);
1401 		return (NULL);
1402 	}
1403 	return (conf->pc_location);
1404 }
1405 /*
1406  * Close a configuration, freeing all associated resources. Once a
1407  * configuration is closed, it can no longer be used.
1408  */
1409 int
1410 pool_conf_close(pool_conf_t *conf)
1411 {
1412 	int rv;
1413 
1414 	if (pool_conf_status(conf) == POF_INVALID) {
1415 		pool_seterror(POE_BADPARAM);
1416 		return (PO_FAIL);
1417 	}
1418 	rv = conf->pc_prov->pc_close(conf);
1419 	conf->pc_prov = NULL;
1420 	free((void *)conf->pc_location);
1421 	conf->pc_location = NULL;
1422 	conf->pc_state = POF_INVALID;
1423 	return (rv);
1424 }
1425 
1426 /*
1427  * Remove a configuration, freeing all associated resources. Once a
1428  * configuration is removed, it can no longer be accessed and is forever
1429  * gone.
1430  */
1431 int
1432 pool_conf_remove(pool_conf_t *conf)
1433 {
1434 	int rv;
1435 
1436 	if (pool_conf_status(conf) == POF_INVALID) {
1437 		pool_seterror(POE_BADPARAM);
1438 		return (PO_FAIL);
1439 	}
1440 	rv = conf->pc_prov->pc_remove(conf);
1441 	conf->pc_state = POF_INVALID;
1442 	return (rv);
1443 }
1444 
1445 /*
1446  * pool_conf_alloc() allocate the resources to represent a configuration.
1447  */
1448 pool_conf_t *
1449 pool_conf_alloc(void)
1450 {
1451 	pool_conf_t *conf;
1452 
1453 	if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) {
1454 		pool_seterror(POE_SYSTEM);
1455 		return (NULL);
1456 	}
1457 	conf->pc_state = POF_INVALID;
1458 	return (conf);
1459 }
1460 
1461 /*
1462  * pool_conf_free() frees the resources associated with a configuration.
1463  */
1464 void
1465 pool_conf_free(pool_conf_t *conf)
1466 {
1467 	free(conf);
1468 }
1469 
1470 /*
1471  * pool_conf_open() opens a configuration, establishing all required
1472  * connections to the data source.
1473  */
1474 int
1475 pool_conf_open(pool_conf_t *conf, const char *location, int oflags)
1476 {
1477 	/*
1478 	 * Since you can't do anything to a pool configuration without opening
1479 	 * it, this represents a good point to intialise structures that would
1480 	 * otherwise need to be initialised in a .init section.
1481 	 */
1482 	internal_init();
1483 
1484 	if (pool_conf_status(conf) != POF_INVALID) {
1485 		/*
1486 		 * Already opened configuration, return PO_FAIL
1487 		 */
1488 		pool_seterror(POE_BADPARAM);
1489 		return (PO_FAIL);
1490 	}
1491 	if (oflags & ~(PO_RDONLY | PO_RDWR | PO_CREAT | PO_DISCO | PO_UPDATE |
1492 	    PO_TEMP)) {
1493 		pool_seterror(POE_BADPARAM);
1494 		return (PO_FAIL);
1495 	}
1496 
1497 	/*
1498 	 * Creating a configuration implies read-write access, so make
1499 	 * sure that PO_RDWR is set in addition if PO_CREAT is set.
1500 	 */
1501 	if (oflags & PO_CREAT)
1502 		oflags |= PO_RDWR;
1503 
1504 	/* location is ignored when creating a temporary configuration */
1505 	if (oflags & PO_TEMP)
1506 		location = "";
1507 
1508 	if ((conf->pc_location = strdup(location)) == NULL) {
1509 		pool_seterror(POE_SYSTEM);
1510 		return (PO_FAIL);
1511 	}
1512 	/*
1513 	 * This is the crossover point into the actual data provider
1514 	 * implementation, allocate a data provider of the appropriate
1515 	 * type for your data storage medium. In this case it's either a kernel
1516 	 * or xml data provider. To use a different data provider, write some
1517 	 * code to implement all the required interfaces and then change the
1518 	 * following code to allocate a data provider which uses your new code.
1519 	 * All data provider routines can be static, apart from the allocation
1520 	 * routine.
1521 	 *
1522 	 * For temporary pools (PO_TEMP) we start with a copy of the current
1523 	 * dynamic configuration and do all of the updates in-memory.
1524 	 */
1525 	if (oflags & PO_TEMP) {
1526 		if (pool_knl_connection_alloc(conf, PO_TEMP) != PO_SUCCESS) {
1527 			conf->pc_state = POF_INVALID;
1528 			return (PO_FAIL);
1529 		}
1530 		/* set rdwr flag so we can updated the in-memory config. */
1531 		conf->pc_prov->pc_oflags |= PO_RDWR;
1532 
1533 	} else if (strcmp(location, pool_dynamic_location()) == 0) {
1534 		if (pool_knl_connection_alloc(conf, oflags) != PO_SUCCESS) {
1535 			conf->pc_state = POF_INVALID;
1536 			return (PO_FAIL);
1537 		}
1538 	} else {
1539 		if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) {
1540 			conf->pc_state = POF_INVALID;
1541 			return (PO_FAIL);
1542 		}
1543 	}
1544 	return (PO_SUCCESS);
1545 }
1546 
1547 /*
1548  * Rollback a configuration. This will undo all changes to the configuration
1549  * since the last time pool_conf_commit was called.
1550  */
1551 int
1552 pool_conf_rollback(pool_conf_t *conf)
1553 {
1554 	if (pool_conf_status(conf) == POF_INVALID) {
1555 		pool_seterror(POE_BADPARAM);
1556 		return (PO_FAIL);
1557 	}
1558 	return (conf->pc_prov->pc_rollback(conf));
1559 }
1560 
1561 /*
1562  * Commit a configuration. This will apply all changes to the
1563  * configuration to the permanent data store. The active parameter
1564  * indicates whether the configuration should be used to update the
1565  * dynamic configuration from the supplied (static) configuration or
1566  * whether it should be written back to persistent store.
1567  */
1568 int
1569 pool_conf_commit(pool_conf_t *conf, int active)
1570 {
1571 	int retval;
1572 
1573 	if (pool_conf_status(conf) == POF_INVALID) {
1574 		pool_seterror(POE_BADPARAM);
1575 		return (PO_FAIL);
1576 	}
1577 	if (active) {
1578 		int oflags;
1579 
1580 		if (conf_is_dynamic(conf) == PO_TRUE) {
1581 			pool_seterror(POE_BADPARAM);
1582 			return (PO_FAIL);
1583 		}
1584 		/*
1585 		 * Pretend that the configuration was opened PO_RDWR
1586 		 * so that a configuration which was opened PO_RDONLY
1587 		 * can be committed. The original flags are preserved
1588 		 * in oflags and restored after pool_conf_commit_sys()
1589 		 * returns.
1590 		 */
1591 		oflags = conf->pc_prov->pc_oflags;
1592 		conf->pc_prov->pc_oflags |= PO_RDWR;
1593 		retval = pool_conf_commit_sys(conf, active);
1594 		conf->pc_prov->pc_oflags = oflags;
1595 	} else {
1596 		/*
1597 		 * Write the configuration back to the backing store.
1598 		 */
1599 		retval =  conf->pc_prov->pc_commit(conf);
1600 	}
1601 	return (retval);
1602 }
1603 
1604 /*
1605  * Export a configuration. This will export a configuration in the specified
1606  * format (fmt) to the specified location.
1607  */
1608 int
1609 pool_conf_export(const pool_conf_t *conf, const char *location,
1610     pool_export_format_t fmt)
1611 {
1612 	if (pool_conf_status(conf) == POF_INVALID) {
1613 		pool_seterror(POE_BADPARAM);
1614 		return (PO_FAIL);
1615 	}
1616 	return (conf->pc_prov->pc_export(conf, location, fmt));
1617 }
1618 
1619 /*
1620  * Validate a configuration. This will validate a configuration at the
1621  * specified level.
1622  */
1623 int
1624 pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level)
1625 {
1626 	if (pool_conf_status(conf) == POF_INVALID) {
1627 		pool_seterror(POE_BADPARAM);
1628 		return (PO_FAIL);
1629 	}
1630 	return (conf->pc_prov->pc_validate(conf, level));
1631 }
1632 
1633 /*
1634  * Update the snapshot of a configuration. This can only be used on a
1635  * dynamic configuration.
1636  */
1637 int
1638 pool_conf_update(const pool_conf_t *conf, int *changed)
1639 {
1640 	if (pool_conf_status(conf) == POF_INVALID ||
1641 	    conf_is_dynamic(conf) == PO_FALSE) {
1642 		pool_seterror(POE_BADPARAM);
1643 		return (PO_FAIL);
1644 	}
1645 	/*
1646 	 * Since this function only makes sense for dynamic
1647 	 * configurations, just call directly into the appropriate
1648 	 * function. This could be added into the pool_connection_t
1649 	 * interface if it was ever required.
1650 	 */
1651 	if (changed)
1652 		*changed = 0;
1653 	return (pool_knl_update((pool_conf_t *)conf, changed));
1654 }
1655 
1656 /*
1657  * Walk the properties of the supplied elem, calling the user supplied
1658  * function repeatedly as long as the user function returns
1659  * PO_SUCCESS.
1660  */
1661 int
1662 pool_walk_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg,
1663     int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *,
1664 	pool_value_t *, void *))
1665 {
1666 	return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0));
1667 }
1668 
1669 void
1670 free_value_list(int npvals, pool_value_t **pvals)
1671 {
1672 	int j;
1673 
1674 	for (j = 0; j < npvals; j++) {
1675 		if (pvals[j])
1676 			pool_value_free(pvals[j]);
1677 	}
1678 	free(pvals);
1679 }
1680 
1681 /*
1682  * Walk the properties of the supplied elem, calling the user supplied
1683  * function repeatedly as long as the user function returns
1684  * PO_SUCCESS.
1685  * The list of properties to be walked is retrieved from the element
1686  */
1687 int
1688 pool_walk_any_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg,
1689     int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *,
1690 	pool_value_t *, void *), int any)
1691 {
1692 	pool_value_t **pvals;
1693 	int i;
1694 	const pool_prop_t *props = provider_get_props(elem);
1695 	uint_t npvals;
1696 
1697 	if (pool_conf_status(conf) == POF_INVALID) {
1698 		pool_seterror(POE_BADPARAM);
1699 		return (PO_FAIL);
1700 	}
1701 
1702 	if (props == NULL) {
1703 		pool_seterror(POE_INVALID_CONF);
1704 		return (PO_FAIL);
1705 	}
1706 
1707 	if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL)
1708 		return (PO_FAIL);
1709 
1710 	/*
1711 	 * Now walk the managed properties. As we find managed
1712 	 * properties removed them from the list of all properties to
1713 	 * prevent duplication.
1714 	 */
1715 	for (i = 0;  props[i].pp_pname != NULL; i++) {
1716 		int j;
1717 
1718 		/*
1719 		 * Special processing for type
1720 		 */
1721 		if (strcmp(props[i].pp_pname, c_type) == 0) {
1722 			pool_value_t val = POOL_VALUE_INITIALIZER;
1723 
1724 			if (pool_value_set_name(&val, props[i].pp_pname) ==
1725 			    PO_FAIL) {
1726 				free_value_list(npvals, pvals);
1727 				return (PO_FAIL);
1728 			}
1729 			if (props[i].pp_op.ppo_get_value(elem, &val) ==
1730 			    PO_FAIL) {
1731 				free_value_list(npvals, pvals);
1732 				return (PO_FAIL);
1733 			}
1734 			if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) {
1735 				if (prop_callback(conf, elem, props[i].pp_pname,
1736 				    &val, arg) != PO_SUCCESS) {
1737 					free_value_list(npvals, pvals);
1738 					pool_seterror(POE_BADPARAM);
1739 					return (PO_FAIL);
1740 				}
1741 			}
1742 			continue;
1743 		}
1744 
1745 		for (j = 0; j < npvals; j++) {
1746 			if (pvals[j] && strcmp(pool_value_get_name(pvals[j]),
1747 			    props[i].pp_pname) == 0)
1748 				break;
1749 		}
1750 		/*
1751 		 * If we have found the property, then j < npvals. Process it
1752 		 * according to our property attributes. Otherwise, it's not
1753 		 * a managed property, so just ignore it until later.
1754 		 */
1755 		if (j < npvals) {
1756 			if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) {
1757 				if (props[i].pp_op.ppo_get_value) {
1758 					if (pool_value_set_name(pvals[j],
1759 					props[i].pp_pname) == PO_FAIL) {
1760 						free_value_list(npvals, pvals);
1761 						return (PO_FAIL);
1762 					}
1763 					if (props[i].pp_op.ppo_get_value(elem,
1764 					    pvals[j]) == PO_FAIL) {
1765 						free_value_list(npvals, pvals);
1766 						return (PO_FAIL);
1767 					}
1768 				}
1769 				if (prop_callback(conf, elem, props[i].pp_pname,
1770 				    pvals[j], arg) != PO_SUCCESS) {
1771 					free_value_list(npvals, pvals);
1772 					pool_seterror(POE_BADPARAM);
1773 					return (PO_FAIL);
1774 				}
1775 			}
1776 			pool_value_free(pvals[j]);
1777 			pvals[j] = NULL;
1778 		}
1779 	}
1780 	for (i = 0;  i < npvals; i++) {
1781 		if (pvals[i]) {
1782 			const char *name = pool_value_get_name(pvals[i]);
1783 			char *qname = strrchr(name, '.');
1784 			if ((qname && qname[1] != '_') ||
1785 			    (!qname && name[0] != '_')) {
1786 				if (prop_callback(conf, elem, name, pvals[i],
1787 				    arg) != PO_SUCCESS) {
1788 					free_value_list(npvals, pvals);
1789 					pool_seterror(POE_BADPARAM);
1790 					return (PO_FAIL);
1791 				}
1792 			}
1793 			pool_value_free(pvals[i]);
1794 			pvals[i] = NULL;
1795 		}
1796 	}
1797 	free(pvals);
1798 	return (PO_SUCCESS);
1799 }
1800 
1801 /*
1802  * Return a pool, searching the supplied configuration for a pool with the
1803  * supplied name. The search is case sensitive.
1804  */
1805 pool_t *
1806 pool_get_pool(const pool_conf_t *conf, const char *name)
1807 {
1808 	pool_value_t *props[] = { NULL, NULL };
1809 	pool_t **rs;
1810 	pool_t *ret;
1811 	uint_t size = 0;
1812 	pool_value_t val = POOL_VALUE_INITIALIZER;
1813 
1814 	props[0] = &val;
1815 
1816 	if (pool_conf_status(conf) == POF_INVALID) {
1817 		pool_seterror(POE_BADPARAM);
1818 		return (NULL);
1819 	}
1820 
1821 	if (pool_value_set_name(props[0], "pool.name") != PO_SUCCESS ||
1822 	    pool_value_set_string(props[0], name) != PO_SUCCESS) {
1823 		return (NULL);
1824 	}
1825 	rs = pool_query_pools(conf, &size, props);
1826 	if (rs == NULL) { /* Can't find a pool to match the name */
1827 		return (NULL);
1828 	}
1829 	if (size != 1) {
1830 		free(rs);
1831 		pool_seterror(POE_INVALID_CONF);
1832 		return (NULL);
1833 	}
1834 	ret = rs[0];
1835 	free(rs);
1836 	return (ret);
1837 }
1838 
1839 /*
1840  * Return a result set of pools, searching the supplied configuration
1841  * for pools which match the supplied property criteria. props is a null
1842  * terminated list of properties which will be used to match qualifying
1843  * pools. size is updated with the size of the pool
1844  */
1845 pool_t **
1846 pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props)
1847 {
1848 	pool_result_set_t *rs;
1849 	pool_elem_t *pe;
1850 	pool_t **result = NULL;
1851 	int i = 0;
1852 
1853 	if (pool_conf_status(conf) == POF_INVALID) {
1854 		pool_seterror(POE_BADPARAM);
1855 		return (NULL);
1856 	}
1857 	rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props);
1858 	if (rs == NULL) {
1859 		return (NULL);
1860 	}
1861 	if ((*size = pool_rs_count(rs)) == 0) {
1862 		(void) pool_rs_close(rs);
1863 		return (NULL);
1864 	}
1865 	if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) {
1866 		pool_seterror(POE_SYSTEM);
1867 		(void) pool_rs_close(rs);
1868 		return (NULL);
1869 	}
1870 	(void) memset(result, 0, sizeof (pool_t *) * (*size + 1));
1871 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
1872 		if (pool_elem_class(pe) != PEC_POOL) {
1873 			pool_seterror(POE_INVALID_CONF);
1874 			free(result);
1875 			(void) pool_rs_close(rs);
1876 			return (NULL);
1877 		}
1878 		result[i++] = pool_elem_pool(pe);
1879 	}
1880 	(void) pool_rs_close(rs);
1881 	return (result);
1882 }
1883 
1884 /*
1885  * Return an res, searching the supplied configuration for an res with the
1886  * supplied name. The search is case sensitive.
1887  */
1888 pool_resource_t *
1889 pool_get_resource(const pool_conf_t *conf, const char *sz_type,
1890     const char *name)
1891 {
1892 	pool_value_t *props[] = { NULL, NULL, NULL };
1893 	pool_resource_t **rs;
1894 	pool_resource_t *ret;
1895 	uint_t size = 0;
1896 	char_buf_t *cb = NULL;
1897 	pool_value_t val0 = POOL_VALUE_INITIALIZER;
1898 	pool_value_t val1 = POOL_VALUE_INITIALIZER;
1899 
1900 	if (pool_conf_status(conf) == POF_INVALID) {
1901 		pool_seterror(POE_BADPARAM);
1902 		return (NULL);
1903 	}
1904 
1905 	if (sz_type == NULL) {
1906 		pool_seterror(POE_BADPARAM);
1907 		return (NULL);
1908 	}
1909 
1910 	props[0] = &val0;
1911 	props[1] = &val1;
1912 
1913 	if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS ||
1914 	    pool_value_set_name(props[0], c_type) != PO_SUCCESS)
1915 		return (NULL);
1916 
1917 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1918 		return (NULL);
1919 	}
1920 	if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) {
1921 		free_char_buf(cb);
1922 		return (NULL);
1923 	}
1924 	if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) {
1925 		free_char_buf(cb);
1926 		return (NULL);
1927 	}
1928 	if (pool_value_set_string(props[1], name) != PO_SUCCESS) {
1929 		free_char_buf(cb);
1930 		return (NULL);
1931 	}
1932 	free_char_buf(cb);
1933 	rs = pool_query_resources(conf, &size, props);
1934 	if (rs == NULL) {
1935 		return (NULL);
1936 	}
1937 	if (size != 1) {
1938 		free(rs);
1939 		pool_seterror(POE_INVALID_CONF);
1940 		return (NULL);
1941 	}
1942 	ret = rs[0];
1943 	free(rs);
1944 	return (ret);
1945 }
1946 
1947 /*
1948  * Return a result set of res (actually as pool_elem_ts), searching the
1949  * supplied configuration for res which match the supplied property
1950  * criteria. props is a null terminated list of properties which will be used
1951  * to match qualifying res.
1952  */
1953 pool_resource_t **
1954 pool_query_resources(const pool_conf_t *conf, uint_t *size,
1955     pool_value_t **props)
1956 {
1957 	pool_result_set_t *rs;
1958 	pool_elem_t *pe;
1959 	pool_resource_t **result = NULL;
1960 	int i = 0;
1961 
1962 	if (pool_conf_status(conf) == POF_INVALID) {
1963 		pool_seterror(POE_BADPARAM);
1964 		return (NULL);
1965 	}
1966 
1967 	*size = 0;
1968 
1969 	rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props);
1970 	if (rs == NULL) {
1971 		return (NULL);
1972 	}
1973 	if ((*size = pool_rs_count(rs)) == 0) {
1974 		(void) pool_rs_close(rs);
1975 		return (NULL);
1976 	}
1977 	if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1)))
1978 	    == NULL) {
1979 		pool_seterror(POE_SYSTEM);
1980 		(void) pool_rs_close(rs);
1981 		return (NULL);
1982 	}
1983 	(void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1));
1984 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
1985 		if (pool_elem_class(pe) != PEC_RES_COMP &&
1986 		    pool_elem_class(pe) != PEC_RES_AGG) {
1987 			pool_seterror(POE_INVALID_CONF);
1988 			free(result);
1989 			(void) pool_rs_close(rs);
1990 			return (NULL);
1991 		}
1992 		result[i++] = pool_elem_res(pe);
1993 	}
1994 	(void) pool_rs_close(rs);
1995 	return (result);
1996 }
1997 
1998 /*
1999  * Return a result set of comp (actually as pool_elem_ts), searching the
2000  * supplied configuration for comp which match the supplied property
2001  * criteria. props is a null terminated list of properties which will be used
2002  * to match qualifying comp.
2003  */
2004 pool_component_t **
2005 pool_query_components(const pool_conf_t *conf, uint_t *size,
2006     pool_value_t **props)
2007 {
2008 	return (pool_query_resource_components(conf, NULL, size, props));
2009 }
2010 
2011 /*
2012  * Destroy a pool. If the pool cannot be found or removed an error is
2013  * returned. This is basically a wrapper around pool_elem_remove to ensure
2014  * some type safety for the pool subtype.
2015  */
2016 int
2017 pool_destroy(pool_conf_t *conf, pool_t *pp)
2018 {
2019 	pool_elem_t *pe;
2020 
2021 	if (pool_conf_check(conf) != PO_SUCCESS)
2022 		return (PO_FAIL);
2023 
2024 	pe = TO_ELEM(pp);
2025 
2026 	/*
2027 	 * Cannot destroy the default pool.
2028 	 */
2029 	if (elem_is_default(pe) == PO_TRUE) {
2030 		pool_seterror(POE_BADPARAM);
2031 		return (PO_FAIL);
2032 	}
2033 	if (pool_elem_remove(pe) != PO_SUCCESS)
2034 		return (PO_FAIL);
2035 	return (PO_SUCCESS);
2036 }
2037 
2038 /*
2039  * Destroy an res. If the res cannot be found or removed an error is
2040  * returned. This is basically a wrapper around pool_elem_remove to ensure
2041  * some type safety for the res subtype.
2042  */
2043 int
2044 pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs)
2045 {
2046 	pool_elem_t *pe;
2047 	pool_component_t **rl;
2048 	uint_t res_size;
2049 	pool_t **pl;
2050 	uint_t npool;
2051 	int i;
2052 
2053 	if (pool_conf_check(conf) != PO_SUCCESS)
2054 		return (PO_FAIL);
2055 
2056 	pe = TO_ELEM(prs);
2057 
2058 	if (resource_is_system(prs) == PO_TRUE) {
2059 		pool_seterror(POE_BADPARAM);
2060 		return (PO_FAIL);
2061 	}
2062 	/*
2063 	 * Walk all the pools and dissociate any pools which are using
2064 	 * this resource.
2065 	 */
2066 	if ((pl = pool_query_pools(conf, &npool, NULL)) != NULL) {
2067 		for (i = 0; i < npool; i++) {
2068 			pool_resource_t **rl;
2069 			uint_t nres;
2070 			int j;
2071 
2072 			if ((rl = pool_query_pool_resources(conf, pl[i], &nres,
2073 			    NULL)) != NULL) {
2074 				for (j = 0; j < nres; j++) {
2075 					if (rl[j] == prs) {
2076 						if (pool_dissociate(conf, pl[i],
2077 						    rl[j]) != PO_SUCCESS) {
2078 							free(rl);
2079 							free(pl);
2080 							return (PO_FAIL);
2081 						}
2082 						break;
2083 					}
2084 				}
2085 			free(rl);
2086 			}
2087 		}
2088 		free(pl);
2089 	}
2090 	if (pe->pe_class == PEC_RES_COMP) {
2091 		pool_resource_t *default_set_res;
2092 
2093 		/*
2094 		 * Use the xtransfer option to move comp around
2095 		 */
2096 		default_set_res = (pool_resource_t *)get_default_resource(prs);
2097 
2098 		if ((rl = pool_query_resource_components(conf, prs, &res_size,
2099 		    NULL)) != NULL) {
2100 			int ostate = conf->pc_state;
2101 			conf->pc_state = POF_DESTROY;
2102 			if (pool_resource_xtransfer(conf, prs, default_set_res,
2103 			    rl) == PO_FAIL) {
2104 				free(rl);
2105 				conf->pc_state = ostate;
2106 				return (PO_FAIL);
2107 			}
2108 			conf->pc_state = ostate;
2109 			free(rl);
2110 		}
2111 	}
2112 	if (pool_elem_remove(pe) != PO_SUCCESS)
2113 		return (PO_FAIL);
2114 	return (PO_SUCCESS);
2115 }
2116 
2117 /*
2118  * Destroy a comp. If the comp cannot be found or removed an error is
2119  * returned. This is basically a wrapper around pool_elem_remove to ensure
2120  * some type safety for the comp subtype.
2121  */
2122 int
2123 pool_component_destroy(pool_component_t *pr)
2124 {
2125 	pool_elem_t *pe = TO_ELEM(pr);
2126 
2127 	if (pool_elem_remove(pe) != PO_SUCCESS)
2128 		return (PO_FAIL);
2129 	return (PO_SUCCESS);
2130 }
2131 
2132 /*
2133  * Remove a pool_elem_t from a configuration. This has been "hidden" away as
2134  * a static routine since the only elements which are currently being removed
2135  * are pools, res & comp and the wrapper functions above provide type-safe
2136  * access. However, if there is a need to remove other types of elements
2137  * then this could be promoted to pool_impl.h or more wrappers could
2138  * be added to pool_impl.h.
2139  */
2140 int
2141 pool_elem_remove(pool_elem_t *pe)
2142 {
2143 	return (pe->pe_remove(pe));
2144 }
2145 
2146 /*
2147  * Execute a query to search for a qualifying set of elements.
2148  */
2149 pool_result_set_t *
2150 pool_exec_query(const pool_conf_t *conf, const pool_elem_t *src,
2151     const char *src_attr, pool_elem_class_t classes, pool_value_t **props)
2152 {
2153 	return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes,
2154 	    props));
2155 }
2156 
2157 /*
2158  * Get the next result from a result set of elements.
2159  */
2160 pool_elem_t *
2161 pool_rs_next(pool_result_set_t *set)
2162 {
2163 	return (set->prs_next(set));
2164 }
2165 
2166 /*
2167  * Get the previous result from a result set of elements.
2168  */
2169 pool_elem_t *
2170 pool_rs_prev(pool_result_set_t *set)
2171 {
2172 	return (set->prs_prev(set));
2173 }
2174 
2175 /*
2176  * Get the first result from a result set of elements.
2177  */
2178 pool_elem_t *
2179 pool_rs_first(pool_result_set_t *set)
2180 {
2181 	return (set->prs_first(set));
2182 }
2183 
2184 /*
2185  * Get the last result from a result set of elements.
2186  */
2187 pool_elem_t *
2188 pool_rs_last(pool_result_set_t *set)
2189 {
2190 	return (set->prs_last(set));
2191 }
2192 
2193 
2194 /*
2195  * Get the count for a result set of elements.
2196  */
2197 int
2198 pool_rs_count(pool_result_set_t *set)
2199 {
2200 	return (set->prs_count(set));
2201 }
2202 
2203 /*
2204  * Get the index for a result set of elements.
2205  */
2206 int
2207 pool_rs_get_index(pool_result_set_t *set)
2208 {
2209 	return (set->prs_get_index(set));
2210 }
2211 
2212 /*
2213  * Set the index for a result set of elements.
2214  */
2215 int
2216 pool_rs_set_index(pool_result_set_t *set, int index)
2217 {
2218 	return (set->prs_set_index(set, index));
2219 }
2220 
2221 /*
2222  * Close a result set of elements, freeing all associated resources.
2223  */
2224 int
2225 pool_rs_close(pool_result_set_t *set)
2226 {
2227 	return (set->prs_close(set));
2228 }
2229 
2230 /*
2231  * When transferring resource components using pool_resource_transfer,
2232  * this function is invoked to choose which actual components will be
2233  * transferred.
2234  */
2235 int
2236 choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size)
2237 {
2238 	pool_component_t **components = NULL, *moved[] = { NULL, NULL };
2239 	int i;
2240 	uint_t ncomponent;
2241 	pool_conf_t *conf = TO_CONF(TO_ELEM(src));
2242 
2243 	if (size == 0)
2244 		return (PO_SUCCESS);
2245 	/*
2246 	 * Get the component list from our src component.
2247 	 */
2248 	if ((components = pool_query_resource_components(conf, src, &ncomponent,
2249 	    NULL)) == NULL) {
2250 		pool_seterror(POE_BADPARAM);
2251 		return (PO_FAIL);
2252 	}
2253 	qsort(components, ncomponent, sizeof (pool_elem_t *),
2254 	    qsort_elem_compare);
2255 	/*
2256 	 * Components that aren't specifically requested by the resource
2257 	 * should be transferred out first.
2258 	 */
2259 	for (i = 0; size > 0 && components[i] != NULL; i++) {
2260 		if (!cpu_is_requested(components[i])) {
2261 			moved[0] = components[i];
2262 			if (pool_resource_xtransfer(conf, src, dst, moved) ==
2263 			    PO_SUCCESS) {
2264 				size--;
2265 			}
2266 		}
2267 	}
2268 
2269 	/*
2270 	 * If we couldn't find enough "un-requested" components, select random
2271 	 * requested components.
2272 	 */
2273 	for (i = 0; size > 0 && components[i] != NULL; i++) {
2274 		if (cpu_is_requested(components[i])) {
2275 			moved[0] = components[i];
2276 			if (pool_resource_xtransfer(conf, src, dst, moved) ==
2277 			    PO_SUCCESS) {
2278 				size--;
2279 			}
2280 		}
2281 	}
2282 
2283 	free(components);
2284 	/*
2285 	 * If we couldn't transfer out all the resources we asked for, then
2286 	 * return error.
2287 	 */
2288 	return (size == 0 ? PO_SUCCESS : PO_FAIL);
2289 }
2290 
2291 /*
2292  * Common processing for a resource transfer (xfer or xxfer).
2293  *
2294  * - Return XFER_CONTINUE if the transfer should proceeed
2295  * - Return XFER_FAIL if the transfer should be stopped in failure
2296  * - Return XFER_SUCCESS if the transfer should be stopped in success
2297  */
2298 int
2299 setup_transfer(pool_conf_t *conf, pool_resource_t *src, pool_resource_t *tgt,
2300     uint64_t size, uint64_t *src_size, uint64_t *tgt_size)
2301 {
2302 	uint64_t src_min;
2303 	uint64_t tgt_max;
2304 
2305 	if (pool_conf_check(conf) != PO_SUCCESS)
2306 		return (XFER_FAIL);
2307 
2308 	/*
2309 	 * Makes sure the two resources are of the same type
2310 	 */
2311 	if (pool_resource_elem_class(TO_ELEM(src)) !=
2312 	    pool_resource_elem_class(TO_ELEM(tgt))) {
2313 		pool_seterror(POE_BADPARAM);
2314 		return (XFER_FAIL);
2315 	}
2316 
2317 	/*
2318 	 * Transferring to yourself is a no-op
2319 	 */
2320 	if (src == tgt)
2321 		return (XFER_SUCCESS);
2322 
2323 	/*
2324 	 * Transferring nothing is a no-op
2325 	 */
2326 	if (size == 0)
2327 		return (XFER_SUCCESS);
2328 
2329 	if (resource_get_min(src, &src_min) != PO_SUCCESS ||
2330 	    resource_get_size(src, src_size) != PO_SUCCESS ||
2331 	    resource_get_max(tgt, &tgt_max) != PO_SUCCESS ||
2332 	    resource_get_size(tgt, tgt_size) != PO_SUCCESS) {
2333 		pool_seterror(POE_BADPARAM);
2334 		return (XFER_FAIL);
2335 	}
2336 	if (pool_conf_status(conf) != POF_DESTROY) {
2337 		/*
2338 		 * src_size - donating >= src.min
2339 		 * size + receiving <= tgt.max (except for default)
2340 		 */
2341 #ifdef DEBUG
2342 		dprintf("conf is %s\n", pool_conf_location(conf));
2343 		dprintf("setup_transfer: src_size %llu\n", *src_size);
2344 		pool_elem_dprintf(TO_ELEM(src));
2345 		dprintf("setup_transfer: tgt_size %llu\n", *tgt_size);
2346 		pool_elem_dprintf(TO_ELEM(tgt));
2347 #endif	/* DEBUG */
2348 		if (*src_size - size < src_min ||
2349 		    (resource_is_default(tgt) == PO_FALSE &&
2350 			*tgt_size + size > tgt_max)) {
2351 			pool_seterror(POE_INVALID_CONF);
2352 			return (XFER_FAIL);
2353 		}
2354 	}
2355 	return (XFER_CONTINUE);
2356 }
2357 
2358 /*
2359  * Transfer resource quantities from one resource set to another.
2360  */
2361 int
2362 pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src,
2363     pool_resource_t *tgt, uint64_t size)
2364 {
2365 	uint64_t src_size;
2366 	uint64_t tgt_size;
2367 	int ret;
2368 
2369 	if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2370 	    != XFER_CONTINUE)
2371 		return (ret);
2372 	/*
2373 	 * If this resource is a res_comp we must call move components
2374 	 */
2375 	if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP)
2376 		return (choose_components(src, tgt, size));
2377 	/*
2378 	 * Now do the transfer.
2379 	 */
2380 	ret = conf->pc_prov->pc_res_xfer(src, tgt, size);
2381 	/*
2382 	 * Modify the sizes of the resource sets if the process was
2383 	 * successful
2384 	 */
2385 	if (ret == PO_SUCCESS) {
2386 		pool_value_t val = POOL_VALUE_INITIALIZER;
2387 
2388 		src_size -= size;
2389 		tgt_size += size;
2390 		pool_value_set_uint64(&val, src_size);
2391 		(void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop,
2392 		    &val);
2393 		pool_value_set_uint64(&val, tgt_size);
2394 		(void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop,
2395 		    &val);
2396 	}
2397 	return (ret);
2398 }
2399 
2400 /*
2401  * Transfer resource components from one resource set to another.
2402  */
2403 int
2404 pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src,
2405     pool_resource_t *tgt,
2406     pool_component_t **rl)
2407 {
2408 	int i;
2409 	uint64_t src_size;
2410 	uint64_t tgt_size;
2411 	uint64_t size;
2412 	int ret;
2413 
2414 	/*
2415 	 * Make sure the components are all contained in 'src'. This
2416 	 * processing must be done before setup_transfer so that size
2417 	 * is known.
2418 	 */
2419 	for (i = 0; rl[i] != NULL; i++) {
2420 #ifdef DEBUG
2421 		dprintf("resource xtransfer\n");
2422 		dprintf("in conf %s\n", pool_conf_location(conf));
2423 		dprintf("transferring component\n");
2424 		pool_elem_dprintf(TO_ELEM(rl[i]));
2425 		dprintf("from\n");
2426 		pool_elem_dprintf(TO_ELEM(src));
2427 		dprintf("to\n");
2428 		pool_elem_dprintf(TO_ELEM(tgt));
2429 #endif	/* DEBUG */
2430 
2431 		if (pool_get_owning_resource(conf, rl[i]) != src) {
2432 			pool_seterror(POE_BADPARAM);
2433 			return (PO_FAIL);
2434 		}
2435 	}
2436 
2437 	size = (uint64_t)i;
2438 
2439 	if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2440 	    != XFER_CONTINUE)
2441 		return (ret);
2442 
2443 	ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl);
2444 	/*
2445 	 * Modify the sizes of the resource sets if the process was
2446 	 * successful
2447 	 */
2448 	if (ret == PO_SUCCESS) {
2449 		pool_value_t val = POOL_VALUE_INITIALIZER;
2450 
2451 #ifdef DEBUG
2452 		dprintf("src_size %llu\n", src_size);
2453 		dprintf("tgt_size %llu\n", tgt_size);
2454 		dprintf("size %llu\n", size);
2455 #endif	/* DEBUG */
2456 		src_size -= size;
2457 		tgt_size += size;
2458 		pool_value_set_uint64(&val, src_size);
2459 		(void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop,
2460 		    &val);
2461 		pool_value_set_uint64(&val, tgt_size);
2462 		(void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop,
2463 		    &val);
2464 	}
2465 	return (ret);
2466 }
2467 
2468 /*
2469  * Find the owning resource for a resource component.
2470  */
2471 pool_resource_t *
2472 pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp)
2473 {
2474 	if (pool_conf_status(conf) == POF_INVALID) {
2475 		pool_seterror(POE_BADPARAM);
2476 		return (NULL);
2477 	}
2478 	return (pool_elem_res(pool_get_container(TO_ELEM(comp))));
2479 }
2480 
2481 /*
2482  * pool_get_container() returns the container of pc.
2483  */
2484 pool_elem_t *
2485 pool_get_container(const pool_elem_t *pc)
2486 {
2487 	return (pc->pe_get_container(pc));
2488 }
2489 
2490 /*
2491  * pool_set_container() moves pc so that it is contained by pp.
2492  *
2493  * Returns PO_SUCCESS/PO_FAIL
2494  */
2495 int
2496 pool_set_container(pool_elem_t *pp, pool_elem_t *pc)
2497 {
2498 	return (pc->pe_set_container(pp, pc));
2499 }
2500 
2501 /*
2502  * Conversion routines for converting to and from elem and it's various
2503  * subtypes of system, pool, res and comp.
2504  */
2505 pool_elem_t *
2506 pool_system_elem(const pool_system_t *ph)
2507 {
2508 	return ((pool_elem_t *)ph);
2509 }
2510 
2511 pool_elem_t *
2512 pool_conf_to_elem(const pool_conf_t *conf)
2513 {
2514 	pool_system_t *sys;
2515 
2516 	if (pool_conf_status(conf) == POF_INVALID) {
2517 		pool_seterror(POE_BADPARAM);
2518 		return (NULL);
2519 	}
2520 	if ((sys = pool_conf_system(conf)) == NULL) {
2521 		pool_seterror(POE_BADPARAM);
2522 		return (NULL);
2523 	}
2524 	return (pool_system_elem(sys));
2525 }
2526 
2527 pool_elem_t *
2528 pool_to_elem(const pool_conf_t *conf, const pool_t *pp)
2529 {
2530 	if (pool_conf_status(conf) == POF_INVALID) {
2531 		pool_seterror(POE_BADPARAM);
2532 		return (NULL);
2533 	}
2534 	return ((pool_elem_t *)pp);
2535 }
2536 
2537 pool_elem_t *
2538 pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs)
2539 {
2540 	if (pool_conf_status(conf) == POF_INVALID) {
2541 		pool_seterror(POE_BADPARAM);
2542 		return (NULL);
2543 	}
2544 	return ((pool_elem_t *)prs);
2545 }
2546 
2547 pool_elem_t *
2548 pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr)
2549 {
2550 	if (pool_conf_status(conf) == POF_INVALID) {
2551 		pool_seterror(POE_BADPARAM);
2552 		return (NULL);
2553 	}
2554 	return ((pool_elem_t *)pr);
2555 }
2556 
2557 /*
2558  * Walk all the pools of the configuration calling the user supplied function
2559  * as long as the user function continues to return PO_TRUE
2560  */
2561 int
2562 pool_walk_pools(pool_conf_t *conf, void *arg,
2563     int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg))
2564 {
2565 	pool_t **rs;
2566 	int i;
2567 	uint_t size;
2568 	int error = PO_SUCCESS;
2569 
2570 	if (pool_conf_status(conf) == POF_INVALID) {
2571 		pool_seterror(POE_BADPARAM);
2572 		return (PO_FAIL);
2573 	}
2574 
2575 	if ((rs = pool_query_pools(conf, &size, NULL)) == NULL) /* None */
2576 		return (PO_SUCCESS);
2577 	for (i = 0; i < size; i++)
2578 		if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2579 			error = PO_FAIL;
2580 			break;
2581 		}
2582 	free(rs);
2583 	return (error);
2584 }
2585 
2586 /*
2587  * Walk all the comp of the res calling the user supplied function
2588  * as long as the user function continues to return PO_TRUE
2589  */
2590 int
2591 pool_walk_components(pool_conf_t *conf, pool_resource_t *prs, void *arg,
2592     int (*callback)(pool_conf_t *conf, pool_component_t *pr, void *arg))
2593 {
2594 	pool_component_t **rs;
2595 	int i;
2596 	uint_t size;
2597 	int error = PO_SUCCESS;
2598 
2599 	if (pool_conf_status(conf) == POF_INVALID) {
2600 		pool_seterror(POE_BADPARAM);
2601 		return (PO_FAIL);
2602 	}
2603 
2604 	if ((rs = pool_query_resource_components(conf, prs, &size, NULL)) ==
2605 	    NULL)
2606 		return (PO_SUCCESS); /* None */
2607 	for (i = 0; i < size; i++)
2608 		if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2609 			error = PO_FAIL;
2610 			break;
2611 		}
2612 	free(rs);
2613 	return (error);
2614 }
2615 
2616 /*
2617  * Return an array of all matching res for the supplied pool.
2618  */
2619 pool_resource_t **
2620 pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp,
2621     uint_t *size, pool_value_t **props)
2622 {
2623 	pool_result_set_t *rs;
2624 	pool_elem_t *pe;
2625 	pool_resource_t **result = NULL;
2626 	int i = 0;
2627 
2628 	if (pool_conf_status(conf) == POF_INVALID) {
2629 		pool_seterror(POE_BADPARAM);
2630 		return (NULL);
2631 	}
2632 
2633 	pe = TO_ELEM(pp);
2634 
2635 	rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props);
2636 	if (rs == NULL) {
2637 		return (NULL);
2638 	}
2639 	if ((*size = pool_rs_count(rs)) == 0) {
2640 		(void) pool_rs_close(rs);
2641 		return (NULL);
2642 	}
2643 	if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1)))
2644 	    == NULL) {
2645 		pool_seterror(POE_SYSTEM);
2646 		(void) pool_rs_close(rs);
2647 		return (NULL);
2648 	}
2649 	(void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1));
2650 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2651 		if (pool_elem_class(pe) != PEC_RES_COMP &&
2652 		    pool_elem_class(pe) != PEC_RES_AGG) {
2653 			pool_seterror(POE_INVALID_CONF);
2654 			free(result);
2655 			(void) pool_rs_close(rs);
2656 			return (NULL);
2657 		}
2658 		result[i++] = pool_elem_res(pe);
2659 	}
2660 	(void) pool_rs_close(rs);
2661 	return (result);
2662 }
2663 
2664 /*
2665  * Walk all the res of the pool calling the user supplied function
2666  * as long as the user function continues to return PO_TRUE
2667  */
2668 int
2669 pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg,
2670     int (*callback)(pool_conf_t *, pool_resource_t *, void *))
2671 {
2672 	pool_resource_t **rs;
2673 	int i;
2674 	uint_t size;
2675 	int error = PO_SUCCESS;
2676 
2677 	if (pool_conf_status(conf) == POF_INVALID) {
2678 		pool_seterror(POE_BADPARAM);
2679 		return (PO_FAIL);
2680 	}
2681 	if ((rs = pool_query_pool_resources(conf, pp, &size, NULL)) == NULL)
2682 		return (PO_SUCCESS); /* None */
2683 	for (i = 0; i < size; i++)
2684 		if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2685 			error = PO_FAIL;
2686 			break;
2687 		}
2688 	free(rs);
2689 	return (error);
2690 }
2691 
2692 /*
2693  * Return a result set of all comp for the supplied res.
2694  */
2695 pool_component_t **
2696 pool_query_resource_components(const pool_conf_t *conf,
2697     const pool_resource_t *prs, uint_t *size, pool_value_t **props)
2698 {
2699 	pool_result_set_t *rs;
2700 	pool_elem_t *pe;
2701 	pool_component_t **result = NULL;
2702 	int i = 0;
2703 
2704 	if (pool_conf_status(conf) == POF_INVALID) {
2705 		pool_seterror(POE_BADPARAM);
2706 		return (NULL);
2707 	}
2708 	pe = TO_ELEM(prs);
2709 
2710 	rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props);
2711 	if (rs == NULL) {
2712 		return (NULL);
2713 	}
2714 	if ((*size = pool_rs_count(rs)) == 0) {
2715 		(void) pool_rs_close(rs);
2716 		return (NULL);
2717 	}
2718 	if ((result = malloc(sizeof (pool_component_t *) * (*size + 1)))
2719 	    == NULL) {
2720 		pool_seterror(POE_SYSTEM);
2721 		(void) pool_rs_close(rs);
2722 		return (NULL);
2723 	}
2724 	(void) memset(result, 0, sizeof (pool_component_t *) * (*size + 1));
2725 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2726 		if (pool_elem_class(pe) != PEC_COMP) {
2727 			pool_seterror(POE_INVALID_CONF);
2728 			free(result);
2729 			(void) pool_rs_close(rs);
2730 			return (NULL);
2731 		}
2732 		result[i++] = pool_elem_comp(pe);
2733 	}
2734 	(void) pool_rs_close(rs);
2735 	return (result);
2736 }
2737 
2738 /*
2739  * pool_version() returns the version of this library, depending on the supplied
2740  * parameter.
2741  *
2742  * Returns: library version depening on the supplied ver parameter.
2743  */
2744 uint_t
2745 pool_version(uint_t ver)
2746 {
2747 	switch (ver) {
2748 	case POOL_VER_NONE:
2749 		break;
2750 	case POOL_VER_CURRENT:
2751 		pool_workver = ver;
2752 		break;
2753 	default:
2754 		return (POOL_VER_NONE);
2755 	}
2756 	return (pool_workver);
2757 }
2758 
2759 /*
2760  * pool_associate() associates the supplied resource to the supplied pool.
2761  *
2762  * Returns: PO_SUCCESS/PO_FAIL
2763  */
2764 int
2765 pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2766 {
2767 	if (pool_conf_check(conf) != PO_SUCCESS)
2768 		return (PO_FAIL);
2769 
2770 	return (pool->pp_associate(pool, res));
2771 }
2772 
2773 /*
2774  * pool_dissociate() dissociates the supplied resource from the supplied pool.
2775  *
2776  * Returns: PO_SUCCESS/PO_FAIL
2777  */
2778 int
2779 pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2780 {
2781 	if (pool_conf_check(conf) != PO_SUCCESS)
2782 		return (PO_FAIL);
2783 
2784 	if (elem_is_default(TO_ELEM(res)))
2785 		return (PO_SUCCESS);
2786 	return (pool->pp_dissociate(pool, res));
2787 }
2788 
2789 /*
2790  * Compare two elements for purposes of ordering.
2791  * Return:
2792  *	< 0 if e1 is "before" e2
2793  *	0 if e1 "equals" e2
2794  *	> 0 if e1 comes after e2
2795  */
2796 int
2797 pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2)
2798 {
2799 	char *name1, *name2;
2800 	pool_value_t val = POOL_VALUE_INITIALIZER;
2801 	int retval;
2802 
2803 	/*
2804 	 * We may be asked to compare two elements from different classes.
2805 	 * They are different so return (1).
2806 	 */
2807 	if (pool_elem_same_class(e1, e2) != PO_TRUE)
2808 		return (1);
2809 
2810 	/*
2811 	 * If the class is PEC_SYSTEM, always match them
2812 	 */
2813 	if (pool_elem_class(e1) == PEC_SYSTEM)
2814 		return (0);
2815 
2816 	/*
2817 	 * If we are going to compare components, then use sys_id
2818 	 */
2819 	if (pool_elem_class(e1) == PEC_COMP) {
2820 		int64_t sys_id1, sys_id2;
2821 
2822 		if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2823 			return (-1);
2824 		}
2825 		(void) pool_value_get_int64(&val, &sys_id1);
2826 		if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) {
2827 			return (-1);
2828 		}
2829 		(void) pool_value_get_int64(&val, &sys_id2);
2830 		retval = (sys_id1 - sys_id2);
2831 	} else {
2832 		if (pool_get_ns_property(e1, "name", &val) == POC_INVAL) {
2833 			return (-1);
2834 		}
2835 		(void) pool_value_get_string(&val, (const char **)&name1);
2836 		if ((name1 = strdup(name1)) == NULL) {
2837 			return (-1);
2838 		}
2839 
2840 		if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) {
2841 			return (-1);
2842 		}
2843 
2844 		(void) pool_value_get_string(&val, (const char **)&name2);
2845 		retval = strcmp(name1, name2);
2846 		free(name1);
2847 	}
2848 	return (retval);
2849 }
2850 
2851 /*
2852  * Compare two elements for purposes of ordering.
2853  * Return:
2854  *	< 0 if e1 is "before" e2
2855  *	0 if e1 "equals" e2
2856  *	> 0 if e1 comes after e2
2857  */
2858 int
2859 pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2)
2860 {
2861 	pool_value_t val = POOL_VALUE_INITIALIZER;
2862 	int64_t sys_id1, sys_id2;
2863 
2864 	/*
2865 	 * We may be asked to compare two elements from different classes.
2866 	 * They are different so return the difference in their classes
2867 	 */
2868 	if (pool_elem_same_class(e1, e2) != PO_TRUE)
2869 		return (1);
2870 
2871 	/*
2872 	 * If the class is PEC_SYSTEM, always match them
2873 	 */
2874 	if (pool_elem_class(e1) == PEC_SYSTEM)
2875 		return (0);
2876 
2877 	/*
2878 	 * Compare with sys_id
2879 	 */
2880 	if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2881 		assert(!"no sys_id on e1\n");
2882 	}
2883 	(void) pool_value_get_int64(&val, &sys_id1);
2884 	if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) {
2885 		assert(!"no sys_id on e2\n");
2886 	}
2887 	(void) pool_value_get_int64(&val, &sys_id2);
2888 	return (sys_id1 - sys_id2);
2889 }
2890 
2891 /*
2892  * Return PO_TRUE if the supplied elems are of the same class.
2893  */
2894 int
2895 pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2)
2896 {
2897 	if (pool_elem_class(e1) != pool_elem_class(e2))
2898 		return (PO_FALSE);
2899 
2900 	/*
2901 	 * Check to make sure the fundamental class of the elements match
2902 	 */
2903 	if (pool_elem_class(e1) == PEC_RES_COMP ||
2904 	    pool_elem_class(e1) == PEC_RES_AGG)
2905 		if (pool_resource_elem_class(e1) !=
2906 		    pool_resource_elem_class(e2))
2907 			return (PO_FALSE);
2908 	if (pool_elem_class(e1) == PEC_COMP)
2909 		if (pool_component_elem_class(e1) !=
2910 		    pool_component_elem_class(e2))
2911 			return (PO_FALSE);
2912 	return (PO_TRUE);
2913 }
2914 
2915 /*
2916  * pool_conf_check() checks that the configuration state isn't invalid
2917  * and that the configuration was opened for modification.
2918  */
2919 int
2920 pool_conf_check(const pool_conf_t *conf)
2921 {
2922 	if (pool_conf_status(conf) == POF_INVALID) {
2923 		pool_seterror(POE_BADPARAM);
2924 		return (PO_FAIL);
2925 	}
2926 
2927 	if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) {
2928 		pool_seterror(POE_BADPARAM);
2929 		return (PO_FAIL);
2930 	}
2931 	return (PO_SUCCESS);
2932 }
2933