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