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 2004 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 <stdio.h> 30*0Sstevel@tonic-gate #include <meta.h> 31*0Sstevel@tonic-gate #include "meta_repartition.h" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate /* 36*0Sstevel@tonic-gate * FUNCTION: meta_replicaslice() 37*0Sstevel@tonic-gate * INPUT: dnp - the name of the drive to check 38*0Sstevel@tonic-gate * OUTPUT: slicep - pointer to slice number 39*0Sstevel@tonic-gate * ep - pointer to an md_error_t structure in which 40*0Sstevel@tonic-gate * to return errors to the caller 41*0Sstevel@tonic-gate * RETURNS: int - 0 - value pointed to by slicep is valid 42*0Sstevel@tonic-gate * -1 - otherwise 43*0Sstevel@tonic-gate * 44*0Sstevel@tonic-gate * PURPOSE: Determine which slice of the specified drive to 45*0Sstevel@tonic-gate * reserve, presumably for metadb replica usage. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * NOTE: If slicep is NULL, the return code will indicate 48*0Sstevel@tonic-gate * whether or not the slice number could be determined 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate int 51*0Sstevel@tonic-gate meta_replicaslice( 52*0Sstevel@tonic-gate mddrivename_t *dnp, 53*0Sstevel@tonic-gate uint_t *slicep, 54*0Sstevel@tonic-gate md_error_t *ep 55*0Sstevel@tonic-gate ) 56*0Sstevel@tonic-gate { 57*0Sstevel@tonic-gate int err = 0; 58*0Sstevel@tonic-gate int ioctl_return; 59*0Sstevel@tonic-gate int fd; 60*0Sstevel@tonic-gate char *rname; 61*0Sstevel@tonic-gate struct dk_geom geom; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate rname = dnp->rname; 64*0Sstevel@tonic-gate if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) { 65*0Sstevel@tonic-gate char *n; 66*0Sstevel@tonic-gate int open_errno; 67*0Sstevel@tonic-gate size_t len; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate if (errno != ENOENT) 70*0Sstevel@tonic-gate return (mdsyserror(ep, errno, rname)); 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate len = strlen(rname) + 3; 73*0Sstevel@tonic-gate n = Zalloc(len); 74*0Sstevel@tonic-gate (void) snprintf(n, len, "%ss0", rname); 75*0Sstevel@tonic-gate fd = open(n, (O_RDONLY|O_NDELAY), 0); 76*0Sstevel@tonic-gate open_errno = errno; 77*0Sstevel@tonic-gate Free(n); 78*0Sstevel@tonic-gate if (fd < 0) { 79*0Sstevel@tonic-gate return (mdsyserror(ep, open_errno, rname)); 80*0Sstevel@tonic-gate } 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* 84*0Sstevel@tonic-gate * if our drivenamep points to a device not supporting 85*0Sstevel@tonic-gate * DKIOCGGEOM, we have an EFI label. 86*0Sstevel@tonic-gate */ 87*0Sstevel@tonic-gate errno = 0; 88*0Sstevel@tonic-gate ioctl_return = ioctl(fd, DKIOCGGEOM, &geom); 89*0Sstevel@tonic-gate err = errno; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate (void) close(fd); 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate /* 94*0Sstevel@tonic-gate * If the DKIOCGGEOM ioctl succeeded, then the device has a 95*0Sstevel@tonic-gate * VTOC style label. In this case, we use slice 7. 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate if (ioctl_return == 0) { 98*0Sstevel@tonic-gate if (slicep != NULL) { 99*0Sstevel@tonic-gate *slicep = MD_SLICE7; 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate return (0); 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* 105*0Sstevel@tonic-gate * ENOTSUP indicates an EFI style label, in which case slice 7 106*0Sstevel@tonic-gate * cannot be used because its minor number is reserved. In 107*0Sstevel@tonic-gate * this case, use slice 6. 108*0Sstevel@tonic-gate */ 109*0Sstevel@tonic-gate if (err == ENOTSUP) { 110*0Sstevel@tonic-gate if (slicep != NULL) { 111*0Sstevel@tonic-gate *slicep = MD_SLICE6; 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate return (0); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate /* 117*0Sstevel@tonic-gate * Those are the only two cases we know how to deal with; 118*0Sstevel@tonic-gate * either the drivenamep didn't point to a disk, or the ioctl 119*0Sstevel@tonic-gate * failed for some other reason. 120*0Sstevel@tonic-gate */ 121*0Sstevel@tonic-gate if (err == ENOTTY) { 122*0Sstevel@tonic-gate return (mddeverror(ep, MDE_NOT_DISK, NODEV, rname)); 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate return (mdsyserror(ep, err, rname)); 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * FUNCTION: meta_repartition_drive() 132*0Sstevel@tonic-gate * INPUT: sp - the set name for the device to check 133*0Sstevel@tonic-gate * dnp - the name of the drive to partition 134*0Sstevel@tonic-gate * options - options (see NOTES) 135*0Sstevel@tonic-gate * OUTPUT: vtocp - pointer to an mdvtoc_t structure in which 136*0Sstevel@tonic-gate * to return the new VTOC to the caller 137*0Sstevel@tonic-gate * ep - pointer to an md_error_t structure in which 138*0Sstevel@tonic-gate * to return errors to the caller 139*0Sstevel@tonic-gate * RETURNS: int - 0 - drive was or can be repartitioned 140*0Sstevel@tonic-gate * -1 - drive could not or should not be 141*0Sstevel@tonic-gate * repartitioned 142*0Sstevel@tonic-gate * PURPOSE: Repartition a disk for use in a disk set or in order 143*0Sstevel@tonic-gate * to create soft partitions on it. Alternatively, 144*0Sstevel@tonic-gate * return the VTOC that the disk would have if it were 145*0Sstevel@tonic-gate * repartitioned without actually repartitioning it. 146*0Sstevel@tonic-gate * 147*0Sstevel@tonic-gate * NOTES: 148*0Sstevel@tonic-gate * 149*0Sstevel@tonic-gate * This routine will repartition a drive to make it suitable for 150*0Sstevel@tonic-gate * inclusion in a diskset. Specifically, it will create a 151*0Sstevel@tonic-gate * proposed VTOC that specifies a replica slice that begins at the 152*0Sstevel@tonic-gate * first valid lba, is large enough to hold a label and a metadb 153*0Sstevel@tonic-gate * replica, does not overlap any other slices, and is unmountable. 154*0Sstevel@tonic-gate * If the current replica slice already satisfies those criteria, 155*0Sstevel@tonic-gate * the routine will neither create a proposed VTOC nor repartition 156*0Sstevel@tonic-gate * the drive unless the MD_REPART_FORCE flag is passed into the 157*0Sstevel@tonic-gate * routine in the options argument. If the routine does create a 158*0Sstevel@tonic-gate * proposed VTOC, it will return the proposed VTOC in *vtocp if 159*0Sstevel@tonic-gate * vtocp isn't NULL. 160*0Sstevel@tonic-gate * 161*0Sstevel@tonic-gate * The slice to be used as the replica slice is determined by the 162*0Sstevel@tonic-gate * function meta_replicaslice(). 163*0Sstevel@tonic-gate * 164*0Sstevel@tonic-gate * If the replica slice does not satisfy the above criteria or the 165*0Sstevel@tonic-gate * MD_REPART_FORCE flag is set, the proposed VTOC will specify a 166*0Sstevel@tonic-gate * replica slice that satisfies the above criteria, a slice zero 167*0Sstevel@tonic-gate * that contains the remaining space on the disk, and no other 168*0Sstevel@tonic-gate * slices. If that repartitioning would cause the replica slice 169*0Sstevel@tonic-gate * to move or shrink, and the MD_REPART_LEAVE_REP option is set, 170*0Sstevel@tonic-gate * the routine will return -1 without creating or returning a 171*0Sstevel@tonic-gate * proposed vtoc, and without repartitioning the disk. Otherwise 172*0Sstevel@tonic-gate * the routine will repartition the disk unless the 173*0Sstevel@tonic-gate * MD_REPART_DONT_LABEL flag is set in the options argument. 174*0Sstevel@tonic-gate * 175*0Sstevel@tonic-gate * If the MD_REPART_DONT_LABEL flag is set in the options argument, 176*0Sstevel@tonic-gate * but the routine would otherwise repartition the drive, the 177*0Sstevel@tonic-gate * routine won't repartition the drive, but will create a proposed 178*0Sstevel@tonic-gate * VTOC that satisfies the criteria defined above and return it 179*0Sstevel@tonic-gate * it in *vtocp if vtocp isn't NULL, The MD_REPART_DONT_LABEL 180*0Sstevel@tonic-gate * option allows calling routines to determine what the contents of 181*0Sstevel@tonic-gate * the drive's VTOC would be if the drive were repartitioned without 182*0Sstevel@tonic-gate * actually repartitioning the drive. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate int 185*0Sstevel@tonic-gate meta_repartition_drive( 186*0Sstevel@tonic-gate mdsetname_t *sp, 187*0Sstevel@tonic-gate mddrivename_t *dnp, 188*0Sstevel@tonic-gate int options, 189*0Sstevel@tonic-gate mdvtoc_t *vtocp, 190*0Sstevel@tonic-gate md_error_t *ep 191*0Sstevel@tonic-gate ) 192*0Sstevel@tonic-gate { 193*0Sstevel@tonic-gate uint_t replicaslice; 194*0Sstevel@tonic-gate diskaddr_t first_lba, last_lba; 195*0Sstevel@tonic-gate int round_sizes = 1; 196*0Sstevel@tonic-gate unsigned long long cylsize; 197*0Sstevel@tonic-gate unsigned long long drvsize; 198*0Sstevel@tonic-gate int i; 199*0Sstevel@tonic-gate mdgeom_t *mdgp; 200*0Sstevel@tonic-gate mdvtoc_t *mdvp; 201*0Sstevel@tonic-gate mdvtoc_t proposed_vtoc; 202*0Sstevel@tonic-gate uint_t reservedcyl; 203*0Sstevel@tonic-gate ushort_t resflag; 204*0Sstevel@tonic-gate mdname_t *resnp; 205*0Sstevel@tonic-gate unsigned long long ressize; 206*0Sstevel@tonic-gate md_set_desc *sd; 207*0Sstevel@tonic-gate daddr_t dbsize; 208*0Sstevel@tonic-gate diskaddr_t replica_start; 209*0Sstevel@tonic-gate diskaddr_t replica_size; 210*0Sstevel@tonic-gate diskaddr_t replica_end; 211*0Sstevel@tonic-gate diskaddr_t data_start; 212*0Sstevel@tonic-gate diskaddr_t data_size; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate if (meta_replicaslice(dnp, &replicaslice, ep) != 0) { 215*0Sstevel@tonic-gate return (-1); 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* Don't round for EFI disks */ 219*0Sstevel@tonic-gate if (replicaslice == MD_SLICE6) 220*0Sstevel@tonic-gate round_sizes = 0; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * We took as argument a drive name pointer, but we need a 224*0Sstevel@tonic-gate * slice name pointer to retrieve vtoc information. So get 225*0Sstevel@tonic-gate * the name pointer for slice zero first, then use it to get 226*0Sstevel@tonic-gate * the vtoc info for the disk. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate if ((resnp = metaslicename(dnp, MD_SLICE0, ep)) == NULL) 229*0Sstevel@tonic-gate return (-1); 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate if ((mdvp = metagetvtoc(resnp, FALSE, NULL, ep)) == NULL) 232*0Sstevel@tonic-gate return (-1); 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* 235*0Sstevel@tonic-gate * Determine the metadb size. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate dbsize = MD_DBSIZE; 238*0Sstevel@tonic-gate if (!metaislocalset(sp)) { 239*0Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL) 240*0Sstevel@tonic-gate return (-1); 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate if (MD_MNSET_DESC(sd)) 243*0Sstevel@tonic-gate dbsize = MD_MN_DBSIZE; 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* If we've got an efi disk, we better have lba info */ 247*0Sstevel@tonic-gate first_lba = mdvp->first_lba; 248*0Sstevel@tonic-gate last_lba = mdvp->last_lba; 249*0Sstevel@tonic-gate ASSERT((round_sizes != 0) || (last_lba > 0)); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * At this point, ressize is used as a minimum value. Later 253*0Sstevel@tonic-gate * it will be rounded up to a cylinder boundary if 254*0Sstevel@tonic-gate * appropriate. ressize is in units of disk sectors. 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate ressize = dbsize + VTOC_SIZE; 257*0Sstevel@tonic-gate resflag = V_UNMNT; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * If we're forcing the repartition, we can skip the replica 261*0Sstevel@tonic-gate * slice and overlap tests. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate if (options & MD_REPART_FORCE) { 264*0Sstevel@tonic-gate goto do_repartition; 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * Replica slice tests: it must begin at first_lba, be long 269*0Sstevel@tonic-gate * enough, have the right flags, and not overlap any other 270*0Sstevel@tonic-gate * slices. If any of these conditions is violated, we need to 271*0Sstevel@tonic-gate * repartition the disk. 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate if (mdvp->parts[replicaslice].start != first_lba) { 274*0Sstevel@tonic-gate goto do_repartition; 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate if (mdvp->parts[replicaslice].size < ressize) { 278*0Sstevel@tonic-gate goto do_repartition; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate if (mdvp->parts[replicaslice].flag != resflag) { 282*0Sstevel@tonic-gate goto do_repartition; 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate /* 286*0Sstevel@tonic-gate * Check for overlap: this test should use the actual size of 287*0Sstevel@tonic-gate * the replica slice, as contained in the vtoc, and NOT the 288*0Sstevel@tonic-gate * minimum size calculated above. 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate replica_end = first_lba + mdvp->parts[replicaslice].size; 291*0Sstevel@tonic-gate for (i = 0; i < mdvp->nparts; i++) { 292*0Sstevel@tonic-gate if (i != replicaslice) { 293*0Sstevel@tonic-gate if ((mdvp->parts[i].size > 0) && 294*0Sstevel@tonic-gate (mdvp->parts[i].start < replica_end)) { 295*0Sstevel@tonic-gate goto do_repartition; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * If we passed the above tests, then the disk is already 302*0Sstevel@tonic-gate * partitioned appropriately, and we're not being told to 303*0Sstevel@tonic-gate * force a change. 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate return (0); 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate do_repartition: 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* Retrieve disk geometry info and round to cylinder sizes */ 310*0Sstevel@tonic-gate if (round_sizes != 0) { 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if ((mdgp = metagetgeom(resnp, ep)) == NULL) 313*0Sstevel@tonic-gate return (-1); 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * Both cylsize and drvsize are in units of disk 317*0Sstevel@tonic-gate * sectors. 318*0Sstevel@tonic-gate * 319*0Sstevel@tonic-gate * The intended results are of type unsigned long 320*0Sstevel@tonic-gate * long. Since each operand of the first 321*0Sstevel@tonic-gate * multiplication is of type unsigned int, we risk 322*0Sstevel@tonic-gate * overflow by multiplying and then converting the 323*0Sstevel@tonic-gate * result. Therefore we explicitly cast (at least) 324*0Sstevel@tonic-gate * one of the operands, forcing conversion BEFORE 325*0Sstevel@tonic-gate * multiplication, and avoiding overflow. The second 326*0Sstevel@tonic-gate * assignment is OK, since one of the operands is 327*0Sstevel@tonic-gate * already of the desired type. 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate cylsize = 330*0Sstevel@tonic-gate ((unsigned long long)mdgp->nhead) * mdgp->nsect; 331*0Sstevel@tonic-gate drvsize = cylsize * mdgp->ncyl; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * How many cylinders must we reserve for the replica 335*0Sstevel@tonic-gate * slice to ensure that it meets the previously 336*0Sstevel@tonic-gate * calculated minimum size? 337*0Sstevel@tonic-gate */ 338*0Sstevel@tonic-gate reservedcyl = (ressize + cylsize - 1) / cylsize; 339*0Sstevel@tonic-gate ressize = reservedcyl * cylsize; 340*0Sstevel@tonic-gate } else { 341*0Sstevel@tonic-gate drvsize = last_lba - first_lba; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* Would this require a forbidden change? */ 345*0Sstevel@tonic-gate if (options & MD_REPART_LEAVE_REP) { 346*0Sstevel@tonic-gate if ((mdvp->parts[replicaslice].start != first_lba) || 347*0Sstevel@tonic-gate (mdvp->parts[replicaslice].size < ressize)) { 348*0Sstevel@tonic-gate return (mddeverror(ep, MDE_REPART_REPLICA, 349*0Sstevel@tonic-gate resnp->dev, NULL)); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * It seems unlikely that someone would pass us too small a 355*0Sstevel@tonic-gate * disk, but it's still worth checking for... 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate if (((round_sizes != 0) && (reservedcyl >= (int)mdgp->ncyl)) || 358*0Sstevel@tonic-gate ((round_sizes == 0) && (ressize + first_lba >= last_lba))) { 359*0Sstevel@tonic-gate return (mdmddberror(ep, MDE_DB_TOOSMALL, 360*0Sstevel@tonic-gate meta_getminor(resnp->dev), sp->setno, 0, NULL)); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate replica_start = first_lba; 364*0Sstevel@tonic-gate replica_size = ressize; 365*0Sstevel@tonic-gate data_start = first_lba + ressize; 366*0Sstevel@tonic-gate data_size = drvsize - ressize; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* 369*0Sstevel@tonic-gate * Create the proposed VTOC. First copy the current VTOC 370*0Sstevel@tonic-gate * into the proposed VTOC to duplicate the values that don't 371*0Sstevel@tonic-gate * need to change. Then change the partition table and set 372*0Sstevel@tonic-gate * the flag value for the replica slice to resflag to reserve it 373*0Sstevel@tonic-gate * for metadata. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate proposed_vtoc = *mdvp; 376*0Sstevel@tonic-gate /* We need at least replicaslice partitions in the proposed vtoc */ 377*0Sstevel@tonic-gate if (replicaslice >= proposed_vtoc.nparts) { 378*0Sstevel@tonic-gate proposed_vtoc.nparts = replicaslice + 1; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate for (i = 0; i < proposed_vtoc.nparts; i++) { 381*0Sstevel@tonic-gate /* don't change the reserved partition of an EFI device */ 382*0Sstevel@tonic-gate if (proposed_vtoc.parts[i].tag == V_RESERVED) 383*0Sstevel@tonic-gate data_size = proposed_vtoc.parts[i].start - data_start; 384*0Sstevel@tonic-gate else 385*0Sstevel@tonic-gate (void) memset(&proposed_vtoc.parts[i], '\0', 386*0Sstevel@tonic-gate sizeof (proposed_vtoc.parts[i])); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate proposed_vtoc.parts[MD_SLICE0].start = data_start; 390*0Sstevel@tonic-gate proposed_vtoc.parts[MD_SLICE0].size = data_size; 391*0Sstevel@tonic-gate proposed_vtoc.parts[MD_SLICE0].tag = V_USR; 392*0Sstevel@tonic-gate proposed_vtoc.parts[replicaslice].start = replica_start; 393*0Sstevel@tonic-gate proposed_vtoc.parts[replicaslice].size = replica_size; 394*0Sstevel@tonic-gate proposed_vtoc.parts[replicaslice].flag = resflag; 395*0Sstevel@tonic-gate proposed_vtoc.parts[replicaslice].tag = V_USR; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate if (!(options & MD_REPART_DONT_LABEL)) { 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * Label the disk with the proposed VTOC. 400*0Sstevel@tonic-gate */ 401*0Sstevel@tonic-gate *mdvp = proposed_vtoc; 402*0Sstevel@tonic-gate if (metasetvtoc(resnp, ep) != 0) { 403*0Sstevel@tonic-gate return (-1); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate if (vtocp != NULL) { 408*0Sstevel@tonic-gate /* 409*0Sstevel@tonic-gate * Return the proposed VTOC. 410*0Sstevel@tonic-gate */ 411*0Sstevel@tonic-gate *vtocp = proposed_vtoc; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate return (0); 415*0Sstevel@tonic-gate } 416