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