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 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 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 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 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 * 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 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 668 remove_dead_elems(const void *key, void **value, void *cl) 669 { 670 pool_knl_elem_t *pke = (pool_knl_elem_t *)key; 671 pool_conf_t *conf = TO_CONF(TO_ELEM(pke)); 672 pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; 673 674 assert(dict_remove(prov->pkc_elements, pke) != NULL); 675 #ifdef DEBUG 676 dprintf("remove_dead_elems:\n"); 677 pool_elem_dprintf(TO_ELEM(pke)); 678 #endif /* DEBUG */ 679 pool_knl_elem_free(pke, PO_TRUE); 680 } 681 682 /* 683 * Find elements which were not updated the last time that 684 * load_group() was called. Add those elements into a separate map 685 * (passed in cl) which will be later used to remove these elements 686 * from the configuration map. 687 */ 688 /* ARGSUSED1 */ 689 static void 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 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 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 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 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 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 921 pool_knl_export(const pool_conf_t *conf, const char *location, 922 pool_export_format_t fmt) 923 { 924 xmlNodePtr node_comment; 925 xmlNodePtr system; 926 int ret; 927 pool_t **ps; 928 pool_resource_t **rs; 929 uint_t nelem; 930 int i; 931 struct knl_to_xml info; 932 char_buf_t *cb = NULL; 933 xmlValidCtxtPtr cvp; 934 935 xml_init(); 936 937 938 switch (fmt) { 939 case POX_NATIVE: 940 info.ktx_doc = xmlNewDoc(BAD_CAST "1.0"); 941 (void) xmlCreateIntSubset(info.ktx_doc, BAD_CAST "system", 942 BAD_CAST "-//Sun Microsystems Inc//DTD Resource " 943 "Management All//EN", 944 BAD_CAST dtd_location); 945 946 if ((cvp = xmlNewValidCtxt()) == NULL) { 947 xmlFreeDoc(info.ktx_doc); 948 pool_seterror(POE_DATASTORE); 949 return (PO_FAIL); 950 } 951 /* 952 * Call xmlValidateDocument() to force the parsing of 953 * the DTD. Ignore errors and warning messages as we 954 * know the document isn't valid. 955 */ 956 (void) xmlValidateDocument(cvp, info.ktx_doc); 957 xmlFreeValidCtxt(cvp); 958 if ((info.ktx_node = node_create(NULL, BAD_CAST "system")) == 959 NULL) { 960 xmlFreeDoc(info.ktx_doc); 961 pool_seterror(POE_DATASTORE); 962 return (PO_FAIL); 963 } 964 965 system = info.ktx_node; 966 info.ktx_doc->_private = (void *)conf; 967 968 (void) xmlDocSetRootElement(info.ktx_doc, info.ktx_node); 969 (void) xmlSetProp(info.ktx_node, BAD_CAST c_ref_id, 970 BAD_CAST "dummy"); 971 if ((node_comment = xmlNewDocComment(info.ktx_doc, 972 BAD_CAST "\nConfiguration for pools facility. Do NOT" 973 " edit this file by hand - use poolcfg(1)" 974 " or libpool(3POOL) instead.\n")) == NULL) { 975 xmlFreeDoc(info.ktx_doc); 976 pool_seterror(POE_DATASTORE); 977 return (PO_FAIL); 978 } 979 if (xmlAddPrevSibling(info.ktx_node, node_comment) == NULL) { 980 xmlFree(node_comment); 981 xmlFreeDoc(info.ktx_doc); 982 pool_seterror(POE_DATASTORE); 983 return (PO_FAIL); 984 } 985 if (pool_walk_any_properties((pool_conf_t *)conf, 986 pool_conf_to_elem(conf), &info, prop_build_cb, 1) == 987 PO_FAIL) { 988 xmlFreeDoc(info.ktx_doc); 989 return (PO_FAIL); 990 } 991 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 992 xmlFreeDoc(info.ktx_doc); 993 return (PO_FAIL); 994 } 995 /* 996 * Now add pool details 997 */ 998 if ((ps = pool_query_pools(conf, &nelem, NULL)) != NULL) { 999 for (i = 0; i < nelem; i++) { 1000 pool_elem_t *elem = TO_ELEM(ps[i]); 1001 uint_t nreselem; 1002 const char *sep = ""; 1003 int j; 1004 1005 if (elem_is_tmp(elem)) 1006 continue; 1007 1008 if ((info.ktx_node = node_create(system, 1009 BAD_CAST element_class_tags 1010 [pool_elem_class(elem)])) == NULL) { 1011 free(ps); 1012 free_char_buf(cb); 1013 xmlFreeDoc(info.ktx_doc); 1014 pool_seterror(POE_DATASTORE); 1015 return (PO_FAIL); 1016 } 1017 if (pool_walk_any_properties( 1018 (pool_conf_t *)conf, 1019 elem, &info, prop_build_cb, 1) == PO_FAIL) { 1020 free(ps); 1021 free_char_buf(cb); 1022 xmlFreeDoc(info.ktx_doc); 1023 return (PO_FAIL); 1024 } 1025 /* 1026 * TODO: pset specific res manipulation 1027 */ 1028 if ((rs = pool_query_pool_resources(conf, ps[i], 1029 &nreselem, NULL)) == NULL) { 1030 free(ps); 1031 free_char_buf(cb); 1032 xmlFreeDoc(info.ktx_doc); 1033 pool_seterror(POE_INVALID_CONF); 1034 return (PO_FAIL); 1035 } 1036 if (set_char_buf(cb, "") == PO_FAIL) { 1037 free(rs); 1038 free(ps); 1039 free_char_buf(cb); 1040 xmlFreeDoc(info.ktx_doc); 1041 return (PO_FAIL); 1042 } 1043 for (j = 0; j < nreselem; j++) { 1044 pool_elem_t *reselem = TO_ELEM(rs[j]); 1045 if (append_char_buf(cb, "%s%s_%d", sep, 1046 pool_elem_class_string(reselem), 1047 (int)elem_get_sysid(reselem)) == 1048 PO_FAIL) { 1049 free(rs); 1050 free(ps); 1051 free_char_buf(cb); 1052 xmlFreeDoc(info.ktx_doc); 1053 return (PO_FAIL); 1054 } 1055 sep = " "; 1056 } 1057 free(rs); 1058 (void) xmlSetProp(info.ktx_node, BAD_CAST "res", 1059 BAD_CAST cb->cb_buf); 1060 if (set_char_buf(cb, "%s_%d", 1061 pool_elem_class_string(elem), 1062 (int)elem_get_sysid(elem)) == PO_FAIL) { 1063 free(ps); 1064 free_char_buf(cb); 1065 xmlFreeDoc(info.ktx_doc); 1066 return (PO_FAIL); 1067 } 1068 (void) xmlSetProp(info.ktx_node, 1069 BAD_CAST c_ref_id, 1070 BAD_CAST cb->cb_buf); 1071 } 1072 free(ps); 1073 } 1074 /* 1075 * Now add resource details (including components) 1076 */ 1077 if ((rs = pool_query_resources(conf, &nelem, NULL)) != NULL) { 1078 for (i = 0; i < nelem; i++) { 1079 pool_elem_t *elem = TO_ELEM(rs[i]); 1080 pool_component_t **cs = NULL; 1081 uint_t ncompelem; 1082 int j; 1083 1084 if (elem_is_tmp(elem)) 1085 continue; 1086 1087 if ((info.ktx_node = node_create(system, 1088 BAD_CAST element_class_tags 1089 [pool_elem_class(elem)])) == NULL) { 1090 free(rs); 1091 free_char_buf(cb); 1092 xmlFreeDoc(info.ktx_doc); 1093 pool_seterror(POE_DATASTORE); 1094 return (PO_FAIL); 1095 } 1096 if (pool_walk_any_properties( 1097 (pool_conf_t *)conf, 1098 elem, &info, prop_build_cb, 1) == PO_FAIL) { 1099 free(rs); 1100 free_char_buf(cb); 1101 xmlFreeDoc(info.ktx_doc); 1102 return (PO_FAIL); 1103 } 1104 if (set_char_buf(cb, "%s_%d", 1105 pool_elem_class_string(elem), 1106 (int)elem_get_sysid(elem)) == PO_FAIL) { 1107 free(rs); 1108 free_char_buf(cb); 1109 xmlFreeDoc(info.ktx_doc); 1110 return (PO_FAIL); 1111 } 1112 (void) xmlSetProp(info.ktx_node, 1113 BAD_CAST c_ref_id, 1114 BAD_CAST cb->cb_buf); 1115 if ((cs = pool_query_resource_components(conf, 1116 rs[i], &ncompelem, NULL)) != NULL) { 1117 xmlNodePtr resource = info.ktx_node; 1118 1119 for (j = 0; j < ncompelem; j++) { 1120 pool_elem_t *compelem = 1121 TO_ELEM(cs[j]); 1122 if ((info.ktx_node = 1123 node_create(resource, 1124 BAD_CAST element_class_tags 1125 [pool_elem_class( 1126 compelem)])) == NULL) { 1127 pool_seterror( 1128 POE_DATASTORE); 1129 free(rs); 1130 free(cs); 1131 free_char_buf(cb); 1132 xmlFreeDoc(info. 1133 ktx_doc); 1134 return (PO_FAIL); 1135 } 1136 if (pool_walk_any_properties( 1137 (pool_conf_t *)conf, 1138 compelem, &info, 1139 prop_build_cb, 1) == 1140 PO_FAIL) { 1141 free(rs); 1142 free(cs); 1143 free_char_buf(cb); 1144 xmlFreeDoc(info. 1145 ktx_doc); 1146 return (PO_FAIL); 1147 } 1148 if (set_char_buf(cb, "%s_%d", 1149 pool_elem_class_string( 1150 compelem), 1151 (int)elem_get_sysid( 1152 compelem)) == PO_FAIL) { 1153 free(rs); 1154 free(cs); 1155 free_char_buf(cb); 1156 xmlFreeDoc(info. 1157 ktx_doc); 1158 return (PO_FAIL); 1159 } 1160 (void) xmlSetProp(info.ktx_node, 1161 BAD_CAST c_ref_id, 1162 BAD_CAST cb->cb_buf); 1163 } 1164 free(cs); 1165 } 1166 } 1167 free(rs); 1168 } 1169 free_char_buf(cb); 1170 /* 1171 * Set up the message handlers prior to calling 1172 * xmlValidateDocument() 1173 */ 1174 if ((cvp = xmlNewValidCtxt()) == NULL) { 1175 xmlFreeDoc(info.ktx_doc); 1176 pool_seterror(POE_DATASTORE); 1177 return (PO_FAIL); 1178 } 1179 cvp->error = pool_error_func; 1180 cvp->warning = pool_error_func; 1181 if (xmlValidateDocument(cvp, info.ktx_doc) == 0) { 1182 xmlFreeValidCtxt(cvp); 1183 xmlFreeDoc(info.ktx_doc); 1184 pool_seterror(POE_INVALID_CONF); 1185 return (PO_FAIL); 1186 } 1187 xmlFreeValidCtxt(cvp); 1188 ret = xmlSaveFormatFile(location, info.ktx_doc, 1); 1189 xmlFreeDoc(info.ktx_doc); 1190 if (ret == -1) { 1191 pool_seterror(POE_SYSTEM); 1192 return (PO_FAIL); 1193 } 1194 return (PO_SUCCESS); 1195 default: 1196 pool_seterror(POE_BADPARAM); 1197 return (PO_FAIL); 1198 } 1199 } 1200 1201 /* 1202 * Rollback the changes to the kernel 1203 */ 1204 int 1205 pool_knl_recover(pool_conf_t *conf) 1206 { 1207 pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; 1208 1209 prov->pkc_log->l_state = LS_RECOVER; 1210 if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) { 1211 dprintf("Library configuration consistency error\n"); 1212 prov->pkc_log->l_state = LS_FAIL; 1213 pool_seterror(POE_INVALID_CONF); 1214 return (PO_FAIL); 1215 } 1216 prov->pkc_log->l_state = LS_DO; 1217 return (PO_SUCCESS); 1218 } 1219 1220 /* 1221 * Rollback the changes to the configuration 1222 */ 1223 int 1224 pool_knl_rollback(pool_conf_t *conf) 1225 { 1226 pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov; 1227 1228 prov->pkc_log->l_state = LS_UNDO; 1229 if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) { 1230 dprintf("Kernel configuration consistency error\n"); 1231 (void) log_walk(prov->pkc_log, log_item_release); 1232 log_empty(prov->pkc_log); 1233 prov->pkc_log->l_state = LS_FAIL; 1234 pool_seterror(POE_INVALID_CONF); 1235 return (PO_FAIL); 1236 } 1237 (void) log_walk(prov->pkc_log, log_item_release); 1238 log_empty(prov->pkc_log); 1239 prov->pkc_log->l_state = LS_DO; 1240 return (PO_SUCCESS); 1241 } 1242 1243 /* 1244 * Callback used to build the result set for a query. Each invocation will 1245 * supply a candidate element for inclusion. The element is filtered by: 1246 * - class 1247 * - properties 1248 * If the element "matches" the target, then it is added to the result 1249 * set, otherwise it is ignored. 1250 */ 1251 /* ARGSUSED1 */ 1252 static void 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 * 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 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 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 * 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 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 * 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 * 1593 pool_knl_elem_wrap(pool_conf_t *conf, pool_elem_class_t class, 1594 pool_resource_elem_class_t res_class, 1595 pool_component_elem_class_t comp_class) 1596 { 1597 pool_knl_elem_t *elem; 1598 pool_elem_t *pe; 1599 1600 switch (class) { 1601 case PEC_SYSTEM: 1602 if ((elem = malloc(sizeof (pool_knl_system_t))) == NULL) { 1603 pool_seterror(POE_SYSTEM); 1604 return (NULL); 1605 } 1606 (void) memset(elem, 0, sizeof (pool_knl_system_t)); 1607 break; 1608 case PEC_POOL: 1609 if ((elem = malloc(sizeof (pool_knl_pool_t))) == NULL) { 1610 pool_seterror(POE_SYSTEM); 1611 return (NULL); 1612 } 1613 (void) memset(elem, 0, sizeof (pool_knl_pool_t)); 1614 break; 1615 case PEC_RES_COMP: 1616 case PEC_RES_AGG: 1617 if ((elem = malloc(sizeof (pool_knl_resource_t))) == NULL) { 1618 pool_seterror(POE_SYSTEM); 1619 return (NULL); 1620 } 1621 (void) memset(elem, 0, sizeof (pool_knl_resource_t)); 1622 break; 1623 case PEC_COMP: 1624 if ((elem = malloc(sizeof (pool_knl_component_t))) == NULL) { 1625 pool_seterror(POE_SYSTEM); 1626 return (NULL); 1627 } 1628 (void) memset(elem, 0, sizeof (pool_knl_component_t)); 1629 break; 1630 default: 1631 pool_seterror(POE_BADPARAM); 1632 return (NULL); 1633 } 1634 pe = TO_ELEM(elem); 1635 pe->pe_conf = conf; 1636 pe->pe_class = class; 1637 pe->pe_resource_class = res_class; 1638 pe->pe_component_class = comp_class; 1639 /* Set up the function pointers for element manipulation */ 1640 pe->pe_get_prop = pool_knl_get_property; 1641 pe->pe_put_prop = pool_knl_put_property; 1642 pe->pe_rm_prop = pool_knl_rm_property; 1643 pe->pe_get_props = pool_knl_get_properties; 1644 pe->pe_remove = pool_knl_elem_remove; 1645 pe->pe_get_container = pool_knl_get_container; 1646 pe->pe_set_container = pool_knl_set_container; 1647 /* 1648 * Specific initialisation for different types of element 1649 */ 1650 if (class == PEC_POOL) { 1651 pool_knl_pool_t *pp = (pool_knl_pool_t *)elem; 1652 pp->pp_associate = pool_knl_pool_associate; 1653 pp->pp_dissociate = pool_knl_pool_dissociate; 1654 pp->pkp_assoc[PREC_PSET] = (pool_knl_resource_t *) 1655 resource_by_sysid(conf, PS_NONE, "pset"); 1656 } 1657 if (class == PEC_RES_COMP || class == PEC_RES_AGG) { 1658 pool_knl_resource_t *pr = (pool_knl_resource_t *)elem; 1659 pr->pr_is_system = pool_knl_resource_is_system; 1660 pr->pr_can_associate = pool_knl_resource_can_associate; 1661 } 1662 #if DEBUG 1663 if (dict_put(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks, 1664 elem, elem) != NULL) 1665 assert(!"leak map put failed"); 1666 dprintf("allocated %p\n", elem); 1667 #endif /* DEBUG */ 1668 return (elem); 1669 } 1670 1671 /* 1672 * Allocate a new pool_knl_elem_t in the supplied configuration of the 1673 * specified class. 1674 * Returns element pointer/NULL 1675 */ 1676 pool_elem_t * 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 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 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 1853 pool_knl_res_transfer(pool_resource_t *src, pool_resource_t *tgt, 1854 uint64_t size) { 1855 return (PO_FAIL); 1856 } 1857 1858 /* 1859 * Transfer resource components from one resource set to another. 1860 */ 1861 int 1862 pool_knl_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt, 1863 pool_component_t **rl) { 1864 pool_elem_t *src_e = TO_ELEM(src); 1865 pool_elem_t *tgt_e = TO_ELEM(tgt); 1866 pool_xtransfer_undo_t *xtransfer; 1867 size_t size; 1868 pool_knl_connection_t *prov = 1869 (pool_knl_connection_t *)TO_CONF(src_e)->pc_prov; 1870 1871 if (prov->pkc_log->l_state != LS_DO) { 1872 /* 1873 * Walk the Result Set and move the resource components 1874 */ 1875 for (size = 0; rl[size] != NULL; size++) { 1876 if (pool_set_container(TO_ELEM(tgt), 1877 TO_ELEM(rl[size])) == PO_FAIL) { 1878 return (PO_FAIL); 1879 } 1880 } 1881 return (PO_SUCCESS); 1882 } 1883 1884 /* 1885 * The remaining logic is setting up the arguments for the 1886 * POOL_XTRANSFER ioctl and appending the details into the log. 1887 */ 1888 if ((xtransfer = malloc(sizeof (pool_xtransfer_undo_t))) == NULL) { 1889 pool_seterror(POE_SYSTEM); 1890 return (PO_FAIL); 1891 } 1892 1893 if (pool_elem_class(src_e) == PEC_RES_COMP) { 1894 xtransfer->pxu_ioctl.px_o_id_type = 1895 pool_resource_elem_class(src_e); 1896 } else { 1897 pool_seterror(POE_BADPARAM); 1898 return (PO_FAIL); 1899 } 1900 1901 1902 for (xtransfer->pxu_ioctl.px_o_complist_size = 0; 1903 rl[xtransfer->pxu_ioctl.px_o_complist_size] != NULL; 1904 xtransfer->pxu_ioctl.px_o_complist_size++) 1905 /* calculate the size using the terminating NULL */; 1906 if ((xtransfer->pxu_ioctl.px_o_comp_list = 1907 calloc(xtransfer->pxu_ioctl.px_o_complist_size, 1908 sizeof (id_t))) == NULL) { 1909 pool_seterror(POE_SYSTEM); 1910 return (PO_FAIL); 1911 } 1912 if ((xtransfer->pxu_rl = calloc( 1913 xtransfer->pxu_ioctl.px_o_complist_size + 1, 1914 sizeof (pool_component_t *))) == NULL) { 1915 pool_seterror(POE_SYSTEM); 1916 return (PO_FAIL); 1917 } 1918 (void) memcpy(xtransfer->pxu_rl, rl, 1919 xtransfer->pxu_ioctl.px_o_complist_size * 1920 sizeof (pool_component_t *)); 1921 xtransfer->pxu_src = src_e; 1922 xtransfer->pxu_tgt = tgt_e; 1923 1924 if (log_append(prov->pkc_log, POOL_XTRANSFER, (void *)xtransfer) != 1925 PO_SUCCESS) { 1926 free(xtransfer); 1927 return (PO_FAIL); 1928 } 1929 for (size = 0; rl[size] != NULL; size++) { 1930 if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[size])) == 1931 PO_FAIL) { 1932 return (PO_FAIL); 1933 } 1934 } 1935 return (PO_SUCCESS); 1936 } 1937 1938 /* 1939 * Return the parent of an element. 1940 */ 1941 pool_elem_t * 1942 pool_knl_get_container(const pool_elem_t *pe) 1943 { 1944 pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; 1945 1946 return ((pool_elem_t *)pke->pke_parent); 1947 } 1948 1949 /* 1950 * Note: This function is resource specific, needs extending for other 1951 * resource types 1952 */ 1953 int 1954 pool_knl_resource_is_system(const pool_resource_t *pr) 1955 { 1956 switch (pool_resource_elem_class(TO_ELEM(pr))) { 1957 case PREC_PSET: 1958 return (PSID_IS_SYSSET( 1959 elem_get_sysid(TO_ELEM(pr)))); 1960 default: 1961 return (PO_FALSE); 1962 } 1963 } 1964 1965 /* 1966 * Note: This function is resource specific, needs extending for other 1967 * resource types 1968 */ 1969 int 1970 pool_knl_resource_can_associate(const pool_resource_t *pr) 1971 { 1972 switch (pool_resource_elem_class(TO_ELEM(pr))) { 1973 case PREC_PSET: 1974 return (PO_TRUE); 1975 default: 1976 return (PO_FALSE); 1977 } 1978 } 1979 1980 /* 1981 * pool_knl_pool_associate() associates the supplied resource to the 1982 * supplied pool. 1983 * 1984 * Returns: PO_SUCCESS/PO_FAIL 1985 */ 1986 int 1987 pool_knl_pool_associate(pool_t *pool, const pool_resource_t *resource) 1988 { 1989 pool_knl_connection_t *prov; 1990 pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool; 1991 pool_resource_elem_class_t res_class = 1992 pool_resource_elem_class(TO_ELEM(resource)); 1993 pool_assoc_undo_t *assoc; 1994 pool_knl_resource_t *orig_res = pkp->pkp_assoc[res_class]; 1995 1996 /* 1997 * Are we allowed to associate with this target? 1998 */ 1999 if (pool_knl_resource_can_associate(resource) == PO_FALSE) { 2000 pool_seterror(POE_BADPARAM); 2001 return (PO_FAIL); 2002 } 2003 prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov; 2004 2005 if (prov->pkc_log->l_state != LS_DO) { 2006 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource; 2007 return (PO_SUCCESS); 2008 } 2009 2010 /* 2011 * The remaining logic is setting up the arguments for the 2012 * POOL_ASSOC ioctl and appending the details into the log. 2013 */ 2014 if ((assoc = malloc(sizeof (pool_assoc_undo_t))) == NULL) { 2015 pool_seterror(POE_SYSTEM); 2016 return (PO_FAIL); 2017 } 2018 assoc->pau_assoc = TO_ELEM(pool); 2019 assoc->pau_oldres = (pool_elem_t *)orig_res; 2020 assoc->pau_newres = TO_ELEM(resource); 2021 2022 assoc->pau_ioctl.pa_o_id_type = res_class; 2023 2024 if (log_append(prov->pkc_log, POOL_ASSOC, (void *)assoc) != 2025 PO_SUCCESS) { 2026 free(assoc); 2027 pkp->pkp_assoc[res_class] = orig_res; 2028 return (PO_FAIL); 2029 } 2030 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource; 2031 return (PO_SUCCESS); 2032 } 2033 2034 /* 2035 * pool_knl_pool_dissociate() dissociates the supplied resource from 2036 * the supplied pool. 2037 * 2038 * Returns: PO_SUCCESS/PO_FAIL 2039 */ 2040 int 2041 pool_knl_pool_dissociate(pool_t *pool, const pool_resource_t *resource) 2042 { 2043 pool_knl_connection_t *prov; 2044 pool_dissoc_undo_t *dissoc; 2045 pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool; 2046 pool_resource_t *default_res = (pool_resource_t *)get_default_resource( 2047 resource); 2048 pool_resource_elem_class_t res_class = 2049 pool_resource_elem_class(TO_ELEM(resource)); 2050 2051 prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov; 2052 2053 if (prov->pkc_log->l_state != LS_DO) { 2054 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res; 2055 return (PO_SUCCESS); 2056 } 2057 /* 2058 * The remaining logic is setting up the arguments for the 2059 * POOL_DISSOC ioctl and appending the details into the log. 2060 */ 2061 if ((dissoc = malloc(sizeof (pool_dissoc_undo_t))) == NULL) { 2062 pool_seterror(POE_SYSTEM); 2063 return (PO_FAIL); 2064 } 2065 dissoc->pdu_dissoc = TO_ELEM(pool); 2066 dissoc->pdu_oldres = TO_ELEM(resource); 2067 dissoc->pdu_newres = TO_ELEM(default_res); 2068 2069 dissoc->pdu_ioctl.pd_o_id_type = res_class; 2070 2071 if (log_append(prov->pkc_log, POOL_DISSOC, (void *)dissoc) != 2072 PO_SUCCESS) { 2073 free(dissoc); 2074 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource; 2075 return (PO_FAIL); 2076 } 2077 2078 /* 2079 * Update our local copy 2080 */ 2081 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res; 2082 return (PO_SUCCESS); 2083 } 2084 2085 /* 2086 * Allocate a data provider for the supplied configuration and optionally 2087 * discover resources. 2088 * The data provider is the cross over point from the "abstract" configuration 2089 * functions into the data representation specific manipulation routines. 2090 * This function sets up all the required pointers to create a kernel aware 2091 * data provider. 2092 * Returns PO_SUCCESS/PO_FAIL 2093 */ 2094 int 2095 pool_knl_connection_alloc(pool_conf_t *conf, int oflags) 2096 { 2097 pool_knl_connection_t *prov; 2098 2099 if ((prov = malloc(sizeof (pool_knl_connection_t))) == NULL) { 2100 pool_seterror(POE_SYSTEM); 2101 return (PO_FAIL); 2102 } 2103 (void) memset(prov, 0, sizeof (pool_knl_connection_t)); 2104 /* 2105 * Initialise data members 2106 */ 2107 prov->pc_name = strdup("kernel"); 2108 prov->pc_store_type = KERNEL_DATA_STORE; 2109 prov->pc_oflags = oflags; 2110 /* 2111 * Initialise function pointers 2112 */ 2113 prov->pc_close = pool_knl_close; 2114 prov->pc_validate = pool_knl_validate; 2115 prov->pc_commit = pool_knl_commit; 2116 prov->pc_export = pool_knl_export; 2117 prov->pc_rollback = pool_knl_rollback; 2118 prov->pc_exec_query = pool_knl_exec_query; 2119 prov->pc_elem_create = pool_knl_elem_create; 2120 prov->pc_remove = pool_knl_remove; 2121 prov->pc_res_xfer = pool_knl_res_transfer; 2122 prov->pc_res_xxfer = pool_knl_res_xtransfer; 2123 prov->pc_get_binding = pool_knl_get_binding; 2124 prov->pc_set_binding = pool_knl_set_binding; 2125 prov->pc_get_resource_binding = pool_knl_get_resource_binding; 2126 /* 2127 * Associate the provider to it's configuration 2128 */ 2129 conf->pc_prov = (pool_connection_t *)prov; 2130 /* 2131 * End of common initialisation 2132 */ 2133 /* 2134 * Attempt to open the pseudo device, if the configuration is opened 2135 * readonly then try to open an info device, otherwise try to open 2136 * the writeable device. 2137 */ 2138 if (oflags & PO_RDWR) { 2139 if ((prov->pkc_fd = blocking_open(pool_dynamic_location(), 2140 O_RDWR)) < 0) { 2141 free(prov); 2142 conf->pc_prov = NULL; 2143 pool_seterror(POE_SYSTEM); 2144 return (PO_FAIL); 2145 } 2146 } else { 2147 if ((prov->pkc_fd = open(pool_info_location, O_RDWR)) < 0) { 2148 free(prov); 2149 conf->pc_prov = NULL; 2150 pool_seterror(POE_SYSTEM); 2151 return (PO_FAIL); 2152 } 2153 } 2154 /* 2155 * Allocate the element dictionary 2156 */ 2157 if ((prov->pkc_elements = dict_new((int (*)(const void *, const void *)) 2158 pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) { 2159 (void) close(prov->pkc_fd); 2160 free(prov); 2161 conf->pc_prov = NULL; 2162 pool_seterror(POE_SYSTEM); 2163 return (PO_FAIL); 2164 } 2165 #if DEBUG 2166 if ((prov->pkc_leaks = dict_new(NULL, NULL)) == NULL) { 2167 dict_free(&prov->pkc_elements); 2168 (void) close(prov->pkc_fd); 2169 free(prov); 2170 conf->pc_prov = NULL; 2171 pool_seterror(POE_SYSTEM); 2172 return (PO_FAIL); 2173 } 2174 #endif /* DEBUG */ 2175 /* 2176 * Allocate the transaction log 2177 */ 2178 if ((prov->pkc_log = log_alloc(conf)) == NULL) { 2179 #if DEBUG 2180 dict_free(&prov->pkc_leaks); 2181 #endif /* DEBUG */ 2182 dict_free(&prov->pkc_elements); 2183 (void) close(prov->pkc_fd); 2184 free(prov); 2185 conf->pc_prov = NULL; 2186 return (PO_FAIL); 2187 } 2188 /* 2189 * At this point the configuration provider has been initialized, 2190 * mark the configuration as valid so that the various routines 2191 * which rely on a valid configuration will work correctly. 2192 */ 2193 conf->pc_state = POF_VALID; 2194 /* 2195 * Update the library snapshot from the kernel 2196 */ 2197 if (pool_knl_update(conf, NULL) != PO_SUCCESS) { 2198 #if DEBUG 2199 dict_free(&prov->pkc_leaks); 2200 #endif /* DEBUG */ 2201 dict_free(&prov->pkc_elements); 2202 (void) close(prov->pkc_fd); 2203 free(prov); 2204 conf->pc_prov = NULL; 2205 conf->pc_state = POF_INVALID; 2206 return (PO_FAIL); 2207 } 2208 return (PO_SUCCESS); 2209 } 2210 2211 #if DEBUG 2212 static void 2213 pool_knl_elem_printf_cb(const void *key, void **value, void *cl) 2214 { 2215 pool_knl_elem_t *pke = (pool_knl_elem_t *)key; 2216 dict_hdl_t *map = (dict_hdl_t *)cl; 2217 2218 dprintf("leak elem:%p\n", pke); 2219 if (pke->pke_properties != NULL) { 2220 nvlist_print(stdout, pke->pke_properties); 2221 } else 2222 dprintf("no properties\n"); 2223 assert(dict_get(map, pke) == NULL); 2224 } 2225 #endif /* DEBUG */ 2226 /* 2227 * pool_knl_elem_free() releases the resources associated with the 2228 * supplied element. 2229 */ 2230 static void 2231 pool_knl_elem_free(pool_knl_elem_t *pke, int freeprop) 2232 { 2233 #if DEBUG 2234 pool_conf_t *conf = TO_CONF(TO_ELEM(pke)); 2235 if (dict_remove(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks, 2236 pke) == NULL) 2237 dprintf("%p, wasn't in the leak map\n", pke); 2238 if (freeprop == PO_TRUE) { 2239 pool_elem_dprintf(TO_ELEM(pke)); 2240 } 2241 dprintf("released %p\n", pke); 2242 #endif /* DEBUG */ 2243 if (freeprop == PO_TRUE) { 2244 nvlist_free(pke->pke_properties); 2245 } 2246 free(pke); 2247 } 2248 2249 /* 2250 * pool_knl_elem_free_cb() is designed to be used with 2251 * dict_map(). When a connection is freed, this function is used to 2252 * free all element resources. 2253 */ 2254 /* ARGSUSED1 */ 2255 static void 2256 pool_knl_elem_free_cb(const void *key, void **value, void *cl) 2257 { 2258 pool_knl_elem_t *pke = (pool_knl_elem_t *)key; 2259 2260 #ifdef DEBUG 2261 dprintf("pool_knl_elem_free_cb:\n"); 2262 dprintf("about to release %p ", pke); 2263 pool_elem_dprintf(TO_ELEM(pke)); 2264 #endif /* DEBUG */ 2265 pool_knl_elem_free(pke, PO_TRUE); 2266 } 2267 2268 /* 2269 * Free the resources for a kernel data provider. 2270 */ 2271 void 2272 pool_knl_connection_free(pool_knl_connection_t *prov) 2273 { 2274 if (prov->pkc_log != NULL) { 2275 (void) log_walk(prov->pkc_log, log_item_release); 2276 log_free(prov->pkc_log); 2277 } 2278 if (prov->pkc_elements != NULL) { 2279 dict_map(prov->pkc_elements, pool_knl_elem_free_cb, NULL); 2280 #if DEBUG 2281 dprintf("dict length is %llu\n", dict_length(prov->pkc_leaks)); 2282 dict_map(prov->pkc_leaks, pool_knl_elem_printf_cb, 2283 prov->pkc_elements); 2284 assert(dict_length(prov->pkc_leaks) == 0); 2285 dict_free(&prov->pkc_leaks); 2286 #endif /* DEBUG */ 2287 dict_free(&prov->pkc_elements); 2288 } 2289 free((void *)prov->pc_name); 2290 free(prov); 2291 } 2292 2293 /* 2294 * Return the specified property value. 2295 * 2296 * POC_INVAL is returned if an error is detected and the error code is updated 2297 * to indicate the cause of the error. 2298 */ 2299 pool_value_class_t 2300 pool_knl_get_property(const pool_elem_t *pe, const char *name, 2301 pool_value_t *val) 2302 { 2303 pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; 2304 nvpair_t *pair; 2305 const pool_prop_t *prop; 2306 2307 if ((prop = provider_get_prop(pe, name)) != NULL) 2308 if (prop_is_stored(prop) == PO_FALSE) 2309 return (pool_knl_get_dynamic_property(pe, name, val)); 2310 2311 if ((pair = pool_knl_find_nvpair(pke->pke_properties, name)) == NULL) { 2312 pool_seterror(POE_BADPARAM); 2313 return (POC_INVAL); 2314 } 2315 2316 if (pool_value_from_nvpair(val, pair) == PO_FAIL) { 2317 return (POC_INVAL); 2318 } 2319 2320 return (pool_value_get_type(val)); 2321 } 2322 2323 /* 2324 * Return the specified property value. 2325 * 2326 * If a property is designated as dynamic, then this function will 2327 * always try to return the latest value of the property from the 2328 * kernel. 2329 * 2330 * POC_INVAL is returned if an error is detected and the error code is updated 2331 * to indicate the cause of the error. 2332 */ 2333 pool_value_class_t 2334 pool_knl_get_dynamic_property(const pool_elem_t *pe, const char *name, 2335 pool_value_t *val) 2336 { 2337 pool_knl_connection_t *prov; 2338 pool_propget_t propget = { 0 }; 2339 nvlist_t *proplist; 2340 nvpair_t *pair; 2341 2342 propget.pp_o_id_type = pool_elem_class(pe); 2343 if (pool_elem_class(pe) == PEC_RES_COMP || 2344 pool_elem_class(pe) == PEC_RES_AGG) 2345 propget.pp_o_id_subtype = pool_resource_elem_class(pe); 2346 if (pool_elem_class(pe) == PEC_COMP) 2347 propget.pp_o_id_subtype = 2348 (pool_resource_elem_class_t)pool_component_elem_class(pe); 2349 2350 propget.pp_o_id = elem_get_sysid(pe); 2351 propget.pp_o_prop_name_size = strlen(name); 2352 propget.pp_o_prop_name = (char *)name; 2353 propget.pp_i_bufsize = KERNEL_SNAPSHOT_BUF_SZ; 2354 propget.pp_i_buf = malloc(KERNEL_SNAPSHOT_BUF_SZ); 2355 bzero(propget.pp_i_buf, KERNEL_SNAPSHOT_BUF_SZ); 2356 2357 prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; 2358 if (ioctl(prov->pkc_fd, POOL_PROPGET, &propget) < 0) { 2359 free(propget.pp_i_buf); 2360 pool_seterror(POE_SYSTEM); 2361 return (POC_INVAL); 2362 } 2363 if (nvlist_unpack(propget.pp_i_buf, propget.pp_i_bufsize, 2364 &proplist, 0) != 0) { 2365 free(propget.pp_i_buf); 2366 pool_seterror(POE_SYSTEM); 2367 return (POC_INVAL); 2368 } 2369 free(propget.pp_i_buf); 2370 2371 if ((pair = nvlist_next_nvpair(proplist, NULL)) == NULL) { 2372 nvlist_free(proplist); 2373 pool_seterror(POE_SYSTEM); 2374 return (POC_INVAL); 2375 } 2376 2377 if (pool_value_from_nvpair(val, pair) == PO_FAIL) { 2378 nvlist_free(proplist); 2379 return (POC_INVAL); 2380 } 2381 nvlist_free(proplist); 2382 return (pool_value_get_type(val)); 2383 } 2384 2385 /* 2386 * Update the specified property value. 2387 * 2388 * PO_FAIL is returned if an error is detected and the error code is updated 2389 * to indicate the cause of the error. 2390 */ 2391 int 2392 pool_knl_put_property(pool_elem_t *pe, const char *name, 2393 const pool_value_t *val) 2394 { 2395 pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; 2396 pool_knl_connection_t *prov = 2397 (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; 2398 nvpair_t *bp, *ap; 2399 pool_propput_undo_t *propput; 2400 nvlist_t *bl = NULL; 2401 const pool_prop_t *prop; 2402 2403 if ((bp = pool_knl_find_nvpair(pke->pke_properties, name)) != NULL) { 2404 if (nvlist_alloc(&bl, NV_UNIQUE_NAME_TYPE, 0) != 0) { 2405 pool_seterror(POE_SYSTEM); 2406 return (PO_FAIL); 2407 } 2408 if (nvlist_add_nvpair(bl, bp) != 0) { 2409 nvlist_free(bl); 2410 pool_seterror(POE_SYSTEM); 2411 return (PO_FAIL); 2412 } 2413 } 2414 if (pool_knl_nvlist_add_value(pke->pke_properties, name, val) != 2415 PO_SUCCESS) 2416 return (PO_FAIL); 2417 2418 if (prov->pkc_log->l_state != LS_DO) { 2419 nvlist_free(bl); 2420 return (PO_SUCCESS); 2421 } 2422 /* 2423 * The remaining logic is setting up the arguments for the 2424 * POOL_PROPPUT ioctl and appending the details into the log. 2425 */ 2426 if ((propput = malloc(sizeof (pool_propput_undo_t))) == NULL) { 2427 pool_seterror(POE_SYSTEM); 2428 return (PO_FAIL); 2429 } 2430 (void) memset(propput, 0, sizeof (pool_propput_undo_t)); 2431 propput->ppu_blist = bl; 2432 2433 ap = pool_knl_find_nvpair(pke->pke_properties, name); 2434 2435 if (nvlist_alloc(&propput->ppu_alist, NV_UNIQUE_NAME_TYPE, 0) != 0) { 2436 nvlist_free(propput->ppu_blist); 2437 free(propput); 2438 pool_seterror(POE_SYSTEM); 2439 return (PO_FAIL); 2440 } 2441 if (nvlist_add_nvpair(propput->ppu_alist, ap) != 0) { 2442 nvlist_free(propput->ppu_blist); 2443 nvlist_free(propput->ppu_alist); 2444 free(propput); 2445 pool_seterror(POE_SYSTEM); 2446 return (PO_FAIL); 2447 } 2448 2449 if (nvlist_pack(propput->ppu_alist, 2450 (char **)&propput->ppu_ioctl.pp_o_buf, 2451 &propput->ppu_ioctl.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) { 2452 pool_seterror(POE_SYSTEM); 2453 return (PO_FAIL); 2454 } 2455 nvlist_free(propput->ppu_alist); 2456 propput->ppu_ioctl.pp_o_id_type = pool_elem_class(pe); 2457 if (pool_elem_class(pe) == PEC_RES_COMP || 2458 pool_elem_class(pe) == PEC_RES_AGG) 2459 propput->ppu_ioctl.pp_o_id_sub_type = 2460 pool_resource_elem_class(pe); 2461 if (pool_elem_class(pe) == PEC_COMP) 2462 propput->ppu_ioctl.pp_o_id_sub_type = 2463 (pool_resource_elem_class_t)pool_component_elem_class(pe); 2464 2465 propput->ppu_elem = pe; 2466 if ((prop = provider_get_prop(propput->ppu_elem, name)) != NULL) { 2467 if (prop_is_readonly(prop) == PO_TRUE) 2468 propput->ppu_doioctl |= KERNEL_PROP_RDONLY; 2469 } 2470 2471 if (log_append(prov->pkc_log, POOL_PROPPUT, (void *)propput) != 2472 PO_SUCCESS) { 2473 nvlist_free(propput->ppu_blist); 2474 free(propput); 2475 return (PO_FAIL); 2476 } 2477 return (PO_SUCCESS); 2478 } 2479 2480 /* 2481 * Remove the specified property value. 2482 * 2483 * PO_FAIL is returned if an error is detected and the error code is 2484 * updated to indicate the cause of the error. 2485 */ 2486 int 2487 pool_knl_rm_property(pool_elem_t *pe, const char *name) 2488 { 2489 pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; 2490 pool_knl_connection_t *prov = 2491 (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov; 2492 pool_proprm_undo_t *proprm; 2493 2494 if (pool_knl_find_nvpair(pke->pke_properties, name) == NULL) { 2495 pool_seterror(POE_BADPARAM); 2496 return (PO_FAIL); 2497 } 2498 2499 if ((proprm = malloc(sizeof (pool_proprm_undo_t))) == NULL) { 2500 pool_seterror(POE_SYSTEM); 2501 return (PO_FAIL); 2502 } 2503 (void) memset(proprm, 0, sizeof (pool_proprm_undo_t)); 2504 proprm->pru_oldval.pv_class = POC_INVAL; 2505 (void) pool_get_property(TO_CONF(pe), pe, name, &proprm->pru_oldval); 2506 2507 if (prov->pkc_log->l_state != LS_DO) { 2508 free(proprm); 2509 (void) nvlist_remove_all(pke->pke_properties, (char *)name); 2510 return (PO_SUCCESS); 2511 } 2512 /* 2513 * The remaining logic is setting up the arguments for the 2514 * POOL_PROPRM ioctl and appending the details into the log. 2515 */ 2516 2517 proprm->pru_ioctl.pp_o_id_type = pool_elem_class(pe); 2518 if (pool_elem_class(pe) == PEC_RES_COMP || 2519 pool_elem_class(pe) == PEC_RES_AGG) 2520 proprm->pru_ioctl.pp_o_id_sub_type = 2521 pool_resource_elem_class(pe); 2522 2523 if (pool_elem_class(pe) == PEC_COMP) 2524 proprm->pru_ioctl.pp_o_id_sub_type = 2525 (pool_resource_elem_class_t)pool_component_elem_class(pe); 2526 2527 proprm->pru_ioctl.pp_o_prop_name_size = strlen(name); 2528 proprm->pru_ioctl.pp_o_prop_name = 2529 (char *)pool_value_get_name(&proprm->pru_oldval); 2530 proprm->pru_elem = pe; 2531 2532 if (log_append(prov->pkc_log, POOL_PROPRM, (void *)proprm) != 2533 PO_SUCCESS) { 2534 free(proprm); 2535 return (PO_FAIL); 2536 } 2537 2538 (void) nvlist_remove_all(pke->pke_properties, (char *)name); 2539 return (PO_SUCCESS); 2540 } 2541 2542 /* 2543 * Return a NULL terminated array of pool_value_t which represents all 2544 * of the properties stored for an element 2545 * 2546 * Return NULL on failure. It is the caller's responsibility to free 2547 * the returned array of values. 2548 */ 2549 pool_value_t ** 2550 pool_knl_get_properties(const pool_elem_t *pe, uint_t *nprops) 2551 { 2552 nvpair_t *pair; 2553 pool_value_t **result; 2554 pool_knl_elem_t *pke = (pool_knl_elem_t *)pe; 2555 int i = 0; 2556 2557 *nprops = 0; 2558 2559 for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL; 2560 pair = nvlist_next_nvpair(pke->pke_properties, pair)) 2561 (*nprops)++; 2562 if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) { 2563 pool_seterror(POE_SYSTEM); 2564 return (NULL); 2565 } 2566 for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL; 2567 pair = nvlist_next_nvpair(pke->pke_properties, pair), i++) { 2568 result[i] = pool_value_alloc(); 2569 if (pool_value_from_nvpair(result[i], pair) == PO_FAIL) { 2570 while (i-- >= 0) 2571 pool_value_free(result[i]); 2572 free(result); 2573 return (NULL); 2574 } 2575 } 2576 return (result); 2577 } 2578 2579 /* 2580 * Append an entry to a result set. Reallocate the array used to store 2581 * results if it's full. 2582 * Returns PO_SUCCESS/PO_FAIL 2583 */ 2584 int 2585 pool_knl_result_set_append(pool_knl_result_set_t *rs, pool_knl_elem_t *pke) 2586 { 2587 if (rs->pkr_count == rs->pkr_size) 2588 if (pool_knl_result_set_realloc(rs) != PO_SUCCESS) 2589 return (PO_FAIL); 2590 2591 rs->pkr_list[rs->pkr_count++] = pke; 2592 2593 return (PO_SUCCESS); 2594 } 2595 2596 /* 2597 * Resize the array used to store results. A simple doubling strategy 2598 * is used. 2599 * Returns PO_SUCCESS/PO_FAIL 2600 */ 2601 int 2602 pool_knl_result_set_realloc(pool_knl_result_set_t *rs) 2603 { 2604 pool_knl_elem_t **old_list = rs->pkr_list; 2605 int new_size = rs->pkr_size * 2; 2606 2607 if ((rs->pkr_list = realloc(rs->pkr_list, 2608 new_size * sizeof (pool_knl_elem_t *))) == NULL) { 2609 rs->pkr_list = old_list; 2610 pool_seterror(POE_SYSTEM); 2611 return (PO_FAIL); 2612 } 2613 rs->pkr_size = new_size; 2614 2615 return (PO_SUCCESS); 2616 } 2617 2618 /* 2619 * Allocate a result set. The Result Set stores the result of a query. 2620 * Returns pool_knl_result_set_t pointer/NULL 2621 */ 2622 pool_knl_result_set_t * 2623 pool_knl_result_set_alloc(const pool_conf_t *conf) 2624 { 2625 pool_knl_result_set_t *rs; 2626 2627 if ((rs = malloc(sizeof (pool_knl_result_set_t))) == NULL) { 2628 pool_seterror(POE_SYSTEM); 2629 return (NULL); 2630 } 2631 (void) memset(rs, 0, sizeof (pool_knl_result_set_t)); 2632 rs->pkr_size = KERNEL_RS_INITIAL_SZ; 2633 if (pool_knl_result_set_realloc(rs) == PO_FAIL) { 2634 free(rs); 2635 pool_seterror(POE_SYSTEM); 2636 return (NULL); 2637 } 2638 rs->prs_conf = conf; 2639 rs->prs_index = -1; 2640 rs->prs_active = PO_TRUE; 2641 /* Fix up the result set accessor functions to the knl specfic ones */ 2642 rs->prs_next = pool_knl_rs_next; 2643 rs->prs_prev = pool_knl_rs_prev; 2644 rs->prs_first = pool_knl_rs_first; 2645 rs->prs_last = pool_knl_rs_last; 2646 rs->prs_get_index = pool_knl_rs_get_index; 2647 rs->prs_set_index = pool_knl_rs_set_index; 2648 rs->prs_close = pool_knl_rs_close; 2649 rs->prs_count = pool_knl_rs_count; 2650 return (rs); 2651 } 2652 2653 /* 2654 * Free a result set. Ensure that the resources are all released at 2655 * this point. 2656 */ 2657 void 2658 pool_knl_result_set_free(pool_knl_result_set_t *rs) 2659 { 2660 free(rs->pkr_list); 2661 free(rs); 2662 } 2663 /* 2664 * Return the next element in a result set. 2665 * Returns pool_elem_t pointer/NULL 2666 */ 2667 pool_elem_t * 2668 pool_knl_rs_next(pool_result_set_t *set) 2669 { 2670 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2671 2672 if (kset->prs_index == kset->pkr_count - 1) 2673 return (NULL); 2674 return ((pool_elem_t *)kset->pkr_list[++kset->prs_index]); 2675 } 2676 2677 /* 2678 * Return the previous element in a result set. 2679 * Returns pool_elem_t pointer/NULL 2680 */ 2681 pool_elem_t * 2682 pool_knl_rs_prev(pool_result_set_t *set) 2683 { 2684 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2685 2686 if (kset->prs_index < 0) 2687 return (NULL); 2688 return ((pool_elem_t *)kset->pkr_list[kset->prs_index--]); 2689 } 2690 2691 /* 2692 * Sets the current index in a result set. 2693 * Returns PO_SUCCESS/PO_FAIL 2694 */ 2695 int 2696 pool_knl_rs_set_index(pool_result_set_t *set, int index) 2697 { 2698 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2699 2700 if (index < 0 || index >= kset->pkr_count) { 2701 pool_seterror(POE_BADPARAM); 2702 return (PO_FAIL); 2703 } 2704 kset->prs_index = index; 2705 return (PO_SUCCESS); 2706 } 2707 2708 /* 2709 * Return the current index in a result set. 2710 * Returns current index 2711 */ 2712 int 2713 pool_knl_rs_get_index(pool_result_set_t *set) 2714 { 2715 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2716 2717 return (kset->prs_index); 2718 } 2719 2720 /* 2721 * Return the first element in a result set. 2722 * Returns pool_elem_t pointer/NULL 2723 */ 2724 pool_elem_t * 2725 pool_knl_rs_first(pool_result_set_t *set) 2726 { 2727 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2728 2729 return ((pool_elem_t *)kset->pkr_list[0]); 2730 } 2731 2732 /* 2733 * Return the last element in a result set. 2734 * Returns pool_elem_t pointer/NULL 2735 */ 2736 pool_elem_t * 2737 pool_knl_rs_last(pool_result_set_t *set) 2738 { 2739 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2740 2741 return ((pool_elem_t *)kset->pkr_list[kset->pkr_count - 1]); 2742 } 2743 2744 /* 2745 * Return the number of results in a result set. 2746 * Returns result count 2747 */ 2748 int 2749 pool_knl_rs_count(pool_result_set_t *set) 2750 { 2751 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2752 2753 return (kset->pkr_count); 2754 } 2755 2756 2757 /* 2758 * Close a result set. Free the resources 2759 * Returns PO_SUCCESS/PO_FAIL 2760 */ 2761 int 2762 pool_knl_rs_close(pool_result_set_t *set) 2763 { 2764 pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set; 2765 2766 pool_knl_result_set_free(kset); 2767 return (PO_SUCCESS); 2768 } 2769 2770 /* 2771 * Commit an individual transaction log item(). This processing is 2772 * essential to the pool_conf_commit() logic. When pool_conf_commit() 2773 * is invoked, the pending transaction log for the configuration is 2774 * walked and all pending changes to the kernel are invoked. If a 2775 * change succeeds it is marked in the log as successful and 2776 * processing continues, if it fails then failure is returned and the 2777 * log will be "rolled back" to undo changes to the library snapshot 2778 * and the kernel. 2779 */ 2780 int 2781 log_item_commit(log_item_t *li) 2782 { 2783 pool_knl_connection_t *prov = 2784 (pool_knl_connection_t *)li->li_log->l_conf->pc_prov; 2785 pool_create_undo_t *create; 2786 pool_destroy_undo_t *destroy; 2787 pool_assoc_undo_t *assoc; 2788 pool_dissoc_undo_t *dissoc; 2789 pool_propput_undo_t *propput; 2790 pool_proprm_undo_t *proprm; 2791 pool_xtransfer_undo_t *xtransfer; 2792 char_buf_t *cb; 2793 size_t size; 2794 pool_elem_t *pair; 2795 pool_value_t val = POOL_VALUE_INITIALIZER; 2796 int ret; 2797 2798 switch (li->li_op) { 2799 case POOL_CREATE: 2800 create = (pool_create_undo_t *)li->li_details; 2801 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 2802 return (PO_FAIL); 2803 if (set_char_buf(cb, "%s.sys_id", 2804 pool_elem_class_string(create->pcu_elem)) != PO_SUCCESS) { 2805 free_char_buf(cb); 2806 return (PO_FAIL); 2807 } 2808 #ifdef DEBUG 2809 dprintf("log_item_commit: POOL_CREATE, remove from dict\n"); 2810 pool_elem_dprintf(create->pcu_elem); 2811 #endif /* DEBUG */ 2812 /* 2813 * May not need to remove the element if it was 2814 * already destroyed before commit. Just cast the 2815 * return to void. 2816 */ 2817 (void) dict_remove(prov->pkc_elements, 2818 (pool_knl_elem_t *)create->pcu_elem); 2819 2820 if (ioctl(prov->pkc_fd, POOL_CREATE, &create->pcu_ioctl) < 0) { 2821 pool_seterror(POE_SYSTEM); 2822 return (PO_FAIL); 2823 } 2824 /* 2825 * Now that we have created our element in the kernel, 2826 * it has a valid allocated system id. Remove the 2827 * element from the element dictionary, using the 2828 * current key, and then re-insert under the new key. 2829 */ 2830 #ifdef DEBUG 2831 pool_elem_dprintf(create->pcu_elem); 2832 #endif /* DEBUG */ 2833 assert(nvlist_add_int64( 2834 ((pool_knl_elem_t *)create->pcu_elem)->pke_properties, 2835 cb->cb_buf, create->pcu_ioctl.pc_i_id) == 0); 2836 free_char_buf(cb); 2837 assert(dict_put(prov->pkc_elements, create->pcu_elem, 2838 create->pcu_elem) == NULL); 2839 /* 2840 * If the element has a pair in the static 2841 * configuration, update it with the sys_id 2842 */ 2843 if ((pair = pool_get_pair(create->pcu_elem)) != NULL) { 2844 pool_value_set_int64(&val, create->pcu_ioctl.pc_i_id); 2845 assert(pool_put_any_ns_property(pair, c_sys_prop, &val) 2846 == PO_SUCCESS); 2847 } 2848 li->li_state = LS_UNDO; 2849 break; 2850 case POOL_DESTROY: 2851 destroy = (pool_destroy_undo_t *)li->li_details; 2852 2853 destroy->pdu_ioctl.pd_o_id = elem_get_sysid(destroy->pdu_elem); 2854 2855 /* 2856 * It may be that this element was created in the last 2857 * transaction. In which case POOL_CREATE, above, will 2858 * have re-inserted the element in the dictionary. Try 2859 * to remove it just in case this has occurred. 2860 */ 2861 (void) dict_remove(prov->pkc_elements, 2862 (pool_knl_elem_t *)destroy->pdu_elem); 2863 while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY, 2864 &destroy->pdu_ioctl)) < 0 && errno == EAGAIN) 2865 ; 2866 if (ret < 0) { 2867 pool_seterror(POE_SYSTEM); 2868 return (PO_FAIL); 2869 } 2870 #ifdef DEBUG 2871 dprintf("log_item_commit: POOL_DESTROY\n"); 2872 pool_elem_dprintf(destroy->pdu_elem); 2873 #endif /* DEBUG */ 2874 li->li_state = LS_UNDO; 2875 break; 2876 case POOL_ASSOC: 2877 assoc = (pool_assoc_undo_t *)li->li_details; 2878 2879 assoc->pau_ioctl.pa_o_pool_id = 2880 elem_get_sysid(assoc->pau_assoc); 2881 assoc->pau_ioctl.pa_o_res_id = 2882 elem_get_sysid(assoc->pau_newres); 2883 while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, 2884 &assoc->pau_ioctl)) < 0 && errno == EAGAIN) 2885 ; 2886 if (ret < 0) { 2887 pool_seterror(POE_SYSTEM); 2888 return (PO_FAIL); 2889 } 2890 li->li_state = LS_UNDO; 2891 break; 2892 case POOL_DISSOC: 2893 dissoc = (pool_dissoc_undo_t *)li->li_details; 2894 2895 dissoc->pdu_ioctl.pd_o_pool_id = 2896 elem_get_sysid(dissoc->pdu_dissoc); 2897 2898 while ((ret = ioctl(prov->pkc_fd, POOL_DISSOC, 2899 &dissoc->pdu_ioctl)) < 0 && errno == EAGAIN) 2900 ; 2901 if (ret < 0) { 2902 pool_seterror(POE_SYSTEM); 2903 return (PO_FAIL); 2904 } 2905 li->li_state = LS_UNDO; 2906 break; 2907 case POOL_TRANSFER: 2908 li->li_state = LS_UNDO; 2909 pool_seterror(POE_BADPARAM); 2910 return (PO_FAIL); 2911 case POOL_XTRANSFER: 2912 xtransfer = (pool_xtransfer_undo_t *)li->li_details; 2913 2914 xtransfer->pxu_ioctl.px_o_src_id = 2915 elem_get_sysid(xtransfer->pxu_src); 2916 xtransfer->pxu_ioctl.px_o_tgt_id = 2917 elem_get_sysid(xtransfer->pxu_tgt); 2918 for (size = 0; xtransfer->pxu_rl[size] != NULL; size ++) { 2919 xtransfer->pxu_ioctl.px_o_comp_list[size] = 2920 elem_get_sysid(TO_ELEM(xtransfer->pxu_rl[size])); 2921 #ifdef DEBUG 2922 dprintf("log_item_commit: POOL_XTRANSFER\n"); 2923 pool_elem_dprintf(TO_ELEM(xtransfer->pxu_rl[size])); 2924 #endif /* DEBUG */ 2925 } 2926 2927 /* 2928 * Don't actually transfer resources if the configuration 2929 * is in POF_DESTROY state. This is to prevent problems 2930 * relating to transferring off-line CPUs. Instead rely 2931 * on the POOL_DESTROY ioctl to transfer the CPUS. 2932 */ 2933 if (li->li_log->l_conf->pc_state != POF_DESTROY && 2934 ioctl(prov->pkc_fd, POOL_XTRANSFER, 2935 &xtransfer->pxu_ioctl) < 0) { 2936 #ifdef DEBUG 2937 dprintf("log_item_commit: POOL_XTRANSFER, ioctl " 2938 "failed\n"); 2939 #endif /* DEBUG */ 2940 pool_seterror(POE_SYSTEM); 2941 return (PO_FAIL); 2942 } 2943 li->li_state = LS_UNDO; 2944 break; 2945 case POOL_PROPPUT: 2946 propput = (pool_propput_undo_t *)li->li_details; 2947 2948 if (pool_elem_class(propput->ppu_elem) != PEC_SYSTEM) { 2949 propput->ppu_ioctl.pp_o_id = 2950 elem_get_sysid(propput->ppu_elem); 2951 } 2952 /* 2953 * Some properties, e.g. pset.size, are read-only in the 2954 * kernel and attempting to change them will fail and cause 2955 * problems. Although this property is read-only through the 2956 * public interface, the library needs to modify it's value. 2957 */ 2958 if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) { 2959 if (ioctl(prov->pkc_fd, POOL_PROPPUT, 2960 &propput->ppu_ioctl) < 0) { 2961 pool_seterror(POE_SYSTEM); 2962 return (PO_FAIL); 2963 } 2964 } 2965 li->li_state = LS_UNDO; 2966 break; 2967 case POOL_PROPRM: 2968 proprm = (pool_proprm_undo_t *)li->li_details; 2969 2970 if (pool_elem_class(proprm->pru_elem) != PEC_SYSTEM) { 2971 proprm->pru_ioctl.pp_o_id = 2972 elem_get_sysid(proprm->pru_elem); 2973 } 2974 if (ioctl(prov->pkc_fd, POOL_PROPRM, &proprm->pru_ioctl) < 0) { 2975 pool_seterror(POE_SYSTEM); 2976 return (PO_FAIL); 2977 } 2978 li->li_state = LS_UNDO; 2979 break; 2980 default: 2981 return (PO_FAIL); 2982 } 2983 return (PO_SUCCESS); 2984 } 2985 2986 /* 2987 * Undo an individual transaction log item(). This processing is 2988 * essential to the pool_conf_commit() and pool_conf_rollback() 2989 * logic. Changes to the libpool snapshot and the kernel are carried 2990 * out separately. The library snapshot is updated synchronously, 2991 * however the kernel update is delayed until the user calls 2992 * pool_conf_commit(). 2993 * 2994 * When undoing transactions, library changes will be undone unless 2995 * this invocation is as a result of a commit failure, in which case 2996 * the log state will be LS_RECOVER. Kernel changes will only be 2997 * undone if they are marked as having been done, in which case the 2998 * log item state will be LS_UNDO. 2999 */ 3000 int 3001 log_item_undo(log_item_t *li) 3002 { 3003 pool_knl_connection_t *prov = 3004 (pool_knl_connection_t *)li->li_log->l_conf->pc_prov; 3005 pool_create_undo_t *create; 3006 pool_destroy_undo_t *destroy; 3007 pool_assoc_undo_t *assoc; 3008 pool_dissoc_undo_t *dissoc; 3009 pool_propput_undo_t *propput; 3010 pool_proprm_undo_t *proprm; 3011 pool_xtransfer_undo_t *xtransfer; 3012 char_buf_t *cb; 3013 size_t size; 3014 pool_destroy_t u_destroy; 3015 pool_create_t u_create; 3016 pool_assoc_t u_assoc; 3017 pool_xtransfer_t u_xtransfer; 3018 pool_propput_t u_propput; 3019 pool_proprm_t u_proprm; 3020 pool_conf_t *conf = li->li_log->l_conf; 3021 nvpair_t *pair; 3022 nvlist_t *tmplist; 3023 int ret; 3024 3025 if (li->li_log->l_state != LS_RECOVER) { 3026 switch (li->li_op) { 3027 case POOL_CREATE: 3028 create = (pool_create_undo_t *)li->li_details; 3029 3030 (void) dict_remove(prov->pkc_elements, create->pcu_elem); 3031 #ifdef DEBUG 3032 dprintf("log_item_undo: POOL_CREATE\n"); 3033 assert(create->pcu_elem != NULL); 3034 dprintf("log_item_undo: POOL_CREATE %p\n", create->pcu_elem); 3035 pool_elem_dprintf(create->pcu_elem); 3036 #endif /* DEBUG */ 3037 pool_knl_elem_free((pool_knl_elem_t *)create->pcu_elem, 3038 PO_TRUE); 3039 break; 3040 case POOL_DESTROY: 3041 destroy = (pool_destroy_undo_t *)li->li_details; 3042 3043 assert(dict_put(prov->pkc_elements, destroy->pdu_elem, 3044 destroy->pdu_elem) == NULL); 3045 break; 3046 case POOL_ASSOC: 3047 assoc = (pool_assoc_undo_t *)li->li_details; 3048 3049 if (assoc->pau_oldres != NULL) 3050 ((pool_knl_pool_t *)assoc->pau_assoc)->pkp_assoc 3051 [pool_resource_elem_class(assoc->pau_oldres)] = 3052 (pool_knl_resource_t *)assoc->pau_oldres; 3053 break; 3054 case POOL_DISSOC: 3055 dissoc = (pool_dissoc_undo_t *)li->li_details; 3056 3057 if (dissoc->pdu_oldres != NULL) 3058 ((pool_knl_pool_t *)dissoc->pdu_dissoc)->pkp_assoc 3059 [pool_resource_elem_class(dissoc->pdu_oldres)] = 3060 (pool_knl_resource_t *)dissoc->pdu_oldres; 3061 break; 3062 case POOL_TRANSFER: 3063 pool_seterror(POE_BADPARAM); 3064 return (PO_FAIL); 3065 case POOL_XTRANSFER: 3066 xtransfer = (pool_xtransfer_undo_t *)li->li_details; 3067 3068 for (size = 0; xtransfer->pxu_rl[size] != NULL; size++) { 3069 pool_value_t val = POOL_VALUE_INITIALIZER; 3070 uint64_t src_size; 3071 uint64_t tgt_size; 3072 3073 if (pool_set_container(xtransfer->pxu_src, 3074 TO_ELEM(xtransfer->pxu_rl[size])) == PO_FAIL) { 3075 return (PO_FAIL); 3076 } 3077 /* 3078 * Maintain the library view of the size 3079 */ 3080 if (resource_get_size(pool_elem_res(xtransfer->pxu_src), 3081 &src_size) != PO_SUCCESS || 3082 resource_get_size(pool_elem_res(xtransfer->pxu_tgt), 3083 &tgt_size) != PO_SUCCESS) { 3084 pool_seterror(POE_BADPARAM); 3085 return (PO_FAIL); 3086 } 3087 src_size++; 3088 tgt_size--; 3089 pool_value_set_uint64(&val, src_size); 3090 (void) pool_put_any_ns_property(xtransfer->pxu_src, 3091 c_size_prop, &val); 3092 pool_value_set_uint64(&val, tgt_size); 3093 (void) pool_put_any_ns_property(xtransfer->pxu_tgt, 3094 c_size_prop, &val); 3095 } 3096 break; 3097 case POOL_PROPPUT: 3098 propput = (pool_propput_undo_t *)li->li_details; 3099 3100 if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) { 3101 if (propput->ppu_blist != NULL) { 3102 if (nvlist_merge( 3103 ((pool_knl_elem_t *)propput->ppu_elem)-> 3104 pke_properties, propput->ppu_blist, 0) 3105 != 0) { 3106 pool_seterror(POE_SYSTEM); 3107 return (PO_FAIL); 3108 } 3109 } else { 3110 if (nvlist_unpack(propput->ppu_ioctl.pp_o_buf, 3111 propput->ppu_ioctl.pp_o_bufsize, 3112 &propput->ppu_alist, 0) != 0) { 3113 pool_seterror(POE_SYSTEM); 3114 return (PO_FAIL); 3115 } 3116 pair = nvlist_next_nvpair(propput->ppu_alist, 3117 NULL); 3118 (void) nvlist_remove_all(((pool_knl_elem_t *) 3119 propput->ppu_elem)->pke_properties, 3120 nvpair_name(pair)); 3121 nvlist_free(propput->ppu_alist); 3122 } 3123 } 3124 break; 3125 case POOL_PROPRM: 3126 proprm = (pool_proprm_undo_t *)li->li_details; 3127 3128 if (pool_value_get_type(&proprm->pru_oldval) != POC_INVAL) { 3129 if (pool_put_property(conf, proprm->pru_elem, 3130 proprm->pru_ioctl.pp_o_prop_name, 3131 &proprm->pru_oldval) != PO_SUCCESS) { 3132 return (PO_FAIL); 3133 } 3134 } 3135 break; 3136 default: 3137 return (PO_FAIL); 3138 } 3139 } 3140 /* 3141 * Only try to undo the state of the kernel if we modified it. 3142 */ 3143 if (li->li_state == LS_DO) { 3144 return (PO_SUCCESS); 3145 } 3146 3147 switch (li->li_op) { 3148 case POOL_CREATE: 3149 create = (pool_create_undo_t *)li->li_details; 3150 3151 u_destroy.pd_o_type = create->pcu_ioctl.pc_o_type; 3152 u_destroy.pd_o_sub_type = create->pcu_ioctl.pc_o_sub_type; 3153 u_destroy.pd_o_id = create->pcu_ioctl.pc_i_id; 3154 3155 while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY, 3156 &u_destroy)) < 0 && errno == EAGAIN) 3157 ; 3158 if (ret < 0) { 3159 pool_seterror(POE_SYSTEM); 3160 return (PO_FAIL); 3161 } 3162 li->li_state = LS_DO; 3163 break; 3164 case POOL_DESTROY: 3165 destroy = (pool_destroy_undo_t *)li->li_details; 3166 3167 u_create.pc_o_type = destroy->pdu_ioctl.pd_o_type; 3168 u_create.pc_o_sub_type = destroy->pdu_ioctl.pd_o_sub_type; 3169 3170 if (ioctl(prov->pkc_fd, POOL_CREATE, &u_create) < 0) { 3171 pool_seterror(POE_SYSTEM); 3172 return (PO_FAIL); 3173 } 3174 3175 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 3176 return (PO_FAIL); 3177 } 3178 if (set_char_buf(cb, "%s.sys_id", 3179 pool_elem_class_string(destroy->pdu_elem)) != PO_SUCCESS) { 3180 free_char_buf(cb); 3181 return (PO_FAIL); 3182 } 3183 (void) nvlist_add_int64( 3184 ((pool_knl_elem_t *)destroy->pdu_elem)->pke_properties, 3185 cb->cb_buf, u_create.pc_i_id); 3186 free_char_buf(cb); 3187 if (dict_put(prov->pkc_elements, destroy->pdu_elem, 3188 destroy->pdu_elem) != NULL) { 3189 pool_seterror(POE_SYSTEM); 3190 return (PO_FAIL); 3191 } 3192 /* 3193 * Now we need to reset all the properties and 3194 * associations in the kernel for this newly created 3195 * replacement. 3196 */ 3197 u_propput.pp_o_id_type = destroy->pdu_ioctl.pd_o_type; 3198 u_propput.pp_o_id_sub_type = destroy->pdu_ioctl.pd_o_sub_type; 3199 u_propput.pp_o_id = u_create.pc_i_id; 3200 u_propput.pp_o_buf = NULL; 3201 /* 3202 * Remove the read-only properties before attempting 3203 * to restore the state of the newly created property 3204 */ 3205 (void) nvlist_dup(((pool_knl_elem_t *)destroy->pdu_elem)-> 3206 pke_properties, &tmplist, 0); 3207 for (pair = nvlist_next_nvpair(tmplist, NULL); pair != NULL; 3208 pair = nvlist_next_nvpair(tmplist, pair)) { 3209 const pool_prop_t *prop; 3210 char *name = nvpair_name(pair); 3211 if ((prop = provider_get_prop(destroy->pdu_elem, 3212 name)) != NULL) 3213 if (prop_is_readonly(prop) == PO_TRUE) 3214 (void) nvlist_remove_all(tmplist, name); 3215 } 3216 if (nvlist_pack(tmplist, (char **)&u_propput.pp_o_buf, 3217 &u_propput.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) { 3218 pool_seterror(POE_SYSTEM); 3219 return (PO_FAIL); 3220 } 3221 nvlist_free(tmplist); 3222 if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) { 3223 free(u_propput.pp_o_buf); 3224 pool_seterror(POE_SYSTEM); 3225 return (PO_FAIL); 3226 } 3227 free(u_propput.pp_o_buf); 3228 /* 3229 * Now reset the associations for all the resource 3230 * types if the thing which we are recreating is a 3231 * pool 3232 * 3233 * TODO: This is resource specific and must be 3234 * extended for additional resource types. 3235 */ 3236 if (destroy->pdu_ioctl.pd_o_type == PEC_POOL) { 3237 u_assoc.pa_o_pool_id = u_create.pc_i_id; 3238 u_assoc.pa_o_res_id = 3239 elem_get_sysid( 3240 TO_ELEM(((pool_knl_pool_t *)destroy->pdu_elem)-> 3241 pkp_assoc[PREC_PSET])); 3242 u_assoc.pa_o_id_type = PREC_PSET; 3243 3244 if (ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc) < 0) { 3245 pool_seterror(POE_SYSTEM); 3246 return (PO_FAIL); 3247 } 3248 } 3249 li->li_state = LS_DO; 3250 break; 3251 case POOL_ASSOC: 3252 assoc = (pool_assoc_undo_t *)li->li_details; 3253 3254 u_assoc.pa_o_pool_id = elem_get_sysid(assoc->pau_assoc); 3255 u_assoc.pa_o_res_id = elem_get_sysid(assoc->pau_oldres); 3256 u_assoc.pa_o_id_type = assoc->pau_ioctl.pa_o_id_type; 3257 3258 while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 && 3259 errno == EAGAIN) 3260 ; 3261 if (ret < 0) { 3262 pool_seterror(POE_SYSTEM); 3263 return (PO_FAIL); 3264 } 3265 li->li_state = LS_DO; 3266 break; 3267 case POOL_DISSOC: 3268 dissoc = (pool_dissoc_undo_t *)li->li_details; 3269 3270 u_assoc.pa_o_pool_id = elem_get_sysid(dissoc->pdu_dissoc); 3271 u_assoc.pa_o_res_id = elem_get_sysid(dissoc->pdu_oldres); 3272 u_assoc.pa_o_id_type = dissoc->pdu_ioctl.pd_o_id_type; 3273 3274 while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 && 3275 errno == EAGAIN) 3276 ; 3277 if (ret < 0) { 3278 pool_seterror(POE_SYSTEM); 3279 return (PO_FAIL); 3280 } 3281 li->li_state = LS_DO; 3282 break; 3283 case POOL_TRANSFER: 3284 li->li_state = LS_DO; 3285 pool_seterror(POE_BADPARAM); 3286 return (PO_FAIL); 3287 case POOL_XTRANSFER: 3288 xtransfer = (pool_xtransfer_undo_t *)li->li_details; 3289 3290 (void) memcpy(&u_xtransfer, &xtransfer->pxu_ioctl, 3291 sizeof (pool_xtransfer_t)); 3292 u_xtransfer.px_o_src_id = elem_get_sysid(xtransfer->pxu_tgt); 3293 u_xtransfer.px_o_tgt_id = elem_get_sysid(xtransfer->pxu_src); 3294 3295 if (ioctl(prov->pkc_fd, POOL_XTRANSFER, &u_xtransfer) < 0) { 3296 pool_seterror(POE_SYSTEM); 3297 return (PO_FAIL); 3298 } 3299 li->li_state = LS_DO; 3300 break; 3301 case POOL_PROPPUT: 3302 propput = (pool_propput_undo_t *)li->li_details; 3303 3304 if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) { 3305 if (propput->ppu_blist) { 3306 (void) memcpy(&u_propput, &propput->ppu_ioctl, 3307 sizeof (pool_propput_t)); 3308 u_propput.pp_o_id = 3309 elem_get_sysid(propput->ppu_elem); 3310 u_propput.pp_o_buf = NULL; 3311 if (nvlist_pack(propput->ppu_blist, 3312 (char **)&u_propput.pp_o_buf, 3313 &u_propput.pp_o_bufsize, 3314 NV_ENCODE_NATIVE, 0) != 0) { 3315 pool_seterror(POE_SYSTEM); 3316 return (PO_FAIL); 3317 } 3318 if (ioctl(prov->pkc_fd, POOL_PROPPUT, 3319 &u_propput) < 0) { 3320 free(u_propput.pp_o_buf); 3321 pool_seterror(POE_SYSTEM); 3322 return (PO_FAIL); 3323 } 3324 free(u_propput.pp_o_buf); 3325 } else { 3326 if (nvlist_unpack(propput-> 3327 ppu_ioctl.pp_o_buf, 3328 propput->ppu_ioctl.pp_o_bufsize, 3329 &propput->ppu_alist, 0) != 0) { 3330 pool_seterror(POE_SYSTEM); 3331 return (PO_FAIL); 3332 } 3333 u_proprm.pp_o_id_type = 3334 propput->ppu_ioctl.pp_o_id_type; 3335 u_proprm.pp_o_id_sub_type = 3336 propput->ppu_ioctl.pp_o_id_sub_type; 3337 u_proprm.pp_o_id = 3338 elem_get_sysid(propput->ppu_elem); 3339 pair = nvlist_next_nvpair(propput->ppu_alist, 3340 NULL); 3341 u_proprm.pp_o_prop_name = nvpair_name(pair); 3342 u_proprm.pp_o_prop_name_size = 3343 strlen(u_proprm.pp_o_prop_name); 3344 3345 if (provider_get_prop(propput->ppu_elem, 3346 u_proprm.pp_o_prop_name) == NULL) { 3347 if (ioctl(prov->pkc_fd, POOL_PROPRM, 3348 &u_proprm) < 0) { 3349 nvlist_free(propput->ppu_alist); 3350 pool_seterror(POE_SYSTEM); 3351 return (PO_FAIL); 3352 } 3353 } 3354 nvlist_free(propput->ppu_alist); 3355 } 3356 } 3357 li->li_state = LS_DO; 3358 break; 3359 case POOL_PROPRM: 3360 proprm = (pool_proprm_undo_t *)li->li_details; 3361 3362 u_propput.pp_o_id_type = proprm->pru_ioctl.pp_o_id_type; 3363 u_propput.pp_o_id_sub_type = 3364 proprm->pru_ioctl.pp_o_id_sub_type; 3365 u_propput.pp_o_id = elem_get_sysid(proprm->pru_elem); 3366 u_propput.pp_o_buf = NULL; 3367 /* 3368 * Only try to remove the appropriate property 3369 */ 3370 if (nvlist_alloc(&tmplist, NV_UNIQUE_NAME_TYPE, 0) != 3371 0) { 3372 pool_seterror(POE_SYSTEM); 3373 return (PO_FAIL); 3374 } 3375 if (pool_knl_nvlist_add_value(tmplist, 3376 pool_value_get_name(&proprm->pru_oldval), 3377 &proprm->pru_oldval) != PO_SUCCESS) 3378 return (PO_FAIL); 3379 3380 if (nvlist_pack(tmplist, 3381 (char **)&u_propput.pp_o_buf, &u_propput.pp_o_bufsize, 3382 NV_ENCODE_NATIVE, 0) != 0) { 3383 nvlist_free(tmplist); 3384 pool_seterror(POE_SYSTEM); 3385 return (PO_FAIL); 3386 } 3387 nvlist_free(tmplist); 3388 if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) { 3389 free(u_propput.pp_o_buf); 3390 pool_seterror(POE_SYSTEM); 3391 return (PO_FAIL); 3392 } 3393 free(u_propput.pp_o_buf); 3394 li->li_state = LS_DO; 3395 break; 3396 default: 3397 return (PO_FAIL); 3398 } 3399 return (PO_SUCCESS); 3400 } 3401 3402 /* 3403 * A log item stores state about the transaction it represents. This 3404 * function releases the resources associated with the transaction and 3405 * used to store the transaction state. 3406 */ 3407 int 3408 log_item_release(log_item_t *li) 3409 { 3410 pool_create_undo_t *create; 3411 pool_destroy_undo_t *destroy; 3412 pool_assoc_undo_t *assoc; 3413 pool_dissoc_undo_t *dissoc; 3414 pool_propput_undo_t *propput; 3415 pool_proprm_undo_t *proprm; 3416 pool_xtransfer_undo_t *xtransfer; 3417 3418 switch (li->li_op) { 3419 case POOL_CREATE: 3420 create = (pool_create_undo_t *)li->li_details; 3421 3422 free(create); 3423 break; 3424 case POOL_DESTROY: 3425 destroy = (pool_destroy_undo_t *)li->li_details; 3426 3427 #ifdef DEBUG 3428 dprintf("log_item_release: POOL_DESTROY\n"); 3429 #endif /* DEBUG */ 3430 3431 if (li->li_state == LS_UNDO) { 3432 #ifdef DEBUG 3433 pool_elem_dprintf(destroy->pdu_elem); 3434 #endif /* DEBUG */ 3435 pool_knl_elem_free((pool_knl_elem_t *)destroy-> 3436 pdu_elem, PO_TRUE); 3437 } 3438 free(destroy); 3439 break; 3440 case POOL_ASSOC: 3441 assoc = (pool_assoc_undo_t *)li->li_details; 3442 3443 free(assoc); 3444 break; 3445 case POOL_DISSOC: 3446 dissoc = (pool_dissoc_undo_t *)li->li_details; 3447 3448 free(dissoc); 3449 break; 3450 case POOL_TRANSFER: 3451 pool_seterror(POE_BADPARAM); 3452 return (PO_FAIL); 3453 case POOL_XTRANSFER: 3454 xtransfer = (pool_xtransfer_undo_t *)li->li_details; 3455 3456 free(xtransfer->pxu_rl); 3457 free(xtransfer->pxu_ioctl.px_o_comp_list); 3458 free(xtransfer); 3459 break; 3460 case POOL_PROPPUT: 3461 propput = (pool_propput_undo_t *)li->li_details; 3462 3463 nvlist_free(propput->ppu_blist); 3464 free(propput->ppu_ioctl.pp_o_buf); 3465 free(propput); 3466 break; 3467 case POOL_PROPRM: 3468 proprm = (pool_proprm_undo_t *)li->li_details; 3469 3470 free(proprm); 3471 break; 3472 default: 3473 return (PO_FAIL); 3474 } 3475 return (PO_SUCCESS); 3476 } 3477 3478 /* 3479 * pool_knl_nvlist_add_value() adds a pool_value_t to an nvlist. 3480 */ 3481 int 3482 pool_knl_nvlist_add_value(nvlist_t *list, const char *name, 3483 const pool_value_t *pv) 3484 { 3485 uint64_t uval; 3486 int64_t ival; 3487 double dval; 3488 uchar_t dval_b[sizeof (double)]; 3489 uchar_t bval; 3490 const char *sval; 3491 pool_value_class_t type; 3492 char *nv_name; 3493 3494 if ((type = pool_value_get_type(pv)) == POC_INVAL) { 3495 pool_seterror(POE_BADPARAM); 3496 return (PO_FAIL); 3497 } 3498 nv_name = (char *)name; 3499 3500 switch (type) { 3501 case POC_UINT: 3502 if (pool_value_get_uint64(pv, &uval) == POC_INVAL) { 3503 return (PO_FAIL); 3504 } 3505 if (nvlist_add_uint64(list, nv_name, uval) != 0) { 3506 pool_seterror(POE_SYSTEM); 3507 return (PO_FAIL); 3508 } 3509 break; 3510 case POC_INT: 3511 if (pool_value_get_int64(pv, &ival) == POC_INVAL) { 3512 return (PO_FAIL); 3513 } 3514 if (nvlist_add_int64(list, nv_name, ival) != 0) { 3515 pool_seterror(POE_SYSTEM); 3516 return (PO_FAIL); 3517 } 3518 break; 3519 case POC_DOUBLE: 3520 if (pool_value_get_double(pv, &dval) == POC_INVAL) { 3521 return (PO_FAIL); 3522 } 3523 /* 3524 * Since there is no support for doubles in the 3525 * kernel, store the double value in a byte array. 3526 */ 3527 (void) memcpy(dval_b, &dval, sizeof (double)); 3528 if (nvlist_add_byte_array(list, nv_name, dval_b, 3529 sizeof (double)) != 0) { 3530 pool_seterror(POE_SYSTEM); 3531 return (PO_FAIL); 3532 } 3533 break; 3534 case POC_BOOL: 3535 if (pool_value_get_bool(pv, &bval) == POC_INVAL) { 3536 return (PO_FAIL); 3537 } 3538 if (nvlist_add_byte(list, nv_name, bval) != 0) { 3539 pool_seterror(POE_SYSTEM); 3540 return (PO_FAIL); 3541 } 3542 break; 3543 case POC_STRING: 3544 if (pool_value_get_string(pv, &sval) == POC_INVAL) { 3545 return (PO_FAIL); 3546 } 3547 if (nvlist_add_string(list, nv_name, (char *)sval) != 0) { 3548 pool_seterror(POE_SYSTEM); 3549 return (PO_FAIL); 3550 } 3551 break; 3552 default: 3553 pool_seterror(POE_BADPARAM); 3554 return (PO_FAIL); 3555 } 3556 return (PO_SUCCESS); 3557 } 3558 3559 /* 3560 * hash_id() hashes all elements in a pool configuration using the 3561 * "sys_id" property. Not all elements have a "sys_id" property, 3562 * however elem_get_sysid() caters for this by always returning a 3563 * constant value for those elements. This isn't anticipated to lead 3564 * to a performance degradation in the hash, since those elements 3565 * which are likely to be most prevalent in a configuration do have 3566 * "sys_id" as a property. 3567 */ 3568 uint64_t 3569 hash_id(const pool_elem_t *pe) 3570 { 3571 id_t id; 3572 3573 id = elem_get_sysid(pe); 3574 return (hash_buf(&id, sizeof (id))); 3575 } 3576 3577 /* 3578 * blocking_open() guarantees access to the pool device, if open() 3579 * is failing with EBUSY. 3580 */ 3581 int 3582 blocking_open(const char *path, int oflag) 3583 { 3584 int fd; 3585 3586 while ((fd = open(path, oflag)) == -1 && errno == EBUSY) 3587 (void) poll(NULL, 0, 1 * MILLISEC); 3588 3589 return (fd); 3590 } 3591