1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <string.h>
30
31 #include <libintl.h>
32
33 #include "metassist.h"
34 #include "volume_dlist.h"
35 #include "volume_error.h"
36 #include "volume_string.h"
37 #include "volume_output.h"
38
39 #define _LAYOUT_VALIDATE_C
40
41 #include "layout_discovery.h"
42 #include "layout_dlist_util.h"
43 #include "layout_device_cache.h"
44 #include "layout_device_util.h"
45 #include "layout_request.h"
46 #include "layout_slice.h"
47 #include "layout_svm_util.h"
48 #include "layout_validate.h"
49
50 /*
51 * This module contains the majority of the validation code which
52 * layout applies to input requests. The assumption/agreement with
53 * the controller implementation is that requests passed into layout
54 * have undergone syntactic validation and that layout is responsible
55 * for semantic validation.
56 *
57 * The semantic validation that is handled:
58 *
59 * 1. For a toplevel diskset request, validate:
60 *
61 * - the number of disksets is not exceeded
62 * - the number of devices is not exceeded
63 *
64 * (These items are not directly validated within this module,
65 * but it is useful to document that they are handled somewhere).
66 *
67 * 2. For any devconfig_t representing a volume request, verify that:
68 *
69 * - all HSP names are semantically valid. The name should conform
70 * to the HSP naming convention: hspXXX.
71 *
72 * - all concat, stripe, mirror, and volume names refer to
73 * unused, semantically valid metadevice names. Examples of
74 * bad data:
75 *
76 * - a valid volume name that is already in use (d0, d10)
77 *
78 * - a valid volume name that is used two or more times to
79 * refer to new elements in the request.
80 *
81 * - a valid volume name that is out of range (d99877,
82 * d44356) or exceeds the maximum number of possible
83 * volumes given the current SVM configuration.
84 *
85 * - all available and unavailable device specifications refer
86 * to existing controllers, disks, or slices on the system.
87 * Examples of bad data:
88 *
89 * - a valid but non-existent controller (c23, c2)
90 * - a valid but non-existent disk (c0t0d8, c1t0d0)
91 * - a valid slice on a non-existent disk or controller
92 * (c0t0d8s7, c1t0d05)
93 * - a valid slice on an existing disk (c0t0d0s12,
94 * c0t0d0s9)
95 *
96 * - any typed volume request that explicitly specifies components
97 * requires additional validation to detect syntactically valid
98 * expressions that are semantically ambiguous:
99 *
100 * a concat request that:
101 * - specifies size and components is invalid
102 *
103 * a stripe request that:
104 * - specifies size and components is invalid
105 * - specifies mincomp and components but not enough
106 * components is invalid
107 * - specifies maxcomp and components but too many
108 * components is invalid
109 *
110 * a HSP request that:
111 * - specifies components that are not appropriate for
112 * the volumes the HSP serves is invalid (?)
113 *
114 * a stripe, concat or HSP request that:
115 * - specifies a component that was used in a prior
116 * request is invalid
117 * - specifies a component that does not exist in the
118 * diskset is invalid (e.g., c0t0d0s0, but c0t0d0 is
119 * not yet in the diskset)
120 *
121 * a mirror request that:
122 * - specifies nsubs and components but not enough
123 * components is invalid
124 * - specifies components and the components specify
125 * different sizes results in a WARNING since the total
126 * usable capacity of the mirror is determined by the
127 * smallest of its submirrors.
128 * - specifies components and the components specify
129 * components results in a WARNING since the submirrors
130 * may end up with different sizes
131 */
132 static int validate_request_name(
133 devconfig_t *req,
134 component_type_t type);
135
136 static int validate_request_size(
137 devconfig_t *req,
138 component_type_t type);
139
140 static int validate_minimum_size(
141 uint64_t nbytes);
142
143 static uint64_t apply_layout_overhead_factor(
144 uint64_t req_size);
145
146 static int get_space_available_for_request(
147 devconfig_t *request,
148 dlist_t *usable_slices,
149 uint64_t *avail_space);
150
151 static int do_available_space_check(
152 uint64_t req_size,
153 uint64_t raw_avail_space,
154 devconfig_t *request,
155 dlist_t *usable_slices);
156
157 static int validate_request_redundancy_level(
158 devconfig_t *req);
159
160 static int validate_request_npaths(
161 devconfig_t *req);
162
163 static int validate_request_submirrors(
164 devconfig_t *req);
165
166 static int validate_submirror_types(
167 dlist_t *submirrors);
168
169 static int validate_submirror_number(
170 devconfig_t *req,
171 dlist_t *submirrors);
172
173 static int validate_submirror_sizes(
174 devconfig_t *req,
175 dlist_t *submirrors);
176
177 static int validate_submirror_size_and_components(
178 devconfig_t *submir,
179 uint64_t mirror_size,
180 uint64_t *assumed_size,
181 dlist_t **submirs_with_size,
182 dlist_t **submirs_with_comps,
183 dlist_t **submirs_no_size_or_comps);
184
185 static int validate_slice_components(
186 devconfig_t *req,
187 component_type_t type);
188
189 static char *get_device_aliases_string(
190 dm_descriptor_t desc);
191
192 static int validate_device_array(
193 char **array,
194 char *which,
195 dlist_t **list);
196
197 static int add_reserved_name(char *name);
198 static boolean_t is_rsvd_name(char *name);
199 static dlist_t *_rsvd_names = NULL;
200
201 /*
202 * FUNCTION: release_validatation_caches()
203 *
204 * RETURNS: int - 0
205 *
206 * PURPOSE: Cleanup function.
207 *
208 * Purges list of reserved volume names. Should be called
209 * after all layout requests have been processed.
210 */
211 int
release_validation_caches()212 release_validation_caches()
213 {
214 dlist_free_items(_rsvd_names, NULL);
215 _rsvd_names = NULL;
216
217 return (0);
218 }
219
220 /*
221 * FUNCTION: validate_basic_svm_config()
222 *
223 * RETURNS: int - 0 on success
224 * !0 on failure
225 *
226 * PURPOSE: Check to see if the local set metadb replicas have been created.
227 *
228 * Makes sure at least 1 metadb replica exists for the local set.
229 */
230 int
validate_basic_svm_config()231 validate_basic_svm_config()
232 {
233 int error = 0;
234 int nreplicas = 0;
235
236 if ((error = get_n_metadb_replicas(&nreplicas)) == 0) {
237 if (nreplicas == 0) {
238 volume_set_error(
239 gettext("Failed: State database replicas must "
240 "exist before using %s.\n"
241 "See metadb(1M) and %s(1M)."),
242 progname, progname);
243 error = -1;
244 } else {
245 oprintf(OUTPUT_DEBUG,
246 gettext("%d metadb replicas found.\n"),
247 nreplicas);
248 }
249 }
250
251 return (error);
252 }
253
254 /*
255 * FUNCTION: validate_request_sizes(devconfig_t *req)
256 *
257 * INPUT: req: a devconfig_t pointer to the toplevel request
258 *
259 * RETURNS: int - 0 on success
260 * !0 on failure
261 *
262 * PURPOSE: Check to see if the any of the individual volume request
263 * sizes exceeds the raw available space on the system or
264 * the space available to that specific request.
265 *
266 * Check to see if the total space for all requests exceeds
267 * the raw available space.
268 *
269 * If any check fails, stop checking, emit an error and
270 * return -1.
271 *
272 * Note: this function must be called after the slice
273 * usages have been determined and the list of usable
274 * slices has been generated.
275 */
276 int
validate_request_sizes(devconfig_t * request)277 validate_request_sizes(
278 devconfig_t *request)
279 {
280 int error = 0;
281 dlist_t *usable_slices;
282 dlist_t *iter;
283 char bad_rqst_info[BUFSIZ];
284 uint64_t bad_rqst_space = 0;
285 uint64_t total_rqst_space = 0;
286 uint64_t raw_space = 0;
287
288 (void) get_usable_slices(&usable_slices);
289
290 /*
291 * calculate raw available space: space on slices that are
292 * "available" based on the diskset defaults or global defaults
293 */
294 if ((error = get_space_available_for_request(request,
295 usable_slices, &raw_space)) != 0) {
296 return (error);
297 }
298
299 if (raw_space == 0) {
300 volume_set_error(
301 gettext("Failed: there is no available space.\n"));
302 return (-1);
303 }
304
305 /* deduct sizes of reserved components */
306 (void) get_reserved_slices(&iter);
307 for (; (iter != NULL) && (raw_space != 0) && (error == 0);
308 iter = iter->next) {
309 dm_descriptor_t slice = (uintptr_t)iter->obj;
310 uint64_t nbytes;
311 if ((error = slice_get_size(slice, &nbytes)) == 0) {
312 if (raw_space >= nbytes) {
313 raw_space -= nbytes;
314 } else {
315 raw_space = 0;
316 }
317 }
318 }
319
320 /*
321 * check each volume request's size against raw_space,
322 * if that looks ok, do a closer check with the request's
323 * available devices
324 */
325 iter = devconfig_get_components(request);
326 for (; (iter != NULL) && (error == 0); iter = iter->next) {
327
328 devconfig_t *req = (devconfig_t *)iter->obj;
329 component_type_t type = TYPE_UNKNOWN;
330 char *typestr = NULL;
331 uint64_t nbytes = 0;
332
333 (void) devconfig_get_type(req, &type);
334 if (type == TYPE_HSP) {
335 continue;
336 }
337
338 typestr = devconfig_type_to_str(type);
339
340 if ((error = devconfig_get_size(req, &nbytes)) == 0) {
341
342 /* check specified size */
343
344 if (type == TYPE_CONCAT || type == TYPE_STRIPE) {
345 if ((error = do_available_space_check(
346 apply_layout_overhead_factor(nbytes),
347 raw_space, req, usable_slices)) == 0) {
348 total_rqst_space += nbytes;
349 } else if (error == ENOSPC || error == E2BIG) {
350 (void) snprintf(bad_rqst_info, BUFSIZ-1,
351 "%s", typestr);
352 bad_rqst_space = nbytes;
353 }
354 } else if (type == TYPE_MIRROR) {
355 uint16_t nsubs = 0;
356 if ((error = get_mirror_nsubs(req, &nsubs)) == 0) {
357 if ((error = do_available_space_check(
358 apply_layout_overhead_factor(nbytes * nsubs),
359 raw_space, req, usable_slices)) == 0) {
360 total_rqst_space += (nsubs * nbytes);
361 } else {
362 (void) snprintf(bad_rqst_info, BUFSIZ-1,
363 gettext("%s with %d submirrors"),
364 typestr, nsubs);
365 bad_rqst_space = nbytes;
366 }
367 }
368 }
369
370 } else if ((error == ERR_ATTR_UNSET) && (type == TYPE_MIRROR)) {
371
372 /* mirror specified no size: find submirror that does */
373
374 dlist_t *subs = devconfig_get_components(req);
375
376 error = 0;
377 if (subs != NULL) {
378 dlist_t *iter2;
379 int nsubs = dlist_length(subs);
380 for (iter2 = subs;
381 (iter2 != NULL) && (error == 0);
382 iter2 = iter2->next) {
383 devconfig_t *sub = (devconfig_t *)iter2->obj;
384 if ((error = devconfig_get_size(sub, &nbytes)) == 0) {
385 if ((error = do_available_space_check(
386 apply_layout_overhead_factor(nbytes * nsubs),
387 raw_space, req, usable_slices)) == 0) {
388 total_rqst_space += (nbytes * nsubs);
389 } else {
390 (void) snprintf(bad_rqst_info, BUFSIZ-1,
391 gettext("%s with %d submirrors"),
392 typestr, nsubs);
393 bad_rqst_space = nbytes;
394 }
395 break;
396 } else if (error == ERR_ATTR_UNSET) {
397 error = 0;
398 }
399 }
400 }
401 }
402 }
403
404 /*
405 * do_available_space_check may return ENOSPC or E2BIG
406 */
407 if (error == ENOSPC) {
408 char *sizestr = NULL;
409 (void) bytes_to_sizestr(bad_rqst_space,
410 &sizestr, universal_units, B_FALSE);
411
412 volume_set_error(
413 gettext("Failed: the request for a %s %s "
414 "exceeds the available space.\n"),
415 sizestr, bad_rqst_info);
416
417 free(sizestr);
418 error = -1;
419
420 } else if (error == E2BIG) {
421 char *sizestr = NULL;
422 (void) bytes_to_sizestr(bad_rqst_space,
423 &sizestr, universal_units, B_FALSE);
424
425 volume_set_error(
426 gettext("Failed: the request for a %s %s "
427 "exceeds the usable space on the device(s) "
428 "specified as available.\n"),
429 sizestr, bad_rqst_info);
430
431 free(sizestr);
432 error = -1;
433
434 } else if (apply_layout_overhead_factor(total_rqst_space) > raw_space) {
435 char *sizestr = NULL;
436 (void) bytes_to_sizestr(
437 total_rqst_space, &sizestr, universal_units, B_FALSE);
438
439 volume_set_error(
440 gettext("Failed: the total space requested for the "
441 "volumes (about %s) exceeds the available "
442 "space.\n"),
443 sizestr);
444
445 free(sizestr);
446 error = -1;
447 }
448
449 return (error);
450 }
451
452 /*
453 * FUNCTION: apply_layout_overhead_factor(uint64_t req_size)
454 *
455 * INPUT: req_size: a requested volume size
456 *
457 * RETURNS: the requested volume size with an overhead factor applied
458 *
459 * PURPOSE: The input size size is inflated by a "fudge" factor
460 * to account for some of the expected overhead required for
461 * volumes such as block and cylinder boundary alignment.
462 */
463 static uint64_t
apply_layout_overhead_factor(uint64_t req_size)464 apply_layout_overhead_factor(
465 uint64_t req_size)
466 {
467 double overhead = 1.15;
468 double d_size = req_size;
469 uint64_t result = (uint64_t)(d_size * overhead);
470
471 return (result);
472 }
473
474 /*
475 * FUNCTION: get_space_available_for_request(devconfig_t *request,
476 * dlist_t *usable_slices, uint64_t *avail_space)
477 *
478 * INPUT: request: a devconfig_t volume request
479 * usable_slices: a list of usable slice dm_descriptor_t handles
480 *
481 * OUTPUT: avail_space: the total space on slices in the usable_slice
482 * list that is available for use by the input
483 * request.
484 *
485 * RETURNS: int - 0 on success
486 * !0 on failure
487 *
488 * PURPOSE: Iterate the input list of usable slices, determine which are
489 * available to the input request and accumulate the total space
490 * they represent.
491 *
492 * The slices in the usable_slice list are those with no apparent
493 * usage detected. The slice_is_available() check determines
494 * whether the slice passes the available/unavailable device
495 * specification associated with the input request.
496 */
497 static int
get_space_available_for_request(devconfig_t * request,dlist_t * usable_slices,uint64_t * avail_space)498 get_space_available_for_request(
499 devconfig_t *request,
500 dlist_t *usable_slices,
501 uint64_t *avail_space)
502 {
503 dlist_t *iter;
504 int error = 0;
505
506 *avail_space = 0;
507
508 for (iter = usable_slices;
509 (iter != NULL) && (error == 0);
510 iter = iter->next) {
511 dm_descriptor_t slice = (uintptr_t)iter->obj;
512 char *sname;
513 uint64_t nbytes;
514 boolean_t avail = B_FALSE;
515 if ((error = get_display_name(slice, &sname)) == 0) {
516 if ((error = slice_is_available(sname, request, &avail)) == 0) {
517 if (avail == B_TRUE) {
518 if ((error = slice_get_size(slice, &nbytes)) == 0) {
519 *avail_space += nbytes;
520 }
521 }
522 }
523 }
524 }
525
526 return (error);
527 }
528
529 /*
530 * FUNCTION: do_available_space_check(uint64_t req_size,
531 * uint64_t raw_avail_space, devconfig_t *request,
532 * dlist_t *usable_slices)
533 *
534 * INPUT: req_size: the requested size of a volume
535 * raw_avail_space:the total available space for all volumes
536 * request: a devconfig_t volume request
537 * usable_slices: a list of usable slice dm_descriptor_t handles
538 *
539 * RETURNS: int - ENOSPC if the requested size exceeds the raw
540 * available space.
541 *
542 * E2BIG if the requested size exceeds the space
543 * available specifically to the input request,
544 * taking into account its available and
545 * unavailable device specifications.
546 *
547 * 0 otherwise
548 *
549 * PURPOSE: Check the input request size against different forms of
550 * available space.
551 *
552 * If the requested size is less than the raw_avail_space, do the
553 * more expensive check against the space specifically available
554 * to the input request.
555 */
556 static int
do_available_space_check(uint64_t req_size,uint64_t raw_avail_space,devconfig_t * request,dlist_t * usable_slices)557 do_available_space_check(
558 uint64_t req_size,
559 uint64_t raw_avail_space,
560 devconfig_t *request,
561 dlist_t *usable_slices)
562 {
563 int error = 0;
564
565 if (req_size > raw_avail_space) {
566 error = ENOSPC;
567 } else {
568 uint64_t avail_space = 0;
569 if ((error = get_space_available_for_request(request,
570 usable_slices, &avail_space)) == 0) {
571 if (req_size > avail_space) {
572 error = E2BIG;
573 }
574 }
575 }
576
577 return (error);
578 }
579
580 /*
581 * FUNCTION: validate_request(devconfig_t *req)
582 *
583 * INPUT: req - a devconfig_t representing a volume layout request.
584 *
585 * RETURNS: int - 0 if the request passes validation
586 * !0 otherwise.
587 *
588 * PURPOSE: Main entry point into the layout request semantic
589 * validatation.
590 *
591 * Determines the type of volume requested and invokes the
592 * appropriate validation functions.
593 */
594 int
validate_request(devconfig_t * req)595 validate_request(
596 devconfig_t *req)
597 {
598 int error = 0;
599 component_type_t type = TYPE_UNKNOWN;
600
601 ((error = validate_request_avail_unavail(req)) != 0) ||
602 (error = devconfig_get_type(req, &type));
603 if (error != 0) {
604 return (error);
605 }
606
607 if (type == TYPE_MIRROR) {
608
609 ((error = validate_request_name(req, type)) != 0) ||
610 (error = validate_request_size(req, type)) ||
611 (error = validate_request_submirrors(req));
612
613 } else if (type == TYPE_CONCAT || type == TYPE_STRIPE) {
614
615 ((error = validate_request_name(req, type)) != 0) ||
616 (error = validate_request_size(req, type)) ||
617 (error = validate_slice_components(req, type));
618
619 } else if (type == TYPE_HSP) {
620
621 ((error = validate_request_name(req, type)) != 0) ||
622 (error = validate_slice_components(req, type));
623
624 } else if (type == TYPE_VOLUME) {
625
626 ((error = validate_request_name(req, type)) != 0) ||
627 (error = validate_request_redundancy_level(req)) ||
628 (error = validate_request_npaths(req));
629
630 }
631
632 return (error);
633 }
634
635 /*
636 * FUNCTION: validate_reserved_slices()
637 *
638 * RETURNS: int - 0 if all reserved slices are usable in
639 * new devices.
640 * !0 otherwise.
641 *
642 * PURPOSE: Ensures that each reserved slice is actually usable
643 * as a volume component.
644 *
645 * Retrieves list of reserved slices and list of usable
646 * slices. Ensures that each reserved slice is in the
647 * usable list, generates an error if it is not.
648 *
649 * This is broken out as a separate function because
650 * initial validation is using the lists of all known
651 * devices. Device "usability" is only determined after
652 * the initial validation has completed successfully.
653 */
654 int
validate_reserved_slices()655 validate_reserved_slices()
656 {
657 dlist_t *reserved_slices;
658 dlist_t *usable_slices;
659 int error = 0;
660
661 ((error = get_reserved_slices(&reserved_slices)) != 0) ||
662 (error = get_usable_slices(&usable_slices));
663 if (error == 0) {
664
665 dlist_t *iter;
666 for (iter = reserved_slices;
667 (iter != NULL) && (error == 0);
668 iter = iter->next) {
669
670 if (dlist_contains(usable_slices, iter->obj,
671 compare_descriptor_names) != B_TRUE) {
672
673 dm_descriptor_t slice = (uintptr_t)iter->obj;
674 char *name = NULL;
675
676 error = get_display_name(slice, &name);
677 if (error == 0) {
678 char *aliases = get_device_aliases_string(slice);
679 if (aliases[0] != NULL) {
680 volume_set_error(
681 gettext("A requested volume component "
682 "is currently in use: \"%s\" "
683 "(aliases: %s).\n"),
684 name, aliases);
685 } else {
686 volume_set_error(
687 gettext("A requested volume component "
688 "is currently in use: \"%s\"\n"),
689 name);
690 }
691 error = -1;
692 }
693 }
694 }
695 }
696
697 return (error);
698 }
699
700 /*
701 * FUNCTION: validate_request_avail_unavail(devconfig_t *req)
702 *
703 * INPUT: req - a devconfig_t representing a volume layout request.
704 *
705 * RETURNS: int - 0 if the request passes validation
706 * !0 otherwise.
707 *
708 * PURPOSE: validation function for a request's lists of available
709 * and unavailable devices.
710 *
711 * validates that both lists contain names of known devices.
712 *
713 * validates that the same name does not appear in both lists.
714 */
715 int
validate_request_avail_unavail(devconfig_t * req)716 validate_request_avail_unavail(
717 devconfig_t *req)
718 {
719 dlist_t *avail = NULL;
720 dlist_t *unavail = NULL;
721 int error = 0;
722
723 /* check that each array contains valid devices */
724 ((error = validate_device_array(devconfig_get_available(req),
725 gettext("available"), &avail)) != 0) ||
726 (error = validate_device_array(devconfig_get_unavailable(req),
727 gettext("unavailable"), &unavail));
728
729 /* check that the arrays don't both contain the same device(s) */
730 if (error == 0) {
731 dlist_t *iter;
732 for (iter = avail; iter != NULL; iter = iter->next) {
733 if (dlist_contains(unavail, iter->obj,
734 compare_descriptor_names) == B_TRUE) {
735 char *name;
736 char *aliases =
737 get_device_aliases_string((uintptr_t)iter->obj);
738
739 (void) get_display_name((uintptr_t)iter->obj, &name);
740 if (aliases[0] != NULL) {
741 volume_set_error(
742 gettext("\"%s\" specified as both available "
743 "and unavailable.\n"
744 "It has these aliases: %s\n"),
745 name, aliases);
746 } else {
747 volume_set_error(
748 gettext("\"%s\" specified as both available "
749 "and unavailable.\n"),
750 name);
751 }
752 error = -1;
753 break;
754 }
755 }
756 }
757
758 dlist_free_items(avail, NULL);
759 dlist_free_items(unavail, NULL);
760
761 return (error);
762 }
763
764 /*
765 * FUNCTION: validate_device_array(char **array, char *which, dlist_t **list)
766 *
767 * INPUT: array - an array of char * device names
768 * which - either "available" or "unavailable"
769 * indicating the array name to use in
770 * error strings.
771 * OUTPUT: list - a list of device descriptors corresponding the each
772 * of the input names.
773 *
774 * RETURNS: int - 0 if the array passes validation
775 * !0 otherwise.
776 *
777 * PURPOSE: validation function for a request's list of available
778 * or unavailable devices.
779 *
780 * DID names are converted to CTD names.
781 *
782 * The CTD name must be of an available slice, disk or
783 * HBA, or a known used slice, disk or HBA that was
784 * discovered when the system's devices were probed.
785 *
786 * Any other name is assumed to refer to a device not
787 * attached to the system and results in a validation
788 * failure.
789 *
790 * Descriptors for validated devices are added to the input
791 * list.
792 */
793 int
validate_device_array(char ** array,char * which,dlist_t ** list)794 validate_device_array(
795 char **array,
796 char *which,
797 dlist_t **list)
798 {
799 int error = 0;
800 int i = 0;
801
802 if (array == NULL || *array == NULL) {
803 return (0);
804 }
805
806 for (i = 0; (array[i] != NULL) && (error == 0); i++) {
807
808 dm_descriptor_t slice = (dm_descriptor_t)0;
809 dm_descriptor_t disk = (dm_descriptor_t)0;
810 dm_descriptor_t hba = (dm_descriptor_t)0;
811 char *name = array[i];
812
813 /* name must correspond to a known HBA, disk, or slice */
814 if ((error = hba_get_by_name(name, &hba)) == 0) {
815 if (hba == (dm_descriptor_t)0) {
816 if ((error = disk_get_by_name(name, &disk)) == 0) {
817 if (disk == (dm_descriptor_t)0) {
818 error = slice_get_by_name(name, &slice);
819 }
820 }
821 }
822 }
823
824 if (error != 0) {
825 break;
826 }
827
828 /* 0 sized slices cannot be used as-is, pretend non-existant */
829 if (slice != (dm_descriptor_t)0) {
830 uint64_t size = 0;
831 if ((error = slice_get_size(slice, &size)) == 0) {
832 if (size == 0) {
833 slice = (dm_descriptor_t)0;
834 }
835 }
836 }
837
838 oprintf(OUTPUT_DEBUG,
839 gettext(" validate %s (%s): s=%llu, d=%llu, c=%llu\n"),
840 which, array[i], slice, disk, hba);
841
842 if ((error == 0) && ((slice != 0) || (disk != 0) || (hba != 0))) {
843
844 /* name represents an individual "device", add it to the list */
845 dm_descriptor_t desc = (dm_descriptor_t)0;
846 dlist_t *item;
847
848 if (slice != 0) {
849 desc = slice;
850 } else if (disk != 0) {
851 desc = disk;
852 } else if (hba != 0) {
853 desc = hba;
854 }
855
856 if ((item = dlist_new_item((void *)(uintptr_t)desc)) == NULL) {
857 error = ENOMEM;
858 } else {
859 *list = dlist_append(item, *list, AT_HEAD);
860 }
861
862 } else if (is_ctd_target_name(name) == B_TRUE) {
863
864 /* expand target to all of its disks */
865 dlist_t *disks = NULL;
866 if ((error = get_disks_for_target(name, &disks)) == 0) {
867 if ((disks == NULL) || (dlist_length(disks) == 0)) {
868 volume_set_error(
869 gettext("nonexistent device specified "
870 "as %s: \"%s\"."),
871 which, array[i]);
872 error = -1;
873 } else {
874 dlist_t *iter;
875 for (iter = disks;
876 (iter != NULL) && (error == 0);
877 iter = iter->next) {
878
879 dlist_t *item;
880 if ((item = dlist_new_item(iter->obj)) == NULL) {
881 error = ENOMEM;
882 } else {
883 *list = dlist_append(item, *list, AT_HEAD);
884 }
885 }
886 }
887 }
888
889 } else {
890
891 /* not a slice, disk, target or ctrl */
892 volume_set_error(
893 gettext("nonexistent device specified "
894 "as %s: \"%s\"."),
895 which, array[i]);
896 error = -1;
897 }
898 }
899
900 return (error);
901 }
902
903 /*
904 * FUNCTION: validate_request_name(devconfig_t *req, component_type_t type)
905 *
906 * INPUT: req - a devconfig_t volume request
907 * type - the volume type being requested
908 *
909 * SIDEEFFECT: if the request specifies a name and the name is valid and
910 * not currently in use an attempt is made to reserve it.
911 * if the name has already been reserved by a prior volume
912 * request, validation fails.
913 *
914 * RETURNS: int - 0 if the requested name passes validation
915 * (or there is no name request)
916 * !0 otherwise.
917 *
918 * PURPOSE: Validation function for a request's volume name.
919 *
920 * a HSP name must be valid and reservable.
921 *
922 * a volume name must be valid and reservable.
923 */
924 static int
validate_request_name(devconfig_t * req,component_type_t type)925 validate_request_name(
926 devconfig_t *req,
927 component_type_t type)
928 {
929 char *name = NULL;
930 char *typestr = devconfig_type_to_str(type);
931 int error = 0;
932
933 if ((error = devconfig_get_name(req, &name)) != 0) {
934 if (error != ERR_ATTR_UNSET) {
935 volume_set_error(
936 gettext("error getting requested name.\n"));
937 return (error);
938 }
939 /* no name specified */
940 return (0);
941 }
942
943 if (type == TYPE_HSP) {
944 if (is_hsp_name_valid(name) == 0) {
945 volume_set_error(
946 gettext("requested %s name \"%s\" is not valid.\n"),
947 typestr, name);
948 error = -1;
949 } else if (reserve_hsp_name(name) != 0) {
950 if (is_rsvd_name(name) == B_TRUE) {
951 volume_set_error(
952 gettext("requested %s name \"%s\" used "
953 "previously in this request.\n"),
954 typestr, name);
955 } else {
956 volume_set_error(
957 gettext("requested %s name \"%s\" is not "
958 "available.\n"),
959 typestr, name);
960 }
961 error = -1;
962 } else {
963 error = add_reserved_name(name);
964 }
965 } else {
966 if (is_volume_name_valid(name) == 0) {
967 volume_set_error(
968 gettext("requested %s name \"%s\" is not valid.\n"),
969 typestr, name);
970 error = -1;
971 } else if (is_volume_name_in_range(name) != B_TRUE) {
972 int max = 0;
973 (void) get_max_number_of_devices(&max);
974 volume_set_error(
975 gettext("requested %s name \"%s\" is not legal.\n"
976 "Use a name less than d%d.\n"),
977 typestr, name, max);
978 error = -1;
979 } else if (reserve_volume_name(name) != 0) {
980 if (is_rsvd_name(name) == B_TRUE) {
981 volume_set_error(
982 gettext("requested %s name \"%s\" used "
983 "previously in this request.\n"),
984 typestr, name);
985 } else {
986 volume_set_error(
987 gettext("requested %s name \"%s\" is not "
988 "available, a volume with that name "
989 "already exists.\n"),
990 typestr, name);
991 }
992 error = -1;
993 } else {
994 error = add_reserved_name(name);
995 }
996 }
997
998 return (error);
999 }
1000
1001 /*
1002 * FUNCTION: add_reserved_name(char *name)
1003 *
1004 * INPUT: name - a char * volume name
1005 *
1006 * RETURNS: int - 0 on success
1007 * !0 otherwise.
1008 *
1009 * PURPOSE: Helper which remembers specfically requested names
1010 * in a private list to ensure that the same name isn't
1011 * requested more than once.
1012 */
1013 static int
add_reserved_name(char * name)1014 add_reserved_name(
1015 char *name)
1016 {
1017 dlist_t *item = NULL;
1018
1019 if ((item = dlist_new_item(name)) == NULL) {
1020 return (ENOMEM);
1021 }
1022
1023 _rsvd_names = dlist_append(item, _rsvd_names, AT_TAIL);
1024
1025 return (0);
1026 }
1027
1028 /*
1029 * FUNCTION: is_rsvd_name(char *name)
1030 *
1031 * INPUT: name - a char * volume name
1032 *
1033 * RETURNS: boolean_t - B_TRUE if the requested name is currently
1034 * reserved, B_FALSE otherwise.
1035 *
1036 * PURPOSE: Helper which checks to see if the input volume
1037 * name was previously reserved.
1038 */
1039 static boolean_t
is_rsvd_name(char * name)1040 is_rsvd_name(
1041 char *name)
1042 {
1043 dlist_t *iter = NULL;
1044
1045 for (iter = _rsvd_names; iter != NULL; iter = iter->next) {
1046 if ((string_case_compare(name, (char *)iter->obj)) == 0) {
1047 return (B_TRUE);
1048 }
1049 }
1050
1051 return (B_FALSE);
1052 }
1053
1054 /*
1055 * FUNCTION: validate_request_size(devconfig_t *req, component_type_t type)
1056 *
1057 * INPUT: req - a devconfig_t volume request
1058 * type - the volume type being requested
1059 *
1060 * RETURNS: int - 0 if the requested size passes validation
1061 * (or there is no size request)
1062 * !0 otherwise.
1063 *
1064 * PURPOSE: Validation function for a request's volume size.
1065 *
1066 * a HSP request can have no size.
1067 *
1068 * a concat, stripe or mirror request may have a size.
1069 * if size is specified, the request cannot also specify
1070 * components. Conversely, if the request does not specify
1071 * a size, it must specify components.
1072 */
1073 static int
validate_request_size(devconfig_t * req,component_type_t type)1074 validate_request_size(
1075 devconfig_t *req,
1076 component_type_t type)
1077 {
1078 uint64_t nbytes = 0;
1079 int error = 0;
1080
1081 if (type == TYPE_HSP) {
1082 return (0);
1083 }
1084
1085 if ((error = devconfig_get_size(req, &nbytes)) != 0) {
1086 if (error == ERR_ATTR_UNSET) {
1087 /* nbytes not specified, request must have subcomponents */
1088 dlist_t *list = devconfig_get_components(req);
1089 if (list != NULL && dlist_length(list) > 0) {
1090 error = 0;
1091 } else {
1092 volume_set_error(
1093 gettext("%s request specifies no size or "
1094 "subcomponents.\n"),
1095 devconfig_type_to_str(type));
1096 error = -1;
1097 }
1098 }
1099 return (error);
1100 }
1101
1102 return (error);
1103 }
1104
1105 /*
1106 * FUNCTION: validate_minimum_size(uint64_t nbytes)
1107 *
1108 * INPUT: nbytes - requested volume size in bytes
1109 *
1110 * RETURNS: int - 0 if the requested size passes validation
1111 * (or there is no size request)
1112 * !0 otherwise.
1113 *
1114 * PURPOSE: Validation function for a request's volume size.
1115 *
1116 * an error is issued if the requested size <= 512K.
1117 */
1118 static int
validate_minimum_size(uint64_t nbytes)1119 validate_minimum_size(
1120 uint64_t nbytes)
1121 {
1122 static uint64_t min = (512 * 1024) - 1;
1123 int error = 0;
1124
1125 if (nbytes <= min) {
1126 char *sizestr = NULL;
1127 char *minstr = NULL;
1128
1129 (void) bytes_to_sizestr(
1130 nbytes, &sizestr, universal_units, B_FALSE);
1131 (void) bytes_to_sizestr(
1132 min, &minstr, universal_units, B_FALSE);
1133
1134 volume_set_error(
1135 gettext("requested volume size (%s) must be "
1136 "greater than %s.\n"),
1137 sizestr, minstr);
1138
1139 free(sizestr);
1140 free(minstr);
1141
1142 error = -1;
1143 }
1144
1145 return (error);
1146 }
1147
1148 /*
1149 * FUNCTION: validate_request_redundancy_level(devconfig_t *req)
1150 *
1151 * INPUT: req - a devconfig_t volume request
1152 *
1153 * RETURNS: int - 0 if the requested redundancy level
1154 * passes validation (or none was requested)
1155 * !0 otherwise.
1156 *
1157 * PURPOSE: Validation function for a redundant volume request's
1158 * redundancy level.
1159 *
1160 * If the request specifies redundancy, the value must be
1161 * between 1 and 4.
1162 */
1163 static int
validate_request_redundancy_level(devconfig_t * req)1164 validate_request_redundancy_level(
1165 devconfig_t *req)
1166 {
1167 uint16_t rlevel = 0;
1168 int error = 0;
1169
1170 if ((error = devconfig_get_volume_redundancy_level(
1171 req, &rlevel)) != 0) {
1172 if (error == ERR_ATTR_UNSET) {
1173 error = 0;
1174 }
1175 return (error);
1176 }
1177
1178 if (rlevel > 4) {
1179 volume_set_error(gettext(
1180 "requested redundancy level must be between 0 and 4.\n"));
1181 error = -1;
1182 }
1183
1184 return (error);
1185 }
1186
1187 /*
1188 * FUNCTION: validate_request_npaths(devconfig_t *req)
1189 *
1190 * INPUT: req - a devconfig_t volume request
1191 *
1192 * RETURNS: int - 0 if the requested # of redundant data paths
1193 * passes validation (or none was requested)
1194 * !0 otherwise.
1195 *
1196 * PURPOSE: Validation function for a volume request's number of
1197 * redundant data paths. This value controls the number
1198 * of independent data paths slices components selected
1199 * for the volume should have.
1200 *
1201 * If the request specifies npaths, the value must be
1202 * between 1 and 4 (4 is an arbitrary upper limit, there
1203 * is no known physical limit).
1204 */
1205 static int
validate_request_npaths(devconfig_t * req)1206 validate_request_npaths(
1207 devconfig_t *req)
1208 {
1209 uint16_t npaths = 0;
1210 uint16_t minpaths = 1;
1211 uint16_t maxpaths = 4;
1212
1213 int error = 0;
1214
1215 if ((error = devconfig_get_volume_npaths(req, &npaths)) != 0) {
1216 if (error == ERR_ATTR_UNSET) {
1217 error = 0;
1218 }
1219 return (error);
1220 }
1221
1222 if (npaths < minpaths || npaths > maxpaths) {
1223 volume_set_error(
1224 gettext("requested number of redundant paths must be "
1225 "between %d and %d.\n"), minpaths, maxpaths);
1226 error = -1;
1227 }
1228
1229
1230 if ((npaths > 1) && (is_mpxio_enabled() != B_TRUE)) {
1231 volume_set_error(
1232 gettext("requested number of redundant paths (%d) cannot "
1233 "be provided, MPXIO is not enabled on this "
1234 "system."),
1235 npaths);
1236 error = -1;
1237 }
1238
1239 return (error);
1240 }
1241
1242 /*
1243 * FUNCTION: validate_request_submirrors(devconfig_t *req)
1244 *
1245 * INPUT: req - a devconfig_t volume request
1246 *
1247 * RETURNS: int - 0 if the requested mirror's submirrors
1248 * pass validation
1249 * !0 otherwise.
1250 *
1251 * PURPOSE: Validation function for a mirror volume request's
1252 * explicitly specified submirror components.
1253 *
1254 * Items to check:
1255 * a. submirror types
1256 * b. submirror number
1257 * c. submirror sizes
1258 */
1259 static int
validate_request_submirrors(devconfig_t * req)1260 validate_request_submirrors(
1261 devconfig_t *req)
1262 {
1263 dlist_t *submirrors = NULL;
1264 int error = 0;
1265
1266 submirrors = devconfig_get_components(req);
1267
1268 ((error = validate_submirror_types(submirrors)) != 0) ||
1269 (error = validate_submirror_number(req, submirrors)) ||
1270 (error = validate_submirror_sizes(req, submirrors));
1271
1272 return (error);
1273 }
1274
1275 /*
1276 * FUNCTION: validate_submirror_types(dlist_t *subs)
1277 *
1278 * INPUT: subs - a list of submirror requests
1279 *
1280 * RETURNS: int - 0 if the requested submirrors
1281 * pass validation
1282 * !0 otherwise.
1283 *
1284 * PURPOSE: Validation function for a mirror volume request's
1285 * explicitly specified submirror components.
1286 *
1287 * Checks that each requested submirror request
1288 * is for a concat or stripe.
1289 */
1290 static int
validate_submirror_types(dlist_t * submirrors)1291 validate_submirror_types(
1292 dlist_t *submirrors)
1293 {
1294 dlist_t *iter;
1295 int error = 0;
1296
1297 /* specified submirrors must be stripes or concats */
1298 for (iter = submirrors;
1299 (iter != NULL) && (error == 0);
1300 iter = iter->next) {
1301
1302 devconfig_t *submir = (devconfig_t *)iter->obj;
1303 component_type_t submirtype = TYPE_UNKNOWN;
1304
1305 if ((error = devconfig_get_type(submir, &submirtype)) != 0) {
1306 volume_set_error(
1307 gettext("failed to get requested component type.\n"));
1308 break;
1309 }
1310
1311 if (submirtype != TYPE_CONCAT && submirtype != TYPE_STRIPE) {
1312 volume_set_error(
1313 gettext("requested submirror type \"%s\" "
1314 "is not valid.\n"),
1315 devconfig_type_to_str(submirtype));
1316 error = -1;
1317 break;
1318 }
1319 }
1320
1321 return (error);
1322 }
1323
1324 /*
1325 * FUNCTION: validate_submirror_number(devconfig_t *req, dlist_t *subs)
1326 *
1327 * INPUT: req - the mirror request
1328 * subs - the list of requested submirrors
1329 *
1330 * RETURNS: int - 0 if the requested submirrors
1331 * pass validation
1332 * !0 otherwise.
1333 *
1334 * PURPOSE: Validation function for a mirror volume request's
1335 * explicitly specified submirror components.
1336 *
1337 * Checks that the number of submirror components
1338 * that have been specified matches the number of
1339 * submirrors specified.
1340 */
1341 static int
validate_submirror_number(devconfig_t * req,dlist_t * submirrors)1342 validate_submirror_number(
1343 devconfig_t *req,
1344 dlist_t *submirrors)
1345 {
1346 uint16_t nsubs = 0;
1347 int error = 0;
1348
1349 if ((error = devconfig_get_mirror_nsubs(req, &nsubs)) != 0) {
1350 if (error == ERR_ATTR_UNSET) {
1351 /* not specified */
1352 error = 0;
1353 }
1354 } else if ((submirrors != NULL) &&
1355 (dlist_length(submirrors) != nsubs)) {
1356 volume_set_error(
1357 gettext("the requested number of submirrors (%d) differs "
1358 "from the number of specified submirrors (%d).\n"),
1359 nsubs, dlist_length(submirrors));
1360 error = -1;
1361 }
1362
1363 return (error);
1364 }
1365
1366 /*
1367 * FUNCTION: validate_submirror_sizes(devconfig_t *req,
1368 * dlist_t *submirrors)
1369 *
1370 * INPUT: req - the mirror request
1371 * submirrors - the list of requested submirrors
1372 *
1373 * RETURNS: int - 0 if the requested submirrors
1374 * pass validation
1375 * !0 otherwise.
1376 *
1377 * PURPOSE: Validation function for a mirror volume request's
1378 * explicitly specified size. Assumes that the mirror's size
1379 * has been validated by validate_request_size().
1380 *
1381 * Compares explicitly requested mirror size against specified
1382 * component sizes and checks:
1383 *
1384 * - any submirror request that specifies both size and
1385 * components is invalid
1386 * - any submirror request specifying a size different
1387 * than that explictly requested for the mirror is
1388 * invalid
1389 * - a submirror request specifying a size < 512K is invalid.
1390 *
1391 * Other validation/warnings:
1392 *
1393 * - submirrors that specify components may end up with
1394 * usable capacity that differs from what was specified
1395 * for the mirror.
1396 *
1397 * - submirrors which specify neither size nor components are
1398 * assumed to be the size requested for the mirror. If the
1399 * mirror size is not specified, the first explicit size for
1400 * a submirror is assumed as the size for the mirror.
1401 */
1402 static int
validate_submirror_sizes(devconfig_t * req,dlist_t * submirrors)1403 validate_submirror_sizes(
1404 devconfig_t *req,
1405 dlist_t *submirrors)
1406 {
1407 dlist_t *submirs_with_size = NULL;
1408 dlist_t *submirs_with_comps = NULL;
1409 dlist_t *submirs_with_nothing = NULL;
1410
1411 dlist_t *iter = NULL;
1412 uint64_t mirror_size = 0;
1413 uint64_t assumed_size = 0;
1414 int error = 0;
1415
1416 if (submirrors == NULL || dlist_length(submirrors) == 0) {
1417 return (0);
1418 }
1419
1420 if ((error = devconfig_get_size(req, &mirror_size)) != 0) {
1421 if (error == ERR_ATTR_UNSET) {
1422 error = 0;
1423 } else {
1424 return (error);
1425 }
1426 }
1427
1428 /*
1429 * check size and component for each submirror,
1430 * collect those that specify size, components or neither
1431 * into separate lists.
1432 */
1433 for (iter = submirrors;
1434 (iter != NULL) && (error == 0);
1435 iter = iter->next) {
1436
1437 devconfig_t *submir = (devconfig_t *)iter->obj;
1438
1439 error = validate_submirror_size_and_components(submir,
1440 mirror_size, &assumed_size, &submirs_with_size,
1441 &submirs_with_comps, &submirs_with_nothing);
1442
1443 }
1444
1445 if (error == 0) {
1446
1447 int n_size = dlist_length(submirs_with_size);
1448 int n_comp = dlist_length(submirs_with_comps);
1449 int n_none = dlist_length(submirs_with_nothing);
1450
1451 if ((n_size != 0) && (n_comp != 0)) {
1452 /* some submirrors specified size, some components */
1453 oprintf(OUTPUT_TERSE,
1454 gettext(" *** warning: %d submirrors are specified "
1455 "by size, %d specified by components.\n"
1456 " The resulting mirror capacity will be "
1457 "that of the smallest submirror.\n"),
1458 n_size, n_comp);
1459 }
1460
1461 if (n_none != 0) {
1462 if (assumed_size != 0) {
1463 /* some submirrors specified neither size or components */
1464 char *sizestr = NULL;
1465
1466 (void) bytes_to_sizestr(
1467 assumed_size, &sizestr, universal_units, B_FALSE);
1468
1469 oprintf(OUTPUT_TERSE,
1470 gettext(" *** warning: %d submirrors specified "
1471 "neither size or components,\n"
1472 " the assumed size is %s.\n"),
1473 n_none, sizestr);
1474
1475 free(sizestr);
1476
1477 } else if (mirror_size == 0) {
1478 volume_set_error(
1479 gettext("no size specified for requested "
1480 "mirror and no sizes/components "
1481 "specified for its submirrors."));
1482
1483 error = -1;
1484 }
1485 }
1486
1487 dlist_free_items(submirs_with_size, NULL);
1488 dlist_free_items(submirs_with_comps, NULL);
1489 dlist_free_items(submirs_with_nothing, NULL);
1490
1491 }
1492
1493 return (error);
1494 }
1495
1496 /*
1497 * FUNCTION: validate_submirror_size_and_components(
1498 * devconfig_t *submir,
1499 * uint64_t mirror_size,
1500 * uint64_t *assumed_size,
1501 * dlist_t **submirs_with_size,
1502 * dlist_t **submirs_with_comps,
1503 * dlist_t **submirs_no_size_or_comps)
1504 *
1505 * INPUT: submir - a specific submirror request
1506 * mirror_size, - the size specified for the mirror
1507 *
1508 * OUTPUT: assumed_size - the assumed size of the mirror,
1509 * if none specified.
1510 * submirs_with_size - pointer to a list of submirror
1511 * requests that specify a size
1512 * submirs_with_comps - pointer to a list of submirror
1513 * requests that specify components
1514 * submirs_no_size_or_comps - pointer to a list of
1515 * submirror requests that specify neither
1516 * a size or components
1517 *
1518 * RETURNS: int - 0 if the requested submirrors
1519 * pass validation
1520 * !0 otherwise.
1521 *
1522 * PURPOSE: Validation function which checks a specific submirror
1523 * request's size and components against the parent mirror's
1524 * size.
1525 *
1526 * - any submirror request that specifies both size and
1527 * components is invalid
1528 * - any submirror request specifying a size different
1529 * than that explictly requested for the mirror is
1530 * invalid
1531 * - a submirror request specifying a size < 512K is invalid.
1532 * - any components specified for a submirror are validated.
1533 *
1534 * If the submirror passes the validation checks, it is added
1535 * to the appropriate output list.
1536 *
1537 * If the input mirror_size is 0 and the submirror specifies
1538 * a valid size, the submirror size is returned as the
1539 * assumed_size for the mirror.
1540 */
1541 static int
validate_submirror_size_and_components(devconfig_t * submir,uint64_t mirror_size,uint64_t * assumed_size,dlist_t ** submirs_with_size,dlist_t ** submirs_with_comps,dlist_t ** submirs_no_size_or_comps)1542 validate_submirror_size_and_components(
1543 devconfig_t *submir,
1544 uint64_t mirror_size,
1545 uint64_t *assumed_size,
1546 dlist_t **submirs_with_size,
1547 dlist_t **submirs_with_comps,
1548 dlist_t **submirs_no_size_or_comps)
1549 {
1550 uint64_t submir_size = 0;
1551 component_type_t submir_type = TYPE_UNKNOWN;
1552 char *submir_typestr = NULL;
1553 dlist_t *submir_comps = NULL;
1554 dlist_t *item = NULL;
1555 int n_submir_comps = 0;
1556 int error = 0;
1557
1558 submir_comps = devconfig_get_components(submir);
1559 if (submir_comps != NULL) {
1560 n_submir_comps = dlist_length(submir_comps);
1561 }
1562
1563 if ((error = devconfig_get_size(submir, &submir_size)) != 0) {
1564 if (error == ERR_ATTR_UNSET) {
1565 /* submirror size not specified */
1566 error = 0;
1567 submir_size = 0;
1568 }
1569 }
1570
1571 if (error != 0) {
1572 return (error);
1573 }
1574
1575 /* submirror type previously validated */
1576 (void) devconfig_get_type(submir, &submir_type);
1577 submir_typestr = devconfig_type_to_str(submir_type);
1578
1579 if (submir_size == 0) {
1580
1581 /* submirror has no size, components? */
1582 if (n_submir_comps > 0) {
1583
1584 /* validate components */
1585 error = validate_slice_components(submir, submir_type);
1586
1587 item = dlist_new_item((void *)submir);
1588 if (item == NULL) {
1589 error = ENOMEM;
1590 } else {
1591 *submirs_with_comps =
1592 dlist_append(item, *submirs_with_comps, AT_TAIL);
1593 }
1594
1595 } else {
1596
1597 /* no size or components */
1598 item = dlist_new_item((void *)submir);
1599 if (item == NULL) {
1600 error = ENOMEM;
1601 } else {
1602 *submirs_no_size_or_comps =
1603 dlist_append(item, *submirs_no_size_or_comps, AT_TAIL);
1604 }
1605
1606 }
1607
1608 } else {
1609
1610 /* submirror has size, check it */
1611 if (error == 0) {
1612 error = validate_minimum_size(submir_size);
1613 }
1614
1615 /* check size against mirror's size */
1616 if ((error == 0) && (submir_size != mirror_size)) {
1617
1618 if (mirror_size != 0) {
1619
1620 /* sizes differ */
1621 char *sizestr = NULL;
1622 char *mstr = NULL;
1623
1624 (void) bytes_to_sizestr(
1625 submir_size, &sizestr, universal_units, B_FALSE);
1626 (void) bytes_to_sizestr(
1627 mirror_size, &mstr, universal_units, B_FALSE);
1628
1629 volume_set_error(
1630 gettext("the requested submirror size (%s) "
1631 "differs from the requested mirror "
1632 "size (%s).\n"),
1633 sizestr, mstr);
1634
1635 error = -1;
1636
1637 free(sizestr);
1638 free(mstr);
1639
1640 } else if (*assumed_size == 0) {
1641
1642 /* first size assumed as mirror size */
1643 char *sizestr = NULL;
1644
1645 (void) bytes_to_sizestr(
1646 submir_size, &sizestr, universal_units, B_FALSE);
1647
1648 oprintf(OUTPUT_TERSE,
1649 gettext(" *** warning, using first "
1650 "explicit submirror size (%s)\n"
1651 " as the mirror size\n"),
1652 sizestr);
1653
1654 *assumed_size = submir_size;
1655
1656 free(sizestr);
1657
1658 } else if (submir_size != *assumed_size) {
1659
1660 /* submirror sizes differ */
1661 char *sizestr1 = NULL;
1662 char *sizestr2 = NULL;
1663
1664 (void) bytes_to_sizestr(
1665 submir_size, &sizestr1, universal_units, B_FALSE);
1666 (void) bytes_to_sizestr(
1667 *assumed_size, &sizestr2, universal_units, B_FALSE);
1668
1669 volume_set_error(
1670 gettext("submirror specifies different "
1671 "size (%s) than a previous "
1672 "submirror (%s)\n"),
1673 sizestr1, sizestr2);
1674
1675 free(sizestr1);
1676 free(sizestr2);
1677
1678 error = -1;
1679 }
1680 }
1681
1682 if ((error == 0) && (n_submir_comps > 0)) {
1683
1684 /* size and subcomponents specified */
1685 char *sizestr = NULL;
1686
1687 (void) bytes_to_sizestr(
1688 submir_size, &sizestr, universal_units, B_FALSE);
1689
1690 volume_set_error(
1691 gettext("%s submirror specifies both an "
1692 "explicit size (%s) and components.\n"),
1693 submir_typestr, sizestr);
1694
1695 free(sizestr);
1696 error = -1;
1697
1698 }
1699
1700 if (error == 0) {
1701 item = dlist_new_item((void *)submir);
1702 if (item == NULL) {
1703 error = ENOMEM;
1704 } else {
1705 *submirs_with_size =
1706 dlist_append(item, *submirs_with_size, AT_TAIL);
1707 }
1708 }
1709 }
1710
1711 return (error);
1712 }
1713
1714
1715 /*
1716 * FUNCTION: validate_slice_components(devconfig_t *req,
1717 * component_type_t type)
1718 *
1719 * INPUT: req - the request
1720 * type - the type of volume being requested
1721 *
1722 * SIDEEFFECT: if the slice component is otherwise valid, an attempt is made
1723 * to reserve it.
1724 *
1725 * RETURNS: int - 0 if the request passes slice component validation
1726 * !0 otherwise.
1727 *
1728 * PURPOSE: Validation function for a concat, stripe or HSP request's
1729 * explicitly specified slice components.
1730 *
1731 * Is the component slice a known device
1732 * Is the component slice available
1733 * Is the component slice already reserved
1734 *
1735 * If the request is for a stripe or concat and the
1736 * request specifies an explicit size, it cannot also
1737 * specify component slices. This is a validation failure.
1738 *
1739 * If the request is for a stripe, the number of specified
1740 * slice components must agree with any expilcit specification
1741 * of the minimum or maximum number of components the stripe
1742 * should have.
1743 */
1744 static int
validate_slice_components(devconfig_t * req,component_type_t type)1745 validate_slice_components(
1746 devconfig_t *req,
1747 component_type_t type)
1748 {
1749 dlist_t *list = NULL;
1750 dlist_t *iter = NULL;
1751 int error = 0;
1752 int ncomp = 0;
1753
1754 char *dsname = get_request_diskset();
1755 char *voltype = devconfig_type_to_str(type);
1756
1757 list = devconfig_get_components(req);
1758
1759 for (iter = list; (iter != NULL) && (error == 0); iter = iter->next) {
1760
1761 devconfig_t *comp = (devconfig_t *)iter->obj;
1762 component_type_t ctype = TYPE_UNKNOWN;
1763 char *cname = NULL;
1764 dm_descriptor_t slice = (dm_descriptor_t)0;
1765
1766 if ((error = devconfig_get_type(comp, &ctype)) != 0) {
1767 volume_set_error(
1768 gettext("error getting requested component type."),
1769 voltype);
1770
1771 continue;
1772 }
1773
1774 if ((error = devconfig_get_name(comp, &cname)) != 0) {
1775 volume_set_error(
1776 gettext("error getting requested component name."));
1777
1778 continue;
1779 }
1780
1781 if (cname == NULL || cname[0] == '\0') {
1782 volume_set_error(
1783 gettext("%s requested component has no name."),
1784 voltype);
1785
1786 error = -1;
1787 continue;
1788 }
1789
1790 if (ctype == TYPE_SLICE) {
1791
1792 boolean_t in_set = B_FALSE;
1793 boolean_t is_avail = B_FALSE;
1794 boolean_t is_rsvd = B_FALSE;
1795 dm_descriptor_t disk = (dm_descriptor_t)0;
1796
1797 /* is the slice known and explicitly available? */
1798 if ((error = slice_is_available(cname, req,
1799 &is_avail)) != 0) {
1800
1801 if (error == ENODEV) {
1802 volume_set_error(
1803 gettext("%s requested component does not "
1804 "exist: \"%s\"."),
1805 voltype, cname);
1806 error = -1;
1807 }
1808 continue;
1809 }
1810
1811 if (is_avail != B_TRUE) {
1812 volume_set_error(
1813 gettext("%s requested component is "
1814 "unavailable: \"%s\"."),
1815 voltype, cname);
1816
1817 error = -1;
1818 continue;
1819 }
1820
1821 /* get slice and its disk */
1822 ((error = slice_get_by_name(cname, &slice)) != 0) ||
1823 (error = slice_get_disk(slice, &disk)) ||
1824 (error = is_reserved_slice(slice, &is_rsvd)) ||
1825 (error = is_disk_in_diskset(disk, dsname, &in_set));
1826 if (error != 0) {
1827 continue;
1828 }
1829
1830 /* is disk in the set? */
1831 if (in_set != B_TRUE) {
1832 volume_set_error(
1833 gettext("%s specifies a component not in "
1834 "disk set \"%s\": \"%s\"."),
1835 voltype, dsname, cname);
1836
1837 error = -1;
1838 continue;
1839 }
1840
1841 /* was slice specified in some other request? */
1842 if (is_rsvd == B_TRUE) {
1843 /* include aliases in the error */
1844 char *aliases =
1845 get_device_aliases_string((dm_descriptor_t)slice);
1846
1847 if (aliases[0] != NULL) {
1848 volume_set_error(
1849 gettext("%s specifies a previously used "
1850 "component: \"%s\" "
1851 "(aliases: %s).\n"),
1852 voltype, cname, aliases);
1853 } else {
1854 volume_set_error(
1855 gettext("%s specifies a previously used "
1856 "component: \"%s\"\n"),
1857 voltype, cname);
1858 }
1859
1860 error = -1;
1861 continue;
1862 }
1863
1864 /* component is ok, reserve it */
1865 error = add_reserved_slice(slice);
1866
1867 /*
1868 * the reserved slice component still needs to be
1869 * checked against slices in use by SVM, but that
1870 * information isn't available yet: the usable
1871 * slice derivation happens after validation.
1872 *
1873 * validate_reserved_slices() can be used to check
1874 * them once the usable slices are determined.
1875 */
1876
1877 } else {
1878 volume_set_error(
1879 gettext("%s requested component has illegal type."),
1880 voltype);
1881
1882 error = -1;
1883 continue;
1884 }
1885 }
1886
1887 if (error != 0) {
1888 return (error);
1889 }
1890
1891 ncomp = dlist_length(list);
1892 if ((ncomp > 0) && (type == TYPE_CONCAT || type == TYPE_STRIPE)) {
1893 /* explicit size requested for the stripe/concat? */
1894 uint64_t size = 0;
1895 if ((error = devconfig_get_size(req, &size)) != 0) {
1896 if (error == ERR_ATTR_UNSET) {
1897 error = 0;
1898 }
1899 } else {
1900 /* size and components both specified */
1901 char *sizestr = NULL;
1902
1903 (void) bytes_to_sizestr(
1904 size, &sizestr, universal_units, B_FALSE);
1905
1906 volume_set_error(
1907 gettext("%s specifies both an explicit size (%s) "
1908 "and components."),
1909 voltype, sizestr);
1910
1911 free(sizestr);
1912 error = -1;
1913 }
1914 }
1915
1916 if (error != 0) {
1917 return (error);
1918 }
1919
1920 if ((ncomp > 0) && (type == TYPE_STRIPE)) {
1921 /* does # of components agree with min & max comps? */
1922 uint16_t min = 0;
1923 uint16_t max = 0;
1924 if ((error = devconfig_get_stripe_mincomp(req, &min)) != 0) {
1925 if (error == ERR_ATTR_UNSET) {
1926 /* min comp not requested */
1927 error = 0;
1928 } else {
1929 /* error getting requested mincomp */
1930 return (error);
1931 }
1932
1933 } else if (ncomp < min) {
1934 /* specified comps < requested mincomp */
1935 volume_set_error(
1936 gettext("%s specifies fewer components (%d) than the "
1937 "minimum number requested (%d).\n"),
1938 voltype, ncomp, min);
1939
1940 error = -1;
1941 return (error);
1942 }
1943
1944 if ((error = devconfig_get_stripe_maxcomp(req, &max)) != 0) {
1945 if (error == ERR_ATTR_UNSET) {
1946 /* max comp not requested */
1947 error = 0;
1948 } else {
1949 /* error getting request maxcomp */
1950 return (error);
1951 }
1952 } else if (ncomp > max) {
1953 /* specified comps > requested maxcomp */
1954 volume_set_error(
1955 gettext("%s specifies more components (%d) than the "
1956 "maximum number requested (%d).\n"),
1957 voltype, ncomp, max);
1958 error = -1;
1959 return (error);
1960 }
1961 }
1962
1963 return (error);
1964 }
1965
1966 /*
1967 * Generate a list of known aliases for the input descriptor.
1968 *
1969 * The returned string buffer is in the form: "alias1", "alias2"...
1970 */
1971 static char *
get_device_aliases_string(dm_descriptor_t desc)1972 get_device_aliases_string(
1973 dm_descriptor_t desc)
1974 {
1975 static char buf[BUFSIZ];
1976 dlist_t *aliases = NULL;
1977 dlist_t *iter = NULL;
1978
1979 buf[0] = '\0';
1980 (void) get_aliases(desc, &aliases);
1981 for (iter = aliases; iter != NULL; iter = iter->next) {
1982 if (*buf == '\0') {
1983 (void) snprintf(buf, BUFSIZ-1, "\"%s\"", (char *)iter->obj);
1984 } else {
1985 char tmp[BUFSIZ];
1986 (void) strcpy(buf, tmp);
1987 (void) snprintf(buf, BUFSIZ-1, "%s, \"%s\"",
1988 tmp, (char *)iter->obj);
1989 }
1990 }
1991 dlist_free_items(aliases, free);
1992
1993 return (buf);
1994 }
1995