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