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