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