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