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