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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <limits.h> 27 #include <pool.h> 28 #include <stdlib.h> 29 #include <stdio.h> 30 #include <string.h> 31 #include <synch.h> 32 #include <thread.h> 33 34 #include <sys/loadavg.h> 35 #include <sys/types.h> 36 #include <sys/utsname.h> 37 38 #include "dict.h" 39 #include "pool_internal.h" 40 #include "pool_impl.h" 41 42 /* 43 * Atom structure, used to reference count string atoms. 44 */ 45 typedef struct { 46 char *a_string; /* String atom */ 47 uint_t a_count; /* String reference count */ 48 } atom_t; 49 50 /* 51 * The _internal_lock is used to lock the state of libpool during 52 * internal initialisation operations. 53 */ 54 mutex_t _internal_lock; 55 56 static int _libpool_debug = 0; /* debugging messages */ 57 static dict_hdl_t *_pv_atoms; /* pool_value_t atoms */ 58 static mutex_t _atom_lock; /* atom table lock */ 59 static int _libpool_internal_initialised = PO_FALSE; 60 61 /* 62 * Various useful constant strings which are often encountered 63 */ 64 const char *c_a_dtype = "a-dtype"; 65 const char *c_name = "name"; 66 const char *c_type = "type"; 67 const char *c_ref_id = "ref_id"; 68 const char *c_max_prop = "max"; 69 const char *c_min_prop = "min"; 70 const char *c_size_prop = "size"; 71 const char *c_sys_prop = "sys_id"; 72 73 /* 74 * prop_is_type() checks the supplied property and returns PO_TRUE if the 75 * property value is set for the property else PO_FALSE 76 */ 77 static int prop_is_type(int, const pool_prop_t *); 78 static int resource_get_common(const pool_resource_t *, const char *, 79 uint64_t *); 80 static int64_t elem_get_expected_int64(const pool_elem_t *, const char *); 81 82 /* 83 * The following returns a malloc'ed string which must be free'd by the 84 * caller. 85 */ 86 static char *elem_get_expected_string(const pool_elem_t *, const char *); 87 static int element_props_init(pool_prop_t *); 88 89 /* 90 * Each element class/sub-class has a set of properties and behaviours 91 * which are used to create the element with appropriate property 92 * values and to ensure correct property manipulations. The details 93 * are all stored in the following arrays. 94 */ 95 96 static int elem_name_init(pool_prop_t *); 97 static int elem_comment_init(pool_prop_t *); 98 99 static int pool_importance_init(pool_prop_t *); 100 static int pool_active_init(pool_prop_t *); 101 102 static int res_max_init(pool_prop_t *); 103 static int res_min_init(pool_prop_t *); 104 static int res_size_init(pool_prop_t *); 105 static int res_load_init(pool_prop_t *); 106 107 static int pset_units_init(pool_prop_t *); 108 109 static int cpu_status_init(pool_prop_t *); 110 111 static int elem_no_set(pool_elem_t *, const pool_value_t *); 112 static int elem_set_name(pool_elem_t *, const pool_value_t *); 113 static int elem_get_type(const pool_elem_t *, pool_value_t *); 114 static int elem_set_string(pool_elem_t *, const pool_value_t *); 115 static int elem_set_bool(pool_elem_t *, const pool_value_t *); 116 static int elem_set_uint(pool_elem_t *, const pool_value_t *); 117 118 static int system_set_allocate(pool_elem_t *, const pool_value_t *); 119 120 static int pool_set_scheduler(pool_elem_t *, const pool_value_t *); 121 static int pool_set_active(pool_elem_t *, const pool_value_t *); 122 123 static int res_set_max(pool_elem_t *, const pool_value_t *); 124 static int res_set_min(pool_elem_t *, const pool_value_t *); 125 126 static int cpu_set_status(pool_elem_t *, const pool_value_t *); 127 128 static const char *pool_elem_class_name[] = { 129 "invalid", 130 "system", 131 "pool", 132 "component resource", 133 "aggregate resource", 134 "component" 135 }; 136 137 /* 138 * This must be kept in sync with the pool_resource_elem_ctl array and 139 * the "enum pool_resource_elem_class" type. 140 */ 141 static const char *pool_resource_elem_class_name[] = { 142 "invalid", 143 "pset" 144 }; 145 146 static const char *pool_component_elem_class_name[] = { 147 "invalid", 148 "cpu" 149 }; 150 151 static pool_prop_t system_props[] = { 152 { "system.name", POOL_VALUE_INITIALIZER, PP_STORED, NULL, 153 { NULL, elem_set_name } }, 154 { "system.ref_id", POOL_VALUE_INITIALIZER, 155 PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, 156 { "system.comment", POOL_VALUE_INITIALIZER, PP_STORED, NULL, NULL }, 157 { "system.version", POOL_VALUE_INITIALIZER, 158 PP_STORED | PP_READ, NULL, NULL }, 159 { "system.bind-default", POOL_VALUE_INITIALIZER, 160 PP_STORED, NULL, NULL }, 161 { "system.allocate-method", POOL_VALUE_INITIALIZER, 162 PP_STORED | PP_OPTIONAL, NULL, { NULL, system_set_allocate } }, 163 { "system.poold.log-level", POOL_VALUE_INITIALIZER, 164 PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, 165 { "system.poold.log-location", POOL_VALUE_INITIALIZER, 166 PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, 167 { "system.poold.monitor-interval", POOL_VALUE_INITIALIZER, 168 PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_uint } }, 169 { "system.poold.history-file", POOL_VALUE_INITIALIZER, 170 PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, 171 { "system.poold.objectives", POOL_VALUE_INITIALIZER, 172 PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, 173 NULL 174 }; 175 176 static pool_prop_t pool_props[] = { 177 { "pool.sys_id", POOL_VALUE_INITIALIZER, 178 PP_STORED | PP_READ, NULL, NULL }, 179 { "pool.name", POOL_VALUE_INITIALIZER, 180 PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } }, 181 { "pool.res", POOL_VALUE_INITIALIZER, 182 PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, 183 { "pool.ref_id", POOL_VALUE_INITIALIZER, 184 PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, 185 { "pool.active", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, 186 pool_active_init, { NULL, pool_set_active } }, 187 { "pool.default", POOL_VALUE_INITIALIZER, 188 PP_STORED | PP_READ, NULL, NULL }, 189 { "pool.scheduler", POOL_VALUE_INITIALIZER, 190 PP_STORED | PP_OPTIONAL, NULL, 191 { NULL, pool_set_scheduler } }, 192 { "pool.importance", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, 193 pool_importance_init, NULL }, 194 { "pool.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, 195 elem_comment_init, NULL }, 196 NULL 197 }; 198 199 static pool_prop_t pset_props[] = { 200 { "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, 201 { elem_get_type, NULL } }, 202 { "pset.sys_id", POOL_VALUE_INITIALIZER, 203 PP_STORED | PP_READ, NULL, NULL }, 204 { "pset.name", POOL_VALUE_INITIALIZER, 205 PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } }, 206 { "pset.ref_id", POOL_VALUE_INITIALIZER, 207 PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, 208 { "pset.default", POOL_VALUE_INITIALIZER, 209 PP_STORED | PP_READ, NULL, NULL }, 210 { "pset.min", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_min_init, 211 { NULL, res_set_min } }, 212 { "pset.max", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_max_init, 213 { NULL, res_set_max } }, 214 { "pset.units", POOL_VALUE_INITIALIZER, 215 PP_STORED | PP_INIT, pset_units_init, NULL }, 216 { "pset.load", POOL_VALUE_INITIALIZER, PP_READ | PP_INIT, 217 res_load_init, NULL }, 218 { "pset.size", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT | PP_READ, 219 res_size_init, NULL }, 220 { "pset.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, 221 elem_comment_init, NULL }, 222 { "pset.poold.objectives", POOL_VALUE_INITIALIZER, 223 PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, 224 NULL 225 }; 226 227 static pool_prop_t cpu_props[] = { 228 { "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, 229 { elem_get_type, NULL } }, 230 { "cpu.sys_id", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, 231 NULL }, 232 { "cpu.ref_id", POOL_VALUE_INITIALIZER, 233 PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, 234 { "cpu.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, 235 elem_comment_init, NULL }, 236 { "cpu.status", POOL_VALUE_INITIALIZER, PP_INIT, cpu_status_init, 237 { NULL, cpu_set_status } }, 238 { "cpu.pinned", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, 239 { NULL, elem_set_bool } }, 240 NULL 241 }; 242 243 static pool_prop_t *pool_elem_ctl[] = { 244 NULL, 245 system_props, 246 pool_props, 247 NULL, 248 NULL, 249 NULL 250 }; 251 252 /* 253 * This must be kept in sync with the pool_resource_elem_class_name array and 254 * the "enum pool_resource_elem_class" type. 255 */ 256 static pool_prop_t *pool_resource_elem_ctl[] = { 257 NULL, 258 pset_props 259 }; 260 261 static pool_prop_t *pool_component_elem_ctl[] = { 262 NULL, 263 cpu_props 264 }; 265 266 static void 267 atom_init(void) 268 { 269 (void) mutex_lock(&_atom_lock); 270 /* 271 * Initialize pool_value_t atom dictionary 272 */ 273 if (_pv_atoms == NULL) 274 if ((_pv_atoms = dict_new((int (*)(const void *, const void *)) 275 strcmp, (uint64_t (*)(const void *))hash_str)) == NULL) 276 abort(); 277 (void) mutex_unlock(&_atom_lock); 278 } 279 280 /* 281 * Initializer, called when the library is initialized. 282 */ 283 void 284 internal_init(void) 285 { 286 (void) mutex_lock(&_internal_lock); 287 if (_libpool_internal_initialised == PO_TRUE) { 288 (void) mutex_unlock(&_internal_lock); 289 return; 290 } 291 atom_init(); 292 /* 293 * Initialize all available property arrays. 294 */ 295 if (element_props_init(system_props) == PO_FAIL) 296 abort(); 297 if (element_props_init(pool_props) == PO_FAIL) 298 abort(); 299 if (element_props_init(pset_props) == PO_FAIL) 300 abort(); 301 if (element_props_init(cpu_props) == PO_FAIL) 302 abort(); 303 _libpool_internal_initialised = PO_TRUE; 304 (void) mutex_unlock(&_internal_lock); 305 306 } 307 308 static int 309 element_props_init(pool_prop_t *props) 310 { 311 int i; 312 313 for (i = 0; props[i].pp_pname != NULL; i++) { 314 /* 315 * Initialise each of the properties 316 */ 317 if (pool_value_set_name(&props[i].pp_value, 318 props[i].pp_pname) != PO_SUCCESS) { 319 return (PO_FAIL); 320 } 321 if (props[i].pp_init && 322 props[i].pp_init(&props[i]) != PO_SUCCESS) { 323 return (PO_FAIL); 324 } 325 } 326 return (PO_SUCCESS); 327 } 328 329 330 /* 331 * These functions intialise the properties of this plugin. The only reason 332 * they exist is because the ability to perform the static initialisation of 333 * union members properly was only introduced in the C99 standard. i.e. if you 334 * could do {.f = 1.0} like in the proposed C99 standard then that would 335 * be the preferred way to do this as it keeps the data in the array and 336 * minimises the scope for errors. However, until that time these functions 337 * are the best way to minimise the scope for errors and to maximise 338 * maintainability. 339 * 340 * There is one function for each property, and the initial value for each 341 * property is hard-coded into each function. 342 */ 343 344 static int 345 elem_name_init(pool_prop_t *prop) 346 { 347 return (string_init(prop, "default")); 348 } 349 350 static int 351 elem_comment_init(pool_prop_t *prop) 352 { 353 return (string_init(prop, "")); 354 } 355 356 static int 357 pool_importance_init(pool_prop_t *prop) 358 { 359 return (int_init(prop, 1)); 360 } 361 362 static int 363 pool_active_init(pool_prop_t *prop) 364 { 365 return (bool_init(prop, PO_TRUE)); 366 } 367 368 static int 369 res_max_init(pool_prop_t *prop) 370 { 371 return (uint_init(prop, 0)); 372 } 373 374 static int 375 res_min_init(pool_prop_t *prop) 376 { 377 return (uint_init(prop, 0)); 378 } 379 380 static int 381 res_size_init(pool_prop_t *prop) 382 { 383 return (uint_init(prop, 0)); 384 } 385 386 static int 387 res_load_init(pool_prop_t *prop) 388 { 389 return (uint_init(prop, 0)); 390 } 391 392 static int 393 pset_units_init(pool_prop_t *prop) 394 { 395 return (string_init(prop, "population")); 396 } 397 398 static int 399 cpu_status_init(pool_prop_t *prop) 400 { 401 return (string_init(prop, PS_ONLINE)); 402 } 403 404 /* 405 * Individual property manipulation routines for use by the generic 406 * get/put property routines 407 */ 408 409 /* 410 * Many properties cannot be modified. This function prevents property 411 * modification. 412 */ 413 /* ARGSUSED */ 414 static int 415 elem_no_set(pool_elem_t *elem, const pool_value_t *pval) 416 { 417 return (PO_FAIL); 418 } 419 420 /* 421 * Duplicate names for a pool or resource type are illegal. 422 */ 423 static int 424 elem_set_name(pool_elem_t *elem, const pool_value_t *pval) 425 { 426 const char *nm; 427 pool_t *pool; 428 pool_resource_t *res; 429 430 if (pool_value_get_string(pval, &nm) != PO_SUCCESS) { 431 return (PO_FAIL); 432 } 433 if (!is_valid_name(nm)) { 434 pool_seterror(POE_PUTPROP); 435 return (PO_FAIL); 436 } 437 switch (pool_elem_class(elem)) { 438 case PEC_SYSTEM: 439 break; 440 case PEC_POOL: 441 pool = pool_get_pool(TO_CONF(elem), nm); 442 if (pool != NULL && pool != pool_elem_pool(elem)) { 443 pool_seterror(POE_PUTPROP); 444 return (PO_FAIL); 445 } 446 break; 447 case PEC_RES_COMP: 448 case PEC_RES_AGG: 449 res = pool_get_resource(TO_CONF(elem), 450 pool_elem_class_string(elem), nm); 451 if (res != NULL && res != pool_elem_res(elem)) { 452 pool_seterror(POE_PUTPROP); 453 return (PO_FAIL); 454 } 455 break; 456 default: 457 return (PO_FAIL); 458 } 459 return (PO_SUCCESS); 460 } 461 462 /* 463 * Ensure the type is a string. 464 */ 465 /* ARGSUSED */ 466 static int 467 elem_set_string(pool_elem_t *elem, const pool_value_t *pval) 468 { 469 if (pool_value_get_type(pval) == POC_STRING) 470 return (PO_SUCCESS); 471 else { 472 pool_seterror(POE_BADPARAM); 473 return (PO_FAIL); 474 } 475 } 476 477 /* 478 * Ensure the type is a boolean. 479 */ 480 /* ARGSUSED */ 481 static int 482 elem_set_bool(pool_elem_t *elem, const pool_value_t *pval) 483 { 484 if (pool_value_get_type(pval) == POC_BOOL) 485 return (PO_SUCCESS); 486 else { 487 pool_seterror(POE_BADPARAM); 488 return (PO_FAIL); 489 } 490 } 491 492 /* 493 * Ensure the type is an unsigned int. 494 */ 495 /* ARGSUSED */ 496 static int 497 elem_set_uint(pool_elem_t *elem, const pool_value_t *pval) 498 { 499 if (pool_value_get_type(pval) == POC_UINT) 500 return (PO_SUCCESS); 501 else { 502 pool_seterror(POE_BADPARAM); 503 return (PO_FAIL); 504 } 505 } 506 507 /* ARGSUSED */ 508 int 509 system_set_allocate(pool_elem_t *elem, const pool_value_t *pval) 510 { 511 const char *sval; 512 513 if (pool_value_get_string(pval, &sval) != PO_SUCCESS) { 514 pool_seterror(POE_PUTPROP); 515 return (PO_FAIL); 516 } 517 if (strcmp(POA_IMPORTANCE, sval) != 0 && 518 strcmp(POA_SURPLUS_TO_DEFAULT, sval) != 0) { 519 pool_seterror(POE_PUTPROP); 520 return (PO_FAIL); 521 } 522 return (PO_SUCCESS); 523 } 524 525 /* ARGSUSED */ 526 int 527 pool_set_active(pool_elem_t *elem, const pool_value_t *pval) 528 { 529 uchar_t bval; 530 531 if (pool_value_get_type(pval) != POC_BOOL) { 532 pool_seterror(POE_BADPARAM); 533 return (PO_FAIL); 534 } 535 (void) pool_value_get_bool(pval, &bval); 536 if (bval != 1) { 537 /* 538 * "active" must be true on pools for 539 * now. 540 */ 541 pool_seterror(POE_BADPARAM); 542 return (PO_FAIL); 543 } 544 return (PO_SUCCESS); 545 } 546 547 /* ARGSUSED */ 548 int 549 pool_set_scheduler(pool_elem_t *elem, const pool_value_t *pval) 550 { 551 pcinfo_t pcinfo; 552 const char *sched; 553 554 if (pool_value_get_string(pval, &sched) != 0) { 555 pool_seterror(POE_PUTPROP); 556 return (PO_FAIL); 557 } 558 (void) strncpy(pcinfo.pc_clname, sched, PC_CLNMSZ); 559 if (priocntl(0, 0, PC_GETCID, &pcinfo) == -1) { 560 pool_seterror(POE_PUTPROP); 561 return (PO_FAIL); 562 } 563 return (PO_SUCCESS); 564 } 565 566 static int 567 res_set_max(pool_elem_t *elem, const pool_value_t *pval) 568 { 569 uint64_t min, max; 570 pool_value_t val = POOL_VALUE_INITIALIZER; 571 572 /* 573 * max must be a uint 574 */ 575 if (pool_value_get_uint64(pval, &max) != PO_SUCCESS) { 576 pool_seterror(POE_PUTPROP); 577 return (PO_FAIL); 578 } 579 /* 580 * max can't be less than min (if it exists) 581 */ 582 if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) 583 return (PO_SUCCESS); 584 if (pool_value_get_uint64(&val, &min) != PO_SUCCESS) { 585 pool_seterror(POE_PUTPROP); 586 return (PO_FAIL); 587 } 588 if (max < min) { 589 pool_seterror(POE_PUTPROP); 590 return (PO_FAIL); 591 } 592 /* 593 * Ensure that changes to the max in a dynamic configuration 594 * are still valid. 595 */ 596 if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) { 597 uint64_t oldmax; 598 599 if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) { 600 pool_seterror(POE_PUTPROP); 601 return (PO_FAIL); 602 } 603 if (pool_value_get_uint64(&val, &oldmax) != PO_SUCCESS) { 604 pool_seterror(POE_PUTPROP); 605 return (PO_FAIL); 606 } 607 if (max < oldmax) { 608 /* 609 * Ensure that the modified total max is >= size 610 * of all resources of this type 611 */ 612 return (pool_validate_resource(TO_CONF(elem), 613 pool_elem_class_string(elem), c_max_prop, 614 max - oldmax)); 615 } 616 } 617 return (PO_SUCCESS); 618 } 619 620 static int 621 res_set_min(pool_elem_t *elem, const pool_value_t *pval) 622 { 623 uint64_t min, max; 624 pool_value_t val = POOL_VALUE_INITIALIZER; 625 626 /* 627 * min must be a uint 628 */ 629 if (pool_value_get_uint64(pval, &min) != PO_SUCCESS) { 630 pool_seterror(POE_PUTPROP); 631 return (PO_FAIL); 632 } 633 /* 634 * min can't be more than max (if it exists) 635 */ 636 if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) 637 return (PO_SUCCESS); 638 if (pool_value_get_uint64(&val, &max) != PO_SUCCESS) { 639 pool_seterror(POE_PUTPROP); 640 return (PO_FAIL); 641 } 642 if (min > max) { 643 pool_seterror(POE_PUTPROP); 644 return (PO_FAIL); 645 } 646 647 switch (pool_resource_elem_class(elem)) { 648 case PREC_PSET: 649 if (resource_is_default(pool_elem_res(elem))) { 650 if (min < 1) { 651 pool_seterror(POE_PUTPROP); 652 return (PO_FAIL); 653 } 654 } 655 break; 656 default: 657 break; 658 } 659 660 /* 661 * Ensure that changes to the min in a dynamic configuration 662 * are still valid. 663 */ 664 if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) { 665 uint64_t oldmin; 666 667 if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) { 668 pool_seterror(POE_PUTPROP); 669 return (PO_FAIL); 670 } 671 if (pool_value_get_uint64(&val, &oldmin) != PO_SUCCESS) { 672 pool_seterror(POE_PUTPROP); 673 return (PO_FAIL); 674 } 675 if (min > oldmin) { 676 /* 677 * Ensure that the modified total min is <= size 678 * of all resources of this type 679 */ 680 return (pool_validate_resource(TO_CONF(elem), 681 pool_elem_class_string(elem), c_min_prop, 682 min - oldmin)); 683 } 684 } 685 return (PO_SUCCESS); 686 } 687 688 /* ARGSUSED */ 689 int 690 cpu_set_status(pool_elem_t *elem, const pool_value_t *pval) 691 { 692 const char *status; 693 694 if (pool_value_get_string(pval, &status) != 0) { 695 pool_seterror(POE_PUTPROP); 696 return (PO_FAIL); 697 } 698 699 if (strcmp(PS_ONLINE, status) != 0 && 700 strcmp(PS_OFFLINE, status) != 0 && 701 strcmp(PS_NOINTR, status) != 0 && 702 strcmp(PS_SPARE, status) != 0 && 703 strcmp(PS_FAULTED, status) != 0) { 704 pool_seterror(POE_PUTPROP); 705 return (PO_FAIL); 706 } 707 return (PO_SUCCESS); 708 } 709 710 static int 711 elem_get_type(const pool_elem_t *elem, pool_value_t *pval) 712 { 713 if (pool_value_set_string(pval, pool_elem_class_string(elem)) == 714 PO_FAIL) 715 return (PO_FAIL); 716 return (PO_SUCCESS); 717 } 718 719 /* 720 * More general utilities 721 */ 722 /* 723 * Is the supplied configuration the dynamic configuration 724 * Return: PO_TRUE/PO_FALSE 725 */ 726 int 727 conf_is_dynamic(const pool_conf_t *conf) 728 { 729 if (strcmp(pool_conf_location(conf), pool_dynamic_location()) == 0) 730 return (PO_TRUE); 731 return (PO_FALSE); 732 } 733 734 /* 735 * uint_init() initialises the value of the supplied property with the 736 * supplied value. 737 * Returns PO_SUCCESS 738 */ 739 int 740 uint_init(pool_prop_t *prop, uint64_t val) 741 { 742 pool_value_set_uint64(&prop->pp_value, val); 743 return (PO_SUCCESS); 744 } 745 746 /* 747 * int_init() initialises the value of the supplied property with the 748 * supplied value. 749 * Returns PO_SUCCESS 750 */ 751 int 752 int_init(pool_prop_t *prop, int64_t val) 753 { 754 pool_value_set_int64(&prop->pp_value, val); 755 return (PO_SUCCESS); 756 } 757 758 /* 759 * double_init() initialises the value of the supplied property with the 760 * supplied value. 761 * Returns PO_SUCCESS 762 */ 763 int 764 double_init(pool_prop_t *prop, double val) 765 { 766 pool_value_set_double(&prop->pp_value, val); 767 return (PO_SUCCESS); 768 } 769 770 /* 771 * bool_init() initialises the value of the supplied property with the 772 * supplied value. 773 * Returns PO_SUCCESS 774 */ 775 int 776 bool_init(pool_prop_t *prop, uchar_t val) 777 { 778 pool_value_set_bool(&prop->pp_value, val); 779 return (PO_SUCCESS); 780 } 781 782 /* 783 * string_init() initialises the value of the supplied property with the 784 * supplied value. 785 * Returns PO_SUCCESS/PO_FAIL 786 */ 787 int 788 string_init(pool_prop_t *prop, const char *val) 789 { 790 return (pool_value_set_string(&prop->pp_value, val)); 791 } 792 793 /* 794 * pool_get_provider_count() returns the count of registered providers. 795 * 796 * Returns count of registered providers 797 */ 798 uint_t 799 pool_get_provider_count(void) 800 { 801 uint_t count = 0; 802 int i; 803 804 for (i = 0; i < sizeof (pool_resource_elem_ctl) / 805 sizeof (pool_resource_elem_ctl[0]); i++) { 806 if (pool_resource_elem_ctl[i] != NULL) 807 count++; 808 } 809 return (count); 810 } 811 812 /* 813 * Return all the props for a specified provider 814 */ 815 const pool_prop_t * 816 provider_get_props(const pool_elem_t *elem) 817 { 818 const pool_prop_t *prop_list = NULL; 819 pool_elem_class_t elem_class = pool_elem_class(elem); 820 821 switch (elem_class) { 822 case PEC_SYSTEM: 823 case PEC_POOL: 824 prop_list = pool_elem_ctl[elem_class]; 825 break; 826 case PEC_RES_AGG: 827 case PEC_RES_COMP: 828 prop_list = pool_resource_elem_ctl 829 [pool_resource_elem_class(elem)]; 830 break; 831 case PEC_COMP: 832 prop_list = pool_component_elem_ctl 833 [pool_component_elem_class(elem)]; 834 break; 835 } 836 return (prop_list); 837 } 838 839 /* 840 * provider_get_prop() return the pool_prop_t structure which 841 * describes the supplied property name for the supplied provider. 842 * 843 * Returns the property description or NULL if it doesn't exist. 844 */ 845 const pool_prop_t * 846 provider_get_prop(const pool_elem_t *elem, const char *name) 847 { 848 int i; 849 const pool_prop_t *prop_list; 850 851 if ((prop_list = provider_get_props(elem)) == NULL) 852 return (NULL); 853 854 for (i = 0; prop_list[i].pp_pname != NULL; i++) { 855 if (strcmp(name, prop_list[i].pp_pname) == 0) { 856 return (&prop_list[i]); 857 } 858 } 859 return (NULL); 860 } 861 862 /* 863 * prop_is_type() checks the supplied property and returns PO_TRUE if the 864 * property value is 1 else PO_FALSE 865 */ 866 static int 867 prop_is_type(int prop_type, const pool_prop_t *prop) 868 { 869 return ((prop->pp_perms & prop_type) ? PO_TRUE : PO_FALSE); 870 } 871 872 /* 873 * prop_is_stored() returns PO_TRUE if the property is stored in the backing 874 * configuration and PO_FALSE else. 875 */ 876 int 877 prop_is_stored(const pool_prop_t *prop) 878 { 879 return (prop_is_type(PP_STORED, prop)); 880 } 881 882 /* 883 * prop_is_readonly() returns PO_TRUE if the property is a read-only property 884 * and PO_FALSE else. 885 */ 886 int 887 prop_is_readonly(const pool_prop_t *prop) 888 { 889 return (prop_is_type(PP_READ, prop)); 890 } 891 892 /* 893 * prop_is_init() returns PO_TRUE if the property should be 894 * initialised when an element of this type is created and PO_FALSE 895 * else. 896 */ 897 int 898 prop_is_init(const pool_prop_t *prop) 899 { 900 return (prop_is_type(PP_INIT, prop)); 901 } 902 903 /* 904 * prop_is_hidden() returns PO_TRUE if the property should be hidden 905 * from access by the external property access mechanisms. 906 */ 907 int 908 prop_is_hidden(const pool_prop_t *prop) 909 { 910 return (prop_is_type(PP_HIDDEN, prop)); 911 } 912 913 /* 914 * prop_is_optional() returns PO_TRUE if the property is optional and 915 * can be removed by external property access mechanisms. 916 */ 917 int 918 prop_is_optional(const pool_prop_t *prop) 919 { 920 return (prop_is_type(PP_OPTIONAL, prop)); 921 } 922 923 int 924 cpu_is_requested(pool_component_t *component) 925 { 926 pool_value_t val = POOL_VALUE_INITIALIZER; 927 uchar_t requested; 928 929 if (pool_get_property(TO_CONF(TO_ELEM(component)), TO_ELEM(component), 930 "cpu.requested", &val) != POC_BOOL) { 931 return (PO_FALSE); 932 } 933 if (pool_value_get_bool(&val, &requested) != PO_SUCCESS) { 934 return (PO_FALSE); 935 } 936 return ((int)requested); 937 } 938 939 /* 940 * Common code for various resource get functions 941 */ 942 static int 943 resource_get_common(const pool_resource_t *res, const char *name, 944 uint64_t *uval) 945 { 946 pool_value_t val = POOL_VALUE_INITIALIZER; 947 pool_value_class_t pvc; 948 int retval = PO_SUCCESS; 949 950 pvc = pool_get_ns_property(TO_ELEM(res), name, &val); 951 if (pvc == POC_INVAL) { 952 *uval = 0; 953 #ifdef DEBUG 954 dprintf("can't retrieve %s\n"); 955 pool_elem_dprintf(TO_ELEM(res)); 956 #endif /* DEBUG */ 957 } else if (pvc == POC_UINT) { 958 retval = pool_value_get_uint64(&val, uval); 959 } 960 return (retval); 961 } 962 963 /* 964 * resource_get_size() updates size with the size of the supplied resource. 965 * 966 * Returns PO_SUCCESS/PO_FAIL 967 */ 968 int 969 resource_get_size(const pool_resource_t *res, uint64_t *size) 970 { 971 return (resource_get_common(res, c_size_prop, size)); 972 } 973 974 /* 975 * resource_get_pinned() updates pinned with the size of the 976 * pinned part of a supplied resource. Resource is not available for 977 * allocation if it is marked as "pinned". 978 * 979 * Returns PO_SUCCESS/PO_FAIL 980 */ 981 int 982 resource_get_pinned(const pool_resource_t *res, uint64_t *pinned) 983 { 984 pool_value_t *props[] = { NULL, NULL }; 985 pool_value_t val = POOL_VALUE_INITIALIZER; 986 pool_component_t **cs = NULL; 987 uint_t ncompelem; 988 989 props[0] = &val; 990 991 pool_value_set_bool(props[0], PO_TRUE); 992 if (pool_value_set_name(props[0], "cpu.pinned") != PO_SUCCESS) 993 return (PO_FAIL); 994 995 if ((cs = pool_query_resource_components(TO_CONF(TO_ELEM(res)), res, 996 &ncompelem, props)) != NULL) { 997 *pinned = ncompelem; 998 free(cs); 999 } else 1000 *pinned = 0; 1001 return (PO_SUCCESS); 1002 } 1003 1004 /* 1005 * resource_get_min() updates min with the minimum size of the supplied 1006 * resource. 1007 * 1008 * Returns PO_SUCCESS/PO_FAIL 1009 */ 1010 int 1011 resource_get_min(const pool_resource_t *res, uint64_t *min) 1012 { 1013 return (resource_get_common(res, c_min_prop, min)); 1014 } 1015 1016 /* 1017 * resource_get_max() updates max with the maximum size of the supplied 1018 * resource. 1019 * 1020 * Returns PO_SUCCESS/PO_FAIL 1021 */ 1022 int 1023 resource_get_max(const pool_resource_t *res, uint64_t *max) 1024 { 1025 return (resource_get_common(res, c_max_prop, max)); 1026 } 1027 1028 /* 1029 * TODO: This is pset specific 1030 * 1031 * get_default_resource() returns the default resource for type of the supplied 1032 * resource. 1033 * 1034 * Returns A pointer to the default resource of the same type as the supplied 1035 * resource. 1036 */ 1037 const pool_resource_t * 1038 get_default_resource(const pool_resource_t *res) 1039 { 1040 return (resource_by_sysid(TO_CONF(TO_ELEM(res)), PS_NONE, 1041 pool_elem_class_string(TO_ELEM(res)))); 1042 } 1043 1044 /* 1045 * resource_is_default() returns 1 if the supplied resource is the default 1046 * resource for it's type. 1047 */ 1048 int 1049 resource_is_default(const pool_resource_t *res) 1050 { 1051 1052 return (get_default_resource(res) == res); 1053 } 1054 1055 /* 1056 * resource_is_system() determines if the resource is a system resource. 1057 */ 1058 int 1059 resource_is_system(const pool_resource_t *res) 1060 { 1061 return (res->pr_is_system(res)); 1062 1063 } 1064 1065 /* 1066 * resource_can_associate() determines if it is possible to associate 1067 * with the supplied resource. 1068 */ 1069 int 1070 resource_can_associate(const pool_resource_t *res) 1071 { 1072 return (res->pr_can_associate(res)); 1073 } 1074 1075 /* 1076 * Common code to get an int64 property. 1077 * Unfortunately (-1) is a valid psetid, so we'll return (-2) in case of 1078 * error. 1079 */ 1080 static int64_t 1081 elem_get_expected_int64(const pool_elem_t *elem, const char *name) 1082 { 1083 int64_t val64; 1084 pool_value_t val = POOL_VALUE_INITIALIZER; 1085 1086 if (pool_get_ns_property(elem, name, &val) != POC_INT) { 1087 return (POOL_SYSID_BAD); 1088 } 1089 (void) pool_value_get_int64(&val, &val64); 1090 1091 return (val64); 1092 } 1093 1094 /* 1095 * The following returns a malloc'ed string which must be free'd by the 1096 * caller. 1097 */ 1098 static char * 1099 elem_get_expected_string(const pool_elem_t *elem, const char *name) 1100 { 1101 pool_value_t val = POOL_VALUE_INITIALIZER; 1102 char *retval; 1103 1104 if (pool_get_ns_property(elem, name, &val) != POC_STRING) { 1105 return (NULL); 1106 } 1107 (void) pool_value_get_string(&val, (const char **)&retval); 1108 retval = strdup(retval); 1109 return (retval); 1110 } 1111 1112 /* 1113 * elem_get_sysid() returns the sys_id for the supplied elem. 1114 */ 1115 id_t 1116 elem_get_sysid(const pool_elem_t *elem) 1117 { 1118 return ((id_t)elem_get_expected_int64(elem, c_sys_prop)); 1119 } 1120 1121 /* 1122 * elem_get_name() returns the name for the supplied elem. Note that 1123 * it is the caller's responsibility to free this memory. 1124 */ 1125 char * 1126 elem_get_name(const pool_elem_t *elem) 1127 { 1128 return (elem_get_expected_string(elem, c_name)); 1129 } 1130 1131 /* 1132 * elem_is_default() returns 1 if the supplied elem is the default 1133 * elem for it's type. 1134 */ 1135 int 1136 elem_is_default(const pool_elem_t *res) 1137 { 1138 1139 return (get_default_elem(res) == res); 1140 } 1141 1142 /* 1143 * Return B_TRUE if the element has the 'temporary' property set. 1144 */ 1145 boolean_t 1146 elem_is_tmp(const pool_elem_t *elem) 1147 { 1148 pool_value_t val = POOL_VALUE_INITIALIZER; 1149 uchar_t bval; 1150 1151 if (pool_get_ns_property(elem, "temporary", &val) != POC_BOOL) 1152 return (B_FALSE); 1153 1154 (void) pool_value_get_bool(&val, &bval); 1155 1156 return (bval != 0); 1157 } 1158 1159 /* 1160 * get_default_elem() returns the default elem for type of the supplied 1161 * elem. 1162 * 1163 * Returns A pointer to the default elem of the same type as the 1164 * supplied elem or NULL on error. Trying to access the default elem 1165 * for a type of element which doesn't support the notion of default 1166 * is an error. 1167 */ 1168 const pool_elem_t * 1169 get_default_elem(const pool_elem_t *pe) 1170 { 1171 pool_result_set_t *rs; 1172 pool_value_t *props[] = { NULL, NULL }; 1173 pool_value_t val = POOL_VALUE_INITIALIZER; 1174 char_buf_t *cb; 1175 const pool_elem_t *pe_default; 1176 1177 props[0] = &val; 1178 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 1179 return (NULL); 1180 } 1181 if (set_char_buf(cb, "%s.default", pool_elem_class_string(pe)) != 1182 PO_SUCCESS) { 1183 free_char_buf(cb); 1184 return (NULL); 1185 } 1186 if (pool_value_set_name(props[0], cb->cb_buf) != PO_SUCCESS) { 1187 free_char_buf(cb); 1188 return (NULL); 1189 } 1190 free_char_buf(cb); 1191 pool_value_set_bool(props[0], PO_TRUE); 1192 1193 if ((rs = pool_exec_query(TO_CONF(pe), NULL, NULL, 1194 PEC_QRY_ELEM(pe), props)) == NULL) { 1195 pool_seterror(POE_INVALID_CONF); 1196 return (NULL); 1197 } 1198 if (pool_rs_count(rs) != 1) { 1199 (void) pool_rs_close(rs); 1200 pool_seterror(POE_INVALID_CONF); 1201 return (NULL); 1202 } 1203 1204 pe_default = rs->prs_next(rs); 1205 (void) pool_rs_close(rs); 1206 return (pe_default); 1207 } 1208 1209 /* 1210 * is_a_known_prefix() determines if the supplied prop_name is a known 1211 * name for the supplied class. 1212 * 1213 * Returns a pointer to the prefix if it is found or NULL 1214 */ 1215 const char * 1216 is_a_known_prefix(pool_elem_class_t class, const char *prop_name) 1217 { 1218 int i; 1219 int len; 1220 1221 switch (class) { 1222 case PEC_SYSTEM: 1223 case PEC_POOL: 1224 len = strlen(pool_elem_class_name[class]); 1225 if (strncmp(prop_name, pool_elem_class_name[class], len) == 0 && 1226 prop_name[len] == '.' || strcmp(prop_name, c_type) == 0) 1227 return (pool_elem_class_name[class]); 1228 break; 1229 case PEC_RES_COMP: 1230 case PEC_RES_AGG: 1231 for (i = 0; i < sizeof (pool_resource_elem_class_name) / 1232 sizeof (pool_resource_elem_class_name[0]); i++) { 1233 len = strlen(pool_resource_elem_class_name[i]); 1234 if (strncmp(prop_name, 1235 pool_resource_elem_class_name[i], len) == 0 && 1236 prop_name[len] == '.' || 1237 strcmp(prop_name, c_type) == 0) 1238 return (pool_resource_elem_class_name[i]); 1239 } 1240 break; 1241 case PEC_COMP: 1242 for (i = 0; i < sizeof (pool_component_elem_class_name) / 1243 sizeof (pool_component_elem_class_name[0]); i++) { 1244 len = strlen(pool_component_elem_class_name[i]); 1245 if (strncmp(prop_name, 1246 pool_component_elem_class_name[i], len) == 0 && 1247 prop_name[len] == '.' || 1248 strcmp(prop_name, c_type) == 0) 1249 return (pool_component_elem_class_name[i]); 1250 } 1251 break; 1252 default: 1253 break; 1254 } 1255 return (NULL); 1256 } 1257 1258 1259 const char * 1260 pool_elem_class_string(const pool_elem_t *pe) 1261 { 1262 switch (pool_elem_class(pe)) { 1263 case PEC_SYSTEM: 1264 case PEC_POOL: 1265 return (pool_elem_class_name[pool_elem_class(pe)]); 1266 case PEC_RES_COMP: 1267 case PEC_RES_AGG: 1268 return (pool_resource_elem_class_name 1269 [pool_resource_elem_class(pe)]); 1270 case PEC_COMP: 1271 return (pool_component_elem_class_name 1272 [pool_component_elem_class(pe)]); 1273 default: 1274 return (pool_elem_class_name[PEC_INVALID]); 1275 } 1276 } 1277 1278 const char * 1279 pool_resource_type_string(pool_resource_elem_class_t type) 1280 { 1281 return (pool_resource_elem_class_name[type]); 1282 } 1283 1284 const char * 1285 pool_component_type_string(pool_component_elem_class_t type) 1286 { 1287 return (pool_component_elem_class_name[type]); 1288 } 1289 1290 /* 1291 * resource_by_sysid() finds a resource from it's supplied sysid and type. 1292 * 1293 * Returns a pointer to the resource or NULL if it doesn't exist. 1294 */ 1295 pool_resource_t * 1296 resource_by_sysid(const pool_conf_t *conf, id_t sysid, const char *type) 1297 { 1298 pool_value_t *props[] = { NULL, NULL, NULL }; 1299 pool_resource_t **resources = NULL; 1300 pool_resource_t *retval = NULL; 1301 uint_t nelem; 1302 char_buf_t *cb; 1303 pool_value_t val0 = POOL_VALUE_INITIALIZER; 1304 pool_value_t val1 = POOL_VALUE_INITIALIZER; 1305 1306 props[0] = &val0; 1307 props[1] = &val1; 1308 1309 if (pool_value_set_string(props[0], type) != PO_SUCCESS || 1310 pool_value_set_name(props[0], c_type) != PO_SUCCESS) 1311 return (NULL); 1312 1313 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 1314 return (NULL); 1315 } 1316 if (set_char_buf(cb, "%s.sys_id", type) != PO_SUCCESS) { 1317 free_char_buf(cb); 1318 return (NULL); 1319 } 1320 if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { 1321 free_char_buf(cb); 1322 return (NULL); 1323 } 1324 free_char_buf(cb); 1325 pool_value_set_int64(props[1], sysid); 1326 1327 resources = pool_query_resources(conf, &nelem, props); 1328 1329 if (resources != NULL) { 1330 retval = resources[0]; 1331 free(resources); 1332 } 1333 return (retval); 1334 } 1335 1336 pool_elem_class_t 1337 pool_elem_class_from_string(const char *type) 1338 { 1339 int i; 1340 1341 for (i = 0; i < sizeof (pool_elem_class_name) / 1342 sizeof (pool_elem_class_name[0]); i++) { 1343 if (strcmp(pool_elem_class_name[i], type) == 0) 1344 break; 1345 } 1346 if (i == sizeof (pool_elem_class_name) / 1347 sizeof (pool_elem_class_name[0])) 1348 return (PEC_INVALID); 1349 return ((pool_elem_class_t)i); 1350 } 1351 1352 pool_resource_elem_class_t 1353 pool_resource_elem_class_from_string(const char *type) 1354 { 1355 int i; 1356 1357 for (i = 0; i < sizeof (pool_resource_elem_class_name) / 1358 sizeof (pool_resource_elem_class_name[0]); i++) { 1359 if (strcmp(pool_resource_elem_class_name[i], type) == 0) 1360 break; 1361 } 1362 if (i == sizeof (pool_resource_elem_class_name) / 1363 sizeof (pool_resource_elem_class_name[0])) 1364 return (PREC_INVALID); 1365 return ((pool_resource_elem_class_t)i); 1366 } 1367 1368 pool_component_elem_class_t 1369 pool_component_elem_class_from_string(const char *type) 1370 { 1371 int i; 1372 1373 for (i = 0; i < sizeof (pool_component_elem_class_name) / 1374 sizeof (pool_component_elem_class_name[0]); i++) { 1375 if (strcmp(pool_component_elem_class_name[i], type) == 0) 1376 break; 1377 } 1378 if (i == sizeof (pool_component_elem_class_name) / 1379 sizeof (pool_component_elem_class_name[0])) 1380 return (PCEC_INVALID); 1381 return ((pool_component_elem_class_t)i); 1382 } 1383 1384 /* 1385 * pool_resource_type_list() populates the supplied array of pointers 1386 * with the names of the available resource types on this system. 1387 */ 1388 int 1389 pool_resource_type_list(const char **types, uint_t *numtypes) 1390 { 1391 int i, j; 1392 uint_t maxnum = *numtypes; 1393 1394 *numtypes = pool_get_provider_count(); 1395 1396 if (types) { 1397 for (i = 0, j = 0; i < sizeof (pool_resource_elem_ctl) / 1398 sizeof (pool_resource_elem_ctl[0]) && j < maxnum; i++) { 1399 if (pool_resource_elem_ctl[i] != NULL) 1400 types[j++] = pool_resource_elem_class_name[i]; 1401 } 1402 } 1403 return (PO_SUCCESS); 1404 } 1405 1406 /* 1407 * Return the system element for the supplied conf. 1408 * NULL is returned if an error is detected and the error code is updated 1409 * to indicate the cause of the error. 1410 */ 1411 pool_system_t * 1412 pool_conf_system(const pool_conf_t *conf) 1413 { 1414 pool_elem_t *system; 1415 pool_result_set_t *rs; 1416 1417 if ((rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_SYSTEM, NULL)) == 1418 NULL) { 1419 pool_seterror(POE_INVALID_CONF); 1420 return (NULL); 1421 } 1422 /* There should only be one system record */ 1423 if (pool_rs_count(rs) != 1) { 1424 pool_seterror(POE_INVALID_CONF); 1425 (void) pool_rs_close(rs); 1426 return (NULL); 1427 } 1428 system = rs->prs_next(rs); 1429 (void) pool_rs_close(rs); 1430 return (pool_elem_system(system)); 1431 } 1432 1433 pool_system_t * 1434 pool_elem_system(const pool_elem_t *pe) 1435 { 1436 if (pe->pe_class != PEC_SYSTEM) { 1437 pool_seterror(POE_BADPARAM); 1438 return (NULL); 1439 } 1440 return ((pool_system_t *)pe); 1441 } 1442 1443 pool_t * 1444 pool_elem_pool(const pool_elem_t *pe) 1445 { 1446 if (pe->pe_class != PEC_POOL) { 1447 pool_seterror(POE_BADPARAM); 1448 return (NULL); 1449 } 1450 return ((pool_t *)pe); 1451 } 1452 1453 pool_resource_t * 1454 pool_elem_res(const pool_elem_t *pe) 1455 { 1456 if (pe->pe_class != PEC_RES_COMP && 1457 pool_elem_class(pe) != PEC_RES_AGG) { 1458 pool_seterror(POE_BADPARAM); 1459 return (NULL); 1460 } 1461 return ((pool_resource_t *)pe); 1462 } 1463 1464 pool_component_t * 1465 pool_elem_comp(const pool_elem_t *pe) 1466 { 1467 if (pe->pe_class != PEC_COMP) { 1468 pool_seterror(POE_BADPARAM); 1469 return (NULL); 1470 } 1471 return ((pool_component_t *)pe); 1472 } 1473 1474 /* 1475 * qsort_elem_compare() is used for qsort elemement comparison. 1476 * 1477 * Returns see qsort(3c) 1478 */ 1479 int 1480 qsort_elem_compare(const void *a, const void *b) 1481 { 1482 const pool_elem_t *e1 = *(const pool_elem_t **)a; 1483 const pool_elem_t *e2 = *(const pool_elem_t **)b; 1484 1485 /* 1486 * Special case for handling name changes on default elements 1487 * If both elements are default elements then always return 0 1488 */ 1489 if (pool_elem_same_class(e1, e2) == PO_TRUE && 1490 (elem_is_default(e1) && elem_is_default(e2))) 1491 return (0); 1492 else 1493 return (pool_elem_compare_name(e1, e2)); 1494 } 1495 1496 /* 1497 * Dynamic character buffers. 1498 */ 1499 1500 /* 1501 * Resize the supplied character buffer to the new size. 1502 */ 1503 static int 1504 resize_char_buf(char_buf_t *cb, size_t size) 1505 { 1506 char *re_cb = NULL; 1507 1508 if ((re_cb = realloc(cb->cb_buf, size)) == NULL) { 1509 pool_seterror(POE_SYSTEM); 1510 return (PO_FAIL); 1511 } 1512 /* If inital allocation, make sure buffer is zeroed */ 1513 if (cb->cb_buf == NULL) 1514 (void) memset(re_cb, 0, sizeof (re_cb)); 1515 /* If resized smaller, make sure buffer NULL terminated */ 1516 if (size < cb->cb_size) 1517 re_cb[size] = 0; 1518 cb->cb_buf = re_cb; 1519 cb->cb_size = size; 1520 return (PO_SUCCESS); 1521 } 1522 1523 /* 1524 * Allocate a new char_buf_t structure. If there isn't enough memory, return 1525 * NULL. Initialise the new char_buf_t to 0 and then call resize_char_buf 1526 * to initialise the character buffer. Return a pointer to the new 1527 * char_buf_t if the operation succeeds. 1528 */ 1529 char_buf_t * 1530 alloc_char_buf(size_t size) 1531 { 1532 char_buf_t *cb; 1533 1534 if ((cb = malloc(sizeof (char_buf_t))) == NULL) { 1535 pool_seterror(POE_SYSTEM); 1536 return (NULL); 1537 } 1538 (void) memset(cb, 0, sizeof (char_buf_t)); 1539 1540 if (resize_char_buf(cb, size + 1) == PO_FAIL) { 1541 free(cb); 1542 return (NULL); 1543 } 1544 return (cb); 1545 } 1546 1547 /* 1548 * Free the character buffer and then free the char_buf_t. 1549 */ 1550 void 1551 free_char_buf(char_buf_t *cb) 1552 { 1553 free((void *)cb->cb_buf); 1554 free(cb); 1555 } 1556 1557 /* 1558 * Set the character buffer to the supplied data. The user supplies a printf 1559 * like format string and then an appropriate number of parameters for the 1560 * specified format. The character buffer is automatically resized to fit 1561 * the data as determined by resize_char_buf. 1562 */ 1563 /*PRINTFLIKE2*/ 1564 int 1565 set_char_buf(char_buf_t *cb, const char *fmt, ...) 1566 { 1567 va_list ap; 1568 int new_size; 1569 1570 va_start(ap, fmt); 1571 if ((new_size = vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap)) >= 1572 cb->cb_size) { 1573 if (resize_char_buf(cb, new_size + 1) != PO_SUCCESS) { 1574 pool_seterror(POE_SYSTEM); 1575 return (PO_FAIL); 1576 } 1577 (void) vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap); 1578 } 1579 va_end(ap); 1580 return (PO_SUCCESS); 1581 } 1582 1583 /* 1584 * Append the supplied data to the character buffer. The user supplies a printf 1585 * like format string and then an appropriate number of parameters for the 1586 * specified format. The character buffer is automatically resized to fit 1587 * the data as determined by resize_char_buf. 1588 */ 1589 /*PRINTFLIKE2*/ 1590 int 1591 append_char_buf(char_buf_t *cb, const char *fmt, ...) 1592 { 1593 va_list ap; 1594 int new_len; 1595 char size_buf[1]; 1596 int old_len = 0; 1597 1598 if (cb->cb_buf != NULL) 1599 old_len = strlen(cb->cb_buf); 1600 va_start(ap, fmt); 1601 new_len = vsnprintf(size_buf, sizeof (size_buf), fmt, ap); 1602 if (new_len + old_len >= cb->cb_size) { 1603 if (resize_char_buf(cb, old_len + new_len + 1) != 1604 PO_SUCCESS) { 1605 pool_seterror(POE_SYSTEM); 1606 return (PO_FAIL); 1607 } 1608 } 1609 /* 1610 * Resized the buffer to the right size, now append the new data 1611 */ 1612 (void) vsnprintf(&cb->cb_buf[old_len], cb->cb_size - old_len, fmt, ap); 1613 va_end(ap); 1614 return (PO_SUCCESS); 1615 } 1616 1617 /* 1618 * Return the class for the supplied elem. 1619 * If the return is PEC_INVALID, the error code will be set to reflect cause. 1620 */ 1621 pool_elem_class_t 1622 pool_elem_class(const pool_elem_t *elem) 1623 { 1624 return (elem->pe_class); 1625 } 1626 1627 1628 /* 1629 * Return the resource class for the supplied elem. 1630 */ 1631 pool_resource_elem_class_t 1632 pool_resource_elem_class(const pool_elem_t *elem) 1633 { 1634 return (elem->pe_resource_class); 1635 } 1636 1637 /* 1638 * Return the component class for the supplied elem. 1639 */ 1640 pool_component_elem_class_t 1641 pool_component_elem_class(const pool_elem_t *elem) 1642 { 1643 return (elem->pe_component_class); 1644 } 1645 1646 pool_elem_t * 1647 pool_get_pair(const pool_elem_t *pe) 1648 { 1649 return (pe->pe_pair); 1650 } 1651 1652 void 1653 pool_set_pair(pool_elem_t *pe1, pool_elem_t *pe2) 1654 { 1655 pe1->pe_pair = pe2; 1656 } 1657 1658 int 1659 pool_validate_resource(const pool_conf_t *conf, const char *type, 1660 const char *prop, int64_t delta) 1661 { 1662 pool_conf_t *dyn; 1663 uint_t nelem; 1664 uint64_t available, required, uval; 1665 int i; 1666 pool_resource_t **rl; 1667 pool_value_t val = POOL_VALUE_INITIALIZER; 1668 pool_value_t val1 = POOL_VALUE_INITIALIZER; 1669 pool_value_t *pvals[] = { NULL, NULL }; 1670 1671 if (strcmp(prop, c_min_prop) && strcmp(prop, c_max_prop)) { 1672 pool_seterror(POE_BADPARAM); 1673 return (PO_FAIL); 1674 } 1675 1676 pvals[0] = &val; 1677 (void) pool_value_set_string(&val, type); 1678 (void) pool_value_set_name(&val, c_type); 1679 1680 /* 1681 * Check that there are available resources on this 1682 * system for this configuration to be applied. Find 1683 * each resource type and then find all resources of 1684 * each type and total ".min". Find all available 1685 * resources and ensure >= total min. 1686 */ 1687 1688 available = 0; 1689 required = delta; 1690 1691 if ((rl = (pool_query_resources(conf, &nelem, pvals))) == NULL) 1692 return (PO_FAIL); 1693 1694 for (i = 0; i < nelem; i++) { 1695 if (pool_get_ns_property(TO_ELEM(rl[i]), prop, 1696 &val1) == POC_INVAL || 1697 pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) { 1698 free(rl); 1699 return (PO_FAIL); 1700 } 1701 /* 1702 * Watch out for overflow 1703 */ 1704 if (required + uval < required) { 1705 required = UINT64_MAX; 1706 break; 1707 } else 1708 required += uval; 1709 } 1710 1711 if (conf_is_dynamic(conf) == PO_TRUE) { 1712 dyn = (pool_conf_t *)conf; 1713 } else { 1714 free(rl); 1715 if ((dyn = pool_conf_alloc()) == NULL) 1716 return (PO_FAIL); 1717 if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDONLY) != 1718 PO_SUCCESS) { 1719 pool_conf_free(dyn); 1720 return (PO_FAIL); 1721 } 1722 if ((rl = (pool_query_resources(dyn, &nelem, pvals))) == 1723 NULL) { 1724 (void) pool_conf_close(dyn); 1725 pool_conf_free(dyn); 1726 return (PO_FAIL); 1727 } 1728 } 1729 for (i = 0; i < nelem; i++) { 1730 if (pool_get_ns_property(TO_ELEM(rl[i]), c_size_prop, 1731 &val1) == POC_INVAL || 1732 pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) { 1733 free(rl); 1734 if (conf != dyn) { 1735 (void) pool_conf_close(dyn); 1736 pool_conf_free(dyn); 1737 } 1738 return (PO_FAIL); 1739 } 1740 available += uval; 1741 } 1742 free(rl); 1743 if (conf != dyn) { 1744 (void) pool_conf_close(dyn); 1745 pool_conf_free(dyn); 1746 } 1747 if (strcmp(prop, c_min_prop) == 0) { 1748 if (available < required) { 1749 pool_seterror(POE_INVALID_CONF); 1750 return (PO_FAIL); 1751 } 1752 } else { 1753 if (available > required) { 1754 pool_seterror(POE_INVALID_CONF); 1755 return (PO_FAIL); 1756 } 1757 } 1758 return (PO_SUCCESS); 1759 } 1760 1761 /* 1762 * If _libpool_debug is set, printf the debug message to stderr with an 1763 * appropriate prefix in front of it. 1764 */ 1765 void 1766 do_dprintf(const char *format, va_list ap) 1767 { 1768 if (_libpool_debug) { 1769 (void) fputs("libpool DEBUG: ", stderr); 1770 (void) vfprintf(stderr, format, ap); 1771 } 1772 } 1773 1774 /*PRINTFLIKE1*/ 1775 void 1776 dprintf(const char *format, ...) 1777 { 1778 if (_libpool_debug) { 1779 va_list alist; 1780 va_start(alist, format); 1781 do_dprintf(format, alist); 1782 va_end(alist); 1783 } 1784 } 1785 1786 /* 1787 * log_alloc() allocates a new, empty transaction log. 1788 * 1789 * Returns a pointer to the new log or NULL on failure. 1790 */ 1791 log_t * 1792 log_alloc(pool_conf_t *conf) 1793 { 1794 log_t *l; 1795 1796 if ((l = calloc(1, sizeof (log_t))) == NULL) { 1797 pool_seterror(POE_SYSTEM); 1798 return (NULL); 1799 } 1800 l->l_state = LS_DO; 1801 l->l_conf = conf; 1802 if ((l->l_sentinel = log_item_alloc(l, 0, NULL)) 1803 == NULL) { 1804 free(l); 1805 pool_seterror(POE_SYSTEM); 1806 return (NULL); 1807 } 1808 l->l_sentinel->li_next = l->l_sentinel; 1809 l->l_sentinel->li_prev = l->l_sentinel; 1810 1811 return (l); 1812 } 1813 1814 /* 1815 * log_free() reclaims the resources associated with a transaction log. 1816 */ 1817 void 1818 log_free(log_t *l) 1819 { 1820 (void) log_walk(l, log_item_free); 1821 (void) log_item_free(l->l_sentinel); 1822 free(l); 1823 } 1824 /* 1825 * log_empty() removes all items from a transaction log. It is the 1826 * users responsibility to ensure that any resources associated with 1827 * an item are reclaimed before this function is invoked. 1828 */ 1829 void 1830 log_empty(log_t *l) 1831 { 1832 (void) log_walk(l, log_item_free); 1833 } 1834 1835 /* 1836 * log_walk() visits each log item in turn and executes the supplied action 1837 * using the item as a parameter. If no action is supplied, then the item 1838 * uses it's own stored action. 1839 * 1840 * Returns PO_SUCCESS/PO_FAIL 1841 */ 1842 int 1843 log_walk(log_t *l, log_item_action_t action) 1844 { 1845 log_item_t *li, *li_next; 1846 1847 li = l->l_sentinel->li_next; 1848 while (li != l->l_sentinel) { 1849 li_next = li->li_next; 1850 if ((action(li)) != PO_SUCCESS) 1851 return (PO_FAIL); 1852 li = li_next; 1853 } 1854 return (PO_SUCCESS); 1855 } 1856 1857 /* 1858 * log_reverse_walk() visits each log item in turn (in reverse order) 1859 * and executes the supplied action using the item as a parameter. 1860 * 1861 * Returns PO_SUCCESS/PO_FAIL 1862 */ 1863 int 1864 log_reverse_walk(log_t *l, log_item_action_t action) 1865 { 1866 log_item_t *li, *li_prev; 1867 1868 li = l->l_sentinel->li_prev; 1869 while (li != l->l_sentinel) { 1870 li_prev = li->li_prev; 1871 if ((action(li)) != PO_SUCCESS) 1872 return (PO_FAIL); 1873 li = li_prev; 1874 } 1875 return (PO_SUCCESS); 1876 } 1877 1878 /* 1879 * log_size() returns the size of the log, i.e. the number of items pending in 1880 * the log. 1881 */ 1882 uint_t 1883 log_size(log_t *l) 1884 { 1885 log_item_t *li; 1886 uint_t size = 0; 1887 1888 for (li = l->l_sentinel->li_next; li != l->l_sentinel; li = li->li_next) 1889 size++; 1890 return (size); 1891 } 1892 1893 /* 1894 * log_append() allocates a new log item to hold the supplied details and 1895 * appends the newly created item to the supplied log. 1896 * 1897 * Returns PO_SUCCESS/PO_FAIL 1898 */ 1899 int 1900 log_append(log_t *l, int op, void *details) 1901 { 1902 log_item_t *li; 1903 1904 if ((li = log_item_alloc(l, op, details)) == NULL) { 1905 l->l_state = LS_UNDO; 1906 return (PO_FAIL); 1907 } 1908 /* 1909 * Link it in 1910 */ 1911 li->li_prev = l->l_sentinel->li_prev; 1912 li->li_next = l->l_sentinel; 1913 l->l_sentinel->li_prev->li_next = li; 1914 l->l_sentinel->li_prev = li; 1915 return (PO_SUCCESS); 1916 } 1917 1918 /* 1919 * log_item_alloc() allocates a new transaction log item. The item should be 1920 * used to store details about a transaction which may need to be undone if 1921 * commit processing fails. 1922 * 1923 * Returns a pointer to a new transaction log item or NULL. 1924 */ 1925 log_item_t * 1926 log_item_alloc(log_t *l, int op, void *details) 1927 { 1928 log_item_t *li; 1929 1930 if ((li = malloc(sizeof (log_item_t))) == NULL) { 1931 pool_seterror(POE_SYSTEM); 1932 return (NULL); 1933 } 1934 1935 (void) memset(li, 0, sizeof (log_item_t)); 1936 li->li_log = l; 1937 li->li_op = op; 1938 li->li_details = details; 1939 li->li_state = LS_DO; 1940 1941 return (li); 1942 } 1943 1944 /* 1945 * log_item_free() reclaims the resources associated with a log_item_t. 1946 */ 1947 int 1948 log_item_free(log_item_t *li) 1949 { 1950 li->li_prev->li_next = li->li_next; 1951 li->li_next->li_prev = li->li_prev; 1952 free(li); 1953 return (PO_SUCCESS); 1954 } 1955 1956 /* 1957 * atom_string() checks the string table to see if a string is already 1958 * stored. If it is, return a pointer to it. If not, duplicate the 1959 * string and return a pointer to the duplicate. 1960 */ 1961 const char * 1962 atom_string(const char *s) 1963 { 1964 atom_t *atom; 1965 1966 /* 1967 * atom_init() must have completed successfully 1968 */ 1969 atom_init(); 1970 (void) mutex_lock(&_atom_lock); 1971 if ((atom = dict_get(_pv_atoms, s)) == NULL) { 1972 if ((atom = calloc(1, sizeof (atom_t))) == NULL) { 1973 pool_seterror(POE_SYSTEM); 1974 (void) mutex_unlock(&_atom_lock); 1975 return (NULL); 1976 } 1977 if ((atom->a_string = strdup(s)) == NULL) { 1978 (void) mutex_unlock(&_atom_lock); 1979 free(atom); 1980 pool_seterror(POE_SYSTEM); 1981 return (NULL); 1982 } 1983 (void) dict_put(_pv_atoms, atom->a_string, atom); 1984 } 1985 atom->a_count++; 1986 (void) mutex_unlock(&_atom_lock); 1987 return (atom->a_string); 1988 } 1989 1990 /* 1991 * atom_free() decrements the reference count for the supplied 1992 * string. If the reference count reaches zero, then the atom is 1993 * destroyed. 1994 */ 1995 void 1996 atom_free(const char *s) 1997 { 1998 atom_t *atom; 1999 2000 (void) mutex_lock(&_atom_lock); 2001 if ((atom = dict_get(_pv_atoms, s)) != NULL) { 2002 if (--atom->a_count == 0) { 2003 (void) dict_remove(_pv_atoms, s); 2004 free(atom->a_string); 2005 free(atom); 2006 } 2007 } 2008 (void) mutex_unlock(&_atom_lock); 2009 } 2010 2011 #ifdef DEBUG 2012 /* 2013 * log_item_dprintf() prints the contents of the supplied log item using the 2014 * pools dprintf() trace mechanism. 2015 * 2016 * Returns PO_SUCCESS 2017 */ 2018 void 2019 log_item_dprintf(log_item_t *li) 2020 { 2021 dprintf("LOGDUMP: %d operation, %p\n", li->li_op, li->li_details); 2022 } 2023 2024 /* 2025 * log_item_dprintf() prints the contents of the supplied log item using the 2026 * pools dprintf() trace mechanism. 2027 * 2028 * Returns PO_SUCCESS 2029 */ 2030 void 2031 pool_elem_dprintf(const pool_elem_t *pe) 2032 { 2033 if (pool_elem_class(pe) != PEC_COMP) { 2034 const char *name = elem_get_name(pe); 2035 dprintf("element type: %s name: %s\n", 2036 pool_elem_class_string(pe), name); 2037 free((void *)name); 2038 } else { 2039 id_t sys_id = elem_get_sysid(pe); 2040 dprintf("element type: %s sys_id: %d\n", 2041 pool_elem_class_string(pe), sys_id); 2042 } 2043 } 2044 #endif /* DEBUG */ 2045