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