xref: /onnv-gate/usr/src/lib/libpool/common/pool_commit.c (revision 2324:d58781926d5c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2324Ssdussud  * Common Development and Distribution License (the "License").
6*2324Ssdussud  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2324Ssdussud  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * These functions implement the process of commitment for a pool
300Sstevel@tonic-gate  * configuration. This process can be described as taking instructions
310Sstevel@tonic-gate  * from a static configuration file and using the information about
320Sstevel@tonic-gate  * the target system contained in the dynamic configuration to make
330Sstevel@tonic-gate  * decisions about how best to allocate resources to meet the
340Sstevel@tonic-gate  * constraints specified in the static configuration file.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * Mechanically, this process relies upon ordering the individual
370Sstevel@tonic-gate  * components of the file and stepping through the lists of components
380Sstevel@tonic-gate  * and taking actions depending on their type and which file they are
390Sstevel@tonic-gate  * part of.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * Configuration components can be broken down into different types
420Sstevel@tonic-gate  * which are then treated according to the following table:
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * Element Type		Action
450Sstevel@tonic-gate  * system || pool ||
460Sstevel@tonic-gate  * res_comp || res_agg	If the element is a required element, then create or
470Sstevel@tonic-gate  *			update it (don't destroy required elements in the
480Sstevel@tonic-gate  *			static configuration) otherwise manipulate the
490Sstevel@tonic-gate  *			dynamic configuration to create, destroy or update
500Sstevel@tonic-gate  *			the element on the system.
510Sstevel@tonic-gate  * comp			Create, destroy or update the static configuration
520Sstevel@tonic-gate  *			component.
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * The treatment of the different elements reflects the fact that all
550Sstevel@tonic-gate  * elements other than comp are configurable and thus libpool can
560Sstevel@tonic-gate  * create, destroy and modify these elements at will. comp elements
570Sstevel@tonic-gate  * reflect the disposition of the system, these elements can be moved
580Sstevel@tonic-gate  * around but they can't be created or destroyed in the dynamic
590Sstevel@tonic-gate  * configuration in the commit process. comp elements can be created
600Sstevel@tonic-gate  * and destroyed in the static configuration file as a result of a
610Sstevel@tonic-gate  * commit operation, since it's possible for a comp to not appear in
620Sstevel@tonic-gate  * the dynamic configuration. For instance, if the static
630Sstevel@tonic-gate  * configuration file was created on a different machine or after a DR
640Sstevel@tonic-gate  * operation which has removed or added components.
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate #include <assert.h>
680Sstevel@tonic-gate #include <stdio.h>
690Sstevel@tonic-gate #include <stdlib.h>
700Sstevel@tonic-gate #include <sys/types.h>
710Sstevel@tonic-gate #include <errno.h>
720Sstevel@tonic-gate #include <string.h>
730Sstevel@tonic-gate #include <limits.h>
740Sstevel@tonic-gate #include <unistd.h>
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #include <pool.h>
770Sstevel@tonic-gate #include "pool_internal.h"
780Sstevel@tonic-gate #include "pool_impl.h"
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #define	MIN(x, y) ((x) < (y) ? (x) : (y))
810Sstevel@tonic-gate #define	MAX(x, y) ((x) > (y) ? (x) : (y))
820Sstevel@tonic-gate #define	POA_IMPORTANCE_NUM	0
830Sstevel@tonic-gate #define	POA_SURPLUS_TO_DEFAULT_NUM	1
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * This resource specific structure is used to determine allocation of resources
870Sstevel@tonic-gate  * during resource set allocation.  Each set will receive its min, plus
880Sstevel@tonic-gate  * some number of dealt resources based on the global allocation policy.
890Sstevel@tonic-gate  */
900Sstevel@tonic-gate typedef struct res_info {
910Sstevel@tonic-gate 	pool_resource_t	*ri_res;	/* Resource set */
920Sstevel@tonic-gate 	uint64_t	ri_min;		/* Resource set's low watermark */
930Sstevel@tonic-gate 	uint64_t	ri_max;		/* Resource set's high watermark */
940Sstevel@tonic-gate 	uint64_t	ri_oldsize;	/* Size of resource set at the start */
950Sstevel@tonic-gate 	uint64_t	ri_newsize;	/* New resource set size allocated */
960Sstevel@tonic-gate 	uint64_t	ri_pinned;	/* Count of pinned resources in set */
970Sstevel@tonic-gate 	uint64_t	ri_dealt;	/* Count of resources dealt to set */
980Sstevel@tonic-gate 	int64_t		ri_transfer;	/* oldsize - newsize */
990Sstevel@tonic-gate 					/* The signed quantity of resources */
1000Sstevel@tonic-gate 					/* to tranfer into or out of this */
1010Sstevel@tonic-gate 					/* resource set */
1020Sstevel@tonic-gate 					/* + transfer: tranfer resources out */
1030Sstevel@tonic-gate 					/* - transfer: tranfer resources in */
1040Sstevel@tonic-gate } res_info_t;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate  * diff_and_fix operations
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate static int		commit_create(pool_conf_t *, pool_elem_t **);
1100Sstevel@tonic-gate static int		commit_delete(pool_elem_t *);
1110Sstevel@tonic-gate static int		commit_update(pool_elem_t *, pool_elem_t *, int);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * configuration commit processing
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate static int		diff_and_fix(pool_conf_t *, pool_conf_t *);
1170Sstevel@tonic-gate static int		process_elem_lt(pool_elem_t *, pool_conf_t *);
1180Sstevel@tonic-gate static int		process_elem_gt(pool_elem_t *, pool_conf_t *,
1190Sstevel@tonic-gate     pool_conf_t *);
1200Sstevel@tonic-gate static int		process_lists(int, pool_conf_t *,
1210Sstevel@tonic-gate     pool_conf_t *, int);
1220Sstevel@tonic-gate static pool_elem_t	**get_elem_list(const pool_conf_t *, int, uint_t *);
1230Sstevel@tonic-gate static int		share_resources(pool_conf_t *);
1240Sstevel@tonic-gate static int		resource_allocate(const char *, pool_resource_t **,
1250Sstevel@tonic-gate     uint_t);
1260Sstevel@tonic-gate static int		resource_allocate_default(pool_resource_t **, uint_t);
1270Sstevel@tonic-gate static int		pset_allocate_imp(pool_resource_t **, uint_t);
1280Sstevel@tonic-gate static int		resource_compare_by_descending_importance(const void *,
1290Sstevel@tonic-gate     const void *);
1300Sstevel@tonic-gate static int		compute_size_to_transfer(const void *, const void *);
1310Sstevel@tonic-gate static int		set_importance_cb(pool_conf_t *, pool_t *, void *);
1320Sstevel@tonic-gate static int		unset_importance_cb(pool_conf_t *, pool_t *, void *);
1330Sstevel@tonic-gate static int		add_importance_props(pool_conf_t *);
1340Sstevel@tonic-gate static int		remove_importance_props(pool_conf_t *);
1350Sstevel@tonic-gate static int		clone_element(pool_conf_t *, pool_elem_t *,
1360Sstevel@tonic-gate     const char *, pool_value_t *, void *);
1370Sstevel@tonic-gate static int		clean_element(pool_conf_t *, pool_elem_t *,
1380Sstevel@tonic-gate     const char *, pool_value_t *, void *);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate  * commit_create() is used to create a configuration element upon the
1420Sstevel@tonic-gate  * system.  Since only pools and resource actually need to perform any
1430Sstevel@tonic-gate  * action, other elements are ignored as a no-op.
1440Sstevel@tonic-gate  */
1450Sstevel@tonic-gate static int
1460Sstevel@tonic-gate commit_create(pool_conf_t *conf, pool_elem_t **e1)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	pool_resource_t *res;
1490Sstevel@tonic-gate 	pool_t *pool;
1500Sstevel@tonic-gate 	const char *res_type;
1510Sstevel@tonic-gate 	pool_elem_t *src = *e1;
1520Sstevel@tonic-gate 	uint64_t smin, smax, dmax;
1530Sstevel@tonic-gate 	pool_value_t val = POOL_VALUE_INITIALIZER;
1540Sstevel@tonic-gate 	char *name;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	switch (pool_elem_class(src)) {
1570Sstevel@tonic-gate 	case PEC_SYSTEM:	/* NO-OP */
1580Sstevel@tonic-gate 		break;
1590Sstevel@tonic-gate 	case PEC_POOL:
1600Sstevel@tonic-gate 		name = elem_get_name(src);
1610Sstevel@tonic-gate 		if ((pool = pool_create(conf, name)) == NULL) {
1620Sstevel@tonic-gate 			free(name);
1630Sstevel@tonic-gate 			return (PO_FAIL);
1640Sstevel@tonic-gate 		}
1650Sstevel@tonic-gate 		free(name);
1660Sstevel@tonic-gate 		/*
1670Sstevel@tonic-gate 		 * Now copy the properties from the original pool to the
1680Sstevel@tonic-gate 		 * new one
1690Sstevel@tonic-gate 		 */
1700Sstevel@tonic-gate 		if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(pool),
1710Sstevel@tonic-gate 		    clone_element) != PO_SUCCESS)
1720Sstevel@tonic-gate 			return (PO_FAIL);
1730Sstevel@tonic-gate 		/*
1740Sstevel@tonic-gate 		 * Add a pointer to the src element which can be
1750Sstevel@tonic-gate 		 * updated with a sys_id when the sys_id is allocated
1760Sstevel@tonic-gate 		 * to the created element.
1770Sstevel@tonic-gate 		 */
1780Sstevel@tonic-gate 		pool_set_pair(TO_ELEM(pool), src);
1790Sstevel@tonic-gate 		*e1 = TO_ELEM(pool);
1800Sstevel@tonic-gate 		break;
1810Sstevel@tonic-gate 	case PEC_RES_COMP:
1820Sstevel@tonic-gate 	case PEC_RES_AGG:
1830Sstevel@tonic-gate 		name = elem_get_name(src);
1840Sstevel@tonic-gate 		res_type = pool_elem_class_string(src);
1850Sstevel@tonic-gate 		if ((res = pool_resource_create(conf, res_type, name)) ==
1860Sstevel@tonic-gate 		    NULL) {
1870Sstevel@tonic-gate 			free(name);
1880Sstevel@tonic-gate 			return (PO_FAIL);
1890Sstevel@tonic-gate 		}
1900Sstevel@tonic-gate 		free(name);
1910Sstevel@tonic-gate 		/*
1920Sstevel@tonic-gate 		 * Need to do some ordering of property updates.
1930Sstevel@tonic-gate 		 * Compare the values of source min/max and
1940Sstevel@tonic-gate 		 * destination min/max. If smin < dmax then update the
1950Sstevel@tonic-gate 		 * smin first, else update the max first.
1960Sstevel@tonic-gate 		 */
1970Sstevel@tonic-gate 		if (resource_get_min(pool_elem_res(src), &smin) != PO_SUCCESS ||
1980Sstevel@tonic-gate 		    resource_get_max(pool_elem_res(src), &smax) != PO_SUCCESS ||
1990Sstevel@tonic-gate 		    resource_get_max(res, &dmax) != PO_SUCCESS)
2000Sstevel@tonic-gate 			return (PO_FAIL);
2010Sstevel@tonic-gate 		if (smin < dmax) {
2020Sstevel@tonic-gate 			pool_value_set_uint64(&val, smin);
2030Sstevel@tonic-gate 			if (pool_put_ns_property(TO_ELEM(res), c_min_prop,
2040Sstevel@tonic-gate 			    &val) != PO_SUCCESS)
2050Sstevel@tonic-gate 				return (PO_FAIL);
2060Sstevel@tonic-gate 		} else {
2070Sstevel@tonic-gate 			pool_value_set_uint64(&val, smax);
2080Sstevel@tonic-gate 			if (pool_put_ns_property(TO_ELEM(res), c_max_prop,
2090Sstevel@tonic-gate 			    &val) != PO_SUCCESS)
2100Sstevel@tonic-gate 				return (PO_FAIL);
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 		/*
2130Sstevel@tonic-gate 		 * Now copy the properties from the original resource
2140Sstevel@tonic-gate 		 * to the new one
2150Sstevel@tonic-gate 		 */
2160Sstevel@tonic-gate 		if (pool_walk_properties(TO_CONF(src), src, TO_ELEM(res),
2170Sstevel@tonic-gate 		    clone_element) != PO_SUCCESS)
2180Sstevel@tonic-gate 			return (PO_FAIL);
2190Sstevel@tonic-gate 		/*
2200Sstevel@tonic-gate 		 * Add a pointer to the src element which can be
2210Sstevel@tonic-gate 		 * updated with a sys_id when the sys_id is allocated
2220Sstevel@tonic-gate 		 * to the created element.
2230Sstevel@tonic-gate 		 */
2240Sstevel@tonic-gate 		pool_set_pair(TO_ELEM(res), src);
2250Sstevel@tonic-gate 		*e1 = TO_ELEM(res);
2260Sstevel@tonic-gate 		break;
2270Sstevel@tonic-gate 	case PEC_COMP:		/* NO-OP */
2280Sstevel@tonic-gate 		break;
2290Sstevel@tonic-gate 	default:
2300Sstevel@tonic-gate 		return (PO_FAIL);
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 	return (PO_SUCCESS);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate  * commit_delete() is used to delete a configuration element upon the
2380Sstevel@tonic-gate  * system.  Since only pools and resources actually need to perform
2390Sstevel@tonic-gate  * any action, other elements are ignored as a no-op.
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate static int
2420Sstevel@tonic-gate commit_delete(pool_elem_t *pe)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	pool_resource_t *res;
2450Sstevel@tonic-gate 	pool_t *pool;
2460Sstevel@tonic-gate 	int ret = 0;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	switch (pool_elem_class(pe)) {
2490Sstevel@tonic-gate 	case PEC_SYSTEM:	/* NO-OP */
2500Sstevel@tonic-gate 		break;
2510Sstevel@tonic-gate 	case PEC_POOL:
2520Sstevel@tonic-gate 		pool = pool_elem_pool(pe);
2530Sstevel@tonic-gate 		ret = pool_destroy(TO_CONF(pe), pool);
2540Sstevel@tonic-gate 		break;
2550Sstevel@tonic-gate 	case PEC_RES_COMP:
2560Sstevel@tonic-gate 	case PEC_RES_AGG:
2570Sstevel@tonic-gate 		res = pool_elem_res(pe);
2580Sstevel@tonic-gate 		ret = pool_resource_destroy(TO_CONF(pe), res);
2590Sstevel@tonic-gate 		break;
2600Sstevel@tonic-gate 	case PEC_COMP:		/* NO-OP */
2610Sstevel@tonic-gate 		break;
2620Sstevel@tonic-gate 	default:
2630Sstevel@tonic-gate 		return (PO_FAIL);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 	return (ret);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate  * commit_update() is used to update a configuration element upon the
2700Sstevel@tonic-gate  * system or in a static configuration file. The pass parameter
2710Sstevel@tonic-gate  * governs whether properties are being updated or associations.  In
2720Sstevel@tonic-gate  * pass 0, properties are updated. If the element is of class
2730Sstevel@tonic-gate  * PEC_COMP, then make sure that the element in the static
2740Sstevel@tonic-gate  * configuration file is correctly located before proceeding with the
2750Sstevel@tonic-gate  * update. Then, the element in the dynamic configuration file is
2760Sstevel@tonic-gate  * updated. In pass 1, ie. pass != 0, any pool components have their
2770Sstevel@tonic-gate  * associations updated in the dynamic configuration.
2780Sstevel@tonic-gate  */
2790Sstevel@tonic-gate static int
2800Sstevel@tonic-gate commit_update(pool_elem_t *e1, pool_elem_t *e2, int pass)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	if (pass == 0) {
2830Sstevel@tonic-gate 		pool_resource_t *res1;
2840Sstevel@tonic-gate 		pool_resource_t *res2;
2850Sstevel@tonic-gate 		if (pool_elem_class(e1) == PEC_COMP) {
2860Sstevel@tonic-gate 			res1 = pool_get_owning_resource(TO_CONF(e1),
2870Sstevel@tonic-gate 			    pool_elem_comp(e1));
2880Sstevel@tonic-gate 			res2 = pool_get_owning_resource(TO_CONF(e2),
2890Sstevel@tonic-gate 			    pool_elem_comp(e2));
2900Sstevel@tonic-gate 			if (pool_elem_compare_name(TO_ELEM(res1),
2910Sstevel@tonic-gate 			    TO_ELEM(res2)) != 0) {
2920Sstevel@tonic-gate 				char *name;
2930Sstevel@tonic-gate 				const pool_resource_t *newres;
2940Sstevel@tonic-gate 				pool_component_t *comps[2] = { NULL };
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 				comps[0] = pool_elem_comp(e2);
297*2324Ssdussud 				name = elem_get_name(TO_ELEM(res1));
2980Sstevel@tonic-gate 				newres = pool_get_resource(TO_CONF(e2),
2990Sstevel@tonic-gate 				    pool_elem_class_string(TO_ELEM(res1)),
3000Sstevel@tonic-gate 				    name);
3010Sstevel@tonic-gate 				free(name);
3020Sstevel@tonic-gate 				assert(newres);
3030Sstevel@tonic-gate #ifdef DEBUG
3040Sstevel@tonic-gate 				dprintf("transferring: res, comp\n");
3050Sstevel@tonic-gate 				pool_elem_dprintf(TO_ELEM(newres));
3060Sstevel@tonic-gate 				pool_elem_dprintf(e2);
3070Sstevel@tonic-gate #endif	/* DEBUG */
3080Sstevel@tonic-gate 				(void) pool_resource_xtransfer(TO_CONF(e2),
3090Sstevel@tonic-gate 				    res2, (pool_resource_t *)newres, comps);
3100Sstevel@tonic-gate 			}
3110Sstevel@tonic-gate 		}
3120Sstevel@tonic-gate 		if (pool_walk_properties(TO_CONF(e2), e2, NULL,
3130Sstevel@tonic-gate 		    clean_element) != PO_SUCCESS) {
3140Sstevel@tonic-gate 			return (PO_FAIL);
3150Sstevel@tonic-gate 		}
3160Sstevel@tonic-gate 		/*
3170Sstevel@tonic-gate 		 * Need to do some ordering of property updates if the
3180Sstevel@tonic-gate 		 * element to be updated is a resource.  Compare the
3190Sstevel@tonic-gate 		 * values of source min/max and destination
3200Sstevel@tonic-gate 		 * min/max. If smin < dmax then update the smin first,
3210Sstevel@tonic-gate 		 * else update the max first.
3220Sstevel@tonic-gate 		 */
3230Sstevel@tonic-gate 		if (pool_elem_class(e1) == PEC_RES_COMP ||
3240Sstevel@tonic-gate 		    pool_elem_class(e1) == PEC_RES_AGG) {
3250Sstevel@tonic-gate 			uint64_t smin, smax, dmax;
3260Sstevel@tonic-gate 			pool_value_t val = POOL_VALUE_INITIALIZER;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 			if (resource_get_min(pool_elem_res(e1), &smin) !=
3290Sstevel@tonic-gate 			    PO_SUCCESS ||
3300Sstevel@tonic-gate 			    resource_get_max(pool_elem_res(e1), &smax) !=
3310Sstevel@tonic-gate 			    PO_SUCCESS ||
3320Sstevel@tonic-gate 			    resource_get_max(pool_elem_res(e2), &dmax) !=
3330Sstevel@tonic-gate 			    PO_SUCCESS)
3340Sstevel@tonic-gate 				return (PO_FAIL);
3350Sstevel@tonic-gate 			if (smin < dmax) {
3360Sstevel@tonic-gate 				pool_value_set_uint64(&val, smin);
3370Sstevel@tonic-gate 				if (pool_put_ns_property(e2, c_min_prop,
3380Sstevel@tonic-gate 				    &val) != PO_SUCCESS)
3390Sstevel@tonic-gate 					return (PO_FAIL);
3400Sstevel@tonic-gate 			} else {
3410Sstevel@tonic-gate 				pool_value_set_uint64(&val, smax);
3420Sstevel@tonic-gate 				if (pool_put_ns_property(e2, c_max_prop,
3430Sstevel@tonic-gate 				    &val) != PO_SUCCESS)
3440Sstevel@tonic-gate 					return (PO_FAIL);
3450Sstevel@tonic-gate 			}
3460Sstevel@tonic-gate 		}
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * This next couple of steps needs some
3490Sstevel@tonic-gate 		 * explanation. The first walk, copies all the
3500Sstevel@tonic-gate 		 * properties that are writeable from the static
3510Sstevel@tonic-gate 		 * configuration to the dynamic configuration. The
3520Sstevel@tonic-gate 		 * second walk copies all properties (writeable or
3530Sstevel@tonic-gate 		 * not) from the dynamic configuration element back to
3540Sstevel@tonic-gate 		 * the static configuration element. This ensures that
3550Sstevel@tonic-gate 		 * updates from the static configuration element are
3560Sstevel@tonic-gate 		 * correctly applied to the dynamic configuration and
3570Sstevel@tonic-gate 		 * then the static configuration element is updated
3580Sstevel@tonic-gate 		 * with the latest values of the read-only xproperties
3590Sstevel@tonic-gate 		 * from the dynamic configuration element. The
3600Sstevel@tonic-gate 		 * enforcing of permisssions is performed in
3610Sstevel@tonic-gate 		 * clone_element by its choice of property
3620Sstevel@tonic-gate 		 * manipulation function.
3630Sstevel@tonic-gate 		 */
3640Sstevel@tonic-gate 		if (pool_walk_properties(TO_CONF(e1), e1, e2, clone_element) !=
3650Sstevel@tonic-gate 		    PO_SUCCESS) {
3660Sstevel@tonic-gate 			return (PO_FAIL);
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 		if (pool_walk_properties(TO_CONF(e2), e2, e1, clone_element) !=
3690Sstevel@tonic-gate 		    PO_SUCCESS) {
3700Sstevel@tonic-gate 			return (PO_FAIL);
3710Sstevel@tonic-gate 		}
3720Sstevel@tonic-gate 	} else {
3730Sstevel@tonic-gate 		if (pool_elem_class(e1) == PEC_POOL) {
3740Sstevel@tonic-gate 			pool_resource_t **rs;
3750Sstevel@tonic-gate 			uint_t nelem;
3760Sstevel@tonic-gate 			int i;
3770Sstevel@tonic-gate 			pool_value_t val = POOL_VALUE_INITIALIZER;
3780Sstevel@tonic-gate 			pool_value_t *pvals[] = { NULL, NULL };
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 			pvals[0] = &val;
3810Sstevel@tonic-gate 			if (pool_value_set_string(&val, "pset") != PO_SUCCESS ||
3820Sstevel@tonic-gate 			    pool_value_set_name(&val, c_type) != PO_SUCCESS)
3830Sstevel@tonic-gate 				return (PO_FAIL);
3840Sstevel@tonic-gate 			if ((rs = pool_query_pool_resources(TO_CONF(e1),
3850Sstevel@tonic-gate 			    pool_elem_pool(e1), &nelem, pvals)) != NULL) {
3860Sstevel@tonic-gate 				for (i = 0; i < nelem; i++) {
3870Sstevel@tonic-gate 					const pool_resource_t *tgt_res;
3880Sstevel@tonic-gate 					char *res_name =
3890Sstevel@tonic-gate 					    elem_get_name(TO_ELEM(rs[i]));
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 					if ((tgt_res = pool_get_resource(
3920Sstevel@tonic-gate 					    TO_CONF(e2), pool_elem_class_string(
3930Sstevel@tonic-gate 					    TO_ELEM(rs[i])), res_name)) ==
3940Sstevel@tonic-gate 					    NULL) {
3950Sstevel@tonic-gate 						tgt_res = get_default_resource(
3960Sstevel@tonic-gate 						    rs[i]);
3970Sstevel@tonic-gate 					}
3980Sstevel@tonic-gate 					free(res_name);
3990Sstevel@tonic-gate 					if (pool_associate(TO_CONF(e2),
4000Sstevel@tonic-gate 					    pool_elem_pool(e2), tgt_res) !=
4010Sstevel@tonic-gate 					    PO_SUCCESS) {
4020Sstevel@tonic-gate 						free(rs);
4030Sstevel@tonic-gate 						return (PO_FAIL);
4040Sstevel@tonic-gate 					}
4050Sstevel@tonic-gate 				}
4060Sstevel@tonic-gate 				free(rs);
4070Sstevel@tonic-gate 			}
4080Sstevel@tonic-gate 		}
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 	return (PO_SUCCESS);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate /*
4140Sstevel@tonic-gate  * diff_and_fix() works out the differences between two configurations
4150Sstevel@tonic-gate  * and modifies the state of the system to match the operations
4160Sstevel@tonic-gate  * required to bring the two configurations into sync.
4170Sstevel@tonic-gate  *
4180Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL.
4190Sstevel@tonic-gate  */
4200Sstevel@tonic-gate static int
4210Sstevel@tonic-gate diff_and_fix(pool_conf_t *stc, pool_conf_t *dyn)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	/*
4240Sstevel@tonic-gate 	 * The ordering of the operations is significant, we must
4250Sstevel@tonic-gate 	 * process the system element, then the pools elements, then
4260Sstevel@tonic-gate 	 * the resource elements, then the pools elements again and
4270Sstevel@tonic-gate 	 * finally the resource components.
4280Sstevel@tonic-gate 	 *
4290Sstevel@tonic-gate 	 * TODO
4300Sstevel@tonic-gate 	 * PEC_RES_COMP are the only type of resources
4310Sstevel@tonic-gate 	 * currently. When PEC_RES_AGG resources are added they must
4320Sstevel@tonic-gate 	 * also be processed.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	if (process_lists(PEC_SYSTEM, stc, dyn, 0) != PO_SUCCESS) {
4350Sstevel@tonic-gate 		return (PO_FAIL);
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate 	if (process_lists(PEC_POOL, stc, dyn, 0) != PO_SUCCESS) {
4380Sstevel@tonic-gate 		return (PO_FAIL);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 	if (process_lists(PEC_RES_COMP, stc, dyn, 0) != PO_SUCCESS) {
4410Sstevel@tonic-gate 		return (PO_FAIL);
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 	if (process_lists(PEC_COMP, stc, dyn, 0) != PO_SUCCESS) {
4440Sstevel@tonic-gate 		return (PO_FAIL);
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 	if (process_lists(PEC_POOL, stc, dyn, 1) != PO_SUCCESS) {
4470Sstevel@tonic-gate 		return (PO_FAIL);
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 	/*
4500Sstevel@tonic-gate 	 * Share the resources. It has to be called for both
4510Sstevel@tonic-gate 	 * configurations to ensure that the configurations still look
4520Sstevel@tonic-gate 	 * the same.
4530Sstevel@tonic-gate 	 */
4540Sstevel@tonic-gate 	if (share_resources(dyn) != PO_SUCCESS) {
4550Sstevel@tonic-gate 		return (PO_FAIL);
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 	if (share_resources(stc) != PO_SUCCESS) {
4580Sstevel@tonic-gate 		return (PO_FAIL);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 	return (PO_SUCCESS);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate static int
4640Sstevel@tonic-gate process_elem_lt(pool_elem_t *pe, pool_conf_t *dyn)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	if (pool_elem_class(pe) == PEC_COMP) {
4670Sstevel@tonic-gate 		if (pool_component_destroy(pool_elem_comp(pe)) == PO_FAIL) {
4680Sstevel@tonic-gate 			return (PO_FAIL);
4690Sstevel@tonic-gate 		}
4700Sstevel@tonic-gate 	} else if (! elem_is_default(pe)) {
4710Sstevel@tonic-gate 		if (commit_create(dyn, &pe) != PO_SUCCESS) {
4720Sstevel@tonic-gate 			return (PO_FAIL);
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 	return (PO_SUCCESS);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate static int
4790Sstevel@tonic-gate process_elem_gt(pool_elem_t *pe, pool_conf_t *stc, pool_conf_t *dyn)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	if (pool_elem_class(pe) == PEC_COMP) {
4820Sstevel@tonic-gate 		pool_resource_t *owner;
4830Sstevel@tonic-gate 		const pool_resource_t *parent_res;
4840Sstevel@tonic-gate 		pool_value_t val = POOL_VALUE_INITIALIZER;
4850Sstevel@tonic-gate 		const pool_component_t *newcomp;
4860Sstevel@tonic-gate 		const char *resname;
4870Sstevel@tonic-gate 		const char *restype;
4880Sstevel@tonic-gate 		/*
4890Sstevel@tonic-gate 		 * I have to find the right parent in the static
4900Sstevel@tonic-gate 		 * configuration. It may not exist, in which case it's
4910Sstevel@tonic-gate 		 * correct to put it in the default
4920Sstevel@tonic-gate 		 */
4930Sstevel@tonic-gate 		owner = pool_get_owning_resource(dyn,
4940Sstevel@tonic-gate 		    pool_elem_comp(pe));
4950Sstevel@tonic-gate 		if (pool_get_ns_property(TO_ELEM(owner), "name", &val) ==
4960Sstevel@tonic-gate 		    POC_INVAL)
4970Sstevel@tonic-gate 			return (PO_FAIL);
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		if (pool_value_get_string(&val, &resname) == PO_FAIL)
5000Sstevel@tonic-gate 			return (PO_FAIL);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 		if ((resname = strdup(resname)) == NULL)
5030Sstevel@tonic-gate 			return (PO_FAIL);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		restype = pool_elem_class_string(TO_ELEM(owner));
5060Sstevel@tonic-gate 		parent_res = pool_get_resource(stc, restype, resname);
5070Sstevel@tonic-gate 		free((void *)resname);
5080Sstevel@tonic-gate 		if (parent_res == NULL)
5090Sstevel@tonic-gate 			parent_res = resource_by_sysid(stc, PS_NONE, restype);
5100Sstevel@tonic-gate 		/*
5110Sstevel@tonic-gate 		 * Now need to make a copy of the component in the
5120Sstevel@tonic-gate 		 * dynamic configuration in the static configuration.
5130Sstevel@tonic-gate 		 */
5140Sstevel@tonic-gate 		if ((newcomp = pool_component_create(stc, parent_res,
5150Sstevel@tonic-gate 		    elem_get_sysid(pe))) == NULL)
5160Sstevel@tonic-gate 			return (PO_FAIL);
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 		if (pool_walk_properties(TO_CONF(pe), pe, TO_ELEM(newcomp),
5190Sstevel@tonic-gate 		    clone_element) != PO_SUCCESS)
5200Sstevel@tonic-gate 			return (PO_FAIL);
5210Sstevel@tonic-gate 	} else if (elem_is_default(pe)) {
5220Sstevel@tonic-gate 		pool_resource_t *newres;
5230Sstevel@tonic-gate 		pool_t *newpool;
5240Sstevel@tonic-gate 		char *name;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		if ((name = elem_get_name(pe)) == NULL)
5270Sstevel@tonic-gate 			return (PO_FAIL);
5280Sstevel@tonic-gate 		switch (pool_elem_class(pe)) {
5290Sstevel@tonic-gate 		case PEC_POOL:
5300Sstevel@tonic-gate 			if ((newpool = pool_create(stc, name)) == NULL) {
5310Sstevel@tonic-gate 				free(name);
5320Sstevel@tonic-gate 				return (PO_FAIL);
5330Sstevel@tonic-gate 			}
5340Sstevel@tonic-gate 			free(name);
5350Sstevel@tonic-gate 			if (pool_walk_properties(TO_CONF(pe), pe,
5360Sstevel@tonic-gate 			    TO_ELEM(newpool), clone_element) != PO_SUCCESS)
5370Sstevel@tonic-gate 				return (PO_FAIL);
5380Sstevel@tonic-gate 			break;
5390Sstevel@tonic-gate 		case PEC_RES_AGG:
5400Sstevel@tonic-gate 		case PEC_RES_COMP:
5410Sstevel@tonic-gate 			if ((newres = pool_resource_create(stc,
5420Sstevel@tonic-gate 			    pool_elem_class_string(pe), name)) ==
5430Sstevel@tonic-gate 			    NULL) {
5440Sstevel@tonic-gate 				free(name);
5450Sstevel@tonic-gate 				return (PO_FAIL);
5460Sstevel@tonic-gate 			}
5470Sstevel@tonic-gate 			free(name);
5480Sstevel@tonic-gate 			if (pool_walk_properties(TO_CONF(pe), pe,
5490Sstevel@tonic-gate 			    TO_ELEM(newres), clone_element) != PO_SUCCESS)
5500Sstevel@tonic-gate 				return (PO_FAIL);
5510Sstevel@tonic-gate 			break;
5520Sstevel@tonic-gate 		default:
5530Sstevel@tonic-gate 			free(name);
5540Sstevel@tonic-gate 			break;
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 	} else {
5570Sstevel@tonic-gate 		if (commit_delete(pe) != PO_SUCCESS)
5580Sstevel@tonic-gate 			return (PO_FAIL);
5590Sstevel@tonic-gate 	}
5600Sstevel@tonic-gate 	return (PO_SUCCESS);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate /*
5640Sstevel@tonic-gate  * This function compares the elements of the supplied type in the
5650Sstevel@tonic-gate  * static and dynamic configurations supplied. The lists of elements
5660Sstevel@tonic-gate  * are compared and used to create, delete and updated elements in
5670Sstevel@tonic-gate  * both the static and dynamic configurations. The pass parameter is
5680Sstevel@tonic-gate  * used to indicate to commit_update() whether property updates or
5690Sstevel@tonic-gate  * association updates should be performed.
5700Sstevel@tonic-gate  */
5710Sstevel@tonic-gate static int
5720Sstevel@tonic-gate process_lists(int type, pool_conf_t *stc, pool_conf_t *dyn, int pass)
5730Sstevel@tonic-gate {
5740Sstevel@tonic-gate 	uint_t stc_nelem = 0, dyn_nelem = 0;
5750Sstevel@tonic-gate 	pool_elem_t **stc_elems, **dyn_elems;
5760Sstevel@tonic-gate 	int i, j;
5770Sstevel@tonic-gate 	int status = PO_SUCCESS;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	if ((stc_elems = get_elem_list(stc, type, &stc_nelem)) == NULL)
5800Sstevel@tonic-gate 		return (PO_FAIL);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	qsort(stc_elems, stc_nelem, sizeof (pool_elem_t *),
5830Sstevel@tonic-gate 	    qsort_elem_compare);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if ((dyn_elems = get_elem_list(dyn, type, &dyn_nelem)) == NULL) {
5860Sstevel@tonic-gate 		free(stc_elems);
5870Sstevel@tonic-gate 		return (PO_FAIL);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	qsort(dyn_elems, dyn_nelem, sizeof (pool_elem_t *),
5910Sstevel@tonic-gate 	    qsort_elem_compare);
5920Sstevel@tonic-gate 	/*
5930Sstevel@tonic-gate 	 * Step through and do the updating, remember that we are
5940Sstevel@tonic-gate 	 * comparing using the compare function for the configuration
5950Sstevel@tonic-gate 	 * and that is fixed.
5960Sstevel@tonic-gate 	 */
5970Sstevel@tonic-gate 	i = j = 0;
5980Sstevel@tonic-gate 	while (status == PO_SUCCESS && i < stc_nelem && j < dyn_nelem) {
5990Sstevel@tonic-gate 		int compare;
6000Sstevel@tonic-gate 		/*
6010Sstevel@tonic-gate 		 * We are going to do this by stepping through the static
6020Sstevel@tonic-gate 		 * list first.
6030Sstevel@tonic-gate 		 */
6040Sstevel@tonic-gate 		if (elem_is_default(stc_elems[i]) &&
6050Sstevel@tonic-gate 		    elem_is_default(dyn_elems[j]))
6060Sstevel@tonic-gate 			compare = 0;
6070Sstevel@tonic-gate 		else
6080Sstevel@tonic-gate 			compare = pool_elem_compare_name(stc_elems[i],
6090Sstevel@tonic-gate 			    dyn_elems[j]);
6100Sstevel@tonic-gate 		if (compare < 0) {
6110Sstevel@tonic-gate 			status = process_elem_lt(stc_elems[i], dyn);
6120Sstevel@tonic-gate 			i++;
6130Sstevel@tonic-gate 		} else if (compare > 0) {
6140Sstevel@tonic-gate 			status = process_elem_gt(dyn_elems[j], stc, dyn);
6150Sstevel@tonic-gate 			j++;
6160Sstevel@tonic-gate 		} else {	/* compare == 0 */
6170Sstevel@tonic-gate 			if (commit_update(stc_elems[i], dyn_elems[j], pass)
6180Sstevel@tonic-gate 			    != PO_SUCCESS) {
6190Sstevel@tonic-gate 				status = PO_FAIL;
6200Sstevel@tonic-gate 			}
6210Sstevel@tonic-gate 			i++;
6220Sstevel@tonic-gate 			j++;
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 	}
6250Sstevel@tonic-gate 	if (status == PO_FAIL) {
6260Sstevel@tonic-gate 		free(stc_elems);
6270Sstevel@tonic-gate 		free(dyn_elems);
6280Sstevel@tonic-gate 		return (PO_FAIL);
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 	while (status == PO_SUCCESS && i < stc_nelem) {
6310Sstevel@tonic-gate 		status = process_elem_lt(stc_elems[i], dyn);
6320Sstevel@tonic-gate 		i++;
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 	if (status == PO_FAIL) {
6350Sstevel@tonic-gate 		free(stc_elems);
6360Sstevel@tonic-gate 		free(dyn_elems);
6370Sstevel@tonic-gate 		return (PO_FAIL);
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 	while (status == PO_SUCCESS && j < dyn_nelem) {
6400Sstevel@tonic-gate 		status = process_elem_gt(dyn_elems[j], stc, dyn);
6410Sstevel@tonic-gate 		j++;
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 	free(stc_elems);
6440Sstevel@tonic-gate 	free(dyn_elems);
6450Sstevel@tonic-gate 	return (status);
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate /*
6490Sstevel@tonic-gate  * get_elem_list() returns a list of pool_elem_t's. The size of the
6500Sstevel@tonic-gate  * list is written into nelem. The list contains elements of all types
6510Sstevel@tonic-gate  * that pools is interested in: i.e. system, pool, resources and
6520Sstevel@tonic-gate  * resource components. It is the caller's responsibility to free the
6530Sstevel@tonic-gate  * list when it is finished with.
6540Sstevel@tonic-gate  *
6550Sstevel@tonic-gate  * The array of pointers returned by the type specific query can be
6560Sstevel@tonic-gate  * safely cast to be an array of pool_elem_t pointers. In the case of
6570Sstevel@tonic-gate  * PEC_RES_COMP some additional processing is required to qualify the
6580Sstevel@tonic-gate  * list of elements.
6590Sstevel@tonic-gate  *
6600Sstevel@tonic-gate  * Returns a pointer to a list of pool_elem_t's or NULL on failure.
6610Sstevel@tonic-gate  */
6620Sstevel@tonic-gate static pool_elem_t **
6630Sstevel@tonic-gate get_elem_list(const pool_conf_t *conf, int type, uint_t *nelem)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate 	pool_resource_t **rl;
6660Sstevel@tonic-gate 	pool_t **pl;
6670Sstevel@tonic-gate 	pool_component_t **cl;
6680Sstevel@tonic-gate 	pool_elem_t **elems = NULL;
6690Sstevel@tonic-gate 	int i;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	switch (type) {
6720Sstevel@tonic-gate 	case PEC_SYSTEM:
6730Sstevel@tonic-gate 		if ((elems = malloc(sizeof (pool_elem_t *))) == NULL)
6740Sstevel@tonic-gate 			return (NULL);
6750Sstevel@tonic-gate 		*nelem = 1;
6760Sstevel@tonic-gate 		elems[0] = pool_conf_to_elem(conf);
6770Sstevel@tonic-gate 		break;
6780Sstevel@tonic-gate 	case PEC_POOL:
6790Sstevel@tonic-gate 		if ((pl = pool_query_pools(conf, nelem, NULL)) != NULL) {
6800Sstevel@tonic-gate 			elems = (pool_elem_t **)pl;
6810Sstevel@tonic-gate 		}
6820Sstevel@tonic-gate 		break;
6830Sstevel@tonic-gate 	case PEC_RES_COMP:
6840Sstevel@tonic-gate 		if ((rl = pool_query_resources(conf, nelem, NULL)) != NULL) {
6850Sstevel@tonic-gate 			int j = 0;
6860Sstevel@tonic-gate 			elems = (pool_elem_t **)rl;
6870Sstevel@tonic-gate 			for (i = 0; i < *nelem; i++) {
6880Sstevel@tonic-gate 				if (pool_elem_class(TO_ELEM(rl[i])) ==
6890Sstevel@tonic-gate 				    PEC_RES_COMP)
6900Sstevel@tonic-gate 					elems[j++] = TO_ELEM(rl[i]);
6910Sstevel@tonic-gate 			}
6920Sstevel@tonic-gate 			*nelem = j;
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		break;
6950Sstevel@tonic-gate 	case PEC_COMP:
6960Sstevel@tonic-gate 		if ((cl = pool_query_components(conf, nelem, NULL)) != NULL) {
6970Sstevel@tonic-gate 			elems = (pool_elem_t **)cl;
6980Sstevel@tonic-gate 		}
6990Sstevel@tonic-gate 		break;
7000Sstevel@tonic-gate 	default:
7010Sstevel@tonic-gate 		abort();
7020Sstevel@tonic-gate 		break;
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 	return (elems);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate  * share_resources() sets up the allocation of resources by each
7090Sstevel@tonic-gate  * provider.  Firstly all resources are updated with the importance of
7100Sstevel@tonic-gate  * each pool, then each resource provider is invoked in turn with a
7110Sstevel@tonic-gate  * list of it's own resources.  Finally, the pool importance details
7120Sstevel@tonic-gate  * are removed from the resources.
7130Sstevel@tonic-gate  *
7140Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL
7150Sstevel@tonic-gate  */
7160Sstevel@tonic-gate static int
7170Sstevel@tonic-gate share_resources(pool_conf_t *conf)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	pool_resource_t **resources;
7200Sstevel@tonic-gate 	uint_t nelem;
7210Sstevel@tonic-gate 	pool_value_t *props[] = { NULL, NULL };
7220Sstevel@tonic-gate 	pool_value_t val = POOL_VALUE_INITIALIZER;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	props[0] = &val;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/*
7270Sstevel@tonic-gate 	 * Call an allocation function for each type of supported resource.
7280Sstevel@tonic-gate 	 * This function is responsible for "sharing" resources to resource
7290Sstevel@tonic-gate 	 * sets as determined by the system.allocate-method.
7300Sstevel@tonic-gate 	 */
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (pool_value_set_string(props[0], "pset") != PO_SUCCESS ||
7330Sstevel@tonic-gate 	    pool_value_set_name(props[0], c_type) != PO_SUCCESS)
7340Sstevel@tonic-gate 		return (PO_FAIL);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	if (add_importance_props(conf) != PO_SUCCESS) {
7370Sstevel@tonic-gate 		(void) remove_importance_props(conf);
7380Sstevel@tonic-gate 		return (PO_FAIL);
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	if ((resources = pool_query_resources(conf, &nelem, props)) != NULL) {
7420Sstevel@tonic-gate 		/*
7430Sstevel@tonic-gate 		 * 'pool.importance' defines the importance of a pool;
7440Sstevel@tonic-gate 		 * resources inherit the importance of the pool that
7450Sstevel@tonic-gate 		 * is associated with them. If more than one pool is
7460Sstevel@tonic-gate 		 * associated with a resource, the importance of the
7470Sstevel@tonic-gate 		 * resource is the maximum importance of all
7480Sstevel@tonic-gate 		 * associated pools.  Use '_importance' on resources
7490Sstevel@tonic-gate 		 * to determine who gets extra.
7500Sstevel@tonic-gate 		 */
7510Sstevel@tonic-gate 		if (resource_allocate("pset", resources, nelem) != PO_SUCCESS) {
7520Sstevel@tonic-gate 			free(resources);
7530Sstevel@tonic-gate 			(void) remove_importance_props(conf);
7540Sstevel@tonic-gate 			return (PO_FAIL);
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 	free(resources);
7580Sstevel@tonic-gate 	(void) remove_importance_props(conf);
7590Sstevel@tonic-gate 	return (PO_SUCCESS);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate /*
7640Sstevel@tonic-gate  * Work out which allocation method to use based on the value of the
7650Sstevel@tonic-gate  * system.allocate-method property.
7660Sstevel@tonic-gate  */
7670Sstevel@tonic-gate int
7680Sstevel@tonic-gate resource_allocate(const char *type, pool_resource_t **res, uint_t nelem)
7690Sstevel@tonic-gate {
7700Sstevel@tonic-gate 	pool_elem_t *pe;
7710Sstevel@tonic-gate 	const char *method_name;
7720Sstevel@tonic-gate 	uint64_t method;
7730Sstevel@tonic-gate 	pool_value_t val = POOL_VALUE_INITIALIZER;
7740Sstevel@tonic-gate 	int ret;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	pe = pool_conf_to_elem(TO_CONF(TO_ELEM(res[0])));
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	if (pool_get_ns_property(pe, "allocate-method", &val) != POC_STRING)
7790Sstevel@tonic-gate 		method_name = POA_IMPORTANCE;
7800Sstevel@tonic-gate 	else {
7810Sstevel@tonic-gate 		(void) pool_value_get_string(&val, &method_name);
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 	if (strcmp(POA_IMPORTANCE, method_name) != 0) {
7840Sstevel@tonic-gate 		if (strcmp(POA_SURPLUS_TO_DEFAULT, method_name) != 0) {
7850Sstevel@tonic-gate 			pool_seterror(POE_INVALID_CONF);
7860Sstevel@tonic-gate 			return (PO_FAIL);
7870Sstevel@tonic-gate 		} else {
7880Sstevel@tonic-gate 			method = POA_SURPLUS_TO_DEFAULT_NUM;
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 	} else {
7910Sstevel@tonic-gate 		method = POA_IMPORTANCE_NUM;
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 	switch (method) {
7940Sstevel@tonic-gate 	case POA_IMPORTANCE_NUM:
7950Sstevel@tonic-gate 		/*
7960Sstevel@tonic-gate 		 * TODO: Add support for new resource types
7970Sstevel@tonic-gate 		 */
7980Sstevel@tonic-gate 		switch (pool_resource_elem_class_from_string(type)) {
7990Sstevel@tonic-gate 		case PREC_PSET:
8000Sstevel@tonic-gate 			ret = pset_allocate_imp(res, nelem);
8010Sstevel@tonic-gate 			break;
8020Sstevel@tonic-gate 		default:
8030Sstevel@tonic-gate 			ret = PO_FAIL;
8040Sstevel@tonic-gate 			break;
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 		break;
8070Sstevel@tonic-gate 	case POA_SURPLUS_TO_DEFAULT_NUM:
8080Sstevel@tonic-gate 		ret = resource_allocate_default(res, nelem);
8090Sstevel@tonic-gate 		break;
8100Sstevel@tonic-gate 	}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	return (ret);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate /*
8160Sstevel@tonic-gate  * Each set will get its minimum, however if there is more than the
8170Sstevel@tonic-gate  * total minimum available, then leave this in the default set.
8180Sstevel@tonic-gate  */
8190Sstevel@tonic-gate int
8200Sstevel@tonic-gate resource_allocate_default(pool_resource_t **res, uint_t nelem)
8210Sstevel@tonic-gate {
8220Sstevel@tonic-gate 	res_info_t *res_info;
8230Sstevel@tonic-gate 	uint_t j;
8240Sstevel@tonic-gate 	pool_resource_t *default_res = NULL;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	if (nelem == 1)
8270Sstevel@tonic-gate 		return (PO_SUCCESS);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) {
8300Sstevel@tonic-gate 		return (PO_FAIL);
8310Sstevel@tonic-gate 	}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/* Load current resource values. */
8340Sstevel@tonic-gate 	for (j = 0; j < nelem; j++) {
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		if (default_res == NULL &&
8370Sstevel@tonic-gate 		    resource_is_default(res[j]) == PO_TRUE)
8380Sstevel@tonic-gate 			default_res = res[j];
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 		if (resource_get_max(res[j],
8410Sstevel@tonic-gate 		    &res_info[j].ri_max) == PO_FAIL ||
8420Sstevel@tonic-gate 		    resource_get_min(res[j],
8430Sstevel@tonic-gate 			&res_info[j].ri_min) == PO_FAIL ||
8440Sstevel@tonic-gate 		    resource_get_size(res[j],
8450Sstevel@tonic-gate 			&res_info[j].ri_oldsize) == PO_FAIL ||
8460Sstevel@tonic-gate 		    resource_get_pinned(res[j],
8470Sstevel@tonic-gate 			&res_info[j].ri_pinned) == PO_FAIL) {
8480Sstevel@tonic-gate 			free(res_info);
8490Sstevel@tonic-gate 			return (PO_FAIL);
8500Sstevel@tonic-gate 		}
8510Sstevel@tonic-gate 		res_info[j].ri_res = res[j];
8520Sstevel@tonic-gate 	}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	/*
8550Sstevel@tonic-gate 	 * Firstly, for all resources that have size greater than min,
8560Sstevel@tonic-gate 	 * transfer all movable size above min to the default resource.
8570Sstevel@tonic-gate 	 */
8580Sstevel@tonic-gate 	for (j = 0; j < nelem; j++) {
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		uint64_t real_min;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 		/* compute the real minimum number of resources */
8630Sstevel@tonic-gate 		real_min = MAX(res_info[j].ri_pinned, res_info[j].ri_min);
8640Sstevel@tonic-gate 		if (res_info[j].ri_res != default_res &&
8650Sstevel@tonic-gate 		    res_info[j].ri_oldsize > real_min) {
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 			uint64_t num;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 			num = res_info[j].ri_oldsize - real_min;
8700Sstevel@tonic-gate 			if (pool_resource_transfer(
8710Sstevel@tonic-gate 			    TO_CONF(TO_ELEM(default_res)),
8720Sstevel@tonic-gate 				res_info[j].ri_res, default_res, num) !=
8730Sstevel@tonic-gate 			    PO_SUCCESS) {
8740Sstevel@tonic-gate 				free(res_info);
8750Sstevel@tonic-gate 				return (PO_FAIL);
8760Sstevel@tonic-gate 			}
8770Sstevel@tonic-gate 		}
8780Sstevel@tonic-gate 	}
8790Sstevel@tonic-gate 	/*
8800Sstevel@tonic-gate 	 * Now, transfer resources below min from the default.
8810Sstevel@tonic-gate 	 */
8820Sstevel@tonic-gate 	for (j = 0; j < nelem; j++) {
8830Sstevel@tonic-gate 		/*
8840Sstevel@tonic-gate 		 * We don't want to interfere with resources which are reserved
8850Sstevel@tonic-gate 		 */
8860Sstevel@tonic-gate 		if (res_info[j].ri_res != default_res &&
8870Sstevel@tonic-gate 		    res_info[j].ri_oldsize < res_info[j].ri_min) {
8880Sstevel@tonic-gate 			if (pool_resource_transfer(
8890Sstevel@tonic-gate 			    TO_CONF(TO_ELEM(default_res)),
8900Sstevel@tonic-gate 			    default_res, res_info[j].ri_res,
8910Sstevel@tonic-gate 			    res_info[j].ri_min - res_info[j].ri_oldsize) !=
8920Sstevel@tonic-gate 			    PO_SUCCESS) {
8930Sstevel@tonic-gate 				free(res_info);
8940Sstevel@tonic-gate 				return (PO_FAIL);
8950Sstevel@tonic-gate 			}
8960Sstevel@tonic-gate 		}
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate 	free(res_info);
8990Sstevel@tonic-gate 	return (PO_SUCCESS);
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate /*
9030Sstevel@tonic-gate  * Allocate cpus to pset resource sets, favoring sets with higher importance.
9040Sstevel@tonic-gate  *
9050Sstevel@tonic-gate  * Step 1: Sort resource sets by decreasing importance, and load each sets
9060Sstevel@tonic-gate  *	   current size (oldsize), min, max, and number of pinned cpus.
9070Sstevel@tonic-gate  *	   Compute the total number of cpus by totaling oldsize.
9080Sstevel@tonic-gate  *
9090Sstevel@tonic-gate  * Step 2: Compute the newsize for each set:
9100Sstevel@tonic-gate  *
9110Sstevel@tonic-gate  * 	Give each set its min number of cpus.  This min may be greater than
9120Sstevel@tonic-gate  *	its pset.min due to pinned cpus. If there are more cpus than the total
9130Sstevel@tonic-gate  *	of all mins, then the surplus cpus are dealt round-robin to all sets
9140Sstevel@tonic-gate  *	(up to their max) in order of decreasing importance.  A set may be
9150Sstevel@tonic-gate  *	skipped during dealing because it started with more than its min due to
9160Sstevel@tonic-gate  * 	pinned cpus.  The dealing stops when there are no more cpus or all
9170Sstevel@tonic-gate  *	sets are at their max. If all sets are at their max, any remaining cpus
9180Sstevel@tonic-gate  *	are given to the default set.
9190Sstevel@tonic-gate  *
9200Sstevel@tonic-gate  * Step 3: Transfer cpus from sets with (oldsize > newsize) to sets with
9210Sstevel@tonic-gate  *	   (oldsize < newsize).
9220Sstevel@tonic-gate  */
9230Sstevel@tonic-gate int
9240Sstevel@tonic-gate pset_allocate_imp(pool_resource_t **res, uint_t nelem)
9250Sstevel@tonic-gate {
9260Sstevel@tonic-gate 	res_info_t *res_info;
9270Sstevel@tonic-gate 	res_info_t *default_res_info;
9280Sstevel@tonic-gate 	const pool_resource_t *default_res = NULL;
9290Sstevel@tonic-gate 	uint64_t tot_resources = 0;	/* total count of resources */
9300Sstevel@tonic-gate 	uint64_t tot_min = 0;		/* total of all resource set mins */
9310Sstevel@tonic-gate 	uint64_t num_to_deal = 0;	/* total resources above mins to deal */
9320Sstevel@tonic-gate 	uint64_t sets_maxed = 0;	/* number of resource sets dealt to  */
9330Sstevel@tonic-gate 					/* their max */
9340Sstevel@tonic-gate 	uint64_t sets_finished = 0;	/* number of resource sets that have */
9350Sstevel@tonic-gate 					/* size == newsize */
9360Sstevel@tonic-gate 	int donor, receiver;
9370Sstevel@tonic-gate 	int deal;
9380Sstevel@tonic-gate 	int j;
9390Sstevel@tonic-gate 	int ret = PO_SUCCESS;
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/*
9420Sstevel@tonic-gate 	 * Build list of res_info_t's
9430Sstevel@tonic-gate 	 */
9440Sstevel@tonic-gate 	if ((res_info = calloc(nelem, sizeof (res_info_t))) == NULL) {
9450Sstevel@tonic-gate 		pool_seterror(POE_SYSTEM);
9460Sstevel@tonic-gate 		return (PO_FAIL);
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	/* Order resources by importance, most important being first */
9500Sstevel@tonic-gate 	qsort(res, nelem, sizeof (pool_resource_t *),
9510Sstevel@tonic-gate 	    resource_compare_by_descending_importance);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	for (j = 0; j < nelem; j++) {
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		/* Track which resource is the default */
9560Sstevel@tonic-gate 		if (default_res == NULL &&
9570Sstevel@tonic-gate 		    resource_is_default(res[j]) == PO_TRUE) {
9580Sstevel@tonic-gate 			default_res = res[j];
9590Sstevel@tonic-gate 			default_res_info = &(res_info[j]);
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		/* Load sets' current values */
9630Sstevel@tonic-gate 		if (resource_get_max(res[j], &res_info[j].ri_max) == PO_FAIL ||
9640Sstevel@tonic-gate 		    resource_get_min(res[j], &res_info[j].ri_min) == PO_FAIL ||
9650Sstevel@tonic-gate 		    resource_get_size(res[j], &res_info[j].ri_oldsize) ==
9660Sstevel@tonic-gate 		    PO_FAIL ||
9670Sstevel@tonic-gate 		    resource_get_pinned(res[j],
9680Sstevel@tonic-gate 		    &res_info[j].ri_pinned) == PO_FAIL) {
9690Sstevel@tonic-gate 			free(res_info);
9700Sstevel@tonic-gate 			return (PO_FAIL);
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		/* Start each set's newsize out at their min. */
9740Sstevel@tonic-gate 		res_info[j].ri_newsize = res_info[j].ri_min;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 		/* pre-deal pinned resources that exceed min */
9770Sstevel@tonic-gate 		if (res_info[j].ri_pinned > res_info[j].ri_min) {
9780Sstevel@tonic-gate 			res_info[j].ri_newsize = res_info[j].ri_pinned;
9790Sstevel@tonic-gate 			res_info[j].ri_dealt =
9800Sstevel@tonic-gate 			    res_info[j].ri_newsize - res_info[j].ri_min;
9810Sstevel@tonic-gate 		}
9820Sstevel@tonic-gate 		res_info[j].ri_res = res[j];
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 		/* Compute total number of resources to deal out */
9850Sstevel@tonic-gate 		tot_resources += res_info[j].ri_oldsize;
9860Sstevel@tonic-gate 		tot_min += res_info[j].ri_newsize;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate #ifdef DEBUG
9890Sstevel@tonic-gate 		dprintf("res allocation details\n");
9900Sstevel@tonic-gate 		pool_elem_dprintf(TO_ELEM(res[j]));
9910Sstevel@tonic-gate 		dprintf("size=%llu\n", res_info[j].ri_oldsize);
9920Sstevel@tonic-gate #endif	/* DEBUG */
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	num_to_deal = tot_resources - tot_min;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	/*
9980Sstevel@tonic-gate 	 * Deal one resource to each set, and then another, until all
9990Sstevel@tonic-gate 	 * resources are dealt or all sets are at their max.
10000Sstevel@tonic-gate 	 */
10010Sstevel@tonic-gate 	for (deal = 1; num_to_deal > 0 && sets_maxed < nelem; deal++) {
10020Sstevel@tonic-gate 		for (j = 0; j < nelem; j++) {
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 			/*
10050Sstevel@tonic-gate 			 * Skip this resource set if it has already been
10060Sstevel@tonic-gate 			 * pre-dealt a resource due to pinned resources.
10070Sstevel@tonic-gate 			 */
10080Sstevel@tonic-gate 			if (res_info[j].ri_dealt >= deal)
10090Sstevel@tonic-gate 				continue;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 			if (res_info[j].ri_newsize < res_info[j].ri_max) {
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 				res_info[j].ri_dealt++;
10140Sstevel@tonic-gate 				res_info[j].ri_newsize++;
10150Sstevel@tonic-gate 				if (res_info[j].ri_newsize ==
10160Sstevel@tonic-gate 				    res_info[j].ri_max)
10170Sstevel@tonic-gate 					sets_maxed++;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 				num_to_deal--;
10200Sstevel@tonic-gate 				if (num_to_deal == 0)
10210Sstevel@tonic-gate 					break;
10220Sstevel@tonic-gate 			}
10230Sstevel@tonic-gate 		}
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	/*
10270Sstevel@tonic-gate 	 * If all resource sets are at their max, deal the remaining to the
10280Sstevel@tonic-gate 	 * default resource set.
10290Sstevel@tonic-gate 	 */
10300Sstevel@tonic-gate 	if ((sets_maxed == nelem) && (num_to_deal > 0)) {
10310Sstevel@tonic-gate 		default_res_info->ri_dealt += num_to_deal;
10320Sstevel@tonic-gate 		default_res_info->ri_newsize += num_to_deal;
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	/*
10360Sstevel@tonic-gate 	 * Sort so that resource sets needing resources preced resource sets
10370Sstevel@tonic-gate 	 * that have extra resources.  The sort function will also compute
10380Sstevel@tonic-gate 	 * The quantity of resources that need to be transfered into or out
10390Sstevel@tonic-gate 	 * of each set so that it's size == newsize.
10400Sstevel@tonic-gate 	 */
10410Sstevel@tonic-gate 	qsort(res_info, nelem, sizeof (res_info_t),
10420Sstevel@tonic-gate 	    compute_size_to_transfer);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	/*
10450Sstevel@tonic-gate 	 * The donor index starts at the end of the resource set list and
10460Sstevel@tonic-gate 	 * walks up.  The receiver index starts at the beginning of the
10470Sstevel@tonic-gate 	 * resource set list and walks down.  Cpu's are transfered from the
10480Sstevel@tonic-gate 	 * donors to the receivers until all sets have transfer == 0).
10490Sstevel@tonic-gate 	 */
10500Sstevel@tonic-gate 	donor = nelem - 1;
10510Sstevel@tonic-gate 	receiver = 0;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	/* Number of sets with transfer == 0 */
10540Sstevel@tonic-gate 	sets_finished = 0;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	/* Tranfer resources so that each set's size becomes newsize */
10570Sstevel@tonic-gate 	for (;;) {
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		uint64_t ntrans;
10600Sstevel@tonic-gate 		if (donor == receiver) {
10610Sstevel@tonic-gate 			if (res_info[donor].ri_transfer != 0) {
10620Sstevel@tonic-gate 				free(res_info);
10630Sstevel@tonic-gate 				return (PO_FAIL);
10640Sstevel@tonic-gate 			}
10650Sstevel@tonic-gate 			sets_finished++;
10660Sstevel@tonic-gate 			break;
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 		if (res_info[donor].ri_transfer == 0) {
10690Sstevel@tonic-gate 			sets_finished++;
10700Sstevel@tonic-gate 			donor--;
10710Sstevel@tonic-gate 			continue;
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 		if (res_info[receiver].ri_transfer == 0) {
10740Sstevel@tonic-gate 			sets_finished++;
10750Sstevel@tonic-gate 			receiver++;
10760Sstevel@tonic-gate 			continue;
10770Sstevel@tonic-gate 		}
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 		/* Transfer resources from the donor set to the receiver */
10800Sstevel@tonic-gate 		ntrans = MIN(res_info[donor].ri_transfer,
10810Sstevel@tonic-gate 			    -res_info[receiver].ri_transfer);
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 		if (pool_resource_transfer(
10840Sstevel@tonic-gate 			TO_CONF(TO_ELEM(res_info[donor].ri_res)),
10850Sstevel@tonic-gate 			    res_info[donor].ri_res, res_info[receiver].ri_res,
10860Sstevel@tonic-gate 			    ntrans) != PO_SUCCESS) {
10870Sstevel@tonic-gate 				free(res_info);
10880Sstevel@tonic-gate 				return (PO_FAIL);
10890Sstevel@tonic-gate 			}
10900Sstevel@tonic-gate 		res_info[donor].ri_transfer -= ntrans;
10910Sstevel@tonic-gate 		res_info[receiver].ri_transfer += ntrans;
10920Sstevel@tonic-gate 	}
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	if (sets_finished != nelem)
10950Sstevel@tonic-gate 		ret = PO_FAIL;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	free(res_info);
10980Sstevel@tonic-gate 	return (ret);
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate /*
11020Sstevel@tonic-gate  * Used as a qsort parameter to help order resources in terms of their
11030Sstevel@tonic-gate  * importance, higher importance being first.
11040Sstevel@tonic-gate  */
11050Sstevel@tonic-gate int
11060Sstevel@tonic-gate resource_compare_by_descending_importance(const void *arg1, const void *arg2)
11070Sstevel@tonic-gate {
11080Sstevel@tonic-gate 	pool_elem_t *elem1;
11090Sstevel@tonic-gate 	pool_elem_t *elem2;
11100Sstevel@tonic-gate 	pool_resource_t **res1 = (pool_resource_t **)arg1;
11110Sstevel@tonic-gate 	pool_resource_t **res2 = (pool_resource_t **)arg2;
11120Sstevel@tonic-gate 	pool_value_t val = POOL_VALUE_INITIALIZER;
11130Sstevel@tonic-gate 	int64_t i1 = 0, i2 = 0;
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	elem1 = TO_ELEM(*res1);
11160Sstevel@tonic-gate 	elem2 = TO_ELEM(*res2);
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	if (pool_get_property(TO_CONF(elem1), elem1, "_importance", &val) ==
11190Sstevel@tonic-gate 	    POC_INT)
11200Sstevel@tonic-gate 		(void) pool_value_get_int64(&val, &i1);
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	if (pool_get_property(TO_CONF(elem2), elem2, "_importance", &val) ==
11230Sstevel@tonic-gate 	    POC_INT)
11240Sstevel@tonic-gate 		(void) pool_value_get_int64(&val, &i2);
11250Sstevel@tonic-gate 	return (i1 > i2 ? -1 : (i1 < i2 ? 1 : 0));
11260Sstevel@tonic-gate }
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate /*
11290Sstevel@tonic-gate  * Sort in increasing order so that resource sets with extra resources are at
11300Sstevel@tonic-gate  * the end and resource sets needing resources are at the beginning.
11310Sstevel@tonic-gate  */
11320Sstevel@tonic-gate int
11330Sstevel@tonic-gate compute_size_to_transfer(const void *arg1, const void *arg2)
11340Sstevel@tonic-gate {
11350Sstevel@tonic-gate 	res_info_t *r1 = (res_info_t *)arg1, *r2 = (res_info_t *)arg2;
11360Sstevel@tonic-gate 	r1->ri_transfer = (int64_t)r1->ri_oldsize - (int64_t)r1->ri_newsize;
11370Sstevel@tonic-gate 	r2->ri_transfer = (int64_t)r2->ri_oldsize - (int64_t)r2->ri_newsize;
11380Sstevel@tonic-gate 	return (r1->ri_transfer > r2->ri_transfer ? 1 :
11390Sstevel@tonic-gate 	    (r1->ri_transfer < r2->ri_transfer ? -1 : 0));
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate /*
11430Sstevel@tonic-gate  * set_importance_cb() is used to create "_importance" props on each
11440Sstevel@tonic-gate  * resource associated with a pool.
11450Sstevel@tonic-gate  *
11460Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL
11470Sstevel@tonic-gate  */
11480Sstevel@tonic-gate /*ARGSUSED*/
11490Sstevel@tonic-gate static int
11500Sstevel@tonic-gate set_importance_cb(pool_conf_t *conf, pool_t *pool, void *unused)
11510Sstevel@tonic-gate {
11520Sstevel@tonic-gate 	pool_value_t val = POOL_VALUE_INITIALIZER;
11530Sstevel@tonic-gate 	int64_t importance;
11540Sstevel@tonic-gate 	pool_resource_t **res;
11550Sstevel@tonic-gate 	uint_t nelem, i;
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	if (pool_get_property(conf, TO_ELEM(pool), "pool.importance", &val) !=
11580Sstevel@tonic-gate 	    POC_INT) {
11590Sstevel@tonic-gate 		pool_seterror(POE_INVALID_CONF);
11600Sstevel@tonic-gate 		return (PO_FAIL);
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 	(void) pool_value_get_int64(&val, &importance);
11630Sstevel@tonic-gate 	if ((res = pool_query_pool_resources(conf, pool, &nelem, NULL)) ==
11640Sstevel@tonic-gate 	    NULL) {
11650Sstevel@tonic-gate 		return (PO_FAIL);
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 	for (i = 0; res[i] != NULL; i++) {
11680Sstevel@tonic-gate 		int64_t old_importance = INT64_MIN;
11690Sstevel@tonic-gate 		pool_elem_t *elem = TO_ELEM(res[i]);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		if (pool_get_property(conf, elem, "_importance", &val) ==
11720Sstevel@tonic-gate 		    POC_INT)
11730Sstevel@tonic-gate 			(void) pool_value_get_int64(&val, &old_importance);
11740Sstevel@tonic-gate 		if (old_importance <= importance) {
11750Sstevel@tonic-gate 			(void) pool_value_set_int64(&val, importance);
11760Sstevel@tonic-gate 			(void) pool_put_property(conf, elem, "_importance",
11770Sstevel@tonic-gate 			    &val);
11780Sstevel@tonic-gate 		}
11790Sstevel@tonic-gate 	}
11800Sstevel@tonic-gate 	free(res);
11810Sstevel@tonic-gate 	return (PO_SUCCESS);
11820Sstevel@tonic-gate }
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate /*
11850Sstevel@tonic-gate  * unset_importance_cb() is used to remove "_importance" props from
11860Sstevel@tonic-gate  * each resource associated with a pool.
11870Sstevel@tonic-gate  *
11880Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL
11890Sstevel@tonic-gate  */
11900Sstevel@tonic-gate /*ARGSUSED*/
11910Sstevel@tonic-gate static int
11920Sstevel@tonic-gate unset_importance_cb(pool_conf_t *conf, pool_t *pool, void *unused)
11930Sstevel@tonic-gate {
11940Sstevel@tonic-gate 	pool_resource_t **res;
11950Sstevel@tonic-gate 	uint_t nelem, i;
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	if ((res = pool_query_pool_resources(conf, pool, &nelem, NULL)) ==
11980Sstevel@tonic-gate 	    NULL) {
11990Sstevel@tonic-gate 		return (PO_FAIL);
12000Sstevel@tonic-gate 	}
12010Sstevel@tonic-gate 	for (i = 0; res[i] != NULL; i++) {
12020Sstevel@tonic-gate 		if (pool_rm_property(conf, TO_ELEM(res[i]), "_importance") ==
12030Sstevel@tonic-gate 		    PO_FAIL) {
12040Sstevel@tonic-gate 			free(res);
12050Sstevel@tonic-gate 			return (PO_FAIL);
12060Sstevel@tonic-gate 		}
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 	free(res);
12090Sstevel@tonic-gate 	return (PO_SUCCESS);
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate /*
12130Sstevel@tonic-gate  * add_importance_props() is used to create "_importance" props on
12140Sstevel@tonic-gate  * each resource associated with a pool.
12150Sstevel@tonic-gate  *
12160Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL
12170Sstevel@tonic-gate  */
12180Sstevel@tonic-gate static int
12190Sstevel@tonic-gate add_importance_props(pool_conf_t *conf)
12200Sstevel@tonic-gate {
12210Sstevel@tonic-gate 	return (pool_walk_pools(conf, NULL, set_importance_cb));
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate /*
12250Sstevel@tonic-gate  * remove_importance_props() is used to remove "_importance" props on
12260Sstevel@tonic-gate  * each resource associated with a pool.
12270Sstevel@tonic-gate  *
12280Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL
12290Sstevel@tonic-gate  */
12300Sstevel@tonic-gate static int
12310Sstevel@tonic-gate remove_importance_props(pool_conf_t *conf)
12320Sstevel@tonic-gate {
12330Sstevel@tonic-gate 	return (pool_walk_pools(conf, NULL, unset_importance_cb));
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate /*
12370Sstevel@tonic-gate  * pool_conf_commit_sys() takes a configuration and modifies both the
12380Sstevel@tonic-gate  * supplied configuration and the dynamic configuration. The goal of
12390Sstevel@tonic-gate  * this modification is to generate a dynamic configuration which best
12400Sstevel@tonic-gate  * represents the constraints laid down in the static configuration
12410Sstevel@tonic-gate  * and to update the static configuration with the results of this
12420Sstevel@tonic-gate  * process.
12430Sstevel@tonic-gate  *
12440Sstevel@tonic-gate  * Returns PO_SUCCESS/PO_FAIL
12450Sstevel@tonic-gate  */
12460Sstevel@tonic-gate int
12470Sstevel@tonic-gate pool_conf_commit_sys(pool_conf_t *conf, int validate)
12480Sstevel@tonic-gate {
12490Sstevel@tonic-gate 	pool_conf_t *dyn;
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	if ((dyn = pool_conf_alloc()) == NULL)
12520Sstevel@tonic-gate 		return (PO_FAIL);
12530Sstevel@tonic-gate 	if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDWR) !=
12540Sstevel@tonic-gate 	    PO_SUCCESS) {
12550Sstevel@tonic-gate 		pool_conf_free(dyn);
12560Sstevel@tonic-gate 		return (PO_FAIL);
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 	if (validate == PO_TRUE) {
12590Sstevel@tonic-gate 		if (pool_conf_validate(conf, POV_RUNTIME) != PO_SUCCESS) {
12600Sstevel@tonic-gate 			(void) pool_conf_close(dyn);
12610Sstevel@tonic-gate 			pool_conf_free(dyn);
12620Sstevel@tonic-gate 			return (PO_FAIL);
12630Sstevel@tonic-gate 		}
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 	/*
12660Sstevel@tonic-gate 	 * Now try to make the two things "the same".
12670Sstevel@tonic-gate 	 */
12680Sstevel@tonic-gate 	if (diff_and_fix(conf, dyn) != PO_SUCCESS) {
12690Sstevel@tonic-gate 		(void) pool_conf_close(dyn);
12700Sstevel@tonic-gate 		pool_conf_free(dyn);
12710Sstevel@tonic-gate 		pool_seterror(POE_INVALID_CONF);
12720Sstevel@tonic-gate 		return (PO_FAIL);
12730Sstevel@tonic-gate 	}
12740Sstevel@tonic-gate 	if (dyn->pc_prov->pc_commit(dyn) != PO_SUCCESS) {
12750Sstevel@tonic-gate 		(void) pool_conf_close(dyn);
12760Sstevel@tonic-gate 		pool_conf_free(dyn);
12770Sstevel@tonic-gate 		return (PO_FAIL);
12780Sstevel@tonic-gate 	}
12790Sstevel@tonic-gate 	(void) pool_conf_close(dyn);
12800Sstevel@tonic-gate 	pool_conf_free(dyn);
12810Sstevel@tonic-gate 	return (PO_SUCCESS);
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate /*
12850Sstevel@tonic-gate  * Copies all properties from one element to another. If the property
12860Sstevel@tonic-gate  * is a readonly property, then don't copy it.
12870Sstevel@tonic-gate  */
12880Sstevel@tonic-gate /* ARGSUSED */
12890Sstevel@tonic-gate static int
12900Sstevel@tonic-gate clone_element(pool_conf_t *conf, pool_elem_t *pe, const char *name,
12910Sstevel@tonic-gate     pool_value_t *pv, void *user)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate 	pool_elem_t *tgt = (pool_elem_t *)user;
12940Sstevel@tonic-gate 	const pool_prop_t *prop;
12950Sstevel@tonic-gate #ifdef DEBUG
12960Sstevel@tonic-gate 	dprintf("Cloning %s from %s\n",
12970Sstevel@tonic-gate 	    pool_conf_location(TO_CONF(TO_ELEM(tgt))),
12980Sstevel@tonic-gate 	    pool_conf_location(TO_CONF(pe)));
12990Sstevel@tonic-gate 	assert(TO_CONF(TO_ELEM(tgt)) != TO_CONF(pe));
13000Sstevel@tonic-gate 	dprintf("clone_element: Processing %s\n", name);
13010Sstevel@tonic-gate 	pool_value_dprintf(pv);
13020Sstevel@tonic-gate #endif	/* DEBUG */
13030Sstevel@tonic-gate 	/*
13040Sstevel@tonic-gate 	 * Some properties should be ignored
13050Sstevel@tonic-gate 	 */
13060Sstevel@tonic-gate 	if ((prop = provider_get_prop(pe, name)) != NULL &&
13070Sstevel@tonic-gate 	    prop_is_readonly(prop) == PO_TRUE)
13080Sstevel@tonic-gate 		return (PO_SUCCESS);
13090Sstevel@tonic-gate 	return (pool_put_property(TO_CONF(tgt), tgt, name, pv) == PO_FAIL);
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate /*
13130Sstevel@tonic-gate  * Removes all properties from one element. Properties which are
13140Sstevel@tonic-gate  * managed by the configuration are ignored.
13150Sstevel@tonic-gate  */
13160Sstevel@tonic-gate /* ARGSUSED3 */
13170Sstevel@tonic-gate static int
13180Sstevel@tonic-gate clean_element(pool_conf_t *conf, pool_elem_t *pe, const char *name,
13190Sstevel@tonic-gate     pool_value_t *pv, void *user)
13200Sstevel@tonic-gate {
13210Sstevel@tonic-gate 	const pool_prop_t *prop;
13220Sstevel@tonic-gate 	/*
13230Sstevel@tonic-gate 	 * Some properties should be ignored
13240Sstevel@tonic-gate 	 */
13250Sstevel@tonic-gate 	if ((prop = provider_get_prop(pe, name)) != NULL &&
13260Sstevel@tonic-gate 	    prop_is_optional(prop) == PO_FALSE)
13270Sstevel@tonic-gate 		return (PO_SUCCESS);
13280Sstevel@tonic-gate 	return (pool_rm_property(conf, (pool_elem_t *)pe, name) == PO_FAIL);
13290Sstevel@tonic-gate }
1330