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