xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_validate.c (revision b6c8bd52ccb0f3491c2bd1f5867985cef630564a)
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