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