diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-09-17 14:23:19 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-09-17 14:23:19 +0400 |
commit | de28f63015e215a128e3e64ae99db9f44099d23d (patch) | |
tree | 6155a91e1993a150ae9f8af53bfeb18c0ab4dde4 | |
download | libpool-de28f63015e215a128e3e64ae99db9f44099d23d.tar.gz |
Initial illumos sourcesillumos
27 files changed, 18685 insertions, 0 deletions
diff --git a/usr/src/lib/libpool/common/dict.c b/usr/src/lib/libpool/common/dict.c new file mode 100644 index 0000000..0e54022 --- /dev/null +++ b/usr/src/lib/libpool/common/dict.c @@ -0,0 +1,386 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file contains a basic dictionary implementation which stores + * arbitrary key-value mappings. It is used by libpool to store + * information about element pointers (pool_elem_t) in the kernel + * provider implementation. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> + +#include "dict.h" + +/* + * HASH_64_INIT is the same as the INIT value since it is the value + * used by FNV (FNV1_64_INIT). More details on FNV are available at: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + */ +#define HASH_64_INIT (0xcbf29ce484222325ULL) /* Hash initializer */ + +/* + * HASH_64_PRIME is a large prime number chosen to minimize hashing + * collisions. + */ +#define HASH_64_PRIME (0x100000001b3ULL) /* Large Prime */ + +/* + * DICT_SIZE is chosen as it is the nearest prime to 2^9 (512). 512 is + * chosen as it is unlikely that this dictionary will contain more + * elements than this in normal operation. Of course overflow in each + * bucket is acceptable, but if there is too much overflow, then + * performance will degrade to that of a list. + */ +#define DICT_SIZE 509 /* Reasonable prime */ + +/* + * Data Types + */ + +/* + * A key bucket. + */ +typedef struct dict_bucket +{ + const void *db_key; /* key */ + void *db_value; /* value */ + struct dict_bucket *db_next; /* next bucket */ +} dict_bucket_t; + +/* + * A dictionary which holds a mapping between a key and a value. + * dh_change - detects changes to the dictionary. + * dh_cmp - comparison function + * dh_hash - hashing function + * dh_buckets - key storage + * dh_size - # of buckets + */ +struct dict_hdl { + uint64_t dh_change; + int (*dh_cmp)(const void *, const void *); + uint64_t (*dh_hash)(const void *); + uint64_t dh_length; + dict_bucket_t **dh_buckets; + uint64_t dh_size; +}; + +/* + * Utility functions. Mainly used for debugging + */ + +#if defined(DEBUG) + +static void bit_print_32(unsigned int); +static void bit_print_64(unsigned long long); + +#endif /* DEBUG */ + +/* + * Default functions for hashing and comparing if the user does not specify + * these values when creating the dictionary. + */ +static int cmp_addr(const void *, const void *); +static uint64_t hash_addr(const void *); + +/* + * static functions + */ + +#if defined(DEBUG) + +/* + * Print to standard out the bit representation of the supplied value + */ +void +bit_print_32(unsigned int v) +{ +#pragma error_messages(off, E_INTEGER_OVERFLOW_DETECTED) + int i, mask = 1 << 31; +#pragma error_messages(on, E_INTEGER_OVERFLOW_DETECTED) + + for (i = 1; i <= 32; i++) { + (void) putchar(((v & mask) == 0) ? '0' : '1'); + v <<= 1; + if (i % 8 == 0 && i != 32) + (void) putchar(' '); + } + (void) putchar('\n'); +} + +/* + * Print to standard out the bit representation of the supplied value + */ +void +bit_print_64(unsigned long long v) +{ +#pragma error_messages(off, E_INTEGER_OVERFLOW_DETECTED) + long long mask = 1ll << 63; +#pragma error_messages(on, E_INTEGER_OVERFLOW_DETECTED) + int i; + + for (i = 1; i <= 64; i++) { + (void) putchar(((v & mask) == 0) ? '0' : '1'); + v <<= 1; + if (i % 8 == 0 && i != 64) + (void) putchar(' '); + } + (void) putchar('\n'); +} + + + +#endif /* DEBUG */ + +/* + * Default comparison function which is used if no comparison function + * is supplied when the dictionary is created. The default behaviour + * is to compare memory address. + */ +int +cmp_addr(const void *x, const void *y) +{ + return (x != y); +} + + +/* + * The default hashing function which is used if no hashing function + * is provided when the dictionary is created. The default behaviour + * is to use the hash_buf() function. + */ +uint64_t +hash_addr(const void *key) +{ + return (hash_buf(&key, sizeof (key))); +} + + +/* + * public interface + */ + +/* + * Return a hash which is built by manipulating each byte in the + * supplied data. The hash logic follows the approach suggested in the + * FNV hash. + */ +uint64_t +hash_buf(const void *buf, size_t len) +{ + uchar_t *start = (uchar_t *)buf; + uchar_t *end = start + len; + uint64_t hash = HASH_64_INIT; + + while (start < end) { + hash *= HASH_64_PRIME; + hash ^= (uint64_t)*start++; + } + + return (hash); +} + + +/* + * Return a hash which is built by manipulating each byte in the + * supplied string. The hash logic follows the approach suggested in + * the FNV hash. + */ +uint64_t +hash_str(const char *str) +{ + uchar_t *p = (uchar_t *)str; + uint64_t hash = HASH_64_INIT; + + while (*p) { + hash *= HASH_64_PRIME; + hash ^= (uint64_t)*p++; + } + + return (hash); +} + +/* + * Return the number of keys held in the supplied dictionary. + */ +uint64_t +dict_length(dict_hdl_t *hdl) +{ + return (hdl->dh_length); +} + +/* + * Free the supplied dictionary and all it's associated resource. + */ +void +dict_free(dict_hdl_t **hdl) +{ + if ((*hdl)->dh_length > 0) { + uint64_t i; + for (i = 0; i < (*hdl)->dh_size; i++) { + dict_bucket_t *this, *next; + for (this = (*hdl)->dh_buckets[i]; this != NULL; + this = next) { + next = this->db_next; + free(this); + } + } + } + free((*hdl)->dh_buckets); + free((*hdl)); + *hdl = NULL; +} + +/* + * Create a new dictionary using the supplied comparison and hashing + * functions. If none are supplied then the defaults are used. + */ +dict_hdl_t * +dict_new(int (*cmp)(const void *, const void *), + uint64_t (*hash)(const void *)) +{ + dict_hdl_t *hdl; + + if ((hdl = calloc(1, sizeof (dict_hdl_t))) == NULL) + return (NULL); + hdl->dh_size = DICT_SIZE; + if ((hdl->dh_buckets = calloc(hdl->dh_size, sizeof (dict_bucket_t *))) + == NULL) { + free(hdl); + return (NULL); + } + hdl->dh_cmp = cmp ? cmp : cmp_addr; + hdl->dh_hash = hash ? hash : hash_addr; + return (hdl); +} + +/* + * Get a value from the hash. Null is returned if the key cannot be + * found. + */ +void * +dict_get(dict_hdl_t *hdl, const void *key) +{ + uint64_t i; + dict_bucket_t *bucket; + + i = (*hdl->dh_hash)(key)%hdl->dh_size; + for (bucket = hdl->dh_buckets[i]; bucket != NULL; + bucket = bucket->db_next) + if ((*hdl->dh_cmp)(key, bucket->db_key) == 0) + break; + return (bucket ? bucket->db_value : NULL); +} + +/* + * Put an entry into the hash. Null is returned if this key was not + * already present, otherwise the previous value is returned. + */ +void * +dict_put(dict_hdl_t *hdl, const void *key, void *value) +{ + uint64_t i; + dict_bucket_t *bucket; + void *prev = NULL; + + i = (*hdl->dh_hash)(key)%hdl->dh_size; + for (bucket = hdl->dh_buckets[i]; bucket != NULL; + bucket = bucket->db_next) + if ((*hdl->dh_cmp)(key, bucket->db_key) == 0) + break; + if (bucket) { + prev = bucket->db_value; + } else { + bucket = malloc(sizeof (dict_bucket_t)); + bucket->db_key = key; + bucket->db_next = hdl->dh_buckets[i]; + hdl->dh_buckets[i] = bucket; + hdl->dh_length++; + } + hdl->dh_change++; + bucket->db_value = value; + return (prev); +} + +/* + * Remove the key/value from the dictionary. The value is returned if + * the key is found. NULL is returned if the key cannot be located. + */ +void * +dict_remove(dict_hdl_t *hdl, const void *key) +{ + uint64_t i; + dict_bucket_t **pbucket; + + hdl->dh_change++; + i = (*hdl->dh_hash)(key)%hdl->dh_size; + + for (pbucket = &hdl->dh_buckets[i]; *pbucket != NULL; + pbucket = &(*pbucket)->db_next) { + if ((*hdl->dh_cmp)(key, (*pbucket)->db_key) == 0) { + dict_bucket_t *bucket = *pbucket; + void *value = bucket->db_value; + + *pbucket = bucket->db_next; + free(bucket); + hdl->dh_length--; + return (value); + } + } + return (NULL); +} + +/* + * For all entries in the dictionary call the user supplied function + * (apply) with the key, value and user supplied data. If the + * dictionary is modifed while this function is executing, then the + * function will fail with an assertion about table modifcation. + */ +void +dict_map(dict_hdl_t *hdl, void (*apply)(const void *, void **, void *), + void *cl) +{ + uint64_t i; + dict_bucket_t *bucket = NULL; + uint64_t change_stamp = hdl->dh_change; + + for (i = 0; i < hdl->dh_size; i++) { + for (bucket = hdl->dh_buckets[i]; bucket != NULL; + bucket = bucket->db_next) { + apply(bucket->db_key, &bucket->db_value, cl); + if (hdl->dh_change != change_stamp) + assert(!"table modified illegally"); + } + } +} diff --git a/usr/src/lib/libpool/common/dict.h b/usr/src/lib/libpool/common/dict.h new file mode 100644 index 0000000..ec75212 --- /dev/null +++ b/usr/src/lib/libpool/common/dict.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DICT_H +#define _DICT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct dict_hdl dict_hdl_t; + +/* + * Hash functions + */ + +extern uint64_t hash_buf(const void *, size_t); +extern uint64_t hash_str(const char *); + +/* + * Dictionary functions + */ +extern void dict_free(dict_hdl_t **); +extern uint64_t dict_length(dict_hdl_t *); +extern dict_hdl_t *dict_new(int (*)(const void *, const void *), + uint64_t (*)(const void *)); + +/* + * Dictionary entry functions + */ + +extern void *dict_get(dict_hdl_t *, const void *); +extern void *dict_put(dict_hdl_t *, const void *, void *); +extern void *dict_remove(dict_hdl_t *, const void *); + +extern void dict_map(dict_hdl_t *, + void (*)(const void *, void **, void *), void *); + +/* + * Dictionary conversion + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DICT_H */ diff --git a/usr/src/lib/libpool/common/pool.c b/usr/src/lib/libpool/common/pool.c new file mode 100644 index 0000000..bcd8c9a --- /dev/null +++ b/usr/src/lib/libpool/common/pool.c @@ -0,0 +1,2944 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <thread.h> +#include <pthread.h> +#include <synch.h> +#include <unistd.h> +#include <stropts.h> +#include <fcntl.h> +#include <note.h> +#include <errno.h> +#include <ctype.h> +#include <libintl.h> +#include <libscf.h> +#include <pool.h> +#include <signal.h> + +#include <sys/pool.h> +#include <sys/priocntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include "pool_internal.h" +#include "pool_impl.h" + +/* + * libpool Interface Routines + * + * pool.c implements (most of) the external interface to libpool + * users. Some of the interface is implemented in pool_internal.c for + * reasons of internal code organisation. The core requirements for + * pool.c are: + * + * Data Abstraction + * + * The abstraction of the actual datastore so that no details of the + * underlying data representation mechanism are revealed to users of + * the library. For instance, the fact that we use the kernel or files + * to store our configurations is completely abstracted via the + * various libpool APIs. + * + * External Interaction + * + * libpool users manipulate configuration components via the API + * defined in pool.h. Most functions in this file act as interceptors, + * validating parameters before redirecting the request into a + * specific datastore implementation for the actual work to be done. + * + * These main sets of requirements have driven the design so that it + * is possible to replace the entire datastore type without having to + * modify the external (or internal provider) APIs. It is possible to + * modify the storage technology used by libpool by implementing a new + * set of datastore provider operations. Simply modify the + * pool_conf_open() routine to establish a new datastore as the + * provider for a configuration. + * + * The key components in a libpool configuration are : + * pool_conf_t - This represents a complete configuration instance + * pool_t - A pool inside a configuration + * pool_resource_t - A resource inside a configuration + * pool_component_t - A component of a resource + * + */ + +/* + * Used to control transfer setup. + */ +#define XFER_FAIL PO_FAIL +#define XFER_SUCCESS PO_SUCCESS +#define XFER_CONTINUE 1 + +#define SMF_SVC_INSTANCE "svc:/system/pools:default" +#define E_ERROR 1 /* Exit status for error */ + +#ifndef TEXT_DOMAIN +#define TEXT_DOMAIN "SYS_TEST" +#endif /* TEXT_DOMAIN */ + +const char pool_info_location[] = "/dev/pool"; + +/* + * Static data + */ +static const char static_location[] = "/etc/pooladm.conf"; +static const char dynamic_location[] = "/dev/poolctl"; +static thread_key_t errkey = THR_ONCE_KEY; + +/* + * libpool error code + */ +static int pool_errval = POE_OK; + +/* + * libpool version + */ +static uint_t pool_workver = POOL_VER_CURRENT; + +static const char *data_type_tags[] = { + "uint", + "int", + "float", + "boolean", + "string" +}; + +/* + * static functions + */ +static int pool_elem_remove(pool_elem_t *); +static int is_valid_prop_name(const char *); +static int prop_buf_build_cb(pool_conf_t *, pool_elem_t *, const char *, + pool_value_t *, void *); +static char *pool_base_info(const pool_elem_t *, char_buf_t *, int); +static int choose_components(pool_resource_t *, pool_resource_t *, uint64_t); +static int pool_conf_check(const pool_conf_t *); +static void free_value_list(int, pool_value_t **); +static int setup_transfer(pool_conf_t *, pool_resource_t *, pool_resource_t *, + uint64_t, uint64_t *, uint64_t *); + +/* + * Return the "static" location string for libpool. + */ +const char * +pool_static_location(void) +{ + return (static_location); +} + +/* + * Return the "dynamic" location string for libpool. + */ +const char * +pool_dynamic_location(void) +{ + return (dynamic_location); +} + +/* + * Return the status for a configuration. If the configuration has + * been successfully opened, then the status will be POF_VALID or + * POF_DESTROY. If the configuration failed to open properly or has + * been closed or removed, then the status will be POF_INVALID. + */ +pool_conf_state_t +pool_conf_status(const pool_conf_t *conf) +{ + return (conf->pc_state); +} + +/* + * Bind idtype id to the pool name. + */ +int +pool_set_binding(const char *pool_name, idtype_t idtype, id_t id) +{ + pool_conf_t *conf; + int result; + + if ((conf = pool_conf_alloc()) == NULL) + return (PO_FAIL); + + if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) { + pool_conf_free(conf); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + + result = conf->pc_prov->pc_set_binding(conf, pool_name, idtype, id); + + (void) pool_conf_close(conf); + pool_conf_free(conf); + return (result); +} + +/* + * pool_get_resource_binding() returns the binding for a pid to the supplied + * type of resource. If a binding cannot be determined, NULL is returned. + */ +char * +pool_get_resource_binding(const char *sz_type, pid_t pid) +{ + pool_conf_t *conf; + char *result; + pool_resource_elem_class_t type; + + if ((type = pool_resource_elem_class_from_string(sz_type)) == + PREC_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if ((conf = pool_conf_alloc()) == NULL) + return (NULL); + + if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) + != PO_SUCCESS) { + pool_seterror(POE_INVALID_CONF); + pool_conf_free(conf); + return (NULL); + } + result = conf->pc_prov->pc_get_resource_binding(conf, type, pid); + (void) pool_conf_close(conf); + pool_conf_free(conf); + return (result); +} + +/* + * pool_get_binding() returns the binding for a pid to a pool. If a + * binding cannot be determined, NULL is returned. + */ +char * +pool_get_binding(pid_t pid) +{ + pool_conf_t *conf; + char *result; + + if ((conf = pool_conf_alloc()) == NULL) + return (NULL); + + if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) + != PO_SUCCESS) { + pool_seterror(POE_INVALID_CONF); + pool_conf_free(conf); + return (NULL); + } + result = conf->pc_prov->pc_get_binding(conf, pid); + (void) pool_conf_close(conf); + pool_conf_free(conf); + return (result); +} + +/*ARGSUSED*/ +int +prop_buf_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name, + pool_value_t *pval, void *user) +{ + uint64_t u; + int64_t i; + uchar_t bool; + const char *str; + double d; + char_buf_t *cb = (char_buf_t *)user; + int type = pool_value_get_type(pval); + + /* + * Ignore "type" and "<type>.name" properties as these are not + * to be displayed by this function + */ + if (strcmp(name, c_type) == 0 || + strcmp(property_name_minus_ns(pe, name), c_name) == 0) + return (PO_SUCCESS); + if (append_char_buf(cb, "\n%s\t%s\t%s ", cb->cb_tab_buf, + data_type_tags[type], name) == PO_FAIL) + return (PO_FAIL); + switch (type) { + case POC_UINT: + (void) pool_value_get_uint64(pval, &u); + if (append_char_buf(cb, "%llu", (u_longlong_t)u) == PO_FAIL) + return (PO_FAIL); + break; + case POC_INT: + (void) pool_value_get_int64(pval, &i); + if (append_char_buf(cb, "%lld", (longlong_t)i) == PO_FAIL) + return (PO_FAIL); + break; + case POC_STRING: + (void) pool_value_get_string(pval, &str); + if (append_char_buf(cb, "%s", str) == PO_FAIL) + return (PO_FAIL); + break; + case POC_BOOL: + (void) pool_value_get_bool(pval, &bool); + if (bool == 0) { + if (append_char_buf(cb, "%s", "false") == PO_FAIL) + return (PO_FAIL); + } else { + if (append_char_buf(cb, "%s", "true") == PO_FAIL) + return (PO_FAIL); + } + break; + case POC_DOUBLE: + (void) pool_value_get_double(pval, &d); + if (append_char_buf(cb, "%g", d) == PO_FAIL) + return (PO_FAIL); + break; + case POC_INVAL: /* Do nothing */ + break; + default: + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Return a buffer which describes the element + * pe is a pointer to the element + * deep is PO_TRUE/PO_FALSE to indicate whether children should be included + */ +char * +pool_base_info(const pool_elem_t *pe, char_buf_t *cb, int deep) +{ + const char *sres; + uint_t i; + uint_t nelem; + + pool_value_t val = POOL_VALUE_INITIALIZER; + pool_resource_t **rs; + pool_elem_t *elem; + pool_conf_t *conf = TO_CONF(pe); + + if (cb == NULL) { + char *ret = NULL; + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) + return (NULL); + + /* + * Populate the buffer with element details + */ + (void) pool_base_info(pe, cb, deep); + if (cb->cb_buf) + ret = strdup(cb->cb_buf); + free_char_buf(cb); + return (ret); + } + + if (append_char_buf(cb, "\n%s%s", cb->cb_tab_buf, + pool_elem_class_string(pe)) == PO_FAIL) { + return (NULL); + } + + if (pool_get_ns_property(pe, c_name, &val) == POC_STRING) { + (void) pool_value_get_string(&val, &sres); + if (append_char_buf(cb, " %s", sres) == PO_FAIL) { + return (NULL); + } + } + + /* + * Add in some details about the element + */ + if (pool_walk_properties(conf, (pool_elem_t *)pe, cb, + prop_buf_build_cb) == PO_FAIL) { + (void) append_char_buf(cb, "\n%s%s\n", cb->cb_tab_buf, + "Cannot access the properties of this element."); + return (NULL); + } + if (append_char_buf(cb, "%s", "\n") == PO_FAIL) + return (NULL); + + if (pe->pe_class == PEC_POOL) { + /* + * A shallow display of a pool only lists the resources by name + */ + + if ((rs = pool_query_pool_resources(conf, pool_elem_pool(pe), + &nelem, NULL)) == NULL) { + return (NULL); + } + + for (i = 0; i < nelem; i++) { + const char *str; + + elem = TO_ELEM(rs[i]); + + if (append_char_buf(cb, "\t%s%s", cb->cb_tab_buf, + pool_elem_class_string(elem)) == PO_FAIL) { + free(rs); + return (NULL); + } + + if (pool_get_ns_property(elem, c_name, &val) != + POC_STRING) { + free(rs); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + (void) pool_value_get_string(&val, &str); + if (append_char_buf(cb, "\t%s\n", str) == PO_FAIL) { + free(rs); + return (NULL); + } + } + free(rs); + } + if (deep == PO_TRUE) { + pool_t **ps; + pool_component_t **cs; + + if (strlcat(cb->cb_tab_buf, "\t", CB_TAB_BUF_SIZE) + >= CB_TAB_BUF_SIZE) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + switch (pe->pe_class) { + case PEC_SYSTEM: + if ((ps = pool_query_pools(conf, &nelem, NULL)) != + NULL) { /* process the pools */ + for (i = 0; i < nelem; i++) { + elem = TO_ELEM(ps[i]); + if (pool_base_info(elem, cb, + PO_FALSE) == NULL) { + free(ps); + return (NULL); + } + } + free(ps); + } + if ((rs = pool_query_resources(conf, &nelem, NULL)) != + NULL) { + for (i = 0; i < nelem; i++) { + elem = TO_ELEM(rs[i]); + if (pool_base_info(elem, cb, + PO_TRUE) == NULL) { + free(rs); + return (NULL); + } + } + free(rs); + } + break; + case PEC_POOL: + if ((rs = pool_query_pool_resources(conf, + pool_elem_pool(pe), &nelem, NULL)) == NULL) + return (NULL); + for (i = 0; i < nelem; i++) { + elem = TO_ELEM(rs[i]); + if (pool_base_info(elem, cb, PO_TRUE) == NULL) { + free(rs); + return (NULL); + } + } + free(rs); + break; + case PEC_RES_COMP: + if ((cs = pool_query_resource_components(conf, + pool_elem_res(pe), &nelem, NULL)) != NULL) { + for (i = 0; i < nelem; i++) { + elem = TO_ELEM(cs[i]); + if (pool_base_info(elem, cb, + PO_FALSE) == NULL) { + free(cs); + return (NULL); + } + } + free(cs); + } + break; + case PEC_RES_AGG: + case PEC_COMP: + break; + default: + /*NOTREACHED*/ + break; + } + if (cb->cb_tab_buf[0] != 0) + cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0; + } + return (cb->cb_buf); +} + +/* + * Returns The information on the specified pool or NULL. + * + * Errors If the status of the conf is INVALID or the supplied + * value of deep is illegal, POE_BADPARAM. + * + * The caller is responsible for free(3c)ing the string returned. + */ +char * +pool_info(const pool_conf_t *conf, const pool_t *pool, int deep) +{ + pool_elem_t *pe; + + pe = TO_ELEM(pool); + + if (TO_CONF(pe) != conf) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + return (pool_base_info(pe, NULL, deep)); +} + +/* + * Returns The information on the specified resource or NULL. + * + * Errors If the status of the conf is INVALID or the supplied + * value of deep is illegal, POE_BADPARAM. + * + * The caller is responsible for free(3c)ing the string returned. + */ +char * +pool_resource_info(const pool_conf_t *conf, const pool_resource_t *res, + int deep) +{ + pool_elem_t *pe; + + pe = TO_ELEM(res); + + if (TO_CONF(pe) != conf) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + return (pool_base_info(pe, NULL, deep)); +} + +/* + * Returns The information on the specified component or NULL. + * + * Errors If the status of the conf is INVALID or the supplied + * value of deep is illegal, POE_BADPARAM. + * + * The caller is responsible for free(3c)ing the string returned. + */ +char * +pool_component_info(const pool_conf_t *conf, const pool_component_t *comp, + int deep) +{ + pool_elem_t *pe; + + pe = TO_ELEM(comp); + + if (TO_CONF(pe) != conf) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + return (pool_base_info(pe, NULL, deep)); +} + +/* + * Returns The information on the specified conf or NULL. + * + * Errors If the status of the conf is INVALID or the supplied + * value of deep is illegal, POE_BADPARAM. + * + * The caller is responsible for free(3c)ing the string returned. + */ +char * +pool_conf_info(const pool_conf_t *conf, int deep) +{ + pool_elem_t *pe; + + if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + if ((pe = pool_conf_to_elem(conf)) == NULL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return (pool_base_info(pe, NULL, deep)); +} + + +/* + * Set the thread specific error value. + */ +void +pool_seterror(int errval) +{ + if (thr_main()) { + pool_errval = errval; + return; + } + (void) thr_keycreate_once(&errkey, 0); + (void) thr_setspecific(errkey, (void *)(intptr_t)errval); +} + +/* + * Return the current value of the error code. + * Returns: int error code + */ +int +pool_error(void) +{ + if (thr_main()) + return (pool_errval); + if (errkey == THR_ONCE_KEY) + return (POE_OK); + return ((uintptr_t)pthread_getspecific(errkey)); +} + +/* + * Return the text represenation for the current value of the error code. + * Returns: const char * error string + */ +const char * +pool_strerror(int error) +{ + char *str; + + switch (error) { + case POE_OK: + str = dgettext(TEXT_DOMAIN, "Operation successful"); + break; + case POE_BAD_PROP_TYPE: + str = dgettext(TEXT_DOMAIN, + "Attempted to retrieve the wrong property type"); + break; + case POE_INVALID_CONF: + str = dgettext(TEXT_DOMAIN, "Invalid configuration"); + break; + case POE_NOTSUP: + str = dgettext(TEXT_DOMAIN, "Operation is not supported"); + break; + case POE_INVALID_SEARCH: + str = dgettext(TEXT_DOMAIN, "Invalid search"); + break; + case POE_BADPARAM: + str = dgettext(TEXT_DOMAIN, "Bad parameter supplied"); + break; + case POE_PUTPROP: + str = dgettext(TEXT_DOMAIN, "Error putting property"); + break; + case POE_DATASTORE: + str = dgettext(TEXT_DOMAIN, "Pools repository error"); + break; + case POE_SYSTEM: + str = dgettext(TEXT_DOMAIN, "System error"); + break; + case POE_ACCESS: + str = dgettext(TEXT_DOMAIN, "Permission denied"); + break; + default: + errno = ESRCH; + str = NULL; + } + return (str); +} + +int +pool_get_status(int *state) +{ + int fd; + pool_status_t status; + + if ((fd = open(pool_info_location, O_RDONLY)) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (ioctl(fd, POOL_STATUSQ, &status) < 0) { + (void) close(fd); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) close(fd); + + *state = status.ps_io_state; + + return (PO_SUCCESS); +} + +int +pool_set_status(int state) +{ + int old_state; + + if (pool_get_status(&old_state) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if (old_state != state) { + int fd; + pool_status_t status; + char *fmri; + + /* + * Changing the status of pools is performed by enabling + * or disabling the pools service instance. If this + * function has not been invoked by startd then we simply + * enable/disable the service and return success. + * + * There is no way to specify that state changes must be + * synchronous using the library API as yet, so we use + * the -s option provided by svcadm. + */ + fmri = getenv("SMF_FMRI"); + if (fmri == NULL) { + FILE *p; + char *cmd; + + if (state != 0) { + cmd = "/usr/sbin/svcadm enable -s " \ + SMF_SVC_INSTANCE; + } else { + cmd = "/usr/sbin/svcadm disable -s " \ + SMF_SVC_INSTANCE; + } + if ((p = popen(cmd, "wF")) == NULL || pclose(p) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + return (PO_SUCCESS); + } + + if ((fd = open(pool_dynamic_location(), O_RDWR | O_EXCL)) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + /* + * If pools are being enabled/disabled by another smf service, + * enable the smf service instance. This must be done + * asynchronously as one service cannot synchronously + * enable/disable another. + */ + if (strcmp(fmri, SMF_SVC_INSTANCE) != 0) { + int res; + + if (state != 0) + res = smf_enable_instance(SMF_SVC_INSTANCE, 0); + else + res = smf_disable_instance(SMF_SVC_INSTANCE, 0); + + if (res != 0) { + (void) close(fd); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + status.ps_io_state = state; + + if (ioctl(fd, POOL_STATUS, &status) < 0) { + (void) close(fd); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + (void) close(fd); + + } + return (PO_SUCCESS); +} + +/* + * General Data Provider Independent Access Methods + */ + +/* + * Property manipulation code. + * + * The pool_(get|rm|set)_property() functions consult the plugins before + * looking at the actual configuration. This allows plugins to provide + * "virtual" properties that may not exist in the configuration file per se, + * but behave like regular properties. This also allows plugins to reserve + * certain properties as read-only, non-removable, etc. + * + * A negative value returned from the plugin denotes error, 0 means that the + * property request should be forwarded to the backend, and 1 means the request + * was satisfied by the plugin and should not be processed further. + * + * The (get|rm|set)_property() functions bypass the plugin layer completely, + * and hence should not be generally used. + */ + +/* + * Return true if the string passed in matches the pattern + * [A-Za-z][A-Za-z0-9,._-]* + */ +int +is_valid_name(const char *name) +{ + int i; + char c; + + if (name == NULL) + return (PO_FALSE); + if (!isalpha(name[0])) + return (PO_FALSE); + for (i = 1; (c = name[i]) != '\0'; i++) { + if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-') + return (PO_FALSE); + } + return (PO_TRUE); +} + +/* + * Return true if the string passed in matches the pattern + * [A-Za-z_][A-Za-z0-9,._-]* + * A property name starting with a '_' is an "invisible" property that does not + * show up in a property walk. + */ +int +is_valid_prop_name(const char *prop_name) +{ + int i; + char c; + + if (prop_name == NULL) + return (PO_FALSE); + if (!isalpha(prop_name[0]) && prop_name[0] != '_') + return (PO_FALSE); + for (i = 1; (c = prop_name[i]) != '\0'; i++) { + if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-') + return (PO_FALSE); + } + return (PO_TRUE); +} + +/* + * Return the specified property value. + * + * POC_INVAL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +pool_value_class_t +pool_get_property(const pool_conf_t *conf, const pool_elem_t *pe, + const char *name, pool_value_t *val) +{ + const pool_prop_t *prop_info; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (POC_INVAL); + } + if (pool_value_set_name(val, name) != PO_SUCCESS) { + return (POC_INVAL); + } + /* + * Check to see if this is a property we are managing. If it + * is and it has an interceptor installed for property + * retrieval, use it. + */ + if ((prop_info = provider_get_prop(pe, name)) != NULL && + prop_info->pp_op.ppo_get_value != NULL) { + if (prop_info->pp_op.ppo_get_value(pe, val) == PO_FAIL) + return (POC_INVAL); + else + return (pool_value_get_type(val)); + } + return (pe->pe_get_prop(pe, name, val)); +} + +/* + * Return the specified property value with the namespace prepended. + * e.g. If this function is used to get the property "name" on a pool, it will + * attempt to retrieve "pool.name". + * + * POC_INVAL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +pool_value_class_t +pool_get_ns_property(const pool_elem_t *pe, const char *name, pool_value_t *val) +{ + int ret; + char_buf_t *cb; + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) + return (POC_INVAL); + if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == + PO_FAIL) { + free_char_buf(cb); + return (POC_INVAL); + } + ret = pool_get_property(TO_CONF(pe), pe, cb->cb_buf, val); + free_char_buf(cb); + return (ret); +} + +/* + * Update the specified property value. + * + * PO_FAIL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +int +pool_put_property(pool_conf_t *conf, pool_elem_t *pe, const char *name, + const pool_value_t *val) +{ + const pool_prop_t *prop_info; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + if (TO_CONF(pe) != conf) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + /* Don't allow (re)setting of the "temporary" property */ + if (!is_valid_prop_name(name) || strstr(name, ".temporary") != NULL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + /* Don't allow rename of temporary pools/resources */ + if (strstr(name, ".name") != NULL && elem_is_tmp(pe)) { + boolean_t rename = B_TRUE; + pool_value_t *pv = pool_value_alloc(); + + if (pe->pe_get_prop(pe, name, pv) != POC_INVAL) { + const char *s1 = NULL; + const char *s2 = NULL; + + (void) pool_value_get_string(pv, &s1); + (void) pool_value_get_string(val, &s2); + if (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0) + rename = B_FALSE; + } + pool_value_free(pv); + + if (rename) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + + /* + * Check to see if this is a property we are managing. If it is, + * ensure that we are happy with what the user is doing. + */ + if ((prop_info = provider_get_prop(pe, name)) != NULL) { + if (prop_is_readonly(prop_info) == PO_TRUE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + if (prop_info->pp_op.ppo_set_value && + prop_info->pp_op.ppo_set_value(pe, val) == PO_FAIL) + return (PO_FAIL); + } + + return (pe->pe_put_prop(pe, name, val)); +} + +/* + * Set temporary property to flag as a temporary element. + * + * PO_FAIL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +int +pool_set_temporary(pool_conf_t *conf, pool_elem_t *pe) +{ + int res; + char name[128]; + pool_value_t *val; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + if (TO_CONF(pe) != conf) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + /* create property name based on element type */ + if (snprintf(name, sizeof (name), "%s.temporary", + pool_elem_class_string(pe)) > sizeof (name)) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if ((val = pool_value_alloc()) == NULL) + return (PO_FAIL); + + pool_value_set_bool(val, (uchar_t)1); + + res = pe->pe_put_prop(pe, name, val); + + pool_value_free(val); + + return (res); +} + +/* + * Update the specified property value with the namespace prepended. + * e.g. If this function is used to update the property "name" on a pool, it + * will attempt to update "pool.name". + * + * PO_FAIL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +int +pool_put_ns_property(pool_elem_t *pe, const char *name, + const pool_value_t *val) +{ + char_buf_t *cb; + int ret; + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) + return (PO_FAIL); + if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == + PO_FAIL) { + free_char_buf(cb); + return (PO_FAIL); + } + ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val); + free_char_buf(cb); + return (ret); +} + +/* + * Update the specified property value. Do not use the property + * protection mechanism. This function should only be used for cases + * where the library must bypass the normal property protection + * mechanism. The only known use is to update properties in the static + * configuration when performing a commit. + * + * PO_FAIL is returned if an error is detected and the error code is + * updated to indicate the cause of the error. + */ +int +pool_put_any_property(pool_elem_t *pe, const char *name, + const pool_value_t *val) +{ + if (!is_valid_prop_name(name)) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + return (pe->pe_put_prop(pe, name, val)); +} + +/* + * Update the specified property value with the namespace prepended. + * e.g. If this function is used to update the property "name" on a pool, it + * will attempt to update "pool.name". + * + * PO_FAIL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +int +pool_put_any_ns_property(pool_elem_t *pe, const char *name, + const pool_value_t *val) +{ + char_buf_t *cb; + int ret; + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) + return (PO_FAIL); + if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == + PO_FAIL) { + free_char_buf(cb); + return (PO_FAIL); + } + ret = pool_put_any_property(pe, cb->cb_buf, val); + free_char_buf(cb); + return (ret); +} + +/* + * Remove the specified property value. Note that some properties are + * mandatory and thus failure to remove these properties is inevitable. + * PO_FAIL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +int +pool_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name) +{ + const pool_prop_t *prop_info; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + if (TO_CONF(pe) != conf) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + /* Don't allow removal of the "temporary" property */ + if (strstr(name, ".temporary") != NULL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + /* + * Check to see if this is a property we are managing. If it is, + * ensure that we are happy with what the user is doing. + */ + if ((prop_info = provider_get_prop(pe, name)) != NULL) { + if (prop_is_optional(prop_info) == PO_FALSE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + return (pe->pe_rm_prop(pe, name)); +} + +/* + * Check if the supplied name is a namespace protected property for the supplied + * element, pe. If it is, return the prefix, otherwise just return NULL. + */ +const char * +is_ns_property(const pool_elem_t *pe, const char *name) +{ + const char *prefix; + + if ((prefix = pool_elem_class_string(pe)) != NULL) { + if (strncmp(name, prefix, strlen(prefix)) == 0) + return (prefix); + } + return (NULL); +} + +/* + * Check if the supplied name is a namespace protected property for the supplied + * element, pe. If it is, return the property name with the namespace stripped, + * otherwise just return the name. + */ +const char * +property_name_minus_ns(const pool_elem_t *pe, const char *name) +{ + const char *prefix; + if ((prefix = is_ns_property(pe, name)) != NULL) { + return (name + strlen(prefix) + 1); + } + return (name); +} + +/* + * Create an element to represent a pool and add it to the supplied + * configuration. + */ +pool_t * +pool_create(pool_conf_t *conf, const char *name) +{ + pool_elem_t *pe; + pool_value_t val = POOL_VALUE_INITIALIZER; + const pool_prop_t *default_props; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (NULL); + + if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) { + /* + * A pool with the same name exists. Reject. + */ + pool_seterror(POE_BADPARAM); + return (NULL); + } + if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_POOL, PREC_INVALID, + PCEC_INVALID)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if ((default_props = provider_get_props(pe)) != NULL) { + int i; + for (i = 0; default_props[i].pp_pname != NULL; i++) { + if (prop_is_init(&default_props[i]) && + (pool_put_any_property(pe, + default_props[i].pp_pname, + &default_props[i].pp_value) == PO_FAIL)) { + (void) pool_destroy(conf, pool_elem_pool(pe)); + return (NULL); + } + } + } + if (pool_value_set_string(&val, name) != PO_SUCCESS) { + (void) pool_destroy(conf, pool_elem_pool(pe)); + pool_seterror(POE_SYSTEM); + return (NULL); + } + if (pool_put_property(conf, pe, "pool.name", &val) == PO_FAIL) { + (void) pool_destroy(conf, pool_elem_pool(pe)); + pool_seterror(POE_PUTPROP); + return (NULL); + } + + /* + * If we are creating a temporary pool configuration, flag the pool. + */ + if (conf->pc_prov->pc_oflags & PO_TEMP) { + if (pool_set_temporary(conf, pe) == PO_FAIL) { + (void) pool_destroy(conf, pool_elem_pool(pe)); + return (NULL); + } + } + + return (pool_elem_pool(pe)); +} + +/* + * Create an element to represent a res. + */ +pool_resource_t * +pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name) +{ + pool_elem_t *pe; + pool_value_t val = POOL_VALUE_INITIALIZER; + const pool_prop_t *default_props; + pool_resource_t **resources; + int is_default = 0; + uint_t nelem; + pool_elem_class_t elem_class; + pool_resource_elem_class_t type; + pool_value_t *props[] = { NULL, NULL }; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (NULL); + + if ((type = pool_resource_elem_class_from_string(sz_type)) == + PREC_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (strcmp(sz_type, "pset") != 0) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) != + NULL) { + /* + * Resources must be unique by name+type. + */ + pool_seterror(POE_BADPARAM); + return (NULL); + } + + props[0] = &val; + + if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS || + pool_value_set_name(props[0], c_type) != PO_SUCCESS) { + return (NULL); + } + + if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) { + /* + * This is the first representative of this type; when it's + * created it should be created with 'default' = 'true'. + */ + is_default = 1; + } else { + free(resources); + } + /* + * TODO: If Additional PEC_RES_COMP types are added to + * pool_impl.h, this would need to be extended. + */ + switch (type) { + case PREC_PSET: + elem_class = PEC_RES_COMP; + break; + default: + elem_class = PEC_RES_AGG; + break; + } + if ((pe = conf->pc_prov->pc_elem_create(conf, elem_class, type, + PCEC_INVALID)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + + /* + * The plugins contain a list of default properties and their values + * for resources. The resource returned, hence, is fully initialized. + */ + if ((default_props = provider_get_props(pe)) != NULL) { + int i; + for (i = 0; default_props[i].pp_pname != NULL; i++) { + if (prop_is_init(&default_props[i]) && + pool_put_any_property(pe, default_props[i].pp_pname, + &default_props[i].pp_value) == PO_FAIL) { + (void) pool_resource_destroy(conf, + pool_elem_res(pe)); + return (NULL); + } + } + } + if (pool_value_set_string(&val, name) != PO_SUCCESS || + pool_put_ns_property(pe, "name", &val) != PO_SUCCESS) { + (void) pool_resource_destroy(conf, pool_elem_res(pe)); + return (NULL); + } + if (is_default) { + pool_value_set_bool(&val, PO_TRUE); + if (pool_put_any_ns_property(pe, "default", &val) != + PO_SUCCESS) { + (void) pool_resource_destroy(conf, pool_elem_res(pe)); + return (NULL); + } + } + + /* + * If we are creating a temporary pool configuration, flag the resource. + */ + if (conf->pc_prov->pc_oflags & PO_TEMP) { + if (pool_set_temporary(conf, pe) != PO_SUCCESS) { + (void) pool_resource_destroy(conf, pool_elem_res(pe)); + return (NULL); + } + } + + return (pool_elem_res(pe)); +} + +/* + * Create an element to represent a resource component. + */ +pool_component_t * +pool_component_create(pool_conf_t *conf, const pool_resource_t *res, + int64_t sys_id) +{ + pool_elem_t *pe; + pool_value_t val = POOL_VALUE_INITIALIZER; + const pool_prop_t *default_props; + char refbuf[KEY_BUFFER_SIZE]; + + if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_COMP, + PREC_INVALID, PCEC_CPU)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + /* + * TODO: If additional PEC_COMP types are added in pool_impl.h, + * this would need to be extended. + */ + pe->pe_component_class = PCEC_CPU; + /* Now set the container for this comp */ + if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) { + (void) pool_component_destroy(pool_elem_comp(pe)); + return (NULL); + } + /* + * The plugins contain a list of default properties and their values + * for resources. The resource returned, hence, is fully initialized. + */ + if ((default_props = provider_get_props(pe)) != NULL) { + int i; + for (i = 0; default_props[i].pp_pname != NULL; i++) { + if (prop_is_init(&default_props[i]) && + pool_put_any_property(pe, + default_props[i].pp_pname, + &default_props[i].pp_value) == PO_FAIL) { + (void) pool_component_destroy( + pool_elem_comp(pe)); + return (NULL); + } + } + } + /* + * Set additional attributes/properties on component. + */ + pool_value_set_int64(&val, sys_id); + if (pool_put_any_ns_property(pe, c_sys_prop, &val) != PO_SUCCESS) { + (void) pool_component_destroy(pool_elem_comp(pe)); + return (NULL); + } + if (snprintf(refbuf, KEY_BUFFER_SIZE, "%s_%lld", + pool_elem_class_string(pe), sys_id) > KEY_BUFFER_SIZE) { + (void) pool_component_destroy(pool_elem_comp(pe)); + return (NULL); + } + if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) { + (void) pool_component_destroy(pool_elem_comp(pe)); + return (NULL); + } + if (pool_put_any_ns_property(pe, c_ref_id, &val) != PO_SUCCESS) { + (void) pool_component_destroy(pool_elem_comp(pe)); + return (NULL); + } + return (pool_elem_comp(pe)); +} + +/* + * Return the location of a configuration. + */ +const char * +pool_conf_location(const pool_conf_t *conf) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return (conf->pc_location); +} +/* + * Close a configuration, freeing all associated resources. Once a + * configuration is closed, it can no longer be used. + */ +int +pool_conf_close(pool_conf_t *conf) +{ + int rv; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + rv = conf->pc_prov->pc_close(conf); + conf->pc_prov = NULL; + free((void *)conf->pc_location); + conf->pc_location = NULL; + conf->pc_state = POF_INVALID; + return (rv); +} + +/* + * Remove a configuration, freeing all associated resources. Once a + * configuration is removed, it can no longer be accessed and is forever + * gone. + */ +int +pool_conf_remove(pool_conf_t *conf) +{ + int rv; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + rv = conf->pc_prov->pc_remove(conf); + conf->pc_state = POF_INVALID; + return (rv); +} + +/* + * pool_conf_alloc() allocate the resources to represent a configuration. + */ +pool_conf_t * +pool_conf_alloc(void) +{ + pool_conf_t *conf; + + if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + conf->pc_state = POF_INVALID; + return (conf); +} + +/* + * pool_conf_free() frees the resources associated with a configuration. + */ +void +pool_conf_free(pool_conf_t *conf) +{ + free(conf); +} + +/* + * pool_conf_open() opens a configuration, establishing all required + * connections to the data source. + */ +int +pool_conf_open(pool_conf_t *conf, const char *location, int oflags) +{ + /* + * Since you can't do anything to a pool configuration without opening + * it, this represents a good point to intialise structures that would + * otherwise need to be initialised in a .init section. + */ + internal_init(); + + if (pool_conf_status(conf) != POF_INVALID) { + /* + * Already opened configuration, return PO_FAIL + */ + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + if (oflags & ~(PO_RDONLY | PO_RDWR | PO_CREAT | PO_DISCO | PO_UPDATE | + PO_TEMP)) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + /* + * Creating a configuration implies read-write access, so make + * sure that PO_RDWR is set in addition if PO_CREAT is set. + */ + if (oflags & PO_CREAT) + oflags |= PO_RDWR; + + /* location is ignored when creating a temporary configuration */ + if (oflags & PO_TEMP) + location = ""; + + if ((conf->pc_location = strdup(location)) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * This is the crossover point into the actual data provider + * implementation, allocate a data provider of the appropriate + * type for your data storage medium. In this case it's either a kernel + * or xml data provider. To use a different data provider, write some + * code to implement all the required interfaces and then change the + * following code to allocate a data provider which uses your new code. + * All data provider routines can be static, apart from the allocation + * routine. + * + * For temporary pools (PO_TEMP) we start with a copy of the current + * dynamic configuration and do all of the updates in-memory. + */ + if (oflags & PO_TEMP) { + if (pool_knl_connection_alloc(conf, PO_TEMP) != PO_SUCCESS) { + conf->pc_state = POF_INVALID; + return (PO_FAIL); + } + /* set rdwr flag so we can updated the in-memory config. */ + conf->pc_prov->pc_oflags |= PO_RDWR; + + } else if (strcmp(location, pool_dynamic_location()) == 0) { + if (pool_knl_connection_alloc(conf, oflags) != PO_SUCCESS) { + conf->pc_state = POF_INVALID; + return (PO_FAIL); + } + } else { + if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) { + conf->pc_state = POF_INVALID; + return (PO_FAIL); + } + } + return (PO_SUCCESS); +} + +/* + * Rollback a configuration. This will undo all changes to the configuration + * since the last time pool_conf_commit was called. + */ +int +pool_conf_rollback(pool_conf_t *conf) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + return (conf->pc_prov->pc_rollback(conf)); +} + +/* + * Commit a configuration. This will apply all changes to the + * configuration to the permanent data store. The active parameter + * indicates whether the configuration should be used to update the + * dynamic configuration from the supplied (static) configuration or + * whether it should be written back to persistent store. + */ +int +pool_conf_commit(pool_conf_t *conf, int active) +{ + int retval; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + if (active) { + int oflags; + + if (conf_is_dynamic(conf) == PO_TRUE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + /* + * Pretend that the configuration was opened PO_RDWR + * so that a configuration which was opened PO_RDONLY + * can be committed. The original flags are preserved + * in oflags and restored after pool_conf_commit_sys() + * returns. + */ + oflags = conf->pc_prov->pc_oflags; + conf->pc_prov->pc_oflags |= PO_RDWR; + retval = pool_conf_commit_sys(conf, active); + conf->pc_prov->pc_oflags = oflags; + } else { + /* + * Write the configuration back to the backing store. + */ + retval = conf->pc_prov->pc_commit(conf); + } + return (retval); +} + +/* + * Export a configuration. This will export a configuration in the specified + * format (fmt) to the specified location. + */ +int +pool_conf_export(const pool_conf_t *conf, const char *location, + pool_export_format_t fmt) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + return (conf->pc_prov->pc_export(conf, location, fmt)); +} + +/* + * Validate a configuration. This will validate a configuration at the + * specified level. + */ +int +pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + return (conf->pc_prov->pc_validate(conf, level)); +} + +/* + * Update the snapshot of a configuration. This can only be used on a + * dynamic configuration. + */ +int +pool_conf_update(const pool_conf_t *conf, int *changed) +{ + if (pool_conf_status(conf) == POF_INVALID || + conf_is_dynamic(conf) == PO_FALSE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + /* + * Since this function only makes sense for dynamic + * configurations, just call directly into the appropriate + * function. This could be added into the pool_connection_t + * interface if it was ever required. + */ + if (changed) + *changed = 0; + return (pool_knl_update((pool_conf_t *)conf, changed)); +} + +/* + * Walk the properties of the supplied elem, calling the user supplied + * function repeatedly as long as the user function returns + * PO_SUCCESS. + */ +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 *)) +{ + return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0)); +} + +void +free_value_list(int npvals, pool_value_t **pvals) +{ + int j; + + for (j = 0; j < npvals; j++) { + if (pvals[j]) + pool_value_free(pvals[j]); + } + free(pvals); +} + +/* + * Walk the properties of the supplied elem, calling the user supplied + * function repeatedly as long as the user function returns + * PO_SUCCESS. + * The list of properties to be walked is retrieved from the element + */ +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) +{ + pool_value_t **pvals; + int i; + const pool_prop_t *props = provider_get_props(elem); + uint_t npvals; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + if (props == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + + if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL) + return (PO_FAIL); + + /* + * Now walk the managed properties. As we find managed + * properties removed them from the list of all properties to + * prevent duplication. + */ + for (i = 0; props[i].pp_pname != NULL; i++) { + int j; + + /* + * Special processing for type + */ + if (strcmp(props[i].pp_pname, c_type) == 0) { + pool_value_t val = POOL_VALUE_INITIALIZER; + + if (pool_value_set_name(&val, props[i].pp_pname) == + PO_FAIL) { + free_value_list(npvals, pvals); + return (PO_FAIL); + } + if (props[i].pp_op.ppo_get_value(elem, &val) == + PO_FAIL) { + free_value_list(npvals, pvals); + return (PO_FAIL); + } + if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) { + if (prop_callback(conf, elem, props[i].pp_pname, + &val, arg) != PO_SUCCESS) { + free_value_list(npvals, pvals); + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + continue; + } + + for (j = 0; j < npvals; j++) { + if (pvals[j] && strcmp(pool_value_get_name(pvals[j]), + props[i].pp_pname) == 0) + break; + } + /* + * If we have found the property, then j < npvals. Process it + * according to our property attributes. Otherwise, it's not + * a managed property, so just ignore it until later. + */ + if (j < npvals) { + if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) { + if (props[i].pp_op.ppo_get_value) { + if (pool_value_set_name(pvals[j], + props[i].pp_pname) == PO_FAIL) { + free_value_list(npvals, pvals); + return (PO_FAIL); + } + if (props[i].pp_op.ppo_get_value(elem, + pvals[j]) == PO_FAIL) { + free_value_list(npvals, pvals); + return (PO_FAIL); + } + } + if (prop_callback(conf, elem, props[i].pp_pname, + pvals[j], arg) != PO_SUCCESS) { + free_value_list(npvals, pvals); + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + pool_value_free(pvals[j]); + pvals[j] = NULL; + } + } + for (i = 0; i < npvals; i++) { + if (pvals[i]) { + const char *name = pool_value_get_name(pvals[i]); + char *qname = strrchr(name, '.'); + if ((qname && qname[1] != '_') || + (!qname && name[0] != '_')) { + if (prop_callback(conf, elem, name, pvals[i], + arg) != PO_SUCCESS) { + free_value_list(npvals, pvals); + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + pool_value_free(pvals[i]); + pvals[i] = NULL; + } + } + free(pvals); + return (PO_SUCCESS); +} + +/* + * Return a pool, searching the supplied configuration for a pool with the + * supplied name. The search is case sensitive. + */ +pool_t * +pool_get_pool(const pool_conf_t *conf, const char *name) +{ + pool_value_t *props[] = { NULL, NULL }; + pool_t **rs; + pool_t *ret; + uint_t size = 0; + pool_value_t val = POOL_VALUE_INITIALIZER; + + props[0] = &val; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (pool_value_set_name(props[0], "pool.name") != PO_SUCCESS || + pool_value_set_string(props[0], name) != PO_SUCCESS) { + return (NULL); + } + rs = pool_query_pools(conf, &size, props); + if (rs == NULL) { /* Can't find a pool to match the name */ + return (NULL); + } + if (size != 1) { + free(rs); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + ret = rs[0]; + free(rs); + return (ret); +} + +/* + * Return a result set of pools, searching the supplied configuration + * for pools which match the supplied property criteria. props is a null + * terminated list of properties which will be used to match qualifying + * pools. size is updated with the size of the pool + */ +pool_t ** +pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props) +{ + pool_result_set_t *rs; + pool_elem_t *pe; + pool_t **result = NULL; + int i = 0; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props); + if (rs == NULL) { + return (NULL); + } + if ((*size = pool_rs_count(rs)) == 0) { + (void) pool_rs_close(rs); + return (NULL); + } + if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) { + pool_seterror(POE_SYSTEM); + (void) pool_rs_close(rs); + return (NULL); + } + (void) memset(result, 0, sizeof (pool_t *) * (*size + 1)); + for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { + if (pool_elem_class(pe) != PEC_POOL) { + pool_seterror(POE_INVALID_CONF); + free(result); + (void) pool_rs_close(rs); + return (NULL); + } + result[i++] = pool_elem_pool(pe); + } + (void) pool_rs_close(rs); + return (result); +} + +/* + * Return an res, searching the supplied configuration for an res with the + * supplied name. The search is case sensitive. + */ +pool_resource_t * +pool_get_resource(const pool_conf_t *conf, const char *sz_type, + const char *name) +{ + pool_value_t *props[] = { NULL, NULL, NULL }; + pool_resource_t **rs; + pool_resource_t *ret; + uint_t size = 0; + char_buf_t *cb = NULL; + pool_value_t val0 = POOL_VALUE_INITIALIZER; + pool_value_t val1 = POOL_VALUE_INITIALIZER; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (sz_type == NULL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + props[0] = &val0; + props[1] = &val1; + + if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS || + pool_value_set_name(props[0], c_type) != PO_SUCCESS) + return (NULL); + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + return (NULL); + } + if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + if (pool_value_set_string(props[1], name) != PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + free_char_buf(cb); + rs = pool_query_resources(conf, &size, props); + if (rs == NULL) { + return (NULL); + } + if (size != 1) { + free(rs); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + ret = rs[0]; + free(rs); + return (ret); +} + +/* + * Return a result set of res (actually as pool_elem_ts), searching the + * supplied configuration for res which match the supplied property + * criteria. props is a null terminated list of properties which will be used + * to match qualifying res. + */ +pool_resource_t ** +pool_query_resources(const pool_conf_t *conf, uint_t *size, + pool_value_t **props) +{ + pool_result_set_t *rs; + pool_elem_t *pe; + pool_resource_t **result = NULL; + int i = 0; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + *size = 0; + + rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props); + if (rs == NULL) { + return (NULL); + } + if ((*size = pool_rs_count(rs)) == 0) { + (void) pool_rs_close(rs); + return (NULL); + } + if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1))) + == NULL) { + pool_seterror(POE_SYSTEM); + (void) pool_rs_close(rs); + return (NULL); + } + (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1)); + for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { + if (pool_elem_class(pe) != PEC_RES_COMP && + pool_elem_class(pe) != PEC_RES_AGG) { + pool_seterror(POE_INVALID_CONF); + free(result); + (void) pool_rs_close(rs); + return (NULL); + } + result[i++] = pool_elem_res(pe); + } + (void) pool_rs_close(rs); + return (result); +} + +/* + * Return a result set of comp (actually as pool_elem_ts), searching the + * supplied configuration for comp which match the supplied property + * criteria. props is a null terminated list of properties which will be used + * to match qualifying comp. + */ +pool_component_t ** +pool_query_components(const pool_conf_t *conf, uint_t *size, + pool_value_t **props) +{ + return (pool_query_resource_components(conf, NULL, size, props)); +} + +/* + * Destroy a pool. If the pool cannot be found or removed an error is + * returned. This is basically a wrapper around pool_elem_remove to ensure + * some type safety for the pool subtype. + */ +int +pool_destroy(pool_conf_t *conf, pool_t *pp) +{ + pool_elem_t *pe; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + pe = TO_ELEM(pp); + + /* + * Cannot destroy the default pool. + */ + if (elem_is_default(pe) == PO_TRUE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + if (pool_elem_remove(pe) != PO_SUCCESS) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * Destroy an res. If the res cannot be found or removed an error is + * returned. This is basically a wrapper around pool_elem_remove to ensure + * some type safety for the res subtype. + */ +int +pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs) +{ + pool_elem_t *pe; + pool_component_t **rl; + uint_t res_size; + pool_t **pl; + uint_t npool; + int i; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + pe = TO_ELEM(prs); + + if (resource_is_system(prs) == PO_TRUE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + /* + * Walk all the pools and dissociate any pools which are using + * this resource. + */ + if ((pl = pool_query_pools(conf, &npool, NULL)) != NULL) { + for (i = 0; i < npool; i++) { + pool_resource_t **rl; + uint_t nres; + int j; + + if ((rl = pool_query_pool_resources(conf, pl[i], &nres, + NULL)) != NULL) { + for (j = 0; j < nres; j++) { + if (rl[j] == prs) { + if (pool_dissociate(conf, pl[i], + rl[j]) != PO_SUCCESS) { + free(rl); + free(pl); + return (PO_FAIL); + } + break; + } + } + free(rl); + } + } + free(pl); + } + if (pe->pe_class == PEC_RES_COMP) { + pool_resource_t *default_set_res; + + /* + * Use the xtransfer option to move comp around + */ + default_set_res = (pool_resource_t *)get_default_resource(prs); + + if ((rl = pool_query_resource_components(conf, prs, &res_size, + NULL)) != NULL) { + int ostate = conf->pc_state; + conf->pc_state = POF_DESTROY; + if (pool_resource_xtransfer(conf, prs, default_set_res, + rl) == PO_FAIL) { + free(rl); + conf->pc_state = ostate; + return (PO_FAIL); + } + conf->pc_state = ostate; + free(rl); + } + } + if (pool_elem_remove(pe) != PO_SUCCESS) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * Destroy a comp. If the comp cannot be found or removed an error is + * returned. This is basically a wrapper around pool_elem_remove to ensure + * some type safety for the comp subtype. + */ +int +pool_component_destroy(pool_component_t *pr) +{ + pool_elem_t *pe = TO_ELEM(pr); + + if (pool_elem_remove(pe) != PO_SUCCESS) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * Remove a pool_elem_t from a configuration. This has been "hidden" away as + * a static routine since the only elements which are currently being removed + * are pools, res & comp and the wrapper functions above provide type-safe + * access. However, if there is a need to remove other types of elements + * then this could be promoted to pool_impl.h or more wrappers could + * be added to pool_impl.h. + */ +int +pool_elem_remove(pool_elem_t *pe) +{ + return (pe->pe_remove(pe)); +} + +/* + * Execute a query to search for a qualifying set of elements. + */ +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) +{ + return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes, + props)); +} + +/* + * Get the next result from a result set of elements. + */ +pool_elem_t * +pool_rs_next(pool_result_set_t *set) +{ + return (set->prs_next(set)); +} + +/* + * Get the previous result from a result set of elements. + */ +pool_elem_t * +pool_rs_prev(pool_result_set_t *set) +{ + return (set->prs_prev(set)); +} + +/* + * Get the first result from a result set of elements. + */ +pool_elem_t * +pool_rs_first(pool_result_set_t *set) +{ + return (set->prs_first(set)); +} + +/* + * Get the last result from a result set of elements. + */ +pool_elem_t * +pool_rs_last(pool_result_set_t *set) +{ + return (set->prs_last(set)); +} + + +/* + * Get the count for a result set of elements. + */ +int +pool_rs_count(pool_result_set_t *set) +{ + return (set->prs_count(set)); +} + +/* + * Get the index for a result set of elements. + */ +int +pool_rs_get_index(pool_result_set_t *set) +{ + return (set->prs_get_index(set)); +} + +/* + * Set the index for a result set of elements. + */ +int +pool_rs_set_index(pool_result_set_t *set, int index) +{ + return (set->prs_set_index(set, index)); +} + +/* + * Close a result set of elements, freeing all associated resources. + */ +int +pool_rs_close(pool_result_set_t *set) +{ + return (set->prs_close(set)); +} + +/* + * When transferring resource components using pool_resource_transfer, + * this function is invoked to choose which actual components will be + * transferred. + */ +int +choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size) +{ + pool_component_t **components = NULL, *moved[] = { NULL, NULL }; + int i; + uint_t ncomponent; + pool_conf_t *conf = TO_CONF(TO_ELEM(src)); + + if (size == 0) + return (PO_SUCCESS); + /* + * Get the component list from our src component. + */ + if ((components = pool_query_resource_components(conf, src, &ncomponent, + NULL)) == NULL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + qsort(components, ncomponent, sizeof (pool_elem_t *), + qsort_elem_compare); + /* + * Components that aren't specifically requested by the resource + * should be transferred out first. + */ + for (i = 0; size > 0 && components[i] != NULL; i++) { + if (!cpu_is_requested(components[i])) { + moved[0] = components[i]; + if (pool_resource_xtransfer(conf, src, dst, moved) == + PO_SUCCESS) { + size--; + } + } + } + + /* + * If we couldn't find enough "un-requested" components, select random + * requested components. + */ + for (i = 0; size > 0 && components[i] != NULL; i++) { + if (cpu_is_requested(components[i])) { + moved[0] = components[i]; + if (pool_resource_xtransfer(conf, src, dst, moved) == + PO_SUCCESS) { + size--; + } + } + } + + free(components); + /* + * If we couldn't transfer out all the resources we asked for, then + * return error. + */ + return (size == 0 ? PO_SUCCESS : PO_FAIL); +} + +/* + * Common processing for a resource transfer (xfer or xxfer). + * + * - Return XFER_CONTINUE if the transfer should proceeed + * - Return XFER_FAIL if the transfer should be stopped in failure + * - Return XFER_SUCCESS if the transfer should be stopped in success + */ +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) +{ + uint64_t src_min; + uint64_t tgt_max; + + if (pool_conf_check(conf) != PO_SUCCESS) + return (XFER_FAIL); + + /* + * Makes sure the two resources are of the same type + */ + if (pool_resource_elem_class(TO_ELEM(src)) != + pool_resource_elem_class(TO_ELEM(tgt))) { + pool_seterror(POE_BADPARAM); + return (XFER_FAIL); + } + + /* + * Transferring to yourself is a no-op + */ + if (src == tgt) + return (XFER_SUCCESS); + + /* + * Transferring nothing is a no-op + */ + if (size == 0) + return (XFER_SUCCESS); + + if (resource_get_min(src, &src_min) != PO_SUCCESS || + resource_get_size(src, src_size) != PO_SUCCESS || + resource_get_max(tgt, &tgt_max) != PO_SUCCESS || + resource_get_size(tgt, tgt_size) != PO_SUCCESS) { + pool_seterror(POE_BADPARAM); + return (XFER_FAIL); + } + if (pool_conf_status(conf) != POF_DESTROY) { + /* + * src_size - donating >= src.min + * size + receiving <= tgt.max (except for default) + */ +#ifdef DEBUG + dprintf("conf is %s\n", pool_conf_location(conf)); + dprintf("setup_transfer: src_size %llu\n", *src_size); + pool_elem_dprintf(TO_ELEM(src)); + dprintf("setup_transfer: tgt_size %llu\n", *tgt_size); + pool_elem_dprintf(TO_ELEM(tgt)); +#endif /* DEBUG */ + if (*src_size - size < src_min || + (resource_is_default(tgt) == PO_FALSE && + *tgt_size + size > tgt_max)) { + pool_seterror(POE_INVALID_CONF); + return (XFER_FAIL); + } + } + return (XFER_CONTINUE); +} + +/* + * Transfer resource quantities from one resource set to another. + */ +int +pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src, + pool_resource_t *tgt, uint64_t size) +{ + uint64_t src_size; + uint64_t tgt_size; + int ret; + + if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size)) + != XFER_CONTINUE) + return (ret); + /* + * If this resource is a res_comp we must call move components + */ + if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP) + return (choose_components(src, tgt, size)); + /* + * Now do the transfer. + */ + ret = conf->pc_prov->pc_res_xfer(src, tgt, size); + /* + * Modify the sizes of the resource sets if the process was + * successful + */ + if (ret == PO_SUCCESS) { + pool_value_t val = POOL_VALUE_INITIALIZER; + + src_size -= size; + tgt_size += size; + pool_value_set_uint64(&val, src_size); + (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop, + &val); + pool_value_set_uint64(&val, tgt_size); + (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop, + &val); + } + return (ret); +} + +/* + * Transfer resource components from one resource set to another. + */ +int +pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src, + pool_resource_t *tgt, + pool_component_t **rl) +{ + int i; + uint64_t src_size; + uint64_t tgt_size; + uint64_t size; + int ret; + + /* + * Make sure the components are all contained in 'src'. This + * processing must be done before setup_transfer so that size + * is known. + */ + for (i = 0; rl[i] != NULL; i++) { +#ifdef DEBUG + dprintf("resource xtransfer\n"); + dprintf("in conf %s\n", pool_conf_location(conf)); + dprintf("transferring component\n"); + pool_elem_dprintf(TO_ELEM(rl[i])); + dprintf("from\n"); + pool_elem_dprintf(TO_ELEM(src)); + dprintf("to\n"); + pool_elem_dprintf(TO_ELEM(tgt)); +#endif /* DEBUG */ + + if (pool_get_owning_resource(conf, rl[i]) != src) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + + size = (uint64_t)i; + + if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size)) + != XFER_CONTINUE) + return (ret); + + ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl); + /* + * Modify the sizes of the resource sets if the process was + * successful + */ + if (ret == PO_SUCCESS) { + pool_value_t val = POOL_VALUE_INITIALIZER; + +#ifdef DEBUG + dprintf("src_size %llu\n", src_size); + dprintf("tgt_size %llu\n", tgt_size); + dprintf("size %llu\n", size); +#endif /* DEBUG */ + src_size -= size; + tgt_size += size; + pool_value_set_uint64(&val, src_size); + (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop, + &val); + pool_value_set_uint64(&val, tgt_size); + (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop, + &val); + } + return (ret); +} + +/* + * Find the owning resource for a resource component. + */ +pool_resource_t * +pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return (pool_elem_res(pool_get_container(TO_ELEM(comp)))); +} + +/* + * pool_get_container() returns the container of pc. + */ +pool_elem_t * +pool_get_container(const pool_elem_t *pc) +{ + return (pc->pe_get_container(pc)); +} + +/* + * pool_set_container() moves pc so that it is contained by pp. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_set_container(pool_elem_t *pp, pool_elem_t *pc) +{ + return (pc->pe_set_container(pp, pc)); +} + +/* + * Conversion routines for converting to and from elem and it's various + * subtypes of system, pool, res and comp. + */ +pool_elem_t * +pool_system_elem(const pool_system_t *ph) +{ + return ((pool_elem_t *)ph); +} + +pool_elem_t * +pool_conf_to_elem(const pool_conf_t *conf) +{ + pool_system_t *sys; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + if ((sys = pool_conf_system(conf)) == NULL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return (pool_system_elem(sys)); +} + +pool_elem_t * +pool_to_elem(const pool_conf_t *conf, const pool_t *pp) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_elem_t *)pp); +} + +pool_elem_t * +pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_elem_t *)prs); +} + +pool_elem_t * +pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_elem_t *)pr); +} + +/* + * Walk all the pools of the configuration calling the user supplied function + * as long as the user function continues to return PO_TRUE + */ +int +pool_walk_pools(pool_conf_t *conf, void *arg, + int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg)) +{ + pool_t **rs; + int i; + uint_t size; + int error = PO_SUCCESS; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + if ((rs = pool_query_pools(conf, &size, NULL)) == NULL) /* None */ + return (PO_SUCCESS); + for (i = 0; i < size; i++) + if (callback(conf, rs[i], arg) != PO_SUCCESS) { + error = PO_FAIL; + break; + } + free(rs); + return (error); +} + +/* + * Walk all the comp of the res calling the user supplied function + * as long as the user function continues to return PO_TRUE + */ +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)) +{ + pool_component_t **rs; + int i; + uint_t size; + int error = PO_SUCCESS; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + if ((rs = pool_query_resource_components(conf, prs, &size, NULL)) == + NULL) + return (PO_SUCCESS); /* None */ + for (i = 0; i < size; i++) + if (callback(conf, rs[i], arg) != PO_SUCCESS) { + error = PO_FAIL; + break; + } + free(rs); + return (error); +} + +/* + * Return an array of all matching res for the supplied pool. + */ +pool_resource_t ** +pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp, + uint_t *size, pool_value_t **props) +{ + pool_result_set_t *rs; + pool_elem_t *pe; + pool_resource_t **result = NULL; + int i = 0; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + pe = TO_ELEM(pp); + + rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props); + if (rs == NULL) { + return (NULL); + } + if ((*size = pool_rs_count(rs)) == 0) { + (void) pool_rs_close(rs); + return (NULL); + } + if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1))) + == NULL) { + pool_seterror(POE_SYSTEM); + (void) pool_rs_close(rs); + return (NULL); + } + (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1)); + for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { + if (pool_elem_class(pe) != PEC_RES_COMP && + pool_elem_class(pe) != PEC_RES_AGG) { + pool_seterror(POE_INVALID_CONF); + free(result); + (void) pool_rs_close(rs); + return (NULL); + } + result[i++] = pool_elem_res(pe); + } + (void) pool_rs_close(rs); + return (result); +} + +/* + * Walk all the res of the pool calling the user supplied function + * as long as the user function continues to return PO_TRUE + */ +int +pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg, + int (*callback)(pool_conf_t *, pool_resource_t *, void *)) +{ + pool_resource_t **rs; + int i; + uint_t size; + int error = PO_SUCCESS; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + if ((rs = pool_query_pool_resources(conf, pp, &size, NULL)) == NULL) + return (PO_SUCCESS); /* None */ + for (i = 0; i < size; i++) + if (callback(conf, rs[i], arg) != PO_SUCCESS) { + error = PO_FAIL; + break; + } + free(rs); + return (error); +} + +/* + * Return a result set of all comp for the supplied res. + */ +pool_component_t ** +pool_query_resource_components(const pool_conf_t *conf, + const pool_resource_t *prs, uint_t *size, pool_value_t **props) +{ + pool_result_set_t *rs; + pool_elem_t *pe; + pool_component_t **result = NULL; + int i = 0; + + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + pe = TO_ELEM(prs); + + rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props); + if (rs == NULL) { + return (NULL); + } + if ((*size = pool_rs_count(rs)) == 0) { + (void) pool_rs_close(rs); + return (NULL); + } + if ((result = malloc(sizeof (pool_component_t *) * (*size + 1))) + == NULL) { + pool_seterror(POE_SYSTEM); + (void) pool_rs_close(rs); + return (NULL); + } + (void) memset(result, 0, sizeof (pool_component_t *) * (*size + 1)); + for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { + if (pool_elem_class(pe) != PEC_COMP) { + pool_seterror(POE_INVALID_CONF); + free(result); + (void) pool_rs_close(rs); + return (NULL); + } + result[i++] = pool_elem_comp(pe); + } + (void) pool_rs_close(rs); + return (result); +} + +/* + * pool_version() returns the version of this library, depending on the supplied + * parameter. + * + * Returns: library version depening on the supplied ver parameter. + */ +uint_t +pool_version(uint_t ver) +{ + switch (ver) { + case POOL_VER_NONE: + break; + case POOL_VER_CURRENT: + pool_workver = ver; + break; + default: + return (POOL_VER_NONE); + } + return (pool_workver); +} + +/* + * pool_associate() associates the supplied resource to the supplied pool. + * + * Returns: PO_SUCCESS/PO_FAIL + */ +int +pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res) +{ + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + return (pool->pp_associate(pool, res)); +} + +/* + * pool_dissociate() dissociates the supplied resource from the supplied pool. + * + * Returns: PO_SUCCESS/PO_FAIL + */ +int +pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res) +{ + if (pool_conf_check(conf) != PO_SUCCESS) + return (PO_FAIL); + + if (elem_is_default(TO_ELEM(res))) + return (PO_SUCCESS); + return (pool->pp_dissociate(pool, res)); +} + +/* + * Compare two elements for purposes of ordering. + * Return: + * < 0 if e1 is "before" e2 + * 0 if e1 "equals" e2 + * > 0 if e1 comes after e2 + */ +int +pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2) +{ + char *name1, *name2; + pool_value_t val = POOL_VALUE_INITIALIZER; + int retval; + + /* + * We may be asked to compare two elements from different classes. + * They are different so return (1). + */ + if (pool_elem_same_class(e1, e2) != PO_TRUE) + return (1); + + /* + * If the class is PEC_SYSTEM, always match them + */ + if (pool_elem_class(e1) == PEC_SYSTEM) + return (0); + + /* + * If we are going to compare components, then use sys_id + */ + if (pool_elem_class(e1) == PEC_COMP) { + int64_t sys_id1, sys_id2; + + if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) { + return (-1); + } + (void) pool_value_get_int64(&val, &sys_id1); + if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) { + return (-1); + } + (void) pool_value_get_int64(&val, &sys_id2); + retval = (sys_id1 - sys_id2); + } else { + if (pool_get_ns_property(e1, "name", &val) == POC_INVAL) { + return (-1); + } + (void) pool_value_get_string(&val, (const char **)&name1); + if ((name1 = strdup(name1)) == NULL) { + return (-1); + } + + if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) { + return (-1); + } + + (void) pool_value_get_string(&val, (const char **)&name2); + retval = strcmp(name1, name2); + free(name1); + } + return (retval); +} + +/* + * Compare two elements for purposes of ordering. + * Return: + * < 0 if e1 is "before" e2 + * 0 if e1 "equals" e2 + * > 0 if e1 comes after e2 + */ +int +pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + int64_t sys_id1, sys_id2; + + /* + * We may be asked to compare two elements from different classes. + * They are different so return the difference in their classes + */ + if (pool_elem_same_class(e1, e2) != PO_TRUE) + return (1); + + /* + * If the class is PEC_SYSTEM, always match them + */ + if (pool_elem_class(e1) == PEC_SYSTEM) + return (0); + + /* + * Compare with sys_id + */ + if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) { + assert(!"no sys_id on e1\n"); + } + (void) pool_value_get_int64(&val, &sys_id1); + if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) { + assert(!"no sys_id on e2\n"); + } + (void) pool_value_get_int64(&val, &sys_id2); + return (sys_id1 - sys_id2); +} + +/* + * Return PO_TRUE if the supplied elems are of the same class. + */ +int +pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2) +{ + if (pool_elem_class(e1) != pool_elem_class(e2)) + return (PO_FALSE); + + /* + * Check to make sure the fundamental class of the elements match + */ + if (pool_elem_class(e1) == PEC_RES_COMP || + pool_elem_class(e1) == PEC_RES_AGG) + if (pool_resource_elem_class(e1) != + pool_resource_elem_class(e2)) + return (PO_FALSE); + if (pool_elem_class(e1) == PEC_COMP) + if (pool_component_elem_class(e1) != + pool_component_elem_class(e2)) + return (PO_FALSE); + return (PO_TRUE); +} + +/* + * pool_conf_check() checks that the configuration state isn't invalid + * and that the configuration was opened for modification. + */ +int +pool_conf_check(const pool_conf_t *conf) +{ + if (pool_conf_status(conf) == POF_INVALID) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + return (PO_SUCCESS); +} diff --git a/usr/src/lib/libpool/common/pool.h b/usr/src/lib/libpool/common/pool.h new file mode 100644 index 0000000..ee11aad --- /dev/null +++ b/usr/src/lib/libpool/common/pool.h @@ -0,0 +1,280 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * NOTE + * + * The following contents of this file are private to the + * implementation of the Solaris system and are subject to change at + * any time without notice. Applications using these interfaces may + * fail to run on future releases. + */ + +#ifndef _POOL_H +#define _POOL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/procset.h> +#include <sys/types.h> +#include <sys/pool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Library versioning support (c.f. elf_version(3e)). + * + * You can enquire about the version number of the library + * by passing POOL_VER_NONE. POOL_VER_CURRENT is the current + * (most capable) version. + * + * You can set the version used by the library by passing the + * required version number. If this is not possible, the version + * returned will be POOL_VER_NONE. + */ +#define POOL_VER_CURRENT 1 +#define POOL_VER_NONE 0 + +extern uint_t pool_version(uint_t ver); + +#ifndef PO_TRUE +#define PO_TRUE 1 +#endif + +#ifndef PO_FALSE +#define PO_FALSE 0 +#endif + +#ifndef PO_SUCCESS +#define PO_SUCCESS 0 +#endif + +#ifndef PO_FAIL +#define PO_FAIL -1 +#endif + +/* Error codes */ +#define POE_OK 0 +#define POE_BAD_PROP_TYPE 1 +#define POE_INVALID_CONF 2 +#define POE_NOTSUP 3 +#define POE_INVALID_SEARCH 4 +#define POE_BADPARAM 5 +#define POE_PUTPROP 6 +#define POE_DATASTORE 7 +#define POE_SYSTEM 8 +#define POE_ACCESS 9 + +/* Open Flags */ +#define PO_RDONLY 0x0 +#define PO_RDWR 0x1 +#define PO_CREAT 0x2 +#define PO_DISCO 0x4 +#define PO_UPDATE 0x8 +#define PO_TEMP 0x10 + +/* Allocation policy */ +#define POA_IMPORTANCE "importance based" +#define POA_SURPLUS_TO_DEFAULT "surplus to default" + +/* Pools updates */ +#define POU_SYSTEM 0x1 +#define POU_POOL 0x2 +#define POU_PSET 0x4 +#define POU_CPU 0x8 + +/* Data Export Formats */ +typedef enum pool_export_format { + POX_NATIVE, /* Native data representation format */ + POX_TEXT /* Text */ +} pool_export_format_t; + +/* Property data types */ +typedef enum pool_value_class { + POC_INVAL = -1, + POC_UINT, + POC_INT, + POC_DOUBLE, + POC_BOOL, + POC_STRING +} pool_value_class_t; + +/* Validation levels */ +typedef enum pool_valid_level { + POV_NONE = 0, /* No validation */ + POV_LOOSE, /* Loose validation */ + POV_STRICT, /* Strict validation */ + POV_RUNTIME /* Validate instantiation on current machine */ +} pool_valid_level_t; + +/* conf states */ +typedef enum pool_conf_state { + POF_INVALID = -1, + POF_VALID, + POF_DESTROY +} pool_conf_state_t; + +/* Element data values */ +typedef struct pool_value pool_value_t; + +/* Elements */ +typedef struct pool_elem pool_elem_t; +typedef struct pool pool_t; +typedef struct pool_resource pool_resource_t; +typedef struct pool_component pool_component_t; + +/* + * Resource management configuration + */ +typedef struct pool_conf pool_conf_t; + +extern int pool_error(void); +extern const char *pool_strerror(int); +extern int pool_resource_type_list(const char **, uint_t *); +extern int pool_get_status(int *); +extern int pool_set_status(int); + +/* Configuration manipulation */ +extern pool_conf_t *pool_conf_alloc(void); +extern void pool_conf_free(pool_conf_t *); +extern pool_conf_state_t pool_conf_status(const pool_conf_t *); + +extern int pool_conf_close(pool_conf_t *); +extern int pool_conf_remove(pool_conf_t *); +extern int pool_conf_open(pool_conf_t *, const char *, int); +extern int pool_conf_rollback(pool_conf_t *); +extern int pool_conf_commit(pool_conf_t *, int); +extern int pool_conf_export(const pool_conf_t *, const char *, + pool_export_format_t); +extern int pool_conf_validate(const pool_conf_t *, pool_valid_level_t); +extern int pool_conf_update(const pool_conf_t *, int *); +extern pool_t *pool_get_pool(const pool_conf_t *, const char *); +extern pool_t **pool_query_pools(const pool_conf_t *, uint_t *, + pool_value_t **); +extern pool_resource_t *pool_get_resource(const pool_conf_t *, const char *, + const char *); +extern pool_resource_t **pool_query_resources(const pool_conf_t *, uint_t *, + pool_value_t **); +extern pool_component_t **pool_query_components(const pool_conf_t *, uint_t *, + pool_value_t **); +extern const char *pool_conf_location(const pool_conf_t *); +extern char *pool_conf_info(const pool_conf_t *, int); + +/* Resource manipulation */ +extern pool_resource_t *pool_resource_create(pool_conf_t *, const char *, + const char *); +extern int pool_resource_destroy(pool_conf_t *, pool_resource_t *); +extern int pool_resource_transfer(pool_conf_t *, pool_resource_t *, + pool_resource_t *, uint64_t); +extern int pool_resource_xtransfer(pool_conf_t *, pool_resource_t *, + pool_resource_t *, pool_component_t **); +extern pool_component_t **pool_query_resource_components(const pool_conf_t *, + const pool_resource_t *, uint_t *, pool_value_t **); +extern char *pool_resource_info(const pool_conf_t *, const pool_resource_t *, + int); + +/* Pool manipulation */ +extern pool_t *pool_create(pool_conf_t *, const char *); +extern int pool_destroy(pool_conf_t *, pool_t *); +extern int pool_associate(pool_conf_t *, pool_t *, const pool_resource_t *); +extern int pool_dissociate(pool_conf_t *, pool_t *, const pool_resource_t *); +extern char *pool_info(const pool_conf_t *, const pool_t *, int); +extern pool_resource_t **pool_query_pool_resources(const pool_conf_t *, + const pool_t *, uint_t *, pool_value_t **); + +/* Resource Component Manipulation */ +extern pool_resource_t *pool_get_owning_resource(const pool_conf_t *, + const pool_component_t *); +extern char *pool_component_info(const pool_conf_t *, const pool_component_t *, + int); + +/* Property manipulation */ +extern pool_value_class_t pool_get_property(const pool_conf_t *, + const pool_elem_t *, const char *, pool_value_t *); +extern int pool_put_property(pool_conf_t *, pool_elem_t *, const char *, + const pool_value_t *); +extern int pool_rm_property(pool_conf_t *, pool_elem_t *, const char *); + +/* + * Walk the associated properties of the supplied element calling the supplied + * function for each property in turn. There is no implied order in the walk. + * The arg parameter allows caller-specific data to be passed to the call. + */ +extern int pool_walk_properties(pool_conf_t *, pool_elem_t *, void *, + int (*)(pool_conf_t *, pool_elem_t *, const char *, pool_value_t *, + void *)); + +/* Get the underlying element */ +extern pool_elem_t *pool_conf_to_elem(const pool_conf_t *); +extern pool_elem_t *pool_to_elem(const pool_conf_t *, const pool_t *); +extern pool_elem_t *pool_resource_to_elem(const pool_conf_t *, + const pool_resource_t *); +extern pool_elem_t *pool_component_to_elem(const pool_conf_t *, + const pool_component_t *); + +/* Pool Property Value Manipulation */ +/* Get/Set Pool Property Values and Type */ +extern int pool_value_get_uint64(const pool_value_t *, uint64_t *); +extern int pool_value_get_int64(const pool_value_t *, int64_t *); +extern int pool_value_get_double(const pool_value_t *, double *); +extern int pool_value_get_bool(const pool_value_t *, uchar_t *); +extern int pool_value_get_string(const pool_value_t *, const char **); +extern pool_value_class_t pool_value_get_type(const pool_value_t *); +extern void pool_value_set_uint64(pool_value_t *, uint64_t); +extern void pool_value_set_int64(pool_value_t *, int64_t); +extern void pool_value_set_double(pool_value_t *, double); +extern void pool_value_set_bool(pool_value_t *, uchar_t); +extern int pool_value_set_string(pool_value_t *, const char *); +extern const char *pool_value_get_name(const pool_value_t *); +extern int pool_value_set_name(pool_value_t *, const char *); + +/* Pool Property Value Creation/Destruction */ +extern pool_value_t *pool_value_alloc(void); +extern void pool_value_free(pool_value_t *); + +/* Default pool data store locations */ +extern const char *pool_static_location(void); +extern const char *pool_dynamic_location(void); + +/* Binding */ +extern int pool_set_binding(const char *, idtype_t, id_t); +extern char *pool_get_binding(pid_t); +extern char *pool_get_resource_binding(const char *, pid_t); + +/* Walking */ +extern int pool_walk_pools(pool_conf_t *, void *, + int (*)(pool_conf_t *, pool_t *, void *)); +extern int pool_walk_resources(pool_conf_t *, pool_t *, void *, + int (*)(pool_conf_t *, pool_resource_t *, void *)); +extern int pool_walk_components(pool_conf_t *, pool_resource_t *, void *, + int (*)(pool_conf_t *, pool_component_t *, void *)); + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_H */ diff --git a/usr/src/lib/libpool/common/pool_commit.c b/usr/src/lib/libpool/common/pool_commit.c new file mode 100644 index 0000000..b996524 --- /dev/null +++ b/usr/src/lib/libpool/common/pool_commit.c @@ -0,0 +1,1340 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * These functions implement the process of commitment for a pool + * configuration. This process can be described as taking instructions + * from a static configuration file and using the information about + * the target system contained in the dynamic configuration to make + * decisions about how best to allocate resources to meet the + * constraints specified in the static configuration file. + * + * Mechanically, this process relies upon ordering the individual + * components of the file and stepping through the lists of components + * and taking actions depending on their type and which file they are + * part of. + * + * Configuration components can be broken down into different types + * which are then treated according to the following table: + * + * Element Type Action + * system || pool || + * res_comp || res_agg If the element is a required element, then create or + * update it (don't destroy required elements in the + * static configuration) otherwise manipulate the + * dynamic configuration to create, destroy or update + * the element on the system. + * comp Create, destroy or update the static configuration + * component. + * + * The treatment of the different elements reflects the fact that all + * elements other than comp are configurable and thus libpool can + * create, destroy and modify these elements at will. comp elements + * reflect the disposition of the system, these elements can be moved + * around but they can't be created or destroyed in the dynamic + * configuration in the commit process. comp elements can be created + * and destroyed in the static configuration file as a result of a + * commit operation, since it's possible for a comp to not appear in + * the dynamic configuration. For instance, if the static + * configuration file was created on a different machine or after a DR + * operation which has removed or added components. + * + */ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <unistd.h> + +#include <pool.h> +#include "pool_internal.h" +#include "pool_impl.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define POA_IMPORTANCE_NUM 0 +#define POA_SURPLUS_TO_DEFAULT_NUM 1 + +/* + * This resource specific structure is used to determine allocation of resources + * during resource set allocation. Each set will receive its min, plus + * some number of dealt resources based on the global allocation policy. + */ +typedef struct res_info { + pool_resource_t *ri_res; /* Resource set */ + uint64_t ri_min; /* Resource set's low watermark */ + uint64_t ri_max; /* Resource set's high watermark */ + uint64_t ri_oldsize; /* Size of resource set at the start */ + uint64_t ri_newsize; /* New resource set size allocated */ + uint64_t ri_pinned; /* Count of pinned resources in set */ + uint64_t ri_dealt; /* Count of resources dealt to set */ + int64_t ri_transfer; /* oldsize - newsize */ + /* The signed quantity of resources */ + /* to tranfer into or out of this */ + /* resource set */ + /* + transfer: tranfer resources out */ + /* - transfer: tranfer resources in */ +} res_info_t; + +/* + * diff_and_fix operations + */ +static int commit_create(pool_conf_t *, pool_elem_t **); +static int commit_delete(pool_elem_t *); +static int commit_update(pool_elem_t *, pool_elem_t *, int); + +/* + * configuration commit processing + */ +static int diff_and_fix(pool_conf_t *, pool_conf_t *); +static int process_elem_lt(pool_elem_t *, pool_conf_t *); +static int process_elem_gt(pool_elem_t *, pool_conf_t *, + pool_conf_t *); +static int process_lists(int, pool_conf_t *, + pool_conf_t *, int); +static pool_elem_t **get_elem_list(const pool_conf_t *, int, uint_t *); +static int share_resources(pool_conf_t *); +static int resource_allocate(const char *, pool_resource_t **, + uint_t); +static int resource_allocate_default(pool_resource_t **, uint_t); +static int pset_allocate_imp(pool_resource_t **, uint_t); +static int resource_compare_by_descending_importance(const void *, + const void *); +static int compute_size_to_transfer(const void *, const void *); +static int set_importance_cb(pool_conf_t *, pool_t *, void *); +static int unset_importance_cb(pool_conf_t *, pool_t *, void *); +static int add_importance_props(pool_conf_t *); +static int remove_importance_props(pool_conf_t *); +static int clone_element(pool_conf_t *, pool_elem_t *, + const char *, pool_value_t *, void *); +static int clean_element(pool_conf_t *, pool_elem_t *, + const char *, pool_value_t *, void *); + +/* + * commit_create() is used to create a configuration element upon the + * system. Since only pools and resource actually need to perform any + * action, other elements are ignored as a no-op. + */ +static int +commit_create(pool_conf_t *conf, pool_elem_t **e1) +{ + pool_resource_t *res; + pool_t *pool; + const char *res_type; + pool_elem_t *src = *e1; + uint64_t smin, smax, dmax; + pool_value_t val = POOL_VALUE_INITIALIZER; + char *name; + + switch (pool_elem_class(src)) { + case PEC_SYSTEM: /* NO-OP */ + break; + case PEC_POOL: + name = elem_get_name(src); + if ((pool = pool_create(conf, name)) == NULL) { + free(name); + return (PO_FAIL); + } + free(name); + /* + * Now copy the properties from the original pool to the + * new one + */ + if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(pool), + clone_element) != PO_SUCCESS) + return (PO_FAIL); + /* + * Add a pointer to the src element which can be + * updated with a sys_id when the sys_id is allocated + * to the created element. + */ + pool_set_pair(TO_ELEM(pool), src); + *e1 = TO_ELEM(pool); + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + name = elem_get_name(src); + res_type = pool_elem_class_string(src); + if ((res = pool_resource_create(conf, res_type, name)) == + NULL) { + free(name); + return (PO_FAIL); + } + free(name); + /* + * Need to do some ordering of property updates. + * Compare the values of source min/max and + * destination min/max. If smin < dmax then update the + * smin first, else update the max first. + */ + if (resource_get_min(pool_elem_res(src), &smin) != PO_SUCCESS || + resource_get_max(pool_elem_res(src), &smax) != PO_SUCCESS || + resource_get_max(res, &dmax) != PO_SUCCESS) + return (PO_FAIL); + if (smin < dmax) { + pool_value_set_uint64(&val, smin); + if (pool_put_ns_property(TO_ELEM(res), c_min_prop, + &val) != PO_SUCCESS) + return (PO_FAIL); + } else { + pool_value_set_uint64(&val, smax); + if (pool_put_ns_property(TO_ELEM(res), c_max_prop, + &val) != PO_SUCCESS) + return (PO_FAIL); + } + /* + * Now copy the properties from the original resource + * to the new one + */ + if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(res), + clone_element) != PO_SUCCESS) + return (PO_FAIL); + /* + * Add a pointer to the src element which can be + * updated with a sys_id when the sys_id is allocated + * to the created element. + */ + pool_set_pair(TO_ELEM(res), src); + *e1 = TO_ELEM(res); + break; + case PEC_COMP: /* NO-OP */ + break; + default: + return (PO_FAIL); + } + return (PO_SUCCESS); +} + + +/* + * commit_delete() is used to delete a configuration element upon the + * system. Since only pools and resources actually need to perform + * any action, other elements are ignored as a no-op. + */ +static int +commit_delete(pool_elem_t *pe) +{ + pool_resource_t *res; + pool_t *pool; + int ret = 0; + + if (elem_is_tmp(pe)) + return (PO_SUCCESS); + + switch (pool_elem_class(pe)) { + case PEC_SYSTEM: /* NO-OP */ + break; + case PEC_POOL: + pool = pool_elem_pool(pe); + ret = pool_destroy(TO_CONF(pe), pool); + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + res = pool_elem_res(pe); + ret = pool_resource_destroy(TO_CONF(pe), res); + break; + case PEC_COMP: /* NO-OP */ + break; + default: + return (PO_FAIL); + } + return (ret); +} + +/* + * commit_update() is used to update a configuration element upon the + * system or in a static configuration file. The pass parameter + * governs whether properties are being updated or associations. In + * pass 0, properties are updated. If the element is of class + * PEC_COMP, then make sure that the element in the static + * configuration file is correctly located before proceeding with the + * update. Then, the element in the dynamic configuration file is + * updated. In pass 1, ie. pass != 0, any pool components have their + * associations updated in the dynamic configuration. + */ +static int +commit_update(pool_elem_t *e1, pool_elem_t *e2, int pass) +{ + if (pass == 0) { + pool_resource_t *res1; + pool_resource_t *res2; + if (pool_elem_class(e1) == PEC_COMP) { + res1 = pool_get_owning_resource(TO_CONF(e1), + pool_elem_comp(e1)); + res2 = pool_get_owning_resource(TO_CONF(e2), + pool_elem_comp(e2)); + if (pool_elem_compare_name(TO_ELEM(res1), + TO_ELEM(res2)) != 0) { + char *name; + const pool_resource_t *newres; + pool_component_t *comps[2] = { NULL }; + + comps[0] = pool_elem_comp(e2); + name = elem_get_name(TO_ELEM(res1)); + newres = pool_get_resource(TO_CONF(e2), + pool_elem_class_string(TO_ELEM(res1)), + name); + free(name); + assert(newres); +#ifdef DEBUG + dprintf("transferring: res, comp\n"); + pool_elem_dprintf(TO_ELEM(newres)); + pool_elem_dprintf(e2); +#endif /* DEBUG */ + (void) pool_resource_xtransfer(TO_CONF(e2), + res2, (pool_resource_t *)newres, comps); + } + } + if (pool_walk_properties(TO_CONF(e2), e2, NULL, + clean_element) != PO_SUCCESS) { + return (PO_FAIL); + } + /* + * Need to do some ordering of property updates if the + * element to be updated is a resource. Compare the + * values of source min/max and destination + * min/max. If smin < dmax then update the smin first, + * else update the max first. + */ + if (pool_elem_class(e1) == PEC_RES_COMP || + pool_elem_class(e1) == PEC_RES_AGG) { + uint64_t smin, smax, dmax; + pool_value_t val = POOL_VALUE_INITIALIZER; + + if (resource_get_min(pool_elem_res(e1), &smin) != + PO_SUCCESS || + resource_get_max(pool_elem_res(e1), &smax) != + PO_SUCCESS || + resource_get_max(pool_elem_res(e2), &dmax) != + PO_SUCCESS) + return (PO_FAIL); + if (smin < dmax) { + pool_value_set_uint64(&val, smin); + if (pool_put_ns_property(e2, c_min_prop, + &val) != PO_SUCCESS) + return (PO_FAIL); + } else { + pool_value_set_uint64(&val, smax); + if (pool_put_ns_property(e2, c_max_prop, + &val) != PO_SUCCESS) + return (PO_FAIL); + } + } + /* + * This next couple of steps needs some + * explanation. The first walk, copies all the + * properties that are writeable from the static + * configuration to the dynamic configuration. The + * second walk copies all properties (writeable or + * not) from the dynamic configuration element back to + * the static configuration element. This ensures that + * updates from the static configuration element are + * correctly applied to the dynamic configuration and + * then the static configuration element is updated + * with the latest values of the read-only xproperties + * from the dynamic configuration element. The + * enforcing of permisssions is performed in + * clone_element by its choice of property + * manipulation function. + */ + if (pool_walk_properties(TO_CONF(e1), e1, e2, clone_element) != + PO_SUCCESS) { + return (PO_FAIL); + } + if (pool_walk_properties(TO_CONF(e2), e2, e1, clone_element) != + PO_SUCCESS) { + return (PO_FAIL); + } + } else { + if (pool_elem_class(e1) == PEC_POOL) { + pool_resource_t **rs; + uint_t nelem; + int i; + pool_value_t val = POOL_VALUE_INITIALIZER; + pool_value_t *pvals[] = { NULL, NULL }; + + pvals[0] = &val; + if (pool_value_set_string(&val, "pset") != PO_SUCCESS || + pool_value_set_name(&val, c_type) != PO_SUCCESS) + return (PO_FAIL); + if ((rs = pool_query_pool_resources(TO_CONF(e1), + pool_elem_pool(e1), &nelem, pvals)) != NULL) { + for (i = 0; i < nelem; i++) { + const pool_resource_t *tgt_res; + char *res_name = + elem_get_name(TO_ELEM(rs[i])); + + if ((tgt_res = pool_get_resource( + TO_CONF(e2), pool_elem_class_string( + TO_ELEM(rs[i])), res_name)) == + NULL) { + tgt_res = get_default_resource( + rs[i]); + } + free(res_name); + if (pool_associate(TO_CONF(e2), + pool_elem_pool(e2), tgt_res) != + PO_SUCCESS) { + free(rs); + return (PO_FAIL); + } + } + free(rs); + } + } + } + return (PO_SUCCESS); +} + +/* + * diff_and_fix() works out the differences between two configurations + * and modifies the state of the system to match the operations + * required to bring the two configurations into sync. + * + * Returns PO_SUCCESS/PO_FAIL. + */ +static int +diff_and_fix(pool_conf_t *stc, pool_conf_t *dyn) +{ + /* + * The ordering of the operations is significant, we must + * process the system element, then the pools elements, then + * the resource elements, then the pools elements again and + * finally the resource components. + * + * TODO + * PEC_RES_COMP are the only type of resources + * currently. When PEC_RES_AGG resources are added they must + * also be processed. + */ + if (process_lists(PEC_SYSTEM, stc, dyn, 0) != PO_SUCCESS) { + return (PO_FAIL); + } + if (process_lists(PEC_POOL, stc, dyn, 0) != PO_SUCCESS) { + return (PO_FAIL); + } + if (process_lists(PEC_RES_COMP, stc, dyn, 0) != PO_SUCCESS) { + return (PO_FAIL); + } + if (process_lists(PEC_COMP, stc, dyn, 0) != PO_SUCCESS) { + return (PO_FAIL); + } + if (process_lists(PEC_POOL, stc, dyn, 1) != PO_SUCCESS) { + return (PO_FAIL); + } + /* + * Share the resources. It has to be called for both + * configurations to ensure that the configurations still look + * the same. + */ + if (share_resources(dyn) != PO_SUCCESS) { + return (PO_FAIL); + } + if (share_resources(stc) != PO_SUCCESS) { + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +static int +process_elem_lt(pool_elem_t *pe, pool_conf_t *dyn) +{ + if (pool_elem_class(pe) == PEC_COMP) { + if (pool_component_destroy(pool_elem_comp(pe)) == PO_FAIL) { + return (PO_FAIL); + } + } else if (! elem_is_default(pe)) { + if (commit_create(dyn, &pe) != PO_SUCCESS) { + return (PO_FAIL); + } + } + return (PO_SUCCESS); +} + +static int +process_elem_gt(pool_elem_t *pe, pool_conf_t *stc, pool_conf_t *dyn) +{ + if (pool_elem_class(pe) == PEC_COMP) { + pool_resource_t *owner; + const pool_resource_t *parent_res; + pool_value_t val = POOL_VALUE_INITIALIZER; + const pool_component_t *newcomp; + const char *resname; + const char *restype; + /* + * I have to find the right parent in the static + * configuration. It may not exist, in which case it's + * correct to put it in the default + */ + owner = pool_get_owning_resource(dyn, + pool_elem_comp(pe)); + if (pool_get_ns_property(TO_ELEM(owner), "name", &val) == + POC_INVAL) + return (PO_FAIL); + + if (pool_value_get_string(&val, &resname) == PO_FAIL) + return (PO_FAIL); + + if ((resname = strdup(resname)) == NULL) + return (PO_FAIL); + + restype = pool_elem_class_string(TO_ELEM(owner)); + parent_res = pool_get_resource(stc, restype, resname); + free((void *)resname); + if (parent_res == NULL) + parent_res = resource_by_sysid(stc, PS_NONE, restype); + /* + * Now need to make a copy of the component in the + * dynamic configuration in the static configuration. + */ + if ((newcomp = pool_component_create(stc, parent_res, + elem_get_sysid(pe))) == NULL) + return (PO_FAIL); + + if (pool_walk_properties(TO_CONF(pe), pe, TO_ELEM(newcomp), + clone_element) != PO_SUCCESS) + return (PO_FAIL); + } else if (elem_is_default(pe)) { + pool_resource_t *newres; + pool_t *newpool; + char *name; + + if ((name = elem_get_name(pe)) == NULL) + return (PO_FAIL); + switch (pool_elem_class(pe)) { + case PEC_POOL: + if ((newpool = pool_create(stc, name)) == NULL) { + free(name); + return (PO_FAIL); + } + free(name); + if (pool_walk_properties(TO_CONF(pe), pe, + TO_ELEM(newpool), clone_element) != PO_SUCCESS) + return (PO_FAIL); + break; + case PEC_RES_AGG: + case PEC_RES_COMP: + if ((newres = pool_resource_create(stc, + pool_elem_class_string(pe), name)) == + NULL) { + free(name); + return (PO_FAIL); + } + free(name); + if (pool_walk_properties(TO_CONF(pe), pe, + TO_ELEM(newres), clone_element) != PO_SUCCESS) + return (PO_FAIL); + break; + default: + free(name); + break; + } + } else { + if (commit_delete(pe) != PO_SUCCESS) + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * This function compares the elements of the supplied type in the + * static and dynamic configurations supplied. The lists of elements + * are compared and used to create, delete and updated elements in + * both the static and dynamic configurations. The pass parameter is + * used to indicate to commit_update() whether property updates or + * association updates should be performed. + */ +static int +process_lists(int type, pool_conf_t *stc, pool_conf_t *dyn, int pass) +{ + uint_t stc_nelem = 0, dyn_nelem = 0; + pool_elem_t **stc_elems, **dyn_elems; + int i, j; + int status = PO_SUCCESS; + + if ((stc_elems = get_elem_list(stc, type, &stc_nelem)) == NULL) + return (PO_FAIL); + + qsort(stc_elems, stc_nelem, sizeof (pool_elem_t *), + qsort_elem_compare); + + if ((dyn_elems = get_elem_list(dyn, type, &dyn_nelem)) == NULL) { + free(stc_elems); + return (PO_FAIL); + } + + qsort(dyn_elems, dyn_nelem, sizeof (pool_elem_t *), + qsort_elem_compare); + /* + * Step through and do the updating, remember that we are + * comparing using the compare function for the configuration + * and that is fixed. + */ + i = j = 0; + while (status == PO_SUCCESS && i < stc_nelem && j < dyn_nelem) { + int compare; + /* + * We are going to do this by stepping through the static + * list first. + */ + if (elem_is_default(stc_elems[i]) && + elem_is_default(dyn_elems[j])) + compare = 0; + else + compare = pool_elem_compare_name(stc_elems[i], + dyn_elems[j]); + if (compare < 0) { + status = process_elem_lt(stc_elems[i], dyn); + i++; + } else if (compare > 0) { + status = process_elem_gt(dyn_elems[j], stc, dyn); + j++; + } else { /* compare == 0 */ + if (commit_update(stc_elems[i], dyn_elems[j], pass) + != PO_SUCCESS) { + status = PO_FAIL; + } + i++; + j++; + } + } + if (status == PO_FAIL) { + free(stc_elems); + free(dyn_elems); + return (PO_FAIL); + } + while (status == PO_SUCCESS && i < stc_nelem) { + status = process_elem_lt(stc_elems[i], dyn); + i++; + } + if (status == PO_FAIL) { + free(stc_elems); + free(dyn_elems); + return (PO_FAIL); + } + while (status == PO_SUCCESS && j < dyn_nelem) { + status = process_elem_gt(dyn_elems[j], stc, dyn); + j++; + } + free(stc_elems); + free(dyn_elems); + return (status); +} + +/* + * get_elem_list() returns a list of pool_elem_t's. The size of the + * list is written into nelem. The list contains elements of all types + * that pools is interested in: i.e. system, pool, resources and + * resource components. It is the caller's responsibility to free the + * list when it is finished with. + * + * The array of pointers returned by the type specific query can be + * safely cast to be an array of pool_elem_t pointers. In the case of + * PEC_RES_COMP some additional processing is required to qualify the + * list of elements. + * + * Returns a pointer to a list of pool_elem_t's or NULL on failure. + */ +static pool_elem_t ** +get_elem_list(const pool_conf_t *conf, int type, uint_t *nelem) +{ + pool_resource_t **rl; + pool_t **pl; + pool_component_t **cl; + pool_elem_t **elems = NULL; + int i; + + switch (type) { + case PEC_SYSTEM: + if ((elems = malloc(sizeof (pool_elem_t *))) == NULL) + return (NULL); + *nelem = 1; + elems[0] = pool_conf_to_elem(conf); + break; + case PEC_POOL: + if ((pl = pool_query_pools(conf, nelem, NULL)) != NULL) { + elems = (pool_elem_t **)pl; + } + break; + case PEC_RES_COMP: + if ((rl = pool_query_resources(conf, nelem, NULL)) != NULL) { + int j = 0; + elems = (pool_elem_t **)rl; + for (i = 0; i < *nelem; i++) { + if (pool_elem_class(TO_ELEM(rl[i])) == + PEC_RES_COMP) + elems[j++] = TO_ELEM(rl[i]); + } + *nelem = j; + } + break; + case PEC_COMP: + if ((cl = pool_query_components(conf, nelem, NULL)) != NULL) { + elems = (pool_elem_t **)cl; + } + break; + default: + abort(); + break; + } + return (elems); +} + +/* + * share_resources() sets up the allocation of resources by each + * provider. Firstly all resources are updated with the importance of + * each pool, then each resource provider is invoked in turn with a + * list of it's own resources. Finally, the pool importance details + * are removed from the resources. + * + * Returns PO_SUCCESS/PO_FAIL + */ +static int +share_resources(pool_conf_t *conf) +{ + pool_resource_t **resources; + uint_t nelem; + pool_value_t *props[] = { NULL, NULL }; + pool_value_t val = POOL_VALUE_INITIALIZER; + + props[0] = &val; + + /* + * Call an allocation function for each type of supported resource. + * This function is responsible for "sharing" resources to resource + * sets as determined by the system.allocate-method. + */ + + if (pool_value_set_string(props[0], "pset") != PO_SUCCESS || + pool_value_set_name(props[0], c_type) != PO_SUCCESS) + return (PO_FAIL); + + if (add_importance_props(conf) != PO_SUCCESS) { + (void) remove_importance_props(conf); + return (PO_FAIL); + } + + if ((resources = pool_query_resources(conf, &nelem, props)) != NULL) { + /* + * 'pool.importance' defines the importance of a pool; + * resources inherit the importance of the pool that + * is associated with them. If more than one pool is + * associated with a resource, the importance of the + * resource is the maximum importance of all + * associated pools. Use '_importance' on resources + * to determine who gets extra. + */ + if (resource_allocate("pset", resources, nelem) != PO_SUCCESS) { + free(resources); + (void) remove_importance_props(conf); + return (PO_FAIL); + } + } + free(resources); + (void) remove_importance_props(conf); + return (PO_SUCCESS); +} + + +/* + * Work out which allocation method to use based on the value of the + * system.allocate-method property. + */ +int +resource_allocate(const char *type, pool_resource_t **res, uint_t nelem) +{ + pool_elem_t *pe; + const char *method_name; + uint64_t method; + pool_value_t val = POOL_VALUE_INITIALIZER; + int ret; + + pe = pool_conf_to_elem(TO_CONF(TO_ELEM(res[0]))); + + if (pool_get_ns_property(pe, "allocate-method", &val) != POC_STRING) + method_name = POA_IMPORTANCE; + else { + (void) pool_value_get_string(&val, &method_name); + } + if (strcmp(POA_IMPORTANCE, method_name) != 0) { + if (strcmp(POA_SURPLUS_TO_DEFAULT, method_name) != 0) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } else { + method = POA_SURPLUS_TO_DEFAULT_NUM; + } + } else { + method = POA_IMPORTANCE_NUM; + } + switch (method) { + case POA_IMPORTANCE_NUM: + /* + * TODO: Add support for new resource types + */ + switch (pool_resource_elem_class_from_string(type)) { + case PREC_PSET: + ret = pset_allocate_imp(res, nelem); + break; + default: + ret = PO_FAIL; + break; + } + break; + case POA_SURPLUS_TO_DEFAULT_NUM: + ret = resource_allocate_default(res, nelem); + break; + } + + return (ret); +} + +/* + * Each set will get its minimum, however if there is more than the + * total minimum available, then leave this in the default set. + */ +int +resource_allocate_default(pool_resource_t **res, uint_t nelem) +{ + res_info_t *res_info; + uint_t j; + pool_resource_t *default_res = NULL; + + if (nelem == 1) + return (PO_SUCCESS); + + if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) { + return (PO_FAIL); + } + + /* Load current resource values. */ + for (j = 0; j < nelem; j++) { + + if (default_res == NULL && + resource_is_default(res[j]) == PO_TRUE) + default_res = res[j]; + + if (resource_get_max(res[j], + &res_info[j].ri_max) == PO_FAIL || + resource_get_min(res[j], + &res_info[j].ri_min) == PO_FAIL || + resource_get_size(res[j], + &res_info[j].ri_oldsize) == PO_FAIL || + resource_get_pinned(res[j], + &res_info[j].ri_pinned) == PO_FAIL) { + free(res_info); + return (PO_FAIL); + } + res_info[j].ri_res = res[j]; + } + + /* + * Firstly, for all resources that have size greater than min, + * transfer all movable size above min to the default resource. + */ + for (j = 0; j < nelem; j++) { + + uint64_t real_min; + + /* compute the real minimum number of resources */ + real_min = MAX(res_info[j].ri_pinned, res_info[j].ri_min); + if (res_info[j].ri_res != default_res && + res_info[j].ri_oldsize > real_min) { + + uint64_t num; + + num = res_info[j].ri_oldsize - real_min; + if (pool_resource_transfer( + TO_CONF(TO_ELEM(default_res)), + res_info[j].ri_res, default_res, num) != + PO_SUCCESS) { + free(res_info); + return (PO_FAIL); + } + } + } + /* + * Now, transfer resources below min from the default. + */ + for (j = 0; j < nelem; j++) { + /* + * We don't want to interfere with resources which are reserved + */ + if (res_info[j].ri_res != default_res && + res_info[j].ri_oldsize < res_info[j].ri_min) { + if (pool_resource_transfer( + TO_CONF(TO_ELEM(default_res)), + default_res, res_info[j].ri_res, + res_info[j].ri_min - res_info[j].ri_oldsize) != + PO_SUCCESS) { + free(res_info); + return (PO_FAIL); + } + } + } + free(res_info); + return (PO_SUCCESS); +} + +/* + * Allocate cpus to pset resource sets, favoring sets with higher importance. + * + * Step 1: Sort resource sets by decreasing importance, and load each sets + * current size (oldsize), min, max, and number of pinned cpus. + * Compute the total number of cpus by totaling oldsize. + * + * Step 2: Compute the newsize for each set: + * + * Give each set its min number of cpus. This min may be greater than + * its pset.min due to pinned cpus. If there are more cpus than the total + * of all mins, then the surplus cpus are dealt round-robin to all sets + * (up to their max) in order of decreasing importance. A set may be + * skipped during dealing because it started with more than its min due to + * pinned cpus. The dealing stops when there are no more cpus or all + * sets are at their max. If all sets are at their max, any remaining cpus + * are given to the default set. + * + * Step 3: Transfer cpus from sets with (oldsize > newsize) to sets with + * (oldsize < newsize). + */ +int +pset_allocate_imp(pool_resource_t **res, uint_t nelem) +{ + res_info_t *res_info; + res_info_t *default_res_info; + const pool_resource_t *default_res = NULL; + uint64_t tot_resources = 0; /* total count of resources */ + uint64_t tot_min = 0; /* total of all resource set mins */ + uint64_t num_to_deal = 0; /* total resources above mins to deal */ + uint64_t sets_maxed = 0; /* number of resource sets dealt to */ + /* their max */ + uint64_t sets_finished = 0; /* number of resource sets that have */ + /* size == newsize */ + int donor, receiver; + int deal; + int j; + int ret = PO_SUCCESS; + + /* + * Build list of res_info_t's + */ + if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + /* Order resources by importance, most important being first */ + qsort(res, nelem, sizeof (pool_resource_t *), + resource_compare_by_descending_importance); + + for (j = 0; j < nelem; j++) { + + /* Track which resource is the default */ + if (default_res == NULL && + resource_is_default(res[j]) == PO_TRUE) { + default_res = res[j]; + default_res_info = &(res_info[j]); + } + + /* Load sets' current values */ + if (resource_get_max(res[j], &res_info[j].ri_max) == PO_FAIL || + resource_get_min(res[j], &res_info[j].ri_min) == PO_FAIL || + resource_get_size(res[j], &res_info[j].ri_oldsize) == + PO_FAIL || + resource_get_pinned(res[j], + &res_info[j].ri_pinned) == PO_FAIL) { + free(res_info); + return (PO_FAIL); + } + + /* Start each set's newsize out at their min. */ + res_info[j].ri_newsize = res_info[j].ri_min; + + /* pre-deal pinned resources that exceed min */ + if (res_info[j].ri_pinned > res_info[j].ri_min) { + res_info[j].ri_newsize = res_info[j].ri_pinned; + res_info[j].ri_dealt = + res_info[j].ri_newsize - res_info[j].ri_min; + } + res_info[j].ri_res = res[j]; + + /* Compute total number of resources to deal out */ + tot_resources += res_info[j].ri_oldsize; + tot_min += res_info[j].ri_newsize; + +#ifdef DEBUG + dprintf("res allocation details\n"); + pool_elem_dprintf(TO_ELEM(res[j])); + dprintf("size=%llu\n", res_info[j].ri_oldsize); +#endif /* DEBUG */ + } + + num_to_deal = tot_resources - tot_min; + + /* + * Deal one resource to each set, and then another, until all + * resources are dealt or all sets are at their max. + */ + for (deal = 1; num_to_deal > 0 && sets_maxed < nelem; deal++) { + for (j = 0; j < nelem; j++) { + + /* + * Skip this resource set if it has already been + * pre-dealt a resource due to pinned resources. + */ + if (res_info[j].ri_dealt >= deal) + continue; + + if (res_info[j].ri_newsize < res_info[j].ri_max) { + + res_info[j].ri_dealt++; + res_info[j].ri_newsize++; + if (res_info[j].ri_newsize == + res_info[j].ri_max) + sets_maxed++; + + num_to_deal--; + if (num_to_deal == 0) + break; + } + } + } + + /* + * If all resource sets are at their max, deal the remaining to the + * default resource set. + */ + if ((sets_maxed == nelem) && (num_to_deal > 0)) { + default_res_info->ri_dealt += num_to_deal; + default_res_info->ri_newsize += num_to_deal; + } + + /* + * Sort so that resource sets needing resources preced resource sets + * that have extra resources. The sort function will also compute + * The quantity of resources that need to be transfered into or out + * of each set so that it's size == newsize. + */ + qsort(res_info, nelem, sizeof (res_info_t), + compute_size_to_transfer); + + /* + * The donor index starts at the end of the resource set list and + * walks up. The receiver index starts at the beginning of the + * resource set list and walks down. Cpu's are transfered from the + * donors to the receivers until all sets have transfer == 0). + */ + donor = nelem - 1; + receiver = 0; + + /* Number of sets with transfer == 0 */ + sets_finished = 0; + + /* Tranfer resources so that each set's size becomes newsize */ + for (;;) { + + uint64_t ntrans; + if (donor == receiver) { + if (res_info[donor].ri_transfer != 0) { + free(res_info); + return (PO_FAIL); + } + sets_finished++; + break; + } + if (res_info[donor].ri_transfer == 0) { + sets_finished++; + donor--; + continue; + } + if (res_info[receiver].ri_transfer == 0) { + sets_finished++; + receiver++; + continue; + } + + /* Transfer resources from the donor set to the receiver */ + ntrans = MIN(res_info[donor].ri_transfer, + -res_info[receiver].ri_transfer); + + if (pool_resource_transfer( + TO_CONF(TO_ELEM(res_info[donor].ri_res)), + res_info[donor].ri_res, res_info[receiver].ri_res, + ntrans) != PO_SUCCESS) { + free(res_info); + return (PO_FAIL); + } + res_info[donor].ri_transfer -= ntrans; + res_info[receiver].ri_transfer += ntrans; + } + + if (sets_finished != nelem) + ret = PO_FAIL; + + free(res_info); + return (ret); +} + +/* + * Used as a qsort parameter to help order resources in terms of their + * importance, higher importance being first. + */ +int +resource_compare_by_descending_importance(const void *arg1, const void *arg2) +{ + pool_elem_t *elem1; + pool_elem_t *elem2; + pool_resource_t **res1 = (pool_resource_t **)arg1; + pool_resource_t **res2 = (pool_resource_t **)arg2; + pool_value_t val = POOL_VALUE_INITIALIZER; + int64_t i1 = 0, i2 = 0; + + elem1 = TO_ELEM(*res1); + elem2 = TO_ELEM(*res2); + + if (pool_get_property(TO_CONF(elem1), elem1, "_importance", &val) == + POC_INT) + (void) pool_value_get_int64(&val, &i1); + + if (pool_get_property(TO_CONF(elem2), elem2, "_importance", &val) == + POC_INT) + (void) pool_value_get_int64(&val, &i2); + return (i1 > i2 ? -1 : (i1 < i2 ? 1 : 0)); +} + +/* + * Sort in increasing order so that resource sets with extra resources are at + * the end and resource sets needing resources are at the beginning. + */ +int +compute_size_to_transfer(const void *arg1, const void *arg2) +{ + res_info_t *r1 = (res_info_t *)arg1, *r2 = (res_info_t *)arg2; + r1->ri_transfer = (int64_t)r1->ri_oldsize - (int64_t)r1->ri_newsize; + r2->ri_transfer = (int64_t)r2->ri_oldsize - (int64_t)r2->ri_newsize; + return (r1->ri_transfer > r2->ri_transfer ? 1 : + (r1->ri_transfer < r2->ri_transfer ? -1 : 0)); +} + +/* + * set_importance_cb() is used to create "_importance" props on each + * resource associated with a pool. + * + * Returns PO_SUCCESS/PO_FAIL + */ +/*ARGSUSED*/ +static int +set_importance_cb(pool_conf_t *conf, pool_t *pool, void *unused) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + int64_t importance; + pool_resource_t **res; + uint_t nelem, i; + + if (pool_get_property(conf, TO_ELEM(pool), "pool.importance", &val) != + POC_INT) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + (void) pool_value_get_int64(&val, &importance); + if ((res = pool_query_pool_resources(conf, pool, &nelem, NULL)) == + NULL) { + return (PO_FAIL); + } + for (i = 0; res[i] != NULL; i++) { + int64_t old_importance = INT64_MIN; + pool_elem_t *elem = TO_ELEM(res[i]); + + if (pool_get_property(conf, elem, "_importance", &val) == + POC_INT) + (void) pool_value_get_int64(&val, &old_importance); + if (old_importance <= importance) { + (void) pool_value_set_int64(&val, importance); + (void) pool_put_property(conf, elem, "_importance", + &val); + } + } + free(res); + return (PO_SUCCESS); +} + +/* + * unset_importance_cb() is used to remove "_importance" props from + * each resource associated with a pool. + * + * Returns PO_SUCCESS/PO_FAIL + */ +/*ARGSUSED*/ +static int +unset_importance_cb(pool_conf_t *conf, pool_t *pool, void *unused) +{ + pool_resource_t **res; + uint_t nelem, i; + + if ((res = pool_query_pool_resources(conf, pool, &nelem, NULL)) == + NULL) { + return (PO_FAIL); + } + for (i = 0; res[i] != NULL; i++) { + if (pool_rm_property(conf, TO_ELEM(res[i]), "_importance") == + PO_FAIL) { + free(res); + return (PO_FAIL); + } + } + free(res); + return (PO_SUCCESS); +} + +/* + * add_importance_props() is used to create "_importance" props on + * each resource associated with a pool. + * + * Returns PO_SUCCESS/PO_FAIL + */ +static int +add_importance_props(pool_conf_t *conf) +{ + return (pool_walk_pools(conf, NULL, set_importance_cb)); +} + +/* + * remove_importance_props() is used to remove "_importance" props on + * each resource associated with a pool. + * + * Returns PO_SUCCESS/PO_FAIL + */ +static int +remove_importance_props(pool_conf_t *conf) +{ + return (pool_walk_pools(conf, NULL, unset_importance_cb)); +} + +/* + * pool_conf_commit_sys() takes a configuration and modifies both the + * supplied configuration and the dynamic configuration. The goal of + * this modification is to generate a dynamic configuration which best + * represents the constraints laid down in the static configuration + * and to update the static configuration with the results of this + * process. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_conf_commit_sys(pool_conf_t *conf, int validate) +{ + pool_conf_t *dyn; + + if ((dyn = pool_conf_alloc()) == NULL) + return (PO_FAIL); + if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDWR) != + PO_SUCCESS) { + pool_conf_free(dyn); + return (PO_FAIL); + } + if (validate == PO_TRUE) { + if (pool_conf_validate(conf, POV_RUNTIME) != PO_SUCCESS) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + return (PO_FAIL); + } + } + /* + * Now try to make the two things "the same". + */ + if (diff_and_fix(conf, dyn) != PO_SUCCESS) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + if (dyn->pc_prov->pc_commit(dyn) != PO_SUCCESS) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + return (PO_FAIL); + } + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + return (PO_SUCCESS); +} + +/* + * Copies all properties from one element to another. If the property + * is a readonly property, then don't copy it. + */ +/* ARGSUSED */ +static int +clone_element(pool_conf_t *conf, pool_elem_t *pe, const char *name, + pool_value_t *pv, void *user) +{ + pool_elem_t *tgt = (pool_elem_t *)user; + const pool_prop_t *prop; +#ifdef DEBUG + dprintf("Cloning %s from %s\n", + pool_conf_location(TO_CONF(TO_ELEM(tgt))), + pool_conf_location(TO_CONF(pe))); + assert(TO_CONF(TO_ELEM(tgt)) != TO_CONF(pe)); + dprintf("clone_element: Processing %s\n", name); + pool_value_dprintf(pv); +#endif /* DEBUG */ + /* + * Some properties should be ignored + */ + if ((prop = provider_get_prop(pe, name)) != NULL && + prop_is_readonly(prop) == PO_TRUE) + return (PO_SUCCESS); + + /* The temporary property needs special handling */ + if (strstr(name, ".temporary") != NULL) + return (pool_set_temporary(TO_CONF(tgt), tgt) == + PO_FAIL ? PO_FAIL : PO_SUCCESS); + else + return (pool_put_property(TO_CONF(tgt), tgt, name, pv) == + PO_FAIL ? PO_FAIL : PO_SUCCESS); +} + +/* + * Removes all properties from one element. Properties which are + * managed by the configuration are ignored. + */ +/* ARGSUSED3 */ +static int +clean_element(pool_conf_t *conf, pool_elem_t *pe, const char *name, + pool_value_t *pv, void *user) +{ + const pool_prop_t *prop; + /* + * Some properties should be ignored + */ + if (strstr(name, ".temporary") != NULL || + ((prop = provider_get_prop(pe, name)) != NULL && + prop_is_optional(prop) == PO_FALSE)) + return (PO_SUCCESS); + return (pool_rm_property(conf, (pool_elem_t *)pe, name) == PO_FAIL); +} diff --git a/usr/src/lib/libpool/common/pool_impl.h b/usr/src/lib/libpool/common/pool_impl.h new file mode 100644 index 0000000..c917d52 --- /dev/null +++ b/usr/src/lib/libpool/common/pool_impl.h @@ -0,0 +1,283 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _POOL_IMPL_H +#define _POOL_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains the definitions of types and supporting + * functions to implement the libpool generic data manipulation + * facility. + * + * libpool is designed so that the data representation/storage method + * used may be easily replaced without affecting core functionality. + * A libpool configuration is connected to a particular data + * representation/storage "driver" via the pool_connection_t + * type. When a configuration is opened (see pool_conf_open) the + * libpool implementation allocates a specific data manipulation type + * and initialises it. For instance, see pool_xml_connection_alloc. + * + * This function represents a cross-over point and all routines used + * for data representation/storage are controlled by the type of + * allocated connection. + * + * Currently, there are two implemented methods of access. Data may be + * retrieved from the kernel, using the pool_knl_connection_t + * function. This implementation relies on a private interface + * provided by a driver, /dev/pool, and presents data retrieved from + * the kernel via the standard libpool interface. Alternatively, data + * may be retrieved from an XML file, via pool_xml_connection_t, and + * presented through the standard libpool interface. For details of + * these two implementations, see pool_kernel_impl.h and + * pool_xml_impl.h. + * + * In addition to defining a specific connection type for a desired + * data representation/storage medium, several other structures must + * be defined to allow manipulation of configuration elements. + * + * Configuration elements are represented as pool_elem_t instances, or + * as sub-types of this generic type (such as pool_t, which represents + * a pool element) with groups (or sets) of these instances available + * for manipulation via the pool_result_set_t type. + * + * For more information on the implementation of these types, read the + * detailed comments above each structure definition. + */ + +/* + * The pool_elem_t is used to represent a configuration element.The + * class of the element is stored within the structure along with a + * pointer to the containing configuration and a pointer to the + * element's specific subtype. + * + * The function pointers are initialised when the element is allocated + * to use the specific functions provided by the concrete data + * representation. + * + * The full set of operations that can be performed on an element + * which require special treatment from the data + * representation/storage medium are defined. + */ +struct pool_elem { + pool_conf_t *pe_conf; /* Configuration */ + pool_elem_class_t pe_class; /* Element class */ + pool_resource_elem_class_t pe_resource_class; /* Resource class */ + pool_component_elem_class_t pe_component_class; /* Component class */ + struct pool_elem *pe_pair; /* Static pair */ + pool_value_class_t (*pe_get_prop)(const pool_elem_t *, const char *, + pool_value_t *); + int (*pe_put_prop)(pool_elem_t *, const char *, const pool_value_t *); + int (*pe_rm_prop)(pool_elem_t *, const char *); + pool_value_t **(*pe_get_props)(const pool_elem_t *, uint_t *); + int (*pe_remove)(pool_elem_t *); + pool_elem_t *(*pe_get_container)(const pool_elem_t *); + int (*pe_set_container)(pool_elem_t *, pool_elem_t *); +}; + +/* + * libpool performs many operations against a pool_elem_t. This basic + * type is extended to provide specific functionality and type safety + * for each of the different types of element supported by + * libpool. There are four types of element: + * - pool_system_t, represents an entire configuration + * - pool_t, represents a single pool + * - pool_resource_t, represents a single resource + * - pool_component_t, represents a single resource component + * + * pool_system_t is an internal structure, the other structures are + * externally visible and form a major part of the libpool interface. + */ +typedef struct pool_system +{ + pool_elem_t ps_elem; + void *pe_pad1; + void *pe_pad2; +} pool_system_t; + +struct pool +{ + pool_elem_t pp_elem; + /* + * Specific to pool_t + */ + int (*pp_associate)(pool_t *, const pool_resource_t *); + int (*pp_dissociate)(pool_t *, const pool_resource_t *); +}; + +struct pool_resource +{ + pool_elem_t pr_elem; + /* + * Specific to pool_resource_t + */ + int (*pr_is_system)(const pool_resource_t *); + int (*pr_can_associate)(const pool_resource_t *); +}; + +struct pool_component +{ + pool_elem_t pc_elem; + void *pe_pad1; + void *pe_pad2; +}; + +/* + * The pool_result_set_t is used to represent a collection (set) of + * configuration elements. The configuration to which this result set + * applies is stored along with an indicator as to whether the result + * set is still in use. + * + * The function pointers are initialised when the element is allocated + * to use the specific functions provided by the concrete data + * representation. + * + * The full set of operations that can be performed on an element + * which require special treatment from the data + * representation/storage medium are defined. + */ +typedef struct pool_result_set { + pool_conf_t *prs_conf; /* Configuration */ + int prs_active; /* Query active? */ + int prs_index; /* Result Index */ + pool_elem_t *(*prs_next)(struct pool_result_set *); + pool_elem_t *(*prs_prev)(struct pool_result_set *); + pool_elem_t *(*prs_first)(struct pool_result_set *); + pool_elem_t *(*prs_last)(struct pool_result_set *); + int (*prs_set_index)(struct pool_result_set *, int); + int (*prs_get_index)(struct pool_result_set *); + int (*prs_close)(struct pool_result_set *); + int (*prs_count)(struct pool_result_set *); +} pool_result_set_t; + +/* + * The pool_connection_t is used to represent a connection between a + * libpool configuration and a particular implementation of the + * libpool interface in a specific data representation/storage medium, + * e.g. XML. + * + * The name of the storage medium is stored along with the type of the + * data store. + * + * The function pointers are initialised when the element is allocated + * to use the specific functions provided by the concrete data + * representation. + * + * The full set of operations that can be performed on an element + * which require special treatment from the data + * representation/storage medium are defined. + */ +typedef struct pool_connection { + const char *pc_name; /* Provider name */ + int pc_store_type; /* Datastore type */ + int pc_oflags; /* Open flags */ + int (*pc_close)(pool_conf_t *); + int (*pc_validate)(const pool_conf_t *, pool_valid_level_t); + int (*pc_commit)(pool_conf_t *); + int (*pc_export)(const pool_conf_t *, const char *, + pool_export_format_t); + int (*pc_rollback)(pool_conf_t *); + pool_result_set_t *(*pc_exec_query)(const pool_conf_t *, + const pool_elem_t *, const char *, pool_elem_class_t, + pool_value_t **); + pool_elem_t *(*pc_elem_create)(pool_conf_t *, pool_elem_class_t, + pool_resource_elem_class_t, pool_component_elem_class_t); + int (*pc_remove)(pool_conf_t *); + int (*pc_res_xfer)(pool_resource_t *, pool_resource_t *, uint64_t); + int (*pc_res_xxfer)(pool_resource_t *, pool_resource_t *, + pool_component_t **); + char *(*pc_get_binding)(pool_conf_t *, pid_t); + int (*pc_set_binding)(pool_conf_t *, const char *, idtype_t, id_t); + char *(*pc_get_resource_binding)(pool_conf_t *, + pool_resource_elem_class_t, pid_t); +} pool_connection_t; + +/* + * pool_conf represents a resource management configuration. The + * configuration location is stored in the pc_location member with the + * state of the configuration stored in pc_state. + * + * The pc_prov member provides data representation/storage abstraction + * for the configuration since all access to data is performed through + * this member. + */ +struct pool_conf { + const char *pc_location; /* Location */ + pool_connection_t *pc_prov; /* Data Provider */ + pool_conf_state_t pc_state; /* State */ +}; + +/* + * Convert a pool_elem_t to it's appropriate sub-type. + */ +extern pool_system_t *pool_conf_system(const pool_conf_t *); +extern pool_system_t *pool_elem_system(const pool_elem_t *); +extern pool_t *pool_elem_pool(const pool_elem_t *); +extern pool_resource_t *pool_elem_res(const pool_elem_t *); +extern pool_component_t *pool_elem_comp(const pool_elem_t *); + +/* + * Convert a pool_system_t to a pool_elem_t. + */ +extern pool_elem_t *pool_system_elem(const pool_system_t *); + +/* + * Get/Set an element's "pair" element. A pair element is a temporary + * association at commit between an element in the dynamic + * configuration and an element in the static configuration. This + * relationship is stored in the pe_pair member of the element. + */ +extern pool_elem_t *pool_get_pair(const pool_elem_t *); +extern void pool_set_pair(pool_elem_t *, pool_elem_t *); + +/* + * Result Set Manipulation + */ +extern pool_elem_t *pool_rs_next(pool_result_set_t *); +extern pool_elem_t *pool_rs_prev(pool_result_set_t *); +extern pool_elem_t *pool_rs_first(pool_result_set_t *); +extern pool_elem_t *pool_rs_last(pool_result_set_t *); +extern int pool_rs_count(pool_result_set_t *); +extern int pool_rs_get_index(pool_result_set_t *); +extern int pool_rs_set_index(pool_result_set_t *, int); +extern int pool_rs_close(pool_result_set_t *); + +/* + * General Purpose Query + */ +extern pool_result_set_t *pool_exec_query(const pool_conf_t *, + const pool_elem_t *, const char *, pool_elem_class_t, pool_value_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_IMPL_H */ diff --git a/usr/src/lib/libpool/common/pool_internal.c b/usr/src/lib/libpool/common/pool_internal.c new file mode 100644 index 0000000..5e572f6 --- /dev/null +++ b/usr/src/lib/libpool/common/pool_internal.c @@ -0,0 +1,2046 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <limits.h> +#include <pool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <synch.h> +#include <thread.h> + +#include <sys/loadavg.h> +#include <sys/types.h> +#include <sys/utsname.h> + +#include "dict.h" +#include "pool_internal.h" +#include "pool_impl.h" + +/* + * Atom structure, used to reference count string atoms. + */ +typedef struct { + char *a_string; /* String atom */ + uint_t a_count; /* String reference count */ +} atom_t; + +/* + * The _internal_lock is used to lock the state of libpool during + * internal initialisation operations. + */ +mutex_t _internal_lock; + +static int _libpool_debug = 0; /* debugging messages */ +static dict_hdl_t *_pv_atoms; /* pool_value_t atoms */ +static mutex_t _atom_lock; /* atom table lock */ +static int _libpool_internal_initialised = PO_FALSE; + +/* + * Various useful constant strings which are often encountered + */ +const char *c_a_dtype = "a-dtype"; +const char *c_name = "name"; +const char *c_type = "type"; +const char *c_ref_id = "ref_id"; +const char *c_max_prop = "max"; +const char *c_min_prop = "min"; +const char *c_size_prop = "size"; +const char *c_sys_prop = "sys_id"; + +/* + * prop_is_type() checks the supplied property and returns PO_TRUE if the + * property value is set for the property else PO_FALSE + */ +static int prop_is_type(int, const pool_prop_t *); +static int resource_get_common(const pool_resource_t *, const char *, + uint64_t *); +static int64_t elem_get_expected_int64(const pool_elem_t *, const char *); + +/* + * The following returns a malloc'ed string which must be free'd by the + * caller. + */ +static char *elem_get_expected_string(const pool_elem_t *, const char *); +static int element_props_init(pool_prop_t *); + +/* + * Each element class/sub-class has a set of properties and behaviours + * which are used to create the element with appropriate property + * values and to ensure correct property manipulations. The details + * are all stored in the following arrays. + */ + +static int elem_name_init(pool_prop_t *); +static int elem_comment_init(pool_prop_t *); + +static int pool_importance_init(pool_prop_t *); +static int pool_active_init(pool_prop_t *); + +static int res_max_init(pool_prop_t *); +static int res_min_init(pool_prop_t *); +static int res_size_init(pool_prop_t *); +static int res_load_init(pool_prop_t *); + +static int pset_units_init(pool_prop_t *); + +static int cpu_status_init(pool_prop_t *); + +static int elem_no_set(pool_elem_t *, const pool_value_t *); +static int elem_set_name(pool_elem_t *, const pool_value_t *); +static int elem_get_type(const pool_elem_t *, pool_value_t *); +static int elem_set_string(pool_elem_t *, const pool_value_t *); +static int elem_set_bool(pool_elem_t *, const pool_value_t *); +static int elem_set_uint(pool_elem_t *, const pool_value_t *); + +static int system_set_allocate(pool_elem_t *, const pool_value_t *); + +static int pool_set_scheduler(pool_elem_t *, const pool_value_t *); +static int pool_set_active(pool_elem_t *, const pool_value_t *); + +static int res_set_max(pool_elem_t *, const pool_value_t *); +static int res_set_min(pool_elem_t *, const pool_value_t *); + +static int cpu_set_status(pool_elem_t *, const pool_value_t *); + +static const char *pool_elem_class_name[] = { + "invalid", + "system", + "pool", + "component resource", + "aggregate resource", + "component" +}; + +/* + * This must be kept in sync with the pool_resource_elem_ctl array and + * the "enum pool_resource_elem_class" type. + */ +static const char *pool_resource_elem_class_name[] = { + "invalid", + "pset" +}; + +static const char *pool_component_elem_class_name[] = { + "invalid", + "cpu" +}; + +static pool_prop_t system_props[] = { + { "system.name", POOL_VALUE_INITIALIZER, PP_STORED, NULL, + { NULL, elem_set_name } }, + { "system.ref_id", POOL_VALUE_INITIALIZER, + PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, + { "system.comment", POOL_VALUE_INITIALIZER, PP_STORED, NULL, NULL }, + { "system.version", POOL_VALUE_INITIALIZER, + PP_STORED | PP_READ, NULL, NULL }, + { "system.bind-default", POOL_VALUE_INITIALIZER, + PP_STORED, NULL, NULL }, + { "system.allocate-method", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, system_set_allocate } }, + { "system.poold.log-level", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, + { "system.poold.log-location", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, + { "system.poold.monitor-interval", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_uint } }, + { "system.poold.history-file", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, + { "system.poold.objectives", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, + NULL +}; + +static pool_prop_t pool_props[] = { + { "pool.sys_id", POOL_VALUE_INITIALIZER, + PP_STORED | PP_READ, NULL, NULL }, + { "pool.name", POOL_VALUE_INITIALIZER, + PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } }, + { "pool.res", POOL_VALUE_INITIALIZER, + PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, + { "pool.ref_id", POOL_VALUE_INITIALIZER, + PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, + { "pool.active", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, + pool_active_init, { NULL, pool_set_active } }, + { "pool.default", POOL_VALUE_INITIALIZER, + PP_STORED | PP_READ, NULL, NULL }, + { "pool.scheduler", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, + { NULL, pool_set_scheduler } }, + { "pool.importance", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, + pool_importance_init, NULL }, + { "pool.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, + elem_comment_init, NULL }, + NULL +}; + +static pool_prop_t pset_props[] = { + { "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, + { elem_get_type, NULL } }, + { "pset.sys_id", POOL_VALUE_INITIALIZER, + PP_STORED | PP_READ, NULL, NULL }, + { "pset.name", POOL_VALUE_INITIALIZER, + PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } }, + { "pset.ref_id", POOL_VALUE_INITIALIZER, + PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, + { "pset.default", POOL_VALUE_INITIALIZER, + PP_STORED | PP_READ, NULL, NULL }, + { "pset.min", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_min_init, + { NULL, res_set_min } }, + { "pset.max", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_max_init, + { NULL, res_set_max } }, + { "pset.units", POOL_VALUE_INITIALIZER, + PP_STORED | PP_INIT, pset_units_init, NULL }, + { "pset.load", POOL_VALUE_INITIALIZER, PP_READ | PP_INIT, + res_load_init, NULL }, + { "pset.size", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT | PP_READ, + res_size_init, NULL }, + { "pset.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, + elem_comment_init, NULL }, + { "pset.poold.objectives", POOL_VALUE_INITIALIZER, + PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, + NULL +}; + +static pool_prop_t cpu_props[] = { + { "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, + { elem_get_type, NULL } }, + { "cpu.sys_id", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, + NULL }, + { "cpu.ref_id", POOL_VALUE_INITIALIZER, + PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, + { "cpu.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, + elem_comment_init, NULL }, + { "cpu.status", POOL_VALUE_INITIALIZER, PP_INIT, cpu_status_init, + { NULL, cpu_set_status } }, + { "cpu.pinned", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, + { NULL, elem_set_bool } }, + NULL +}; + +static pool_prop_t *pool_elem_ctl[] = { + NULL, + system_props, + pool_props, + NULL, + NULL, + NULL +}; + +/* + * This must be kept in sync with the pool_resource_elem_class_name array and + * the "enum pool_resource_elem_class" type. + */ +static pool_prop_t *pool_resource_elem_ctl[] = { + NULL, + pset_props +}; + +static pool_prop_t *pool_component_elem_ctl[] = { + NULL, + cpu_props +}; + +static void +atom_init(void) +{ + (void) mutex_lock(&_atom_lock); + /* + * Initialize pool_value_t atom dictionary + */ + if (_pv_atoms == NULL) + if ((_pv_atoms = dict_new((int (*)(const void *, const void *)) + strcmp, (uint64_t (*)(const void *))hash_str)) == NULL) + abort(); + (void) mutex_unlock(&_atom_lock); +} + +/* + * Initializer, called when the library is initialized. + */ +void +internal_init(void) +{ + (void) mutex_lock(&_internal_lock); + if (_libpool_internal_initialised == PO_TRUE) { + (void) mutex_unlock(&_internal_lock); + return; + } + atom_init(); + /* + * Initialize all available property arrays. + */ + if (element_props_init(system_props) == PO_FAIL) + abort(); + if (element_props_init(pool_props) == PO_FAIL) + abort(); + if (element_props_init(pset_props) == PO_FAIL) + abort(); + if (element_props_init(cpu_props) == PO_FAIL) + abort(); + _libpool_internal_initialised = PO_TRUE; + (void) mutex_unlock(&_internal_lock); + +} + +static int +element_props_init(pool_prop_t *props) +{ + int i; + + for (i = 0; props[i].pp_pname != NULL; i++) { + /* + * Initialise each of the properties + */ + if (pool_value_set_name(&props[i].pp_value, + props[i].pp_pname) != PO_SUCCESS) { + return (PO_FAIL); + } + if (props[i].pp_init && + props[i].pp_init(&props[i]) != PO_SUCCESS) { + return (PO_FAIL); + } + } + return (PO_SUCCESS); +} + + +/* + * These functions intialise the properties of this plugin. The only reason + * they exist is because the ability to perform the static initialisation of + * union members properly was only introduced in the C99 standard. i.e. if you + * could do {.f = 1.0} like in the proposed C99 standard then that would + * be the preferred way to do this as it keeps the data in the array and + * minimises the scope for errors. However, until that time these functions + * are the best way to minimise the scope for errors and to maximise + * maintainability. + * + * There is one function for each property, and the initial value for each + * property is hard-coded into each function. + */ + +static int +elem_name_init(pool_prop_t *prop) +{ + return (string_init(prop, "default")); +} + +static int +elem_comment_init(pool_prop_t *prop) +{ + return (string_init(prop, "")); +} + +static int +pool_importance_init(pool_prop_t *prop) +{ + return (int_init(prop, 1)); +} + +static int +pool_active_init(pool_prop_t *prop) +{ + return (bool_init(prop, PO_TRUE)); +} + +static int +res_max_init(pool_prop_t *prop) +{ + return (uint_init(prop, 0)); +} + +static int +res_min_init(pool_prop_t *prop) +{ + return (uint_init(prop, 0)); +} + +static int +res_size_init(pool_prop_t *prop) +{ + return (uint_init(prop, 0)); +} + +static int +res_load_init(pool_prop_t *prop) +{ + return (uint_init(prop, 0)); +} + +static int +pset_units_init(pool_prop_t *prop) +{ + return (string_init(prop, "population")); +} + +static int +cpu_status_init(pool_prop_t *prop) +{ + return (string_init(prop, PS_ONLINE)); +} + +/* + * Individual property manipulation routines for use by the generic + * get/put property routines + */ + +/* + * Many properties cannot be modified. This function prevents property + * modification. + */ +/* ARGSUSED */ +static int +elem_no_set(pool_elem_t *elem, const pool_value_t *pval) +{ + return (PO_FAIL); +} + +/* + * Duplicate names for a pool or resource type are illegal. + */ +static int +elem_set_name(pool_elem_t *elem, const pool_value_t *pval) +{ + const char *nm; + pool_t *pool; + pool_resource_t *res; + + if (pool_value_get_string(pval, &nm) != PO_SUCCESS) { + return (PO_FAIL); + } + if (!is_valid_name(nm)) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + switch (pool_elem_class(elem)) { + case PEC_SYSTEM: + break; + case PEC_POOL: + pool = pool_get_pool(TO_CONF(elem), nm); + if (pool != NULL && pool != pool_elem_pool(elem)) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + res = pool_get_resource(TO_CONF(elem), + pool_elem_class_string(elem), nm); + if (res != NULL && res != pool_elem_res(elem)) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + break; + default: + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Ensure the type is a string. + */ +/* ARGSUSED */ +static int +elem_set_string(pool_elem_t *elem, const pool_value_t *pval) +{ + if (pool_value_get_type(pval) == POC_STRING) + return (PO_SUCCESS); + else { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } +} + +/* + * Ensure the type is a boolean. + */ +/* ARGSUSED */ +static int +elem_set_bool(pool_elem_t *elem, const pool_value_t *pval) +{ + if (pool_value_get_type(pval) == POC_BOOL) + return (PO_SUCCESS); + else { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } +} + +/* + * Ensure the type is an unsigned int. + */ +/* ARGSUSED */ +static int +elem_set_uint(pool_elem_t *elem, const pool_value_t *pval) +{ + if (pool_value_get_type(pval) == POC_UINT) + return (PO_SUCCESS); + else { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } +} + +/* ARGSUSED */ +int +system_set_allocate(pool_elem_t *elem, const pool_value_t *pval) +{ + const char *sval; + + if (pool_value_get_string(pval, &sval) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (strcmp(POA_IMPORTANCE, sval) != 0 && + strcmp(POA_SURPLUS_TO_DEFAULT, sval) != 0) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* ARGSUSED */ +int +pool_set_active(pool_elem_t *elem, const pool_value_t *pval) +{ + uchar_t bval; + + if (pool_value_get_type(pval) != POC_BOOL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + (void) pool_value_get_bool(pval, &bval); + if (bval != 1) { + /* + * "active" must be true on pools for + * now. + */ + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* ARGSUSED */ +int +pool_set_scheduler(pool_elem_t *elem, const pool_value_t *pval) +{ + pcinfo_t pcinfo; + const char *sched; + + if (pool_value_get_string(pval, &sched) != 0) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + (void) strncpy(pcinfo.pc_clname, sched, PC_CLNMSZ); + if (priocntl(0, 0, PC_GETCID, &pcinfo) == -1) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +static int +res_set_max(pool_elem_t *elem, const pool_value_t *pval) +{ + uint64_t min, max; + pool_value_t val = POOL_VALUE_INITIALIZER; + + /* + * max must be a uint + */ + if (pool_value_get_uint64(pval, &max) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + /* + * max can't be less than min (if it exists) + */ + if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) + return (PO_SUCCESS); + if (pool_value_get_uint64(&val, &min) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (max < min) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + /* + * Ensure that changes to the max in a dynamic configuration + * are still valid. + */ + if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) { + uint64_t oldmax; + + if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (pool_value_get_uint64(&val, &oldmax) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (max < oldmax) { + /* + * Ensure that the modified total max is >= size + * of all resources of this type + */ + return (pool_validate_resource(TO_CONF(elem), + pool_elem_class_string(elem), c_max_prop, + max - oldmax)); + } + } + return (PO_SUCCESS); +} + +static int +res_set_min(pool_elem_t *elem, const pool_value_t *pval) +{ + uint64_t min, max; + pool_value_t val = POOL_VALUE_INITIALIZER; + + /* + * min must be a uint + */ + if (pool_value_get_uint64(pval, &min) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + /* + * min can't be more than max (if it exists) + */ + if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) + return (PO_SUCCESS); + if (pool_value_get_uint64(&val, &max) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (min > max) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + + switch (pool_resource_elem_class(elem)) { + case PREC_PSET: + if (resource_is_default(pool_elem_res(elem))) { + if (min < 1) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + } + break; + default: + break; + } + + /* + * Ensure that changes to the min in a dynamic configuration + * are still valid. + */ + if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) { + uint64_t oldmin; + + if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (pool_value_get_uint64(&val, &oldmin) != PO_SUCCESS) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + if (min > oldmin) { + /* + * Ensure that the modified total min is <= size + * of all resources of this type + */ + return (pool_validate_resource(TO_CONF(elem), + pool_elem_class_string(elem), c_min_prop, + min - oldmin)); + } + } + return (PO_SUCCESS); +} + +/* ARGSUSED */ +int +cpu_set_status(pool_elem_t *elem, const pool_value_t *pval) +{ + const char *status; + + if (pool_value_get_string(pval, &status) != 0) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + + if (strcmp(PS_ONLINE, status) != 0 && + strcmp(PS_OFFLINE, status) != 0 && + strcmp(PS_NOINTR, status) != 0 && + strcmp(PS_SPARE, status) != 0 && + strcmp(PS_FAULTED, status) != 0) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +static int +elem_get_type(const pool_elem_t *elem, pool_value_t *pval) +{ + if (pool_value_set_string(pval, pool_elem_class_string(elem)) == + PO_FAIL) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * More general utilities + */ +/* + * Is the supplied configuration the dynamic configuration + * Return: PO_TRUE/PO_FALSE + */ +int +conf_is_dynamic(const pool_conf_t *conf) +{ + if (strcmp(pool_conf_location(conf), pool_dynamic_location()) == 0) + return (PO_TRUE); + return (PO_FALSE); +} + +/* + * uint_init() initialises the value of the supplied property with the + * supplied value. + * Returns PO_SUCCESS + */ +int +uint_init(pool_prop_t *prop, uint64_t val) +{ + pool_value_set_uint64(&prop->pp_value, val); + return (PO_SUCCESS); +} + +/* + * int_init() initialises the value of the supplied property with the + * supplied value. + * Returns PO_SUCCESS + */ +int +int_init(pool_prop_t *prop, int64_t val) +{ + pool_value_set_int64(&prop->pp_value, val); + return (PO_SUCCESS); +} + +/* + * double_init() initialises the value of the supplied property with the + * supplied value. + * Returns PO_SUCCESS + */ +int +double_init(pool_prop_t *prop, double val) +{ + pool_value_set_double(&prop->pp_value, val); + return (PO_SUCCESS); +} + +/* + * bool_init() initialises the value of the supplied property with the + * supplied value. + * Returns PO_SUCCESS + */ +int +bool_init(pool_prop_t *prop, uchar_t val) +{ + pool_value_set_bool(&prop->pp_value, val); + return (PO_SUCCESS); +} + +/* + * string_init() initialises the value of the supplied property with the + * supplied value. + * Returns PO_SUCCESS/PO_FAIL + */ +int +string_init(pool_prop_t *prop, const char *val) +{ + return (pool_value_set_string(&prop->pp_value, val)); +} + +/* + * pool_get_provider_count() returns the count of registered providers. + * + * Returns count of registered providers + */ +uint_t +pool_get_provider_count(void) +{ + uint_t count = 0; + int i; + + for (i = 0; i < sizeof (pool_resource_elem_ctl) / + sizeof (pool_resource_elem_ctl[0]); i++) { + if (pool_resource_elem_ctl[i] != NULL) + count++; + } + return (count); +} + +/* + * Return all the props for a specified provider + */ +const pool_prop_t * +provider_get_props(const pool_elem_t *elem) +{ + const pool_prop_t *prop_list = NULL; + pool_elem_class_t elem_class = pool_elem_class(elem); + + switch (elem_class) { + case PEC_SYSTEM: + case PEC_POOL: + prop_list = pool_elem_ctl[elem_class]; + break; + case PEC_RES_AGG: + case PEC_RES_COMP: + prop_list = pool_resource_elem_ctl + [pool_resource_elem_class(elem)]; + break; + case PEC_COMP: + prop_list = pool_component_elem_ctl + [pool_component_elem_class(elem)]; + break; + } + return (prop_list); +} + +/* + * provider_get_prop() return the pool_prop_t structure which + * describes the supplied property name for the supplied provider. + * + * Returns the property description or NULL if it doesn't exist. + */ +const pool_prop_t * +provider_get_prop(const pool_elem_t *elem, const char *name) +{ + int i; + const pool_prop_t *prop_list; + + if ((prop_list = provider_get_props(elem)) == NULL) + return (NULL); + + for (i = 0; prop_list[i].pp_pname != NULL; i++) { + if (strcmp(name, prop_list[i].pp_pname) == 0) { + return (&prop_list[i]); + } + } + return (NULL); +} + +/* + * prop_is_type() checks the supplied property and returns PO_TRUE if the + * property value is 1 else PO_FALSE + */ +static int +prop_is_type(int prop_type, const pool_prop_t *prop) +{ + return ((prop->pp_perms & prop_type) ? PO_TRUE : PO_FALSE); +} + +/* + * prop_is_stored() returns PO_TRUE if the property is stored in the backing + * configuration and PO_FALSE else. + */ +int +prop_is_stored(const pool_prop_t *prop) +{ + return (prop_is_type(PP_STORED, prop)); +} + +/* + * prop_is_readonly() returns PO_TRUE if the property is a read-only property + * and PO_FALSE else. + */ +int +prop_is_readonly(const pool_prop_t *prop) +{ + return (prop_is_type(PP_READ, prop)); +} + +/* + * prop_is_init() returns PO_TRUE if the property should be + * initialised when an element of this type is created and PO_FALSE + * else. + */ +int +prop_is_init(const pool_prop_t *prop) +{ + return (prop_is_type(PP_INIT, prop)); +} + +/* + * prop_is_hidden() returns PO_TRUE if the property should be hidden + * from access by the external property access mechanisms. + */ +int +prop_is_hidden(const pool_prop_t *prop) +{ + return (prop_is_type(PP_HIDDEN, prop)); +} + +/* + * prop_is_optional() returns PO_TRUE if the property is optional and + * can be removed by external property access mechanisms. + */ +int +prop_is_optional(const pool_prop_t *prop) +{ + return (prop_is_type(PP_OPTIONAL, prop)); +} + +int +cpu_is_requested(pool_component_t *component) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + uchar_t requested; + + if (pool_get_property(TO_CONF(TO_ELEM(component)), TO_ELEM(component), + "cpu.requested", &val) != POC_BOOL) { + return (PO_FALSE); + } + if (pool_value_get_bool(&val, &requested) != PO_SUCCESS) { + return (PO_FALSE); + } + return ((int)requested); +} + +/* + * Common code for various resource get functions + */ +static int +resource_get_common(const pool_resource_t *res, const char *name, + uint64_t *uval) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + pool_value_class_t pvc; + int retval = PO_SUCCESS; + + pvc = pool_get_ns_property(TO_ELEM(res), name, &val); + if (pvc == POC_INVAL) { + *uval = 0; +#ifdef DEBUG + dprintf("can't retrieve %s\n"); + pool_elem_dprintf(TO_ELEM(res)); +#endif /* DEBUG */ + } else if (pvc == POC_UINT) { + retval = pool_value_get_uint64(&val, uval); + } + return (retval); +} + +/* + * resource_get_size() updates size with the size of the supplied resource. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +resource_get_size(const pool_resource_t *res, uint64_t *size) +{ + return (resource_get_common(res, c_size_prop, size)); +} + +/* + * resource_get_pinned() updates pinned with the size of the + * pinned part of a supplied resource. Resource is not available for + * allocation if it is marked as "pinned". + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +resource_get_pinned(const pool_resource_t *res, uint64_t *pinned) +{ + pool_value_t *props[] = { NULL, NULL }; + pool_value_t val = POOL_VALUE_INITIALIZER; + pool_component_t **cs = NULL; + uint_t ncompelem; + + props[0] = &val; + + pool_value_set_bool(props[0], PO_TRUE); + if (pool_value_set_name(props[0], "cpu.pinned") != PO_SUCCESS) + return (PO_FAIL); + + if ((cs = pool_query_resource_components(TO_CONF(TO_ELEM(res)), res, + &ncompelem, props)) != NULL) { + *pinned = ncompelem; + free(cs); + } else + *pinned = 0; + return (PO_SUCCESS); +} + +/* + * resource_get_min() updates min with the minimum size of the supplied + * resource. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +resource_get_min(const pool_resource_t *res, uint64_t *min) +{ + return (resource_get_common(res, c_min_prop, min)); +} + +/* + * resource_get_max() updates max with the maximum size of the supplied + * resource. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +resource_get_max(const pool_resource_t *res, uint64_t *max) +{ + return (resource_get_common(res, c_max_prop, max)); +} + +/* + * TODO: This is pset specific + * + * get_default_resource() returns the default resource for type of the supplied + * resource. + * + * Returns A pointer to the default resource of the same type as the supplied + * resource. + */ +const pool_resource_t * +get_default_resource(const pool_resource_t *res) +{ + return (resource_by_sysid(TO_CONF(TO_ELEM(res)), PS_NONE, + pool_elem_class_string(TO_ELEM(res)))); +} + +/* + * resource_is_default() returns 1 if the supplied resource is the default + * resource for it's type. + */ +int +resource_is_default(const pool_resource_t *res) +{ + + return (get_default_resource(res) == res); +} + +/* + * resource_is_system() determines if the resource is a system resource. + */ +int +resource_is_system(const pool_resource_t *res) +{ + return (res->pr_is_system(res)); + +} + +/* + * resource_can_associate() determines if it is possible to associate + * with the supplied resource. + */ +int +resource_can_associate(const pool_resource_t *res) +{ + return (res->pr_can_associate(res)); +} + +/* + * Common code to get an int64 property. + * Unfortunately (-1) is a valid psetid, so we'll return (-2) in case of + * error. + */ +static int64_t +elem_get_expected_int64(const pool_elem_t *elem, const char *name) +{ + int64_t val64; + pool_value_t val = POOL_VALUE_INITIALIZER; + + if (pool_get_ns_property(elem, name, &val) != POC_INT) { + return (POOL_SYSID_BAD); + } + (void) pool_value_get_int64(&val, &val64); + + return (val64); +} + +/* + * The following returns a malloc'ed string which must be free'd by the + * caller. + */ +static char * +elem_get_expected_string(const pool_elem_t *elem, const char *name) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + char *retval; + + if (pool_get_ns_property(elem, name, &val) != POC_STRING) { + return (NULL); + } + (void) pool_value_get_string(&val, (const char **)&retval); + retval = strdup(retval); + return (retval); +} + +/* + * elem_get_sysid() returns the sys_id for the supplied elem. + */ +id_t +elem_get_sysid(const pool_elem_t *elem) +{ + return ((id_t)elem_get_expected_int64(elem, c_sys_prop)); +} + +/* + * elem_get_name() returns the name for the supplied elem. Note that + * it is the caller's responsibility to free this memory. + */ +char * +elem_get_name(const pool_elem_t *elem) +{ + return (elem_get_expected_string(elem, c_name)); +} + +/* + * elem_is_default() returns 1 if the supplied elem is the default + * elem for it's type. + */ +int +elem_is_default(const pool_elem_t *res) +{ + + return (get_default_elem(res) == res); +} + +/* + * Return B_TRUE if the element has the 'temporary' property set. + */ +boolean_t +elem_is_tmp(const pool_elem_t *elem) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + uchar_t bval; + + if (pool_get_ns_property(elem, "temporary", &val) != POC_BOOL) + return (B_FALSE); + + (void) pool_value_get_bool(&val, &bval); + + return (bval != 0); +} + +/* + * get_default_elem() returns the default elem for type of the supplied + * elem. + * + * Returns A pointer to the default elem of the same type as the + * supplied elem or NULL on error. Trying to access the default elem + * for a type of element which doesn't support the notion of default + * is an error. + */ +const pool_elem_t * +get_default_elem(const pool_elem_t *pe) +{ + pool_result_set_t *rs; + pool_value_t *props[] = { NULL, NULL }; + pool_value_t val = POOL_VALUE_INITIALIZER; + char_buf_t *cb; + const pool_elem_t *pe_default; + + props[0] = &val; + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + return (NULL); + } + if (set_char_buf(cb, "%s.default", pool_elem_class_string(pe)) != + PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + if (pool_value_set_name(props[0], cb->cb_buf) != PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + free_char_buf(cb); + pool_value_set_bool(props[0], PO_TRUE); + + if ((rs = pool_exec_query(TO_CONF(pe), NULL, NULL, + PEC_QRY_ELEM(pe), props)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if (pool_rs_count(rs) != 1) { + (void) pool_rs_close(rs); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + + pe_default = rs->prs_next(rs); + (void) pool_rs_close(rs); + return (pe_default); +} + +/* + * is_a_known_prefix() determines if the supplied prop_name is a known + * name for the supplied class. + * + * Returns a pointer to the prefix if it is found or NULL + */ +const char * +is_a_known_prefix(pool_elem_class_t class, const char *prop_name) +{ + int i; + int len; + + switch (class) { + case PEC_SYSTEM: + case PEC_POOL: + len = strlen(pool_elem_class_name[class]); + if (strncmp(prop_name, pool_elem_class_name[class], len) == 0 && + prop_name[len] == '.' || strcmp(prop_name, c_type) == 0) + return (pool_elem_class_name[class]); + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + for (i = 0; i < sizeof (pool_resource_elem_class_name) / + sizeof (pool_resource_elem_class_name[0]); i++) { + len = strlen(pool_resource_elem_class_name[i]); + if (strncmp(prop_name, + pool_resource_elem_class_name[i], len) == 0 && + prop_name[len] == '.' || + strcmp(prop_name, c_type) == 0) + return (pool_resource_elem_class_name[i]); + } + break; + case PEC_COMP: + for (i = 0; i < sizeof (pool_component_elem_class_name) / + sizeof (pool_component_elem_class_name[0]); i++) { + len = strlen(pool_component_elem_class_name[i]); + if (strncmp(prop_name, + pool_component_elem_class_name[i], len) == 0 && + prop_name[len] == '.' || + strcmp(prop_name, c_type) == 0) + return (pool_component_elem_class_name[i]); + } + break; + default: + break; + } + return (NULL); +} + + +const char * +pool_elem_class_string(const pool_elem_t *pe) +{ + switch (pool_elem_class(pe)) { + case PEC_SYSTEM: + case PEC_POOL: + return (pool_elem_class_name[pool_elem_class(pe)]); + case PEC_RES_COMP: + case PEC_RES_AGG: + return (pool_resource_elem_class_name + [pool_resource_elem_class(pe)]); + case PEC_COMP: + return (pool_component_elem_class_name + [pool_component_elem_class(pe)]); + default: + return (pool_elem_class_name[PEC_INVALID]); + } +} + +const char * +pool_resource_type_string(pool_resource_elem_class_t type) +{ + return (pool_resource_elem_class_name[type]); +} + +const char * +pool_component_type_string(pool_component_elem_class_t type) +{ + return (pool_component_elem_class_name[type]); +} + +/* + * resource_by_sysid() finds a resource from it's supplied sysid and type. + * + * Returns a pointer to the resource or NULL if it doesn't exist. + */ +pool_resource_t * +resource_by_sysid(const pool_conf_t *conf, id_t sysid, const char *type) +{ + pool_value_t *props[] = { NULL, NULL, NULL }; + pool_resource_t **resources = NULL; + pool_resource_t *retval = NULL; + uint_t nelem; + char_buf_t *cb; + pool_value_t val0 = POOL_VALUE_INITIALIZER; + pool_value_t val1 = POOL_VALUE_INITIALIZER; + + props[0] = &val0; + props[1] = &val1; + + if (pool_value_set_string(props[0], type) != PO_SUCCESS || + pool_value_set_name(props[0], c_type) != PO_SUCCESS) + return (NULL); + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + return (NULL); + } + if (set_char_buf(cb, "%s.sys_id", type) != PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { + free_char_buf(cb); + return (NULL); + } + free_char_buf(cb); + pool_value_set_int64(props[1], sysid); + + resources = pool_query_resources(conf, &nelem, props); + + if (resources != NULL) { + retval = resources[0]; + free(resources); + } + return (retval); +} + +pool_elem_class_t +pool_elem_class_from_string(const char *type) +{ + int i; + + for (i = 0; i < sizeof (pool_elem_class_name) / + sizeof (pool_elem_class_name[0]); i++) { + if (strcmp(pool_elem_class_name[i], type) == 0) + break; + } + if (i == sizeof (pool_elem_class_name) / + sizeof (pool_elem_class_name[0])) + return (PEC_INVALID); + return ((pool_elem_class_t)i); +} + +pool_resource_elem_class_t +pool_resource_elem_class_from_string(const char *type) +{ + int i; + + for (i = 0; i < sizeof (pool_resource_elem_class_name) / + sizeof (pool_resource_elem_class_name[0]); i++) { + if (strcmp(pool_resource_elem_class_name[i], type) == 0) + break; + } + if (i == sizeof (pool_resource_elem_class_name) / + sizeof (pool_resource_elem_class_name[0])) + return (PREC_INVALID); + return ((pool_resource_elem_class_t)i); +} + +pool_component_elem_class_t +pool_component_elem_class_from_string(const char *type) +{ + int i; + + for (i = 0; i < sizeof (pool_component_elem_class_name) / + sizeof (pool_component_elem_class_name[0]); i++) { + if (strcmp(pool_component_elem_class_name[i], type) == 0) + break; + } + if (i == sizeof (pool_component_elem_class_name) / + sizeof (pool_component_elem_class_name[0])) + return (PCEC_INVALID); + return ((pool_component_elem_class_t)i); +} + +/* + * pool_resource_type_list() populates the supplied array of pointers + * with the names of the available resource types on this system. + */ +int +pool_resource_type_list(const char **types, uint_t *numtypes) +{ + int i, j; + uint_t maxnum = *numtypes; + + *numtypes = pool_get_provider_count(); + + if (types) { + for (i = 0, j = 0; i < sizeof (pool_resource_elem_ctl) / + sizeof (pool_resource_elem_ctl[0]) && j < maxnum; i++) { + if (pool_resource_elem_ctl[i] != NULL) + types[j++] = pool_resource_elem_class_name[i]; + } + } + return (PO_SUCCESS); +} + +/* + * Return the system element for the supplied conf. + * NULL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +pool_system_t * +pool_conf_system(const pool_conf_t *conf) +{ + pool_elem_t *system; + pool_result_set_t *rs; + + if ((rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_SYSTEM, NULL)) == + NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + /* There should only be one system record */ + if (pool_rs_count(rs) != 1) { + pool_seterror(POE_INVALID_CONF); + (void) pool_rs_close(rs); + return (NULL); + } + system = rs->prs_next(rs); + (void) pool_rs_close(rs); + return (pool_elem_system(system)); +} + +pool_system_t * +pool_elem_system(const pool_elem_t *pe) +{ + if (pe->pe_class != PEC_SYSTEM) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_system_t *)pe); +} + +pool_t * +pool_elem_pool(const pool_elem_t *pe) +{ + if (pe->pe_class != PEC_POOL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_t *)pe); +} + +pool_resource_t * +pool_elem_res(const pool_elem_t *pe) +{ + if (pe->pe_class != PEC_RES_COMP && + pool_elem_class(pe) != PEC_RES_AGG) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_resource_t *)pe); +} + +pool_component_t * +pool_elem_comp(const pool_elem_t *pe) +{ + if (pe->pe_class != PEC_COMP) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + return ((pool_component_t *)pe); +} + +/* + * qsort_elem_compare() is used for qsort elemement comparison. + * + * Returns see qsort(3c) + */ +int +qsort_elem_compare(const void *a, const void *b) +{ + const pool_elem_t *e1 = *(const pool_elem_t **)a; + const pool_elem_t *e2 = *(const pool_elem_t **)b; + + /* + * Special case for handling name changes on default elements + * If both elements are default elements then always return 0 + */ + if (pool_elem_same_class(e1, e2) == PO_TRUE && + (elem_is_default(e1) && elem_is_default(e2))) + return (0); + else + return (pool_elem_compare_name(e1, e2)); +} + +/* + * Dynamic character buffers. + */ + +/* + * Resize the supplied character buffer to the new size. + */ +static int +resize_char_buf(char_buf_t *cb, size_t size) +{ + char *re_cb = NULL; + + if ((re_cb = realloc(cb->cb_buf, size)) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* If inital allocation, make sure buffer is zeroed */ + if (cb->cb_buf == NULL) + (void) memset(re_cb, 0, sizeof (re_cb)); + /* If resized smaller, make sure buffer NULL terminated */ + if (size < cb->cb_size) + re_cb[size] = 0; + cb->cb_buf = re_cb; + cb->cb_size = size; + return (PO_SUCCESS); +} + +/* + * Allocate a new char_buf_t structure. If there isn't enough memory, return + * NULL. Initialise the new char_buf_t to 0 and then call resize_char_buf + * to initialise the character buffer. Return a pointer to the new + * char_buf_t if the operation succeeds. + */ +char_buf_t * +alloc_char_buf(size_t size) +{ + char_buf_t *cb; + + if ((cb = malloc(sizeof (char_buf_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(cb, 0, sizeof (char_buf_t)); + + if (resize_char_buf(cb, size + 1) == PO_FAIL) { + free(cb); + return (NULL); + } + return (cb); +} + +/* + * Free the character buffer and then free the char_buf_t. + */ +void +free_char_buf(char_buf_t *cb) +{ + free((void *)cb->cb_buf); + free(cb); +} + +/* + * Set the character buffer to the supplied data. The user supplies a printf + * like format string and then an appropriate number of parameters for the + * specified format. The character buffer is automatically resized to fit + * the data as determined by resize_char_buf. + */ +/*PRINTFLIKE2*/ +int +set_char_buf(char_buf_t *cb, const char *fmt, ...) +{ + va_list ap; + int new_size; + + va_start(ap, fmt); + if ((new_size = vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap)) >= + cb->cb_size) { + if (resize_char_buf(cb, new_size + 1) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap); + } + va_end(ap); + return (PO_SUCCESS); +} + +/* + * Append the supplied data to the character buffer. The user supplies a printf + * like format string and then an appropriate number of parameters for the + * specified format. The character buffer is automatically resized to fit + * the data as determined by resize_char_buf. + */ +/*PRINTFLIKE2*/ +int +append_char_buf(char_buf_t *cb, const char *fmt, ...) +{ + va_list ap; + int new_len; + char size_buf[1]; + int old_len = 0; + + if (cb->cb_buf != NULL) + old_len = strlen(cb->cb_buf); + va_start(ap, fmt); + new_len = vsnprintf(size_buf, sizeof (size_buf), fmt, ap); + if (new_len + old_len >= cb->cb_size) { + if (resize_char_buf(cb, old_len + new_len + 1) != + PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + /* + * Resized the buffer to the right size, now append the new data + */ + (void) vsnprintf(&cb->cb_buf[old_len], cb->cb_size - old_len, fmt, ap); + va_end(ap); + return (PO_SUCCESS); +} + +/* + * Return the class for the supplied elem. + * If the return is PEC_INVALID, the error code will be set to reflect cause. + */ +pool_elem_class_t +pool_elem_class(const pool_elem_t *elem) +{ + return (elem->pe_class); +} + + +/* + * Return the resource class for the supplied elem. + */ +pool_resource_elem_class_t +pool_resource_elem_class(const pool_elem_t *elem) +{ + return (elem->pe_resource_class); +} + +/* + * Return the component class for the supplied elem. + */ +pool_component_elem_class_t +pool_component_elem_class(const pool_elem_t *elem) +{ + return (elem->pe_component_class); +} + +pool_elem_t * +pool_get_pair(const pool_elem_t *pe) +{ + return (pe->pe_pair); +} + +void +pool_set_pair(pool_elem_t *pe1, pool_elem_t *pe2) +{ + pe1->pe_pair = pe2; +} + +int +pool_validate_resource(const pool_conf_t *conf, const char *type, + const char *prop, int64_t delta) +{ + pool_conf_t *dyn; + uint_t nelem; + uint64_t available, required, uval; + int i; + pool_resource_t **rl; + pool_value_t val = POOL_VALUE_INITIALIZER; + pool_value_t val1 = POOL_VALUE_INITIALIZER; + pool_value_t *pvals[] = { NULL, NULL }; + + if (strcmp(prop, c_min_prop) && strcmp(prop, c_max_prop)) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + pvals[0] = &val; + (void) pool_value_set_string(&val, type); + (void) pool_value_set_name(&val, c_type); + + /* + * Check that there are available resources on this + * system for this configuration to be applied. Find + * each resource type and then find all resources of + * each type and total ".min". Find all available + * resources and ensure >= total min. + */ + + available = 0; + required = delta; + + if ((rl = (pool_query_resources(conf, &nelem, pvals))) == NULL) + return (PO_FAIL); + + for (i = 0; i < nelem; i++) { + if (pool_get_ns_property(TO_ELEM(rl[i]), prop, + &val1) == POC_INVAL || + pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) { + free(rl); + return (PO_FAIL); + } + /* + * Watch out for overflow + */ + if (required + uval < required) { + required = UINT64_MAX; + break; + } else + required += uval; + } + + if (conf_is_dynamic(conf) == PO_TRUE) { + dyn = (pool_conf_t *)conf; + } else { + free(rl); + if ((dyn = pool_conf_alloc()) == NULL) + return (PO_FAIL); + if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDONLY) != + PO_SUCCESS) { + pool_conf_free(dyn); + return (PO_FAIL); + } + if ((rl = (pool_query_resources(dyn, &nelem, pvals))) == + NULL) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + return (PO_FAIL); + } + } + for (i = 0; i < nelem; i++) { + if (pool_get_ns_property(TO_ELEM(rl[i]), c_size_prop, + &val1) == POC_INVAL || + pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) { + free(rl); + if (conf != dyn) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + } + return (PO_FAIL); + } + available += uval; + } + free(rl); + if (conf != dyn) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + } + if (strcmp(prop, c_min_prop) == 0) { + if (available < required) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + } else { + if (available > required) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + } + return (PO_SUCCESS); +} + +/* + * If _libpool_debug is set, printf the debug message to stderr with an + * appropriate prefix in front of it. + */ +void +do_dprintf(const char *format, va_list ap) +{ + if (_libpool_debug) { + (void) fputs("libpool DEBUG: ", stderr); + (void) vfprintf(stderr, format, ap); + } +} + +/*PRINTFLIKE1*/ +void +dprintf(const char *format, ...) +{ + if (_libpool_debug) { + va_list alist; + va_start(alist, format); + do_dprintf(format, alist); + va_end(alist); + } +} + +/* + * log_alloc() allocates a new, empty transaction log. + * + * Returns a pointer to the new log or NULL on failure. + */ +log_t * +log_alloc(pool_conf_t *conf) +{ + log_t *l; + + if ((l = calloc(1, sizeof (log_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + l->l_state = LS_DO; + l->l_conf = conf; + if ((l->l_sentinel = log_item_alloc(l, 0, NULL)) + == NULL) { + free(l); + pool_seterror(POE_SYSTEM); + return (NULL); + } + l->l_sentinel->li_next = l->l_sentinel; + l->l_sentinel->li_prev = l->l_sentinel; + + return (l); +} + +/* + * log_free() reclaims the resources associated with a transaction log. + */ +void +log_free(log_t *l) +{ + (void) log_walk(l, log_item_free); + (void) log_item_free(l->l_sentinel); + free(l); +} +/* + * log_empty() removes all items from a transaction log. It is the + * users responsibility to ensure that any resources associated with + * an item are reclaimed before this function is invoked. + */ +void +log_empty(log_t *l) +{ + (void) log_walk(l, log_item_free); +} + +/* + * log_walk() visits each log item in turn and executes the supplied action + * using the item as a parameter. If no action is supplied, then the item + * uses it's own stored action. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +log_walk(log_t *l, log_item_action_t action) +{ + log_item_t *li, *li_next; + + li = l->l_sentinel->li_next; + while (li != l->l_sentinel) { + li_next = li->li_next; + if ((action(li)) != PO_SUCCESS) + return (PO_FAIL); + li = li_next; + } + return (PO_SUCCESS); +} + +/* + * log_reverse_walk() visits each log item in turn (in reverse order) + * and executes the supplied action using the item as a parameter. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +log_reverse_walk(log_t *l, log_item_action_t action) +{ + log_item_t *li, *li_prev; + + li = l->l_sentinel->li_prev; + while (li != l->l_sentinel) { + li_prev = li->li_prev; + if ((action(li)) != PO_SUCCESS) + return (PO_FAIL); + li = li_prev; + } + return (PO_SUCCESS); +} + +/* + * log_size() returns the size of the log, i.e. the number of items pending in + * the log. + */ +uint_t +log_size(log_t *l) +{ + log_item_t *li; + uint_t size = 0; + + for (li = l->l_sentinel->li_next; li != l->l_sentinel; li = li->li_next) + size++; + return (size); +} + +/* + * log_append() allocates a new log item to hold the supplied details and + * appends the newly created item to the supplied log. + * + * Returns PO_SUCCESS/PO_FAIL + */ +int +log_append(log_t *l, int op, void *details) +{ + log_item_t *li; + + if ((li = log_item_alloc(l, op, details)) == NULL) { + l->l_state = LS_UNDO; + return (PO_FAIL); + } + /* + * Link it in + */ + li->li_prev = l->l_sentinel->li_prev; + li->li_next = l->l_sentinel; + l->l_sentinel->li_prev->li_next = li; + l->l_sentinel->li_prev = li; + return (PO_SUCCESS); +} + +/* + * log_item_alloc() allocates a new transaction log item. The item should be + * used to store details about a transaction which may need to be undone if + * commit processing fails. + * + * Returns a pointer to a new transaction log item or NULL. + */ +log_item_t * +log_item_alloc(log_t *l, int op, void *details) +{ + log_item_t *li; + + if ((li = malloc(sizeof (log_item_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + + (void) memset(li, 0, sizeof (log_item_t)); + li->li_log = l; + li->li_op = op; + li->li_details = details; + li->li_state = LS_DO; + + return (li); +} + +/* + * log_item_free() reclaims the resources associated with a log_item_t. + */ +int +log_item_free(log_item_t *li) +{ + li->li_prev->li_next = li->li_next; + li->li_next->li_prev = li->li_prev; + free(li); + return (PO_SUCCESS); +} + +/* + * atom_string() checks the string table to see if a string is already + * stored. If it is, return a pointer to it. If not, duplicate the + * string and return a pointer to the duplicate. + */ +const char * +atom_string(const char *s) +{ + atom_t *atom; + + /* + * atom_init() must have completed successfully + */ + atom_init(); + (void) mutex_lock(&_atom_lock); + if ((atom = dict_get(_pv_atoms, s)) == NULL) { + if ((atom = calloc(1, sizeof (atom_t))) == NULL) { + pool_seterror(POE_SYSTEM); + (void) mutex_unlock(&_atom_lock); + return (NULL); + } + if ((atom->a_string = strdup(s)) == NULL) { + (void) mutex_unlock(&_atom_lock); + free(atom); + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) dict_put(_pv_atoms, atom->a_string, atom); + } + atom->a_count++; + (void) mutex_unlock(&_atom_lock); + return (atom->a_string); +} + +/* + * atom_free() decrements the reference count for the supplied + * string. If the reference count reaches zero, then the atom is + * destroyed. + */ +void +atom_free(const char *s) +{ + atom_t *atom; + + (void) mutex_lock(&_atom_lock); + if ((atom = dict_get(_pv_atoms, s)) != NULL) { + if (--atom->a_count == 0) { + (void) dict_remove(_pv_atoms, s); + free(atom->a_string); + free(atom); + } + } + (void) mutex_unlock(&_atom_lock); +} + +#ifdef DEBUG +/* + * log_item_dprintf() prints the contents of the supplied log item using the + * pools dprintf() trace mechanism. + * + * Returns PO_SUCCESS + */ +void +log_item_dprintf(log_item_t *li) +{ + dprintf("LOGDUMP: %d operation, %p\n", li->li_op, li->li_details); +} + +/* + * log_item_dprintf() prints the contents of the supplied log item using the + * pools dprintf() trace mechanism. + * + * Returns PO_SUCCESS + */ +void +pool_elem_dprintf(const pool_elem_t *pe) +{ + if (pool_elem_class(pe) != PEC_COMP) { + const char *name = elem_get_name(pe); + dprintf("element type: %s name: %s\n", + pool_elem_class_string(pe), name); + free((void *)name); + } else { + id_t sys_id = elem_get_sysid(pe); + dprintf("element type: %s sys_id: %d\n", + pool_elem_class_string(pe), sys_id); + } +} +#endif /* DEBUG */ diff --git a/usr/src/lib/libpool/common/pool_internal.h b/usr/src/lib/libpool/common/pool_internal.h new file mode 100644 index 0000000..e172d23 --- /dev/null +++ b/usr/src/lib/libpool/common/pool_internal.h @@ -0,0 +1,476 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _POOL_INTERNAL_H +#define _POOL_INTERNAL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libnvpair.h> +#include <stdarg.h> +#include <sys/pool.h> +#include <sys/pool_impl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains the libpool internal definitions which are not + * directly related to the data access abstraction logic. + */ + +/* + * Define the various query specifiers for use in the + * pool_connection_t query function, pc_exec_query. + */ + +#define PEC_QRY_ANY (PEC_QRY_SYSTEM | PEC_QRY_POOL | PEC_QRY_RES | \ + PEC_QRY_COMP) +#define PEC_QRY_SYSTEM (1 << PEC_SYSTEM) +#define PEC_QRY_POOL (1 << PEC_POOL) +#define PEC_QRY_RES (PEC_QRY_RES_COMP | PEC_QRY_RES_AGG) +#define PEC_QRY_RES_COMP (1 << PEC_RES_COMP) +#define PEC_QRY_RES_AGG (1 << PEC_RES_AGG) +#define PEC_QRY_COMP (1 << PEC_COMP) +#define PEC_QRY_ELEM(e) (1 << pool_elem_class(e)) + +/* + * Internal type conversion macros + */ +#define TO_ELEM(s) ((pool_elem_t *)s) +/* + * Get the configuration to which the supplied element belongs. + */ +#define TO_CONF(s) (s->pe_conf) + +/* + * Known Data Store Types + */ + +#define XML_DATA_STORE 0 +#define KERNEL_DATA_STORE 1 + +/* + * Limits on pool values names and strings + */ +#define PV_NAME_MAX_LEN 1024 +#define PV_VALUE_MAX_LEN 1024 + +/* + * CB_TAB_BUF_SIZE represents the maximum number of indents to which a + * char_buf_t is expected to grow. This value would need to be raised + * if it was ever exceeded. It is an arbitrary limit, but currently + * the implementation does not exceed a depth of 4. + */ + +#define CB_TAB_BUF_SIZE 8 +#define CB_DEFAULT_LEN 256 + +/* + * Helpful pset macros + */ +#define PSID_IS_SYSSET(psid) (psid == PS_NONE) +#define POOL_SYSID_BAD (-2) +#define POOL_SYSID_BAD_STRING "-2" + +/* + * Size of generated ref_id buffer + */ + +#define KEY_BUFFER_SIZE 48 + +/* + * Various useful constant strings which are often encountered + */ +extern const char *c_a_dtype; +extern const char *c_name; +extern const char *c_type; +extern const char *c_ref_id; +extern const char *c_max_prop; +extern const char *c_min_prop; +extern const char *c_size_prop; +extern const char *c_sys_prop; + +/* + * The char_buf_t type is a very simple string implementation which + * makes it easier to manipulate complex character data. + */ +typedef struct char_buf +{ + size_t cb_size; + char *cb_buf; + char cb_tab_buf[CB_TAB_BUF_SIZE]; +} char_buf_t; + +/* + * libpool uses an opaque discriminated union type, pool_value_t, to + * contain values which are used to get/set properties on + * configuration components. Each value is strictly typed and the + * functions to manipulate these types are exported through the + * external interface. + */ + +/* + * Initialize a pool_value_t + */ +#define POOL_VALUE_INITIALIZER /* = DEFAULT POOL VALUE */ \ + {POC_INVAL, NULL, NULL } + +struct pool_value { + pool_value_class_t pv_class; /* Value type */ + const char *pv_name; /* Value name */ + union + { + uint64_t u; + int64_t i; + double d; + uchar_t b; + const char *s; + } pv_u; +}; + +/* + * The pool_prop_op_t structure is used to perform property specific validation + * when setting the values of properties in a plugin and when getting a property + * value which is not stored (i.e. it is generated dynamically by the plugin at + * access. + * + * - ppo_get_value will provide a value for the specified property + * - ppo_set_value will allow a provider to validate a value before setting it + */ +typedef struct pool_prop_op { + int (*ppo_get_value)(const pool_elem_t *, pool_value_t *); + int (*ppo_set_value)(pool_elem_t *, const pool_value_t *); +} pool_prop_op_t; + +/* + * The pool_prop_t structure is used to hold all property related information + * for each property that a provider is interested in. + * + * - pp_pname is the name of the property + * - pp_value is the initial value of the property + * - pp_perms is an OR'd bitmap of the access characteristics for the property + * - pp_init is a function which initialises the value member of the property + * - pp_op is optional and supports access and validation of property values + */ +typedef struct pool_prop { + const char *pp_pname; + pool_value_t pp_value; + uint_t pp_perms; + int (*pp_init)(struct pool_prop *); + pool_prop_op_t pp_op; +} pool_prop_t; + +/* + * log state + */ +enum log_state { + LS_DO, + LS_UNDO, + LS_RECOVER, + LS_FAIL +}; + +/* + * Forward declaration + */ +typedef struct log log_t; + +/* + * log item. + * + * Used to describe each operation which needs to be logged. When + * modifications are desired to the kernel, they are logged in the + * configuration log file. If the user commits the changes, then the + * log entries are processed in sequence. If rollback is called, the + * log is dismissed without being processed. If the commit operation + * fails, then the log is "rolled back" to undo the previously + * successful operations. + */ +typedef struct log_item { + log_t *li_log; /* Log containing this item */ + int li_op; /* Type of operation */ + void *li_details; /* Operation details */ + struct log_item *li_next; /* List of log items */ + struct log_item *li_prev; /* List of log items */ + enum log_state li_state; /* Item state */ +} log_item_t; + +/* + * log. + * + * This maintains a list of log items. The sentinel is used to + * simplify processing around the "empty list". The state of the log + * indicates whether transactions are being processed normally, or + * whether recovery is in progress. + */ +struct log +{ + pool_conf_t *l_conf; /* Configuration for this log */ + log_item_t *l_sentinel; /* Log sentinel */ + enum log_state l_state; /* Log state */ +}; + + +/* + * log item action function type + */ +typedef int (*log_item_action_t)(log_item_t *); + +/* + * Get the max/min/size property value of a resource. + */ +extern int resource_get_max(const pool_resource_t *, uint64_t *); +extern int resource_get_min(const pool_resource_t *, uint64_t *); +extern int resource_get_size(const pool_resource_t *, uint64_t *); +extern int resource_get_pinned(const pool_resource_t *, + uint64_t *); + +/* + * Element utility operations. + */ +extern char *elem_get_name(const pool_elem_t *); +extern id_t elem_get_sysid(const pool_elem_t *); +extern int elem_is_default(const pool_elem_t *); +extern boolean_t elem_is_tmp(const pool_elem_t *); +extern const pool_elem_t *get_default_elem(const pool_elem_t *); +extern int qsort_elem_compare(const void *, const void *); + +/* + * Get the class of the supplied element. + */ +extern const char *pool_elem_class_string(const pool_elem_t *); +extern const char *pool_resource_type_string(pool_resource_elem_class_t); +extern const char *pool_component_type_string(pool_component_elem_class_t); + +/* + * Commit the supplied configuration to the system. This function + * attempts to make the system look like the supplied configuration. + */ +extern int pool_conf_commit_sys(pool_conf_t *, int); + +/* + * Allocate an XML/kernel connection to a data representation. + */ +extern int pool_xml_connection_alloc(pool_conf_t *, int); +extern int pool_knl_connection_alloc(pool_conf_t *, int); + +/* + * Create/Destroy a pool component belonging to the supplied resource + */ +extern pool_component_t *pool_component_create(pool_conf_t *, + const pool_resource_t *, int64_t); +extern int pool_component_destroy(pool_component_t *); + +/* + * Get/Set the owner (container) of a particular configuration + * element. + */ +extern pool_elem_t *pool_get_container(const pool_elem_t *); +extern int pool_set_container(pool_elem_t *, pool_elem_t *); + +/* + * These functions are used for debugging. Setting the environment + * variable LIBPOOL_DEBUG to 1, enables these functions. + */ +extern void do_dprintf(const char *, va_list); +extern void dprintf(const char *, ...); + +/* + * libpool maintains it's own error value, rather than further pollute + * errno, this function is used to set the current error value for + * retrieval. + */ +extern void pool_seterror(int); + +/* + * Element Class + */ +extern pool_elem_class_t pool_elem_class(const pool_elem_t *); +extern pool_resource_elem_class_t pool_resource_elem_class(const pool_elem_t *); +extern pool_component_elem_class_t pool_component_elem_class(const + pool_elem_t *); +extern int pool_elem_same_class(const pool_elem_t *, const pool_elem_t *); +extern pool_elem_class_t pool_elem_class_from_string(const char *); +extern pool_resource_elem_class_t pool_resource_elem_class_from_string(const + char *); +extern pool_component_elem_class_t pool_component_elem_class_from_string(const + char *); + +/* + * Element Equivalency + */ +extern int pool_elem_compare(const pool_elem_t *, + const pool_elem_t *); +extern int pool_elem_compare_name(const pool_elem_t *, + const pool_elem_t *); + +/* + * Dynamic character buffers. Limited functionality but enough for our + * purposes. + */ +extern char_buf_t *alloc_char_buf(size_t); +extern void free_char_buf(char_buf_t *); +extern int set_char_buf(char_buf_t *, const char *, ...); +extern int append_char_buf(char_buf_t *, const char *, ...); + +/* + * Internal functions for use with pool values. + */ +extern int pool_value_equal(pool_value_t *, pool_value_t *); +extern int pool_value_from_nvpair(pool_value_t *, nvpair_t *); + +/* + * Check to ensure that the supplied string is a valid name for a pool + * element. + */ +extern int is_valid_name(const char *); + +/* + * Functions related to element prefix manipulation. You can get the + * prefix for a supplied element or find out if a supplied string is a + * valid prefix for a certain class of element. + */ +extern const char *elem_get_prefix(const pool_elem_t *); +extern const char *is_a_known_prefix(pool_elem_class_t, const char *); + +/* + * Internal property manipulators + */ +extern int pool_put_ns_property(pool_elem_t *, const char *, + const pool_value_t *); +extern int pool_put_any_property(pool_elem_t *, const char *, + const pool_value_t *); +extern int pool_put_any_ns_property(pool_elem_t *, const char *, + const pool_value_t *); +extern pool_value_class_t pool_get_ns_property(const pool_elem_t *, + const char *, pool_value_t *); +extern int pool_walk_any_properties(pool_conf_t *, pool_elem_t *, + void *, int (*)(pool_conf_t *, pool_elem_t *, const char *, + pool_value_t *, void *), int); +extern int pool_set_temporary(pool_conf_t *, pool_elem_t *); + +/* + * Namespace aware utility functions. + */ +extern const char *is_ns_property(const pool_elem_t *, const char *); +extern const char *property_name_minus_ns(const pool_elem_t *, + const char *); + +/* + * Initialisation routines. + */ +extern void internal_init(void); + +/* + * Is the supplied configuration the dynamic configuration? + */ +extern int conf_is_dynamic(const pool_conf_t *); + +/* + * Update the library snapshot from the kernel + */ +extern int pool_knl_update(pool_conf_t *, int *); + +/* + * Resource property functions + */ +extern int resource_is_default(const pool_resource_t *); +extern int resource_is_system(const pool_resource_t *); +extern int resource_can_associate(const pool_resource_t *); +extern const pool_resource_t *get_default_resource(const pool_resource_t *); +extern pool_resource_t *resource_by_sysid(const pool_conf_t *, id_t, + const char *); + +/* + * Resource property provider functions + */ +extern uint_t pool_get_provider_count(void); +extern const pool_prop_t *provider_get_props(const pool_elem_t *); +extern const pool_prop_t *provider_get_prop(const pool_elem_t *, + const char *); +extern int prop_is_stored(const pool_prop_t *); +extern int prop_is_readonly(const pool_prop_t *); +extern int prop_is_init(const pool_prop_t *); +extern int prop_is_hidden(const pool_prop_t *); +extern int prop_is_optional(const pool_prop_t *); + +/* + * Component property functions + */ +extern int cpu_is_requested(pool_component_t *); + +/* + * Simple initialisation routines for values used when initialising the + * property arrays for each plugin + * Return PO_SUCCESS/PO_FAIL to indicate success/failure + */ +extern int uint_init(pool_prop_t *, uint64_t); +extern int int_init(pool_prop_t *, int64_t); +extern int double_init(pool_prop_t *, double); +extern int bool_init(pool_prop_t *, uchar_t); +extern int string_init(pool_prop_t *, const char *); + + +/* + * log functions + */ +extern log_t *log_alloc(pool_conf_t *); +extern void log_free(log_t *); +extern void log_empty(log_t *); +extern int log_walk(log_t *, log_item_action_t); +extern int log_reverse_walk(log_t *, log_item_action_t); +extern uint_t log_size(log_t *); +extern int log_append(log_t *, int, void *); + +/* + * log item functions + */ +extern log_item_t *log_item_alloc(log_t *, int, void *); +extern int log_item_free(log_item_t *); + +extern int pool_validate_resource(const pool_conf_t *, + const char *, const char *, int64_t); + +/* + * String atom functions + */ +extern const char *atom_string(const char *); +extern void atom_free(const char *); +/* + * debugging functions + */ +#ifdef DEBUG +extern void log_item_dprintf(log_item_t *); +extern void pool_value_dprintf(const pool_value_t *); +extern void pool_elem_dprintf(const pool_elem_t *); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_INTERNAL_H */ diff --git a/usr/src/lib/libpool/common/pool_kernel.c b/usr/src/lib/libpool/common/pool_kernel.c new file mode 100644 index 0000000..2e1375e --- /dev/null +++ b/usr/src/lib/libpool/common/pool_kernel.c @@ -0,0 +1,3591 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * Copyright 2012 Milan Jurik. All rights reserved. + */ + +#include <assert.h> +#include <errno.h> +#include <exacct.h> +#include <fcntl.h> +#include <libnvpair.h> +#include <limits.h> +#include <poll.h> +#include <pool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stropts.h> +#include <thread.h> +#include <time.h> +#include <unistd.h> + +#include <libxml/tree.h> + +#include <sys/mman.h> +#include <sys/pool.h> +#include <sys/pool_impl.h> +#include <sys/priocntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "dict.h" + +#include "pool_internal.h" +#include "pool_impl.h" +#include "pool_kernel_impl.h" + +/* + * libpool kernel Manipulation Routines + * + * pool_kernel.c implements the kernel manipulation routines used by the + * libpool kernel datastore. The functions are grouped into the following + * logical areas + * + */ + +/* + * Device snapshot transfer buffer size + */ +#define KERNEL_SNAPSHOT_BUF_SZ 65535 + +/* + * Kernel result set's initial size. 8 is probably large enough for + * most queries. Queries requiring more space are accomodated using + * realloc on a per result set basis. + */ +#define KERNEL_RS_INITIAL_SZ 8 + +/* + * Property manipulation macros + */ +#define KERNEL_PROP_RDONLY 0x1 + +/* + * Information required to evaluate qualifying elements for a query + */ +struct query_obj { + const pool_conf_t *conf; + const pool_elem_t *src; + const char *src_attr; + pool_elem_class_t classes; + pool_value_t **props; + pool_knl_result_set_t *rs; +}; + +/* + * Identifies a pool element with a processor set id + */ +typedef struct pool_set_xref { + pool_knl_pool_t *psx_pool; + uint_t psx_pset_id; + struct pool_set_xref *psx_next; +} pool_set_xref_t; + +/* + * Controls exacct snapshot load into libpool data structure + */ +typedef struct pool_snap_load { + int *psl_changed; + pool_set_xref_t *psl_xref; + pool_elem_t *psl_system; + pool_knl_resource_t *psl_pset; +} pool_snap_load_t; + +/* + * Information about an XML document which is being constructed + */ +struct knl_to_xml { + xmlDocPtr ktx_doc; + xmlNodePtr ktx_node; +}; + +/* + * Undo structure processing. The following structures are all used to + * allow changes to the libpool snapshot and kernel following an + * unsuccessful commit. + */ +typedef struct pool_create_undo { + pool_create_t pcu_ioctl; + pool_elem_t *pcu_elem; +} pool_create_undo_t; + +typedef struct pool_destroy_undo { + pool_destroy_t pdu_ioctl; + pool_elem_t *pdu_elem; +} pool_destroy_undo_t; + +typedef struct pool_assoc_undo { + pool_assoc_t pau_ioctl; + pool_elem_t *pau_assoc; + pool_elem_t *pau_oldres; + pool_elem_t *pau_newres; +} pool_assoc_undo_t; + +typedef struct pool_dissoc_undo { + pool_dissoc_t pdu_ioctl; + pool_elem_t *pdu_dissoc; + pool_elem_t *pdu_oldres; + pool_elem_t *pdu_newres; +} pool_dissoc_undo_t; + +typedef struct pool_xtransfer_undo { + pool_xtransfer_t pxu_ioctl; + pool_elem_t *pxu_src; + pool_elem_t *pxu_tgt; + pool_component_t **pxu_rl; +} pool_xtransfer_undo_t; + +typedef struct pool_propput_undo { + pool_propput_t ppu_ioctl; + pool_elem_t *ppu_elem; + nvlist_t *ppu_alist; + nvlist_t *ppu_blist; + uchar_t ppu_doioctl; +} pool_propput_undo_t; + +typedef struct pool_proprm_undo { + pool_proprm_t pru_ioctl; + pool_elem_t *pru_elem; + pool_value_t pru_oldval; +} pool_proprm_undo_t; + +extern const char *dtd_location; + +extern const char *element_class_tags[]; +extern const char pool_info_location[]; + +/* + * These functions are defined in pool_xml.c and represent the minimum + * XML support required to allow a pool kernel configuration to be + * exported as an XML document. + */ +extern int pool_xml_set_attr(xmlNodePtr, xmlChar *, const pool_value_t *); +extern int pool_xml_set_prop(xmlNodePtr, xmlChar *, const pool_value_t *); +extern void xml_init(void); +extern xmlNodePtr node_create(xmlNodePtr, const xmlChar *); +extern void pool_error_func(void *, const char *, ...); +/* + * Utilities + */ +static int load_group(pool_conf_t *, pool_knl_elem_t *, ea_object_t *, + pool_snap_load_t *); +static void pool_knl_elem_free(pool_knl_elem_t *, int); +static int pool_knl_put_xml_property(pool_elem_t *, xmlNodePtr, const char *, + const pool_value_t *); +static int pool_knl_snap_load_push(pool_snap_load_t *, pool_knl_pool_t *); +static int pool_knl_snap_load_update(pool_snap_load_t *, int, uint_t); +static int pool_knl_snap_load_remove(pool_snap_load_t *, int, uint_t); +static nvpair_t *pool_knl_find_nvpair(nvlist_t *, const char *); +static int pool_knl_nvlist_add_value(nvlist_t *, const char *, + const pool_value_t *); +static int pool_knl_recover(pool_conf_t *); +static uint64_t hash_id(const pool_elem_t *); +static int blocking_open(const char *, int); + +/* + * Connections + */ +static void pool_knl_connection_free(pool_knl_connection_t *); + +/* + * Configuration + */ +static int pool_knl_close(pool_conf_t *); +static int pool_knl_validate(const pool_conf_t *, pool_valid_level_t); +static int pool_knl_commit(pool_conf_t *); +static int pool_knl_export(const pool_conf_t *, const char *, + pool_export_format_t); +static int pool_knl_rollback(pool_conf_t *); +static pool_result_set_t *pool_knl_exec_query(const pool_conf_t *, + const pool_elem_t *, const char *, pool_elem_class_t, pool_value_t **); +static int pool_knl_remove(pool_conf_t *); +static char *pool_knl_get_binding(pool_conf_t *, pid_t); +static int pool_knl_set_binding(pool_conf_t *, const char *, idtype_t, id_t); +static char *pool_knl_get_resource_binding(pool_conf_t *, + pool_resource_elem_class_t, pid_t); +static int pool_knl_res_transfer(pool_resource_t *, pool_resource_t *, + uint64_t); +static int pool_knl_res_xtransfer(pool_resource_t *, pool_resource_t *, + pool_component_t **); + +/* + * Result Sets + */ +static pool_knl_result_set_t *pool_knl_result_set_alloc(const pool_conf_t *); +static int pool_knl_result_set_append(pool_knl_result_set_t *, + pool_knl_elem_t *); +static int pool_knl_result_set_realloc(pool_knl_result_set_t *); +static void pool_knl_result_set_free(pool_knl_result_set_t *); +static pool_elem_t *pool_knl_rs_next(pool_result_set_t *); +static pool_elem_t *pool_knl_rs_prev(pool_result_set_t *); +static pool_elem_t *pool_knl_rs_first(pool_result_set_t *); +static pool_elem_t *pool_knl_rs_last(pool_result_set_t *); +static int pool_knl_rs_set_index(pool_result_set_t *, int); +static int pool_knl_rs_get_index(pool_result_set_t *); +static int pool_knl_rs_count(pool_result_set_t *); +static int pool_knl_rs_close(pool_result_set_t *); + +/* + * Element (and sub-type) + */ +static pool_knl_elem_t *pool_knl_elem_wrap(pool_conf_t *, pool_elem_class_t, + pool_resource_elem_class_t, pool_component_elem_class_t); +static pool_elem_t *pool_knl_elem_create(pool_conf_t *, pool_elem_class_t, + pool_resource_elem_class_t, pool_component_elem_class_t); +static int pool_knl_elem_remove(pool_elem_t *); +static int pool_knl_set_container(pool_elem_t *, pool_elem_t *); +static pool_elem_t *pool_knl_get_container(const pool_elem_t *); +/* + * Pool element specific + */ +static int pool_knl_pool_associate(pool_t *, const pool_resource_t *); +static int pool_knl_pool_dissociate(pool_t *, const pool_resource_t *); + +/* + * Resource elements specific + */ +static int pool_knl_resource_is_system(const pool_resource_t *); +static int pool_knl_resource_can_associate(const pool_resource_t *); + +/* Properties */ +static pool_value_class_t pool_knl_get_property(const pool_elem_t *, + const char *, pool_value_t *); +static pool_value_class_t pool_knl_get_dynamic_property(const pool_elem_t *, + const char *, pool_value_t *); +static int pool_knl_put_property(pool_elem_t *, const char *, + const pool_value_t *); +static int pool_knl_rm_property(pool_elem_t *, const char *); +static pool_value_t **pool_knl_get_properties(const pool_elem_t *, uint_t *); + +/* + * Logging + */ +static int log_item_commit(log_item_t *); +static int log_item_undo(log_item_t *); +static int log_item_release(log_item_t *); + +/* + * Utilities + */ + +/* + * load_group() updates the library configuration with the kernel + * snapshot supplied in ep. The function is designed to be called + * recursively. This function depends implicitly on the ordering of + * the data provided in ep. Changes to the ordering of data in ep must + * be matched by changes to this function. + */ +int +load_group(pool_conf_t *conf, pool_knl_elem_t *elem, ea_object_t *ep, + pool_snap_load_t *psl) +{ + ea_object_t *eo; + pool_knl_elem_t *old_elem; + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + int ret = PO_SUCCESS; + + if ((ep->eo_catalog & EXD_DATA_MASK) == EXD_GROUP_SYSTEM) { + if ((elem = pool_knl_elem_wrap(conf, PEC_SYSTEM, PREC_INVALID, + PCEC_INVALID)) == NULL) + return (PO_FAIL); + if (nvlist_alloc(&elem->pke_properties, NV_UNIQUE_NAME_TYPE, + 0) != 0) { + pool_knl_elem_free(elem, PO_FALSE); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Check to see if we already have an element + * for this data. If we have, free the newly + * created elem and continue with the old one + */ + if ((old_elem = dict_get(prov->pkc_elements, elem)) != NULL) { + nvlist_free(old_elem->pke_properties); + old_elem->pke_properties = elem->pke_properties; + pool_knl_elem_free(elem, PO_FALSE); + elem = old_elem; + } else { + if (dict_put(prov->pkc_elements, elem, elem) != NULL) { + pool_knl_elem_free(elem, PO_TRUE); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + psl->psl_system = (pool_elem_t *)elem; + } + + for (eo = ep->eo_group.eg_objs; eo != NULL; eo = eo->eo_next) { + int data; + pool_knl_elem_t *prop_elem = NULL; + + data = (eo->eo_catalog & EXD_DATA_MASK); + + switch (data) { + case EXD_SYSTEM_TSTAMP: + case EXD_POOL_TSTAMP: + case EXD_PSET_TSTAMP: + case EXD_CPU_TSTAMP: + if (eo->eo_item.ei_uint64 > prov->pkc_lotime) { + if (eo->eo_item.ei_uint64 > prov->pkc_ltime) + prov->pkc_ltime = eo->eo_item.ei_uint64; + if (psl->psl_changed) { + switch (data) { + case EXD_SYSTEM_TSTAMP: + *psl->psl_changed |= POU_SYSTEM; + break; + case EXD_POOL_TSTAMP: + *psl->psl_changed |= POU_POOL; + break; + case EXD_PSET_TSTAMP: + *psl->psl_changed |= POU_PSET; + break; + case EXD_CPU_TSTAMP: + *psl->psl_changed |= POU_CPU; + break; + } + } + } + break; + case EXD_SYSTEM_PROP: + case EXD_POOL_PROP: + case EXD_PSET_PROP: + case EXD_CPU_PROP: + if (data == EXD_PSET_PROP) { + prop_elem = elem; + elem = (pool_knl_elem_t *)psl->psl_pset; + } + nvlist_free(elem->pke_properties); + if (nvlist_unpack(eo->eo_item.ei_raw, + eo->eo_item.ei_size, &elem->pke_properties, 0) != + 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + elem->pke_ltime = prov->pkc_ltime; + if (data == EXD_PSET_PROP) { + elem = prop_elem; + } + break; + case EXD_POOL_POOLID: + if (nvlist_alloc(&elem->pke_properties, + NV_UNIQUE_NAME_TYPE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (nvlist_add_int64(elem->pke_properties, + "pool.sys_id", + (int64_t)eo->eo_item.ei_uint32) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if ((old_elem = dict_get(prov->pkc_elements, elem)) != + NULL) { + nvlist_free(old_elem->pke_properties); + old_elem->pke_properties = elem->pke_properties; + pool_knl_elem_free(elem, PO_FALSE); + elem = old_elem; + } else { + if (dict_put(prov->pkc_elements, elem, elem) != + NULL) { + pool_knl_elem_free(elem, PO_TRUE); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + if (pool_knl_snap_load_push(psl, + (pool_knl_pool_t *)elem) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + ((pool_knl_pool_t *)elem)->pkp_assoc[PREC_PSET] = NULL; + break; + case EXD_POOL_PSETID: + if (pool_knl_snap_load_update(psl, EXD_POOL_PSETID, + eo->eo_item.ei_uint32) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case EXD_PSET_PSETID: + if (nvlist_alloc(&elem->pke_properties, + NV_UNIQUE_NAME_TYPE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (nvlist_add_int64(elem->pke_properties, + "pset.sys_id", + (int64_t)eo->eo_item.ei_uint32) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if ((old_elem = dict_get(prov->pkc_elements, elem)) != + NULL) { + nvlist_free(old_elem->pke_properties); + old_elem->pke_properties = elem->pke_properties; + pool_knl_elem_free(elem, PO_FALSE); + elem = old_elem; + } else { + if (dict_put(prov->pkc_elements, elem, elem) != + NULL) { + pool_knl_elem_free(elem, PO_TRUE); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + psl->psl_pset = (pool_knl_resource_t *)elem; + if (pool_knl_snap_load_remove(psl, data, + eo->eo_item.ei_uint32) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case EXD_CPU_CPUID: + if (nvlist_alloc(&elem->pke_properties, + NV_UNIQUE_NAME_TYPE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (nvlist_add_int64(elem->pke_properties, + "cpu.sys_id", + (int64_t)eo->eo_item.ei_uint32) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if ((old_elem = dict_get(prov->pkc_elements, elem)) != + NULL) { + nvlist_free(old_elem->pke_properties); + old_elem->pke_properties = elem->pke_properties; + old_elem->pke_parent = elem->pke_parent; + pool_knl_elem_free(elem, PO_FALSE); + elem = old_elem; + } else { + if (dict_put(prov->pkc_elements, elem, elem) != + NULL) { + pool_knl_elem_free(elem, PO_TRUE); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + break; + case EXD_GROUP_POOL: + if ((elem = pool_knl_elem_wrap(conf, PEC_POOL, + PREC_INVALID, PCEC_INVALID)) == NULL) + return (PO_FAIL); + if (pool_set_container(psl->psl_system, + (pool_elem_t *)elem) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case EXD_GROUP_PSET: + if ((elem = pool_knl_elem_wrap(conf, PEC_RES_COMP, + PREC_PSET, PCEC_INVALID)) == NULL) + return (PO_FAIL); + if (pool_set_container(psl->psl_system, + (pool_elem_t *)elem) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case EXD_GROUP_CPU: + if ((elem = pool_knl_elem_wrap(conf, PEC_COMP, + PREC_INVALID, PCEC_CPU)) == NULL) + return (PO_FAIL); + if (pool_set_container((pool_elem_t *)psl->psl_pset, + (pool_elem_t *)elem) != PO_SUCCESS) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + default: + break; + } + + + if (eo->eo_type == EO_GROUP) { + if ((ret = load_group(conf, elem, eo, psl)) == PO_FAIL) + break; + } + } + return (ret); +} + +/* + * Push a snapshot entry onto the list of pools in the snapshot. + */ +int +pool_knl_snap_load_push(pool_snap_load_t *psl, pool_knl_pool_t *pkp) +{ + pool_set_xref_t *psx; + + if ((psx = malloc(sizeof (pool_set_xref_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(psx, 0, sizeof (pool_set_xref_t)); + psx->psx_pool = pkp; + /* + * Push onto the list of pools + */ + psx->psx_next = psl->psl_xref; + psl->psl_xref = psx; + + return (PO_SUCCESS); +} + +/* + * Update the current cross-reference for the supplied type of + * resource. + */ +int +pool_knl_snap_load_update(pool_snap_load_t *psl, int type, uint_t id) +{ + switch (type) { + case EXD_POOL_PSETID: + psl->psl_xref->psx_pset_id = id; + break; + default: + return (PO_FAIL); + } + + return (PO_SUCCESS); +} + +/* + * Remove a resource entry with the supplied type and id from the + * snapshot list when it is no longer required. + */ +int +pool_knl_snap_load_remove(pool_snap_load_t *psl, int type, uint_t id) +{ + pool_set_xref_t *current, *prev, *next; + + for (prev = NULL, current = psl->psl_xref; current != NULL; + current = next) { + switch (type) { + case EXD_PSET_PSETID: + if (current->psx_pset_id == id) + current->psx_pool->pkp_assoc[PREC_PSET] = + psl->psl_pset; + break; + default: + return (PO_FAIL); + } + next = current->psx_next; + if (current->psx_pool->pkp_assoc[PREC_PSET] != NULL) { + if (prev != NULL) { + prev->psx_next = current->psx_next; + } else { + psl->psl_xref = current->psx_next; + } + free(current); + } else + prev = current; + } + + return (PO_SUCCESS); +} + +/* + * Return the nvpair with the supplied name from the supplied list. + * + * NULL is returned if the name cannot be found in the list. + */ +nvpair_t * +pool_knl_find_nvpair(nvlist_t *l, const char *name) +{ + nvpair_t *pair; + + for (pair = nvlist_next_nvpair(l, NULL); pair != NULL; + pair = nvlist_next_nvpair(l, pair)) { + if (strcmp(nvpair_name(pair), name) == 0) + break; + } + return (pair); +} + +/* + * Close the configuration. There are a few steps to closing a configuration: + * - Close the pseudo device + * - Free the data provider + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_knl_close(pool_conf_t *conf) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + + if (close(prov->pkc_fd) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Rollback any pending changes before freeing the prov. This + * ensures there are no memory leaks from pending transactions. + * However, don't rollback when we've done a temporary pool since the + * pool/resources haven't really been committed in this case. + * They will all be freed in pool_knl_connection_free and we don't + * want to double free them. + */ + if (!(conf->pc_prov->pc_oflags & PO_TEMP)) + (void) pool_knl_rollback(conf); + pool_knl_connection_free(prov); + return (PO_SUCCESS); +} + +/* + * Remove elements in this map (previously identified as "dead") from + * the configuration map (prov->pkc_elements). + */ + +/* ARGSUSED1 */ +static void +remove_dead_elems(const void *key, void **value, void *cl) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)key; + pool_conf_t *conf = TO_CONF(TO_ELEM(pke)); + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + + assert(dict_remove(prov->pkc_elements, pke) != NULL); +#ifdef DEBUG + dprintf("remove_dead_elems:\n"); + pool_elem_dprintf(TO_ELEM(pke)); +#endif /* DEBUG */ + pool_knl_elem_free(pke, PO_TRUE); +} + +/* + * Find elements which were not updated the last time that + * load_group() was called. Add those elements into a separate map + * (passed in cl) which will be later used to remove these elements + * from the configuration map. + */ +/* ARGSUSED1 */ +static void +find_dead_elems(const void *key, void **value, void *cl) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)key; + pool_conf_t *conf = TO_CONF(TO_ELEM(pke)); + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + dict_hdl_t *dead_map = (dict_hdl_t *)cl; + + if (pke->pke_ltime < prov->pkc_ltime) + (void) dict_put(dead_map, pke, pke); +} + +/* + * Update the snapshot held by the library. This function acts as the + * controller for the snapshot update procedure. Then snapshot is + * actually updated in multiple phases by the load_group() function + * (which updates existing elements and creates new elements as + * required) and then by find_dead_elems and remove_dead_elems + * (respectively responsible for identifying elements which are to be + * removed and then removing them). + * + * Returns PO_SUCCESS + */ +int +pool_knl_update(pool_conf_t *conf, int *changed) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + pool_query_t query = {0}; + ea_object_t *ep; + dict_hdl_t *dead_map; + pool_snap_load_t psl = { NULL }; + + /* + * Ensure the library snapshot is consistent, if there are any + * outstanding transactions return failure. + */ + if (log_size(prov->pkc_log) != 0) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + /* + * Query the kernel for a snapshot of the configuration state. Use + * load_group to allocate the user-land representation of the + * data returned in the snapshot. + */ + /* LINTED E_CONSTANT_CONDITION */ + while (1) { + if (ioctl(prov->pkc_fd, POOL_QUERY, &query) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if ((query.pq_io_buf = calloc(1, + (query.pq_io_bufsize < KERNEL_SNAPSHOT_BUF_SZ) ? + query.pq_io_bufsize * 2 : query.pq_io_bufsize)) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (ioctl(prov->pkc_fd, POOL_QUERY, &query) < 0) { + free(query.pq_io_buf); + if (errno != ENOMEM) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + query.pq_io_bufsize = 0; + query.pq_io_buf = NULL; + } else + break; + } + if (ea_unpack_object(&ep, EUP_NOALLOC, query.pq_io_buf, + query.pq_io_bufsize) != EO_GROUP) { + free(query.pq_io_buf); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + /* + * Update the library snapshot + */ + psl.psl_changed = changed; + prov->pkc_lotime = prov->pkc_ltime; + if (load_group(conf, NULL, ep, &psl) != PO_SUCCESS) { + free(query.pq_io_buf); + ea_free_object(ep, EUP_NOALLOC); + return (PO_FAIL); + } + + free(query.pq_io_buf); + ea_free_object(ep, EUP_NOALLOC); + /* + * Now search the dictionary for items that must be removed because + * they were neither created nor updated. + */ + if ((dead_map = dict_new((int (*)(const void *, const void *)) + pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + dict_map(prov->pkc_elements, find_dead_elems, dead_map); + + if (dict_length(dead_map) > 0) { + dict_map(dead_map, remove_dead_elems, NULL); + } + dict_free(&dead_map); + + return (PO_SUCCESS); +} + +/* + * Rely on the kernel to always keep a kernel configuration valid. + * Returns PO_SUCCESS + */ +/* ARGSUSED */ +int +pool_knl_validate(const pool_conf_t *conf, pool_valid_level_t level) +{ + return ((conf->pc_state == POF_INVALID) ? PO_FAIL : PO_SUCCESS); +} + +/* + * Process all the outstanding transactions in the log. If the processing + * fails, then attempt to rollback and "undo" the changes. + */ +int +pool_knl_commit(pool_conf_t *conf) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + int lock = 1; + + /* + * Lock the kernel state for the commit + */ + if (ioctl(prov->pkc_fd, POOL_COMMIT, lock) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + lock = 0; + /* + * If the state is LS_FAIL, then try to recover before + * performing the commit. + */ + if (prov->pkc_log->l_state == LS_FAIL) { + if (pool_knl_recover(conf) == PO_FAIL) { + /* + * Unlock the kernel state for the + * commit. Assert that this * can't fail, + * since if it ever does fail the library is + * unusable. + */ + assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0); + } + } + /* + * Commit the log + */ + if (log_walk(prov->pkc_log, log_item_commit) != PO_SUCCESS) { + (void) pool_knl_recover(conf); + /* + * Unlock the kernel state for the commit. Assert that + * this can't fail, since if it ever does fail the + * library is unusable. + */ + assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Unlock the kernel state for the commit. Assert that this + * can't fail, since if it ever does fail the library is + * unusable. + */ + assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0); + /* + * Release the log resources + */ + (void) log_walk(prov->pkc_log, log_item_release); + log_empty(prov->pkc_log); + return (PO_SUCCESS); +} + +/* + * prop_build_cb() is designed to be called from + * pool_walk_properties(). The property value is used to put an XML + * property on the supplied ktx_node. This is an essential part of the + * mechanism used to export a kernel configuration in libpool XML + * form. + */ +/* ARGSUSED */ +static int +prop_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name, + pool_value_t *pval, void *user) +{ + struct knl_to_xml *info = (struct knl_to_xml *)user; + + return (pool_knl_put_xml_property((pool_elem_t *)pe, info->ktx_node, + name, pval)); +} + +/* + * Duplicate some of the functionality from pool_xml_put_property() + * (see pool_xml.c) to allow a kernel configuration to add XML nodes + * to an XML tree which represents the kernel configuration. This is + * an essential part of the mechanism used to export a kernel + * configuration in libpool XML form. + */ +int +pool_knl_put_xml_property(pool_elem_t *pe, xmlNodePtr node, const char *name, + const pool_value_t *val) +{ + + /* + * "type" is a special attribute which is not visible ever outside of + * libpool. Use the specific type accessor function. + */ + if (strcmp(name, c_type) == 0) { + return (pool_xml_set_attr(node, BAD_CAST name, + val)); + } + if (is_ns_property(pe, name) != NULL) { /* in ns */ + if (pool_xml_set_attr(node, + BAD_CAST property_name_minus_ns(pe, name), val) == PO_FAIL) + return (pool_xml_set_prop(node, BAD_CAST name, + val)); + } else + return (pool_xml_set_prop(node, BAD_CAST name, val)); + return (PO_SUCCESS); +} + +/* + * Export the kernel configuration as an XML file. The configuration + * is used to build an XML document in memory. This document is then + * saved to the supplied location. + */ +int +pool_knl_export(const pool_conf_t *conf, const char *location, + pool_export_format_t fmt) +{ + xmlNodePtr node_comment; + xmlNodePtr system; + int ret; + pool_t **ps; + pool_resource_t **rs; + uint_t nelem; + int i; + struct knl_to_xml info; + char_buf_t *cb = NULL; + xmlValidCtxtPtr cvp; + + xml_init(); + + + switch (fmt) { + case POX_NATIVE: + info.ktx_doc = xmlNewDoc(BAD_CAST "1.0"); + (void) xmlCreateIntSubset(info.ktx_doc, BAD_CAST "system", + BAD_CAST "-//Sun Microsystems Inc//DTD Resource " + "Management All//EN", + BAD_CAST dtd_location); + + if ((cvp = xmlNewValidCtxt()) == NULL) { + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + /* + * Call xmlValidateDocument() to force the parsing of + * the DTD. Ignore errors and warning messages as we + * know the document isn't valid. + */ + (void) xmlValidateDocument(cvp, info.ktx_doc); + xmlFreeValidCtxt(cvp); + if ((info.ktx_node = node_create(NULL, BAD_CAST "system")) == + NULL) { + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + + system = info.ktx_node; + info.ktx_doc->_private = (void *)conf; + + (void) xmlDocSetRootElement(info.ktx_doc, info.ktx_node); + (void) xmlSetProp(info.ktx_node, BAD_CAST c_ref_id, + BAD_CAST "dummy"); + if ((node_comment = xmlNewDocComment(info.ktx_doc, + BAD_CAST "\nConfiguration for pools facility. Do NOT" + " edit this file by hand - use poolcfg(1)" + " or libpool(3POOL) instead.\n")) == NULL) { + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + if (xmlAddPrevSibling(info.ktx_node, node_comment) == NULL) { + xmlFree(node_comment); + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + if (pool_walk_any_properties((pool_conf_t *)conf, + pool_conf_to_elem(conf), &info, prop_build_cb, 1) == + PO_FAIL) { + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + /* + * Now add pool details + */ + if ((ps = pool_query_pools(conf, &nelem, NULL)) != NULL) { + for (i = 0; i < nelem; i++) { + pool_elem_t *elem = TO_ELEM(ps[i]); + uint_t nreselem; + const char *sep = ""; + int j; + + if (elem_is_tmp(elem)) + continue; + + if ((info.ktx_node = node_create(system, + BAD_CAST element_class_tags + [pool_elem_class(elem)])) == NULL) { + free(ps); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + if (pool_walk_any_properties( + (pool_conf_t *)conf, + elem, &info, prop_build_cb, 1) == PO_FAIL) { + free(ps); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + /* + * TODO: pset specific res manipulation + */ + if ((rs = pool_query_pool_resources(conf, ps[i], + &nreselem, NULL)) == NULL) { + free(ps); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + if (set_char_buf(cb, "") == PO_FAIL) { + free(rs); + free(ps); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + for (j = 0; j < nreselem; j++) { + pool_elem_t *reselem = TO_ELEM(rs[j]); + if (append_char_buf(cb, "%s%s_%d", sep, + pool_elem_class_string(reselem), + (int)elem_get_sysid(reselem)) == + PO_FAIL) { + free(rs); + free(ps); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + sep = " "; + } + free(rs); + (void) xmlSetProp(info.ktx_node, BAD_CAST "res", + BAD_CAST cb->cb_buf); + if (set_char_buf(cb, "%s_%d", + pool_elem_class_string(elem), + (int)elem_get_sysid(elem)) == PO_FAIL) { + free(ps); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + (void) xmlSetProp(info.ktx_node, + BAD_CAST c_ref_id, + BAD_CAST cb->cb_buf); + } + free(ps); + } + /* + * Now add resource details (including components) + */ + if ((rs = pool_query_resources(conf, &nelem, NULL)) != NULL) { + for (i = 0; i < nelem; i++) { + pool_elem_t *elem = TO_ELEM(rs[i]); + pool_component_t **cs = NULL; + uint_t ncompelem; + int j; + + if (elem_is_tmp(elem)) + continue; + + if ((info.ktx_node = node_create(system, + BAD_CAST element_class_tags + [pool_elem_class(elem)])) == NULL) { + free(rs); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + if (pool_walk_any_properties( + (pool_conf_t *)conf, + elem, &info, prop_build_cb, 1) == PO_FAIL) { + free(rs); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + if (set_char_buf(cb, "%s_%d", + pool_elem_class_string(elem), + (int)elem_get_sysid(elem)) == PO_FAIL) { + free(rs); + free_char_buf(cb); + xmlFreeDoc(info.ktx_doc); + return (PO_FAIL); + } + (void) xmlSetProp(info.ktx_node, + BAD_CAST c_ref_id, + BAD_CAST cb->cb_buf); + if ((cs = pool_query_resource_components(conf, + rs[i], &ncompelem, NULL)) != NULL) { + xmlNodePtr resource = info.ktx_node; + + for (j = 0; j < ncompelem; j++) { + pool_elem_t *compelem = + TO_ELEM(cs[j]); + if ((info.ktx_node = + node_create(resource, + BAD_CAST element_class_tags + [pool_elem_class( + compelem)])) == NULL) { + pool_seterror( + POE_DATASTORE); + free(rs); + free(cs); + free_char_buf(cb); + xmlFreeDoc(info. + ktx_doc); + return (PO_FAIL); + } + if (pool_walk_any_properties( + (pool_conf_t *)conf, + compelem, &info, + prop_build_cb, 1) == + PO_FAIL) { + free(rs); + free(cs); + free_char_buf(cb); + xmlFreeDoc(info. + ktx_doc); + return (PO_FAIL); + } + if (set_char_buf(cb, "%s_%d", + pool_elem_class_string( + compelem), + (int)elem_get_sysid( + compelem)) == PO_FAIL) { + free(rs); + free(cs); + free_char_buf(cb); + xmlFreeDoc(info. + ktx_doc); + return (PO_FAIL); + } + (void) xmlSetProp(info.ktx_node, + BAD_CAST c_ref_id, + BAD_CAST cb->cb_buf); + } + free(cs); + } + } + free(rs); + } + free_char_buf(cb); + /* + * Set up the message handlers prior to calling + * xmlValidateDocument() + */ + if ((cvp = xmlNewValidCtxt()) == NULL) { + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + cvp->error = pool_error_func; + cvp->warning = pool_error_func; + if (xmlValidateDocument(cvp, info.ktx_doc) == 0) { + xmlFreeValidCtxt(cvp); + xmlFreeDoc(info.ktx_doc); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + xmlFreeValidCtxt(cvp); + ret = xmlSaveFormatFile(location, info.ktx_doc, 1); + xmlFreeDoc(info.ktx_doc); + if (ret == -1) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + return (PO_SUCCESS); + default: + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } +} + +/* + * Rollback the changes to the kernel + */ +int +pool_knl_recover(pool_conf_t *conf) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + + prov->pkc_log->l_state = LS_RECOVER; + if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) { + dprintf("Library configuration consistency error\n"); + prov->pkc_log->l_state = LS_FAIL; + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + prov->pkc_log->l_state = LS_DO; + return (PO_SUCCESS); +} + +/* + * Rollback the changes to the configuration + */ +int +pool_knl_rollback(pool_conf_t *conf) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + + prov->pkc_log->l_state = LS_UNDO; + if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) { + dprintf("Kernel configuration consistency error\n"); + (void) log_walk(prov->pkc_log, log_item_release); + log_empty(prov->pkc_log); + prov->pkc_log->l_state = LS_FAIL; + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + (void) log_walk(prov->pkc_log, log_item_release); + log_empty(prov->pkc_log); + prov->pkc_log->l_state = LS_DO; + return (PO_SUCCESS); +} + +/* + * Callback used to build the result set for a query. Each invocation will + * supply a candidate element for inclusion. The element is filtered by: + * - class + * - properties + * If the element "matches" the target, then it is added to the result + * set, otherwise it is ignored. + */ +/* ARGSUSED1 */ +static void +build_result_set(const void *key, void **value, void *cl) +{ + struct query_obj *qo = (struct query_obj *)cl; + pool_knl_elem_t *pke = (pool_knl_elem_t *)key; + + /* + * Check to see if it's the right class of element + */ + if (qo->classes & (1 << pool_elem_class((pool_elem_t *)key))) { + int i; + /* + * Now check to see if the src element is correct. If no src + * element is supplied, ignore this check + */ + if (qo->src) { + pool_knl_elem_t *parent; + + for (parent = pke; parent != NULL; + parent = parent->pke_parent) { + if (parent == (pool_knl_elem_t *)qo->src) + break; + } + if (parent == NULL) + return; + } + /* + * Now check for property matches (if there are any specified) + */ + if (qo->props) { + int matched = PO_TRUE; + for (i = 0; qo->props[i] != NULL; i++) { + pool_value_t val = POOL_VALUE_INITIALIZER; + + if (pool_get_property(TO_CONF(TO_ELEM(pke)), + (pool_elem_t *)pke, + pool_value_get_name(qo->props[i]), &val) == + POC_INVAL) { + matched = PO_FALSE; + break; + } else { + if (pool_value_equal(qo->props[i], + &val) != PO_TRUE) { + matched = PO_FALSE; + break; + } + } + } + if (matched == PO_TRUE) + (void) pool_knl_result_set_append(qo->rs, + (pool_knl_elem_t *)key); + } else { + (void) pool_knl_result_set_append(qo->rs, + (pool_knl_elem_t *)key); + } + } +} + +/* + * Execute the supplied query and return a result set which contains + * all qualifying elements. + */ +pool_result_set_t * +pool_knl_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) +{ + pool_knl_result_set_t *rs; + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + struct query_obj qo; + int matched = PO_TRUE; + + /* + * Have a buffer at this point, that we can use + */ + if ((rs = pool_knl_result_set_alloc(conf)) == NULL) { + return (NULL); + } + qo.conf = conf; + qo.src = src; + qo.src_attr = src_attr; + qo.classes = classes; + qo.props = props; + qo.rs = rs; + if (src_attr != NULL) { + pool_knl_pool_t *pkp = (pool_knl_pool_t *)src; + + /* + * Note: This logic is resource specific and must be + * extended for additional resource types. + */ + /* + * Check for property matches (if there are any specified) + */ + if (props) { + int i; + + for (i = 0; props[i] != NULL; i++) { + pool_value_t val = POOL_VALUE_INITIALIZER; + + if (pool_get_property(conf, + (pool_elem_t *)pkp->pkp_assoc[PREC_PSET], + pool_value_get_name(props[i]), &val) == + POC_INVAL) { + matched = PO_FALSE; + break; + } else { + if (pool_value_equal(props[i], + &val) != PO_TRUE) { + matched = PO_FALSE; + break; + } + } + } + } + + if (matched == PO_TRUE) + (void) pool_knl_result_set_append(rs, + (pool_knl_elem_t *)pkp->pkp_assoc[PREC_PSET]); + } else + dict_map(prov->pkc_elements, build_result_set, &qo); + + if (rs->pkr_count == 0) + pool_seterror(POE_INVALID_SEARCH); + return ((pool_result_set_t *)rs); +} + +/* + * Callback function intended to be used from pool_walk_pools(). If + * the supplied pool is not the default pool attempt to destroy it. + */ +/*ARGSUSED*/ +static int +destroy_pool_cb(pool_conf_t *conf, pool_t *pool, void *unused) +{ + if (elem_is_default(TO_ELEM(pool)) != PO_TRUE) + return (pool_destroy(conf, pool)); + /* + * Return PO_SUCCESS even though we don't delete the default + * pool so that the walk continues + */ + return (PO_SUCCESS); +} + +/* + * Remove the configuration details. This means remove all elements + * apart from the system elements. + */ +int +pool_knl_remove(pool_conf_t *conf) +{ + uint_t i, nelem; + pool_resource_t **resources; + + conf->pc_state = POF_DESTROY; + if ((resources = pool_query_resources(conf, &nelem, NULL)) != NULL) { + for (i = 0; i < nelem; i++) { + if (resource_is_system(resources[i]) == PO_FALSE) + if (pool_resource_destroy(conf, resources[i]) != + PO_SUCCESS) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + } + free(resources); + } + (void) pool_walk_pools(conf, conf, destroy_pool_cb); + if (pool_conf_commit(conf, PO_FALSE) != PO_SUCCESS) + return (PO_FAIL); + + if (pool_conf_close(conf) != PO_SUCCESS) + return (PO_FAIL); + + return (PO_SUCCESS); +} + +/* + * Determine the name of the pool to which the supplied pid is + * bound. If it cannot be determined return NULL. + */ +char * +pool_knl_get_binding(pool_conf_t *conf, pid_t pid) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + const char *sval; + char *name = NULL; + pool_bindq_t bindq; + pool_value_t *props[] = { NULL, NULL }; + uint_t nelem = 0; + pool_t **pools; + pool_value_t val = POOL_VALUE_INITIALIZER; + + props[0] = &val; + + bindq.pb_o_id_type = P_PID; + bindq.pb_o_id = pid; + if (ioctl(prov->pkc_fd, POOL_BINDQ, &bindq) < 0) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + + if (pool_value_set_name(props[0], "pool.sys_id") != PO_SUCCESS) { + return (NULL); + } + pool_value_set_int64(props[0], bindq.pb_i_id); + if ((pools = pool_query_pools(conf, &nelem, props)) == NULL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (nelem != 1) { + free(pools); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if (pool_get_ns_property(TO_ELEM(pools[0]), c_name, props[0]) + == POC_INVAL) { + free(pools); + return (NULL); + } + if (pool_value_get_string(props[0], &sval) != PO_SUCCESS) { + free(pools); + return (NULL); + } + if ((name = strdup(sval)) == NULL) { + free(pools); + pool_seterror(POE_SYSTEM); + return (NULL); + } + return (name); +} + +/* + * Bind idtype id to the pool name. + */ +int +pool_knl_set_binding(pool_conf_t *conf, const char *pool_name, idtype_t idtype, + id_t id) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + pool_bind_t bind; + pool_t *pool; + int ret; + + if ((pool = pool_get_pool(conf, pool_name)) == NULL) + return (PO_FAIL); + + bind.pb_o_id_type = idtype; + bind.pb_o_id = id; + bind.pb_o_pool_id = elem_get_sysid(TO_ELEM(pool)); + + while ((ret = ioctl(prov->pkc_fd, POOL_BIND, &bind)) < 0 && + errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * pool_knl_get_resource_binding() returns the binding for a pid to + * the supplied type of resource. If a binding cannot be determined, + * NULL is returned. + */ +char * +pool_knl_get_resource_binding(pool_conf_t *conf, + pool_resource_elem_class_t type, pid_t pid) +{ + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + const char *sval; + char *name = NULL; + pool_bindq_t bindq; + pool_value_t *props[] = { NULL, NULL }; + uint_t nelem = 0; + pool_t **pools; + pool_resource_t **resources; + pool_value_t val = POOL_VALUE_INITIALIZER; + + props[0] = &val; + bindq.pb_o_id_type = P_PID; + bindq.pb_o_id = pid; + if (ioctl(prov->pkc_fd, POOL_BINDQ, &bindq) < 0) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + + if (pool_value_set_name(props[0], "pool.sys_id") != PO_SUCCESS) { + return (NULL); + } + pool_value_set_int64(props[0], bindq.pb_i_id); + if ((pools = pool_query_pools(conf, &nelem, props)) == NULL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if (nelem != 1) { + free(pools); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + + if (pool_value_set_string(props[0], pool_resource_type_string(type)) != + PO_SUCCESS || + pool_value_set_name(props[0], c_type) != PO_SUCCESS) { + free(pools); + return (NULL); + } + + if ((resources = pool_query_pool_resources(conf, pools[0], &nelem, + NULL)) == NULL) { + free(pools); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + free(pools); + if (nelem != 1) { + free(resources); + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if (pool_get_ns_property(TO_ELEM(resources[0]), c_name, props[0]) == + POC_INVAL) { + free(resources); + return (NULL); + } + free(resources); + if (pool_value_get_string(props[0], &sval) != PO_SUCCESS) { + return (NULL); + } + if ((name = strdup(sval)) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + return (name); +} + +/* + * Allocate the required library data structure and initialise it. + */ +pool_knl_elem_t * +pool_knl_elem_wrap(pool_conf_t *conf, pool_elem_class_t class, + pool_resource_elem_class_t res_class, + pool_component_elem_class_t comp_class) +{ + pool_knl_elem_t *elem; + pool_elem_t *pe; + + switch (class) { + case PEC_SYSTEM: + if ((elem = malloc(sizeof (pool_knl_system_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_knl_system_t)); + break; + case PEC_POOL: + if ((elem = malloc(sizeof (pool_knl_pool_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_knl_pool_t)); + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + if ((elem = malloc(sizeof (pool_knl_resource_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_knl_resource_t)); + break; + case PEC_COMP: + if ((elem = malloc(sizeof (pool_knl_component_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_knl_component_t)); + break; + default: + pool_seterror(POE_BADPARAM); + return (NULL); + } + pe = TO_ELEM(elem); + pe->pe_conf = conf; + pe->pe_class = class; + pe->pe_resource_class = res_class; + pe->pe_component_class = comp_class; + /* Set up the function pointers for element manipulation */ + pe->pe_get_prop = pool_knl_get_property; + pe->pe_put_prop = pool_knl_put_property; + pe->pe_rm_prop = pool_knl_rm_property; + pe->pe_get_props = pool_knl_get_properties; + pe->pe_remove = pool_knl_elem_remove; + pe->pe_get_container = pool_knl_get_container; + pe->pe_set_container = pool_knl_set_container; + /* + * Specific initialisation for different types of element + */ + if (class == PEC_POOL) { + pool_knl_pool_t *pp = (pool_knl_pool_t *)elem; + pp->pp_associate = pool_knl_pool_associate; + pp->pp_dissociate = pool_knl_pool_dissociate; + pp->pkp_assoc[PREC_PSET] = (pool_knl_resource_t *) + resource_by_sysid(conf, PS_NONE, "pset"); + } + if (class == PEC_RES_COMP || class == PEC_RES_AGG) { + pool_knl_resource_t *pr = (pool_knl_resource_t *)elem; + pr->pr_is_system = pool_knl_resource_is_system; + pr->pr_can_associate = pool_knl_resource_can_associate; + } +#if DEBUG + if (dict_put(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks, + elem, elem) != NULL) + assert(!"leak map put failed"); + dprintf("allocated %p\n", elem); +#endif /* DEBUG */ + return (elem); +} + +/* + * Allocate a new pool_knl_elem_t in the supplied configuration of the + * specified class. + * Returns element pointer/NULL + */ +pool_elem_t * +pool_knl_elem_create(pool_conf_t *conf, pool_elem_class_t class, + pool_resource_elem_class_t res_class, + pool_component_elem_class_t comp_class) +{ + pool_knl_elem_t *elem; + pool_create_undo_t *create; + pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; + static int id = -3; + char_buf_t *cb; + + if ((elem = pool_knl_elem_wrap(conf, class, res_class, comp_class)) == + NULL) + return (NULL); + + /* + * Allocate an nvlist to hold properties + */ + if (nvlist_alloc(&elem->pke_properties, NV_UNIQUE_NAME_TYPE, 0) != 0) { + pool_knl_elem_free(elem, PO_FALSE); + pool_seterror(POE_SYSTEM); + return (NULL); + } + /* + * Allocate a temporary ID and name until the element is + * created for real + */ + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + pool_knl_elem_free(elem, PO_TRUE); + return (NULL); + } + if (set_char_buf(cb, "%s.sys_id", + pool_elem_class_string((pool_elem_t *)elem)) != PO_SUCCESS) { + pool_knl_elem_free(elem, PO_TRUE); + free_char_buf(cb); + return (NULL); + } + (void) nvlist_add_int64(elem->pke_properties, cb->cb_buf, id--); + if (set_char_buf(cb, "%s.name", + pool_elem_class_string((pool_elem_t *)elem)) != PO_SUCCESS) { + pool_knl_elem_free(elem, PO_TRUE); + free_char_buf(cb); + return (NULL); + } + (void) nvlist_add_string(elem->pke_properties, cb->cb_buf, ""); + /* + * If it's a resource class, it will need an initial size + */ + if (class == PEC_RES_COMP || class == PEC_RES_AGG) { + if (set_char_buf(cb, "%s.size", + pool_elem_class_string((pool_elem_t *)elem)) != + PO_SUCCESS) { + pool_knl_elem_free(elem, PO_TRUE); + free_char_buf(cb); + return (NULL); + } + (void) nvlist_add_uint64(elem->pke_properties, cb->cb_buf, 0); + } + free_char_buf(cb); + + /* + * Register the newly created element + */ + if (dict_put(prov->pkc_elements, elem, elem) != NULL) { + pool_knl_elem_free(elem, PO_TRUE); + pool_seterror(POE_SYSTEM); + return (NULL); + } + + if (prov->pkc_log->l_state != LS_DO) + return ((pool_elem_t *)elem); + + /* + * The remaining logic is setting up the arguments for the + * POOL_CREATE ioctl and appending the details into the log. + */ + if ((create = malloc(sizeof (pool_create_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + create->pcu_ioctl.pc_o_type = class; + switch (class) { + case PEC_SYSTEM: + pool_seterror(POE_BADPARAM); + free(create); + return (NULL); + case PEC_POOL: /* NO-OP */ + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + create->pcu_ioctl.pc_o_sub_type = res_class; + break; + case PEC_COMP: + create->pcu_ioctl.pc_o_sub_type = comp_class; + break; + default: + pool_seterror(POE_BADPARAM); + free(create); + return (NULL); + } + + create->pcu_elem = (pool_elem_t *)elem; + + if (log_append(prov->pkc_log, POOL_CREATE, (void *)create) != + PO_SUCCESS) { + free(create); + return (NULL); + } + return ((pool_elem_t *)elem); +} + +/* + * Remove the details of the element from our userland copy and destroy + * the element (if appropriate) in the kernel. + */ +int +pool_knl_elem_remove(pool_elem_t *pe) +{ + pool_knl_connection_t *prov; + pool_destroy_undo_t *destroy; + + prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; + + if (dict_remove(prov->pkc_elements, pe) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (prov->pkc_log->l_state != LS_DO) { + return (PO_SUCCESS); + } + + /* + * The remaining logic is setting up the arguments for the + * POOL_DESTROY ioctl and appending the details into the log. + */ + if ((destroy = malloc(sizeof (pool_destroy_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + destroy->pdu_ioctl.pd_o_type = pool_elem_class(pe); + + if (destroy->pdu_ioctl.pd_o_type == PEC_RES_COMP || + destroy->pdu_ioctl.pd_o_type == PEC_RES_AGG) + destroy->pdu_ioctl.pd_o_sub_type = pool_resource_elem_class(pe); + + if (destroy->pdu_ioctl.pd_o_type == PEC_COMP) + destroy->pdu_ioctl.pd_o_sub_type = + pool_component_elem_class(pe); + + destroy->pdu_elem = pe; + + if (log_append(prov->pkc_log, POOL_DESTROY, (void *)destroy) != + PO_SUCCESS) { + free(destroy); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Set the parent of the supplied child to the supplied parent + */ +int +pool_knl_set_container(pool_elem_t *pp, pool_elem_t *pc) +{ + pool_knl_elem_t *pkp = (pool_knl_elem_t *)pp; + pool_knl_elem_t *pkc = (pool_knl_elem_t *)pc; + + pkc->pke_parent = pkp; + return (PO_SUCCESS); +} + +/* + * TODO: Needed for msets and ssets. + */ +/* ARGSUSED */ +int +pool_knl_res_transfer(pool_resource_t *src, pool_resource_t *tgt, + uint64_t size) { + return (PO_FAIL); +} + +/* + * Transfer resource components from one resource set to another. + */ +int +pool_knl_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt, + pool_component_t **rl) { + pool_elem_t *src_e = TO_ELEM(src); + pool_elem_t *tgt_e = TO_ELEM(tgt); + pool_xtransfer_undo_t *xtransfer; + size_t size; + pool_knl_connection_t *prov = + (pool_knl_connection_t *)TO_CONF(src_e)->pc_prov; + + if (prov->pkc_log->l_state != LS_DO) { + /* + * Walk the Result Set and move the resource components + */ + for (size = 0; rl[size] != NULL; size++) { + if (pool_set_container(TO_ELEM(tgt), + TO_ELEM(rl[size])) == PO_FAIL) { + return (PO_FAIL); + } + } + return (PO_SUCCESS); + } + + /* + * The remaining logic is setting up the arguments for the + * POOL_XTRANSFER ioctl and appending the details into the log. + */ + if ((xtransfer = malloc(sizeof (pool_xtransfer_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if (pool_elem_class(src_e) == PEC_RES_COMP) { + xtransfer->pxu_ioctl.px_o_id_type = + pool_resource_elem_class(src_e); + } else { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + + for (xtransfer->pxu_ioctl.px_o_complist_size = 0; + rl[xtransfer->pxu_ioctl.px_o_complist_size] != NULL; + xtransfer->pxu_ioctl.px_o_complist_size++) + /* calculate the size using the terminating NULL */; + if ((xtransfer->pxu_ioctl.px_o_comp_list = + calloc(xtransfer->pxu_ioctl.px_o_complist_size, + sizeof (id_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if ((xtransfer->pxu_rl = calloc( + xtransfer->pxu_ioctl.px_o_complist_size + 1, + sizeof (pool_component_t *))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memcpy(xtransfer->pxu_rl, rl, + xtransfer->pxu_ioctl.px_o_complist_size * + sizeof (pool_component_t *)); + xtransfer->pxu_src = src_e; + xtransfer->pxu_tgt = tgt_e; + + if (log_append(prov->pkc_log, POOL_XTRANSFER, (void *)xtransfer) != + PO_SUCCESS) { + free(xtransfer); + return (PO_FAIL); + } + for (size = 0; rl[size] != NULL; size++) { + if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[size])) == + PO_FAIL) { + return (PO_FAIL); + } + } + return (PO_SUCCESS); +} + +/* + * Return the parent of an element. + */ +pool_elem_t * +pool_knl_get_container(const pool_elem_t *pe) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; + + return ((pool_elem_t *)pke->pke_parent); +} + +/* + * Note: This function is resource specific, needs extending for other + * resource types + */ +int +pool_knl_resource_is_system(const pool_resource_t *pr) +{ + switch (pool_resource_elem_class(TO_ELEM(pr))) { + case PREC_PSET: + return (PSID_IS_SYSSET( + elem_get_sysid(TO_ELEM(pr)))); + default: + return (PO_FALSE); + } +} + +/* + * Note: This function is resource specific, needs extending for other + * resource types + */ +int +pool_knl_resource_can_associate(const pool_resource_t *pr) +{ + switch (pool_resource_elem_class(TO_ELEM(pr))) { + case PREC_PSET: + return (PO_TRUE); + default: + return (PO_FALSE); + } +} + +/* + * pool_knl_pool_associate() associates the supplied resource to the + * supplied pool. + * + * Returns: PO_SUCCESS/PO_FAIL + */ +int +pool_knl_pool_associate(pool_t *pool, const pool_resource_t *resource) +{ + pool_knl_connection_t *prov; + pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool; + pool_resource_elem_class_t res_class = + pool_resource_elem_class(TO_ELEM(resource)); + pool_assoc_undo_t *assoc; + pool_knl_resource_t *orig_res = pkp->pkp_assoc[res_class]; + + /* + * Are we allowed to associate with this target? + */ + if (pool_knl_resource_can_associate(resource) == PO_FALSE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov; + + if (prov->pkc_log->l_state != LS_DO) { + pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource; + return (PO_SUCCESS); + } + + /* + * The remaining logic is setting up the arguments for the + * POOL_ASSOC ioctl and appending the details into the log. + */ + if ((assoc = malloc(sizeof (pool_assoc_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + assoc->pau_assoc = TO_ELEM(pool); + assoc->pau_oldres = (pool_elem_t *)orig_res; + assoc->pau_newres = TO_ELEM(resource); + + assoc->pau_ioctl.pa_o_id_type = res_class; + + if (log_append(prov->pkc_log, POOL_ASSOC, (void *)assoc) != + PO_SUCCESS) { + free(assoc); + pkp->pkp_assoc[res_class] = orig_res; + return (PO_FAIL); + } + pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource; + return (PO_SUCCESS); +} + +/* + * pool_knl_pool_dissociate() dissociates the supplied resource from + * the supplied pool. + * + * Returns: PO_SUCCESS/PO_FAIL + */ +int +pool_knl_pool_dissociate(pool_t *pool, const pool_resource_t *resource) +{ + pool_knl_connection_t *prov; + pool_dissoc_undo_t *dissoc; + pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool; + pool_resource_t *default_res = (pool_resource_t *)get_default_resource( + resource); + pool_resource_elem_class_t res_class = + pool_resource_elem_class(TO_ELEM(resource)); + + prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov; + + if (prov->pkc_log->l_state != LS_DO) { + pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res; + return (PO_SUCCESS); + } + /* + * The remaining logic is setting up the arguments for the + * POOL_DISSOC ioctl and appending the details into the log. + */ + if ((dissoc = malloc(sizeof (pool_dissoc_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + dissoc->pdu_dissoc = TO_ELEM(pool); + dissoc->pdu_oldres = TO_ELEM(resource); + dissoc->pdu_newres = TO_ELEM(default_res); + + dissoc->pdu_ioctl.pd_o_id_type = res_class; + + if (log_append(prov->pkc_log, POOL_DISSOC, (void *)dissoc) != + PO_SUCCESS) { + free(dissoc); + pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource; + return (PO_FAIL); + } + + /* + * Update our local copy + */ + pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res; + return (PO_SUCCESS); +} + +/* + * Allocate a data provider for the supplied configuration and optionally + * discover resources. + * The data provider is the cross over point from the "abstract" configuration + * functions into the data representation specific manipulation routines. + * This function sets up all the required pointers to create a kernel aware + * data provider. + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_knl_connection_alloc(pool_conf_t *conf, int oflags) +{ + pool_knl_connection_t *prov; + + if ((prov = malloc(sizeof (pool_knl_connection_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(prov, 0, sizeof (pool_knl_connection_t)); + /* + * Initialise data members + */ + prov->pc_name = strdup("kernel"); + prov->pc_store_type = KERNEL_DATA_STORE; + prov->pc_oflags = oflags; + /* + * Initialise function pointers + */ + prov->pc_close = pool_knl_close; + prov->pc_validate = pool_knl_validate; + prov->pc_commit = pool_knl_commit; + prov->pc_export = pool_knl_export; + prov->pc_rollback = pool_knl_rollback; + prov->pc_exec_query = pool_knl_exec_query; + prov->pc_elem_create = pool_knl_elem_create; + prov->pc_remove = pool_knl_remove; + prov->pc_res_xfer = pool_knl_res_transfer; + prov->pc_res_xxfer = pool_knl_res_xtransfer; + prov->pc_get_binding = pool_knl_get_binding; + prov->pc_set_binding = pool_knl_set_binding; + prov->pc_get_resource_binding = pool_knl_get_resource_binding; + /* + * Associate the provider to it's configuration + */ + conf->pc_prov = (pool_connection_t *)prov; + /* + * End of common initialisation + */ + /* + * Attempt to open the pseudo device, if the configuration is opened + * readonly then try to open an info device, otherwise try to open + * the writeable device. + */ + if (oflags & PO_RDWR) { + if ((prov->pkc_fd = blocking_open(pool_dynamic_location(), + O_RDWR)) < 0) { + free(prov); + conf->pc_prov = NULL; + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } else { + if ((prov->pkc_fd = open(pool_info_location, O_RDWR)) < 0) { + free(prov); + conf->pc_prov = NULL; + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + /* + * Allocate the element dictionary + */ + if ((prov->pkc_elements = dict_new((int (*)(const void *, const void *)) + pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) { + (void) close(prov->pkc_fd); + free(prov); + conf->pc_prov = NULL; + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } +#if DEBUG + if ((prov->pkc_leaks = dict_new(NULL, NULL)) == NULL) { + dict_free(&prov->pkc_elements); + (void) close(prov->pkc_fd); + free(prov); + conf->pc_prov = NULL; + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } +#endif /* DEBUG */ + /* + * Allocate the transaction log + */ + if ((prov->pkc_log = log_alloc(conf)) == NULL) { +#if DEBUG + dict_free(&prov->pkc_leaks); +#endif /* DEBUG */ + dict_free(&prov->pkc_elements); + (void) close(prov->pkc_fd); + free(prov); + conf->pc_prov = NULL; + return (PO_FAIL); + } + /* + * At this point the configuration provider has been initialized, + * mark the configuration as valid so that the various routines + * which rely on a valid configuration will work correctly. + */ + conf->pc_state = POF_VALID; + /* + * Update the library snapshot from the kernel + */ + if (pool_knl_update(conf, NULL) != PO_SUCCESS) { +#if DEBUG + dict_free(&prov->pkc_leaks); +#endif /* DEBUG */ + dict_free(&prov->pkc_elements); + (void) close(prov->pkc_fd); + free(prov); + conf->pc_prov = NULL; + conf->pc_state = POF_INVALID; + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +#if DEBUG +static void +pool_knl_elem_printf_cb(const void *key, void **value, void *cl) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)key; + dict_hdl_t *map = (dict_hdl_t *)cl; + + dprintf("leak elem:%p\n", pke); + if (pke->pke_properties != NULL) { + nvlist_print(stdout, pke->pke_properties); + } else + dprintf("no properties\n"); + assert(dict_get(map, pke) == NULL); +} +#endif /* DEBUG */ +/* + * pool_knl_elem_free() releases the resources associated with the + * supplied element. + */ +static void +pool_knl_elem_free(pool_knl_elem_t *pke, int freeprop) +{ +#if DEBUG + pool_conf_t *conf = TO_CONF(TO_ELEM(pke)); + if (dict_remove(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks, + pke) == NULL) + dprintf("%p, wasn't in the leak map\n", pke); + if (freeprop == PO_TRUE) { + pool_elem_dprintf(TO_ELEM(pke)); + } + dprintf("released %p\n", pke); +#endif /* DEBUG */ + if (freeprop == PO_TRUE) { + nvlist_free(pke->pke_properties); + } + free(pke); +} + +/* + * pool_knl_elem_free_cb() is designed to be used with + * dict_map(). When a connection is freed, this function is used to + * free all element resources. + */ +/* ARGSUSED1 */ +static void +pool_knl_elem_free_cb(const void *key, void **value, void *cl) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)key; + +#ifdef DEBUG + dprintf("pool_knl_elem_free_cb:\n"); + dprintf("about to release %p ", pke); + pool_elem_dprintf(TO_ELEM(pke)); +#endif /* DEBUG */ + pool_knl_elem_free(pke, PO_TRUE); +} + +/* + * Free the resources for a kernel data provider. + */ +void +pool_knl_connection_free(pool_knl_connection_t *prov) +{ + if (prov->pkc_log != NULL) { + (void) log_walk(prov->pkc_log, log_item_release); + log_free(prov->pkc_log); + } + if (prov->pkc_elements != NULL) { + dict_map(prov->pkc_elements, pool_knl_elem_free_cb, NULL); +#if DEBUG + dprintf("dict length is %llu\n", dict_length(prov->pkc_leaks)); + dict_map(prov->pkc_leaks, pool_knl_elem_printf_cb, + prov->pkc_elements); + assert(dict_length(prov->pkc_leaks) == 0); + dict_free(&prov->pkc_leaks); +#endif /* DEBUG */ + dict_free(&prov->pkc_elements); + } + free((void *)prov->pc_name); + free(prov); +} + +/* + * Return the specified property value. + * + * POC_INVAL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +pool_value_class_t +pool_knl_get_property(const pool_elem_t *pe, const char *name, + pool_value_t *val) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; + nvpair_t *pair; + const pool_prop_t *prop; + + if ((prop = provider_get_prop(pe, name)) != NULL) + if (prop_is_stored(prop) == PO_FALSE) + return (pool_knl_get_dynamic_property(pe, name, val)); + + if ((pair = pool_knl_find_nvpair(pke->pke_properties, name)) == NULL) { + pool_seterror(POE_BADPARAM); + return (POC_INVAL); + } + + if (pool_value_from_nvpair(val, pair) == PO_FAIL) { + return (POC_INVAL); + } + + return (pool_value_get_type(val)); +} + +/* + * Return the specified property value. + * + * If a property is designated as dynamic, then this function will + * always try to return the latest value of the property from the + * kernel. + * + * POC_INVAL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +pool_value_class_t +pool_knl_get_dynamic_property(const pool_elem_t *pe, const char *name, + pool_value_t *val) +{ + pool_knl_connection_t *prov; + pool_propget_t propget = { 0 }; + nvlist_t *proplist; + nvpair_t *pair; + + propget.pp_o_id_type = pool_elem_class(pe); + if (pool_elem_class(pe) == PEC_RES_COMP || + pool_elem_class(pe) == PEC_RES_AGG) + propget.pp_o_id_subtype = pool_resource_elem_class(pe); + if (pool_elem_class(pe) == PEC_COMP) + propget.pp_o_id_subtype = + (pool_resource_elem_class_t)pool_component_elem_class(pe); + + propget.pp_o_id = elem_get_sysid(pe); + propget.pp_o_prop_name_size = strlen(name); + propget.pp_o_prop_name = (char *)name; + propget.pp_i_bufsize = KERNEL_SNAPSHOT_BUF_SZ; + propget.pp_i_buf = malloc(KERNEL_SNAPSHOT_BUF_SZ); + bzero(propget.pp_i_buf, KERNEL_SNAPSHOT_BUF_SZ); + + prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; + if (ioctl(prov->pkc_fd, POOL_PROPGET, &propget) < 0) { + free(propget.pp_i_buf); + pool_seterror(POE_SYSTEM); + return (POC_INVAL); + } + if (nvlist_unpack(propget.pp_i_buf, propget.pp_i_bufsize, + &proplist, 0) != 0) { + free(propget.pp_i_buf); + pool_seterror(POE_SYSTEM); + return (POC_INVAL); + } + free(propget.pp_i_buf); + + if ((pair = nvlist_next_nvpair(proplist, NULL)) == NULL) { + nvlist_free(proplist); + pool_seterror(POE_SYSTEM); + return (POC_INVAL); + } + + if (pool_value_from_nvpair(val, pair) == PO_FAIL) { + nvlist_free(proplist); + return (POC_INVAL); + } + nvlist_free(proplist); + return (pool_value_get_type(val)); +} + +/* + * Update the specified property value. + * + * PO_FAIL is returned if an error is detected and the error code is updated + * to indicate the cause of the error. + */ +int +pool_knl_put_property(pool_elem_t *pe, const char *name, + const pool_value_t *val) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; + pool_knl_connection_t *prov = + (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; + nvpair_t *bp, *ap; + pool_propput_undo_t *propput; + nvlist_t *bl = NULL; + const pool_prop_t *prop; + + if ((bp = pool_knl_find_nvpair(pke->pke_properties, name)) != NULL) { + if (nvlist_alloc(&bl, NV_UNIQUE_NAME_TYPE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (nvlist_add_nvpair(bl, bp) != 0) { + nvlist_free(bl); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + if (pool_knl_nvlist_add_value(pke->pke_properties, name, val) != + PO_SUCCESS) + return (PO_FAIL); + + if (prov->pkc_log->l_state != LS_DO) { + if (bl) + nvlist_free(bl); + return (PO_SUCCESS); + } + /* + * The remaining logic is setting up the arguments for the + * POOL_PROPPUT ioctl and appending the details into the log. + */ + if ((propput = malloc(sizeof (pool_propput_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(propput, 0, sizeof (pool_propput_undo_t)); + propput->ppu_blist = bl; + + ap = pool_knl_find_nvpair(pke->pke_properties, name); + + if (nvlist_alloc(&propput->ppu_alist, NV_UNIQUE_NAME_TYPE, 0) != 0) { + nvlist_free(propput->ppu_blist); + free(propput); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (nvlist_add_nvpair(propput->ppu_alist, ap) != 0) { + nvlist_free(propput->ppu_blist); + nvlist_free(propput->ppu_alist); + free(propput); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if (nvlist_pack(propput->ppu_alist, + (char **)&propput->ppu_ioctl.pp_o_buf, + &propput->ppu_ioctl.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + nvlist_free(propput->ppu_alist); + propput->ppu_ioctl.pp_o_id_type = pool_elem_class(pe); + if (pool_elem_class(pe) == PEC_RES_COMP || + pool_elem_class(pe) == PEC_RES_AGG) + propput->ppu_ioctl.pp_o_id_sub_type = + pool_resource_elem_class(pe); + if (pool_elem_class(pe) == PEC_COMP) + propput->ppu_ioctl.pp_o_id_sub_type = + (pool_resource_elem_class_t)pool_component_elem_class(pe); + + propput->ppu_elem = pe; + if ((prop = provider_get_prop(propput->ppu_elem, name)) != NULL) { + if (prop_is_readonly(prop) == PO_TRUE) + propput->ppu_doioctl |= KERNEL_PROP_RDONLY; + } + + if (log_append(prov->pkc_log, POOL_PROPPUT, (void *)propput) != + PO_SUCCESS) { + nvlist_free(propput->ppu_blist); + free(propput); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Remove the specified property value. + * + * PO_FAIL is returned if an error is detected and the error code is + * updated to indicate the cause of the error. + */ +int +pool_knl_rm_property(pool_elem_t *pe, const char *name) +{ + pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; + pool_knl_connection_t *prov = + (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; + pool_proprm_undo_t *proprm; + + if (pool_knl_find_nvpair(pke->pke_properties, name) == NULL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + if ((proprm = malloc(sizeof (pool_proprm_undo_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(proprm, 0, sizeof (pool_proprm_undo_t)); + proprm->pru_oldval.pv_class = POC_INVAL; + (void) pool_get_property(TO_CONF(pe), pe, name, &proprm->pru_oldval); + + if (prov->pkc_log->l_state != LS_DO) { + free(proprm); + (void) nvlist_remove_all(pke->pke_properties, (char *)name); + return (PO_SUCCESS); + } + /* + * The remaining logic is setting up the arguments for the + * POOL_PROPRM ioctl and appending the details into the log. + */ + + proprm->pru_ioctl.pp_o_id_type = pool_elem_class(pe); + if (pool_elem_class(pe) == PEC_RES_COMP || + pool_elem_class(pe) == PEC_RES_AGG) + proprm->pru_ioctl.pp_o_id_sub_type = + pool_resource_elem_class(pe); + + if (pool_elem_class(pe) == PEC_COMP) + proprm->pru_ioctl.pp_o_id_sub_type = + (pool_resource_elem_class_t)pool_component_elem_class(pe); + + proprm->pru_ioctl.pp_o_prop_name_size = strlen(name); + proprm->pru_ioctl.pp_o_prop_name = + (char *)pool_value_get_name(&proprm->pru_oldval); + proprm->pru_elem = pe; + + if (log_append(prov->pkc_log, POOL_PROPRM, (void *)proprm) != + PO_SUCCESS) { + free(proprm); + return (PO_FAIL); + } + + (void) nvlist_remove_all(pke->pke_properties, (char *)name); + return (PO_SUCCESS); +} + +/* + * Return a NULL terminated array of pool_value_t which represents all + * of the properties stored for an element + * + * Return NULL on failure. It is the caller's responsibility to free + * the returned array of values. + */ +pool_value_t ** +pool_knl_get_properties(const pool_elem_t *pe, uint_t *nprops) +{ + nvpair_t *pair; + pool_value_t **result; + pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; + int i = 0; + + *nprops = 0; + + for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL; + pair = nvlist_next_nvpair(pke->pke_properties, pair)) + (*nprops)++; + if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL; + pair = nvlist_next_nvpair(pke->pke_properties, pair), i++) { + result[i] = pool_value_alloc(); + if (pool_value_from_nvpair(result[i], pair) == PO_FAIL) { + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + return (NULL); + } + } + return (result); +} + +/* + * Append an entry to a result set. Reallocate the array used to store + * results if it's full. + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_knl_result_set_append(pool_knl_result_set_t *rs, pool_knl_elem_t *pke) +{ + if (rs->pkr_count == rs->pkr_size) + if (pool_knl_result_set_realloc(rs) != PO_SUCCESS) + return (PO_FAIL); + + rs->pkr_list[rs->pkr_count++] = pke; + + return (PO_SUCCESS); +} + +/* + * Resize the array used to store results. A simple doubling strategy + * is used. + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_knl_result_set_realloc(pool_knl_result_set_t *rs) +{ + pool_knl_elem_t **old_list = rs->pkr_list; + int new_size = rs->pkr_size * 2; + + if ((rs->pkr_list = realloc(rs->pkr_list, + new_size * sizeof (pool_knl_elem_t *))) == NULL) { + rs->pkr_list = old_list; + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + rs->pkr_size = new_size; + + return (PO_SUCCESS); +} + +/* + * Allocate a result set. The Result Set stores the result of a query. + * Returns pool_knl_result_set_t pointer/NULL + */ +pool_knl_result_set_t * +pool_knl_result_set_alloc(const pool_conf_t *conf) +{ + pool_knl_result_set_t *rs; + + if ((rs = malloc(sizeof (pool_knl_result_set_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(rs, 0, sizeof (pool_knl_result_set_t)); + rs->pkr_size = KERNEL_RS_INITIAL_SZ; + if (pool_knl_result_set_realloc(rs) == PO_FAIL) { + free(rs); + pool_seterror(POE_SYSTEM); + return (NULL); + } + rs->prs_conf = conf; + rs->prs_index = -1; + rs->prs_active = PO_TRUE; + /* Fix up the result set accessor functions to the knl specfic ones */ + rs->prs_next = pool_knl_rs_next; + rs->prs_prev = pool_knl_rs_prev; + rs->prs_first = pool_knl_rs_first; + rs->prs_last = pool_knl_rs_last; + rs->prs_get_index = pool_knl_rs_get_index; + rs->prs_set_index = pool_knl_rs_set_index; + rs->prs_close = pool_knl_rs_close; + rs->prs_count = pool_knl_rs_count; + return (rs); +} + +/* + * Free a result set. Ensure that the resources are all released at + * this point. + */ +void +pool_knl_result_set_free(pool_knl_result_set_t *rs) +{ + free(rs->pkr_list); + free(rs); +} +/* + * Return the next element in a result set. + * Returns pool_elem_t pointer/NULL + */ +pool_elem_t * +pool_knl_rs_next(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + if (kset->prs_index == kset->pkr_count - 1) + return (NULL); + return ((pool_elem_t *)kset->pkr_list[++kset->prs_index]); +} + +/* + * Return the previous element in a result set. + * Returns pool_elem_t pointer/NULL + */ +pool_elem_t * +pool_knl_rs_prev(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + if (kset->prs_index < 0) + return (NULL); + return ((pool_elem_t *)kset->pkr_list[kset->prs_index--]); +} + +/* + * Sets the current index in a result set. + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_knl_rs_set_index(pool_result_set_t *set, int index) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + if (index < 0 || index >= kset->pkr_count) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + kset->prs_index = index; + return (PO_SUCCESS); +} + +/* + * Return the current index in a result set. + * Returns current index + */ +int +pool_knl_rs_get_index(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + return (kset->prs_index); +} + +/* + * Return the first element in a result set. + * Returns pool_elem_t pointer/NULL + */ +pool_elem_t * +pool_knl_rs_first(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + return ((pool_elem_t *)kset->pkr_list[0]); +} + +/* + * Return the last element in a result set. + * Returns pool_elem_t pointer/NULL + */ +pool_elem_t * +pool_knl_rs_last(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + return ((pool_elem_t *)kset->pkr_list[kset->pkr_count - 1]); +} + +/* + * Return the number of results in a result set. + * Returns result count + */ +int +pool_knl_rs_count(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + return (kset->pkr_count); +} + + +/* + * Close a result set. Free the resources + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_knl_rs_close(pool_result_set_t *set) +{ + pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; + + pool_knl_result_set_free(kset); + return (PO_SUCCESS); +} + +/* + * Commit an individual transaction log item(). This processing is + * essential to the pool_conf_commit() logic. When pool_conf_commit() + * is invoked, the pending transaction log for the configuration is + * walked and all pending changes to the kernel are invoked. If a + * change succeeds it is marked in the log as successful and + * processing continues, if it fails then failure is returned and the + * log will be "rolled back" to undo changes to the library snapshot + * and the kernel. + */ +int +log_item_commit(log_item_t *li) +{ + pool_knl_connection_t *prov = + (pool_knl_connection_t *)li->li_log->l_conf->pc_prov; + pool_create_undo_t *create; + pool_destroy_undo_t *destroy; + pool_assoc_undo_t *assoc; + pool_dissoc_undo_t *dissoc; + pool_propput_undo_t *propput; + pool_proprm_undo_t *proprm; + pool_xtransfer_undo_t *xtransfer; + char_buf_t *cb; + size_t size; + pool_elem_t *pair; + pool_value_t val = POOL_VALUE_INITIALIZER; + int ret; + + switch (li->li_op) { + case POOL_CREATE: + create = (pool_create_undo_t *)li->li_details; + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) + return (PO_FAIL); + if (set_char_buf(cb, "%s.sys_id", + pool_elem_class_string(create->pcu_elem)) != PO_SUCCESS) { + free_char_buf(cb); + return (PO_FAIL); + } +#ifdef DEBUG + dprintf("log_item_commit: POOL_CREATE, remove from dict\n"); + pool_elem_dprintf(create->pcu_elem); +#endif /* DEBUG */ + /* + * May not need to remove the element if it was + * already destroyed before commit. Just cast the + * return to void. + */ + (void) dict_remove(prov->pkc_elements, + (pool_knl_elem_t *)create->pcu_elem); + + if (ioctl(prov->pkc_fd, POOL_CREATE, &create->pcu_ioctl) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Now that we have created our element in the kernel, + * it has a valid allocated system id. Remove the + * element from the element dictionary, using the + * current key, and then re-insert under the new key. + */ +#ifdef DEBUG + pool_elem_dprintf(create->pcu_elem); +#endif /* DEBUG */ + assert(nvlist_add_int64( + ((pool_knl_elem_t *)create->pcu_elem)->pke_properties, + cb->cb_buf, create->pcu_ioctl.pc_i_id) == 0); + free_char_buf(cb); + assert(dict_put(prov->pkc_elements, create->pcu_elem, + create->pcu_elem) == NULL); + /* + * If the element has a pair in the static + * configuration, update it with the sys_id + */ + if ((pair = pool_get_pair(create->pcu_elem)) != NULL) { + pool_value_set_int64(&val, create->pcu_ioctl.pc_i_id); + assert(pool_put_any_ns_property(pair, c_sys_prop, &val) + == PO_SUCCESS); + } + li->li_state = LS_UNDO; + break; + case POOL_DESTROY: + destroy = (pool_destroy_undo_t *)li->li_details; + + destroy->pdu_ioctl.pd_o_id = elem_get_sysid(destroy->pdu_elem); + + /* + * It may be that this element was created in the last + * transaction. In which case POOL_CREATE, above, will + * have re-inserted the element in the dictionary. Try + * to remove it just in case this has occurred. + */ + (void) dict_remove(prov->pkc_elements, + (pool_knl_elem_t *)destroy->pdu_elem); + while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY, + &destroy->pdu_ioctl)) < 0 && errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } +#ifdef DEBUG + dprintf("log_item_commit: POOL_DESTROY\n"); + pool_elem_dprintf(destroy->pdu_elem); +#endif /* DEBUG */ + li->li_state = LS_UNDO; + break; + case POOL_ASSOC: + assoc = (pool_assoc_undo_t *)li->li_details; + + assoc->pau_ioctl.pa_o_pool_id = + elem_get_sysid(assoc->pau_assoc); + assoc->pau_ioctl.pa_o_res_id = + elem_get_sysid(assoc->pau_newres); + while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, + &assoc->pau_ioctl)) < 0 && errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_UNDO; + break; + case POOL_DISSOC: + dissoc = (pool_dissoc_undo_t *)li->li_details; + + dissoc->pdu_ioctl.pd_o_pool_id = + elem_get_sysid(dissoc->pdu_dissoc); + + while ((ret = ioctl(prov->pkc_fd, POOL_DISSOC, + &dissoc->pdu_ioctl)) < 0 && errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_UNDO; + break; + case POOL_TRANSFER: + li->li_state = LS_UNDO; + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + case POOL_XTRANSFER: + xtransfer = (pool_xtransfer_undo_t *)li->li_details; + + xtransfer->pxu_ioctl.px_o_src_id = + elem_get_sysid(xtransfer->pxu_src); + xtransfer->pxu_ioctl.px_o_tgt_id = + elem_get_sysid(xtransfer->pxu_tgt); + for (size = 0; xtransfer->pxu_rl[size] != NULL; size ++) { + xtransfer->pxu_ioctl.px_o_comp_list[size] = + elem_get_sysid(TO_ELEM(xtransfer->pxu_rl[size])); +#ifdef DEBUG + dprintf("log_item_commit: POOL_XTRANSFER\n"); + pool_elem_dprintf(TO_ELEM(xtransfer->pxu_rl[size])); +#endif /* DEBUG */ + } + + /* + * Don't actually transfer resources if the configuration + * is in POF_DESTROY state. This is to prevent problems + * relating to transferring off-line CPUs. Instead rely + * on the POOL_DESTROY ioctl to transfer the CPUS. + */ + if (li->li_log->l_conf->pc_state != POF_DESTROY && + ioctl(prov->pkc_fd, POOL_XTRANSFER, + &xtransfer->pxu_ioctl) < 0) { +#ifdef DEBUG + dprintf("log_item_commit: POOL_XTRANSFER, ioctl " + "failed\n"); +#endif /* DEBUG */ + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_UNDO; + break; + case POOL_PROPPUT: + propput = (pool_propput_undo_t *)li->li_details; + + if (pool_elem_class(propput->ppu_elem) != PEC_SYSTEM) { + propput->ppu_ioctl.pp_o_id = + elem_get_sysid(propput->ppu_elem); + } + /* + * Some properties, e.g. pset.size, are read-only in the + * kernel and attempting to change them will fail and cause + * problems. Although this property is read-only through the + * public interface, the library needs to modify it's value. + */ + if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) { + if (ioctl(prov->pkc_fd, POOL_PROPPUT, + &propput->ppu_ioctl) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + li->li_state = LS_UNDO; + break; + case POOL_PROPRM: + proprm = (pool_proprm_undo_t *)li->li_details; + + if (pool_elem_class(proprm->pru_elem) != PEC_SYSTEM) { + proprm->pru_ioctl.pp_o_id = + elem_get_sysid(proprm->pru_elem); + } + if (ioctl(prov->pkc_fd, POOL_PROPRM, &proprm->pru_ioctl) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_UNDO; + break; + default: + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Undo an individual transaction log item(). This processing is + * essential to the pool_conf_commit() and pool_conf_rollback() + * logic. Changes to the libpool snapshot and the kernel are carried + * out separately. The library snapshot is updated synchronously, + * however the kernel update is delayed until the user calls + * pool_conf_commit(). + * + * When undoing transactions, library changes will be undone unless + * this invocation is as a result of a commit failure, in which case + * the log state will be LS_RECOVER. Kernel changes will only be + * undone if they are marked as having been done, in which case the + * log item state will be LS_UNDO. + */ +int +log_item_undo(log_item_t *li) +{ + pool_knl_connection_t *prov = + (pool_knl_connection_t *)li->li_log->l_conf->pc_prov; + pool_create_undo_t *create; + pool_destroy_undo_t *destroy; + pool_assoc_undo_t *assoc; + pool_dissoc_undo_t *dissoc; + pool_propput_undo_t *propput; + pool_proprm_undo_t *proprm; + pool_xtransfer_undo_t *xtransfer; + char_buf_t *cb; + size_t size; + pool_destroy_t u_destroy; + pool_create_t u_create; + pool_assoc_t u_assoc; + pool_xtransfer_t u_xtransfer; + pool_propput_t u_propput; + pool_proprm_t u_proprm; + pool_conf_t *conf = li->li_log->l_conf; + nvpair_t *pair; + nvlist_t *tmplist; + int ret; + + if (li->li_log->l_state != LS_RECOVER) { + switch (li->li_op) { + case POOL_CREATE: + create = (pool_create_undo_t *)li->li_details; + + (void) dict_remove(prov->pkc_elements, create->pcu_elem); +#ifdef DEBUG + dprintf("log_item_undo: POOL_CREATE\n"); + assert(create->pcu_elem != NULL); + dprintf("log_item_undo: POOL_CREATE %p\n", create->pcu_elem); + pool_elem_dprintf(create->pcu_elem); +#endif /* DEBUG */ + pool_knl_elem_free((pool_knl_elem_t *)create->pcu_elem, + PO_TRUE); + break; + case POOL_DESTROY: + destroy = (pool_destroy_undo_t *)li->li_details; + + assert(dict_put(prov->pkc_elements, destroy->pdu_elem, + destroy->pdu_elem) == NULL); + break; + case POOL_ASSOC: + assoc = (pool_assoc_undo_t *)li->li_details; + + if (assoc->pau_oldres != NULL) + ((pool_knl_pool_t *)assoc->pau_assoc)->pkp_assoc + [pool_resource_elem_class(assoc->pau_oldres)] = + (pool_knl_resource_t *)assoc->pau_oldres; + break; + case POOL_DISSOC: + dissoc = (pool_dissoc_undo_t *)li->li_details; + + if (dissoc->pdu_oldres != NULL) + ((pool_knl_pool_t *)dissoc->pdu_dissoc)->pkp_assoc + [pool_resource_elem_class(dissoc->pdu_oldres)] = + (pool_knl_resource_t *)dissoc->pdu_oldres; + break; + case POOL_TRANSFER: + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + case POOL_XTRANSFER: + xtransfer = (pool_xtransfer_undo_t *)li->li_details; + + for (size = 0; xtransfer->pxu_rl[size] != NULL; size++) { + pool_value_t val = POOL_VALUE_INITIALIZER; + uint64_t src_size; + uint64_t tgt_size; + + if (pool_set_container(xtransfer->pxu_src, + TO_ELEM(xtransfer->pxu_rl[size])) == PO_FAIL) { + return (PO_FAIL); + } + /* + * Maintain the library view of the size + */ + if (resource_get_size(pool_elem_res(xtransfer->pxu_src), + &src_size) != PO_SUCCESS || + resource_get_size(pool_elem_res(xtransfer->pxu_tgt), + &tgt_size) != PO_SUCCESS) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + src_size++; + tgt_size--; + pool_value_set_uint64(&val, src_size); + (void) pool_put_any_ns_property(xtransfer->pxu_src, + c_size_prop, &val); + pool_value_set_uint64(&val, tgt_size); + (void) pool_put_any_ns_property(xtransfer->pxu_tgt, + c_size_prop, &val); + } + break; + case POOL_PROPPUT: + propput = (pool_propput_undo_t *)li->li_details; + + if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) { + if (propput->ppu_blist != NULL) { + if (nvlist_merge( + ((pool_knl_elem_t *)propput->ppu_elem)-> + pke_properties, propput->ppu_blist, 0) + != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } else { + if (nvlist_unpack(propput->ppu_ioctl.pp_o_buf, + propput->ppu_ioctl.pp_o_bufsize, + &propput->ppu_alist, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + pair = nvlist_next_nvpair(propput->ppu_alist, + NULL); + (void) nvlist_remove_all(((pool_knl_elem_t *) + propput->ppu_elem)->pke_properties, + nvpair_name(pair)); + nvlist_free(propput->ppu_alist); + } + } + break; + case POOL_PROPRM: + proprm = (pool_proprm_undo_t *)li->li_details; + + if (pool_value_get_type(&proprm->pru_oldval) != POC_INVAL) { + if (pool_put_property(conf, proprm->pru_elem, + proprm->pru_ioctl.pp_o_prop_name, + &proprm->pru_oldval) != PO_SUCCESS) { + return (PO_FAIL); + } + } + break; + default: + return (PO_FAIL); + } + } + /* + * Only try to undo the state of the kernel if we modified it. + */ + if (li->li_state == LS_DO) { + return (PO_SUCCESS); + } + + switch (li->li_op) { + case POOL_CREATE: + create = (pool_create_undo_t *)li->li_details; + + u_destroy.pd_o_type = create->pcu_ioctl.pc_o_type; + u_destroy.pd_o_sub_type = create->pcu_ioctl.pc_o_sub_type; + u_destroy.pd_o_id = create->pcu_ioctl.pc_i_id; + + while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY, + &u_destroy)) < 0 && errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_DO; + break; + case POOL_DESTROY: + destroy = (pool_destroy_undo_t *)li->li_details; + + u_create.pc_o_type = destroy->pdu_ioctl.pd_o_type; + u_create.pc_o_sub_type = destroy->pdu_ioctl.pd_o_sub_type; + + if (ioctl(prov->pkc_fd, POOL_CREATE, &u_create) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + return (PO_FAIL); + } + if (set_char_buf(cb, "%s.sys_id", + pool_elem_class_string(destroy->pdu_elem)) != PO_SUCCESS) { + free_char_buf(cb); + return (PO_FAIL); + } + (void) nvlist_add_int64( + ((pool_knl_elem_t *)destroy->pdu_elem)->pke_properties, + cb->cb_buf, u_create.pc_i_id); + free_char_buf(cb); + if (dict_put(prov->pkc_elements, destroy->pdu_elem, + destroy->pdu_elem) != NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Now we need to reset all the properties and + * associations in the kernel for this newly created + * replacement. + */ + u_propput.pp_o_id_type = destroy->pdu_ioctl.pd_o_type; + u_propput.pp_o_id_sub_type = destroy->pdu_ioctl.pd_o_sub_type; + u_propput.pp_o_id = u_create.pc_i_id; + u_propput.pp_o_buf = NULL; + /* + * Remove the read-only properties before attempting + * to restore the state of the newly created property + */ + (void) nvlist_dup(((pool_knl_elem_t *)destroy->pdu_elem)-> + pke_properties, &tmplist, 0); + for (pair = nvlist_next_nvpair(tmplist, NULL); pair != NULL; + pair = nvlist_next_nvpair(tmplist, pair)) { + const pool_prop_t *prop; + char *name = nvpair_name(pair); + if ((prop = provider_get_prop(destroy->pdu_elem, + name)) != NULL) + if (prop_is_readonly(prop) == PO_TRUE) + (void) nvlist_remove_all(tmplist, name); + } + if (nvlist_pack(tmplist, (char **)&u_propput.pp_o_buf, + &u_propput.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + nvlist_free(tmplist); + if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) { + free(u_propput.pp_o_buf); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + free(u_propput.pp_o_buf); + /* + * Now reset the associations for all the resource + * types if the thing which we are recreating is a + * pool + * + * TODO: This is resource specific and must be + * extended for additional resource types. + */ + if (destroy->pdu_ioctl.pd_o_type == PEC_POOL) { + u_assoc.pa_o_pool_id = u_create.pc_i_id; + u_assoc.pa_o_res_id = + elem_get_sysid( + TO_ELEM(((pool_knl_pool_t *)destroy->pdu_elem)-> + pkp_assoc[PREC_PSET])); + u_assoc.pa_o_id_type = PREC_PSET; + + if (ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + li->li_state = LS_DO; + break; + case POOL_ASSOC: + assoc = (pool_assoc_undo_t *)li->li_details; + + u_assoc.pa_o_pool_id = elem_get_sysid(assoc->pau_assoc); + u_assoc.pa_o_res_id = elem_get_sysid(assoc->pau_oldres); + u_assoc.pa_o_id_type = assoc->pau_ioctl.pa_o_id_type; + + while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 && + errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_DO; + break; + case POOL_DISSOC: + dissoc = (pool_dissoc_undo_t *)li->li_details; + + u_assoc.pa_o_pool_id = elem_get_sysid(dissoc->pdu_dissoc); + u_assoc.pa_o_res_id = elem_get_sysid(dissoc->pdu_oldres); + u_assoc.pa_o_id_type = dissoc->pdu_ioctl.pd_o_id_type; + + while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 && + errno == EAGAIN) + ; + if (ret < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_DO; + break; + case POOL_TRANSFER: + li->li_state = LS_DO; + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + case POOL_XTRANSFER: + xtransfer = (pool_xtransfer_undo_t *)li->li_details; + + (void) memcpy(&u_xtransfer, &xtransfer->pxu_ioctl, + sizeof (pool_xtransfer_t)); + u_xtransfer.px_o_src_id = elem_get_sysid(xtransfer->pxu_tgt); + u_xtransfer.px_o_tgt_id = elem_get_sysid(xtransfer->pxu_src); + + if (ioctl(prov->pkc_fd, POOL_XTRANSFER, &u_xtransfer) < 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + li->li_state = LS_DO; + break; + case POOL_PROPPUT: + propput = (pool_propput_undo_t *)li->li_details; + + if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) { + if (propput->ppu_blist) { + (void) memcpy(&u_propput, &propput->ppu_ioctl, + sizeof (pool_propput_t)); + u_propput.pp_o_id = + elem_get_sysid(propput->ppu_elem); + u_propput.pp_o_buf = NULL; + if (nvlist_pack(propput->ppu_blist, + (char **)&u_propput.pp_o_buf, + &u_propput.pp_o_bufsize, + NV_ENCODE_NATIVE, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (ioctl(prov->pkc_fd, POOL_PROPPUT, + &u_propput) < 0) { + free(u_propput.pp_o_buf); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + free(u_propput.pp_o_buf); + } else { + if (nvlist_unpack(propput-> + ppu_ioctl.pp_o_buf, + propput->ppu_ioctl.pp_o_bufsize, + &propput->ppu_alist, 0) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + u_proprm.pp_o_id_type = + propput->ppu_ioctl.pp_o_id_type; + u_proprm.pp_o_id_sub_type = + propput->ppu_ioctl.pp_o_id_sub_type; + u_proprm.pp_o_id = + elem_get_sysid(propput->ppu_elem); + pair = nvlist_next_nvpair(propput->ppu_alist, + NULL); + u_proprm.pp_o_prop_name = nvpair_name(pair); + u_proprm.pp_o_prop_name_size = + strlen(u_proprm.pp_o_prop_name); + + if (provider_get_prop(propput->ppu_elem, + u_proprm.pp_o_prop_name) == NULL) { + if (ioctl(prov->pkc_fd, POOL_PROPRM, + &u_proprm) < 0) { + nvlist_free(propput->ppu_alist); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + } + nvlist_free(propput->ppu_alist); + } + } + li->li_state = LS_DO; + break; + case POOL_PROPRM: + proprm = (pool_proprm_undo_t *)li->li_details; + + u_propput.pp_o_id_type = proprm->pru_ioctl.pp_o_id_type; + u_propput.pp_o_id_sub_type = + proprm->pru_ioctl.pp_o_id_sub_type; + u_propput.pp_o_id = elem_get_sysid(proprm->pru_elem); + u_propput.pp_o_buf = NULL; + /* + * Only try to remove the appropriate property + */ + if (nvlist_alloc(&tmplist, NV_UNIQUE_NAME_TYPE, 0) != + 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (pool_knl_nvlist_add_value(tmplist, + pool_value_get_name(&proprm->pru_oldval), + &proprm->pru_oldval) != PO_SUCCESS) + return (PO_FAIL); + + if (nvlist_pack(tmplist, + (char **)&u_propput.pp_o_buf, &u_propput.pp_o_bufsize, + NV_ENCODE_NATIVE, 0) != 0) { + nvlist_free(tmplist); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + nvlist_free(tmplist); + if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) { + free(u_propput.pp_o_buf); + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + free(u_propput.pp_o_buf); + li->li_state = LS_DO; + break; + default: + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * A log item stores state about the transaction it represents. This + * function releases the resources associated with the transaction and + * used to store the transaction state. + */ +int +log_item_release(log_item_t *li) +{ + pool_create_undo_t *create; + pool_destroy_undo_t *destroy; + pool_assoc_undo_t *assoc; + pool_dissoc_undo_t *dissoc; + pool_propput_undo_t *propput; + pool_proprm_undo_t *proprm; + pool_xtransfer_undo_t *xtransfer; + + switch (li->li_op) { + case POOL_CREATE: + create = (pool_create_undo_t *)li->li_details; + + free(create); + break; + case POOL_DESTROY: + destroy = (pool_destroy_undo_t *)li->li_details; + +#ifdef DEBUG + dprintf("log_item_release: POOL_DESTROY\n"); +#endif /* DEBUG */ + + if (li->li_state == LS_UNDO) { +#ifdef DEBUG + pool_elem_dprintf(destroy->pdu_elem); +#endif /* DEBUG */ + pool_knl_elem_free((pool_knl_elem_t *)destroy-> + pdu_elem, PO_TRUE); + } + free(destroy); + break; + case POOL_ASSOC: + assoc = (pool_assoc_undo_t *)li->li_details; + + free(assoc); + break; + case POOL_DISSOC: + dissoc = (pool_dissoc_undo_t *)li->li_details; + + free(dissoc); + break; + case POOL_TRANSFER: + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + case POOL_XTRANSFER: + xtransfer = (pool_xtransfer_undo_t *)li->li_details; + + free(xtransfer->pxu_rl); + free(xtransfer->pxu_ioctl.px_o_comp_list); + free(xtransfer); + break; + case POOL_PROPPUT: + propput = (pool_propput_undo_t *)li->li_details; + + if (propput->ppu_blist) + nvlist_free(propput->ppu_blist); + free(propput->ppu_ioctl.pp_o_buf); + free(propput); + break; + case POOL_PROPRM: + proprm = (pool_proprm_undo_t *)li->li_details; + + free(proprm); + break; + default: + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * pool_knl_nvlist_add_value() adds a pool_value_t to an nvlist. + */ +int +pool_knl_nvlist_add_value(nvlist_t *list, const char *name, + const pool_value_t *pv) +{ + uint64_t uval; + int64_t ival; + double dval; + uchar_t dval_b[sizeof (double)]; + uchar_t bval; + const char *sval; + pool_value_class_t type; + char *nv_name; + + if ((type = pool_value_get_type(pv)) == POC_INVAL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + nv_name = (char *)name; + + switch (type) { + case POC_UINT: + if (pool_value_get_uint64(pv, &uval) == POC_INVAL) { + return (PO_FAIL); + } + if (nvlist_add_uint64(list, nv_name, uval) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case POC_INT: + if (pool_value_get_int64(pv, &ival) == POC_INVAL) { + return (PO_FAIL); + } + if (nvlist_add_int64(list, nv_name, ival) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case POC_DOUBLE: + if (pool_value_get_double(pv, &dval) == POC_INVAL) { + return (PO_FAIL); + } + /* + * Since there is no support for doubles in the + * kernel, store the double value in a byte array. + */ + (void) memcpy(dval_b, &dval, sizeof (double)); + if (nvlist_add_byte_array(list, nv_name, dval_b, + sizeof (double)) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case POC_BOOL: + if (pool_value_get_bool(pv, &bval) == POC_INVAL) { + return (PO_FAIL); + } + if (nvlist_add_byte(list, nv_name, bval) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + case POC_STRING: + if (pool_value_get_string(pv, &sval) == POC_INVAL) { + return (PO_FAIL); + } + if (nvlist_add_string(list, nv_name, (char *)sval) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + break; + default: + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * hash_id() hashes all elements in a pool configuration using the + * "sys_id" property. Not all elements have a "sys_id" property, + * however elem_get_sysid() caters for this by always returning a + * constant value for those elements. This isn't anticipated to lead + * to a performance degradation in the hash, since those elements + * which are likely to be most prevalent in a configuration do have + * "sys_id" as a property. + */ +uint64_t +hash_id(const pool_elem_t *pe) +{ + id_t id; + + id = elem_get_sysid(pe); + return (hash_buf(&id, sizeof (id))); +} + +/* + * blocking_open() guarantees access to the pool device, if open() + * is failing with EBUSY. + */ +int +blocking_open(const char *path, int oflag) +{ + int fd; + + while ((fd = open(path, oflag)) == -1 && errno == EBUSY) + (void) poll(NULL, 0, 1 * MILLISEC); + + return (fd); +} diff --git a/usr/src/lib/libpool/common/pool_kernel_impl.h b/usr/src/lib/libpool/common/pool_kernel_impl.h new file mode 100644 index 0000000..a732b7b --- /dev/null +++ b/usr/src/lib/libpool/common/pool_kernel_impl.h @@ -0,0 +1,182 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _POOL_KERNEL_IMPL_H +#define _POOL_KERNEL_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains the definitions of types and supporting + * functions to implement the libpool kernel specific data + * manipulation facility. + * + * For more information on the libpool generic data manipulation + * facility, look at pool_impl.h. + * + * The central types for the generic data representation/storage + * facility are here enhanced to provide additional kernel specific + * information. + */ + +/* + * pool_knl_elem_t is the kernel specific representation of the + * pool_elem_t structure. + */ +typedef struct pool_knl_elem { + /* + * Common to pool_elem_t + */ + pool_elem_t pke_elem; + void *pke_pad1; + void *pke_pad2; + /* + * Common to pool_knl_elem_t + */ + nvlist_t *pke_properties; /* Properties nvlist */ + struct pool_knl_elem *pke_parent; /* Element parent */ + uint64_t pke_ltime; /* Library timestamp */ +} pool_knl_elem_t; + +typedef pool_knl_elem_t pool_knl_system_t; + +typedef struct pool_knl_resource { + /* + * Common to pool_elem_t + */ + pool_elem_t pke_elem; + /* + * Specific to pool_resource_t + */ + int (*pr_is_system)(const pool_resource_t *); + int (*pr_can_associate)(const pool_resource_t *); + /* + * Common to pool_knl_elem_t + */ + nvlist_t *pke_properties; /* Properties nvlist */ + struct pool_knl_elem *pke_parent; /* Element parent */ + uint64_t pke_ltime; /* Library timestamp */ +} pool_knl_resource_t; + +typedef pool_knl_elem_t pool_knl_component_t; + +typedef struct pool_knl_pool { + /* + * Common to pool_elem_t + */ + pool_elem_t pke_elem; + /* + * Specific to pool_t + */ + int (*pp_associate)(pool_t *, const pool_resource_t *); + int (*pp_dissociate)(pool_t *, const pool_resource_t *); + /* + * Common to pool_knl_elem_t + */ + nvlist_t *pke_properties; /* Properties nvlist */ + struct pool_knl_elem *pke_parent; /* Element parent */ + uint64_t pke_ltime; /* Library timestamp */ + /* + * Specific to pool_knl_pool_t + */ + pool_knl_resource_t *pkp_assoc[4]; /* Pool resources */ +} pool_knl_pool_t; + +/* + * pool_knl_result_set_t is the kernel specific representation of the + * pool_result_set_t structure. + * + */ +typedef struct pool_knl_result_set { + const pool_conf_t *prs_conf; /* Configuration */ + int prs_active; /* Query active? */ + int prs_index; /* Result Index */ + pool_elem_t *(*prs_next)(pool_result_set_t *); + pool_elem_t *(*prs_prev)(pool_result_set_t *); + pool_elem_t *(*prs_first)(pool_result_set_t *); + pool_elem_t *(*prs_last)(pool_result_set_t *); + int (*prs_set_index)(pool_result_set_t *, int); + int (*prs_get_index)(pool_result_set_t *); + int (*prs_close)(pool_result_set_t *); + int (*prs_count)(pool_result_set_t *); + /* + * End of common part + */ + pool_knl_elem_t **pkr_list; /* Result members */ + int pkr_count; /* Result set count */ + int pkr_size; /* Result set size */ +} pool_knl_result_set_t; + +/* + * pool_knl_connection_t is the kernel specific representation of the + * pool_connection_t structure. + * + */ +typedef struct pool_knl_connection { + const char *pc_name; /* Provider name */ + int pc_store_type; /* Datastore type */ + int pc_oflags; /* Open flags */ + int (*pc_close)(pool_conf_t *); + int (*pc_validate)(const pool_conf_t *, pool_valid_level_t); + int (*pc_commit)(pool_conf_t *); + int (*pc_export)(const pool_conf_t *, const char *, + pool_export_format_t); + int (*pc_rollback)(pool_conf_t *); + pool_result_set_t *(*pc_exec_query)(const pool_conf_t *, + const pool_elem_t *, const char *, + pool_elem_class_t, pool_value_t **); + pool_elem_t *(*pc_elem_create)(pool_conf_t *, pool_elem_class_t, + pool_resource_elem_class_t, pool_component_elem_class_t); + int (*pc_remove)(pool_conf_t *); + int (*pc_res_xfer)(pool_resource_t *, pool_resource_t *, uint64_t); + int (*pc_res_xxfer)(pool_resource_t *, pool_resource_t *, + pool_component_t **); + char *(*pc_get_binding)(pool_conf_t *, pid_t); + int (*pc_set_binding)(pool_conf_t *, const char *, idtype_t, id_t); + char *(*pc_get_resource_binding)(pool_conf_t *, + pool_resource_elem_class_t, pid_t); + /* + * End of common part + */ + int pkc_fd; /* Pool device */ + dict_hdl_t *pkc_elements; /* Elements */ +#if DEBUG + dict_hdl_t *pkc_leaks; /* Elements */ +#endif /* DEBUG */ + log_t *pkc_log; /* Transaction log */ + hrtime_t pkc_ltime; /* Snap updated */ + hrtime_t pkc_lotime; /* Snap last updated */ +} pool_knl_connection_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_KERNEL_IMPL_H */ diff --git a/usr/src/lib/libpool/common/pool_value.c b/usr/src/lib/libpool/common/pool_value.c new file mode 100644 index 0000000..c724f02 --- /dev/null +++ b/usr/src/lib/libpool/common/pool_value.c @@ -0,0 +1,446 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pool.h> +#include "pool_internal.h" + +/* + * libpool Value Manipulation Routines + * + * pool_value.c implements the value (pool_value_t) functionality for + * libpool. The datatypes supported are: uint64_t, int64_t, double, + * uchar_t (boolean), const char * (string). Values are used to + * represent data stored to and retrieved from the datastore in a + * simple discriminated union. + * + * Values are dynamically allocated using pool_value_alloc() and + * destroyed using pool_value_free(). + * + * Values may be allocated statically for internal use in + * libpool. Statically allocated pool_value_t variables must be + * initialised with the POOL_VALUE_INITIALIZER macro, otherwise the + * results are unpredictable. + * + * A pool_value_t variable can be used to store values in any of the + * supported datatypes. + * + * A pool_value_t's name and string value are limited in size to + * PV_NAME_MAX_LEN and PV_VALUE_MAX_LEN respectively. Attempting to + * store values which are greater than this in length will fail with a + * POE_BADPARAM error. + */ + +/* + * Get the uint64_t data held by the value. If the data type isn't + * uint64_t return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. + */ +int +pool_value_get_uint64(const pool_value_t *pv, uint64_t *result) +{ + if (pv->pv_class != POC_UINT) { + pool_seterror(POE_BAD_PROP_TYPE); + return (PO_FAIL); + } + *result = pv->pv_u.u; + return (PO_SUCCESS); +} + +/* + * Get the int64_t data held by the value. If the data type isn't + * int64_t return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. + */ +int +pool_value_get_int64(const pool_value_t *pv, int64_t *result) +{ + if (pv->pv_class != POC_INT) { + pool_seterror(POE_BAD_PROP_TYPE); + return (PO_FAIL); + } + *result = pv->pv_u.i; + return (PO_SUCCESS); +} + +/* + * Get the double data held by the value. If the data type isn't + * double return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. + */ + +int +pool_value_get_double(const pool_value_t *pv, double *result) +{ + if (pv->pv_class != POC_DOUBLE) { + pool_seterror(POE_BAD_PROP_TYPE); + return (PO_FAIL); + } + *result = pv->pv_u.d; + return (PO_SUCCESS); +} + +/* + * Get the boolean data held by the value. If the data type isn't + * boolean return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. + */ +int +pool_value_get_bool(const pool_value_t *pv, uchar_t *result) +{ + if (pv->pv_class != POC_BOOL) { + pool_seterror(POE_BAD_PROP_TYPE); + return (PO_FAIL); + } + *result = pv->pv_u.b; + return (PO_SUCCESS); +} + +/* + * Get the string data held by the value. If the data type isn't + * string return PO_FAIL and set pool_error to be POE_BAD_PROP_TYPE. + */ +int +pool_value_get_string(const pool_value_t *pv, const char **result) +{ + if (pv->pv_class != POC_STRING) { + pool_seterror(POE_BAD_PROP_TYPE); + return (PO_FAIL); + } + *result = pv->pv_u.s; + return (PO_SUCCESS); +} + +/* + * Get the type of the data held by the value. If the value has never + * been used to store data, then the type is POC_INVAL. + */ +pool_value_class_t +pool_value_get_type(const pool_value_t *pv) +{ + return (pv->pv_class); +} + +/* + * Set the value's data to the supplied uint64_t data. Update the type + * of the value data to POC_UINT. + */ +void +pool_value_set_uint64(pool_value_t *pv, uint64_t val) +{ + if (pv->pv_class == POC_STRING) + atom_free(pv->pv_u.s); + pv->pv_class = POC_UINT; + pv->pv_u.u = val; +} + +/* + * Set the value's data to the supplied int64_t data. Update the type + * of the value data to POC_INT. + */ +void +pool_value_set_int64(pool_value_t *pv, int64_t val) +{ + if (pv->pv_class == POC_STRING) + atom_free(pv->pv_u.s); + pv->pv_class = POC_INT; + pv->pv_u.i = val; +} + +/* + * Set the value's data to the supplied double data. Update the type + * of the value data to POC_DOUBLE. + */ + +void +pool_value_set_double(pool_value_t *pv, double val) +{ + if (pv->pv_class == POC_STRING) + atom_free(pv->pv_u.s); + pv->pv_class = POC_DOUBLE; + pv->pv_u.d = val; +} + +/* + * Set the value's data to the supplied uchar_t data. Update the type + * of the value data to POC_BOOL. + */ +void +pool_value_set_bool(pool_value_t *pv, uchar_t val) +{ + if (pv->pv_class == POC_STRING) + atom_free(pv->pv_u.s); + pv->pv_class = POC_BOOL; + pv->pv_u.b = !!val; /* Lock value at 0 or 1 */ +} + +/* + * Try to make an internal copy of the val, returning PO_SUCCESS or + * PO_FAIL if the copy works or fails. + */ +int +pool_value_set_string(pool_value_t *pv, const char *val) +{ + if (pv->pv_class == POC_STRING) + atom_free(pv->pv_u.s); + pv->pv_class = POC_STRING; + if (val == NULL || strlen(val) >= PV_VALUE_MAX_LEN) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } else { + if ((pv->pv_u.s = atom_string(val)) == NULL) + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Allocate a pool_value_t structure and initialise it to 0. Set the + * type to POC_INVAL and return a pointer to the new pool_value_t. If + * memory allocation fails, set POE_SYSTEM and return NULL. + */ +pool_value_t * +pool_value_alloc(void) +{ + pool_value_t *val; + + if ((val = malloc(sizeof (pool_value_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(val, 0, sizeof (pool_value_t)); + val->pv_class = POC_INVAL; + return (val); +} + +/* + * Free any atoms associated with the value and then free the value + * itself. + */ +void +pool_value_free(pool_value_t *pv) +{ + if (pv->pv_name) + atom_free(pv->pv_name); + if (pv->pv_class == POC_STRING) + atom_free(pv->pv_u.s); + free(pv); +} + +/* + * Return a pointer to the name of the value. This may be NULL if the + * name has never been set. + */ +const char * +pool_value_get_name(const pool_value_t *pv) +{ + return (pv->pv_name); +} + +/* + * Set the name of the value to the supplied name. + */ +int +pool_value_set_name(pool_value_t *pv, const char *name) +{ + if (name == NULL || strlen(name) >= PV_NAME_MAX_LEN) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } else { + if (pv->pv_name) + atom_free(pv->pv_name); + if ((pv->pv_name = atom_string(name)) == NULL) + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Use the supplied nvpair_t to set the name, type and value of the + * supplied pool_value_t. + * + * Return: PO_SUCCESS/PO_FAIL + */ +int +pool_value_from_nvpair(pool_value_t *pv, nvpair_t *pn) +{ + uchar_t bval; + uint64_t uval; + int64_t ival; + double dval; + uint_t nelem; + uchar_t *dval_b; + char *sval; + + if (pool_value_set_name(pv, nvpair_name(pn)) != PO_SUCCESS) + return (PO_FAIL); + switch (nvpair_type(pn)) { + case DATA_TYPE_BYTE: + if (nvpair_value_byte(pn, &bval) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + pool_value_set_bool(pv, bval); + break; + case DATA_TYPE_BYTE_ARRAY: + if (nvpair_value_byte_array(pn, &dval_b, &nelem) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memcpy(&dval, dval_b, sizeof (double)); + pool_value_set_double(pv, dval); + break; + case DATA_TYPE_INT64: + if (nvpair_value_int64(pn, &ival) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + pool_value_set_int64(pv, ival); + break; + case DATA_TYPE_UINT64: + if (nvpair_value_uint64(pn, &uval) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + pool_value_set_uint64(pv, uval); + break; + case DATA_TYPE_STRING: + if (nvpair_value_string(pn, &sval) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + if (pool_value_set_string(pv, sval) != PO_SUCCESS) + return (PO_FAIL); + break; + default: + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Check to see if the values held by two supplied values are + * equal. First compare the pointers to see if we are comparing to + * ourselves, if we are return PO_TRUE. If not, get the types and + * ensure they match, if they don't return PO_FALSE. Then do a type + * specific comparison returning PO_TRUE or PO_FALSE accordingly. + */ +int +pool_value_equal(pool_value_t *pv1, pool_value_t *pv2) +{ + uint64_t uval1, uval2; + int64_t ival1, ival2; + double dval1, dval2; + uchar_t bval1, bval2; + const char *sval1, *sval2; + pool_value_class_t type; + + if (pv1 == pv2) /* optimisation */ + return (PO_TRUE); + + type = pool_value_get_type(pv1); + if (type != pool_value_get_type(pv2)) + return (PO_FALSE); + + switch (type) { + case POC_UINT: + (void) pool_value_get_uint64(pv1, &uval1); + (void) pool_value_get_uint64(pv2, &uval2); + if (uval1 == uval2) + return (PO_TRUE); + break; + case POC_INT: + (void) pool_value_get_int64(pv1, &ival1); + (void) pool_value_get_int64(pv2, &ival2); + if (ival1 == ival2) + return (PO_TRUE); + break; + case POC_DOUBLE: + (void) pool_value_get_double(pv1, &dval1); + (void) pool_value_get_double(pv2, &dval2); + if (dval1 == dval2) + return (PO_TRUE); + break; + case POC_BOOL: + (void) pool_value_get_bool(pv1, &bval1); + (void) pool_value_get_bool(pv2, &bval2); + if (bval1 == bval2) + return (PO_TRUE); + break; + case POC_STRING: + (void) pool_value_get_string(pv1, &sval1); + (void) pool_value_get_string(pv2, &sval2); + if (strcmp(sval1, sval2) == 0) + return (PO_TRUE); + break; + } + return (PO_FALSE); +} + +#ifdef DEBUG +/* + * Trace pool_value_t details using dprintf + */ +void +pool_value_dprintf(const pool_value_t *pv) +{ + const char *class_name[] = { + "POC_UINT", + "POC_INT", + "POC_DOUBLE", + "POC_BOOL", + "POC_STRING" + }; + + dprintf("name: %s\n", pv->pv_name ? pv->pv_name : "NULL"); + if (pv->pv_class >= POC_UINT && pv->pv_class <= POC_STRING) + dprintf("type: %s\n", class_name[pv->pv_class]); + else + dprintf("type: POC_INVAL\n"); + switch (pv->pv_class) { + case POC_UINT: + dprintf("value: %llu\n", pv->pv_u.u); + break; + case POC_INT: + dprintf("value: %lld\n", pv->pv_u.i); + break; + case POC_DOUBLE: + dprintf("value: %f\n", pv->pv_u.d); + break; + case POC_BOOL: + dprintf("value: %s\n", pv->pv_u.b ? "true" : "false"); + break; + case POC_STRING: + dprintf("value: %s\n", pv->pv_u.s); + break; + default: + dprintf("value: invalid\n"); + break; + } +} +#endif /* DEBUG */ diff --git a/usr/src/lib/libpool/common/pool_xml.c b/usr/src/lib/libpool/common/pool_xml.c new file mode 100644 index 0000000..4f0b6df --- /dev/null +++ b/usr/src/lib/libpool/common/pool_xml.c @@ -0,0 +1,2787 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <thread.h> +#include <time.h> +#include <unistd.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/utsname.h> + +#include <libxml/debugXML.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xmlerror.h> +#include <libxml/xpath.h> +#include <libxml/xmlmemory.h> + +#include <pool.h> +#include "pool_internal.h" +#include "pool_impl.h" +#include "pool_xml_impl.h" + +/* + * libpool XML Manipulation Routines + * + * pool_xml.c implements the XML manipulation routines used by the libpool + * XML datastore. The functions are grouped into the following logical areas + * - Result Sets + * The XPath API is used to search the XML document represented by a + * configuration. The results of XPath queries are represented through + * pool_result_set_t structures as part of the abstraction of the datastore + * representation. (see pool.c comment for more details) + * + * - Property Manipulation + * Validated XML (XML associated with a DTD) does not allow the introduction + * of attributes which are not recognised by the DTD. This is a limitation + * since we want to allow libpool to associate an arbitrary number of + * properties with an element. The property manipulation code overcomes this + * limitation by allowing property sub-elements to be created and manipulated + * through a single API so that they are indistinguishable from attributes + * to the libpool user. + * + * - XML Element/Attribute Manipulation + * These routines manipulate XML elements and attributes and are the routines + * which interact most directly with libxml. + * + * - File Processing/IO + * Since libpool must present its data in a consistent fashion, we have to + * implement file locking above libxml. These routines allow us to lock files + * during processing and maintain data integrity between processes. Note + * that locks are at the process scope and are advisory (see fcntl). + * + * - Utilities + * Sundry utility functions that aren't easily categorised. + */ + +#define MAX_PROP_SIZE 1024 /* Size of property buffer */ +/* + * The PAGE_READ_SIZE value is used to determine the size of the input buffer + * used to parse XML files. + */ +#define PAGE_READ_SIZE 8192 +#define ELEM_TYPE_COUNT 6 /* Count of Element types */ + +typedef struct dtype_tbl +{ + xmlChar *dt_name; + int dt_type; +} dtype_tbl_t; + +typedef struct elem_type_tbl +{ + xmlChar *ett_elem; + dtype_tbl_t (*ett_dtype)[]; +} elem_type_tbl_t; + +extern int xmlDoValidityCheckingDefaultValue; + +/* + * The _xml_lock is used to lock the state of libpool during + * xml initialisation operations. + */ +static mutex_t _xml_lock; + +const char *element_class_tags[] = { + "any", + "system", + "pool", + "res_comp", + "res_agg", + "comp", + NULL +}; + +static const char *data_type_tags[] = { + "uint", + "int", + "float", + "boolean", + "string" +}; + +const char *dtd_location = "file:///usr/share/lib/xml/dtd/rm_pool.dtd.1"; + +static elem_type_tbl_t elem_tbl[ELEM_TYPE_COUNT] = {0}; + +/* libpool initialisation indicator */ +static int _libpool_xml_initialised = PO_FALSE; + +/* + * Utility functions + */ +/* + * Those functions which are not static are shared with pool_kernel.c + * They provide the required XML support for exporting a kernel + * configuration as an XML document. + */ +void xml_init(void); +static int create_shadow(xmlNodePtr node); +static int pool_xml_free_doc(pool_conf_t *conf); +static int prop_sort(const void *a, const void *b); +static int dtd_exists(const char *path); +static void build_dtype_accelerator(void); +static dtype_tbl_t (*build_dtype_tbl(const xmlChar *rawdata))[]; +static int get_fast_dtype(xmlNodePtr node, xmlChar *name); +static int pool_assoc_default_resource_type(pool_t *, + pool_resource_elem_class_t); + +/* + * XML Data access and navigation APIs + */ +static int pool_build_xpath_buf(pool_xml_connection_t *, const pool_elem_t *, + pool_elem_class_t, pool_value_t **, char_buf_t *, int); +/* + * SHARED WITH pool_kernel.c for XML export support + */ +xmlNodePtr node_create(xmlNodePtr parent, const xmlChar *name); +static xmlNodePtr node_create_with_id(xmlNodePtr parent, const xmlChar *name); + +/* Configuration */ +static int pool_xml_close(pool_conf_t *); +static int pool_xml_validate(const pool_conf_t *, pool_valid_level_t); +static int pool_xml_commit(pool_conf_t *conf); +static int pool_xml_export(const pool_conf_t *conf, const char *location, + pool_export_format_t fmt); +static int pool_xml_rollback(pool_conf_t *conf); +static pool_result_set_t *pool_xml_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); +static int pool_xml_remove(pool_conf_t *conf); +static int pool_xml_res_transfer(pool_resource_t *, pool_resource_t *, + uint64_t); +static int pool_xml_res_xtransfer(pool_resource_t *, pool_resource_t *, + pool_component_t **); + +/* Connections */ +static void pool_xml_connection_free(pool_xml_connection_t *prov); + +/* Result Sets */ +static pool_xml_result_set_t *pool_xml_result_set_alloc(const pool_conf_t *); +static void pool_xml_result_set_free(pool_xml_result_set_t *rs); +static pool_elem_t *pool_xml_rs_next(pool_result_set_t *set); +static pool_elem_t *pool_xml_rs_prev(pool_result_set_t *set); +static pool_elem_t *pool_xml_rs_first(pool_result_set_t *set); +static pool_elem_t *pool_xml_rs_last(pool_result_set_t *set); +static int pool_xml_rs_set_index(pool_result_set_t *set, int index); +static int pool_xml_rs_get_index(pool_result_set_t *set); +static int pool_xml_rs_count(pool_result_set_t *set); +static int pool_xml_rs_close(pool_result_set_t *set); + +/* Element (and sub-type) */ +static void pool_xml_elem_init(pool_conf_t *conf, pool_xml_elem_t *elem, + pool_elem_class_t, pool_resource_elem_class_t, pool_component_elem_class_t); +static int pool_xml_elem_wrap(xmlNodePtr node, pool_elem_class_t class, + pool_resource_elem_class_t, pool_component_elem_class_t); +static pool_elem_t *pool_xml_elem_create(pool_conf_t *, pool_elem_class_t, + pool_resource_elem_class_t, pool_component_elem_class_t); +static int pool_xml_elem_remove(pool_elem_t *pe); +static int pool_xml_set_container(pool_elem_t *, pool_elem_t *); +static pool_elem_t *pool_xml_get_container(const pool_elem_t *); + +/* + * Pool element specific + */ +static int pool_xml_pool_associate(pool_t *, const pool_resource_t *); +static int pool_xml_pool_dissociate(pool_t *, const pool_resource_t *); + +/* + * Resource elements specific + */ +static int pool_xml_resource_is_system(const pool_resource_t *); +static int pool_xml_resource_can_associate(const pool_resource_t *); + +/* Properties */ +static pool_value_class_t pool_xml_get_property(const pool_elem_t *, + const char *, pool_value_t *); +static int pool_xml_put_property(pool_elem_t *, const char *, + const pool_value_t *); +static int pool_xml_rm_property(pool_elem_t *, const char *); +static xmlNodePtr property_create(xmlNodePtr, const char *, + pool_value_class_t); + +/* Internal Attribute/Property manipulation */ +static int pool_is_xml_attr(xmlDocPtr, const char *, const char *); +static pool_value_class_t pool_xml_get_attr(xmlNodePtr node, xmlChar *name, + pool_value_t *value); +int pool_xml_set_attr(xmlNodePtr node, xmlChar *name, + const pool_value_t *value); +static pool_value_class_t pool_xml_get_prop(xmlNodePtr node, xmlChar *name, + pool_value_t *value); +int pool_xml_set_prop(xmlNodePtr node, xmlChar *name, + const pool_value_t *value); +static pool_value_t **pool_xml_get_properties(const pool_elem_t *, uint_t *); +/* XML Error handling */ +void pool_error_func(void *ctx, const char *msg, ...); + +/* XML File Input Processing */ +static int pool_xml_open_file(pool_conf_t *conf); +static int pool_xml_parse_document(pool_conf_t *); + +/* + * Initialise this module + */ +void +xml_init() +{ + (void) mutex_lock(&_xml_lock); + if (_libpool_xml_initialised == PO_TRUE) { + (void) mutex_unlock(&_xml_lock); + return; + } + xmlInitParser(); + + /* + * DTD validation, with line numbers. + */ + (void) xmlLineNumbersDefault(1); + xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; + xmlDoValidityCheckingDefaultValue = 1; + /* Try to improve indentation and readability */ + (void) xmlKeepBlanksDefault(0); + /* Send all XML errors to our debug handler */ + xmlSetGenericErrorFunc(NULL, pool_error_func); + /* Load up DTD element a-dtype data to improve performance */ + build_dtype_accelerator(); + _libpool_xml_initialised = PO_TRUE; + (void) mutex_unlock(&_xml_lock); +} + +/* + * Get the next ID for this configuration + */ +static int +get_unique_id(xmlNodePtr node, char *id) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + uint64_t nid = 0; + if (node->doc->_private) { + if (pool_get_ns_property( + pool_conf_to_elem((pool_conf_t *)node->doc->_private), + "_next_id", &val) == POC_UINT) + (void) pool_value_get_uint64(&val, &nid); + } + if (snprintf(id, KEY_BUFFER_SIZE, "id_%llx", nid) > KEY_BUFFER_SIZE) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + pool_value_set_uint64(&val, ++nid); + return (pool_put_ns_property( + pool_conf_to_elem((pool_conf_t *)node->doc->_private), "_next_id", + &val)); +} + +/* Document building functions */ + +/* + * node_create() creates a child node of type name of the supplied parent in + * the supplied document. If the parent or document is NULL, create the node + * but do not associate it with a parent or document. + */ +xmlNodePtr +node_create(xmlNodePtr parent, const xmlChar *name) +{ + xmlNodePtr node; + + if (parent == NULL) + node = xmlNewNode(NULL, name); + else + node = xmlNewChild(parent, NULL, name, NULL); + return (node); +} + +/* + * node_create_with_id() creates a child node of type name of the supplied + * parent with the ref_id generated by get_unique_id(). Actual node creation + * is performed by node_create() and this function just sets the ref_id + * property to the value of the id. + */ +static xmlNodePtr +node_create_with_id(xmlNodePtr parent, const xmlChar *name) +{ + char id[KEY_BUFFER_SIZE]; /* Must be big enough for key below */ + xmlNodePtr node = node_create(parent, name); + if (node != NULL) { + if (get_unique_id(node, id) != PO_SUCCESS) { + xmlUnlinkNode(node); + xmlFreeNode(node); /* recurses all children */ + pool_seterror(POE_DATASTORE); + return (NULL); + } + if (xmlSetProp(node, BAD_CAST c_ref_id, BAD_CAST id) == NULL) { + xmlUnlinkNode(node); + xmlFreeNode(node); /* recurses all children */ + pool_seterror(POE_DATASTORE); + return (NULL); + } + } + return (node); +} + +/* Supporting Data Conversion Routines */ + +/* XML Parser Utility Functions */ + +/* + * Handler for XML Errors. Called by libxml at libxml Error. + */ +/*ARGSUSED*/ +void +pool_error_func(void *ctx, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + do_dprintf(msg, ap); + va_end(ap); +} + +/* + * Free the shadowed elements from within the supplied document and then + * free the document. This function should always be called when freeing + * a pool document to ensure that all "shadow" resources are reclaimed. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_free_doc(pool_conf_t *conf) +{ + /* Only do any of this if there is a document */ + if (((pool_xml_connection_t *)conf->pc_prov)->pxc_doc != NULL) { + pool_elem_t *pe; + pool_result_set_t *rs; + /* Delete all the "shadowed" children of the doc */ + rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_ANY, NULL); + if (rs == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { + /* + * Work out the element type and free the elem + */ + free(pe); + } + (void) pool_rs_close(rs); + xmlFreeDoc(((pool_xml_connection_t *)conf->pc_prov)->pxc_doc); + } + ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc = NULL; + return (PO_SUCCESS); +} + +/* + * Remove an element from the document. Note that only three types of elements + * can be removed, res, comp and pools. comp are moved around to the + * default res when a res is deleted. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_elem_remove(pool_elem_t *pe) +{ + pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; + + /* + * You can only destroy three elements: pools, resources and + * components. + */ + switch (pe->pe_class) { + case PEC_POOL: + case PEC_RES_COMP: + case PEC_RES_AGG: + case PEC_COMP: + if (pxe->pxe_node) { + xmlUnlinkNode(pxe->pxe_node); + xmlFreeNode(pxe->pxe_node); /* recurses all children */ + } + free(pxe); + break; + default: + break; + } + return (PO_SUCCESS); +} + +/* + * Create a property element. + */ +static xmlNodePtr +property_create(xmlNodePtr parent, const char *name, pool_value_class_t type) +{ + + xmlNodePtr element; + pool_value_t val = POOL_VALUE_INITIALIZER; + + if ((element = node_create(parent, BAD_CAST "property")) == NULL) { + pool_seterror(POE_DATASTORE); + return (NULL); + } + if (pool_value_set_string(&val, name) != PO_SUCCESS) { + xmlFree(element); + return (NULL); + } + (void) pool_xml_set_attr(element, BAD_CAST c_name, &val); + if (pool_value_set_string(&val, data_type_tags[type]) != PO_SUCCESS) { + xmlFree(element); + return (NULL); + } + (void) pool_xml_set_attr(element, BAD_CAST c_type, &val); + return (element); +} + +/* + * External clients need to be able to put/get properties and this is the + * way to do it. + * This function is an interceptor, since it will *always* try to manipulate + * an attribute first. If the attribute doesn't exist, then it will treat + * the request as a property request. + */ +static pool_value_class_t +pool_xml_get_property(const pool_elem_t *pe, const char *name, + pool_value_t *val) +{ + pool_value_class_t type; + pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; + + /* + * "type" is a special attribute which is not visible ever outside of + * libpool. Use the specific type accessor function. + */ + if (strcmp(name, c_type) == 0) { + return (pool_xml_get_attr(pxe->pxe_node, BAD_CAST name, + val)); + } + if (is_ns_property(pe, name) != NULL) { /* in ns */ + if ((type = pool_xml_get_attr(pxe->pxe_node, + BAD_CAST property_name_minus_ns(pe, name), val)) + == POC_INVAL) + return (pool_xml_get_prop(pxe->pxe_node, BAD_CAST name, + val)); + } else + return (pool_xml_get_prop(pxe->pxe_node, BAD_CAST name, val)); + + return (type); +} + +/* + * Put a property on an element. Check if the property is an attribute, + * if it is update that value. If not add a property element. + * + * There are three possible conditions here: + * - the name is a ns + * - the name is an attribute + * - the name isn't an attribute + * - the name is not a ns + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_put_property(pool_elem_t *pe, const char *name, + const pool_value_t *val) +{ + pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; + + /* + * "type" is a special attribute which is not visible ever outside of + * libpool. Use the specific type accessor function. + */ + if (strcmp(name, c_type) == 0) { + return (pool_xml_set_attr(pxe->pxe_node, BAD_CAST name, + val)); + } + if (is_ns_property(pe, name) != NULL) { /* in ns */ + if (pool_xml_set_attr(pxe->pxe_node, + BAD_CAST property_name_minus_ns(pe, name), val) == PO_FAIL) + return (pool_xml_set_prop(pxe->pxe_node, BAD_CAST name, + val)); + } else + return (pool_xml_set_prop(pxe->pxe_node, BAD_CAST name, val)); + return (PO_SUCCESS); +} + +/* + * Remove a property from an element. Check if the property is an attribute, + * if it is fail. Otherwise remove the property subelement. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_rm_property(pool_elem_t *pe, const char *name) +{ + pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr path; + char buf[MAX_PROP_SIZE]; + int ret; + + if (xmlHasProp(pxe->pxe_node, BAD_CAST name) != NULL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + /* use xpath to find the node with the appropriate value for name */ + (void) snprintf(buf, sizeof (buf), "property[@name=\"%s\"]", name); + if ((ctx = xmlXPathNewContext(pxe->pxe_node->doc)) == NULL) { + pool_seterror(POE_PUTPROP); + return (PO_FAIL); + } + ctx->node = pxe->pxe_node; + path = xmlXPathEval(BAD_CAST buf, ctx); + + if (path && (path->type == XPATH_NODESET) && + (path->nodesetval->nodeNr == 1)) { + xmlUnlinkNode(path->nodesetval->nodeTab[0]); + xmlFreeNode(path->nodesetval->nodeTab[0]); + ret = PO_SUCCESS; + } else { + pool_seterror(POE_BADPARAM); + ret = PO_FAIL; + } + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + return (ret); +} + +/* + * Get the data type for an attribute name from the element node. The data + * type is returned and the value of the attribute updates the supplied value + * pointer. + */ +static pool_value_class_t +pool_xml_get_attr(xmlNodePtr node, xmlChar *name, pool_value_t *value) +{ + pool_value_class_t data_type; + xmlChar *data; + uint64_t uval; + int64_t ival; + + if (xmlHasProp(node, name) == NULL && pool_is_xml_attr(node->doc, + (const char *) node->name, (const char *) name) == PO_FALSE) { + pool_seterror(POE_BADPARAM); + return (POC_INVAL); + } + if (xmlHasProp(node, BAD_CAST c_a_dtype) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (POC_INVAL); + } + data = xmlGetProp(node, name); + data_type = get_fast_dtype(node, name); + if (data_type != POC_STRING && data == NULL) { + pool_seterror(POE_INVALID_CONF); + return (POC_INVAL); + } + switch (data_type) { + case POC_UINT: + errno = 0; + uval = strtoull((char *)data, NULL, 0); + if (errno != 0) { + data_type = POC_INVAL; + } + else + pool_value_set_uint64(value, uval); + break; + case POC_INT: + errno = 0; + ival = strtoll((char *)data, NULL, 0); + if (errno != 0) { + data_type = POC_INVAL; + } + else + pool_value_set_int64(value, ival); + break; + case POC_DOUBLE: + pool_value_set_double(value, atof((const char *)data)); + break; + case POC_BOOL: + if (strcmp((const char *)data, "true") == 0) + pool_value_set_bool(value, PO_TRUE); + else + pool_value_set_bool(value, PO_FALSE); + break; + case POC_STRING: + if (pool_value_set_string(value, data ? + (const char *)data : "") != PO_SUCCESS) { + xmlFree(data); + return (POC_INVAL); + } + break; + case POC_INVAL: + default: + break; + } + xmlFree(data); + return (data_type); +} + +/* + * Set the data type for an attribute name from the element node. The + * supplied value is used to update the designated name using the data + * type supplied. + */ +int +pool_xml_set_attr(xmlNodePtr node, xmlChar *name, const pool_value_t *value) +{ + xmlChar buf[MAX_PROP_SIZE] = {0}; + uint64_t ures; + int64_t ires; + uchar_t bres; + double dres; + const char *sres; + + pool_value_class_t data_type; + + if (xmlHasProp(node, name) == NULL && pool_is_xml_attr(node->doc, + (const char *) node->name, (const char *) name) == PO_FALSE) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + + if (xmlHasProp(node, BAD_CAST c_a_dtype) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + data_type = get_fast_dtype(node, name); + if (data_type != value->pv_class) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + switch (value->pv_class) { + case POC_UINT: + (void) pool_value_get_uint64(value, &ures); + (void) snprintf((char *)buf, sizeof (buf), "%llu", + (u_longlong_t)ures); + break; + case POC_INT: + (void) pool_value_get_int64(value, &ires); + (void) snprintf((char *)buf, sizeof (buf), "%lld", + (longlong_t)ires); + break; + case POC_DOUBLE: + (void) pool_value_get_double(value, &dres); + (void) snprintf((char *)buf, sizeof (buf), "%f", dres); + break; + case POC_BOOL: + (void) pool_value_get_bool(value, &bres); + if (bres == PO_FALSE) + (void) snprintf((char *)buf, sizeof (buf), + "false"); + else + (void) snprintf((char *)buf, sizeof (buf), + "true"); + break; + case POC_STRING: + (void) pool_value_get_string(value, &sres); + if (sres != NULL) + (void) snprintf((char *)buf, sizeof (buf), "%s", + sres); + break; + case POC_INVAL: + default: + break; + } + if (xmlSetProp(node, name, buf) == NULL) { + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Get the data type for a property name from the element node. The data + * type is returned and the value of the property updates the supplied value + * pointer. The user is responsible for freeing the memory associated with + * a string. + */ +static pool_value_class_t +pool_xml_get_prop(xmlNodePtr node, xmlChar *name, pool_value_t *value) +{ + pool_value_class_t data_type; + xmlChar *data, *node_data; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr path; + char buf[MAX_PROP_SIZE]; + int64_t uval; + int64_t ival; + + /* use xpath to find the node with the appropriate value for name */ + (void) snprintf(buf, sizeof (buf), "property[@name=\"%s\"]", name); + if ((ctx = xmlXPathNewContext(node->doc)) == NULL) { + pool_seterror(POE_BADPARAM); + return (POC_INVAL); + } + ctx->node = node; + path = xmlXPathEval(BAD_CAST buf, ctx); + + if (path && (path->type == XPATH_NODESET) && + (path->nodesetval->nodeNr == 1)) { + int i; + if (xmlHasProp(path->nodesetval->nodeTab[0], + BAD_CAST c_type) == NULL) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_INVALID_CONF); + return (POC_INVAL); + } + /* type is a string representation of the type */ + data = xmlGetProp(path->nodesetval->nodeTab[0], + BAD_CAST c_type); + node_data = xmlNodeGetContent(path->nodesetval->nodeTab[0]); + data_type = POC_INVAL; + for (i = 0; i < (sizeof (data_type_tags) / + sizeof (data_type_tags[0])); i++) { + if (strcmp((char *)data, data_type_tags[i]) == 0) { + data_type = i; + break; + } + } + switch (data_type) { + case POC_UINT: + errno = 0; + uval = strtoull((char *)node_data, NULL, 0); + if (errno != 0) + data_type = POC_INVAL; + else + pool_value_set_uint64(value, uval); + break; + case POC_INT: + errno = 0; + ival = strtoll((char *)node_data, NULL, 0); + if (errno != 0) + data_type = POC_INVAL; + else + pool_value_set_int64(value, ival); + break; + case POC_DOUBLE: + pool_value_set_double(value, + atof((const char *)node_data)); + break; + case POC_BOOL: + if (strcmp((const char *)node_data, "true") + == 0) + pool_value_set_bool(value, PO_TRUE); + else + pool_value_set_bool(value, PO_FALSE); + break; + case POC_STRING: + if (pool_value_set_string(value, + (const char *)node_data) != PO_SUCCESS) { + data_type = POC_INVAL; + break; + } + break; + case POC_INVAL: + default: + break; + } + xmlFree(data); + xmlFree(node_data); + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + return (data_type); + } else { /* No property exists, clean up and return */ + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_BADPARAM); + return (POC_INVAL); + } +} + +/* + * Set the data type for a property name from the element node. The + * supplied value is used to update the designated name using the data + * type supplied. + */ +int +pool_xml_set_prop(xmlNodePtr node, xmlChar *name, const pool_value_t *value) +{ +/* First check if we have a property with this name (and type???). */ + xmlXPathContextPtr ctx; + xmlXPathObjectPtr path; + xmlChar buf[MAX_PROP_SIZE]; + xmlNodePtr element; + uint64_t ures; + int64_t ires; + uchar_t bres; + double dres; + const char *sres; + + /* use xpath to find the node with the appropriate value for name */ + (void) snprintf((char *)buf, sizeof (buf), "property[@name=\"%s\"]", + name); + if ((ctx = xmlXPathNewContext(node->doc)) == NULL) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + ctx->node = node; + path = xmlXPathEval(buf, ctx); + if (path == NULL || path->type != XPATH_NODESET) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } else { + if (path->nodesetval->nodeNr == 0) + element = property_create + (node, (const char *)name, value->pv_class); + else if (path->nodesetval->nodeNr == 1) { + int i; + xmlChar *data; + + element = path->nodesetval->nodeTab[0]; + if (xmlHasProp(element, BAD_CAST c_type) == NULL) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + data = xmlGetProp(element, BAD_CAST c_type); + for (i = 0; i < (sizeof (data_type_tags) / + sizeof (data_type_tags[0])); i++) + if (strcmp((char *)data, data_type_tags[i]) + == 0) { + break; + } + xmlFree(data); + if (value->pv_class != i) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } else { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + } + + switch (value->pv_class) { + case POC_UINT: + (void) pool_value_get_uint64(value, &ures); + (void) snprintf((char *)buf, sizeof (buf), "%llu", + (u_longlong_t)ures); + break; + case POC_INT: + (void) pool_value_get_int64(value, &ires); + (void) snprintf((char *)buf, sizeof (buf), "%lld", + (longlong_t)ires); + break; + case POC_DOUBLE: + (void) pool_value_get_double(value, &dres); + (void) snprintf((char *)buf, sizeof (buf), "%f", dres); + break; + case POC_BOOL: + (void) pool_value_get_bool(value, &bres); + if (bres == PO_FALSE) + (void) snprintf((char *)buf, sizeof (buf), + "false"); + else + (void) snprintf((char *)buf, sizeof (buf), + "true"); + break; + case POC_STRING: + (void) pool_value_get_string(value, &sres); + (void) snprintf((char *)buf, sizeof (buf), "%s", sres); + break; + case POC_INVAL: + default: + break; + } + xmlNodeSetContent(element, buf); + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + return (PO_SUCCESS); +} + +/* + * Return a NULL terminated array of pool_value_t which represents all + * of the properties stored for an element + * + * Return NULL on failure. It is the caller's responsibility to free + * the returned array of values. + */ +pool_value_t ** +pool_xml_get_properties(const pool_elem_t *pe, uint_t *nprops) +{ + pool_value_t **result; + pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; + int i, j; + pool_conf_t *conf = TO_CONF(pe); + xmlElementPtr elemDTD; + xmlAttributePtr attr; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr path; + char_buf_t *cb = NULL; + + *nprops = 0; + + elemDTD = xmlGetDtdElementDesc(pxe->pxe_node->doc->extSubset, + pxe->pxe_node->name); + for (attr = elemDTD->attributes; attr != NULL; attr = attr->nexth) { + if (strcmp((const char *)attr->name, c_a_dtype) != 0 || + strcmp((const char *)attr->name, c_type) != 0) + (*nprops)++; + } + if ((ctx = xmlXPathNewContext( + ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc)) == NULL) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + ctx->node = pxe->pxe_node; + path = xmlXPathEval(BAD_CAST "property", ctx); + + if (path != NULL && path->type == XPATH_NODESET && + path->nodesetval != NULL) + (*nprops) += path->nodesetval->nodeNr; + + if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + pool_seterror(POE_SYSTEM); + return (NULL); + } + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + free(result); + return (NULL); + } + /* + * Now store our attributes and properties in result + */ + for (i = 0, attr = elemDTD->attributes; attr != NULL; + attr = attr->nexth, i++) { + if (strcmp((const char *)attr->name, c_a_dtype) == 0 || + strcmp((const char *)attr->name, c_type) == 0) { + i--; + continue; + } + result[i] = pool_value_alloc(); + if (pool_xml_get_attr(pxe->pxe_node, + BAD_CAST attr->name, result[i]) == POC_INVAL) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + free_char_buf(cb); + return (NULL); + } + if (strcmp((const char *)attr->name, c_type) != 0) { + if (set_char_buf(cb, "%s.%s", + pool_elem_class_string(pe), attr->name) != + PO_SUCCESS) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + free_char_buf(cb); + return (NULL); + } + if (pool_value_set_name(result[i], cb->cb_buf) != + PO_SUCCESS) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + free_char_buf(cb); + return (NULL); + } + } else { + if (pool_value_set_name(result[i], + (const char *)attr->name) != PO_SUCCESS) { + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + free_char_buf(cb); + return (NULL); + } + } + } + free_char_buf(cb); + for (j = 0; j < path->nodesetval->nodeNr; j++, i++) { + xmlChar *name = xmlGetProp(path->nodesetval->nodeTab[j], + BAD_CAST c_name); + + result[i] = pool_value_alloc(); + + if (pool_xml_get_prop(pxe->pxe_node, name, result[i]) == + POC_INVAL) { + xmlFree(name); + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + return (NULL); + } + if (pool_value_set_name(result[i], (const char *)name) != + PO_SUCCESS) { + xmlFree(name); + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + while (i-- >= 0) + pool_value_free(result[i]); + free(result); + return (NULL); + } + xmlFree(name); + } + xmlXPathFreeObject(path); + xmlXPathFreeContext(ctx); + return (result); +} + +/* + * Store a pointer to one of our data types in the _private member of each + * XML data node contained within the passed node. Note this function is + * recursive and so all sub-nodes are also shadowed. Only shadow the nodes + * which we are interested in, i.e. system, pool, res and comp + */ +static int +create_shadow(xmlNodePtr node) +{ + xmlNodePtr sib; + int ret = PO_SUCCESS; + /* Create a data structure of the appropriate type */ + + if (0 == (xmlStrcmp(node->name, + BAD_CAST element_class_tags[PEC_SYSTEM]))) { + ret = pool_xml_elem_wrap(node, PEC_SYSTEM, PREC_INVALID, + PCEC_INVALID); + } else if (0 == (xmlStrcmp(node->name, + BAD_CAST element_class_tags[PEC_POOL]))) { + ret = pool_xml_elem_wrap(node, PEC_POOL, PREC_INVALID, + PCEC_INVALID); + } else if (0 == (xmlStrcmp(node->name, + BAD_CAST element_class_tags[PEC_RES_COMP]))) { + xmlChar *data; + pool_resource_elem_class_t res_class; + data = xmlGetProp(node, BAD_CAST c_type); + + res_class = pool_resource_elem_class_from_string((char *)data); + xmlFree(data); + ret = pool_xml_elem_wrap(node, PEC_RES_COMP, res_class, + PCEC_INVALID); + } else if (0 == (xmlStrcmp(node->name, + BAD_CAST element_class_tags[PEC_RES_AGG]))) { + xmlChar *data; + pool_resource_elem_class_t res_class; + data = xmlGetProp(node, BAD_CAST c_type); + + res_class = pool_resource_elem_class_from_string((char *)data); + xmlFree(data); + ret = pool_xml_elem_wrap(node, PEC_RES_AGG, res_class, + PCEC_INVALID); + } else if (0 == (xmlStrcmp(node->name, + BAD_CAST element_class_tags[PEC_COMP]))) { + xmlChar *data; + pool_component_elem_class_t comp_class; + data = xmlGetProp(node, BAD_CAST c_type); + + comp_class = pool_component_elem_class_from_string( + (char *)data); + xmlFree(data); + ret = pool_xml_elem_wrap(node, PEC_COMP, PREC_INVALID, + comp_class); + } + /* Have to shadow all children and all siblings */ + for (sib = node->children; sib != NULL; sib = sib->next) { + if ((ret = create_shadow(sib)) != PO_SUCCESS) + break; + } + return (ret); +} + + +/* + * XML Data access and navigation APIs + */ + +/* + * Close the configuration. There are a few steps to closing a configuration: + * - Unlock the backing file (if there is one) + * - Close the file (if there is one) + * - Free the shadow memory }Done in pool_xml_free_doc + * - Free the document } + * - Free the data provider for this configuration + * - Free the configuration location specifier + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_close(pool_conf_t *conf) +{ + pool_xml_connection_t *pxc = (pool_xml_connection_t *)conf->pc_prov; + int ret = PO_SUCCESS; + + if (pxc->pxc_file != NULL) { + /* Close (and implicitly) unlock the file */ + if (fclose(pxc->pxc_file) != 0) { + pool_seterror(POE_SYSTEM); + ret = PO_FAIL; + } + pxc->pxc_file = NULL; + } + /* Close the xml specific parts */ + (void) pool_xml_free_doc(conf); + pool_xml_connection_free((pool_xml_connection_t *)conf->pc_prov); + return (ret); +} + +/* + * Remove the configuration from the backing store. In XML terms delete + * the file backing the configuration. You need a copy of the location + * since the pool_conf_close function, frees the location. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_remove(pool_conf_t *conf) +{ + if (pool_conf_location(conf) != NULL) { + /* First unlink the file, to prevent races on open */ + if (unlink(pool_conf_location(conf)) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* Now close the configuration */ + (void) pool_conf_close(conf); + return (PO_SUCCESS); + } + return (PO_FAIL); +} + +/* + * Validate the configuration. There are three levels of validation, loose, + * strict and runtime. In this, XML, implementation, loose is mapped to XML + * validation, strict implements additional application level validation + * checks, e.g. all pools must have unique names, runtime ensures that this + * configuration would instantiate on the current system. + * + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_validate(const pool_conf_t *conf, pool_valid_level_t level) +{ + pool_xml_connection_t *pxc = (pool_xml_connection_t *)conf->pc_prov; + xmlValidCtxtPtr cvp; + + if ((cvp = xmlNewValidCtxt()) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + cvp->error = pool_error_func; + cvp->warning = pool_error_func; + + if (xmlValidateDocument(cvp, pxc->pxc_doc) == 0) { + xmlFreeValidCtxt(cvp); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + xmlFreeValidCtxt(cvp); + + if (level >= POV_RUNTIME) { + /* + * Note: This is resource specific. + */ + return (((pool_validate_resource(conf, "pset", c_min_prop, 0) == + PO_SUCCESS) && + (pool_validate_resource(conf, "pset", c_max_prop, 0) == + PO_SUCCESS)) ? PO_SUCCESS : PO_FAIL); + } + return (PO_SUCCESS); +} + +/* + * Commit the configuration to the backing store. In XML terms this means + * write the changes to the backing file. Read the comments below for details + * on exactly how this operation is performed. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_commit(pool_conf_t *conf) +{ + pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; + xmlOutputBufferPtr buf; + + /* + * Ensure that the configuration file has no contents + */ + if (fseek(prov->pxc_file, 0, SEEK_SET) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if (ftruncate(fileno(prov->pxc_file), 0) == -1) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Create an XML output buffer and write out the contents of the + * configuration to the file. + */ + if ((buf = xmlOutputBufferCreateFile(prov->pxc_file, NULL)) == NULL) { + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + + if (xmlSaveFormatFileTo(buf, prov->pxc_doc, NULL, 1) == -1) { + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + + return (PO_SUCCESS); +} + +/* + * Export the configuration in the specified format to the specified location. + * The only format implemented now is the native format, which saves the + * active configuration to the supplied location. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_export(const pool_conf_t *conf, const char *location, + pool_export_format_t fmt) +{ + int ret; + + switch (fmt) { + case POX_NATIVE: + ret = xmlSaveFormatFile(location, + ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc, + 1); + if (ret == -1) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } else + return (PO_SUCCESS); + + default: + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } +} + +/* + * Discard the configuration and restore the configuration to the values + * specified in the configuration location. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_rollback(pool_conf_t *conf) +{ + pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; + + /* Rollback the file pointer ready for the reparse */ + if (fseek(prov->pxc_file, 0, SEEK_SET) != 0) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* Reparse the document */ + /* In XML terms this means, discard and reparse the document */ + (void) pool_xml_free_doc(conf); + if (pool_xml_parse_document(conf) == PO_FAIL) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * Allocate a new pool_elem_t in the supplied configuration of the specified + * class. + * Returns element pointer/NULL + */ +static void +pool_xml_elem_init(pool_conf_t *conf, pool_xml_elem_t *elem, + pool_elem_class_t class, pool_resource_elem_class_t res_class, + pool_component_elem_class_t comp_class) +{ + pool_elem_t *pe = TO_ELEM(elem); + pe->pe_conf = conf; + pe->pe_class = class; + pe->pe_resource_class = res_class; + pe->pe_component_class = comp_class; + /* Set up the function pointers for element manipulation */ + pe->pe_get_prop = pool_xml_get_property; + pe->pe_put_prop = pool_xml_put_property; + pe->pe_rm_prop = pool_xml_rm_property; + pe->pe_get_props = pool_xml_get_properties; + pe->pe_remove = pool_xml_elem_remove; + pe->pe_get_container = pool_xml_get_container; + pe->pe_set_container = pool_xml_set_container; + /* + * Specific initialisation for different types of element + */ + if (class == PEC_POOL) { + pool_xml_pool_t *pp = (pool_xml_pool_t *)elem; + pp->pp_associate = pool_xml_pool_associate; + pp->pp_dissociate = pool_xml_pool_dissociate; + } + if (class == PEC_RES_COMP || class == PEC_RES_AGG) { + pool_xml_resource_t *pr = (pool_xml_resource_t *)elem; + pr->pr_is_system = pool_xml_resource_is_system; + pr->pr_can_associate = pool_xml_resource_can_associate; + } +} + +/* + * "Wrap" a suplied XML node with a pool_elem_t sub-type of the supplied + * class. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_elem_wrap(xmlNodePtr node, pool_elem_class_t class, + pool_resource_elem_class_t res_class, + pool_component_elem_class_t comp_class) +{ + pool_conf_t *conf = node->doc->_private; + pool_xml_elem_t *elem; + /* Need to do some messing about to support SubTypes */ + switch (class) { + case PEC_SYSTEM: + if ((elem = malloc(sizeof (pool_xml_system_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(elem, 0, sizeof (pool_xml_system_t)); + break; + case PEC_POOL: + if ((elem = malloc(sizeof (pool_xml_pool_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(elem, 0, sizeof (pool_xml_pool_t)); + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + if ((elem = malloc(sizeof (pool_xml_resource_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(elem, 0, sizeof (pool_xml_resource_t)); + break; + case PEC_COMP: + if ((elem = malloc(sizeof (pool_xml_component_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(elem, 0, sizeof (pool_xml_component_t)); + break; + } + pool_xml_elem_init(conf, elem, class, res_class, comp_class); + node->_private = elem; + elem->pxe_node = node; + return (PO_SUCCESS); +} + +/* + * Associate a pool to the default resource for the supplied resource + * type. + */ +int +pool_assoc_default_resource_type(pool_t *pool, pool_resource_elem_class_t type) +{ + pool_value_t *props[] = { NULL, NULL, NULL }; + uint_t rl_size; + pool_resource_t **rsl; + pool_conf_t *conf = TO_ELEM(pool)->pe_conf; + char_buf_t *cb = NULL; + pool_value_t val0 = POOL_VALUE_INITIALIZER; + pool_value_t val1 = POOL_VALUE_INITIALIZER; + + props[0] = &val0; + props[1] = &val1; + + + if (pool_value_set_string(props[0], pool_resource_type_string(type)) != + PO_SUCCESS || + pool_value_set_name(props[0], c_type) != PO_SUCCESS) { + return (PO_FAIL); + } + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { + return (PO_FAIL); + } + + if (set_char_buf(cb, "%s.default", + pool_resource_type_string(type)) != + PO_SUCCESS) { + free_char_buf(cb); + return (PO_FAIL); + } + if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { + free_char_buf(cb); + return (PO_FAIL); + } + pool_value_set_bool(props[1], PO_TRUE); + free_char_buf(cb); + + if ((rsl = pool_query_resources(conf, &rl_size, props)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + + /* + * One default resource set per type + */ + if (rl_size != 1) { + free(rsl); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + if (pool_associate(conf, pool, rsl[0]) < 0) { + free(rsl); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + free(rsl); + return (PO_SUCCESS); +} + +/* + * Create an XML node in the supplied configuration with a pool_elem_t + * sub-type of the supplied class. + * Returns pool_elem_t pointer/NULL + */ +static pool_elem_t * +pool_xml_elem_create(pool_conf_t *conf, pool_elem_class_t class, + pool_resource_elem_class_t res_class, + pool_component_elem_class_t comp_class) +{ + /* In XML terms, create an element of the appropriate class */ + pool_xml_elem_t *elem; + pool_elem_t *parent; + pool_system_t *parent_system; + + if (class == PEC_INVALID) { + pool_seterror(POE_BADPARAM); + return (NULL); + } + + /* Now create the XML component and add to it's parent */ + /* + * If we know the class of an element, we know it's parent. + * PEC_POOL, the parent must be the system node + * PEC_RES, treat as pool. + * PEC_COMP, we don't know the parent, leave this up to the + * create_comp function. + */ + /* Since we know the subtype we can create and populate the sub-type */ + switch (class) { + case PEC_POOL: + if ((parent_system = pool_conf_system(conf)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if ((parent = pool_system_elem(parent_system)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if ((elem = malloc(sizeof (pool_xml_system_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_xml_system_t)); + if ((elem->pxe_node = node_create_with_id( + ((pool_xml_elem_t *)parent)->pxe_node, + BAD_CAST element_class_tags[class])) == NULL) { + pool_seterror(POE_DATASTORE); + (void) pool_xml_elem_remove((pool_elem_t *)elem); + return (NULL); + } + break; + case PEC_RES_COMP: + case PEC_RES_AGG: + if ((parent_system = pool_conf_system(conf)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if ((parent = pool_system_elem(parent_system)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (NULL); + } + if ((elem = malloc(sizeof (pool_xml_resource_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_xml_resource_t)); + if ((elem->pxe_node = node_create_with_id + (((pool_xml_elem_t *)parent)->pxe_node, + BAD_CAST element_class_tags[class])) == NULL) { + pool_seterror(POE_DATASTORE); + (void) pool_xml_elem_remove((pool_elem_t *)elem); + return (NULL); + } + break; + case PEC_COMP: + if ((elem = malloc(sizeof (pool_xml_component_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(elem, 0, sizeof (pool_xml_component_t)); + if ((elem->pxe_node = node_create(NULL, + BAD_CAST element_class_tags[class])) == NULL) { + pool_seterror(POE_DATASTORE); + (void) pool_xml_elem_remove((pool_elem_t *)elem); + return (NULL); + } + break; + default: + pool_seterror(POE_BADPARAM); + return (NULL); + } + pool_xml_elem_init(conf, elem, class, res_class, comp_class); + elem->pxe_node->_private = elem; + if (class == PEC_RES_COMP || class == PEC_RES_AGG || + class == PEC_COMP) { + /* + * Put the type and an invalid sys_id on the node. + */ + if (xmlSetProp(elem->pxe_node, BAD_CAST c_sys_prop, + BAD_CAST POOL_SYSID_BAD_STRING) == NULL) { + pool_seterror(POE_DATASTORE); + (void) pool_xml_elem_remove((pool_elem_t *)elem); + return (NULL); + } + if (xmlSetProp(elem->pxe_node, BAD_CAST c_type, + BAD_CAST pool_elem_class_string( + (pool_elem_t *)elem)) == NULL) { + pool_seterror(POE_DATASTORE); + (void) pool_xml_elem_remove((pool_elem_t *)elem); + return (NULL); + } + } + if (class == PEC_POOL) { + /* + * Note: This is resource specific. + */ + if (pool_assoc_default_resource_type(pool_elem_pool( + (pool_elem_t *)elem), PREC_PSET) == PO_FAIL) { + (void) pool_xml_elem_remove((pool_elem_t *)elem); + return (NULL); + } + } + return ((pool_elem_t *)elem); +} + +/* + * Allocate a data provider for the supplied configuration and optionally + * discover resources. + * The data provider is the cross over point from the "abstract" configuration + * functions into the data representation specific manipulation routines. + * This function sets up all the required pointers to create an XML aware + * data provider. + * Returns PO_SUCCESS/PO_FAIL + */ +int +pool_xml_connection_alloc(pool_conf_t *conf, int oflags) +{ + pool_xml_connection_t *prov; + + xml_init(); + if ((prov = malloc(sizeof (pool_xml_connection_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + (void) memset(prov, 0, sizeof (pool_xml_connection_t)); + /* + * Initialise data members + */ + prov->pc_name = strdup("LIBXML 2.4.0"); + prov->pc_store_type = XML_DATA_STORE; + prov->pc_oflags = oflags; + /* + * Initialise function pointers + */ + prov->pc_close = pool_xml_close; + prov->pc_validate = pool_xml_validate; + prov->pc_commit = pool_xml_commit; + prov->pc_export = pool_xml_export; + prov->pc_rollback = pool_xml_rollback; + prov->pc_exec_query = pool_xml_exec_query; + prov->pc_elem_create = pool_xml_elem_create; + prov->pc_remove = pool_xml_remove; + prov->pc_res_xfer = pool_xml_res_transfer; + prov->pc_res_xxfer = pool_xml_res_xtransfer; + /* + * End of common initialisation + */ + /* + * Associate the provider to it's configuration + */ + conf->pc_prov = (pool_connection_t *)prov; + /* + * At this point the configuration provider has been initialized, + * mark the configuration as valid so that the various routines + * which rely on a valid configuration will work correctly. + */ + conf->pc_state = POF_VALID; + + if ((oflags & PO_CREAT) != 0) { + pool_conf_t *dyn; + + if ((dyn = pool_conf_alloc()) == NULL) + return (PO_FAIL); + + if (pool_conf_open(dyn, pool_dynamic_location(), + PO_RDONLY) != PO_SUCCESS) { + pool_conf_free(dyn); + return (PO_FAIL); + } + + if (pool_conf_export(dyn, conf->pc_location, + POX_NATIVE) != PO_SUCCESS) { + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + return (PO_FAIL); + } + (void) pool_conf_close(dyn); + pool_conf_free(dyn); + } + + if (pool_xml_open_file(conf) == PO_FAIL) { + (void) pool_xml_close(conf); + return (PO_FAIL); + } + + return (PO_SUCCESS); +} + +/* + * Free the resources for an XML data provider. + */ +static void +pool_xml_connection_free(pool_xml_connection_t *prov) +{ + free((void *)prov->pc_name); + free(prov); +} + +/* + * Allocate a result set. The Result Set stores the result of an XPath + * query along with the parameters used to create the result set (for + * debugging purposes). + * Returns pool_xml_result_set_t pointer/NULL + */ +static pool_xml_result_set_t * +pool_xml_result_set_alloc(const pool_conf_t *conf) +{ + pool_xml_result_set_t *rs; + + if ((rs = malloc(sizeof (pool_xml_result_set_t))) == NULL) { + pool_seterror(POE_SYSTEM); + return (NULL); + } + (void) memset(rs, 0, sizeof (pool_xml_result_set_t)); + rs->prs_conf = conf; + rs->prs_index = -1; + rs->prs_active = PO_TRUE; + /* Fix up the result set accessor functions to the xml specfic ones */ + rs->prs_next = pool_xml_rs_next; + rs->prs_prev = pool_xml_rs_prev; + rs->prs_first = pool_xml_rs_first; + rs->prs_last = pool_xml_rs_last; + rs->prs_get_index = pool_xml_rs_get_index; + rs->prs_set_index = pool_xml_rs_set_index; + rs->prs_close = pool_xml_rs_close; + rs->prs_count = pool_xml_rs_count; + return (rs); +} + +/* + * Free a result set. Ensure that the resources are all released at this point. + */ +static void +pool_xml_result_set_free(pool_xml_result_set_t *rs) +{ + if (rs->pxr_path != NULL) + xmlXPathFreeObject(rs->pxr_path); + if (rs->pxr_ctx != NULL) + xmlXPathFreeContext(rs->pxr_ctx); + free(rs); +} + +/* + * Transfer size from one resource to another. + * Returns PO_SUCCESS/PO_FAIL + */ +/* ARGSUSED */ +int +pool_xml_res_transfer(pool_resource_t *src, pool_resource_t *tgt, uint64_t size) +{ + return (PO_SUCCESS); +} + +/* + * Transfer components rl from one resource to another. + * Returns PO_SUCCESS/PO_FAIL + */ +/* ARGSUSED */ +int +pool_xml_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt, + pool_component_t **rl) { + int i; + + /* + * Walk the Result Set and move the resource components + */ + for (i = 0; rl[i] != NULL; i++) { + if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[i])) == + PO_FAIL) { + return (PO_FAIL); + } + } + return (PO_SUCCESS); +} + +/* + * Return the next element in a result set. + * Returns pool_elem_t pointer/NULL + */ +static pool_elem_t * +pool_xml_rs_next(pool_result_set_t *set) +{ + pool_elem_t *next; + /* Since I know this is an XML result set */ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + /* Update the context node */ + if (xset->prs_index == xset->pxr_path->nodesetval->nodeNr - 1) + return (NULL); + next = + xset->pxr_path->nodesetval->nodeTab[++xset->prs_index]->_private; + return (next); +} + +/* + * Return the previous element in a result set. + * Returns pool_elem_t pointer/NULL + */ +static pool_elem_t * +pool_xml_rs_prev(pool_result_set_t *set) +{ + pool_elem_t *prev; + /* Since I know this is an XML result set */ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + /* Update the context node */ + if (xset->prs_index < 0) + return (NULL); + prev = + xset->pxr_path->nodesetval->nodeTab[xset->prs_index--]->_private; + return (prev); +} + +/* + * Sets the current index in a result set. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_rs_set_index(pool_result_set_t *set, int index) +{ + /* Since I know this is an XML result set */ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + if (index < 0 || index >= xset->pxr_path->nodesetval->nodeNr) { + pool_seterror(POE_BADPARAM); + return (PO_FAIL); + } + xset->prs_index = index; + return (PO_SUCCESS); +} + +/* + * Return the current index in a result set. + * Returns current index + */ +static int +pool_xml_rs_get_index(pool_result_set_t *set) +{ + /* Since I know this is an XML result set */ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + return (xset->prs_index); +} + +/* + * Return the first element in a result set. + * Returns pool_elem_t pointer/NULL + */ +static pool_elem_t * +pool_xml_rs_first(pool_result_set_t *set) +{ + /* Since I know this is an XML result set */ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + /* Update the context node */ + return (xset->pxr_path->nodesetval->nodeTab[0]->_private); +} + +/* + * Return the last element in a result set. + * Returns pool_elem_t pointer/NULL + */ +static pool_elem_t * +pool_xml_rs_last(pool_result_set_t *set) +{ + /* Since I know this is an XML result set */ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + /* Update the context node */ + return (xset->pxr_path->nodesetval-> + nodeTab[xset->pxr_path->nodesetval->nodeNr-1]->_private); +} + +/* + * Return the number of results in a result set. + * Returns result count + */ +static int +pool_xml_rs_count(pool_result_set_t *set) +{ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + return (xset->pxr_path->nodesetval->nodeNr); +} + + +/* + * Close a result set. Remove this result set from the list of results and + * free the resources + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_rs_close(pool_result_set_t *set) +{ + pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; + + pool_xml_result_set_free(xset); + return (PO_SUCCESS); +} + +/* + * Set the container for a node. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_set_container(pool_elem_t *pp, pool_elem_t *pc) +{ + pool_xml_elem_t *pxp; + pool_xml_elem_t *pxc; + xmlNodePtr parent; + + pxp = (pool_xml_elem_t *)pp; + pxc = (pool_xml_elem_t *)pc; + parent = pxc->pxe_node->parent; + + xmlUnlinkNode(pxc->pxe_node); + if (xmlAddChild(pxp->pxe_node, pxc->pxe_node) == NULL) { + /* Try to move back */ + (void) xmlAddChild(parent, pxc->pxe_node); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + pc->pe_conf = pp->pe_conf; + return (PO_SUCCESS); +} +/* + * Get the container for a node. + * Returns Container/NULL + */ +static pool_elem_t * +pool_xml_get_container(const pool_elem_t *pc) +{ + pool_xml_elem_t *pxc = (pool_xml_elem_t *)pc; + + return ((pool_elem_t *)pxc->pxe_node->parent->_private); +} + +/* + * Note: This function is resource specific, needs extending for other + * resource types. + */ +int +pool_xml_resource_is_system(const pool_resource_t *pr) +{ + switch (pool_resource_elem_class(TO_ELEM(pr))) { + case PREC_PSET: + return (PSID_IS_SYSSET( + elem_get_sysid(TO_ELEM(pr)))); + default: + return (PO_FALSE); + } +} + +/* + * Note: This function is resource specific, needs extending for other + * resource types. + */ +int +pool_xml_resource_can_associate(const pool_resource_t *pr) +{ + switch (pool_resource_elem_class(TO_ELEM(pr))) { + case PREC_PSET: + return (PO_TRUE); + default: + return (PO_FALSE); + } +} + +/* + * Note: This function is resource specific. It must be extended to support + * multiple resource types. + */ +int +pool_xml_pool_associate(pool_t *pool, const pool_resource_t *pr) +{ + pool_value_t val = POOL_VALUE_INITIALIZER; + + if (pool_xml_get_property(TO_ELEM(pr), + "pset.ref_id", &val) != POC_STRING) + return (PO_FAIL); + if (pool_xml_put_property(TO_ELEM(pool), "pool.res", &val) != + PO_SUCCESS) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * pool_xml_pool_dissociate() simply finds the default resource for + * the type of resource being dissociated and then calls + * pool_xml_pool_associate() to associate to the default resource. + */ +int +pool_xml_pool_dissociate(pool_t *pool, const pool_resource_t *pr) +{ + const pool_resource_t *default_res; + + if ((default_res = get_default_resource(pr)) == NULL) + return (PO_FAIL); + if (default_res == pr) + return (PO_SUCCESS); + return (pool_xml_pool_associate(pool, default_res)); +} + +/* + * pool_xml_open_file() opens a file for a configuration. This establishes + * the locks required to ensure data integrity when manipulating a + * configuration. + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_xml_open_file(pool_conf_t *conf) +{ + struct flock lock; + struct stat s; + + pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; + + /* + * Always close the pxc_file in case there was a previously failed open + */ + if (prov->pxc_file != NULL) { + (void) fclose(prov->pxc_file); + prov->pxc_file = NULL; + } + + /* + * Check that the DTD required for this operation is present. + * If it isn't fail + */ + if (dtd_exists(dtd_location) == PO_FALSE) { + pool_seterror(POE_DATASTORE); + return (PO_FAIL); + } + + if ((prov->pc_oflags & PO_RDWR) != 0) + prov->pxc_file = fopen(conf->pc_location, "r+F"); + else /* Assume opening PO_RDONLY */ + prov->pxc_file = fopen(conf->pc_location, "rF"); + + if (prov->pxc_file == NULL) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + /* + * Setup the lock for the file + */ + lock.l_type = (prov->pc_oflags & PO_RDWR) ? F_WRLCK : F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + if (fcntl(fileno(prov->pxc_file), F_SETLKW, &lock) == -1) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* + * Check to see if the document was removed whilst waiting for + * the lock. If it was return an error. + */ + if (stat(conf->pc_location, &s) == -1) { + (void) fclose(prov->pxc_file); + prov->pxc_file = NULL; + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + /* Parse the document */ + if (pool_xml_parse_document(conf) != PO_SUCCESS) + return (PO_FAIL); + return (PO_SUCCESS); +} + +/* + * Try to work out if an element contains an attribute of the supplied name. + * Search the internal subset first and then the external subset. + * Return PO_TRUE if there is an attribute of that name declared for that + * element. + */ +int +pool_is_xml_attr(xmlDocPtr doc, const char *elem, const char *attr) +{ + xmlDtdPtr internal = xmlGetIntSubset(doc); + xmlDtdPtr external = doc->extSubset; + + if (xmlGetDtdAttrDesc(internal, BAD_CAST elem, BAD_CAST attr) == NULL) + if (xmlGetDtdAttrDesc(external, + BAD_CAST elem, BAD_CAST attr) == NULL) + return (PO_FALSE); + return (PO_TRUE); +} + +/* + * Execute the specified query using XPath. This complex function relies on + * a couple of helpers to build up an XPath query, pool_build_xpath_buf in + * particular. + * conf - the pool configuration being manipulated + * src - the root of the search, if NULL that means whole document + * src_attr - if supplied means an IDREF(S) search on this attribute + * classes - target classes + * props - target properties + * Returns pool_result_set_t pointer/NULL + */ +pool_result_set_t * +pool_xml_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) +{ + char *buf = NULL; + char_buf_t *cb = NULL; + pool_xml_result_set_t *rs; + pool_xml_elem_t *pxe = (pool_xml_elem_t *)src; + pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; + + if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) + return (NULL); + + /* + * Prior to building up the complex XPath query, check to see if + * src_attr is an IDREF(S). If it is use the IDREF(S) information + * to generate the query rather than the other data + */ + if (src_attr != NULL) { + char *tok; + char *lasts; + char *or = ""; + xmlChar *id; + + /* + * Check the arguments for consistency + */ + if (pool_is_xml_attr(prov->pxc_doc, + element_class_tags[src->pe_class], src_attr) != PO_TRUE) { + free_char_buf(cb); + pool_seterror(POE_BADPARAM); + return (NULL); + } + + if ((id = xmlGetProp(pxe->pxe_node, BAD_CAST src_attr)) + == NULL) { + free_char_buf(cb); + pool_seterror(POE_DATASTORE); + return (NULL); + } + for (tok = strtok_r((char *)id, " ", &lasts); + tok != NULL; tok = strtok_r(NULL, " ", &lasts)) { + (void) append_char_buf(cb, "%s//*[@ref_id=\"%s\"]", + or, tok); + or = " | "; + if ((classes & PEC_QRY_SYSTEM) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_SYSTEM, + props, cb, PO_TRUE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + if ((classes & PEC_QRY_POOL) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_POOL, + props, cb, PO_TRUE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + if ((classes & PEC_QRY_RES_COMP) != 0) { + if (pool_build_xpath_buf(prov, src, + PEC_RES_COMP, props, cb, PO_TRUE) + == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } else if ((classes & PEC_QRY_RES_AGG) != 0) { + if (pool_build_xpath_buf(prov, src, + PEC_RES_AGG, props, cb, PO_TRUE) + == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + } + xmlFree(id); + } else { + /* + * Build up an XPath query using the supplied parameters. + * The basic logic is to: + * - Identify which classes are the targets of the query + * - For each class work out if the props are attributes or not + * - Build up a piece of XPath for each class + * - Combine the results into one large XPath query. + * - Execute the query. + */ + if ((classes & PEC_QRY_SYSTEM) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_SYSTEM, props, + cb, PO_FALSE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + if ((classes & PEC_QRY_POOL) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_POOL, props, + cb, PO_FALSE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + if ((classes & PEC_QRY_RES_COMP) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_RES_COMP, props, + cb, PO_FALSE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + if ((classes & PEC_QRY_RES_AGG) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_RES_AGG, props, + cb, PO_FALSE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + if ((classes & PEC_QRY_COMP) != 0) { + if (pool_build_xpath_buf(prov, src, PEC_COMP, props, + cb, PO_FALSE) == PO_FAIL) { + free_char_buf(cb); + return (NULL); + } + } + } + buf = strdup(cb->cb_buf); + free_char_buf(cb); + /* + * Have a buffer at this point, that we can use + */ + if ((rs = pool_xml_result_set_alloc(conf)) == NULL) { + free(buf); + return (NULL); + } + /* + * Set up the XPath Query + */ + if ((rs->pxr_ctx = xmlXPathNewContext( + ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc)) == NULL) { + free(buf); + (void) pool_xml_rs_close((pool_result_set_t *)rs); + pool_seterror(POE_DATASTORE); + return (NULL); + } + if (src == NULL) + rs->pxr_ctx->node = xmlDocGetRootElement + (((pool_xml_connection_t *)conf->pc_prov)->pxc_doc); + else + rs->pxr_ctx->node = pxe->pxe_node; + /* + * Select + */ + rs->pxr_path = xmlXPathEval(BAD_CAST buf, rs->pxr_ctx); + free(buf); + /* + * Generate the result set and wrap the results as pool_elem_t + */ + if (rs->pxr_path->nodesetval->nodeNr == 0) + pool_seterror(POE_INVALID_SEARCH); + return ((pool_result_set_t *)rs); +} + +/* + * Build an XPath query buffer. This is complex and a little fragile, but + * I'm trying to accomplish something complex with as little code as possible. + * I wait the implementation of XMLQuery with baited breath... + * Returns PO_SUCCESS/PO_FAIL + */ +static int +pool_build_xpath_buf(pool_xml_connection_t *prov, const pool_elem_t *src, + pool_elem_class_t class, pool_value_t *props[], char_buf_t *cb, int is_ref) +{ + int i; + const char *ATTR_FMTS[] = { + "[ @%s=\"%llu\" ]", /* POC_UINT */ + "[ @%s=\"%lld\" ]", /* POC_INT */ + "[ @%s=\"%f\" ]", /* POC_DOUBLE */ + "[ @%s=\"%s\" ]", /* POC_BOOL */ + "[ @%s=\"%s\" ]", /* POC_STRING */ + }; + const char *PROP_FMTS[] = { + "[ property[@name=\"%s\"][text()=\"%llu\"] ]", /* POC_UINT */ + "[ property[@name=\"%s\"][text()=\"%lld\"] ]", /* POC_INT */ + "[ property[@name=\"%s\"][text()=\"%f\"] ]", /* POC_DOUBLE */ + "[ property[@name=\"%s\"][text()=\"%s\"] ]", /* POC_BOOL */ + "[ property[@name=\"%s\"][text()=\"%s\"] ]" /* POC_STRING */ + }; + const char **fmts; + int nprop; + const char *last_prop_name = NULL; + char *type_prefix = NULL; + int has_type = PO_FALSE; + + if (is_ref == PO_FALSE) { + if (cb->cb_buf != NULL && strlen(cb->cb_buf) > 0) + (void) append_char_buf(cb, " |"); + if (src != NULL) + (void) append_char_buf(cb, " ./"); + else + (void) append_char_buf(cb, "//"); + (void) append_char_buf(cb, element_class_tags[class]); + } + if (props == NULL || props[0] == NULL) + return (PO_SUCCESS); + for (nprop = 0; props[nprop] != NULL; nprop++) + /* Count properties */; + /* + * Sort the attributes and properties by name. + */ + qsort(props, nprop, sizeof (pool_value_t *), prop_sort); + for (i = 0; i < nprop; i++) { + int is_attr = 0; + const char *prefix; + const char *prop_name; + uint64_t uval; + int64_t ival; + double dval; + uchar_t bval; + const char *sval; + pool_value_class_t pvc; + + prop_name = pool_value_get_name(props[i]); + if ((prefix = is_a_known_prefix(class, prop_name)) != NULL) { + const char *attr_name; + /* + * Possibly an attribute. Strip off the prefix. + */ + if (strcmp(prop_name, c_type) == 0) { + has_type = PO_TRUE; + attr_name = prop_name; + } else + attr_name = prop_name + strlen(prefix) + 1; + if (pool_is_xml_attr(prov->pxc_doc, + element_class_tags[class], attr_name)) { + is_attr = 1; + prop_name = attr_name; + if (class == PEC_RES_COMP || + class == PEC_RES_AGG || + class == PEC_COMP) { + if (type_prefix != NULL) + free(type_prefix); + type_prefix = strdup(prefix); + } + } + } + if (is_attr) { + fmts = ATTR_FMTS; + } else { + fmts = PROP_FMTS; + } + /* + * Add attributes/properties to the search buffer + */ + switch ((pvc = pool_value_get_type(props[i]))) { + case POC_UINT: + (void) pool_value_get_uint64(props[i], &uval); + if (append_char_buf(cb, fmts[pvc], prop_name, uval) + == PO_FAIL) { + free(type_prefix); + return (PO_FAIL); + } + break; + case POC_INT: + (void) pool_value_get_int64(props[i], &ival); + if (append_char_buf(cb, fmts[pvc], prop_name, ival) + == PO_FAIL) { + free(type_prefix); + return (PO_FAIL); + } + break; + case POC_DOUBLE: + (void) pool_value_get_double(props[i], &dval); + if (append_char_buf(cb, fmts[pvc], prop_name, dval) + == PO_FAIL) { + free(type_prefix); + return (PO_FAIL); + } + break; + case POC_BOOL: + (void) pool_value_get_bool(props[i], &bval); + if (append_char_buf(cb, fmts[pvc], prop_name, + bval ? "true" : "false") == PO_FAIL) { + free(type_prefix); + return (PO_FAIL); + } + break; + case POC_STRING: + (void) pool_value_get_string(props[i], &sval); + if (append_char_buf(cb, fmts[pvc], prop_name, sval) + == PO_FAIL) { + free(type_prefix); + return (PO_FAIL); + } + break; + default: + free(type_prefix); + pool_seterror(POE_INVALID_SEARCH); + return (PO_FAIL); + } + if (last_prop_name != NULL) { + const char *suffix1, *suffix2; + /* + * Extra fiddling for namespaces + */ + suffix1 = strrchr(prop_name, '.'); + suffix2 = strrchr(last_prop_name, '.'); + + if (suffix1 != NULL || suffix2 != NULL) { + if (suffix1 == NULL) + suffix1 = prop_name; + else + suffix1++; + if (suffix2 == NULL) + suffix2 = last_prop_name; + else + suffix2++; + } else { + suffix1 = prop_name; + suffix2 = last_prop_name; + } + if (strcmp(suffix1, suffix2) == 0) { + char *where = strrchr(cb->cb_buf, '['); + if (is_attr != PO_TRUE) { + /* repeat */ + while (*--where != '[') + ; + while (*--where != '[') + ; + } + *(where - 1) = 'o'; + *where = 'r'; + } + } + last_prop_name = prop_name; + } + if (has_type == PO_FALSE) { + if (type_prefix) { + if (append_char_buf(cb, ATTR_FMTS[POC_STRING], + c_type, type_prefix) == PO_FAIL) { + free(type_prefix); + return (PO_FAIL); + } + } + } + free(type_prefix); + return (PO_SUCCESS); +} + +/* + * Utility routine for use by quicksort. Assumes that the supplied data + * are pool values and compares the names of the two pool values. + * Returns an integer greater than, equal to, or less than 0. + */ +static int +prop_sort(const void *a, const void *b) +{ + pool_value_t **prop_a = (pool_value_t **)a; + pool_value_t **prop_b = (pool_value_t **)b; + const char *str_a; + const char *str_b; + const char *suffix1, *suffix2; + + str_a = pool_value_get_name(*prop_a); + str_b = pool_value_get_name(*prop_b); + /* + * Extra fiddling for namespaces + */ + suffix1 = strrchr(str_a, '.'); + suffix2 = strrchr(str_b, '.'); + + if (suffix1 != NULL || suffix2 != NULL) { + if (suffix1 == NULL) + suffix1 = str_a; + else + suffix1++; + if (suffix2 == NULL) + suffix2 = str_b; + else + suffix2++; + } else { + suffix1 = str_a; + suffix2 = str_b; + } + return (strcmp(suffix1, suffix2)); +} + +/* + * Order the elements by (ref_id) + */ + +/* + * Returns PO_TRUE/PO_FALSE to indicate whether the supplied path exists on the + * system. It is assumed that the supplied path is in URL format and represents + * a file and so file:// is stripped from the start of the search. + */ +static int +dtd_exists(const char *path) +{ + struct stat buf; + + if (strstr(path, "file://") != path) + return (PO_FALSE); + + if (path[7] == 0) + return (PO_FALSE); + + if (stat(&path[7], &buf) == 0) + return (PO_TRUE); + return (PO_FALSE); +} + +/* + * Build the dtype structures to accelerate data type lookup operations. The + * purpose is to avoid expensive XML manipulations on data which will not + * change over the life of a library invocation. It is designed to be invoked + * once from the library init function. + */ +static void +build_dtype_accelerator(void) +{ + xmlDtdPtr dtd; + const xmlChar *elem_list[ELEM_TYPE_COUNT] = { + BAD_CAST "res_comp", + BAD_CAST "res_agg", + BAD_CAST "comp", + BAD_CAST "pool", + BAD_CAST "property", + BAD_CAST "system" }; + int i; + + if (_libpool_xml_initialised == PO_TRUE) + return; + + /* Load up the d-type data for each element */ + /* + * Store data type information in nested lists + * Top level list contains attribute declaration pointers which + * can be used to match with supplied nodes. + * Second level list contains attribute type information for each + * element declaration + */ + /* + * Unfortunately, there's no easy way to get a list of all DTD + * element descriptions as there is no libxml API to do this (they + * are stored in a hash, which I guess is why). Explicitly seek + * for descriptions for elements that are known to hold an a-dtype + * attribute and build accelerators for those elements. + * If the DTD changes, the library may have to change as well now, + * since this code makes explicit assumptions about which elements + * contain a-dtype information. + */ + + if ((dtd = xmlParseDTD(BAD_CAST "-//Sun Microsystems Inc//DTD Resource" + " Management All//EN", BAD_CAST dtd_location)) == NULL) + return; + for (i = 0; i < ELEM_TYPE_COUNT; i++) { + xmlElementPtr elem; + xmlAttributePtr attr; + + if ((elem = xmlGetDtdElementDesc(dtd, elem_list[i])) == NULL) + return; + elem_tbl[i].ett_elem = xmlStrdup(elem->name); + /* Walk the list of attributes looking for a-dtype */ + for (attr = elem->attributes; attr != NULL; + attr = attr->nexth) { + if (strcmp((const char *)attr->name, c_a_dtype) == 0) { + /* + * Allocate a dtype_tbl_t + */ + elem_tbl[i].ett_dtype = + build_dtype_tbl(attr->defaultValue); + /* This could have returned NULL */ + } + } + } + xmlFreeDtd(dtd); +} + +/* + * build_dtype_tbl() parses the supplied data and returns an array (max size + * of 10, increase if required) of dtype_tbl_t structures holding data type + * information for an element. The supplied data is assumed to be in "a-dtype" + * format. The dtype_tbl_t array is NULL terminated, which is why space for + * 11 members is allocated. + */ +static dtype_tbl_t +(*build_dtype_tbl(const xmlChar *rawdata))[] +{ + char *tok; + char *lasts; + dtype_tbl_t (*tbl)[]; + int j = 0; + xmlChar *data; + const int max_attr = 11; /* Not more than 10 types per element */ + + /* + * Parse the supplied data, assumed to be in a-dtype format, and + * generate a lookup table which is indexed by the name and contains + * the data type + */ + if (rawdata == NULL) + return (NULL); + if ((data = xmlStrdup(rawdata)) == NULL) + return (NULL); + if ((tbl = calloc(max_attr, sizeof (dtype_tbl_t))) == NULL) { + xmlFree(data); + return (NULL); + } + for (tok = strtok_r((char *)data, " ", &lasts); tok != NULL; + tok = strtok_r(NULL, " ", &lasts)) { + int i; + (*tbl)[j].dt_name = xmlStrdup(BAD_CAST tok); + if ((tok = strtok_r(NULL, " ", &lasts)) == NULL) { + int k = j; + for (j = 0; j < k; j++) + free((*tbl)[j].dt_name); + pool_seterror(POE_DATASTORE); + xmlFree(data); + free(tbl); + return (NULL); + } + for (i = 0; i < (sizeof (data_type_tags) / + sizeof (data_type_tags[0])); i++) { + if (strcmp(tok, data_type_tags[i]) == 0) + (*tbl)[j++].dt_type = i; + } + if (j == max_attr) { /* too many attributes, bail out */ + for (j = 0; j < max_attr; j++) + free((*tbl)[j].dt_name); + free(tbl); + xmlFree(data); + return (NULL); + } + } + (*tbl)[j].dt_name = NULL; /* Terminate the table */ + xmlFree(data); + return (tbl); +} + +/* + * get_fast_dtype() finds the data type for a supplied attribute name on a + * supplied node. This is called get_fast_dtype() because it uses the cached + * data type information created at library initialisation. + */ +static int +get_fast_dtype(xmlNodePtr node, xmlChar *name) +{ + int i; + xmlElementPtr elem; + + if ((elem = xmlGetDtdElementDesc(node->doc->extSubset, node->name)) + == NULL) { + pool_seterror(POE_BADPARAM); + return (POC_INVAL); + } + + for (i = 0; i < ELEM_TYPE_COUNT; i++) { + if (xmlStrcmp(elem_tbl[i].ett_elem, elem->name) == 0) { + dtype_tbl_t (*tbl)[] = elem_tbl[i].ett_dtype; + int j = 0; + + if (tbl == NULL) + break; + for (j = 0; (*tbl)[j].dt_name != NULL; j++) + if (xmlStrcmp(name, (*tbl)[j].dt_name) == 0) + return ((*tbl)[j].dt_type); /* found */ + break; /* if we didn't find it in the elem, break */ + } + } + /* If we can't find it, say it's a string */ + return (POC_STRING); +} + +/* + * pool_xml_parse_document() parses the file associated with a supplied + * configuration to regenerate the runtime representation. The supplied + * configuration must reference an already opened file and this is used + * to generate the XML representation via the configuration provider's + * pxc_doc member. + * size must be >=4 in order for "content encoding detection" to work. + */ +static int +pool_xml_parse_document(pool_conf_t *conf) +{ + int res; + char chars[PAGE_READ_SIZE]; + struct stat f_stat; + xmlParserCtxtPtr ctxt; + size_t size; + pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; + xmlNodePtr root; + pool_resource_t **rsl; + uint_t nelem; + int i; + + if (fstat(fileno(prov->pxc_file), &f_stat) == -1) { + pool_seterror(POE_SYSTEM); + return (PO_FAIL); + } + + if (f_stat.st_size == 0) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } else + size = f_stat.st_size < 4 ? 4 : PAGE_READ_SIZE; + + res = fread(chars, 1, size, prov->pxc_file); + + if (res >= 4) { + xmlValidCtxtPtr cvp; + + if ((ctxt = xmlCreatePushParserCtxt(NULL, NULL, + chars, res, conf->pc_location)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + + while ((res = fread(chars, 1, size, prov->pxc_file)) > 0) { + if (xmlParseChunk(ctxt, chars, res, 0) != 0) { + xmlFreeParserCtxt(ctxt); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + } + if (xmlParseChunk(ctxt, chars, 0, 1) != 0) { + xmlFreeParserCtxt(ctxt); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + + if ((cvp = xmlNewValidCtxt()) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + cvp->error = pool_error_func; + cvp->warning = pool_error_func; + + if (xmlValidateDocument(cvp, ctxt->myDoc) == 0) { + xmlFreeValidCtxt(cvp); + xmlFreeParserCtxt(ctxt); + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + prov->pxc_doc = ctxt->myDoc; + xmlFreeValidCtxt(cvp); + xmlFreeParserCtxt(ctxt); + } + if (prov->pxc_doc == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + prov->pxc_doc->_private = conf; + + /* Get the root element */ + if ((root = xmlDocGetRootElement(prov->pxc_doc)) == NULL) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + /* + * Ensure that the parsed tree has been contained within + * our shadow tree. + */ + if (create_shadow(root) != PO_SUCCESS) { + pool_seterror(POE_INVALID_CONF); + return (PO_FAIL); + } + + if (pool_xml_validate(conf, POV_STRICT) != PO_SUCCESS) { + return (PO_FAIL); + } + /* + * For backwards compatibility with S9, make sure that all + * resources have a size and that it is correct. + */ + if ((rsl = pool_query_resources(conf, &nelem, NULL)) != NULL) { + pool_value_t val = POOL_VALUE_INITIALIZER; + for (i = 0; i < nelem; i++) { + if (pool_get_ns_property(TO_ELEM(rsl[i]), c_size_prop, + &val) != POC_UINT) { + pool_component_t **cs; + uint_t size; + if ((cs = pool_query_resource_components(conf, + rsl[i], &size, NULL)) != NULL) { + free(cs); + pool_value_set_uint64(&val, size); + } else + pool_value_set_uint64(&val, 0); + if (pool_put_any_ns_property(TO_ELEM(rsl[i]), + c_size_prop, &val) != PO_SUCCESS) { + free(rsl); + return (PO_FAIL); + } + } + } + free(rsl); + } + return (PO_SUCCESS); +} diff --git a/usr/src/lib/libpool/common/pool_xml_impl.h b/usr/src/lib/libpool/common/pool_xml_impl.h new file mode 100644 index 0000000..dadfa77 --- /dev/null +++ b/usr/src/lib/libpool/common/pool_xml_impl.h @@ -0,0 +1,198 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _POOL_XML_IMPL_H +#define _POOL_XML_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains the definitions of types and supporting + * functions to implement the libpool XML specific data manipulation + * facility. + * + * For more information on the libpool generic data manipulation + * facility, look at pool_impl.h. + * + * The central types for the generic data representation/storage + * facility are here enhanced to provide additional XML specific + * information. + */ + +/* + * pool_xml_elem_t is the XML (to be precise, libxml - although this + * could be easily ported to an alternative C-API xml library) + * specific representation of the pool_elem_t structure. + * + * The pxe_node pointer is a pointer to an XML element which + * represents the element in the XML document + */ +typedef struct pool_xml_elem { + /* + * Common to pool_elem_t + */ + pool_elem_t pxe_elem; + void *pxe_pad1; + void *pxe_pad2; + /* + * Common to pool_xml_elem_t + */ + xmlNodePtr pxe_node; /* XML Element */ +} pool_xml_elem_t; + +typedef pool_xml_elem_t pool_xml_system_t; + +typedef struct pool_xml_resource { + /* + * Common to pool_elem_t + */ + pool_elem_t pxe_elem; + /* + * Specific to pool_resource_t + */ + int (*pr_is_system)(const pool_resource_t *); + int (*pr_can_associate)(const pool_resource_t *); + /* + * Common to pool_xml_elem_t + */ + xmlNodePtr pxe_node; /* XML Element */ +} pool_xml_resource_t; + +typedef struct pool_xml_pool { + /* + * Common to pool_elem_t + */ + pool_elem_t pxe_elem; + /* + * Specific to pool_t + */ + int (*pp_associate)(pool_t *, const pool_resource_t *); + int (*pp_dissociate)(pool_t *, const pool_resource_t *); + /* + * Common to pool_xml_elem_t + */ + xmlNodePtr pxe_node; /* XML Element */ +} pool_xml_pool_t; + +typedef pool_xml_elem_t pool_xml_component_t; + +/* + * pool_xml_result_set_t is the XML (to be precise, libxml - although + * this could be easily ported to an alternative C-API xml library) + * specific representation of the pool_result_set_t structure. + * + * The pxr_ctx member is a pointer to an XML XPath Context which + * represents the context in which this result set is valid. AN + * alternative way of thinking about this is to envisage the context + * as the root of the search which is used to build the result set. + * + * The pxr_path member is a pointer to the compiled XPath statement + * used to generate this result set. + * + * The prs_index member is a cursor into the result set and is used by + * the various result set functions to determine which result set + * member to access. + * + */ +typedef struct pool_xml_result_set { + const pool_conf_t *prs_conf; /* Configuration */ + int prs_active; /* Query active? */ + int prs_index; /* Result Index */ + pool_elem_t *(*prs_next)(pool_result_set_t *); + pool_elem_t *(*prs_prev)(pool_result_set_t *); + pool_elem_t *(*prs_first)(pool_result_set_t *); + pool_elem_t *(*prs_last)(pool_result_set_t *); + int (*prs_set_index)(pool_result_set_t *, int); + int (*prs_get_index)(pool_result_set_t *); + int (*prs_close)(pool_result_set_t *); + int (*prs_count)(pool_result_set_t *); + /* + * End of common part + */ + xmlXPathContextPtr pxr_ctx; /* Result Context */ + xmlXPathObjectPtr pxr_path; /* Result Path Object */ +} pool_xml_result_set_t; + +/* + * pool_xml_connection_t is the XML (to be precise, libxml - although + * this could be easily ported to an alternative C-API xml library) + * specific representation of the pool_result_set_t structure. + * + * The pxc_doc member is a pointer to an XML document structure which + * contains information about the XML document which acts as the data + * store for this connection. + * + * The pxc_file member is a FILE pointer to the data file used to + * store the XML document. + * + * The pxc_oflags member is the OR'd list of options specified when + * opening this connection. + * + * The pxc_cleanup member is a boolean flag indicating whether a + * configuration has a backup which needs to be cleaned up. This is + * used as a means of providing resilient configuration changes in the + * face of potential failure. + * + */ +typedef struct pool_xml_connection { + const char *pc_name; /* Provider name */ + int pc_store_type; /* Datastore type */ + int pc_oflags; /* Open flags */ + int (*pc_close)(pool_conf_t *); + int (*pc_validate)(const pool_conf_t *, pool_valid_level_t); + int (*pc_commit)(pool_conf_t *); + int (*pc_export)(const pool_conf_t *, const char *, + pool_export_format_t); + int (*pc_rollback)(pool_conf_t *); + pool_result_set_t *(*pc_exec_query)(const pool_conf_t *, + const pool_elem_t *, const char *, + pool_elem_class_t, pool_value_t **); + pool_elem_t *(*pc_elem_create)(pool_conf_t *, pool_elem_class_t, + pool_resource_elem_class_t, pool_component_elem_class_t); + int (*pc_remove)(pool_conf_t *); + int (*pc_res_xfer)(pool_resource_t *, pool_resource_t *, uint64_t); + int (*pc_res_xxfer)(pool_resource_t *, pool_resource_t *, + pool_component_t **); + char *(*pc_get_binding)(pool_conf_t *, pid_t); + int (*pc_set_binding)(pool_conf_t *, const char *, idtype_t, id_t); + char *(*pc_get_resource_binding)(pool_conf_t *, + pool_resource_elem_class_t, pid_t); + /* + * End of common part + */ + xmlDocPtr pxc_doc; /* XML document */ + FILE *pxc_file; /* XML File */ +} pool_xml_connection_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_XML_IMPL_H */ diff --git a/usr/src/lib/libpool/dtd/rm_pool.dtd.1 b/usr/src/lib/libpool/dtd/rm_pool.dtd.1 new file mode 100644 index 0000000..97c5cdc --- /dev/null +++ b/usr/src/lib/libpool/dtd/rm_pool.dtd.1 @@ -0,0 +1,119 @@ +<?xml version='1.0' encoding='UTF-8' ?> + +<!-- + Copyright 2005 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License, Version 1.0 only + (the "License"). You may not use this file except in compliance + with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<!--Entity Definitions--> + +<!ENTITY % dynamic_doc "INCLUDE"> + +<!ENTITY % static_doc "IGNORE"> + +<![ %dynamic_doc; [ +<!ENTITY % core "comment CDATA #IMPLIED + ref_id ID #REQUIRED"> +]]> + +<![ %static_doc; [ +<!ENTITY % core "comment CDATA #IMPLIED + ref_id ID #REQUIRED"> +]]> + +<!ENTITY % min_max "min CDATA #REQUIRED + max CDATA #REQUIRED"> + +<!--Element Definitions--> + +<!-- res_comp describes a component resource, this may contain components --> +<!ELEMENT res_comp (comp | property)*> + +<!ATTLIST res_comp %core; + %min_max; + name CDATA #REQUIRED + default (true | false) 'false' + units CDATA #REQUIRED + sys_id CDATA #REQUIRED + type CDATA #REQUIRED + a-dtype NMTOKENS 'min uint + max uint + default boolean + units string + sys_id int + type string'> +<!-- res_agg describes an aggregate resource --> +<!ELEMENT res_agg (property)*> + +<!ATTLIST res_agg %core; + name CDATA #REQUIRED + default (true | false) 'false' + units CDATA #REQUIRED + sys_id CDATA #REQUIRED + type CDATA #REQUIRED + a-dtype NMTOKENS 'default boolean + units string + sys_id int + type string'> + +<!-- comp describes a resource component --> +<!ELEMENT comp (#PCDATA | property)*> + +<!ATTLIST comp %core; + type CDATA #REQUIRED + sys_id NMTOKEN #REQUIRED + a-dtype NMTOKENS 'type string + sys_id int'> + +<!-- pool describes a resource pool --> +<!ELEMENT pool (#PCDATA | property)*> + +<!ATTLIST pool %core; + name CDATA #REQUIRED + importance CDATA #REQUIRED + active (true | false) 'true' + default (true | false) 'false' + res IDREFS #REQUIRED + a-dtype NMTOKENS 'importance int + default boolean + active boolean' > + +<!-- property describes a resource property --> +<!ELEMENT property (#PCDATA)> + +<!ATTLIST property name NMTOKEN #REQUIRED + type NMTOKEN #REQUIRED + a-dtype NMTOKENS 'name string + type string'> + +<!-- system describes a resource system --> +<!ELEMENT system (property | res_comp | res_agg | pool)*> + +<!ATTLIST system %core; + name CDATA #REQUIRED + bind-default (true | false) 'false' + version NMTOKEN #FIXED '1' + a-dtype NMTOKENS 'bind-default boolean + version int'> diff --git a/usr/src/man/man3lib/libpool.3lib b/usr/src/man/man3lib/libpool.3lib new file mode 100644 index 0000000..dda5251 --- /dev/null +++ b/usr/src/man/man3lib/libpool.3lib @@ -0,0 +1,542 @@ +'\" te +.\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH LIBPOOL 3LIB "Dec 14, 2006" +.SH NAME +libpool \- pool configuration manipulation library +.SH SYNOPSIS +.LP +.nf +\fBcc\fR [ \fIflag\fR... ] \fIfile\fR... [ \fIlibrary\fR... ] +#include <\fBpool.h\fR> +.fi + +.SH DESCRIPTION +.sp +.LP +The functions in this library define the interface for reading and writing +resource pools configuration files, as well as that for commiting an existing +configuration to becoming the running OS configuration (with respect to +partitioning subsystems). The <\fBpool.h\fR> header provides type and function +declarations for all library services. +.sp +.LP +The resource pools facility brings together process-bindable resources into a +common abstraction called a pool. Processor sets and other entities can be +configured, grouped, and labelled in a persistent fashion such that workload +components can be associated with a subset of a system's total resources. The +\fBlibpool\fR library provides a C language API for accessing this +functionality, while \fBpooladm\fR(1M), \fBpoolbind\fR(1M), and +\fBpoolcfg\fR(1M) make this facility available through command invocations from +a shell. Each of those manual pages describes aspects of the pools facility; +this page describes the properties available to the various entities managed +within the pools facility. These entities include the system, pools, and the +\fBpset\fR resources for processor sets. +.sp +.LP +When the pools facility is enabled on a system, the behavior of the following +functions is modified. +.sp + +.sp +.TS +c c +l l . +System Call Error Value +_ +\fBpset_assign\fR(pset !=\fBPS_QUERY\fR) \fBENOTSUP\fR +\fBpset_bind\fR(pset !=\fBPS_QUERY\fR) \fBENOTSUP\fR +\fBpset_create()\fR \fBENOTSUP\fR +\fBpset_destroy()\fR \fBENOTSUP\fR +\fBpset_setattr()\fR \fBENOTSUP\fR +.TE + +.sp +.LP +Each active entity within the resource pools framework can have an arbitrary +collection of named, typed properties associated with it. Properties supported +by the pools framework are listed, with descriptions, under each entity below. +In general, resource properties can be one of five types: boolean (\fBbool\fR), +signed (\fBint64\fR) and unsigned (\fBuint64\fR) integers, floating point +(\fBdouble\fR), and \fBstring\fR values. +.sp +.LP +All entities and resources support a string property for commenting purposes; +this property is available for use by management applications to record +descriptions and other administrator oriented data. The comment field is not +used by the default pools commands, except when a configuration is initiated by +the \fBpoolcfg\fR utility, in which case an informative message is placed in +the \fBsystem.comment\fR property for that configuration. +.SS "System" +.sp + +.sp +.TS +c c c +l l l . +Property name Type Description +\fBsystem.allocate-method\fR \fBstring\fR T{ +Allocation method to use when this configuration is instantiated +T} +\fBsystem.bind-default\fR \fBbool\fR T{ +If specified pool not found, bind to pool with 'pool.default' property set to true +T} +\fBsystem.comment\fR \fBstring\fR User description of system +\fBsystem.name\fR \fBstring\fR User name for the configuration +\fBsystem.version\fR \fBint64\fR T{ +\fBlibpool\fR version required to manipulate this configuration +T} +\fBsystem.poold.log-level\fR \fBstring\fR \fBpoold\fR logging level +\fBsystem.poold.log-location\fR \fBstring\fR \fBpoold\fR logging location +\fBsystem.poold.history-file\fR \fBstring\fR \fBpoold\fR decision history location +\fBsystem.poold.monitor-interval\fR \fBuint64\fR \fBpoold\fR monitoring sample interval +\fBsystem.poold.objectives\fR \fBstring\fR \fBpoold\fR objectives for a system. +.TE + +.sp +.LP +The \fBsystem.allocate-method\fR, \fBsystem.bind-default\fR, +\fBsystem.comment\fR, \fBsystem.name\fR, \fBsystem.poold.log-level\fR, +\fBsystem.poold.log-location\fR, \fBsystem.poold.history-file\fR, +\fBsystem.poold.monitor-interval\fR, and \fBsystem.poold.objectives\fR +properties are writable; the \fBsystem.version\fR property is not. +.sp +.LP +The \fBsystem.allocate-method\fR property accepts only two values, "importance +based" and "surplus to default". The default value for this property is +"importance based". The property is optional and if it is not present the +library will allocate resources as though it were present and had the default +value. These strings are defined in <\fBpool.h\fR> as \fBPOA_IMPORTANCE\fR and +\fBPOA_SURPLUS_TO_DEFAULT\fR. +.sp +.LP +If "importance based" allocation is defined, then during a commit the library +will allocate resources to pools using an algorithm that observes minimum and +maximum constraints for resources but favors those resources with greater +importance. +.sp +.LP +If "surplus to default" is defined, then during a commit the library will +allocate minimum resources to all resource sets apart from default which will +receive any surplus. +.sp +.LP +The \fBsystem.bind-default\fR property defaults to true. This property +interacts with the \fBproject.pool\fR resource control to specify the binding +behavior for processes associated with a project. If \fBproject.pool\fR is not +specified, then this property has no effect. If \fBproject.pool\fR is specified +and the specified pool exists, this property has no effect. If the specified +pool does not exist, perhaps because of a reconfiguration, then this property +controls the binding behavior for the project member. If +\fBsystem.bind-default\fR is true, then the project member is bound to the +default pool (identified as the pool for which \fBpool.default\fR is true); +otherise the project member is refused access to the system. Care should be +taken with the pools configuration if this property is set to false, so as to +avoid denying users access to the system. +.sp +.LP +The various \fBpoold\fR properties are used to configure the operation of +\fBpoold\fR(1M). +.sp +.LP +The \fBsystem.poold.log-level\fR property is used to specify the level of +detail provided in log messages. Valid values are: \fBALERT\fR, \fBCRIT\fR, +\fBERR\fR, \fBWARNING\fR, \fBNOTICE\fR, \fBINFO\fR, and \fBDEBUG\fR. +.sp +.LP +\fBALERT\fR provides the least level of detail, \fBDEBUG\fR the greatest. See +\fBsyslog\fR(3C) for more information about the meaning of these debug levels. +If this property is not specified, the default value \fBNOTICE\fR is used. +.sp +.LP +The \fBsystem.poold.log-location\fR property is used to specify the location of +the logfiles generated by \fBpoold\fR. The special value of "syslog" indicates +that logged messages should be written to \fBsyslog()\fR. If this property is +not specified, the default location \fB/var/log/pool\fR is used. +.sp +.LP +The \fBsystem.poold.history-file\fR specifies the location of the decision +history file which is used by \fBpoold\fR to improve the quality of its +decision making over time. If this property is not specified, the default +location \fB/var/adm/pool\fR is used. +.sp +.LP +The \fBsystem.poold.monitor-interval\fR property specifies the monitoring +interval (in milliseconds) to be used by \fBpoold\fR when sampling utilization +statistics. If this property is not specified, the default value of 15 seconds +is used. +.sp +.LP +The \fBsystem.poold.objectives\fR property specifies any system wide +objectives. An objectives property has the following syntax: +.sp +.in +2 +.nf +objectives = objective [; objective]* +objective = [n:] keyword [op] [value] +.fi +.in -2 + +.sp +.LP +All objectives are prefixed with an optional importance. The importance acts as +a multiplier for the objective and thus increases the significance of its +contribution to the objective function evaluation. If no importance is +specified, the default value is 1. +.sp +.LP +The "wt-load" objective is the only objective to which a system element can be +set. This objective favors configurations that match resource allocations to +resource utilization. A resource set that uses more resources will be given +more resources when this objective is active. An administrator should use this +objective when he is relatively satisfied with the constraints established +using the minimum and maximum properties and would like the DRP to manipulate +resources freely within those constraints. +.SS "Pools" +.sp + +.sp +.TS +c c c +l l l . +Property name Type Description +\fBpool.active\fR \fBbool\fR Mark this pool as active, if true. +\fBpool.comment\fR \fBstring\fR User description of pool. +\fBpool.default\fR \fBbool\fR T{ +Mark this pool as the default pool, if true; see system.bind-default property. +T} +\fBpool.importance\fR \fBint64\fR T{ +Relative importance of this pool; for possible resource dispute resolution. +T} +\fBpool.name\fR \fBstring\fR T{ +User name for pool; used by \fBsetproject\fR(3PROJECT) as value for 'project.pool' project attribute in \fBproject\fR(4) database. +T} +\fBpool.scheduler\fR \fBstring\fR T{ +Scheduler class to which consumers of this pool will be bound. This property is optional and if not specified, the scheduler bindings for consumers of this pool are not affected. +T} +\fBpool.sys_id\fR \fBint64\fR System-assigned pool ID. +\fBpool.temporary\fR \fBbool\fR T{ +Mark this pool as a temporary resource; if true, this pool can exist only in the dynamic configuration and cannot be committed to a configuration file. +T} +.TE + +.sp +.LP +The \fBpool.default\fR, \fBpool.sys_id\fR, and \fBpool.temporary\fR properties +are not writable; all other listed properties are writable. +.sp +.LP +If pool.scheduler is specified, it must be set to the name of a valid +scheduling class for the system. See the \fB-c\fR option for \fBpriocntl\fR(1) +for a list of valid class names. +.SS "Processor Sets" +.sp + +.sp +.TS +c c c +l l l . +Property name Type Description +\fBpset.comment\fR \fBstring\fR User description of resource. +\fBpset.default\fR \fBbool\fR Marks default processor set. +\fBpset.load\fR \fBuint64\fR The load for this processor set. +\fBpset.max\fR \fBuint64\fR T{ +Maximum number of CPUs permitted in this processor set. +T} +\fBpset.min\fR \fBuint64\fR T{ +Minimum number of CPUs permitted in this processor set. +T} +\fBpset.name\fR \fBstring\fR User name for resource. +\fBpset.size\fR \fBuint64\fR T{ +Current number of CPUs in this processor set. +T} +\fBpset.sys_id\fR \fBint64\fR System-assigned processor set ID. +\fBpset.temporary\fR \fBbool\fR T{ +Mark this processor set as a temporary resource; if true, this processor set can exist only in the dynamic configuration and cannot be committed to a configuration file. +T} +\fBpset.type\fR \fBstring\fR T{ +Names resource type; value for all processor sets is \fBpset\fR. +T} +\fBpset.units\fR \fBstring\fR T{ +Identifies meaning of size-related properties; value for all processor sets is \fBpopulation\fR. +T} +\fBpset.poold.objectives\fR \fBstring\fR T{ +Specifies the poold objectives for a pset. +T} +.TE + +.sp +.LP +The \fBpset.comment\fR, \fBpset.max\fR, \fBpset.min\fR, \fBpset.name\fR, and +\fBpset.poold.objectives\fR properties are writable; the \fBpset.default\fR, +\fBpset.load\fR, \fBpset.size\fR, \fBpset.sys_id\fR, \fBpset.temporary\fR, +\fBpset.type\fR, and \fBpset.units\fR properties are not. +.sp +.LP +The \fBpset.load\fR property represents the load on a processor set. The lowest +value for this property is 0. The value of \fBpset.load\fR increases in a +linear fashion with the load on the set, as measured by the number of jobs in +the system run queue. +.sp +.LP +The \fBpset.poold.objectives\fR property specifies an objective which is +specific to a particular \fBpset\fR. See the \fBsystem.poold.objectives\fR +entry for the specification of this property's syntax. +.sp +.LP +There are two types of objectives that can be set on a \fBpset\fR: +.sp +.ne 2 +.na +\fB\fBlocality\fR\fR +.ad +.RS 15n +This objective influences the impact that locality, as measured by lgroup data, +has upon the chosen configuration. This objective can take one of three values: +.sp +.ne 2 +.na +\fB\fBtight\fR\fR +.ad +.RS 9n +If set, configurations that maximize resource locality are favored. +.RE + +.sp +.ne 2 +.na +\fB\fBloose\fR\fR +.ad +.RS 9n +If set, configurations that minimize resource locality are favored. +.RE + +.sp +.ne 2 +.na +\fB\fBnone\fR\fR +.ad +.RS 9n +This is the default value for this objective. If set, configuration +favorability is uninfluenced by resource locality. +.RE + +.RE + +.sp +.ne 2 +.na +\fB\fButilization\fR\fR +.ad +.RS 15n +This objective favors configurations that allocate resources to partitions that +are failing to preserve the specified utilization objective. +.RE + +.sp +.LP +These objectives are specified in terms of an operator and a value. The +operators are +.sp +.ne 2 +.na +\fB\fB<\fR\fR +.ad +.RS 5n +The ``less than'' operator is used to indicate that the specified value should +be treated as a maximum target value. +.RE + +.sp +.ne 2 +.na +\fB\fB>\fR\fR +.ad +.RS 5n +The ``greater than'' operator is used to indicate that the specified value +should be treated as a minimum target value. +.RE + +.sp +.ne 2 +.na +\fB\fB~\fR\fR +.ad +.RS 5n +The ``about'' operator is used to indicate that the specified value should be +treated as a target value about which some fluctuation is acceptable. +.RE + +.sp +.LP +Only one objective of each type of operator can be set. For example, if the +\fB~\fR operator is set, the \fB<\fR and \fB>\fR operators cannot be set. It is +possible to set a \fB<\fR and a \fB>\fR operator together; the values will be +validated to ensure that they do not overlap. +.SS "Processors" +.sp + +.sp +.TS +c c c +l l l . +Property name Type Description +_ +\fBcpu.comment\fR \fBstring\fR User description of CPU. +\fBcpu.pinned\fR \fBbool\fR CPU pinned to this processor set. +\fBcpu.status\fR \fBint64\fR T{ +Processor status, on-line, offline or interrupts disabled. +T} +\fBcpu.sys_id\fR \fBint64\fR System-assigned processor ID. +.TE + +.sp +.LP +The \fBcpu.comment\fR, \fBcpu.pinned\fR, and \fBcpu.status\fR properties are +writeable. +.sp +.LP +The \fBcpu.status\fR property can be set only to the following values: +.sp +.ne 2 +.na +\fB\fBoff-line\fR\fR +.ad +.RS 12n +Set the CPU offline. +.RE + +.sp +.ne 2 +.na +\fB\fBon-line\fR\fR +.ad +.RS 12n +Set the CPU online. +.RE + +.sp +.ne 2 +.na +\fB\fBno-intr\fR\fR +.ad +.RS 12n +Disable interrupt processing on the CPU. +.RE + +.sp +.LP +These values are defined in <\fBsys/processor.h\fR> as the \fBPS_OFFLINE\fR, +\fBPS_ONLINE\fR, and \fBPS_NOINTR\fR macros. +.SH INTERFACES +.sp +.LP +The shared object \fBlibpool.so.1\fR provides the public interfaces defined +below. See \fBIntro\fR(3) for additional information on shared object +interfaces. +.sp + +.sp +.TS +l l +l l . +\fBpool_associate\fR \fBpool_component_info\fR +\fBpool_component_to_elem\fR \fBpool_conf_alloc\fR +\fBpool_conf_close\fR \fBpool_conf_commit\fR +\fBpool_conf_export\fR \fBpool_conf_free\fR +\fBpool_conf_info\fR \fBpool_conf_location\fR +\fBpool_conf_open\fR \fBpool_conf_remove\fR +\fBpool_conf_rollback\fR \fBpool_conf_status\fR +\fBpool_conf_to_elem\fR \fBpool_conf_update\fR +\fBpool_conf_validate\fR \fBpool_create\fR +\fBpool_destroy\fR \fBpool_dissociate\fR +\fBpool_dynamic_location\fR \fBpool_error\fR +\fBpool_get_binding\fR \fBpool_get_owning_resource\fR +\fBpool_get_pool\fR \fBpool_get_property\fR +\fBpool_get_resource\fR \fBpool_get_resource_binding\fR +\fBpool_get_status\fR \fBpool_info\fR +\fBpool_put_property\fR \fBpool_query_components\fR +\fBpool_query_pool_resources\fR \fBpool_query_pools\fR +\fBpool_query_resource_components\fR \fBpool_query_resources\fR +\fBpool_resource_create\fR \fBpool_resource_destroy\fR +\fBpool_resource_info\fR \fBpool_resource_to_elem\fR +\fBpool_resource_transfer\fR \fBpool_resource_type_list\fR +\fBpool_resource_xtransfer\fR \fBpool_rm_property\fR +\fBpool_set_binding\fR \fBpool_set_status\fR +\fBpool_static_location\fR \fBpool_strerror\fR +\fBpool_to_elem\fR \fBpool_value_alloc\fR +\fBpool_value_free\fR \fBpool_value_get_bool\fR +\fBpool_value_get_double\fR \fBpool_value_get_int64\fR +\fBpool_value_get_name\fR \fBpool_value_get_string\fR +\fBpool_value_get_type\fR \fBpool_value_get_uint64\fR +\fBpool_value_set_bool\fR \fBpool_value_set_double\fR +\fBpool_value_set_int64\fR \fBpool_value_set_name\fR +\fBpool_value_set_string\fR \fBpool_value_set_uint64\fR +\fBpool_version\fR \fBpool_walk_components\fR +\fBpool_walk_pools\fR \fBpool_walk_properties\fR +\fBpool_walk_resources\fR +.TE + +.SH FILES +.sp +.ne 2 +.na +\fB\fB/usr/lib/libpool.so.1\fR\fR +.ad +.RS 28n +shared object +.RE + +.sp +.ne 2 +.na +\fB\fB/usr/lib/64/libpool.so.1\fR\fR +.ad +.RS 28n +64-bit shared object +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBIntro\fR(3), \fBpool_component_info\fR(3POOL), \fBpool_conf_open\fR(3POOL), +\fBpool_conf_to_elem\fR(3POOL), \fBpool_create\fR(3POOL), +\fBpool_error\fR(3POOL), \fBpool_get_binding\fR(3POOL), +\fBpool_get_property\fR(3POOL), \fBpool_get_resource\fR(3POOL), +\fBpool_resource_create\fR(3POOL), \fBpool_value_alloc\fR(3POOL), +\fBpool_walk_pools\fR(3POOL), \fBattributes\fR(5), \fBsmf\fR(5) +.SH NOTES +.sp +.LP +Functions in \fBlibpool\fR can be used to manipulate static configurations even +when the pools facility is not enabled. See \fBpooladm\fR(1M) and +\fBpool_set_status\fR(3POOL) for more information about enabling the pools +facility. The pools facility must be enabled, however, to modify the dynamic +configuration. +.sp +.LP +Since the Resource Pools facility is an \fBsmf\fR(5) service, it can also be +enabled and disabled using the standard Service Management Facility (SMF) +interfaces. diff --git a/usr/src/man/man3pool/pool_associate.3pool b/usr/src/man/man3pool/pool_associate.3pool new file mode 100644 index 0000000..4584697 --- /dev/null +++ b/usr/src/man/man3pool/pool_associate.3pool @@ -0,0 +1,306 @@ +'\" te +.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_ASSOCIATE 3POOL "Jul 18, 2005" +.SH NAME +pool_associate, pool_create, pool_destroy, pool_dissociate, pool_info, +pool_query_pool_resources \- resource pool manipulation functions +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBint\fR \fBpool_associate\fR(\fBpool_conf_t *\fR\fIconf\fR, \fB pool_t *\fR\fIpool\fR, + \fBpool_resource_t *\fR\fIresource\fR); +.fi + +.LP +.nf +\fBpool_t *\fR\fBpool_create\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBconst char *\fR\fIname\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_destroy\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_t *\fR\fIpool\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_dissociate\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_t *\fR\fIpool\fR, + \fBpool_resource_t *\fR\fIresource\fR); +.fi + +.LP +.nf +\fBconst char *\fR\fBpool_info\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_t *\fR\fIpool\fR, + \fBint\fR \fIflags\fR); +.fi + +.LP +.nf +\fBpool_resource_t **\fR\fBpool_query_pool_resources\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_t *\fR\fIpool\fR, \fBuint_t *\fR\fInelem\fR, \fBpool_value_t **\fR\fIproperties\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +These functions provide mechanisms for constructing and modifying pools entries +within a target pools configuration. The \fIconf\fR argument for each function +refers to the target configuration to which the operation applies. +.sp +.LP +The \fBpool_associate()\fR function associates the specified resource with +\fIpool\fR. A resource can be associated with multiple pools at the same time. +Any resource of this type that was formerly associated with this pool is no +longer associated with the pool. The new association replaces the earlier one. +.sp +.LP +The \fBpool_create()\fR function creates a new pool with the supplied name with +its default properties initialized, and associated with the default resource of +each type. +.sp +.LP +The \fBpool_destroy function()\fR destroys the given pool association. +Associated resources are not modified. +.sp +.LP +The \fBpool_dissociate()\fR function removes the association between the given +resource and pool. On successful completion, the pool is associated with the +default resource of the same type. +.sp +.LP +The \fBpool_info()\fR function returns a string describing the given pool. The +string is allocated with \fBmalloc\fR(3C). The caller is reponsible for freeing +the returned string. If the \fIflags\fR option is non-zero, the string returned +also describes the associated resources of the pool. +.sp +.LP +The \fBpool_query_pool_resources()\fR function returns a null-terminated array +of resources currently associated with the pool that match the given list of +properties. The return value must be freed by the caller. The \fInelem\fR +argument is set to be the length of the array returned. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_create()\fR returns a new initialized pool. +Otherwise it returns \fINULL\fR and \fBpool_error\fR(3POOL) returns the +pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_associate()\fR, \fBpool_destroy()\fR, and +\fBpool_dissociate()\fR return 0. Otherwise, they return -1 and +\fBpool_error()\fR returns the pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_info()\fR returns a string describing the +given pool. Otherwise it returns \fINULL\fR and \fBpool_error()\fR returns the +pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_query_pool_resources()\fR returns a +null-terminated array of resources. Otherwise it returns \fINULL\fR and +\fBpool_error()\fR returns the pool-specific error value. +.SH ERRORS +.sp +.LP +The \fBpool_create()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or \fIname\fR is +already in use. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The pool element could not be created because the configuration would be +invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_PUTPROP\fR\fR +.ad +.RS 20n +One of the supplied properties could not be set. +.RE + +.sp +.LP +The \fBpool_destroy()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.LP +The \fBpool_associate()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR or the parameters +are supplied from a different configuration. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_disassociate()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or the parameters +are supplied from a different configuration. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +No resources could be located for the supplied configuration or the supplied +configuration is not valid (for example, more than one default for a resource +type was found.) +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_info()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or the \fIflags\fR +paramter is neither 0 or 1. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_query_pool_resources()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.SH USAGE +.sp +.LP +Pool names are unique across pools in a given configuration file. It is an +error to attempt to create a pool with a name that is currently used by another +pool within the same configuration. +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_component_info.3pool b/usr/src/man/man3pool/pool_component_info.3pool new file mode 100644 index 0000000..53e53f0 --- /dev/null +++ b/usr/src/man/man3pool/pool_component_info.3pool @@ -0,0 +1,122 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_COMPONENT_INFO 3POOL "Sep 23, 2003" +.SH NAME +pool_component_info, pool_get_owning_resource \- resource pool component +functions +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBconst char *\fR\fBpool_component_info\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_component_t *\fR\fIcomponent\fR, \fBint\fR \fIflags\fR); +.fi + +.LP +.nf +\fBpool_resource_t *\fR\fBpool_get_owning_resource\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_component_t *\fR\fIcomponent\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +Certain resources, such as processor sets, are composed of resource components. +Informational and ownership attributes of resource components are made +available with the \fBpool_component_info()\fR and +\fBpool_get_owning_resource()\fR functions. The \fIconf\fR argument for each +function refers to the target configuration to which the operation applies. +.sp +.LP +The \fBpool_component_info()\fR function returns a string describing +\fIcomponent\fR. The string is allocated with \fBmalloc\fR(3C). The caller is +reponsible for freeing the returned string. The \fIflags\fR argument is +ignored. +.sp +.LP +The \fBpool_get_owning_resource()\fR function returns the resource currently +containing \fIcomponent\fR. Every component is contained by a resource. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_component_info()\fR returns a string. +Otherwise it returns \fINULL\fR and \fBpool_error\fR(3POOL) returns the +pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_get_owning_resource()\fR returns the owning +resource. Otherwise it returns \fINULL\fR and \fBpool_error()\fR returns the +pool-specific error value. +.SH ERRORS +.sp +.LP +The \fBpool_component_info()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or the \fIflags\fR +paramter is neither 0 or 1. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_get_owning_resource()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_component_to_elem.3pool b/usr/src/man/man3pool/pool_component_to_elem.3pool new file mode 100644 index 0000000..39bb56f --- /dev/null +++ b/usr/src/man/man3pool/pool_component_to_elem.3pool @@ -0,0 +1,86 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_COMPONENT_TO_ELEM 3POOL "Sep 23, 2003" +.SH NAME +pool_component_to_elem, pool_to_elem, pool_conf_to_elem, pool_resource_to_elem +\- resource pool element-related functions +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBpool_elem_t *\fR\fBpool_component_to_elem\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_component_t *\fR\fIcomponent\fR); +.fi + +.LP +.nf +\fBpool_elem_t *\fR\fBpool_conf_to_elem\fR(\fBpool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBpool_elem_t *\fR\fBpool_resource_to_elem\fR(\fBpool_conf_t *\fR\fIconf\fR + \fBpool_resource_t *\fR\fIresource\fR); +.fi + +.LP +.nf +\fBpool_elem_t *\fR\fBpool_to_elem\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_t *\fR\fIpool\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +A pool element, as represented by a \fBpool_elem_t\fR, is a common abstraction +for any \fBlibpool\fR entity that contains properties. All such types can be +converted to the opaque \fBpool_elem_t\fR type using the appropriate conversion +functions prototyped above. The \fIconf\fR argument for each function refers to +the target configuration to which the operation applies. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, these functions return a \fBpool_elem_t\fR +corresponding to the argument passed in. Otherwise they return \fINULL\fR and +\fBpool_error\fR(3POOL) returns the pool-specific error value. +.SH ERRORS +.sp +.LP +These function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_conf_alloc.3pool b/usr/src/man/man3pool/pool_conf_alloc.3pool new file mode 100644 index 0000000..011584a --- /dev/null +++ b/usr/src/man/man3pool/pool_conf_alloc.3pool @@ -0,0 +1,669 @@ +'\" te +.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with +.\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_CONF_ALLOC 3POOL "Aug 3, 2009" +.SH NAME +pool_conf_alloc, pool_conf_close, pool_conf_commit, pool_conf_export, +pool_conf_free, pool_conf_info, pool_conf_location, pool_conf_open, +pool_conf_remove, pool_conf_rollback, pool_conf_status, pool_conf_update, +pool_conf_validate \- manipulate resource pool configurations +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBpool_conf_t *\fR\fBpool_conf_alloc\fR(\fBvoid\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_close\fR(\fBpool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_commit\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBint\fR \fIactive\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_export\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBconst char *\fR\fIlocation\fR, + \fBpool_export_format_t\fR \fIformat\fR); +.fi + +.LP +.nf +\fBvoid\fR \fBpool_conf_free\fR(\fBpool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBchar *\fR\fBpool_conf_info\fR(\fBconst pool_conf_t *\fR\fIconf\fR, \fBint\fR \fIflags\fR); +.fi + +.LP +.nf +\fBconst char *\fR\fBpool_conf_location\fR(\fBpool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_open\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBconst char *\fR\fIlocation\fR, + \fBint\fR \fIflags\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_remove\fR(\fBpool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_rollback\fR(\fBpool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBpool_conf_state_t\fR \fBpool_conf_status\fR(\fBconst pool_conf_t *\fR\fIconf\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_update\fR(\fBconst pool_conf_t *\fR\fIconf\fR, \fBint *\fR\fIchanged\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_conf_validate\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_valid_level_t\fR \fIlevel\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +These functions enable the access and creation of configuration files +associated with the pools facility. Since the pool configuration is an opaque +type, an initial configuration is obtained with \fBpool_conf_alloc()\fR and +released with \fBpool_conf_free()\fR when the configuration is no longer of +interest. The \fIconf\fR argument for each function refers to the target +configuration to which the operation applies. +.sp +.LP +The \fBpool_conf_close()\fR function closes the given configuration, releasing +associated resources. +.sp +.LP +The \fBpool_conf_commit()\fR function commits changes made to the given +\fBpool_conf_t\fR to permanent storage. If the \fIactive\fR flag is non-zero, +the state of the system will be configured to match that described in the +supplied \fBpool_conf_t\fR. If configuring the system fails, +\fBpool_conf_commit()\fR will attempt to restore the system to its previous +state. +.sp +.LP +The \fBpool_conf_export()\fR function saves the given configuration to the +specified location. The only currently supported value of \fIformat\fR is +\fBPOX_NATIVE\fR, which is the format native to \fBlibpool\fR, the output of +which can be used as input to \fBpool_conf_open()\fR. +.sp +.LP +The \fBpool_conf_info()\fR function returns a string describing the entire +configuration. The string is allocated with \fBmalloc\fR(3C). The caller is +responsible for freeing the returned string. If the flags option is non-zero, +the string returned also describes the sub-elements (if any) contained in the +configuration. +.sp +.LP +The \fBpool_conf_location()\fR function returns the location string provided to +\fBpool_conf_open()\fR for the given \fBpool_conf_t\fR. +.sp +.LP +The \fBpool_conf_open()\fR function creates a \fBpool_conf_t\fR given a +location at which the configuration is stored. The valid flags are a bitmap of +the following: +.sp +.ne 2 +.na +\fB\fBPO_RDONLY\fR\fR +.ad +.RS 13n +Open for reading only. +.RE + +.sp +.ne 2 +.na +\fB\fBPO_RDWR\fR\fR +.ad +.RS 13n +Open read-write. +.RE + +.sp +.ne 2 +.na +\fB\fBPO_CREAT\fR\fR +.ad +.RS 13n +Create a configuration at the given location if it does not exist. If it does, +truncate it. +.RE + +.sp +.ne 2 +.na +\fB\fBPO_DISCO\fR\fR +.ad +.RS 13n +Perform `discovery'. This option only makes sense when used in conjunction with +\fBPO_CREAT\fR, and causes the returned \fBpool_conf_t\fR to contain the +resources and components currently active on the system. +.sp +The use of this flag is deprecated. \fBPO_CREAT\fR always performs discovery. +If supplied, this flag is ignored. +.RE + +.sp +.ne 2 +.na +\fB\fBPO_UPDATE\fR\fR +.ad +.RS 13n +Use when opening the dynamic state file, which is the configuration at +\fBpool_dynamic_location\fR(3POOL), to ensure that the contents of the dynamic +state file are updated to represent the current state of the system. +.sp +The use of this flag is deprecated. The dynamic state is always current and +does not require updating. If supplied, this flag is ignored. +.RE + +.sp +.LP +A call to \fBpool_conf_open()\fR with the pool dynamic location and write +permission will hang if the dynamic location has already been opened for +writing. +.sp +.LP +The \fBpool_conf_remove()\fR function removes the configuration's permanent +storage. If the configuration is still open, it is first closed. +.sp +.LP +The \fBpool_conf_rollback()\fR function restores the configuration state to +that held in the configuration's permanent storage. This will either be the +state last successfully committed (using \fBpool_conf_commit()\fR) or the state +when the configuration was opened if there have been no successfully committed +changes since then. +.sp +.LP +The \fBpool_conf_status()\fR function returns the status of a configuration, +which can be one of the following values: +.sp +.ne 2 +.na +\fB\fBPOF_INVALID\fR\fR +.ad +.RS 15n +The configuration is not in a suitable state for use. +.RE + +.sp +.ne 2 +.na +\fB\fBPOF_VALID\fR\fR +.ad +.RS 15n +The configuration is in a suitable state for use. +.RE + +.sp +.LP +The \fBpool_conf_update()\fR function updates the library snapshot of kernel +state. If \fIchanged\fR is non-null, it is updated to identify which types of +configuration elements changed during the update. To check for change, treat +the \fIchanged\fR value as a bitmap of possible element types. +.sp +.LP +A change is defined for the different element classes as follows: +.sp +.ne 2 +.na +\fB\fBPOU_SYSTEM\fR\fR +.ad +.RS 14n +A property on the system element has been created, modified, or removed. +.RE + +.sp +.ne 2 +.na +\fB\fBPOU_POOL\fR\fR +.ad +.RS 14n +A property on a pool element has been created, modified, or removed. A pool has +changed a resource association. +.RE + +.sp +.ne 2 +.na +\fB\fBPOU_PSET\fR\fR +.ad +.RS 14n +A property on a pset element has been created, modified, or removed. A pset's +resource composition has changed. +.RE + +.sp +.ne 2 +.na +\fB\fBPOU_CPU\fR\fR +.ad +.RS 14n +A property on a CPU element has been created, modified, or removed. +.RE + +.sp +.LP +The \fBpool_conf_validate()\fR function checks the validity of the contents of +the given configuration. The validation can be at several (increasing) levels +of strictness: +.sp +.ne 2 +.na +\fB\fBPOV_LOOSE\fR\fR +.ad +.RS 15n +Performs basic internal syntax validation. +.RE + +.sp +.ne 2 +.na +\fB\fBPOV_STRICT\fR\fR +.ad +.RS 15n +Performs a more thorough syntax validation and internal consistency checks. +.RE + +.sp +.ne 2 +.na +\fB\fBPOV_RUNTIME\fR\fR +.ad +.RS 15n +Performs an estimate of whether attempting to commit the given configuration on +the system would succeed or fail. It is optimistic in that a successful +validation does not guarantee a subsequent commit operation will be successful; +it is conservative in that a failed validation indicates that a subsequent +commit operation on the current system will always fail. +.RE + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_conf_alloc()\fR returns an initialized +\fBpool_conf_t\fR pointer. Otherwise it returns \fINULL\fR and +\fBpool_error\fR(3POOL) returns the pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_conf_close()\fR, \fBpool_conf_commit()\fR, +\fBpool_conf_export()\fR, \fBpool_conf_open()\fR, \fBpool_conf_remove()\fR, +\fBpool_conf_rollback()\fR, \fBpool_conf_update()\fR, and +\fBpool_conf_validate()\fR return 0. Otherwise they return -1 and +\fBpool_error()\fR returns the pool-specific error value. +.sp +.LP +The \fBpool_conf_status()\fR function returns either \fBPOF_INVALID\fR or +\fBPOF_VALID\fR. +.SH ERRORS +.sp +.LP +The \fBpool_conf_alloc()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +There is not enough memory available to allocate the configuration. Check +\fBerrno\fR for the specific system error code. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.LP +The \fBpool_conf_close()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +The configuration's permanent store cannot be closed. Check \fBerrno\fR for +the specific system error code. +.RE + +.sp +.LP +The \fBpool_conf_commit()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or the active flag +is non-zero and the system could not be modified. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +The permanent store could not be updated. Check \fBerrno\fR for the specific +system error code. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is not valid for this system. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_ACCESS\fR\fR +.ad +.RS 20n +The configuration was not opened with the correct permissions. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_DATASTORE\fR\fR +.ad +.RS 20n +The update of the permanent store has failed and the contents could be +corrupted. Check for a \fB\&.bak\fR file at the datastore location if manual +recovery is required. +.RE + +.sp +.LP +The \fBpool_conf_export()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 17n +The supplied configuration's status is not \fBPOF_VALID\fR or the requested +export format is not supported. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_DATASTORE\fR\fR +.ad +.RS 17n +The creation of the export file failed. A file might have been created at the +specified location but the contents of the file might not be correct. +.RE + +.sp +.LP +The \fBpool_conf_info()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or \fIflags\fR is +neither 0 nor 1. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +There is not enough memory available to allocate the buffer used to build the +information string. Check \fBerrno\fR for the specific system error code. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.LP +The \fBpool_conf_location()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.LP +The \fBpool_conf_open()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is already \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +There is not enough memory available to store the supplied location, or the +pools facility is not active. Check \fBerrno\fR for the specific system error +code. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration to be opened is at \fBpool_dynamic_location\fR(3POOL) and the +configuration is not valid for this system. +.RE + +.sp +.LP +The \fBpool_conf_remove()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +The configuration's permanent storage could not be removed. Check \fBerrno\fR +for the specific system error code. +.RE + +.sp +.LP +The \fBpool_conf_rollback()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +The permanent store could not be accessed. Check \fBerrno\fR for the specific +system error code. +.RE + +.sp +.LP +The \fBpool_conf_update()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or the configuration +is not the dynamic configuration. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_DATASTORE\fR\fR +.ad +.RS 20n +The kernel snapshot cannot be correctly unpacked. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration contains uncommitted transactions. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error occurred during snapshot retrieval and update. +.RE + +.sp +.LP +The \fBpool_conf_validate()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.SH EXAMPLES +.LP +\fBExample 1 \fRCreate the configuration at the specified location. +.sp +.in +2 +.nf +#include <pool.h> +#include <stdio.h> + +\&... + +pool_conf_t *pool_conf; +pool_conf = pool_conf_alloc(); +char *input_location = "/tmp/poolconf.example"; + +if (pool_conf_open(pool_conf, input_location, + PO_RDONLY) < 0) { + fprintf(stderr, "Opening pool configuration %s + failed\en", input_location); +} +.fi +.in -2 + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Uncommitted +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_dynamic_location.3pool b/usr/src/man/man3pool/pool_dynamic_location.3pool new file mode 100644 index 0000000..99dc2e0 --- /dev/null +++ b/usr/src/man/man3pool/pool_dynamic_location.3pool @@ -0,0 +1,206 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_DYNAMIC_LOCATION 3POOL "Sep 23, 2003" +.SH NAME +pool_dynamic_location, pool_static_location, pool_version, pool_get_status, +pool_set_status, pool_resource_type_list \- resource pool framework functions +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBconst char *\fR\fBpool_dynamic_location\fR(\fBvoid\fR); +.fi + +.LP +.nf +\fBconst char *\fR\fBpool_static_location\fR(\fBvoid\fR); +.fi + +.LP +.nf +\fBuint_t\fR \fBpool_version\fR(\fBuint_t\fR \fIver\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_get_status\fR(\fBint *\fR\fIstate\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_set_status\fR(\fBint\fR \fIstate\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_resource_type_list\fR(\fBconst char **\fR\fIreslist\fR, + \fBuint_t *\fR\fInumres\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +The \fBpool_dynamic_location()\fR function returns the location used by the +pools framework to store the dynamic configuration. +.sp +.LP +The \fBpool_static_location()\fR function returns the location used by the +pools framework to store the default configuration used for pools framework +instantiation. +.sp +.LP +The \fBpool_version()\fR function can be used to inquire about the version +number of the library by specifying \fBPOOL_VER_NONE\fR. The current (most +capable) version is \fBPOOL_VER_CURRENT\fR. The user can set the version used +by the library by specifying the required version number. If this is not +possible, the version returned will be \fBPOOL_VER_NONE\fR. +.sp +.LP +The \fBpool_get_status()\fR function retrieves the current state of the pools +facility. If state is non-null, then on successful completion the state of the +pools facility is stored in the location pointed to by state. +.sp +.LP +The \fBpool_set_status()\fR function modifies the current state of the pools +facility. On successful completion the state of the pools facility is changed +to match the value supplied in state. Only two values are valid for state, +\fBPOOL_DISABLED\fR and \fBPOOL_ENABLED\fR, both of which are defined in +<\fBpool.h\fR>. +.sp +.LP +The \fBpool_resource_type_list()\fR function enumerates the resource types +supported by the pools framework on this platform. If \fInumres\fR and +\fIreslist\fR are both non-null, \fIreslist\fR points to a buffer where a list +of resource types in the system is to be stored, and \fInumres\fR points to the +maximum number of resource types the buffer can hold. On successful completion, +the list of resource types up to the maximum buffer size is stored in the +buffer pointed to by \fIreslist\fR. +.SH RETURN VALUES +.sp +.LP +The \fBpool_dynamic_location()\fR function returns the location used by the +pools framework to store the dynamic configuration. +.sp +.LP +The \fBpool_static_location()\fR function returns the location used by the +pools framework to store the default configuration used for pools framework +instantiation. +.sp +.LP +The \fBpool_version()\fR function returns the version number of the library or +\fBPOOL_VER_NONE\fR. +.sp +.LP +Upon successful completion, \fBpool_get_status()\fR, \fBpool_set_status()\fR, +and \fBpool_resource_type_list()\fR all return 0. Otherwise, \(mi1 is returned +and \fBpool_error\fR(3POOL) returns the pool specific error. +.SH ERRORS +.sp +.LP +No errors are defined for \fBpool_dynamic_location()\fR, +\fBpool_static_location()\fR, and \fBpool_version()\fR. +.sp +.LP +The \fBpool_get_status()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 14n +A system error occurred when accessing the kernel pool state. +.RE + +.sp +.LP +The \fBpool_set_status()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 14n +A system error occurred when modifying the kernel pool state. +.RE + +.sp +.LP +The \fBpool_resource_type_list()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The \fInumres\fR parameter was \fINULL\fR. +.RE + +.SH EXAMPLES +.LP +\fBExample 1 \fRGet the static location used by the pools framework. +.sp +.in +2 +.nf +#include sys/types.h> +#include <unistd.h> +#include <pool.h> + +\&... + +const char *location = pool_dynamic_location(); + +\&... + + (void) fprintf(stderr, "pool dynamic location is %s\en", + location); +.fi +.in -2 + +.LP +\fBExample 2 \fREnable the pools facility. +.sp +.in +2 +.nf +#include <stdio.h> +#include <pool.h> + +\&... + + if (pool_set_status(POOL_ENABLED) != 0) { + (void) fprintf(stderr, "pools could not be enabled %s\en", + pool_strerror(pool_error())); + exit(2); + } +\&... +.fi +.in -2 + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_error.3pool b/usr/src/man/man3pool/pool_error.3pool new file mode 100644 index 0000000..a5c1f36 --- /dev/null +++ b/usr/src/man/man3pool/pool_error.3pool @@ -0,0 +1,176 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_ERROR 3POOL "Sep 23, 2003" +.SH NAME +pool_error, pool_strerror \- error interface to resource pools library +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBint\fR \fBpool_error\fR(\fBvoid\fR); +.fi + +.LP +.nf +\fBconst char *\fR\fBpool_strerror\fR(\fBint\fR \fIperr\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +The \fBpool_error()\fR function returns the error value of the last failure +recorded by the invocation of one of the functions of the resource pool +configuration library, \fBlibpool\fR. +.sp +.LP +The \fBpool_strerror()\fR function returns a descriptive null-terminated string +for each of the valid pool error codes. +.sp +.LP +The following error codes can be returned by \fBpool_error()\fR: +.SH RETURN VALUES +.sp +.LP +The \fBpool_error()\fR function returns the current pool error value for the +calling thread from among the following: +.sp +.ne 2 +.na +\fB\fBPOE_ACCESS\fR\fR +.ad +.RS 22n +The operation could not be performed because the configuration was not opened +with the correct opening permissions. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 22n +A bad parameter was supplied. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_BAD_PROP_TYPE\fR\fR +.ad +.RS 22n +An incorrect property type was submitted or encountered during the pool +operation. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_DATASTORE\fR\fR +.ad +.RS 22n +An error occurred within permanent storage. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 22n +The pool configuration presented for the operation is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_SEARCH\fR\fR +.ad +.RS 22n +A query whose outcome set was empty was attempted. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_NOTSUP\fR\fR +.ad +.RS 22n +An unsupported operation was attempted. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_PUTPROP\fR\fR +.ad +.RS 22n +An attempt to write a read-only property was made. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_OK\fR\fR +.ad +.RS 22n +The previous pool operation succeeded. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 22n +An underlying system call or library function failed; \fBerrno\fR(3C) is +preserved where possible. +.RE + +.sp +.LP +The \fBpool_strerror()\fR function returns a pointer to the string +corresponding to the requested error value. If the error value has no +corresponding string, \(mi1 is returned and \fBerrno\fR is set to indicate the +error. +.SH ERRORS +.sp +.LP +The \fBpool_strerror()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBESRCH\fR\fR +.ad +.RS 9n +The specified error value is not defined by the pools error facility. +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBerrno\fR(3C), \fBlibpool\fR(3LIB), pool_error(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_get_binding.3pool b/usr/src/man/man3pool/pool_get_binding.3pool new file mode 100644 index 0000000..b1cae5d --- /dev/null +++ b/usr/src/man/man3pool/pool_get_binding.3pool @@ -0,0 +1,249 @@ +'\" te +.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_GET_BINDING 3POOL "Mar 27, 2007" +.SH NAME +pool_get_binding, pool_set_binding, pool_get_resource_binding \- set and query +process to resource pool bindings +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBchar *\fR\fBpool_get_binding\fR(\fBpid_t\fR \fIpid\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_set_binding\fR(\fBconst char *\fR\fIpool\fR, \fBidtype_t\fR \fIidtype\fR, + \fBid_t\fR \fIid\fR); +.fi + +.LP +.nf +\fBchar *\fR\fBpool_get_resource_binding\fR(\fBconst char *\fR\fItype\fR, \fBpid_t\fR \fIpid\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +The \fBpool_get_binding()\fR function returns the name of the pool on the +running system that contains the set of resources to which the given process is +bound. If no such pool exists on the system or the search returns more than one +pool (since the set of resources is referred to by more than one pool), +\fINULL\fR is returned and the pool error value is set to +\fBPOE_INVALID_SEARCH\fR. +.sp +.LP +It is possible that one of the resources to which the given process is bound is +not associated with a pool. This could occur if a processor set was created +with one of the \fBpset_()\fR functions and the process was then bound to that +set. It could also occur if the process was bound to a resource set not +currently associated with a pool, since resources can exist that are not +associated with a pool. +.sp +.LP +The \fBpool_set_binding()\fR function binds the processes matching \fIidtype\fR +and \fIid\fR to the resources associated with \fIpool\fR on the running system. +This function requires the privilege required by the underlying resource types +referenced by the pool; generally, this requirement is equivalent to requiring +superuser privilege. +.sp +.LP +The \fIidtype\fR parameter can be of the following types: +.sp +.ne 2 +.na +\fB\fBP_PID\fR\fR +.ad +.RS 12n +The \fIid\fR parameter is a pid. +.RE + +.sp +.ne 2 +.na +\fB\fBP_TASKID\fR\fR +.ad +.RS 12n +The \fIid\fR parameter is a taskid. +.RE + +.sp +.ne 2 +.na +\fB\fBP_PROJID\fR\fR +.ad +.RS 12n +The \fIid\fR parameter is a project ID. All currently running processes +belonging to the given project will be bound to the pool's resources. +.RE + +.sp +.LP +The \fBpool_get_resource_binding()\fR function returns the name of the resource +of the supplied type to which the supplied process is bound. +.sp +.LP +The application must explicity free the memory allocated for the return values +for \fBpool_get_binding()\fR and \fBpool_get_resource_binding()\fR. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_get_binding()\fR returns the name of the +pool to which the process is bound. Otherwise it returns \fINULL\fR and +\fBpool_error\fR(3POOL) returns the pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_set_binding()\fR returns \fBPO_SUCCESS\fR. +Otherwise, it returns \fBPO_FAIL\fR and \fBpool_error()\fR returns the +pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_get_resource_binding()\fR returns the name +of the resource of the specified type to which the process is bound. Otherwise +it returns \fINULL\fR and \fBpool_error()\fR returns the pool-specific error +value. +.SH ERRORS +.sp +.LP +The \fBpool_get_binding()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 22n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_SEARCH\fR\fR +.ad +.RS 22n +It is not possible to determine the binding for this target due to the +overlapping nature of the pools configured for this system, or the pool could +not be located. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 22n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_set_binding()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_SEARCH\fR\fR +.ad +.RS 22n +The pool could not be found. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 22n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 22n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_get_resource_binding()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 22n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_SEARCH\fR\fR +.ad +.RS 22n +The target is not bound to a resource of the specified type. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 22n +A system error has occurred. Check the system error code for more details. +.RE + +.SH EXAMPLES +.LP +\fBExample 1 \fRBind the current process to the pool named "target". +.sp +.in +2 +.nf +#include <sys/types.h> +#include <pool.h> +#include <unistd.h> + +\&... + +id_t pid = getpid(); + +\&... + +if (pool_set_binding("target", P_PID, pid) == PO_FAIL) \{ + (void) fprintf(stderr, "pool binding failed (\\%d)\\B{}n", + pool_error()); +\} +.fi +.in -2 + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_get_pool.3pool b/usr/src/man/man3pool/pool_get_pool.3pool new file mode 100644 index 0000000..591a40f --- /dev/null +++ b/usr/src/man/man3pool/pool_get_pool.3pool @@ -0,0 +1,203 @@ +'\" te +.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_GET_POOL 3POOL "Jul 18, 2005" +.SH NAME +pool_get_pool, pool_get_resource, pool_query_components, pool_query_pools, +pool_query_resources \- retrieve resource pool configuration elements +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR]\&.\|.\|. \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBpool_t *\fR\fBpool_get_pool\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBconst char *\fR\fIname\fR); +.fi + +.LP +.nf +\fBpool_resource_t *\fR\fBpool_get_resource\fR(\fBpool_conf_t *\fR\fIconf\fR + \fBconst char *\fR\fItype\fR, \fBconst char *\fR\fIname\fR); +.fi + +.LP +.nf +\fBpool_component_t **\fR\fBpool_query_components\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBuint_t *\fR\fInelem\fR, \fBpool_value_t **\fR\fIprops\fR); +.fi + +.LP +.nf +\fBpool_t **\fR\fBpool_query_pools\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBuint_t *\fR\fInelem\fR, + \fBpool_value_t **\fR\fIprops\fR); +.fi + +.LP +.nf +\fBpool_component_t **\fR\fBpool_query_resources\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBuint_t *\fR\fInelem\fR, \fBpool_value_t **\fR\fIprops\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +These functions provide a means for querying the contents of the specified +configuration. The \fIconf\fR argument for each function refers to the target +configuration to which the operation applies. +.sp +.LP +The \fBpool_get_pool()\fR function returns the pool with the given name from +the provided configuration. +.sp +.LP +The \fBpool_get_resource()\fR function returns the resource with the given name +and type from the provided configuration. +.sp +.LP +The \fBpool_query_components()\fR function retrieves all resource components +that match the given list of properties. If the list of properties is +\fINULL\fR, all components are returned. The number of elements returned is +stored in the location pointed to by \fInelem\fR. The value returned by +\fBpool_query_components()\fR is allocated with \fBmalloc\fR(3C) and must be +explicitly freed. +.sp +.LP +The \fBpool_query_pools()\fR function behaves similarly to +\fBpool_query_components()\fR and returns the list of pools that match the +given list of properties. The value returned must be freed by the caller. +.sp +.LP +The \fBpool_query_resources()\fR function similarly returns the list of +resources that match the given list of properties. The return value must be +freed by the caller. +.SH RETURN VALUES +.sp +.LP +The \fBpool_get_pool()\fR and \fBpool_get_resource()\fR functions return the +matching pool and resource, respectively. Otherwise, they return \fINULL\fR and +\fBpool_error\fR(3POOL) returns the pool-specific error value. +.sp +.LP +The \fBpool_query_components()\fR, \fBpool_query_pools()\fR, and +\fBpool_query_resources()\fR functions return a null-terminated array of +components, pools, and resources, respectively. If the query was unsuccessful +or there were no matches, \fINULL\fR is returned and \fBpool_error()\fR returns +the pool-specific error value. +.SH ERRORS +.sp +.LP +The \fBpool_get_pool()\fR will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.LP +The \fBpool_get_resource()\fR will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +There is not enough memory available to allocate working buffers. Check +\fBerrno\fR for the specific system error code. +.RE + +.sp +.LP +The \fBpool_query_components()\fR, \fBpool_query_pools()\fR, and +\fBpool_query_resources()\fR will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The query generated results that were not of the correct type. The +configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +There is not enough memory available to allocate working buffers. Check +\fBerrno\fR for the specific system error code. +.RE + +.SH EXAMPLES +.LP +\fBExample 1 \fRRetrieve the pool named "foo" from a given configuration. +.sp +.in +2 +.nf +#include <pool.h> +#include <stdio.h> + +\&... + +pool_conf_t *conf; +pool_t *pool; + +\&... + +if ((pool = pool_get_pool(conf, "foo")) == NULL) { + (void) fprintf(stderr, "Cannot retrieve pool named + 'foo'\\B{}n"); + ... +} +.fi +.in -2 + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_get_property.3pool b/usr/src/man/man3pool/pool_get_property.3pool new file mode 100644 index 0000000..410c40d --- /dev/null +++ b/usr/src/man/man3pool/pool_get_property.3pool @@ -0,0 +1,278 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_GET_PROPERTY 3POOL "Sep 23, 2003" +.SH NAME +pool_get_property, pool_put_property, pool_rm_property, pool_walk_properties \- +resource pool element property manipulation +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBpool_value_class_t\fR \fBpool_get_property\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBconst pool_elem_t *\fR\fIelem\fR, \fBconst char *\fR\fIname\fR, + \fBpool_value_t *\fR\fIproperty\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_put_property\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_elem_t *\fR\fIelem\fR, + \fBconst char *\fR\fIname\fR, \fBconst pool_value_t *\fR\fIvalue\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_rm_property\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_elem_t *\fR\fIelem\fR, + \fBconst char *\fR\fIname\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_walk_properties\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_elem_t *\fR\fIelem\fR, + \fBvoid *\fR\fIarg\fR, \fBint (*\fR\fIcallback\fR)(\fBpool_conf_t *\fR, \fBpool_elem_t *\fR, + \fBconst char *\fR, \fBpool_value_t *\fR, \fBvoid *\fR)); +.fi + +.SH DESCRIPTION +.sp +.LP +The various pool types are converted to the common pool element type +(\fBpool_elem_t\fR) before property manipulation. A \fBpool_value_t\fR is an +opaque type that contains a property value of one of the following types: +.sp +.ne 2 +.na +\fB\fBPOC_UINT\fR\fR +.ad +.RS 14n +unsigned 64-bit integer +.RE + +.sp +.ne 2 +.na +\fB\fBPOC_INT\fR\fR +.ad +.RS 14n +signed 64-bit integer +.RE + +.sp +.ne 2 +.na +\fB\fBPOC_DOUBLE\fR\fR +.ad +.RS 14n +signed double-precision floating point value +.RE + +.sp +.ne 2 +.na +\fB\fBPOC_BOOL\fR\fR +.ad +.RS 14n +boolean value: 0 is false, non-zero is true +.RE + +.sp +.ne 2 +.na +\fB\fBPOC_STRING\fR\fR +.ad +.RS 14n +null-terminated string of characters +.RE + +.sp +.LP +The \fIconf\fR argument for each function refers to the target configuration to +which the operation applies. +.sp +.LP +The \fBpool_get_property()\fR function attempts to retrieve the value of the +named property from the element. If the property is not found or an error +occurs, the value \fBPOC_INVAL\fR is returned to indicate error. Otherwise the +type of the value retrieved is returned. +.sp +.LP +The \fBpool_put_property()\fR function attempts to set the named property on +the element to the specified value. Attempting to set a property that does not +currently exist on the element will cause the property with the given name and +value to be created on the element and will not cause an error. An attempt to +overwrite an existing property with a new property of a different type is an +error. +.sp +.LP +The \fBpool_rm_property()\fR function attempts to remove the named property +from the element. If the property does not exist or is not removable, -1 is +returned and \fBpool_error\fR(3POOL) reporst an error of \fBPOE_PUTPROP\fR. +.sp +.LP +The \fBpool_walk_properties()\fR function invokes \fIcallback\fR on all +properties defined for the given element. The \fIcallback\fR is called with the +element itself, the name of the property, the value of the property, and the +caller-provided opaque argument. +.sp +.LP +A number of special properties are reserved for internal use and cannot be set +or removed. Attempting to do so will fail. These properties are documented on +the \fBlibpool\fR(3LIB) manual page. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_get_property()\fR returns the type of the +property. Otherwise it returns \fBPOC_INVAL\fR and \fBpool_error()\fR returns +the pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_put_property()\fR, +\fBpool_rm_property()\fR, and \fBpool_walk_properties()\fR return 0. Otherwise +they return \(mi1 and \fBpool_error()\fR returns the pool-specific error value. +.SH ERRORS +.sp +.LP +The \fBpool_get_property()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR, the supplied +\fIconf\fR does not contain the supplied \fIelem\fR, or the property is +restricted and cannot be accessed by the library. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_put_property()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR, the supplied +\fIconf\fR does not contain the supplied \fIelem\fR, the property name is not +in the correct format, or the property already exists and the supplied type +does not match the existing type. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_PUTPROP\fR\fR +.ad +.RS 20n +The property name is reserved by \fBlibpool\fR and not available for use. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.LP +The \fBpool_rm_property()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR, the supplied +\fIconf\fR does not contain the supplied elem, or the property is reserved by +libpool and cannot be removed. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_PUTPROP\fR\fR +.ad +.RS 16n +The property name is reserved by \fBlibpool\fR and not available for use. +.RE + +.sp +.LP +The \fBpool_walk_properties()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +A system error has occurred. Check the system error code for more details. +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_resource_create.3pool b/usr/src/man/man3pool/pool_resource_create.3pool new file mode 100644 index 0000000..62813a0 --- /dev/null +++ b/usr/src/man/man3pool/pool_resource_create.3pool @@ -0,0 +1,339 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_RESOURCE_CREATE 3POOL "Sep 23, 2003" +.SH NAME +pool_resource_create, pool_resource_destroy, pool_resource_info, +pool_query_resource_components, pool_resource_transfer, pool_resource_xtransfer +\- resource pool resource manipulation functions +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBpool_resource_t *\fR\fBpool_resource_create\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBconst char *\fR\fItype\fR, \fBconst char *\fR\fIname\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_resource_destroy\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_resource_t *\fR\fIresource\fR); +.fi + +.LP +.nf +\fBconst char *\fR\fBpool_resource_info\fR(\fBpool_conf_t *\fR\fIconf\fR + \fBpool_resource_t *\fR\fIresource\fR, \fBint\fR \fIflags\fR); +.fi + +.LP +.nf +\fBpool_component_t **\fR\fBpool_query_resource_components\fR( + \fBpool_conf_t *\fR\fIconf\fR, \fBpool_resource_t *\fR\fIresource\fR, + \fBuint_t *\fR\fInelem\fR, \fBpool_value_t **\fR\fIprops\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_resource_transfer\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_resource_t *\fR\fIsource\fR, \fBpool_resource_t *\fR\fItarget\fR, + \fBuint64_t\fR \fIsize\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_resource_xtransfer\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_resource_t *\fR\fIsource\fR, \fBpool_resource_t *\fR\fItarget\fR, + \fBpool_component_t **\fR\fIcomponents\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +The \fBpool_resource_create()\fR function creates and returns a new resource of +the given \fIname\fR and \fItype\fR in the provided configuration. If there is +already a resource of the given name, the operation will fail. +.sp +.LP +The \fBpool_resource_destroy()\fR function removes the specified \fIresource\fR +from its configuration file. +.sp +.LP +The \fBpool_resource_info()\fR function returns a string describing the given +\fIresource\fR. The string is allocated with \fBmalloc\fR(3C). The caller is +reponsible for freeing the returned string. If the \fIflags\fR argument is +non-zero, the string returned also describes the components (if any) contained +in the resource. +.sp +.LP +The \fBpool_query_resource_components()\fR function returns a null-terminated +array of the components (if any) that comprise the given resource. +.sp +.LP +The \fBpool_resource_transfer()\fR function transfers \fIsize\fR basic units +from the \fIsource\fR resource to the \fItarget\fR. Both resources must be of +the same type for the operation to succeed. Transferring component resources, +such as processors, is always performed as series of +\fBpool_resource_xtransfer()\fR operations, since discrete resources must be +identified for transfer. +.sp +.LP +The \fBpool_resource_xtransfer()\fR function transfers the specific +\fIcomponents\fR from the \fIsource\fR resource to the \fItarget\fR. Both +resources must be of the same type, and of a type that contains components +(such as processor sets). The \fIcomponents\fR argument is a null-terminated +list of \fBpool_component_t\fR. +.sp +.LP +The \fIconf\fR argument for each function refers to the target configuration to +which the operation applies. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_resource_create()\fR returns a new +\fBpool_resource_t\fR with default properties initialized. Otherwise, +\fINULL\fR is returned and \fBpool_error\fR(3POOL) returns the pool-specific +error value. +.sp +.LP +Upon successful completion, \fBpool_resource_destroy()\fR returns 0. Otherwise, +-1 is returned and \fBpool_error()\fR returns the pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_resource_info()\fR returns a string +describing the given resource (and optionally its components). Otherwise, +\fINULL\fR is returned and \fBpool_error()\fR returns the pool-specific error +value. +.sp +.LP + Upon successful completion, \fBpool_query_resource_components()\fR returns a +null-terminated array of \fBpool_component_t *\fR that match the provided +null-terminated property list and are contained in the given resource. +Otherwise, \fINULL\fR is returned and \fBpool_error()\fR returns the +pool-specific error value. +.sp +.LP + Upon successful completion, \fBpool_resource_transfer()\fR and +\fBpool_resource_xtransfer()\fR return 0. Otherwise -1 is returned and +\fBpool_error()\fR returns the pool-specific error value. +.SH ERRORS +.sp +.LP +The \fBpool_resource_create()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or \fIname\fR is in +use for this resource type. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The resource element could not be created because the configuration would be +invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_PUTPROP\fR\fR +.ad +.RS 20n +One of the supplied properties could not be set. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n + A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_resource_destroy()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.LP +The \fBpool_resource_info()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR or the \fIflags\fR +paramter is neither 0 nor 1. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_query_resource_components()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_resource_transfer()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied configuration's status is not \fBPOF_VALID\fR, the two resources +are not of the same type, or the transfer would cause either of the resources +to exceed their \fBmin\fR and \fBmax\fR properties. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 16n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_resource_xtransfer()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR, the two resources +are not of the same type, or the supplied resources do not belong to the +source. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The transfer operation failed and the configuration may be invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.SH EXAMPLES +.LP +\fBExample 1 \fRCreate a new resource of type \fBpset\fR named \fBfoo\fR. +.sp +.in +2 +.nf +#include <pool.h> +#include <stdio.h> + +\&... + +pool_conf_t *conf; +pool_resource_t *resource; +\&... + +if ((resource = pool_resource_create(conf, "pset", + "foo")) == NULL) { + (void) fprintf(stderr, "Cannot create resource\\B{}n"); + ... +} +.fi +.in -2 + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_value_alloc.3pool b/usr/src/man/man3pool/pool_value_alloc.3pool new file mode 100644 index 0000000..8fba812 --- /dev/null +++ b/usr/src/man/man3pool/pool_value_alloc.3pool @@ -0,0 +1,244 @@ +'\" te +.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_VALUE_ALLOC 3POOL "Sep 23, 2003" +.SH NAME +pool_value_alloc, pool_value_free, pool_value_get_bool, pool_value_get_double, +pool_value_get_int64, pool_value_get_name, pool_value_get_string, +pool_value_get_type, pool_value_get_uint64, pool_value_set_bool, +pool_value_set_double, pool_value_set_int64, pool_value_set_name, +pool_value_set_string, pool_value_set_uint64 \- resource pool property value +manipulation functions +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBpool_value_t *\fR\fBpool_value_alloc\fR(\fBvoid\fR); +.fi + +.LP +.nf +\fBvoid\fR \fBpool_value_free\fR(\fBpool_value_t *\fR\fIvalue\fR); +.fi + +.LP +.nf +\fBpool_value_class_t\fR \fBpool_value_get_type\fR( + \fBconst pool_value_t *\fR\fIvalue\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_get_bool\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBuchar_t *\fR\fIbool\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_get_double\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBdouble *\fR\fId\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_get_int64\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBint64_t *\fR\fIi64\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_get_string\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBconst char **\fR\fIstrp\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_get_uint64\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBuint64_t *\fR\fIui64\fR); +.fi + +.LP +.nf +\fBvoid\fR \fBpool_value_set_bool\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBuchar_t\fR \fIbool\fR); +.fi + +.LP +.nf +\fBvoid\fR \fBpool_value_set_double\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBdouble\fR \fId\fR); +.fi + +.LP +.nf +\fBvoid\fR \fBpool_value_set_int64\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBint64_t\fR \fIi64\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_set_string\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBconst char *\fR\fIstrp\fR); +.fi + +.LP +.nf +\fBvoid\fR \fBpool_value_set_uint64\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBuint64_t\fR \fIui64\fR); +.fi + +.LP +.nf +\fBconst char *\fR\fBpool_value_get_name\fR(\fBconst pool_value_t *\fR\fIvalue\fR); +.fi + +.LP +.nf +\fBint\fR \fBpool_value_set_name\fR(\fBconst pool_value_t *\fR\fIvalue\fR, + \fBconst char *\fR\fIname\fR); +.fi + +.SH DESCRIPTION +.sp +.LP +A \fBpool_value_t\fR is an opaque type representing the typed value portion of +a pool property. For a list of the types supported by a \fBpool_value_t\fR, see +\fBpool_get_property\fR(3POOL). +.sp +.LP +The \fBpool_value_alloc()\fR function allocates and returns an opaque container +for a pool property value. The \fBpool_value_free()\fR function must be called +explicitly for allocated property values. +.sp +.LP +The \fBpool_value_get_bool()\fR, \fBpool_value_get_double()\fR, +\fBpool_value_get_int64()\fR, \fBpool_value_get_string()\fR, and +\fBpool_value_get_uint64()\fR functions retrieve the value contained in the +\fBpool_value_t\fR pointed to by \fIvalue\fR to the location pointed to by the +second argument. If the type of the value does not match that expected by the +function, an error value is returned. The string retrieved by +\fBpool_value_get_string()\fR is freed by the library when the value is +overwritten or \fBpool_value_free()\fR is called on the pool property value. +.sp +.LP +The \fBpool_value_get_type()\fR function returns the type of the data contained +by a \fBpool_value_t\fR. If the value is unused then a type of \fBPOC_INVAL\fR +is returned. +.sp +.LP +The \fBpool_value_set_bool()\fR, \fBpool_value_set_double()\fR, +\fBpool_value_set_int64()\fR, \fBpool_value_set_string()\fR, and +\fBpool_value_set_uint64()\fR functions set the value and type of the property +value to the provided values. The \fBpool_value_set_string()\fR function copies +the string passed in and returns -1 if the memory allocation fails. +.sp +.LP +Property values can optionally have names. These names are used to describe +properties as name=value pairs in the various query functions (see +\fBpool_query_resources\fR(3POOL)). A copy of the string passed to +\fBpool_value_set_name()\fR is made by the library, and the value returned by +\fBpool_value_get_name()\fR is freed when the \fBpool_value_t\fR is deallocated +or overwritten. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, \fBpool_value_alloc()\fR returns a pool property +value with type initialized to \fBPVC_INVAL\fR. Otherwise, \fINULL\fR is +returned and \fBpool_error()\fR returns the pool-specific error value. +.sp +.LP +Upon successful completion, \fBpool_value_get_type()\fR returns the type +contained in the property value passed in as an argument. Otherwise, +\fBPOC_INVAL\fR is returned and \fBpool_error()\fR returns the pool-specific +error value. +.sp +.LP +Upon successful completion, \fBpool_value_get_bool()\fR, +\fBpool_value_get_double()\fR, \fBpool_value_get_int64()\fR, +\fBpool_value_get_string()\fR, and \fBpool_value_get_uint64()\fR return 0. +Otherwise -1 is returned and \fBpool_error\fR(3POOL) returns the pool-specific +error value. +.sp +.LP +Upon successful completion, \fBpool_value_set_string()\fR and +\fBpool_value_set_name()\fR return 0. If the memory allocation failed, -1 is +returned and \fBpool_error()\fR returns the pool-specific error value. +.SH ERRORS +.sp +.LP +The \fBpool_value_alloc()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 14n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_value_get_bool()\fR, \fBpool_value_get_double()\fR, +\fBpool_value_get_int64()\fR, \fBpool_value_get_string()\fR, and +\fBpool_value_get_uint64()\fR functions will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 16n +The supplied \fIvalue\fR does not match the type of the requested operation. +.RE + +.sp +.LP +The \fBpool_value_set_string()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 14n +A system error has occurred. Check the system error code for more details. +.RE + +.sp +.LP +The \fBpool_value_set_name()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 14n +A system error has occurred. Check the system error code for more details. +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) diff --git a/usr/src/man/man3pool/pool_walk_components.3pool b/usr/src/man/man3pool/pool_walk_components.3pool new file mode 100644 index 0000000..27d8387 --- /dev/null +++ b/usr/src/man/man3pool/pool_walk_components.3pool @@ -0,0 +1,115 @@ +'\" te +.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. +.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.TH POOL_WALK_COMPONENTS 3POOL "Jul 18, 2005" +.SH NAME +pool_walk_components, pool_walk_pools, pool_walk_resources \- walk objects +within resource pool configurations +.SH SYNOPSIS +.LP +.nf +cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lpool\fR [ \fIlibrary\fR\&.\|.\|. ] +#include <pool.h> + +\fBint\fR \fBpool_walk_components\fR(\fBpool_conf_t *\fR\fIconf\fR, + \fBpool_resource_t *\fR\fIresource\fR, \fBvoid *\fR\fIarg\fR, + \fBint (*\fR\fIcallback\fR)(\fBpool_conf_t *\fR, \fBpool_resource_t *\fR, \fBvoid *\fR)); +.fi + +.LP +.nf +\fBint\fR \fBpool_walk_pools\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBvoid *\fR\fIarg\fR, + \fBint (*\fR\fIcallback\fR)(\fBpool_conf_t *\fR, \fBpool_component_t *\fR, \fBvoid *\fR)); +.fi + +.LP +.nf +\fBint\fR \fBpool_walk_resources\fR(\fBpool_conf_t *\fR\fIconf\fR, \fBpool_t *\fR\fIpool\fR, + \fBvoid *\fR\fIarg\fR, \fBint (*\fR\fIcallback\fR)(\fBpool_conf_t *\fR, + \fBpool_component_t *\fR, \fBvoid *\fR)); +.fi + +.SH DESCRIPTION +.sp +.LP +The walker functions provided with \fBlibpool\fR(3LIB) visit each associated +entity of the given type, and call the caller-provided \fIcallback\fR function +with a user-provided additional opaque argument. There is no implied order of +visiting nodes in the walk. If the \fIcallback\fR function returns a non-zero +value at any of the nodes, the walk is terminated, and an error value of -1 +returned. The \fIconf\fR argument for each function refers to the target +configuration to which the operation applies. +.sp +.LP +The \fBpool_walk_components()\fR function invokes \fIcallback\fR on all +components contained in the resource. +.sp +.LP +The \fBpool_walk_pools()\fR function invokes \fIcallback\fR on all pools +defined in the configuration. +.sp +.LP +The \fBpool_walk_resources()\fR function invokes \fIcallback\fR function on all +resources associated with \fIpool\fR. +.SH RETURN VALUES +.sp +.LP +Upon successful completion of the walk, these functions return 0. Otherwise -1 +is returned and \fBpool_error\fR(3POOL) returns the pool-specific error value. +.SH ERRORS +.sp +.LP +These functions will fail if: +.sp +.ne 2 +.na +\fB\fBPOE_BADPARAM\fR\fR +.ad +.RS 20n +The supplied configuration's status is not \fBPOF_VALID\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_INVALID_CONF\fR\fR +.ad +.RS 20n +The configuration is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBPOE_SYSTEM\fR\fR +.ad +.RS 20n +A system error has occurred. Check the system error code for more details. +.RE + +.SH ATTRIBUTES +.sp +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +CSI Enabled +_ +Interface Stability Unstable +_ +MT-Level Safe +.TE + +.SH SEE ALSO +.sp +.LP +\fBlibpool\fR(3LIB), \fBpool_error\fR(3POOL), \fBattributes\fR(5) |