2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * These functions implement the process of commitment for a pool
2N/A * configuration. This process can be described as taking instructions
2N/A * from a static configuration file and using the information about
2N/A * the target system contained in the dynamic configuration to make
2N/A * decisions about how best to allocate resources to meet the
2N/A * constraints specified in the static configuration file.
2N/A *
2N/A * Mechanically, this process relies upon ordering the individual
2N/A * components of the file and stepping through the lists of components
2N/A * and taking actions depending on their type and which file they are
2N/A * part of.
2N/A *
2N/A * Configuration components can be broken down into different types
2N/A * which are then treated according to the following table:
2N/A *
2N/A * Element Type Action
2N/A * system || pool ||
2N/A * res_comp || res_agg If the element is a required element, then create or
2N/A * update it (don't destroy required elements in the
2N/A * static configuration) otherwise manipulate the
2N/A * dynamic configuration to create, destroy or update
2N/A * the element on the system.
2N/A * comp Create, destroy or update the static configuration
2N/A * component.
2N/A *
2N/A * The treatment of the different elements reflects the fact that all
2N/A * elements other than comp are configurable and thus libpool can
2N/A * create, destroy and modify these elements at will. comp elements
2N/A * reflect the disposition of the system, these elements can be moved
2N/A * around but they can't be created or destroyed in the dynamic
2N/A * configuration in the commit process. comp elements can be created
2N/A * and destroyed in the static configuration file as a result of a
2N/A * commit operation, since it's possible for a comp to not appear in
2N/A * the dynamic configuration. For instance, if the static
2N/A * configuration file was created on a different machine or after a DR
2N/A * operation which has removed or added components.
2N/A *
2N/A */
2N/A#include <assert.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <sys/types.h>
2N/A#include <errno.h>
2N/A#include <string.h>
2N/A#include <limits.h>
2N/A#include <unistd.h>
2N/A
2N/A#include <pool.h>
2N/A#include "pool_internal.h"
2N/A#include "pool_impl.h"
2N/A
2N/A#define MIN(x, y) ((x) < (y) ? (x) : (y))
2N/A#define MAX(x, y) ((x) > (y) ? (x) : (y))
2N/A#define POA_IMPORTANCE_NUM 0
2N/A#define POA_SURPLUS_TO_DEFAULT_NUM 1
2N/A
2N/A/*
2N/A * This resource specific structure is used to determine allocation of resources
2N/A * during resource set allocation. Each set will receive its min, plus
2N/A * some number of dealt resources based on the global allocation policy.
2N/A */
2N/Atypedef struct res_info {
2N/A pool_resource_t *ri_res; /* Resource set */
2N/A uint64_t ri_min; /* Resource set's low watermark */
2N/A uint64_t ri_max; /* Resource set's high watermark */
2N/A uint64_t ri_oldsize; /* Size of resource set at the start */
2N/A uint64_t ri_newsize; /* New resource set size allocated */
2N/A uint64_t ri_pinned; /* Count of pinned resources in set */
2N/A uint64_t ri_dealt; /* Count of resources dealt to set */
2N/A int64_t ri_transfer; /* oldsize - newsize */
2N/A /* The signed quantity of resources */
2N/A /* to tranfer into or out of this */
2N/A /* resource set */
2N/A /* + transfer: tranfer resources out */
2N/A /* - transfer: tranfer resources in */
2N/A} res_info_t;
2N/A
2N/A/*
2N/A * diff_and_fix operations
2N/A */
2N/Astatic int commit_create(pool_conf_t *, pool_elem_t **);
2N/Astatic int commit_delete(pool_elem_t *);
2N/Astatic int commit_update(pool_elem_t *, pool_elem_t *, int);
2N/A
2N/A/*
2N/A * configuration commit processing
2N/A */
2N/Astatic int diff_and_fix(pool_conf_t *, pool_conf_t *);
2N/Astatic int process_elem_lt(pool_elem_t *, pool_conf_t *);
2N/Astatic int process_elem_gt(pool_elem_t *, pool_conf_t *,
2N/A pool_conf_t *);
2N/Astatic int process_lists(int, pool_conf_t *,
2N/A pool_conf_t *, int);
2N/Astatic pool_elem_t **get_elem_list(const pool_conf_t *, int, uint_t *);
2N/Astatic int share_resources(pool_conf_t *);
2N/Astatic int resource_allocate(const char *, pool_resource_t **,
2N/A uint_t);
2N/Astatic int resource_allocate_default(pool_resource_t **, uint_t);
2N/Astatic int pset_allocate_imp(pool_resource_t **, uint_t);
2N/Astatic int resource_compare_by_descending_importance(const void *,
2N/A const void *);
2N/Astatic int compute_size_to_transfer(const void *, const void *);
2N/Astatic int set_importance_cb(pool_conf_t *, pool_t *, void *);
2N/Astatic int unset_importance_cb(pool_conf_t *, pool_t *, void *);
2N/Astatic int add_importance_props(pool_conf_t *);
2N/Astatic int remove_importance_props(pool_conf_t *);
2N/Astatic int clone_element(pool_conf_t *, pool_elem_t *,
2N/A const char *, pool_value_t *, void *);
2N/Astatic int clean_element(pool_conf_t *, pool_elem_t *,
2N/A const char *, pool_value_t *, void *);
2N/A
2N/A/*
2N/A * commit_create() is used to create a configuration element upon the
2N/A * system. Since only pools and resource actually need to perform any
2N/A * action, other elements are ignored as a no-op.
2N/A */
2N/Astatic int
2N/Acommit_create(pool_conf_t *conf, pool_elem_t **e1)
2N/A{
2N/A pool_resource_t *res;
2N/A pool_t *pool;
2N/A const char *res_type;
2N/A pool_elem_t *src = *e1;
2N/A uint64_t smin, smax, dmax;
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A char *name;
2N/A
2N/A switch (pool_elem_class(src)) {
2N/A case PEC_SYSTEM: /* NO-OP */
2N/A break;
2N/A case PEC_POOL:
2N/A name = elem_get_name(src);
2N/A if ((pool = pool_create(conf, name)) == NULL) {
2N/A free(name);
2N/A return (PO_FAIL);
2N/A }
2N/A free(name);
2N/A /*
2N/A * Now copy the properties from the original pool to the
2N/A * new one
2N/A */
2N/A if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(pool),
2N/A clone_element) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A /*
2N/A * Add a pointer to the src element which can be
2N/A * updated with a sys_id when the sys_id is allocated
2N/A * to the created element.
2N/A */
2N/A pool_set_pair(TO_ELEM(pool), src);
2N/A *e1 = TO_ELEM(pool);
2N/A break;
2N/A case PEC_RES_COMP:
2N/A case PEC_RES_AGG:
2N/A name = elem_get_name(src);
2N/A res_type = pool_elem_class_string(src);
2N/A if ((res = pool_resource_create(conf, res_type, name)) ==
2N/A NULL) {
2N/A free(name);
2N/A return (PO_FAIL);
2N/A }
2N/A free(name);
2N/A /*
2N/A * Need to do some ordering of property updates.
2N/A * Compare the values of source min/max and
2N/A * destination min/max. If smin < dmax then update the
2N/A * smin first, else update the max first.
2N/A */
2N/A if (resource_get_min(pool_elem_res(src), &smin) != PO_SUCCESS ||
2N/A resource_get_max(pool_elem_res(src), &smax) != PO_SUCCESS ||
2N/A resource_get_max(res, &dmax) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A if (smin < dmax) {
2N/A pool_value_set_uint64(&val, smin);
2N/A if (pool_put_ns_property(TO_ELEM(res), c_min_prop,
2N/A &val) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A } else {
2N/A pool_value_set_uint64(&val, smax);
2N/A if (pool_put_ns_property(TO_ELEM(res), c_max_prop,
2N/A &val) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A }
2N/A /*
2N/A * Now copy the properties from the original resource
2N/A * to the new one
2N/A */
2N/A if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(res),
2N/A clone_element) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A /*
2N/A * Add a pointer to the src element which can be
2N/A * updated with a sys_id when the sys_id is allocated
2N/A * to the created element.
2N/A */
2N/A pool_set_pair(TO_ELEM(res), src);
2N/A *e1 = TO_ELEM(res);
2N/A break;
2N/A case PEC_COMP: /* NO-OP */
2N/A break;
2N/A default:
2N/A return (PO_FAIL);
2N/A }
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * commit_delete() is used to delete a configuration element upon the
2N/A * system. Since only pools and resources actually need to perform
2N/A * any action, other elements are ignored as a no-op.
2N/A */
2N/Astatic int
2N/Acommit_delete(pool_elem_t *pe)
2N/A{
2N/A pool_resource_t *res;
2N/A pool_t *pool;
2N/A int ret = 0;
2N/A
2N/A if (elem_is_tmp(pe))
2N/A return (PO_SUCCESS);
2N/A
2N/A switch (pool_elem_class(pe)) {
2N/A case PEC_SYSTEM: /* NO-OP */
2N/A break;
2N/A case PEC_POOL:
2N/A pool = pool_elem_pool(pe);
2N/A ret = pool_destroy(TO_CONF(pe), pool);
2N/A break;
2N/A case PEC_RES_COMP:
2N/A case PEC_RES_AGG:
2N/A res = pool_elem_res(pe);
2N/A ret = pool_resource_destroy(TO_CONF(pe), res);
2N/A break;
2N/A case PEC_COMP: /* NO-OP */
2N/A break;
2N/A default:
2N/A return (PO_FAIL);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * commit_update() is used to update a configuration element upon the
2N/A * system or in a static configuration file. The pass parameter
2N/A * governs whether properties are being updated or associations. In
2N/A * pass 0, properties are updated. If the element is of class
2N/A * PEC_COMP, then make sure that the element in the static
2N/A * configuration file is correctly located before proceeding with the
2N/A * update. Then, the element in the dynamic configuration file is
2N/A * updated. In pass 1, ie. pass != 0, any pool components have their
2N/A * associations updated in the dynamic configuration.
2N/A */
2N/Astatic int
2N/Acommit_update(pool_elem_t *e1, pool_elem_t *e2, int pass)
2N/A{
2N/A if (pass == 0) {
2N/A pool_resource_t *res1;
2N/A pool_resource_t *res2;
2N/A if (pool_elem_class(e1) == PEC_COMP) {
2N/A res1 = pool_get_owning_resource(TO_CONF(e1),
2N/A pool_elem_comp(e1));
2N/A res2 = pool_get_owning_resource(TO_CONF(e2),
2N/A pool_elem_comp(e2));
2N/A if (pool_elem_compare_name(TO_ELEM(res1),
2N/A TO_ELEM(res2)) != 0) {
2N/A char *name;
2N/A const pool_resource_t *newres;
2N/A pool_component_t *comps[2] = { NULL };
2N/A
2N/A comps[0] = pool_elem_comp(e2);
2N/A name = elem_get_name(TO_ELEM(res1));
2N/A newres = pool_get_resource(TO_CONF(e2),
2N/A pool_elem_class_string(TO_ELEM(res1)),
2N/A name);
2N/A free(name);
2N/A assert(newres);
2N/A#ifdef DEBUG
2N/A dprintf("transferring: res, comp\n");
2N/A pool_elem_dprintf(TO_ELEM(newres));
2N/A pool_elem_dprintf(e2);
2N/A#endif /* DEBUG */
2N/A (void) pool_resource_xtransfer(TO_CONF(e2),
2N/A res2, (pool_resource_t *)newres, comps);
2N/A }
2N/A }
2N/A if (pool_walk_properties(TO_CONF(e2), e2, NULL,
2N/A clean_element) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A /*
2N/A * Need to do some ordering of property updates if the
2N/A * element to be updated is a resource. Compare the
2N/A * values of source min/max and destination
2N/A * min/max. If smin < dmax then update the smin first,
2N/A * else update the max first.
2N/A */
2N/A if (pool_elem_class(e1) == PEC_RES_COMP ||
2N/A pool_elem_class(e1) == PEC_RES_AGG) {
2N/A uint64_t smin, smax, dmax;
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A
2N/A if (resource_get_min(pool_elem_res(e1), &smin) !=
2N/A PO_SUCCESS ||
2N/A resource_get_max(pool_elem_res(e1), &smax) !=
2N/A PO_SUCCESS ||
2N/A resource_get_max(pool_elem_res(e2), &dmax) !=
2N/A PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A if (smin < dmax) {
2N/A pool_value_set_uint64(&val, smin);
2N/A if (pool_put_ns_property(e2, c_min_prop,
2N/A &val) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A } else {
2N/A pool_value_set_uint64(&val, smax);
2N/A if (pool_put_ns_property(e2, c_max_prop,
2N/A &val) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A /*
2N/A * This next couple of steps needs some
2N/A * explanation. The first walk, copies all the
2N/A * properties that are writeable from the static
2N/A * configuration to the dynamic configuration. The
2N/A * second walk copies all properties (writeable or
2N/A * not) from the dynamic configuration element back to
2N/A * the static configuration element. This ensures that
2N/A * updates from the static configuration element are
2N/A * correctly applied to the dynamic configuration and
2N/A * then the static configuration element is updated
2N/A * with the latest values of the read-only xproperties
2N/A * from the dynamic configuration element. The
2N/A * enforcing of permisssions is performed in
2N/A * clone_element by its choice of property
2N/A * manipulation function.
2N/A */
2N/A if (pool_walk_properties(TO_CONF(e1), e1, e2, clone_element) !=
2N/A PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A if (pool_walk_properties(TO_CONF(e2), e2, e1, clone_element) !=
2N/A PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A } else {
2N/A if (pool_elem_class(e1) == PEC_POOL) {
2N/A pool_resource_t **rs;
2N/A uint_t nelem;
2N/A int i;
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A pool_value_t *pvals[] = { NULL, NULL };
2N/A
2N/A pvals[0] = &val;
2N/A if (pool_value_set_string(&val, "pset") != PO_SUCCESS ||
2N/A pool_value_set_name(&val, c_type) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A if ((rs = pool_query_pool_resources(TO_CONF(e1),
2N/A pool_elem_pool(e1), &nelem, pvals)) != NULL) {
2N/A for (i = 0; i < nelem; i++) {
2N/A const pool_resource_t *tgt_res;
2N/A char *res_name =
2N/A elem_get_name(TO_ELEM(rs[i]));
2N/A
2N/A if ((tgt_res = pool_get_resource(
2N/A TO_CONF(e2), pool_elem_class_string(
2N/A TO_ELEM(rs[i])), res_name)) ==
2N/A NULL) {
2N/A tgt_res = get_default_resource(
2N/A rs[i]);
2N/A }
2N/A free(res_name);
2N/A if (pool_associate(TO_CONF(e2),
2N/A pool_elem_pool(e2), tgt_res) !=
2N/A PO_SUCCESS) {
2N/A free(rs);
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A free(rs);
2N/A }
2N/A }
2N/A }
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * diff_and_fix() works out the differences between two configurations
2N/A * and modifies the state of the system to match the operations
2N/A * required to bring the two configurations into sync.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL.
2N/A */
2N/Astatic int
2N/Adiff_and_fix(pool_conf_t *stc, pool_conf_t *dyn)
2N/A{
2N/A /*
2N/A * The ordering of the operations is significant, we must
2N/A * process the system element, then the pools elements, then
2N/A * the resource elements, then the pools elements again and
2N/A * finally the resource components.
2N/A *
2N/A * TODO
2N/A * PEC_RES_COMP are the only type of resources
2N/A * currently. When PEC_RES_AGG resources are added they must
2N/A * also be processed.
2N/A */
2N/A if (process_lists(PEC_SYSTEM, stc, dyn, 0) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A if (process_lists(PEC_POOL, stc, dyn, 0) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A if (process_lists(PEC_RES_COMP, stc, dyn, 0) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A if (process_lists(PEC_COMP, stc, dyn, 0) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A if (process_lists(PEC_POOL, stc, dyn, 1) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A /*
2N/A * Share the resources. It has to be called for both
2N/A * configurations to ensure that the configurations still look
2N/A * the same.
2N/A */
2N/A if (share_resources(dyn) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A if (share_resources(stc) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Aprocess_elem_lt(pool_elem_t *pe, pool_conf_t *dyn)
2N/A{
2N/A if (pool_elem_class(pe) == PEC_COMP) {
2N/A if (pool_component_destroy(pool_elem_comp(pe)) == PO_FAIL) {
2N/A return (PO_FAIL);
2N/A }
2N/A } else if (! elem_is_default(pe)) {
2N/A if (commit_create(dyn, &pe) != PO_SUCCESS) {
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Aprocess_elem_gt(pool_elem_t *pe, pool_conf_t *stc, pool_conf_t *dyn)
2N/A{
2N/A if (pool_elem_class(pe) == PEC_COMP) {
2N/A pool_resource_t *owner;
2N/A const pool_resource_t *parent_res;
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A const pool_component_t *newcomp;
2N/A const char *resname;
2N/A const char *restype;
2N/A /*
2N/A * I have to find the right parent in the static
2N/A * configuration. It may not exist, in which case it's
2N/A * correct to put it in the default
2N/A */
2N/A owner = pool_get_owning_resource(dyn,
2N/A pool_elem_comp(pe));
2N/A if (pool_get_ns_property(TO_ELEM(owner), "name", &val) ==
2N/A POC_INVAL)
2N/A return (PO_FAIL);
2N/A
2N/A if (pool_value_get_string(&val, &resname) == PO_FAIL)
2N/A return (PO_FAIL);
2N/A
2N/A if ((resname = strdup(resname)) == NULL)
2N/A return (PO_FAIL);
2N/A
2N/A restype = pool_elem_class_string(TO_ELEM(owner));
2N/A parent_res = pool_get_resource(stc, restype, resname);
2N/A free((void *)resname);
2N/A if (parent_res == NULL)
2N/A parent_res = resource_by_sysid(stc, PS_NONE, restype);
2N/A /*
2N/A * Now need to make a copy of the component in the
2N/A * dynamic configuration in the static configuration.
2N/A */
2N/A if ((newcomp = pool_component_create(stc, parent_res,
2N/A elem_get_sysid(pe))) == NULL)
2N/A return (PO_FAIL);
2N/A
2N/A if (pool_walk_properties(TO_CONF(pe), pe, TO_ELEM(newcomp),
2N/A clone_element) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A } else if (elem_is_default(pe)) {
2N/A pool_resource_t *newres;
2N/A pool_t *newpool;
2N/A char *name;
2N/A
2N/A if ((name = elem_get_name(pe)) == NULL)
2N/A return (PO_FAIL);
2N/A switch (pool_elem_class(pe)) {
2N/A case PEC_POOL:
2N/A if ((newpool = pool_create(stc, name)) == NULL) {
2N/A free(name);
2N/A return (PO_FAIL);
2N/A }
2N/A free(name);
2N/A if (pool_walk_properties(TO_CONF(pe), pe,
2N/A TO_ELEM(newpool), clone_element) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A break;
2N/A case PEC_RES_AGG:
2N/A case PEC_RES_COMP:
2N/A if ((newres = pool_resource_create(stc,
2N/A pool_elem_class_string(pe), name)) ==
2N/A NULL) {
2N/A free(name);
2N/A return (PO_FAIL);
2N/A }
2N/A free(name);
2N/A if (pool_walk_properties(TO_CONF(pe), pe,
2N/A TO_ELEM(newres), clone_element) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A break;
2N/A default:
2N/A free(name);
2N/A break;
2N/A }
2N/A } else {
2N/A if (commit_delete(pe) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A }
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function compares the elements of the supplied type in the
2N/A * static and dynamic configurations supplied. The lists of elements
2N/A * are compared and used to create, delete and updated elements in
2N/A * both the static and dynamic configurations. The pass parameter is
2N/A * used to indicate to commit_update() whether property updates or
2N/A * association updates should be performed.
2N/A */
2N/Astatic int
2N/Aprocess_lists(int type, pool_conf_t *stc, pool_conf_t *dyn, int pass)
2N/A{
2N/A uint_t stc_nelem = 0, dyn_nelem = 0;
2N/A pool_elem_t **stc_elems, **dyn_elems;
2N/A int i, j;
2N/A int status = PO_SUCCESS;
2N/A
2N/A if ((stc_elems = get_elem_list(stc, type, &stc_nelem)) == NULL)
2N/A return (PO_FAIL);
2N/A
2N/A qsort(stc_elems, stc_nelem, sizeof (pool_elem_t *),
2N/A qsort_elem_compare);
2N/A
2N/A if ((dyn_elems = get_elem_list(dyn, type, &dyn_nelem)) == NULL) {
2N/A free(stc_elems);
2N/A return (PO_FAIL);
2N/A }
2N/A
2N/A qsort(dyn_elems, dyn_nelem, sizeof (pool_elem_t *),
2N/A qsort_elem_compare);
2N/A /*
2N/A * Step through and do the updating, remember that we are
2N/A * comparing using the compare function for the configuration
2N/A * and that is fixed.
2N/A */
2N/A i = j = 0;
2N/A while (status == PO_SUCCESS && i < stc_nelem && j < dyn_nelem) {
2N/A int compare;
2N/A /*
2N/A * We are going to do this by stepping through the static
2N/A * list first.
2N/A */
2N/A if (elem_is_default(stc_elems[i]) &&
2N/A elem_is_default(dyn_elems[j]))
2N/A compare = 0;
2N/A else
2N/A compare = pool_elem_compare_name(stc_elems[i],
2N/A dyn_elems[j]);
2N/A if (compare < 0) {
2N/A status = process_elem_lt(stc_elems[i], dyn);
2N/A i++;
2N/A } else if (compare > 0) {
2N/A status = process_elem_gt(dyn_elems[j], stc, dyn);
2N/A j++;
2N/A } else { /* compare == 0 */
2N/A if (commit_update(stc_elems[i], dyn_elems[j], pass)
2N/A != PO_SUCCESS) {
2N/A status = PO_FAIL;
2N/A }
2N/A i++;
2N/A j++;
2N/A }
2N/A }
2N/A if (status == PO_FAIL) {
2N/A free(stc_elems);
2N/A free(dyn_elems);
2N/A return (PO_FAIL);
2N/A }
2N/A while (status == PO_SUCCESS && i < stc_nelem) {
2N/A status = process_elem_lt(stc_elems[i], dyn);
2N/A i++;
2N/A }
2N/A if (status == PO_FAIL) {
2N/A free(stc_elems);
2N/A free(dyn_elems);
2N/A return (PO_FAIL);
2N/A }
2N/A while (status == PO_SUCCESS && j < dyn_nelem) {
2N/A status = process_elem_gt(dyn_elems[j], stc, dyn);
2N/A j++;
2N/A }
2N/A free(stc_elems);
2N/A free(dyn_elems);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * get_elem_list() returns a list of pool_elem_t's. The size of the
2N/A * list is written into nelem. The list contains elements of all types
2N/A * that pools is interested in: i.e. system, pool, resources and
2N/A * resource components. It is the caller's responsibility to free the
2N/A * list when it is finished with.
2N/A *
2N/A * The array of pointers returned by the type specific query can be
2N/A * safely cast to be an array of pool_elem_t pointers. In the case of
2N/A * PEC_RES_COMP some additional processing is required to qualify the
2N/A * list of elements.
2N/A *
2N/A * Returns a pointer to a list of pool_elem_t's or NULL on failure.
2N/A */
2N/Astatic pool_elem_t **
2N/Aget_elem_list(const pool_conf_t *conf, int type, uint_t *nelem)
2N/A{
2N/A pool_resource_t **rl;
2N/A pool_t **pl;
2N/A pool_component_t **cl;
2N/A pool_elem_t **elems = NULL;
2N/A int i;
2N/A
2N/A switch (type) {
2N/A case PEC_SYSTEM:
2N/A if ((elems = malloc(sizeof (pool_elem_t *))) == NULL)
2N/A return (NULL);
2N/A *nelem = 1;
2N/A elems[0] = pool_conf_to_elem(conf);
2N/A break;
2N/A case PEC_POOL:
2N/A if ((pl = pool_query_pools(conf, nelem, NULL)) != NULL) {
2N/A elems = (pool_elem_t **)pl;
2N/A }
2N/A break;
2N/A case PEC_RES_COMP:
2N/A if ((rl = pool_query_resources(conf, nelem, NULL)) != NULL) {
2N/A int j = 0;
2N/A elems = (pool_elem_t **)rl;
2N/A for (i = 0; i < *nelem; i++) {
2N/A if (pool_elem_class(TO_ELEM(rl[i])) ==
2N/A PEC_RES_COMP)
2N/A elems[j++] = TO_ELEM(rl[i]);
2N/A }
2N/A *nelem = j;
2N/A }
2N/A break;
2N/A case PEC_COMP:
2N/A if ((cl = pool_query_components(conf, nelem, NULL)) != NULL) {
2N/A elems = (pool_elem_t **)cl;
2N/A }
2N/A break;
2N/A default:
2N/A abort();
2N/A break;
2N/A }
2N/A return (elems);
2N/A}
2N/A
2N/A/*
2N/A * share_resources() sets up the allocation of resources by each
2N/A * provider. Firstly all resources are updated with the importance of
2N/A * each pool, then each resource provider is invoked in turn with a
2N/A * list of it's own resources. Finally, the pool importance details
2N/A * are removed from the resources.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL
2N/A */
2N/Astatic int
2N/Ashare_resources(pool_conf_t *conf)
2N/A{
2N/A pool_resource_t **resources;
2N/A uint_t nelem;
2N/A pool_value_t *props[] = { NULL, NULL };
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A
2N/A props[0] = &val;
2N/A
2N/A /*
2N/A * Call an allocation function for each type of supported resource.
2N/A * This function is responsible for "sharing" resources to resource
2N/A * sets as determined by the system.allocate-method.
2N/A */
2N/A
2N/A if (pool_value_set_string(props[0], "pset") != PO_SUCCESS ||
2N/A pool_value_set_name(props[0], c_type) != PO_SUCCESS)
2N/A return (PO_FAIL);
2N/A
2N/A if (add_importance_props(conf) != PO_SUCCESS) {
2N/A (void) remove_importance_props(conf);
2N/A return (PO_FAIL);
2N/A }
2N/A
2N/A if ((resources = pool_query_resources(conf, &nelem, props)) != NULL) {
2N/A /*
2N/A * 'pool.importance' defines the importance of a pool;
2N/A * resources inherit the importance of the pool that
2N/A * is associated with them. If more than one pool is
2N/A * associated with a resource, the importance of the
2N/A * resource is the maximum importance of all
2N/A * associated pools. Use '_importance' on resources
2N/A * to determine who gets extra.
2N/A */
2N/A if (resource_allocate("pset", resources, nelem) != PO_SUCCESS) {
2N/A free(resources);
2N/A (void) remove_importance_props(conf);
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A free(resources);
2N/A (void) remove_importance_props(conf);
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Work out which allocation method to use based on the value of the
2N/A * system.allocate-method property.
2N/A */
2N/Aint
2N/Aresource_allocate(const char *type, pool_resource_t **res, uint_t nelem)
2N/A{
2N/A pool_elem_t *pe;
2N/A const char *method_name;
2N/A uint64_t method;
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A int ret;
2N/A
2N/A pe = pool_conf_to_elem(TO_CONF(TO_ELEM(res[0])));
2N/A
2N/A if (pool_get_ns_property(pe, "allocate-method", &val) != POC_STRING)
2N/A method_name = POA_IMPORTANCE;
2N/A else {
2N/A (void) pool_value_get_string(&val, &method_name);
2N/A }
2N/A if (strcmp(POA_IMPORTANCE, method_name) != 0) {
2N/A if (strcmp(POA_SURPLUS_TO_DEFAULT, method_name) != 0) {
2N/A pool_seterror(POE_INVALID_CONF);
2N/A return (PO_FAIL);
2N/A } else {
2N/A method = POA_SURPLUS_TO_DEFAULT_NUM;
2N/A }
2N/A } else {
2N/A method = POA_IMPORTANCE_NUM;
2N/A }
2N/A switch (method) {
2N/A case POA_IMPORTANCE_NUM:
2N/A /*
2N/A * TODO: Add support for new resource types
2N/A */
2N/A switch (pool_resource_elem_class_from_string(type)) {
2N/A case PREC_PSET:
2N/A ret = pset_allocate_imp(res, nelem);
2N/A break;
2N/A default:
2N/A ret = PO_FAIL;
2N/A break;
2N/A }
2N/A break;
2N/A case POA_SURPLUS_TO_DEFAULT_NUM:
2N/A ret = resource_allocate_default(res, nelem);
2N/A break;
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Each set will get its minimum, however if there is more than the
2N/A * total minimum available, then leave this in the default set.
2N/A */
2N/Aint
2N/Aresource_allocate_default(pool_resource_t **res, uint_t nelem)
2N/A{
2N/A res_info_t *res_info;
2N/A uint_t j;
2N/A pool_resource_t *default_res = NULL;
2N/A
2N/A if (nelem == 1)
2N/A return (PO_SUCCESS);
2N/A
2N/A if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) {
2N/A return (PO_FAIL);
2N/A }
2N/A
2N/A /* Load current resource values. */
2N/A for (j = 0; j < nelem; j++) {
2N/A
2N/A if (default_res == NULL &&
2N/A resource_is_default(res[j]) == PO_TRUE)
2N/A default_res = res[j];
2N/A
2N/A if (resource_get_max(res[j],
2N/A &res_info[j].ri_max) == PO_FAIL ||
2N/A resource_get_min(res[j],
2N/A &res_info[j].ri_min) == PO_FAIL ||
2N/A resource_get_size(res[j],
2N/A &res_info[j].ri_oldsize) == PO_FAIL ||
2N/A resource_get_pinned(res[j],
2N/A &res_info[j].ri_pinned) == PO_FAIL) {
2N/A free(res_info);
2N/A return (PO_FAIL);
2N/A }
2N/A res_info[j].ri_res = res[j];
2N/A }
2N/A
2N/A /*
2N/A * Firstly, for all resources that have size greater than min,
2N/A * transfer all movable size above min to the default resource.
2N/A */
2N/A for (j = 0; j < nelem; j++) {
2N/A
2N/A uint64_t real_min;
2N/A
2N/A /* compute the real minimum number of resources */
2N/A real_min = MAX(res_info[j].ri_pinned, res_info[j].ri_min);
2N/A if (res_info[j].ri_res != default_res &&
2N/A res_info[j].ri_oldsize > real_min) {
2N/A
2N/A uint64_t num;
2N/A
2N/A num = res_info[j].ri_oldsize - real_min;
2N/A if (pool_resource_transfer(
2N/A TO_CONF(TO_ELEM(default_res)),
2N/A res_info[j].ri_res, default_res, num) !=
2N/A PO_SUCCESS) {
2N/A free(res_info);
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A }
2N/A /*
2N/A * Now, transfer resources below min from the default.
2N/A */
2N/A for (j = 0; j < nelem; j++) {
2N/A /*
2N/A * We don't want to interfere with resources which are reserved
2N/A */
2N/A if (res_info[j].ri_res != default_res &&
2N/A res_info[j].ri_oldsize < res_info[j].ri_min) {
2N/A if (pool_resource_transfer(
2N/A TO_CONF(TO_ELEM(default_res)),
2N/A default_res, res_info[j].ri_res,
2N/A res_info[j].ri_min - res_info[j].ri_oldsize) !=
2N/A PO_SUCCESS) {
2N/A free(res_info);
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A }
2N/A free(res_info);
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Allocate cpus to pset resource sets, favoring sets with higher importance.
2N/A *
2N/A * Step 1: Sort resource sets by decreasing importance, and load each sets
2N/A * current size (oldsize), min, max, and number of pinned cpus.
2N/A * Compute the total number of cpus by totaling oldsize.
2N/A *
2N/A * Step 2: Compute the newsize for each set:
2N/A *
2N/A * Give each set its min number of cpus. This min may be greater than
2N/A * its pset.min due to pinned cpus. If there are more cpus than the total
2N/A * of all mins, then the surplus cpus are dealt round-robin to all sets
2N/A * (up to their max) in order of decreasing importance. A set may be
2N/A * skipped during dealing because it started with more than its min due to
2N/A * pinned cpus. The dealing stops when there are no more cpus or all
2N/A * sets are at their max. If all sets are at their max, any remaining cpus
2N/A * are given to the default set.
2N/A *
2N/A * Step 3: Transfer cpus from sets with (oldsize > newsize) to sets with
2N/A * (oldsize < newsize).
2N/A */
2N/Aint
2N/Apset_allocate_imp(pool_resource_t **res, uint_t nelem)
2N/A{
2N/A res_info_t *res_info;
2N/A res_info_t *default_res_info;
2N/A const pool_resource_t *default_res = NULL;
2N/A uint64_t tot_resources = 0; /* total count of resources */
2N/A uint64_t tot_min = 0; /* total of all resource set mins */
2N/A uint64_t num_to_deal = 0; /* total resources above mins to deal */
2N/A uint64_t sets_maxed = 0; /* number of resource sets dealt to */
2N/A /* their max */
2N/A uint64_t sets_finished = 0; /* number of resource sets that have */
2N/A /* size == newsize */
2N/A int donor, receiver;
2N/A int deal;
2N/A int j;
2N/A int ret = PO_SUCCESS;
2N/A
2N/A /*
2N/A * Build list of res_info_t's
2N/A */
2N/A if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) {
2N/A pool_seterror(POE_SYSTEM);
2N/A return (PO_FAIL);
2N/A }
2N/A
2N/A /* Order resources by importance, most important being first */
2N/A qsort(res, nelem, sizeof (pool_resource_t *),
2N/A resource_compare_by_descending_importance);
2N/A
2N/A for (j = 0; j < nelem; j++) {
2N/A
2N/A /* Track which resource is the default */
2N/A if (default_res == NULL &&
2N/A resource_is_default(res[j]) == PO_TRUE) {
2N/A default_res = res[j];
2N/A default_res_info = &(res_info[j]);
2N/A }
2N/A
2N/A /* Load sets' current values */
2N/A if (resource_get_max(res[j], &res_info[j].ri_max) == PO_FAIL ||
2N/A resource_get_min(res[j], &res_info[j].ri_min) == PO_FAIL ||
2N/A resource_get_size(res[j], &res_info[j].ri_oldsize) ==
2N/A PO_FAIL ||
2N/A resource_get_pinned(res[j],
2N/A &res_info[j].ri_pinned) == PO_FAIL) {
2N/A free(res_info);
2N/A return (PO_FAIL);
2N/A }
2N/A
2N/A /* Start each set's newsize out at their min. */
2N/A res_info[j].ri_newsize = res_info[j].ri_min;
2N/A
2N/A /* pre-deal pinned resources that exceed min */
2N/A if (res_info[j].ri_pinned > res_info[j].ri_min) {
2N/A res_info[j].ri_newsize = res_info[j].ri_pinned;
2N/A res_info[j].ri_dealt =
2N/A res_info[j].ri_newsize - res_info[j].ri_min;
2N/A }
2N/A res_info[j].ri_res = res[j];
2N/A
2N/A /* Compute total number of resources to deal out */
2N/A tot_resources += res_info[j].ri_oldsize;
2N/A tot_min += res_info[j].ri_newsize;
2N/A
2N/A#ifdef DEBUG
2N/A dprintf("res allocation details\n");
2N/A pool_elem_dprintf(TO_ELEM(res[j]));
2N/A dprintf("size=%llu\n", res_info[j].ri_oldsize);
2N/A#endif /* DEBUG */
2N/A }
2N/A
2N/A num_to_deal = tot_resources - tot_min;
2N/A
2N/A /*
2N/A * Deal one resource to each set, and then another, until all
2N/A * resources are dealt or all sets are at their max.
2N/A */
2N/A for (deal = 1; num_to_deal > 0 && sets_maxed < nelem; deal++) {
2N/A for (j = 0; j < nelem; j++) {
2N/A
2N/A /*
2N/A * Skip this resource set if it has already been
2N/A * pre-dealt a resource due to pinned resources.
2N/A */
2N/A if (res_info[j].ri_dealt >= deal)
2N/A continue;
2N/A
2N/A if (res_info[j].ri_newsize < res_info[j].ri_max) {
2N/A
2N/A res_info[j].ri_dealt++;
2N/A res_info[j].ri_newsize++;
2N/A if (res_info[j].ri_newsize ==
2N/A res_info[j].ri_max)
2N/A sets_maxed++;
2N/A
2N/A num_to_deal--;
2N/A if (num_to_deal == 0)
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If all resource sets are at their max, deal the remaining to the
2N/A * default resource set.
2N/A */
2N/A if ((sets_maxed == nelem) && (num_to_deal > 0)) {
2N/A default_res_info->ri_dealt += num_to_deal;
2N/A default_res_info->ri_newsize += num_to_deal;
2N/A }
2N/A
2N/A /*
2N/A * Sort so that resource sets needing resources preced resource sets
2N/A * that have extra resources. The sort function will also compute
2N/A * The quantity of resources that need to be transfered into or out
2N/A * of each set so that it's size == newsize.
2N/A */
2N/A qsort(res_info, nelem, sizeof (res_info_t),
2N/A compute_size_to_transfer);
2N/A
2N/A /*
2N/A * The donor index starts at the end of the resource set list and
2N/A * walks up. The receiver index starts at the beginning of the
2N/A * resource set list and walks down. Cpu's are transfered from the
2N/A * donors to the receivers until all sets have transfer == 0).
2N/A */
2N/A donor = nelem - 1;
2N/A receiver = 0;
2N/A
2N/A /* Number of sets with transfer == 0 */
2N/A sets_finished = 0;
2N/A
2N/A /* Tranfer resources so that each set's size becomes newsize */
2N/A for (;;) {
2N/A
2N/A uint64_t ntrans;
2N/A if (donor == receiver) {
2N/A if (res_info[donor].ri_transfer != 0) {
2N/A free(res_info);
2N/A return (PO_FAIL);
2N/A }
2N/A sets_finished++;
2N/A break;
2N/A }
2N/A if (res_info[donor].ri_transfer == 0) {
2N/A sets_finished++;
2N/A donor--;
2N/A continue;
2N/A }
2N/A if (res_info[receiver].ri_transfer == 0) {
2N/A sets_finished++;
2N/A receiver++;
2N/A continue;
2N/A }
2N/A
2N/A /* Transfer resources from the donor set to the receiver */
2N/A ntrans = MIN(res_info[donor].ri_transfer,
2N/A -res_info[receiver].ri_transfer);
2N/A
2N/A if (pool_resource_transfer(
2N/A TO_CONF(TO_ELEM(res_info[donor].ri_res)),
2N/A res_info[donor].ri_res, res_info[receiver].ri_res,
2N/A ntrans) != PO_SUCCESS) {
2N/A free(res_info);
2N/A return (PO_FAIL);
2N/A }
2N/A res_info[donor].ri_transfer -= ntrans;
2N/A res_info[receiver].ri_transfer += ntrans;
2N/A }
2N/A
2N/A if (sets_finished != nelem)
2N/A ret = PO_FAIL;
2N/A
2N/A free(res_info);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Used as a qsort parameter to help order resources in terms of their
2N/A * importance, higher importance being first.
2N/A */
2N/Aint
2N/Aresource_compare_by_descending_importance(const void *arg1, const void *arg2)
2N/A{
2N/A pool_elem_t *elem1;
2N/A pool_elem_t *elem2;
2N/A pool_resource_t **res1 = (pool_resource_t **)arg1;
2N/A pool_resource_t **res2 = (pool_resource_t **)arg2;
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A int64_t i1 = 0, i2 = 0;
2N/A
2N/A elem1 = TO_ELEM(*res1);
2N/A elem2 = TO_ELEM(*res2);
2N/A
2N/A if (pool_get_property(TO_CONF(elem1), elem1, "_importance", &val) ==
2N/A POC_INT)
2N/A (void) pool_value_get_int64(&val, &i1);
2N/A
2N/A if (pool_get_property(TO_CONF(elem2), elem2, "_importance", &val) ==
2N/A POC_INT)
2N/A (void) pool_value_get_int64(&val, &i2);
2N/A return (i1 > i2 ? -1 : (i1 < i2 ? 1 : 0));
2N/A}
2N/A
2N/A/*
2N/A * Sort in increasing order so that resource sets with extra resources are at
2N/A * the end and resource sets needing resources are at the beginning.
2N/A */
2N/Aint
2N/Acompute_size_to_transfer(const void *arg1, const void *arg2)
2N/A{
2N/A res_info_t *r1 = (res_info_t *)arg1, *r2 = (res_info_t *)arg2;
2N/A r1->ri_transfer = (int64_t)r1->ri_oldsize - (int64_t)r1->ri_newsize;
2N/A r2->ri_transfer = (int64_t)r2->ri_oldsize - (int64_t)r2->ri_newsize;
2N/A return (r1->ri_transfer > r2->ri_transfer ? 1 :
2N/A (r1->ri_transfer < r2->ri_transfer ? -1 : 0));
2N/A}
2N/A
2N/A/*
2N/A * set_importance_cb() is used to create "_importance" props on each
2N/A * resource associated with a pool.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Aset_importance_cb(pool_conf_t *conf, pool_t *pool, void *unused)
2N/A{
2N/A pool_value_t val = POOL_VALUE_INITIALIZER;
2N/A int64_t importance;
2N/A pool_resource_t **res;
2N/A uint_t nelem, i;
2N/A
2N/A if (pool_get_property(conf, TO_ELEM(pool), "pool.importance", &val) !=
2N/A POC_INT) {
2N/A pool_seterror(POE_INVALID_CONF);
2N/A return (PO_FAIL);
2N/A }
2N/A (void) pool_value_get_int64(&val, &importance);
2N/A if ((res = pool_query_pool_resources(conf, pool, &nelem, NULL)) ==
2N/A NULL) {
2N/A return (PO_FAIL);
2N/A }
2N/A for (i = 0; res[i] != NULL; i++) {
2N/A int64_t old_importance = INT64_MIN;
2N/A pool_elem_t *elem = TO_ELEM(res[i]);
2N/A
2N/A if (pool_get_property(conf, elem, "_importance", &val) ==
2N/A POC_INT)
2N/A (void) pool_value_get_int64(&val, &old_importance);
2N/A if (old_importance <= importance) {
2N/A (void) pool_value_set_int64(&val, importance);
2N/A (void) pool_put_property(conf, elem, "_importance",
2N/A &val);
2N/A }
2N/A }
2N/A free(res);
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * unset_importance_cb() is used to remove "_importance" props from
2N/A * each resource associated with a pool.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Aunset_importance_cb(pool_conf_t *conf, pool_t *pool, void *unused)
2N/A{
2N/A pool_resource_t **res;
2N/A uint_t nelem, i;
2N/A
2N/A if ((res = pool_query_pool_resources(conf, pool, &nelem, NULL)) ==
2N/A NULL) {
2N/A return (PO_FAIL);
2N/A }
2N/A for (i = 0; res[i] != NULL; i++) {
2N/A if (pool_rm_property(conf, TO_ELEM(res[i]), "_importance") ==
2N/A PO_FAIL) {
2N/A free(res);
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A free(res);
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * add_importance_props() is used to create "_importance" props on
2N/A * each resource associated with a pool.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL
2N/A */
2N/Astatic int
2N/Aadd_importance_props(pool_conf_t *conf)
2N/A{
2N/A return (pool_walk_pools(conf, NULL, set_importance_cb));
2N/A}
2N/A
2N/A/*
2N/A * remove_importance_props() is used to remove "_importance" props on
2N/A * each resource associated with a pool.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL
2N/A */
2N/Astatic int
2N/Aremove_importance_props(pool_conf_t *conf)
2N/A{
2N/A return (pool_walk_pools(conf, NULL, unset_importance_cb));
2N/A}
2N/A
2N/A/*
2N/A * pool_conf_commit_sys() takes a configuration and modifies both the
2N/A * supplied configuration and the dynamic configuration. The goal of
2N/A * this modification is to generate a dynamic configuration which best
2N/A * represents the constraints laid down in the static configuration
2N/A * and to update the static configuration with the results of this
2N/A * process.
2N/A *
2N/A * Returns PO_SUCCESS/PO_FAIL
2N/A */
2N/Aint
2N/Apool_conf_commit_sys(pool_conf_t *conf, int validate)
2N/A{
2N/A pool_conf_t *dyn;
2N/A
2N/A if ((dyn = pool_conf_alloc()) == NULL)
2N/A return (PO_FAIL);
2N/A if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDWR) !=
2N/A PO_SUCCESS) {
2N/A pool_conf_free(dyn);
2N/A return (PO_FAIL);
2N/A }
2N/A if (validate == PO_TRUE) {
2N/A if (pool_conf_validate(conf, POV_RUNTIME) != PO_SUCCESS) {
2N/A (void) pool_conf_close(dyn);
2N/A pool_conf_free(dyn);
2N/A return (PO_FAIL);
2N/A }
2N/A }
2N/A /*
2N/A * Now try to make the two things "the same".
2N/A */
2N/A if (diff_and_fix(conf, dyn) != PO_SUCCESS) {
2N/A (void) pool_conf_close(dyn);
2N/A pool_conf_free(dyn);
2N/A pool_seterror(POE_INVALID_CONF);
2N/A return (PO_FAIL);
2N/A }
2N/A if (dyn->pc_prov->pc_commit(dyn) != PO_SUCCESS) {
2N/A (void) pool_conf_close(dyn);
2N/A pool_conf_free(dyn);
2N/A return (PO_FAIL);
2N/A }
2N/A (void) pool_conf_close(dyn);
2N/A pool_conf_free(dyn);
2N/A return (PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Copies all properties from one element to another. If the property
2N/A * is a readonly property, then don't copy it.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic int
2N/Aclone_element(pool_conf_t *conf, pool_elem_t *pe, const char *name,
2N/A pool_value_t *pv, void *user)
2N/A{
2N/A pool_elem_t *tgt = (pool_elem_t *)user;
2N/A const pool_prop_t *prop;
2N/A#ifdef DEBUG
2N/A dprintf("Cloning %s from %s\n",
2N/A pool_conf_location(TO_CONF(TO_ELEM(tgt))),
2N/A pool_conf_location(TO_CONF(pe)));
2N/A assert(TO_CONF(TO_ELEM(tgt)) != TO_CONF(pe));
2N/A dprintf("clone_element: Processing %s\n", name);
2N/A pool_value_dprintf(pv);
2N/A#endif /* DEBUG */
2N/A /*
2N/A * Some properties should be ignored
2N/A */
2N/A if ((prop = provider_get_prop(pe, name)) != NULL &&
2N/A prop_is_readonly(prop) == PO_TRUE)
2N/A return (PO_SUCCESS);
2N/A
2N/A /* The temporary property needs special handling */
2N/A if (strstr(name, ".temporary") != NULL)
2N/A return (pool_set_temporary(TO_CONF(tgt), tgt) ==
2N/A PO_FAIL ? PO_FAIL : PO_SUCCESS);
2N/A else
2N/A return (pool_put_property(TO_CONF(tgt), tgt, name, pv) ==
2N/A PO_FAIL ? PO_FAIL : PO_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Removes all properties from one element. Properties which are
2N/A * managed by the configuration are ignored.
2N/A */
2N/A/* ARGSUSED3 */
2N/Astatic int
2N/Aclean_element(pool_conf_t *conf, pool_elem_t *pe, const char *name,
2N/A pool_value_t *pv, void *user)
2N/A{
2N/A const pool_prop_t *prop;
2N/A /*
2N/A * Some properties should be ignored
2N/A */
2N/A if (strstr(name, ".temporary") != NULL ||
2N/A ((prop = provider_get_prop(pe, name)) != NULL &&
2N/A prop_is_optional(prop) == PO_FALSE))
2N/A return (PO_SUCCESS);
2N/A return (pool_rm_property(conf, (pool_elem_t *)pe, name) == PO_FAIL);
2N/A}