1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <thread.h> 34 #include <synch.h> 35 #include <unistd.h> 36 #include <stropts.h> 37 #include <fcntl.h> 38 #include <note.h> 39 #include <errno.h> 40 #include <ctype.h> 41 #include <libintl.h> 42 #include <libscf.h> 43 #include <pool.h> 44 #include <signal.h> 45 46 #include <sys/pool.h> 47 #include <sys/priocntl.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <sys/wait.h> 51 52 #include "pool_internal.h" 53 #include "pool_impl.h" 54 55 /* 56 * libpool Interface Routines 57 * 58 * pool.c implements (most of) the external interface to libpool 59 * users. Some of the interface is implemented in pool_internal.c for 60 * reasons of internal code organisation. The core requirements for 61 * pool.c are: 62 * 63 * Data Abstraction 64 * 65 * The abstraction of the actual datastore so that no details of the 66 * underlying data representation mechanism are revealed to users of 67 * the library. For instance, the fact that we use the kernel or files 68 * to store our configurations is completely abstracted via the 69 * various libpool APIs. 70 * 71 * External Interaction 72 * 73 * libpool users manipulate configuration components via the API 74 * defined in pool.h. Most functions in this file act as interceptors, 75 * validating parameters before redirecting the request into a 76 * specific datastore implementation for the actual work to be done. 77 * 78 * These main sets of requirements have driven the design so that it 79 * is possible to replace the entire datastore type without having to 80 * modify the external (or internal provider) APIs. It is possible to 81 * modify the storage technology used by libpool by implementing a new 82 * set of datastore provider operations. Simply modify the 83 * pool_conf_open() routine to establish a new datastore as the 84 * provider for a configuration. 85 * 86 * The key components in a libpool configuration are : 87 * pool_conf_t - This represents a complete configuration instance 88 * pool_t - A pool inside a configuration 89 * pool_resource_t - A resource inside a configuration 90 * pool_component_t - A component of a resource 91 * 92 */ 93 94 /* 95 * Used to control transfer setup. 96 */ 97 #define XFER_FAIL PO_FAIL 98 #define XFER_SUCCESS PO_SUCCESS 99 #define XFER_CONTINUE 1 100 101 #define SMF_SVC_INSTANCE "svc:/system/pools:default" 102 #define E_ERROR 1 /* Exit status for error */ 103 104 #ifndef TEXT_DOMAIN 105 #define TEXT_DOMAIN "SYS_TEST" 106 #endif /* TEXT_DOMAIN */ 107 108 const char pool_info_location[] = "/dev/pool"; 109 110 /* 111 * Static data 112 */ 113 static const char static_location[] = "/etc/pooladm.conf"; 114 static const char dynamic_location[] = "/dev/poolctl"; 115 static mutex_t keylock; 116 static thread_key_t errkey; 117 static int keyonce = 0; 118 119 /* 120 * libpool error code 121 */ 122 static int pool_errval = POE_OK; 123 124 /* 125 * libpool version 126 */ 127 static uint_t pool_workver = POOL_VER_CURRENT; 128 129 static const char *data_type_tags[] = { 130 "uint", 131 "int", 132 "float", 133 "boolean", 134 "string" 135 }; 136 137 /* 138 * static functions 139 */ 140 static int pool_elem_remove(pool_elem_t *); 141 static int is_valid_prop_name(const char *); 142 static int prop_buf_build_cb(pool_conf_t *, pool_elem_t *, const char *, 143 pool_value_t *, void *); 144 static char *pool_base_info(const pool_elem_t *, char_buf_t *, int); 145 static int choose_components(pool_resource_t *, pool_resource_t *, uint64_t); 146 static int pool_conf_check(const pool_conf_t *); 147 static void free_value_list(int, pool_value_t **); 148 static int setup_transfer(pool_conf_t *, pool_resource_t *, pool_resource_t *, 149 uint64_t, uint64_t *, uint64_t *); 150 151 /* 152 * Return the "static" location string for libpool. 153 */ 154 const char * 155 pool_static_location(void) 156 { 157 return (static_location); 158 } 159 160 /* 161 * Return the "dynamic" location string for libpool. 162 */ 163 const char * 164 pool_dynamic_location(void) 165 { 166 return (dynamic_location); 167 } 168 169 /* 170 * Return the status for a configuration. If the configuration has 171 * been successfully opened, then the status will be POF_VALID or 172 * POF_DESTROY. If the configuration failed to open properly or has 173 * been closed or removed, then the status will be POF_INVALID. 174 */ 175 pool_conf_state_t 176 pool_conf_status(const pool_conf_t *conf) 177 { 178 return (conf->pc_state); 179 } 180 181 /* 182 * Bind idtype id to the pool name. 183 */ 184 int 185 pool_set_binding(const char *pool_name, idtype_t idtype, id_t id) 186 { 187 pool_conf_t *conf; 188 int result; 189 190 if ((conf = pool_conf_alloc()) == NULL) 191 return (PO_FAIL); 192 193 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) { 194 pool_conf_free(conf); 195 pool_seterror(POE_INVALID_CONF); 196 return (PO_FAIL); 197 } 198 199 result = conf->pc_prov->pc_set_binding(conf, pool_name, idtype, id); 200 201 (void) pool_conf_close(conf); 202 pool_conf_free(conf); 203 return (result); 204 } 205 206 /* 207 * pool_get_resource_binding() returns the binding for a pid to the supplied 208 * type of resource. If a binding cannot be determined, NULL is returned. 209 */ 210 char * 211 pool_get_resource_binding(const char *sz_type, pid_t pid) 212 { 213 pool_conf_t *conf; 214 char *result; 215 pool_resource_elem_class_t type; 216 217 if ((type = pool_resource_elem_class_from_string(sz_type)) == 218 PREC_INVALID) { 219 pool_seterror(POE_BADPARAM); 220 return (NULL); 221 } 222 223 if ((conf = pool_conf_alloc()) == NULL) 224 return (NULL); 225 226 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) 227 != PO_SUCCESS) { 228 pool_seterror(POE_INVALID_CONF); 229 pool_conf_free(conf); 230 return (NULL); 231 } 232 result = conf->pc_prov->pc_get_resource_binding(conf, type, pid); 233 (void) pool_conf_close(conf); 234 pool_conf_free(conf); 235 return (result); 236 } 237 238 /* 239 * pool_get_binding() returns the binding for a pid to a pool. If a 240 * binding cannot be determined, NULL is returned. 241 */ 242 char * 243 pool_get_binding(pid_t pid) 244 { 245 pool_conf_t *conf; 246 char *result; 247 248 if ((conf = pool_conf_alloc()) == NULL) 249 return (NULL); 250 251 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) 252 != PO_SUCCESS) { 253 pool_seterror(POE_INVALID_CONF); 254 pool_conf_free(conf); 255 return (NULL); 256 } 257 result = conf->pc_prov->pc_get_binding(conf, pid); 258 (void) pool_conf_close(conf); 259 pool_conf_free(conf); 260 return (result); 261 } 262 263 /*ARGSUSED*/ 264 int 265 prop_buf_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name, 266 pool_value_t *pval, void *user) 267 { 268 uint64_t u; 269 int64_t i; 270 uchar_t bool; 271 const char *str; 272 double d; 273 char_buf_t *cb = (char_buf_t *)user; 274 int type = pool_value_get_type(pval); 275 276 /* 277 * Ignore "type" and "<type>.name" properties as these are not 278 * to be displayed by this function 279 */ 280 if (strcmp(name, c_type) == 0 || 281 strcmp(property_name_minus_ns(pe, name), c_name) == 0) 282 return (PO_SUCCESS); 283 if (append_char_buf(cb, "\n%s\t%s\t%s ", cb->cb_tab_buf, 284 data_type_tags[type], name) == PO_FAIL) 285 return (PO_FAIL); 286 switch (type) { 287 case POC_UINT: 288 (void) pool_value_get_uint64(pval, &u); 289 if (append_char_buf(cb, "%llu", (u_longlong_t)u) == PO_FAIL) 290 return (PO_FAIL); 291 break; 292 case POC_INT: 293 (void) pool_value_get_int64(pval, &i); 294 if (append_char_buf(cb, "%lld", (longlong_t)i) == PO_FAIL) 295 return (PO_FAIL); 296 break; 297 case POC_STRING: 298 (void) pool_value_get_string(pval, &str); 299 if (append_char_buf(cb, "%s", str) == PO_FAIL) 300 return (PO_FAIL); 301 break; 302 case POC_BOOL: 303 (void) pool_value_get_bool(pval, &bool); 304 if (bool == 0) { 305 if (append_char_buf(cb, "%s", "false") == PO_FAIL) 306 return (PO_FAIL); 307 } else { 308 if (append_char_buf(cb, "%s", "true") == PO_FAIL) 309 return (PO_FAIL); 310 } 311 break; 312 case POC_DOUBLE: 313 (void) pool_value_get_double(pval, &d); 314 if (append_char_buf(cb, "%g", d) == PO_FAIL) 315 return (PO_FAIL); 316 break; 317 case POC_INVAL: /* Do nothing */ 318 break; 319 default: 320 return (PO_FAIL); 321 } 322 return (PO_SUCCESS); 323 } 324 325 /* 326 * Return a buffer which describes the element 327 * pe is a pointer to the element 328 * deep is PO_TRUE/PO_FALSE to indicate whether children should be included 329 */ 330 char * 331 pool_base_info(const pool_elem_t *pe, char_buf_t *cb, int deep) 332 { 333 const char *sres; 334 uint_t i; 335 uint_t nelem; 336 337 pool_value_t val = POOL_VALUE_INITIALIZER; 338 pool_resource_t **rs; 339 pool_elem_t *elem; 340 pool_conf_t *conf = TO_CONF(pe); 341 342 if (cb == NULL) { 343 char *ret = NULL; 344 345 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 346 return (NULL); 347 348 /* 349 * Populate the buffer with element details 350 */ 351 (void) pool_base_info(pe, cb, deep); 352 if (cb->cb_buf) 353 ret = strdup(cb->cb_buf); 354 free_char_buf(cb); 355 return (ret); 356 } 357 358 if (append_char_buf(cb, "\n%s%s", cb->cb_tab_buf, 359 pool_elem_class_string(pe)) == PO_FAIL) { 360 return (NULL); 361 } 362 363 if (pool_get_ns_property(pe, c_name, &val) == POC_STRING) { 364 (void) pool_value_get_string(&val, &sres); 365 if (append_char_buf(cb, " %s", sres) == PO_FAIL) { 366 return (NULL); 367 } 368 } 369 370 /* 371 * Add in some details about the element 372 */ 373 if (pool_walk_properties(conf, (pool_elem_t *)pe, cb, 374 prop_buf_build_cb) == PO_FAIL) { 375 (void) append_char_buf(cb, "\n%s%s\n", cb->cb_tab_buf, 376 "Cannot access the properties of this element."); 377 return (NULL); 378 } 379 if (append_char_buf(cb, "%s", "\n") == PO_FAIL) 380 return (NULL); 381 382 if (pe->pe_class == PEC_POOL) { 383 /* 384 * A shallow display of a pool only lists the resources by name 385 */ 386 387 if ((rs = pool_query_pool_resources(conf, pool_elem_pool(pe), 388 &nelem, NULL)) == NULL) { 389 return (NULL); 390 } 391 392 for (i = 0; i < nelem; i++) { 393 const char *str; 394 395 elem = TO_ELEM(rs[i]); 396 397 if (append_char_buf(cb, "\t%s%s", cb->cb_tab_buf, 398 pool_elem_class_string(elem)) == PO_FAIL) { 399 free(rs); 400 return (NULL); 401 } 402 403 if (pool_get_ns_property(elem, c_name, &val) != 404 POC_STRING) { 405 free(rs); 406 pool_seterror(POE_INVALID_CONF); 407 return (NULL); 408 } 409 (void) pool_value_get_string(&val, &str); 410 if (append_char_buf(cb, "\t%s\n", str) == PO_FAIL) { 411 free(rs); 412 return (NULL); 413 } 414 } 415 free(rs); 416 } 417 if (deep == PO_TRUE) { 418 pool_t **ps; 419 pool_component_t **cs; 420 421 if (strlcat(cb->cb_tab_buf, "\t", CB_TAB_BUF_SIZE) 422 >= CB_TAB_BUF_SIZE) { 423 pool_seterror(POE_SYSTEM); 424 return (NULL); 425 } 426 switch (pe->pe_class) { 427 case PEC_SYSTEM: 428 if ((ps = pool_query_pools(conf, &nelem, NULL)) != 429 NULL) { /* process the pools */ 430 for (i = 0; i < nelem; i++) { 431 elem = TO_ELEM(ps[i]); 432 if (pool_base_info(elem, cb, 433 PO_FALSE) == NULL) { 434 free(ps); 435 return (NULL); 436 } 437 } 438 free(ps); 439 } 440 if ((rs = pool_query_resources(conf, &nelem, NULL)) != 441 NULL) { 442 for (i = 0; i < nelem; i++) { 443 elem = TO_ELEM(rs[i]); 444 if (pool_base_info(elem, cb, 445 PO_TRUE) == NULL) { 446 free(rs); 447 return (NULL); 448 } 449 } 450 free(rs); 451 } 452 break; 453 case PEC_POOL: 454 if ((rs = pool_query_pool_resources(conf, 455 pool_elem_pool(pe), &nelem, NULL)) == NULL) 456 return (NULL); 457 for (i = 0; i < nelem; i++) { 458 elem = TO_ELEM(rs[i]); 459 if (pool_base_info(elem, cb, PO_TRUE) == NULL) { 460 free(rs); 461 return (NULL); 462 } 463 } 464 free(rs); 465 break; 466 case PEC_RES_COMP: 467 if ((cs = pool_query_resource_components(conf, 468 pool_elem_res(pe), &nelem, NULL)) != NULL) { 469 for (i = 0; i < nelem; i++) { 470 elem = TO_ELEM(cs[i]); 471 if (pool_base_info(elem, cb, 472 PO_FALSE) == NULL) { 473 free(cs); 474 return (NULL); 475 } 476 } 477 free(cs); 478 } 479 break; 480 case PEC_RES_AGG: 481 case PEC_COMP: 482 break; 483 default: 484 /*NOTREACHED*/ 485 break; 486 } 487 if (cb->cb_tab_buf[0] != 0) 488 cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0; 489 } 490 return (cb->cb_buf); 491 } 492 493 /* 494 * Returns The information on the specified pool or NULL. 495 * 496 * Errors If the status of the conf is INVALID or the supplied 497 * value of deep is illegal, POE_BADPARAM. 498 * 499 * The caller is responsible for free(3c)ing the string returned. 500 */ 501 char * 502 pool_info(const pool_conf_t *conf, const pool_t *pool, int deep) 503 { 504 pool_elem_t *pe; 505 506 pe = TO_ELEM(pool); 507 508 if (TO_CONF(pe) != conf) { 509 pool_seterror(POE_BADPARAM); 510 return (NULL); 511 } 512 513 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { 514 pool_seterror(POE_BADPARAM); 515 return (NULL); 516 } 517 518 return (pool_base_info(pe, NULL, deep)); 519 } 520 521 /* 522 * Returns The information on the specified resource or NULL. 523 * 524 * Errors If the status of the conf is INVALID or the supplied 525 * value of deep is illegal, POE_BADPARAM. 526 * 527 * The caller is responsible for free(3c)ing the string returned. 528 */ 529 char * 530 pool_resource_info(const pool_conf_t *conf, const pool_resource_t *res, 531 int deep) 532 { 533 pool_elem_t *pe; 534 535 pe = TO_ELEM(res); 536 537 if (TO_CONF(pe) != conf) { 538 pool_seterror(POE_BADPARAM); 539 return (NULL); 540 } 541 542 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { 543 pool_seterror(POE_BADPARAM); 544 return (NULL); 545 } 546 547 return (pool_base_info(pe, NULL, deep)); 548 } 549 550 /* 551 * Returns The information on the specified component or NULL. 552 * 553 * Errors If the status of the conf is INVALID or the supplied 554 * value of deep is illegal, POE_BADPARAM. 555 * 556 * The caller is responsible for free(3c)ing the string returned. 557 */ 558 char * 559 pool_component_info(const pool_conf_t *conf, const pool_component_t *comp, 560 int deep) 561 { 562 pool_elem_t *pe; 563 564 pe = TO_ELEM(comp); 565 566 if (TO_CONF(pe) != conf) { 567 pool_seterror(POE_BADPARAM); 568 return (NULL); 569 } 570 571 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { 572 pool_seterror(POE_BADPARAM); 573 return (NULL); 574 } 575 576 return (pool_base_info(pe, NULL, deep)); 577 } 578 579 /* 580 * Returns The information on the specified conf or NULL. 581 * 582 * Errors If the status of the conf is INVALID or the supplied 583 * value of deep is illegal, POE_BADPARAM. 584 * 585 * The caller is responsible for free(3c)ing the string returned. 586 */ 587 char * 588 pool_conf_info(const pool_conf_t *conf, int deep) 589 { 590 pool_elem_t *pe; 591 592 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) { 593 pool_seterror(POE_BADPARAM); 594 return (NULL); 595 } 596 if ((pe = pool_conf_to_elem(conf)) == NULL) { 597 pool_seterror(POE_BADPARAM); 598 return (NULL); 599 } 600 return (pool_base_info(pe, NULL, deep)); 601 } 602 603 604 /* 605 * Set the thread specific error value. 606 */ 607 void 608 pool_seterror(int errval) 609 { 610 if (thr_main()) { 611 pool_errval = errval; 612 return; 613 } 614 if (keyonce == 0) { 615 (void) mutex_lock(&keylock); 616 if (keyonce == 0) { 617 (void) thr_keycreate(&errkey, 0); 618 keyonce++; 619 } 620 (void) mutex_unlock(&keylock); 621 } 622 (void) thr_setspecific(errkey, (void *)(intptr_t)errval); 623 } 624 625 /* 626 * Return the current value of the error code. 627 * Returns: int error code 628 */ 629 int 630 pool_error(void) 631 { 632 void *errval; 633 634 if (thr_main()) 635 return (pool_errval); 636 if (keyonce == 0) 637 return (POE_OK); 638 (void) thr_getspecific(errkey, &errval); 639 return ((intptr_t)errval); 640 } 641 642 /* 643 * Return the text represenation for the current value of the error code. 644 * Returns: const char * error string 645 */ 646 const char * 647 pool_strerror(int error) 648 { 649 char *str; 650 651 switch (error) { 652 case POE_OK: 653 str = dgettext(TEXT_DOMAIN, "Operation successful"); 654 break; 655 case POE_BAD_PROP_TYPE: 656 str = dgettext(TEXT_DOMAIN, 657 "Attempted to retrieve the wrong property type"); 658 break; 659 case POE_INVALID_CONF: 660 str = dgettext(TEXT_DOMAIN, "Invalid configuration"); 661 break; 662 case POE_NOTSUP: 663 str = dgettext(TEXT_DOMAIN, "Operation is not supported"); 664 break; 665 case POE_INVALID_SEARCH: 666 str = dgettext(TEXT_DOMAIN, "Invalid search"); 667 break; 668 case POE_BADPARAM: 669 str = dgettext(TEXT_DOMAIN, "Bad parameter supplied"); 670 break; 671 case POE_PUTPROP: 672 str = dgettext(TEXT_DOMAIN, "Error putting property"); 673 break; 674 case POE_DATASTORE: 675 str = dgettext(TEXT_DOMAIN, "Pools repository error"); 676 break; 677 case POE_SYSTEM: 678 str = dgettext(TEXT_DOMAIN, "System error"); 679 break; 680 case POE_ACCESS: 681 str = dgettext(TEXT_DOMAIN, "Permission denied"); 682 break; 683 default: 684 errno = ESRCH; 685 str = NULL; 686 } 687 return (str); 688 } 689 690 int 691 pool_get_status(int *state) 692 { 693 int fd; 694 pool_status_t status; 695 696 if ((fd = open(pool_info_location, O_RDONLY)) < 0) { 697 pool_seterror(POE_SYSTEM); 698 return (PO_FAIL); 699 } 700 if (ioctl(fd, POOL_STATUSQ, &status) < 0) { 701 (void) close(fd); 702 pool_seterror(POE_SYSTEM); 703 return (PO_FAIL); 704 } 705 (void) close(fd); 706 707 *state = status.ps_io_state; 708 709 return (PO_SUCCESS); 710 } 711 712 int 713 pool_set_status(int state) 714 { 715 int old_state; 716 717 if (pool_get_status(&old_state) != PO_SUCCESS) { 718 pool_seterror(POE_SYSTEM); 719 return (PO_FAIL); 720 } 721 722 if (old_state != state) { 723 int fd; 724 pool_status_t status; 725 char *fmri; 726 727 /* 728 * Changing the status of pools is performed by enabling 729 * or disabling the pools service instance. If this 730 * function has not been invoked by startd then we simply 731 * enable/disable the service and return success. 732 * 733 * There is no way to specify that state changes must be 734 * synchronous using the library API as yet, so we use 735 * the -s option provided by svcadm. 736 */ 737 fmri = getenv("SMF_FMRI"); 738 if (fmri == NULL) { 739 FILE *p; 740 char *cmd; 741 742 if (state != 0) { 743 cmd = "/usr/sbin/svcadm enable -s " \ 744 SMF_SVC_INSTANCE; 745 } else { 746 cmd = "/usr/sbin/svcadm disable -s " \ 747 SMF_SVC_INSTANCE; 748 } 749 if ((p = popen(cmd, "wF")) == NULL || pclose(p) != 0) { 750 pool_seterror(POE_SYSTEM); 751 return (PO_FAIL); 752 } 753 return (PO_SUCCESS); 754 } 755 756 if ((fd = open(pool_dynamic_location(), O_RDWR | O_EXCL)) < 0) { 757 pool_seterror(POE_SYSTEM); 758 return (PO_FAIL); 759 } 760 761 /* 762 * If pools are being enabled/disabled by another smf service, 763 * enable the smf service instance. This must be done 764 * asynchronously as one service cannot synchronously 765 * enable/disable another. 766 */ 767 if (strcmp(fmri, SMF_SVC_INSTANCE) != 0) { 768 int res; 769 770 if (state != 0) 771 res = smf_enable_instance(SMF_SVC_INSTANCE, 0); 772 else 773 res = smf_disable_instance(SMF_SVC_INSTANCE, 0); 774 775 if (res != 0) { 776 (void) close(fd); 777 pool_seterror(POE_SYSTEM); 778 return (PO_FAIL); 779 } 780 } 781 status.ps_io_state = state; 782 783 if (ioctl(fd, POOL_STATUS, &status) < 0) { 784 (void) close(fd); 785 pool_seterror(POE_SYSTEM); 786 return (PO_FAIL); 787 } 788 789 (void) close(fd); 790 791 } 792 return (PO_SUCCESS); 793 } 794 795 /* 796 * General Data Provider Independent Access Methods 797 */ 798 799 /* 800 * Property manipulation code. 801 * 802 * The pool_(get|rm|set)_property() functions consult the plugins before 803 * looking at the actual configuration. This allows plugins to provide 804 * "virtual" properties that may not exist in the configuration file per se, 805 * but behave like regular properties. This also allows plugins to reserve 806 * certain properties as read-only, non-removable, etc. 807 * 808 * A negative value returned from the plugin denotes error, 0 means that the 809 * property request should be forwarded to the backend, and 1 means the request 810 * was satisfied by the plugin and should not be processed further. 811 * 812 * The (get|rm|set)_property() functions bypass the plugin layer completely, 813 * and hence should not be generally used. 814 */ 815 816 /* 817 * Return true if the string passed in matches the pattern 818 * [A-Za-z][A-Za-z0-9,._-]* 819 */ 820 int 821 is_valid_name(const char *name) 822 { 823 int i; 824 char c; 825 826 if (name == NULL) 827 return (PO_FALSE); 828 if (!isalpha(name[0])) 829 return (PO_FALSE); 830 for (i = 1; (c = name[i]) != '\0'; i++) { 831 if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-') 832 return (PO_FALSE); 833 } 834 return (PO_TRUE); 835 } 836 837 /* 838 * Return true if the string passed in matches the pattern 839 * [A-Za-z_][A-Za-z0-9,._-]* 840 * A property name starting with a '_' is an "invisible" property that does not 841 * show up in a property walk. 842 */ 843 int 844 is_valid_prop_name(const char *prop_name) 845 { 846 int i; 847 char c; 848 849 if (prop_name == NULL) 850 return (PO_FALSE); 851 if (!isalpha(prop_name[0]) && prop_name[0] != '_') 852 return (PO_FALSE); 853 for (i = 1; (c = prop_name[i]) != '\0'; i++) { 854 if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-') 855 return (PO_FALSE); 856 } 857 return (PO_TRUE); 858 } 859 860 /* 861 * Return the specified property value. 862 * 863 * POC_INVAL is returned if an error is detected and the error code is updated 864 * to indicate the cause of the error. 865 */ 866 pool_value_class_t 867 pool_get_property(const pool_conf_t *conf, const pool_elem_t *pe, 868 const char *name, pool_value_t *val) 869 { 870 const pool_prop_t *prop_info; 871 872 if (pool_conf_status(conf) == POF_INVALID) { 873 pool_seterror(POE_BADPARAM); 874 return (POC_INVAL); 875 } 876 if (pool_value_set_name(val, name) != PO_SUCCESS) { 877 return (POC_INVAL); 878 } 879 /* 880 * Check to see if this is a property we are managing. If it 881 * is and it has an interceptor installed for property 882 * retrieval, use it. 883 */ 884 if ((prop_info = provider_get_prop(pe, name)) != NULL && 885 prop_info->pp_op.ppo_get_value != NULL) { 886 if (prop_info->pp_op.ppo_get_value(pe, val) == PO_FAIL) 887 return (POC_INVAL); 888 else 889 return (pool_value_get_type(val)); 890 } 891 return (pe->pe_get_prop(pe, name, val)); 892 } 893 894 /* 895 * Return the specified property value with the namespace prepended. 896 * e.g. If this function is used to get the property "name" on a pool, it will 897 * attempt to retrieve "pool.name". 898 * 899 * POC_INVAL is returned if an error is detected and the error code is updated 900 * to indicate the cause of the error. 901 */ 902 pool_value_class_t 903 pool_get_ns_property(const pool_elem_t *pe, const char *name, pool_value_t *val) 904 { 905 int ret; 906 char_buf_t *cb; 907 908 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 909 return (POC_INVAL); 910 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == 911 PO_FAIL) { 912 free_char_buf(cb); 913 return (POC_INVAL); 914 } 915 ret = pool_get_property(TO_CONF(pe), pe, cb->cb_buf, val); 916 free_char_buf(cb); 917 return (ret); 918 } 919 920 /* 921 * Update the specified property value. 922 * 923 * PO_FAIL is returned if an error is detected and the error code is updated 924 * to indicate the cause of the error. 925 */ 926 int 927 pool_put_property(pool_conf_t *conf, pool_elem_t *pe, const char *name, 928 const pool_value_t *val) 929 { 930 const pool_prop_t *prop_info; 931 932 if (pool_conf_check(conf) != PO_SUCCESS) 933 return (PO_FAIL); 934 935 if (TO_CONF(pe) != conf) { 936 pool_seterror(POE_BADPARAM); 937 return (NULL); 938 } 939 940 /* Don't allow (re)setting of the "temporary" property */ 941 if (!is_valid_prop_name(name) || strstr(name, ".temporary") != NULL) { 942 pool_seterror(POE_BADPARAM); 943 return (PO_FAIL); 944 } 945 946 /* Don't allow rename of temporary pools/resources */ 947 if (strstr(name, ".name") != NULL && elem_is_tmp(pe)) { 948 boolean_t rename = B_TRUE; 949 pool_value_t *pv = pool_value_alloc(); 950 951 if (pe->pe_get_prop(pe, name, pv) != POC_INVAL) { 952 const char *s1 = NULL; 953 const char *s2 = NULL; 954 955 (void) pool_value_get_string(pv, &s1); 956 (void) pool_value_get_string(val, &s2); 957 if (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0) 958 rename = B_FALSE; 959 } 960 pool_value_free(pv); 961 962 if (rename) { 963 pool_seterror(POE_BADPARAM); 964 return (PO_FAIL); 965 } 966 } 967 968 /* 969 * Check to see if this is a property we are managing. If it is, 970 * ensure that we are happy with what the user is doing. 971 */ 972 if ((prop_info = provider_get_prop(pe, name)) != NULL) { 973 if (prop_is_readonly(prop_info) == PO_TRUE) { 974 pool_seterror(POE_BADPARAM); 975 return (PO_FAIL); 976 } 977 if (prop_info->pp_op.ppo_set_value && 978 prop_info->pp_op.ppo_set_value(pe, val) == PO_FAIL) 979 return (PO_FAIL); 980 } 981 982 return (pe->pe_put_prop(pe, name, val)); 983 } 984 985 /* 986 * Set temporary property to flag as a temporary element. 987 * 988 * PO_FAIL is returned if an error is detected and the error code is updated 989 * to indicate the cause of the error. 990 */ 991 int 992 pool_set_temporary(pool_conf_t *conf, pool_elem_t *pe) 993 { 994 int res; 995 char name[128]; 996 pool_value_t *val; 997 998 if (pool_conf_check(conf) != PO_SUCCESS) 999 return (PO_FAIL); 1000 1001 if (TO_CONF(pe) != conf) { 1002 pool_seterror(POE_BADPARAM); 1003 return (PO_FAIL); 1004 } 1005 1006 /* create property name based on element type */ 1007 if (snprintf(name, sizeof (name), "%s.temporary", 1008 pool_elem_class_string(pe)) > sizeof (name)) { 1009 pool_seterror(POE_SYSTEM); 1010 return (PO_FAIL); 1011 } 1012 1013 if ((val = pool_value_alloc()) == NULL) 1014 return (PO_FAIL); 1015 1016 pool_value_set_bool(val, (uchar_t)1); 1017 1018 res = pe->pe_put_prop(pe, name, val); 1019 1020 pool_value_free(val); 1021 1022 return (res); 1023 } 1024 1025 /* 1026 * Update the specified property value with the namespace prepended. 1027 * e.g. If this function is used to update the property "name" on a pool, it 1028 * will attempt to update "pool.name". 1029 * 1030 * PO_FAIL is returned if an error is detected and the error code is updated 1031 * to indicate the cause of the error. 1032 */ 1033 int 1034 pool_put_ns_property(pool_elem_t *pe, const char *name, 1035 const pool_value_t *val) 1036 { 1037 char_buf_t *cb; 1038 int ret; 1039 1040 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 1041 return (PO_FAIL); 1042 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == 1043 PO_FAIL) { 1044 free_char_buf(cb); 1045 return (PO_FAIL); 1046 } 1047 ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val); 1048 free_char_buf(cb); 1049 return (ret); 1050 } 1051 1052 /* 1053 * Update the specified property value. Do not use the property 1054 * protection mechanism. This function should only be used for cases 1055 * where the library must bypass the normal property protection 1056 * mechanism. The only known use is to update properties in the static 1057 * configuration when performing a commit. 1058 * 1059 * PO_FAIL is returned if an error is detected and the error code is 1060 * updated to indicate the cause of the error. 1061 */ 1062 int 1063 pool_put_any_property(pool_elem_t *pe, const char *name, 1064 const pool_value_t *val) 1065 { 1066 if (!is_valid_prop_name(name)) { 1067 pool_seterror(POE_BADPARAM); 1068 return (PO_FAIL); 1069 } 1070 1071 return (pe->pe_put_prop(pe, name, val)); 1072 } 1073 1074 /* 1075 * Update the specified property value with the namespace prepended. 1076 * e.g. If this function is used to update the property "name" on a pool, it 1077 * will attempt to update "pool.name". 1078 * 1079 * PO_FAIL is returned if an error is detected and the error code is updated 1080 * to indicate the cause of the error. 1081 */ 1082 int 1083 pool_put_any_ns_property(pool_elem_t *pe, const char *name, 1084 const pool_value_t *val) 1085 { 1086 char_buf_t *cb; 1087 int ret; 1088 1089 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 1090 return (PO_FAIL); 1091 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == 1092 PO_FAIL) { 1093 free_char_buf(cb); 1094 return (PO_FAIL); 1095 } 1096 ret = pool_put_any_property(pe, cb->cb_buf, val); 1097 free_char_buf(cb); 1098 return (ret); 1099 } 1100 1101 /* 1102 * Remove the specified property value. Note that some properties are 1103 * mandatory and thus failure to remove these properties is inevitable. 1104 * PO_FAIL is returned if an error is detected and the error code is updated 1105 * to indicate the cause of the error. 1106 */ 1107 int 1108 pool_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name) 1109 { 1110 const pool_prop_t *prop_info; 1111 1112 if (pool_conf_check(conf) != PO_SUCCESS) 1113 return (PO_FAIL); 1114 1115 if (TO_CONF(pe) != conf) { 1116 pool_seterror(POE_BADPARAM); 1117 return (NULL); 1118 } 1119 1120 /* Don't allow removal of the "temporary" property */ 1121 if (strstr(name, ".temporary") != NULL) { 1122 pool_seterror(POE_BADPARAM); 1123 return (PO_FAIL); 1124 } 1125 1126 /* 1127 * Check to see if this is a property we are managing. If it is, 1128 * ensure that we are happy with what the user is doing. 1129 */ 1130 if ((prop_info = provider_get_prop(pe, name)) != NULL) { 1131 if (prop_is_optional(prop_info) == PO_FALSE) { 1132 pool_seterror(POE_BADPARAM); 1133 return (PO_FAIL); 1134 } 1135 } 1136 return (pe->pe_rm_prop(pe, name)); 1137 } 1138 1139 /* 1140 * Check if the supplied name is a namespace protected property for the supplied 1141 * element, pe. If it is, return the prefix, otherwise just return NULL. 1142 */ 1143 const char * 1144 is_ns_property(const pool_elem_t *pe, const char *name) 1145 { 1146 const char *prefix; 1147 1148 if ((prefix = pool_elem_class_string(pe)) != NULL) { 1149 if (strncmp(name, prefix, strlen(prefix)) == 0) 1150 return (prefix); 1151 } 1152 return (NULL); 1153 } 1154 1155 /* 1156 * Check if the supplied name is a namespace protected property for the supplied 1157 * element, pe. If it is, return the property name with the namespace stripped, 1158 * otherwise just return the name. 1159 */ 1160 const char * 1161 property_name_minus_ns(const pool_elem_t *pe, const char *name) 1162 { 1163 const char *prefix; 1164 if ((prefix = is_ns_property(pe, name)) != NULL) { 1165 return (name + strlen(prefix) + 1); 1166 } 1167 return (name); 1168 } 1169 1170 /* 1171 * Create an element to represent a pool and add it to the supplied 1172 * configuration. 1173 */ 1174 pool_t * 1175 pool_create(pool_conf_t *conf, const char *name) 1176 { 1177 pool_elem_t *pe; 1178 pool_value_t val = POOL_VALUE_INITIALIZER; 1179 const pool_prop_t *default_props; 1180 1181 if (pool_conf_check(conf) != PO_SUCCESS) 1182 return (NULL); 1183 1184 if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) { 1185 /* 1186 * A pool with the same name exists. Reject. 1187 */ 1188 pool_seterror(POE_BADPARAM); 1189 return (NULL); 1190 } 1191 if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_POOL, PREC_INVALID, 1192 PCEC_INVALID)) == NULL) { 1193 pool_seterror(POE_INVALID_CONF); 1194 return (NULL); 1195 } 1196 if ((default_props = provider_get_props(pe)) != NULL) { 1197 int i; 1198 for (i = 0; default_props[i].pp_pname != NULL; i++) { 1199 if (prop_is_init(&default_props[i]) && 1200 (pool_put_any_property(pe, 1201 default_props[i].pp_pname, 1202 &default_props[i].pp_value) == PO_FAIL)) { 1203 (void) pool_destroy(conf, pool_elem_pool(pe)); 1204 return (NULL); 1205 } 1206 } 1207 } 1208 if (pool_value_set_string(&val, name) != PO_SUCCESS) { 1209 (void) pool_destroy(conf, pool_elem_pool(pe)); 1210 pool_seterror(POE_SYSTEM); 1211 return (NULL); 1212 } 1213 if (pool_put_property(conf, pe, "pool.name", &val) == PO_FAIL) { 1214 (void) pool_destroy(conf, pool_elem_pool(pe)); 1215 pool_seterror(POE_PUTPROP); 1216 return (NULL); 1217 } 1218 1219 /* 1220 * If we are creating a temporary pool configuration, flag the pool. 1221 */ 1222 if (conf->pc_prov->pc_oflags & PO_TEMP) { 1223 if (pool_set_temporary(conf, pe) == PO_FAIL) { 1224 (void) pool_destroy(conf, pool_elem_pool(pe)); 1225 return (NULL); 1226 } 1227 } 1228 1229 return (pool_elem_pool(pe)); 1230 } 1231 1232 /* 1233 * Create an element to represent a res. 1234 */ 1235 pool_resource_t * 1236 pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name) 1237 { 1238 pool_elem_t *pe; 1239 pool_value_t val = POOL_VALUE_INITIALIZER; 1240 const pool_prop_t *default_props; 1241 pool_resource_t **resources; 1242 int is_default = 0; 1243 uint_t nelem; 1244 pool_elem_class_t elem_class; 1245 pool_resource_elem_class_t type; 1246 pool_value_t *props[] = { NULL, NULL }; 1247 1248 if (pool_conf_check(conf) != PO_SUCCESS) 1249 return (NULL); 1250 1251 if ((type = pool_resource_elem_class_from_string(sz_type)) == 1252 PREC_INVALID) { 1253 pool_seterror(POE_BADPARAM); 1254 return (NULL); 1255 } 1256 1257 if (strcmp(sz_type, "pset") != 0) { 1258 pool_seterror(POE_BADPARAM); 1259 return (NULL); 1260 } 1261 1262 if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) != 1263 NULL) { 1264 /* 1265 * Resources must be unique by name+type. 1266 */ 1267 pool_seterror(POE_BADPARAM); 1268 return (NULL); 1269 } 1270 1271 props[0] = &val; 1272 1273 if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS || 1274 pool_value_set_name(props[0], c_type) != PO_SUCCESS) { 1275 return (NULL); 1276 } 1277 1278 if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) { 1279 /* 1280 * This is the first representative of this type; when it's 1281 * created it should be created with 'default' = 'true'. 1282 */ 1283 is_default = 1; 1284 } else { 1285 free(resources); 1286 } 1287 /* 1288 * TODO: If Additional PEC_RES_COMP types are added to 1289 * pool_impl.h, this would need to be extended. 1290 */ 1291 switch (type) { 1292 case PREC_PSET: 1293 elem_class = PEC_RES_COMP; 1294 break; 1295 default: 1296 elem_class = PEC_RES_AGG; 1297 break; 1298 } 1299 if ((pe = conf->pc_prov->pc_elem_create(conf, elem_class, type, 1300 PCEC_INVALID)) == NULL) { 1301 pool_seterror(POE_INVALID_CONF); 1302 return (NULL); 1303 } 1304 1305 /* 1306 * The plugins contain a list of default properties and their values 1307 * for resources. The resource returned, hence, is fully initialized. 1308 */ 1309 if ((default_props = provider_get_props(pe)) != NULL) { 1310 int i; 1311 for (i = 0; default_props[i].pp_pname != NULL; i++) { 1312 if (prop_is_init(&default_props[i]) && 1313 pool_put_any_property(pe, default_props[i].pp_pname, 1314 &default_props[i].pp_value) == PO_FAIL) { 1315 (void) pool_resource_destroy(conf, 1316 pool_elem_res(pe)); 1317 return (NULL); 1318 } 1319 } 1320 } 1321 if (pool_value_set_string(&val, name) != PO_SUCCESS || 1322 pool_put_ns_property(pe, "name", &val) != PO_SUCCESS) { 1323 (void) pool_resource_destroy(conf, pool_elem_res(pe)); 1324 return (NULL); 1325 } 1326 if (is_default) { 1327 pool_value_set_bool(&val, PO_TRUE); 1328 if (pool_put_any_ns_property(pe, "default", &val) != 1329 PO_SUCCESS) { 1330 (void) pool_resource_destroy(conf, pool_elem_res(pe)); 1331 return (NULL); 1332 } 1333 } 1334 1335 /* 1336 * If we are creating a temporary pool configuration, flag the resource. 1337 */ 1338 if (conf->pc_prov->pc_oflags & PO_TEMP) { 1339 if (pool_set_temporary(conf, pe) != PO_SUCCESS) { 1340 (void) pool_resource_destroy(conf, pool_elem_res(pe)); 1341 return (NULL); 1342 } 1343 } 1344 1345 return (pool_elem_res(pe)); 1346 } 1347 1348 /* 1349 * Create an element to represent a resource component. 1350 */ 1351 pool_component_t * 1352 pool_component_create(pool_conf_t *conf, const pool_resource_t *res, 1353 int64_t sys_id) 1354 { 1355 pool_elem_t *pe; 1356 pool_value_t val = POOL_VALUE_INITIALIZER; 1357 const pool_prop_t *default_props; 1358 char refbuf[KEY_BUFFER_SIZE]; 1359 1360 if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_COMP, 1361 PREC_INVALID, PCEC_CPU)) == NULL) { 1362 pool_seterror(POE_INVALID_CONF); 1363 return (NULL); 1364 } 1365 /* 1366 * TODO: If additional PEC_COMP types are added in pool_impl.h, 1367 * this would need to be extended. 1368 */ 1369 pe->pe_component_class = PCEC_CPU; 1370 /* Now set the container for this comp */ 1371 if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) { 1372 (void) pool_component_destroy(pool_elem_comp(pe)); 1373 return (NULL); 1374 } 1375 /* 1376 * The plugins contain a list of default properties and their values 1377 * for resources. The resource returned, hence, is fully initialized. 1378 */ 1379 if ((default_props = provider_get_props(pe)) != NULL) { 1380 int i; 1381 for (i = 0; default_props[i].pp_pname != NULL; i++) { 1382 if (prop_is_init(&default_props[i]) && 1383 pool_put_any_property(pe, 1384 default_props[i].pp_pname, 1385 &default_props[i].pp_value) == PO_FAIL) { 1386 (void) pool_component_destroy( 1387 pool_elem_comp(pe)); 1388 return (NULL); 1389 } 1390 } 1391 } 1392 /* 1393 * Set additional attributes/properties on component. 1394 */ 1395 pool_value_set_int64(&val, sys_id); 1396 if (pool_put_any_ns_property(pe, c_sys_prop, &val) != PO_SUCCESS) { 1397 (void) pool_component_destroy(pool_elem_comp(pe)); 1398 return (NULL); 1399 } 1400 if (snprintf(refbuf, KEY_BUFFER_SIZE, "%s_%lld", 1401 pool_elem_class_string(pe), sys_id) > KEY_BUFFER_SIZE) { 1402 (void) pool_component_destroy(pool_elem_comp(pe)); 1403 return (NULL); 1404 } 1405 if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) { 1406 (void) pool_component_destroy(pool_elem_comp(pe)); 1407 return (NULL); 1408 } 1409 if (pool_put_any_ns_property(pe, c_ref_id, &val) != PO_SUCCESS) { 1410 (void) pool_component_destroy(pool_elem_comp(pe)); 1411 return (NULL); 1412 } 1413 return (pool_elem_comp(pe)); 1414 } 1415 1416 /* 1417 * Return the location of a configuration. 1418 */ 1419 const char * 1420 pool_conf_location(const pool_conf_t *conf) 1421 { 1422 if (pool_conf_status(conf) == POF_INVALID) { 1423 pool_seterror(POE_BADPARAM); 1424 return (NULL); 1425 } 1426 return (conf->pc_location); 1427 } 1428 /* 1429 * Close a configuration, freeing all associated resources. Once a 1430 * configuration is closed, it can no longer be used. 1431 */ 1432 int 1433 pool_conf_close(pool_conf_t *conf) 1434 { 1435 int rv; 1436 1437 if (pool_conf_status(conf) == POF_INVALID) { 1438 pool_seterror(POE_BADPARAM); 1439 return (PO_FAIL); 1440 } 1441 rv = conf->pc_prov->pc_close(conf); 1442 conf->pc_prov = NULL; 1443 free((void *)conf->pc_location); 1444 conf->pc_location = NULL; 1445 conf->pc_state = POF_INVALID; 1446 return (rv); 1447 } 1448 1449 /* 1450 * Remove a configuration, freeing all associated resources. Once a 1451 * configuration is removed, it can no longer be accessed and is forever 1452 * gone. 1453 */ 1454 int 1455 pool_conf_remove(pool_conf_t *conf) 1456 { 1457 int rv; 1458 1459 if (pool_conf_status(conf) == POF_INVALID) { 1460 pool_seterror(POE_BADPARAM); 1461 return (PO_FAIL); 1462 } 1463 rv = conf->pc_prov->pc_remove(conf); 1464 conf->pc_state = POF_INVALID; 1465 return (rv); 1466 } 1467 1468 /* 1469 * pool_conf_alloc() allocate the resources to represent a configuration. 1470 */ 1471 pool_conf_t * 1472 pool_conf_alloc(void) 1473 { 1474 pool_conf_t *conf; 1475 1476 if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) { 1477 pool_seterror(POE_SYSTEM); 1478 return (NULL); 1479 } 1480 conf->pc_state = POF_INVALID; 1481 return (conf); 1482 } 1483 1484 /* 1485 * pool_conf_free() frees the resources associated with a configuration. 1486 */ 1487 void 1488 pool_conf_free(pool_conf_t *conf) 1489 { 1490 free(conf); 1491 } 1492 1493 /* 1494 * pool_conf_open() opens a configuration, establishing all required 1495 * connections to the data source. 1496 */ 1497 int 1498 pool_conf_open(pool_conf_t *conf, const char *location, int oflags) 1499 { 1500 /* 1501 * Since you can't do anything to a pool configuration without opening 1502 * it, this represents a good point to intialise structures that would 1503 * otherwise need to be initialised in a .init section. 1504 */ 1505 internal_init(); 1506 1507 if (pool_conf_status(conf) != POF_INVALID) { 1508 /* 1509 * Already opened configuration, return PO_FAIL 1510 */ 1511 pool_seterror(POE_BADPARAM); 1512 return (PO_FAIL); 1513 } 1514 if (oflags & ~(PO_RDONLY | PO_RDWR | PO_CREAT | PO_DISCO | PO_UPDATE | 1515 PO_TEMP)) { 1516 pool_seterror(POE_BADPARAM); 1517 return (PO_FAIL); 1518 } 1519 1520 /* 1521 * Creating a configuration implies read-write access, so make 1522 * sure that PO_RDWR is set in addition if PO_CREAT is set. 1523 */ 1524 if (oflags & PO_CREAT) 1525 oflags |= PO_RDWR; 1526 1527 /* location is ignored when creating a temporary configuration */ 1528 if (oflags & PO_TEMP) 1529 location = ""; 1530 1531 if ((conf->pc_location = strdup(location)) == NULL) { 1532 pool_seterror(POE_SYSTEM); 1533 return (PO_FAIL); 1534 } 1535 /* 1536 * This is the crossover point into the actual data provider 1537 * implementation, allocate a data provider of the appropriate 1538 * type for your data storage medium. In this case it's either a kernel 1539 * or xml data provider. To use a different data provider, write some 1540 * code to implement all the required interfaces and then change the 1541 * following code to allocate a data provider which uses your new code. 1542 * All data provider routines can be static, apart from the allocation 1543 * routine. 1544 * 1545 * For temporary pools (PO_TEMP) we start with a copy of the current 1546 * dynamic configuration and do all of the updates in-memory. 1547 */ 1548 if (oflags & PO_TEMP) { 1549 if (pool_knl_connection_alloc(conf, PO_TEMP) != PO_SUCCESS) { 1550 conf->pc_state = POF_INVALID; 1551 return (PO_FAIL); 1552 } 1553 /* set rdwr flag so we can updated the in-memory config. */ 1554 conf->pc_prov->pc_oflags |= PO_RDWR; 1555 1556 } else if (strcmp(location, pool_dynamic_location()) == 0) { 1557 if (pool_knl_connection_alloc(conf, oflags) != PO_SUCCESS) { 1558 conf->pc_state = POF_INVALID; 1559 return (PO_FAIL); 1560 } 1561 } else { 1562 if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) { 1563 conf->pc_state = POF_INVALID; 1564 return (PO_FAIL); 1565 } 1566 } 1567 return (PO_SUCCESS); 1568 } 1569 1570 /* 1571 * Rollback a configuration. This will undo all changes to the configuration 1572 * since the last time pool_conf_commit was called. 1573 */ 1574 int 1575 pool_conf_rollback(pool_conf_t *conf) 1576 { 1577 if (pool_conf_status(conf) == POF_INVALID) { 1578 pool_seterror(POE_BADPARAM); 1579 return (PO_FAIL); 1580 } 1581 return (conf->pc_prov->pc_rollback(conf)); 1582 } 1583 1584 /* 1585 * Commit a configuration. This will apply all changes to the 1586 * configuration to the permanent data store. The active parameter 1587 * indicates whether the configuration should be used to update the 1588 * dynamic configuration from the supplied (static) configuration or 1589 * whether it should be written back to persistent store. 1590 */ 1591 int 1592 pool_conf_commit(pool_conf_t *conf, int active) 1593 { 1594 int retval; 1595 1596 if (pool_conf_status(conf) == POF_INVALID) { 1597 pool_seterror(POE_BADPARAM); 1598 return (PO_FAIL); 1599 } 1600 if (active) { 1601 int oflags; 1602 1603 if (conf_is_dynamic(conf) == PO_TRUE) { 1604 pool_seterror(POE_BADPARAM); 1605 return (PO_FAIL); 1606 } 1607 /* 1608 * Pretend that the configuration was opened PO_RDWR 1609 * so that a configuration which was opened PO_RDONLY 1610 * can be committed. The original flags are preserved 1611 * in oflags and restored after pool_conf_commit_sys() 1612 * returns. 1613 */ 1614 oflags = conf->pc_prov->pc_oflags; 1615 conf->pc_prov->pc_oflags |= PO_RDWR; 1616 retval = pool_conf_commit_sys(conf, active); 1617 conf->pc_prov->pc_oflags = oflags; 1618 } else { 1619 /* 1620 * Write the configuration back to the backing store. 1621 */ 1622 retval = conf->pc_prov->pc_commit(conf); 1623 } 1624 return (retval); 1625 } 1626 1627 /* 1628 * Export a configuration. This will export a configuration in the specified 1629 * format (fmt) to the specified location. 1630 */ 1631 int 1632 pool_conf_export(const pool_conf_t *conf, const char *location, 1633 pool_export_format_t fmt) 1634 { 1635 if (pool_conf_status(conf) == POF_INVALID) { 1636 pool_seterror(POE_BADPARAM); 1637 return (PO_FAIL); 1638 } 1639 return (conf->pc_prov->pc_export(conf, location, fmt)); 1640 } 1641 1642 /* 1643 * Validate a configuration. This will validate a configuration at the 1644 * specified level. 1645 */ 1646 int 1647 pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level) 1648 { 1649 if (pool_conf_status(conf) == POF_INVALID) { 1650 pool_seterror(POE_BADPARAM); 1651 return (PO_FAIL); 1652 } 1653 return (conf->pc_prov->pc_validate(conf, level)); 1654 } 1655 1656 /* 1657 * Update the snapshot of a configuration. This can only be used on a 1658 * dynamic configuration. 1659 */ 1660 int 1661 pool_conf_update(const pool_conf_t *conf, int *changed) 1662 { 1663 if (pool_conf_status(conf) == POF_INVALID || 1664 conf_is_dynamic(conf) == PO_FALSE) { 1665 pool_seterror(POE_BADPARAM); 1666 return (PO_FAIL); 1667 } 1668 /* 1669 * Since this function only makes sense for dynamic 1670 * configurations, just call directly into the appropriate 1671 * function. This could be added into the pool_connection_t 1672 * interface if it was ever required. 1673 */ 1674 if (changed) 1675 *changed = 0; 1676 return (pool_knl_update((pool_conf_t *)conf, changed)); 1677 } 1678 1679 /* 1680 * Walk the properties of the supplied elem, calling the user supplied 1681 * function repeatedly as long as the user function returns 1682 * PO_SUCCESS. 1683 */ 1684 int 1685 pool_walk_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg, 1686 int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *, 1687 pool_value_t *, void *)) 1688 { 1689 return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0)); 1690 } 1691 1692 void 1693 free_value_list(int npvals, pool_value_t **pvals) 1694 { 1695 int j; 1696 1697 for (j = 0; j < npvals; j++) { 1698 if (pvals[j]) 1699 pool_value_free(pvals[j]); 1700 } 1701 free(pvals); 1702 } 1703 1704 /* 1705 * Walk the properties of the supplied elem, calling the user supplied 1706 * function repeatedly as long as the user function returns 1707 * PO_SUCCESS. 1708 * The list of properties to be walked is retrieved from the element 1709 */ 1710 int 1711 pool_walk_any_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg, 1712 int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *, 1713 pool_value_t *, void *), int any) 1714 { 1715 pool_value_t **pvals; 1716 int i; 1717 const pool_prop_t *props = provider_get_props(elem); 1718 uint_t npvals; 1719 1720 if (pool_conf_status(conf) == POF_INVALID) { 1721 pool_seterror(POE_BADPARAM); 1722 return (PO_FAIL); 1723 } 1724 1725 if (props == NULL) { 1726 pool_seterror(POE_INVALID_CONF); 1727 return (PO_FAIL); 1728 } 1729 1730 if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL) 1731 return (PO_FAIL); 1732 1733 /* 1734 * Now walk the managed properties. As we find managed 1735 * properties removed them from the list of all properties to 1736 * prevent duplication. 1737 */ 1738 for (i = 0; props[i].pp_pname != NULL; i++) { 1739 int j; 1740 1741 /* 1742 * Special processing for type 1743 */ 1744 if (strcmp(props[i].pp_pname, c_type) == 0) { 1745 pool_value_t val = POOL_VALUE_INITIALIZER; 1746 1747 if (pool_value_set_name(&val, props[i].pp_pname) == 1748 PO_FAIL) { 1749 free_value_list(npvals, pvals); 1750 return (PO_FAIL); 1751 } 1752 if (props[i].pp_op.ppo_get_value(elem, &val) == 1753 PO_FAIL) { 1754 free_value_list(npvals, pvals); 1755 return (PO_FAIL); 1756 } 1757 if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) { 1758 if (prop_callback(conf, elem, props[i].pp_pname, 1759 &val, arg) != PO_SUCCESS) { 1760 free_value_list(npvals, pvals); 1761 pool_seterror(POE_BADPARAM); 1762 return (PO_FAIL); 1763 } 1764 } 1765 continue; 1766 } 1767 1768 for (j = 0; j < npvals; j++) { 1769 if (pvals[j] && strcmp(pool_value_get_name(pvals[j]), 1770 props[i].pp_pname) == 0) 1771 break; 1772 } 1773 /* 1774 * If we have found the property, then j < npvals. Process it 1775 * according to our property attributes. Otherwise, it's not 1776 * a managed property, so just ignore it until later. 1777 */ 1778 if (j < npvals) { 1779 if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) { 1780 if (props[i].pp_op.ppo_get_value) { 1781 if (pool_value_set_name(pvals[j], 1782 props[i].pp_pname) == PO_FAIL) { 1783 free_value_list(npvals, pvals); 1784 return (PO_FAIL); 1785 } 1786 if (props[i].pp_op.ppo_get_value(elem, 1787 pvals[j]) == PO_FAIL) { 1788 free_value_list(npvals, pvals); 1789 return (PO_FAIL); 1790 } 1791 } 1792 if (prop_callback(conf, elem, props[i].pp_pname, 1793 pvals[j], arg) != PO_SUCCESS) { 1794 free_value_list(npvals, pvals); 1795 pool_seterror(POE_BADPARAM); 1796 return (PO_FAIL); 1797 } 1798 } 1799 pool_value_free(pvals[j]); 1800 pvals[j] = NULL; 1801 } 1802 } 1803 for (i = 0; i < npvals; i++) { 1804 if (pvals[i]) { 1805 const char *name = pool_value_get_name(pvals[i]); 1806 char *qname = strrchr(name, '.'); 1807 if ((qname && qname[1] != '_') || 1808 (!qname && name[0] != '_')) { 1809 if (prop_callback(conf, elem, name, pvals[i], 1810 arg) != PO_SUCCESS) { 1811 free_value_list(npvals, pvals); 1812 pool_seterror(POE_BADPARAM); 1813 return (PO_FAIL); 1814 } 1815 } 1816 pool_value_free(pvals[i]); 1817 pvals[i] = NULL; 1818 } 1819 } 1820 free(pvals); 1821 return (PO_SUCCESS); 1822 } 1823 1824 /* 1825 * Return a pool, searching the supplied configuration for a pool with the 1826 * supplied name. The search is case sensitive. 1827 */ 1828 pool_t * 1829 pool_get_pool(const pool_conf_t *conf, const char *name) 1830 { 1831 pool_value_t *props[] = { NULL, NULL }; 1832 pool_t **rs; 1833 pool_t *ret; 1834 uint_t size = 0; 1835 pool_value_t val = POOL_VALUE_INITIALIZER; 1836 1837 props[0] = &val; 1838 1839 if (pool_conf_status(conf) == POF_INVALID) { 1840 pool_seterror(POE_BADPARAM); 1841 return (NULL); 1842 } 1843 1844 if (pool_value_set_name(props[0], "pool.name") != PO_SUCCESS || 1845 pool_value_set_string(props[0], name) != PO_SUCCESS) { 1846 return (NULL); 1847 } 1848 rs = pool_query_pools(conf, &size, props); 1849 if (rs == NULL) { /* Can't find a pool to match the name */ 1850 return (NULL); 1851 } 1852 if (size != 1) { 1853 free(rs); 1854 pool_seterror(POE_INVALID_CONF); 1855 return (NULL); 1856 } 1857 ret = rs[0]; 1858 free(rs); 1859 return (ret); 1860 } 1861 1862 /* 1863 * Return a result set of pools, searching the supplied configuration 1864 * for pools which match the supplied property criteria. props is a null 1865 * terminated list of properties which will be used to match qualifying 1866 * pools. size is updated with the size of the pool 1867 */ 1868 pool_t ** 1869 pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props) 1870 { 1871 pool_result_set_t *rs; 1872 pool_elem_t *pe; 1873 pool_t **result = NULL; 1874 int i = 0; 1875 1876 if (pool_conf_status(conf) == POF_INVALID) { 1877 pool_seterror(POE_BADPARAM); 1878 return (NULL); 1879 } 1880 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props); 1881 if (rs == NULL) { 1882 return (NULL); 1883 } 1884 if ((*size = pool_rs_count(rs)) == 0) { 1885 (void) pool_rs_close(rs); 1886 return (NULL); 1887 } 1888 if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) { 1889 pool_seterror(POE_SYSTEM); 1890 (void) pool_rs_close(rs); 1891 return (NULL); 1892 } 1893 (void) memset(result, 0, sizeof (pool_t *) * (*size + 1)); 1894 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 1895 if (pool_elem_class(pe) != PEC_POOL) { 1896 pool_seterror(POE_INVALID_CONF); 1897 free(result); 1898 (void) pool_rs_close(rs); 1899 return (NULL); 1900 } 1901 result[i++] = pool_elem_pool(pe); 1902 } 1903 (void) pool_rs_close(rs); 1904 return (result); 1905 } 1906 1907 /* 1908 * Return an res, searching the supplied configuration for an res with the 1909 * supplied name. The search is case sensitive. 1910 */ 1911 pool_resource_t * 1912 pool_get_resource(const pool_conf_t *conf, const char *sz_type, 1913 const char *name) 1914 { 1915 pool_value_t *props[] = { NULL, NULL, NULL }; 1916 pool_resource_t **rs; 1917 pool_resource_t *ret; 1918 uint_t size = 0; 1919 char_buf_t *cb = NULL; 1920 pool_value_t val0 = POOL_VALUE_INITIALIZER; 1921 pool_value_t val1 = POOL_VALUE_INITIALIZER; 1922 1923 if (pool_conf_status(conf) == POF_INVALID) { 1924 pool_seterror(POE_BADPARAM); 1925 return (NULL); 1926 } 1927 1928 if (sz_type == NULL) { 1929 pool_seterror(POE_BADPARAM); 1930 return (NULL); 1931 } 1932 1933 props[0] = &val0; 1934 props[1] = &val1; 1935 1936 if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS || 1937 pool_value_set_name(props[0], c_type) != PO_SUCCESS) 1938 return (NULL); 1939 1940 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 1941 return (NULL); 1942 } 1943 if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) { 1944 free_char_buf(cb); 1945 return (NULL); 1946 } 1947 if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { 1948 free_char_buf(cb); 1949 return (NULL); 1950 } 1951 if (pool_value_set_string(props[1], name) != PO_SUCCESS) { 1952 free_char_buf(cb); 1953 return (NULL); 1954 } 1955 free_char_buf(cb); 1956 rs = pool_query_resources(conf, &size, props); 1957 if (rs == NULL) { 1958 return (NULL); 1959 } 1960 if (size != 1) { 1961 free(rs); 1962 pool_seterror(POE_INVALID_CONF); 1963 return (NULL); 1964 } 1965 ret = rs[0]; 1966 free(rs); 1967 return (ret); 1968 } 1969 1970 /* 1971 * Return a result set of res (actually as pool_elem_ts), searching the 1972 * supplied configuration for res which match the supplied property 1973 * criteria. props is a null terminated list of properties which will be used 1974 * to match qualifying res. 1975 */ 1976 pool_resource_t ** 1977 pool_query_resources(const pool_conf_t *conf, uint_t *size, 1978 pool_value_t **props) 1979 { 1980 pool_result_set_t *rs; 1981 pool_elem_t *pe; 1982 pool_resource_t **result = NULL; 1983 int i = 0; 1984 1985 if (pool_conf_status(conf) == POF_INVALID) { 1986 pool_seterror(POE_BADPARAM); 1987 return (NULL); 1988 } 1989 1990 *size = 0; 1991 1992 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props); 1993 if (rs == NULL) { 1994 return (NULL); 1995 } 1996 if ((*size = pool_rs_count(rs)) == 0) { 1997 (void) pool_rs_close(rs); 1998 return (NULL); 1999 } 2000 if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1))) 2001 == NULL) { 2002 pool_seterror(POE_SYSTEM); 2003 (void) pool_rs_close(rs); 2004 return (NULL); 2005 } 2006 (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1)); 2007 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 2008 if (pool_elem_class(pe) != PEC_RES_COMP && 2009 pool_elem_class(pe) != PEC_RES_AGG) { 2010 pool_seterror(POE_INVALID_CONF); 2011 free(result); 2012 (void) pool_rs_close(rs); 2013 return (NULL); 2014 } 2015 result[i++] = pool_elem_res(pe); 2016 } 2017 (void) pool_rs_close(rs); 2018 return (result); 2019 } 2020 2021 /* 2022 * Return a result set of comp (actually as pool_elem_ts), searching the 2023 * supplied configuration for comp which match the supplied property 2024 * criteria. props is a null terminated list of properties which will be used 2025 * to match qualifying comp. 2026 */ 2027 pool_component_t ** 2028 pool_query_components(const pool_conf_t *conf, uint_t *size, 2029 pool_value_t **props) 2030 { 2031 return (pool_query_resource_components(conf, NULL, size, props)); 2032 } 2033 2034 /* 2035 * Destroy a pool. If the pool cannot be found or removed an error is 2036 * returned. This is basically a wrapper around pool_elem_remove to ensure 2037 * some type safety for the pool subtype. 2038 */ 2039 int 2040 pool_destroy(pool_conf_t *conf, pool_t *pp) 2041 { 2042 pool_elem_t *pe; 2043 2044 if (pool_conf_check(conf) != PO_SUCCESS) 2045 return (PO_FAIL); 2046 2047 pe = TO_ELEM(pp); 2048 2049 /* 2050 * Cannot destroy the default pool. 2051 */ 2052 if (elem_is_default(pe) == PO_TRUE) { 2053 pool_seterror(POE_BADPARAM); 2054 return (PO_FAIL); 2055 } 2056 if (pool_elem_remove(pe) != PO_SUCCESS) 2057 return (PO_FAIL); 2058 return (PO_SUCCESS); 2059 } 2060 2061 /* 2062 * Destroy an res. If the res cannot be found or removed an error is 2063 * returned. This is basically a wrapper around pool_elem_remove to ensure 2064 * some type safety for the res subtype. 2065 */ 2066 int 2067 pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs) 2068 { 2069 pool_elem_t *pe; 2070 pool_component_t **rl; 2071 uint_t res_size; 2072 pool_t **pl; 2073 uint_t npool; 2074 int i; 2075 2076 if (pool_conf_check(conf) != PO_SUCCESS) 2077 return (PO_FAIL); 2078 2079 pe = TO_ELEM(prs); 2080 2081 if (resource_is_system(prs) == PO_TRUE) { 2082 pool_seterror(POE_BADPARAM); 2083 return (PO_FAIL); 2084 } 2085 /* 2086 * Walk all the pools and dissociate any pools which are using 2087 * this resource. 2088 */ 2089 if ((pl = pool_query_pools(conf, &npool, NULL)) != NULL) { 2090 for (i = 0; i < npool; i++) { 2091 pool_resource_t **rl; 2092 uint_t nres; 2093 int j; 2094 2095 if ((rl = pool_query_pool_resources(conf, pl[i], &nres, 2096 NULL)) != NULL) { 2097 for (j = 0; j < nres; j++) { 2098 if (rl[j] == prs) { 2099 if (pool_dissociate(conf, pl[i], 2100 rl[j]) != PO_SUCCESS) { 2101 free(rl); 2102 free(pl); 2103 return (PO_FAIL); 2104 } 2105 break; 2106 } 2107 } 2108 free(rl); 2109 } 2110 } 2111 free(pl); 2112 } 2113 if (pe->pe_class == PEC_RES_COMP) { 2114 pool_resource_t *default_set_res; 2115 2116 /* 2117 * Use the xtransfer option to move comp around 2118 */ 2119 default_set_res = (pool_resource_t *)get_default_resource(prs); 2120 2121 if ((rl = pool_query_resource_components(conf, prs, &res_size, 2122 NULL)) != NULL) { 2123 int ostate = conf->pc_state; 2124 conf->pc_state = POF_DESTROY; 2125 if (pool_resource_xtransfer(conf, prs, default_set_res, 2126 rl) == PO_FAIL) { 2127 free(rl); 2128 conf->pc_state = ostate; 2129 return (PO_FAIL); 2130 } 2131 conf->pc_state = ostate; 2132 free(rl); 2133 } 2134 } 2135 if (pool_elem_remove(pe) != PO_SUCCESS) 2136 return (PO_FAIL); 2137 return (PO_SUCCESS); 2138 } 2139 2140 /* 2141 * Destroy a comp. If the comp cannot be found or removed an error is 2142 * returned. This is basically a wrapper around pool_elem_remove to ensure 2143 * some type safety for the comp subtype. 2144 */ 2145 int 2146 pool_component_destroy(pool_component_t *pr) 2147 { 2148 pool_elem_t *pe = TO_ELEM(pr); 2149 2150 if (pool_elem_remove(pe) != PO_SUCCESS) 2151 return (PO_FAIL); 2152 return (PO_SUCCESS); 2153 } 2154 2155 /* 2156 * Remove a pool_elem_t from a configuration. This has been "hidden" away as 2157 * a static routine since the only elements which are currently being removed 2158 * are pools, res & comp and the wrapper functions above provide type-safe 2159 * access. However, if there is a need to remove other types of elements 2160 * then this could be promoted to pool_impl.h or more wrappers could 2161 * be added to pool_impl.h. 2162 */ 2163 int 2164 pool_elem_remove(pool_elem_t *pe) 2165 { 2166 return (pe->pe_remove(pe)); 2167 } 2168 2169 /* 2170 * Execute a query to search for a qualifying set of elements. 2171 */ 2172 pool_result_set_t * 2173 pool_exec_query(const pool_conf_t *conf, const pool_elem_t *src, 2174 const char *src_attr, pool_elem_class_t classes, pool_value_t **props) 2175 { 2176 return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes, 2177 props)); 2178 } 2179 2180 /* 2181 * Get the next result from a result set of elements. 2182 */ 2183 pool_elem_t * 2184 pool_rs_next(pool_result_set_t *set) 2185 { 2186 return (set->prs_next(set)); 2187 } 2188 2189 /* 2190 * Get the previous result from a result set of elements. 2191 */ 2192 pool_elem_t * 2193 pool_rs_prev(pool_result_set_t *set) 2194 { 2195 return (set->prs_prev(set)); 2196 } 2197 2198 /* 2199 * Get the first result from a result set of elements. 2200 */ 2201 pool_elem_t * 2202 pool_rs_first(pool_result_set_t *set) 2203 { 2204 return (set->prs_first(set)); 2205 } 2206 2207 /* 2208 * Get the last result from a result set of elements. 2209 */ 2210 pool_elem_t * 2211 pool_rs_last(pool_result_set_t *set) 2212 { 2213 return (set->prs_last(set)); 2214 } 2215 2216 2217 /* 2218 * Get the count for a result set of elements. 2219 */ 2220 int 2221 pool_rs_count(pool_result_set_t *set) 2222 { 2223 return (set->prs_count(set)); 2224 } 2225 2226 /* 2227 * Get the index for a result set of elements. 2228 */ 2229 int 2230 pool_rs_get_index(pool_result_set_t *set) 2231 { 2232 return (set->prs_get_index(set)); 2233 } 2234 2235 /* 2236 * Set the index for a result set of elements. 2237 */ 2238 int 2239 pool_rs_set_index(pool_result_set_t *set, int index) 2240 { 2241 return (set->prs_set_index(set, index)); 2242 } 2243 2244 /* 2245 * Close a result set of elements, freeing all associated resources. 2246 */ 2247 int 2248 pool_rs_close(pool_result_set_t *set) 2249 { 2250 return (set->prs_close(set)); 2251 } 2252 2253 /* 2254 * When transferring resource components using pool_resource_transfer, 2255 * this function is invoked to choose which actual components will be 2256 * transferred. 2257 */ 2258 int 2259 choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size) 2260 { 2261 pool_component_t **components = NULL, *moved[] = { NULL, NULL }; 2262 int i; 2263 uint_t ncomponent; 2264 pool_conf_t *conf = TO_CONF(TO_ELEM(src)); 2265 2266 if (size == 0) 2267 return (PO_SUCCESS); 2268 /* 2269 * Get the component list from our src component. 2270 */ 2271 if ((components = pool_query_resource_components(conf, src, &ncomponent, 2272 NULL)) == NULL) { 2273 pool_seterror(POE_BADPARAM); 2274 return (PO_FAIL); 2275 } 2276 qsort(components, ncomponent, sizeof (pool_elem_t *), 2277 qsort_elem_compare); 2278 /* 2279 * Components that aren't specifically requested by the resource 2280 * should be transferred out first. 2281 */ 2282 for (i = 0; size > 0 && components[i] != NULL; i++) { 2283 if (!cpu_is_requested(components[i])) { 2284 moved[0] = components[i]; 2285 if (pool_resource_xtransfer(conf, src, dst, moved) == 2286 PO_SUCCESS) { 2287 size--; 2288 } 2289 } 2290 } 2291 2292 /* 2293 * If we couldn't find enough "un-requested" components, select random 2294 * requested components. 2295 */ 2296 for (i = 0; size > 0 && components[i] != NULL; i++) { 2297 if (cpu_is_requested(components[i])) { 2298 moved[0] = components[i]; 2299 if (pool_resource_xtransfer(conf, src, dst, moved) == 2300 PO_SUCCESS) { 2301 size--; 2302 } 2303 } 2304 } 2305 2306 free(components); 2307 /* 2308 * If we couldn't transfer out all the resources we asked for, then 2309 * return error. 2310 */ 2311 return (size == 0 ? PO_SUCCESS : PO_FAIL); 2312 } 2313 2314 /* 2315 * Common processing for a resource transfer (xfer or xxfer). 2316 * 2317 * - Return XFER_CONTINUE if the transfer should proceeed 2318 * - Return XFER_FAIL if the transfer should be stopped in failure 2319 * - Return XFER_SUCCESS if the transfer should be stopped in success 2320 */ 2321 int 2322 setup_transfer(pool_conf_t *conf, pool_resource_t *src, pool_resource_t *tgt, 2323 uint64_t size, uint64_t *src_size, uint64_t *tgt_size) 2324 { 2325 uint64_t src_min; 2326 uint64_t tgt_max; 2327 2328 if (pool_conf_check(conf) != PO_SUCCESS) 2329 return (XFER_FAIL); 2330 2331 /* 2332 * Makes sure the two resources are of the same type 2333 */ 2334 if (pool_resource_elem_class(TO_ELEM(src)) != 2335 pool_resource_elem_class(TO_ELEM(tgt))) { 2336 pool_seterror(POE_BADPARAM); 2337 return (XFER_FAIL); 2338 } 2339 2340 /* 2341 * Transferring to yourself is a no-op 2342 */ 2343 if (src == tgt) 2344 return (XFER_SUCCESS); 2345 2346 /* 2347 * Transferring nothing is a no-op 2348 */ 2349 if (size == 0) 2350 return (XFER_SUCCESS); 2351 2352 if (resource_get_min(src, &src_min) != PO_SUCCESS || 2353 resource_get_size(src, src_size) != PO_SUCCESS || 2354 resource_get_max(tgt, &tgt_max) != PO_SUCCESS || 2355 resource_get_size(tgt, tgt_size) != PO_SUCCESS) { 2356 pool_seterror(POE_BADPARAM); 2357 return (XFER_FAIL); 2358 } 2359 if (pool_conf_status(conf) != POF_DESTROY) { 2360 /* 2361 * src_size - donating >= src.min 2362 * size + receiving <= tgt.max (except for default) 2363 */ 2364 #ifdef DEBUG 2365 dprintf("conf is %s\n", pool_conf_location(conf)); 2366 dprintf("setup_transfer: src_size %llu\n", *src_size); 2367 pool_elem_dprintf(TO_ELEM(src)); 2368 dprintf("setup_transfer: tgt_size %llu\n", *tgt_size); 2369 pool_elem_dprintf(TO_ELEM(tgt)); 2370 #endif /* DEBUG */ 2371 if (*src_size - size < src_min || 2372 (resource_is_default(tgt) == PO_FALSE && 2373 *tgt_size + size > tgt_max)) { 2374 pool_seterror(POE_INVALID_CONF); 2375 return (XFER_FAIL); 2376 } 2377 } 2378 return (XFER_CONTINUE); 2379 } 2380 2381 /* 2382 * Transfer resource quantities from one resource set to another. 2383 */ 2384 int 2385 pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src, 2386 pool_resource_t *tgt, uint64_t size) 2387 { 2388 uint64_t src_size; 2389 uint64_t tgt_size; 2390 int ret; 2391 2392 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size)) 2393 != XFER_CONTINUE) 2394 return (ret); 2395 /* 2396 * If this resource is a res_comp we must call move components 2397 */ 2398 if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP) 2399 return (choose_components(src, tgt, size)); 2400 /* 2401 * Now do the transfer. 2402 */ 2403 ret = conf->pc_prov->pc_res_xfer(src, tgt, size); 2404 /* 2405 * Modify the sizes of the resource sets if the process was 2406 * successful 2407 */ 2408 if (ret == PO_SUCCESS) { 2409 pool_value_t val = POOL_VALUE_INITIALIZER; 2410 2411 src_size -= size; 2412 tgt_size += size; 2413 pool_value_set_uint64(&val, src_size); 2414 (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop, 2415 &val); 2416 pool_value_set_uint64(&val, tgt_size); 2417 (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop, 2418 &val); 2419 } 2420 return (ret); 2421 } 2422 2423 /* 2424 * Transfer resource components from one resource set to another. 2425 */ 2426 int 2427 pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src, 2428 pool_resource_t *tgt, 2429 pool_component_t **rl) 2430 { 2431 int i; 2432 uint64_t src_size; 2433 uint64_t tgt_size; 2434 uint64_t size; 2435 int ret; 2436 2437 /* 2438 * Make sure the components are all contained in 'src'. This 2439 * processing must be done before setup_transfer so that size 2440 * is known. 2441 */ 2442 for (i = 0; rl[i] != NULL; i++) { 2443 #ifdef DEBUG 2444 dprintf("resource xtransfer\n"); 2445 dprintf("in conf %s\n", pool_conf_location(conf)); 2446 dprintf("transferring component\n"); 2447 pool_elem_dprintf(TO_ELEM(rl[i])); 2448 dprintf("from\n"); 2449 pool_elem_dprintf(TO_ELEM(src)); 2450 dprintf("to\n"); 2451 pool_elem_dprintf(TO_ELEM(tgt)); 2452 #endif /* DEBUG */ 2453 2454 if (pool_get_owning_resource(conf, rl[i]) != src) { 2455 pool_seterror(POE_BADPARAM); 2456 return (PO_FAIL); 2457 } 2458 } 2459 2460 size = (uint64_t)i; 2461 2462 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size)) 2463 != XFER_CONTINUE) 2464 return (ret); 2465 2466 ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl); 2467 /* 2468 * Modify the sizes of the resource sets if the process was 2469 * successful 2470 */ 2471 if (ret == PO_SUCCESS) { 2472 pool_value_t val = POOL_VALUE_INITIALIZER; 2473 2474 #ifdef DEBUG 2475 dprintf("src_size %llu\n", src_size); 2476 dprintf("tgt_size %llu\n", tgt_size); 2477 dprintf("size %llu\n", size); 2478 #endif /* DEBUG */ 2479 src_size -= size; 2480 tgt_size += size; 2481 pool_value_set_uint64(&val, src_size); 2482 (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop, 2483 &val); 2484 pool_value_set_uint64(&val, tgt_size); 2485 (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop, 2486 &val); 2487 } 2488 return (ret); 2489 } 2490 2491 /* 2492 * Find the owning resource for a resource component. 2493 */ 2494 pool_resource_t * 2495 pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp) 2496 { 2497 if (pool_conf_status(conf) == POF_INVALID) { 2498 pool_seterror(POE_BADPARAM); 2499 return (NULL); 2500 } 2501 return (pool_elem_res(pool_get_container(TO_ELEM(comp)))); 2502 } 2503 2504 /* 2505 * pool_get_container() returns the container of pc. 2506 */ 2507 pool_elem_t * 2508 pool_get_container(const pool_elem_t *pc) 2509 { 2510 return (pc->pe_get_container(pc)); 2511 } 2512 2513 /* 2514 * pool_set_container() moves pc so that it is contained by pp. 2515 * 2516 * Returns PO_SUCCESS/PO_FAIL 2517 */ 2518 int 2519 pool_set_container(pool_elem_t *pp, pool_elem_t *pc) 2520 { 2521 return (pc->pe_set_container(pp, pc)); 2522 } 2523 2524 /* 2525 * Conversion routines for converting to and from elem and it's various 2526 * subtypes of system, pool, res and comp. 2527 */ 2528 pool_elem_t * 2529 pool_system_elem(const pool_system_t *ph) 2530 { 2531 return ((pool_elem_t *)ph); 2532 } 2533 2534 pool_elem_t * 2535 pool_conf_to_elem(const pool_conf_t *conf) 2536 { 2537 pool_system_t *sys; 2538 2539 if (pool_conf_status(conf) == POF_INVALID) { 2540 pool_seterror(POE_BADPARAM); 2541 return (NULL); 2542 } 2543 if ((sys = pool_conf_system(conf)) == NULL) { 2544 pool_seterror(POE_BADPARAM); 2545 return (NULL); 2546 } 2547 return (pool_system_elem(sys)); 2548 } 2549 2550 pool_elem_t * 2551 pool_to_elem(const pool_conf_t *conf, const pool_t *pp) 2552 { 2553 if (pool_conf_status(conf) == POF_INVALID) { 2554 pool_seterror(POE_BADPARAM); 2555 return (NULL); 2556 } 2557 return ((pool_elem_t *)pp); 2558 } 2559 2560 pool_elem_t * 2561 pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs) 2562 { 2563 if (pool_conf_status(conf) == POF_INVALID) { 2564 pool_seterror(POE_BADPARAM); 2565 return (NULL); 2566 } 2567 return ((pool_elem_t *)prs); 2568 } 2569 2570 pool_elem_t * 2571 pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr) 2572 { 2573 if (pool_conf_status(conf) == POF_INVALID) { 2574 pool_seterror(POE_BADPARAM); 2575 return (NULL); 2576 } 2577 return ((pool_elem_t *)pr); 2578 } 2579 2580 /* 2581 * Walk all the pools of the configuration calling the user supplied function 2582 * as long as the user function continues to return PO_TRUE 2583 */ 2584 int 2585 pool_walk_pools(pool_conf_t *conf, void *arg, 2586 int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg)) 2587 { 2588 pool_t **rs; 2589 int i; 2590 uint_t size; 2591 int error = PO_SUCCESS; 2592 2593 if (pool_conf_status(conf) == POF_INVALID) { 2594 pool_seterror(POE_BADPARAM); 2595 return (PO_FAIL); 2596 } 2597 2598 if ((rs = pool_query_pools(conf, &size, NULL)) == NULL) /* None */ 2599 return (PO_SUCCESS); 2600 for (i = 0; i < size; i++) 2601 if (callback(conf, rs[i], arg) != PO_SUCCESS) { 2602 error = PO_FAIL; 2603 break; 2604 } 2605 free(rs); 2606 return (error); 2607 } 2608 2609 /* 2610 * Walk all the comp of the res calling the user supplied function 2611 * as long as the user function continues to return PO_TRUE 2612 */ 2613 int 2614 pool_walk_components(pool_conf_t *conf, pool_resource_t *prs, void *arg, 2615 int (*callback)(pool_conf_t *conf, pool_component_t *pr, void *arg)) 2616 { 2617 pool_component_t **rs; 2618 int i; 2619 uint_t size; 2620 int error = PO_SUCCESS; 2621 2622 if (pool_conf_status(conf) == POF_INVALID) { 2623 pool_seterror(POE_BADPARAM); 2624 return (PO_FAIL); 2625 } 2626 2627 if ((rs = pool_query_resource_components(conf, prs, &size, NULL)) == 2628 NULL) 2629 return (PO_SUCCESS); /* None */ 2630 for (i = 0; i < size; i++) 2631 if (callback(conf, rs[i], arg) != PO_SUCCESS) { 2632 error = PO_FAIL; 2633 break; 2634 } 2635 free(rs); 2636 return (error); 2637 } 2638 2639 /* 2640 * Return an array of all matching res for the supplied pool. 2641 */ 2642 pool_resource_t ** 2643 pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp, 2644 uint_t *size, pool_value_t **props) 2645 { 2646 pool_result_set_t *rs; 2647 pool_elem_t *pe; 2648 pool_resource_t **result = NULL; 2649 int i = 0; 2650 2651 if (pool_conf_status(conf) == POF_INVALID) { 2652 pool_seterror(POE_BADPARAM); 2653 return (NULL); 2654 } 2655 2656 pe = TO_ELEM(pp); 2657 2658 rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props); 2659 if (rs == NULL) { 2660 return (NULL); 2661 } 2662 if ((*size = pool_rs_count(rs)) == 0) { 2663 (void) pool_rs_close(rs); 2664 return (NULL); 2665 } 2666 if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1))) 2667 == NULL) { 2668 pool_seterror(POE_SYSTEM); 2669 (void) pool_rs_close(rs); 2670 return (NULL); 2671 } 2672 (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1)); 2673 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 2674 if (pool_elem_class(pe) != PEC_RES_COMP && 2675 pool_elem_class(pe) != PEC_RES_AGG) { 2676 pool_seterror(POE_INVALID_CONF); 2677 free(result); 2678 (void) pool_rs_close(rs); 2679 return (NULL); 2680 } 2681 result[i++] = pool_elem_res(pe); 2682 } 2683 (void) pool_rs_close(rs); 2684 return (result); 2685 } 2686 2687 /* 2688 * Walk all the res of the pool calling the user supplied function 2689 * as long as the user function continues to return PO_TRUE 2690 */ 2691 int 2692 pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg, 2693 int (*callback)(pool_conf_t *, pool_resource_t *, void *)) 2694 { 2695 pool_resource_t **rs; 2696 int i; 2697 uint_t size; 2698 int error = PO_SUCCESS; 2699 2700 if (pool_conf_status(conf) == POF_INVALID) { 2701 pool_seterror(POE_BADPARAM); 2702 return (PO_FAIL); 2703 } 2704 if ((rs = pool_query_pool_resources(conf, pp, &size, NULL)) == NULL) 2705 return (PO_SUCCESS); /* None */ 2706 for (i = 0; i < size; i++) 2707 if (callback(conf, rs[i], arg) != PO_SUCCESS) { 2708 error = PO_FAIL; 2709 break; 2710 } 2711 free(rs); 2712 return (error); 2713 } 2714 2715 /* 2716 * Return a result set of all comp for the supplied res. 2717 */ 2718 pool_component_t ** 2719 pool_query_resource_components(const pool_conf_t *conf, 2720 const pool_resource_t *prs, uint_t *size, pool_value_t **props) 2721 { 2722 pool_result_set_t *rs; 2723 pool_elem_t *pe; 2724 pool_component_t **result = NULL; 2725 int i = 0; 2726 2727 if (pool_conf_status(conf) == POF_INVALID) { 2728 pool_seterror(POE_BADPARAM); 2729 return (NULL); 2730 } 2731 pe = TO_ELEM(prs); 2732 2733 rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props); 2734 if (rs == NULL) { 2735 return (NULL); 2736 } 2737 if ((*size = pool_rs_count(rs)) == 0) { 2738 (void) pool_rs_close(rs); 2739 return (NULL); 2740 } 2741 if ((result = malloc(sizeof (pool_component_t *) * (*size + 1))) 2742 == NULL) { 2743 pool_seterror(POE_SYSTEM); 2744 (void) pool_rs_close(rs); 2745 return (NULL); 2746 } 2747 (void) memset(result, 0, sizeof (pool_component_t *) * (*size + 1)); 2748 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 2749 if (pool_elem_class(pe) != PEC_COMP) { 2750 pool_seterror(POE_INVALID_CONF); 2751 free(result); 2752 (void) pool_rs_close(rs); 2753 return (NULL); 2754 } 2755 result[i++] = pool_elem_comp(pe); 2756 } 2757 (void) pool_rs_close(rs); 2758 return (result); 2759 } 2760 2761 /* 2762 * pool_version() returns the version of this library, depending on the supplied 2763 * parameter. 2764 * 2765 * Returns: library version depening on the supplied ver parameter. 2766 */ 2767 uint_t 2768 pool_version(uint_t ver) 2769 { 2770 switch (ver) { 2771 case POOL_VER_NONE: 2772 break; 2773 case POOL_VER_CURRENT: 2774 pool_workver = ver; 2775 break; 2776 default: 2777 return (POOL_VER_NONE); 2778 } 2779 return (pool_workver); 2780 } 2781 2782 /* 2783 * pool_associate() associates the supplied resource to the supplied pool. 2784 * 2785 * Returns: PO_SUCCESS/PO_FAIL 2786 */ 2787 int 2788 pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res) 2789 { 2790 if (pool_conf_check(conf) != PO_SUCCESS) 2791 return (PO_FAIL); 2792 2793 return (pool->pp_associate(pool, res)); 2794 } 2795 2796 /* 2797 * pool_dissociate() dissociates the supplied resource from the supplied pool. 2798 * 2799 * Returns: PO_SUCCESS/PO_FAIL 2800 */ 2801 int 2802 pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res) 2803 { 2804 if (pool_conf_check(conf) != PO_SUCCESS) 2805 return (PO_FAIL); 2806 2807 if (elem_is_default(TO_ELEM(res))) 2808 return (PO_SUCCESS); 2809 return (pool->pp_dissociate(pool, res)); 2810 } 2811 2812 /* 2813 * Compare two elements for purposes of ordering. 2814 * Return: 2815 * < 0 if e1 is "before" e2 2816 * 0 if e1 "equals" e2 2817 * > 0 if e1 comes after e2 2818 */ 2819 int 2820 pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2) 2821 { 2822 char *name1, *name2; 2823 pool_value_t val = POOL_VALUE_INITIALIZER; 2824 int retval; 2825 2826 /* 2827 * We may be asked to compare two elements from different classes. 2828 * They are different so return (1). 2829 */ 2830 if (pool_elem_same_class(e1, e2) != PO_TRUE) 2831 return (1); 2832 2833 /* 2834 * If the class is PEC_SYSTEM, always match them 2835 */ 2836 if (pool_elem_class(e1) == PEC_SYSTEM) 2837 return (0); 2838 2839 /* 2840 * If we are going to compare components, then use sys_id 2841 */ 2842 if (pool_elem_class(e1) == PEC_COMP) { 2843 int64_t sys_id1, sys_id2; 2844 2845 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) { 2846 return (-1); 2847 } 2848 (void) pool_value_get_int64(&val, &sys_id1); 2849 if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) { 2850 return (-1); 2851 } 2852 (void) pool_value_get_int64(&val, &sys_id2); 2853 retval = (sys_id1 - sys_id2); 2854 } else { 2855 if (pool_get_ns_property(e1, "name", &val) == POC_INVAL) { 2856 return (-1); 2857 } 2858 (void) pool_value_get_string(&val, (const char **)&name1); 2859 if ((name1 = strdup(name1)) == NULL) { 2860 return (-1); 2861 } 2862 2863 if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) { 2864 return (-1); 2865 } 2866 2867 (void) pool_value_get_string(&val, (const char **)&name2); 2868 retval = strcmp(name1, name2); 2869 free(name1); 2870 } 2871 return (retval); 2872 } 2873 2874 /* 2875 * Compare two elements for purposes of ordering. 2876 * Return: 2877 * < 0 if e1 is "before" e2 2878 * 0 if e1 "equals" e2 2879 * > 0 if e1 comes after e2 2880 */ 2881 int 2882 pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2) 2883 { 2884 pool_value_t val = POOL_VALUE_INITIALIZER; 2885 int64_t sys_id1, sys_id2; 2886 2887 /* 2888 * We may be asked to compare two elements from different classes. 2889 * They are different so return the difference in their classes 2890 */ 2891 if (pool_elem_same_class(e1, e2) != PO_TRUE) 2892 return (1); 2893 2894 /* 2895 * If the class is PEC_SYSTEM, always match them 2896 */ 2897 if (pool_elem_class(e1) == PEC_SYSTEM) 2898 return (0); 2899 2900 /* 2901 * Compare with sys_id 2902 */ 2903 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) { 2904 assert(!"no sys_id on e1\n"); 2905 } 2906 (void) pool_value_get_int64(&val, &sys_id1); 2907 if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) { 2908 assert(!"no sys_id on e2\n"); 2909 } 2910 (void) pool_value_get_int64(&val, &sys_id2); 2911 return (sys_id1 - sys_id2); 2912 } 2913 2914 /* 2915 * Return PO_TRUE if the supplied elems are of the same class. 2916 */ 2917 int 2918 pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2) 2919 { 2920 if (pool_elem_class(e1) != pool_elem_class(e2)) 2921 return (PO_FALSE); 2922 2923 /* 2924 * Check to make sure the fundamental class of the elements match 2925 */ 2926 if (pool_elem_class(e1) == PEC_RES_COMP || 2927 pool_elem_class(e1) == PEC_RES_AGG) 2928 if (pool_resource_elem_class(e1) != 2929 pool_resource_elem_class(e2)) 2930 return (PO_FALSE); 2931 if (pool_elem_class(e1) == PEC_COMP) 2932 if (pool_component_elem_class(e1) != 2933 pool_component_elem_class(e2)) 2934 return (PO_FALSE); 2935 return (PO_TRUE); 2936 } 2937 2938 /* 2939 * pool_conf_check() checks that the configuration state isn't invalid 2940 * and that the configuration was opened for modification. 2941 */ 2942 int 2943 pool_conf_check(const pool_conf_t *conf) 2944 { 2945 if (pool_conf_status(conf) == POF_INVALID) { 2946 pool_seterror(POE_BADPARAM); 2947 return (PO_FAIL); 2948 } 2949 2950 if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) { 2951 pool_seterror(POE_BADPARAM); 2952 return (PO_FAIL); 2953 } 2954 return (PO_SUCCESS); 2955 } 2956