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