#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
typedef struct res_info {
pool_resource_t *ri_res;
uint64_t ri_min;
uint64_t ri_max;
uint64_t ri_oldsize;
uint64_t ri_newsize;
uint64_t ri_pinned;
uint64_t ri_dealt;
int64_t ri_transfer;
} res_info_t;
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);
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 *);
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:
break;
case PEC_POOL:
name = elem_get_name(src);
if ((pool = pool_create(conf, name)) == NULL) {
free(name);
return (PO_FAIL);
}
free(name);
if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(pool),
clone_element) != PO_SUCCESS)
return (PO_FAIL);
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);
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);
}
if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(res),
clone_element) != PO_SUCCESS)
return (PO_FAIL);
pool_set_pair(TO_ELEM(res), src);
*e1 = TO_ELEM(res);
break;
case PEC_COMP:
break;
default:
return (PO_FAIL);
}
return (PO_SUCCESS);
}
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:
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:
break;
default:
return (PO_FAIL);
}
return (ret);
}
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
pool_dprintf("transferring: res, comp\n");
pool_elem_dprintf(TO_ELEM(newres));
pool_elem_dprintf(e2);
#endif
(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);
}
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);
}
}
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);
}
static int
diff_and_fix(pool_conf_t *stc, pool_conf_t *dyn)
{
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);
}
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;
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);
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);
}
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);
i = j = 0;
while (status == PO_SUCCESS && i < stc_nelem && j < dyn_nelem) {
int compare;
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 {
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);
}
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);
}
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;
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) {
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);
}
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:
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);
}
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);
}
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];
}
for (j = 0; j < nelem; j++) {
uint64_t real_min;
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);
}
}
}
for (j = 0; j < nelem; j++) {
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);
}
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;
uint64_t tot_min = 0;
uint64_t num_to_deal = 0;
uint64_t sets_maxed = 0;
uint64_t sets_finished = 0;
int donor, receiver;
int deal;
int j;
int ret = PO_SUCCESS;
if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
qsort(res, nelem, sizeof (pool_resource_t *),
resource_compare_by_descending_importance);
for (j = 0; j < nelem; j++) {
if (default_res == NULL &&
resource_is_default(res[j]) == PO_TRUE) {
default_res = res[j];
default_res_info = &(res_info[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_newsize = res_info[j].ri_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];
tot_resources += res_info[j].ri_oldsize;
tot_min += res_info[j].ri_newsize;
#ifdef DEBUG
pool_dprintf("res allocation details\n");
pool_elem_dprintf(TO_ELEM(res[j]));
pool_dprintf("size=%llu\n", res_info[j].ri_oldsize);
#endif
}
num_to_deal = tot_resources - tot_min;
for (deal = 1; num_to_deal > 0 && sets_maxed < nelem; deal++) {
for (j = 0; j < nelem; j++) {
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 ((sets_maxed == nelem) && (num_to_deal > 0)) {
default_res_info->ri_dealt += num_to_deal;
default_res_info->ri_newsize += num_to_deal;
}
qsort(res_info, nelem, sizeof (res_info_t),
compute_size_to_transfer);
donor = nelem - 1;
receiver = 0;
sets_finished = 0;
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;
}
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);
}
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));
}
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));
}
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);
}
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);
}
static int
add_importance_props(pool_conf_t *conf)
{
return (pool_walk_pools(conf, NULL, set_importance_cb));
}
static int
remove_importance_props(pool_conf_t *conf)
{
return (pool_walk_pools(conf, NULL, unset_importance_cb));
}
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);
}
}
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);
}
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
pool_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));
pool_dprintf("clone_element: Processing %s\n", name);
pool_value_dprintf(pv);
#endif
if ((prop = provider_get_prop(pe, name)) != NULL &&
prop_is_readonly(prop) == PO_TRUE)
return (PO_SUCCESS);
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);
}
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;
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);
}