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