Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * Just in case we're not in a build environment, make sure that
     28  * TEXT_DOMAIN gets set to something.
     29  */
     30 #if !defined(TEXT_DOMAIN)
     31 #define	TEXT_DOMAIN "SYS_TEST"
     32 #endif
     33 
     34 /*
     35  * stripe operations
     36  */
     37 
     38 #include <limits.h>
     39 #include <stdlib.h>
     40 #include <meta.h>
     41 #include <sys/lvm/md_stripe.h>
     42 #include <sys/lvm/md_convert.h>
     43 
     44 #define	QUOTE(x)	#x
     45 #define	VAL2STR(x)	QUOTE(x)
     46 
     47 /*
     48  * replace stripe/concat
     49  */
     50 int
     51 meta_stripe_replace(
     52 	mdsetname_t	*sp,
     53 	mdname_t	*stripenp,
     54 	mdname_t	*oldnp,
     55 	mdname_t	*newnp,
     56 	mdcmdopts_t	options,
     57 	md_error_t	*ep
     58 )
     59 {
     60 	replace_params_t	params;
     61 	md_dev64_t	old_dev, new_dev;
     62 	diskaddr_t	new_start_blk;
     63 	diskaddr_t	new_end_blk, label, size, start_blk;
     64 
     65 	/* should have same set */
     66 	assert(sp != NULL);
     67 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
     68 
     69 	new_dev = newnp->dev;
     70 	new_start_blk = newnp->start_blk;
     71 	new_end_blk = newnp->end_blk;
     72 
     73 	meta_invalidate_name(stripenp);
     74 
     75 	/* the old device binding is now established */
     76 	if ((old_dev = oldnp->dev) == NODEV64)
     77 		return (mdsyserror(ep, ENODEV, oldnp->cname));
     78 
     79 	if (((strcmp(oldnp->rname, newnp->rname) == 0) &&
     80 	    (old_dev != new_dev))) {
     81 		newnp->dev = new_dev;
     82 		newnp->start_blk = new_start_blk;
     83 		newnp->end_blk = new_end_blk;
     84 	}
     85 
     86 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR)
     87 		return (-1);
     88 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR)
     89 		return (-1);
     90 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR)
     91 		return (-1);
     92 	if (start_blk >= size) {
     93 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
     94 		return (-1);
     95 	}
     96 
     97 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
     98 	if (options & MDCMD_DOIT) {
     99 		if (add_key_name(sp, newnp, NULL, ep) != 0)
    100 			return (-1);
    101 	}
    102 
    103 	/*
    104 	 * There is no need to call meta_fixdevid() here as this function is
    105 	 * only called by the metareplace -c command which actually does
    106 	 * nothing (in terms of a resync) and thus does nothing with the devid.
    107 	 */
    108 
    109 	(void) memset(&params, 0, sizeof (params));
    110 	params.mnum = meta_getminor(stripenp->dev);
    111 	MD_SETDRIVERNAME(&params, MD_STRIPE, sp->setno);
    112 
    113 	params.cmd = REPLACE_COMP;
    114 	params.old_dev = old_dev;
    115 	params.new_dev = new_dev;
    116 	params.new_key = newnp->key;
    117 	params.start_blk = newnp->start_blk;
    118 	params.number_blks = size;
    119 	/* Is this just a dryrun ? */
    120 	if ((options & MDCMD_DOIT) == 0) {
    121 		params.options |= MDIOCTL_DRYRUN;
    122 	}
    123 	if (label == 0)
    124 		params.has_label = 0;
    125 	else
    126 		params.has_label = 1;
    127 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
    128 		if (options & MDCMD_DOIT)
    129 			(void) del_key_name(sp, newnp, ep);
    130 		return (mdstealerror(ep, &params.mde));
    131 	}
    132 	meta_invalidate_name(oldnp);
    133 	meta_invalidate_name(newnp);
    134 	meta_invalidate_name(stripenp);
    135 
    136 	if (options & MDCMD_PRINT) {
    137 		(void) printf(dgettext(TEXT_DOMAIN,
    138 		    "%s: device %s is replaced with %s\n"),
    139 		    stripenp->cname, oldnp->cname, newnp->cname);
    140 
    141 	}
    142 	return (0);
    143 }
    144 
    145 
    146 /*
    147  * FUNCTION:	meta_get_stripe_names()
    148  * INPUT:	sp	- the set name to get stripes from
    149  *		options	- options from the command line
    150  * OUTPUT:	nlpp	- list of all stripe names
    151  *		ep	- return error pointer
    152  * RETURNS:	int	- -1 if error, 0 success
    153  * PURPOSE:	returns a list of all stripes in the metadb
    154  *		for all devices in the specified set
    155  */
    156 int
    157 meta_get_stripe_names(
    158 	mdsetname_t	*sp,
    159 	mdnamelist_t	**nlpp,
    160 	int		options,
    161 	md_error_t	*ep
    162 )
    163 {
    164 	return (meta_get_names(MD_STRIPE, sp, nlpp, options, ep));
    165 }
    166 
    167 /*
    168  * free stripe
    169  */
    170 void
    171 meta_free_stripe(
    172 	md_stripe_t	*stripep
    173 )
    174 {
    175 	uint_t		row;
    176 
    177 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
    178 		md_row_t	*rp = &stripep->rows.rows_val[row];
    179 
    180 		if (rp->comps.comps_val != NULL) {
    181 			assert(rp->comps.comps_len > 0);
    182 			Free(rp->comps.comps_val);
    183 		}
    184 	}
    185 	if (stripep->rows.rows_val != NULL) {
    186 		assert(stripep->rows.rows_len > 0);
    187 		Free(stripep->rows.rows_val);
    188 	}
    189 	Free(stripep);
    190 }
    191 
    192 
    193 /*
    194  * get stripe (common)
    195  */
    196 md_stripe_t *
    197 meta_get_stripe_common(
    198 	mdsetname_t	*sp,
    199 	mdname_t	*stripenp,
    200 	int		fast,
    201 	md_error_t	*ep
    202 )
    203 {
    204 	mddrivename_t	*dnp = stripenp->drivenamep;
    205 	char		*miscname;
    206 	ms_unit_t	*ms;
    207 	md_stripe_t	*stripep;
    208 	uint_t		row;
    209 
    210 	/* must have set */
    211 	assert(sp != NULL);
    212 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
    213 
    214 	/* short circuit */
    215 	if (dnp->unitp != NULL) {
    216 		assert(dnp->unitp->type == MD_DEVICE);
    217 		return ((md_stripe_t *)dnp->unitp);
    218 	}
    219 
    220 	/* get miscname and unit */
    221 	if ((miscname = metagetmiscname(stripenp, ep)) == NULL)
    222 		return (NULL);
    223 	if (strcmp(miscname, MD_STRIPE) != 0) {
    224 		(void) mdmderror(ep, MDE_NOT_STRIPE,
    225 		    meta_getminor(stripenp->dev), stripenp->cname);
    226 		return (NULL);
    227 	}
    228 	if ((ms = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL)
    229 		return (NULL);
    230 	assert(ms->c.un_type == MD_DEVICE);
    231 
    232 	/* allocate stripe */
    233 	stripep = Zalloc(sizeof (*stripep));
    234 
    235 	/* allocate rows */
    236 	assert(ms->un_nrows > 0);
    237 	stripep->rows.rows_len = ms->un_nrows;
    238 	stripep->rows.rows_val = Zalloc(stripep->rows.rows_len *
    239 	    sizeof (*stripep->rows.rows_val));
    240 
    241 	/* get common info */
    242 	stripep->common.namep = stripenp;
    243 	stripep->common.type = ms->c.un_type;
    244 	stripep->common.state = ms->c.un_status;
    245 	stripep->common.capabilities = ms->c.un_capabilities;
    246 	stripep->common.parent = ms->c.un_parent;
    247 	stripep->common.size = ms->c.un_total_blocks;
    248 	stripep->common.user_flags = ms->c.un_user_flags;
    249 	stripep->common.revision = ms->c.un_revision;
    250 
    251 	/* get options */
    252 	if ((ms->un_hsp_id != MD_HSP_NONE) &&
    253 	    ((stripep->hspnamep = metahsphspname(&sp, ms->un_hsp_id,
    254 	    ep)) == NULL)) {
    255 		goto out;
    256 	}
    257 
    258 	/* get rows */
    259 	for (row = 0; (row < ms->un_nrows); ++row) {
    260 		struct ms_row	*mdr = &ms->un_row[row];
    261 		struct ms_comp	*mdcomp = (void *)&((char *)ms)[ms->un_ocomp];
    262 		md_row_t	*rp = &stripep->rows.rows_val[row];
    263 		uint_t		comp, c;
    264 
    265 		/* get interlace */
    266 		rp->interlace = mdr->un_interlace;
    267 
    268 		/* allocate comps */
    269 		assert(mdr->un_ncomp > 0);
    270 		rp->comps.comps_len = mdr->un_ncomp;
    271 		rp->comps.comps_val = Zalloc(rp->comps.comps_len *
    272 		    sizeof (*rp->comps.comps_val));
    273 
    274 		/* get components */
    275 		for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp);
    276 		    ++comp, ++c) {
    277 			struct ms_comp	*mdc = &mdcomp[c];
    278 			diskaddr_t	comp_start_blk = mdc->un_start_block;
    279 			md_comp_t	*cp = &rp->comps.comps_val[comp];
    280 
    281 			/* get the component name */
    282 			cp->compnamep = metakeyname(&sp, mdc->un_key, fast, ep);
    283 			if (cp->compnamep == NULL)
    284 				goto out;
    285 
    286 			/* if hotspared */
    287 			if (mdc->un_mirror.ms_hs_id != 0) {
    288 				diskaddr_t hs_start_blk = mdc->un_start_block;
    289 
    290 				/* get the hotspare name */
    291 				cp->hsnamep = metakeyname(&sp,
    292 				    mdc->un_mirror.ms_hs_key, fast, ep);
    293 				if (cp->hsnamep == NULL)
    294 					goto out;
    295 
    296 				if (getenv("META_DEBUG_START_BLK") != NULL) {
    297 					if (metagetstart(sp, cp->hsnamep,
    298 					    ep) == MD_DISKADDR_ERROR)
    299 						mdclrerror(ep);
    300 
    301 					if ((cp->hsnamep->start_blk == 0) &&
    302 					    (hs_start_blk != 0))
    303 						md_eprintf(dgettext(TEXT_DOMAIN,
    304 						    "%s: suspected bad"
    305 						    "start block,"
    306 						    " seems labelled"
    307 						    "[stripe/hs]\n"),
    308 						    cp->hsnamep->cname);
    309 
    310 					if ((cp->hsnamep->start_blk > 0) &&
    311 					    (hs_start_blk == 0) &&
    312 					    ! ((row == 0) && (comp == 0)))
    313 						md_eprintf(dgettext(TEXT_DOMAIN,
    314 						    "%s: suspected bad"
    315 						    "start block, "
    316 						    "seems unlabelled"
    317 						    "[stripe/hs]\n"),
    318 						    cp->hsnamep->cname);
    319 				}
    320 				/* override any start_blk */
    321 				cp->hsnamep->start_blk = hs_start_blk;
    322 
    323 				/* get the right component start_blk */
    324 				comp_start_blk = mdc->un_mirror.ms_orig_blk;
    325 			} else {
    326 				if (getenv("META_DEBUG_START_BLK") != NULL) {
    327 					if (metagetstart(sp, cp->compnamep,
    328 					    ep) == MD_DISKADDR_ERROR)
    329 						mdclrerror(ep);
    330 
    331 					if ((cp->compnamep->start_blk == 0) &&
    332 					    (comp_start_blk != 0))
    333 						md_eprintf(dgettext(TEXT_DOMAIN,
    334 						    "%s: suspected bad"
    335 						    "start block,"
    336 						    " seems labelled"
    337 						    "[stripe]"),
    338 						    cp->compnamep->cname);
    339 
    340 					if ((cp->compnamep->start_blk > 0) &&
    341 					    (comp_start_blk == 0) &&
    342 					    ! ((row == 0) && (comp == 0)))
    343 						md_eprintf(dgettext(TEXT_DOMAIN,
    344 						    "%s: suspected bad"
    345 						    "start block, "
    346 						    "seems unlabelled"
    347 						    "[stripe]"),
    348 						    cp->compnamep->cname);
    349 				}
    350 			}
    351 
    352 			/* override any start_blk */
    353 			cp->compnamep->start_blk = comp_start_blk;
    354 
    355 			/* get state */
    356 			cp->state = mdc->un_mirror.ms_state;
    357 
    358 			/* get time of last state change */
    359 			cp->timestamp = mdc->un_mirror.ms_timestamp;
    360 
    361 			/* get lasterr count */
    362 			cp->lasterrcnt = mdc->un_mirror.ms_lasterrcnt;
    363 		}
    364 	}
    365 
    366 	/* cleanup, return success */
    367 	Free(ms);
    368 	dnp->unitp = (md_common_t *)stripep;
    369 	return (stripep);
    370 
    371 	/* cleanup, return error */
    372 out:
    373 	Free(ms);
    374 	meta_free_stripe(stripep);
    375 	return (NULL);
    376 }
    377 
    378 /*
    379  * get stripe
    380  */
    381 md_stripe_t *
    382 meta_get_stripe(
    383 	mdsetname_t	*sp,
    384 	mdname_t	*stripenp,
    385 	md_error_t	*ep
    386 )
    387 {
    388 	return (meta_get_stripe_common(sp, stripenp, 0, ep));
    389 }
    390 
    391 /*
    392  * check stripe for dev
    393  */
    394 static int
    395 in_stripe(
    396 	mdsetname_t	*sp,
    397 	mdname_t	*stripenp,
    398 	mdname_t	*np,
    399 	diskaddr_t	slblk,
    400 	diskaddr_t	nblks,
    401 	md_error_t	*ep
    402 )
    403 {
    404 	md_stripe_t	*stripep;
    405 	uint_t		row;
    406 
    407 	/* should be in the same set */
    408 	assert(sp != NULL);
    409 
    410 	/* get unit */
    411 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
    412 		return (-1);
    413 
    414 	/* look in rows */
    415 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
    416 		md_row_t	*rp = &stripep->rows.rows_val[row];
    417 		uint_t		comp;
    418 
    419 		/* look in columns */
    420 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
    421 			md_comp_t	*cp = &rp->comps.comps_val[comp];
    422 			mdname_t	*compnp = cp->compnamep;
    423 			diskaddr_t	comp_sblk;
    424 			int		err;
    425 
    426 			/* check same drive since metagetstart() can fail */
    427 			if ((err = meta_check_samedrive(np, compnp, ep)) < 0)
    428 				return (-1);
    429 			else if (err == 0)
    430 				continue;
    431 
    432 			/* check overlap */
    433 			if ((comp_sblk = metagetstart(sp, compnp, ep)) ==
    434 			    MD_DISKADDR_ERROR)
    435 				return (-1);
    436 			if (meta_check_overlap(stripenp->cname, np,
    437 			    slblk, nblks, compnp, comp_sblk, -1,
    438 			    ep) != 0) {
    439 				return (-1);
    440 			}
    441 		}
    442 	}
    443 
    444 	/* return success */
    445 	return (0);
    446 }
    447 
    448 /*
    449  * check to see if we're in a stripe
    450  */
    451 int
    452 meta_check_instripe(
    453 	mdsetname_t	*sp,
    454 	mdname_t	*np,
    455 	diskaddr_t	slblk,
    456 	diskaddr_t	nblks,
    457 	md_error_t	*ep
    458 )
    459 {
    460 	mdnamelist_t	*stripenlp = NULL;
    461 	mdnamelist_t	*p;
    462 	int		rval = 0;
    463 
    464 	/* should have a set */
    465 	assert(sp != NULL);
    466 
    467 	/* for each stripe */
    468 	if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0)
    469 		return (-1);
    470 	for (p = stripenlp; (p != NULL); p = p->next) {
    471 		mdname_t	*stripenp = p->namep;
    472 
    473 		/* check stripe */
    474 		if (in_stripe(sp, stripenp, np, slblk, nblks, ep) != 0) {
    475 			rval = -1;
    476 			break;
    477 		}
    478 	}
    479 
    480 	/* cleanup, return success */
    481 	metafreenamelist(stripenlp);
    482 	return (rval);
    483 }
    484 
    485 /*
    486  * check component
    487  */
    488 int
    489 meta_check_component(
    490 	mdsetname_t	*sp,
    491 	mdname_t	*np,
    492 	int		force,
    493 	md_error_t	*ep
    494 )
    495 {
    496 	mdchkopts_t	options = (MDCHK_ALLOW_MDDB);
    497 	md_common_t	*mdp;
    498 
    499 	/*
    500 	 * See if we are a soft partition: meta_sp_issp() returns 0 if
    501 	 * np points to a soft partition, so the if and else clauses
    502 	 * here represent "not a soft partition" and "soft partition,"
    503 	 * respectively.
    504 	 */
    505 	if (meta_sp_issp(sp, np, ep) != 0) {
    506 		/* make sure we have a disk */
    507 		if (metachkcomp(np, ep) != 0)
    508 			return (-1);
    509 	} else {
    510 		/* make sure soft partition can parent & doesn't have parent */
    511 		if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
    512 			return (mdmderror(ep, MDE_INVAL_UNIT, NULL,
    513 			    np->cname));
    514 		if (mdp->capabilities == MD_CANT_PARENT)
    515 			return (mdmderror(ep, MDE_INVAL_UNIT, NULL,
    516 			    np->cname));
    517 		if (MD_HAS_PARENT(mdp->parent)) {
    518 			mdname_t *pnp;
    519 
    520 			pnp = metamnumname(&sp, mdp->parent, 0, ep);
    521 			if (pnp == NULL) {
    522 				return (-1);
    523 			}
    524 
    525 			return (mduseerror(ep, MDE_ALREADY, np->dev,
    526 			    pnp->cname, np->cname));
    527 		}
    528 	}
    529 
    530 	/* check to ensure that it is not already in use */
    531 	if ((! force) &&
    532 	    (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0)) {
    533 		return (-1);
    534 	}
    535 
    536 	/* make sure it is in the set */
    537 	if (meta_check_inset(sp, np, ep) != 0)
    538 		return (-1);
    539 
    540 	/* make sure its not in a metadevice */
    541 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
    542 		return (-1);
    543 
    544 	/* return success */
    545 	return (0);
    546 }
    547 
    548 /*
    549  * print stripe
    550  */
    551 static int
    552 stripe_print(
    553 	md_stripe_t	*stripep,
    554 	char		*fname,
    555 	FILE		*fp,
    556 	mdprtopts_t	options,
    557 	md_error_t	*ep
    558 )
    559 {
    560 	uint_t		row;
    561 	int		rval = -1;
    562 
    563 	if (options & PRINT_LARGEDEVICES) {
    564 		if (stripep->common.revision != MD_64BIT_META_DEV) {
    565 			rval = 0;
    566 			goto out;
    567 		}
    568 	}
    569 
    570 	if (options & PRINT_FN) {
    571 		if (stripep->common.revision != MD_FN_META_DEV) {
    572 			rval = 0;
    573 			goto out;
    574 		}
    575 	}
    576 
    577 	/* print name and num rows */
    578 	if (fprintf(fp, "%s %u",
    579 	    stripep->common.namep->cname, stripep->rows.rows_len) == EOF)
    580 		goto out;
    581 
    582 	/* print rows */
    583 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
    584 		md_row_t	*rp = &stripep->rows.rows_val[row];
    585 		uint_t		comp;
    586 
    587 		/* print num components */
    588 		if (fprintf(fp, " %u", rp->comps.comps_len) == EOF)
    589 			goto out;
    590 
    591 		/*
    592 		 * Print components. Always print the full path name.
    593 		 */
    594 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
    595 			md_comp_t	*cp = &rp->comps.comps_val[comp];
    596 
    597 			if (fprintf(fp, " %s", cp->compnamep->rname) == EOF)
    598 				goto out;
    599 		}
    600 
    601 		/* print interlace */
    602 		if (rp->comps.comps_len > 1)
    603 			if (fprintf(fp, " -i %lldb", rp->interlace) == EOF)
    604 				goto out;
    605 
    606 		/* print continuation */
    607 		if (row != (stripep->rows.rows_len - 1))
    608 			if (fprintf(fp, " \\\n\t") == EOF)
    609 				goto out;
    610 	}
    611 
    612 	/* print hotspare name */
    613 	if (stripep->hspnamep != NULL)
    614 		if (fprintf(fp, " -h %s", stripep->hspnamep->hspname) == EOF)
    615 			goto out;
    616 
    617 	/* terminate last line */
    618 	if (fprintf(fp, "\n") == EOF)
    619 		goto out;
    620 
    621 	/* success */
    622 	rval = 0;
    623 
    624 	/* cleanup, return error */
    625 out:
    626 	if (rval != 0)
    627 		(void) mdsyserror(ep, errno, fname);
    628 	return (rval);
    629 }
    630 
    631 /*
    632  * convert component state to name
    633  */
    634 char *
    635 comp_state_to_name(
    636 	md_comp_t	*mdcp,
    637 	md_timeval32_t	*tvp,
    638 	uint_t		tstate	/* Errored tstate flags */
    639 )
    640 {
    641 	comp_state_t	state = mdcp->state;
    642 
    643 	/* grab time */
    644 	if (tvp != NULL)
    645 		*tvp = mdcp->timestamp;
    646 
    647 	if (tstate != 0) {
    648 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
    649 	}
    650 
    651 	/* return state */
    652 	switch (state) {
    653 	case CS_OKAY:
    654 		return (dgettext(TEXT_DOMAIN, "Okay"));
    655 	case CS_ERRED:
    656 		return (dgettext(TEXT_DOMAIN, "Maintenance"));
    657 	case CS_LAST_ERRED:
    658 		return (dgettext(TEXT_DOMAIN, "Last Erred"));
    659 	case CS_RESYNC:
    660 		return (dgettext(TEXT_DOMAIN, "Resyncing"));
    661 	default:
    662 		return (dgettext(TEXT_DOMAIN, "invalid"));
    663 	}
    664 }
    665 
    666 /*
    667  * print subdevice stripe row
    668  */
    669 static int
    670 subdev_row_report(
    671 	mdsetname_t	*sp,
    672 	md_row_t	*rp,
    673 	char		*fname,
    674 	FILE		*fp,
    675 	mdprtopts_t	options,
    676 	uint_t		top_tstate,	/* Errored tstate flags */
    677 	md_error_t	*ep
    678 )
    679 {
    680 	uint_t		comp;
    681 	int		rval = -1;
    682 	ddi_devid_t	dtp;
    683 	int		len = 0;
    684 
    685 
    686 	/*
    687 	 * building a format string on the fly that will be used
    688 	 * in fprintf. This is to allow really really long ctd names
    689 	 */
    690 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
    691 		md_comp_t	*cp = &rp->comps.comps_val[comp];
    692 		char		*cname = cp->compnamep->cname;
    693 
    694 		len = max(len, strlen(cname));
    695 	}
    696 
    697 	len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
    698 	len += 2;
    699 	/* print header */
    700 	if (! (options & PRINT_TIMES)) {
    701 		if (fprintf(fp,
    702 		    "\t%-*.*s %-12.12s %5.5s %12.12s %5.5s %s\n",
    703 		    len, len,
    704 		    dgettext(TEXT_DOMAIN, "Device"),
    705 		    dgettext(TEXT_DOMAIN, "Start Block"),
    706 		    dgettext(TEXT_DOMAIN, "Dbase"),
    707 		    dgettext(TEXT_DOMAIN, "State"),
    708 		    dgettext(TEXT_DOMAIN, "Reloc"),
    709 		    dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
    710 			goto out;
    711 		}
    712 	} else {
    713 		if (fprintf(fp,
    714 		    "\t%-*s %5s %5s %-11s %-5s %-9s %s\n",
    715 		    len,
    716 		    dgettext(TEXT_DOMAIN, "Device"),
    717 		    dgettext(TEXT_DOMAIN, "Start"),
    718 		    dgettext(TEXT_DOMAIN, "Dbase"),
    719 		    dgettext(TEXT_DOMAIN, "State"),
    720 		    dgettext(TEXT_DOMAIN, "Reloc"),
    721 		    dgettext(TEXT_DOMAIN, "Hot Spare"),
    722 		    dgettext(TEXT_DOMAIN, "Time")) == EOF) {
    723 			goto out;
    724 		}
    725 	}
    726 
    727 
    728 	/* print components */
    729 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
    730 		md_comp_t	*cp = &rp->comps.comps_val[comp];
    731 		mdname_t	*namep = cp->compnamep;
    732 		char		*cname = namep->cname;
    733 		diskaddr_t	start_blk;
    734 		int		has_mddb;
    735 		char		*has_mddb_str;
    736 		char		*comp_state;
    737 		md_timeval32_t	tv;
    738 		char		*hsname = ((cp->hsnamep != NULL) ?
    739 		    cp->hsnamep->cname : "");
    740 		char		*devid = " ";
    741 		mdname_t	*didnp = NULL;
    742 		uint_t		tstate = 0;
    743 
    744 		/* get info */
    745 		if ((start_blk = metagetstart(sp, namep, ep)) ==
    746 		    MD_DISKADDR_ERROR) {
    747 			return (-1);
    748 		}
    749 		if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) {
    750 			return (-1);
    751 		}
    752 		if (has_mddb)
    753 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
    754 		else
    755 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
    756 
    757 		/*
    758 		 * If the component is a metadevice, print out either
    759 		 * unavailable or the state of the metadevice, if not
    760 		 * a metadevice, print nothing if the state of the
    761 		 * stripe is unavailable
    762 		 */
    763 		if (metaismeta(namep)) {
    764 			if (meta_get_tstate(namep->dev, &tstate, ep) != 0)
    765 				return (-1);
    766 			comp_state = comp_state_to_name(cp, &tv, tstate &
    767 			    MD_DEV_ERRORED);
    768 		} else {
    769 			/*
    770 			 * if top_tstate is set, that implies that you have
    771 			 * a ctd type device with an unavailable metadevice
    772 			 * on top of it. If so, print a - for it's state
    773 			 */
    774 			if (top_tstate != 0)
    775 				comp_state = "-";
    776 			else
    777 				comp_state = comp_state_to_name(cp, &tv,
    778 				    tstate & MD_DEV_ERRORED);
    779 		}
    780 
    781 		/* populate the key in the name_p structure */
    782 		if ((didnp = metadevname(&sp, namep->dev, ep))
    783 		    == NULL) {
    784 			return (-1);
    785 		}
    786 
    787 	    /* determine if devid does NOT exist */
    788 		if (options & PRINT_DEVID) {
    789 			if ((dtp = meta_getdidbykey(sp->setno,
    790 			    getmyside(sp, ep), didnp->key, ep)) == NULL)
    791 				devid = dgettext(TEXT_DOMAIN, "No ");
    792 			else {
    793 				devid = dgettext(TEXT_DOMAIN, "Yes");
    794 				free(dtp);
    795 			}
    796 		}
    797 		/* print info */
    798 		/*
    799 		 * building a format string on the fly that will be used
    800 		 * in fprintf. This is to allow really really long ctd names
    801 		 */
    802 		if (! (options & PRINT_TIMES)) {
    803 			if (fprintf(fp,
    804 			    "\t%-*s %8lld     %-5.5s %12.12s %5.5s %s\n",
    805 			    len, cname, start_blk,
    806 			    has_mddb_str, comp_state, devid, hsname) == EOF) {
    807 				goto out;
    808 			}
    809 		} else {
    810 			char	*timep = meta_print_time(&tv);
    811 
    812 			if (fprintf(fp,
    813 			    "\t%-*s %5lld %-5s %-11s %-5s %-9s %s\n",
    814 			    len, cname, start_blk,
    815 			    has_mddb_str, comp_state, devid, hsname,
    816 			    timep) == EOF) {
    817 				goto out;
    818 			}
    819 		}
    820 	}
    821 
    822 	/* success */
    823 	rval = 0;
    824 
    825 	/* cleanup, return error */
    826 out:
    827 	if (rval != 0)
    828 		(void) mdsyserror(ep, errno, fname);
    829 	return (rval);
    830 }
    831 
    832 /*
    833  * print toplevel stripe row
    834  */
    835 /*ARGSUSED4*/
    836 static int
    837 toplev_row_report(
    838 	mdsetname_t	*sp,
    839 	md_row_t	*rp,
    840 	char		*fname,
    841 	FILE		*fp,
    842 	mdprtopts_t	options,
    843 	md_error_t	*ep
    844 )
    845 {
    846 	uint_t		comp;
    847 	int		rval = -1;
    848 	char		*devid = " ";
    849 	mdname_t	*didnp = NULL;
    850 	int		len = 0;
    851 
    852 	/*
    853 	 * building a format string on the fly that will be used
    854 	 * in fprintf. This is to allow really really long ctd names
    855 	 */
    856 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
    857 		len = max(len,
    858 		    strlen(rp->comps.comps_val[comp].compnamep->cname));
    859 	}
    860 
    861 	len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
    862 	len += 2;
    863 	/* print header */
    864 	if (fprintf(fp,
    865 	    "\t%-*.*s %-12.12s %-5.5s\t%s\n",
    866 	    len, len,
    867 	    dgettext(TEXT_DOMAIN, "Device"),
    868 	    dgettext(TEXT_DOMAIN, "Start Block"),
    869 	    dgettext(TEXT_DOMAIN, "Dbase"),
    870 	    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
    871 		goto out;
    872 	}
    873 
    874 	/* print components */
    875 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
    876 		md_comp_t	*cp = &rp->comps.comps_val[comp];
    877 		mdname_t	*namep = cp->compnamep;
    878 		char		*cname = namep->cname;
    879 		diskaddr_t	start_blk;
    880 		int		has_mddb;
    881 		char		*has_mddb_str;
    882 		ddi_devid_t	dtp;
    883 
    884 		/* get info */
    885 		if ((start_blk = metagetstart(sp, namep, ep)) ==
    886 		    MD_DISKADDR_ERROR) {
    887 			return (-1);
    888 		}
    889 		if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) {
    890 			return (-1);
    891 		}
    892 		if (has_mddb)
    893 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
    894 		else
    895 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
    896 
    897 		/* populate the key in the name_p structure */
    898 		if ((didnp = metadevname(&sp, namep->dev, ep))
    899 		    == NULL) {
    900 			return (-1);
    901 		}
    902 
    903 		/* determine if devid does NOT exist */
    904 		if (options & PRINT_DEVID) {
    905 			if ((dtp = meta_getdidbykey(sp->setno,
    906 			    getmyside(sp, ep), didnp->key, ep)) == NULL) {
    907 				devid = dgettext(TEXT_DOMAIN, "No ");
    908 			} else {
    909 				devid = dgettext(TEXT_DOMAIN, "Yes");
    910 				free(dtp);
    911 			}
    912 		}
    913 		/* print info */
    914 		/*
    915 		 * building a format string on the fly that will be used
    916 		 * in fprintf. This is to allow really really long ctd names
    917 		 */
    918 		if (fprintf(fp,
    919 		    "\t%-*s %8lld     %-5.5s\t%s\n", len,
    920 		    cname, start_blk, has_mddb_str, devid) == EOF) {
    921 			goto out;
    922 		}
    923 	}
    924 
    925 	/* success */
    926 	rval = 0;
    927 
    928 	/* cleanup, return error */
    929 out:
    930 	if (rval != 0)
    931 		(void) mdsyserror(ep, errno, fname);
    932 	return (rval);
    933 }
    934 
    935 /*
    936  * print stripe options
    937  */
    938 int
    939 meta_print_stripe_options(
    940 	mdhspname_t	*hspnamep,
    941 	char		*fname,
    942 	FILE		*fp,
    943 	md_error_t	*ep
    944 )
    945 {
    946 	char		*hspname = ((hspnamep != NULL) ? hspnamep->hspname :
    947 	    dgettext(TEXT_DOMAIN, "none"));
    948 	int		rval = -1;
    949 
    950 	/* print options */
    951 	if (fprintf(fp, dgettext(TEXT_DOMAIN,
    952 	    "    Hot spare pool: %s\n"), hspname) == EOF) {
    953 		goto out;
    954 	}
    955 
    956 	/* success */
    957 	rval = 0;
    958 
    959 	/* cleanup, return error */
    960 out:
    961 	if (rval != 0)
    962 		(void) mdsyserror(ep, errno, fname);
    963 	return (rval);
    964 }
    965 
    966 /*
    967  * report stripe
    968  */
    969 static int
    970 stripe_report(
    971 	mdsetname_t	*sp,
    972 	md_stripe_t	*stripep,
    973 	mdnamelist_t	**nlpp,
    974 	char		*fname,
    975 	FILE		*fp,
    976 	mdprtopts_t	options,
    977 	md_error_t	*ep
    978 )
    979 {
    980 	uint_t		row;
    981 	int		rval = -1;
    982 	uint_t		tstate = 0;
    983 
    984 	/*
    985 	 * if the -B option has been specified check to see if the
    986 	 * metadevice is s "big" one and print if so, also if a
    987 	 * big device we need to store the ctd involved for use in
    988 	 * printing out the relocation information.
    989 	 */
    990 	if (options & PRINT_LARGEDEVICES) {
    991 		if ((stripep->common.revision & MD_64BIT_META_DEV) == 0) {
    992 			rval = 0;
    993 			goto out;
    994 		} else {
    995 			if (meta_getdevs(sp, stripep->common.namep,
    996 			    nlpp, ep) != 0)
    997 				goto out;
    998 		}
    999 	}
   1000 
   1001 	/*
   1002 	 * if the -D option has been specified check to see if the
   1003 	 * metadevice has a descriptive name and print if so, also if a
   1004 	 * descriptive device name we need to store the ctd involved
   1005 	 * for use in printing out the relocation information.
   1006 	 */
   1007 	if (options & PRINT_FN) {
   1008 		if ((stripep->common.revision & MD_FN_META_DEV) == 0) {
   1009 			rval = 0;
   1010 			goto out;
   1011 		} else {
   1012 			if (meta_getdevs(sp, stripep->common.namep,
   1013 			    nlpp, ep) != 0)
   1014 				goto out;
   1015 		}
   1016 	}
   1017 
   1018 	/* print header */
   1019 	if (options & PRINT_HEADER) {
   1020 		if (fprintf(fp, "%s: Concat/Stripe\n",
   1021 		    stripep->common.namep->cname) == EOF) {
   1022 			goto out;
   1023 		}
   1024 
   1025 	}
   1026 
   1027 	/* print hotspare pool */
   1028 	if (stripep->hspnamep != NULL) {
   1029 		if (meta_print_stripe_options(stripep->hspnamep,
   1030 		    fname, fp, ep) != 0) {
   1031 			return (-1);
   1032 		}
   1033 	}
   1034 
   1035 	if (metaismeta(stripep->common.namep)) {
   1036 		if (meta_get_tstate(stripep->common.namep->dev, &tstate, ep)
   1037 		    != 0)
   1038 			return (-1);
   1039 	}
   1040 	if ((tstate & MD_DEV_ERRORED) != 0) {
   1041 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
   1042 		    "    State: Unavailable\n"
   1043 		    "    Reconnect disk and invoke: metastat -i\n")) == EOF) {
   1044 			goto out;
   1045 		}
   1046 	}
   1047 
   1048 	/* print size */
   1049 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
   1050 	    stripep->common.size,
   1051 	    meta_number_to_string(stripep->common.size, DEV_BSIZE))
   1052 	    == EOF) {
   1053 		goto out;
   1054 	}
   1055 
   1056 	/* print rows */
   1057 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   1058 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1059 
   1060 		/* print stripe and interlace */
   1061 		if (rp->comps.comps_len > 1) {
   1062 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
   1063 			    "    Stripe %u: (interlace: %lld blocks)\n"),
   1064 			    row, rp->interlace) == EOF) {
   1065 				goto out;
   1066 			}
   1067 		} else {
   1068 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
   1069 			    "    Stripe %u:\n"),
   1070 			    row) == EOF) {
   1071 				goto out;
   1072 			}
   1073 		}
   1074 
   1075 		/* print components appropriately */
   1076 		if (MD_HAS_PARENT(stripep->common.parent)) {
   1077 			if (subdev_row_report(sp, rp, fname, fp, options,
   1078 			    tstate & MD_DEV_ERRORED, ep) != 0) {
   1079 				return (-1);
   1080 			}
   1081 		} else {
   1082 			if (toplev_row_report(sp, rp, fname, fp, options,
   1083 			    ep) != 0) {
   1084 				return (-1);
   1085 			}
   1086 		}
   1087 	}
   1088 
   1089 	/* add extra line */
   1090 	if (fprintf(fp, "\n") == EOF)
   1091 		goto out;
   1092 
   1093 	/* success */
   1094 	rval = 0;
   1095 
   1096 	/* cleanup, return error */
   1097 out:
   1098 	if (rval != 0)
   1099 		(void) mdsyserror(ep, errno, fname);
   1100 	return (rval);
   1101 }
   1102 
   1103 /*
   1104  * print/report stripe
   1105  */
   1106 int
   1107 meta_stripe_print(
   1108 	mdsetname_t	*sp,
   1109 	mdname_t	*stripenp,
   1110 	mdnamelist_t	**nlpp,
   1111 	char		*fname,
   1112 	FILE		*fp,
   1113 	mdprtopts_t	options,
   1114 	md_error_t	*ep
   1115 )
   1116 {
   1117 	md_stripe_t	*stripep;
   1118 	int		row, comp;
   1119 
   1120 	/* should have same set */
   1121 	assert(sp != NULL);
   1122 	assert((stripenp == NULL) ||
   1123 	    (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))));
   1124 
   1125 	/* print all stripes */
   1126 	if (stripenp == NULL) {
   1127 		mdnamelist_t	*nlp = NULL;
   1128 		mdnamelist_t	*p;
   1129 		int		cnt;
   1130 		int		rval = 0;
   1131 
   1132 		/* get list */
   1133 		if ((cnt = meta_get_stripe_names(sp, &nlp, options, ep)) < 0)
   1134 			return (-1);
   1135 		else if (cnt == 0)
   1136 			return (0);
   1137 
   1138 		/* recurse */
   1139 		for (p = nlp; (p != NULL); p = p->next) {
   1140 			mdname_t	*np = p->namep;
   1141 
   1142 			if (meta_stripe_print(sp, np, nlpp, fname, fp,
   1143 			    options, ep) != 0)
   1144 				rval = -1;
   1145 		}
   1146 
   1147 		/* cleanup, return success */
   1148 		metafreenamelist(nlp);
   1149 		return (rval);
   1150 	}
   1151 
   1152 	/* get unit structure */
   1153 	if ((stripep = meta_get_stripe_common(sp, stripenp,
   1154 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
   1155 		return (-1);
   1156 
   1157 	/* check for parented */
   1158 	if ((! (options & PRINT_SUBDEVS)) &&
   1159 	    (MD_HAS_PARENT(stripep->common.parent))) {
   1160 		return (0);
   1161 	}
   1162 
   1163 	/* print appropriate detail */
   1164 	if (options & PRINT_SHORT) {
   1165 		if (stripe_print(stripep, fname, fp, options, ep) != 0)
   1166 			return (-1);
   1167 	} else {
   1168 		if (stripe_report(sp, stripep, nlpp, fname, fp, options,
   1169 		    ep) != 0)
   1170 			return (-1);
   1171 	}
   1172 
   1173 	/* Recurse on components that are metadevices */
   1174 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   1175 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1176 
   1177 		/* look for components that are metadevices */
   1178 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   1179 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1180 			mdname_t	*namep = cp->compnamep;
   1181 
   1182 			if ((metaismeta(namep)) &&
   1183 			    (meta_print_name(sp, namep, nlpp, fname, fp,
   1184 			    (options | PRINT_HEADER | PRINT_SUBDEVS),
   1185 			    NULL, ep) != 0)) {
   1186 				return (-1);
   1187 			}
   1188 		}
   1189 	}
   1190 	return (0);
   1191 }
   1192 
   1193 /*
   1194  * find stripe component to replace
   1195  */
   1196 int
   1197 meta_find_erred_comp(
   1198 	mdsetname_t	*sp,
   1199 	mdname_t	*stripenp,
   1200 	mdname_t	**compnpp,
   1201 	comp_state_t	*compstate,
   1202 	md_error_t	*ep
   1203 )
   1204 {
   1205 	md_stripe_t	*stripep;
   1206 	md_comp_t	*compp = NULL;
   1207 	uint_t		lasterrcnt = 0;
   1208 	uint_t		row;
   1209 
   1210 	/* get stripe */
   1211 	*compnpp = NULL;
   1212 	if ((stripep = meta_get_stripe_common(sp, stripenp, 1, ep)) == NULL)
   1213 		return (-1);
   1214 
   1215 	/*
   1216 	 * Try to find the first erred component.
   1217 	 * If there is not one, then look for the
   1218 	 *	first last_erred component.
   1219 	 */
   1220 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   1221 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1222 		uint_t		comp;
   1223 
   1224 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   1225 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1226 
   1227 			if ((cp->state == CS_ERRED) && ((compp == NULL) ||
   1228 			    (cp->lasterrcnt < lasterrcnt))) {
   1229 				compp = cp;
   1230 				lasterrcnt = cp->lasterrcnt;
   1231 			}
   1232 		}
   1233 	}
   1234 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   1235 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1236 		uint_t		comp;
   1237 
   1238 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   1239 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1240 
   1241 			if ((cp->state == CS_LAST_ERRED) && ((compp == NULL) ||
   1242 			    (cp->lasterrcnt < lasterrcnt))) {
   1243 				compp = cp;
   1244 				lasterrcnt = cp->lasterrcnt;
   1245 			}
   1246 		}
   1247 	}
   1248 
   1249 	/* return component */
   1250 	if (compp != NULL) {
   1251 		*compnpp = compp->compnamep;
   1252 		*compstate = compp->state;
   1253 	}
   1254 
   1255 	/* return success */
   1256 	return (0);
   1257 }
   1258 
   1259 /*
   1260  * invalidate component names
   1261  */
   1262 static int
   1263 invalidate_components(
   1264 	mdsetname_t	*sp,
   1265 	mdname_t	*stripenp,
   1266 	md_error_t	*ep
   1267 )
   1268 {
   1269 	md_stripe_t	*stripep;
   1270 	uint_t		row;
   1271 
   1272 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
   1273 		return (-1);
   1274 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   1275 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1276 		uint_t		comp;
   1277 
   1278 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   1279 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1280 			mdname_t	*compnp = cp->compnamep;
   1281 
   1282 			meta_invalidate_name(compnp);
   1283 		}
   1284 	}
   1285 	return (0);
   1286 }
   1287 
   1288 /*
   1289  * attach components to stripe
   1290  */
   1291 int
   1292 meta_stripe_attach(
   1293 	mdsetname_t		*sp,
   1294 	mdname_t		*stripenp,
   1295 	mdnamelist_t		*nlp,
   1296 	diskaddr_t		interlace,
   1297 	mdcmdopts_t		options,
   1298 	md_error_t		*ep
   1299 )
   1300 {
   1301 	mdnamelist_t		*lp;
   1302 	ms_unit_t		*old_un, *new_un;
   1303 	struct ms_row		*mdr, *new_mdr;
   1304 	uint_t			newcomps, ncomps, icomp;
   1305 	uint_t			row;
   1306 	size_t			mdsize, first_comp;
   1307 	diskaddr_t		new_blks;
   1308 	diskaddr_t		limit;
   1309 	diskaddr_t		disk_size = 0;
   1310 	ms_comp_t		*mdcomp, *new_comp;
   1311 	uint_t			write_reinstruct = 0;
   1312 	uint_t			read_reinstruct = 0;
   1313 	mdnamelist_t		*keynlp = NULL;
   1314 	uint_t			round_cyl = 1;
   1315 	minor_t			parent;
   1316 	md_grow_params_t	mgp;
   1317 	int			rval = -1;
   1318 	md_timeval32_t		creation_time;
   1319 	int			create_flag = MD_CRO_32BIT;
   1320 
   1321 	/* should have a set */
   1322 	assert(sp != NULL);
   1323 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
   1324 
   1325 	/* check type */
   1326 	if (metachkmeta(stripenp, ep) != 0)
   1327 		return (-1);
   1328 
   1329 	/* check and count components */
   1330 	assert(nlp != NULL);
   1331 	newcomps = 0;
   1332 	for (lp = nlp; (lp != NULL); lp = lp->next) {
   1333 		mdname_t	*np = lp->namep;
   1334 		mdnamelist_t	*p;
   1335 
   1336 		/* check against existing devices */
   1337 		if (meta_check_component(sp, np, 0, ep) != 0)
   1338 			return (-1);
   1339 
   1340 		/* check against ourselves */
   1341 		for (p = lp->next; (p != NULL); p = p->next) {
   1342 			if (meta_check_overlap(np->cname, np, 0, -1,
   1343 			    p->namep, 0, -1, ep) != 0) {
   1344 				return (-1);
   1345 			}
   1346 		}
   1347 
   1348 		/* count */
   1349 		++newcomps;
   1350 	}
   1351 
   1352 	/* get old unit */
   1353 	if ((old_un = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL)
   1354 		return (-1);
   1355 
   1356 	/* if zero, inherit the last rows interlace value */
   1357 	if (interlace == 0) {
   1358 		mdr = &old_un->un_row[old_un->un_nrows - 1];
   1359 		interlace = mdr->un_interlace;
   1360 	}
   1361 
   1362 	/*
   1363 	 * calculate size of new unit structure
   1364 	 */
   1365 
   1366 	/* unit + rows */
   1367 	mdsize = sizeof (ms_unit_t) - sizeof (struct ms_row);
   1368 	mdsize += sizeof (struct ms_row) * (old_un->un_nrows + 1);
   1369 
   1370 	/* number of new components being added */
   1371 	ncomps = newcomps;
   1372 
   1373 	/* count the # of components in the old unit */
   1374 	mdr = &old_un->un_row[0];
   1375 	for (row = 0; (row < old_un->un_nrows); row++)
   1376 		ncomps += mdr[row].un_ncomp;
   1377 	first_comp = roundup(mdsize, sizeof (long long));
   1378 	mdsize += sizeof (ms_comp_t) * ncomps + (first_comp - mdsize);
   1379 
   1380 	/* allocate new unit */
   1381 	new_un = Zalloc(mdsize);
   1382 	new_un->un_ocomp = first_comp;
   1383 
   1384 	/* compute new data */
   1385 	new_mdr = &new_un->un_row[old_un->un_nrows];
   1386 	new_mdr->un_icomp = ncomps - newcomps;
   1387 	new_mdr->un_ncomp = newcomps;
   1388 	new_mdr->un_blocks = 0;
   1389 	new_mdr->un_cum_blocks =
   1390 	    old_un->un_row[old_un->un_nrows - 1].un_cum_blocks;
   1391 	new_mdr->un_interlace = interlace;
   1392 
   1393 	/* for each new device */
   1394 	mdcomp = (struct ms_comp *)(void *)&((char *)new_un)[new_un->un_ocomp];
   1395 	icomp = new_mdr->un_icomp;
   1396 	if (meta_gettimeofday(&creation_time) == -1)
   1397 		return (mdsyserror(ep, errno, NULL));
   1398 	for (lp = nlp; (lp != NULL); lp = lp->next) {
   1399 		mdname_t	*np = lp->namep;
   1400 		diskaddr_t	size, start_blk;
   1401 		mdgeom_t		*geomp;
   1402 
   1403 		/* figure out how big */
   1404 		if ((size = metagetsize(np, ep)) == MD_DISKADDR_ERROR)
   1405 			goto out;
   1406 		if ((start_blk = metagetstart(sp, np, ep)) ==
   1407 		    MD_DISKADDR_ERROR)
   1408 			goto out;
   1409 		if (start_blk >= size) {
   1410 			(void) mdsyserror(ep, ENOSPC, np->cname);
   1411 			goto out;
   1412 		}
   1413 		size -= start_blk;
   1414 		if (newcomps > 1)
   1415 			size = rounddown(size, interlace);
   1416 
   1417 		/* adjust for smallest disk */
   1418 		if (disk_size == 0) {
   1419 			disk_size = size;
   1420 		} else if (size < disk_size) {
   1421 			disk_size = size;
   1422 		}
   1423 
   1424 		/* get worst reinstructs */
   1425 		if ((geomp = metagetgeom(np, ep)) == NULL)
   1426 			goto out;
   1427 		if (geomp->write_reinstruct > write_reinstruct)
   1428 			write_reinstruct = geomp->write_reinstruct;
   1429 		if (geomp->read_reinstruct > read_reinstruct)
   1430 			read_reinstruct = geomp->read_reinstruct;
   1431 
   1432 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
   1433 		if (options & MDCMD_DOIT) {
   1434 			/* store name in namespace */
   1435 			if (add_key_name(sp, np, &keynlp, ep) != 0)
   1436 				goto out;
   1437 		}
   1438 
   1439 		/* build new component */
   1440 		new_comp = &mdcomp[icomp++];
   1441 		new_comp->un_key = np->key;
   1442 		new_comp->un_dev = np->dev;
   1443 		new_comp->un_start_block = start_blk;
   1444 		new_comp->un_mirror.ms_state = CS_OKAY;
   1445 		new_comp->un_mirror.ms_timestamp = creation_time;
   1446 	}
   1447 
   1448 	limit = LLONG_MAX;
   1449 
   1450 	/* compute new size */
   1451 	new_mdr->un_blocks = new_mdr->un_ncomp * disk_size;
   1452 	new_blks = new_mdr->un_cum_blocks + new_mdr->un_blocks;
   1453 	if (new_blks > limit) {
   1454 		new_mdr->un_cum_blocks = limit;
   1455 		new_blks = limit;
   1456 		md_eprintf(dgettext(TEXT_DOMAIN,
   1457 		    "unit size overflow, limit is %lld blocks\n"),
   1458 		    limit);
   1459 	} else {
   1460 		new_mdr->un_cum_blocks += new_mdr->un_blocks;
   1461 	}
   1462 	new_un->c.un_actual_tb = new_mdr->un_cum_blocks;
   1463 	new_un->un_nrows = old_un->un_nrows + 1;
   1464 
   1465 	/* adjust geometry */
   1466 	new_un->c.un_nhead = old_un->c.un_nhead;
   1467 	new_un->c.un_nsect = old_un->c.un_nsect;
   1468 	new_un->c.un_rpm = old_un->c.un_rpm;
   1469 	new_un->c.un_wr_reinstruct = old_un->c.un_wr_reinstruct;
   1470 	new_un->c.un_rd_reinstruct = old_un->c.un_rd_reinstruct;
   1471 	if (meta_adjust_geom((md_unit_t *)new_un, stripenp,
   1472 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
   1473 		goto out;
   1474 
   1475 	/* if in dryrun mode, we are done here. */
   1476 	if ((options & MDCMD_DOIT) == 0)  {
   1477 		if (options & MDCMD_PRINT) {
   1478 			if (newcomps == 1) {
   1479 				(void) printf(dgettext(TEXT_DOMAIN,
   1480 				    "%s: attaching component would suceed\n"),
   1481 				    stripenp->cname);
   1482 			} else {
   1483 				(void) printf(dgettext(TEXT_DOMAIN,
   1484 				    "%s: attaching components would suceed\n"),
   1485 				    stripenp->cname);
   1486 			}
   1487 		}
   1488 		rval = 0; /* success */
   1489 		goto out;
   1490 	}
   1491 
   1492 	create_flag = meta_check_devicesize(new_un->c.un_total_blocks);
   1493 
   1494 	/* grow stripe */
   1495 	(void) memset(&mgp, 0, sizeof (mgp));
   1496 	mgp.mnum = MD_SID(old_un);
   1497 	MD_SETDRIVERNAME(&mgp, MD_STRIPE, sp->setno);
   1498 	mgp.size = mdsize;
   1499 	mgp.mdp = (uintptr_t)new_un;
   1500 	mgp.nrows = old_un->un_nrows;
   1501 	if (create_flag == MD_CRO_32BIT) {
   1502 		mgp.options = MD_CRO_32BIT;
   1503 		new_un->c.un_revision &= ~MD_64BIT_META_DEV;
   1504 	} else {
   1505 		mgp.options = MD_CRO_64BIT;
   1506 		new_un->c.un_revision |= MD_64BIT_META_DEV;
   1507 	}
   1508 
   1509 	if ((MD_HAS_PARENT(old_un->c.un_parent)) &&
   1510 	    (old_un->c.un_parent != MD_MULTI_PARENT)) {
   1511 		mgp.npar = 1;
   1512 		parent = old_un->c.un_parent;
   1513 		mgp.par = (uintptr_t)(&parent);
   1514 	}
   1515 
   1516 	if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, NULL) != 0) {
   1517 		(void) mdstealerror(ep, &mgp.mde);
   1518 		goto out;
   1519 	}
   1520 
   1521 	/* clear cache */
   1522 	if (invalidate_components(sp, stripenp, ep) != 0)
   1523 		goto out;
   1524 	meta_invalidate_name(stripenp);
   1525 
   1526 	/* let em know */
   1527 	if (options & MDCMD_PRINT) {
   1528 		if (newcomps == 1) {
   1529 			(void) printf(dgettext(TEXT_DOMAIN,
   1530 			    "%s: component is attached\n"), stripenp->cname);
   1531 		} else {
   1532 			(void) printf(dgettext(TEXT_DOMAIN,
   1533 			    "%s: components are attached\n"), stripenp->cname);
   1534 		}
   1535 		(void) fflush(stdout);
   1536 	}
   1537 
   1538 	/* grow any parents */
   1539 	if (meta_concat_parent(sp, stripenp, ep) != 0)
   1540 		return (-1);
   1541 
   1542 	rval = 0;	/* success */
   1543 
   1544 	/* cleanup, return error */
   1545 out:
   1546 	Free(old_un);
   1547 	Free(new_un);
   1548 	if (options & MDCMD_DOIT) {
   1549 		if (rval != 0)
   1550 			(void) del_key_names(sp, keynlp, NULL);
   1551 		metafreenamelist(keynlp);
   1552 	}
   1553 	return (rval);
   1554 }
   1555 
   1556 /*
   1557  * get stripe parameters
   1558  */
   1559 int
   1560 meta_stripe_get_params(
   1561 	mdsetname_t	*sp,
   1562 	mdname_t	*stripenp,
   1563 	ms_params_t	*paramsp,
   1564 	md_error_t	*ep
   1565 )
   1566 {
   1567 	md_stripe_t	*stripep;
   1568 
   1569 	/* should have a set */
   1570 	assert(sp != NULL);
   1571 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
   1572 
   1573 	/* check name */
   1574 	if (metachkmeta(stripenp, ep) != 0)
   1575 		return (-1);
   1576 
   1577 	/* get unit */
   1578 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
   1579 		return (-1);
   1580 
   1581 	/* return parameters */
   1582 	(void) memset(paramsp, 0, sizeof (*paramsp));
   1583 	if (stripep->hspnamep == NULL)
   1584 		paramsp->hsp_id = MD_HSP_NONE;
   1585 	else
   1586 		paramsp->hsp_id = stripep->hspnamep->hsp;
   1587 	return (0);
   1588 }
   1589 
   1590 /*
   1591  * set stripe parameters
   1592  */
   1593 int
   1594 meta_stripe_set_params(
   1595 	mdsetname_t		*sp,
   1596 	mdname_t		*stripenp,
   1597 	ms_params_t		*paramsp,
   1598 	md_error_t		*ep
   1599 )
   1600 {
   1601 	md_stripe_params_t	msp;
   1602 
   1603 	/* should have a set */
   1604 	assert(sp != NULL);
   1605 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
   1606 
   1607 	/* check name */
   1608 	if (metachkmeta(stripenp, ep) != 0)
   1609 		return (-1);
   1610 
   1611 	/* set parameters */
   1612 	(void) memset(&msp, 0, sizeof (msp));
   1613 	MD_SETDRIVERNAME(&msp, MD_STRIPE, sp->setno);
   1614 	msp.mnum = meta_getminor(stripenp->dev);
   1615 	msp.params = *paramsp;
   1616 	if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, stripenp->cname) != 0)
   1617 		return (mdstealerror(ep, &msp.mde));
   1618 
   1619 	/* clear cache */
   1620 	meta_invalidate_name(stripenp);
   1621 
   1622 	/* return success */
   1623 	return (0);
   1624 }
   1625 
   1626 /*
   1627  * check for dups in the stripe itself
   1628  */
   1629 static int
   1630 check_twice(
   1631 	md_stripe_t	*stripep,
   1632 	uint_t		row,
   1633 	uint_t		comp,
   1634 	md_error_t	*ep
   1635 )
   1636 {
   1637 	mdname_t	*stripenp = stripep->common.namep;
   1638 	mdname_t	*thisnp;
   1639 	uint_t		r;
   1640 
   1641 	thisnp = stripep->rows.rows_val[row].comps.comps_val[comp].compnamep;
   1642 	for (r = 0; (r <= row); ++r) {
   1643 		md_row_t	*rp = &stripep->rows.rows_val[r];
   1644 		uint_t		e = ((r == row) ? comp : rp->comps.comps_len);
   1645 		uint_t		c;
   1646 
   1647 		for (c = 0; (c < e); ++c) {
   1648 			md_comp_t	*cp = &rp->comps.comps_val[c];
   1649 			mdname_t	*compnp = cp->compnamep;
   1650 
   1651 			if (meta_check_overlap(stripenp->cname, thisnp, 0, -1,
   1652 			    compnp, 0, -1, ep) != 0) {
   1653 				return (-1);
   1654 			}
   1655 		}
   1656 	}
   1657 	return (0);
   1658 }
   1659 
   1660 /*
   1661  * default stripe interlace
   1662  */
   1663 diskaddr_t
   1664 meta_default_stripe_interlace(void)
   1665 {
   1666 	diskaddr_t		interlace;
   1667 
   1668 	/* default to 512k, round up if necessary */
   1669 	interlace = btodb(512 * 1024);
   1670 	if (interlace < btodb(MININTERLACE))
   1671 		interlace = roundup(MININTERLACE, interlace);
   1672 	return (interlace);
   1673 }
   1674 
   1675 /*
   1676  * convert interlaces
   1677  */
   1678 int
   1679 meta_stripe_check_interlace(
   1680 	diskaddr_t	interlace,
   1681 	char		*uname,
   1682 	md_error_t	*ep
   1683 )
   1684 {
   1685 	if ((interlace < btodb(MININTERLACE)) ||
   1686 	    (interlace > btodb(MAXINTERLACE))) {
   1687 		return (mderror(ep, MDE_BAD_INTERLACE, uname));
   1688 	}
   1689 	return (0);
   1690 }
   1691 
   1692 
   1693 /*
   1694  * check stripe
   1695  */
   1696 int
   1697 meta_check_stripe(
   1698 	mdsetname_t	*sp,
   1699 	md_stripe_t	*stripep,
   1700 	mdcmdopts_t	options,
   1701 	md_error_t	*ep
   1702 )
   1703 {
   1704 	mdname_t	*stripenp = stripep->common.namep;
   1705 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
   1706 	int		doit = ((options & MDCMD_DOIT) ? 1 : 0);
   1707 	int		updateit = ((options & MDCMD_UPDATE) ? 1 : 0);
   1708 	uint_t		row;
   1709 
   1710 	/* check rows */
   1711 	if (stripep->rows.rows_len < 1) {
   1712 		return (mdmderror(ep, MDE_BAD_STRIPE,
   1713 		    meta_getminor(stripenp->dev), stripenp->cname));
   1714 	}
   1715 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   1716 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1717 		uint_t		comp;
   1718 
   1719 		/* check number */
   1720 		if (rp->comps.comps_len < 1) {
   1721 			return (mdmderror(ep, MDE_BAD_STRIPE,
   1722 			    meta_getminor(stripenp->dev), stripenp->cname));
   1723 		}
   1724 
   1725 		/* compute default interlace */
   1726 		if (rp->interlace == 0) {
   1727 			rp->interlace = meta_default_stripe_interlace();
   1728 		}
   1729 
   1730 		/* check interlace */
   1731 		if (meta_stripe_check_interlace(rp->interlace, stripenp->cname,
   1732 		    ep) != 0) {
   1733 			return (-1);
   1734 		}
   1735 
   1736 		/* check components */
   1737 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   1738 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1739 			mdname_t	*compnp = cp->compnamep;
   1740 			diskaddr_t	start_blk, size;
   1741 
   1742 			/* check component */
   1743 			if (!updateit) {
   1744 				if (meta_check_component(sp, compnp,
   1745 				    force, ep) != 0)
   1746 					return (-1);
   1747 				if (((start_blk = metagetstart(sp, compnp,
   1748 				    ep)) == MD_DISKADDR_ERROR) ||
   1749 				    ((size = metagetsize(compnp, ep)) ==
   1750 				    MD_DISKADDR_ERROR)) {
   1751 					return (-1);
   1752 				}
   1753 				if (start_blk >= size)
   1754 					return (mdsyserror(ep, ENOSPC,
   1755 					    compnp->cname));
   1756 				size -= start_blk;
   1757 				size = rounddown(size, rp->interlace);
   1758 				if (size == 0)
   1759 					return (mdsyserror(ep, ENOSPC,
   1760 					    compnp->cname));
   1761 			}
   1762 
   1763 			/* check this stripe too */
   1764 			if (check_twice(stripep, row, comp, ep) != 0)
   1765 				return (-1);
   1766 		}
   1767 	}
   1768 
   1769 	/* check hotspare pool name */
   1770 	if (doit) {
   1771 		if ((stripep->hspnamep != NULL) &&
   1772 		    (metachkhsp(sp, stripep->hspnamep, ep) != 0)) {
   1773 			return (-1);
   1774 		}
   1775 	}
   1776 
   1777 	/* return success */
   1778 	return (0);
   1779 }
   1780 
   1781 /*
   1782  * setup stripe geometry
   1783  */
   1784 static int
   1785 stripe_geom(
   1786 	md_stripe_t	*stripep,
   1787 	ms_unit_t	*ms,
   1788 	md_error_t	*ep
   1789 )
   1790 {
   1791 	uint_t		nrow = stripep->rows.rows_len;
   1792 	uint_t		write_reinstruct = 0;
   1793 	uint_t		read_reinstruct = 0;
   1794 	uint_t		round_cyl = 1;
   1795 	uint_t		row;
   1796 	mdgeom_t	*geomp;
   1797 	diskaddr_t	first_row_size = 0;
   1798 	char		*miscname;
   1799 	int		is_sp = 0;
   1800 
   1801 	/* get worst reinstructs */
   1802 	for (row = 0; (row < nrow); ++row) {
   1803 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1804 		uint_t		ncomp = rp->comps.comps_len;
   1805 		uint_t		comp;
   1806 
   1807 		for (comp = 0; (comp < ncomp); ++comp) {
   1808 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1809 			mdname_t	*compnp = cp->compnamep;
   1810 
   1811 			if ((geomp = metagetgeom(compnp, ep)) == NULL)
   1812 				return (-1);
   1813 			if (geomp->write_reinstruct > write_reinstruct)
   1814 				write_reinstruct = geomp->write_reinstruct;
   1815 			if (geomp->read_reinstruct > read_reinstruct)
   1816 				read_reinstruct = geomp->read_reinstruct;
   1817 		}
   1818 	}
   1819 
   1820 	if ((geomp = metagetgeom(
   1821 	    stripep->rows.rows_val[0].comps.comps_val[0].compnamep,
   1822 	    ep)) == NULL) {
   1823 		return (-1);
   1824 	}
   1825 	/*
   1826 	 * Figure out if the first component is a softpartition as the
   1827 	 * truncation check only occurs on them.
   1828 	 */
   1829 	if ((miscname = metagetmiscname(
   1830 	    stripep->rows.rows_val[0].comps.comps_val[0].compnamep,
   1831 	    ep)) == NULL) {
   1832 		if (!mdisdeverror(ep, MDE_NOT_META))
   1833 			return (-1);
   1834 	} else if (strcmp(miscname, MD_SP) == 0) {
   1835 		is_sp = 1;
   1836 	}
   1837 
   1838 	/*
   1839 	 * If the stripe is to be multi-terabyte we should
   1840 	 * use EFI geometries, else we can get rounding errors
   1841 	 * in meta_setup_geom().
   1842 	 */
   1843 
   1844 	if (ms->c.un_actual_tb > MD_MAX_BLKS_FOR_SMALL_DEVS) {
   1845 		geomp->nhead = MD_EFI_FG_HEADS;
   1846 		geomp->nsect = MD_EFI_FG_SECTORS;
   1847 		geomp->rpm = MD_EFI_FG_RPM;
   1848 	}
   1849 
   1850 	/* setup geometry from first device */
   1851 	if (meta_setup_geom((md_unit_t *)ms, stripep->common.namep, geomp,
   1852 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
   1853 		return (-1);
   1854 
   1855 	/*
   1856 	 * Here we want to make sure that any truncation did not
   1857 	 * result in lost data (or, more appropriately, inaccessible
   1858 	 * data).
   1859 	 *
   1860 	 * This is mainly a danger for (1, 1) concats, but it is
   1861 	 * mathematically possible for other somewhat contrived
   1862 	 * arrangements where in the sum of the lengths of each row
   1863 	 * beyond the first is smaller than the cylinder size of the
   1864 	 * only component in the first row.
   1865 	 *
   1866 	 * It is tempting to simply test for truncation here, by
   1867 	 * (md->c.un_total_blocks < md->c.un_actual_tb). That does
   1868 	 * not tell us, however, if rounding resulted in data loss,
   1869 	 * rather only that it occurred. The somewhat less obvious
   1870 	 * test below covers both the obvious (1, 1) case and the
   1871 	 * aforementioned corner case.
   1872 	 */
   1873 	first_row_size = ms->un_row[0].un_blocks;
   1874 	if (is_sp == 1) {
   1875 		md_unit_t	*md = (md_unit_t *)ms;
   1876 
   1877 		if (md->c.un_total_blocks < first_row_size) {
   1878 			char buf[] = VAL2STR(ULLONG_MAX);
   1879 
   1880 			/*
   1881 			 * The only difference here is the text of the error
   1882 			 * message, since the remediation is slightly
   1883 			 * different in the one-component versus
   1884 			 * multiple-component cases.
   1885 			 */
   1886 			if (nrow == 1) {
   1887 				(void) mderror(ep, MDE_STRIPE_TRUNC_SINGLE,
   1888 				    stripep->common.namep->cname);
   1889 			} else {
   1890 				(void) mderror(ep, MDE_STRIPE_TRUNC_MULTIPLE,
   1891 				    stripep->common.namep->cname);
   1892 			}
   1893 
   1894 			/*
   1895 			 * By the size comparison above and the initialization
   1896 			 * of buf[] in terms of ULLONG_MAX, we guarantee that
   1897 			 * the value arg is non-negative and that we won't
   1898 			 * overflow the container.
   1899 			 */
   1900 			mderrorextra(ep, ulltostr((md->c.un_total_blocks +
   1901 			    (geomp->nhead * geomp->nsect))
   1902 			    - first_row_size, &buf[sizeof (buf) - 1]));
   1903 
   1904 			return (-1);
   1905 		}
   1906 	}
   1907 
   1908 	/* return success */
   1909 	return (0);
   1910 }
   1911 
   1912 /*
   1913  * create stripe
   1914  */
   1915 int
   1916 meta_create_stripe(
   1917 	mdsetname_t	*sp,
   1918 	md_stripe_t	*stripep,
   1919 	mdcmdopts_t	options,
   1920 	md_error_t	*ep
   1921 )
   1922 {
   1923 	mdname_t	*stripenp = stripep->common.namep;
   1924 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
   1925 	int		doall = ((options & MDCMD_ALLOPTION) ? 1 : 0);
   1926 	uint_t		nrow = stripep->rows.rows_len;
   1927 	uint_t		ncomp = 0;
   1928 	uint_t		icomp = 0;
   1929 	diskaddr_t	cum_blocks = 0;
   1930 	diskaddr_t	limit;
   1931 	size_t		mdsize, first_comp;
   1932 	uint_t		row;
   1933 	ms_unit_t	*ms;
   1934 	ms_comp_t	*mdcomp;
   1935 	mdnamelist_t	*keynlp = NULL;
   1936 	md_set_params_t	set_params;
   1937 	int		rval = -1;
   1938 	md_timeval32_t	creation_time;
   1939 	int		create_flag = MD_CRO_32BIT;
   1940 
   1941 	/* validate stripe */
   1942 	if (meta_check_stripe(sp, stripep, options, ep) != 0)
   1943 		return (-1);
   1944 
   1945 	/* allocate stripe unit */
   1946 	mdsize = sizeof (*ms) - sizeof (ms->un_row[0]);
   1947 	mdsize += sizeof (ms->un_row) * nrow;
   1948 	for (row = 0; (row < nrow); ++row) {
   1949 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1950 
   1951 		ncomp += rp->comps.comps_len;
   1952 	}
   1953 	first_comp = roundup(mdsize, sizeof (long long));
   1954 	mdsize += (first_comp - mdsize) + (ncomp * sizeof (ms_comp_t));
   1955 	ms = Zalloc(mdsize);
   1956 	ms->un_ocomp = first_comp;
   1957 	if (meta_gettimeofday(&creation_time) == -1)
   1958 		return (mdsyserror(ep, errno, NULL));
   1959 
   1960 	/* do rows */
   1961 	mdcomp = (ms_comp_t *)(void *)&((char *)ms)[ms->un_ocomp];
   1962 	for (row = 0; (row < nrow); ++row) {
   1963 		md_row_t	*rp = &stripep->rows.rows_val[row];
   1964 		uint_t		ncomp = rp->comps.comps_len;
   1965 		struct ms_row	*mdr = &ms->un_row[row];
   1966 		diskaddr_t	disk_size = 0;
   1967 		uint_t		comp;
   1968 
   1969 		/* setup component count and offfset */
   1970 		mdr->un_icomp = icomp;
   1971 		mdr->un_ncomp = ncomp;
   1972 
   1973 		/* do components */
   1974 		for (comp = 0; (comp < ncomp); ++comp) {
   1975 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   1976 			mdname_t	*compnp = cp->compnamep;
   1977 			ms_comp_t	*mdc = &mdcomp[icomp++];
   1978 			diskaddr_t	size, start_blk;
   1979 
   1980 			/*
   1981 			 * get start and size
   1982 			 * if first component is labelled, include label
   1983 			 */
   1984 			if ((size = metagetsize(compnp, ep)) ==
   1985 			    MD_DISKADDR_ERROR)
   1986 				goto out;
   1987 			if ((start_blk = metagetstart(sp, compnp, ep)) ==
   1988 			    MD_DISKADDR_ERROR)
   1989 				goto out;
   1990 			if ((row == 0) && (comp == 0)) {
   1991 				diskaddr_t	label;
   1992 				int		has_db;
   1993 
   1994 				if ((has_db = metahasmddb(sp, compnp, ep)) < 0)
   1995 					goto out;
   1996 				if ((label = metagetlabel(compnp, ep)) ==
   1997 				    MD_DISKADDR_ERROR)
   1998 					goto out;
   1999 				if ((has_db == 0) && (label != 0)) {
   2000 					ms->c.un_flag |= MD_LABELED;
   2001 					start_blk = compnp->start_blk = 0;
   2002 				}
   2003 			}
   2004 			/* make sure we still have something left */
   2005 			if (start_blk >= size) {
   2006 				(void) mdsyserror(ep, ENOSPC, compnp->cname);
   2007 				goto out;
   2008 			}
   2009 			size -= start_blk;
   2010 
   2011 			/*
   2012 			 * round down by interlace: this only applies
   2013 			 * if this row is a stripe, as indicated by
   2014 			 * (ncomp > 1)
   2015 			 */
   2016 			if (ncomp > 1)
   2017 				size = rounddown(size, rp->interlace);
   2018 
   2019 			if (size == 0) {
   2020 				(void) mdsyserror(ep, ENOSPC, compnp->cname);
   2021 				goto out;
   2022 			}
   2023 
   2024 			/*
   2025 			 * adjust for smallest disk: for a concat (any
   2026 			 * row with only one component), this will
   2027 			 * never hit the second conditional.
   2028 			 */
   2029 			if (disk_size == 0) {
   2030 				disk_size = size;
   2031 			} else if (size < disk_size) {
   2032 				disk_size = size;
   2033 			}
   2034 
   2035 			if (options & MDCMD_DOIT) {
   2036 				/* store name in namespace */
   2037 				if (add_key_name(sp, compnp, &keynlp, ep) != 0)
   2038 					goto out;
   2039 			}
   2040 
   2041 			/* setup component */
   2042 			mdc->un_key = compnp->key;
   2043 			mdc->un_dev = compnp->dev;
   2044 			mdc->un_start_block = start_blk;
   2045 			mdc->un_mirror.ms_state = CS_OKAY;
   2046 			mdc->un_mirror.ms_timestamp = creation_time;
   2047 		}
   2048 		limit = LLONG_MAX;
   2049 
   2050 		/* setup row */
   2051 		mdr->un_blocks = mdr->un_ncomp * disk_size;
   2052 		cum_blocks += mdr->un_blocks;
   2053 		if (cum_blocks > limit) {
   2054 			cum_blocks = limit;
   2055 			md_eprintf(dgettext(TEXT_DOMAIN,
   2056 			    "unit size overflow, limit is %lld blocks\n"),
   2057 			    limit);
   2058 		}
   2059 		mdr->un_cum_blocks = cum_blocks;
   2060 		mdr->un_interlace = rp->interlace;
   2061 	}
   2062 
   2063 	/* setup unit */
   2064 	ms->c.un_type = MD_DEVICE;
   2065 	MD_SID(ms) = meta_getminor(stripenp->dev);
   2066 	ms->c.un_actual_tb = cum_blocks;
   2067 	ms->c.un_size = mdsize;
   2068 	if (stripep->hspnamep != NULL)
   2069 		ms->un_hsp_id = stripep->hspnamep->hsp;
   2070 	else
   2071 		ms->un_hsp_id = MD_HSP_NONE;
   2072 	ms->un_nrows = nrow;
   2073 
   2074 	/* fill in the size of the stripe */
   2075 	if (options & MDCMD_UPDATE) {
   2076 		stripep->common.size = ms->c.un_total_blocks;
   2077 		for (row = 0; (row < nrow); ++row) {
   2078 			stripep->rows.rows_val[row].row_size =
   2079 			    ms->un_row[row].un_blocks;
   2080 		}
   2081 	}
   2082 
   2083 	if (stripe_geom(stripep, ms, ep) != 0) {
   2084 		/*
   2085 		 * If the device is being truncated then only allow this
   2086 		 * if the user is aware (using the -f option) or they
   2087 		 * are in a recovery/complete build situation (using the -a
   2088 		 * option).
   2089 		 */
   2090 		if ((mdiserror(ep, MDE_STRIPE_TRUNC_SINGLE) ||
   2091 		    mdiserror(ep, MDE_STRIPE_TRUNC_MULTIPLE)) &&
   2092 		    (force || doall)) {
   2093 			md_eprintf(dgettext(TEXT_DOMAIN,
   2094 "%s: WARNING: This form of metainit is not recommended.\n"
   2095 "The stripe is truncating the size of the underlying device.\n"
   2096 "Please see ERRORS in metainit(1M) for additional information.\n"),
   2097 			    stripenp->cname);
   2098 			mdclrerror(ep);
   2099 		} else {
   2100 			goto out;
   2101 		}
   2102 	}
   2103 
   2104 	create_flag = meta_check_devicesize(ms->c.un_total_blocks);
   2105 
   2106 	/* if we're not doing anything, return success */
   2107 	if (! (options & MDCMD_DOIT)) {
   2108 		rval = 0;	/* success */
   2109 		goto out;
   2110 	}
   2111 
   2112 	/* create stripe */
   2113 	(void) memset(&set_params, 0, sizeof (set_params));
   2114 
   2115 	/* did the user tell us to generate a large device? */
   2116 	if (create_flag == MD_CRO_64BIT) {
   2117 		ms->c.un_revision |= MD_64BIT_META_DEV;
   2118 		set_params.options = MD_CRO_64BIT;
   2119 	} else {
   2120 		ms->c.un_revision &= ~MD_64BIT_META_DEV;
   2121 		set_params.options = MD_CRO_32BIT;
   2122 	}
   2123 
   2124 	set_params.mnum = MD_SID(ms);
   2125 	set_params.size = ms->c.un_size;
   2126 	set_params.mdp = (uintptr_t)ms;
   2127 	MD_SETDRIVERNAME(&set_params, MD_STRIPE, MD_MIN2SET(set_params.mnum));
   2128 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
   2129 	    stripenp->cname) != 0) {
   2130 		(void) mdstealerror(ep, &set_params.mde);
   2131 		goto out;
   2132 	}
   2133 	rval = 0;	/* success */
   2134 
   2135 	/* cleanup, return success */
   2136 out:
   2137 	Free(ms);
   2138 	if (rval != 0) {
   2139 		(void) del_key_names(sp, keynlp, NULL);
   2140 	}
   2141 
   2142 	metafreenamelist(keynlp);
   2143 	if ((rval == 0) && (options & MDCMD_DOIT)) {
   2144 		if (invalidate_components(sp, stripenp, ep) != 0)
   2145 			rval = -1;
   2146 		meta_invalidate_name(stripenp);
   2147 	}
   2148 	return (rval);
   2149 }
   2150 
   2151 /*
   2152  * initialize stripe
   2153  * NOTE: this functions is metainit(1m)'s command line parser!
   2154  */
   2155 int
   2156 meta_init_stripe(
   2157 	mdsetname_t	**spp,
   2158 	int		argc,
   2159 	char		*argv[],
   2160 	mdcmdopts_t	options,
   2161 	md_error_t	*ep
   2162 )
   2163 {
   2164 	char		*uname = argv[0];
   2165 	mdname_t	*stripenp = NULL;
   2166 	int		old_optind;
   2167 	int		c;
   2168 	md_stripe_t	*stripep = NULL;
   2169 	uint_t		nrow, row;
   2170 	int		rval = -1;
   2171 
   2172 	/* get stripe name */
   2173 	assert(argc > 0);
   2174 	if (argc < 1)
   2175 		goto syntax;
   2176 
   2177 	if ((stripenp = metaname(spp, uname, META_DEVICE, ep)) == NULL)
   2178 		goto out;
   2179 	assert(*spp != NULL);
   2180 	uname = stripenp->cname;
   2181 	if (metachkmeta(stripenp, ep) != 0)
   2182 		goto out;
   2183 
   2184 	if (!(options & MDCMD_NOLOCK)) {
   2185 		/* grab set lock */
   2186 		if (meta_lock(*spp, TRUE, ep))
   2187 			goto out;
   2188 
   2189 		if (meta_check_ownership(*spp, ep) != 0)
   2190 			goto out;
   2191 	}
   2192 
   2193 	/* see if it exists already */
   2194 	if (metagetmiscname(stripenp, ep) != NULL) {
   2195 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
   2196 		    meta_getminor(stripenp->dev), uname);
   2197 		goto out;
   2198 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
   2199 		goto out;
   2200 	} else {
   2201 		mdclrerror(ep);
   2202 	}
   2203 	--argc, ++argv;
   2204 
   2205 	/* parse general options */
   2206 	optind = 0;
   2207 	opterr = 0;
   2208 	if (getopt(argc, argv, "") != -1)
   2209 		goto options;
   2210 
   2211 	/* allocate stripe */
   2212 	stripep = Zalloc(sizeof (*stripep));
   2213 
   2214 	/* setup common */
   2215 	stripep->common.namep = stripenp;
   2216 	stripep->common.type = MD_DEVICE;
   2217 
   2218 	/* allocate and parse rows */
   2219 	if (argc < 1) {
   2220 		(void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev),
   2221 		    uname);
   2222 		goto out;
   2223 	} else if ((sscanf(argv[0], "%u", &nrow) != 1) || ((int)nrow < 0)) {
   2224 		goto syntax;
   2225 	} else if (nrow < 1) {
   2226 		(void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev),
   2227 		    uname);
   2228 		goto out;
   2229 	}
   2230 	--argc, ++argv;
   2231 	stripep->rows.rows_len = nrow;
   2232 	stripep->rows.rows_val =
   2233 	    Zalloc(nrow * sizeof (*stripep->rows.rows_val));
   2234 	for (row = 0; (row < nrow); ++row) {
   2235 		md_row_t	*mdr = &stripep->rows.rows_val[row];
   2236 		uint_t		ncomp, comp;
   2237 
   2238 		/* allocate and parse components */
   2239 		if (argc < 1) {
   2240 			(void) mdmderror(ep, MDE_NROWS,
   2241 			    meta_getminor(stripenp->dev), uname);
   2242 			goto out;
   2243 		} else if ((sscanf(argv[0], "%u", &ncomp) != 1) ||
   2244 		    ((int)ncomp < 0)) {
   2245 			goto syntax;
   2246 		} else if (ncomp < 1) {
   2247 			(void) mdmderror(ep, MDE_NCOMPS,
   2248 			    meta_getminor(stripenp->dev), uname);
   2249 			goto out;
   2250 		}
   2251 		--argc, ++argv;
   2252 		mdr->comps.comps_len = ncomp;
   2253 		mdr->comps.comps_val =
   2254 		    Zalloc(ncomp * sizeof (*mdr->comps.comps_val));
   2255 		for (comp = 0; (comp < ncomp); ++comp) {
   2256 			md_comp_t	*mdc = &mdr->comps.comps_val[comp];
   2257 			mdname_t	*compnp;
   2258 
   2259 			/* parse component name */
   2260 			if (argc < 1) {
   2261 				(void) mdmderror(ep, MDE_NCOMPS,
   2262 				    meta_getminor(stripenp->dev), uname);
   2263 				goto out;
   2264 			}
   2265 			if ((compnp = metaname(spp, argv[0], UNKNOWN,
   2266 			    ep)) == NULL) {
   2267 				goto out;
   2268 			}
   2269 			/* check for soft partition */
   2270 			if (meta_sp_issp(*spp, compnp, ep) != 0) {
   2271 				/* check disk */
   2272 				if (metachkcomp(compnp, ep) != 0) {
   2273 					goto out;
   2274 				}
   2275 			}
   2276 			mdc->compnamep = compnp;
   2277 			--argc, ++argv;
   2278 		}
   2279 
   2280 		/* parse row options */
   2281 		old_optind = optind = 0;
   2282 		opterr = 0;
   2283 		while ((c = getopt(argc, argv, "i:")) != -1) {
   2284 			switch (c) {
   2285 			case 'i':
   2286 				if (parse_interlace(uname, optarg,
   2287 				    &mdr->interlace, ep) != 0) {
   2288 					goto out;
   2289 				}
   2290 				if (meta_stripe_check_interlace(mdr->interlace,
   2291 				    uname, ep))
   2292 					goto out;
   2293 				break;
   2294 
   2295 			default:
   2296 				optind = old_optind;	/* bomb out later */
   2297 				goto done_row_opts;
   2298 			}
   2299 			old_optind = optind;
   2300 		}
   2301 done_row_opts:
   2302 		argc -= optind;
   2303 		argv += optind;
   2304 	}
   2305 
   2306 	/* parse stripe options */
   2307 	old_optind = optind = 0;
   2308 	opterr = 0;
   2309 	while ((c = getopt(argc, argv, "h:")) != -1) {
   2310 		switch (c) {
   2311 		case 'h':
   2312 			if ((stripep->hspnamep = metahspname(spp, optarg,
   2313 			    ep)) == NULL) {
   2314 				goto out;
   2315 			}
   2316 
   2317 			/*
   2318 			 * Get out if the specified hotspare pool really
   2319 			 * doesn't exist.
   2320 			 */
   2321 			if (stripep->hspnamep->hsp == MD_HSP_NONE) {
   2322 				(void) mdhsperror(ep, MDE_INVAL_HSP,
   2323 				    stripep->hspnamep->hsp, optarg);
   2324 				goto out;
   2325 			}
   2326 			break;
   2327 
   2328 		default:
   2329 			argc += old_optind;
   2330 			argv += old_optind;
   2331 			goto options;
   2332 		}
   2333 		old_optind = optind;
   2334 	}
   2335 	argc -= optind;
   2336 	argv += optind;
   2337 
   2338 	/* we should be at the end */
   2339 	if (argc != 0)
   2340 		goto syntax;
   2341 
   2342 	/* create stripe */
   2343 	if (meta_create_stripe(*spp, stripep, options, ep) != 0)
   2344 		goto out;
   2345 	rval = 0;	/* success */
   2346 
   2347 	/* let em know */
   2348 	if (options & MDCMD_PRINT) {
   2349 		(void) printf(dgettext(TEXT_DOMAIN,
   2350 		    "%s: Concat/Stripe is setup\n"),
   2351 		    uname);
   2352 		(void) fflush(stdout);
   2353 	}
   2354 	goto out;
   2355 
   2356 	/* syntax error */
   2357 syntax:
   2358 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
   2359 	goto out;
   2360 
   2361 	/* options error */
   2362 options:
   2363 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
   2364 	goto out;
   2365 
   2366 	/* cleanup, return error */
   2367 out:
   2368 	if (stripep != NULL)
   2369 		meta_free_stripe(stripep);
   2370 	return (rval);
   2371 }
   2372 
   2373 /*
   2374  * reset stripes
   2375  */
   2376 int
   2377 meta_stripe_reset(
   2378 	mdsetname_t	*sp,
   2379 	mdname_t	*stripenp,
   2380 	mdcmdopts_t	options,
   2381 	md_error_t	*ep
   2382 )
   2383 {
   2384 	md_stripe_t	*stripep;
   2385 	int		rval = -1;
   2386 	int		row, comp;
   2387 
   2388 	/* should have same set */
   2389 	assert(sp != NULL);
   2390 	assert((stripenp == NULL) ||
   2391 	    (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))));
   2392 
   2393 	/* reset all stripes */
   2394 	if (stripenp == NULL) {
   2395 		mdnamelist_t	*stripenlp = NULL;
   2396 		mdnamelist_t	*p;
   2397 
   2398 		/* for each stripe */
   2399 		rval = 0;
   2400 		if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0)
   2401 			return (-1);
   2402 		for (p = stripenlp; (p != NULL); p = p->next) {
   2403 			/* reset stripe */
   2404 			stripenp = p->namep;
   2405 
   2406 			/*
   2407 			 * If this is a multi-node set, we send a series
   2408 			 * of individual metaclear commands.
   2409 			 */
   2410 			if (meta_is_mn_set(sp, ep)) {
   2411 				if (meta_mn_send_metaclear_command(sp,
   2412 				    stripenp->cname, options, 0, ep) != 0) {
   2413 					rval = -1;
   2414 					break;
   2415 				}
   2416 			} else {
   2417 				if (meta_stripe_reset(sp, stripenp,
   2418 				    options, ep) != 0) {
   2419 					rval = -1;
   2420 					break;
   2421 				}
   2422 			}
   2423 		}
   2424 
   2425 		/* cleanup, return success */
   2426 		metafreenamelist(stripenlp);
   2427 		return (rval);
   2428 	}
   2429 
   2430 	/* check name */
   2431 	if (metachkmeta(stripenp, ep) != 0)
   2432 		return (-1);
   2433 
   2434 	/* get unit structure */
   2435 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
   2436 		return (-1);
   2437 
   2438 	/* make sure nobody owns us */
   2439 	if (MD_HAS_PARENT(stripep->common.parent)) {
   2440 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(stripenp->dev),
   2441 		    stripenp->cname));
   2442 	}
   2443 
   2444 	/* clear subdevices cache */
   2445 	if (invalidate_components(sp, stripenp, ep) != 0)
   2446 		return (-1);
   2447 
   2448 	/* clear metadevice */
   2449 	if (meta_reset(sp, stripenp, options, ep) != 0)
   2450 		goto out;
   2451 	rval = 0;	/* success */
   2452 
   2453 	/* let em know */
   2454 	if (options & MDCMD_PRINT) {
   2455 		(void) printf(dgettext(TEXT_DOMAIN,
   2456 		    "%s: Concat/Stripe is cleared\n"),
   2457 		    stripenp->cname);
   2458 		(void) fflush(stdout);
   2459 	}
   2460 
   2461 	/* clear subdevices */
   2462 	if (! (options & MDCMD_RECURSE))
   2463 		goto out;
   2464 
   2465 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
   2466 		md_row_t	*rp = &stripep->rows.rows_val[row];
   2467 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   2468 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   2469 			mdname_t	*compnp = cp->compnamep;
   2470 
   2471 			/* only recurse on metadevices */
   2472 			if (! metaismeta(compnp))
   2473 				continue;
   2474 
   2475 			if (meta_reset_by_name(sp, compnp, options, ep) != 0)
   2476 				rval = -1;
   2477 		}
   2478 	}
   2479 
   2480 	/* cleanup, return success */
   2481 out:
   2482 	meta_invalidate_name(stripenp);
   2483 	return (rval);
   2484 }
   2485 
   2486 /*
   2487  * reports TRUE if any stripe component is in error
   2488  */
   2489 int
   2490 meta_stripe_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *stripe_names)
   2491 {
   2492 	mdnamelist_t	*nlp;
   2493 	md_error_t	  status	= mdnullerror;
   2494 	md_error_t	 *ep		= &status;
   2495 	int		  any_errs	= FALSE;
   2496 
   2497 	for (nlp = stripe_names; nlp; nlp = nlp->next) {
   2498 		md_stripe_t	*stripep;
   2499 		int		 row;
   2500 
   2501 		if ((stripep = meta_get_stripe(sp, nlp->namep, ep)) == NULL) {
   2502 			any_errs |= TRUE;
   2503 			goto out;
   2504 		}
   2505 
   2506 		for (row = 0; row < stripep->rows.rows_len; ++row) {
   2507 			md_row_t	*rp	= &stripep->rows.rows_val[row];
   2508 			uint_t		 comp;
   2509 
   2510 			for (comp = 0; comp < rp->comps.comps_len; ++comp) {
   2511 				md_comp_t *cp	= &rp->comps.comps_val[comp];
   2512 
   2513 				if (cp->state != CS_OKAY) {
   2514 					any_errs |= TRUE;
   2515 					goto out;
   2516 				}
   2517 			}
   2518 		}
   2519 	}
   2520 out:
   2521 	if (!mdisok(ep))
   2522 		mdclrerror(ep);
   2523 
   2524 	return (any_errs);
   2525 }
   2526 
   2527 int
   2528 meta_stripe_check_component(
   2529 	mdsetname_t	*sp,
   2530 	mdname_t	*np,
   2531 	md_dev64_t	mydevs,
   2532 	md_error_t	*ep
   2533 )
   2534 {
   2535 	md_stripe_t	*stripe;
   2536 	mdnm_params_t	nm;
   2537 	md_getdevs_params_t	mgd;
   2538 	side_t	sideno;
   2539 	char	*miscname;
   2540 	md_dev64_t	*mydev = NULL;
   2541 	mdkey_t	key;
   2542 	char	*pname = NULL, *t;
   2543 	char	*ctd_name = NULL;
   2544 	char	*devname = NULL;
   2545 	int	len;
   2546 	int	cnt, i;
   2547 	int	rval = -1;
   2548 
   2549 	(void) memset(&nm, '\0', sizeof (nm));
   2550 	if ((stripe = meta_get_stripe_common(sp, np, 0, ep)) == NULL)
   2551 		return (-1);
   2552 
   2553 	if ((miscname = metagetmiscname(np, ep)) == NULL)
   2554 		return (-1);
   2555 
   2556 	sideno = getmyside(sp, ep);
   2557 
   2558 
   2559 	/* get count of underlying devices */
   2560 
   2561 	(void) memset(&mgd, '\0', sizeof (mgd));
   2562 	MD_SETDRIVERNAME(&mgd, miscname, sp->setno);
   2563 	mgd.mnum = meta_getminor(np->dev);
   2564 	mgd.cnt = 0;
   2565 	mgd.devs = NULL;
   2566 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, np->cname) != 0) {
   2567 		(void) mdstealerror(ep, &mgd.mde);
   2568 		rval = 0;
   2569 		goto out;
   2570 	} else if (mgd.cnt <= 0) {
   2571 		assert(mgd.cnt >= 0);
   2572 		rval = 0;
   2573 		goto out;
   2574 	}
   2575 
   2576 	/*
   2577 	 * Now get the data from the unit structure.
   2578 	 * The compnamep stuff contains the data from
   2579 	 * the namespace and we need the un_dev
   2580 	 * from the unit structure.
   2581 	 */
   2582 	mydev = Zalloc(sizeof (*mydev) * mgd.cnt);
   2583 	mgd.devs = (uintptr_t)mydev;
   2584 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, np->cname) != 0) {
   2585 		(void) mdstealerror(ep, &mgd.mde);
   2586 		rval = 0;
   2587 		goto out;
   2588 	} else if (mgd.cnt <= 0) {
   2589 		assert(mgd.cnt >= 0);
   2590 		rval = 0;
   2591 		goto out;
   2592 	}
   2593 
   2594 	for (cnt = 0, i = 0; i < stripe->rows.rows_len; i++) {
   2595 		md_row_t	*rp = &stripe->rows.rows_val[i];
   2596 		uint_t	comp;
   2597 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
   2598 			md_comp_t	*cp = &rp->comps.comps_val[comp];
   2599 			mdname_t	*compnp = cp->compnamep;
   2600 
   2601 			if (mydevs == mydev[cnt]) {
   2602 				/* Get the devname from the name space. */
   2603 				if ((devname = meta_getnmentbydev(sp->setno,
   2604 				    sideno, compnp->dev, NULL, NULL,
   2605 				    &key, ep)) == NULL) {
   2606 					goto out;
   2607 				}
   2608 
   2609 				if (compnp->dev != meta_getminor(mydev[cnt])) {
   2610 					/*
   2611 					 * The minor numbers are different.
   2612 					 * Update the namespace with the
   2613 					 * information from the component.
   2614 					 */
   2615 
   2616 					t = strrchr(devname, '/');
   2617 					t++;
   2618 					ctd_name = Strdup(t);
   2619 
   2620 					len = strlen(devname);
   2621 					t = strrchr(devname, '/');
   2622 					t++;
   2623 					pname = Zalloc((len - strlen(t)) + 1);
   2624 					(void) strncpy(pname, devname,
   2625 					    (len - strlen(t)));
   2626 
   2627 					if (meta_update_namespace(sp->setno,
   2628 					    sideno, ctd_name, mydev[i],
   2629 					    key, pname, ep) != 0) {
   2630 						goto out;
   2631 					}
   2632 				}
   2633 				rval = 0;
   2634 				break;
   2635 			} /*  End of if (mydevs == mydev[i]) */
   2636 			cnt++;
   2637 		} /* End of second for loop */
   2638 	} /* End of first for loop */
   2639 out:
   2640 	if (pname != NULL)
   2641 		Free(pname);
   2642 	if (ctd_name != NULL)
   2643 		Free(ctd_name);
   2644 	if (devname != NULL)
   2645 		Free(devname);
   2646 	if (mydev != NULL)
   2647 		Free(mydev);
   2648 	return (rval);
   2649 }
   2650