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