import less(1)
[unleashed/tickless.git] / usr / src / lib / libpool / common / pool.c
blobd16efae94a81f02ff39a5930313e492e9aa8949e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
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>
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>
51 #include "pool_internal.h"
52 #include "pool_impl.h"
55 * libpool Interface Routines
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:
62 * Data Abstraction
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.
70 * External Interaction
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.
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.
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
94 * Used to control transfer setup.
96 #define XFER_FAIL PO_FAIL
97 #define XFER_SUCCESS PO_SUCCESS
98 #define XFER_CONTINUE 1
100 #define SMF_SVC_INSTANCE "svc:/system/pools:default"
101 #define E_ERROR 1 /* Exit status for error */
103 #ifndef TEXT_DOMAIN
104 #define TEXT_DOMAIN "SYS_TEST"
105 #endif /* TEXT_DOMAIN */
107 const char pool_info_location[] = "/dev/pool";
110 * Static data
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;
117 * libpool error code
119 static int pool_errval = POE_OK;
122 * libpool version
124 static uint_t pool_workver = POOL_VER_CURRENT;
126 static const char *data_type_tags[] = {
127 "uint",
128 "int",
129 "float",
130 "boolean",
131 "string"
135 * static functions
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 *);
149 * Return the "static" location string for libpool.
151 const char *
152 pool_static_location(void)
154 return (static_location);
158 * Return the "dynamic" location string for libpool.
160 const char *
161 pool_dynamic_location(void)
163 return (dynamic_location);
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.
172 pool_conf_state_t
173 pool_conf_status(const pool_conf_t *conf)
175 return (conf->pc_state);
179 * Bind idtype id to the pool name.
182 pool_set_binding(const char *pool_name, idtype_t idtype, id_t id)
184 pool_conf_t *conf;
185 int result;
187 if ((conf = pool_conf_alloc()) == NULL)
188 return (PO_FAIL);
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);
196 result = conf->pc_prov->pc_set_binding(conf, pool_name, idtype, id);
198 (void) pool_conf_close(conf);
199 pool_conf_free(conf);
200 return (result);
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.
207 char *
208 pool_get_resource_binding(const char *sz_type, pid_t pid)
210 pool_conf_t *conf;
211 char *result;
212 pool_resource_elem_class_t type;
214 if ((type = pool_resource_elem_class_from_string(sz_type)) ==
215 PREC_INVALID) {
216 pool_seterror(POE_BADPARAM);
217 return (NULL);
220 if ((conf = pool_conf_alloc()) == NULL)
221 return (NULL);
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);
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);
236 * pool_get_binding() returns the binding for a pid to a pool. If a
237 * binding cannot be determined, NULL is returned.
239 char *
240 pool_get_binding(pid_t pid)
242 pool_conf_t *conf;
243 char *result;
245 if ((conf = pool_conf_alloc()) == NULL)
246 return (NULL);
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);
254 result = conf->pc_prov->pc_get_binding(conf, pid);
255 (void) pool_conf_close(conf);
256 pool_conf_free(conf);
257 return (result);
260 /*ARGSUSED*/
262 prop_buf_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name,
263 pool_value_t *pval, void *user)
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);
274 * Ignore "type" and "<type>.name" properties as these are not
275 * to be displayed by this function
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);
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);
319 return (PO_SUCCESS);
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
327 char *
328 pool_base_info(const pool_elem_t *pe, char_buf_t *cb, int deep)
330 const char *sres;
331 uint_t i;
332 uint_t nelem;
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);
339 if (cb == NULL) {
340 char *ret = NULL;
342 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
343 return (NULL);
346 * Populate the buffer with element details
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);
355 if (append_char_buf(cb, "\n%s%s", cb->cb_tab_buf,
356 pool_elem_class_string(pe)) == PO_FAIL) {
357 return (NULL);
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);
368 * Add in some details about the element
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);
376 if (append_char_buf(cb, "%s", "\n") == PO_FAIL)
377 return (NULL);
379 if (pe->pe_class == PEC_POOL) {
381 * A shallow display of a pool only lists the resources by name
384 if ((rs = pool_query_pool_resources(conf, pool_elem_pool(pe),
385 &nelem, NULL)) == NULL) {
386 return (NULL);
389 for (i = 0; i < nelem; i++) {
390 const char *str;
392 elem = TO_ELEM(rs[i]);
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);
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);
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);
412 free(rs);
414 if (deep == PO_TRUE) {
415 pool_t **ps;
416 pool_component_t **cs;
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);
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);
435 free(ps);
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);
447 free(rs);
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);
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);
474 free(cs);
476 break;
477 case PEC_RES_AGG:
478 case PEC_COMP:
479 break;
480 default:
481 /*NOTREACHED*/
482 break;
484 if (cb->cb_tab_buf[0] != 0)
485 cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0;
487 return (cb->cb_buf);
491 * Returns The information on the specified pool or NULL.
493 * Errors If the status of the conf is INVALID or the supplied
494 * value of deep is illegal, POE_BADPARAM.
496 * The caller is responsible for free(3c)ing the string returned.
498 char *
499 pool_info(const pool_conf_t *conf, const pool_t *pool, int deep)
501 pool_elem_t *pe;
503 pe = TO_ELEM(pool);
505 if (TO_CONF(pe) != conf) {
506 pool_seterror(POE_BADPARAM);
507 return (NULL);
510 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
511 pool_seterror(POE_BADPARAM);
512 return (NULL);
515 return (pool_base_info(pe, NULL, deep));
519 * Returns The information on the specified resource or NULL.
521 * Errors If the status of the conf is INVALID or the supplied
522 * value of deep is illegal, POE_BADPARAM.
524 * The caller is responsible for free(3c)ing the string returned.
526 char *
527 pool_resource_info(const pool_conf_t *conf, const pool_resource_t *res,
528 int deep)
530 pool_elem_t *pe;
532 pe = TO_ELEM(res);
534 if (TO_CONF(pe) != conf) {
535 pool_seterror(POE_BADPARAM);
536 return (NULL);
539 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
540 pool_seterror(POE_BADPARAM);
541 return (NULL);
544 return (pool_base_info(pe, NULL, deep));
548 * Returns The information on the specified component or NULL.
550 * Errors If the status of the conf is INVALID or the supplied
551 * value of deep is illegal, POE_BADPARAM.
553 * The caller is responsible for free(3c)ing the string returned.
555 char *
556 pool_component_info(const pool_conf_t *conf, const pool_component_t *comp,
557 int deep)
559 pool_elem_t *pe;
561 pe = TO_ELEM(comp);
563 if (TO_CONF(pe) != conf) {
564 pool_seterror(POE_BADPARAM);
565 return (NULL);
568 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
569 pool_seterror(POE_BADPARAM);
570 return (NULL);
573 return (pool_base_info(pe, NULL, deep));
577 * Returns The information on the specified conf or NULL.
579 * Errors If the status of the conf is INVALID or the supplied
580 * value of deep is illegal, POE_BADPARAM.
582 * The caller is responsible for free(3c)ing the string returned.
584 char *
585 pool_conf_info(const pool_conf_t *conf, int deep)
587 pool_elem_t *pe;
589 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
590 pool_seterror(POE_BADPARAM);
591 return (NULL);
593 if ((pe = pool_conf_to_elem(conf)) == NULL) {
594 pool_seterror(POE_BADPARAM);
595 return (NULL);
597 return (pool_base_info(pe, NULL, deep));
602 * Set the thread specific error value.
604 void
605 pool_seterror(int errval)
607 if (thr_main()) {
608 pool_errval = errval;
609 return;
611 (void) thr_keycreate_once(&errkey, 0);
612 (void) thr_setspecific(errkey, (void *)(intptr_t)errval);
616 * Return the current value of the error code.
617 * Returns: int error code
620 pool_error(void)
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));
630 * Return the text represenation for the current value of the error code.
631 * Returns: const char * error string
633 const char *
634 pool_strerror(int error)
636 char *str;
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;
674 return (str);
678 pool_get_status(int *state)
680 int fd;
681 pool_status_t status;
683 if ((fd = open(pool_info_location, O_RDONLY)) < 0) {
684 pool_seterror(POE_SYSTEM);
685 return (PO_FAIL);
687 if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
688 (void) close(fd);
689 pool_seterror(POE_SYSTEM);
690 return (PO_FAIL);
692 (void) close(fd);
694 *state = status.ps_io_state;
696 return (PO_SUCCESS);
700 pool_set_status(int state)
702 int old_state;
704 if (pool_get_status(&old_state) != PO_SUCCESS) {
705 pool_seterror(POE_SYSTEM);
706 return (PO_FAIL);
709 if (old_state != state) {
710 int fd;
711 pool_status_t status;
712 char *fmri;
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.
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.
724 fmri = getenv("SMF_FMRI");
725 if (fmri == NULL) {
726 FILE *p;
727 char *cmd;
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;
736 if ((p = popen(cmd, "wF")) == NULL || pclose(p) != 0) {
737 pool_seterror(POE_SYSTEM);
738 return (PO_FAIL);
740 return (PO_SUCCESS);
743 if ((fd = open(pool_dynamic_location(), O_RDWR | O_EXCL)) < 0) {
744 pool_seterror(POE_SYSTEM);
745 return (PO_FAIL);
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.
754 if (strcmp(fmri, SMF_SVC_INSTANCE) != 0) {
755 int res;
757 if (state != 0)
758 res = smf_enable_instance(SMF_SVC_INSTANCE, 0);
759 else
760 res = smf_disable_instance(SMF_SVC_INSTANCE, 0);
762 if (res != 0) {
763 (void) close(fd);
764 pool_seterror(POE_SYSTEM);
765 return (PO_FAIL);
768 status.ps_io_state = state;
770 if (ioctl(fd, POOL_STATUS, &status) < 0) {
771 (void) close(fd);
772 pool_seterror(POE_SYSTEM);
773 return (PO_FAIL);
776 (void) close(fd);
779 return (PO_SUCCESS);
783 * General Data Provider Independent Access Methods
787 * Property manipulation code.
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.
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.
799 * The (get|rm|set)_property() functions bypass the plugin layer completely,
800 * and hence should not be generally used.
804 * Return true if the string passed in matches the pattern
805 * [A-Za-z][A-Za-z0-9,._-]*
808 is_valid_name(const char *name)
810 int i;
811 char c;
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);
821 return (PO_TRUE);
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.
831 is_valid_prop_name(const char *prop_name)
833 int i;
834 char c;
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);
844 return (PO_TRUE);
848 * Return the specified property value.
850 * POC_INVAL is returned if an error is detected and the error code is updated
851 * to indicate the cause of the error.
853 pool_value_class_t
854 pool_get_property(const pool_conf_t *conf, const pool_elem_t *pe,
855 const char *name, pool_value_t *val)
857 const pool_prop_t *prop_info;
859 if (pool_conf_status(conf) == POF_INVALID) {
860 pool_seterror(POE_BADPARAM);
861 return (POC_INVAL);
863 if (pool_value_set_name(val, name) != PO_SUCCESS) {
864 return (POC_INVAL);
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.
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));
878 return (pe->pe_get_prop(pe, name, val));
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".
886 * POC_INVAL is returned if an error is detected and the error code is updated
887 * to indicate the cause of the error.
889 pool_value_class_t
890 pool_get_ns_property(const pool_elem_t *pe, const char *name, pool_value_t *val)
892 int ret;
893 char_buf_t *cb;
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);
902 ret = pool_get_property(TO_CONF(pe), pe, cb->cb_buf, val);
903 free_char_buf(cb);
904 return (ret);
908 * Update the specified property value.
910 * PO_FAIL is returned if an error is detected and the error code is updated
911 * to indicate the cause of the error.
914 pool_put_property(pool_conf_t *conf, pool_elem_t *pe, const char *name,
915 const pool_value_t *val)
917 const pool_prop_t *prop_info;
919 if (pool_conf_check(conf) != PO_SUCCESS)
920 return (PO_FAIL);
922 if (TO_CONF(pe) != conf) {
923 pool_seterror(POE_BADPARAM);
924 return (0);
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);
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();
938 if (pe->pe_get_prop(pe, name, pv) != POC_INVAL) {
939 const char *s1 = NULL;
940 const char *s2 = NULL;
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;
947 pool_value_free(pv);
949 if (rename) {
950 pool_seterror(POE_BADPARAM);
951 return (PO_FAIL);
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.
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);
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);
969 return (pe->pe_put_prop(pe, name, val));
973 * Set temporary property to flag as a temporary element.
975 * PO_FAIL is returned if an error is detected and the error code is updated
976 * to indicate the cause of the error.
979 pool_set_temporary(pool_conf_t *conf, pool_elem_t *pe)
981 int res;
982 char name[128];
983 pool_value_t *val;
985 if (pool_conf_check(conf) != PO_SUCCESS)
986 return (PO_FAIL);
988 if (TO_CONF(pe) != conf) {
989 pool_seterror(POE_BADPARAM);
990 return (PO_FAIL);
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);
1000 if ((val = pool_value_alloc()) == NULL)
1001 return (PO_FAIL);
1003 pool_value_set_bool(val, (uchar_t)1);
1005 res = pe->pe_put_prop(pe, name, val);
1007 pool_value_free(val);
1009 return (res);
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".
1017 * PO_FAIL is returned if an error is detected and the error code is updated
1018 * to indicate the cause of the error.
1021 pool_put_ns_property(pool_elem_t *pe, const char *name,
1022 const pool_value_t *val)
1024 char_buf_t *cb;
1025 int ret;
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);
1034 ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val);
1035 free_char_buf(cb);
1036 return (ret);
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.
1046 * PO_FAIL is returned if an error is detected and the error code is
1047 * updated to indicate the cause of the error.
1050 pool_put_any_property(pool_elem_t *pe, const char *name,
1051 const pool_value_t *val)
1053 if (!is_valid_prop_name(name)) {
1054 pool_seterror(POE_BADPARAM);
1055 return (PO_FAIL);
1058 return (pe->pe_put_prop(pe, name, val));
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".
1066 * PO_FAIL is returned if an error is detected and the error code is updated
1067 * to indicate the cause of the error.
1070 pool_put_any_ns_property(pool_elem_t *pe, const char *name,
1071 const pool_value_t *val)
1073 char_buf_t *cb;
1074 int ret;
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);
1083 ret = pool_put_any_property(pe, cb->cb_buf, val);
1084 free_char_buf(cb);
1085 return (ret);
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.
1095 pool_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name)
1097 const pool_prop_t *prop_info;
1099 if (pool_conf_check(conf) != PO_SUCCESS)
1100 return (PO_FAIL);
1102 if (TO_CONF(pe) != conf) {
1103 pool_seterror(POE_BADPARAM);
1104 return (0);
1107 /* Don't allow removal of the "temporary" property */
1108 if (strstr(name, ".temporary") != NULL) {
1109 pool_seterror(POE_BADPARAM);
1110 return (PO_FAIL);
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.
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);
1123 return (pe->pe_rm_prop(pe, name));
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.
1130 const char *
1131 is_ns_property(const pool_elem_t *pe, const char *name)
1133 const char *prefix;
1135 if ((prefix = pool_elem_class_string(pe)) != NULL) {
1136 if (strncmp(name, prefix, strlen(prefix)) == 0)
1137 return (prefix);
1139 return (NULL);
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.
1147 const char *
1148 property_name_minus_ns(const pool_elem_t *pe, const char *name)
1150 const char *prefix;
1151 if ((prefix = is_ns_property(pe, name)) != NULL) {
1152 return (name + strlen(prefix) + 1);
1154 return (name);
1158 * Create an element to represent a pool and add it to the supplied
1159 * configuration.
1161 pool_t *
1162 pool_create(pool_conf_t *conf, const char *name)
1164 pool_elem_t *pe;
1165 pool_value_t val = POOL_VALUE_INITIALIZER;
1166 const pool_prop_t *default_props;
1168 if (pool_conf_check(conf) != PO_SUCCESS)
1169 return (NULL);
1171 if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) {
1173 * A pool with the same name exists. Reject.
1175 pool_seterror(POE_BADPARAM);
1176 return (NULL);
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);
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);
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);
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);
1207 * If we are creating a temporary pool configuration, flag the pool.
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);
1216 return (pool_elem_pool(pe));
1220 * Create an element to represent a res.
1222 pool_resource_t *
1223 pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name)
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 };
1235 if (pool_conf_check(conf) != PO_SUCCESS)
1236 return (NULL);
1238 if ((type = pool_resource_elem_class_from_string(sz_type)) ==
1239 PREC_INVALID) {
1240 pool_seterror(POE_BADPARAM);
1241 return (NULL);
1244 if (strcmp(sz_type, "pset") != 0) {
1245 pool_seterror(POE_BADPARAM);
1246 return (NULL);
1249 if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) !=
1250 NULL) {
1252 * Resources must be unique by name+type.
1254 pool_seterror(POE_BADPARAM);
1255 return (NULL);
1258 props[0] = &val;
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);
1265 if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) {
1267 * This is the first representative of this type; when it's
1268 * created it should be created with 'default' = 'true'.
1270 is_default = 1;
1271 } else {
1272 free(resources);
1275 * TODO: If Additional PEC_RES_COMP types are added to
1276 * pool_impl.h, this would need to be extended.
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;
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);
1293 * The plugins contain a list of default properties and their values
1294 * for resources. The resource returned, hence, is fully initialized.
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);
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);
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);
1323 * If we are creating a temporary pool configuration, flag the resource.
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);
1332 return (pool_elem_res(pe));
1336 * Create an element to represent a resource component.
1338 pool_component_t *
1339 pool_component_create(pool_conf_t *conf, const pool_resource_t *res,
1340 int64_t sys_id)
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];
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);
1353 * TODO: If additional PEC_COMP types are added in pool_impl.h,
1354 * this would need to be extended.
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);
1363 * The plugins contain a list of default properties and their values
1364 * for resources. The resource returned, hence, is fully initialized.
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);
1380 * Set additional attributes/properties on component.
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);
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);
1392 if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) {
1393 (void) pool_component_destroy(pool_elem_comp(pe));
1394 return (NULL);
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);
1400 return (pool_elem_comp(pe));
1404 * Return the location of a configuration.
1406 const char *
1407 pool_conf_location(const pool_conf_t *conf)
1409 if (pool_conf_status(conf) == POF_INVALID) {
1410 pool_seterror(POE_BADPARAM);
1411 return (NULL);
1413 return (conf->pc_location);
1416 * Close a configuration, freeing all associated resources. Once a
1417 * configuration is closed, it can no longer be used.
1420 pool_conf_close(pool_conf_t *conf)
1422 int rv;
1424 if (pool_conf_status(conf) == POF_INVALID) {
1425 pool_seterror(POE_BADPARAM);
1426 return (PO_FAIL);
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);
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.
1442 pool_conf_remove(pool_conf_t *conf)
1444 int rv;
1446 if (pool_conf_status(conf) == POF_INVALID) {
1447 pool_seterror(POE_BADPARAM);
1448 return (PO_FAIL);
1450 rv = conf->pc_prov->pc_remove(conf);
1451 conf->pc_state = POF_INVALID;
1452 return (rv);
1456 * pool_conf_alloc() allocate the resources to represent a configuration.
1458 pool_conf_t *
1459 pool_conf_alloc(void)
1461 pool_conf_t *conf;
1463 if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) {
1464 pool_seterror(POE_SYSTEM);
1465 return (NULL);
1467 conf->pc_state = POF_INVALID;
1468 return (conf);
1472 * pool_conf_free() frees the resources associated with a configuration.
1474 void
1475 pool_conf_free(pool_conf_t *conf)
1477 free(conf);
1481 * pool_conf_open() opens a configuration, establishing all required
1482 * connections to the data source.
1485 pool_conf_open(pool_conf_t *conf, const char *location, int oflags)
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.
1492 internal_init();
1494 if (pool_conf_status(conf) != POF_INVALID) {
1496 * Already opened configuration, return PO_FAIL
1498 pool_seterror(POE_BADPARAM);
1499 return (PO_FAIL);
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);
1508 * Creating a configuration implies read-write access, so make
1509 * sure that PO_RDWR is set in addition if PO_CREAT is set.
1511 if (oflags & PO_CREAT)
1512 oflags |= PO_RDWR;
1514 /* location is ignored when creating a temporary configuration */
1515 if (oflags & PO_TEMP)
1516 location = "";
1518 if ((conf->pc_location = strdup(location)) == NULL) {
1519 pool_seterror(POE_SYSTEM);
1520 return (PO_FAIL);
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.
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.
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);
1540 /* set rdwr flag so we can updated the in-memory config. */
1541 conf->pc_prov->pc_oflags |= PO_RDWR;
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);
1548 } else {
1549 if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) {
1550 conf->pc_state = POF_INVALID;
1551 return (PO_FAIL);
1554 return (PO_SUCCESS);
1558 * Rollback a configuration. This will undo all changes to the configuration
1559 * since the last time pool_conf_commit was called.
1562 pool_conf_rollback(pool_conf_t *conf)
1564 if (pool_conf_status(conf) == POF_INVALID) {
1565 pool_seterror(POE_BADPARAM);
1566 return (PO_FAIL);
1568 return (conf->pc_prov->pc_rollback(conf));
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.
1579 pool_conf_commit(pool_conf_t *conf, int active)
1581 int retval;
1583 if (pool_conf_status(conf) == POF_INVALID) {
1584 pool_seterror(POE_BADPARAM);
1585 return (PO_FAIL);
1587 if (active) {
1588 int oflags;
1590 if (conf_is_dynamic(conf) == PO_TRUE) {
1591 pool_seterror(POE_BADPARAM);
1592 return (PO_FAIL);
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.
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 {
1607 * Write the configuration back to the backing store.
1609 retval = conf->pc_prov->pc_commit(conf);
1611 return (retval);
1615 * Export a configuration. This will export a configuration in the specified
1616 * format (fmt) to the specified location.
1619 pool_conf_export(const pool_conf_t *conf, const char *location,
1620 pool_export_format_t fmt)
1622 if (pool_conf_status(conf) == POF_INVALID) {
1623 pool_seterror(POE_BADPARAM);
1624 return (PO_FAIL);
1626 return (conf->pc_prov->pc_export(conf, location, fmt));
1630 * Validate a configuration. This will validate a configuration at the
1631 * specified level.
1634 pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level)
1636 if (pool_conf_status(conf) == POF_INVALID) {
1637 pool_seterror(POE_BADPARAM);
1638 return (PO_FAIL);
1640 return (conf->pc_prov->pc_validate(conf, level));
1644 * Update the snapshot of a configuration. This can only be used on a
1645 * dynamic configuration.
1648 pool_conf_update(const pool_conf_t *conf, int *changed)
1650 if (pool_conf_status(conf) == POF_INVALID ||
1651 conf_is_dynamic(conf) == PO_FALSE) {
1652 pool_seterror(POE_BADPARAM);
1653 return (PO_FAIL);
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.
1661 if (changed)
1662 *changed = 0;
1663 return (pool_knl_update((pool_conf_t *)conf, changed));
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.
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 *))
1676 return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0));
1679 void
1680 free_value_list(int npvals, pool_value_t **pvals)
1682 int j;
1684 for (j = 0; j < npvals; j++) {
1685 if (pvals[j])
1686 pool_value_free(pvals[j]);
1688 free(pvals);
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
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)
1702 pool_value_t **pvals;
1703 int i;
1704 const pool_prop_t *props = provider_get_props(elem);
1705 uint_t npvals;
1707 if (pool_conf_status(conf) == POF_INVALID) {
1708 pool_seterror(POE_BADPARAM);
1709 return (PO_FAIL);
1712 if (props == NULL) {
1713 pool_seterror(POE_INVALID_CONF);
1714 return (PO_FAIL);
1717 if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL)
1718 return (PO_FAIL);
1721 * Now walk the managed properties. As we find managed
1722 * properties removed them from the list of all properties to
1723 * prevent duplication.
1725 for (i = 0; props[i].pp_pname != NULL; i++) {
1726 int j;
1729 * Special processing for type
1731 if (strcmp(props[i].pp_pname, c_type) == 0) {
1732 pool_value_t val = POOL_VALUE_INITIALIZER;
1734 if (pool_value_set_name(&val, props[i].pp_pname) ==
1735 PO_FAIL) {
1736 free_value_list(npvals, pvals);
1737 return (PO_FAIL);
1739 if (props[i].pp_op.ppo_get_value(elem, &val) ==
1740 PO_FAIL) {
1741 free_value_list(npvals, pvals);
1742 return (PO_FAIL);
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);
1752 continue;
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;
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.
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);
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);
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);
1786 pool_value_free(pvals[j]);
1787 pvals[j] = NULL;
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);
1803 pool_value_free(pvals[i]);
1804 pvals[i] = NULL;
1807 free(pvals);
1808 return (PO_SUCCESS);
1812 * Return a pool, searching the supplied configuration for a pool with the
1813 * supplied name. The search is case sensitive.
1815 pool_t *
1816 pool_get_pool(const pool_conf_t *conf, const char *name)
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;
1824 props[0] = &val;
1826 if (pool_conf_status(conf) == POF_INVALID) {
1827 pool_seterror(POE_BADPARAM);
1828 return (NULL);
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);
1835 rs = pool_query_pools(conf, &size, props);
1836 if (rs == NULL) { /* Can't find a pool to match the name */
1837 return (NULL);
1839 if (size != 1) {
1840 free(rs);
1841 pool_seterror(POE_INVALID_CONF);
1842 return (NULL);
1844 ret = rs[0];
1845 free(rs);
1846 return (ret);
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
1855 pool_t **
1856 pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props)
1858 pool_result_set_t *rs;
1859 pool_elem_t *pe;
1860 pool_t **result = NULL;
1861 int i = 0;
1863 if (pool_conf_status(conf) == POF_INVALID) {
1864 pool_seterror(POE_BADPARAM);
1865 return (NULL);
1867 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props);
1868 if (rs == NULL) {
1869 return (NULL);
1871 if ((*size = pool_rs_count(rs)) == 0) {
1872 (void) pool_rs_close(rs);
1873 return (NULL);
1875 if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) {
1876 pool_seterror(POE_SYSTEM);
1877 (void) pool_rs_close(rs);
1878 return (NULL);
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);
1888 result[i++] = pool_elem_pool(pe);
1890 (void) pool_rs_close(rs);
1891 return (result);
1895 * Return an res, searching the supplied configuration for an res with the
1896 * supplied name. The search is case sensitive.
1898 pool_resource_t *
1899 pool_get_resource(const pool_conf_t *conf, const char *sz_type,
1900 const char *name)
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;
1910 if (pool_conf_status(conf) == POF_INVALID) {
1911 pool_seterror(POE_BADPARAM);
1912 return (NULL);
1915 if (sz_type == NULL) {
1916 pool_seterror(POE_BADPARAM);
1917 return (NULL);
1920 props[0] = &val0;
1921 props[1] = &val1;
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);
1927 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1928 return (NULL);
1930 if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) {
1931 free_char_buf(cb);
1932 return (NULL);
1934 if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) {
1935 free_char_buf(cb);
1936 return (NULL);
1938 if (pool_value_set_string(props[1], name) != PO_SUCCESS) {
1939 free_char_buf(cb);
1940 return (NULL);
1942 free_char_buf(cb);
1943 rs = pool_query_resources(conf, &size, props);
1944 if (rs == NULL) {
1945 return (NULL);
1947 if (size != 1) {
1948 free(rs);
1949 pool_seterror(POE_INVALID_CONF);
1950 return (NULL);
1952 ret = rs[0];
1953 free(rs);
1954 return (ret);
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.
1963 pool_resource_t **
1964 pool_query_resources(const pool_conf_t *conf, uint_t *size,
1965 pool_value_t **props)
1967 pool_result_set_t *rs;
1968 pool_elem_t *pe;
1969 pool_resource_t **result = NULL;
1970 int i = 0;
1972 if (pool_conf_status(conf) == POF_INVALID) {
1973 pool_seterror(POE_BADPARAM);
1974 return (NULL);
1977 *size = 0;
1979 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props);
1980 if (rs == NULL) {
1981 return (NULL);
1983 if ((*size = pool_rs_count(rs)) == 0) {
1984 (void) pool_rs_close(rs);
1985 return (NULL);
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);
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);
2002 result[i++] = pool_elem_res(pe);
2004 (void) pool_rs_close(rs);
2005 return (result);
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.
2014 pool_component_t **
2015 pool_query_components(const pool_conf_t *conf, uint_t *size,
2016 pool_value_t **props)
2018 return (pool_query_resource_components(conf, NULL, size, props));
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.
2027 pool_destroy(pool_conf_t *conf, pool_t *pp)
2029 pool_elem_t *pe;
2031 if (pool_conf_check(conf) != PO_SUCCESS)
2032 return (PO_FAIL);
2034 pe = TO_ELEM(pp);
2037 * Cannot destroy the default pool.
2039 if (elem_is_default(pe) == PO_TRUE) {
2040 pool_seterror(POE_BADPARAM);
2041 return (PO_FAIL);
2043 if (pool_elem_remove(pe) != PO_SUCCESS)
2044 return (PO_FAIL);
2045 return (PO_SUCCESS);
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.
2054 pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs)
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;
2063 if (pool_conf_check(conf) != PO_SUCCESS)
2064 return (PO_FAIL);
2066 pe = TO_ELEM(prs);
2068 if (resource_is_system(prs) == PO_TRUE) {
2069 pool_seterror(POE_BADPARAM);
2070 return (PO_FAIL);
2073 * Walk all the pools and dissociate any pools which are using
2074 * this resource.
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;
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);
2092 break;
2095 free(rl);
2098 free(pl);
2100 if (pe->pe_class == PEC_RES_COMP) {
2101 pool_resource_t *default_set_res;
2104 * Use the xtransfer option to move comp around
2106 default_set_res = (pool_resource_t *)get_default_resource(prs);
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);
2118 conf->pc_state = ostate;
2119 free(rl);
2122 if (pool_elem_remove(pe) != PO_SUCCESS)
2123 return (PO_FAIL);
2124 return (PO_SUCCESS);
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.
2133 pool_component_destroy(pool_component_t *pr)
2135 pool_elem_t *pe = TO_ELEM(pr);
2137 if (pool_elem_remove(pe) != PO_SUCCESS)
2138 return (PO_FAIL);
2139 return (PO_SUCCESS);
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.
2151 pool_elem_remove(pool_elem_t *pe)
2153 return (pe->pe_remove(pe));
2157 * Execute a query to search for a qualifying set of elements.
2159 pool_result_set_t *
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)
2163 return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes,
2164 props));
2168 * Get the next result from a result set of elements.
2170 pool_elem_t *
2171 pool_rs_next(pool_result_set_t *set)
2173 return (set->prs_next(set));
2177 * Get the previous result from a result set of elements.
2179 pool_elem_t *
2180 pool_rs_prev(pool_result_set_t *set)
2182 return (set->prs_prev(set));
2186 * Get the first result from a result set of elements.
2188 pool_elem_t *
2189 pool_rs_first(pool_result_set_t *set)
2191 return (set->prs_first(set));
2195 * Get the last result from a result set of elements.
2197 pool_elem_t *
2198 pool_rs_last(pool_result_set_t *set)
2200 return (set->prs_last(set));
2205 * Get the count for a result set of elements.
2208 pool_rs_count(pool_result_set_t *set)
2210 return (set->prs_count(set));
2214 * Get the index for a result set of elements.
2217 pool_rs_get_index(pool_result_set_t *set)
2219 return (set->prs_get_index(set));
2223 * Set the index for a result set of elements.
2226 pool_rs_set_index(pool_result_set_t *set, int index)
2228 return (set->prs_set_index(set, index));
2232 * Close a result set of elements, freeing all associated resources.
2235 pool_rs_close(pool_result_set_t *set)
2237 return (set->prs_close(set));
2241 * When transferring resource components using pool_resource_transfer,
2242 * this function is invoked to choose which actual components will be
2243 * transferred.
2246 choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size)
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));
2253 if (size == 0)
2254 return (PO_SUCCESS);
2256 * Get the component list from our src component.
2258 if ((components = pool_query_resource_components(conf, src, &ncomponent,
2259 NULL)) == NULL) {
2260 pool_seterror(POE_BADPARAM);
2261 return (PO_FAIL);
2263 qsort(components, ncomponent, sizeof (pool_elem_t *),
2264 qsort_elem_compare);
2266 * Components that aren't specifically requested by the resource
2267 * should be transferred out first.
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--;
2280 * If we couldn't find enough "un-requested" components, select random
2281 * requested components.
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--;
2293 free(components);
2295 * If we couldn't transfer out all the resources we asked for, then
2296 * return error.
2298 return (size == 0 ? PO_SUCCESS : PO_FAIL);
2302 * Common processing for a resource transfer (xfer or xxfer).
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
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)
2312 uint64_t src_min;
2313 uint64_t tgt_max;
2315 if (pool_conf_check(conf) != PO_SUCCESS)
2316 return (XFER_FAIL);
2319 * Makes sure the two resources are of the same type
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);
2328 * Transferring to yourself is a no-op
2330 if (src == tgt)
2331 return (XFER_SUCCESS);
2334 * Transferring nothing is a no-op
2336 if (size == 0)
2337 return (XFER_SUCCESS);
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);
2346 if (pool_conf_status(conf) != POF_DESTROY) {
2348 * src_size - donating >= src.min
2349 * size + receiving <= tgt.max (except for default)
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);
2365 return (XFER_CONTINUE);
2369 * Transfer resource quantities from one resource set to another.
2372 pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src,
2373 pool_resource_t *tgt, uint64_t size)
2375 uint64_t src_size;
2376 uint64_t tgt_size;
2377 int ret;
2379 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2380 != XFER_CONTINUE)
2381 return (ret);
2383 * If this resource is a res_comp we must call move components
2385 if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP)
2386 return (choose_components(src, tgt, size));
2388 * Now do the transfer.
2390 ret = conf->pc_prov->pc_res_xfer(src, tgt, size);
2392 * Modify the sizes of the resource sets if the process was
2393 * successful
2395 if (ret == PO_SUCCESS) {
2396 pool_value_t val = POOL_VALUE_INITIALIZER;
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);
2407 return (ret);
2411 * Transfer resource components from one resource set to another.
2414 pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src,
2415 pool_resource_t *tgt,
2416 pool_component_t **rl)
2418 int i;
2419 uint64_t src_size;
2420 uint64_t tgt_size;
2421 uint64_t size;
2422 int ret;
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.
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 */
2441 if (pool_get_owning_resource(conf, rl[i]) != src) {
2442 pool_seterror(POE_BADPARAM);
2443 return (PO_FAIL);
2447 size = (uint64_t)i;
2449 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2450 != XFER_CONTINUE)
2451 return (ret);
2453 ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl);
2455 * Modify the sizes of the resource sets if the process was
2456 * successful
2458 if (ret == PO_SUCCESS) {
2459 pool_value_t val = POOL_VALUE_INITIALIZER;
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);
2475 return (ret);
2479 * Find the owning resource for a resource component.
2481 pool_resource_t *
2482 pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp)
2484 if (pool_conf_status(conf) == POF_INVALID) {
2485 pool_seterror(POE_BADPARAM);
2486 return (NULL);
2488 return (pool_elem_res(pool_get_container(TO_ELEM(comp))));
2492 * pool_get_container() returns the container of pc.
2494 pool_elem_t *
2495 pool_get_container(const pool_elem_t *pc)
2497 return (pc->pe_get_container(pc));
2501 * pool_set_container() moves pc so that it is contained by pp.
2503 * Returns PO_SUCCESS/PO_FAIL
2506 pool_set_container(pool_elem_t *pp, pool_elem_t *pc)
2508 return (pc->pe_set_container(pp, pc));
2512 * Conversion routines for converting to and from elem and it's various
2513 * subtypes of system, pool, res and comp.
2515 pool_elem_t *
2516 pool_system_elem(const pool_system_t *ph)
2518 return ((pool_elem_t *)ph);
2521 pool_elem_t *
2522 pool_conf_to_elem(const pool_conf_t *conf)
2524 pool_system_t *sys;
2526 if (pool_conf_status(conf) == POF_INVALID) {
2527 pool_seterror(POE_BADPARAM);
2528 return (NULL);
2530 if ((sys = pool_conf_system(conf)) == NULL) {
2531 pool_seterror(POE_BADPARAM);
2532 return (NULL);
2534 return (pool_system_elem(sys));
2537 pool_elem_t *
2538 pool_to_elem(const pool_conf_t *conf, const pool_t *pp)
2540 if (pool_conf_status(conf) == POF_INVALID) {
2541 pool_seterror(POE_BADPARAM);
2542 return (NULL);
2544 return ((pool_elem_t *)pp);
2547 pool_elem_t *
2548 pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs)
2550 if (pool_conf_status(conf) == POF_INVALID) {
2551 pool_seterror(POE_BADPARAM);
2552 return (NULL);
2554 return ((pool_elem_t *)prs);
2557 pool_elem_t *
2558 pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr)
2560 if (pool_conf_status(conf) == POF_INVALID) {
2561 pool_seterror(POE_BADPARAM);
2562 return (NULL);
2564 return ((pool_elem_t *)pr);
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
2572 pool_walk_pools(pool_conf_t *conf, void *arg,
2573 int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg))
2575 pool_t **rs;
2576 int i;
2577 uint_t size;
2578 int error = PO_SUCCESS;
2580 if (pool_conf_status(conf) == POF_INVALID) {
2581 pool_seterror(POE_BADPARAM);
2582 return (PO_FAIL);
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;
2592 free(rs);
2593 return (error);
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
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))
2604 pool_component_t **rs;
2605 int i;
2606 uint_t size;
2607 int error = PO_SUCCESS;
2609 if (pool_conf_status(conf) == POF_INVALID) {
2610 pool_seterror(POE_BADPARAM);
2611 return (PO_FAIL);
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;
2622 free(rs);
2623 return (error);
2627 * Return an array of all matching res for the supplied pool.
2629 pool_resource_t **
2630 pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp,
2631 uint_t *size, pool_value_t **props)
2633 pool_result_set_t *rs;
2634 pool_elem_t *pe;
2635 pool_resource_t **result = NULL;
2636 int i = 0;
2638 if (pool_conf_status(conf) == POF_INVALID) {
2639 pool_seterror(POE_BADPARAM);
2640 return (NULL);
2643 pe = TO_ELEM(pp);
2645 rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props);
2646 if (rs == NULL) {
2647 return (NULL);
2649 if ((*size = pool_rs_count(rs)) == 0) {
2650 (void) pool_rs_close(rs);
2651 return (NULL);
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);
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);
2668 result[i++] = pool_elem_res(pe);
2670 (void) pool_rs_close(rs);
2671 return (result);
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
2679 pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg,
2680 int (*callback)(pool_conf_t *, pool_resource_t *, void *))
2682 pool_resource_t **rs;
2683 int i;
2684 uint_t size;
2685 int error = PO_SUCCESS;
2687 if (pool_conf_status(conf) == POF_INVALID) {
2688 pool_seterror(POE_BADPARAM);
2689 return (PO_FAIL);
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;
2698 free(rs);
2699 return (error);
2703 * Return a result set of all comp for the supplied res.
2705 pool_component_t **
2706 pool_query_resource_components(const pool_conf_t *conf,
2707 const pool_resource_t *prs, uint_t *size, pool_value_t **props)
2709 pool_result_set_t *rs;
2710 pool_elem_t *pe;
2711 pool_component_t **result = NULL;
2712 int i = 0;
2714 if (pool_conf_status(conf) == POF_INVALID) {
2715 pool_seterror(POE_BADPARAM);
2716 return (NULL);
2718 pe = TO_ELEM(prs);
2720 rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props);
2721 if (rs == NULL) {
2722 return (NULL);
2724 if ((*size = pool_rs_count(rs)) == 0) {
2725 (void) pool_rs_close(rs);
2726 return (NULL);
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);
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);
2742 result[i++] = pool_elem_comp(pe);
2744 (void) pool_rs_close(rs);
2745 return (result);
2749 * pool_version() returns the version of this library, depending on the supplied
2750 * parameter.
2752 * Returns: library version depening on the supplied ver parameter.
2754 uint_t
2755 pool_version(uint_t ver)
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);
2766 return (pool_workver);
2770 * pool_associate() associates the supplied resource to the supplied pool.
2772 * Returns: PO_SUCCESS/PO_FAIL
2775 pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2777 if (pool_conf_check(conf) != PO_SUCCESS)
2778 return (PO_FAIL);
2780 return (pool->pp_associate(pool, res));
2784 * pool_dissociate() dissociates the supplied resource from the supplied pool.
2786 * Returns: PO_SUCCESS/PO_FAIL
2789 pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2791 if (pool_conf_check(conf) != PO_SUCCESS)
2792 return (PO_FAIL);
2794 if (elem_is_default(TO_ELEM(res)))
2795 return (PO_SUCCESS);
2796 return (pool->pp_dissociate(pool, res));
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
2807 pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2)
2809 char *name1, *name2;
2810 pool_value_t val = POOL_VALUE_INITIALIZER;
2811 int retval;
2814 * We may be asked to compare two elements from different classes.
2815 * They are different so return (1).
2817 if (pool_elem_same_class(e1, e2) != PO_TRUE)
2818 return (1);
2821 * If the class is PEC_SYSTEM, always match them
2823 if (pool_elem_class(e1) == PEC_SYSTEM)
2824 return (0);
2827 * If we are going to compare components, then use sys_id
2829 if (pool_elem_class(e1) == PEC_COMP) {
2830 int64_t sys_id1, sys_id2;
2832 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2833 return (-1);
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);
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);
2845 (void) pool_value_get_string(&val, (const char **)&name1);
2846 if ((name1 = strdup(name1)) == NULL) {
2847 return (-1);
2850 if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) {
2851 return (-1);
2854 (void) pool_value_get_string(&val, (const char **)&name2);
2855 retval = strcmp(name1, name2);
2856 free(name1);
2858 return (retval);
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
2869 pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2)
2871 pool_value_t val = POOL_VALUE_INITIALIZER;
2872 int64_t sys_id1, sys_id2;
2875 * We may be asked to compare two elements from different classes.
2876 * They are different so return the difference in their classes
2878 if (pool_elem_same_class(e1, e2) != PO_TRUE)
2879 return (1);
2882 * If the class is PEC_SYSTEM, always match them
2884 if (pool_elem_class(e1) == PEC_SYSTEM)
2885 return (0);
2888 * Compare with sys_id
2890 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2891 assert(!"no sys_id on e1\n");
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");
2897 (void) pool_value_get_int64(&val, &sys_id2);
2898 return (sys_id1 - sys_id2);
2902 * Return PO_TRUE if the supplied elems are of the same class.
2905 pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2)
2907 if (pool_elem_class(e1) != pool_elem_class(e2))
2908 return (PO_FALSE);
2911 * Check to make sure the fundamental class of the elements match
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);
2926 * pool_conf_check() checks that the configuration state isn't invalid
2927 * and that the configuration was opened for modification.
2930 pool_conf_check(const pool_conf_t *conf)
2932 if (pool_conf_status(conf) == POF_INVALID) {
2933 pool_seterror(POE_BADPARAM);
2934 return (PO_FAIL);
2937 if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) {
2938 pool_seterror(POE_BADPARAM);
2939 return (PO_FAIL);
2941 return (PO_SUCCESS);