xref: /onnv-gate/usr/src/cmd/lvm/metassist/layout/layout_validate.c (revision 62:5e51ad5d0496)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include "metassist.h"
340Sstevel@tonic-gate #include "volume_dlist.h"
350Sstevel@tonic-gate #include "volume_error.h"
360Sstevel@tonic-gate #include "volume_string.h"
370Sstevel@tonic-gate #include "volume_output.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #define	_LAYOUT_VALIDATE_C
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include "layout_discovery.h"
420Sstevel@tonic-gate #include "layout_dlist_util.h"
430Sstevel@tonic-gate #include "layout_device_cache.h"
440Sstevel@tonic-gate #include "layout_device_util.h"
450Sstevel@tonic-gate #include "layout_request.h"
460Sstevel@tonic-gate #include "layout_slice.h"
470Sstevel@tonic-gate #include "layout_svm_util.h"
480Sstevel@tonic-gate #include "layout_validate.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * This module contains the majority of the validation code which
520Sstevel@tonic-gate  * layout applies to input requests. The assumption/agreement with
530Sstevel@tonic-gate  * the controller implementation is that requests passed into layout
540Sstevel@tonic-gate  * have undergone syntactic validation and that layout is responsible
550Sstevel@tonic-gate  * for semantic validation.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * The semantic validation that is handled:
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  * 1. For a toplevel diskset request, validate:
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  *	- the number of disksets is not exceeded
620Sstevel@tonic-gate  *	- the number of devices is not exceeded
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  *	(These items are not directly validated within this module,
650Sstevel@tonic-gate  *	but it is useful to document that they are handled somewhere).
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  * 2. For any devconfig_t representing a volume request, verify that:
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  *	- all HSP names are semantically valid.  The name should conform
700Sstevel@tonic-gate  *	  to the HSP naming convention: hspXXX.
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  *	- all concat, stripe, mirror, and volume names refer to
730Sstevel@tonic-gate  *        unused, semantically valid metadevice names. Examples of
740Sstevel@tonic-gate  *        bad data:
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  *            - a valid volume name that is already in use (d0, d10)
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  *            - a valid volume name that is used two or more times to
790Sstevel@tonic-gate  *		refer to new elements in the request.
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  *            - a valid volume name that is out of range (d99877,
820Sstevel@tonic-gate  *		d44356) or exceeds the maximum number of possible
830Sstevel@tonic-gate  *		volumes given the current SVM configuration.
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  *	- all available and unavailable	device specifications refer
860Sstevel@tonic-gate  *	  to existing controllers, disks, or slices on the system.
870Sstevel@tonic-gate  *	  Examples of bad data:
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  *            - a valid but non-existent controller (c23, c2)
900Sstevel@tonic-gate  *            - a valid but non-existent disk (c0t0d8, c1t0d0)
910Sstevel@tonic-gate  *            - a valid slice on a non-existent disk or controller
920Sstevel@tonic-gate  *		(c0t0d8s7, c1t0d05)
930Sstevel@tonic-gate  *            - a valid slice on an existing disk (c0t0d0s12,
940Sstevel@tonic-gate  *          	c0t0d0s9)
950Sstevel@tonic-gate  *
960Sstevel@tonic-gate  *	- any typed volume request that explicitly specifies components
970Sstevel@tonic-gate  *	  requires additional validation to detect syntactically valid
980Sstevel@tonic-gate  *	  expressions that are semantically ambiguous:
990Sstevel@tonic-gate  *
1000Sstevel@tonic-gate  *	  a concat request that:
1010Sstevel@tonic-gate  *	      - specifies size and components is invalid
1020Sstevel@tonic-gate  *
1030Sstevel@tonic-gate  *	  a stripe request that:
1040Sstevel@tonic-gate  *	      - specifies size and components is invalid
1050Sstevel@tonic-gate  *	      - specifies mincomp and components but not enough
1060Sstevel@tonic-gate  *		components is invalid
1070Sstevel@tonic-gate  *	      - specifies maxcomp and components but too many
1080Sstevel@tonic-gate  *		components is invalid
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  *	  a HSP request that:
1110Sstevel@tonic-gate  *	      - specifies components that are not appropriate for
1120Sstevel@tonic-gate  *		the volumes the HSP serves is invalid (?)
1130Sstevel@tonic-gate  *
1140Sstevel@tonic-gate  *	  a stripe, concat or HSP request that:
1150Sstevel@tonic-gate  *	      - specifies a component that was used in a prior
1160Sstevel@tonic-gate  *		request is invalid
1170Sstevel@tonic-gate  *	      - specifies a component that does not exist in the
1180Sstevel@tonic-gate  *		diskset is invalid (e.g., c0t0d0s0, but c0t0d0 is
1190Sstevel@tonic-gate  *		not yet in the diskset)
1200Sstevel@tonic-gate  *
1210Sstevel@tonic-gate  *	  a mirror request that:
1220Sstevel@tonic-gate  *	      - specifies nsubs and components but not enough
1230Sstevel@tonic-gate  *		components is invalid
1240Sstevel@tonic-gate  *	      - specifies components and the components specify
1250Sstevel@tonic-gate  *		different sizes results in a WARNING since the total
1260Sstevel@tonic-gate  *		usable capacity of the mirror is determined by the
1270Sstevel@tonic-gate  *		smallest of its submirrors.
1280Sstevel@tonic-gate  *	      - specifies components and the components specify
1290Sstevel@tonic-gate  *		components results in a WARNING since the submirrors
1300Sstevel@tonic-gate  *		may end up with different sizes
1310Sstevel@tonic-gate  */
1320Sstevel@tonic-gate static  int validate_request_name(
1330Sstevel@tonic-gate 	devconfig_t	*req,
1340Sstevel@tonic-gate 	component_type_t type);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate static  int validate_request_size(
1370Sstevel@tonic-gate 	devconfig_t	*req,
1380Sstevel@tonic-gate 	component_type_t type);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate static int validate_minimum_size(
1410Sstevel@tonic-gate 	uint64_t	nbytes);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate static uint64_t apply_layout_overhead_factor(
1440Sstevel@tonic-gate 	uint64_t req_size);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static int get_space_available_for_request(
1470Sstevel@tonic-gate 	devconfig_t	*request,
1480Sstevel@tonic-gate 	dlist_t		*usable_slices,
1490Sstevel@tonic-gate 	uint64_t	*avail_space);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate static int do_available_space_check(
1520Sstevel@tonic-gate 	uint64_t	req_size,
1530Sstevel@tonic-gate 	uint64_t	raw_avail_space,
1540Sstevel@tonic-gate 	devconfig_t	*request,
1550Sstevel@tonic-gate 	dlist_t		*usable_slices);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate static int validate_request_redundancy_level(
1580Sstevel@tonic-gate 	devconfig_t	*req);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate static int validate_request_npaths(
1610Sstevel@tonic-gate 	devconfig_t	*req);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate static  int validate_request_submirrors(
1640Sstevel@tonic-gate 	devconfig_t	*req);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate static  int validate_submirror_types(
1670Sstevel@tonic-gate 	dlist_t		*submirrors);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static  int validate_submirror_number(
1700Sstevel@tonic-gate 	devconfig_t	*req,
1710Sstevel@tonic-gate 	dlist_t		*submirrors);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate static  int validate_submirror_sizes(
1740Sstevel@tonic-gate 	devconfig_t	*req,
1750Sstevel@tonic-gate 	dlist_t		*submirrors);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static int validate_submirror_size_and_components(
1780Sstevel@tonic-gate 	devconfig_t	*submir,
1790Sstevel@tonic-gate 	uint64_t	mirror_size,
1800Sstevel@tonic-gate 	uint64_t	*assumed_size,
1810Sstevel@tonic-gate 	dlist_t		**submirs_with_size,
1820Sstevel@tonic-gate 	dlist_t		**submirs_with_comps,
1830Sstevel@tonic-gate 	dlist_t		**submirs_no_size_or_comps);
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate static  int validate_slice_components(
1860Sstevel@tonic-gate 	devconfig_t	*req,
1870Sstevel@tonic-gate 	component_type_t type);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate static char *get_device_aliases_string(
1900Sstevel@tonic-gate 	dm_descriptor_t desc);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static int validate_device_array(
1930Sstevel@tonic-gate 	char	**array,
1940Sstevel@tonic-gate 	char	*which,
1950Sstevel@tonic-gate 	dlist_t	**list);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static int add_reserved_name(char *name);
1980Sstevel@tonic-gate static boolean_t is_rsvd_name(char *name);
1990Sstevel@tonic-gate static dlist_t *_rsvd_names = NULL;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  * FUNCTION:	release_validatation_caches()
2030Sstevel@tonic-gate  *
2040Sstevel@tonic-gate  * RETURNS:	int	- 0
2050Sstevel@tonic-gate  *
2060Sstevel@tonic-gate  * PURPOSE:	Cleanup function.
2070Sstevel@tonic-gate  *
2080Sstevel@tonic-gate  *		Purges list of reserved volume names.  Should be called
2090Sstevel@tonic-gate  *		after all layout requests have been processed.
2100Sstevel@tonic-gate  */
2110Sstevel@tonic-gate int
release_validation_caches()2120Sstevel@tonic-gate release_validation_caches()
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	dlist_free_items(_rsvd_names, NULL);
2150Sstevel@tonic-gate 	_rsvd_names = NULL;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	return (0);
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate  * FUNCTION:	validate_basic_svm_config()
2220Sstevel@tonic-gate  *
2230Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2240Sstevel@tonic-gate  *			 !0 on failure
2250Sstevel@tonic-gate  *
2260Sstevel@tonic-gate  * PURPOSE:	Check to see if the local set metadb replicas have been created.
2270Sstevel@tonic-gate  *
2280Sstevel@tonic-gate  *		Makes sure at least 1 metadb replica exists for the local set.
2290Sstevel@tonic-gate  */
2300Sstevel@tonic-gate int
validate_basic_svm_config()2310Sstevel@tonic-gate validate_basic_svm_config()
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	int error = 0;
2340Sstevel@tonic-gate 	int nreplicas = 0;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	if ((error = get_n_metadb_replicas(&nreplicas)) == 0) {
2370Sstevel@tonic-gate 	    if (nreplicas == 0) {
2380Sstevel@tonic-gate 		volume_set_error(
2390Sstevel@tonic-gate 			gettext("Failed: State database replicas must "
2400Sstevel@tonic-gate 				"exist before using %s.\n"
2410Sstevel@tonic-gate 				"See metadb(1M) and %s(1M)."),
2420Sstevel@tonic-gate 			progname, progname);
2430Sstevel@tonic-gate 		error = -1;
2440Sstevel@tonic-gate 	    } else {
2450Sstevel@tonic-gate 		oprintf(OUTPUT_DEBUG,
2460Sstevel@tonic-gate 			gettext("%d metadb replicas found.\n"),
2470Sstevel@tonic-gate 			nreplicas);
2480Sstevel@tonic-gate 	    }
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	return (error);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * FUNCTION:	validate_request_sizes(devconfig_t *req)
2560Sstevel@tonic-gate  *
2570Sstevel@tonic-gate  * INPUT:	req:	a devconfig_t pointer to the toplevel request
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2600Sstevel@tonic-gate  *			 !0 on failure
2610Sstevel@tonic-gate  *
2620Sstevel@tonic-gate  * PURPOSE:	Check to see if the any of the individual volume request
2630Sstevel@tonic-gate  *		sizes exceeds the raw available space on the system or
2640Sstevel@tonic-gate  *		the space available to that specific request.
2650Sstevel@tonic-gate  *
2660Sstevel@tonic-gate  *		Check to see if the total space for all requests exceeds
2670Sstevel@tonic-gate  *		the raw available space.
2680Sstevel@tonic-gate  *
2690Sstevel@tonic-gate  *		If any check fails, stop checking, emit an error and
2700Sstevel@tonic-gate  *		return -1.
2710Sstevel@tonic-gate  *
2720Sstevel@tonic-gate  *		Note: this function must be called after the slice
2730Sstevel@tonic-gate  *		usages have been determined and the list of usable
2740Sstevel@tonic-gate  *		slices has been generated.
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate int
validate_request_sizes(devconfig_t * request)2770Sstevel@tonic-gate validate_request_sizes(
2780Sstevel@tonic-gate 	devconfig_t	*request)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 	int		error = 0;
2810Sstevel@tonic-gate 	dlist_t		*usable_slices;
2820Sstevel@tonic-gate 	dlist_t		*iter;
2830Sstevel@tonic-gate 	char		bad_rqst_info[BUFSIZ];
2840Sstevel@tonic-gate 	uint64_t	bad_rqst_space = 0;
2850Sstevel@tonic-gate 	uint64_t	total_rqst_space = 0;
2860Sstevel@tonic-gate 	uint64_t	raw_space = 0;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	(void) get_usable_slices(&usable_slices);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	/*
2910Sstevel@tonic-gate 	 * calculate raw available space: space on slices that are
2920Sstevel@tonic-gate 	 * "available" based on the diskset defaults or global defaults
2930Sstevel@tonic-gate 	 */
2940Sstevel@tonic-gate 	if ((error = get_space_available_for_request(request,
2950Sstevel@tonic-gate 	    usable_slices, &raw_space)) != 0) {
2960Sstevel@tonic-gate 	    return (error);
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	if (raw_space == 0) {
3000Sstevel@tonic-gate 	    volume_set_error(
3010Sstevel@tonic-gate 		    gettext("Failed: there is no available space.\n"));
3020Sstevel@tonic-gate 	    return (-1);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	/* deduct sizes of reserved components */
3060Sstevel@tonic-gate 	(void) get_reserved_slices(&iter);
3070Sstevel@tonic-gate 	for (; (iter != NULL) && (raw_space != 0) && (error == 0);
3080Sstevel@tonic-gate 	    iter = iter->next) {
3090Sstevel@tonic-gate 	    dm_descriptor_t slice = (uintptr_t)iter->obj;
3100Sstevel@tonic-gate 	    uint64_t	nbytes;
3110Sstevel@tonic-gate 	    if ((error = slice_get_size(slice, &nbytes)) == 0) {
3120Sstevel@tonic-gate 		if (raw_space >= nbytes) {
3130Sstevel@tonic-gate 		    raw_space -= nbytes;
3140Sstevel@tonic-gate 		} else {
3150Sstevel@tonic-gate 		    raw_space = 0;
3160Sstevel@tonic-gate 		}
3170Sstevel@tonic-gate 	    }
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/*
3210Sstevel@tonic-gate 	 * check each volume request's size against raw_space,
3220Sstevel@tonic-gate 	 * if that looks ok, do a closer check with the request's
3230Sstevel@tonic-gate 	 * available devices
3240Sstevel@tonic-gate 	 */
3250Sstevel@tonic-gate 	iter = devconfig_get_components(request);
3260Sstevel@tonic-gate 	for (; (iter != NULL) && (error == 0); iter = iter->next) {
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	    devconfig_t		*req = (devconfig_t *)iter->obj;
3290Sstevel@tonic-gate 	    component_type_t	type = TYPE_UNKNOWN;
3300Sstevel@tonic-gate 	    char		*typestr = NULL;
3310Sstevel@tonic-gate 	    uint64_t		nbytes = 0;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	    (void) devconfig_get_type(req, &type);
3340Sstevel@tonic-gate 	    if (type == TYPE_HSP) {
3350Sstevel@tonic-gate 		continue;
3360Sstevel@tonic-gate 	    }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	    typestr = devconfig_type_to_str(type);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	    if ((error = devconfig_get_size(req, &nbytes)) == 0) {
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		/* check specified size */
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 		if (type == TYPE_CONCAT || type == TYPE_STRIPE) {
3450Sstevel@tonic-gate 		    if ((error = do_available_space_check(
3460Sstevel@tonic-gate 			apply_layout_overhead_factor(nbytes),
3470Sstevel@tonic-gate 			raw_space, req, usable_slices)) == 0) {
3480Sstevel@tonic-gate 			total_rqst_space += nbytes;
3490Sstevel@tonic-gate 		    } else if (error == ENOSPC || error == E2BIG) {
3500Sstevel@tonic-gate 			(void) snprintf(bad_rqst_info, BUFSIZ-1,
3510Sstevel@tonic-gate 				"%s", typestr);
3520Sstevel@tonic-gate 			bad_rqst_space = nbytes;
3530Sstevel@tonic-gate 		    }
3540Sstevel@tonic-gate 		} else if (type == TYPE_MIRROR) {
3550Sstevel@tonic-gate 		    uint16_t nsubs = 0;
3560Sstevel@tonic-gate 		    if ((error = get_mirror_nsubs(req, &nsubs)) == 0) {
3570Sstevel@tonic-gate 			if ((error = do_available_space_check(
3580Sstevel@tonic-gate 			    apply_layout_overhead_factor(nbytes * nsubs),
3590Sstevel@tonic-gate 			    raw_space, req, usable_slices)) == 0) {
3600Sstevel@tonic-gate 			    total_rqst_space += (nsubs * nbytes);
3610Sstevel@tonic-gate 			} else {
3620Sstevel@tonic-gate 			    (void) snprintf(bad_rqst_info, BUFSIZ-1,
3630Sstevel@tonic-gate 				    gettext("%s with %d submirrors"),
3640Sstevel@tonic-gate 				    typestr, nsubs);
3650Sstevel@tonic-gate 			    bad_rqst_space = nbytes;
3660Sstevel@tonic-gate 			}
3670Sstevel@tonic-gate 		    }
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	    } else if ((error == ERR_ATTR_UNSET) && (type == TYPE_MIRROR)) {
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		/* mirror specified no size: find submirror that does */
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		dlist_t *subs = devconfig_get_components(req);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 		error = 0;
3770Sstevel@tonic-gate 		if (subs != NULL) {
3780Sstevel@tonic-gate 		    dlist_t	*iter2;
3790Sstevel@tonic-gate 		    int		nsubs = dlist_length(subs);
3800Sstevel@tonic-gate 		    for (iter2 = subs;
3810Sstevel@tonic-gate 			(iter2 != NULL) && (error == 0);
3820Sstevel@tonic-gate 			iter2 = iter2->next) {
3830Sstevel@tonic-gate 			devconfig_t *sub = (devconfig_t *)iter2->obj;
3840Sstevel@tonic-gate 			if ((error = devconfig_get_size(sub, &nbytes)) == 0) {
3850Sstevel@tonic-gate 			    if ((error = do_available_space_check(
3860Sstevel@tonic-gate 				apply_layout_overhead_factor(nbytes * nsubs),
3870Sstevel@tonic-gate 				raw_space, req, usable_slices)) == 0) {
3880Sstevel@tonic-gate 				total_rqst_space += (nbytes * nsubs);
3890Sstevel@tonic-gate 			    } else {
3900Sstevel@tonic-gate 				(void) snprintf(bad_rqst_info, BUFSIZ-1,
3910Sstevel@tonic-gate 					gettext("%s with %d submirrors"),
3920Sstevel@tonic-gate 					typestr, nsubs);
3930Sstevel@tonic-gate 				bad_rqst_space = nbytes;
3940Sstevel@tonic-gate 			    }
3950Sstevel@tonic-gate 			    break;
3960Sstevel@tonic-gate 			} else if (error == ERR_ATTR_UNSET) {
3970Sstevel@tonic-gate 			    error = 0;
3980Sstevel@tonic-gate 			}
3990Sstevel@tonic-gate 		    }
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 	    }
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	/*
4050Sstevel@tonic-gate 	 * do_available_space_check may return ENOSPC or E2BIG
4060Sstevel@tonic-gate 	 */
4070Sstevel@tonic-gate 	if (error == ENOSPC) {
4080Sstevel@tonic-gate 	    char *sizestr = NULL;
4090Sstevel@tonic-gate 	    (void) bytes_to_sizestr(bad_rqst_space,
4100Sstevel@tonic-gate 		    &sizestr, universal_units, B_FALSE);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	    volume_set_error(
4130Sstevel@tonic-gate 		    gettext("Failed: the request for a %s %s "
4140Sstevel@tonic-gate 			    "exceeds the available space.\n"),
4150Sstevel@tonic-gate 		    sizestr, bad_rqst_info);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	    free(sizestr);
4180Sstevel@tonic-gate 	    error = -1;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	} else if (error == E2BIG) {
4210Sstevel@tonic-gate 	    char *sizestr = NULL;
4220Sstevel@tonic-gate 	    (void) bytes_to_sizestr(bad_rqst_space,
4230Sstevel@tonic-gate 		    &sizestr, universal_units, B_FALSE);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	    volume_set_error(
4260Sstevel@tonic-gate 		    gettext("Failed: the request for a %s %s "
4270Sstevel@tonic-gate 			    "exceeds the usable space on the device(s) "
4280Sstevel@tonic-gate 			    "specified as available.\n"),
4290Sstevel@tonic-gate 		    sizestr, bad_rqst_info);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	    free(sizestr);
4320Sstevel@tonic-gate 	    error = -1;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	} else if (apply_layout_overhead_factor(total_rqst_space) > raw_space) {
4350Sstevel@tonic-gate 	    char *sizestr = NULL;
4360Sstevel@tonic-gate 	    (void) bytes_to_sizestr(
4370Sstevel@tonic-gate 		    total_rqst_space, &sizestr, universal_units, B_FALSE);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	    volume_set_error(
4400Sstevel@tonic-gate 		    gettext("Failed: the total space requested for the "
4410Sstevel@tonic-gate 			    "volumes (about %s) exceeds the available "
4420Sstevel@tonic-gate 			    "space.\n"),
4430Sstevel@tonic-gate 		    sizestr);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	    free(sizestr);
4460Sstevel@tonic-gate 	    error = -1;
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	return (error);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate /*
4530Sstevel@tonic-gate  * FUNCTION:	apply_layout_overhead_factor(uint64_t req_size)
4540Sstevel@tonic-gate  *
4550Sstevel@tonic-gate  * INPUT:	req_size: a requested volume size
4560Sstevel@tonic-gate  *
4570Sstevel@tonic-gate  * RETURNS:	the requested volume size with an overhead factor applied
4580Sstevel@tonic-gate  *
4590Sstevel@tonic-gate  * PURPOSE:	The input size size is inflated by a "fudge" factor
4600Sstevel@tonic-gate  *		to account for some of the expected overhead required for
4610Sstevel@tonic-gate  *		volumes such as block and cylinder boundary alignment.
4620Sstevel@tonic-gate  */
4630Sstevel@tonic-gate static uint64_t
apply_layout_overhead_factor(uint64_t req_size)4640Sstevel@tonic-gate apply_layout_overhead_factor(
4650Sstevel@tonic-gate 	uint64_t req_size)
4660Sstevel@tonic-gate {
4670Sstevel@tonic-gate 	double	overhead = 1.15;
4680Sstevel@tonic-gate 	double  d_size = req_size;
4690Sstevel@tonic-gate 	uint64_t result = (uint64_t)(d_size * overhead);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	return (result);
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate /*
4750Sstevel@tonic-gate  * FUNCTION:	get_space_available_for_request(devconfig_t *request,
4760Sstevel@tonic-gate  *			dlist_t *usable_slices, uint64_t *avail_space)
4770Sstevel@tonic-gate  *
4780Sstevel@tonic-gate  * INPUT:	request:	a devconfig_t volume request
4790Sstevel@tonic-gate  *		usable_slices:	a list of usable slice dm_descriptor_t handles
4800Sstevel@tonic-gate  *
4810Sstevel@tonic-gate  * OUTPUT:	avail_space:	the total space on slices in the usable_slice
4820Sstevel@tonic-gate  *				list that is available for use by the input
4830Sstevel@tonic-gate  *				request.
4840Sstevel@tonic-gate  *
4850Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
4860Sstevel@tonic-gate  *			 !0 on failure
4870Sstevel@tonic-gate  *
4880Sstevel@tonic-gate  * PURPOSE:	Iterate the input list of usable slices, determine which are
4890Sstevel@tonic-gate  *		available to the input request and accumulate the total space
4900Sstevel@tonic-gate  *		they represent.
4910Sstevel@tonic-gate  *
4920Sstevel@tonic-gate  *		The slices in the usable_slice list are those with no apparent
4930Sstevel@tonic-gate  *		usage detected.  The slice_is_available() check determines
4940Sstevel@tonic-gate  *		whether the slice passes the available/unavailable device
4950Sstevel@tonic-gate  *		specification associated with the input request.
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate static int
get_space_available_for_request(devconfig_t * request,dlist_t * usable_slices,uint64_t * avail_space)4980Sstevel@tonic-gate get_space_available_for_request(
4990Sstevel@tonic-gate 	devconfig_t	*request,
5000Sstevel@tonic-gate 	dlist_t		*usable_slices,
5010Sstevel@tonic-gate 	uint64_t	*avail_space)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	dlist_t	*iter;
5040Sstevel@tonic-gate 	int	error = 0;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	*avail_space = 0;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	for (iter = usable_slices;
5090Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
5100Sstevel@tonic-gate 	    iter = iter->next) {
5110Sstevel@tonic-gate 	    dm_descriptor_t slice = (uintptr_t)iter->obj;
5120Sstevel@tonic-gate 	    char	*sname;
5130Sstevel@tonic-gate 	    uint64_t	nbytes;
5140Sstevel@tonic-gate 	    boolean_t	avail = B_FALSE;
5150Sstevel@tonic-gate 	    if ((error = get_display_name(slice, &sname)) == 0) {
5160Sstevel@tonic-gate 		if ((error = slice_is_available(sname, request, &avail)) == 0) {
5170Sstevel@tonic-gate 		    if (avail == B_TRUE) {
5180Sstevel@tonic-gate 			if ((error = slice_get_size(slice, &nbytes)) == 0) {
5190Sstevel@tonic-gate 			    *avail_space += nbytes;
5200Sstevel@tonic-gate 			}
5210Sstevel@tonic-gate 		    }
5220Sstevel@tonic-gate 		}
5230Sstevel@tonic-gate 	    }
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	return (error);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate /*
5300Sstevel@tonic-gate  * FUNCTION:	do_available_space_check(uint64_t req_size,
5310Sstevel@tonic-gate  *		uint64_t raw_avail_space, devconfig_t *request,
5320Sstevel@tonic-gate  *		dlist_t *usable_slices)
5330Sstevel@tonic-gate  *
5340Sstevel@tonic-gate  * INPUT:	req_size:	the requested size of a volume
5350Sstevel@tonic-gate  *		raw_avail_space:the total available space for all volumes
5360Sstevel@tonic-gate  *		request:	a devconfig_t volume request
5370Sstevel@tonic-gate  *		usable_slices:	a list of usable slice dm_descriptor_t handles
5380Sstevel@tonic-gate  *
5390Sstevel@tonic-gate  * RETURNS:	int	- ENOSPC if the requested size exceeds the raw
5400Sstevel@tonic-gate  *				available space.
5410Sstevel@tonic-gate  *
5420Sstevel@tonic-gate  *			  E2BIG if the requested size exceeds the space
5430Sstevel@tonic-gate  *				available specifically to the input request,
5440Sstevel@tonic-gate  *				taking into account its available and
5450Sstevel@tonic-gate  *				unavailable device specifications.
5460Sstevel@tonic-gate  *
5470Sstevel@tonic-gate  *			  0 otherwise
5480Sstevel@tonic-gate  *
5490Sstevel@tonic-gate  * PURPOSE:	Check the input request size against different forms of
5500Sstevel@tonic-gate  *		available space.
5510Sstevel@tonic-gate  *
5520Sstevel@tonic-gate  *		If the requested size is less than the raw_avail_space, do the
5530Sstevel@tonic-gate  *		more expensive check against the space specifically available
5540Sstevel@tonic-gate  *		to the input request.
5550Sstevel@tonic-gate  */
5560Sstevel@tonic-gate static int
do_available_space_check(uint64_t req_size,uint64_t raw_avail_space,devconfig_t * request,dlist_t * usable_slices)5570Sstevel@tonic-gate do_available_space_check(
5580Sstevel@tonic-gate 	uint64_t	req_size,
5590Sstevel@tonic-gate 	uint64_t	raw_avail_space,
5600Sstevel@tonic-gate 	devconfig_t	*request,
5610Sstevel@tonic-gate 	dlist_t		*usable_slices)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	int	error = 0;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	if (req_size > raw_avail_space) {
5660Sstevel@tonic-gate 	    error = ENOSPC;
5670Sstevel@tonic-gate 	} else {
5680Sstevel@tonic-gate 	    uint64_t avail_space = 0;
5690Sstevel@tonic-gate 	    if ((error = get_space_available_for_request(request,
5700Sstevel@tonic-gate 		usable_slices, &avail_space)) == 0) {
5710Sstevel@tonic-gate 		if (req_size > avail_space) {
5720Sstevel@tonic-gate 		    error = E2BIG;
5730Sstevel@tonic-gate 		}
5740Sstevel@tonic-gate 	    }
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	return (error);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate  * FUNCTION:	validate_request(devconfig_t *req)
5820Sstevel@tonic-gate  *
5830Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t representing a volume layout request.
5840Sstevel@tonic-gate  *
5850Sstevel@tonic-gate  * RETURNS:	int	- 0 if the request passes validation
5860Sstevel@tonic-gate  *			 !0 otherwise.
5870Sstevel@tonic-gate  *
5880Sstevel@tonic-gate  * PURPOSE:	Main entry point into the layout request semantic
5890Sstevel@tonic-gate  *		validatation.
5900Sstevel@tonic-gate  *
5910Sstevel@tonic-gate  *		Determines the type of volume requested and invokes the
5920Sstevel@tonic-gate  *		appropriate validation functions.
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate int
validate_request(devconfig_t * req)5950Sstevel@tonic-gate validate_request(
5960Sstevel@tonic-gate 	devconfig_t *req)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate 	int 	error = 0;
5990Sstevel@tonic-gate 	component_type_t type = TYPE_UNKNOWN;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	((error = validate_request_avail_unavail(req)) != 0) ||
6020Sstevel@tonic-gate 	(error = devconfig_get_type(req, &type));
6030Sstevel@tonic-gate 	if (error != 0) {
6040Sstevel@tonic-gate 	    return (error);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	if (type == TYPE_MIRROR) {
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	    ((error = validate_request_name(req, type)) != 0) ||
6100Sstevel@tonic-gate 	    (error = validate_request_size(req, type)) ||
6110Sstevel@tonic-gate 	    (error = validate_request_submirrors(req));
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	} else if (type == TYPE_CONCAT || type == TYPE_STRIPE) {
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	    ((error = validate_request_name(req, type)) != 0) ||
6160Sstevel@tonic-gate 	    (error = validate_request_size(req, type)) ||
6170Sstevel@tonic-gate 	    (error = validate_slice_components(req, type));
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	} else if (type == TYPE_HSP) {
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	    ((error = validate_request_name(req, type)) != 0) ||
6220Sstevel@tonic-gate 	    (error = validate_slice_components(req, type));
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	} else if (type == TYPE_VOLUME) {
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	    ((error = validate_request_name(req, type)) != 0) ||
6270Sstevel@tonic-gate 	    (error = validate_request_redundancy_level(req)) ||
6280Sstevel@tonic-gate 	    (error = validate_request_npaths(req));
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	return (error);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate /*
6360Sstevel@tonic-gate  * FUNCTION:	validate_reserved_slices()
6370Sstevel@tonic-gate  *
6380Sstevel@tonic-gate  * RETURNS:	int	- 0 if all reserved slices are usable in
6390Sstevel@tonic-gate  *			    new devices.
6400Sstevel@tonic-gate  *			 !0 otherwise.
6410Sstevel@tonic-gate  *
6420Sstevel@tonic-gate  * PURPOSE:	Ensures that each reserved slice is actually usable
6430Sstevel@tonic-gate  *		as a volume component.
6440Sstevel@tonic-gate  *
6450Sstevel@tonic-gate  *		Retrieves list of reserved slices and list of usable
6460Sstevel@tonic-gate  *		slices.  Ensures that each reserved slice is in the
6470Sstevel@tonic-gate  *		usable list, generates an error if it is not.
6480Sstevel@tonic-gate  *
6490Sstevel@tonic-gate  *		This is broken out as a separate function because
6500Sstevel@tonic-gate  *		initial validation is using the lists of all known
6510Sstevel@tonic-gate  *		devices.  Device "usability" is only determined after
6520Sstevel@tonic-gate  *		the initial validation has completed successfully.
6530Sstevel@tonic-gate  */
6540Sstevel@tonic-gate int
validate_reserved_slices()6550Sstevel@tonic-gate validate_reserved_slices()
6560Sstevel@tonic-gate {
6570Sstevel@tonic-gate 	dlist_t	*reserved_slices;
6580Sstevel@tonic-gate 	dlist_t	*usable_slices;
6590Sstevel@tonic-gate 	int 	error = 0;
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	((error = get_reserved_slices(&reserved_slices)) != 0) ||
6620Sstevel@tonic-gate 	(error = get_usable_slices(&usable_slices));
6630Sstevel@tonic-gate 	if (error == 0) {
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	    dlist_t *iter;
6660Sstevel@tonic-gate 	    for (iter = reserved_slices;
6670Sstevel@tonic-gate 		(iter != NULL) && (error == 0);
6680Sstevel@tonic-gate 		iter = iter->next) {
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 		if (dlist_contains(usable_slices, iter->obj,
6710Sstevel@tonic-gate 			    compare_descriptor_names) != B_TRUE) {
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 		    dm_descriptor_t slice = (uintptr_t)iter->obj;
6740Sstevel@tonic-gate 		    char *name = NULL;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 		    error = get_display_name(slice, &name);
6770Sstevel@tonic-gate 		    if (error == 0) {
6780Sstevel@tonic-gate 			char *aliases = get_device_aliases_string(slice);
6790Sstevel@tonic-gate 			if (aliases[0] != NULL) {
6800Sstevel@tonic-gate 			    volume_set_error(
6810Sstevel@tonic-gate 				    gettext("A requested volume component "
6820Sstevel@tonic-gate 					    "is currently in use: \"%s\" "
6830Sstevel@tonic-gate 					    "(aliases: %s).\n"),
6840Sstevel@tonic-gate 				    name, aliases);
6850Sstevel@tonic-gate 			} else {
6860Sstevel@tonic-gate 			    volume_set_error(
6870Sstevel@tonic-gate 				    gettext("A requested volume component "
6880Sstevel@tonic-gate 					    "is currently in use: \"%s\"\n"),
6890Sstevel@tonic-gate 				    name);
6900Sstevel@tonic-gate 			}
6910Sstevel@tonic-gate 			error = -1;
6920Sstevel@tonic-gate 		    }
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 	    }
6950Sstevel@tonic-gate 	}
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	return (error);
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate /*
7010Sstevel@tonic-gate  * FUNCTION:	validate_request_avail_unavail(devconfig_t *req)
7020Sstevel@tonic-gate  *
7030Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t representing a volume layout request.
7040Sstevel@tonic-gate  *
7050Sstevel@tonic-gate  * RETURNS:	int	- 0 if the request passes validation
7060Sstevel@tonic-gate  *			 !0 otherwise.
7070Sstevel@tonic-gate  *
7080Sstevel@tonic-gate  * PURPOSE:	validation function for a request's lists of available
7090Sstevel@tonic-gate  *		and unavailable devices.
7100Sstevel@tonic-gate  *
7110Sstevel@tonic-gate  *		validates that both lists contain names of known devices.
7120Sstevel@tonic-gate  *
7130Sstevel@tonic-gate  *		validates that the same name does not appear in both lists.
7140Sstevel@tonic-gate  */
7150Sstevel@tonic-gate int
validate_request_avail_unavail(devconfig_t * req)7160Sstevel@tonic-gate validate_request_avail_unavail(
7170Sstevel@tonic-gate 	devconfig_t *req)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	dlist_t	*avail = NULL;
7200Sstevel@tonic-gate 	dlist_t	*unavail = NULL;
7210Sstevel@tonic-gate 	int	error = 0;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	/* check that each array contains valid devices */
7240Sstevel@tonic-gate 	((error = validate_device_array(devconfig_get_available(req),
7250Sstevel@tonic-gate 		gettext("available"), &avail)) != 0) ||
7260Sstevel@tonic-gate 	(error = validate_device_array(devconfig_get_unavailable(req),
7270Sstevel@tonic-gate 		gettext("unavailable"), &unavail));
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/* check that the arrays don't both contain the same device(s) */
7300Sstevel@tonic-gate 	if (error == 0) {
7310Sstevel@tonic-gate 	    dlist_t *iter;
7320Sstevel@tonic-gate 	    for (iter = avail; iter != NULL; iter = iter->next) {
7330Sstevel@tonic-gate 		if (dlist_contains(unavail, iter->obj,
7340Sstevel@tonic-gate 			    compare_descriptor_names) == B_TRUE) {
7350Sstevel@tonic-gate 		    char *name;
7360Sstevel@tonic-gate 		    char *aliases =
7370Sstevel@tonic-gate 			get_device_aliases_string((uintptr_t)iter->obj);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 		    (void) get_display_name((uintptr_t)iter->obj, &name);
7400Sstevel@tonic-gate 		    if (aliases[0] != NULL) {
7410Sstevel@tonic-gate 			volume_set_error(
7420Sstevel@tonic-gate 				gettext("\"%s\" specified as both available "
7430Sstevel@tonic-gate 					"and unavailable.\n"
7440Sstevel@tonic-gate 					"It has these aliases: %s\n"),
7450Sstevel@tonic-gate 				name, aliases);
7460Sstevel@tonic-gate 		    } else {
7470Sstevel@tonic-gate 			volume_set_error(
7480Sstevel@tonic-gate 				gettext("\"%s\" specified as both available "
7490Sstevel@tonic-gate 					"and unavailable.\n"),
7500Sstevel@tonic-gate 				name);
7510Sstevel@tonic-gate 		    }
7520Sstevel@tonic-gate 		    error = -1;
7530Sstevel@tonic-gate 		    break;
7540Sstevel@tonic-gate 		}
7550Sstevel@tonic-gate 	    }
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	dlist_free_items(avail, NULL);
7590Sstevel@tonic-gate 	dlist_free_items(unavail, NULL);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	return (error);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate /*
7650Sstevel@tonic-gate  * FUNCTION:	validate_device_array(char **array, char *which, dlist_t **list)
7660Sstevel@tonic-gate  *
7670Sstevel@tonic-gate  * INPUT:	array	- an array of char * device names
7680Sstevel@tonic-gate  * 		which   - either "available" or "unavailable"
7690Sstevel@tonic-gate  *			  indicating the array name to use in
7700Sstevel@tonic-gate  *			  error strings.
7710Sstevel@tonic-gate  * OUTPUT:	list	- a list of device descriptors corresponding the each
7720Sstevel@tonic-gate  *			  of the input names.
7730Sstevel@tonic-gate  *
7740Sstevel@tonic-gate  * RETURNS:	int	- 0 if the array passes validation
7750Sstevel@tonic-gate  *			 !0 otherwise.
7760Sstevel@tonic-gate  *
7770Sstevel@tonic-gate  * PURPOSE:	validation function for a request's list of available
7780Sstevel@tonic-gate  *		or unavailable devices.
7790Sstevel@tonic-gate  *
7800Sstevel@tonic-gate  *		DID names are converted to CTD names.
7810Sstevel@tonic-gate  *
7820Sstevel@tonic-gate  *		The CTD name must be of an available slice, disk or
7830Sstevel@tonic-gate  *		HBA, or a known used slice, disk or HBA that was
7840Sstevel@tonic-gate  *		discovered when the system's devices were probed.
7850Sstevel@tonic-gate  *
7860Sstevel@tonic-gate  *		Any other name is assumed to refer to a device not
7870Sstevel@tonic-gate  *		attached to the system and results in a validation
7880Sstevel@tonic-gate  *		failure.
7890Sstevel@tonic-gate  *
7900Sstevel@tonic-gate  *		Descriptors for validated devices are added to the input
7910Sstevel@tonic-gate  *		list.
7920Sstevel@tonic-gate  */
7930Sstevel@tonic-gate int
validate_device_array(char ** array,char * which,dlist_t ** list)7940Sstevel@tonic-gate validate_device_array(
7950Sstevel@tonic-gate 	char	**array,
7960Sstevel@tonic-gate 	char	*which,
7970Sstevel@tonic-gate 	dlist_t	**list)
7980Sstevel@tonic-gate {
7990Sstevel@tonic-gate 	int	error = 0;
8000Sstevel@tonic-gate 	int	i = 0;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	if (array == NULL || *array == NULL) {
8030Sstevel@tonic-gate 	    return (0);
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	for (i = 0; (array[i] != NULL) && (error == 0); i++) {
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	    dm_descriptor_t slice = (dm_descriptor_t)0;
8090Sstevel@tonic-gate 	    dm_descriptor_t disk = (dm_descriptor_t)0;
8100Sstevel@tonic-gate 	    dm_descriptor_t hba = (dm_descriptor_t)0;
8110Sstevel@tonic-gate 	    char	*name = array[i];
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	    /* name must correspond to a known HBA, disk, or slice */
8140Sstevel@tonic-gate 	    if ((error = hba_get_by_name(name, &hba)) == 0) {
8150Sstevel@tonic-gate 		if (hba == (dm_descriptor_t)0) {
8160Sstevel@tonic-gate 		    if ((error = disk_get_by_name(name, &disk)) == 0) {
8170Sstevel@tonic-gate 			if (disk == (dm_descriptor_t)0) {
8180Sstevel@tonic-gate 			    error = slice_get_by_name(name, &slice);
8190Sstevel@tonic-gate 			}
8200Sstevel@tonic-gate 		    }
8210Sstevel@tonic-gate 		}
8220Sstevel@tonic-gate 	    }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	    if (error != 0) {
8250Sstevel@tonic-gate 		break;
8260Sstevel@tonic-gate 	    }
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	    /* 0 sized slices cannot be used as-is, pretend non-existant */
8290Sstevel@tonic-gate 	    if (slice != (dm_descriptor_t)0) {
8300Sstevel@tonic-gate 		uint64_t size = 0;
8310Sstevel@tonic-gate 		if ((error = slice_get_size(slice, &size)) == 0) {
8320Sstevel@tonic-gate 		    if (size == 0) {
8330Sstevel@tonic-gate 			slice = (dm_descriptor_t)0;
8340Sstevel@tonic-gate 		    }
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 	    }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
8390Sstevel@tonic-gate 		    gettext("  validate %s (%s): s=%llu, d=%llu, c=%llu\n"),
8400Sstevel@tonic-gate 		    which, array[i], slice, disk, hba);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	    if ((error == 0) && ((slice != 0) || (disk != 0) || (hba != 0))) {
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		/* name represents an individual "device", add it to the list */
8450Sstevel@tonic-gate 		dm_descriptor_t desc = (dm_descriptor_t)0;
8460Sstevel@tonic-gate 		dlist_t *item;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 		if (slice != 0) {
8490Sstevel@tonic-gate 		    desc = slice;
8500Sstevel@tonic-gate 		} else if (disk != 0) {
8510Sstevel@tonic-gate 		    desc = disk;
8520Sstevel@tonic-gate 		} else if (hba != 0) {
8530Sstevel@tonic-gate 		    desc = hba;
8540Sstevel@tonic-gate 		}
8550Sstevel@tonic-gate 
856*62Sjeanm 		if ((item = dlist_new_item((void *)(uintptr_t)desc)) == NULL) {
8570Sstevel@tonic-gate 		    error = ENOMEM;
8580Sstevel@tonic-gate 		} else {
8590Sstevel@tonic-gate 		    *list = dlist_append(item, *list, AT_HEAD);
8600Sstevel@tonic-gate 		}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	    } else if (is_ctd_target_name(name) == B_TRUE) {
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		/* expand target to all of its disks */
8650Sstevel@tonic-gate 		dlist_t *disks = NULL;
8660Sstevel@tonic-gate 		if ((error = get_disks_for_target(name, &disks)) == 0) {
8670Sstevel@tonic-gate 		    if ((disks == NULL) || (dlist_length(disks) == 0)) {
8680Sstevel@tonic-gate 			volume_set_error(
8690Sstevel@tonic-gate 				gettext("nonexistent device specified "
8700Sstevel@tonic-gate 					"as %s: \"%s\"."),
8710Sstevel@tonic-gate 				which, array[i]);
8720Sstevel@tonic-gate 			error = -1;
8730Sstevel@tonic-gate 		    } else {
8740Sstevel@tonic-gate 			dlist_t *iter;
8750Sstevel@tonic-gate 			for (iter = disks;
8760Sstevel@tonic-gate 			    (iter != NULL) && (error == 0);
8770Sstevel@tonic-gate 			    iter = iter->next) {
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 			    dlist_t *item;
8800Sstevel@tonic-gate 			    if ((item = dlist_new_item(iter->obj)) == NULL) {
8810Sstevel@tonic-gate 				error = ENOMEM;
8820Sstevel@tonic-gate 			    } else {
8830Sstevel@tonic-gate 				*list = dlist_append(item, *list, AT_HEAD);
8840Sstevel@tonic-gate 			    }
8850Sstevel@tonic-gate 			}
8860Sstevel@tonic-gate 		    }
8870Sstevel@tonic-gate 		}
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	    } else {
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		/* not a slice, disk, target or ctrl */
8920Sstevel@tonic-gate 		volume_set_error(
8930Sstevel@tonic-gate 			gettext("nonexistent device specified "
8940Sstevel@tonic-gate 				"as %s: \"%s\"."),
8950Sstevel@tonic-gate 			which, array[i]);
8960Sstevel@tonic-gate 		error = -1;
8970Sstevel@tonic-gate 	    }
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	return (error);
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate /*
9040Sstevel@tonic-gate  * FUNCTION:	validate_request_name(devconfig_t *req, component_type_t type)
9050Sstevel@tonic-gate  *
9060Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t volume request
9070Sstevel@tonic-gate  * 		type	- the volume type being requested
9080Sstevel@tonic-gate  *
9090Sstevel@tonic-gate  * SIDEEFFECT:  if the request specifies a name and the name is valid and
9100Sstevel@tonic-gate  *		not currently in use an attempt is made to reserve it.
9110Sstevel@tonic-gate  *		if the name has already been reserved by a prior volume
9120Sstevel@tonic-gate  *		request, validation fails.
9130Sstevel@tonic-gate  *
9140Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested name passes validation
9150Sstevel@tonic-gate  *				(or there is no name request)
9160Sstevel@tonic-gate  *			 !0 otherwise.
9170Sstevel@tonic-gate  *
9180Sstevel@tonic-gate  * PURPOSE:	Validation function for a request's volume name.
9190Sstevel@tonic-gate  *
9200Sstevel@tonic-gate  *		a HSP name must be valid and reservable.
9210Sstevel@tonic-gate  *
9220Sstevel@tonic-gate  *		a volume name must be valid and reservable.
9230Sstevel@tonic-gate  */
9240Sstevel@tonic-gate static int
validate_request_name(devconfig_t * req,component_type_t type)9250Sstevel@tonic-gate validate_request_name(
9260Sstevel@tonic-gate 	devconfig_t	*req,
9270Sstevel@tonic-gate 	component_type_t type)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	char	*name = NULL;
9300Sstevel@tonic-gate 	char	*typestr = devconfig_type_to_str(type);
9310Sstevel@tonic-gate 	int	error = 0;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	if ((error = devconfig_get_name(req, &name)) != 0) {
9340Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
9350Sstevel@tonic-gate 		volume_set_error(
9360Sstevel@tonic-gate 			gettext("error getting requested name.\n"));
9370Sstevel@tonic-gate 		return (error);
9380Sstevel@tonic-gate 	    }
9390Sstevel@tonic-gate 	    /* no name specified */
9400Sstevel@tonic-gate 	    return (0);
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	if (type == TYPE_HSP) {
9440Sstevel@tonic-gate 	    if (is_hsp_name_valid(name) == 0) {
9450Sstevel@tonic-gate 		volume_set_error(
9460Sstevel@tonic-gate 			gettext("requested %s name \"%s\" is not valid.\n"),
9470Sstevel@tonic-gate 			typestr, name);
9480Sstevel@tonic-gate 		error = -1;
9490Sstevel@tonic-gate 	    } else if (reserve_hsp_name(name) != 0) {
9500Sstevel@tonic-gate 		if (is_rsvd_name(name) == B_TRUE) {
9510Sstevel@tonic-gate 		    volume_set_error(
9520Sstevel@tonic-gate 			    gettext("requested %s name \"%s\" used "
9530Sstevel@tonic-gate 				    "previously in this request.\n"),
9540Sstevel@tonic-gate 			    typestr, name);
9550Sstevel@tonic-gate 		} else {
9560Sstevel@tonic-gate 		    volume_set_error(
9570Sstevel@tonic-gate 			    gettext("requested %s name \"%s\" is not "
9580Sstevel@tonic-gate 				    "available.\n"),
9590Sstevel@tonic-gate 			    typestr, name);
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 		error = -1;
9620Sstevel@tonic-gate 	    } else {
9630Sstevel@tonic-gate 		error = add_reserved_name(name);
9640Sstevel@tonic-gate 	    }
9650Sstevel@tonic-gate 	} else {
9660Sstevel@tonic-gate 	    if (is_volume_name_valid(name) == 0) {
9670Sstevel@tonic-gate 		volume_set_error(
9680Sstevel@tonic-gate 			gettext("requested %s name \"%s\" is not valid.\n"),
9690Sstevel@tonic-gate 			typestr, name);
9700Sstevel@tonic-gate 		error = -1;
9710Sstevel@tonic-gate 	    } else if (is_volume_name_in_range(name) != B_TRUE) {
9720Sstevel@tonic-gate 		int max = 0;
9730Sstevel@tonic-gate 		(void) get_max_number_of_devices(&max);
9740Sstevel@tonic-gate 		volume_set_error(
9750Sstevel@tonic-gate 			gettext("requested %s name \"%s\" is not legal.\n"
9760Sstevel@tonic-gate 				"Use a name less than d%d.\n"),
9770Sstevel@tonic-gate 			typestr, name, max);
9780Sstevel@tonic-gate 		error = -1;
9790Sstevel@tonic-gate 	    } else if (reserve_volume_name(name) != 0) {
9800Sstevel@tonic-gate 		if (is_rsvd_name(name) == B_TRUE) {
9810Sstevel@tonic-gate 		    volume_set_error(
9820Sstevel@tonic-gate 			    gettext("requested %s name \"%s\" used "
9830Sstevel@tonic-gate 				    "previously in this request.\n"),
9840Sstevel@tonic-gate 			    typestr, name);
9850Sstevel@tonic-gate 		} else {
9860Sstevel@tonic-gate 		    volume_set_error(
9870Sstevel@tonic-gate 			    gettext("requested %s name \"%s\" is not "
9880Sstevel@tonic-gate 				    "available, a volume with that name "
9890Sstevel@tonic-gate 				    "already exists.\n"),
9900Sstevel@tonic-gate 			    typestr, name);
9910Sstevel@tonic-gate 		}
9920Sstevel@tonic-gate 		error = -1;
9930Sstevel@tonic-gate 	    } else {
9940Sstevel@tonic-gate 		error = add_reserved_name(name);
9950Sstevel@tonic-gate 	    }
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	return (error);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate /*
10020Sstevel@tonic-gate  * FUNCTION:	add_reserved_name(char *name)
10030Sstevel@tonic-gate  *
10040Sstevel@tonic-gate  * INPUT:	name	- a char * volume name
10050Sstevel@tonic-gate  *
10060Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
10070Sstevel@tonic-gate  *			 !0 otherwise.
10080Sstevel@tonic-gate  *
10090Sstevel@tonic-gate  * PURPOSE:	Helper which remembers specfically requested names
10100Sstevel@tonic-gate  *		in a private list to ensure that the same name isn't
10110Sstevel@tonic-gate  *		requested more than once.
10120Sstevel@tonic-gate  */
10130Sstevel@tonic-gate static int
add_reserved_name(char * name)10140Sstevel@tonic-gate add_reserved_name(
10150Sstevel@tonic-gate 	char	*name)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	dlist_t	*item = NULL;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	if ((item = dlist_new_item(name)) == NULL) {
10200Sstevel@tonic-gate 	    return (ENOMEM);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	_rsvd_names = dlist_append(item, _rsvd_names, AT_TAIL);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	return (0);
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate /*
10290Sstevel@tonic-gate  * FUNCTION:	is_rsvd_name(char *name)
10300Sstevel@tonic-gate  *
10310Sstevel@tonic-gate  * INPUT:	name	- a char * volume name
10320Sstevel@tonic-gate  *
10330Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the requested name is currently
10340Sstevel@tonic-gate  *				reserved, B_FALSE otherwise.
10350Sstevel@tonic-gate  *
10360Sstevel@tonic-gate  * PURPOSE:	Helper which checks to see if the input volume
10370Sstevel@tonic-gate  *		name was previously reserved.
10380Sstevel@tonic-gate  */
10390Sstevel@tonic-gate static boolean_t
is_rsvd_name(char * name)10400Sstevel@tonic-gate is_rsvd_name(
10410Sstevel@tonic-gate 	char	*name)
10420Sstevel@tonic-gate {
10430Sstevel@tonic-gate 	dlist_t	*iter = NULL;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	for (iter = _rsvd_names; iter != NULL; iter = iter->next) {
10460Sstevel@tonic-gate 	    if ((string_case_compare(name, (char *)iter->obj)) == 0) {
10470Sstevel@tonic-gate 		return (B_TRUE);
10480Sstevel@tonic-gate 	    }
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	return (B_FALSE);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate /*
10550Sstevel@tonic-gate  * FUNCTION:	validate_request_size(devconfig_t *req, component_type_t type)
10560Sstevel@tonic-gate  *
10570Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t volume request
10580Sstevel@tonic-gate  * 		type	- the volume type being requested
10590Sstevel@tonic-gate  *
10600Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested size passes validation
10610Sstevel@tonic-gate  *				(or there is no size request)
10620Sstevel@tonic-gate  *			 !0 otherwise.
10630Sstevel@tonic-gate  *
10640Sstevel@tonic-gate  * PURPOSE:	Validation function for a request's volume size.
10650Sstevel@tonic-gate  *
10660Sstevel@tonic-gate  *		a HSP request can have no size.
10670Sstevel@tonic-gate  *
10680Sstevel@tonic-gate  *		a concat, stripe or mirror request may have a size.
10690Sstevel@tonic-gate  *		if size is specified, the request cannot also specify
10700Sstevel@tonic-gate  *		components.  Conversely, if the request does not specify
10710Sstevel@tonic-gate  *		a size, it must specify components.
10720Sstevel@tonic-gate  */
10730Sstevel@tonic-gate static int
validate_request_size(devconfig_t * req,component_type_t type)10740Sstevel@tonic-gate validate_request_size(
10750Sstevel@tonic-gate 	devconfig_t	*req,
10760Sstevel@tonic-gate 	component_type_t type)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	uint64_t nbytes = 0;
10790Sstevel@tonic-gate 	int	error = 0;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	if (type == TYPE_HSP) {
10820Sstevel@tonic-gate 	    return (0);
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	if ((error = devconfig_get_size(req, &nbytes)) != 0) {
10860Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
10870Sstevel@tonic-gate 		/* nbytes not specified, request must have subcomponents */
10880Sstevel@tonic-gate 		dlist_t *list = devconfig_get_components(req);
10890Sstevel@tonic-gate 		if (list != NULL && dlist_length(list) > 0) {
10900Sstevel@tonic-gate 		    error = 0;
10910Sstevel@tonic-gate 		} else {
10920Sstevel@tonic-gate 		    volume_set_error(
10930Sstevel@tonic-gate 			    gettext("%s request specifies no size or "
10940Sstevel@tonic-gate 				    "subcomponents.\n"),
10950Sstevel@tonic-gate 			    devconfig_type_to_str(type));
10960Sstevel@tonic-gate 		    error = -1;
10970Sstevel@tonic-gate 		}
10980Sstevel@tonic-gate 	    }
10990Sstevel@tonic-gate 	    return (error);
11000Sstevel@tonic-gate 	}
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	return (error);
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate /*
11060Sstevel@tonic-gate  * FUNCTION:	validate_minimum_size(uint64_t	nbytes)
11070Sstevel@tonic-gate  *
11080Sstevel@tonic-gate  * INPUT:	nbytes	- requested volume size in bytes
11090Sstevel@tonic-gate  *
11100Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested size passes validation
11110Sstevel@tonic-gate  *				(or there is no size request)
11120Sstevel@tonic-gate  *			 !0 otherwise.
11130Sstevel@tonic-gate  *
11140Sstevel@tonic-gate  * PURPOSE:	Validation function for a request's volume size.
11150Sstevel@tonic-gate  *
11160Sstevel@tonic-gate  *		an error is issued if the requested size <= 512K.
11170Sstevel@tonic-gate  */
11180Sstevel@tonic-gate static int
validate_minimum_size(uint64_t nbytes)11190Sstevel@tonic-gate validate_minimum_size(
11200Sstevel@tonic-gate 	uint64_t	nbytes)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	static uint64_t min = (512 * 1024) - 1;
11230Sstevel@tonic-gate 	int	error = 0;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	if (nbytes <= min) {
11260Sstevel@tonic-gate 	    char *sizestr = NULL;
11270Sstevel@tonic-gate 	    char *minstr = NULL;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	    (void) bytes_to_sizestr(
11300Sstevel@tonic-gate 		    nbytes, &sizestr, universal_units, B_FALSE);
11310Sstevel@tonic-gate 	    (void) bytes_to_sizestr(
11320Sstevel@tonic-gate 		    min, &minstr, universal_units, B_FALSE);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	    volume_set_error(
11350Sstevel@tonic-gate 		    gettext("requested volume size (%s) must be "
11360Sstevel@tonic-gate 			    "greater than %s.\n"),
11370Sstevel@tonic-gate 		    sizestr, minstr);
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	    free(sizestr);
11400Sstevel@tonic-gate 	    free(minstr);
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	    error = -1;
11430Sstevel@tonic-gate 	}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	return (error);
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate /*
11490Sstevel@tonic-gate  * FUNCTION:	validate_request_redundancy_level(devconfig_t *req)
11500Sstevel@tonic-gate  *
11510Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t volume request
11520Sstevel@tonic-gate  *
11530Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested redundancy level
11540Sstevel@tonic-gate  *			    passes validation (or none was requested)
11550Sstevel@tonic-gate  *			 !0 otherwise.
11560Sstevel@tonic-gate  *
11570Sstevel@tonic-gate  * PURPOSE:	Validation function for a redundant volume request's
11580Sstevel@tonic-gate  *		redundancy level.
11590Sstevel@tonic-gate  *
11600Sstevel@tonic-gate  *		If the request specifies redundancy, the value must be
11610Sstevel@tonic-gate  *		between 1 and 4.
11620Sstevel@tonic-gate  */
11630Sstevel@tonic-gate static int
validate_request_redundancy_level(devconfig_t * req)11640Sstevel@tonic-gate validate_request_redundancy_level(
11650Sstevel@tonic-gate 	devconfig_t	*req)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate 	uint16_t rlevel = 0;
11680Sstevel@tonic-gate 	int	error = 0;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if ((error = devconfig_get_volume_redundancy_level(
11710Sstevel@tonic-gate 	    req, &rlevel)) != 0) {
11720Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
11730Sstevel@tonic-gate 		error = 0;
11740Sstevel@tonic-gate 	    }
11750Sstevel@tonic-gate 	    return (error);
11760Sstevel@tonic-gate 	}
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	if (rlevel > 4) {
11790Sstevel@tonic-gate 	    volume_set_error(gettext(
11800Sstevel@tonic-gate 		"requested redundancy level must be between 0 and 4.\n"));
11810Sstevel@tonic-gate 	    error = -1;
11820Sstevel@tonic-gate 	}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	return (error);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate /*
11880Sstevel@tonic-gate  * FUNCTION:	validate_request_npaths(devconfig_t *req)
11890Sstevel@tonic-gate  *
11900Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t volume request
11910Sstevel@tonic-gate  *
11920Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested # of redundant data paths
11930Sstevel@tonic-gate  *				passes validation (or none was requested)
11940Sstevel@tonic-gate  *			 !0 otherwise.
11950Sstevel@tonic-gate  *
11960Sstevel@tonic-gate  * PURPOSE:	Validation function for a volume request's number of
11970Sstevel@tonic-gate  *		redundant data paths.  This value controls the number
11980Sstevel@tonic-gate  *		of independent data paths slices components selected
11990Sstevel@tonic-gate  *		for the volume should have.
12000Sstevel@tonic-gate  *
12010Sstevel@tonic-gate  *		If the request specifies npaths, the value must be
12020Sstevel@tonic-gate  *		between 1 and 4 (4 is an arbitrary upper limit, there
12030Sstevel@tonic-gate  *		is no known physical limit).
12040Sstevel@tonic-gate  */
12050Sstevel@tonic-gate static int
validate_request_npaths(devconfig_t * req)12060Sstevel@tonic-gate validate_request_npaths(
12070Sstevel@tonic-gate 	devconfig_t	*req)
12080Sstevel@tonic-gate {
12090Sstevel@tonic-gate 	uint16_t npaths = 0;
12100Sstevel@tonic-gate 	uint16_t minpaths = 1;
12110Sstevel@tonic-gate 	uint16_t maxpaths = 4;
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	int	error = 0;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	if ((error = devconfig_get_volume_npaths(req, &npaths)) != 0) {
12160Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
12170Sstevel@tonic-gate 		error = 0;
12180Sstevel@tonic-gate 	    }
12190Sstevel@tonic-gate 	    return (error);
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	if (npaths < minpaths || npaths > maxpaths) {
12230Sstevel@tonic-gate 	    volume_set_error(
12240Sstevel@tonic-gate 	    gettext("requested number of redundant paths must be "
12250Sstevel@tonic-gate 		    "between %d and %d.\n"), minpaths, maxpaths);
12260Sstevel@tonic-gate 	    error = -1;
12270Sstevel@tonic-gate 	}
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	if ((npaths > 1) && (is_mpxio_enabled() != B_TRUE)) {
12310Sstevel@tonic-gate 	    volume_set_error(
12320Sstevel@tonic-gate 		    gettext("requested number of redundant paths (%d) cannot "
12330Sstevel@tonic-gate 			    "be provided, MPXIO is not enabled on this "
12340Sstevel@tonic-gate 			    "system."),
12350Sstevel@tonic-gate 		    npaths);
12360Sstevel@tonic-gate 	    error = -1;
12370Sstevel@tonic-gate 	}
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	return (error);
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate /*
12430Sstevel@tonic-gate  * FUNCTION:	validate_request_submirrors(devconfig_t *req)
12440Sstevel@tonic-gate  *
12450Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t volume request
12460Sstevel@tonic-gate  *
12470Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested mirror's submirrors
12480Sstevel@tonic-gate  *				pass validation
12490Sstevel@tonic-gate  *			 !0 otherwise.
12500Sstevel@tonic-gate  *
12510Sstevel@tonic-gate  * PURPOSE:	Validation function for a mirror volume request's
12520Sstevel@tonic-gate  *		explicitly specified submirror components.
12530Sstevel@tonic-gate  *
12540Sstevel@tonic-gate  * 		Items to check:
12550Sstevel@tonic-gate  *		a. submirror types
12560Sstevel@tonic-gate  *		b. submirror number
12570Sstevel@tonic-gate  *		c. submirror sizes
12580Sstevel@tonic-gate  */
12590Sstevel@tonic-gate static int
validate_request_submirrors(devconfig_t * req)12600Sstevel@tonic-gate validate_request_submirrors(
12610Sstevel@tonic-gate 	devconfig_t	*req)
12620Sstevel@tonic-gate {
12630Sstevel@tonic-gate 	dlist_t	*submirrors = NULL;
12640Sstevel@tonic-gate 	int	error = 0;
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	submirrors = devconfig_get_components(req);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	((error = validate_submirror_types(submirrors)) != 0) ||
12690Sstevel@tonic-gate 	(error = validate_submirror_number(req, submirrors)) ||
12700Sstevel@tonic-gate 	(error = validate_submirror_sizes(req, submirrors));
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	return (error);
12730Sstevel@tonic-gate }
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate /*
12760Sstevel@tonic-gate  * FUNCTION:	validate_submirror_types(dlist_t *subs)
12770Sstevel@tonic-gate  *
12780Sstevel@tonic-gate  * INPUT:	subs	- a list of submirror requests
12790Sstevel@tonic-gate  *
12800Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested submirrors
12810Sstevel@tonic-gate  *				pass validation
12820Sstevel@tonic-gate  *			 !0 otherwise.
12830Sstevel@tonic-gate  *
12840Sstevel@tonic-gate  * PURPOSE:	Validation function for a mirror volume request's
12850Sstevel@tonic-gate  *		explicitly specified submirror components.
12860Sstevel@tonic-gate  *
12870Sstevel@tonic-gate  * 		Checks that each requested submirror request
12880Sstevel@tonic-gate  *		is for a concat or stripe.
12890Sstevel@tonic-gate  */
12900Sstevel@tonic-gate static int
validate_submirror_types(dlist_t * submirrors)12910Sstevel@tonic-gate validate_submirror_types(
12920Sstevel@tonic-gate 	dlist_t	*submirrors)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate 	dlist_t *iter;
12950Sstevel@tonic-gate 	int 	error = 0;
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	/* specified submirrors must be stripes or concats */
12980Sstevel@tonic-gate 	for (iter = submirrors;
12990Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
13000Sstevel@tonic-gate 	    iter = iter->next) {
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	    devconfig_t		*submir = (devconfig_t *)iter->obj;
13030Sstevel@tonic-gate 	    component_type_t	submirtype = TYPE_UNKNOWN;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	    if ((error = devconfig_get_type(submir, &submirtype)) != 0) {
13060Sstevel@tonic-gate 		volume_set_error(
13070Sstevel@tonic-gate 			gettext("failed to get requested component type.\n"));
13080Sstevel@tonic-gate 		break;
13090Sstevel@tonic-gate 	    }
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	    if (submirtype != TYPE_CONCAT && submirtype != TYPE_STRIPE) {
13120Sstevel@tonic-gate 		volume_set_error(
13130Sstevel@tonic-gate 			gettext("requested submirror type \"%s\" "
13140Sstevel@tonic-gate 				"is not valid.\n"),
13150Sstevel@tonic-gate 			devconfig_type_to_str(submirtype));
13160Sstevel@tonic-gate 		error = -1;
13170Sstevel@tonic-gate 		break;
13180Sstevel@tonic-gate 	    }
13190Sstevel@tonic-gate 	}
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	return (error);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate /*
13250Sstevel@tonic-gate  * FUNCTION:	validate_submirror_number(devconfig_t *req, dlist_t *subs)
13260Sstevel@tonic-gate  *
13270Sstevel@tonic-gate  * INPUT:	req	- the mirror request
13280Sstevel@tonic-gate  *		subs	- the list of requested submirrors
13290Sstevel@tonic-gate  *
13300Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested submirrors
13310Sstevel@tonic-gate  *				pass validation
13320Sstevel@tonic-gate  *			 !0 otherwise.
13330Sstevel@tonic-gate  *
13340Sstevel@tonic-gate  * PURPOSE:	Validation function for a mirror volume request's
13350Sstevel@tonic-gate  *		explicitly specified submirror components.
13360Sstevel@tonic-gate  *
13370Sstevel@tonic-gate  * 		Checks that the number of submirror components
13380Sstevel@tonic-gate  *		that have been specified matches the number of
13390Sstevel@tonic-gate  *		submirrors specified.
13400Sstevel@tonic-gate  */
13410Sstevel@tonic-gate static int
validate_submirror_number(devconfig_t * req,dlist_t * submirrors)13420Sstevel@tonic-gate validate_submirror_number(
13430Sstevel@tonic-gate 	devconfig_t	*req,
13440Sstevel@tonic-gate 	dlist_t		*submirrors)
13450Sstevel@tonic-gate {
13460Sstevel@tonic-gate 	uint16_t	nsubs = 0;
13470Sstevel@tonic-gate 	int 		error = 0;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	if ((error = devconfig_get_mirror_nsubs(req, &nsubs)) != 0) {
13500Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
13510Sstevel@tonic-gate 		/* not specified */
13520Sstevel@tonic-gate 		error = 0;
13530Sstevel@tonic-gate 	    }
13540Sstevel@tonic-gate 	} else if ((submirrors != NULL) &&
13550Sstevel@tonic-gate 	    (dlist_length(submirrors) != nsubs)) {
13560Sstevel@tonic-gate 	    volume_set_error(
13570Sstevel@tonic-gate 		    gettext("the requested number of submirrors (%d) differs "
13580Sstevel@tonic-gate 			    "from the number of specified submirrors (%d).\n"),
13590Sstevel@tonic-gate 		    nsubs, dlist_length(submirrors));
13600Sstevel@tonic-gate 	    error = -1;
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	return (error);
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate /*
13670Sstevel@tonic-gate  * FUNCTION:	validate_submirror_sizes(devconfig_t *req,
13680Sstevel@tonic-gate  *			dlist_t *submirrors)
13690Sstevel@tonic-gate  *
13700Sstevel@tonic-gate  * INPUT:	req	- the mirror request
13710Sstevel@tonic-gate  *		submirrors	- the list of requested submirrors
13720Sstevel@tonic-gate  *
13730Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested submirrors
13740Sstevel@tonic-gate  *				pass validation
13750Sstevel@tonic-gate  *			 !0 otherwise.
13760Sstevel@tonic-gate  *
13770Sstevel@tonic-gate  * PURPOSE:	Validation function for a mirror volume request's
13780Sstevel@tonic-gate  *		explicitly specified size.  Assumes that the mirror's size
13790Sstevel@tonic-gate  *		has been validated by validate_request_size().
13800Sstevel@tonic-gate  *
13810Sstevel@tonic-gate  * 		Compares explicitly requested mirror size against specified
13820Sstevel@tonic-gate  *		component sizes and checks:
13830Sstevel@tonic-gate  *
13840Sstevel@tonic-gate  * 		- any submirror request that specifies both size and
13850Sstevel@tonic-gate  *		  components is invalid
13860Sstevel@tonic-gate  *		- any submirror request specifying a size different
13870Sstevel@tonic-gate  *		  than that explictly requested for the mirror is
13880Sstevel@tonic-gate  *		  invalid
13890Sstevel@tonic-gate  *		- a submirror request specifying a size < 512K is invalid.
13900Sstevel@tonic-gate  *
13910Sstevel@tonic-gate  *		Other validation/warnings:
13920Sstevel@tonic-gate  *
13930Sstevel@tonic-gate  *		- submirrors that specify components may end up with
13940Sstevel@tonic-gate  *		  usable capacity that differs from what was specified
13950Sstevel@tonic-gate  *		  for the mirror.
13960Sstevel@tonic-gate  *
13970Sstevel@tonic-gate  *		- submirrors which specify neither size nor components are
13980Sstevel@tonic-gate  *		  assumed to be the size requested for the mirror.  If the
13990Sstevel@tonic-gate  *		  mirror size is not specified, the first explicit size for
14000Sstevel@tonic-gate  *		  a submirror is assumed as the size for the mirror.
14010Sstevel@tonic-gate  */
14020Sstevel@tonic-gate static int
validate_submirror_sizes(devconfig_t * req,dlist_t * submirrors)14030Sstevel@tonic-gate validate_submirror_sizes(
14040Sstevel@tonic-gate 	devconfig_t	*req,
14050Sstevel@tonic-gate 	dlist_t		*submirrors)
14060Sstevel@tonic-gate {
14070Sstevel@tonic-gate 	dlist_t		*submirs_with_size = NULL;
14080Sstevel@tonic-gate 	dlist_t		*submirs_with_comps = NULL;
14090Sstevel@tonic-gate 	dlist_t		*submirs_with_nothing = NULL;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	dlist_t		*iter = NULL;
14120Sstevel@tonic-gate 	uint64_t	mirror_size = 0;
14130Sstevel@tonic-gate 	uint64_t	assumed_size = 0;
14140Sstevel@tonic-gate 	int		error = 0;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	if (submirrors == NULL || dlist_length(submirrors) == 0) {
14170Sstevel@tonic-gate 	    return (0);
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	if ((error = devconfig_get_size(req, &mirror_size)) != 0) {
14210Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
14220Sstevel@tonic-gate 		error = 0;
14230Sstevel@tonic-gate 	    } else {
14240Sstevel@tonic-gate 		return (error);
14250Sstevel@tonic-gate 	    }
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	/*
14290Sstevel@tonic-gate 	 * check size and component for each submirror,
14300Sstevel@tonic-gate 	 * collect those that specify size, components or neither
14310Sstevel@tonic-gate 	 * into separate lists.
14320Sstevel@tonic-gate 	 */
14330Sstevel@tonic-gate 	for (iter = submirrors;
14340Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
14350Sstevel@tonic-gate 	    iter = iter->next) {
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	    devconfig_t *submir = (devconfig_t *)iter->obj;
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	    error = validate_submirror_size_and_components(submir,
14400Sstevel@tonic-gate 		    mirror_size, &assumed_size, &submirs_with_size,
14410Sstevel@tonic-gate 		    &submirs_with_comps, &submirs_with_nothing);
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	}
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	if (error == 0) {
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	    int n_size = dlist_length(submirs_with_size);
14480Sstevel@tonic-gate 	    int n_comp = dlist_length(submirs_with_comps);
14490Sstevel@tonic-gate 	    int n_none = dlist_length(submirs_with_nothing);
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	    if ((n_size != 0) && (n_comp != 0)) {
14520Sstevel@tonic-gate 		/* some submirrors specified size, some components */
14530Sstevel@tonic-gate 		oprintf(OUTPUT_TERSE,
14540Sstevel@tonic-gate 			gettext("  *** warning: %d submirrors are specified "
14550Sstevel@tonic-gate 				"by size, %d specified by components.\n"
14560Sstevel@tonic-gate 				"      The resulting mirror capacity will be "
14570Sstevel@tonic-gate 				"that of the smallest submirror.\n"),
14580Sstevel@tonic-gate 			n_size, n_comp);
14590Sstevel@tonic-gate 	    }
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	    if (n_none != 0) {
14620Sstevel@tonic-gate 		if (assumed_size != 0) {
14630Sstevel@tonic-gate 		    /* some submirrors specified neither size or components */
14640Sstevel@tonic-gate 		    char *sizestr = NULL;
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 		    (void) bytes_to_sizestr(
14670Sstevel@tonic-gate 			    assumed_size, &sizestr, universal_units, B_FALSE);
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 		    oprintf(OUTPUT_TERSE,
14700Sstevel@tonic-gate 			    gettext("  *** warning: %d submirrors specified "
14710Sstevel@tonic-gate 				    "neither size or components,\n"
14720Sstevel@tonic-gate 				    "      the assumed size is %s.\n"),
14730Sstevel@tonic-gate 			    n_none, sizestr);
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 		    free(sizestr);
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 		} else if (mirror_size == 0) {
14780Sstevel@tonic-gate 		    volume_set_error(
14790Sstevel@tonic-gate 			    gettext("no size specified for requested "
14800Sstevel@tonic-gate 				    "mirror and no sizes/components "
14810Sstevel@tonic-gate 				    "specified for its submirrors."));
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 		    error = -1;
14840Sstevel@tonic-gate 		}
14850Sstevel@tonic-gate 	    }
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	    dlist_free_items(submirs_with_size, NULL);
14880Sstevel@tonic-gate 	    dlist_free_items(submirs_with_comps, NULL);
14890Sstevel@tonic-gate 	    dlist_free_items(submirs_with_nothing, NULL);
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	return (error);
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate /*
14970Sstevel@tonic-gate  * FUNCTION:	validate_submirror_size_and_components(
14980Sstevel@tonic-gate  *			devconfig_t *submir,
14990Sstevel@tonic-gate  *			uint64_t mirror_size,
15000Sstevel@tonic-gate  *			uint64_t *assumed_size,
15010Sstevel@tonic-gate  *			dlist_t	**submirs_with_size,
15020Sstevel@tonic-gate  *			dlist_t	**submirs_with_comps,
15030Sstevel@tonic-gate  *			dlist_t	**submirs_no_size_or_comps)
15040Sstevel@tonic-gate  *
15050Sstevel@tonic-gate  * INPUT:	submir	- a specific submirror request
15060Sstevel@tonic-gate  *		mirror_size, - the size specified for the mirror
15070Sstevel@tonic-gate  *
15080Sstevel@tonic-gate  * OUTPUT:	assumed_size - the assumed size of the mirror,
15090Sstevel@tonic-gate  *				if none specified.
15100Sstevel@tonic-gate  *		submirs_with_size - pointer to a list of submirror
15110Sstevel@tonic-gate  *				requests that specify a size
15120Sstevel@tonic-gate  *		submirs_with_comps - pointer to a list of submirror
15130Sstevel@tonic-gate  *				requests that specify components
15140Sstevel@tonic-gate  *		submirs_no_size_or_comps - pointer to a list of
15150Sstevel@tonic-gate  *				submirror requests that specify neither
15160Sstevel@tonic-gate  *				a size or components
15170Sstevel@tonic-gate  *
15180Sstevel@tonic-gate  * RETURNS:	int	- 0 if the requested submirrors
15190Sstevel@tonic-gate  *				pass validation
15200Sstevel@tonic-gate  *			 !0 otherwise.
15210Sstevel@tonic-gate  *
15220Sstevel@tonic-gate  * PURPOSE:	Validation function which checks a specific submirror
15230Sstevel@tonic-gate  *		request's size and components against the parent mirror's
15240Sstevel@tonic-gate  *		size.
15250Sstevel@tonic-gate  *
15260Sstevel@tonic-gate  * 		- any submirror request that specifies both size and
15270Sstevel@tonic-gate  *		  components is invalid
15280Sstevel@tonic-gate  *		- any submirror request specifying a size different
15290Sstevel@tonic-gate  *		  than that explictly requested for the mirror is
15300Sstevel@tonic-gate  *		  invalid
15310Sstevel@tonic-gate  *		- a submirror request specifying a size < 512K is invalid.
15320Sstevel@tonic-gate  *		- any components specified for a submirror are validated.
15330Sstevel@tonic-gate  *
15340Sstevel@tonic-gate  *		If the submirror passes the validation checks, it is added
15350Sstevel@tonic-gate  *		to the appropriate output list.
15360Sstevel@tonic-gate  *
15370Sstevel@tonic-gate  *		If the input mirror_size is 0 and the submirror specifies
15380Sstevel@tonic-gate  *		a valid size, the submirror size is returned as the
15390Sstevel@tonic-gate  *		assumed_size for the mirror.
15400Sstevel@tonic-gate  */
15410Sstevel@tonic-gate static int
validate_submirror_size_and_components(devconfig_t * submir,uint64_t mirror_size,uint64_t * assumed_size,dlist_t ** submirs_with_size,dlist_t ** submirs_with_comps,dlist_t ** submirs_no_size_or_comps)15420Sstevel@tonic-gate validate_submirror_size_and_components(
15430Sstevel@tonic-gate 	devconfig_t	*submir,
15440Sstevel@tonic-gate 	uint64_t	mirror_size,
15450Sstevel@tonic-gate 	uint64_t	*assumed_size,
15460Sstevel@tonic-gate 	dlist_t		**submirs_with_size,
15470Sstevel@tonic-gate 	dlist_t		**submirs_with_comps,
15480Sstevel@tonic-gate 	dlist_t		**submirs_no_size_or_comps)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate 	uint64_t		submir_size = 0;
15510Sstevel@tonic-gate 	component_type_t	submir_type = TYPE_UNKNOWN;
15520Sstevel@tonic-gate 	char			*submir_typestr = NULL;
15530Sstevel@tonic-gate 	dlist_t			*submir_comps = NULL;
15540Sstevel@tonic-gate 	dlist_t			*item = NULL;
15550Sstevel@tonic-gate 	int			n_submir_comps = 0;
15560Sstevel@tonic-gate 	int			error = 0;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	submir_comps = devconfig_get_components(submir);
15590Sstevel@tonic-gate 	if (submir_comps != NULL) {
15600Sstevel@tonic-gate 	    n_submir_comps = dlist_length(submir_comps);
15610Sstevel@tonic-gate 	}
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	if ((error = devconfig_get_size(submir, &submir_size)) != 0) {
15640Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
15650Sstevel@tonic-gate 		/* submirror size not specified */
15660Sstevel@tonic-gate 		error = 0;
15670Sstevel@tonic-gate 		submir_size = 0;
15680Sstevel@tonic-gate 	    }
15690Sstevel@tonic-gate 	}
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	if (error != 0) {
15720Sstevel@tonic-gate 	    return (error);
15730Sstevel@tonic-gate 	}
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	/* submirror type previously validated */
15760Sstevel@tonic-gate 	(void) devconfig_get_type(submir, &submir_type);
15770Sstevel@tonic-gate 	submir_typestr = devconfig_type_to_str(submir_type);
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	if (submir_size == 0) {
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 	    /* submirror has no size, components? */
15820Sstevel@tonic-gate 	    if (n_submir_comps > 0) {
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 		/* validate components */
15850Sstevel@tonic-gate 		error = validate_slice_components(submir, submir_type);
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 		item = dlist_new_item((void *)submir);
15880Sstevel@tonic-gate 		if (item == NULL) {
15890Sstevel@tonic-gate 		    error = ENOMEM;
15900Sstevel@tonic-gate 		} else {
15910Sstevel@tonic-gate 		    *submirs_with_comps =
15920Sstevel@tonic-gate 			dlist_append(item, *submirs_with_comps, AT_TAIL);
15930Sstevel@tonic-gate 		}
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	    } else {
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 		/* no size or components */
15980Sstevel@tonic-gate 		item = dlist_new_item((void *)submir);
15990Sstevel@tonic-gate 		if (item == NULL) {
16000Sstevel@tonic-gate 		    error = ENOMEM;
16010Sstevel@tonic-gate 		} else {
16020Sstevel@tonic-gate 		    *submirs_no_size_or_comps =
16030Sstevel@tonic-gate 			dlist_append(item, *submirs_no_size_or_comps, AT_TAIL);
16040Sstevel@tonic-gate 		}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	    }
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	} else {
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	    /* submirror has size, check it */
16110Sstevel@tonic-gate 	    if (error == 0) {
16120Sstevel@tonic-gate 		error = validate_minimum_size(submir_size);
16130Sstevel@tonic-gate 	    }
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	    /* check size against mirror's size */
16160Sstevel@tonic-gate 	    if ((error == 0) && (submir_size != mirror_size)) {
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		if (mirror_size != 0) {
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 		    /* sizes differ */
16210Sstevel@tonic-gate 		    char *sizestr = NULL;
16220Sstevel@tonic-gate 		    char *mstr = NULL;
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 		    (void) bytes_to_sizestr(
16250Sstevel@tonic-gate 			    submir_size, &sizestr, universal_units, B_FALSE);
16260Sstevel@tonic-gate 		    (void) bytes_to_sizestr(
16270Sstevel@tonic-gate 			    mirror_size, &mstr, universal_units, B_FALSE);
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 		    volume_set_error(
16300Sstevel@tonic-gate 			    gettext("the requested submirror size (%s) "
16310Sstevel@tonic-gate 				    "differs from the requested mirror "
16320Sstevel@tonic-gate 				    "size (%s).\n"),
16330Sstevel@tonic-gate 			    sizestr, mstr);
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 		    error = -1;
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 		    free(sizestr);
16380Sstevel@tonic-gate 		    free(mstr);
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 		} else if (*assumed_size == 0) {
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 		    /* first size assumed as mirror size */
16430Sstevel@tonic-gate 		    char *sizestr = NULL;
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 		    (void) bytes_to_sizestr(
16460Sstevel@tonic-gate 			    submir_size, &sizestr, universal_units, B_FALSE);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 		    oprintf(OUTPUT_TERSE,
16490Sstevel@tonic-gate 			    gettext("  *** warning, using first "
16500Sstevel@tonic-gate 				    "explicit submirror size (%s)\n"
16510Sstevel@tonic-gate 				    "      as the mirror size\n"),
16520Sstevel@tonic-gate 			    sizestr);
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 		    *assumed_size = submir_size;
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 		    free(sizestr);
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 		} else if (submir_size != *assumed_size) {
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 		    /* submirror sizes differ */
16610Sstevel@tonic-gate 		    char *sizestr1 = NULL;
16620Sstevel@tonic-gate 		    char *sizestr2 = NULL;
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 		    (void) bytes_to_sizestr(
16650Sstevel@tonic-gate 			    submir_size, &sizestr1, universal_units, B_FALSE);
16660Sstevel@tonic-gate 		    (void) bytes_to_sizestr(
16670Sstevel@tonic-gate 			    *assumed_size, &sizestr2, universal_units, B_FALSE);
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 		    volume_set_error(
16700Sstevel@tonic-gate 			    gettext("submirror specifies different "
16710Sstevel@tonic-gate 				    "size (%s) than a previous "
16720Sstevel@tonic-gate 				    "submirror (%s)\n"),
16730Sstevel@tonic-gate 			    sizestr1, sizestr2);
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 		    free(sizestr1);
16760Sstevel@tonic-gate 		    free(sizestr2);
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 		    error = -1;
16790Sstevel@tonic-gate 		}
16800Sstevel@tonic-gate 	    }
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	    if ((error == 0) && (n_submir_comps > 0)) {
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 		/* size and subcomponents specified */
16850Sstevel@tonic-gate 		char *sizestr = NULL;
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 		(void) bytes_to_sizestr(
16880Sstevel@tonic-gate 			submir_size, &sizestr, universal_units, B_FALSE);
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 		volume_set_error(
16910Sstevel@tonic-gate 			gettext("%s submirror specifies both an "
16920Sstevel@tonic-gate 				"explicit size (%s) and components.\n"),
16930Sstevel@tonic-gate 			submir_typestr, sizestr);
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 		free(sizestr);
16960Sstevel@tonic-gate 		error = -1;
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 	    }
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	    if (error == 0) {
17010Sstevel@tonic-gate 		item = dlist_new_item((void *)submir);
17020Sstevel@tonic-gate 		if (item == NULL) {
17030Sstevel@tonic-gate 		    error = ENOMEM;
17040Sstevel@tonic-gate 		} else {
17050Sstevel@tonic-gate 		    *submirs_with_size =
17060Sstevel@tonic-gate 			dlist_append(item, *submirs_with_size, AT_TAIL);
17070Sstevel@tonic-gate 		}
17080Sstevel@tonic-gate 	    }
17090Sstevel@tonic-gate 	}
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	return (error);
17120Sstevel@tonic-gate }
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate /*
17160Sstevel@tonic-gate  * FUNCTION:	validate_slice_components(devconfig_t *req,
17170Sstevel@tonic-gate  *			component_type_t type)
17180Sstevel@tonic-gate  *
17190Sstevel@tonic-gate  * INPUT:	req	- the request
17200Sstevel@tonic-gate  *		type	- the type of volume being requested
17210Sstevel@tonic-gate  *
17220Sstevel@tonic-gate  * SIDEEFFECT:	if the slice component is otherwise valid, an attempt is made
17230Sstevel@tonic-gate  *		to reserve it.
17240Sstevel@tonic-gate  *
17250Sstevel@tonic-gate  * RETURNS:	int	- 0 if the request passes slice component validation
17260Sstevel@tonic-gate  *			 !0 otherwise.
17270Sstevel@tonic-gate  *
17280Sstevel@tonic-gate  * PURPOSE:	Validation function for a concat, stripe or HSP request's
17290Sstevel@tonic-gate  *		explicitly specified slice components.
17300Sstevel@tonic-gate  *
17310Sstevel@tonic-gate  *		Is the component slice a known device
17320Sstevel@tonic-gate  *		Is the component slice available
17330Sstevel@tonic-gate  *		Is the component slice already reserved
17340Sstevel@tonic-gate  *
17350Sstevel@tonic-gate  *		If the request is for a stripe or concat and the
17360Sstevel@tonic-gate  *		request specifies an explicit size, it cannot also
17370Sstevel@tonic-gate  *		specify component slices.  This is a validation failure.
17380Sstevel@tonic-gate  *
17390Sstevel@tonic-gate  *		If the request is for a stripe, the number of specified
17400Sstevel@tonic-gate  *		slice components must agree with any expilcit specification
17410Sstevel@tonic-gate  *		of the minimum or maximum number of components the stripe
17420Sstevel@tonic-gate  *		should have.
17430Sstevel@tonic-gate  */
17440Sstevel@tonic-gate static int
validate_slice_components(devconfig_t * req,component_type_t type)17450Sstevel@tonic-gate validate_slice_components(
17460Sstevel@tonic-gate 	devconfig_t	*req,
17470Sstevel@tonic-gate 	component_type_t type)
17480Sstevel@tonic-gate {
17490Sstevel@tonic-gate 	dlist_t	*list = NULL;
17500Sstevel@tonic-gate 	dlist_t	*iter = NULL;
17510Sstevel@tonic-gate 	int	error = 0;
17520Sstevel@tonic-gate 	int	ncomp = 0;
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 	char	*dsname = get_request_diskset();
17550Sstevel@tonic-gate 	char	*voltype = devconfig_type_to_str(type);
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	list = devconfig_get_components(req);
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	for (iter = list; (iter != NULL) && (error == 0); iter = iter->next) {
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	    devconfig_t		*comp = (devconfig_t *)iter->obj;
17620Sstevel@tonic-gate 	    component_type_t	ctype = TYPE_UNKNOWN;
17630Sstevel@tonic-gate 	    char		*cname = NULL;
17640Sstevel@tonic-gate 	    dm_descriptor_t	slice = (dm_descriptor_t)0;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	    if ((error = devconfig_get_type(comp, &ctype)) != 0) {
17670Sstevel@tonic-gate 		volume_set_error(
17680Sstevel@tonic-gate 			gettext("error getting requested component type."),
17690Sstevel@tonic-gate 			voltype);
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 		continue;
17720Sstevel@tonic-gate 	    }
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	    if ((error = devconfig_get_name(comp, &cname)) != 0) {
17750Sstevel@tonic-gate 		volume_set_error(
17760Sstevel@tonic-gate 		    gettext("error getting requested component name."));
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 		continue;
17790Sstevel@tonic-gate 	    }
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	    if (cname == NULL || cname[0] == '\0') {
17820Sstevel@tonic-gate 		volume_set_error(
17830Sstevel@tonic-gate 			gettext("%s requested component has no name."),
17840Sstevel@tonic-gate 			voltype);
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 		error = -1;
17870Sstevel@tonic-gate 		continue;
17880Sstevel@tonic-gate 	    }
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 	    if (ctype == TYPE_SLICE) {
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 		boolean_t	in_set = B_FALSE;
17930Sstevel@tonic-gate 		boolean_t	is_avail = B_FALSE;
17940Sstevel@tonic-gate 		boolean_t	is_rsvd = B_FALSE;
17950Sstevel@tonic-gate 		dm_descriptor_t	disk = (dm_descriptor_t)0;
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 		/* is the slice known and explicitly available? */
17980Sstevel@tonic-gate 		if ((error = slice_is_available(cname, req,
17990Sstevel@tonic-gate 		    &is_avail)) != 0) {
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 		    if (error == ENODEV) {
18020Sstevel@tonic-gate 			volume_set_error(
18030Sstevel@tonic-gate 				gettext("%s requested component does not "
18040Sstevel@tonic-gate 					"exist: \"%s\"."),
18050Sstevel@tonic-gate 				voltype, cname);
18060Sstevel@tonic-gate 			error = -1;
18070Sstevel@tonic-gate 		    }
18080Sstevel@tonic-gate 		    continue;
18090Sstevel@tonic-gate 		}
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 		if (is_avail != B_TRUE) {
18120Sstevel@tonic-gate 		    volume_set_error(
18130Sstevel@tonic-gate 			    gettext("%s requested component is "
18140Sstevel@tonic-gate 				    "unavailable: \"%s\"."),
18150Sstevel@tonic-gate 			    voltype, cname);
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 		    error = -1;
18180Sstevel@tonic-gate 		    continue;
18190Sstevel@tonic-gate 		}
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 		/* get slice and its disk */
18220Sstevel@tonic-gate 		((error = slice_get_by_name(cname, &slice)) != 0) ||
18230Sstevel@tonic-gate 		(error = slice_get_disk(slice, &disk)) ||
18240Sstevel@tonic-gate 		(error = is_reserved_slice(slice, &is_rsvd)) ||
18250Sstevel@tonic-gate 		(error = is_disk_in_diskset(disk, dsname, &in_set));
18260Sstevel@tonic-gate 		if (error != 0) {
18270Sstevel@tonic-gate 		    continue;
18280Sstevel@tonic-gate 		}
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate 		/* is disk in the set? */
18310Sstevel@tonic-gate 		if (in_set != B_TRUE) {
18320Sstevel@tonic-gate 		    volume_set_error(
18330Sstevel@tonic-gate 			    gettext("%s specifies a component not in "
18340Sstevel@tonic-gate 				    "disk set \"%s\": \"%s\"."),
18350Sstevel@tonic-gate 			    voltype, dsname, cname);
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 		    error = -1;
18380Sstevel@tonic-gate 		    continue;
18390Sstevel@tonic-gate 		}
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 		/* was slice specified in some other request? */
18420Sstevel@tonic-gate 		if (is_rsvd == B_TRUE) {
18430Sstevel@tonic-gate 		    /* include aliases in the error */
18440Sstevel@tonic-gate 		    char *aliases =
18450Sstevel@tonic-gate 			get_device_aliases_string((dm_descriptor_t)slice);
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 		    if (aliases[0] != NULL) {
18480Sstevel@tonic-gate 			volume_set_error(
18490Sstevel@tonic-gate 				gettext("%s specifies a previously used "
18500Sstevel@tonic-gate 					"component: \"%s\" "
18510Sstevel@tonic-gate 					"(aliases: %s).\n"),
18520Sstevel@tonic-gate 				voltype, cname, aliases);
18530Sstevel@tonic-gate 		    } else {
18540Sstevel@tonic-gate 			volume_set_error(
18550Sstevel@tonic-gate 				gettext("%s specifies a previously used "
18560Sstevel@tonic-gate 					"component: \"%s\"\n"),
18570Sstevel@tonic-gate 				voltype, cname);
18580Sstevel@tonic-gate 		    }
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 		    error = -1;
18610Sstevel@tonic-gate 		    continue;
18620Sstevel@tonic-gate 		}
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 		/* component is ok, reserve it */
18650Sstevel@tonic-gate 		error = add_reserved_slice(slice);
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 		/*
18680Sstevel@tonic-gate 		 * the reserved slice component still needs to be
18690Sstevel@tonic-gate 		 * checked against slices in use by SVM, but that
18700Sstevel@tonic-gate 		 * information isn't available yet: the usable
18710Sstevel@tonic-gate 		 * slice derivation happens after validation.
18720Sstevel@tonic-gate 		 *
18730Sstevel@tonic-gate 		 * validate_reserved_slices() can be used to check
18740Sstevel@tonic-gate 		 * them once the usable slices are determined.
18750Sstevel@tonic-gate 		 */
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 	    } else {
18780Sstevel@tonic-gate 		volume_set_error(
18790Sstevel@tonic-gate 			gettext("%s requested component has illegal type."),
18800Sstevel@tonic-gate 			voltype);
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 		error = -1;
18830Sstevel@tonic-gate 		continue;
18840Sstevel@tonic-gate 	    }
18850Sstevel@tonic-gate 	}
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	if (error != 0) {
18880Sstevel@tonic-gate 	    return (error);
18890Sstevel@tonic-gate 	}
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 	ncomp = dlist_length(list);
18920Sstevel@tonic-gate 	if ((ncomp > 0) && (type == TYPE_CONCAT || type == TYPE_STRIPE)) {
18930Sstevel@tonic-gate 	    /* explicit size requested for the stripe/concat? */
18940Sstevel@tonic-gate 	    uint64_t	size = 0;
18950Sstevel@tonic-gate 	    if ((error = devconfig_get_size(req, &size)) != 0) {
18960Sstevel@tonic-gate 		if (error == ERR_ATTR_UNSET) {
18970Sstevel@tonic-gate 		    error = 0;
18980Sstevel@tonic-gate 		}
18990Sstevel@tonic-gate 	    } else {
19000Sstevel@tonic-gate 		/* size and components both specified */
19010Sstevel@tonic-gate 		char *sizestr = NULL;
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 		(void) bytes_to_sizestr(
19040Sstevel@tonic-gate 			size, &sizestr, universal_units, B_FALSE);
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 		volume_set_error(
19070Sstevel@tonic-gate 			gettext("%s specifies both an explicit size (%s) "
19080Sstevel@tonic-gate 				"and components."),
19090Sstevel@tonic-gate 			voltype, sizestr);
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 		free(sizestr);
19120Sstevel@tonic-gate 		error = -1;
19130Sstevel@tonic-gate 	    }
19140Sstevel@tonic-gate 	}
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 	if (error != 0) {
19170Sstevel@tonic-gate 	    return (error);
19180Sstevel@tonic-gate 	}
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	if ((ncomp > 0) && (type == TYPE_STRIPE)) {
19210Sstevel@tonic-gate 	    /* does # of components agree with min & max comps? */
19220Sstevel@tonic-gate 	    uint16_t min = 0;
19230Sstevel@tonic-gate 	    uint16_t max = 0;
19240Sstevel@tonic-gate 	    if ((error = devconfig_get_stripe_mincomp(req, &min)) != 0) {
19250Sstevel@tonic-gate 		if (error == ERR_ATTR_UNSET) {
19260Sstevel@tonic-gate 		    /* min comp not requested */
19270Sstevel@tonic-gate 		    error = 0;
19280Sstevel@tonic-gate 		} else {
19290Sstevel@tonic-gate 		    /* error getting requested mincomp */
19300Sstevel@tonic-gate 		    return (error);
19310Sstevel@tonic-gate 		}
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	    } else if (ncomp < min) {
19340Sstevel@tonic-gate 		/* specified comps < requested mincomp */
19350Sstevel@tonic-gate 		volume_set_error(
19360Sstevel@tonic-gate 			gettext("%s specifies fewer components (%d) than the "
19370Sstevel@tonic-gate 				"minimum number requested (%d).\n"),
19380Sstevel@tonic-gate 			voltype, ncomp, min);
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 		error = -1;
19410Sstevel@tonic-gate 		return (error);
19420Sstevel@tonic-gate 	    }
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	    if ((error = devconfig_get_stripe_maxcomp(req, &max)) != 0) {
19450Sstevel@tonic-gate 		if (error == ERR_ATTR_UNSET) {
19460Sstevel@tonic-gate 		    /* max comp not requested */
19470Sstevel@tonic-gate 		    error = 0;
19480Sstevel@tonic-gate 		} else {
19490Sstevel@tonic-gate 		    /* error getting request maxcomp */
19500Sstevel@tonic-gate 		    return (error);
19510Sstevel@tonic-gate 		}
19520Sstevel@tonic-gate 	    } else if (ncomp > max) {
19530Sstevel@tonic-gate 		/* specified comps > requested maxcomp */
19540Sstevel@tonic-gate 		volume_set_error(
19550Sstevel@tonic-gate 			gettext("%s specifies more components (%d) than the "
19560Sstevel@tonic-gate 				"maximum number requested (%d).\n"),
19570Sstevel@tonic-gate 			voltype, ncomp, max);
19580Sstevel@tonic-gate 		error = -1;
19590Sstevel@tonic-gate 		return (error);
19600Sstevel@tonic-gate 	    }
19610Sstevel@tonic-gate 	}
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 	return (error);
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate /*
19670Sstevel@tonic-gate  * Generate a list of known aliases for the input descriptor.
19680Sstevel@tonic-gate  *
19690Sstevel@tonic-gate  * The returned string buffer is in the form: "alias1", "alias2"...
19700Sstevel@tonic-gate  */
19710Sstevel@tonic-gate static char *
get_device_aliases_string(dm_descriptor_t desc)19720Sstevel@tonic-gate get_device_aliases_string(
19730Sstevel@tonic-gate 	dm_descriptor_t desc)
19740Sstevel@tonic-gate {
19750Sstevel@tonic-gate 	static char buf[BUFSIZ];
19760Sstevel@tonic-gate 	dlist_t *aliases = NULL;
19770Sstevel@tonic-gate 	dlist_t *iter = NULL;
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 	buf[0] = '\0';
19800Sstevel@tonic-gate 	(void) get_aliases(desc, &aliases);
19810Sstevel@tonic-gate 	for (iter = aliases; iter != NULL; iter = iter->next) {
19820Sstevel@tonic-gate 	    if (*buf == '\0') {
19830Sstevel@tonic-gate 		(void) snprintf(buf, BUFSIZ-1, "\"%s\"", (char *)iter->obj);
19840Sstevel@tonic-gate 	    } else {
19850Sstevel@tonic-gate 		char tmp[BUFSIZ];
19860Sstevel@tonic-gate 		(void) strcpy(buf, tmp);
19870Sstevel@tonic-gate 		(void) snprintf(buf, BUFSIZ-1, "%s, \"%s\"",
19880Sstevel@tonic-gate 			tmp, (char *)iter->obj);
19890Sstevel@tonic-gate 	    }
19900Sstevel@tonic-gate 	}
19910Sstevel@tonic-gate 	dlist_free_items(aliases, free);
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate 	return (buf);
19940Sstevel@tonic-gate }
1995