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