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