#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"
#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
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SYS_TEST"
#endif
const char pool_info_location[] = "/dev/pool";
static const char static_location[] = "/etc/pooladm.conf";
static const char dynamic_location[] = "/dev/poolctl";
static thread_key_t errkey = THR_ONCE_KEY;
static int pool_errval = POE_OK;
static uint_t pool_workver = POOL_VER_CURRENT;
static const char *data_type_tags[] = {
"uint",
"int",
"float",
"boolean",
"string"
};
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 *);
const char *
pool_static_location(void)
{
return (static_location);
}
const char *
pool_dynamic_location(void)
{
return (dynamic_location);
}
pool_conf_state_t
pool_conf_status(const pool_conf_t *conf)
{
return (conf->pc_state);
}
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);
}
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);
}
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);
}
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);
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:
break;
default:
return (PO_FAIL);
}
return (PO_SUCCESS);
}
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);
(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);
}
}
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) {
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) {
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:
break;
}
if (cb->cb_tab_buf[0] != 0)
cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0;
}
return (cb->cb_buf);
}
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));
}
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));
}
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));
}
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));
}
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);
}
int
pool_error(void)
{
if (thr_main())
return (pool_errval);
if (errkey == THR_ONCE_KEY)
return (POE_OK);
return ((uintptr_t)pthread_getspecific(errkey));
}
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;
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 (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);
}
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);
}
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);
}
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);
}
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));
}
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);
}
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 (PO_FAIL);
}
if (!is_valid_prop_name(name) || strstr(name, ".temporary") != NULL) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
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);
}
}
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));
}
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);
}
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);
}
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);
}
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));
}
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);
}
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 (PO_FAIL);
}
if (strstr(name, ".temporary") != NULL) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
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));
}
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);
}
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);
}
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) {
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 (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));
}
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) {
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) {
is_default = 1;
} else {
free(resources);
}
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);
}
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 (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));
}
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);
}
pe->pe_component_class = PCEC_CPU;
if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) {
(void) pool_component_destroy(pool_elem_comp(pe));
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_component_destroy(
pool_elem_comp(pe));
return (NULL);
}
}
}
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));
}
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);
}
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);
}
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_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);
}
void
pool_conf_free(pool_conf_t *conf)
{
free(conf);
}
int
pool_conf_open(pool_conf_t *conf, const char *location, int oflags)
{
internal_init();
if (pool_conf_status(conf) != POF_INVALID) {
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);
}
if (oflags & PO_CREAT)
oflags |= PO_RDWR;
if (oflags & PO_TEMP)
location = "";
if ((conf->pc_location = strdup(location)) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
if (oflags & PO_TEMP) {
if (pool_knl_connection_alloc(conf, PO_TEMP) != PO_SUCCESS) {
conf->pc_state = POF_INVALID;
return (PO_FAIL);
}
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);
}
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));
}
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);
}
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 {
retval = conf->pc_prov->pc_commit(conf);
}
return (retval);
}
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));
}
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));
}
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);
}
if (changed)
*changed = 0;
return (pool_knl_update((pool_conf_t *)conf, changed));
}
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);
}
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);
for (i = 0; props[i].pp_pname != NULL; i++) {
int j;
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 (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);
}
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) {
return (NULL);
}
if (size != 1) {
free(rs);
pool_seterror(POE_INVALID_CONF);
return (NULL);
}
ret = rs[0];
free(rs);
return (ret);
}
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);
}
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);
}
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);
}
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));
}
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);
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);
}
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);
}
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;
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);
}
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);
}
int
pool_elem_remove(pool_elem_t *pe)
{
return (pe->pe_remove(pe));
}
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));
}
pool_elem_t *
pool_rs_next(pool_result_set_t *set)
{
return (set->prs_next(set));
}
pool_elem_t *
pool_rs_prev(pool_result_set_t *set)
{
return (set->prs_prev(set));
}
pool_elem_t *
pool_rs_first(pool_result_set_t *set)
{
return (set->prs_first(set));
}
pool_elem_t *
pool_rs_last(pool_result_set_t *set)
{
return (set->prs_last(set));
}
int
pool_rs_count(pool_result_set_t *set)
{
return (set->prs_count(set));
}
int
pool_rs_get_index(pool_result_set_t *set)
{
return (set->prs_get_index(set));
}
int
pool_rs_set_index(pool_result_set_t *set, int index)
{
return (set->prs_set_index(set, index));
}
int
pool_rs_close(pool_result_set_t *set)
{
return (set->prs_close(set));
}
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);
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);
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--;
}
}
}
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);
return (size == 0 ? PO_SUCCESS : PO_FAIL);
}
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);
if (pool_resource_elem_class(TO_ELEM(src)) !=
pool_resource_elem_class(TO_ELEM(tgt))) {
pool_seterror(POE_BADPARAM);
return (XFER_FAIL);
}
if (src == tgt)
return (XFER_SUCCESS);
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) {
#ifdef DEBUG
pool_dprintf("conf is %s\n", pool_conf_location(conf));
pool_dprintf("setup_transfer: src_size %llu\n", *src_size);
pool_elem_dprintf(TO_ELEM(src));
pool_dprintf("setup_transfer: tgt_size %llu\n", *tgt_size);
pool_elem_dprintf(TO_ELEM(tgt));
#endif
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);
}
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 (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP)
return (choose_components(src, tgt, size));
ret = conf->pc_prov->pc_res_xfer(src, tgt, size);
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);
}
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;
for (i = 0; rl[i] != NULL; i++) {
#ifdef DEBUG
pool_dprintf("resource xtransfer\n");
pool_dprintf("in conf %s\n", pool_conf_location(conf));
pool_dprintf("transferring component\n");
pool_elem_dprintf(TO_ELEM(rl[i]));
pool_dprintf("from\n");
pool_elem_dprintf(TO_ELEM(src));
pool_dprintf("to\n");
pool_elem_dprintf(TO_ELEM(tgt));
#endif
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);
if (ret == PO_SUCCESS) {
pool_value_t val = POOL_VALUE_INITIALIZER;
#ifdef DEBUG
pool_dprintf("src_size %llu\n", src_size);
pool_dprintf("tgt_size %llu\n", tgt_size);
pool_dprintf("size %llu\n", size);
#endif
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);
}
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_elem_t *
pool_get_container(const pool_elem_t *pc)
{
return (pc->pe_get_container(pc));
}
int
pool_set_container(pool_elem_t *pp, pool_elem_t *pc)
{
return (pc->pe_set_container(pp, pc));
}
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);
}
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)
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);
}
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);
for (i = 0; i < size; i++)
if (callback(conf, rs[i], arg) != PO_SUCCESS) {
error = PO_FAIL;
break;
}
free(rs);
return (error);
}
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);
}
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);
for (i = 0; i < size; i++)
if (callback(conf, rs[i], arg) != PO_SUCCESS) {
error = PO_FAIL;
break;
}
free(rs);
return (error);
}
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);
}
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);
}
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));
}
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));
}
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;
if (pool_elem_same_class(e1, e2) != PO_TRUE)
return (1);
if (pool_elem_class(e1) == PEC_SYSTEM)
return (0);
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);
}
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;
if (pool_elem_same_class(e1, e2) != PO_TRUE)
return (1);
if (pool_elem_class(e1) == PEC_SYSTEM)
return (0);
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);
}
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);
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);
}
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);
}