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