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 2003 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 <assert.h> 30*0Sstevel@tonic-gate #include <string.h> 31*0Sstevel@tonic-gate #include <libintl.h> 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include "volume_error.h" 34*0Sstevel@tonic-gate #include "volume_defaults.h" 35*0Sstevel@tonic-gate #include "volume_dlist.h" 36*0Sstevel@tonic-gate #include "volume_output.h" 37*0Sstevel@tonic-gate #include "volume_request.h" 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include "layout.h" 40*0Sstevel@tonic-gate #include "layout_request.h" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #include "layout_concat.h" 43*0Sstevel@tonic-gate #include "layout_discovery.h" 44*0Sstevel@tonic-gate #include "layout_device_cache.h" 45*0Sstevel@tonic-gate #include "layout_device_util.h" 46*0Sstevel@tonic-gate #include "layout_dlist_util.h" 47*0Sstevel@tonic-gate #include "layout_hsp.h" 48*0Sstevel@tonic-gate #include "layout_mirror.h" 49*0Sstevel@tonic-gate #include "layout_slice.h" 50*0Sstevel@tonic-gate #include "layout_stripe.h" 51*0Sstevel@tonic-gate #include "layout_svm_util.h" 52*0Sstevel@tonic-gate #include "layout_validate.h" 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #define _LAYOUT_C 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate static int layout_init(devconfig_t *request, defaults_t *defaults); 57*0Sstevel@tonic-gate static int layout_diskset(request_t *request, dlist_t *results); 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate static int process_request(devconfig_t *request, dlist_t **results); 60*0Sstevel@tonic-gate static int process_qos_request(devconfig_t *request, dlist_t **results); 61*0Sstevel@tonic-gate static int process_hsp_request(devconfig_t *request, dlist_t **results); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * stuff for making/updating the HSP to service devices 65*0Sstevel@tonic-gate * created by the toplevel request 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate static devconfig_t *_hsp_request = NULL; 68*0Sstevel@tonic-gate static dlist_t *_hsp_devices = NULL; 69*0Sstevel@tonic-gate static void set_hsp_request(devconfig_t *request); 70*0Sstevel@tonic-gate static void unset_hsp_request(); 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * struct to track which disks have been explicitly modified 74*0Sstevel@tonic-gate * during the layout process... 75*0Sstevel@tonic-gate * 76*0Sstevel@tonic-gate * disk is the dm_descriptor_t of the modified disk 77*0Sstevel@tonic-gate * accessname is the name to access the disk thru 78*0Sstevel@tonic-gate * slices is the list of modified slices on the disk 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate typedef struct { 81*0Sstevel@tonic-gate dm_descriptor_t disk; 82*0Sstevel@tonic-gate char *accessname; 83*0Sstevel@tonic-gate dlist_t *slices; 84*0Sstevel@tonic-gate } moddisk_t; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * modified_disks is a list of moddisk_t structs 88*0Sstevel@tonic-gate * tracking disks have been modified during layout. 89*0Sstevel@tonic-gate */ 90*0Sstevel@tonic-gate static dlist_t *_modified_disks = NULL; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate static int collect_modified_disks(devconfig_t *request, dlist_t *results); 93*0Sstevel@tonic-gate static int add_modified_disks_to_diskset( 94*0Sstevel@tonic-gate dlist_t *devices, 95*0Sstevel@tonic-gate devconfig_t *diskset); 96*0Sstevel@tonic-gate static int release_modified_disks(); 97*0Sstevel@tonic-gate static int get_removed_slices_for_disks( 98*0Sstevel@tonic-gate dlist_t *mod_disks); 99*0Sstevel@tonic-gate static int get_modified_slices_for_disks( 100*0Sstevel@tonic-gate dlist_t *moddisks); 101*0Sstevel@tonic-gate static int compare_disk_to_moddisk_disk( 102*0Sstevel@tonic-gate void *disk, 103*0Sstevel@tonic-gate void *moddisk); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate static int convert_device_names(devconfig_t *request, dlist_t *devs); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * FUNCTION: get_layout(devconfig_t *request, defaults_t *defaults) 109*0Sstevel@tonic-gate * 110*0Sstevel@tonic-gate * INPUT: request - a devconfig_t pointer to the toplevel request 111*0Sstevel@tonic-gate * defaults - a results_t pointer to the defaults 112*0Sstevel@tonic-gate * 113*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 114*0Sstevel@tonic-gate * !0 - otherwise 115*0Sstevel@tonic-gate * 116*0Sstevel@tonic-gate * PURPOSE: Public entry point to layout module. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate int 119*0Sstevel@tonic-gate get_layout( 120*0Sstevel@tonic-gate request_t *request, 121*0Sstevel@tonic-gate defaults_t *defaults) 122*0Sstevel@tonic-gate { 123*0Sstevel@tonic-gate devconfig_t *diskset_req = NULL; 124*0Sstevel@tonic-gate dlist_t *iter = NULL; 125*0Sstevel@tonic-gate dlist_t *results = NULL; 126*0Sstevel@tonic-gate int error = 0; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate if ((diskset_req = request_get_diskset_req(request)) != NULL) { 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* initialize using the the top-level disk set request... */ 131*0Sstevel@tonic-gate if ((error = layout_init(diskset_req, defaults)) != 0) { 132*0Sstevel@tonic-gate return (error); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 136*0Sstevel@tonic-gate gettext("\nProcessing volume request...\n")); 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate iter = devconfig_get_components(diskset_req); 139*0Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) { 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* process each volume request, stop on any error */ 142*0Sstevel@tonic-gate devconfig_t *subreq = (devconfig_t *)iter->obj; 143*0Sstevel@tonic-gate dlist_t *subres = NULL; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate ((error = process_request(subreq, &subres)) != 0) || 146*0Sstevel@tonic-gate (error = collect_modified_disks(subreq, subres)) || 147*0Sstevel@tonic-gate (error = convert_device_names(subreq, subres)); 148*0Sstevel@tonic-gate if (error == 0) { 149*0Sstevel@tonic-gate results = dlist_append(subres, results, AT_TAIL); 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate if (error == 0) { 154*0Sstevel@tonic-gate /* process HSP request */ 155*0Sstevel@tonic-gate dlist_t *subres = NULL; 156*0Sstevel@tonic-gate error = process_hsp_request(diskset_req, &subres); 157*0Sstevel@tonic-gate if (error == 0) { 158*0Sstevel@tonic-gate results = dlist_append(subres, results, AT_TAIL); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate if (error == 0) { 163*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 164*0Sstevel@tonic-gate gettext("\nAssembling volume specification...\n")); 165*0Sstevel@tonic-gate /* determine required diskset modifications */ 166*0Sstevel@tonic-gate error = layout_diskset(request, results); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate layout_clean_up(); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (error == 0) { 172*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 173*0Sstevel@tonic-gate gettext("\nVolume request completed successfully.\n")); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate } else { 177*0Sstevel@tonic-gate volume_set_error( 178*0Sstevel@tonic-gate gettext("Malformed request, missing top level " 179*0Sstevel@tonic-gate "disk set request.")); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate return (error); 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * FUNCTION: layout_clean_up() 187*0Sstevel@tonic-gate * 188*0Sstevel@tonic-gate * PURPOSE: function which handles the details of cleaning up cached 189*0Sstevel@tonic-gate * data and any other memory allocated during the layout 190*0Sstevel@tonic-gate * process. 191*0Sstevel@tonic-gate * 192*0Sstevel@tonic-gate * release physical device data structs 193*0Sstevel@tonic-gate * release SVM logical device data structs 194*0Sstevel@tonic-gate * release validation data structs 195*0Sstevel@tonic-gate * release modified device data structs 196*0Sstevel@tonic-gate * release request processing data structs 197*0Sstevel@tonic-gate * 198*0Sstevel@tonic-gate * This function is also exported as part of the public 199*0Sstevel@tonic-gate * interface to the layout module, clients of layout 200*0Sstevel@tonic-gate * are required to call this function if get_layout() 201*0Sstevel@tonic-gate * was called and was not allowed to return. For example, 202*0Sstevel@tonic-gate * if SIGINT was received while a layout request was in 203*0Sstevel@tonic-gate * process. 204*0Sstevel@tonic-gate */ 205*0Sstevel@tonic-gate void 206*0Sstevel@tonic-gate layout_clean_up() 207*0Sstevel@tonic-gate { 208*0Sstevel@tonic-gate (void) release_request_caches(); 209*0Sstevel@tonic-gate (void) release_validation_caches(); 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate (void) release_slices_to_remove(); 212*0Sstevel@tonic-gate (void) release_modified_slices(); 213*0Sstevel@tonic-gate (void) release_modified_disks(); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate (void) release_reserved_slices(); 216*0Sstevel@tonic-gate (void) release_used_slices(); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate (void) release_usable_devices(); 219*0Sstevel@tonic-gate (void) release_svm_names(get_request_diskset()); 220*0Sstevel@tonic-gate (void) release_known_devices(); 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate (void) unset_hsp_request(NULL); 223*0Sstevel@tonic-gate (void) unset_request_defaults(NULL); 224*0Sstevel@tonic-gate (void) unset_request_diskset(NULL); 225*0Sstevel@tonic-gate (void) unset_toplevel_request(NULL); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate /* 229*0Sstevel@tonic-gate * FUNCTION: layout_init(devconfig_t *diskset, defaults_t *defaults) 230*0Sstevel@tonic-gate * 231*0Sstevel@tonic-gate * INPUT: diskset - a devconfig_t pointer to the toplevel request 232*0Sstevel@tonic-gate * defaults - a results_t pointer to the defaults 233*0Sstevel@tonic-gate * 234*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 235*0Sstevel@tonic-gate * !0 - otherwise 236*0Sstevel@tonic-gate * 237*0Sstevel@tonic-gate * PURPOSE: function which handles the details of initializing the layout 238*0Sstevel@tonic-gate * module prior to processing a request. 239*0Sstevel@tonic-gate * 240*0Sstevel@tonic-gate * Determines the requested disk set and validates it. 241*0Sstevel@tonic-gate * 242*0Sstevel@tonic-gate * Scans the physical device configuration. 243*0Sstevel@tonic-gate * Scans the SVM logical device configuration. 244*0Sstevel@tonic-gate * 245*0Sstevel@tonic-gate * Initializes layout private global data structures and does 246*0Sstevel@tonic-gate * semantic validation of the request. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate static int 249*0Sstevel@tonic-gate layout_init( 250*0Sstevel@tonic-gate devconfig_t *diskset, 251*0Sstevel@tonic-gate defaults_t *defaults) 252*0Sstevel@tonic-gate { 253*0Sstevel@tonic-gate dlist_t *iter = NULL; 254*0Sstevel@tonic-gate int error = 0; 255*0Sstevel@tonic-gate char *dsname = NULL; 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate ((error = validate_basic_svm_config()) != 0) || 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* determine & validate requested disk set name */ 260*0Sstevel@tonic-gate (error = devconfig_get_name(diskset, &dsname)) || 261*0Sstevel@tonic-gate (error = set_request_diskset(dsname)) || 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate /* discover known physical and logical devices */ 264*0Sstevel@tonic-gate (error = discover_known_devices()) || 265*0Sstevel@tonic-gate (error = scan_svm_names(dsname)) || 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* validate and remember toplevel request */ 268*0Sstevel@tonic-gate (error = set_toplevel_request(diskset)) || 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* validate and remember defaults for this request */ 271*0Sstevel@tonic-gate (error = set_request_defaults(defaults)); 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate if (error != 0) { 274*0Sstevel@tonic-gate return (error); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 278*0Sstevel@tonic-gate gettext("\nValidating volume request...\n")); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate iter = devconfig_get_components(diskset); 281*0Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) { 282*0Sstevel@tonic-gate devconfig_t *subreq = (devconfig_t *)iter->obj; 283*0Sstevel@tonic-gate error = validate_request(subreq); 284*0Sstevel@tonic-gate } 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate if (error == 0) { 287*0Sstevel@tonic-gate error = discover_usable_devices(dsname); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate if (error == 0) { 291*0Sstevel@tonic-gate /* final validation on explicitly requested components */ 292*0Sstevel@tonic-gate error = validate_reserved_slices(); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if (error == 0) { 296*0Sstevel@tonic-gate /* final validation on request sizes vs. actual avail space */ 297*0Sstevel@tonic-gate error = validate_request_sizes(diskset); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate return (error); 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * FUNCTION: process_request(devconfig_t *req, dlist_t **results) 305*0Sstevel@tonic-gate * 306*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 307*0Sstevel@tonic-gate * results - pointer to a list of resulting volumes 308*0Sstevel@tonic-gate * 309*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 310*0Sstevel@tonic-gate * !0 - otherwise 311*0Sstevel@tonic-gate * 312*0Sstevel@tonic-gate * PURPOSE: function which handles the details of an explicit 313*0Sstevel@tonic-gate * volume request. 314*0Sstevel@tonic-gate * 315*0Sstevel@tonic-gate * Determines the requested volume type, whether the 316*0Sstevel@tonic-gate * request contains specific subcomponents and dispatches 317*0Sstevel@tonic-gate * to the appropriate layout function for that type. 318*0Sstevel@tonic-gate * 319*0Sstevel@tonic-gate * Resulting volumes are appended to the results list. 320*0Sstevel@tonic-gate * 321*0Sstevel@tonic-gate * Note that an HSP request is held until all the volumes 322*0Sstevel@tonic-gate * in the request have been successfully composed. This 323*0Sstevel@tonic-gate * ensures that HSP spare sizing can be appropriate to 324*0Sstevel@tonic-gate * those volumes. 325*0Sstevel@tonic-gate */ 326*0Sstevel@tonic-gate static int 327*0Sstevel@tonic-gate process_request( 328*0Sstevel@tonic-gate devconfig_t *req, 329*0Sstevel@tonic-gate dlist_t **results) 330*0Sstevel@tonic-gate { 331*0Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN; 332*0Sstevel@tonic-gate uint64_t nbytes = 0; /* requested volume size */ 333*0Sstevel@tonic-gate dlist_t *comps = NULL; 334*0Sstevel@tonic-gate int ncomps = 0; 335*0Sstevel@tonic-gate int error = 0; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate (void) devconfig_get_type(req, &type); 338*0Sstevel@tonic-gate (void) devconfig_get_size(req, &nbytes); 339*0Sstevel@tonic-gate comps = devconfig_get_components(req); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (type == TYPE_HSP) { 342*0Sstevel@tonic-gate /* HSP processing needs to happen after all other volumes. */ 343*0Sstevel@tonic-gate /* set the HSP request aside until all other requests have */ 344*0Sstevel@tonic-gate /* been completed successfully */ 345*0Sstevel@tonic-gate set_hsp_request(req); 346*0Sstevel@tonic-gate return (0); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, "\n"); 350*0Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, "******************\n"); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate ncomps = dlist_length(comps); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate if (type == TYPE_STRIPE) { 355*0Sstevel@tonic-gate if (ncomps > 0) { 356*0Sstevel@tonic-gate return (populate_explicit_stripe(req, results)); 357*0Sstevel@tonic-gate } else { 358*0Sstevel@tonic-gate return (layout_stripe(req, nbytes, results)); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate if (type == TYPE_CONCAT) { 363*0Sstevel@tonic-gate if (ncomps > 0) { 364*0Sstevel@tonic-gate return (populate_explicit_concat(req, results)); 365*0Sstevel@tonic-gate } else { 366*0Sstevel@tonic-gate return (layout_concat(req, nbytes, results)); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate if (type == TYPE_MIRROR) { 371*0Sstevel@tonic-gate if (ncomps > 0) { 372*0Sstevel@tonic-gate return (populate_explicit_mirror(req, results)); 373*0Sstevel@tonic-gate } else { 374*0Sstevel@tonic-gate uint16_t nsubs = 0; 375*0Sstevel@tonic-gate if ((error = get_mirror_nsubs(req, &nsubs)) != 0) { 376*0Sstevel@tonic-gate return (error); 377*0Sstevel@tonic-gate } else { 378*0Sstevel@tonic-gate return (layout_mirror(req, nsubs, nbytes, results)); 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate if (type == TYPE_VOLUME) { 384*0Sstevel@tonic-gate error = process_qos_request(req, results); 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate return (error); 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate /* 391*0Sstevel@tonic-gate * FUNCTION: process_qos_request(devconfig_t *req, dlist_t **results) 392*0Sstevel@tonic-gate * 393*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 394*0Sstevel@tonic-gate * results - pointer to a list of resulting volumes 395*0Sstevel@tonic-gate * 396*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 397*0Sstevel@tonic-gate * !0 - otherwise 398*0Sstevel@tonic-gate * 399*0Sstevel@tonic-gate * PURPOSE: function which handles the details of mapping an implicit 400*0Sstevel@tonic-gate * volume request of QoS attributes into a volume type. 401*0Sstevel@tonic-gate * 402*0Sstevel@tonic-gate * Resulting volumes are appended to the results list. 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate static int 405*0Sstevel@tonic-gate process_qos_request( 406*0Sstevel@tonic-gate devconfig_t *req, 407*0Sstevel@tonic-gate dlist_t **results) 408*0Sstevel@tonic-gate { 409*0Sstevel@tonic-gate int error = 0; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate uint64_t nbytes = 0; 412*0Sstevel@tonic-gate uint16_t rlevel = 0; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* get QoS attributes */ 415*0Sstevel@tonic-gate (void) devconfig_get_size(req, &nbytes); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate if ((error = get_volume_redundancy_level(req, &rlevel)) != 0) { 418*0Sstevel@tonic-gate if (error == ERR_ATTR_UNSET) { 419*0Sstevel@tonic-gate error = 0; 420*0Sstevel@tonic-gate rlevel = 0; 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate if (error == 0) { 425*0Sstevel@tonic-gate if (rlevel == 0) { 426*0Sstevel@tonic-gate error = layout_stripe(req, nbytes, results); 427*0Sstevel@tonic-gate } else { 428*0Sstevel@tonic-gate error = layout_mirror(req, rlevel, nbytes, results); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate return (error); 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * FUNCTION: layout_diskset(request_t *req, dlist_t **results) 437*0Sstevel@tonic-gate * 438*0Sstevel@tonic-gate * INPUT: req - a request_t pointer to the toplevel request 439*0Sstevel@tonic-gate * results - pointer to the list of composed result volumes 440*0Sstevel@tonic-gate * 441*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 442*0Sstevel@tonic-gate * !0 - otherwise 443*0Sstevel@tonic-gate * 444*0Sstevel@tonic-gate * PURPOSE: function which handles the details of completing an layout 445*0Sstevel@tonic-gate * request. 446*0Sstevel@tonic-gate * 447*0Sstevel@tonic-gate * Determines if the disk set specified in the request currently 448*0Sstevel@tonic-gate * exists and sets it up for creation if it doesn't. 449*0Sstevel@tonic-gate * 450*0Sstevel@tonic-gate * Adds new disks required by the result volumes to the disk set. 451*0Sstevel@tonic-gate * 452*0Sstevel@tonic-gate * Attaches the result volumes to the disk set result. 453*0Sstevel@tonic-gate * 454*0Sstevel@tonic-gate * Convert slice and disk names to preferred names. 455*0Sstevel@tonic-gate * 456*0Sstevel@tonic-gate * Attaches the disk set result to the toplevel request. 457*0Sstevel@tonic-gate */ 458*0Sstevel@tonic-gate static int 459*0Sstevel@tonic-gate layout_diskset( 460*0Sstevel@tonic-gate request_t *request, 461*0Sstevel@tonic-gate dlist_t *results) 462*0Sstevel@tonic-gate { 463*0Sstevel@tonic-gate int error = 0; 464*0Sstevel@tonic-gate devconfig_t *diskset = NULL; 465*0Sstevel@tonic-gate dlist_t *comps = NULL; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate ((error = new_devconfig(&diskset, TYPE_DISKSET)) != 0) || 468*0Sstevel@tonic-gate (error = devconfig_set_name(diskset, get_request_diskset())) || 469*0Sstevel@tonic-gate (error = add_modified_disks_to_diskset(results, diskset)); 470*0Sstevel@tonic-gate if (error != 0) { 471*0Sstevel@tonic-gate free_devconfig(diskset); 472*0Sstevel@tonic-gate return (error); 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate /* add resulting volumes */ 476*0Sstevel@tonic-gate if (results != NULL) { 477*0Sstevel@tonic-gate comps = devconfig_get_components(diskset); 478*0Sstevel@tonic-gate comps = dlist_append(results, comps, AT_TAIL); 479*0Sstevel@tonic-gate devconfig_set_components(diskset, comps); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate request_set_diskset_config(request, diskset); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate return (error); 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate /* 488*0Sstevel@tonic-gate * FUNCTION: convert_device_names(devconfig_t request, dlist_t *devices) 489*0Sstevel@tonic-gate * 490*0Sstevel@tonic-gate * INPUT: request - a devconfig_t request pointer 491*0Sstevel@tonic-gate * devices - a list of devconfig_t devices 492*0Sstevel@tonic-gate * 493*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 494*0Sstevel@tonic-gate * !0 - on any error 495*0Sstevel@tonic-gate * 496*0Sstevel@tonic-gate * PURPOSE: Utility function to convert any slice or disk drive 497*0Sstevel@tonic-gate * names in a result devconfig_t to the preferred name 498*0Sstevel@tonic-gate * which should be used to access the device. 499*0Sstevel@tonic-gate * 500*0Sstevel@tonic-gate * This convert the temporary names used by layout to 501*0Sstevel@tonic-gate * the proper DID or /dev/dsk alias. 502*0Sstevel@tonic-gate */ 503*0Sstevel@tonic-gate static int 504*0Sstevel@tonic-gate convert_device_names( 505*0Sstevel@tonic-gate devconfig_t *request, 506*0Sstevel@tonic-gate dlist_t *devices) 507*0Sstevel@tonic-gate { 508*0Sstevel@tonic-gate int error = 0; 509*0Sstevel@tonic-gate dlist_t *iter; 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate for (iter = devices; 512*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 513*0Sstevel@tonic-gate iter = iter->next) { 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate devconfig_t *dev = (devconfig_t *)iter->obj; 516*0Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN; 517*0Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0; 518*0Sstevel@tonic-gate char *devname = NULL; 519*0Sstevel@tonic-gate char *diskname = NULL; 520*0Sstevel@tonic-gate char *slicename = NULL; 521*0Sstevel@tonic-gate uint16_t index; 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate if ((error = devconfig_get_type(dev, &type)) == 0) { 524*0Sstevel@tonic-gate switch (type) { 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate case TYPE_MIRROR: 527*0Sstevel@tonic-gate case TYPE_STRIPE: 528*0Sstevel@tonic-gate case TYPE_CONCAT: 529*0Sstevel@tonic-gate case TYPE_HSP: 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate error = convert_device_names(request, 532*0Sstevel@tonic-gate devconfig_get_components(dev)); 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate break; 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate case TYPE_SLICE: 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate ((error = devconfig_get_name(dev, &devname)) != 0) || 539*0Sstevel@tonic-gate (error = devconfig_get_slice_index(dev, &index)) || 540*0Sstevel@tonic-gate (error = get_disk_for_named_slice(devname, &disk)) || 541*0Sstevel@tonic-gate (error = get_device_access_name(request, disk, 542*0Sstevel@tonic-gate &diskname)) || 543*0Sstevel@tonic-gate (error = make_slicename_for_diskname_and_index( 544*0Sstevel@tonic-gate diskname, index, &slicename)); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if ((error == 0) && (slicename != NULL)) { 547*0Sstevel@tonic-gate error = devconfig_set_name(dev, slicename); 548*0Sstevel@tonic-gate free(slicename); 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate break; 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate return (error); 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * FUNCTION: add_modified_disk(devconfig_t request, dm_descriptor_t disk); 561*0Sstevel@tonic-gate * 562*0Sstevel@tonic-gate * INPUT: request - a pointr to a devconfig_t request 563*0Sstevel@tonic-gate * disk - dm_descriptor_t handle for a disk that has been modified 564*0Sstevel@tonic-gate * 565*0Sstevel@tonic-gate * SIDEEFFECTS: adds an entry to the _modified_disks list which tracks 566*0Sstevel@tonic-gate * the disks that have been explicitly modified by 567*0Sstevel@tonic-gate * the layout code. 568*0Sstevel@tonic-gate * 569*0Sstevel@tonic-gate * RETURNS: int - 0 on success 570*0Sstevel@tonic-gate * !0 otherwise 571*0Sstevel@tonic-gate * 572*0Sstevel@tonic-gate * PURPOSE: Adds the input disk to the list of those that have been 573*0Sstevel@tonic-gate * modified. 574*0Sstevel@tonic-gate * 575*0Sstevel@tonic-gate * Disks are modified during layout for two reasons: 576*0Sstevel@tonic-gate * 577*0Sstevel@tonic-gate * 1. any disk that is to be added to the disk set gets 578*0Sstevel@tonic-gate * an explicitly updated label. 579*0Sstevel@tonic-gate * 580*0Sstevel@tonic-gate * 2. once a disk is in the disk set, existing slices 581*0Sstevel@tonic-gate * may be resized or new slices can be added. 582*0Sstevel@tonic-gate */ 583*0Sstevel@tonic-gate int 584*0Sstevel@tonic-gate add_modified_disk( 585*0Sstevel@tonic-gate devconfig_t *request, 586*0Sstevel@tonic-gate dm_descriptor_t disk) 587*0Sstevel@tonic-gate { 588*0Sstevel@tonic-gate dlist_t *iter = NULL; 589*0Sstevel@tonic-gate moddisk_t *moddisk = NULL; 590*0Sstevel@tonic-gate dlist_t *item = NULL; 591*0Sstevel@tonic-gate int error = 0; 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate for (iter = _modified_disks; iter != NULL; iter = iter->next) { 594*0Sstevel@tonic-gate moddisk = (moddisk_t *)iter->obj; 595*0Sstevel@tonic-gate if (compare_descriptor_names( 596*0Sstevel@tonic-gate (void *)moddisk->disk, (void *)disk) == 0) { 597*0Sstevel@tonic-gate /* already in list */ 598*0Sstevel@tonic-gate return (0); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate moddisk = (moddisk_t *)calloc(1, sizeof (moddisk_t)); 603*0Sstevel@tonic-gate if (moddisk == NULL) { 604*0Sstevel@tonic-gate error = ENOMEM; 605*0Sstevel@tonic-gate } else { 606*0Sstevel@tonic-gate char *aname = NULL; 607*0Sstevel@tonic-gate error = get_device_access_name(request, disk, &aname); 608*0Sstevel@tonic-gate if (error == 0) { 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate /* add to list of modified disks */ 611*0Sstevel@tonic-gate moddisk->disk = disk; 612*0Sstevel@tonic-gate moddisk->accessname = aname; 613*0Sstevel@tonic-gate moddisk->slices = NULL; 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate if ((item = dlist_new_item((void *)moddisk)) == NULL) { 616*0Sstevel@tonic-gate free(moddisk); 617*0Sstevel@tonic-gate error = ENOMEM; 618*0Sstevel@tonic-gate } else { 619*0Sstevel@tonic-gate _modified_disks = 620*0Sstevel@tonic-gate dlist_append(item, _modified_disks, AT_HEAD); 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate return (error); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * FUNCTION: collect_modified_disks(devconfig_t *request, dlist_t* devs) 630*0Sstevel@tonic-gate * 631*0Sstevel@tonic-gate * INPUT: devs - pointer to a list of composed volumes 632*0Sstevel@tonic-gate * OUTPUT: none - 633*0Sstevel@tonic-gate * SIDEEFFECT: updates the module global list _modified_disks 634*0Sstevel@tonic-gate * 635*0Sstevel@tonic-gate * RETURNS: int - 0 - success 636*0Sstevel@tonic-gate * !0 - failure 637*0Sstevel@tonic-gate * 638*0Sstevel@tonic-gate * PURPOSE: Helper to maintain the list of disks to be added to the 639*0Sstevel@tonic-gate * disk set. 640*0Sstevel@tonic-gate * 641*0Sstevel@tonic-gate * Iterates the input list of devices and determines which 642*0Sstevel@tonic-gate * disks they use. If a disk is not in the _modified_disks 643*0Sstevel@tonic-gate * list, it is added. 644*0Sstevel@tonic-gate */ 645*0Sstevel@tonic-gate static int 646*0Sstevel@tonic-gate collect_modified_disks( 647*0Sstevel@tonic-gate devconfig_t *request, 648*0Sstevel@tonic-gate dlist_t *devs) 649*0Sstevel@tonic-gate { 650*0Sstevel@tonic-gate int error = 0; 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate char *sname = NULL; 653*0Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0; 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate for (; (devs != NULL) && (error == 0); devs = devs->next) { 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate devconfig_t *dev = (devconfig_t *)devs->obj; 658*0Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN; 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate if ((error = devconfig_get_type(dev, &type)) == 0) { 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate switch (type) { 663*0Sstevel@tonic-gate case TYPE_MIRROR: 664*0Sstevel@tonic-gate case TYPE_STRIPE: 665*0Sstevel@tonic-gate case TYPE_CONCAT: 666*0Sstevel@tonic-gate case TYPE_HSP: 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate error = collect_modified_disks(request, 669*0Sstevel@tonic-gate devconfig_get_components(dev)); 670*0Sstevel@tonic-gate break; 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate case TYPE_SLICE: 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate ((error = devconfig_get_name(dev, &sname)) != 0) || 675*0Sstevel@tonic-gate (error = get_disk_for_named_slice(sname, &disk)) || 676*0Sstevel@tonic-gate (error = add_modified_disk(request, disk)); 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate break; 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate return (error); 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * FUNCTION: add_modified_disks_to_diskset(dlist_t *devices, 688*0Sstevel@tonic-gate * devconfig_t *diskset) 689*0Sstevel@tonic-gate * 690*0Sstevel@tonic-gate * INPUT: devices - pointer to a list of devices 691*0Sstevel@tonic-gate * 692*0Sstevel@tonic-gate * OUTPUT: diskset - pointer to a devconfig_t representing the disk set, 693*0Sstevel@tonic-gate * updated to include modified disks and slices as 694*0Sstevel@tonic-gate * components. 695*0Sstevel@tonic-gate * 696*0Sstevel@tonic-gate * RETURNS: int - 0 - success 697*0Sstevel@tonic-gate * !0 - failure 698*0Sstevel@tonic-gate * 699*0Sstevel@tonic-gate * PURPOSE: Helper to add devconfig_t structs for disks and slices 700*0Sstevel@tonic-gate * to the disk set. 701*0Sstevel@tonic-gate * 702*0Sstevel@tonic-gate * Updates the list of _modified_disks by examining the input 703*0Sstevel@tonic-gate * list of composed devices. 704*0Sstevel@tonic-gate * 705*0Sstevel@tonic-gate * Iterates _modified_disks and creates a devconfig_t component 706*0Sstevel@tonic-gate * for each disk in the list, the list of disks is then attached 707*0Sstevel@tonic-gate * to the input disk set. 708*0Sstevel@tonic-gate * 709*0Sstevel@tonic-gate * Modified slices for disks in the disk set are added as well. 710*0Sstevel@tonic-gate */ 711*0Sstevel@tonic-gate static int 712*0Sstevel@tonic-gate add_modified_disks_to_diskset( 713*0Sstevel@tonic-gate dlist_t *results, 714*0Sstevel@tonic-gate devconfig_t *diskset) 715*0Sstevel@tonic-gate { 716*0Sstevel@tonic-gate int error = 0; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate dlist_t *iter; 719*0Sstevel@tonic-gate dlist_t *list = NULL; 720*0Sstevel@tonic-gate char *dsname = get_request_diskset(); 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate /* add modified disks to disk set's component list */ 723*0Sstevel@tonic-gate list = devconfig_get_components(diskset); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 726*0Sstevel@tonic-gate gettext(" Collecting modified disks...\n")); 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate /* collect removed slices for modified disks */ 729*0Sstevel@tonic-gate error = get_removed_slices_for_disks(_modified_disks); 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate /* collect modified slices for modified disks */ 732*0Sstevel@tonic-gate error = get_modified_slices_for_disks(_modified_disks); 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate for (iter = _modified_disks; 735*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 736*0Sstevel@tonic-gate iter = iter->next) { 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate moddisk_t *moddisk = (moddisk_t *)iter->obj; 739*0Sstevel@tonic-gate dm_descriptor_t disk = moddisk->disk; 740*0Sstevel@tonic-gate devconfig_t *newdisk = NULL; 741*0Sstevel@tonic-gate boolean_t in_set = B_FALSE; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, " %s\n", moddisk->accessname); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate error = is_disk_in_diskset(disk, dsname, &in_set); 746*0Sstevel@tonic-gate if ((error == 0) && (in_set != B_TRUE)) { 747*0Sstevel@tonic-gate /* New disk, add it to the disk set */ 748*0Sstevel@tonic-gate ((error = new_devconfig(&newdisk, TYPE_DRIVE)) != 0) || 749*0Sstevel@tonic-gate (error = devconfig_set_name(newdisk, moddisk->accessname)); 750*0Sstevel@tonic-gate if (error == 0) { 751*0Sstevel@tonic-gate dlist_t *item = dlist_new_item(newdisk); 752*0Sstevel@tonic-gate if (item == NULL) { 753*0Sstevel@tonic-gate error = ENOMEM; 754*0Sstevel@tonic-gate } else { 755*0Sstevel@tonic-gate list = dlist_append(item, list, AT_TAIL); 756*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 757*0Sstevel@tonic-gate gettext(" must add %s to disk set \"%s\"\n"), 758*0Sstevel@tonic-gate moddisk->accessname, dsname); 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate } else { 761*0Sstevel@tonic-gate free_devconfig(newdisk); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate if ((error == 0) && (moddisk->slices != NULL)) { 766*0Sstevel@tonic-gate /* move moddisk's slice list to disk set comp list */ 767*0Sstevel@tonic-gate list = dlist_append(moddisk->slices, list, AT_TAIL); 768*0Sstevel@tonic-gate moddisk->slices = NULL; 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate if (error == 0) { 773*0Sstevel@tonic-gate devconfig_set_components(diskset, list); 774*0Sstevel@tonic-gate } else { 775*0Sstevel@tonic-gate dlist_free_items(list, NULL); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate return (error); 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate /* 782*0Sstevel@tonic-gate * FUNCTIONS: void release_modified_disks() 783*0Sstevel@tonic-gate * 784*0Sstevel@tonic-gate * INPUT: none - 785*0Sstevel@tonic-gate * OUTPUT: none - 786*0Sstevel@tonic-gate * 787*0Sstevel@tonic-gate * PURPOSE: cleanup the module global list of disks that need 788*0Sstevel@tonic-gate * to be added to the disk set to satisfy the request. 789*0Sstevel@tonic-gate */ 790*0Sstevel@tonic-gate static int 791*0Sstevel@tonic-gate release_modified_disks() 792*0Sstevel@tonic-gate { 793*0Sstevel@tonic-gate dlist_t *iter = _modified_disks; 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate for (; iter != NULL; iter = iter->next) { 796*0Sstevel@tonic-gate moddisk_t *moddisk = (moddisk_t *)iter->obj; 797*0Sstevel@tonic-gate if (moddisk->slices != NULL) { 798*0Sstevel@tonic-gate dlist_free_items(moddisk->slices, free_devconfig); 799*0Sstevel@tonic-gate moddisk->slices = NULL; 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate free(moddisk); 802*0Sstevel@tonic-gate iter->obj = NULL; 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate dlist_free_items(_modified_disks, NULL); 806*0Sstevel@tonic-gate _modified_disks = NULL; 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate return (0); 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate /* 812*0Sstevel@tonic-gate * FUNCTION: get_removed_slices_for_disks(dlist_t *mod_disks) 813*0Sstevel@tonic-gate * 814*0Sstevel@tonic-gate * INPUT: mod_disks - a list of moddisk_t structs 815*0Sstevel@tonic-gate * 816*0Sstevel@tonic-gate * OUTPUT: mod_disks - the list of moddisk_t structs updated with 817*0Sstevel@tonic-gate * the slices to be removed for each disk 818*0Sstevel@tonic-gate * 819*0Sstevel@tonic-gate * RETURNS: int - 0 - success 820*0Sstevel@tonic-gate * !0 - failure 821*0Sstevel@tonic-gate * 822*0Sstevel@tonic-gate * PURPOSE: Helper to create a list of devconfig_t structs 823*0Sstevel@tonic-gate * for slices on the input disks which need to be 824*0Sstevel@tonic-gate * removed from the system. 825*0Sstevel@tonic-gate * 826*0Sstevel@tonic-gate * Iterates the list of slices to be removed and 827*0Sstevel@tonic-gate * creates a devconfig_t component for each slice 828*0Sstevel@tonic-gate * in the list that is on any of the input modified 829*0Sstevel@tonic-gate * disks. 830*0Sstevel@tonic-gate * 831*0Sstevel@tonic-gate * Slice names are constructed using the modified disk's 832*0Sstevel@tonic-gate * access name to ensure that the correct alias is 833*0Sstevel@tonic-gate * used to get to the slice. 834*0Sstevel@tonic-gate */ 835*0Sstevel@tonic-gate static int 836*0Sstevel@tonic-gate get_removed_slices_for_disks( 837*0Sstevel@tonic-gate dlist_t *mod_disks) 838*0Sstevel@tonic-gate { 839*0Sstevel@tonic-gate int error = 0; 840*0Sstevel@tonic-gate dlist_t *iter = NULL; 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate /* collect slices to be removed for the modified disks */ 843*0Sstevel@tonic-gate for (iter = get_slices_to_remove(); 844*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 845*0Sstevel@tonic-gate iter = iter->next) { 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate rmvdslice_t *rmvd = (rmvdslice_t *)iter->obj; 848*0Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0; 849*0Sstevel@tonic-gate moddisk_t *moddisk = NULL; 850*0Sstevel@tonic-gate char *sname = NULL; 851*0Sstevel@tonic-gate devconfig_t *newslice = NULL; 852*0Sstevel@tonic-gate dlist_t *item = NULL; 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate (void) get_disk_for_named_slice(rmvd->slice_name, &disk); 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate if ((item = dlist_find(mod_disks, (void *)disk, 857*0Sstevel@tonic-gate compare_disk_to_moddisk_disk)) == NULL) { 858*0Sstevel@tonic-gate /* slice on disk that we don't care about */ 859*0Sstevel@tonic-gate continue; 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate moddisk = (moddisk_t *)item->obj; 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate /* create output slice struct for the removed slice */ 865*0Sstevel@tonic-gate ((error = make_slicename_for_diskname_and_index( 866*0Sstevel@tonic-gate moddisk->accessname, rmvd->slice_index, &sname)) != 0) || 867*0Sstevel@tonic-gate (error = new_devconfig(&newslice, TYPE_SLICE)) || 868*0Sstevel@tonic-gate (error = devconfig_set_name(newslice, sname)) || 869*0Sstevel@tonic-gate (error = devconfig_set_size_in_blocks(newslice, 0)); 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate /* add to the moddisk's list of slices */ 872*0Sstevel@tonic-gate if (error == 0) { 873*0Sstevel@tonic-gate if ((item = dlist_new_item(newslice)) == NULL) { 874*0Sstevel@tonic-gate free_devconfig(newslice); 875*0Sstevel@tonic-gate error = ENOMEM; 876*0Sstevel@tonic-gate } else { 877*0Sstevel@tonic-gate moddisk->slices = 878*0Sstevel@tonic-gate dlist_append(item, moddisk->slices, AT_TAIL); 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate } else { 881*0Sstevel@tonic-gate free_devconfig(newslice); 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate return (error); 886*0Sstevel@tonic-gate } 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate /* 889*0Sstevel@tonic-gate * FUNCTION: get_modified_slices_for_disks(dlist_t *mod_disks) 890*0Sstevel@tonic-gate * 891*0Sstevel@tonic-gate * INPUT: mod_disks - a list of moddisk_t structs 892*0Sstevel@tonic-gate * 893*0Sstevel@tonic-gate * OUTPUT: mod_disks - the list of moddisk_t structs updated with 894*0Sstevel@tonic-gate * the modified slices for each disk 895*0Sstevel@tonic-gate * 896*0Sstevel@tonic-gate * RETURNS: int - 0 - success 897*0Sstevel@tonic-gate * !0 - failure 898*0Sstevel@tonic-gate * 899*0Sstevel@tonic-gate * PURPOSE: Helper to create a list of devconfig_t structs 900*0Sstevel@tonic-gate * for slices on the input disks which have been 901*0Sstevel@tonic-gate * modified for use by layout. 902*0Sstevel@tonic-gate * 903*0Sstevel@tonic-gate * Iterates the list of modified slices and creates a 904*0Sstevel@tonic-gate * devconfig_t component for each slice in the list 905*0Sstevel@tonic-gate * that is on any of the input modified disks. 906*0Sstevel@tonic-gate * 907*0Sstevel@tonic-gate * Slice names are constructed using the modified disk's 908*0Sstevel@tonic-gate * access name to ensure that the correct alias is 909*0Sstevel@tonic-gate * used to get to the slice. 910*0Sstevel@tonic-gate */ 911*0Sstevel@tonic-gate int 912*0Sstevel@tonic-gate get_modified_slices_for_disks( 913*0Sstevel@tonic-gate dlist_t *mod_disks) 914*0Sstevel@tonic-gate { 915*0Sstevel@tonic-gate int error = 0; 916*0Sstevel@tonic-gate dlist_t *iter = NULL; 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate for (iter = get_modified_slices(); 919*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 920*0Sstevel@tonic-gate iter = iter->next) { 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate modslice_t *mods = (modslice_t *)iter->obj; 923*0Sstevel@tonic-gate devconfig_t *slice = mods->slice_devcfg; 924*0Sstevel@tonic-gate devconfig_t *newslice = NULL; 925*0Sstevel@tonic-gate dm_descriptor_t disk; 926*0Sstevel@tonic-gate moddisk_t *moddisk; 927*0Sstevel@tonic-gate dlist_t *item; 928*0Sstevel@tonic-gate char *sname = NULL; 929*0Sstevel@tonic-gate uint64_t stblk = 0; 930*0Sstevel@tonic-gate uint64_t nblks = 0; 931*0Sstevel@tonic-gate uint16_t index; 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* only add modified slices that were sources */ 934*0Sstevel@tonic-gate if ((mods->times_modified == 0) || 935*0Sstevel@tonic-gate (mods->src_slice_desc != (dm_descriptor_t)0)) { 936*0Sstevel@tonic-gate continue; 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate (void) devconfig_get_name(slice, &sname); 940*0Sstevel@tonic-gate (void) get_disk_for_named_slice(sname, &disk); 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate if ((item = dlist_find(mod_disks, (void *)disk, 943*0Sstevel@tonic-gate compare_disk_to_moddisk_disk)) == NULL) { 944*0Sstevel@tonic-gate /* slice on disk that we don't care about */ 945*0Sstevel@tonic-gate continue; 946*0Sstevel@tonic-gate } 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate moddisk = (moddisk_t *)item->obj; 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate /* create output slice struct for the modified slice */ 951*0Sstevel@tonic-gate ((error = devconfig_get_slice_start_block(slice, 952*0Sstevel@tonic-gate &stblk)) != 0) || 953*0Sstevel@tonic-gate (error = devconfig_get_size_in_blocks(slice, &nblks)) || 954*0Sstevel@tonic-gate (error = devconfig_get_slice_index(slice, &index)) || 955*0Sstevel@tonic-gate (error = make_slicename_for_diskname_and_index( 956*0Sstevel@tonic-gate moddisk->accessname, index, &sname)) || 957*0Sstevel@tonic-gate (error = new_devconfig(&newslice, TYPE_SLICE)) || 958*0Sstevel@tonic-gate (error = devconfig_set_name(newslice, sname)) || 959*0Sstevel@tonic-gate (error = devconfig_set_slice_start_block(newslice, stblk)) || 960*0Sstevel@tonic-gate (error = devconfig_set_size_in_blocks(newslice, nblks)); 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate /* add to the moddisk's list of slices */ 963*0Sstevel@tonic-gate if (error == 0) { 964*0Sstevel@tonic-gate if ((item = dlist_new_item(newslice)) == NULL) { 965*0Sstevel@tonic-gate free_devconfig(newslice); 966*0Sstevel@tonic-gate error = ENOMEM; 967*0Sstevel@tonic-gate } else { 968*0Sstevel@tonic-gate moddisk->slices = 969*0Sstevel@tonic-gate dlist_append(item, moddisk->slices, AT_TAIL); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate } else { 972*0Sstevel@tonic-gate free_devconfig(newslice); 973*0Sstevel@tonic-gate } 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate return (error); 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate /* 980*0Sstevel@tonic-gate * FUNCTION: compare_disk_to_moddisk_disk(void *disk, void *moddisk) 981*0Sstevel@tonic-gate * 982*0Sstevel@tonic-gate * INPUT: disk - opaque pointer to a dm_descriptor_t 983*0Sstevel@tonic-gate * moddisk - opaque moddisk_t pointer 984*0Sstevel@tonic-gate * 985*0Sstevel@tonic-gate * RETURNS: int - 0 - if disk == moddisk->disk 986*0Sstevel@tonic-gate * !0 - otherwise 987*0Sstevel@tonic-gate * 988*0Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the input disk dm_descriptor_t 989*0Sstevel@tonic-gate * handle to the disk dm_descriptor_t handle in the input 990*0Sstevel@tonic-gate * moddisk_t struct. 991*0Sstevel@tonic-gate * 992*0Sstevel@tonic-gate * Comparison is done via compare_descriptor_names. 993*0Sstevel@tonic-gate */ 994*0Sstevel@tonic-gate static int 995*0Sstevel@tonic-gate compare_disk_to_moddisk_disk( 996*0Sstevel@tonic-gate void *disk, 997*0Sstevel@tonic-gate void *moddisk) 998*0Sstevel@tonic-gate { 999*0Sstevel@tonic-gate assert(disk != (dm_descriptor_t)0); 1000*0Sstevel@tonic-gate assert(moddisk != NULL); 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate return (compare_descriptor_names((void *)disk, 1003*0Sstevel@tonic-gate (void *)((moddisk_t *)moddisk)->disk)); 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * FUNCTIONS: void set_hsp_request() 1008*0Sstevel@tonic-gate * 1009*0Sstevel@tonic-gate * INPUT: none - 1010*0Sstevel@tonic-gate * OUTPUT: none - 1011*0Sstevel@tonic-gate * 1012*0Sstevel@tonic-gate * PURPOSE: set the module global HSP request struct. 1013*0Sstevel@tonic-gate */ 1014*0Sstevel@tonic-gate static void 1015*0Sstevel@tonic-gate set_hsp_request( 1016*0Sstevel@tonic-gate devconfig_t *req) 1017*0Sstevel@tonic-gate { 1018*0Sstevel@tonic-gate _hsp_request = req; 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate /* 1022*0Sstevel@tonic-gate * FUNCTIONS: void unset_hsp_request() 1023*0Sstevel@tonic-gate * 1024*0Sstevel@tonic-gate * INPUT: none - 1025*0Sstevel@tonic-gate * OUTPUT: none - 1026*0Sstevel@tonic-gate * 1027*0Sstevel@tonic-gate * PURPOSE: unset the module global HSP request struct. 1028*0Sstevel@tonic-gate */ 1029*0Sstevel@tonic-gate static void 1030*0Sstevel@tonic-gate unset_hsp_request() 1031*0Sstevel@tonic-gate { 1032*0Sstevel@tonic-gate _hsp_request = NULL; 1033*0Sstevel@tonic-gate } 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate /* 1036*0Sstevel@tonic-gate * FUNCTION: process_hsp_request(devconfig_t *req, dlist_t **results) 1037*0Sstevel@tonic-gate * INPUT: req - pointer to the toplevel disk set devconfig_t request 1038*0Sstevel@tonic-gate * results - pointer to a list of composed results 1039*0Sstevel@tonic-gate * 1040*0Sstevel@tonic-gate * RETURNS: int - 0 - success 1041*0Sstevel@tonic-gate * !0 - failure 1042*0Sstevel@tonic-gate * 1043*0Sstevel@tonic-gate * PURPOSE: Helper which determines HSP processing for the 1044*0Sstevel@tonic-gate * composed volumes which need HSP spares. 1045*0Sstevel@tonic-gate */ 1046*0Sstevel@tonic-gate static int 1047*0Sstevel@tonic-gate process_hsp_request( 1048*0Sstevel@tonic-gate devconfig_t *req, 1049*0Sstevel@tonic-gate dlist_t **results) 1050*0Sstevel@tonic-gate { 1051*0Sstevel@tonic-gate int error = 0; 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate if (_hsp_request != NULL) { 1054*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 1055*0Sstevel@tonic-gate gettext("\nProcessing HSP...\n")); 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate if (_hsp_devices == NULL) { 1059*0Sstevel@tonic-gate /* no devices -> no HSP */ 1060*0Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, 1061*0Sstevel@tonic-gate gettext(" No devices require hot spares...\n")); 1062*0Sstevel@tonic-gate } else { 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, "\n"); 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate ((error = layout_hsp(req, _hsp_request, _hsp_devices, 1067*0Sstevel@tonic-gate results)) != 0) || 1068*0Sstevel@tonic-gate (error = collect_modified_disks(_hsp_request, *results)) || 1069*0Sstevel@tonic-gate (error = convert_device_names(_hsp_request, *results)); 1070*0Sstevel@tonic-gate } 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate return (error); 1073*0Sstevel@tonic-gate } 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate /* 1076*0Sstevel@tonic-gate * FUNCTION: add_to_hsp_list(dlist_t* list) 1077*0Sstevel@tonic-gate * INPUT: devs - pointer to a list of composed volumes 1078*0Sstevel@tonic-gate * OUTPUT: none - 1079*0Sstevel@tonic-gate * SIDEEFFECT: updates the module global list _hsp_devices 1080*0Sstevel@tonic-gate * 1081*0Sstevel@tonic-gate * RETURNS: int - 0 - success 1082*0Sstevel@tonic-gate * !0 - failure 1083*0Sstevel@tonic-gate * 1084*0Sstevel@tonic-gate * PURPOSE: Helper to update the list of devices which need HSP spares. 1085*0Sstevel@tonic-gate * 1086*0Sstevel@tonic-gate * Iterates the input list of devices and adds them them to the 1087*0Sstevel@tonic-gate * module provate list of devices needing spares. 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate int 1090*0Sstevel@tonic-gate add_to_hsp_list( 1091*0Sstevel@tonic-gate dlist_t *list) 1092*0Sstevel@tonic-gate { 1093*0Sstevel@tonic-gate dlist_t *iter = NULL; 1094*0Sstevel@tonic-gate int error = 0; 1095*0Sstevel@tonic-gate 1096*0Sstevel@tonic-gate for (iter = list; iter != NULL; iter = iter->next) { 1097*0Sstevel@tonic-gate dlist_t *item = NULL; 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate if ((item = dlist_new_item(iter->obj)) == NULL) { 1100*0Sstevel@tonic-gate error = ENOMEM; 1101*0Sstevel@tonic-gate break; 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate _hsp_devices = dlist_append(item, _hsp_devices, AT_HEAD); 1104*0Sstevel@tonic-gate } 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate return (error); 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate /* 1110*0Sstevel@tonic-gate * FUNCTION: string_case_compare( 1111*0Sstevel@tonic-gate * char *str1, char *str2) 1112*0Sstevel@tonic-gate * 1113*0Sstevel@tonic-gate * INPUT: str1 - char * 1114*0Sstevel@tonic-gate * str2 - char * 1115*0Sstevel@tonic-gate * 1116*0Sstevel@tonic-gate * RETURNS: int - <0 - if str1 < str2 1117*0Sstevel@tonic-gate * 0 - if str1 == str2 1118*0Sstevel@tonic-gate * >0 - if str1 > str2 1119*0Sstevel@tonic-gate * 1120*0Sstevel@tonic-gate * PURPOSE: More robust case independent string comparison function. 1121*0Sstevel@tonic-gate * 1122*0Sstevel@tonic-gate * Assumes str1 and str2 are both char * 1123*0Sstevel@tonic-gate * 1124*0Sstevel@tonic-gate * Compares the lengths of each and if equivalent compares 1125*0Sstevel@tonic-gate * the strings using strcasecmp. 1126*0Sstevel@tonic-gate */ 1127*0Sstevel@tonic-gate int 1128*0Sstevel@tonic-gate string_case_compare( 1129*0Sstevel@tonic-gate char *str1, 1130*0Sstevel@tonic-gate char *str2) 1131*0Sstevel@tonic-gate { 1132*0Sstevel@tonic-gate int result = 0; 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate assert(str1 != NULL); 1135*0Sstevel@tonic-gate assert(str2 != NULL); 1136*0Sstevel@tonic-gate 1137*0Sstevel@tonic-gate if ((result = (strlen(str1) - strlen(str2))) == 0) { 1138*0Sstevel@tonic-gate result = strcasecmp(str1, str2); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate return (result); 1142*0Sstevel@tonic-gate } 1143