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 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <thread.h>
34 #include <pthread.h>
35 #include <synch.h>
36 #include <unistd.h>
37 #include <stropts.h>
38 #include <fcntl.h>
39 #include <note.h>
40 #include <errno.h>
41 #include <ctype.h>
42 #include <libintl.h>
43 #include <libscf.h>
44 #include <pool.h>
45 #include <signal.h>
46
47 #include <sys/pool.h>
48 #include <sys/priocntl.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/wait.h>
52
53 #include "pool_internal.h"
54 #include "pool_impl.h"
55
56 /*
57 * libpool Interface Routines
58 *
59 * pool.c implements (most of) the external interface to libpool
60 * users. Some of the interface is implemented in pool_internal.c for
61 * reasons of internal code organisation. The core requirements for
62 * pool.c are:
63 *
64 * Data Abstraction
65 *
66 * The abstraction of the actual datastore so that no details of the
67 * underlying data representation mechanism are revealed to users of
68 * the library. For instance, the fact that we use the kernel or files
69 * to store our configurations is completely abstracted via the
70 * various libpool APIs.
71 *
72 * External Interaction
73 *
74 * libpool users manipulate configuration components via the API
75 * defined in pool.h. Most functions in this file act as interceptors,
76 * validating parameters before redirecting the request into a
77 * specific datastore implementation for the actual work to be done.
78 *
79 * These main sets of requirements have driven the design so that it
80 * is possible to replace the entire datastore type without having to
81 * modify the external (or internal provider) APIs. It is possible to
82 * modify the storage technology used by libpool by implementing a new
83 * set of datastore provider operations. Simply modify the
84 * pool_conf_open() routine to establish a new datastore as the
85 * provider for a configuration.
86 *
87 * The key components in a libpool configuration are :
88 * pool_conf_t - This represents a complete configuration instance
89 * pool_t - A pool inside a configuration
90 * pool_resource_t - A resource inside a configuration
91 * pool_component_t - A component of a resource
92 *
93 */
94
95 /*
96 * Used to control transfer setup.
97 */
98 #define XFER_FAIL PO_FAIL
99 #define XFER_SUCCESS PO_SUCCESS
100 #define XFER_CONTINUE 1
101
102 #define SMF_SVC_INSTANCE "svc:/system/pools:default"
103 #define E_ERROR 1 /* Exit status for error */
104
105 #ifndef TEXT_DOMAIN
106 #define TEXT_DOMAIN "SYS_TEST"
107 #endif /* TEXT_DOMAIN */
108
109 const char pool_info_location[] = "/dev/pool";
110
111 /*
112 * Static data
113 */
114 static const char static_location[] = "/etc/pooladm.conf";
115 static const char dynamic_location[] = "/dev/poolctl";
116 static thread_key_t errkey = THR_ONCE_KEY;
117
118 /*
119 * libpool error code
120 */
121 static int pool_errval = POE_OK;
122
123 /*
124 * libpool version
125 */
126 static uint_t pool_workver = POOL_VER_CURRENT;
127
128 static const char *data_type_tags[] = {
129 "uint",
130 "int",
131 "float",
132 "boolean",
133 "string"
134 };
135
136 /*
137 * static functions
138 */
139 static int pool_elem_remove(pool_elem_t *);
140 static int is_valid_prop_name(const char *);
141 static int prop_buf_build_cb(pool_conf_t *, pool_elem_t *, const char *,
142 pool_value_t *, void *);
143 static char *pool_base_info(const pool_elem_t *, char_buf_t *, int);
144 static int choose_components(pool_resource_t *, pool_resource_t *, uint64_t);
145 static int pool_conf_check(const pool_conf_t *);
146 static void free_value_list(int, pool_value_t **);
147 static int setup_transfer(pool_conf_t *, pool_resource_t *, pool_resource_t *,
148 uint64_t, uint64_t *, uint64_t *);
149
150 /*
151 * Return the "static" location string for libpool.
152 */
153 const char *
pool_static_location(void)154 pool_static_location(void)
155 {
156 return (static_location);
157 }
158
159 /*
160 * Return the "dynamic" location string for libpool.
161 */
162 const char *
pool_dynamic_location(void)163 pool_dynamic_location(void)
164 {
165 return (dynamic_location);
166 }
167
168 /*
169 * Return the status for a configuration. If the configuration has
170 * been successfully opened, then the status will be POF_VALID or
171 * POF_DESTROY. If the configuration failed to open properly or has
172 * been closed or removed, then the status will be POF_INVALID.
173 */
174 pool_conf_state_t
pool_conf_status(const pool_conf_t * conf)175 pool_conf_status(const pool_conf_t *conf)
176 {
177 return (conf->pc_state);
178 }
179
180 /*
181 * Bind idtype id to the pool name.
182 */
183 int
pool_set_binding(const char * pool_name,idtype_t idtype,id_t id)184 pool_set_binding(const char *pool_name, idtype_t idtype, id_t id)
185 {
186 pool_conf_t *conf;
187 int result;
188
189 if ((conf = pool_conf_alloc()) == NULL)
190 return (PO_FAIL);
191
192 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
193 pool_conf_free(conf);
194 pool_seterror(POE_INVALID_CONF);
195 return (PO_FAIL);
196 }
197
198 result = conf->pc_prov->pc_set_binding(conf, pool_name, idtype, id);
199
200 (void) pool_conf_close(conf);
201 pool_conf_free(conf);
202 return (result);
203 }
204
205 /*
206 * pool_get_resource_binding() returns the binding for a pid to the supplied
207 * type of resource. If a binding cannot be determined, NULL is returned.
208 */
209 char *
pool_get_resource_binding(const char * sz_type,pid_t pid)210 pool_get_resource_binding(const char *sz_type, pid_t pid)
211 {
212 pool_conf_t *conf;
213 char *result;
214 pool_resource_elem_class_t type;
215
216 if ((type = pool_resource_elem_class_from_string(sz_type)) ==
217 PREC_INVALID) {
218 pool_seterror(POE_BADPARAM);
219 return (NULL);
220 }
221
222 if ((conf = pool_conf_alloc()) == NULL)
223 return (NULL);
224
225 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)
226 != PO_SUCCESS) {
227 pool_seterror(POE_INVALID_CONF);
228 pool_conf_free(conf);
229 return (NULL);
230 }
231 result = conf->pc_prov->pc_get_resource_binding(conf, type, pid);
232 (void) pool_conf_close(conf);
233 pool_conf_free(conf);
234 return (result);
235 }
236
237 /*
238 * pool_get_binding() returns the binding for a pid to a pool. If a
239 * binding cannot be determined, NULL is returned.
240 */
241 char *
pool_get_binding(pid_t pid)242 pool_get_binding(pid_t pid)
243 {
244 pool_conf_t *conf;
245 char *result;
246
247 if ((conf = pool_conf_alloc()) == NULL)
248 return (NULL);
249
250 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)
251 != PO_SUCCESS) {
252 pool_seterror(POE_INVALID_CONF);
253 pool_conf_free(conf);
254 return (NULL);
255 }
256 result = conf->pc_prov->pc_get_binding(conf, pid);
257 (void) pool_conf_close(conf);
258 pool_conf_free(conf);
259 return (result);
260 }
261
262 /*ARGSUSED*/
263 int
prop_buf_build_cb(pool_conf_t * UNUSED,pool_elem_t * pe,const char * name,pool_value_t * pval,void * user)264 prop_buf_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name,
265 pool_value_t *pval, void *user)
266 {
267 uint64_t u;
268 int64_t i;
269 uchar_t bool;
270 const char *str;
271 double d;
272 char_buf_t *cb = (char_buf_t *)user;
273 int type = pool_value_get_type(pval);
274
275 /*
276 * Ignore "type" and "<type>.name" properties as these are not
277 * to be displayed by this function
278 */
279 if (strcmp(name, c_type) == 0 ||
280 strcmp(property_name_minus_ns(pe, name), c_name) == 0)
281 return (PO_SUCCESS);
282 if (append_char_buf(cb, "\n%s\t%s\t%s ", cb->cb_tab_buf,
283 data_type_tags[type], name) == PO_FAIL)
284 return (PO_FAIL);
285 switch (type) {
286 case POC_UINT:
287 (void) pool_value_get_uint64(pval, &u);
288 if (append_char_buf(cb, "%llu", (u_longlong_t)u) == PO_FAIL)
289 return (PO_FAIL);
290 break;
291 case POC_INT:
292 (void) pool_value_get_int64(pval, &i);
293 if (append_char_buf(cb, "%lld", (longlong_t)i) == PO_FAIL)
294 return (PO_FAIL);
295 break;
296 case POC_STRING:
297 (void) pool_value_get_string(pval, &str);
298 if (append_char_buf(cb, "%s", str) == PO_FAIL)
299 return (PO_FAIL);
300 break;
301 case POC_BOOL:
302 (void) pool_value_get_bool(pval, &bool);
303 if (bool == 0) {
304 if (append_char_buf(cb, "%s", "false") == PO_FAIL)
305 return (PO_FAIL);
306 } else {
307 if (append_char_buf(cb, "%s", "true") == PO_FAIL)
308 return (PO_FAIL);
309 }
310 break;
311 case POC_DOUBLE:
312 (void) pool_value_get_double(pval, &d);
313 if (append_char_buf(cb, "%g", d) == PO_FAIL)
314 return (PO_FAIL);
315 break;
316 case POC_INVAL: /* Do nothing */
317 break;
318 default:
319 return (PO_FAIL);
320 }
321 return (PO_SUCCESS);
322 }
323
324 /*
325 * Return a buffer which describes the element
326 * pe is a pointer to the element
327 * deep is PO_TRUE/PO_FALSE to indicate whether children should be included
328 */
329 char *
pool_base_info(const pool_elem_t * pe,char_buf_t * cb,int deep)330 pool_base_info(const pool_elem_t *pe, char_buf_t *cb, int deep)
331 {
332 const char *sres;
333 uint_t i;
334 uint_t nelem;
335
336 pool_value_t val = POOL_VALUE_INITIALIZER;
337 pool_resource_t **rs;
338 pool_elem_t *elem;
339 pool_conf_t *conf = TO_CONF(pe);
340
341 if (cb == NULL) {
342 char *ret = NULL;
343
344 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
345 return (NULL);
346
347 /*
348 * Populate the buffer with element details
349 */
350 (void) pool_base_info(pe, cb, deep);
351 if (cb->cb_buf)
352 ret = strdup(cb->cb_buf);
353 free_char_buf(cb);
354 return (ret);
355 }
356
357 if (append_char_buf(cb, "\n%s%s", cb->cb_tab_buf,
358 pool_elem_class_string(pe)) == PO_FAIL) {
359 return (NULL);
360 }
361
362 if (pool_get_ns_property(pe, c_name, &val) == POC_STRING) {
363 (void) pool_value_get_string(&val, &sres);
364 if (append_char_buf(cb, " %s", sres) == PO_FAIL) {
365 return (NULL);
366 }
367 }
368
369 /*
370 * Add in some details about the element
371 */
372 if (pool_walk_properties(conf, (pool_elem_t *)pe, cb,
373 prop_buf_build_cb) == PO_FAIL) {
374 (void) append_char_buf(cb, "\n%s%s\n", cb->cb_tab_buf,
375 "Cannot access the properties of this element.");
376 return (NULL);
377 }
378 if (append_char_buf(cb, "%s", "\n") == PO_FAIL)
379 return (NULL);
380
381 if (pe->pe_class == PEC_POOL) {
382 /*
383 * A shallow display of a pool only lists the resources by name
384 */
385
386 if ((rs = pool_query_pool_resources(conf, pool_elem_pool(pe),
387 &nelem, NULL)) == NULL) {
388 return (NULL);
389 }
390
391 for (i = 0; i < nelem; i++) {
392 const char *str;
393
394 elem = TO_ELEM(rs[i]);
395
396 if (append_char_buf(cb, "\t%s%s", cb->cb_tab_buf,
397 pool_elem_class_string(elem)) == PO_FAIL) {
398 free(rs);
399 return (NULL);
400 }
401
402 if (pool_get_ns_property(elem, c_name, &val) !=
403 POC_STRING) {
404 free(rs);
405 pool_seterror(POE_INVALID_CONF);
406 return (NULL);
407 }
408 (void) pool_value_get_string(&val, &str);
409 if (append_char_buf(cb, "\t%s\n", str) == PO_FAIL) {
410 free(rs);
411 return (NULL);
412 }
413 }
414 free(rs);
415 }
416 if (deep == PO_TRUE) {
417 pool_t **ps;
418 pool_component_t **cs;
419
420 if (strlcat(cb->cb_tab_buf, "\t", CB_TAB_BUF_SIZE)
421 >= CB_TAB_BUF_SIZE) {
422 pool_seterror(POE_SYSTEM);
423 return (NULL);
424 }
425 switch (pe->pe_class) {
426 case PEC_SYSTEM:
427 if ((ps = pool_query_pools(conf, &nelem, NULL)) !=
428 NULL) { /* process the pools */
429 for (i = 0; i < nelem; i++) {
430 elem = TO_ELEM(ps[i]);
431 if (pool_base_info(elem, cb,
432 PO_FALSE) == NULL) {
433 free(ps);
434 return (NULL);
435 }
436 }
437 free(ps);
438 }
439 if ((rs = pool_query_resources(conf, &nelem, NULL)) !=
440 NULL) {
441 for (i = 0; i < nelem; i++) {
442 elem = TO_ELEM(rs[i]);
443 if (pool_base_info(elem, cb,
444 PO_TRUE) == NULL) {
445 free(rs);
446 return (NULL);
447 }
448 }
449 free(rs);
450 }
451 break;
452 case PEC_POOL:
453 if ((rs = pool_query_pool_resources(conf,
454 pool_elem_pool(pe), &nelem, NULL)) == NULL)
455 return (NULL);
456 for (i = 0; i < nelem; i++) {
457 elem = TO_ELEM(rs[i]);
458 if (pool_base_info(elem, cb, PO_TRUE) == NULL) {
459 free(rs);
460 return (NULL);
461 }
462 }
463 free(rs);
464 break;
465 case PEC_RES_COMP:
466 if ((cs = pool_query_resource_components(conf,
467 pool_elem_res(pe), &nelem, NULL)) != NULL) {
468 for (i = 0; i < nelem; i++) {
469 elem = TO_ELEM(cs[i]);
470 if (pool_base_info(elem, cb,
471 PO_FALSE) == NULL) {
472 free(cs);
473 return (NULL);
474 }
475 }
476 free(cs);
477 }
478 break;
479 case PEC_RES_AGG:
480 case PEC_COMP:
481 break;
482 default:
483 /*NOTREACHED*/
484 break;
485 }
486 if (cb->cb_tab_buf[0] != 0)
487 cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0;
488 }
489 return (cb->cb_buf);
490 }
491
492 /*
493 * Returns The information on the specified pool or NULL.
494 *
495 * Errors If the status of the conf is INVALID or the supplied
496 * value of deep is illegal, POE_BADPARAM.
497 *
498 * The caller is responsible for free(3c)ing the string returned.
499 */
500 char *
pool_info(const pool_conf_t * conf,const pool_t * pool,int deep)501 pool_info(const pool_conf_t *conf, const pool_t *pool, int deep)
502 {
503 pool_elem_t *pe;
504
505 pe = TO_ELEM(pool);
506
507 if (TO_CONF(pe) != conf) {
508 pool_seterror(POE_BADPARAM);
509 return (NULL);
510 }
511
512 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
513 pool_seterror(POE_BADPARAM);
514 return (NULL);
515 }
516
517 return (pool_base_info(pe, NULL, deep));
518 }
519
520 /*
521 * Returns The information on the specified resource or NULL.
522 *
523 * Errors If the status of the conf is INVALID or the supplied
524 * value of deep is illegal, POE_BADPARAM.
525 *
526 * The caller is responsible for free(3c)ing the string returned.
527 */
528 char *
pool_resource_info(const pool_conf_t * conf,const pool_resource_t * res,int deep)529 pool_resource_info(const pool_conf_t *conf, const pool_resource_t *res,
530 int deep)
531 {
532 pool_elem_t *pe;
533
534 pe = TO_ELEM(res);
535
536 if (TO_CONF(pe) != conf) {
537 pool_seterror(POE_BADPARAM);
538 return (NULL);
539 }
540
541 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
542 pool_seterror(POE_BADPARAM);
543 return (NULL);
544 }
545
546 return (pool_base_info(pe, NULL, deep));
547 }
548
549 /*
550 * Returns The information on the specified component or NULL.
551 *
552 * Errors If the status of the conf is INVALID or the supplied
553 * value of deep is illegal, POE_BADPARAM.
554 *
555 * The caller is responsible for free(3c)ing the string returned.
556 */
557 char *
pool_component_info(const pool_conf_t * conf,const pool_component_t * comp,int deep)558 pool_component_info(const pool_conf_t *conf, const pool_component_t *comp,
559 int deep)
560 {
561 pool_elem_t *pe;
562
563 pe = TO_ELEM(comp);
564
565 if (TO_CONF(pe) != conf) {
566 pool_seterror(POE_BADPARAM);
567 return (NULL);
568 }
569
570 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
571 pool_seterror(POE_BADPARAM);
572 return (NULL);
573 }
574
575 return (pool_base_info(pe, NULL, deep));
576 }
577
578 /*
579 * Returns The information on the specified conf or NULL.
580 *
581 * Errors If the status of the conf is INVALID or the supplied
582 * value of deep is illegal, POE_BADPARAM.
583 *
584 * The caller is responsible for free(3c)ing the string returned.
585 */
586 char *
pool_conf_info(const pool_conf_t * conf,int deep)587 pool_conf_info(const pool_conf_t *conf, int deep)
588 {
589 pool_elem_t *pe;
590
591 if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
592 pool_seterror(POE_BADPARAM);
593 return (NULL);
594 }
595 if ((pe = pool_conf_to_elem(conf)) == NULL) {
596 pool_seterror(POE_BADPARAM);
597 return (NULL);
598 }
599 return (pool_base_info(pe, NULL, deep));
600 }
601
602
603 /*
604 * Set the thread specific error value.
605 */
606 void
pool_seterror(int errval)607 pool_seterror(int errval)
608 {
609 if (thr_main()) {
610 pool_errval = errval;
611 return;
612 }
613 (void) thr_keycreate_once(&errkey, 0);
614 (void) thr_setspecific(errkey, (void *)(intptr_t)errval);
615 }
616
617 /*
618 * Return the current value of the error code.
619 * Returns: int error code
620 */
621 int
pool_error(void)622 pool_error(void)
623 {
624 if (thr_main())
625 return (pool_errval);
626 if (errkey == THR_ONCE_KEY)
627 return (POE_OK);
628 return ((uintptr_t)pthread_getspecific(errkey));
629 }
630
631 /*
632 * Return the text represenation for the current value of the error code.
633 * Returns: const char * error string
634 */
635 const char *
pool_strerror(int error)636 pool_strerror(int error)
637 {
638 char *str;
639
640 switch (error) {
641 case POE_OK:
642 str = dgettext(TEXT_DOMAIN, "Operation successful");
643 break;
644 case POE_BAD_PROP_TYPE:
645 str = dgettext(TEXT_DOMAIN,
646 "Attempted to retrieve the wrong property type");
647 break;
648 case POE_INVALID_CONF:
649 str = dgettext(TEXT_DOMAIN, "Invalid configuration");
650 break;
651 case POE_NOTSUP:
652 str = dgettext(TEXT_DOMAIN, "Operation is not supported");
653 break;
654 case POE_INVALID_SEARCH:
655 str = dgettext(TEXT_DOMAIN, "Invalid search");
656 break;
657 case POE_BADPARAM:
658 str = dgettext(TEXT_DOMAIN, "Bad parameter supplied");
659 break;
660 case POE_PUTPROP:
661 str = dgettext(TEXT_DOMAIN, "Error putting property");
662 break;
663 case POE_DATASTORE:
664 str = dgettext(TEXT_DOMAIN, "Pools repository error");
665 break;
666 case POE_SYSTEM:
667 str = dgettext(TEXT_DOMAIN, "System error");
668 break;
669 case POE_ACCESS:
670 str = dgettext(TEXT_DOMAIN, "Permission denied");
671 break;
672 default:
673 errno = ESRCH;
674 str = NULL;
675 }
676 return (str);
677 }
678
679 int
pool_get_status(int * state)680 pool_get_status(int *state)
681 {
682 int fd;
683 pool_status_t status;
684
685 if ((fd = open(pool_info_location, O_RDONLY)) < 0) {
686 pool_seterror(POE_SYSTEM);
687 return (PO_FAIL);
688 }
689 if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
690 (void) close(fd);
691 pool_seterror(POE_SYSTEM);
692 return (PO_FAIL);
693 }
694 (void) close(fd);
695
696 *state = status.ps_io_state;
697
698 return (PO_SUCCESS);
699 }
700
701 int
pool_set_status(int state)702 pool_set_status(int state)
703 {
704 int old_state;
705
706 if (pool_get_status(&old_state) != PO_SUCCESS) {
707 pool_seterror(POE_SYSTEM);
708 return (PO_FAIL);
709 }
710
711 if (old_state != state) {
712 int fd;
713 pool_status_t status;
714 char *fmri;
715
716 /*
717 * Changing the status of pools is performed by enabling
718 * or disabling the pools service instance. If this
719 * function has not been invoked by startd then we simply
720 * enable/disable the service and return success.
721 *
722 * There is no way to specify that state changes must be
723 * synchronous using the library API as yet, so we use
724 * the -s option provided by svcadm.
725 */
726 fmri = getenv("SMF_FMRI");
727 if (fmri == NULL) {
728 FILE *p;
729 char *cmd;
730
731 if (state != 0) {
732 cmd = "/usr/sbin/svcadm enable -s " \
733 SMF_SVC_INSTANCE;
734 } else {
735 cmd = "/usr/sbin/svcadm disable -s " \
736 SMF_SVC_INSTANCE;
737 }
738 if ((p = popen(cmd, "wF")) == NULL || pclose(p) != 0) {
739 pool_seterror(POE_SYSTEM);
740 return (PO_FAIL);
741 }
742 return (PO_SUCCESS);
743 }
744
745 if ((fd = open(pool_dynamic_location(), O_RDWR | O_EXCL)) < 0) {
746 pool_seterror(POE_SYSTEM);
747 return (PO_FAIL);
748 }
749
750 /*
751 * If pools are being enabled/disabled by another smf service,
752 * enable the smf service instance. This must be done
753 * asynchronously as one service cannot synchronously
754 * enable/disable another.
755 */
756 if (strcmp(fmri, SMF_SVC_INSTANCE) != 0) {
757 int res;
758
759 if (state != 0)
760 res = smf_enable_instance(SMF_SVC_INSTANCE, 0);
761 else
762 res = smf_disable_instance(SMF_SVC_INSTANCE, 0);
763
764 if (res != 0) {
765 (void) close(fd);
766 pool_seterror(POE_SYSTEM);
767 return (PO_FAIL);
768 }
769 }
770 status.ps_io_state = state;
771
772 if (ioctl(fd, POOL_STATUS, &status) < 0) {
773 (void) close(fd);
774 pool_seterror(POE_SYSTEM);
775 return (PO_FAIL);
776 }
777
778 (void) close(fd);
779
780 }
781 return (PO_SUCCESS);
782 }
783
784 /*
785 * General Data Provider Independent Access Methods
786 */
787
788 /*
789 * Property manipulation code.
790 *
791 * The pool_(get|rm|set)_property() functions consult the plugins before
792 * looking at the actual configuration. This allows plugins to provide
793 * "virtual" properties that may not exist in the configuration file per se,
794 * but behave like regular properties. This also allows plugins to reserve
795 * certain properties as read-only, non-removable, etc.
796 *
797 * A negative value returned from the plugin denotes error, 0 means that the
798 * property request should be forwarded to the backend, and 1 means the request
799 * was satisfied by the plugin and should not be processed further.
800 *
801 * The (get|rm|set)_property() functions bypass the plugin layer completely,
802 * and hence should not be generally used.
803 */
804
805 /*
806 * Return true if the string passed in matches the pattern
807 * [A-Za-z][A-Za-z0-9,._-]*
808 */
809 int
is_valid_name(const char * name)810 is_valid_name(const char *name)
811 {
812 int i;
813 char c;
814
815 if (name == NULL)
816 return (PO_FALSE);
817 if (!isalpha(name[0]))
818 return (PO_FALSE);
819 for (i = 1; (c = name[i]) != '\0'; i++) {
820 if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-')
821 return (PO_FALSE);
822 }
823 return (PO_TRUE);
824 }
825
826 /*
827 * Return true if the string passed in matches the pattern
828 * [A-Za-z_][A-Za-z0-9,._-]*
829 * A property name starting with a '_' is an "invisible" property that does not
830 * show up in a property walk.
831 */
832 int
is_valid_prop_name(const char * prop_name)833 is_valid_prop_name(const char *prop_name)
834 {
835 int i;
836 char c;
837
838 if (prop_name == NULL)
839 return (PO_FALSE);
840 if (!isalpha(prop_name[0]) && prop_name[0] != '_')
841 return (PO_FALSE);
842 for (i = 1; (c = prop_name[i]) != '\0'; i++) {
843 if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-')
844 return (PO_FALSE);
845 }
846 return (PO_TRUE);
847 }
848
849 /*
850 * Return the specified property value.
851 *
852 * POC_INVAL is returned if an error is detected and the error code is updated
853 * to indicate the cause of the error.
854 */
855 pool_value_class_t
pool_get_property(const pool_conf_t * conf,const pool_elem_t * pe,const char * name,pool_value_t * val)856 pool_get_property(const pool_conf_t *conf, const pool_elem_t *pe,
857 const char *name, pool_value_t *val)
858 {
859 const pool_prop_t *prop_info;
860
861 if (pool_conf_status(conf) == POF_INVALID) {
862 pool_seterror(POE_BADPARAM);
863 return (POC_INVAL);
864 }
865 if (pool_value_set_name(val, name) != PO_SUCCESS) {
866 return (POC_INVAL);
867 }
868 /*
869 * Check to see if this is a property we are managing. If it
870 * is and it has an interceptor installed for property
871 * retrieval, use it.
872 */
873 if ((prop_info = provider_get_prop(pe, name)) != NULL &&
874 prop_info->pp_op.ppo_get_value != NULL) {
875 if (prop_info->pp_op.ppo_get_value(pe, val) == PO_FAIL)
876 return (POC_INVAL);
877 else
878 return (pool_value_get_type(val));
879 }
880 return (pe->pe_get_prop(pe, name, val));
881 }
882
883 /*
884 * Return the specified property value with the namespace prepended.
885 * e.g. If this function is used to get the property "name" on a pool, it will
886 * attempt to retrieve "pool.name".
887 *
888 * POC_INVAL is returned if an error is detected and the error code is updated
889 * to indicate the cause of the error.
890 */
891 pool_value_class_t
pool_get_ns_property(const pool_elem_t * pe,const char * name,pool_value_t * val)892 pool_get_ns_property(const pool_elem_t *pe, const char *name, pool_value_t *val)
893 {
894 int ret;
895 char_buf_t *cb;
896
897 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
898 return (POC_INVAL);
899 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
900 PO_FAIL) {
901 free_char_buf(cb);
902 return (POC_INVAL);
903 }
904 ret = pool_get_property(TO_CONF(pe), pe, cb->cb_buf, val);
905 free_char_buf(cb);
906 return (ret);
907 }
908
909 /*
910 * Update the specified property value.
911 *
912 * PO_FAIL is returned if an error is detected and the error code is updated
913 * to indicate the cause of the error.
914 */
915 int
pool_put_property(pool_conf_t * conf,pool_elem_t * pe,const char * name,const pool_value_t * val)916 pool_put_property(pool_conf_t *conf, pool_elem_t *pe, const char *name,
917 const pool_value_t *val)
918 {
919 const pool_prop_t *prop_info;
920
921 if (pool_conf_check(conf) != PO_SUCCESS)
922 return (PO_FAIL);
923
924 if (TO_CONF(pe) != conf) {
925 pool_seterror(POE_BADPARAM);
926 return (NULL);
927 }
928
929 /* Don't allow (re)setting of the "temporary" property */
930 if (!is_valid_prop_name(name) || strstr(name, ".temporary") != NULL) {
931 pool_seterror(POE_BADPARAM);
932 return (PO_FAIL);
933 }
934
935 /* Don't allow rename of temporary pools/resources */
936 if (strstr(name, ".name") != NULL && elem_is_tmp(pe)) {
937 boolean_t rename = B_TRUE;
938 pool_value_t *pv = pool_value_alloc();
939
940 if (pe->pe_get_prop(pe, name, pv) != POC_INVAL) {
941 const char *s1 = NULL;
942 const char *s2 = NULL;
943
944 (void) pool_value_get_string(pv, &s1);
945 (void) pool_value_get_string(val, &s2);
946 if (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0)
947 rename = B_FALSE;
948 }
949 pool_value_free(pv);
950
951 if (rename) {
952 pool_seterror(POE_BADPARAM);
953 return (PO_FAIL);
954 }
955 }
956
957 /*
958 * Check to see if this is a property we are managing. If it is,
959 * ensure that we are happy with what the user is doing.
960 */
961 if ((prop_info = provider_get_prop(pe, name)) != NULL) {
962 if (prop_is_readonly(prop_info) == PO_TRUE) {
963 pool_seterror(POE_BADPARAM);
964 return (PO_FAIL);
965 }
966 if (prop_info->pp_op.ppo_set_value &&
967 prop_info->pp_op.ppo_set_value(pe, val) == PO_FAIL)
968 return (PO_FAIL);
969 }
970
971 return (pe->pe_put_prop(pe, name, val));
972 }
973
974 /*
975 * Set temporary property to flag as a temporary element.
976 *
977 * PO_FAIL is returned if an error is detected and the error code is updated
978 * to indicate the cause of the error.
979 */
980 int
pool_set_temporary(pool_conf_t * conf,pool_elem_t * pe)981 pool_set_temporary(pool_conf_t *conf, pool_elem_t *pe)
982 {
983 int res;
984 char name[128];
985 pool_value_t *val;
986
987 if (pool_conf_check(conf) != PO_SUCCESS)
988 return (PO_FAIL);
989
990 if (TO_CONF(pe) != conf) {
991 pool_seterror(POE_BADPARAM);
992 return (PO_FAIL);
993 }
994
995 /* create property name based on element type */
996 if (snprintf(name, sizeof (name), "%s.temporary",
997 pool_elem_class_string(pe)) > sizeof (name)) {
998 pool_seterror(POE_SYSTEM);
999 return (PO_FAIL);
1000 }
1001
1002 if ((val = pool_value_alloc()) == NULL)
1003 return (PO_FAIL);
1004
1005 pool_value_set_bool(val, (uchar_t)1);
1006
1007 res = pe->pe_put_prop(pe, name, val);
1008
1009 pool_value_free(val);
1010
1011 return (res);
1012 }
1013
1014 /*
1015 * Update the specified property value with the namespace prepended.
1016 * e.g. If this function is used to update the property "name" on a pool, it
1017 * will attempt to update "pool.name".
1018 *
1019 * PO_FAIL is returned if an error is detected and the error code is updated
1020 * to indicate the cause of the error.
1021 */
1022 int
pool_put_ns_property(pool_elem_t * pe,const char * name,const pool_value_t * val)1023 pool_put_ns_property(pool_elem_t *pe, const char *name,
1024 const pool_value_t *val)
1025 {
1026 char_buf_t *cb;
1027 int ret;
1028
1029 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
1030 return (PO_FAIL);
1031 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
1032 PO_FAIL) {
1033 free_char_buf(cb);
1034 return (PO_FAIL);
1035 }
1036 ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val);
1037 free_char_buf(cb);
1038 return (ret);
1039 }
1040
1041 /*
1042 * Update the specified property value. Do not use the property
1043 * protection mechanism. This function should only be used for cases
1044 * where the library must bypass the normal property protection
1045 * mechanism. The only known use is to update properties in the static
1046 * configuration when performing a commit.
1047 *
1048 * PO_FAIL is returned if an error is detected and the error code is
1049 * updated to indicate the cause of the error.
1050 */
1051 int
pool_put_any_property(pool_elem_t * pe,const char * name,const pool_value_t * val)1052 pool_put_any_property(pool_elem_t *pe, const char *name,
1053 const pool_value_t *val)
1054 {
1055 if (!is_valid_prop_name(name)) {
1056 pool_seterror(POE_BADPARAM);
1057 return (PO_FAIL);
1058 }
1059
1060 return (pe->pe_put_prop(pe, name, val));
1061 }
1062
1063 /*
1064 * Update the specified property value with the namespace prepended.
1065 * e.g. If this function is used to update the property "name" on a pool, it
1066 * will attempt to update "pool.name".
1067 *
1068 * PO_FAIL is returned if an error is detected and the error code is updated
1069 * to indicate the cause of the error.
1070 */
1071 int
pool_put_any_ns_property(pool_elem_t * pe,const char * name,const pool_value_t * val)1072 pool_put_any_ns_property(pool_elem_t *pe, const char *name,
1073 const pool_value_t *val)
1074 {
1075 char_buf_t *cb;
1076 int ret;
1077
1078 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
1079 return (PO_FAIL);
1080 if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
1081 PO_FAIL) {
1082 free_char_buf(cb);
1083 return (PO_FAIL);
1084 }
1085 ret = pool_put_any_property(pe, cb->cb_buf, val);
1086 free_char_buf(cb);
1087 return (ret);
1088 }
1089
1090 /*
1091 * Remove the specified property value. Note that some properties are
1092 * mandatory and thus failure to remove these properties is inevitable.
1093 * PO_FAIL is returned if an error is detected and the error code is updated
1094 * to indicate the cause of the error.
1095 */
1096 int
pool_rm_property(pool_conf_t * conf,pool_elem_t * pe,const char * name)1097 pool_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name)
1098 {
1099 const pool_prop_t *prop_info;
1100
1101 if (pool_conf_check(conf) != PO_SUCCESS)
1102 return (PO_FAIL);
1103
1104 if (TO_CONF(pe) != conf) {
1105 pool_seterror(POE_BADPARAM);
1106 return (NULL);
1107 }
1108
1109 /* Don't allow removal of the "temporary" property */
1110 if (strstr(name, ".temporary") != NULL) {
1111 pool_seterror(POE_BADPARAM);
1112 return (PO_FAIL);
1113 }
1114
1115 /*
1116 * Check to see if this is a property we are managing. If it is,
1117 * ensure that we are happy with what the user is doing.
1118 */
1119 if ((prop_info = provider_get_prop(pe, name)) != NULL) {
1120 if (prop_is_optional(prop_info) == PO_FALSE) {
1121 pool_seterror(POE_BADPARAM);
1122 return (PO_FAIL);
1123 }
1124 }
1125 return (pe->pe_rm_prop(pe, name));
1126 }
1127
1128 /*
1129 * Check if the supplied name is a namespace protected property for the supplied
1130 * element, pe. If it is, return the prefix, otherwise just return NULL.
1131 */
1132 const char *
is_ns_property(const pool_elem_t * pe,const char * name)1133 is_ns_property(const pool_elem_t *pe, const char *name)
1134 {
1135 const char *prefix;
1136
1137 if ((prefix = pool_elem_class_string(pe)) != NULL) {
1138 if (strncmp(name, prefix, strlen(prefix)) == 0)
1139 return (prefix);
1140 }
1141 return (NULL);
1142 }
1143
1144 /*
1145 * Check if the supplied name is a namespace protected property for the supplied
1146 * element, pe. If it is, return the property name with the namespace stripped,
1147 * otherwise just return the name.
1148 */
1149 const char *
property_name_minus_ns(const pool_elem_t * pe,const char * name)1150 property_name_minus_ns(const pool_elem_t *pe, const char *name)
1151 {
1152 const char *prefix;
1153 if ((prefix = is_ns_property(pe, name)) != NULL) {
1154 return (name + strlen(prefix) + 1);
1155 }
1156 return (name);
1157 }
1158
1159 /*
1160 * Create an element to represent a pool and add it to the supplied
1161 * configuration.
1162 */
1163 pool_t *
pool_create(pool_conf_t * conf,const char * name)1164 pool_create(pool_conf_t *conf, const char *name)
1165 {
1166 pool_elem_t *pe;
1167 pool_value_t val = POOL_VALUE_INITIALIZER;
1168 const pool_prop_t *default_props;
1169
1170 if (pool_conf_check(conf) != PO_SUCCESS)
1171 return (NULL);
1172
1173 if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) {
1174 /*
1175 * A pool with the same name exists. Reject.
1176 */
1177 pool_seterror(POE_BADPARAM);
1178 return (NULL);
1179 }
1180 if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_POOL, PREC_INVALID,
1181 PCEC_INVALID)) == NULL) {
1182 pool_seterror(POE_INVALID_CONF);
1183 return (NULL);
1184 }
1185 if ((default_props = provider_get_props(pe)) != NULL) {
1186 int i;
1187 for (i = 0; default_props[i].pp_pname != NULL; i++) {
1188 if (prop_is_init(&default_props[i]) &&
1189 (pool_put_any_property(pe,
1190 default_props[i].pp_pname,
1191 &default_props[i].pp_value) == PO_FAIL)) {
1192 (void) pool_destroy(conf, pool_elem_pool(pe));
1193 return (NULL);
1194 }
1195 }
1196 }
1197 if (pool_value_set_string(&val, name) != PO_SUCCESS) {
1198 (void) pool_destroy(conf, pool_elem_pool(pe));
1199 pool_seterror(POE_SYSTEM);
1200 return (NULL);
1201 }
1202 if (pool_put_property(conf, pe, "pool.name", &val) == PO_FAIL) {
1203 (void) pool_destroy(conf, pool_elem_pool(pe));
1204 pool_seterror(POE_PUTPROP);
1205 return (NULL);
1206 }
1207
1208 /*
1209 * If we are creating a temporary pool configuration, flag the pool.
1210 */
1211 if (conf->pc_prov->pc_oflags & PO_TEMP) {
1212 if (pool_set_temporary(conf, pe) == PO_FAIL) {
1213 (void) pool_destroy(conf, pool_elem_pool(pe));
1214 return (NULL);
1215 }
1216 }
1217
1218 return (pool_elem_pool(pe));
1219 }
1220
1221 /*
1222 * Create an element to represent a res.
1223 */
1224 pool_resource_t *
pool_resource_create(pool_conf_t * conf,const char * sz_type,const char * name)1225 pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name)
1226 {
1227 pool_elem_t *pe;
1228 pool_value_t val = POOL_VALUE_INITIALIZER;
1229 const pool_prop_t *default_props;
1230 pool_resource_t **resources;
1231 int is_default = 0;
1232 uint_t nelem;
1233 pool_elem_class_t elem_class;
1234 pool_resource_elem_class_t type;
1235 pool_value_t *props[] = { NULL, NULL };
1236
1237 if (pool_conf_check(conf) != PO_SUCCESS)
1238 return (NULL);
1239
1240 if ((type = pool_resource_elem_class_from_string(sz_type)) ==
1241 PREC_INVALID) {
1242 pool_seterror(POE_BADPARAM);
1243 return (NULL);
1244 }
1245
1246 if (strcmp(sz_type, "pset") != 0) {
1247 pool_seterror(POE_BADPARAM);
1248 return (NULL);
1249 }
1250
1251 if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) !=
1252 NULL) {
1253 /*
1254 * Resources must be unique by name+type.
1255 */
1256 pool_seterror(POE_BADPARAM);
1257 return (NULL);
1258 }
1259
1260 props[0] = &val;
1261
1262 if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS ||
1263 pool_value_set_name(props[0], c_type) != PO_SUCCESS) {
1264 return (NULL);
1265 }
1266
1267 if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) {
1268 /*
1269 * This is the first representative of this type; when it's
1270 * created it should be created with 'default' = 'true'.
1271 */
1272 is_default = 1;
1273 } else {
1274 free(resources);
1275 }
1276 /*
1277 * TODO: If Additional PEC_RES_COMP types are added to
1278 * pool_impl.h, this would need to be extended.
1279 */
1280 switch (type) {
1281 case PREC_PSET:
1282 elem_class = PEC_RES_COMP;
1283 break;
1284 default:
1285 elem_class = PEC_RES_AGG;
1286 break;
1287 }
1288 if ((pe = conf->pc_prov->pc_elem_create(conf, elem_class, type,
1289 PCEC_INVALID)) == NULL) {
1290 pool_seterror(POE_INVALID_CONF);
1291 return (NULL);
1292 }
1293
1294 /*
1295 * The plugins contain a list of default properties and their values
1296 * for resources. The resource returned, hence, is fully initialized.
1297 */
1298 if ((default_props = provider_get_props(pe)) != NULL) {
1299 int i;
1300 for (i = 0; default_props[i].pp_pname != NULL; i++) {
1301 if (prop_is_init(&default_props[i]) &&
1302 pool_put_any_property(pe, default_props[i].pp_pname,
1303 &default_props[i].pp_value) == PO_FAIL) {
1304 (void) pool_resource_destroy(conf,
1305 pool_elem_res(pe));
1306 return (NULL);
1307 }
1308 }
1309 }
1310 if (pool_value_set_string(&val, name) != PO_SUCCESS ||
1311 pool_put_ns_property(pe, "name", &val) != PO_SUCCESS) {
1312 (void) pool_resource_destroy(conf, pool_elem_res(pe));
1313 return (NULL);
1314 }
1315 if (is_default) {
1316 pool_value_set_bool(&val, PO_TRUE);
1317 if (pool_put_any_ns_property(pe, "default", &val) !=
1318 PO_SUCCESS) {
1319 (void) pool_resource_destroy(conf, pool_elem_res(pe));
1320 return (NULL);
1321 }
1322 }
1323
1324 /*
1325 * If we are creating a temporary pool configuration, flag the resource.
1326 */
1327 if (conf->pc_prov->pc_oflags & PO_TEMP) {
1328 if (pool_set_temporary(conf, pe) != PO_SUCCESS) {
1329 (void) pool_resource_destroy(conf, pool_elem_res(pe));
1330 return (NULL);
1331 }
1332 }
1333
1334 return (pool_elem_res(pe));
1335 }
1336
1337 /*
1338 * Create an element to represent a resource component.
1339 */
1340 pool_component_t *
pool_component_create(pool_conf_t * conf,const pool_resource_t * res,int64_t sys_id)1341 pool_component_create(pool_conf_t *conf, const pool_resource_t *res,
1342 int64_t sys_id)
1343 {
1344 pool_elem_t *pe;
1345 pool_value_t val = POOL_VALUE_INITIALIZER;
1346 const pool_prop_t *default_props;
1347 char refbuf[KEY_BUFFER_SIZE];
1348
1349 if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_COMP,
1350 PREC_INVALID, PCEC_CPU)) == NULL) {
1351 pool_seterror(POE_INVALID_CONF);
1352 return (NULL);
1353 }
1354 /*
1355 * TODO: If additional PEC_COMP types are added in pool_impl.h,
1356 * this would need to be extended.
1357 */
1358 pe->pe_component_class = PCEC_CPU;
1359 /* Now set the container for this comp */
1360 if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) {
1361 (void) pool_component_destroy(pool_elem_comp(pe));
1362 return (NULL);
1363 }
1364 /*
1365 * The plugins contain a list of default properties and their values
1366 * for resources. The resource returned, hence, is fully initialized.
1367 */
1368 if ((default_props = provider_get_props(pe)) != NULL) {
1369 int i;
1370 for (i = 0; default_props[i].pp_pname != NULL; i++) {
1371 if (prop_is_init(&default_props[i]) &&
1372 pool_put_any_property(pe,
1373 default_props[i].pp_pname,
1374 &default_props[i].pp_value) == PO_FAIL) {
1375 (void) pool_component_destroy(
1376 pool_elem_comp(pe));
1377 return (NULL);
1378 }
1379 }
1380 }
1381 /*
1382 * Set additional attributes/properties on component.
1383 */
1384 pool_value_set_int64(&val, sys_id);
1385 if (pool_put_any_ns_property(pe, c_sys_prop, &val) != PO_SUCCESS) {
1386 (void) pool_component_destroy(pool_elem_comp(pe));
1387 return (NULL);
1388 }
1389 if (snprintf(refbuf, KEY_BUFFER_SIZE, "%s_%lld",
1390 pool_elem_class_string(pe), sys_id) > KEY_BUFFER_SIZE) {
1391 (void) pool_component_destroy(pool_elem_comp(pe));
1392 return (NULL);
1393 }
1394 if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) {
1395 (void) pool_component_destroy(pool_elem_comp(pe));
1396 return (NULL);
1397 }
1398 if (pool_put_any_ns_property(pe, c_ref_id, &val) != PO_SUCCESS) {
1399 (void) pool_component_destroy(pool_elem_comp(pe));
1400 return (NULL);
1401 }
1402 return (pool_elem_comp(pe));
1403 }
1404
1405 /*
1406 * Return the location of a configuration.
1407 */
1408 const char *
pool_conf_location(const pool_conf_t * conf)1409 pool_conf_location(const pool_conf_t *conf)
1410 {
1411 if (pool_conf_status(conf) == POF_INVALID) {
1412 pool_seterror(POE_BADPARAM);
1413 return (NULL);
1414 }
1415 return (conf->pc_location);
1416 }
1417 /*
1418 * Close a configuration, freeing all associated resources. Once a
1419 * configuration is closed, it can no longer be used.
1420 */
1421 int
pool_conf_close(pool_conf_t * conf)1422 pool_conf_close(pool_conf_t *conf)
1423 {
1424 int rv;
1425
1426 if (pool_conf_status(conf) == POF_INVALID) {
1427 pool_seterror(POE_BADPARAM);
1428 return (PO_FAIL);
1429 }
1430 rv = conf->pc_prov->pc_close(conf);
1431 conf->pc_prov = NULL;
1432 free((void *)conf->pc_location);
1433 conf->pc_location = NULL;
1434 conf->pc_state = POF_INVALID;
1435 return (rv);
1436 }
1437
1438 /*
1439 * Remove a configuration, freeing all associated resources. Once a
1440 * configuration is removed, it can no longer be accessed and is forever
1441 * gone.
1442 */
1443 int
pool_conf_remove(pool_conf_t * conf)1444 pool_conf_remove(pool_conf_t *conf)
1445 {
1446 int rv;
1447
1448 if (pool_conf_status(conf) == POF_INVALID) {
1449 pool_seterror(POE_BADPARAM);
1450 return (PO_FAIL);
1451 }
1452 rv = conf->pc_prov->pc_remove(conf);
1453 conf->pc_state = POF_INVALID;
1454 return (rv);
1455 }
1456
1457 /*
1458 * pool_conf_alloc() allocate the resources to represent a configuration.
1459 */
1460 pool_conf_t *
pool_conf_alloc(void)1461 pool_conf_alloc(void)
1462 {
1463 pool_conf_t *conf;
1464
1465 if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) {
1466 pool_seterror(POE_SYSTEM);
1467 return (NULL);
1468 }
1469 conf->pc_state = POF_INVALID;
1470 return (conf);
1471 }
1472
1473 /*
1474 * pool_conf_free() frees the resources associated with a configuration.
1475 */
1476 void
pool_conf_free(pool_conf_t * conf)1477 pool_conf_free(pool_conf_t *conf)
1478 {
1479 free(conf);
1480 }
1481
1482 /*
1483 * pool_conf_open() opens a configuration, establishing all required
1484 * connections to the data source.
1485 */
1486 int
pool_conf_open(pool_conf_t * conf,const char * location,int oflags)1487 pool_conf_open(pool_conf_t *conf, const char *location, int oflags)
1488 {
1489 /*
1490 * Since you can't do anything to a pool configuration without opening
1491 * it, this represents a good point to intialise structures that would
1492 * otherwise need to be initialised in a .init section.
1493 */
1494 internal_init();
1495
1496 if (pool_conf_status(conf) != POF_INVALID) {
1497 /*
1498 * Already opened configuration, return PO_FAIL
1499 */
1500 pool_seterror(POE_BADPARAM);
1501 return (PO_FAIL);
1502 }
1503 if (oflags & ~(PO_RDONLY | PO_RDWR | PO_CREAT | PO_DISCO | PO_UPDATE |
1504 PO_TEMP)) {
1505 pool_seterror(POE_BADPARAM);
1506 return (PO_FAIL);
1507 }
1508
1509 /*
1510 * Creating a configuration implies read-write access, so make
1511 * sure that PO_RDWR is set in addition if PO_CREAT is set.
1512 */
1513 if (oflags & PO_CREAT)
1514 oflags |= PO_RDWR;
1515
1516 /* location is ignored when creating a temporary configuration */
1517 if (oflags & PO_TEMP)
1518 location = "";
1519
1520 if ((conf->pc_location = strdup(location)) == NULL) {
1521 pool_seterror(POE_SYSTEM);
1522 return (PO_FAIL);
1523 }
1524 /*
1525 * This is the crossover point into the actual data provider
1526 * implementation, allocate a data provider of the appropriate
1527 * type for your data storage medium. In this case it's either a kernel
1528 * or xml data provider. To use a different data provider, write some
1529 * code to implement all the required interfaces and then change the
1530 * following code to allocate a data provider which uses your new code.
1531 * All data provider routines can be static, apart from the allocation
1532 * routine.
1533 *
1534 * For temporary pools (PO_TEMP) we start with a copy of the current
1535 * dynamic configuration and do all of the updates in-memory.
1536 */
1537 if (oflags & PO_TEMP) {
1538 if (pool_knl_connection_alloc(conf, PO_TEMP) != PO_SUCCESS) {
1539 conf->pc_state = POF_INVALID;
1540 return (PO_FAIL);
1541 }
1542 /* set rdwr flag so we can updated the in-memory config. */
1543 conf->pc_prov->pc_oflags |= PO_RDWR;
1544
1545 } else if (strcmp(location, pool_dynamic_location()) == 0) {
1546 if (pool_knl_connection_alloc(conf, oflags) != PO_SUCCESS) {
1547 conf->pc_state = POF_INVALID;
1548 return (PO_FAIL);
1549 }
1550 } else {
1551 if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) {
1552 conf->pc_state = POF_INVALID;
1553 return (PO_FAIL);
1554 }
1555 }
1556 return (PO_SUCCESS);
1557 }
1558
1559 /*
1560 * Rollback a configuration. This will undo all changes to the configuration
1561 * since the last time pool_conf_commit was called.
1562 */
1563 int
pool_conf_rollback(pool_conf_t * conf)1564 pool_conf_rollback(pool_conf_t *conf)
1565 {
1566 if (pool_conf_status(conf) == POF_INVALID) {
1567 pool_seterror(POE_BADPARAM);
1568 return (PO_FAIL);
1569 }
1570 return (conf->pc_prov->pc_rollback(conf));
1571 }
1572
1573 /*
1574 * Commit a configuration. This will apply all changes to the
1575 * configuration to the permanent data store. The active parameter
1576 * indicates whether the configuration should be used to update the
1577 * dynamic configuration from the supplied (static) configuration or
1578 * whether it should be written back to persistent store.
1579 */
1580 int
pool_conf_commit(pool_conf_t * conf,int active)1581 pool_conf_commit(pool_conf_t *conf, int active)
1582 {
1583 int retval;
1584
1585 if (pool_conf_status(conf) == POF_INVALID) {
1586 pool_seterror(POE_BADPARAM);
1587 return (PO_FAIL);
1588 }
1589 if (active) {
1590 int oflags;
1591
1592 if (conf_is_dynamic(conf) == PO_TRUE) {
1593 pool_seterror(POE_BADPARAM);
1594 return (PO_FAIL);
1595 }
1596 /*
1597 * Pretend that the configuration was opened PO_RDWR
1598 * so that a configuration which was opened PO_RDONLY
1599 * can be committed. The original flags are preserved
1600 * in oflags and restored after pool_conf_commit_sys()
1601 * returns.
1602 */
1603 oflags = conf->pc_prov->pc_oflags;
1604 conf->pc_prov->pc_oflags |= PO_RDWR;
1605 retval = pool_conf_commit_sys(conf, active);
1606 conf->pc_prov->pc_oflags = oflags;
1607 } else {
1608 /*
1609 * Write the configuration back to the backing store.
1610 */
1611 retval = conf->pc_prov->pc_commit(conf);
1612 }
1613 return (retval);
1614 }
1615
1616 /*
1617 * Export a configuration. This will export a configuration in the specified
1618 * format (fmt) to the specified location.
1619 */
1620 int
pool_conf_export(const pool_conf_t * conf,const char * location,pool_export_format_t fmt)1621 pool_conf_export(const pool_conf_t *conf, const char *location,
1622 pool_export_format_t fmt)
1623 {
1624 if (pool_conf_status(conf) == POF_INVALID) {
1625 pool_seterror(POE_BADPARAM);
1626 return (PO_FAIL);
1627 }
1628 return (conf->pc_prov->pc_export(conf, location, fmt));
1629 }
1630
1631 /*
1632 * Validate a configuration. This will validate a configuration at the
1633 * specified level.
1634 */
1635 int
pool_conf_validate(const pool_conf_t * conf,pool_valid_level_t level)1636 pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level)
1637 {
1638 if (pool_conf_status(conf) == POF_INVALID) {
1639 pool_seterror(POE_BADPARAM);
1640 return (PO_FAIL);
1641 }
1642 return (conf->pc_prov->pc_validate(conf, level));
1643 }
1644
1645 /*
1646 * Update the snapshot of a configuration. This can only be used on a
1647 * dynamic configuration.
1648 */
1649 int
pool_conf_update(const pool_conf_t * conf,int * changed)1650 pool_conf_update(const pool_conf_t *conf, int *changed)
1651 {
1652 if (pool_conf_status(conf) == POF_INVALID ||
1653 conf_is_dynamic(conf) == PO_FALSE) {
1654 pool_seterror(POE_BADPARAM);
1655 return (PO_FAIL);
1656 }
1657 /*
1658 * Since this function only makes sense for dynamic
1659 * configurations, just call directly into the appropriate
1660 * function. This could be added into the pool_connection_t
1661 * interface if it was ever required.
1662 */
1663 if (changed)
1664 *changed = 0;
1665 return (pool_knl_update((pool_conf_t *)conf, changed));
1666 }
1667
1668 /*
1669 * Walk the properties of the supplied elem, calling the user supplied
1670 * function repeatedly as long as the user function returns
1671 * PO_SUCCESS.
1672 */
1673 int
pool_walk_properties(pool_conf_t * conf,pool_elem_t * elem,void * arg,int (* prop_callback)(pool_conf_t *,pool_elem_t *,const char *,pool_value_t *,void *))1674 pool_walk_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg,
1675 int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *,
1676 pool_value_t *, void *))
1677 {
1678 return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0));
1679 }
1680
1681 void
free_value_list(int npvals,pool_value_t ** pvals)1682 free_value_list(int npvals, pool_value_t **pvals)
1683 {
1684 int j;
1685
1686 for (j = 0; j < npvals; j++) {
1687 if (pvals[j])
1688 pool_value_free(pvals[j]);
1689 }
1690 free(pvals);
1691 }
1692
1693 /*
1694 * Walk the properties of the supplied elem, calling the user supplied
1695 * function repeatedly as long as the user function returns
1696 * PO_SUCCESS.
1697 * The list of properties to be walked is retrieved from the element
1698 */
1699 int
pool_walk_any_properties(pool_conf_t * conf,pool_elem_t * elem,void * arg,int (* prop_callback)(pool_conf_t *,pool_elem_t *,const char *,pool_value_t *,void *),int any)1700 pool_walk_any_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg,
1701 int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *,
1702 pool_value_t *, void *), int any)
1703 {
1704 pool_value_t **pvals;
1705 int i;
1706 const pool_prop_t *props = provider_get_props(elem);
1707 uint_t npvals;
1708
1709 if (pool_conf_status(conf) == POF_INVALID) {
1710 pool_seterror(POE_BADPARAM);
1711 return (PO_FAIL);
1712 }
1713
1714 if (props == NULL) {
1715 pool_seterror(POE_INVALID_CONF);
1716 return (PO_FAIL);
1717 }
1718
1719 if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL)
1720 return (PO_FAIL);
1721
1722 /*
1723 * Now walk the managed properties. As we find managed
1724 * properties removed them from the list of all properties to
1725 * prevent duplication.
1726 */
1727 for (i = 0; props[i].pp_pname != NULL; i++) {
1728 int j;
1729
1730 /*
1731 * Special processing for type
1732 */
1733 if (strcmp(props[i].pp_pname, c_type) == 0) {
1734 pool_value_t val = POOL_VALUE_INITIALIZER;
1735
1736 if (pool_value_set_name(&val, props[i].pp_pname) ==
1737 PO_FAIL) {
1738 free_value_list(npvals, pvals);
1739 return (PO_FAIL);
1740 }
1741 if (props[i].pp_op.ppo_get_value(elem, &val) ==
1742 PO_FAIL) {
1743 free_value_list(npvals, pvals);
1744 return (PO_FAIL);
1745 }
1746 if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) {
1747 if (prop_callback(conf, elem, props[i].pp_pname,
1748 &val, arg) != PO_SUCCESS) {
1749 free_value_list(npvals, pvals);
1750 pool_seterror(POE_BADPARAM);
1751 return (PO_FAIL);
1752 }
1753 }
1754 continue;
1755 }
1756
1757 for (j = 0; j < npvals; j++) {
1758 if (pvals[j] && strcmp(pool_value_get_name(pvals[j]),
1759 props[i].pp_pname) == 0)
1760 break;
1761 }
1762 /*
1763 * If we have found the property, then j < npvals. Process it
1764 * according to our property attributes. Otherwise, it's not
1765 * a managed property, so just ignore it until later.
1766 */
1767 if (j < npvals) {
1768 if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) {
1769 if (props[i].pp_op.ppo_get_value) {
1770 if (pool_value_set_name(pvals[j],
1771 props[i].pp_pname) == PO_FAIL) {
1772 free_value_list(npvals, pvals);
1773 return (PO_FAIL);
1774 }
1775 if (props[i].pp_op.ppo_get_value(elem,
1776 pvals[j]) == PO_FAIL) {
1777 free_value_list(npvals, pvals);
1778 return (PO_FAIL);
1779 }
1780 }
1781 if (prop_callback(conf, elem, props[i].pp_pname,
1782 pvals[j], arg) != PO_SUCCESS) {
1783 free_value_list(npvals, pvals);
1784 pool_seterror(POE_BADPARAM);
1785 return (PO_FAIL);
1786 }
1787 }
1788 pool_value_free(pvals[j]);
1789 pvals[j] = NULL;
1790 }
1791 }
1792 for (i = 0; i < npvals; i++) {
1793 if (pvals[i]) {
1794 const char *name = pool_value_get_name(pvals[i]);
1795 char *qname = strrchr(name, '.');
1796 if ((qname && qname[1] != '_') ||
1797 (!qname && name[0] != '_')) {
1798 if (prop_callback(conf, elem, name, pvals[i],
1799 arg) != PO_SUCCESS) {
1800 free_value_list(npvals, pvals);
1801 pool_seterror(POE_BADPARAM);
1802 return (PO_FAIL);
1803 }
1804 }
1805 pool_value_free(pvals[i]);
1806 pvals[i] = NULL;
1807 }
1808 }
1809 free(pvals);
1810 return (PO_SUCCESS);
1811 }
1812
1813 /*
1814 * Return a pool, searching the supplied configuration for a pool with the
1815 * supplied name. The search is case sensitive.
1816 */
1817 pool_t *
pool_get_pool(const pool_conf_t * conf,const char * name)1818 pool_get_pool(const pool_conf_t *conf, const char *name)
1819 {
1820 pool_value_t *props[] = { NULL, NULL };
1821 pool_t **rs;
1822 pool_t *ret;
1823 uint_t size = 0;
1824 pool_value_t val = POOL_VALUE_INITIALIZER;
1825
1826 props[0] = &val;
1827
1828 if (pool_conf_status(conf) == POF_INVALID) {
1829 pool_seterror(POE_BADPARAM);
1830 return (NULL);
1831 }
1832
1833 if (pool_value_set_name(props[0], "pool.name") != PO_SUCCESS ||
1834 pool_value_set_string(props[0], name) != PO_SUCCESS) {
1835 return (NULL);
1836 }
1837 rs = pool_query_pools(conf, &size, props);
1838 if (rs == NULL) { /* Can't find a pool to match the name */
1839 return (NULL);
1840 }
1841 if (size != 1) {
1842 free(rs);
1843 pool_seterror(POE_INVALID_CONF);
1844 return (NULL);
1845 }
1846 ret = rs[0];
1847 free(rs);
1848 return (ret);
1849 }
1850
1851 /*
1852 * Return a result set of pools, searching the supplied configuration
1853 * for pools which match the supplied property criteria. props is a null
1854 * terminated list of properties which will be used to match qualifying
1855 * pools. size is updated with the size of the pool
1856 */
1857 pool_t **
pool_query_pools(const pool_conf_t * conf,uint_t * size,pool_value_t ** props)1858 pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props)
1859 {
1860 pool_result_set_t *rs;
1861 pool_elem_t *pe;
1862 pool_t **result = NULL;
1863 int i = 0;
1864
1865 if (pool_conf_status(conf) == POF_INVALID) {
1866 pool_seterror(POE_BADPARAM);
1867 return (NULL);
1868 }
1869 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props);
1870 if (rs == NULL) {
1871 return (NULL);
1872 }
1873 if ((*size = pool_rs_count(rs)) == 0) {
1874 (void) pool_rs_close(rs);
1875 return (NULL);
1876 }
1877 if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) {
1878 pool_seterror(POE_SYSTEM);
1879 (void) pool_rs_close(rs);
1880 return (NULL);
1881 }
1882 (void) memset(result, 0, sizeof (pool_t *) * (*size + 1));
1883 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
1884 if (pool_elem_class(pe) != PEC_POOL) {
1885 pool_seterror(POE_INVALID_CONF);
1886 free(result);
1887 (void) pool_rs_close(rs);
1888 return (NULL);
1889 }
1890 result[i++] = pool_elem_pool(pe);
1891 }
1892 (void) pool_rs_close(rs);
1893 return (result);
1894 }
1895
1896 /*
1897 * Return an res, searching the supplied configuration for an res with the
1898 * supplied name. The search is case sensitive.
1899 */
1900 pool_resource_t *
pool_get_resource(const pool_conf_t * conf,const char * sz_type,const char * name)1901 pool_get_resource(const pool_conf_t *conf, const char *sz_type,
1902 const char *name)
1903 {
1904 pool_value_t *props[] = { NULL, NULL, NULL };
1905 pool_resource_t **rs;
1906 pool_resource_t *ret;
1907 uint_t size = 0;
1908 char_buf_t *cb = NULL;
1909 pool_value_t val0 = POOL_VALUE_INITIALIZER;
1910 pool_value_t val1 = POOL_VALUE_INITIALIZER;
1911
1912 if (pool_conf_status(conf) == POF_INVALID) {
1913 pool_seterror(POE_BADPARAM);
1914 return (NULL);
1915 }
1916
1917 if (sz_type == NULL) {
1918 pool_seterror(POE_BADPARAM);
1919 return (NULL);
1920 }
1921
1922 props[0] = &val0;
1923 props[1] = &val1;
1924
1925 if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS ||
1926 pool_value_set_name(props[0], c_type) != PO_SUCCESS)
1927 return (NULL);
1928
1929 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1930 return (NULL);
1931 }
1932 if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) {
1933 free_char_buf(cb);
1934 return (NULL);
1935 }
1936 if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) {
1937 free_char_buf(cb);
1938 return (NULL);
1939 }
1940 if (pool_value_set_string(props[1], name) != PO_SUCCESS) {
1941 free_char_buf(cb);
1942 return (NULL);
1943 }
1944 free_char_buf(cb);
1945 rs = pool_query_resources(conf, &size, props);
1946 if (rs == NULL) {
1947 return (NULL);
1948 }
1949 if (size != 1) {
1950 free(rs);
1951 pool_seterror(POE_INVALID_CONF);
1952 return (NULL);
1953 }
1954 ret = rs[0];
1955 free(rs);
1956 return (ret);
1957 }
1958
1959 /*
1960 * Return a result set of res (actually as pool_elem_ts), searching the
1961 * supplied configuration for res which match the supplied property
1962 * criteria. props is a null terminated list of properties which will be used
1963 * to match qualifying res.
1964 */
1965 pool_resource_t **
pool_query_resources(const pool_conf_t * conf,uint_t * size,pool_value_t ** props)1966 pool_query_resources(const pool_conf_t *conf, uint_t *size,
1967 pool_value_t **props)
1968 {
1969 pool_result_set_t *rs;
1970 pool_elem_t *pe;
1971 pool_resource_t **result = NULL;
1972 int i = 0;
1973
1974 if (pool_conf_status(conf) == POF_INVALID) {
1975 pool_seterror(POE_BADPARAM);
1976 return (NULL);
1977 }
1978
1979 *size = 0;
1980
1981 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props);
1982 if (rs == NULL) {
1983 return (NULL);
1984 }
1985 if ((*size = pool_rs_count(rs)) == 0) {
1986 (void) pool_rs_close(rs);
1987 return (NULL);
1988 }
1989 if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1)))
1990 == NULL) {
1991 pool_seterror(POE_SYSTEM);
1992 (void) pool_rs_close(rs);
1993 return (NULL);
1994 }
1995 (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1));
1996 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
1997 if (pool_elem_class(pe) != PEC_RES_COMP &&
1998 pool_elem_class(pe) != PEC_RES_AGG) {
1999 pool_seterror(POE_INVALID_CONF);
2000 free(result);
2001 (void) pool_rs_close(rs);
2002 return (NULL);
2003 }
2004 result[i++] = pool_elem_res(pe);
2005 }
2006 (void) pool_rs_close(rs);
2007 return (result);
2008 }
2009
2010 /*
2011 * Return a result set of comp (actually as pool_elem_ts), searching the
2012 * supplied configuration for comp which match the supplied property
2013 * criteria. props is a null terminated list of properties which will be used
2014 * to match qualifying comp.
2015 */
2016 pool_component_t **
pool_query_components(const pool_conf_t * conf,uint_t * size,pool_value_t ** props)2017 pool_query_components(const pool_conf_t *conf, uint_t *size,
2018 pool_value_t **props)
2019 {
2020 return (pool_query_resource_components(conf, NULL, size, props));
2021 }
2022
2023 /*
2024 * Destroy a pool. If the pool cannot be found or removed an error is
2025 * returned. This is basically a wrapper around pool_elem_remove to ensure
2026 * some type safety for the pool subtype.
2027 */
2028 int
pool_destroy(pool_conf_t * conf,pool_t * pp)2029 pool_destroy(pool_conf_t *conf, pool_t *pp)
2030 {
2031 pool_elem_t *pe;
2032
2033 if (pool_conf_check(conf) != PO_SUCCESS)
2034 return (PO_FAIL);
2035
2036 pe = TO_ELEM(pp);
2037
2038 /*
2039 * Cannot destroy the default pool.
2040 */
2041 if (elem_is_default(pe) == PO_TRUE) {
2042 pool_seterror(POE_BADPARAM);
2043 return (PO_FAIL);
2044 }
2045 if (pool_elem_remove(pe) != PO_SUCCESS)
2046 return (PO_FAIL);
2047 return (PO_SUCCESS);
2048 }
2049
2050 /*
2051 * Destroy an res. If the res cannot be found or removed an error is
2052 * returned. This is basically a wrapper around pool_elem_remove to ensure
2053 * some type safety for the res subtype.
2054 */
2055 int
pool_resource_destroy(pool_conf_t * conf,pool_resource_t * prs)2056 pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs)
2057 {
2058 pool_elem_t *pe;
2059 pool_component_t **rl;
2060 uint_t res_size;
2061 pool_t **pl;
2062 uint_t npool;
2063 int i;
2064
2065 if (pool_conf_check(conf) != PO_SUCCESS)
2066 return (PO_FAIL);
2067
2068 pe = TO_ELEM(prs);
2069
2070 if (resource_is_system(prs) == PO_TRUE) {
2071 pool_seterror(POE_BADPARAM);
2072 return (PO_FAIL);
2073 }
2074 /*
2075 * Walk all the pools and dissociate any pools which are using
2076 * this resource.
2077 */
2078 if ((pl = pool_query_pools(conf, &npool, NULL)) != NULL) {
2079 for (i = 0; i < npool; i++) {
2080 pool_resource_t **rl;
2081 uint_t nres;
2082 int j;
2083
2084 if ((rl = pool_query_pool_resources(conf, pl[i], &nres,
2085 NULL)) != NULL) {
2086 for (j = 0; j < nres; j++) {
2087 if (rl[j] == prs) {
2088 if (pool_dissociate(conf, pl[i],
2089 rl[j]) != PO_SUCCESS) {
2090 free(rl);
2091 free(pl);
2092 return (PO_FAIL);
2093 }
2094 break;
2095 }
2096 }
2097 free(rl);
2098 }
2099 }
2100 free(pl);
2101 }
2102 if (pe->pe_class == PEC_RES_COMP) {
2103 pool_resource_t *default_set_res;
2104
2105 /*
2106 * Use the xtransfer option to move comp around
2107 */
2108 default_set_res = (pool_resource_t *)get_default_resource(prs);
2109
2110 if ((rl = pool_query_resource_components(conf, prs, &res_size,
2111 NULL)) != NULL) {
2112 int ostate = conf->pc_state;
2113 conf->pc_state = POF_DESTROY;
2114 if (pool_resource_xtransfer(conf, prs, default_set_res,
2115 rl) == PO_FAIL) {
2116 free(rl);
2117 conf->pc_state = ostate;
2118 return (PO_FAIL);
2119 }
2120 conf->pc_state = ostate;
2121 free(rl);
2122 }
2123 }
2124 if (pool_elem_remove(pe) != PO_SUCCESS)
2125 return (PO_FAIL);
2126 return (PO_SUCCESS);
2127 }
2128
2129 /*
2130 * Destroy a comp. If the comp cannot be found or removed an error is
2131 * returned. This is basically a wrapper around pool_elem_remove to ensure
2132 * some type safety for the comp subtype.
2133 */
2134 int
pool_component_destroy(pool_component_t * pr)2135 pool_component_destroy(pool_component_t *pr)
2136 {
2137 pool_elem_t *pe = TO_ELEM(pr);
2138
2139 if (pool_elem_remove(pe) != PO_SUCCESS)
2140 return (PO_FAIL);
2141 return (PO_SUCCESS);
2142 }
2143
2144 /*
2145 * Remove a pool_elem_t from a configuration. This has been "hidden" away as
2146 * a static routine since the only elements which are currently being removed
2147 * are pools, res & comp and the wrapper functions above provide type-safe
2148 * access. However, if there is a need to remove other types of elements
2149 * then this could be promoted to pool_impl.h or more wrappers could
2150 * be added to pool_impl.h.
2151 */
2152 int
pool_elem_remove(pool_elem_t * pe)2153 pool_elem_remove(pool_elem_t *pe)
2154 {
2155 return (pe->pe_remove(pe));
2156 }
2157
2158 /*
2159 * Execute a query to search for a qualifying set of elements.
2160 */
2161 pool_result_set_t *
pool_exec_query(const pool_conf_t * conf,const pool_elem_t * src,const char * src_attr,pool_elem_class_t classes,pool_value_t ** props)2162 pool_exec_query(const pool_conf_t *conf, const pool_elem_t *src,
2163 const char *src_attr, pool_elem_class_t classes, pool_value_t **props)
2164 {
2165 return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes,
2166 props));
2167 }
2168
2169 /*
2170 * Get the next result from a result set of elements.
2171 */
2172 pool_elem_t *
pool_rs_next(pool_result_set_t * set)2173 pool_rs_next(pool_result_set_t *set)
2174 {
2175 return (set->prs_next(set));
2176 }
2177
2178 /*
2179 * Get the previous result from a result set of elements.
2180 */
2181 pool_elem_t *
pool_rs_prev(pool_result_set_t * set)2182 pool_rs_prev(pool_result_set_t *set)
2183 {
2184 return (set->prs_prev(set));
2185 }
2186
2187 /*
2188 * Get the first result from a result set of elements.
2189 */
2190 pool_elem_t *
pool_rs_first(pool_result_set_t * set)2191 pool_rs_first(pool_result_set_t *set)
2192 {
2193 return (set->prs_first(set));
2194 }
2195
2196 /*
2197 * Get the last result from a result set of elements.
2198 */
2199 pool_elem_t *
pool_rs_last(pool_result_set_t * set)2200 pool_rs_last(pool_result_set_t *set)
2201 {
2202 return (set->prs_last(set));
2203 }
2204
2205
2206 /*
2207 * Get the count for a result set of elements.
2208 */
2209 int
pool_rs_count(pool_result_set_t * set)2210 pool_rs_count(pool_result_set_t *set)
2211 {
2212 return (set->prs_count(set));
2213 }
2214
2215 /*
2216 * Get the index for a result set of elements.
2217 */
2218 int
pool_rs_get_index(pool_result_set_t * set)2219 pool_rs_get_index(pool_result_set_t *set)
2220 {
2221 return (set->prs_get_index(set));
2222 }
2223
2224 /*
2225 * Set the index for a result set of elements.
2226 */
2227 int
pool_rs_set_index(pool_result_set_t * set,int index)2228 pool_rs_set_index(pool_result_set_t *set, int index)
2229 {
2230 return (set->prs_set_index(set, index));
2231 }
2232
2233 /*
2234 * Close a result set of elements, freeing all associated resources.
2235 */
2236 int
pool_rs_close(pool_result_set_t * set)2237 pool_rs_close(pool_result_set_t *set)
2238 {
2239 return (set->prs_close(set));
2240 }
2241
2242 /*
2243 * When transferring resource components using pool_resource_transfer,
2244 * this function is invoked to choose which actual components will be
2245 * transferred.
2246 */
2247 int
choose_components(pool_resource_t * src,pool_resource_t * dst,uint64_t size)2248 choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size)
2249 {
2250 pool_component_t **components = NULL, *moved[] = { NULL, NULL };
2251 int i;
2252 uint_t ncomponent;
2253 pool_conf_t *conf = TO_CONF(TO_ELEM(src));
2254
2255 if (size == 0)
2256 return (PO_SUCCESS);
2257 /*
2258 * Get the component list from our src component.
2259 */
2260 if ((components = pool_query_resource_components(conf, src, &ncomponent,
2261 NULL)) == NULL) {
2262 pool_seterror(POE_BADPARAM);
2263 return (PO_FAIL);
2264 }
2265 qsort(components, ncomponent, sizeof (pool_elem_t *),
2266 qsort_elem_compare);
2267 /*
2268 * Components that aren't specifically requested by the resource
2269 * should be transferred out first.
2270 */
2271 for (i = 0; size > 0 && components[i] != NULL; i++) {
2272 if (!cpu_is_requested(components[i])) {
2273 moved[0] = components[i];
2274 if (pool_resource_xtransfer(conf, src, dst, moved) ==
2275 PO_SUCCESS) {
2276 size--;
2277 }
2278 }
2279 }
2280
2281 /*
2282 * If we couldn't find enough "un-requested" components, select random
2283 * requested components.
2284 */
2285 for (i = 0; size > 0 && components[i] != NULL; i++) {
2286 if (cpu_is_requested(components[i])) {
2287 moved[0] = components[i];
2288 if (pool_resource_xtransfer(conf, src, dst, moved) ==
2289 PO_SUCCESS) {
2290 size--;
2291 }
2292 }
2293 }
2294
2295 free(components);
2296 /*
2297 * If we couldn't transfer out all the resources we asked for, then
2298 * return error.
2299 */
2300 return (size == 0 ? PO_SUCCESS : PO_FAIL);
2301 }
2302
2303 /*
2304 * Common processing for a resource transfer (xfer or xxfer).
2305 *
2306 * - Return XFER_CONTINUE if the transfer should proceeed
2307 * - Return XFER_FAIL if the transfer should be stopped in failure
2308 * - Return XFER_SUCCESS if the transfer should be stopped in success
2309 */
2310 int
setup_transfer(pool_conf_t * conf,pool_resource_t * src,pool_resource_t * tgt,uint64_t size,uint64_t * src_size,uint64_t * tgt_size)2311 setup_transfer(pool_conf_t *conf, pool_resource_t *src, pool_resource_t *tgt,
2312 uint64_t size, uint64_t *src_size, uint64_t *tgt_size)
2313 {
2314 uint64_t src_min;
2315 uint64_t tgt_max;
2316
2317 if (pool_conf_check(conf) != PO_SUCCESS)
2318 return (XFER_FAIL);
2319
2320 /*
2321 * Makes sure the two resources are of the same type
2322 */
2323 if (pool_resource_elem_class(TO_ELEM(src)) !=
2324 pool_resource_elem_class(TO_ELEM(tgt))) {
2325 pool_seterror(POE_BADPARAM);
2326 return (XFER_FAIL);
2327 }
2328
2329 /*
2330 * Transferring to yourself is a no-op
2331 */
2332 if (src == tgt)
2333 return (XFER_SUCCESS);
2334
2335 /*
2336 * Transferring nothing is a no-op
2337 */
2338 if (size == 0)
2339 return (XFER_SUCCESS);
2340
2341 if (resource_get_min(src, &src_min) != PO_SUCCESS ||
2342 resource_get_size(src, src_size) != PO_SUCCESS ||
2343 resource_get_max(tgt, &tgt_max) != PO_SUCCESS ||
2344 resource_get_size(tgt, tgt_size) != PO_SUCCESS) {
2345 pool_seterror(POE_BADPARAM);
2346 return (XFER_FAIL);
2347 }
2348 if (pool_conf_status(conf) != POF_DESTROY) {
2349 /*
2350 * src_size - donating >= src.min
2351 * size + receiving <= tgt.max (except for default)
2352 */
2353 #ifdef DEBUG
2354 dprintf("conf is %s\n", pool_conf_location(conf));
2355 dprintf("setup_transfer: src_size %llu\n", *src_size);
2356 pool_elem_dprintf(TO_ELEM(src));
2357 dprintf("setup_transfer: tgt_size %llu\n", *tgt_size);
2358 pool_elem_dprintf(TO_ELEM(tgt));
2359 #endif /* DEBUG */
2360 if (*src_size - size < src_min ||
2361 (resource_is_default(tgt) == PO_FALSE &&
2362 *tgt_size + size > tgt_max)) {
2363 pool_seterror(POE_INVALID_CONF);
2364 return (XFER_FAIL);
2365 }
2366 }
2367 return (XFER_CONTINUE);
2368 }
2369
2370 /*
2371 * Transfer resource quantities from one resource set to another.
2372 */
2373 int
pool_resource_transfer(pool_conf_t * conf,pool_resource_t * src,pool_resource_t * tgt,uint64_t size)2374 pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src,
2375 pool_resource_t *tgt, uint64_t size)
2376 {
2377 uint64_t src_size;
2378 uint64_t tgt_size;
2379 int ret;
2380
2381 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2382 != XFER_CONTINUE)
2383 return (ret);
2384 /*
2385 * If this resource is a res_comp we must call move components
2386 */
2387 if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP)
2388 return (choose_components(src, tgt, size));
2389 /*
2390 * Now do the transfer.
2391 */
2392 ret = conf->pc_prov->pc_res_xfer(src, tgt, size);
2393 /*
2394 * Modify the sizes of the resource sets if the process was
2395 * successful
2396 */
2397 if (ret == PO_SUCCESS) {
2398 pool_value_t val = POOL_VALUE_INITIALIZER;
2399
2400 src_size -= size;
2401 tgt_size += size;
2402 pool_value_set_uint64(&val, src_size);
2403 (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop,
2404 &val);
2405 pool_value_set_uint64(&val, tgt_size);
2406 (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop,
2407 &val);
2408 }
2409 return (ret);
2410 }
2411
2412 /*
2413 * Transfer resource components from one resource set to another.
2414 */
2415 int
pool_resource_xtransfer(pool_conf_t * conf,pool_resource_t * src,pool_resource_t * tgt,pool_component_t ** rl)2416 pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src,
2417 pool_resource_t *tgt,
2418 pool_component_t **rl)
2419 {
2420 int i;
2421 uint64_t src_size;
2422 uint64_t tgt_size;
2423 uint64_t size;
2424 int ret;
2425
2426 /*
2427 * Make sure the components are all contained in 'src'. This
2428 * processing must be done before setup_transfer so that size
2429 * is known.
2430 */
2431 for (i = 0; rl[i] != NULL; i++) {
2432 #ifdef DEBUG
2433 dprintf("resource xtransfer\n");
2434 dprintf("in conf %s\n", pool_conf_location(conf));
2435 dprintf("transferring component\n");
2436 pool_elem_dprintf(TO_ELEM(rl[i]));
2437 dprintf("from\n");
2438 pool_elem_dprintf(TO_ELEM(src));
2439 dprintf("to\n");
2440 pool_elem_dprintf(TO_ELEM(tgt));
2441 #endif /* DEBUG */
2442
2443 if (pool_get_owning_resource(conf, rl[i]) != src) {
2444 pool_seterror(POE_BADPARAM);
2445 return (PO_FAIL);
2446 }
2447 }
2448
2449 size = (uint64_t)i;
2450
2451 if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2452 != XFER_CONTINUE)
2453 return (ret);
2454
2455 ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl);
2456 /*
2457 * Modify the sizes of the resource sets if the process was
2458 * successful
2459 */
2460 if (ret == PO_SUCCESS) {
2461 pool_value_t val = POOL_VALUE_INITIALIZER;
2462
2463 #ifdef DEBUG
2464 dprintf("src_size %llu\n", src_size);
2465 dprintf("tgt_size %llu\n", tgt_size);
2466 dprintf("size %llu\n", size);
2467 #endif /* DEBUG */
2468 src_size -= size;
2469 tgt_size += size;
2470 pool_value_set_uint64(&val, src_size);
2471 (void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop,
2472 &val);
2473 pool_value_set_uint64(&val, tgt_size);
2474 (void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop,
2475 &val);
2476 }
2477 return (ret);
2478 }
2479
2480 /*
2481 * Find the owning resource for a resource component.
2482 */
2483 pool_resource_t *
pool_get_owning_resource(const pool_conf_t * conf,const pool_component_t * comp)2484 pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp)
2485 {
2486 if (pool_conf_status(conf) == POF_INVALID) {
2487 pool_seterror(POE_BADPARAM);
2488 return (NULL);
2489 }
2490 return (pool_elem_res(pool_get_container(TO_ELEM(comp))));
2491 }
2492
2493 /*
2494 * pool_get_container() returns the container of pc.
2495 */
2496 pool_elem_t *
pool_get_container(const pool_elem_t * pc)2497 pool_get_container(const pool_elem_t *pc)
2498 {
2499 return (pc->pe_get_container(pc));
2500 }
2501
2502 /*
2503 * pool_set_container() moves pc so that it is contained by pp.
2504 *
2505 * Returns PO_SUCCESS/PO_FAIL
2506 */
2507 int
pool_set_container(pool_elem_t * pp,pool_elem_t * pc)2508 pool_set_container(pool_elem_t *pp, pool_elem_t *pc)
2509 {
2510 return (pc->pe_set_container(pp, pc));
2511 }
2512
2513 /*
2514 * Conversion routines for converting to and from elem and it's various
2515 * subtypes of system, pool, res and comp.
2516 */
2517 pool_elem_t *
pool_system_elem(const pool_system_t * ph)2518 pool_system_elem(const pool_system_t *ph)
2519 {
2520 return ((pool_elem_t *)ph);
2521 }
2522
2523 pool_elem_t *
pool_conf_to_elem(const pool_conf_t * conf)2524 pool_conf_to_elem(const pool_conf_t *conf)
2525 {
2526 pool_system_t *sys;
2527
2528 if (pool_conf_status(conf) == POF_INVALID) {
2529 pool_seterror(POE_BADPARAM);
2530 return (NULL);
2531 }
2532 if ((sys = pool_conf_system(conf)) == NULL) {
2533 pool_seterror(POE_BADPARAM);
2534 return (NULL);
2535 }
2536 return (pool_system_elem(sys));
2537 }
2538
2539 pool_elem_t *
pool_to_elem(const pool_conf_t * conf,const pool_t * pp)2540 pool_to_elem(const pool_conf_t *conf, const pool_t *pp)
2541 {
2542 if (pool_conf_status(conf) == POF_INVALID) {
2543 pool_seterror(POE_BADPARAM);
2544 return (NULL);
2545 }
2546 return ((pool_elem_t *)pp);
2547 }
2548
2549 pool_elem_t *
pool_resource_to_elem(const pool_conf_t * conf,const pool_resource_t * prs)2550 pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs)
2551 {
2552 if (pool_conf_status(conf) == POF_INVALID) {
2553 pool_seterror(POE_BADPARAM);
2554 return (NULL);
2555 }
2556 return ((pool_elem_t *)prs);
2557 }
2558
2559 pool_elem_t *
pool_component_to_elem(const pool_conf_t * conf,const pool_component_t * pr)2560 pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr)
2561 {
2562 if (pool_conf_status(conf) == POF_INVALID) {
2563 pool_seterror(POE_BADPARAM);
2564 return (NULL);
2565 }
2566 return ((pool_elem_t *)pr);
2567 }
2568
2569 /*
2570 * Walk all the pools of the configuration calling the user supplied function
2571 * as long as the user function continues to return PO_TRUE
2572 */
2573 int
pool_walk_pools(pool_conf_t * conf,void * arg,int (* callback)(pool_conf_t * conf,pool_t * pool,void * arg))2574 pool_walk_pools(pool_conf_t *conf, void *arg,
2575 int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg))
2576 {
2577 pool_t **rs;
2578 int i;
2579 uint_t size;
2580 int error = PO_SUCCESS;
2581
2582 if (pool_conf_status(conf) == POF_INVALID) {
2583 pool_seterror(POE_BADPARAM);
2584 return (PO_FAIL);
2585 }
2586
2587 if ((rs = pool_query_pools(conf, &size, NULL)) == NULL) /* None */
2588 return (PO_SUCCESS);
2589 for (i = 0; i < size; i++)
2590 if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2591 error = PO_FAIL;
2592 break;
2593 }
2594 free(rs);
2595 return (error);
2596 }
2597
2598 /*
2599 * Walk all the comp of the res calling the user supplied function
2600 * as long as the user function continues to return PO_TRUE
2601 */
2602 int
pool_walk_components(pool_conf_t * conf,pool_resource_t * prs,void * arg,int (* callback)(pool_conf_t * conf,pool_component_t * pr,void * arg))2603 pool_walk_components(pool_conf_t *conf, pool_resource_t *prs, void *arg,
2604 int (*callback)(pool_conf_t *conf, pool_component_t *pr, void *arg))
2605 {
2606 pool_component_t **rs;
2607 int i;
2608 uint_t size;
2609 int error = PO_SUCCESS;
2610
2611 if (pool_conf_status(conf) == POF_INVALID) {
2612 pool_seterror(POE_BADPARAM);
2613 return (PO_FAIL);
2614 }
2615
2616 if ((rs = pool_query_resource_components(conf, prs, &size, NULL)) ==
2617 NULL)
2618 return (PO_SUCCESS); /* None */
2619 for (i = 0; i < size; i++)
2620 if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2621 error = PO_FAIL;
2622 break;
2623 }
2624 free(rs);
2625 return (error);
2626 }
2627
2628 /*
2629 * Return an array of all matching res for the supplied pool.
2630 */
2631 pool_resource_t **
pool_query_pool_resources(const pool_conf_t * conf,const pool_t * pp,uint_t * size,pool_value_t ** props)2632 pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp,
2633 uint_t *size, pool_value_t **props)
2634 {
2635 pool_result_set_t *rs;
2636 pool_elem_t *pe;
2637 pool_resource_t **result = NULL;
2638 int i = 0;
2639
2640 if (pool_conf_status(conf) == POF_INVALID) {
2641 pool_seterror(POE_BADPARAM);
2642 return (NULL);
2643 }
2644
2645 pe = TO_ELEM(pp);
2646
2647 rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props);
2648 if (rs == NULL) {
2649 return (NULL);
2650 }
2651 if ((*size = pool_rs_count(rs)) == 0) {
2652 (void) pool_rs_close(rs);
2653 return (NULL);
2654 }
2655 if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1)))
2656 == NULL) {
2657 pool_seterror(POE_SYSTEM);
2658 (void) pool_rs_close(rs);
2659 return (NULL);
2660 }
2661 (void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1));
2662 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2663 if (pool_elem_class(pe) != PEC_RES_COMP &&
2664 pool_elem_class(pe) != PEC_RES_AGG) {
2665 pool_seterror(POE_INVALID_CONF);
2666 free(result);
2667 (void) pool_rs_close(rs);
2668 return (NULL);
2669 }
2670 result[i++] = pool_elem_res(pe);
2671 }
2672 (void) pool_rs_close(rs);
2673 return (result);
2674 }
2675
2676 /*
2677 * Walk all the res of the pool calling the user supplied function
2678 * as long as the user function continues to return PO_TRUE
2679 */
2680 int
pool_walk_resources(pool_conf_t * conf,pool_t * pp,void * arg,int (* callback)(pool_conf_t *,pool_resource_t *,void *))2681 pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg,
2682 int (*callback)(pool_conf_t *, pool_resource_t *, void *))
2683 {
2684 pool_resource_t **rs;
2685 int i;
2686 uint_t size;
2687 int error = PO_SUCCESS;
2688
2689 if (pool_conf_status(conf) == POF_INVALID) {
2690 pool_seterror(POE_BADPARAM);
2691 return (PO_FAIL);
2692 }
2693 if ((rs = pool_query_pool_resources(conf, pp, &size, NULL)) == NULL)
2694 return (PO_SUCCESS); /* None */
2695 for (i = 0; i < size; i++)
2696 if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2697 error = PO_FAIL;
2698 break;
2699 }
2700 free(rs);
2701 return (error);
2702 }
2703
2704 /*
2705 * Return a result set of all comp for the supplied res.
2706 */
2707 pool_component_t **
pool_query_resource_components(const pool_conf_t * conf,const pool_resource_t * prs,uint_t * size,pool_value_t ** props)2708 pool_query_resource_components(const pool_conf_t *conf,
2709 const pool_resource_t *prs, uint_t *size, pool_value_t **props)
2710 {
2711 pool_result_set_t *rs;
2712 pool_elem_t *pe;
2713 pool_component_t **result = NULL;
2714 int i = 0;
2715
2716 if (pool_conf_status(conf) == POF_INVALID) {
2717 pool_seterror(POE_BADPARAM);
2718 return (NULL);
2719 }
2720 pe = TO_ELEM(prs);
2721
2722 rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props);
2723 if (rs == NULL) {
2724 return (NULL);
2725 }
2726 if ((*size = pool_rs_count(rs)) == 0) {
2727 (void) pool_rs_close(rs);
2728 return (NULL);
2729 }
2730 if ((result = malloc(sizeof (pool_component_t *) * (*size + 1)))
2731 == NULL) {
2732 pool_seterror(POE_SYSTEM);
2733 (void) pool_rs_close(rs);
2734 return (NULL);
2735 }
2736 (void) memset(result, 0, sizeof (pool_component_t *) * (*size + 1));
2737 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2738 if (pool_elem_class(pe) != PEC_COMP) {
2739 pool_seterror(POE_INVALID_CONF);
2740 free(result);
2741 (void) pool_rs_close(rs);
2742 return (NULL);
2743 }
2744 result[i++] = pool_elem_comp(pe);
2745 }
2746 (void) pool_rs_close(rs);
2747 return (result);
2748 }
2749
2750 /*
2751 * pool_version() returns the version of this library, depending on the supplied
2752 * parameter.
2753 *
2754 * Returns: library version depening on the supplied ver parameter.
2755 */
2756 uint_t
pool_version(uint_t ver)2757 pool_version(uint_t ver)
2758 {
2759 switch (ver) {
2760 case POOL_VER_NONE:
2761 break;
2762 case POOL_VER_CURRENT:
2763 pool_workver = ver;
2764 break;
2765 default:
2766 return (POOL_VER_NONE);
2767 }
2768 return (pool_workver);
2769 }
2770
2771 /*
2772 * pool_associate() associates the supplied resource to the supplied pool.
2773 *
2774 * Returns: PO_SUCCESS/PO_FAIL
2775 */
2776 int
pool_associate(pool_conf_t * conf,pool_t * pool,const pool_resource_t * res)2777 pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2778 {
2779 if (pool_conf_check(conf) != PO_SUCCESS)
2780 return (PO_FAIL);
2781
2782 return (pool->pp_associate(pool, res));
2783 }
2784
2785 /*
2786 * pool_dissociate() dissociates the supplied resource from the supplied pool.
2787 *
2788 * Returns: PO_SUCCESS/PO_FAIL
2789 */
2790 int
pool_dissociate(pool_conf_t * conf,pool_t * pool,const pool_resource_t * res)2791 pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2792 {
2793 if (pool_conf_check(conf) != PO_SUCCESS)
2794 return (PO_FAIL);
2795
2796 if (elem_is_default(TO_ELEM(res)))
2797 return (PO_SUCCESS);
2798 return (pool->pp_dissociate(pool, res));
2799 }
2800
2801 /*
2802 * Compare two elements for purposes of ordering.
2803 * Return:
2804 * < 0 if e1 is "before" e2
2805 * 0 if e1 "equals" e2
2806 * > 0 if e1 comes after e2
2807 */
2808 int
pool_elem_compare_name(const pool_elem_t * e1,const pool_elem_t * e2)2809 pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2)
2810 {
2811 char *name1, *name2;
2812 pool_value_t val = POOL_VALUE_INITIALIZER;
2813 int retval;
2814
2815 /*
2816 * We may be asked to compare two elements from different classes.
2817 * They are different so return (1).
2818 */
2819 if (pool_elem_same_class(e1, e2) != PO_TRUE)
2820 return (1);
2821
2822 /*
2823 * If the class is PEC_SYSTEM, always match them
2824 */
2825 if (pool_elem_class(e1) == PEC_SYSTEM)
2826 return (0);
2827
2828 /*
2829 * If we are going to compare components, then use sys_id
2830 */
2831 if (pool_elem_class(e1) == PEC_COMP) {
2832 int64_t sys_id1, sys_id2;
2833
2834 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2835 return (-1);
2836 }
2837 (void) pool_value_get_int64(&val, &sys_id1);
2838 if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) {
2839 return (-1);
2840 }
2841 (void) pool_value_get_int64(&val, &sys_id2);
2842 retval = (sys_id1 - sys_id2);
2843 } else {
2844 if (pool_get_ns_property(e1, "name", &val) == POC_INVAL) {
2845 return (-1);
2846 }
2847 (void) pool_value_get_string(&val, (const char **)&name1);
2848 if ((name1 = strdup(name1)) == NULL) {
2849 return (-1);
2850 }
2851
2852 if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) {
2853 return (-1);
2854 }
2855
2856 (void) pool_value_get_string(&val, (const char **)&name2);
2857 retval = strcmp(name1, name2);
2858 free(name1);
2859 }
2860 return (retval);
2861 }
2862
2863 /*
2864 * Compare two elements for purposes of ordering.
2865 * Return:
2866 * < 0 if e1 is "before" e2
2867 * 0 if e1 "equals" e2
2868 * > 0 if e1 comes after e2
2869 */
2870 int
pool_elem_compare(const pool_elem_t * e1,const pool_elem_t * e2)2871 pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2)
2872 {
2873 pool_value_t val = POOL_VALUE_INITIALIZER;
2874 int64_t sys_id1, sys_id2;
2875
2876 /*
2877 * We may be asked to compare two elements from different classes.
2878 * They are different so return the difference in their classes
2879 */
2880 if (pool_elem_same_class(e1, e2) != PO_TRUE)
2881 return (1);
2882
2883 /*
2884 * If the class is PEC_SYSTEM, always match them
2885 */
2886 if (pool_elem_class(e1) == PEC_SYSTEM)
2887 return (0);
2888
2889 /*
2890 * Compare with sys_id
2891 */
2892 if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2893 assert(!"no sys_id on e1\n");
2894 }
2895 (void) pool_value_get_int64(&val, &sys_id1);
2896 if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) {
2897 assert(!"no sys_id on e2\n");
2898 }
2899 (void) pool_value_get_int64(&val, &sys_id2);
2900 return (sys_id1 - sys_id2);
2901 }
2902
2903 /*
2904 * Return PO_TRUE if the supplied elems are of the same class.
2905 */
2906 int
pool_elem_same_class(const pool_elem_t * e1,const pool_elem_t * e2)2907 pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2)
2908 {
2909 if (pool_elem_class(e1) != pool_elem_class(e2))
2910 return (PO_FALSE);
2911
2912 /*
2913 * Check to make sure the fundamental class of the elements match
2914 */
2915 if (pool_elem_class(e1) == PEC_RES_COMP ||
2916 pool_elem_class(e1) == PEC_RES_AGG)
2917 if (pool_resource_elem_class(e1) !=
2918 pool_resource_elem_class(e2))
2919 return (PO_FALSE);
2920 if (pool_elem_class(e1) == PEC_COMP)
2921 if (pool_component_elem_class(e1) !=
2922 pool_component_elem_class(e2))
2923 return (PO_FALSE);
2924 return (PO_TRUE);
2925 }
2926
2927 /*
2928 * pool_conf_check() checks that the configuration state isn't invalid
2929 * and that the configuration was opened for modification.
2930 */
2931 int
pool_conf_check(const pool_conf_t * conf)2932 pool_conf_check(const pool_conf_t *conf)
2933 {
2934 if (pool_conf_status(conf) == POF_INVALID) {
2935 pool_seterror(POE_BADPARAM);
2936 return (PO_FAIL);
2937 }
2938
2939 if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) {
2940 pool_seterror(POE_BADPARAM);
2941 return (PO_FAIL);
2942 }
2943 return (PO_SUCCESS);
2944 }
2945