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