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