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