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