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