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 if (!is_valid_prop_name(name)) { 918 pool_seterror(POE_BADPARAM); 919 return (PO_FAIL); 920 } 921 /* 922 * Check to see if this is a property we are managing. If it is, 923 * ensure that we are happy with what the user is doing. 924 */ 925 if ((prop_info = provider_get_prop(pe, name)) != NULL) { 926 if (prop_is_readonly(prop_info) == PO_TRUE) { 927 pool_seterror(POE_BADPARAM); 928 return (PO_FAIL); 929 } 930 if (prop_info->pp_op.ppo_set_value && 931 prop_info->pp_op.ppo_set_value(pe, val) == PO_FAIL) 932 return (PO_FAIL); 933 } 934 935 return (pe->pe_put_prop(pe, name, val)); 936 } 937 938 /* 939 * Update the specified property value with the namespace prepended. 940 * e.g. If this function is used to update the property "name" on a pool, it 941 * will attempt to update "pool.name". 942 * 943 * PO_FAIL is returned if an error is detected and the error code is updated 944 * to indicate the cause of the error. 945 */ 946 int 947 pool_put_ns_property(pool_elem_t *pe, const char *name, 948 const pool_value_t *val) 949 { 950 char_buf_t *cb; 951 int ret; 952 953 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 954 return (PO_FAIL); 955 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == 956 PO_FAIL) { 957 free_char_buf(cb); 958 return (PO_FAIL); 959 } 960 ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val); 961 free_char_buf(cb); 962 return (ret); 963 } 964 965 /* 966 * Update the specified property value. Do not use the property 967 * protection mechanism. This function should only be used for cases 968 * where the library must bypass the normal property protection 969 * mechanism. The only known use is to update properties in the static 970 * configuration when performing a commit. 971 * 972 * PO_FAIL is returned if an error is detected and the error code is 973 * updated to indicate the cause of the error. 974 */ 975 int 976 pool_put_any_property(pool_elem_t *pe, const char *name, 977 const pool_value_t *val) 978 { 979 if (!is_valid_prop_name(name)) { 980 pool_seterror(POE_BADPARAM); 981 return (PO_FAIL); 982 } 983 984 return (pe->pe_put_prop(pe, name, val)); 985 } 986 987 /* 988 * Update the specified property value with the namespace prepended. 989 * e.g. If this function is used to update the property "name" on a pool, it 990 * will attempt to update "pool.name". 991 * 992 * PO_FAIL is returned if an error is detected and the error code is updated 993 * to indicate the cause of the error. 994 */ 995 int 996 pool_put_any_ns_property(pool_elem_t *pe, const char *name, 997 const pool_value_t *val) 998 { 999 char_buf_t *cb; 1000 int ret; 1001 1002 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 1003 return (PO_FAIL); 1004 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) == 1005 PO_FAIL) { 1006 free_char_buf(cb); 1007 return (PO_FAIL); 1008 } 1009 ret = pool_put_any_property(pe, cb->cb_buf, val); 1010 free_char_buf(cb); 1011 return (ret); 1012 } 1013 1014 /* 1015 * Remove the specified property value. Note that some properties are 1016 * mandatory and thus failure to remove these properties is inevitable. 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_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name) 1022 { 1023 const pool_prop_t *prop_info; 1024 1025 if (pool_conf_check(conf) != PO_SUCCESS) 1026 return (PO_FAIL); 1027 1028 if (TO_CONF(pe) != conf) { 1029 pool_seterror(POE_BADPARAM); 1030 return (NULL); 1031 } 1032 1033 /* 1034 * Check to see if this is a property we are managing. If it is, 1035 * ensure that we are happy with what the user is doing. 1036 */ 1037 if ((prop_info = provider_get_prop(pe, name)) != NULL) { 1038 if (prop_is_optional(prop_info) == PO_FALSE) { 1039 pool_seterror(POE_BADPARAM); 1040 return (PO_FAIL); 1041 } 1042 } 1043 return (pe->pe_rm_prop(pe, name)); 1044 } 1045 1046 /* 1047 * Check if the supplied name is a namespace protected property for the supplied 1048 * element, pe. If it is, return the prefix, otherwise just return NULL. 1049 */ 1050 const char * 1051 is_ns_property(const pool_elem_t *pe, const char *name) 1052 { 1053 const char *prefix; 1054 1055 if ((prefix = pool_elem_class_string(pe)) != NULL) { 1056 if (strncmp(name, prefix, strlen(prefix)) == 0) 1057 return (prefix); 1058 } 1059 return (NULL); 1060 } 1061 1062 /* 1063 * Check if the supplied name is a namespace protected property for the supplied 1064 * element, pe. If it is, return the property name with the namespace stripped, 1065 * otherwise just return the name. 1066 */ 1067 const char * 1068 property_name_minus_ns(const pool_elem_t *pe, const char *name) 1069 { 1070 const char *prefix; 1071 if ((prefix = is_ns_property(pe, name)) != NULL) { 1072 return (name + strlen(prefix) + 1); 1073 } 1074 return (name); 1075 } 1076 1077 /* 1078 * Create an element to represent a pool and add it to the supplied 1079 * configuration. 1080 */ 1081 pool_t * 1082 pool_create(pool_conf_t *conf, const char *name) 1083 { 1084 pool_elem_t *pe; 1085 pool_value_t val = POOL_VALUE_INITIALIZER; 1086 const pool_prop_t *default_props; 1087 1088 if (pool_conf_check(conf) != PO_SUCCESS) 1089 return (NULL); 1090 1091 if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) { 1092 /* 1093 * A pool with the same name exists. Reject. 1094 */ 1095 pool_seterror(POE_BADPARAM); 1096 return (NULL); 1097 } 1098 if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_POOL, PREC_INVALID, 1099 PCEC_INVALID)) == NULL) { 1100 pool_seterror(POE_INVALID_CONF); 1101 return (NULL); 1102 } 1103 if ((default_props = provider_get_props(pe)) != NULL) { 1104 int i; 1105 for (i = 0; default_props[i].pp_pname != NULL; i++) { 1106 if (prop_is_init(&default_props[i]) && 1107 (pool_put_any_property(pe, 1108 default_props[i].pp_pname, 1109 &default_props[i].pp_value) == PO_FAIL)) { 1110 (void) pool_destroy(conf, pool_elem_pool(pe)); 1111 return (NULL); 1112 } 1113 } 1114 } 1115 if (pool_value_set_string(&val, name) != PO_SUCCESS) { 1116 (void) pool_destroy(conf, pool_elem_pool(pe)); 1117 pool_seterror(POE_SYSTEM); 1118 return (NULL); 1119 } 1120 if (pool_put_property(conf, pe, "pool.name", &val) == PO_FAIL) { 1121 (void) pool_destroy(conf, pool_elem_pool(pe)); 1122 pool_seterror(POE_PUTPROP); 1123 return (NULL); 1124 } 1125 return (pool_elem_pool(pe)); 1126 } 1127 1128 /* 1129 * Create an element to represent a res. 1130 */ 1131 pool_resource_t * 1132 pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name) 1133 { 1134 pool_elem_t *pe; 1135 pool_value_t val = POOL_VALUE_INITIALIZER; 1136 const pool_prop_t *default_props; 1137 pool_resource_t **resources; 1138 int is_default = 0; 1139 uint_t nelem; 1140 pool_elem_class_t elem_class; 1141 pool_resource_elem_class_t type; 1142 pool_value_t *props[] = { NULL, NULL }; 1143 1144 if (pool_conf_check(conf) != PO_SUCCESS) 1145 return (NULL); 1146 1147 if ((type = pool_resource_elem_class_from_string(sz_type)) == 1148 PREC_INVALID) { 1149 pool_seterror(POE_BADPARAM); 1150 return (NULL); 1151 } 1152 1153 if (strcmp(sz_type, "pset") != 0) { 1154 pool_seterror(POE_BADPARAM); 1155 return (NULL); 1156 } 1157 1158 if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) != 1159 NULL) { 1160 /* 1161 * Resources must be unique by name+type. 1162 */ 1163 pool_seterror(POE_BADPARAM); 1164 return (NULL); 1165 } 1166 1167 props[0] = &val; 1168 1169 if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS || 1170 pool_value_set_name(props[0], c_type) != PO_SUCCESS) { 1171 return (NULL); 1172 } 1173 1174 if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) { 1175 /* 1176 * This is the first representative of this type; when it's 1177 * created it should be created with 'default' = 'true'. 1178 */ 1179 is_default = 1; 1180 } else { 1181 free(resources); 1182 } 1183 /* 1184 * TODO: If Additional PEC_RES_COMP types are added to 1185 * pool_impl.h, this would need to be extended. 1186 */ 1187 switch (type) { 1188 case PREC_PSET: 1189 elem_class = PEC_RES_COMP; 1190 break; 1191 default: 1192 elem_class = PEC_RES_AGG; 1193 break; 1194 } 1195 if ((pe = conf->pc_prov->pc_elem_create(conf, elem_class, type, 1196 PCEC_INVALID)) == NULL) { 1197 pool_seterror(POE_INVALID_CONF); 1198 return (NULL); 1199 } 1200 1201 /* 1202 * The plugins contain a list of default properties and their values 1203 * for resources. The resource returned, hence, is fully initialized. 1204 */ 1205 if ((default_props = provider_get_props(pe)) != NULL) { 1206 int i; 1207 for (i = 0; default_props[i].pp_pname != NULL; i++) { 1208 if (prop_is_init(&default_props[i]) && 1209 pool_put_any_property(pe, default_props[i].pp_pname, 1210 &default_props[i].pp_value) == PO_FAIL) { 1211 (void) pool_resource_destroy(conf, 1212 pool_elem_res(pe)); 1213 return (NULL); 1214 } 1215 } 1216 } 1217 if (pool_value_set_string(&val, name) != PO_SUCCESS || 1218 pool_put_ns_property(pe, "name", &val) != PO_SUCCESS) { 1219 (void) pool_resource_destroy(conf, pool_elem_res(pe)); 1220 return (NULL); 1221 } 1222 if (is_default) { 1223 pool_value_set_bool(&val, PO_TRUE); 1224 if (pool_put_any_ns_property(pe, "default", &val) != 1225 PO_SUCCESS) { 1226 (void) pool_resource_destroy(conf, pool_elem_res(pe)); 1227 return (NULL); 1228 } 1229 } 1230 return (pool_elem_res(pe)); 1231 } 1232 1233 /* 1234 * Create an element to represent a resource component. 1235 */ 1236 pool_component_t * 1237 pool_component_create(pool_conf_t *conf, const pool_resource_t *res, 1238 int64_t sys_id) 1239 { 1240 pool_elem_t *pe; 1241 pool_value_t val = POOL_VALUE_INITIALIZER; 1242 const pool_prop_t *default_props; 1243 char refbuf[KEY_BUFFER_SIZE]; 1244 1245 if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_COMP, 1246 PREC_INVALID, PCEC_CPU)) == NULL) { 1247 pool_seterror(POE_INVALID_CONF); 1248 return (NULL); 1249 } 1250 /* 1251 * TODO: If additional PEC_COMP types are added in pool_impl.h, 1252 * this would need to be extended. 1253 */ 1254 pe->pe_component_class = PCEC_CPU; 1255 /* Now set the container for this comp */ 1256 if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) { 1257 (void) pool_component_destroy(pool_elem_comp(pe)); 1258 return (NULL); 1259 } 1260 /* 1261 * The plugins contain a list of default properties and their values 1262 * for resources. The resource returned, hence, is fully initialized. 1263 */ 1264 if ((default_props = provider_get_props(pe)) != NULL) { 1265 int i; 1266 for (i = 0; default_props[i].pp_pname != NULL; i++) { 1267 if (prop_is_init(&default_props[i]) && 1268 pool_put_any_property(pe, 1269 default_props[i].pp_pname, 1270 &default_props[i].pp_value) == PO_FAIL) { 1271 (void) pool_component_destroy( 1272 pool_elem_comp(pe)); 1273 return (NULL); 1274 } 1275 } 1276 } 1277 /* 1278 * Set additional attributes/properties on component. 1279 */ 1280 pool_value_set_int64(&val, sys_id); 1281 if (pool_put_any_ns_property(pe, c_sys_prop, &val) != PO_SUCCESS) { 1282 (void) pool_component_destroy(pool_elem_comp(pe)); 1283 return (NULL); 1284 } 1285 if (snprintf(refbuf, KEY_BUFFER_SIZE, "%s_%lld", 1286 pool_elem_class_string(pe), sys_id) > KEY_BUFFER_SIZE) { 1287 (void) pool_component_destroy(pool_elem_comp(pe)); 1288 return (NULL); 1289 } 1290 if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) { 1291 (void) pool_component_destroy(pool_elem_comp(pe)); 1292 return (NULL); 1293 } 1294 if (pool_put_any_ns_property(pe, c_ref_id, &val) != PO_SUCCESS) { 1295 (void) pool_component_destroy(pool_elem_comp(pe)); 1296 return (NULL); 1297 } 1298 return (pool_elem_comp(pe)); 1299 } 1300 1301 /* 1302 * Return the location of a configuration. 1303 */ 1304 const char * 1305 pool_conf_location(const pool_conf_t *conf) 1306 { 1307 if (pool_conf_status(conf) == POF_INVALID) { 1308 pool_seterror(POE_BADPARAM); 1309 return (NULL); 1310 } 1311 return (conf->pc_location); 1312 } 1313 /* 1314 * Close a configuration, freeing all associated resources. Once a 1315 * configuration is closed, it can no longer be used. 1316 */ 1317 int 1318 pool_conf_close(pool_conf_t *conf) 1319 { 1320 int rv; 1321 1322 if (pool_conf_status(conf) == POF_INVALID) { 1323 pool_seterror(POE_BADPARAM); 1324 return (PO_FAIL); 1325 } 1326 rv = conf->pc_prov->pc_close(conf); 1327 conf->pc_prov = NULL; 1328 free((void *)conf->pc_location); 1329 conf->pc_location = NULL; 1330 conf->pc_state = POF_INVALID; 1331 return (rv); 1332 } 1333 1334 /* 1335 * Remove a configuration, freeing all associated resources. Once a 1336 * configuration is removed, it can no longer be accessed and is forever 1337 * gone. 1338 */ 1339 int 1340 pool_conf_remove(pool_conf_t *conf) 1341 { 1342 int rv; 1343 1344 if (pool_conf_status(conf) == POF_INVALID) { 1345 pool_seterror(POE_BADPARAM); 1346 return (PO_FAIL); 1347 } 1348 rv = conf->pc_prov->pc_remove(conf); 1349 conf->pc_state = POF_INVALID; 1350 return (rv); 1351 } 1352 1353 /* 1354 * pool_conf_alloc() allocate the resources to represent a configuration. 1355 */ 1356 pool_conf_t * 1357 pool_conf_alloc(void) 1358 { 1359 pool_conf_t *conf; 1360 1361 if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) { 1362 pool_seterror(POE_SYSTEM); 1363 return (NULL); 1364 } 1365 conf->pc_state = POF_INVALID; 1366 return (conf); 1367 } 1368 1369 /* 1370 * pool_conf_free() frees the resources associated with a configuration. 1371 */ 1372 void 1373 pool_conf_free(pool_conf_t *conf) 1374 { 1375 free(conf); 1376 } 1377 1378 /* 1379 * pool_conf_open() opens a configuration, establishing all required 1380 * connections to the data source. 1381 */ 1382 int 1383 pool_conf_open(pool_conf_t *conf, const char *location, int oflags) 1384 { 1385 /* 1386 * Since you can't do anything to a pool configuration without opening 1387 * it, this represents a good point to intialise structures that would 1388 * otherwise need to be initialised in a .init section. 1389 */ 1390 internal_init(); 1391 1392 if (pool_conf_status(conf) != POF_INVALID) { 1393 /* 1394 * Already opened configuration, return PO_FAIL 1395 */ 1396 pool_seterror(POE_BADPARAM); 1397 return (PO_FAIL); 1398 } 1399 if (oflags & ~(PO_RDONLY | PO_RDWR | PO_CREAT | PO_DISCO | PO_UPDATE)) { 1400 pool_seterror(POE_BADPARAM); 1401 return (PO_FAIL); 1402 } 1403 1404 /* 1405 * Creating a configuration implies read-write access, so make 1406 * sure that PO_RDWR is set in addition if PO_CREAT is set. 1407 */ 1408 if (oflags & PO_CREAT) 1409 oflags |= PO_RDWR; 1410 1411 if ((conf->pc_location = strdup(location)) == NULL) { 1412 pool_seterror(POE_SYSTEM); 1413 return (PO_FAIL); 1414 } 1415 /* 1416 * This is the crossover point into the actual data provider 1417 * implementation, allocate a data provider of the appropriate 1418 * type for your data storage medium. In this case it's a kernel 1419 * data provider. To use a different data provider, write some 1420 * code to implement all the required interfaces and then 1421 * change the next line to allocate a data provider which uses your 1422 * new code. All data provider routines can be static, apart from 1423 * the allocation routine. 1424 */ 1425 if (strcmp(location, pool_dynamic_location()) == 0) { 1426 if (pool_knl_connection_alloc(conf, oflags) != PO_SUCCESS) { 1427 conf->pc_state = POF_INVALID; 1428 return (PO_FAIL); 1429 } 1430 } else { 1431 if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) { 1432 conf->pc_state = POF_INVALID; 1433 return (PO_FAIL); 1434 } 1435 } 1436 return (PO_SUCCESS); 1437 } 1438 1439 /* 1440 * Rollback a configuration. This will undo all changes to the configuration 1441 * since the last time pool_conf_commit was called. 1442 */ 1443 int 1444 pool_conf_rollback(pool_conf_t *conf) 1445 { 1446 if (pool_conf_status(conf) == POF_INVALID) { 1447 pool_seterror(POE_BADPARAM); 1448 return (PO_FAIL); 1449 } 1450 return (conf->pc_prov->pc_rollback(conf)); 1451 } 1452 1453 /* 1454 * Commit a configuration. This will apply all changes to the 1455 * configuration to the permanent data store. The active parameter 1456 * indicates whether the configuration should be used to update the 1457 * dynamic configuration from the supplied (static) configuration or 1458 * whether it should be written back to persistent store. 1459 */ 1460 int 1461 pool_conf_commit(pool_conf_t *conf, int active) 1462 { 1463 int retval; 1464 1465 if (pool_conf_status(conf) == POF_INVALID) { 1466 pool_seterror(POE_BADPARAM); 1467 return (PO_FAIL); 1468 } 1469 if (active) { 1470 int oflags; 1471 1472 if (conf_is_dynamic(conf) == PO_TRUE) { 1473 pool_seterror(POE_BADPARAM); 1474 return (PO_FAIL); 1475 } 1476 /* 1477 * Pretend that the configuration was opened PO_RDWR 1478 * so that a configuration which was opened PO_RDONLY 1479 * can be committed. The original flags are preserved 1480 * in oflags and restored after pool_conf_commit_sys() 1481 * returns. 1482 */ 1483 oflags = conf->pc_prov->pc_oflags; 1484 conf->pc_prov->pc_oflags |= PO_RDWR; 1485 retval = pool_conf_commit_sys(conf, active); 1486 conf->pc_prov->pc_oflags = oflags; 1487 } else { 1488 /* 1489 * Write the configuration back to the backing store. 1490 */ 1491 retval = conf->pc_prov->pc_commit(conf); 1492 } 1493 return (retval); 1494 } 1495 1496 /* 1497 * Export a configuration. This will export a configuration in the specified 1498 * format (fmt) to the specified location. 1499 */ 1500 int 1501 pool_conf_export(const pool_conf_t *conf, const char *location, 1502 pool_export_format_t fmt) 1503 { 1504 if (pool_conf_status(conf) == POF_INVALID) { 1505 pool_seterror(POE_BADPARAM); 1506 return (PO_FAIL); 1507 } 1508 return (conf->pc_prov->pc_export(conf, location, fmt)); 1509 } 1510 1511 /* 1512 * Validate a configuration. This will validate a configuration at the 1513 * specified level. 1514 */ 1515 int 1516 pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level) 1517 { 1518 if (pool_conf_status(conf) == POF_INVALID) { 1519 pool_seterror(POE_BADPARAM); 1520 return (PO_FAIL); 1521 } 1522 return (conf->pc_prov->pc_validate(conf, level)); 1523 } 1524 1525 /* 1526 * Update the snapshot of a configuration. This can only be used on a 1527 * dynamic configuration. 1528 */ 1529 int 1530 pool_conf_update(const pool_conf_t *conf, int *changed) 1531 { 1532 if (pool_conf_status(conf) == POF_INVALID || 1533 conf_is_dynamic(conf) == PO_FALSE) { 1534 pool_seterror(POE_BADPARAM); 1535 return (PO_FAIL); 1536 } 1537 /* 1538 * Since this function only makes sense for dynamic 1539 * configurations, just call directly into the appropriate 1540 * function. This could be added into the pool_connection_t 1541 * interface if it was ever required. 1542 */ 1543 if (changed) 1544 *changed = 0; 1545 return (pool_knl_update((pool_conf_t *)conf, changed)); 1546 } 1547 1548 /* 1549 * Walk the properties of the supplied elem, calling the user supplied 1550 * function repeatedly as long as the user function returns 1551 * PO_SUCCESS. 1552 */ 1553 int 1554 pool_walk_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg, 1555 int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *, 1556 pool_value_t *, void *)) 1557 { 1558 return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0)); 1559 } 1560 1561 void 1562 free_value_list(int npvals, pool_value_t **pvals) 1563 { 1564 int j; 1565 1566 for (j = 0; j < npvals; j++) { 1567 if (pvals[j]) 1568 pool_value_free(pvals[j]); 1569 } 1570 free(pvals); 1571 } 1572 1573 /* 1574 * Walk the properties of the supplied elem, calling the user supplied 1575 * function repeatedly as long as the user function returns 1576 * PO_SUCCESS. 1577 * The list of properties to be walked is retrieved from the element 1578 */ 1579 int 1580 pool_walk_any_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg, 1581 int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *, 1582 pool_value_t *, void *), int any) 1583 { 1584 pool_value_t **pvals; 1585 int i; 1586 const pool_prop_t *props = provider_get_props(elem); 1587 uint_t npvals; 1588 1589 if (pool_conf_status(conf) == POF_INVALID) { 1590 pool_seterror(POE_BADPARAM); 1591 return (PO_FAIL); 1592 } 1593 1594 if (props == NULL) { 1595 pool_seterror(POE_INVALID_CONF); 1596 return (PO_FAIL); 1597 } 1598 1599 if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL) 1600 return (PO_FAIL); 1601 1602 /* 1603 * Now walk the managed properties. As we find managed 1604 * properties removed them from the list of all properties to 1605 * prevent duplication. 1606 */ 1607 for (i = 0; props[i].pp_pname != NULL; i++) { 1608 int j; 1609 1610 /* 1611 * Special processing for type 1612 */ 1613 if (strcmp(props[i].pp_pname, c_type) == 0) { 1614 pool_value_t val = POOL_VALUE_INITIALIZER; 1615 1616 if (pool_value_set_name(&val, props[i].pp_pname) == 1617 PO_FAIL) { 1618 free_value_list(npvals, pvals); 1619 return (PO_FAIL); 1620 } 1621 if (props[i].pp_op.ppo_get_value(elem, &val) == 1622 PO_FAIL) { 1623 free_value_list(npvals, pvals); 1624 return (PO_FAIL); 1625 } 1626 if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) { 1627 if (prop_callback(conf, elem, props[i].pp_pname, 1628 &val, arg) != PO_SUCCESS) { 1629 free_value_list(npvals, pvals); 1630 pool_seterror(POE_BADPARAM); 1631 return (PO_FAIL); 1632 } 1633 } 1634 continue; 1635 } 1636 1637 for (j = 0; j < npvals; j++) { 1638 if (pvals[j] && strcmp(pool_value_get_name(pvals[j]), 1639 props[i].pp_pname) == 0) 1640 break; 1641 } 1642 /* 1643 * If we have found the property, then j < npvals. Process it 1644 * according to our property attributes. Otherwise, it's not 1645 * a managed property, so just ignore it until later. 1646 */ 1647 if (j < npvals) { 1648 if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) { 1649 if (props[i].pp_op.ppo_get_value) { 1650 if (pool_value_set_name(pvals[j], 1651 props[i].pp_pname) == PO_FAIL) { 1652 free_value_list(npvals, pvals); 1653 return (PO_FAIL); 1654 } 1655 if (props[i].pp_op.ppo_get_value(elem, 1656 pvals[j]) == PO_FAIL) { 1657 free_value_list(npvals, pvals); 1658 return (PO_FAIL); 1659 } 1660 } 1661 if (prop_callback(conf, elem, props[i].pp_pname, 1662 pvals[j], arg) != PO_SUCCESS) { 1663 free_value_list(npvals, pvals); 1664 pool_seterror(POE_BADPARAM); 1665 return (PO_FAIL); 1666 } 1667 } 1668 pool_value_free(pvals[j]); 1669 pvals[j] = NULL; 1670 } 1671 } 1672 for (i = 0; i < npvals; i++) { 1673 if (pvals[i]) { 1674 const char *name = pool_value_get_name(pvals[i]); 1675 char *qname = strrchr(name, '.'); 1676 if ((qname && qname[1] != '_') || 1677 (!qname && name[0] != '_')) { 1678 if (prop_callback(conf, elem, name, pvals[i], 1679 arg) != PO_SUCCESS) { 1680 free_value_list(npvals, pvals); 1681 pool_seterror(POE_BADPARAM); 1682 return (PO_FAIL); 1683 } 1684 } 1685 pool_value_free(pvals[i]); 1686 pvals[i] = NULL; 1687 } 1688 } 1689 free(pvals); 1690 return (PO_SUCCESS); 1691 } 1692 1693 /* 1694 * Return a pool, searching the supplied configuration for a pool with the 1695 * supplied name. The search is case sensitive. 1696 */ 1697 pool_t * 1698 pool_get_pool(const pool_conf_t *conf, const char *name) 1699 { 1700 pool_value_t *props[] = { NULL, NULL }; 1701 pool_t **rs; 1702 pool_t *ret; 1703 uint_t size = 0; 1704 pool_value_t val = POOL_VALUE_INITIALIZER; 1705 1706 props[0] = &val; 1707 1708 if (pool_conf_status(conf) == POF_INVALID) { 1709 pool_seterror(POE_BADPARAM); 1710 return (NULL); 1711 } 1712 1713 if (pool_value_set_name(props[0], "pool.name") != PO_SUCCESS || 1714 pool_value_set_string(props[0], name) != PO_SUCCESS) { 1715 return (NULL); 1716 } 1717 rs = pool_query_pools(conf, &size, props); 1718 if (rs == NULL) { /* Can't find a pool to match the name */ 1719 return (NULL); 1720 } 1721 if (size != 1) { 1722 free(rs); 1723 pool_seterror(POE_INVALID_CONF); 1724 return (NULL); 1725 } 1726 ret = rs[0]; 1727 free(rs); 1728 return (ret); 1729 } 1730 1731 /* 1732 * Return a result set of pools, searching the supplied configuration 1733 * for pools which match the supplied property criteria. props is a null 1734 * terminated list of properties which will be used to match qualifying 1735 * pools. size is updated with the size of the pool 1736 */ 1737 pool_t ** 1738 pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props) 1739 { 1740 pool_result_set_t *rs; 1741 pool_elem_t *pe; 1742 pool_t **result = NULL; 1743 int i = 0; 1744 1745 if (pool_conf_status(conf) == POF_INVALID) { 1746 pool_seterror(POE_BADPARAM); 1747 return (NULL); 1748 } 1749 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props); 1750 if (rs == NULL) { 1751 return (NULL); 1752 } 1753 if ((*size = pool_rs_count(rs)) == 0) { 1754 (void) pool_rs_close(rs); 1755 return (NULL); 1756 } 1757 if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) { 1758 pool_seterror(POE_SYSTEM); 1759 (void) pool_rs_close(rs); 1760 return (NULL); 1761 } 1762 (void) memset(result, 0, sizeof (pool_t *) * (*size + 1)); 1763 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 1764 if (pool_elem_class(pe) != PEC_POOL) { 1765 pool_seterror(POE_INVALID_CONF); 1766 free(result); 1767 (void) pool_rs_close(rs); 1768 return (NULL); 1769 } 1770 result[i++] = pool_elem_pool(pe); 1771 } 1772 (void) pool_rs_close(rs); 1773 return (result); 1774 } 1775 1776 /* 1777 * Return an res, searching the supplied configuration for an res with the 1778 * supplied name. The search is case sensitive. 1779 */ 1780 pool_resource_t * 1781 pool_get_resource(const pool_conf_t *conf, const char *sz_type, 1782 const char *name) 1783 { 1784 pool_value_t *props[] = { NULL, NULL, NULL }; 1785 pool_resource_t **rs; 1786 pool_resource_t *ret; 1787 uint_t size = 0; 1788 char_buf_t *cb = NULL; 1789 pool_value_t val0 = POOL_VALUE_INITIALIZER; 1790 pool_value_t val1 = POOL_VALUE_INITIALIZER; 1791 1792 if (pool_conf_status(conf) == POF_INVALID) { 1793 pool_seterror(POE_BADPARAM); 1794 return (NULL); 1795 } 1796 1797 if (sz_type == NULL) { 1798 pool_seterror(POE_BADPARAM); 1799 return (NULL); 1800 } 1801 1802 props[0] = &val0; 1803 props[1] = &val1; 1804 1805 if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS || 1806 pool_value_set_name(props[0], c_type) != PO_SUCCESS) 1807 return (NULL); 1808 1809 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 1810 return (NULL); 1811 } 1812 if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) { 1813 free_char_buf(cb); 1814 return (NULL); 1815 } 1816 if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { 1817 free_char_buf(cb); 1818 return (NULL); 1819 } 1820 if (pool_value_set_string(props[1], name) != PO_SUCCESS) { 1821 free_char_buf(cb); 1822 return (NULL); 1823 } 1824 free_char_buf(cb); 1825 rs = pool_query_resources(conf, &size, props); 1826 if (rs == NULL) { 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 res (actually as pool_elem_ts), searching the 1841 * supplied configuration for res which match the supplied property 1842 * criteria. props is a null terminated list of properties which will be used 1843 * to match qualifying res. 1844 */ 1845 pool_resource_t ** 1846 pool_query_resources(const pool_conf_t *conf, uint_t *size, 1847 pool_value_t **props) 1848 { 1849 pool_result_set_t *rs; 1850 pool_elem_t *pe; 1851 pool_resource_t **result = NULL; 1852 int i = 0; 1853 1854 if (pool_conf_status(conf) == POF_INVALID) { 1855 pool_seterror(POE_BADPARAM); 1856 return (NULL); 1857 } 1858 1859 *size = 0; 1860 1861 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props); 1862 if (rs == NULL) { 1863 return (NULL); 1864 } 1865 if ((*size = pool_rs_count(rs)) == 0) { 1866 (void) pool_rs_close(rs); 1867 return (NULL); 1868 } 1869 if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1))) 1870 == NULL) { 1871 pool_seterror(POE_SYSTEM); 1872 (void) pool_rs_close(rs); 1873 return (NULL); 1874 } 1875 (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1)); 1876 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 1877 if (pool_elem_class(pe) != PEC_RES_COMP && 1878 pool_elem_class(pe) != PEC_RES_AGG) { 1879 pool_seterror(POE_INVALID_CONF); 1880 free(result); 1881 (void) pool_rs_close(rs); 1882 return (NULL); 1883 } 1884 result[i++] = pool_elem_res(pe); 1885 } 1886 (void) pool_rs_close(rs); 1887 return (result); 1888 } 1889 1890 /* 1891 * Return a result set of comp (actually as pool_elem_ts), searching the 1892 * supplied configuration for comp which match the supplied property 1893 * criteria. props is a null terminated list of properties which will be used 1894 * to match qualifying comp. 1895 */ 1896 pool_component_t ** 1897 pool_query_components(const pool_conf_t *conf, uint_t *size, 1898 pool_value_t **props) 1899 { 1900 return (pool_query_resource_components(conf, NULL, size, props)); 1901 } 1902 1903 /* 1904 * Destroy a pool. If the pool cannot be found or removed an error is 1905 * returned. This is basically a wrapper around pool_elem_remove to ensure 1906 * some type safety for the pool subtype. 1907 */ 1908 int 1909 pool_destroy(pool_conf_t *conf, pool_t *pp) 1910 { 1911 pool_elem_t *pe; 1912 1913 if (pool_conf_check(conf) != PO_SUCCESS) 1914 return (PO_FAIL); 1915 1916 pe = TO_ELEM(pp); 1917 1918 /* 1919 * Cannot destroy the default pool. 1920 */ 1921 if (elem_is_default(pe) == PO_TRUE) { 1922 pool_seterror(POE_BADPARAM); 1923 return (PO_FAIL); 1924 } 1925 if (pool_elem_remove(pe) != PO_SUCCESS) 1926 return (PO_FAIL); 1927 return (PO_SUCCESS); 1928 } 1929 1930 /* 1931 * Destroy an res. If the res cannot be found or removed an error is 1932 * returned. This is basically a wrapper around pool_elem_remove to ensure 1933 * some type safety for the res subtype. 1934 */ 1935 int 1936 pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs) 1937 { 1938 pool_elem_t *pe; 1939 pool_component_t **rl; 1940 uint_t res_size; 1941 pool_t **pl; 1942 uint_t npool; 1943 int i; 1944 1945 if (pool_conf_check(conf) != PO_SUCCESS) 1946 return (PO_FAIL); 1947 1948 pe = TO_ELEM(prs); 1949 1950 if (resource_is_system(prs) == PO_TRUE) { 1951 pool_seterror(POE_BADPARAM); 1952 return (PO_FAIL); 1953 } 1954 /* 1955 * Walk all the pools and dissociate any pools which are using 1956 * this resource. 1957 */ 1958 if ((pl = pool_query_pools(conf, &npool, NULL)) != NULL) { 1959 for (i = 0; i < npool; i++) { 1960 pool_resource_t **rl; 1961 uint_t nres; 1962 int j; 1963 1964 if ((rl = pool_query_pool_resources(conf, pl[i], &nres, 1965 NULL)) != NULL) { 1966 for (j = 0; j < nres; j++) { 1967 if (rl[j] == prs) { 1968 if (pool_dissociate(conf, pl[i], 1969 rl[j]) != PO_SUCCESS) { 1970 free(rl); 1971 free(pl); 1972 return (PO_FAIL); 1973 } 1974 break; 1975 } 1976 } 1977 free(rl); 1978 } 1979 } 1980 free(pl); 1981 } 1982 if (pe->pe_class == PEC_RES_COMP) { 1983 pool_resource_t *default_set_res; 1984 1985 /* 1986 * Use the xtransfer option to move comp around 1987 */ 1988 default_set_res = (pool_resource_t *)get_default_resource(prs); 1989 1990 if ((rl = pool_query_resource_components(conf, prs, &res_size, 1991 NULL)) != NULL) { 1992 int ostate = conf->pc_state; 1993 conf->pc_state = POF_DESTROY; 1994 if (pool_resource_xtransfer(conf, prs, default_set_res, 1995 rl) == PO_FAIL) { 1996 free(rl); 1997 conf->pc_state = ostate; 1998 return (PO_FAIL); 1999 } 2000 conf->pc_state = ostate; 2001 free(rl); 2002 } 2003 } 2004 if (pool_elem_remove(pe) != PO_SUCCESS) 2005 return (PO_FAIL); 2006 return (PO_SUCCESS); 2007 } 2008 2009 /* 2010 * Destroy a comp. If the comp cannot be found or removed an error is 2011 * returned. This is basically a wrapper around pool_elem_remove to ensure 2012 * some type safety for the comp subtype. 2013 */ 2014 int 2015 pool_component_destroy(pool_component_t *pr) 2016 { 2017 pool_elem_t *pe = TO_ELEM(pr); 2018 2019 if (pool_elem_remove(pe) != PO_SUCCESS) 2020 return (PO_FAIL); 2021 return (PO_SUCCESS); 2022 } 2023 2024 /* 2025 * Remove a pool_elem_t from a configuration. This has been "hidden" away as 2026 * a static routine since the only elements which are currently being removed 2027 * are pools, res & comp and the wrapper functions above provide type-safe 2028 * access. However, if there is a need to remove other types of elements 2029 * then this could be promoted to pool_impl.h or more wrappers could 2030 * be added to pool_impl.h. 2031 */ 2032 int 2033 pool_elem_remove(pool_elem_t *pe) 2034 { 2035 return (pe->pe_remove(pe)); 2036 } 2037 2038 /* 2039 * Execute a query to search for a qualifying set of elements. 2040 */ 2041 pool_result_set_t * 2042 pool_exec_query(const pool_conf_t *conf, const pool_elem_t *src, 2043 const char *src_attr, pool_elem_class_t classes, pool_value_t **props) 2044 { 2045 return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes, 2046 props)); 2047 } 2048 2049 /* 2050 * Get the next result from a result set of elements. 2051 */ 2052 pool_elem_t * 2053 pool_rs_next(pool_result_set_t *set) 2054 { 2055 return (set->prs_next(set)); 2056 } 2057 2058 /* 2059 * Get the previous result from a result set of elements. 2060 */ 2061 pool_elem_t * 2062 pool_rs_prev(pool_result_set_t *set) 2063 { 2064 return (set->prs_prev(set)); 2065 } 2066 2067 /* 2068 * Get the first result from a result set of elements. 2069 */ 2070 pool_elem_t * 2071 pool_rs_first(pool_result_set_t *set) 2072 { 2073 return (set->prs_first(set)); 2074 } 2075 2076 /* 2077 * Get the last result from a result set of elements. 2078 */ 2079 pool_elem_t * 2080 pool_rs_last(pool_result_set_t *set) 2081 { 2082 return (set->prs_last(set)); 2083 } 2084 2085 2086 /* 2087 * Get the count for a result set of elements. 2088 */ 2089 int 2090 pool_rs_count(pool_result_set_t *set) 2091 { 2092 return (set->prs_count(set)); 2093 } 2094 2095 /* 2096 * Get the index for a result set of elements. 2097 */ 2098 int 2099 pool_rs_get_index(pool_result_set_t *set) 2100 { 2101 return (set->prs_get_index(set)); 2102 } 2103 2104 /* 2105 * Set the index for a result set of elements. 2106 */ 2107 int 2108 pool_rs_set_index(pool_result_set_t *set, int index) 2109 { 2110 return (set->prs_set_index(set, index)); 2111 } 2112 2113 /* 2114 * Close a result set of elements, freeing all associated resources. 2115 */ 2116 int 2117 pool_rs_close(pool_result_set_t *set) 2118 { 2119 return (set->prs_close(set)); 2120 } 2121 2122 /* 2123 * When transferring resource components using pool_resource_transfer, 2124 * this function is invoked to choose which actual components will be 2125 * transferred. 2126 */ 2127 int 2128 choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size) 2129 { 2130 pool_component_t **components = NULL, *moved[] = { NULL, NULL }; 2131 int i; 2132 uint_t ncomponent; 2133 pool_conf_t *conf = TO_CONF(TO_ELEM(src)); 2134 2135 if (size == 0) 2136 return (PO_SUCCESS); 2137 /* 2138 * Get the component list from our src component. 2139 */ 2140 if ((components = pool_query_resource_components(conf, src, &ncomponent, 2141 NULL)) == NULL) { 2142 pool_seterror(POE_BADPARAM); 2143 return (PO_FAIL); 2144 } 2145 qsort(components, ncomponent, sizeof (pool_elem_t *), 2146 qsort_elem_compare); 2147 /* 2148 * Components that aren't specifically requested by the resource 2149 * should be transferred out first. 2150 */ 2151 for (i = 0; size > 0 && components[i] != NULL; i++) { 2152 if (!cpu_is_requested(components[i])) { 2153 moved[0] = components[i]; 2154 if (pool_resource_xtransfer(conf, src, dst, moved) == 2155 PO_SUCCESS) { 2156 size--; 2157 } 2158 } 2159 } 2160 2161 /* 2162 * If we couldn't find enough "un-requested" components, select random 2163 * requested components. 2164 */ 2165 for (i = 0; size > 0 && components[i] != NULL; i++) { 2166 if (cpu_is_requested(components[i])) { 2167 moved[0] = components[i]; 2168 if (pool_resource_xtransfer(conf, src, dst, moved) == 2169 PO_SUCCESS) { 2170 size--; 2171 } 2172 } 2173 } 2174 2175 free(components); 2176 /* 2177 * If we couldn't transfer out all the resources we asked for, then 2178 * return error. 2179 */ 2180 return (size == 0 ? PO_SUCCESS : PO_FAIL); 2181 } 2182 2183 /* 2184 * Common processing for a resource transfer (xfer or xxfer). 2185 * 2186 * - Return XFER_CONTINUE if the transfer should proceeed 2187 * - Return XFER_FAIL if the transfer should be stopped in failure 2188 * - Return XFER_SUCCESS if the transfer should be stopped in success 2189 */ 2190 int 2191 setup_transfer(pool_conf_t *conf, pool_resource_t *src, pool_resource_t *tgt, 2192 uint64_t size, uint64_t *src_size, uint64_t *tgt_size) 2193 { 2194 uint64_t src_min; 2195 uint64_t tgt_max; 2196 2197 if (pool_conf_check(conf) != PO_SUCCESS) 2198 return (XFER_FAIL); 2199 2200 /* 2201 * Makes sure the two resources are of the same type 2202 */ 2203 if (pool_resource_elem_class(TO_ELEM(src)) != 2204 pool_resource_elem_class(TO_ELEM(tgt))) { 2205 pool_seterror(POE_BADPARAM); 2206 return (XFER_FAIL); 2207 } 2208 2209 /* 2210 * Transferring to yourself is a no-op 2211 */ 2212 if (src == tgt) 2213 return (XFER_SUCCESS); 2214 2215 /* 2216 * Transferring nothing is a no-op 2217 */ 2218 if (size == 0) 2219 return (XFER_SUCCESS); 2220 2221 if (resource_get_min(src, &src_min) != PO_SUCCESS || 2222 resource_get_size(src, src_size) != PO_SUCCESS || 2223 resource_get_max(tgt, &tgt_max) != PO_SUCCESS || 2224 resource_get_size(tgt, tgt_size) != PO_SUCCESS) { 2225 pool_seterror(POE_BADPARAM); 2226 return (XFER_FAIL); 2227 } 2228 if (pool_conf_status(conf) != POF_DESTROY) { 2229 /* 2230 * src_size - donating >= src.min 2231 * size + receiving <= tgt.max (except for default) 2232 */ 2233 #ifdef DEBUG 2234 dprintf("conf is %s\n", pool_conf_location(conf)); 2235 dprintf("setup_transfer: src_size %llu\n", *src_size); 2236 pool_elem_dprintf(TO_ELEM(src)); 2237 dprintf("setup_transfer: tgt_size %llu\n", *tgt_size); 2238 pool_elem_dprintf(TO_ELEM(tgt)); 2239 #endif /* DEBUG */ 2240 if (*src_size - size < src_min || 2241 (resource_is_default(tgt) == PO_FALSE && 2242 *tgt_size + size > tgt_max)) { 2243 pool_seterror(POE_INVALID_CONF); 2244 return (XFER_FAIL); 2245 } 2246 } 2247 return (XFER_CONTINUE); 2248 } 2249 2250 /* 2251 * Transfer resource quantities from one resource set to another. 2252 */ 2253 int 2254 pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src, 2255 pool_resource_t *tgt, uint64_t size) 2256 { 2257 uint64_t src_size; 2258 uint64_t tgt_size; 2259 int ret; 2260 2261 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size)) 2262 != XFER_CONTINUE) 2263 return (ret); 2264 /* 2265 * If this resource is a res_comp we must call move components 2266 */ 2267 if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP) 2268 return (choose_components(src, tgt, size)); 2269 /* 2270 * Now do the transfer. 2271 */ 2272 ret = conf->pc_prov->pc_res_xfer(src, tgt, size); 2273 /* 2274 * Modify the sizes of the resource sets if the process was 2275 * successful 2276 */ 2277 if (ret == PO_SUCCESS) { 2278 pool_value_t val = POOL_VALUE_INITIALIZER; 2279 2280 src_size -= size; 2281 tgt_size += size; 2282 pool_value_set_uint64(&val, src_size); 2283 (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop, 2284 &val); 2285 pool_value_set_uint64(&val, tgt_size); 2286 (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop, 2287 &val); 2288 } 2289 return (ret); 2290 } 2291 2292 /* 2293 * Transfer resource components from one resource set to another. 2294 */ 2295 int 2296 pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src, 2297 pool_resource_t *tgt, 2298 pool_component_t **rl) 2299 { 2300 int i; 2301 uint64_t src_size; 2302 uint64_t tgt_size; 2303 uint64_t size; 2304 int ret; 2305 2306 /* 2307 * Make sure the components are all contained in 'src'. This 2308 * processing must be done before setup_transfer so that size 2309 * is known. 2310 */ 2311 for (i = 0; rl[i] != NULL; i++) { 2312 #ifdef DEBUG 2313 dprintf("resource xtransfer\n"); 2314 dprintf("in conf %s\n", pool_conf_location(conf)); 2315 dprintf("transferring component\n"); 2316 pool_elem_dprintf(TO_ELEM(rl[i])); 2317 dprintf("from\n"); 2318 pool_elem_dprintf(TO_ELEM(src)); 2319 dprintf("to\n"); 2320 pool_elem_dprintf(TO_ELEM(tgt)); 2321 #endif /* DEBUG */ 2322 2323 if (pool_get_owning_resource(conf, rl[i]) != src) { 2324 pool_seterror(POE_BADPARAM); 2325 return (PO_FAIL); 2326 } 2327 } 2328 2329 size = (uint64_t)i; 2330 2331 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size)) 2332 != XFER_CONTINUE) 2333 return (ret); 2334 2335 ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl); 2336 /* 2337 * Modify the sizes of the resource sets if the process was 2338 * successful 2339 */ 2340 if (ret == PO_SUCCESS) { 2341 pool_value_t val = POOL_VALUE_INITIALIZER; 2342 2343 #ifdef DEBUG 2344 dprintf("src_size %llu\n", src_size); 2345 dprintf("tgt_size %llu\n", tgt_size); 2346 dprintf("size %llu\n", size); 2347 #endif /* DEBUG */ 2348 src_size -= size; 2349 tgt_size += size; 2350 pool_value_set_uint64(&val, src_size); 2351 (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop, 2352 &val); 2353 pool_value_set_uint64(&val, tgt_size); 2354 (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop, 2355 &val); 2356 } 2357 return (ret); 2358 } 2359 2360 /* 2361 * Find the owning resource for a resource component. 2362 */ 2363 pool_resource_t * 2364 pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp) 2365 { 2366 if (pool_conf_status(conf) == POF_INVALID) { 2367 pool_seterror(POE_BADPARAM); 2368 return (NULL); 2369 } 2370 return (pool_elem_res(pool_get_container(TO_ELEM(comp)))); 2371 } 2372 2373 /* 2374 * pool_get_container() returns the container of pc. 2375 */ 2376 pool_elem_t * 2377 pool_get_container(const pool_elem_t *pc) 2378 { 2379 return (pc->pe_get_container(pc)); 2380 } 2381 2382 /* 2383 * pool_set_container() moves pc so that it is contained by pp. 2384 * 2385 * Returns PO_SUCCESS/PO_FAIL 2386 */ 2387 int 2388 pool_set_container(pool_elem_t *pp, pool_elem_t *pc) 2389 { 2390 return (pc->pe_set_container(pp, pc)); 2391 } 2392 2393 /* 2394 * Conversion routines for converting to and from elem and it's various 2395 * subtypes of system, pool, res and comp. 2396 */ 2397 pool_elem_t * 2398 pool_system_elem(const pool_system_t *ph) 2399 { 2400 return ((pool_elem_t *)ph); 2401 } 2402 2403 pool_elem_t * 2404 pool_conf_to_elem(const pool_conf_t *conf) 2405 { 2406 pool_system_t *sys; 2407 2408 if (pool_conf_status(conf) == POF_INVALID) { 2409 pool_seterror(POE_BADPARAM); 2410 return (NULL); 2411 } 2412 if ((sys = pool_conf_system(conf)) == NULL) { 2413 pool_seterror(POE_BADPARAM); 2414 return (NULL); 2415 } 2416 return (pool_system_elem(sys)); 2417 } 2418 2419 pool_elem_t * 2420 pool_to_elem(const pool_conf_t *conf, const pool_t *pp) 2421 { 2422 if (pool_conf_status(conf) == POF_INVALID) { 2423 pool_seterror(POE_BADPARAM); 2424 return (NULL); 2425 } 2426 return ((pool_elem_t *)pp); 2427 } 2428 2429 pool_elem_t * 2430 pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs) 2431 { 2432 if (pool_conf_status(conf) == POF_INVALID) { 2433 pool_seterror(POE_BADPARAM); 2434 return (NULL); 2435 } 2436 return ((pool_elem_t *)prs); 2437 } 2438 2439 pool_elem_t * 2440 pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr) 2441 { 2442 if (pool_conf_status(conf) == POF_INVALID) { 2443 pool_seterror(POE_BADPARAM); 2444 return (NULL); 2445 } 2446 return ((pool_elem_t *)pr); 2447 } 2448 2449 /* 2450 * Walk all the pools of the configuration calling the user supplied function 2451 * as long as the user function continues to return PO_TRUE 2452 */ 2453 int 2454 pool_walk_pools(pool_conf_t *conf, void *arg, 2455 int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg)) 2456 { 2457 pool_t **rs; 2458 int i; 2459 uint_t size; 2460 int error = PO_SUCCESS; 2461 2462 if (pool_conf_status(conf) == POF_INVALID) { 2463 pool_seterror(POE_BADPARAM); 2464 return (PO_FAIL); 2465 } 2466 2467 if ((rs = pool_query_pools(conf, &size, NULL)) == NULL) /* None */ 2468 return (PO_SUCCESS); 2469 for (i = 0; i < size; i++) 2470 if (callback(conf, rs[i], arg) != PO_SUCCESS) { 2471 error = PO_FAIL; 2472 break; 2473 } 2474 free(rs); 2475 return (error); 2476 } 2477 2478 /* 2479 * Walk all the comp of the res calling the user supplied function 2480 * as long as the user function continues to return PO_TRUE 2481 */ 2482 int 2483 pool_walk_components(pool_conf_t *conf, pool_resource_t *prs, void *arg, 2484 int (*callback)(pool_conf_t *conf, pool_component_t *pr, void *arg)) 2485 { 2486 pool_component_t **rs; 2487 int i; 2488 uint_t size; 2489 int error = PO_SUCCESS; 2490 2491 if (pool_conf_status(conf) == POF_INVALID) { 2492 pool_seterror(POE_BADPARAM); 2493 return (PO_FAIL); 2494 } 2495 2496 if ((rs = pool_query_resource_components(conf, prs, &size, NULL)) == 2497 NULL) 2498 return (PO_SUCCESS); /* None */ 2499 for (i = 0; i < size; i++) 2500 if (callback(conf, rs[i], arg) != PO_SUCCESS) { 2501 error = PO_FAIL; 2502 break; 2503 } 2504 free(rs); 2505 return (error); 2506 } 2507 2508 /* 2509 * Return an array of all matching res for the supplied pool. 2510 */ 2511 pool_resource_t ** 2512 pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp, 2513 uint_t *size, pool_value_t **props) 2514 { 2515 pool_result_set_t *rs; 2516 pool_elem_t *pe; 2517 pool_resource_t **result = NULL; 2518 int i = 0; 2519 2520 if (pool_conf_status(conf) == POF_INVALID) { 2521 pool_seterror(POE_BADPARAM); 2522 return (NULL); 2523 } 2524 2525 pe = TO_ELEM(pp); 2526 2527 rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props); 2528 if (rs == NULL) { 2529 return (NULL); 2530 } 2531 if ((*size = pool_rs_count(rs)) == 0) { 2532 (void) pool_rs_close(rs); 2533 return (NULL); 2534 } 2535 if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1))) 2536 == NULL) { 2537 pool_seterror(POE_SYSTEM); 2538 (void) pool_rs_close(rs); 2539 return (NULL); 2540 } 2541 (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1)); 2542 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 2543 if (pool_elem_class(pe) != PEC_RES_COMP && 2544 pool_elem_class(pe) != PEC_RES_AGG) { 2545 pool_seterror(POE_INVALID_CONF); 2546 free(result); 2547 (void) pool_rs_close(rs); 2548 return (NULL); 2549 } 2550 result[i++] = pool_elem_res(pe); 2551 } 2552 (void) pool_rs_close(rs); 2553 return (result); 2554 } 2555 2556 /* 2557 * Walk all the res of the pool calling the user supplied function 2558 * as long as the user function continues to return PO_TRUE 2559 */ 2560 int 2561 pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg, 2562 int (*callback)(pool_conf_t *, pool_resource_t *, void *)) 2563 { 2564 pool_resource_t **rs; 2565 int i; 2566 uint_t size; 2567 int error = PO_SUCCESS; 2568 2569 if (pool_conf_status(conf) == POF_INVALID) { 2570 pool_seterror(POE_BADPARAM); 2571 return (PO_FAIL); 2572 } 2573 if ((rs = pool_query_pool_resources(conf, pp, &size, NULL)) == NULL) 2574 return (PO_SUCCESS); /* None */ 2575 for (i = 0; i < size; i++) 2576 if (callback(conf, rs[i], arg) != PO_SUCCESS) { 2577 error = PO_FAIL; 2578 break; 2579 } 2580 free(rs); 2581 return (error); 2582 } 2583 2584 /* 2585 * Return a result set of all comp for the supplied res. 2586 */ 2587 pool_component_t ** 2588 pool_query_resource_components(const pool_conf_t *conf, 2589 const pool_resource_t *prs, uint_t *size, pool_value_t **props) 2590 { 2591 pool_result_set_t *rs; 2592 pool_elem_t *pe; 2593 pool_component_t **result = NULL; 2594 int i = 0; 2595 2596 if (pool_conf_status(conf) == POF_INVALID) { 2597 pool_seterror(POE_BADPARAM); 2598 return (NULL); 2599 } 2600 pe = TO_ELEM(prs); 2601 2602 rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props); 2603 if (rs == NULL) { 2604 return (NULL); 2605 } 2606 if ((*size = pool_rs_count(rs)) == 0) { 2607 (void) pool_rs_close(rs); 2608 return (NULL); 2609 } 2610 if ((result = malloc(sizeof (pool_component_t *) * (*size + 1))) 2611 == NULL) { 2612 pool_seterror(POE_SYSTEM); 2613 (void) pool_rs_close(rs); 2614 return (NULL); 2615 } 2616 (void) memset(result, 0, sizeof (pool_component_t *) * (*size + 1)); 2617 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 2618 if (pool_elem_class(pe) != PEC_COMP) { 2619 pool_seterror(POE_INVALID_CONF); 2620 free(result); 2621 (void) pool_rs_close(rs); 2622 return (NULL); 2623 } 2624 result[i++] = pool_elem_comp(pe); 2625 } 2626 (void) pool_rs_close(rs); 2627 return (result); 2628 } 2629 2630 /* 2631 * pool_version() returns the version of this library, depending on the supplied 2632 * parameter. 2633 * 2634 * Returns: library version depening on the supplied ver parameter. 2635 */ 2636 uint_t 2637 pool_version(uint_t ver) 2638 { 2639 switch (ver) { 2640 case POOL_VER_NONE: 2641 break; 2642 case POOL_VER_CURRENT: 2643 pool_workver = ver; 2644 break; 2645 default: 2646 return (POOL_VER_NONE); 2647 } 2648 return (pool_workver); 2649 } 2650 2651 /* 2652 * pool_associate() associates the supplied resource to the supplied pool. 2653 * 2654 * Returns: PO_SUCCESS/PO_FAIL 2655 */ 2656 int 2657 pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res) 2658 { 2659 if (pool_conf_check(conf) != PO_SUCCESS) 2660 return (PO_FAIL); 2661 2662 return (pool->pp_associate(pool, res)); 2663 } 2664 2665 /* 2666 * pool_dissociate() dissociates the supplied resource from the supplied pool. 2667 * 2668 * Returns: PO_SUCCESS/PO_FAIL 2669 */ 2670 int 2671 pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res) 2672 { 2673 if (pool_conf_check(conf) != PO_SUCCESS) 2674 return (PO_FAIL); 2675 2676 if (elem_is_default(TO_ELEM(res))) 2677 return (PO_SUCCESS); 2678 return (pool->pp_dissociate(pool, res)); 2679 } 2680 2681 /* 2682 * Compare two elements for purposes of ordering. 2683 * Return: 2684 * < 0 if e1 is "before" e2 2685 * 0 if e1 "equals" e2 2686 * > 0 if e1 comes after e2 2687 */ 2688 int 2689 pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2) 2690 { 2691 char *name1, *name2; 2692 pool_value_t val = POOL_VALUE_INITIALIZER; 2693 int retval; 2694 2695 /* 2696 * We may be asked to compare two elements from different classes. 2697 * They are different so return (1). 2698 */ 2699 if (pool_elem_same_class(e1, e2) != PO_TRUE) 2700 return (1); 2701 2702 /* 2703 * If the class is PEC_SYSTEM, always match them 2704 */ 2705 if (pool_elem_class(e1) == PEC_SYSTEM) 2706 return (0); 2707 2708 /* 2709 * If we are going to compare components, then use sys_id 2710 */ 2711 if (pool_elem_class(e1) == PEC_COMP) { 2712 int64_t sys_id1, sys_id2; 2713 2714 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) { 2715 return (-1); 2716 } 2717 (void) pool_value_get_int64(&val, &sys_id1); 2718 if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) { 2719 return (-1); 2720 } 2721 (void) pool_value_get_int64(&val, &sys_id2); 2722 retval = (sys_id1 - sys_id2); 2723 } else { 2724 if (pool_get_ns_property(e1, "name", &val) == POC_INVAL) { 2725 return (-1); 2726 } 2727 (void) pool_value_get_string(&val, (const char **)&name1); 2728 if ((name1 = strdup(name1)) == NULL) { 2729 return (-1); 2730 } 2731 2732 if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) { 2733 return (-1); 2734 } 2735 2736 (void) pool_value_get_string(&val, (const char **)&name2); 2737 retval = strcmp(name1, name2); 2738 free(name1); 2739 } 2740 return (retval); 2741 } 2742 2743 /* 2744 * Compare two elements for purposes of ordering. 2745 * Return: 2746 * < 0 if e1 is "before" e2 2747 * 0 if e1 "equals" e2 2748 * > 0 if e1 comes after e2 2749 */ 2750 int 2751 pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2) 2752 { 2753 pool_value_t val = POOL_VALUE_INITIALIZER; 2754 int64_t sys_id1, sys_id2; 2755 2756 /* 2757 * We may be asked to compare two elements from different classes. 2758 * They are different so return the difference in their classes 2759 */ 2760 if (pool_elem_same_class(e1, e2) != PO_TRUE) 2761 return (1); 2762 2763 /* 2764 * If the class is PEC_SYSTEM, always match them 2765 */ 2766 if (pool_elem_class(e1) == PEC_SYSTEM) 2767 return (0); 2768 2769 /* 2770 * Compare with sys_id 2771 */ 2772 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) { 2773 assert(!"no sys_id on e1\n"); 2774 } 2775 (void) pool_value_get_int64(&val, &sys_id1); 2776 if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) { 2777 assert(!"no sys_id on e2\n"); 2778 } 2779 (void) pool_value_get_int64(&val, &sys_id2); 2780 return (sys_id1 - sys_id2); 2781 } 2782 2783 /* 2784 * Return PO_TRUE if the supplied elems are of the same class. 2785 */ 2786 int 2787 pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2) 2788 { 2789 if (pool_elem_class(e1) != pool_elem_class(e2)) 2790 return (PO_FALSE); 2791 2792 /* 2793 * Check to make sure the fundamental class of the elements match 2794 */ 2795 if (pool_elem_class(e1) == PEC_RES_COMP || 2796 pool_elem_class(e1) == PEC_RES_AGG) 2797 if (pool_resource_elem_class(e1) != 2798 pool_resource_elem_class(e2)) 2799 return (PO_FALSE); 2800 if (pool_elem_class(e1) == PEC_COMP) 2801 if (pool_component_elem_class(e1) != 2802 pool_component_elem_class(e2)) 2803 return (PO_FALSE); 2804 return (PO_TRUE); 2805 } 2806 2807 /* 2808 * pool_conf_check() checks that the configuration state isn't invalid 2809 * and that the configuration was opened for modification. 2810 */ 2811 int 2812 pool_conf_check(const pool_conf_t *conf) 2813 { 2814 if (pool_conf_status(conf) == POF_INVALID) { 2815 pool_seterror(POE_BADPARAM); 2816 return (PO_FAIL); 2817 } 2818 2819 if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) { 2820 pool_seterror(POE_BADPARAM); 2821 return (PO_FAIL); 2822 } 2823 return (PO_SUCCESS); 2824 } 2825