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