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