xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_stripe.c (revision b509e89b2befbaa42939abad9da1d7f5a8c6aaae)
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