xref: /titanic_44/usr/src/lib/libpool/common/pool_kernel.c (revision f808c858fa61e7769218966759510a8b1190dfcf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <assert.h>
30 #include <errno.h>
31 #include <exacct.h>
32 #include <fcntl.h>
33 #include <libnvpair.h>
34 #include <limits.h>
35 #include <poll.h>
36 #include <pool.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <strings.h>
41 #include <stropts.h>
42 #include <thread.h>
43 #include <time.h>
44 #include <unistd.h>
45 
46 #include <libxml/tree.h>
47 
48 #include <sys/mman.h>
49 #include <sys/pool.h>
50 #include <sys/pool_impl.h>
51 #include <sys/priocntl.h>
52 #include <sys/stat.h>
53 #include <sys/time.h>
54 #include <sys/types.h>
55 
56 #include "dict.h"
57 
58 #include "pool_internal.h"
59 #include "pool_impl.h"
60 #include "pool_kernel_impl.h"
61 
62 /*
63  * libpool kernel Manipulation Routines
64  *
65  * pool_kernel.c implements the kernel manipulation routines used by the
66  * libpool kernel datastore. The functions are grouped into the following
67  * logical areas
68  *
69  */
70 
71 /*
72  * Device snapshot transfer buffer size
73  */
74 #define	KERNEL_SNAPSHOT_BUF_SZ	65535
75 
76 /*
77  * Kernel result set's initial size. 8 is probably large enough for
78  * most queries. Queries requiring more space are accomodated using
79  * realloc on a per result set basis.
80  */
81 #define	KERNEL_RS_INITIAL_SZ	8
82 
83 /*
84  * Property manipulation macros
85  */
86 #define	KERNEL_PROP_RDONLY	0x1
87 
88 /*
89  * Information required to evaluate qualifying elements for a query
90  */
91 struct query_obj {
92 	const pool_conf_t *conf;
93 	const pool_elem_t *src;
94 	const char *src_attr;
95 	pool_elem_class_t classes;
96 	pool_value_t **props;
97 	pool_knl_result_set_t *rs;
98 };
99 
100 /*
101  * Identifies a pool element with a processor set id
102  */
103 typedef struct pool_set_xref {
104 	pool_knl_pool_t	*psx_pool;
105 	uint_t		psx_pset_id;
106 	struct pool_set_xref *psx_next;
107 } pool_set_xref_t;
108 
109 /*
110  * Controls exacct snapshot load into libpool data structure
111  */
112 typedef struct pool_snap_load {
113 	int *psl_changed;
114 	pool_set_xref_t *psl_xref;
115 	pool_elem_t *psl_system;
116 	pool_knl_resource_t *psl_pset;
117 } pool_snap_load_t;
118 
119 /*
120  * Information about an XML document which is being constructed
121  */
122 struct knl_to_xml {
123 	xmlDocPtr ktx_doc;
124 	xmlNodePtr ktx_node;
125 };
126 
127 /*
128  * Undo structure processing. The following structures are all used to
129  * allow changes to the libpool snapshot and kernel following an
130  * unsuccessful commit.
131  */
132 typedef struct pool_create_undo {
133 	pool_create_t pcu_ioctl;
134 	pool_elem_t *pcu_elem;
135 } pool_create_undo_t;
136 
137 typedef struct pool_destroy_undo {
138 	pool_destroy_t pdu_ioctl;
139 	pool_elem_t *pdu_elem;
140 } pool_destroy_undo_t;
141 
142 typedef struct pool_assoc_undo {
143 	pool_assoc_t pau_ioctl;
144 	pool_elem_t *pau_assoc;
145 	pool_elem_t *pau_oldres;
146 	pool_elem_t *pau_newres;
147 } pool_assoc_undo_t;
148 
149 typedef struct pool_dissoc_undo {
150 	pool_dissoc_t pdu_ioctl;
151 	pool_elem_t *pdu_dissoc;
152 	pool_elem_t *pdu_oldres;
153 	pool_elem_t *pdu_newres;
154 } pool_dissoc_undo_t;
155 
156 typedef struct pool_xtransfer_undo {
157 	pool_xtransfer_t pxu_ioctl;
158 	pool_elem_t *pxu_src;
159 	pool_elem_t *pxu_tgt;
160 	pool_component_t **pxu_rl;
161 } pool_xtransfer_undo_t;
162 
163 typedef struct pool_propput_undo {
164 	pool_propput_t ppu_ioctl;
165 	pool_elem_t *ppu_elem;
166 	nvlist_t *ppu_alist;
167 	nvlist_t *ppu_blist;
168 	uchar_t ppu_doioctl;
169 } pool_propput_undo_t;
170 
171 typedef struct pool_proprm_undo {
172 	pool_proprm_t pru_ioctl;
173 	pool_elem_t *pru_elem;
174 	pool_value_t pru_oldval;
175 } pool_proprm_undo_t;
176 
177 extern const char *dtd_location;
178 
179 extern const char *element_class_tags[];
180 extern const char pool_info_location[];
181 
182 /*
183  * These functions are defined in pool_xml.c and represent the minimum
184  * XML support required to allow a pool kernel configuration to be
185  * exported as an XML document.
186  */
187 extern int pool_xml_set_attr(xmlNodePtr, xmlChar *, const pool_value_t *);
188 extern int pool_xml_set_prop(xmlNodePtr, xmlChar *, const pool_value_t *);
189 extern void xml_init(void);
190 extern xmlNodePtr node_create(xmlNodePtr, const xmlChar *);
191 extern void pool_error_func(void *, const char *, ...);
192 /*
193  * Utilities
194  */
195 static int load_group(pool_conf_t *, pool_knl_elem_t *, ea_object_t *,
196     pool_snap_load_t *);
197 static void pool_knl_elem_free(pool_knl_elem_t *, int);
198 static int pool_knl_put_xml_property(pool_elem_t *, xmlNodePtr, const char *,
199     const pool_value_t *);
200 static int pool_knl_snap_load_push(pool_snap_load_t *, pool_knl_pool_t *);
201 static int pool_knl_snap_load_update(pool_snap_load_t *, int, uint_t);
202 static int pool_knl_snap_load_remove(pool_snap_load_t *, int, uint_t);
203 static nvpair_t *pool_knl_find_nvpair(nvlist_t *, const char *);
204 static int pool_knl_nvlist_add_value(nvlist_t *, const char *,
205     const pool_value_t *);
206 static int pool_knl_recover(pool_conf_t *);
207 static uint64_t hash_id(const pool_elem_t *);
208 static int blocking_open(const char *, int);
209 
210 /*
211  * Connections
212  */
213 static void pool_knl_connection_free(pool_knl_connection_t *);
214 
215 /*
216  * Configuration
217  */
218 static int pool_knl_close(pool_conf_t *);
219 static int pool_knl_validate(const pool_conf_t *, pool_valid_level_t);
220 static int pool_knl_commit(pool_conf_t *);
221 static int pool_knl_export(const pool_conf_t *, const char *,
222     pool_export_format_t);
223 static int pool_knl_rollback(pool_conf_t *);
224 static pool_result_set_t *pool_knl_exec_query(const pool_conf_t *,
225     const pool_elem_t *, const char *, pool_elem_class_t, pool_value_t **);
226 static int pool_knl_remove(pool_conf_t *);
227 static char *pool_knl_get_binding(pool_conf_t *, pid_t);
228 static int pool_knl_set_binding(pool_conf_t *, const char *, idtype_t, id_t);
229 static char *pool_knl_get_resource_binding(pool_conf_t *,
230     pool_resource_elem_class_t, pid_t);
231 static int pool_knl_res_transfer(pool_resource_t *, pool_resource_t *,
232     uint64_t);
233 static int pool_knl_res_xtransfer(pool_resource_t *, pool_resource_t *,
234     pool_component_t **);
235 
236 /*
237  * Result Sets
238  */
239 static pool_knl_result_set_t *pool_knl_result_set_alloc(const pool_conf_t *);
240 static int pool_knl_result_set_append(pool_knl_result_set_t *,
241     pool_knl_elem_t *);
242 static int pool_knl_result_set_realloc(pool_knl_result_set_t *);
243 static void pool_knl_result_set_free(pool_knl_result_set_t *);
244 static pool_elem_t *pool_knl_rs_next(pool_result_set_t *);
245 static pool_elem_t *pool_knl_rs_prev(pool_result_set_t *);
246 static pool_elem_t *pool_knl_rs_first(pool_result_set_t *);
247 static pool_elem_t *pool_knl_rs_last(pool_result_set_t *);
248 static int pool_knl_rs_set_index(pool_result_set_t *, int);
249 static int pool_knl_rs_get_index(pool_result_set_t *);
250 static int pool_knl_rs_count(pool_result_set_t *);
251 static int pool_knl_rs_close(pool_result_set_t *);
252 
253 /*
254  * Element (and sub-type)
255  */
256 static pool_knl_elem_t *pool_knl_elem_wrap(pool_conf_t *, pool_elem_class_t,
257     pool_resource_elem_class_t, pool_component_elem_class_t);
258 static pool_elem_t *pool_knl_elem_create(pool_conf_t *, pool_elem_class_t,
259     pool_resource_elem_class_t, pool_component_elem_class_t);
260 static int pool_knl_elem_remove(pool_elem_t *);
261 static int pool_knl_set_container(pool_elem_t *, pool_elem_t *);
262 static pool_elem_t *pool_knl_get_container(const pool_elem_t *);
263 /*
264  * Pool element specific
265  */
266 static int pool_knl_pool_associate(pool_t *, const pool_resource_t *);
267 static int pool_knl_pool_dissociate(pool_t *, const pool_resource_t *);
268 
269 /*
270  * Resource elements specific
271  */
272 static int pool_knl_resource_is_system(const pool_resource_t *);
273 static int pool_knl_resource_can_associate(const pool_resource_t *);
274 
275 /* Properties */
276 static pool_value_class_t pool_knl_get_property(const pool_elem_t *,
277     const char *, pool_value_t *);
278 static pool_value_class_t pool_knl_get_dynamic_property(const pool_elem_t *,
279     const char *, pool_value_t *);
280 static int pool_knl_put_property(pool_elem_t *, const char *,
281     const pool_value_t *);
282 static int pool_knl_rm_property(pool_elem_t *, const char *);
283 static pool_value_t **pool_knl_get_properties(const pool_elem_t *, uint_t *);
284 
285 /*
286  * Logging
287  */
288 static int log_item_commit(log_item_t *);
289 static int log_item_undo(log_item_t *);
290 static int log_item_release(log_item_t *);
291 
292 /*
293  * Utilities
294  */
295 
296 /*
297  * load_group() updates the library configuration with the kernel
298  * snapshot supplied in ep. The function is designed to be called
299  * recursively. This function depends implicitly on the ordering of
300  * the data provided in ep. Changes to the ordering of data in ep must
301  * be matched by changes to this function.
302  */
303 int
304 load_group(pool_conf_t *conf, pool_knl_elem_t *elem, ea_object_t *ep,
305     pool_snap_load_t *psl)
306 {
307 	ea_object_t *eo;
308 	pool_knl_elem_t *old_elem;
309 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
310 	int ret = PO_SUCCESS;
311 
312 	if ((ep->eo_catalog & EXD_DATA_MASK) == EXD_GROUP_SYSTEM) {
313 		if ((elem = pool_knl_elem_wrap(conf, PEC_SYSTEM, PREC_INVALID,
314 		    PCEC_INVALID)) == NULL)
315 			return (PO_FAIL);
316 		if (nvlist_alloc(&elem->pke_properties, NV_UNIQUE_NAME_TYPE,
317 		    0) != 0) {
318 			pool_knl_elem_free(elem, PO_FALSE);
319 			pool_seterror(POE_SYSTEM);
320 			return (PO_FAIL);
321 		}
322 		/*
323 		 * Check to see if we already have an element
324 		 * for this data. If we have, free the newly
325 		 * created elem and continue with the old one
326 		 */
327 		if ((old_elem = dict_get(prov->pkc_elements, elem)) != NULL) {
328 			nvlist_free(old_elem->pke_properties);
329 			old_elem->pke_properties = elem->pke_properties;
330 			pool_knl_elem_free(elem, PO_FALSE);
331 			elem = old_elem;
332 		} else {
333 			if (dict_put(prov->pkc_elements, elem, elem) != NULL) {
334 				pool_knl_elem_free(elem, PO_TRUE);
335 				pool_seterror(POE_SYSTEM);
336 				return (PO_FAIL);
337 			}
338 		}
339 		psl->psl_system = (pool_elem_t *)elem;
340 	}
341 
342 	for (eo = ep->eo_group.eg_objs; eo != NULL; eo = eo->eo_next) {
343 		int data;
344 		pool_knl_elem_t *prop_elem = NULL;
345 
346 		data = (eo->eo_catalog & EXD_DATA_MASK);
347 
348 		switch (data) {
349 		case EXD_SYSTEM_TSTAMP:
350 		case EXD_POOL_TSTAMP:
351 		case EXD_PSET_TSTAMP:
352 		case EXD_CPU_TSTAMP:
353 			if (eo->eo_item.ei_uint64 > prov->pkc_lotime) {
354 				if (eo->eo_item.ei_uint64 > prov->pkc_ltime)
355 					prov->pkc_ltime = eo->eo_item.ei_uint64;
356 				if (psl->psl_changed) {
357 					switch (data) {
358 					case EXD_SYSTEM_TSTAMP:
359 						*psl->psl_changed |= POU_SYSTEM;
360 						break;
361 					case EXD_POOL_TSTAMP:
362 						*psl->psl_changed |= POU_POOL;
363 						break;
364 					case EXD_PSET_TSTAMP:
365 						*psl->psl_changed |= POU_PSET;
366 						break;
367 					case EXD_CPU_TSTAMP:
368 						*psl->psl_changed |= POU_CPU;
369 						break;
370 					}
371 				}
372 			}
373 			break;
374 		case EXD_SYSTEM_PROP:
375 		case EXD_POOL_PROP:
376 		case EXD_PSET_PROP:
377 		case EXD_CPU_PROP:
378 			if (data == EXD_PSET_PROP) {
379 				prop_elem = elem;
380 				elem = (pool_knl_elem_t *)psl->psl_pset;
381 			}
382 			nvlist_free(elem->pke_properties);
383 			if (nvlist_unpack(eo->eo_item.ei_raw,
384 			    eo->eo_item.ei_size, &elem->pke_properties, 0) !=
385 			    0) {
386 				pool_seterror(POE_SYSTEM);
387 				return (PO_FAIL);
388 			}
389 			elem->pke_ltime = prov->pkc_ltime;
390 			if (data == EXD_PSET_PROP) {
391 				elem = prop_elem;
392 			}
393 			break;
394 		case EXD_POOL_POOLID:
395 			if (nvlist_alloc(&elem->pke_properties,
396 			    NV_UNIQUE_NAME_TYPE, 0) != 0) {
397 				pool_seterror(POE_SYSTEM);
398 				return (PO_FAIL);
399 			}
400 			if (nvlist_add_int64(elem->pke_properties,
401 			    "pool.sys_id",
402 			    (int64_t)eo->eo_item.ei_uint32) != 0) {
403 				pool_seterror(POE_SYSTEM);
404 				return (PO_FAIL);
405 			}
406 			if ((old_elem = dict_get(prov->pkc_elements, elem)) !=
407 			    NULL) {
408 				nvlist_free(old_elem->pke_properties);
409 				old_elem->pke_properties = elem->pke_properties;
410 				pool_knl_elem_free(elem, PO_FALSE);
411 				elem = old_elem;
412 			} else {
413 				if (dict_put(prov->pkc_elements, elem, elem) !=
414 				    NULL) {
415 					pool_knl_elem_free(elem, PO_TRUE);
416 					pool_seterror(POE_SYSTEM);
417 					return (PO_FAIL);
418 				}
419 			}
420 			if (pool_knl_snap_load_push(psl,
421 			    (pool_knl_pool_t *)elem) != PO_SUCCESS) {
422 				pool_seterror(POE_SYSTEM);
423 				return (PO_FAIL);
424 			}
425 			((pool_knl_pool_t *)elem)->pkp_assoc[PREC_PSET] = NULL;
426 			break;
427 		case EXD_POOL_PSETID:
428 			if (pool_knl_snap_load_update(psl, EXD_POOL_PSETID,
429 			    eo->eo_item.ei_uint32) != PO_SUCCESS) {
430 				pool_seterror(POE_SYSTEM);
431 				return (PO_FAIL);
432 			}
433 			break;
434 		case EXD_PSET_PSETID:
435 			if (nvlist_alloc(&elem->pke_properties,
436 			    NV_UNIQUE_NAME_TYPE, 0) != 0) {
437 				pool_seterror(POE_SYSTEM);
438 				return (PO_FAIL);
439 			}
440 			if (nvlist_add_int64(elem->pke_properties,
441 			    "pset.sys_id",
442 			    (int64_t)eo->eo_item.ei_uint32) != 0) {
443 				pool_seterror(POE_SYSTEM);
444 				return (PO_FAIL);
445 			}
446 			if ((old_elem = dict_get(prov->pkc_elements, elem)) !=
447 			    NULL) {
448 				nvlist_free(old_elem->pke_properties);
449 				old_elem->pke_properties = elem->pke_properties;
450 				pool_knl_elem_free(elem, PO_FALSE);
451 				elem = old_elem;
452 			} else {
453 				if (dict_put(prov->pkc_elements, elem, elem) !=
454 				    NULL) {
455 					pool_knl_elem_free(elem, PO_TRUE);
456 					pool_seterror(POE_SYSTEM);
457 					return (PO_FAIL);
458 				}
459 			}
460 			psl->psl_pset = (pool_knl_resource_t *)elem;
461 			if (pool_knl_snap_load_remove(psl, data,
462 			    eo->eo_item.ei_uint32) != PO_SUCCESS) {
463 				pool_seterror(POE_SYSTEM);
464 				return (PO_FAIL);
465 			}
466 			break;
467 		case EXD_CPU_CPUID:
468 			if (nvlist_alloc(&elem->pke_properties,
469 			    NV_UNIQUE_NAME_TYPE, 0) != 0) {
470 				pool_seterror(POE_SYSTEM);
471 				return (PO_FAIL);
472 			}
473 			if (nvlist_add_int64(elem->pke_properties,
474 			    "cpu.sys_id",
475 			    (int64_t)eo->eo_item.ei_uint32) != 0) {
476 				pool_seterror(POE_SYSTEM);
477 				return (PO_FAIL);
478 			}
479 			if ((old_elem = dict_get(prov->pkc_elements, elem)) !=
480 			    NULL) {
481 				nvlist_free(old_elem->pke_properties);
482 				old_elem->pke_properties = elem->pke_properties;
483 				old_elem->pke_parent = elem->pke_parent;
484 				pool_knl_elem_free(elem, PO_FALSE);
485 				elem = old_elem;
486 			} else {
487 				if (dict_put(prov->pkc_elements, elem, elem) !=
488 				    NULL) {
489 					pool_knl_elem_free(elem, PO_TRUE);
490 					pool_seterror(POE_SYSTEM);
491 					return (PO_FAIL);
492 				}
493 			}
494 			break;
495 		case EXD_GROUP_POOL:
496 			if ((elem = pool_knl_elem_wrap(conf, PEC_POOL,
497 			    PREC_INVALID, PCEC_INVALID)) == NULL)
498 				return (PO_FAIL);
499 			if (pool_set_container(psl->psl_system,
500 			    (pool_elem_t *)elem) != PO_SUCCESS) {
501 				pool_seterror(POE_SYSTEM);
502 				return (PO_FAIL);
503 			}
504 			break;
505 		case EXD_GROUP_PSET:
506 			if ((elem = pool_knl_elem_wrap(conf, PEC_RES_COMP,
507 			    PREC_PSET, PCEC_INVALID)) == NULL)
508 				return (PO_FAIL);
509 			if (pool_set_container(psl->psl_system,
510 			    (pool_elem_t *)elem) != PO_SUCCESS) {
511 				pool_seterror(POE_SYSTEM);
512 				return (PO_FAIL);
513 			}
514 			break;
515 		case EXD_GROUP_CPU:
516 			if ((elem = pool_knl_elem_wrap(conf, PEC_COMP,
517 			    PREC_INVALID, PCEC_CPU)) == NULL)
518 				return (PO_FAIL);
519 			if (pool_set_container((pool_elem_t *)psl->psl_pset,
520 			    (pool_elem_t *)elem) != PO_SUCCESS) {
521 				pool_seterror(POE_SYSTEM);
522 				return (PO_FAIL);
523 			}
524 			break;
525 		default:
526 			break;
527 		}
528 
529 
530 		if (eo->eo_type == EO_GROUP) {
531 			if ((ret = load_group(conf, elem, eo, psl)) == PO_FAIL)
532 				break;
533 		}
534 	}
535 	return (ret);
536 }
537 
538 /*
539  * Push a snapshot entry onto the list of pools in the snapshot.
540  */
541 int
542 pool_knl_snap_load_push(pool_snap_load_t *psl, pool_knl_pool_t *pkp)
543 {
544 	pool_set_xref_t *psx;
545 
546 	if ((psx = malloc(sizeof (pool_set_xref_t))) == NULL) {
547 		pool_seterror(POE_SYSTEM);
548 		return (PO_FAIL);
549 	}
550 	(void) memset(psx, 0, sizeof (pool_set_xref_t));
551 	psx->psx_pool = pkp;
552 	/*
553 	 * Push onto the list of pools
554 	 */
555 	psx->psx_next = psl->psl_xref;
556 	psl->psl_xref = psx;
557 
558 	return (PO_SUCCESS);
559 }
560 
561 /*
562  * Update the current cross-reference for the supplied type of
563  * resource.
564  */
565 int
566 pool_knl_snap_load_update(pool_snap_load_t *psl, int type, uint_t id)
567 {
568 	switch (type) {
569 	case EXD_POOL_PSETID:
570 		psl->psl_xref->psx_pset_id = id;
571 		break;
572 	default:
573 		return (PO_FAIL);
574 	}
575 
576 	return (PO_SUCCESS);
577 }
578 
579 /*
580  * Remove a resource entry with the supplied type and id from the
581  * snapshot list when it is no longer required.
582  */
583 int
584 pool_knl_snap_load_remove(pool_snap_load_t *psl, int type, uint_t id)
585 {
586 	pool_set_xref_t *current, *prev, *next;
587 
588 	for (prev = NULL, current = psl->psl_xref; current != NULL;
589 	    current = next) {
590 		switch (type) {
591 		case EXD_PSET_PSETID:
592 			if (current->psx_pset_id == id)
593 				current->psx_pool->pkp_assoc[PREC_PSET] =
594 				    psl->psl_pset;
595 			break;
596 		default:
597 			return (PO_FAIL);
598 		}
599 		next = current->psx_next;
600 		if (current->psx_pool->pkp_assoc[PREC_PSET] != NULL) {
601 			if (prev != NULL) {
602 				prev->psx_next = current->psx_next;
603 			} else {
604 				psl->psl_xref = current->psx_next;
605 			}
606 			free(current);
607 		} else
608 			prev = current;
609 	}
610 
611 	return (PO_SUCCESS);
612 }
613 
614 /*
615  * Return the nvpair with the supplied name from the supplied list.
616  *
617  * NULL is returned if the name cannot be found in the list.
618  */
619 nvpair_t *
620 pool_knl_find_nvpair(nvlist_t *l, const char *name)
621 {
622 	nvpair_t *pair;
623 
624 	for (pair = nvlist_next_nvpair(l, NULL); pair != NULL;
625 		pair = nvlist_next_nvpair(l, pair)) {
626 		if (strcmp(nvpair_name(pair), name) == 0)
627 			break;
628 	}
629 	return (pair);
630 }
631 
632 /*
633  * Close the configuration. There are a few steps to closing a configuration:
634  * - Close the pseudo device
635  * - Free the data provider
636  * Returns PO_SUCCESS/PO_FAIL
637  */
638 int
639 pool_knl_close(pool_conf_t *conf)
640 {
641 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
642 
643 	if (close(prov->pkc_fd) < 0) {
644 		pool_seterror(POE_SYSTEM);
645 		return (PO_FAIL);
646 	}
647 	/*
648 	 * Rollback any pending changes before freeing the prov. This
649 	 * ensures there are no memory leaks from pending
650 	 * transactions.
651 	 */
652 	(void) pool_knl_rollback(conf);
653 	pool_knl_connection_free(prov);
654 	return (PO_SUCCESS);
655 }
656 
657 /*
658  * Remove elements in this map (previously identified as "dead") from
659  * the configuration map (prov->pkc_elements).
660  */
661 
662 /* ARGSUSED1 */
663 static void
664 remove_dead_elems(const void *key, void **value, void *cl)
665 {
666 	pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
667 	pool_conf_t *conf = TO_CONF(TO_ELEM(pke));
668 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
669 
670 	assert(dict_remove(prov->pkc_elements, pke) != NULL);
671 #ifdef DEBUG
672 	dprintf("remove_dead_elems:\n");
673 	pool_elem_dprintf(TO_ELEM(pke));
674 #endif	/* DEBUG */
675 	pool_knl_elem_free(pke, PO_TRUE);
676 }
677 
678 /*
679  * Find elements which were not updated the last time that
680  * load_group() was called. Add those elements into a separate map
681  * (passed in cl) which will be later used to remove these elements
682  * from the configuration map.
683  */
684 /* ARGSUSED1 */
685 static void
686 find_dead_elems(const void *key, void **value, void *cl)
687 {
688 	pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
689 	pool_conf_t *conf = TO_CONF(TO_ELEM(pke));
690 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
691 	dict_hdl_t *dead_map = (dict_hdl_t *)cl;
692 
693 	if (pke->pke_ltime < prov->pkc_ltime)
694 		(void) dict_put(dead_map, pke, pke);
695 }
696 
697 /*
698  * Update the snapshot held by the library. This function acts as the
699  * controller for the snapshot update procedure. Then snapshot is
700  * actually updated in multiple phases by the load_group() function
701  * (which updates existing elements and creates new elements as
702  * required) and then by find_dead_elems and remove_dead_elems
703  * (respectively responsible for identifying elements which are to be
704  * removed and then removing them).
705  *
706  * Returns PO_SUCCESS
707  */
708 int
709 pool_knl_update(pool_conf_t *conf, int *changed)
710 {
711 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
712 	pool_query_t query = {0};
713 	ea_object_t *ep;
714 	dict_hdl_t *dead_map;
715 	pool_snap_load_t psl = { NULL };
716 
717 	/*
718 	 * Ensure the library snapshot is consistent, if there are any
719 	 * outstanding transactions return failure.
720 	 */
721 	if (log_size(prov->pkc_log) != 0) {
722 		pool_seterror(POE_INVALID_CONF);
723 		return (PO_FAIL);
724 	}
725 	/*
726 	 * Query the kernel for a snapshot of the configuration state. Use
727 	 * load_group to allocate the user-land representation of the
728 	 * data returned in the snapshot.
729 	 */
730 	/* LINTED E_CONSTANT_CONDITION */
731 	while (1) {
732 		if (ioctl(prov->pkc_fd, POOL_QUERY, &query) < 0) {
733 			pool_seterror(POE_SYSTEM);
734 			return (PO_FAIL);
735 		}
736 		if ((query.pq_io_buf = calloc(1,
737 		    (query.pq_io_bufsize < KERNEL_SNAPSHOT_BUF_SZ) ?
738 		    query.pq_io_bufsize * 2 : query.pq_io_bufsize)) == NULL) {
739 			pool_seterror(POE_SYSTEM);
740 			return (PO_FAIL);
741 		}
742 		if (ioctl(prov->pkc_fd, POOL_QUERY, &query) < 0) {
743 			free(query.pq_io_buf);
744 			if (errno != ENOMEM) {
745 				pool_seterror(POE_SYSTEM);
746 				return (PO_FAIL);
747 			}
748 			query.pq_io_bufsize = 0;
749 			query.pq_io_buf = NULL;
750 		} else
751 			break;
752 	}
753 	if (ea_unpack_object(&ep, EUP_NOALLOC, query.pq_io_buf,
754 	    query.pq_io_bufsize) != EO_GROUP) {
755 		free(query.pq_io_buf);
756 		pool_seterror(POE_DATASTORE);
757 		return (PO_FAIL);
758 	}
759 	/*
760 	 * Update the library snapshot
761 	 */
762 	psl.psl_changed = changed;
763 	prov->pkc_lotime = prov->pkc_ltime;
764 	if (load_group(conf, NULL, ep, &psl) != PO_SUCCESS) {
765 		free(query.pq_io_buf);
766 		ea_free_object(ep, EUP_NOALLOC);
767 		return (PO_FAIL);
768 	}
769 
770 	free(query.pq_io_buf);
771 	ea_free_object(ep, EUP_NOALLOC);
772 	/*
773 	 * Now search the dictionary for items that must be removed because
774 	 * they were neither created nor updated.
775 	 */
776 	if ((dead_map = dict_new((int (*)(const void *, const void *))
777 	    pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) {
778 		pool_seterror(POE_SYSTEM);
779 		return (PO_FAIL);
780 	}
781 	dict_map(prov->pkc_elements, find_dead_elems, dead_map);
782 
783 	if (dict_length(dead_map) > 0) {
784 		dict_map(dead_map, remove_dead_elems, NULL);
785 	}
786 	dict_free(&dead_map);
787 
788 	return (PO_SUCCESS);
789 }
790 
791 /*
792  * Rely on the kernel to always keep a kernel configuration valid.
793  * Returns PO_SUCCESS
794  */
795 /* ARGSUSED */
796 int
797 pool_knl_validate(const pool_conf_t *conf, pool_valid_level_t level)
798 {
799 	return ((conf->pc_state == POF_INVALID) ? PO_FAIL : PO_SUCCESS);
800 }
801 
802 /*
803  * Process all the outstanding transactions in the log. If the processing
804  * fails, then attempt to rollback and "undo" the changes.
805  */
806 int
807 pool_knl_commit(pool_conf_t *conf)
808 {
809 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
810 	int lock = 1;
811 
812 	/*
813 	 * Lock the kernel state for the commit
814 	 */
815 	if (ioctl(prov->pkc_fd, POOL_COMMIT, lock) < 0) {
816 		pool_seterror(POE_SYSTEM);
817 		return (PO_FAIL);
818 	}
819 	lock = 0;
820 	/*
821 	 * If the state is LS_FAIL, then try to recover before
822 	 * performing the commit.
823 	 */
824 	if (prov->pkc_log->l_state == LS_FAIL) {
825 		if (pool_knl_recover(conf) == PO_FAIL) {
826 			/*
827 			 * Unlock the kernel state for the
828 			 * commit. Assert that this * can't fail,
829 			 * since if it ever does fail the library is
830 			 * unusable.
831 			 */
832 			assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0);
833 		}
834 	}
835 	/*
836 	 * Commit the log
837 	 */
838 	if (log_walk(prov->pkc_log, log_item_commit) != PO_SUCCESS) {
839 		(void) pool_knl_recover(conf);
840 		/*
841 		 * Unlock the kernel state for the commit. Assert that
842 		 * this can't fail, since if it ever does fail the
843 		 * library is unusable.
844 		 */
845 		assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0);
846 		pool_seterror(POE_SYSTEM);
847 		return (PO_FAIL);
848 	}
849 	/*
850 	 * Unlock the kernel state for the commit. Assert that this
851 	 * can't fail, since if it ever does fail the library is
852 	 * unusable.
853 	 */
854 	assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0);
855 	/*
856 	 * Release the log resources
857 	 */
858 	(void) log_walk(prov->pkc_log, log_item_release);
859 	log_empty(prov->pkc_log);
860 	return (PO_SUCCESS);
861 }
862 
863 /*
864  * prop_build_cb() is designed to be called from
865  * pool_walk_properties(). The property value is used to put an XML
866  * property on the supplied ktx_node. This is an essential part of the
867  * mechanism used to export a kernel configuration in libpool XML
868  * form.
869  */
870 /* ARGSUSED */
871 static int
872 prop_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name,
873     pool_value_t *pval, void *user)
874 {
875 	struct knl_to_xml *info = (struct knl_to_xml *)user;
876 
877 	return (pool_knl_put_xml_property((pool_elem_t *)pe, info->ktx_node,
878 		name, pval));
879 }
880 
881 /*
882  * Duplicate some of the functionality from pool_xml_put_property()
883  * (see pool_xml.c) to allow a kernel configuration to add XML nodes
884  * to an XML tree which represents the kernel configuration. This is
885  * an essential part of the mechanism used to export a kernel
886  * configuration in libpool XML form.
887  */
888 int
889 pool_knl_put_xml_property(pool_elem_t *pe, xmlNodePtr node, const char *name,
890     const pool_value_t *val)
891 {
892 
893 	/*
894 	 * "type" is a special attribute which is not visible ever outside of
895 	 * libpool. Use the specific type accessor function.
896 	 */
897 	if (strcmp(name, c_type) == 0) {
898 		return (pool_xml_set_attr(node, BAD_CAST name,
899 		    val));
900 	}
901 	if (is_ns_property(pe, name) != NULL) {	/* in ns */
902 		if (pool_xml_set_attr(node,
903 		    BAD_CAST property_name_minus_ns(pe, name), val) == PO_FAIL)
904 			return (pool_xml_set_prop(node, BAD_CAST name,
905 			    val));
906 	} else
907 		return (pool_xml_set_prop(node, BAD_CAST name, val));
908 	return (PO_SUCCESS);
909 }
910 
911 /*
912  * Export the kernel configuration as an XML file. The configuration
913  * is used to build an XML document in memory. This document is then
914  * saved to the supplied location.
915  */
916 int
917 pool_knl_export(const pool_conf_t *conf, const char *location,
918     pool_export_format_t fmt)
919 {
920 	xmlNodePtr node_comment;
921 	xmlNodePtr system;
922 	int ret;
923 	pool_t **ps;
924 	pool_resource_t **rs;
925 	uint_t nelem;
926 	int i;
927 	struct knl_to_xml info;
928 	char_buf_t *cb = NULL;
929 	xmlValidCtxtPtr cvp;
930 
931 	xml_init();
932 
933 
934 	switch (fmt) {
935 	case POX_NATIVE:
936 		info.ktx_doc = xmlNewDoc(BAD_CAST "1.0");
937 		xmlCreateIntSubset(info.ktx_doc, BAD_CAST "system",
938 		    BAD_CAST "-//Sun Microsystems Inc//DTD Resource "
939 		    "Management All//EN",
940 		    BAD_CAST dtd_location);
941 
942 		if ((cvp = xmlNewValidCtxt()) == NULL) {
943 			xmlFreeDoc(info.ktx_doc);
944 			pool_seterror(POE_DATASTORE);
945 			return (PO_FAIL);
946 		}
947 		/*
948 		 * Call xmlValidateDocument() to force the parsing of
949 		 * the DTD. Ignore errors and warning messages as we
950 		 * know the document isn't valid.
951 		 */
952 		(void) xmlValidateDocument(cvp, info.ktx_doc);
953 		xmlFreeValidCtxt(cvp);
954 		if ((info.ktx_node = node_create(NULL, BAD_CAST "system")) ==
955 		    NULL) {
956 			xmlFreeDoc(info.ktx_doc);
957 			pool_seterror(POE_DATASTORE);
958 			return (PO_FAIL);
959 		}
960 
961 		system = info.ktx_node;
962 		info.ktx_doc->_private = (void *)conf;
963 
964 		xmlDocSetRootElement(info.ktx_doc, info.ktx_node);
965 		xmlSetProp(info.ktx_node, BAD_CAST c_ref_id, BAD_CAST "dummy");
966 		if ((node_comment = xmlNewDocComment(info.ktx_doc,
967 		    BAD_CAST "\nConfiguration for pools facility. Do NOT"
968 		    " edit this file by hand - use poolcfg(1)"
969 		    " or libpool(3POOL) instead.\n")) == NULL) {
970 			xmlFreeDoc(info.ktx_doc);
971 			pool_seterror(POE_DATASTORE);
972 			return (PO_FAIL);
973 		}
974 		if (xmlAddPrevSibling(info.ktx_node, node_comment) == NULL) {
975 			xmlFree(node_comment);
976 			xmlFreeDoc(info.ktx_doc);
977 			pool_seterror(POE_DATASTORE);
978 			return (PO_FAIL);
979 		}
980 		if (pool_walk_any_properties((pool_conf_t *)conf,
981 		    pool_conf_to_elem(conf), &info, prop_build_cb, 1) ==
982 		    PO_FAIL) {
983 			xmlFreeDoc(info.ktx_doc);
984 			return (PO_FAIL);
985 		}
986 		if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
987 			xmlFreeDoc(info.ktx_doc);
988 			return (PO_FAIL);
989 		}
990 		/*
991 		 * Now add pool details
992 		 */
993 		if ((ps = pool_query_pools(conf, &nelem, NULL)) != NULL) {
994 			for (i = 0; i < nelem; i++) {
995 				pool_elem_t *elem = TO_ELEM(ps[i]);
996 				uint_t nreselem;
997 				const char *sep = "";
998 				int j;
999 
1000 				if ((info.ktx_node = node_create(system,
1001 				    BAD_CAST element_class_tags
1002 				    [pool_elem_class(elem)])) == NULL) {
1003 					free(ps);
1004 					free_char_buf(cb);
1005 					xmlFreeDoc(info.ktx_doc);
1006 					pool_seterror(POE_DATASTORE);
1007 					return (PO_FAIL);
1008 				}
1009 				if (pool_walk_any_properties(
1010 				    (pool_conf_t *)conf,
1011 				    elem, &info, prop_build_cb, 1) == PO_FAIL) {
1012 					free(ps);
1013 					free_char_buf(cb);
1014 					xmlFreeDoc(info.ktx_doc);
1015 					return (PO_FAIL);
1016 				}
1017 				/*
1018 				 * TODO: pset specific res manipulation
1019 				 */
1020 				if ((rs = pool_query_pool_resources(conf, ps[i],
1021 				    &nreselem, NULL)) == NULL) {
1022 					free(ps);
1023 					free_char_buf(cb);
1024 					xmlFreeDoc(info.ktx_doc);
1025 					pool_seterror(POE_INVALID_CONF);
1026 					return (PO_FAIL);
1027 				}
1028 				if (set_char_buf(cb, "") == PO_FAIL) {
1029 					free(rs);
1030 					free(ps);
1031 					free_char_buf(cb);
1032 					xmlFreeDoc(info.ktx_doc);
1033 					return (PO_FAIL);
1034 				}
1035 				for (j = 0; j < nreselem; j++) {
1036 					pool_elem_t *reselem = TO_ELEM(rs[j]);
1037 					if (append_char_buf(cb, "%s%s_%d", sep,
1038 					    pool_elem_class_string(reselem),
1039 					    (int)elem_get_sysid(reselem)) ==
1040 					    PO_FAIL) {
1041 						free(rs);
1042 						free(ps);
1043 						free_char_buf(cb);
1044 						xmlFreeDoc(info.ktx_doc);
1045 						return (PO_FAIL);
1046 					}
1047 					sep = " ";
1048 				}
1049 				free(rs);
1050 				xmlSetProp(info.ktx_node, BAD_CAST "res",
1051 				    BAD_CAST cb->cb_buf);
1052 				if (set_char_buf(cb, "%s_%d",
1053 				    pool_elem_class_string(elem),
1054 				    (int)elem_get_sysid(elem)) == PO_FAIL) {
1055 					free(ps);
1056 					free_char_buf(cb);
1057 					xmlFreeDoc(info.ktx_doc);
1058 					return (PO_FAIL);
1059 				}
1060 				xmlSetProp(info.ktx_node, BAD_CAST c_ref_id,
1061 				    BAD_CAST  cb->cb_buf);
1062 			}
1063 			free(ps);
1064 		}
1065 		/*
1066 		 * Now add resource details (including components)
1067 		 */
1068 		if ((rs = pool_query_resources(conf, &nelem, NULL)) != NULL) {
1069 			for (i = 0; i < nelem; i++) {
1070 				pool_elem_t *elem = TO_ELEM(rs[i]);
1071 				pool_component_t **cs = NULL;
1072 				uint_t ncompelem;
1073 				int j;
1074 
1075 				if ((info.ktx_node = node_create(system,
1076 				    BAD_CAST element_class_tags
1077 				    [pool_elem_class(elem)])) == NULL) {
1078 					free(rs);
1079 					free_char_buf(cb);
1080 					xmlFreeDoc(info.ktx_doc);
1081 					pool_seterror(POE_DATASTORE);
1082 					return (PO_FAIL);
1083 				}
1084 				if (pool_walk_any_properties(
1085 				    (pool_conf_t *)conf,
1086 				    elem, &info, prop_build_cb, 1) == PO_FAIL) {
1087 					free(rs);
1088 					free_char_buf(cb);
1089 					xmlFreeDoc(info.ktx_doc);
1090 					return (PO_FAIL);
1091 				}
1092 				if (set_char_buf(cb, "%s_%d",
1093 				    pool_elem_class_string(elem),
1094 				    (int)elem_get_sysid(elem)) == PO_FAIL) {
1095 					free(rs);
1096 					free_char_buf(cb);
1097 					xmlFreeDoc(info.ktx_doc);
1098 					return (PO_FAIL);
1099 				}
1100 				xmlSetProp(info.ktx_node, BAD_CAST c_ref_id,
1101 				    BAD_CAST  cb->cb_buf);
1102 				if ((cs = pool_query_resource_components(conf,
1103 				    rs[i], &ncompelem, NULL)) != NULL) {
1104 					xmlNodePtr resource = info.ktx_node;
1105 
1106 					for (j = 0; j < ncompelem; j++) {
1107 						pool_elem_t *compelem =
1108 						    TO_ELEM(cs[j]);
1109 						if ((info.ktx_node =
1110 						    node_create(resource,
1111 						    BAD_CAST element_class_tags
1112 						    [pool_elem_class(
1113 						    compelem)])) == NULL) {
1114 							pool_seterror(
1115 							    POE_DATASTORE);
1116 							free(rs);
1117 							free(cs);
1118 							free_char_buf(cb);
1119 							xmlFreeDoc(info.
1120 							    ktx_doc);
1121 							return (PO_FAIL);
1122 						}
1123 						if (pool_walk_any_properties(
1124 						    (pool_conf_t *)conf,
1125 						    compelem, &info,
1126 						    prop_build_cb, 1) ==
1127 						    PO_FAIL) {
1128 							free(rs);
1129 							free(cs);
1130 							free_char_buf(cb);
1131 							xmlFreeDoc(info.
1132 							    ktx_doc);
1133 							return (PO_FAIL);
1134 						}
1135 						if (set_char_buf(cb, "%s_%d",
1136 						    pool_elem_class_string(
1137 						    compelem),
1138 						    (int)elem_get_sysid(
1139 						    compelem)) == PO_FAIL) {
1140 							free(rs);
1141 							free(cs);
1142 							free_char_buf(cb);
1143 							xmlFreeDoc(info.
1144 							    ktx_doc);
1145 							return (PO_FAIL);
1146 						}
1147 						xmlSetProp(info.ktx_node,
1148 						    BAD_CAST c_ref_id,
1149 						    BAD_CAST  cb->cb_buf);
1150 					}
1151 					free(cs);
1152 				}
1153 			}
1154 			free(rs);
1155 		}
1156 		free_char_buf(cb);
1157 		/*
1158 		 * Set up the message handlers prior to calling
1159 		 * xmlValidateDocument()
1160 		 */
1161 		if ((cvp = xmlNewValidCtxt()) == NULL) {
1162 			xmlFreeDoc(info.ktx_doc);
1163 			pool_seterror(POE_DATASTORE);
1164 			return (PO_FAIL);
1165 		}
1166 		cvp->error    = pool_error_func;
1167 		cvp->warning  = pool_error_func;
1168 		if (xmlValidateDocument(cvp, info.ktx_doc) == 0) {
1169 			xmlFreeValidCtxt(cvp);
1170 			xmlFreeDoc(info.ktx_doc);
1171 			pool_seterror(POE_INVALID_CONF);
1172 			return (PO_FAIL);
1173 		}
1174 		xmlFreeValidCtxt(cvp);
1175 		ret = xmlSaveFormatFile(location, info.ktx_doc, 1);
1176 		xmlFreeDoc(info.ktx_doc);
1177 		if (ret == -1) {
1178 			pool_seterror(POE_SYSTEM);
1179 			return (PO_FAIL);
1180 		}
1181 		return (PO_SUCCESS);
1182 	default:
1183 		pool_seterror(POE_BADPARAM);
1184 		return (PO_FAIL);
1185 	}
1186 }
1187 
1188 /*
1189  * Rollback the changes to the kernel
1190  */
1191 int
1192 pool_knl_recover(pool_conf_t *conf)
1193 {
1194 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1195 
1196 	prov->pkc_log->l_state = LS_RECOVER;
1197 	if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) {
1198 		dprintf("Library configuration consistency error\n");
1199 		prov->pkc_log->l_state = LS_FAIL;
1200 		pool_seterror(POE_INVALID_CONF);
1201 		return (PO_FAIL);
1202 	}
1203 	prov->pkc_log->l_state = LS_DO;
1204 	return (PO_SUCCESS);
1205 }
1206 
1207 /*
1208  * Rollback the changes to the configuration
1209  */
1210 int
1211 pool_knl_rollback(pool_conf_t *conf)
1212 {
1213 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1214 
1215 	prov->pkc_log->l_state = LS_UNDO;
1216 	if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) {
1217 		dprintf("Kernel configuration consistency error\n");
1218 		(void) log_walk(prov->pkc_log, log_item_release);
1219 		log_empty(prov->pkc_log);
1220 		prov->pkc_log->l_state = LS_FAIL;
1221 		pool_seterror(POE_INVALID_CONF);
1222 		return (PO_FAIL);
1223 	}
1224 	(void) log_walk(prov->pkc_log, log_item_release);
1225 	log_empty(prov->pkc_log);
1226 	prov->pkc_log->l_state = LS_DO;
1227 	return (PO_SUCCESS);
1228 }
1229 
1230 /*
1231  * Callback used to build the result set for a query. Each invocation will
1232  * supply a candidate element for inclusion. The element is filtered by:
1233  * - class
1234  * - properties
1235  * If the element "matches" the target, then it is added to the result
1236  * set, otherwise it is ignored.
1237  */
1238 /* ARGSUSED1 */
1239 static void
1240 build_result_set(const void *key, void **value, void *cl)
1241 {
1242 	struct query_obj *qo = (struct query_obj *)cl;
1243 	pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
1244 
1245 	/*
1246 	 * Check to see if it's the right class of element
1247 	 */
1248 	if (qo->classes & (1 << pool_elem_class((pool_elem_t *)key))) {
1249 		int i;
1250 		/*
1251 		 * Now check to see if the src element is correct. If no src
1252 		 * element is supplied, ignore this check
1253 		 */
1254 		if (qo->src) {
1255 			pool_knl_elem_t *parent;
1256 
1257 			for (parent = pke; parent != NULL;
1258 			    parent = parent->pke_parent) {
1259 				if (parent == (pool_knl_elem_t *)qo->src)
1260 					break;
1261 			}
1262 			if (parent == NULL)
1263 				return;
1264 		}
1265 		/*
1266 		 * Now check for property matches (if there are any specified)
1267 		 */
1268 		if (qo->props) {
1269 			int matched = PO_TRUE;
1270 			for (i = 0; qo->props[i] != NULL; i++) {
1271 				pool_value_t val = POOL_VALUE_INITIALIZER;
1272 
1273 				if (pool_get_property(TO_CONF(TO_ELEM(pke)),
1274 				    (pool_elem_t *)pke,
1275 				    pool_value_get_name(qo->props[i]), &val) ==
1276 				    POC_INVAL) {
1277 					matched = PO_FALSE;
1278 					break;
1279 				} else {
1280 					if (pool_value_equal(qo->props[i],
1281 					    &val) != PO_TRUE) {
1282 						matched = PO_FALSE;
1283 						break;
1284 					}
1285 				}
1286 			}
1287 			if (matched == PO_TRUE)
1288 				(void) pool_knl_result_set_append(qo->rs,
1289 				(pool_knl_elem_t *)key);
1290 		} else {
1291 			(void) pool_knl_result_set_append(qo->rs,
1292 			    (pool_knl_elem_t *)key);
1293 		}
1294 	}
1295 }
1296 
1297 /*
1298  * Execute the supplied query and return a result set which contains
1299  * all qualifying elements.
1300  */
1301 pool_result_set_t *
1302 pool_knl_exec_query(const pool_conf_t *conf, const pool_elem_t *src,
1303     const char *src_attr, pool_elem_class_t classes, pool_value_t **props)
1304 {
1305 	pool_knl_result_set_t *rs;
1306 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1307 	struct query_obj qo;
1308 	int matched = PO_TRUE;
1309 
1310 	/*
1311 	 * Have a buffer at this point, that we can use
1312 	 */
1313 	if ((rs = pool_knl_result_set_alloc(conf)) == NULL) {
1314 		return (NULL);
1315 	}
1316 	qo.conf = conf;
1317 	qo.src = src;
1318 	qo.src_attr = src_attr;
1319 	qo.classes = classes;
1320 	qo.props = props;
1321 	qo.rs = rs;
1322 	if (src_attr != NULL) {
1323 		pool_knl_pool_t *pkp = (pool_knl_pool_t *)src;
1324 
1325 		/*
1326 		 * Note: This logic is resource specific and must be
1327 		 * extended for additional resource types.
1328 		 */
1329 		/*
1330 		 * Check for property matches (if there are any specified)
1331 		 */
1332 		if (props) {
1333 			int i;
1334 
1335 			for (i = 0; props[i] != NULL; i++) {
1336 				pool_value_t val = POOL_VALUE_INITIALIZER;
1337 
1338 				if (pool_get_property(conf,
1339 				    (pool_elem_t *)pkp->pkp_assoc[PREC_PSET],
1340 				    pool_value_get_name(props[i]), &val) ==
1341 				    POC_INVAL) {
1342 					matched = PO_FALSE;
1343 					break;
1344 				} else {
1345 					if (pool_value_equal(props[i],
1346 					    &val) != PO_TRUE) {
1347 						matched = PO_FALSE;
1348 						break;
1349 					}
1350 				}
1351 			}
1352 		}
1353 
1354 		if (matched == PO_TRUE)
1355 			(void) pool_knl_result_set_append(rs,
1356 			    (pool_knl_elem_t *)pkp->pkp_assoc[PREC_PSET]);
1357 	} else
1358 		dict_map(prov->pkc_elements, build_result_set, &qo);
1359 
1360 	if (rs->pkr_count == 0)
1361 		pool_seterror(POE_INVALID_SEARCH);
1362 	return ((pool_result_set_t *)rs);
1363 }
1364 
1365 /*
1366  * Callback function intended to be used from pool_walk_pools(). If
1367  * the supplied pool is not the default pool attempt to destroy it.
1368  */
1369 /*ARGSUSED*/
1370 static int
1371 destroy_pool_cb(pool_conf_t *conf, pool_t *pool, void *unused)
1372 {
1373 	if (elem_is_default(TO_ELEM(pool)) != PO_TRUE)
1374 		return (pool_destroy(conf, pool));
1375 	/*
1376 	 * Return PO_SUCCESS even though we don't delete the default
1377 	 * pool so that the walk continues
1378 	 */
1379 	return (PO_SUCCESS);
1380 }
1381 
1382 /*
1383  * Remove the configuration details. This means remove all elements
1384  * apart from the system elements.
1385  */
1386 int
1387 pool_knl_remove(pool_conf_t *conf)
1388 {
1389 	uint_t i, nelem;
1390 	pool_resource_t **resources;
1391 
1392 	conf->pc_state = POF_DESTROY;
1393 	if ((resources = pool_query_resources(conf, &nelem, NULL)) != NULL) {
1394 		for (i = 0; i < nelem; i++) {
1395 			if (resource_is_system(resources[i]) == PO_FALSE)
1396 				if (pool_resource_destroy(conf, resources[i]) !=
1397 				    PO_SUCCESS) {
1398 					pool_seterror(POE_INVALID_CONF);
1399 					return (PO_FAIL);
1400 				}
1401 		}
1402 		free(resources);
1403 	}
1404 	(void) pool_walk_pools(conf, conf, destroy_pool_cb);
1405 	if (pool_conf_commit(conf, PO_FALSE) != PO_SUCCESS)
1406 		return (PO_FAIL);
1407 
1408 	if (pool_conf_close(conf) != PO_SUCCESS)
1409 		return (PO_FAIL);
1410 
1411 	return (PO_SUCCESS);
1412 }
1413 
1414 /*
1415  * Determine the name of the pool to which the supplied pid is
1416  * bound. If it cannot be determined return NULL.
1417  */
1418 char *
1419 pool_knl_get_binding(pool_conf_t *conf, pid_t pid)
1420 {
1421 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1422 	const char *sval;
1423 	char *name = NULL;
1424 	pool_bindq_t bindq;
1425 	pool_value_t *props[] = { NULL, NULL };
1426 	uint_t nelem = 0;
1427 	pool_t **pools;
1428 	pool_value_t val = POOL_VALUE_INITIALIZER;
1429 
1430 	props[0] = &val;
1431 
1432 	bindq.pb_o_id_type = P_PID;
1433 	bindq.pb_o_id = pid;
1434 	if (ioctl(prov->pkc_fd, POOL_BINDQ, &bindq) < 0) {
1435 		pool_seterror(POE_SYSTEM);
1436 		return (NULL);
1437 	}
1438 
1439 	if (pool_value_set_name(props[0], "pool.sys_id") != PO_SUCCESS) {
1440 		return (NULL);
1441 	}
1442 	pool_value_set_int64(props[0], bindq.pb_i_id);
1443 	if ((pools = pool_query_pools(conf, &nelem, props)) == NULL) {
1444 		pool_seterror(POE_BADPARAM);
1445 		return (NULL);
1446 	}
1447 
1448 	if (nelem != 1) {
1449 		free(pools);
1450 		pool_seterror(POE_INVALID_CONF);
1451 		return (NULL);
1452 	}
1453 	if (pool_get_ns_property(TO_ELEM(pools[0]), c_name, props[0])
1454 	    == POC_INVAL) {
1455 		free(pools);
1456 		return (NULL);
1457 	}
1458 	if (pool_value_get_string(props[0], &sval) != PO_SUCCESS) {
1459 		free(pools);
1460 		return (NULL);
1461 	}
1462 	if ((name = strdup(sval)) == NULL) {
1463 		free(pools);
1464 		pool_seterror(POE_SYSTEM);
1465 		return (NULL);
1466 	}
1467 	return (name);
1468 }
1469 
1470 /*
1471  * Bind idtype id to the pool name.
1472  */
1473 int
1474 pool_knl_set_binding(pool_conf_t *conf, const char *pool_name, idtype_t idtype,
1475     id_t id)
1476 {
1477 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1478 	pool_bind_t bind;
1479 	pool_t *pool;
1480 	int ret;
1481 
1482 	if ((pool = pool_get_pool(conf, pool_name)) == NULL)
1483 		return (PO_FAIL);
1484 
1485 	bind.pb_o_id_type = idtype;
1486 	bind.pb_o_id = id;
1487 	bind.pb_o_pool_id = elem_get_sysid(TO_ELEM(pool));
1488 
1489 	while ((ret = ioctl(prov->pkc_fd, POOL_BIND, &bind)) < 0 &&
1490 	    errno == EAGAIN);
1491 	if (ret < 0) {
1492 		pool_seterror(POE_SYSTEM);
1493 		return (PO_FAIL);
1494 	}
1495 	return (PO_SUCCESS);
1496 }
1497 
1498 /*
1499  * pool_knl_get_resource_binding() returns the binding for a pid to
1500  * the supplied type of resource. If a binding cannot be determined,
1501  * NULL is returned.
1502  */
1503 char *
1504 pool_knl_get_resource_binding(pool_conf_t *conf,
1505     pool_resource_elem_class_t type, pid_t pid)
1506 {
1507 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1508 	const char *sval;
1509 	char *name = NULL;
1510 	pool_bindq_t bindq;
1511 	pool_value_t *props[] = { NULL, NULL };
1512 	uint_t nelem = 0;
1513 	pool_t **pools;
1514 	pool_resource_t **resources;
1515 	pool_value_t val = POOL_VALUE_INITIALIZER;
1516 
1517 	props[0] = &val;
1518 	bindq.pb_o_id_type = P_PID;
1519 	bindq.pb_o_id = pid;
1520 	if (ioctl(prov->pkc_fd, POOL_BINDQ, &bindq) < 0) {
1521 		pool_seterror(POE_SYSTEM);
1522 		return (NULL);
1523 	}
1524 
1525 	if (pool_value_set_name(props[0], "pool.sys_id") != PO_SUCCESS) {
1526 		return (NULL);
1527 	}
1528 	pool_value_set_int64(props[0], bindq.pb_i_id);
1529 	if ((pools = pool_query_pools(conf, &nelem, props)) == NULL) {
1530 		pool_seterror(POE_BADPARAM);
1531 		return (NULL);
1532 	}
1533 
1534 	if (nelem != 1) {
1535 		free(pools);
1536 		pool_seterror(POE_INVALID_CONF);
1537 		return (NULL);
1538 	}
1539 
1540 	if (pool_value_set_string(props[0], pool_resource_type_string(type)) !=
1541 	    PO_SUCCESS ||
1542 	    pool_value_set_name(props[0], c_type) != PO_SUCCESS) {
1543 		free(pools);
1544 		return (NULL);
1545 	}
1546 
1547 	if ((resources = pool_query_pool_resources(conf, pools[0], &nelem,
1548 	    NULL)) == NULL) {
1549 		free(pools);
1550 		pool_seterror(POE_INVALID_CONF);
1551 		return (NULL);
1552 	}
1553 	free(pools);
1554 	if (nelem != 1) {
1555 		free(resources);
1556 		pool_seterror(POE_INVALID_CONF);
1557 		return (NULL);
1558 	}
1559 	if (pool_get_ns_property(TO_ELEM(resources[0]), c_name, props[0]) ==
1560 	    POC_INVAL) {
1561 		free(resources);
1562 		return (NULL);
1563 	}
1564 	free(resources);
1565 	if (pool_value_get_string(props[0], &sval) != PO_SUCCESS) {
1566 		return (NULL);
1567 	}
1568 	if ((name = strdup(sval)) == NULL) {
1569 		pool_seterror(POE_SYSTEM);
1570 		return (NULL);
1571 	}
1572 	return (name);
1573 }
1574 
1575 /*
1576  * Allocate the required library data structure and initialise it.
1577  */
1578 pool_knl_elem_t *
1579 pool_knl_elem_wrap(pool_conf_t *conf, pool_elem_class_t class,
1580     pool_resource_elem_class_t res_class,
1581     pool_component_elem_class_t comp_class)
1582 {
1583 	pool_knl_elem_t *elem;
1584 	pool_elem_t *pe;
1585 
1586 	switch (class) {
1587 	case PEC_SYSTEM:
1588 		if ((elem = malloc(sizeof (pool_knl_system_t))) == NULL) {
1589 			pool_seterror(POE_SYSTEM);
1590 			return (NULL);
1591 		}
1592 		(void) memset(elem, 0, sizeof (pool_knl_system_t));
1593 		break;
1594 	case PEC_POOL:
1595 		if ((elem = malloc(sizeof (pool_knl_pool_t))) == NULL) {
1596 			pool_seterror(POE_SYSTEM);
1597 			return (NULL);
1598 		}
1599 		(void) memset(elem, 0, sizeof (pool_knl_pool_t));
1600 		break;
1601 	case PEC_RES_COMP:
1602 	case PEC_RES_AGG:
1603 		if ((elem = malloc(sizeof (pool_knl_resource_t))) == NULL) {
1604 			pool_seterror(POE_SYSTEM);
1605 			return (NULL);
1606 		}
1607 		(void) memset(elem, 0, sizeof (pool_knl_resource_t));
1608 		break;
1609 	case PEC_COMP:
1610 		if ((elem = malloc(sizeof (pool_knl_component_t))) == NULL) {
1611 			pool_seterror(POE_SYSTEM);
1612 			return (NULL);
1613 		}
1614 		(void) memset(elem, 0, sizeof (pool_knl_component_t));
1615 		break;
1616 	default:
1617 		pool_seterror(POE_BADPARAM);
1618 		return (NULL);
1619 	}
1620 	pe = TO_ELEM(elem);
1621 	pe->pe_conf = conf;
1622 	pe->pe_class = class;
1623 	pe->pe_resource_class = res_class;
1624 	pe->pe_component_class = comp_class;
1625 	/* Set up the function pointers for element manipulation */
1626 	pe->pe_get_prop = pool_knl_get_property;
1627 	pe->pe_put_prop = pool_knl_put_property;
1628 	pe->pe_rm_prop = pool_knl_rm_property;
1629 	pe->pe_get_props = pool_knl_get_properties;
1630 	pe->pe_remove = pool_knl_elem_remove;
1631 	pe->pe_get_container = pool_knl_get_container;
1632 	pe->pe_set_container = pool_knl_set_container;
1633 	/*
1634 	 * Specific initialisation for different types of element
1635 	 */
1636 	if (class == PEC_POOL) {
1637 		pool_knl_pool_t *pp = (pool_knl_pool_t *)elem;
1638 		pp->pp_associate = pool_knl_pool_associate;
1639 		pp->pp_dissociate = pool_knl_pool_dissociate;
1640 		pp->pkp_assoc[PREC_PSET] = (pool_knl_resource_t *)
1641 		    resource_by_sysid(conf, PS_NONE, "pset");
1642 	}
1643 	if (class == PEC_RES_COMP || class == PEC_RES_AGG) {
1644 		pool_knl_resource_t *pr = (pool_knl_resource_t *)elem;
1645 		pr->pr_is_system = pool_knl_resource_is_system;
1646 		pr->pr_can_associate = pool_knl_resource_can_associate;
1647 	}
1648 #if DEBUG
1649 	if (dict_put(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks,
1650 	    elem, elem) != NULL)
1651 		assert(!"leak map put failed");
1652 	dprintf("allocated %p\n", elem);
1653 #endif	/* DEBUG */
1654 	return (elem);
1655 }
1656 
1657 /*
1658  * Allocate a new pool_knl_elem_t in the supplied configuration of the
1659  * specified class.
1660  * Returns element pointer/NULL
1661  */
1662 pool_elem_t *
1663 pool_knl_elem_create(pool_conf_t *conf, pool_elem_class_t class,
1664     pool_resource_elem_class_t res_class,
1665     pool_component_elem_class_t comp_class)
1666 {
1667 	pool_knl_elem_t *elem;
1668 	pool_create_undo_t *create;
1669 	pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1670 	static int id = -3;
1671 	char_buf_t *cb;
1672 
1673 	if ((elem = pool_knl_elem_wrap(conf, class, res_class, comp_class)) ==
1674 	    NULL)
1675 		return (NULL);
1676 
1677 	/*
1678 	 * Allocate an nvlist to hold properties
1679 	 */
1680 	if (nvlist_alloc(&elem->pke_properties, NV_UNIQUE_NAME_TYPE, 0) != 0) {
1681 		pool_knl_elem_free(elem, PO_FALSE);
1682 		pool_seterror(POE_SYSTEM);
1683 		return (NULL);
1684 	}
1685 	/*
1686 	 * Allocate a temporary ID and name until the element is
1687 	 * created for real
1688 	 */
1689 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1690 		pool_knl_elem_free(elem, PO_TRUE);
1691 		return (NULL);
1692 	}
1693 	if (set_char_buf(cb, "%s.sys_id",
1694 	    pool_elem_class_string((pool_elem_t *)elem)) != PO_SUCCESS) {
1695 		pool_knl_elem_free(elem, PO_TRUE);
1696 		free_char_buf(cb);
1697 		return (NULL);
1698 	}
1699 	(void) nvlist_add_int64(elem->pke_properties, cb->cb_buf, id--);
1700 	if (set_char_buf(cb, "%s.name",
1701 	    pool_elem_class_string((pool_elem_t *)elem)) != PO_SUCCESS) {
1702 		pool_knl_elem_free(elem, PO_TRUE);
1703 		free_char_buf(cb);
1704 		return (NULL);
1705 	}
1706 	(void) nvlist_add_string(elem->pke_properties, cb->cb_buf, "");
1707 	/*
1708 	 * If it's a resource class, it will need an initial size
1709 	 */
1710 	if (class == PEC_RES_COMP || class == PEC_RES_AGG) {
1711 		if (set_char_buf(cb, "%s.size",
1712 		    pool_elem_class_string((pool_elem_t *)elem)) !=
1713 		    PO_SUCCESS) {
1714 			pool_knl_elem_free(elem, PO_TRUE);
1715 			free_char_buf(cb);
1716 			return (NULL);
1717 		}
1718 		(void) nvlist_add_uint64(elem->pke_properties, cb->cb_buf, 0);
1719 	}
1720 	free_char_buf(cb);
1721 
1722 	/*
1723 	 * Register the newly created element
1724 	 */
1725 	if (dict_put(prov->pkc_elements, elem, elem) != NULL) {
1726 		pool_knl_elem_free(elem, PO_TRUE);
1727 		pool_seterror(POE_SYSTEM);
1728 		return (NULL);
1729 	}
1730 
1731 	if (prov->pkc_log->l_state != LS_DO)
1732 		return ((pool_elem_t *)elem);
1733 
1734 	/*
1735 	 * The remaining logic is setting up the arguments for the
1736 	 * POOL_CREATE ioctl and appending the details into the log.
1737 	 */
1738 	if ((create = malloc(sizeof (pool_create_undo_t))) == NULL) {
1739 		pool_seterror(POE_SYSTEM);
1740 		return (NULL);
1741 	}
1742 	create->pcu_ioctl.pc_o_type = class;
1743 	switch (class) {
1744 	case PEC_SYSTEM:
1745 		pool_seterror(POE_BADPARAM);
1746 		free(create);
1747 		return (NULL);
1748 	case PEC_POOL: /* NO-OP */
1749 		break;
1750 	case PEC_RES_COMP:
1751 	case PEC_RES_AGG:
1752 		create->pcu_ioctl.pc_o_sub_type = res_class;
1753 		break;
1754 	case PEC_COMP:
1755 		create->pcu_ioctl.pc_o_sub_type = comp_class;
1756 		break;
1757 	default:
1758 		pool_seterror(POE_BADPARAM);
1759 		free(create);
1760 		return (NULL);
1761 	}
1762 
1763 	create->pcu_elem = (pool_elem_t *)elem;
1764 
1765 	if (log_append(prov->pkc_log, POOL_CREATE, (void *)create) !=
1766 	    PO_SUCCESS) {
1767 		free(create);
1768 		return (NULL);
1769 	}
1770 	return ((pool_elem_t *)elem);
1771 }
1772 
1773 /*
1774  * Remove the details of the element from our userland copy and destroy
1775  * the element (if appropriate) in the kernel.
1776  */
1777 int
1778 pool_knl_elem_remove(pool_elem_t *pe)
1779 {
1780 	pool_knl_connection_t *prov;
1781 	pool_destroy_undo_t *destroy;
1782 
1783 	prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
1784 
1785 	if (dict_remove(prov->pkc_elements, pe) == NULL) {
1786 		pool_seterror(POE_SYSTEM);
1787 		return (PO_FAIL);
1788 	}
1789 	if (prov->pkc_log->l_state != LS_DO) {
1790 		return (PO_SUCCESS);
1791 	}
1792 
1793 	/*
1794 	 * The remaining logic is setting up the arguments for the
1795 	 * POOL_DESTROY ioctl and appending the details into the log.
1796 	 */
1797 	if ((destroy = malloc(sizeof (pool_destroy_undo_t))) == NULL) {
1798 		pool_seterror(POE_SYSTEM);
1799 		return (PO_FAIL);
1800 	}
1801 	destroy->pdu_ioctl.pd_o_type = pool_elem_class(pe);
1802 
1803 	if (destroy->pdu_ioctl.pd_o_type == PEC_RES_COMP ||
1804 	    destroy->pdu_ioctl.pd_o_type == PEC_RES_AGG)
1805 		destroy->pdu_ioctl.pd_o_sub_type = pool_resource_elem_class(pe);
1806 
1807 	if (destroy->pdu_ioctl.pd_o_type == PEC_COMP)
1808 		destroy->pdu_ioctl.pd_o_sub_type =
1809 		    pool_component_elem_class(pe);
1810 
1811 	destroy->pdu_elem = pe;
1812 
1813 	if (log_append(prov->pkc_log, POOL_DESTROY, (void *)destroy) !=
1814 	    PO_SUCCESS) {
1815 		free(destroy);
1816 		return (PO_FAIL);
1817 	}
1818 	return (PO_SUCCESS);
1819 }
1820 
1821 /*
1822  * Set the parent of the supplied child to the supplied parent
1823  */
1824 int
1825 pool_knl_set_container(pool_elem_t *pp, pool_elem_t *pc)
1826 {
1827 	pool_knl_elem_t *pkp = (pool_knl_elem_t *)pp;
1828 	pool_knl_elem_t *pkc = (pool_knl_elem_t *)pc;
1829 
1830 	pkc->pke_parent = pkp;
1831 	return (PO_SUCCESS);
1832 }
1833 
1834 /*
1835  * TODO: Needed for msets and ssets.
1836  */
1837 /* ARGSUSED */
1838 int
1839 pool_knl_res_transfer(pool_resource_t *src, pool_resource_t *tgt,
1840     uint64_t size) {
1841 	return (PO_FAIL);
1842 }
1843 
1844 /*
1845  * Transfer resource components from one resource set to another.
1846  */
1847 int
1848 pool_knl_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt,
1849     pool_component_t **rl) {
1850 	pool_elem_t *src_e = TO_ELEM(src);
1851 	pool_elem_t *tgt_e = TO_ELEM(tgt);
1852 	pool_xtransfer_undo_t *xtransfer;
1853 	size_t size;
1854 	pool_knl_connection_t *prov =
1855 	    (pool_knl_connection_t *)TO_CONF(src_e)->pc_prov;
1856 
1857 	if (prov->pkc_log->l_state != LS_DO) {
1858 		/*
1859 		 * Walk the Result Set and move the resource components
1860 		 */
1861 		for (size = 0; rl[size] != NULL; size++) {
1862 			if (pool_set_container(TO_ELEM(tgt),
1863 			    TO_ELEM(rl[size])) == PO_FAIL) {
1864 				return (PO_FAIL);
1865 			}
1866 		}
1867 		return (PO_SUCCESS);
1868 	}
1869 
1870 	/*
1871 	 * The remaining logic is setting up the arguments for the
1872 	 * POOL_XTRANSFER ioctl and appending the details into the log.
1873 	 */
1874 	if ((xtransfer = malloc(sizeof (pool_xtransfer_undo_t))) == NULL) {
1875 		pool_seterror(POE_SYSTEM);
1876 		return (PO_FAIL);
1877 	}
1878 
1879 	if (pool_elem_class(src_e) == PEC_RES_COMP) {
1880 		xtransfer->pxu_ioctl.px_o_id_type =
1881 		    pool_resource_elem_class(src_e);
1882 	} else {
1883 		pool_seterror(POE_BADPARAM);
1884 		return (PO_FAIL);
1885 	}
1886 
1887 
1888 	for (xtransfer->pxu_ioctl.px_o_complist_size = 0;
1889 	    rl[xtransfer->pxu_ioctl.px_o_complist_size] != NULL;
1890 	    xtransfer->pxu_ioctl.px_o_complist_size++)
1891 		/* calculate the size using the terminating NULL */;
1892 	if ((xtransfer->pxu_ioctl.px_o_comp_list =
1893 		calloc(xtransfer->pxu_ioctl.px_o_complist_size,
1894 		sizeof (id_t))) == NULL) {
1895 		pool_seterror(POE_SYSTEM);
1896 		return (PO_FAIL);
1897 	}
1898 	if ((xtransfer->pxu_rl = calloc(
1899 	    xtransfer->pxu_ioctl.px_o_complist_size + 1,
1900 	    sizeof (pool_component_t *))) == NULL) {
1901 		pool_seterror(POE_SYSTEM);
1902 		return (PO_FAIL);
1903 	}
1904 	(void) memcpy(xtransfer->pxu_rl, rl,
1905 	    xtransfer->pxu_ioctl.px_o_complist_size *
1906 	    sizeof (pool_component_t *));
1907 	xtransfer->pxu_src = src_e;
1908 	xtransfer->pxu_tgt = tgt_e;
1909 
1910 	if (log_append(prov->pkc_log, POOL_XTRANSFER, (void *)xtransfer) !=
1911 	    PO_SUCCESS) {
1912 		free(xtransfer);
1913 		return (PO_FAIL);
1914 	}
1915 	for (size = 0; rl[size] != NULL; size++) {
1916 		if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[size])) ==
1917 		    PO_FAIL) {
1918 			return (PO_FAIL);
1919 		}
1920 	}
1921 	return (PO_SUCCESS);
1922 }
1923 
1924 /*
1925  * Return the parent of an element.
1926  */
1927 pool_elem_t *
1928 pool_knl_get_container(const pool_elem_t *pe)
1929 {
1930 	pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
1931 
1932 	return ((pool_elem_t *)pke->pke_parent);
1933 }
1934 
1935 /*
1936  * Note: This function is resource specific, needs extending for other
1937  * resource types
1938  */
1939 int
1940 pool_knl_resource_is_system(const pool_resource_t *pr)
1941 {
1942 	switch (pool_resource_elem_class(TO_ELEM(pr))) {
1943 	case PREC_PSET:
1944 		return (PSID_IS_SYSSET(
1945 		    elem_get_sysid(TO_ELEM(pr))));
1946 	default:
1947 		return (PO_FALSE);
1948 	}
1949 }
1950 
1951 /*
1952  * Note: This function is resource specific, needs extending for other
1953  * resource types
1954  */
1955 int
1956 pool_knl_resource_can_associate(const pool_resource_t *pr)
1957 {
1958 	switch (pool_resource_elem_class(TO_ELEM(pr))) {
1959 	case PREC_PSET:
1960 		return (PO_TRUE);
1961 	default:
1962 		return (PO_FALSE);
1963 	}
1964 }
1965 
1966 /*
1967  * pool_knl_pool_associate() associates the supplied resource to the
1968  * supplied pool.
1969  *
1970  * Returns: PO_SUCCESS/PO_FAIL
1971  */
1972 int
1973 pool_knl_pool_associate(pool_t *pool, const pool_resource_t *resource)
1974 {
1975 	pool_knl_connection_t *prov;
1976 	pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool;
1977 	pool_resource_elem_class_t res_class =
1978 	    pool_resource_elem_class(TO_ELEM(resource));
1979 	pool_assoc_undo_t *assoc;
1980 	pool_knl_resource_t *orig_res = pkp->pkp_assoc[res_class];
1981 
1982 	/*
1983 	 * Are we allowed to associate with this target?
1984 	 */
1985 	if (pool_knl_resource_can_associate(resource) == PO_FALSE) {
1986 		pool_seterror(POE_BADPARAM);
1987 		return (PO_FAIL);
1988 	}
1989 	prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov;
1990 
1991 	if (prov->pkc_log->l_state != LS_DO) {
1992 		pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource;
1993 		return (PO_SUCCESS);
1994 	}
1995 
1996 	/*
1997 	 * The remaining logic is setting up the arguments for the
1998 	 * POOL_ASSOC ioctl and appending the details into the log.
1999 	 */
2000 	if ((assoc = malloc(sizeof (pool_assoc_undo_t))) == NULL) {
2001 		pool_seterror(POE_SYSTEM);
2002 		return (PO_FAIL);
2003 	}
2004 	assoc->pau_assoc = TO_ELEM(pool);
2005 	assoc->pau_oldres = (pool_elem_t *)orig_res;
2006 	assoc->pau_newres = TO_ELEM(resource);
2007 
2008 	assoc->pau_ioctl.pa_o_id_type = res_class;
2009 
2010 	if (log_append(prov->pkc_log, POOL_ASSOC, (void *)assoc) !=
2011 	    PO_SUCCESS) {
2012 		free(assoc);
2013 		pkp->pkp_assoc[res_class] = orig_res;
2014 		return (PO_FAIL);
2015 	}
2016 	pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource;
2017 	return (PO_SUCCESS);
2018 }
2019 
2020 /*
2021  * pool_knl_pool_dissociate() dissociates the supplied resource from
2022  * the supplied pool.
2023  *
2024  * Returns: PO_SUCCESS/PO_FAIL
2025  */
2026 int
2027 pool_knl_pool_dissociate(pool_t *pool, const pool_resource_t *resource)
2028 {
2029 	pool_knl_connection_t *prov;
2030 	pool_dissoc_undo_t *dissoc;
2031 	pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool;
2032 	pool_resource_t *default_res = (pool_resource_t *)get_default_resource(
2033 	    resource);
2034 	pool_resource_elem_class_t res_class =
2035 	    pool_resource_elem_class(TO_ELEM(resource));
2036 
2037 	prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov;
2038 
2039 	if (prov->pkc_log->l_state != LS_DO) {
2040 		pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res;
2041 		return (PO_SUCCESS);
2042 	}
2043 	/*
2044 	 * The remaining logic is setting up the arguments for the
2045 	 * POOL_DISSOC ioctl and appending the details into the log.
2046 	 */
2047 	if ((dissoc = malloc(sizeof (pool_dissoc_undo_t))) == NULL) {
2048 		pool_seterror(POE_SYSTEM);
2049 		return (PO_FAIL);
2050 	}
2051 	dissoc->pdu_dissoc = TO_ELEM(pool);
2052 	dissoc->pdu_oldres = TO_ELEM(resource);
2053 	dissoc->pdu_newres = TO_ELEM(default_res);
2054 
2055 	dissoc->pdu_ioctl.pd_o_id_type = res_class;
2056 
2057 	if (log_append(prov->pkc_log, POOL_DISSOC, (void *)dissoc) !=
2058 	    PO_SUCCESS) {
2059 		free(dissoc);
2060 		pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource;
2061 		return (PO_FAIL);
2062 	}
2063 
2064 	/*
2065 	 * Update our local copy
2066 	 */
2067 	pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res;
2068 	return (PO_SUCCESS);
2069 }
2070 
2071 /*
2072  * Allocate a data provider for the supplied configuration and optionally
2073  * discover resources.
2074  * The data provider is the cross over point from the "abstract" configuration
2075  * functions into the data representation specific manipulation routines.
2076  * This function sets up all the required pointers to create a kernel aware
2077  * data provider.
2078  * Returns PO_SUCCESS/PO_FAIL
2079  */
2080 int
2081 pool_knl_connection_alloc(pool_conf_t *conf, int oflags)
2082 {
2083 	pool_knl_connection_t *prov;
2084 
2085 	if ((prov = malloc(sizeof (pool_knl_connection_t))) == NULL) {
2086 		pool_seterror(POE_SYSTEM);
2087 		return (PO_FAIL);
2088 	}
2089 	(void) memset(prov, 0, sizeof (pool_knl_connection_t));
2090 	/*
2091 	 * Initialise data members
2092 	 */
2093 	prov->pc_name = strdup("kernel");
2094 	prov->pc_store_type = KERNEL_DATA_STORE;
2095 	prov->pc_oflags = oflags;
2096 	/*
2097 	 * Initialise function pointers
2098 	 */
2099 	prov->pc_close = pool_knl_close;
2100 	prov->pc_validate = pool_knl_validate;
2101 	prov->pc_commit = pool_knl_commit;
2102 	prov->pc_export = pool_knl_export;
2103 	prov->pc_rollback = pool_knl_rollback;
2104 	prov->pc_exec_query = pool_knl_exec_query;
2105 	prov->pc_elem_create = pool_knl_elem_create;
2106 	prov->pc_remove = pool_knl_remove;
2107 	prov->pc_res_xfer = pool_knl_res_transfer;
2108 	prov->pc_res_xxfer = pool_knl_res_xtransfer;
2109 	prov->pc_get_binding = pool_knl_get_binding;
2110 	prov->pc_set_binding = pool_knl_set_binding;
2111 	prov->pc_get_resource_binding = pool_knl_get_resource_binding;
2112 	/*
2113 	 * Associate the provider to it's configuration
2114 	 */
2115 	conf->pc_prov = (pool_connection_t *)prov;
2116 	/*
2117 	 * End of common initialisation
2118 	 */
2119 	/*
2120 	 * Attempt to open the pseudo device, if the configuration is opened
2121 	 * readonly then try to open an info device, otherwise try to open
2122 	 * the writeable device.
2123 	 */
2124 	if (oflags & PO_RDWR) {
2125 		if ((prov->pkc_fd = blocking_open(pool_dynamic_location(),
2126 		    O_RDWR)) < 0) {
2127 			free(prov);
2128 			conf->pc_prov = NULL;
2129 			pool_seterror(POE_SYSTEM);
2130 			return (PO_FAIL);
2131 		}
2132 	} else {
2133 		if ((prov->pkc_fd = open(pool_info_location, O_RDWR)) < 0) {
2134 			free(prov);
2135 			conf->pc_prov = NULL;
2136 			pool_seterror(POE_SYSTEM);
2137 			return (PO_FAIL);
2138 		}
2139 	}
2140 	/*
2141 	 * Allocate the element dictionary
2142 	 */
2143 	if ((prov->pkc_elements = dict_new((int (*)(const void *, const void *))
2144 	    pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) {
2145 		(void) close(prov->pkc_fd);
2146 		free(prov);
2147 		conf->pc_prov = NULL;
2148 		pool_seterror(POE_SYSTEM);
2149 		return (PO_FAIL);
2150 	}
2151 #if DEBUG
2152 	if ((prov->pkc_leaks = dict_new(NULL, NULL)) == NULL) {
2153 		dict_free(&prov->pkc_elements);
2154 		(void) close(prov->pkc_fd);
2155 		free(prov);
2156 		conf->pc_prov = NULL;
2157 		pool_seterror(POE_SYSTEM);
2158 		return (PO_FAIL);
2159 	}
2160 #endif	/* DEBUG */
2161 	/*
2162 	 * Allocate the transaction log
2163 	 */
2164 	if ((prov->pkc_log = log_alloc(conf)) == NULL) {
2165 #if DEBUG
2166 		dict_free(&prov->pkc_leaks);
2167 #endif	/* DEBUG */
2168 		dict_free(&prov->pkc_elements);
2169 		(void) close(prov->pkc_fd);
2170 		free(prov);
2171 		conf->pc_prov = NULL;
2172 		return (PO_FAIL);
2173 	}
2174 	/*
2175 	 * At this point the configuration provider has been initialized,
2176 	 * mark the configuration as valid so that the various routines
2177 	 * which rely on a valid configuration will work correctly.
2178 	 */
2179 	conf->pc_state = POF_VALID;
2180 	/*
2181 	 * Update the library snapshot from the kernel
2182 	 */
2183 	if (pool_knl_update(conf, NULL) != PO_SUCCESS) {
2184 #if DEBUG
2185 		dict_free(&prov->pkc_leaks);
2186 #endif	/* DEBUG */
2187 		dict_free(&prov->pkc_elements);
2188 		(void) close(prov->pkc_fd);
2189 		free(prov);
2190 		conf->pc_prov = NULL;
2191 		conf->pc_state = POF_INVALID;
2192 		return (PO_FAIL);
2193 	}
2194 	return (PO_SUCCESS);
2195 }
2196 
2197 #if DEBUG
2198 static void
2199 pool_knl_elem_printf_cb(const void *key, void **value, void *cl)
2200 {
2201 	pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
2202 	dict_hdl_t *map = (dict_hdl_t *)cl;
2203 
2204 	dprintf("leak elem:%p\n", pke);
2205 	if (pke->pke_properties != NULL) {
2206 		nvlist_print(stdout, pke->pke_properties);
2207 	} else
2208 		dprintf("no properties\n");
2209 	assert(dict_get(map, pke) == NULL);
2210 }
2211 #endif	/* DEBUG */
2212 /*
2213  * pool_knl_elem_free() releases the resources associated with the
2214  * supplied element.
2215  */
2216 static void
2217 pool_knl_elem_free(pool_knl_elem_t *pke, int freeprop)
2218 {
2219 #if DEBUG
2220 	pool_conf_t *conf = TO_CONF(TO_ELEM(pke));
2221 	if (dict_remove(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks,
2222 	    pke) == NULL)
2223 		dprintf("%p, wasn't in the leak map\n", pke);
2224 	if (freeprop == PO_TRUE) {
2225 		pool_elem_dprintf(TO_ELEM(pke));
2226 	}
2227 	dprintf("released %p\n", pke);
2228 #endif	/* DEBUG */
2229 	if (freeprop == PO_TRUE) {
2230 		nvlist_free(pke->pke_properties);
2231 	}
2232 	free(pke);
2233 }
2234 
2235 /*
2236  * pool_knl_elem_free_cb() is designed to be used with
2237  * dict_map(). When a connection is freed, this function is used to
2238  * free all element resources.
2239  */
2240 /* ARGSUSED1 */
2241 static void
2242 pool_knl_elem_free_cb(const void *key, void **value, void *cl)
2243 {
2244 	pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
2245 
2246 #ifdef DEBUG
2247 	dprintf("pool_knl_elem_free_cb:\n");
2248 	dprintf("about to release %p ", pke);
2249 	pool_elem_dprintf(TO_ELEM(pke));
2250 #endif	/* DEBUG */
2251 	pool_knl_elem_free(pke, PO_TRUE);
2252 }
2253 
2254 /*
2255  * Free the resources for a kernel data provider.
2256  */
2257 void
2258 pool_knl_connection_free(pool_knl_connection_t *prov)
2259 {
2260 	if (prov->pkc_log != NULL) {
2261 		(void) log_walk(prov->pkc_log, log_item_release);
2262 		log_free(prov->pkc_log);
2263 	}
2264 	if (prov->pkc_elements != NULL) {
2265 		dict_map(prov->pkc_elements, pool_knl_elem_free_cb, NULL);
2266 #if DEBUG
2267 		dprintf("dict length is %llu\n", dict_length(prov->pkc_leaks));
2268 		dict_map(prov->pkc_leaks, pool_knl_elem_printf_cb,
2269 		    prov->pkc_elements);
2270 		assert(dict_length(prov->pkc_leaks) == 0);
2271 		dict_free(&prov->pkc_leaks);
2272 #endif	/* DEBUG */
2273 		dict_free(&prov->pkc_elements);
2274 	}
2275 	free((void *)prov->pc_name);
2276 	free(prov);
2277 }
2278 
2279 /*
2280  * Return the specified property value.
2281  *
2282  * POC_INVAL is returned if an error is detected and the error code is updated
2283  * to indicate the cause of the error.
2284  */
2285 pool_value_class_t
2286 pool_knl_get_property(const pool_elem_t *pe, const char *name,
2287     pool_value_t *val)
2288 {
2289 	pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2290 	nvpair_t *pair;
2291 	const pool_prop_t *prop;
2292 
2293 	if ((prop = provider_get_prop(pe, name)) != NULL)
2294 		if (prop_is_stored(prop) == PO_FALSE)
2295 			return (pool_knl_get_dynamic_property(pe, name, val));
2296 
2297 	if ((pair = pool_knl_find_nvpair(pke->pke_properties, name)) == NULL) {
2298 		pool_seterror(POE_BADPARAM);
2299 		return (POC_INVAL);
2300 	}
2301 
2302 	if (pool_value_from_nvpair(val, pair) == PO_FAIL) {
2303 		return (POC_INVAL);
2304 	}
2305 
2306 	return (pool_value_get_type(val));
2307 }
2308 
2309 /*
2310  * Return the specified property value.
2311  *
2312  * If a property is designated as dynamic, then this function will
2313  * always try to return the latest value of the property from the
2314  * kernel.
2315  *
2316  * POC_INVAL is returned if an error is detected and the error code is updated
2317  * to indicate the cause of the error.
2318  */
2319 pool_value_class_t
2320 pool_knl_get_dynamic_property(const pool_elem_t *pe, const char *name,
2321     pool_value_t *val)
2322 {
2323 	pool_knl_connection_t *prov;
2324 	pool_propget_t propget = { 0 };
2325 	nvlist_t *proplist;
2326 	nvpair_t *pair;
2327 
2328 	propget.pp_o_id_type = pool_elem_class(pe);
2329 	if (pool_elem_class(pe) == PEC_RES_COMP ||
2330 	    pool_elem_class(pe) == PEC_RES_AGG)
2331 		propget.pp_o_id_subtype = pool_resource_elem_class(pe);
2332 	if (pool_elem_class(pe) == PEC_COMP)
2333 		propget.pp_o_id_subtype =
2334 		    (pool_resource_elem_class_t)pool_component_elem_class(pe);
2335 
2336 	propget.pp_o_id = elem_get_sysid(pe);
2337 	propget.pp_o_prop_name_size = strlen(name);
2338 	propget.pp_o_prop_name = (char *)name;
2339 	propget.pp_i_bufsize = KERNEL_SNAPSHOT_BUF_SZ;
2340 	propget.pp_i_buf = malloc(KERNEL_SNAPSHOT_BUF_SZ);
2341 	bzero(propget.pp_i_buf, KERNEL_SNAPSHOT_BUF_SZ);
2342 
2343 	prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
2344 	if (ioctl(prov->pkc_fd, POOL_PROPGET, &propget) < 0) {
2345 		free(propget.pp_i_buf);
2346 		pool_seterror(POE_SYSTEM);
2347 		return (POC_INVAL);
2348 	}
2349 	if (nvlist_unpack(propget.pp_i_buf, propget.pp_i_bufsize,
2350 	    &proplist, 0) != 0) {
2351 		free(propget.pp_i_buf);
2352 		pool_seterror(POE_SYSTEM);
2353 		return (POC_INVAL);
2354 	}
2355 	free(propget.pp_i_buf);
2356 
2357 	if ((pair = nvlist_next_nvpair(proplist, NULL)) == NULL) {
2358 		nvlist_free(proplist);
2359 		pool_seterror(POE_SYSTEM);
2360 		return (POC_INVAL);
2361 	}
2362 
2363 	if (pool_value_from_nvpair(val, pair) == PO_FAIL) {
2364 		nvlist_free(proplist);
2365 		return (POC_INVAL);
2366 	}
2367 	nvlist_free(proplist);
2368 	return (pool_value_get_type(val));
2369 }
2370 
2371 /*
2372  * Update the specified property value.
2373  *
2374  * PO_FAIL is returned if an error is detected and the error code is updated
2375  * to indicate the cause of the error.
2376  */
2377 int
2378 pool_knl_put_property(pool_elem_t *pe, const char *name,
2379     const pool_value_t *val)
2380 {
2381 	pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2382 	pool_knl_connection_t *prov =
2383 	    (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
2384 	nvpair_t *bp, *ap;
2385 	pool_propput_undo_t *propput;
2386 	nvlist_t *bl = NULL;
2387 	const pool_prop_t *prop;
2388 
2389 	if ((bp = pool_knl_find_nvpair(pke->pke_properties, name)) != NULL) {
2390 		if (nvlist_alloc(&bl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2391 			pool_seterror(POE_SYSTEM);
2392 			return (PO_FAIL);
2393 		}
2394 		if (nvlist_add_nvpair(bl, bp) != 0) {
2395 			nvlist_free(bl);
2396 			pool_seterror(POE_SYSTEM);
2397 			return (PO_FAIL);
2398 		}
2399 	}
2400 	if (pool_knl_nvlist_add_value(pke->pke_properties, name, val) !=
2401 	    PO_SUCCESS)
2402 		return (PO_FAIL);
2403 
2404 	if (prov->pkc_log->l_state != LS_DO) {
2405 		if (bl)
2406 			nvlist_free(bl);
2407 		return (PO_SUCCESS);
2408 	}
2409 	/*
2410 	 * The remaining logic is setting up the arguments for the
2411 	 * POOL_PROPPUT ioctl and appending the details into the log.
2412 	 */
2413 	if ((propput = malloc(sizeof (pool_propput_undo_t))) == NULL) {
2414 		pool_seterror(POE_SYSTEM);
2415 		return (PO_FAIL);
2416 	}
2417 	(void) memset(propput, 0, sizeof (pool_propput_undo_t));
2418 	propput->ppu_blist = bl;
2419 
2420 	ap = pool_knl_find_nvpair(pke->pke_properties, name);
2421 
2422 	if (nvlist_alloc(&propput->ppu_alist, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2423 		nvlist_free(propput->ppu_blist);
2424 		free(propput);
2425 		pool_seterror(POE_SYSTEM);
2426 		return (PO_FAIL);
2427 	}
2428 	if (nvlist_add_nvpair(propput->ppu_alist, ap) != 0) {
2429 		nvlist_free(propput->ppu_blist);
2430 		nvlist_free(propput->ppu_alist);
2431 		free(propput);
2432 		pool_seterror(POE_SYSTEM);
2433 		return (PO_FAIL);
2434 	}
2435 
2436 	if (nvlist_pack(propput->ppu_alist,
2437 	    (char **)&propput->ppu_ioctl.pp_o_buf,
2438 	    &propput->ppu_ioctl.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) {
2439 		pool_seterror(POE_SYSTEM);
2440 		return (PO_FAIL);
2441 	}
2442 	nvlist_free(propput->ppu_alist);
2443 	propput->ppu_ioctl.pp_o_id_type = pool_elem_class(pe);
2444 	if (pool_elem_class(pe) == PEC_RES_COMP ||
2445 	    pool_elem_class(pe) == PEC_RES_AGG)
2446 		propput->ppu_ioctl.pp_o_id_sub_type =
2447 		    pool_resource_elem_class(pe);
2448 	if (pool_elem_class(pe) == PEC_COMP)
2449 		propput->ppu_ioctl.pp_o_id_sub_type =
2450 		    (pool_resource_elem_class_t)pool_component_elem_class(pe);
2451 
2452 	propput->ppu_elem = pe;
2453 	if ((prop = provider_get_prop(propput->ppu_elem, name)) != NULL) {
2454 		if (prop_is_readonly(prop) == PO_TRUE)
2455 			propput->ppu_doioctl |= KERNEL_PROP_RDONLY;
2456 	}
2457 
2458 	if (log_append(prov->pkc_log, POOL_PROPPUT, (void *)propput) !=
2459 	    PO_SUCCESS) {
2460 		nvlist_free(propput->ppu_blist);
2461 		free(propput);
2462 		return (PO_FAIL);
2463 	}
2464 	return (PO_SUCCESS);
2465 }
2466 
2467 /*
2468  * Remove the specified property value.
2469  *
2470  * PO_FAIL is returned if an error is detected and the error code is
2471  * updated to indicate the cause of the error.
2472  */
2473 int
2474 pool_knl_rm_property(pool_elem_t *pe, const char *name)
2475 {
2476 	pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2477 	pool_knl_connection_t *prov =
2478 	    (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
2479 	pool_proprm_undo_t *proprm;
2480 
2481 	if (pool_knl_find_nvpair(pke->pke_properties, name) == NULL) {
2482 		pool_seterror(POE_BADPARAM);
2483 		return (PO_FAIL);
2484 	}
2485 
2486 	if ((proprm = malloc(sizeof (pool_proprm_undo_t))) == NULL) {
2487 		pool_seterror(POE_SYSTEM);
2488 		return (PO_FAIL);
2489 	}
2490 	(void) memset(proprm, 0, sizeof (pool_proprm_undo_t));
2491 	proprm->pru_oldval.pv_class = POC_INVAL;
2492 	(void) pool_get_property(TO_CONF(pe), pe, name, &proprm->pru_oldval);
2493 
2494 	if (prov->pkc_log->l_state != LS_DO) {
2495 		free(proprm);
2496 		(void) nvlist_remove_all(pke->pke_properties, (char *)name);
2497 		return (PO_SUCCESS);
2498 	}
2499 	/*
2500 	 * The remaining logic is setting up the arguments for the
2501 	 * POOL_PROPRM ioctl and appending the details into the log.
2502 	 */
2503 
2504 	proprm->pru_ioctl.pp_o_id_type = pool_elem_class(pe);
2505 	if (pool_elem_class(pe) == PEC_RES_COMP ||
2506 	    pool_elem_class(pe) == PEC_RES_AGG)
2507 		proprm->pru_ioctl.pp_o_id_sub_type =
2508 		    pool_resource_elem_class(pe);
2509 
2510 	if (pool_elem_class(pe) == PEC_COMP)
2511 		proprm->pru_ioctl.pp_o_id_sub_type =
2512 		    (pool_resource_elem_class_t)pool_component_elem_class(pe);
2513 
2514 	proprm->pru_ioctl.pp_o_prop_name_size = strlen(name);
2515 	proprm->pru_ioctl.pp_o_prop_name =
2516 	    (char *)pool_value_get_name(&proprm->pru_oldval);
2517 	proprm->pru_elem = pe;
2518 
2519 	if (log_append(prov->pkc_log, POOL_PROPRM, (void *)proprm) !=
2520 	    PO_SUCCESS) {
2521 		free(proprm);
2522 		return (PO_FAIL);
2523 	}
2524 
2525 	(void) nvlist_remove_all(pke->pke_properties, (char *)name);
2526 	return (PO_SUCCESS);
2527 }
2528 
2529 /*
2530  * Return a NULL terminated array of pool_value_t which represents all
2531  * of the properties stored for an element
2532  *
2533  * Return NULL on failure. It is the caller's responsibility to free
2534  * the returned array of values.
2535  */
2536 pool_value_t **
2537 pool_knl_get_properties(const pool_elem_t *pe, uint_t *nprops)
2538 {
2539 	nvpair_t *pair;
2540 	pool_value_t **result;
2541 	pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2542 	int i = 0;
2543 
2544 	*nprops = 0;
2545 
2546 	for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL;
2547 		pair = nvlist_next_nvpair(pke->pke_properties, pair))
2548 		(*nprops)++;
2549 	if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) {
2550 		pool_seterror(POE_SYSTEM);
2551 		return (NULL);
2552 	}
2553 	for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL;
2554 	    pair = nvlist_next_nvpair(pke->pke_properties, pair), i++) {
2555 		result[i] = pool_value_alloc();
2556 		if (pool_value_from_nvpair(result[i], pair) == PO_FAIL) {
2557 			while (i-- >= 0)
2558 				pool_value_free(result[i]);
2559 			free(result);
2560 			return (NULL);
2561 		}
2562 	}
2563 	return (result);
2564 }
2565 
2566 /*
2567  * Append an entry to a result set. Reallocate the array used to store
2568  * results if it's full.
2569  * Returns PO_SUCCESS/PO_FAIL
2570  */
2571 int
2572 pool_knl_result_set_append(pool_knl_result_set_t *rs, pool_knl_elem_t *pke)
2573 {
2574 	if (rs->pkr_count == rs->pkr_size)
2575 		if (pool_knl_result_set_realloc(rs) != PO_SUCCESS)
2576 			return (PO_FAIL);
2577 
2578 	rs->pkr_list[rs->pkr_count++] = pke;
2579 
2580 	return (PO_SUCCESS);
2581 }
2582 
2583 /*
2584  * Resize the array used to store results. A simple doubling strategy
2585  * is used.
2586  * Returns PO_SUCCESS/PO_FAIL
2587  */
2588 int
2589 pool_knl_result_set_realloc(pool_knl_result_set_t *rs)
2590 {
2591 	pool_knl_elem_t **old_list = rs->pkr_list;
2592 	int new_size = rs->pkr_size * 2;
2593 
2594 	if ((rs->pkr_list = realloc(rs->pkr_list,
2595 	    new_size * sizeof (pool_knl_elem_t *))) == NULL) {
2596 		rs->pkr_list = old_list;
2597 		pool_seterror(POE_SYSTEM);
2598 		return (PO_FAIL);
2599 	}
2600 	rs->pkr_size = new_size;
2601 
2602 	return (PO_SUCCESS);
2603 }
2604 
2605 /*
2606  * Allocate a result set. The Result Set stores the result of a query.
2607  * Returns pool_knl_result_set_t pointer/NULL
2608  */
2609 pool_knl_result_set_t *
2610 pool_knl_result_set_alloc(const pool_conf_t *conf)
2611 {
2612 	pool_knl_result_set_t *rs;
2613 
2614 	if ((rs = malloc(sizeof (pool_knl_result_set_t))) == NULL) {
2615 		pool_seterror(POE_SYSTEM);
2616 		return (NULL);
2617 	}
2618 	(void) memset(rs, 0, sizeof (pool_knl_result_set_t));
2619 	rs->pkr_size = KERNEL_RS_INITIAL_SZ;
2620 	if (pool_knl_result_set_realloc(rs) == PO_FAIL) {
2621 		free(rs);
2622 		pool_seterror(POE_SYSTEM);
2623 		return (NULL);
2624 	}
2625 	rs->prs_conf = conf;
2626 	rs->prs_index = -1;
2627 	rs->prs_active = PO_TRUE;
2628 	/* Fix up the result set accessor functions to the knl specfic ones */
2629 	rs->prs_next = pool_knl_rs_next;
2630 	rs->prs_prev = pool_knl_rs_prev;
2631 	rs->prs_first = pool_knl_rs_first;
2632 	rs->prs_last = pool_knl_rs_last;
2633 	rs->prs_get_index = pool_knl_rs_get_index;
2634 	rs->prs_set_index = pool_knl_rs_set_index;
2635 	rs->prs_close = pool_knl_rs_close;
2636 	rs->prs_count = pool_knl_rs_count;
2637 	return (rs);
2638 }
2639 
2640 /*
2641  * Free a result set. Ensure that the resources are all released at
2642  * this point.
2643  */
2644 void
2645 pool_knl_result_set_free(pool_knl_result_set_t *rs)
2646 {
2647 	free(rs->pkr_list);
2648 	free(rs);
2649 }
2650 /*
2651  * Return the next element in a result set.
2652  * Returns pool_elem_t pointer/NULL
2653  */
2654 pool_elem_t *
2655 pool_knl_rs_next(pool_result_set_t *set)
2656 {
2657 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2658 
2659 	if (kset->prs_index == kset->pkr_count - 1)
2660 		return (NULL);
2661 	return ((pool_elem_t *)kset->pkr_list[++kset->prs_index]);
2662 }
2663 
2664 /*
2665  * Return the previous element in a result set.
2666  * Returns pool_elem_t pointer/NULL
2667  */
2668 pool_elem_t *
2669 pool_knl_rs_prev(pool_result_set_t *set)
2670 {
2671 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2672 
2673 	if (kset->prs_index < 0)
2674 		return (NULL);
2675 	return ((pool_elem_t *)kset->pkr_list[kset->prs_index--]);
2676 }
2677 
2678 /*
2679  * Sets the current index in a result set.
2680  * Returns PO_SUCCESS/PO_FAIL
2681  */
2682 int
2683 pool_knl_rs_set_index(pool_result_set_t *set, int index)
2684 {
2685 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2686 
2687 	if (index < 0 || index >= kset->pkr_count) {
2688 		pool_seterror(POE_BADPARAM);
2689 		return (PO_FAIL);
2690 	}
2691 	kset->prs_index = index;
2692 	return (PO_SUCCESS);
2693 }
2694 
2695 /*
2696  * Return the current index in a result set.
2697  * Returns current index
2698  */
2699 int
2700 pool_knl_rs_get_index(pool_result_set_t *set)
2701 {
2702 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2703 
2704 	return (kset->prs_index);
2705 }
2706 
2707 /*
2708  * Return the first element in a result set.
2709  * Returns pool_elem_t pointer/NULL
2710  */
2711 pool_elem_t *
2712 pool_knl_rs_first(pool_result_set_t *set)
2713 {
2714 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2715 
2716 	return ((pool_elem_t *)kset->pkr_list[0]);
2717 }
2718 
2719 /*
2720  * Return the last element in a result set.
2721  * Returns pool_elem_t pointer/NULL
2722  */
2723 pool_elem_t *
2724 pool_knl_rs_last(pool_result_set_t *set)
2725 {
2726 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2727 
2728 	return ((pool_elem_t *)kset->pkr_list[kset->pkr_count - 1]);
2729 }
2730 
2731 /*
2732  * Return the number of results in a result set.
2733  * Returns result count
2734  */
2735 int
2736 pool_knl_rs_count(pool_result_set_t *set)
2737 {
2738 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2739 
2740 	return (kset->pkr_count);
2741 }
2742 
2743 
2744 /*
2745  * Close a result set. Free the resources
2746  * Returns PO_SUCCESS/PO_FAIL
2747  */
2748 int
2749 pool_knl_rs_close(pool_result_set_t *set)
2750 {
2751 	pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2752 
2753 	pool_knl_result_set_free(kset);
2754 	return (PO_SUCCESS);
2755 }
2756 
2757 /*
2758  * Commit an individual transaction log item(). This processing is
2759  * essential to the pool_conf_commit() logic. When pool_conf_commit()
2760  * is invoked, the pending transaction log for the configuration is
2761  * walked and all pending changes to the kernel are invoked. If a
2762  * change succeeds it is marked in the log as successful and
2763  * processing continues, if it fails then failure is returned and the
2764  * log will be "rolled back" to undo changes to the library snapshot
2765  * and the kernel.
2766  */
2767 int
2768 log_item_commit(log_item_t *li)
2769 {
2770 	pool_knl_connection_t *prov =
2771 	    (pool_knl_connection_t *)li->li_log->l_conf->pc_prov;
2772 	pool_create_undo_t *create;
2773 	pool_destroy_undo_t *destroy;
2774 	pool_assoc_undo_t *assoc;
2775 	pool_dissoc_undo_t *dissoc;
2776 	pool_propput_undo_t *propput;
2777 	pool_proprm_undo_t *proprm;
2778 	pool_xtransfer_undo_t *xtransfer;
2779 	char_buf_t *cb;
2780 	size_t size;
2781 	pool_elem_t *pair;
2782 	pool_value_t val = POOL_VALUE_INITIALIZER;
2783 	int ret;
2784 
2785 	switch (li->li_op) {
2786 	case POOL_CREATE:
2787 		create = (pool_create_undo_t *)li->li_details;
2788 		if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
2789 			return (PO_FAIL);
2790 		if (set_char_buf(cb, "%s.sys_id",
2791 		    pool_elem_class_string(create->pcu_elem)) != PO_SUCCESS) {
2792 			free_char_buf(cb);
2793 			return (PO_FAIL);
2794 		}
2795 #ifdef DEBUG
2796 		dprintf("log_item_commit: POOL_CREATE, remove from dict\n");
2797 		pool_elem_dprintf(create->pcu_elem);
2798 #endif	/* DEBUG */
2799 		/*
2800 		 * May not need to remove the element if it was
2801 		 * already destroyed before commit. Just cast the
2802 		 * return to void.
2803 		 */
2804 		(void) dict_remove(prov->pkc_elements,
2805 		    (pool_knl_elem_t *)create->pcu_elem);
2806 
2807 		if (ioctl(prov->pkc_fd, POOL_CREATE, &create->pcu_ioctl) < 0) {
2808 			pool_seterror(POE_SYSTEM);
2809 			return (PO_FAIL);
2810 		}
2811 		/*
2812 		 * Now that we have created our element in the kernel,
2813 		 * it has a valid allocated system id. Remove the
2814 		 * element from the element dictionary, using the
2815 		 * current key, and then re-insert under the new key.
2816 		 */
2817 #ifdef DEBUG
2818 		pool_elem_dprintf(create->pcu_elem);
2819 #endif	/* DEBUG */
2820 		assert(nvlist_add_int64(
2821 		    ((pool_knl_elem_t *)create->pcu_elem)->pke_properties,
2822 		    cb->cb_buf, create->pcu_ioctl.pc_i_id) == 0);
2823 		free_char_buf(cb);
2824 		assert(dict_put(prov->pkc_elements, create->pcu_elem,
2825 		    create->pcu_elem) == NULL);
2826 		/*
2827 		 * If the element has a pair in the static
2828 		 * configuration, update it with the sys_id
2829 		 */
2830 		if ((pair = pool_get_pair(create->pcu_elem)) != NULL) {
2831 			pool_value_set_int64(&val, create->pcu_ioctl.pc_i_id);
2832 			assert(pool_put_any_ns_property(pair, c_sys_prop, &val)
2833 			    == PO_SUCCESS);
2834 		}
2835 		li->li_state = LS_UNDO;
2836 		break;
2837 	case POOL_DESTROY:
2838 		destroy = (pool_destroy_undo_t *)li->li_details;
2839 
2840 		destroy->pdu_ioctl.pd_o_id = elem_get_sysid(destroy->pdu_elem);
2841 
2842 		/*
2843 		 * It may be that this element was created in the last
2844 		 * transaction. In which case POOL_CREATE, above, will
2845 		 * have re-inserted the element in the dictionary. Try
2846 		 * to remove it just in case this has occurred.
2847 		 */
2848 		(void) dict_remove(prov->pkc_elements,
2849 		    (pool_knl_elem_t *)destroy->pdu_elem);
2850 		while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY,
2851 		    &destroy->pdu_ioctl)) < 0 && errno == EAGAIN);
2852 		if (ret < 0) {
2853 			pool_seterror(POE_SYSTEM);
2854 			return (PO_FAIL);
2855 		}
2856 #ifdef DEBUG
2857 		dprintf("log_item_commit: POOL_DESTROY\n");
2858 		pool_elem_dprintf(destroy->pdu_elem);
2859 #endif	/* DEBUG */
2860 		li->li_state = LS_UNDO;
2861 		break;
2862 	case POOL_ASSOC:
2863 		assoc = (pool_assoc_undo_t *)li->li_details;
2864 
2865 		assoc->pau_ioctl.pa_o_pool_id =
2866 		    elem_get_sysid(assoc->pau_assoc);
2867 		assoc->pau_ioctl.pa_o_res_id =
2868 		    elem_get_sysid(assoc->pau_newres);
2869 		while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC,
2870 		    &assoc->pau_ioctl)) < 0 && errno == EAGAIN);
2871 		if (ret < 0) {
2872 			pool_seterror(POE_SYSTEM);
2873 			return (PO_FAIL);
2874 		}
2875 		li->li_state = LS_UNDO;
2876 		break;
2877 	case POOL_DISSOC:
2878 		dissoc = (pool_dissoc_undo_t *)li->li_details;
2879 
2880 		dissoc->pdu_ioctl.pd_o_pool_id =
2881 		    elem_get_sysid(dissoc->pdu_dissoc);
2882 
2883 		while ((ret = ioctl(prov->pkc_fd, POOL_DISSOC,
2884 		    &dissoc->pdu_ioctl)) < 0 && errno == EAGAIN);
2885 		if (ret < 0) {
2886 			pool_seterror(POE_SYSTEM);
2887 			return (PO_FAIL);
2888 		}
2889 		li->li_state = LS_UNDO;
2890 		break;
2891 	case POOL_TRANSFER:
2892 		li->li_state = LS_UNDO;
2893 		pool_seterror(POE_BADPARAM);
2894 		return (PO_FAIL);
2895 		break;
2896 	case POOL_XTRANSFER:
2897 		xtransfer = (pool_xtransfer_undo_t *)li->li_details;
2898 
2899 		xtransfer->pxu_ioctl.px_o_src_id =
2900 		    elem_get_sysid(xtransfer->pxu_src);
2901 		xtransfer->pxu_ioctl.px_o_tgt_id =
2902 		    elem_get_sysid(xtransfer->pxu_tgt);
2903 		for (size = 0; xtransfer->pxu_rl[size] != NULL; size ++) {
2904 			xtransfer->pxu_ioctl.px_o_comp_list[size] =
2905 			    elem_get_sysid(TO_ELEM(xtransfer->pxu_rl[size]));
2906 #ifdef DEBUG
2907 			dprintf("log_item_commit: POOL_XTRANSFER\n");
2908 			pool_elem_dprintf(TO_ELEM(xtransfer->pxu_rl[size]));
2909 #endif	/* DEBUG */
2910 		}
2911 
2912 		/*
2913 		 * Don't actually transfer resources if the configuration
2914 		 * is in POF_DESTROY state. This is to prevent problems
2915 		 * relating to transferring off-line CPUs. Instead rely
2916 		 * on the POOL_DESTROY ioctl to transfer the CPUS.
2917 		 */
2918 		if (li->li_log->l_conf->pc_state != POF_DESTROY &&
2919 		    ioctl(prov->pkc_fd, POOL_XTRANSFER,
2920 		    &xtransfer->pxu_ioctl) < 0) {
2921 #ifdef DEBUG
2922 			dprintf("log_item_commit: POOL_XTRANSFER, ioctl "
2923 			    "failed\n");
2924 #endif	/* DEBUG */
2925 			pool_seterror(POE_SYSTEM);
2926 			return (PO_FAIL);
2927 		}
2928 		li->li_state = LS_UNDO;
2929 		break;
2930 	case POOL_PROPPUT:
2931 		propput = (pool_propput_undo_t *)li->li_details;
2932 
2933 		if (pool_elem_class(propput->ppu_elem) != PEC_SYSTEM) {
2934 			propput->ppu_ioctl.pp_o_id =
2935 			    elem_get_sysid(propput->ppu_elem);
2936 		}
2937 		/*
2938 		 * Some properties, e.g. pset.size, are read-only in the
2939 		 * kernel and attempting to change them will fail and cause
2940 		 * problems. Although this property is read-only through the
2941 		 * public interface, the library needs to modify it's value.
2942 		 */
2943 		if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) {
2944 			if (ioctl(prov->pkc_fd, POOL_PROPPUT,
2945 			    &propput->ppu_ioctl) < 0) {
2946 				pool_seterror(POE_SYSTEM);
2947 				return (PO_FAIL);
2948 			}
2949 		}
2950 		li->li_state = LS_UNDO;
2951 		break;
2952 	case POOL_PROPRM:
2953 		proprm = (pool_proprm_undo_t *)li->li_details;
2954 
2955 		if (pool_elem_class(proprm->pru_elem) != PEC_SYSTEM) {
2956 			proprm->pru_ioctl.pp_o_id =
2957 			    elem_get_sysid(proprm->pru_elem);
2958 		}
2959 		if (ioctl(prov->pkc_fd, POOL_PROPRM, &proprm->pru_ioctl) < 0) {
2960 			pool_seterror(POE_SYSTEM);
2961 			return (PO_FAIL);
2962 		}
2963 		li->li_state = LS_UNDO;
2964 		break;
2965 	default:
2966 		return (PO_FAIL);
2967 	}
2968 	return (PO_SUCCESS);
2969 }
2970 
2971 /*
2972  * Undo an individual transaction log item(). This processing is
2973  * essential to the pool_conf_commit() and pool_conf_rollback()
2974  * logic. Changes to the libpool snapshot and the kernel are carried
2975  * out separately. The library snapshot is updated synchronously,
2976  * however the kernel update is delayed until the user calls
2977  * pool_conf_commit().
2978  *
2979  * When undoing transactions, library changes will be undone unless
2980  * this invocation is as a result of a commit failure, in which case
2981  * the log state will be LS_RECOVER. Kernel changes will only be
2982  * undone if they are marked as having been done, in which case the
2983  * log item state will be LS_UNDO.
2984  */
2985 int
2986 log_item_undo(log_item_t *li)
2987 {
2988 	pool_knl_connection_t *prov =
2989 	    (pool_knl_connection_t *)li->li_log->l_conf->pc_prov;
2990 	pool_create_undo_t *create;
2991 	pool_destroy_undo_t *destroy;
2992 	pool_assoc_undo_t *assoc;
2993 	pool_dissoc_undo_t *dissoc;
2994 	pool_propput_undo_t *propput;
2995 	pool_proprm_undo_t *proprm;
2996 	pool_xtransfer_undo_t *xtransfer;
2997 	char_buf_t *cb;
2998 	size_t size;
2999 	pool_destroy_t u_destroy;
3000 	pool_create_t u_create;
3001 	pool_assoc_t u_assoc;
3002 	pool_xtransfer_t u_xtransfer;
3003 	pool_propput_t u_propput;
3004 	pool_proprm_t u_proprm;
3005 	pool_conf_t *conf = li->li_log->l_conf;
3006 	nvpair_t *pair;
3007 	nvlist_t *tmplist;
3008 	int ret;
3009 
3010 	if (li->li_log->l_state != LS_RECOVER) {
3011 	switch (li->li_op) {
3012 	case POOL_CREATE:
3013 		create = (pool_create_undo_t *)li->li_details;
3014 
3015 		(void) dict_remove(prov->pkc_elements, create->pcu_elem);
3016 #ifdef DEBUG
3017 		dprintf("log_item_undo: POOL_CREATE\n");
3018 		assert(create->pcu_elem != NULL);
3019 		dprintf("log_item_undo: POOL_CREATE %p\n", create->pcu_elem);
3020 		pool_elem_dprintf(create->pcu_elem);
3021 #endif	/* DEBUG */
3022 		pool_knl_elem_free((pool_knl_elem_t *)create->pcu_elem,
3023 		    PO_TRUE);
3024 		break;
3025 	case POOL_DESTROY:
3026 		destroy = (pool_destroy_undo_t *)li->li_details;
3027 
3028 		assert(dict_put(prov->pkc_elements, destroy->pdu_elem,
3029 		    destroy->pdu_elem) == NULL);
3030 		break;
3031 	case POOL_ASSOC:
3032 		assoc = (pool_assoc_undo_t *)li->li_details;
3033 
3034 		if (assoc->pau_oldres != NULL)
3035 			((pool_knl_pool_t *)assoc->pau_assoc)->pkp_assoc
3036 			    [pool_resource_elem_class(assoc->pau_oldres)] =
3037 			    (pool_knl_resource_t *)assoc->pau_oldres;
3038 		break;
3039 	case POOL_DISSOC:
3040 		dissoc = (pool_dissoc_undo_t *)li->li_details;
3041 
3042 		if (dissoc->pdu_oldres != NULL)
3043 			((pool_knl_pool_t *)dissoc->pdu_dissoc)->pkp_assoc
3044 			    [pool_resource_elem_class(dissoc->pdu_oldres)] =
3045 			    (pool_knl_resource_t *)dissoc->pdu_oldres;
3046 		break;
3047 	case POOL_TRANSFER:
3048 		pool_seterror(POE_BADPARAM);
3049 		return (PO_FAIL);
3050 		break;
3051 	case POOL_XTRANSFER:
3052 		xtransfer = (pool_xtransfer_undo_t *)li->li_details;
3053 
3054 		for (size = 0; xtransfer->pxu_rl[size] != NULL; size++) {
3055 			pool_value_t val = POOL_VALUE_INITIALIZER;
3056 			uint64_t src_size;
3057 			uint64_t tgt_size;
3058 
3059 			if (pool_set_container(xtransfer->pxu_src,
3060 			    TO_ELEM(xtransfer->pxu_rl[size])) == PO_FAIL) {
3061 				return (PO_FAIL);
3062 			}
3063 			/*
3064 			 * Maintain the library view of the size
3065 			 */
3066 			if (resource_get_size(pool_elem_res(xtransfer->pxu_src),
3067 			    &src_size) != PO_SUCCESS ||
3068 			    resource_get_size(pool_elem_res(xtransfer->pxu_tgt),
3069 			    &tgt_size) != PO_SUCCESS) {
3070 				pool_seterror(POE_BADPARAM);
3071 				return (PO_FAIL);
3072 			}
3073 			src_size++;
3074 			tgt_size--;
3075 			pool_value_set_uint64(&val, src_size);
3076 			(void) pool_put_any_ns_property(xtransfer->pxu_src,
3077 			    c_size_prop, &val);
3078 			pool_value_set_uint64(&val, tgt_size);
3079 			(void) pool_put_any_ns_property(xtransfer->pxu_tgt,
3080 			    c_size_prop, &val);
3081 		}
3082 		break;
3083 	case POOL_PROPPUT:
3084 		propput = (pool_propput_undo_t *)li->li_details;
3085 
3086 		if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) {
3087 			if (propput->ppu_blist != NULL) {
3088 				if (nvlist_merge(
3089 				    ((pool_knl_elem_t *)propput->ppu_elem)->
3090 				    pke_properties, propput->ppu_blist, 0)
3091 				    != 0) {
3092 					pool_seterror(POE_SYSTEM);
3093 					return (PO_FAIL);
3094 				}
3095 			} else {
3096 				if (nvlist_unpack(propput->ppu_ioctl.pp_o_buf,
3097 				    propput->ppu_ioctl.pp_o_bufsize,
3098 				    &propput->ppu_alist, 0) != 0) {
3099 					pool_seterror(POE_SYSTEM);
3100 					return (PO_FAIL);
3101 				}
3102 				pair = nvlist_next_nvpair(propput->ppu_alist,
3103 				    NULL);
3104 				(void) nvlist_remove_all(((pool_knl_elem_t *)
3105 				    propput->ppu_elem)->pke_properties,
3106 				    nvpair_name(pair));
3107 				nvlist_free(propput->ppu_alist);
3108 			}
3109 		}
3110 		break;
3111 	case POOL_PROPRM:
3112 		proprm = (pool_proprm_undo_t *)li->li_details;
3113 
3114 		if (pool_value_get_type(&proprm->pru_oldval) != POC_INVAL) {
3115 			if (pool_put_property(conf, proprm->pru_elem,
3116 			    proprm->pru_ioctl.pp_o_prop_name,
3117 			    &proprm->pru_oldval) != PO_SUCCESS) {
3118 				return (PO_FAIL);
3119 			}
3120 		}
3121 		break;
3122 	default:
3123 		return (PO_FAIL);
3124 	}
3125 	}
3126 	/*
3127 	 * Only try to undo the state of the kernel if we modified it.
3128 	 */
3129 	if (li->li_state == LS_DO) {
3130 		return (PO_SUCCESS);
3131 	}
3132 
3133 	switch (li->li_op) {
3134 	case POOL_CREATE:
3135 		create = (pool_create_undo_t *)li->li_details;
3136 
3137 		u_destroy.pd_o_type = create->pcu_ioctl.pc_o_type;
3138 		u_destroy.pd_o_sub_type = create->pcu_ioctl.pc_o_sub_type;
3139 		u_destroy.pd_o_id = create->pcu_ioctl.pc_i_id;
3140 
3141 		while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY,
3142 		    &u_destroy)) < 0 && errno == EAGAIN);
3143 		if (ret < 0) {
3144 			pool_seterror(POE_SYSTEM);
3145 			return (PO_FAIL);
3146 		}
3147 		li->li_state = LS_DO;
3148 		break;
3149 	case POOL_DESTROY:
3150 		destroy = (pool_destroy_undo_t *)li->li_details;
3151 
3152 		u_create.pc_o_type = destroy->pdu_ioctl.pd_o_type;
3153 		u_create.pc_o_sub_type = destroy->pdu_ioctl.pd_o_sub_type;
3154 
3155 		if (ioctl(prov->pkc_fd, POOL_CREATE, &u_create) < 0) {
3156 			pool_seterror(POE_SYSTEM);
3157 			return (PO_FAIL);
3158 		}
3159 
3160 		if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
3161 			return (PO_FAIL);
3162 		}
3163 		if (set_char_buf(cb, "%s.sys_id",
3164 		    pool_elem_class_string(destroy->pdu_elem)) != PO_SUCCESS) {
3165 			free_char_buf(cb);
3166 			return (PO_FAIL);
3167 		}
3168 		(void) nvlist_add_int64(
3169 		    ((pool_knl_elem_t *)destroy->pdu_elem)->pke_properties,
3170 		    cb->cb_buf, u_create.pc_i_id);
3171 		free_char_buf(cb);
3172 		if (dict_put(prov->pkc_elements, destroy->pdu_elem,
3173 		    destroy->pdu_elem) != NULL) {
3174 			pool_seterror(POE_SYSTEM);
3175 			return (PO_FAIL);
3176 		}
3177 		/*
3178 		 * Now we need to reset all the properties and
3179 		 * associations in the kernel for this newly created
3180 		 * replacement.
3181 		 */
3182 		u_propput.pp_o_id_type = destroy->pdu_ioctl.pd_o_type;
3183 		u_propput.pp_o_id_sub_type = destroy->pdu_ioctl.pd_o_sub_type;
3184 		u_propput.pp_o_id = u_create.pc_i_id;
3185 		u_propput.pp_o_buf = NULL;
3186 		/*
3187 		 * Remove the read-only properties before attempting
3188 		 * to restore the state of the newly created property
3189 		 */
3190 		(void) nvlist_dup(((pool_knl_elem_t *)destroy->pdu_elem)->
3191 		pke_properties, &tmplist, 0);
3192 		for (pair = nvlist_next_nvpair(tmplist, NULL); pair != NULL;
3193 		    pair = nvlist_next_nvpair(tmplist, pair)) {
3194 			const pool_prop_t *prop;
3195 			char *name = nvpair_name(pair);
3196 			if ((prop = provider_get_prop(destroy->pdu_elem,
3197 			    name)) != NULL)
3198 				if (prop_is_readonly(prop) == PO_TRUE)
3199 					(void) nvlist_remove_all(tmplist, name);
3200 		}
3201 		if (nvlist_pack(tmplist, (char **)&u_propput.pp_o_buf,
3202 		    &u_propput.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) {
3203 			pool_seterror(POE_SYSTEM);
3204 			return (PO_FAIL);
3205 		}
3206 		nvlist_free(tmplist);
3207 		if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) {
3208 			free(u_propput.pp_o_buf);
3209 			pool_seterror(POE_SYSTEM);
3210 			return (PO_FAIL);
3211 		}
3212 		free(u_propput.pp_o_buf);
3213 		/*
3214 		 * Now reset the associations for all the resource
3215 		 * types if the thing which we are recreating is a
3216 		 * pool
3217 		 *
3218 		 * TODO: This is resource specific and must be
3219 		 * extended for additional resource types.
3220 		 */
3221 		if (destroy->pdu_ioctl.pd_o_type == PEC_POOL) {
3222 			u_assoc.pa_o_pool_id = u_create.pc_i_id;
3223 			u_assoc.pa_o_res_id =
3224 			    elem_get_sysid(
3225 			    TO_ELEM(((pool_knl_pool_t *)destroy->pdu_elem)->
3226 			    pkp_assoc[PREC_PSET]));
3227 			u_assoc.pa_o_id_type = PREC_PSET;
3228 
3229 			if (ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc) < 0) {
3230 				pool_seterror(POE_SYSTEM);
3231 				return (PO_FAIL);
3232 			}
3233 		}
3234 		li->li_state = LS_DO;
3235 		break;
3236 	case POOL_ASSOC:
3237 		assoc = (pool_assoc_undo_t *)li->li_details;
3238 
3239 		u_assoc.pa_o_pool_id = elem_get_sysid(assoc->pau_assoc);
3240 		u_assoc.pa_o_res_id = elem_get_sysid(assoc->pau_oldres);
3241 		u_assoc.pa_o_id_type = assoc->pau_ioctl.pa_o_id_type;
3242 
3243 		while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 &&
3244 		    errno == EAGAIN);
3245 		if (ret < 0) {
3246 			pool_seterror(POE_SYSTEM);
3247 			return (PO_FAIL);
3248 		}
3249 		li->li_state = LS_DO;
3250 		break;
3251 	case POOL_DISSOC:
3252 		dissoc = (pool_dissoc_undo_t *)li->li_details;
3253 
3254 		u_assoc.pa_o_pool_id = elem_get_sysid(dissoc->pdu_dissoc);
3255 		u_assoc.pa_o_res_id = elem_get_sysid(dissoc->pdu_oldres);
3256 		u_assoc.pa_o_id_type = dissoc->pdu_ioctl.pd_o_id_type;
3257 
3258 		while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 &&
3259 		    errno == EAGAIN);
3260 		if (ret < 0) {
3261 			pool_seterror(POE_SYSTEM);
3262 			return (PO_FAIL);
3263 		}
3264 		li->li_state = LS_DO;
3265 		break;
3266 	case POOL_TRANSFER:
3267 		li->li_state = LS_DO;
3268 		pool_seterror(POE_BADPARAM);
3269 		return (PO_FAIL);
3270 		break;
3271 	case POOL_XTRANSFER:
3272 		xtransfer = (pool_xtransfer_undo_t *)li->li_details;
3273 
3274 		(void) memcpy(&u_xtransfer, &xtransfer->pxu_ioctl,
3275 		    sizeof (pool_xtransfer_t));
3276 		u_xtransfer.px_o_src_id = elem_get_sysid(xtransfer->pxu_tgt);
3277 		u_xtransfer.px_o_tgt_id = elem_get_sysid(xtransfer->pxu_src);
3278 
3279 		if (ioctl(prov->pkc_fd, POOL_XTRANSFER, &u_xtransfer) < 0) {
3280 			pool_seterror(POE_SYSTEM);
3281 			return (PO_FAIL);
3282 		}
3283 		li->li_state = LS_DO;
3284 		break;
3285 	case POOL_PROPPUT:
3286 		propput = (pool_propput_undo_t *)li->li_details;
3287 
3288 		if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) {
3289 			if (propput->ppu_blist) {
3290 				(void) memcpy(&u_propput, &propput->ppu_ioctl,
3291 				    sizeof (pool_propput_t));
3292 				u_propput.pp_o_id =
3293 				    elem_get_sysid(propput->ppu_elem);
3294 				u_propput.pp_o_buf = NULL;
3295 				if (nvlist_pack(propput->ppu_blist,
3296 				    (char **)&u_propput.pp_o_buf,
3297 				    &u_propput.pp_o_bufsize,
3298 				    NV_ENCODE_NATIVE, 0) != 0) {
3299 					pool_seterror(POE_SYSTEM);
3300 					return (PO_FAIL);
3301 				}
3302 				if (ioctl(prov->pkc_fd, POOL_PROPPUT,
3303 				    &u_propput) < 0) {
3304 					free(u_propput.pp_o_buf);
3305 					pool_seterror(POE_SYSTEM);
3306 					return (PO_FAIL);
3307 				}
3308 				free(u_propput.pp_o_buf);
3309 			} else {
3310 				if (nvlist_unpack(propput->
3311 				    ppu_ioctl.pp_o_buf,
3312 				    propput->ppu_ioctl.pp_o_bufsize,
3313 				    &propput->ppu_alist, 0) != 0) {
3314 					pool_seterror(POE_SYSTEM);
3315 					return (PO_FAIL);
3316 				}
3317 				u_proprm.pp_o_id_type =
3318 				    propput->ppu_ioctl.pp_o_id_type;
3319 				u_proprm.pp_o_id_sub_type =
3320 				    propput->ppu_ioctl.pp_o_id_sub_type;
3321 				u_proprm.pp_o_id =
3322 				    elem_get_sysid(propput->ppu_elem);
3323 				pair = nvlist_next_nvpair(propput->ppu_alist,
3324 				    NULL);
3325 				u_proprm.pp_o_prop_name = nvpair_name(pair);
3326 				u_proprm.pp_o_prop_name_size =
3327 				    strlen(u_proprm.pp_o_prop_name);
3328 
3329 				if (provider_get_prop(propput->ppu_elem,
3330 				    u_proprm.pp_o_prop_name) == NULL) {
3331 					if (ioctl(prov->pkc_fd, POOL_PROPRM,
3332 					    &u_proprm) < 0) {
3333 						nvlist_free(propput->ppu_alist);
3334 						pool_seterror(POE_SYSTEM);
3335 						return (PO_FAIL);
3336 					}
3337 				}
3338 				nvlist_free(propput->ppu_alist);
3339 			}
3340 		}
3341 		li->li_state = LS_DO;
3342 		break;
3343 	case POOL_PROPRM:
3344 		proprm = (pool_proprm_undo_t *)li->li_details;
3345 
3346 		u_propput.pp_o_id_type = proprm->pru_ioctl.pp_o_id_type;
3347 		u_propput.pp_o_id_sub_type =
3348 		    proprm->pru_ioctl.pp_o_id_sub_type;
3349 		u_propput.pp_o_id = elem_get_sysid(proprm->pru_elem);
3350 		u_propput.pp_o_buf = NULL;
3351 		/*
3352 		 * Only try to remove the appropriate property
3353 		 */
3354 		if (nvlist_alloc(&tmplist, NV_UNIQUE_NAME_TYPE, 0) !=
3355 		    0) {
3356 			pool_seterror(POE_SYSTEM);
3357 			return (PO_FAIL);
3358 		}
3359 		if (pool_knl_nvlist_add_value(tmplist,
3360 		    pool_value_get_name(&proprm->pru_oldval),
3361 		    &proprm->pru_oldval) != PO_SUCCESS)
3362 			return (PO_FAIL);
3363 
3364 		if (nvlist_pack(tmplist,
3365 		    (char **)&u_propput.pp_o_buf, &u_propput.pp_o_bufsize,
3366 		    NV_ENCODE_NATIVE, 0) != 0) {
3367 			nvlist_free(tmplist);
3368 			pool_seterror(POE_SYSTEM);
3369 			return (PO_FAIL);
3370 		}
3371 		nvlist_free(tmplist);
3372 		if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) {
3373 			free(u_propput.pp_o_buf);
3374 			pool_seterror(POE_SYSTEM);
3375 			return (PO_FAIL);
3376 		}
3377 		free(u_propput.pp_o_buf);
3378 		li->li_state = LS_DO;
3379 		break;
3380 	default:
3381 		return (PO_FAIL);
3382 	}
3383 		return (PO_SUCCESS);
3384 }
3385 
3386 /*
3387  * A log item stores state about the transaction it represents. This
3388  * function releases the resources associated with the transaction and
3389  * used to store the transaction state.
3390  */
3391 int
3392 log_item_release(log_item_t *li)
3393 {
3394 	pool_create_undo_t *create;
3395 	pool_destroy_undo_t *destroy;
3396 	pool_assoc_undo_t *assoc;
3397 	pool_dissoc_undo_t *dissoc;
3398 	pool_propput_undo_t *propput;
3399 	pool_proprm_undo_t *proprm;
3400 	pool_xtransfer_undo_t *xtransfer;
3401 
3402 	switch (li->li_op) {
3403 	case POOL_CREATE:
3404 		create = (pool_create_undo_t *)li->li_details;
3405 
3406 		free(create);
3407 		break;
3408 	case POOL_DESTROY:
3409 		destroy = (pool_destroy_undo_t *)li->li_details;
3410 
3411 #ifdef DEBUG
3412 		dprintf("log_item_release: POOL_DESTROY\n");
3413 #endif	/* DEBUG */
3414 
3415 		if (li->li_state == LS_UNDO) {
3416 #ifdef DEBUG
3417 			pool_elem_dprintf(destroy->pdu_elem);
3418 #endif	/* DEBUG */
3419 			pool_knl_elem_free((pool_knl_elem_t *)destroy->
3420 			    pdu_elem, PO_TRUE);
3421 		}
3422 		free(destroy);
3423 		break;
3424 	case POOL_ASSOC:
3425 		assoc = (pool_assoc_undo_t *)li->li_details;
3426 
3427 		free(assoc);
3428 		break;
3429 	case POOL_DISSOC:
3430 		dissoc = (pool_dissoc_undo_t *)li->li_details;
3431 
3432 		free(dissoc);
3433 		break;
3434 	case POOL_TRANSFER:
3435 		pool_seterror(POE_BADPARAM);
3436 		return (PO_FAIL);
3437 		break;
3438 	case POOL_XTRANSFER:
3439 		xtransfer = (pool_xtransfer_undo_t *)li->li_details;
3440 
3441 		free(xtransfer->pxu_rl);
3442 		free(xtransfer->pxu_ioctl.px_o_comp_list);
3443 		free(xtransfer);
3444 		break;
3445 	case POOL_PROPPUT:
3446 		propput = (pool_propput_undo_t *)li->li_details;
3447 
3448 		if (propput->ppu_blist)
3449 			nvlist_free(propput->ppu_blist);
3450 		free(propput->ppu_ioctl.pp_o_buf);
3451 		free(propput);
3452 		break;
3453 	case POOL_PROPRM:
3454 		proprm = (pool_proprm_undo_t *)li->li_details;
3455 
3456 		free(proprm);
3457 		break;
3458 	default:
3459 		return (PO_FAIL);
3460 	}
3461 	return (PO_SUCCESS);
3462 }
3463 
3464 /*
3465  * pool_knl_nvlist_add_value() adds a pool_value_t to an nvlist.
3466  */
3467 int
3468 pool_knl_nvlist_add_value(nvlist_t *list, const char *name,
3469     const pool_value_t *pv)
3470 {
3471 	uint64_t uval;
3472 	int64_t ival;
3473 	double dval;
3474 	uchar_t dval_b[sizeof (double)];
3475 	uchar_t bval;
3476 	const char *sval;
3477 	pool_value_class_t type;
3478 	char *nv_name;
3479 
3480 	if ((type = pool_value_get_type(pv)) == POC_INVAL) {
3481 		pool_seterror(POE_BADPARAM);
3482 		return (PO_FAIL);
3483 	}
3484 	nv_name = (char *)name;
3485 
3486 	switch (type) {
3487 	case POC_UINT:
3488 		if (pool_value_get_uint64(pv, &uval) == POC_INVAL) {
3489 			return (PO_FAIL);
3490 		}
3491 		if (nvlist_add_uint64(list, nv_name, uval) != 0) {
3492 			pool_seterror(POE_SYSTEM);
3493 			return (PO_FAIL);
3494 		}
3495 		break;
3496 	case POC_INT:
3497 		if (pool_value_get_int64(pv, &ival) == POC_INVAL) {
3498 			return (PO_FAIL);
3499 		}
3500 		if (nvlist_add_int64(list, nv_name, ival) != 0) {
3501 			pool_seterror(POE_SYSTEM);
3502 			return (PO_FAIL);
3503 		}
3504 		break;
3505 	case POC_DOUBLE:
3506 		if (pool_value_get_double(pv, &dval) == POC_INVAL) {
3507 			return (PO_FAIL);
3508 		}
3509 		/*
3510 		 * Since there is no support for doubles in the
3511 		 * kernel, store the double value in a byte array.
3512 		 */
3513 		(void) memcpy(dval_b, &dval, sizeof (double));
3514 		if (nvlist_add_byte_array(list, nv_name, dval_b,
3515 		    sizeof (double)) != 0) {
3516 			pool_seterror(POE_SYSTEM);
3517 			return (PO_FAIL);
3518 		}
3519 		break;
3520 	case POC_BOOL:
3521 		if (pool_value_get_bool(pv, &bval) == POC_INVAL) {
3522 			return (PO_FAIL);
3523 		}
3524 		if (nvlist_add_byte(list, nv_name, bval) != 0) {
3525 			pool_seterror(POE_SYSTEM);
3526 			return (PO_FAIL);
3527 		}
3528 		break;
3529 	case POC_STRING:
3530 		if (pool_value_get_string(pv, &sval) == POC_INVAL) {
3531 			return (PO_FAIL);
3532 		}
3533 		if (nvlist_add_string(list, nv_name, (char *)sval) != 0) {
3534 			pool_seterror(POE_SYSTEM);
3535 			return (PO_FAIL);
3536 		}
3537 		break;
3538 	default:
3539 		pool_seterror(POE_BADPARAM);
3540 		return (PO_FAIL);
3541 	}
3542 	return (PO_SUCCESS);
3543 }
3544 
3545 /*
3546  * hash_id() hashes all elements in a pool configuration using the
3547  * "sys_id" property. Not all elements have a "sys_id" property,
3548  * however elem_get_sysid() caters for this by always returning a
3549  * constant value for those elements. This isn't anticipated to lead
3550  * to a performance degradation in the hash, since those elements
3551  * which are likely to be most prevalent in a configuration do have
3552  * "sys_id" as a property.
3553  */
3554 uint64_t
3555 hash_id(const pool_elem_t *pe)
3556 {
3557 	id_t id;
3558 
3559 	id = elem_get_sysid(pe);
3560 	return (hash_buf(&id, sizeof (id)));
3561 }
3562 
3563 /*
3564  *  blocking_open() guarantees access to the pool device, if open()
3565  * is failing with EBUSY.
3566  */
3567 int
3568 blocking_open(const char *path, int oflag)
3569 {
3570 	int fd;
3571 
3572 	while ((fd = open(path, oflag)) == -1 && errno == EBUSY)
3573 		(void) poll(NULL, 0, 1 * MILLISEC);
3574 
3575 	return (fd);
3576 }
3577