/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <libintl.h>
#include "metassist.h"
#include "volume_dlist.h"
#include "volume_error.h"
#include "volume_string.h"
#include "volume_output.h"
#define _LAYOUT_VALIDATE_C
#include "layout_discovery.h"
#include "layout_dlist_util.h"
#include "layout_device_cache.h"
#include "layout_device_util.h"
#include "layout_request.h"
#include "layout_slice.h"
#include "layout_svm_util.h"
#include "layout_validate.h"
/*
* This module contains the majority of the validation code which
* layout applies to input requests. The assumption/agreement with
* the controller implementation is that requests passed into layout
* have undergone syntactic validation and that layout is responsible
* for semantic validation.
*
* The semantic validation that is handled:
*
* 1. For a toplevel diskset request, validate:
*
* - the number of disksets is not exceeded
* - the number of devices is not exceeded
*
* (These items are not directly validated within this module,
* but it is useful to document that they are handled somewhere).
*
* 2. For any devconfig_t representing a volume request, verify that:
*
* - all HSP names are semantically valid. The name should conform
* to the HSP naming convention: hspXXX.
*
* - all concat, stripe, mirror, and volume names refer to
* unused, semantically valid metadevice names. Examples of
* bad data:
*
* - a valid volume name that is already in use (d0, d10)
*
* - a valid volume name that is used two or more times to
* refer to new elements in the request.
*
* - a valid volume name that is out of range (d99877,
* d44356) or exceeds the maximum number of possible
* volumes given the current SVM configuration.
*
* - all available and unavailable device specifications refer
* to existing controllers, disks, or slices on the system.
* Examples of bad data:
*
* - a valid but non-existent controller (c23, c2)
* - a valid but non-existent disk (c0t0d8, c1t0d0)
* - a valid slice on a non-existent disk or controller
* (c0t0d8s7, c1t0d05)
* - a valid slice on an existing disk (c0t0d0s12,
* c0t0d0s9)
*
* - any typed volume request that explicitly specifies components
* requires additional validation to detect syntactically valid
* expressions that are semantically ambiguous:
*
* a concat request that:
* - specifies size and components is invalid
*
* a stripe request that:
* - specifies size and components is invalid
* - specifies mincomp and components but not enough
* components is invalid
* - specifies maxcomp and components but too many
* components is invalid
*
* a HSP request that:
* - specifies components that are not appropriate for
* the volumes the HSP serves is invalid (?)
*
* a stripe, concat or HSP request that:
* - specifies a component that was used in a prior
* request is invalid
* - specifies a component that does not exist in the
* diskset is invalid (e.g., c0t0d0s0, but c0t0d0 is
* not yet in the diskset)
*
* a mirror request that:
* - specifies nsubs and components but not enough
* components is invalid
* - specifies components and the components specify
* different sizes results in a WARNING since the total
* usable capacity of the mirror is determined by the
* smallest of its submirrors.
* - specifies components and the components specify
* components results in a WARNING since the submirrors
* may end up with different sizes
*/
static int validate_request_name(
static int validate_request_size(
static int validate_minimum_size(
static uint64_t apply_layout_overhead_factor(
static int get_space_available_for_request(
static int do_available_space_check(
static int validate_request_redundancy_level(
devconfig_t *req);
static int validate_request_npaths(
devconfig_t *req);
static int validate_request_submirrors(
devconfig_t *req);
static int validate_submirror_types(
static int validate_submirror_number(
static int validate_submirror_sizes(
static int validate_submirror_size_and_components(
static int validate_slice_components(
static char *get_device_aliases_string(
static int validate_device_array(
char **array,
char *which,
static int add_reserved_name(char *name);
/*
* FUNCTION: release_validatation_caches()
*
* RETURNS: int - 0
*
* PURPOSE: Cleanup function.
*
* Purges list of reserved volume names. Should be called
* after all layout requests have been processed.
*/
int
{
_rsvd_names = NULL;
return (0);
}
/*
* FUNCTION: validate_basic_svm_config()
*
* RETURNS: int - 0 on success
* !0 on failure
*
* PURPOSE: Check to see if the local set metadb replicas have been created.
*
* Makes sure at least 1 metadb replica exists for the local set.
*/
int
{
int error = 0;
int nreplicas = 0;
if (nreplicas == 0) {
gettext("Failed: State database replicas must "
"exist before using %s.\n"
"See metadb(1M) and %s(1M)."),
error = -1;
} else {
gettext("%d metadb replicas found.\n"),
}
}
return (error);
}
/*
* FUNCTION: validate_request_sizes(devconfig_t *req)
*
* INPUT: req: a devconfig_t pointer to the toplevel request
*
* RETURNS: int - 0 on success
* !0 on failure
*
* PURPOSE: Check to see if the any of the individual volume request
* sizes exceeds the raw available space on the system or
* the space available to that specific request.
*
* Check to see if the total space for all requests exceeds
* the raw available space.
*
* If any check fails, stop checking, emit an error and
* return -1.
*
* Note: this function must be called after the slice
* usages have been determined and the list of usable
* slices has been generated.
*/
int
{
int error = 0;
(void) get_usable_slices(&usable_slices);
/*
* calculate raw available space: space on slices that are
* "available" based on the diskset defaults or global defaults
*/
usable_slices, &raw_space)) != 0) {
return (error);
}
if (raw_space == 0) {
gettext("Failed: there is no available space.\n"));
return (-1);
}
/* deduct sizes of reserved components */
(void) get_reserved_slices(&iter);
} else {
raw_space = 0;
}
}
}
/*
* check each volume request's size against raw_space,
* if that looks ok, do a closer check with the request's
* available devices
*/
continue;
}
/* check specified size */
if ((error = do_available_space_check(
"%s", typestr);
}
} else if (type == TYPE_MIRROR) {
if ((error = do_available_space_check(
} else {
gettext("%s with %d submirrors"),
}
}
}
/* mirror specified no size: find submirror that does */
error = 0;
if ((error = do_available_space_check(
} else {
gettext("%s with %d submirrors"),
}
break;
} else if (error == ERR_ATTR_UNSET) {
error = 0;
}
}
}
}
}
/*
* do_available_space_check may return ENOSPC or E2BIG
*/
(void) bytes_to_sizestr(bad_rqst_space,
gettext("Failed: the request for a %s %s "
"exceeds the available space.\n"),
error = -1;
(void) bytes_to_sizestr(bad_rqst_space,
gettext("Failed: the request for a %s %s "
"exceeds the usable space on the device(s) "
"specified as available.\n"),
error = -1;
(void) bytes_to_sizestr(
gettext("Failed: the total space requested for the "
"volumes (about %s) exceeds the available "
"space.\n"),
sizestr);
error = -1;
}
return (error);
}
/*
* FUNCTION: apply_layout_overhead_factor(uint64_t req_size)
*
* INPUT: req_size: a requested volume size
*
* RETURNS: the requested volume size with an overhead factor applied
*
* PURPOSE: The input size size is inflated by a "fudge" factor
* to account for some of the expected overhead required for
* volumes such as block and cylinder boundary alignment.
*/
static uint64_t
{
return (result);
}
/*
* FUNCTION: get_space_available_for_request(devconfig_t *request,
* dlist_t *usable_slices, uint64_t *avail_space)
*
* INPUT: request: a devconfig_t volume request
* usable_slices: a list of usable slice dm_descriptor_t handles
*
* OUTPUT: avail_space: the total space on slices in the usable_slice
* list that is available for use by the input
* request.
*
* RETURNS: int - 0 on success
* !0 on failure
*
* PURPOSE: Iterate the input list of usable slices, determine which are
* available to the input request and accumulate the total space
* they represent.
*
* The slices in the usable_slice list are those with no apparent
* usage detected. The slice_is_available() check determines
* whether the slice passes the available/unavailable device
* specification associated with the input request.
*/
static int
{
int error = 0;
*avail_space = 0;
for (iter = usable_slices;
char *sname;
*avail_space += nbytes;
}
}
}
}
}
return (error);
}
/*
* FUNCTION: do_available_space_check(uint64_t req_size,
* uint64_t raw_avail_space, devconfig_t *request,
* dlist_t *usable_slices)
*
* INPUT: req_size: the requested size of a volume
* raw_avail_space:the total available space for all volumes
* request: a devconfig_t volume request
* usable_slices: a list of usable slice dm_descriptor_t handles
*
* RETURNS: int - ENOSPC if the requested size exceeds the raw
* available space.
*
* E2BIG if the requested size exceeds the space
* available specifically to the input request,
* taking into account its available and
* unavailable device specifications.
*
* 0 otherwise
*
* PURPOSE: Check the input request size against different forms of
* available space.
*
* If the requested size is less than the raw_avail_space, do the
* more expensive check against the space specifically available
* to the input request.
*/
static int
{
int error = 0;
if (req_size > raw_avail_space) {
} else {
usable_slices, &avail_space)) == 0) {
if (req_size > avail_space) {
}
}
}
return (error);
}
/*
* FUNCTION: validate_request(devconfig_t *req)
*
* INPUT: req - a devconfig_t representing a volume layout request.
*
* RETURNS: int - 0 if the request passes validation
* !0 otherwise.
*
* PURPOSE: Main entry point into the layout request semantic
* validatation.
*
* Determines the type of volume requested and invokes the
* appropriate validation functions.
*/
int
{
int error = 0;
if (error != 0) {
return (error);
}
if (type == TYPE_MIRROR) {
} else if (type == TYPE_VOLUME) {
}
return (error);
}
/*
* FUNCTION: validate_reserved_slices()
*
* RETURNS: int - 0 if all reserved slices are usable in
* new devices.
* !0 otherwise.
*
* PURPOSE: Ensures that each reserved slice is actually usable
* as a volume component.
*
* Retrieves list of reserved slices and list of usable
* slices. Ensures that each reserved slice is in the
* usable list, generates an error if it is not.
*
* This is broken out as a separate function because
* initial validation is using the lists of all known
* devices. Device "usability" is only determined after
* the initial validation has completed successfully.
*/
int
{
int error = 0;
if (error == 0) {
for (iter = reserved_slices;
compare_descriptor_names) != B_TRUE) {
if (error == 0) {
gettext("A requested volume component "
"is currently in use: \"%s\" "
"(aliases: %s).\n"),
} else {
gettext("A requested volume component "
"is currently in use: \"%s\"\n"),
name);
}
error = -1;
}
}
}
}
return (error);
}
/*
* FUNCTION: validate_request_avail_unavail(devconfig_t *req)
*
* INPUT: req - a devconfig_t representing a volume layout request.
*
* RETURNS: int - 0 if the request passes validation
* !0 otherwise.
*
* PURPOSE: validation function for a request's lists of available
* and unavailable devices.
*
* validates that both lists contain names of known devices.
*
* validates that the same name does not appear in both lists.
*/
int
{
int error = 0;
/* check that each array contains valid devices */
/* check that the arrays don't both contain the same device(s) */
if (error == 0) {
compare_descriptor_names) == B_TRUE) {
char *name;
char *aliases =
gettext("\"%s\" specified as both available "
"and unavailable.\n"
"It has these aliases: %s\n"),
} else {
gettext("\"%s\" specified as both available "
"and unavailable.\n"),
name);
}
error = -1;
break;
}
}
}
return (error);
}
/*
* FUNCTION: validate_device_array(char **array, char *which, dlist_t **list)
*
* INPUT: array - an array of char * device names
* which - either "available" or "unavailable"
* indicating the array name to use in
* error strings.
* OUTPUT: list - a list of device descriptors corresponding the each
* of the input names.
*
* RETURNS: int - 0 if the array passes validation
* !0 otherwise.
*
* PURPOSE: validation function for a request's list of available
* or unavailable devices.
*
* DID names are converted to CTD names.
*
* The CTD name must be of an available slice, disk or
* HBA, or a known used slice, disk or HBA that was
* discovered when the system's devices were probed.
*
* Any other name is assumed to refer to a device not
* attached to the system and results in a validation
* failure.
*
* Descriptors for validated devices are added to the input
* list.
*/
int
char **array,
char *which,
{
int error = 0;
int i = 0;
return (0);
}
/* name must correspond to a known HBA, disk, or slice */
if (hba == (dm_descriptor_t)0) {
if (disk == (dm_descriptor_t)0) {
}
}
}
}
if (error != 0) {
break;
}
/* 0 sized slices cannot be used as-is, pretend non-existant */
if (slice != (dm_descriptor_t)0) {
if (size == 0) {
slice = (dm_descriptor_t)0;
}
}
}
gettext(" validate %s (%s): s=%llu, d=%llu, c=%llu\n"),
/* name represents an individual "device", add it to the list */
if (slice != 0) {
} else if (disk != 0) {
} else if (hba != 0) {
}
} else {
}
/* expand target to all of its disks */
gettext("nonexistent device specified "
"as %s: \"%s\"."),
error = -1;
} else {
} else {
}
}
}
}
} else {
/* not a slice, disk, target or ctrl */
gettext("nonexistent device specified "
"as %s: \"%s\"."),
error = -1;
}
}
return (error);
}
/*
* FUNCTION: validate_request_name(devconfig_t *req, component_type_t type)
*
* INPUT: req - a devconfig_t volume request
* type - the volume type being requested
*
* SIDEEFFECT: if the request specifies a name and the name is valid and
* not currently in use an attempt is made to reserve it.
* if the name has already been reserved by a prior volume
* request, validation fails.
*
* RETURNS: int - 0 if the requested name passes validation
* (or there is no name request)
* !0 otherwise.
*
* PURPOSE: Validation function for a request's volume name.
*
* a HSP name must be valid and reservable.
*
* a volume name must be valid and reservable.
*/
static int
{
int error = 0;
if (error != ERR_ATTR_UNSET) {
gettext("error getting requested name.\n"));
return (error);
}
/* no name specified */
return (0);
}
if (is_hsp_name_valid(name) == 0) {
gettext("requested %s name \"%s\" is not valid.\n"),
error = -1;
} else if (reserve_hsp_name(name) != 0) {
gettext("requested %s name \"%s\" used "
"previously in this request.\n"),
} else {
gettext("requested %s name \"%s\" is not "
"available.\n"),
}
error = -1;
} else {
}
} else {
if (is_volume_name_valid(name) == 0) {
gettext("requested %s name \"%s\" is not valid.\n"),
error = -1;
int max = 0;
(void) get_max_number_of_devices(&max);
gettext("requested %s name \"%s\" is not legal.\n"
"Use a name less than d%d.\n"),
error = -1;
} else if (reserve_volume_name(name) != 0) {
gettext("requested %s name \"%s\" used "
"previously in this request.\n"),
} else {
gettext("requested %s name \"%s\" is not "
"available, a volume with that name "
"already exists.\n"),
}
error = -1;
} else {
}
}
return (error);
}
/*
* FUNCTION: add_reserved_name(char *name)
*
* INPUT: name - a char * volume name
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Helper which remembers specfically requested names
* in a private list to ensure that the same name isn't
* requested more than once.
*/
static int
char *name)
{
return (ENOMEM);
}
return (0);
}
/*
* FUNCTION: is_rsvd_name(char *name)
*
* INPUT: name - a char * volume name
*
* RETURNS: boolean_t - B_TRUE if the requested name is currently
* reserved, B_FALSE otherwise.
*
* PURPOSE: Helper which checks to see if the input volume
* name was previously reserved.
*/
static boolean_t
char *name)
{
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* FUNCTION: validate_request_size(devconfig_t *req, component_type_t type)
*
* INPUT: req - a devconfig_t volume request
* type - the volume type being requested
*
* RETURNS: int - 0 if the requested size passes validation
* (or there is no size request)
* !0 otherwise.
*
* PURPOSE: Validation function for a request's volume size.
*
* a HSP request can have no size.
*
* a concat, stripe or mirror request may have a size.
* if size is specified, the request cannot also specify
* components. Conversely, if the request does not specify
* a size, it must specify components.
*/
static int
{
int error = 0;
return (0);
}
if (error == ERR_ATTR_UNSET) {
/* nbytes not specified, request must have subcomponents */
error = 0;
} else {
gettext("%s request specifies no size or "
"subcomponents.\n"),
error = -1;
}
}
return (error);
}
return (error);
}
/*
* FUNCTION: validate_minimum_size(uint64_t nbytes)
*
* INPUT: nbytes - requested volume size in bytes
*
* RETURNS: int - 0 if the requested size passes validation
* (or there is no size request)
* !0 otherwise.
*
* PURPOSE: Validation function for a request's volume size.
*
* an error is issued if the requested size <= 512K.
*/
static int
{
int error = 0;
(void) bytes_to_sizestr(
(void) bytes_to_sizestr(
gettext("requested volume size (%s) must be "
"greater than %s.\n"),
error = -1;
}
return (error);
}
/*
* FUNCTION: validate_request_redundancy_level(devconfig_t *req)
*
* INPUT: req - a devconfig_t volume request
*
* RETURNS: int - 0 if the requested redundancy level
* passes validation (or none was requested)
* !0 otherwise.
*
* PURPOSE: Validation function for a redundant volume request's
* redundancy level.
*
* If the request specifies redundancy, the value must be
* between 1 and 4.
*/
static int
{
int error = 0;
if (error == ERR_ATTR_UNSET) {
error = 0;
}
return (error);
}
if (rlevel > 4) {
"requested redundancy level must be between 0 and 4.\n"));
error = -1;
}
return (error);
}
/*
* FUNCTION: validate_request_npaths(devconfig_t *req)
*
* INPUT: req - a devconfig_t volume request
*
* RETURNS: int - 0 if the requested # of redundant data paths
* passes validation (or none was requested)
* !0 otherwise.
*
* PURPOSE: Validation function for a volume request's number of
* redundant data paths. This value controls the number
* of independent data paths slices components selected
* for the volume should have.
*
* If the request specifies npaths, the value must be
* between 1 and 4 (4 is an arbitrary upper limit, there
* is no known physical limit).
*/
static int
{
int error = 0;
if (error == ERR_ATTR_UNSET) {
error = 0;
}
return (error);
}
gettext("requested number of redundant paths must be "
error = -1;
}
gettext("requested number of redundant paths (%d) cannot "
"be provided, MPXIO is not enabled on this "
"system."),
npaths);
error = -1;
}
return (error);
}
/*
* FUNCTION: validate_request_submirrors(devconfig_t *req)
*
* INPUT: req - a devconfig_t volume request
*
* RETURNS: int - 0 if the requested mirror's submirrors
* pass validation
* !0 otherwise.
*
* PURPOSE: Validation function for a mirror volume request's
* explicitly specified submirror components.
*
* Items to check:
* a. submirror types
* b. submirror number
* c. submirror sizes
*/
static int
{
int error = 0;
return (error);
}
/*
* FUNCTION: validate_submirror_types(dlist_t *subs)
*
* INPUT: subs - a list of submirror requests
*
* RETURNS: int - 0 if the requested submirrors
* pass validation
* !0 otherwise.
*
* PURPOSE: Validation function for a mirror volume request's
* explicitly specified submirror components.
*
* Checks that each requested submirror request
* is for a concat or stripe.
*/
static int
{
int error = 0;
/* specified submirrors must be stripes or concats */
for (iter = submirrors;
gettext("failed to get requested component type.\n"));
break;
}
gettext("requested submirror type \"%s\" "
"is not valid.\n"),
error = -1;
break;
}
}
return (error);
}
/*
* FUNCTION: validate_submirror_number(devconfig_t *req, dlist_t *subs)
*
* INPUT: req - the mirror request
* subs - the list of requested submirrors
*
* RETURNS: int - 0 if the requested submirrors
* pass validation
* !0 otherwise.
*
* PURPOSE: Validation function for a mirror volume request's
* explicitly specified submirror components.
*
* Checks that the number of submirror components
* that have been specified matches the number of
* submirrors specified.
*/
static int
{
int error = 0;
if (error == ERR_ATTR_UNSET) {
/* not specified */
error = 0;
}
} else if ((submirrors != NULL) &&
gettext("the requested number of submirrors (%d) differs "
"from the number of specified submirrors (%d).\n"),
error = -1;
}
return (error);
}
/*
* FUNCTION: validate_submirror_sizes(devconfig_t *req,
* dlist_t *submirrors)
*
* INPUT: req - the mirror request
* submirrors - the list of requested submirrors
*
* RETURNS: int - 0 if the requested submirrors
* pass validation
* !0 otherwise.
*
* PURPOSE: Validation function for a mirror volume request's
* explicitly specified size. Assumes that the mirror's size
* has been validated by validate_request_size().
*
* Compares explicitly requested mirror size against specified
* component sizes and checks:
*
* - any submirror request that specifies both size and
* components is invalid
* - any submirror request specifying a size different
* than that explictly requested for the mirror is
* invalid
* - a submirror request specifying a size < 512K is invalid.
*
* Other validation/warnings:
*
* - submirrors that specify components may end up with
* usable capacity that differs from what was specified
* for the mirror.
*
* - submirrors which specify neither size nor components are
* assumed to be the size requested for the mirror. If the
* mirror size is not specified, the first explicit size for
* a submirror is assumed as the size for the mirror.
*/
static int
{
int error = 0;
return (0);
}
if (error == ERR_ATTR_UNSET) {
error = 0;
} else {
return (error);
}
}
/*
* check size and component for each submirror,
* collect those that specify size, components or neither
* into separate lists.
*/
for (iter = submirrors;
}
if (error == 0) {
/* some submirrors specified size, some components */
gettext(" *** warning: %d submirrors are specified "
"by size, %d specified by components.\n"
" The resulting mirror capacity will be "
"that of the smallest submirror.\n"),
}
if (n_none != 0) {
if (assumed_size != 0) {
/* some submirrors specified neither size or components */
(void) bytes_to_sizestr(
gettext(" *** warning: %d submirrors specified "
"neither size or components,\n"
" the assumed size is %s.\n"),
} else if (mirror_size == 0) {
gettext("no size specified for requested "
"mirror and no sizes/components "
"specified for its submirrors."));
error = -1;
}
}
}
return (error);
}
/*
* FUNCTION: 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)
*
* INPUT: submir - a specific submirror request
* mirror_size, - the size specified for the mirror
*
* OUTPUT: assumed_size - the assumed size of the mirror,
* if none specified.
* submirs_with_size - pointer to a list of submirror
* requests that specify a size
* submirs_with_comps - pointer to a list of submirror
* requests that specify components
* submirs_no_size_or_comps - pointer to a list of
* submirror requests that specify neither
* a size or components
*
* RETURNS: int - 0 if the requested submirrors
* pass validation
* !0 otherwise.
*
* PURPOSE: Validation function which checks a specific submirror
* request's size and components against the parent mirror's
* size.
*
* - any submirror request that specifies both size and
* components is invalid
* - any submirror request specifying a size different
* than that explictly requested for the mirror is
* invalid
* - a submirror request specifying a size < 512K is invalid.
* - any components specified for a submirror are validated.
*
* If the submirror passes the validation checks, it is added
* to the appropriate output list.
*
* If the input mirror_size is 0 and the submirror specifies
* a valid size, the submirror size is returned as the
* assumed_size for the mirror.
*/
static int
{
int n_submir_comps = 0;
int error = 0;
if (submir_comps != NULL) {
}
if (error == ERR_ATTR_UNSET) {
/* submirror size not specified */
error = 0;
submir_size = 0;
}
}
if (error != 0) {
return (error);
}
/* submirror type previously validated */
if (submir_size == 0) {
/* submirror has no size, components? */
if (n_submir_comps > 0) {
/* validate components */
} else {
}
} else {
/* no size or components */
} else {
}
}
} else {
/* submirror has size, check it */
if (error == 0) {
}
/* check size against mirror's size */
if (mirror_size != 0) {
/* sizes differ */
(void) bytes_to_sizestr(
(void) bytes_to_sizestr(
gettext("the requested submirror size (%s) "
"differs from the requested mirror "
"size (%s).\n"),
error = -1;
} else if (*assumed_size == 0) {
/* first size assumed as mirror size */
(void) bytes_to_sizestr(
gettext(" *** warning, using first "
"explicit submirror size (%s)\n"
" as the mirror size\n"),
sizestr);
} else if (submir_size != *assumed_size) {
/* submirror sizes differ */
(void) bytes_to_sizestr(
(void) bytes_to_sizestr(
gettext("submirror specifies different "
"size (%s) than a previous "
"submirror (%s)\n"),
error = -1;
}
}
if ((error == 0) && (n_submir_comps > 0)) {
/* size and subcomponents specified */
(void) bytes_to_sizestr(
gettext("%s submirror specifies both an "
"explicit size (%s) and components.\n"),
error = -1;
}
if (error == 0) {
} else {
}
}
}
return (error);
}
/*
* FUNCTION: validate_slice_components(devconfig_t *req,
* component_type_t type)
*
* INPUT: req - the request
* type - the type of volume being requested
*
* SIDEEFFECT: if the slice component is otherwise valid, an attempt is made
* to reserve it.
*
* RETURNS: int - 0 if the request passes slice component validation
* !0 otherwise.
*
* PURPOSE: Validation function for a concat, stripe or HSP request's
* explicitly specified slice components.
*
* Is the component slice a known device
* Is the component slice available
* Is the component slice already reserved
*
* If the request is for a stripe or concat and the
* request specifies an explicit size, it cannot also
* specify component slices. This is a validation failure.
*
* If the request is for a stripe, the number of specified
* slice components must agree with any expilcit specification
* of the minimum or maximum number of components the stripe
* should have.
*/
static int
{
int error = 0;
int ncomp = 0;
gettext("error getting requested component type."),
voltype);
continue;
}
gettext("error getting requested component name."));
continue;
}
gettext("%s requested component has no name."),
voltype);
error = -1;
continue;
}
if (ctype == TYPE_SLICE) {
/* is the slice known and explicitly available? */
&is_avail)) != 0) {
gettext("%s requested component does not "
"exist: \"%s\"."),
error = -1;
}
continue;
}
gettext("%s requested component is "
"unavailable: \"%s\"."),
error = -1;
continue;
}
/* get slice and its disk */
if (error != 0) {
continue;
}
/* is disk in the set? */
gettext("%s specifies a component not in "
"disk set \"%s\": \"%s\"."),
error = -1;
continue;
}
/* was slice specified in some other request? */
/* include aliases in the error */
char *aliases =
gettext("%s specifies a previously used "
"component: \"%s\" "
"(aliases: %s).\n"),
} else {
gettext("%s specifies a previously used "
"component: \"%s\"\n"),
}
error = -1;
continue;
}
/* component is ok, reserve it */
/*
* the reserved slice component still needs to be
* checked against slices in use by SVM, but that
* information isn't available yet: the usable
* slice derivation happens after validation.
*
* validate_reserved_slices() can be used to check
* them once the usable slices are determined.
*/
} else {
gettext("%s requested component has illegal type."),
voltype);
error = -1;
continue;
}
}
if (error != 0) {
return (error);
}
if (error == ERR_ATTR_UNSET) {
error = 0;
}
} else {
/* size and components both specified */
(void) bytes_to_sizestr(
gettext("%s specifies both an explicit size (%s) "
"and components."),
error = -1;
}
}
if (error != 0) {
return (error);
}
/* does # of components agree with min & max comps? */
if (error == ERR_ATTR_UNSET) {
/* min comp not requested */
error = 0;
} else {
/* error getting requested mincomp */
return (error);
}
/* specified comps < requested mincomp */
gettext("%s specifies fewer components (%d) than the "
"minimum number requested (%d).\n"),
error = -1;
return (error);
}
if (error == ERR_ATTR_UNSET) {
/* max comp not requested */
error = 0;
} else {
/* error getting request maxcomp */
return (error);
}
/* specified comps > requested maxcomp */
gettext("%s specifies more components (%d) than the "
"maximum number requested (%d).\n"),
error = -1;
return (error);
}
}
return (error);
}
/*
* Generate a list of known aliases for the input descriptor.
*
* The returned string buffer is in the form: "alias1", "alias2"...
*/
static char *
{
buf[0] = '\0';
if (*buf == '\0') {
} else {
}
}
return (buf);
}