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