1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
31*0Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
34*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
35*0Sstevel@tonic-gate #endif
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * soft partition operations
39*0Sstevel@tonic-gate  *
40*0Sstevel@tonic-gate  * Soft Partitions provide a virtual disk mechanism which is used to
41*0Sstevel@tonic-gate  * divide a large volume into many small pieces, each appearing as a
42*0Sstevel@tonic-gate  * separate device.  A soft partition consists of a series of extents,
43*0Sstevel@tonic-gate  * each having an offset and a length.  The extents are logically
44*0Sstevel@tonic-gate  * contiguous, so where the first extent leaves off the second extent
45*0Sstevel@tonic-gate  * picks up.  Which extent a given "virtual offset" belongs to is
46*0Sstevel@tonic-gate  * dependent on the size of all the previous extents in the soft
47*0Sstevel@tonic-gate  * partition.
48*0Sstevel@tonic-gate  *
49*0Sstevel@tonic-gate  * Soft partitions are represented in memory by an extent node
50*0Sstevel@tonic-gate  * (sp_ext_node_t) which contains all of the information necessary to
51*0Sstevel@tonic-gate  * create a unit structure and update the on-disk format, called
52*0Sstevel@tonic-gate  * "watermarks".  These extent nodes are typically kept in a doubly
53*0Sstevel@tonic-gate  * linked list and are manipulated by list manipulation routines.  A
54*0Sstevel@tonic-gate  * list of extents may represent all of the soft partitions on a volume,
55*0Sstevel@tonic-gate  * a single soft partition, or perhaps just a set of extents that need
56*0Sstevel@tonic-gate  * to be updated.  Extent lists may be sorted by extent or by name/seq#,
57*0Sstevel@tonic-gate  * depending on which compare function is used.  Most of the routines
58*0Sstevel@tonic-gate  * require the list be sorted by offset to work, and that's the typical
59*0Sstevel@tonic-gate  * configuration.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * In order to do an allocation, knowledge of all soft partitions on the
62*0Sstevel@tonic-gate  * volume is required.  Then free space is determined from the space
63*0Sstevel@tonic-gate  * that is not allocated, and new allocations can be made from the free
64*0Sstevel@tonic-gate  * space.  Once the new allocations are made, a unit structure is created
65*0Sstevel@tonic-gate  * and the watermarks are updated.  The status is then changed to "okay"
66*0Sstevel@tonic-gate  * on the unit structure to commit the transaction.  If updating the
67*0Sstevel@tonic-gate  * watermarks fails, the unit structure is in an intermediate state and
68*0Sstevel@tonic-gate  * the driver will not allow access to the device.
69*0Sstevel@tonic-gate  *
70*0Sstevel@tonic-gate  * A typical sequence of events is:
71*0Sstevel@tonic-gate  *     1. Fetch the list of names for all soft partitions on a volume
72*0Sstevel@tonic-gate  *         meta_sp_get_by_component()
73*0Sstevel@tonic-gate  *     2. Construct an extent list from the name list
74*0Sstevel@tonic-gate  *         meta_sp_extlist_from_namelist()
75*0Sstevel@tonic-gate  *     3. Fill the gaps in the extent list with free extents
76*0Sstevel@tonic-gate  *         meta_sp_list_freefill()
77*0Sstevel@tonic-gate  *     4. Allocate from the free extents
78*0Sstevel@tonic-gate  *         meta_sp_alloc_by_len()
79*0Sstevel@tonic-gate  *         meta_sp_alloc_by_list()
80*0Sstevel@tonic-gate  *     5. Create the unit structure from the extent list
81*0Sstevel@tonic-gate  *         meta_sp_createunit()
82*0Sstevel@tonic-gate  *         meta_sp_updateunit()
83*0Sstevel@tonic-gate  *     6. Write out the watermarks
84*0Sstevel@tonic-gate  *         meta_sp_update_wm()
85*0Sstevel@tonic-gate  *     7. Set the status to "Okay"
86*0Sstevel@tonic-gate  *         meta_sp_setstatus()
87*0Sstevel@tonic-gate  *
88*0Sstevel@tonic-gate  */
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate #include <stdio.h>
91*0Sstevel@tonic-gate #include <meta.h>
92*0Sstevel@tonic-gate #include "meta_repartition.h"
93*0Sstevel@tonic-gate #include <sys/lvm/md_sp.h>
94*0Sstevel@tonic-gate #include <sys/lvm/md_crc.h>
95*0Sstevel@tonic-gate #include <strings.h>
96*0Sstevel@tonic-gate #include <sys/lvm/md_mirror.h>
97*0Sstevel@tonic-gate #include <sys/bitmap.h>
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate extern int	md_in_daemon;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate typedef struct sp_ext_node {
102*0Sstevel@tonic-gate 	struct sp_ext_node	*ext_next;	/* next element */
103*0Sstevel@tonic-gate 	struct sp_ext_node	*ext_prev;	/* previous element */
104*0Sstevel@tonic-gate 	sp_ext_type_t		ext_type;	/* type of extent */
105*0Sstevel@tonic-gate 	sp_ext_offset_t		ext_offset;	/* starting offset */
106*0Sstevel@tonic-gate 	sp_ext_length_t		ext_length;	/* length of this node */
107*0Sstevel@tonic-gate 	uint_t			ext_flags;	/* extent flags */
108*0Sstevel@tonic-gate 	uint32_t		ext_seq;	/* watermark seq no */
109*0Sstevel@tonic-gate 	mdname_t		*ext_namep;	/* name pointer */
110*0Sstevel@tonic-gate 	mdsetname_t		*ext_setp;	/* set pointer */
111*0Sstevel@tonic-gate } sp_ext_node_t;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /* extent flags */
114*0Sstevel@tonic-gate #define	EXTFLG_UPDATE	(1)
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate /* Extent node compare function for list sorting */
117*0Sstevel@tonic-gate typedef int (*ext_cmpfunc_t)(sp_ext_node_t *, sp_ext_node_t *);
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate /* Function Prototypes */
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /* Debugging Functions */
123*0Sstevel@tonic-gate static void meta_sp_debug(char *format, ...);
124*0Sstevel@tonic-gate static void meta_sp_printunit(mp_unit_t *mp);
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate /* Misc Support Functions */
127*0Sstevel@tonic-gate int meta_sp_parsesize(char *s, sp_ext_length_t *szp);
128*0Sstevel@tonic-gate static int meta_sp_parsesizestring(char *s, sp_ext_length_t *szp);
129*0Sstevel@tonic-gate static int meta_sp_setgeom(mdname_t *np, mdname_t *compnp, mp_unit_t *mp,
130*0Sstevel@tonic-gate 	md_error_t *ep);
131*0Sstevel@tonic-gate static int meta_sp_get_by_component(mdsetname_t *sp, mdname_t *compnp,
132*0Sstevel@tonic-gate     mdnamelist_t **nlpp, int force, md_error_t *ep);
133*0Sstevel@tonic-gate static sp_ext_length_t meta_sp_get_default_alignment(mdsetname_t *sp,
134*0Sstevel@tonic-gate     mdname_t *compnp, md_error_t *ep);
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /* Extent List Manipulation Functions */
137*0Sstevel@tonic-gate static int meta_sp_cmp_by_nameseq(sp_ext_node_t *e1, sp_ext_node_t *e2);
138*0Sstevel@tonic-gate static int meta_sp_cmp_by_offset(sp_ext_node_t *e1, sp_ext_node_t *e2);
139*0Sstevel@tonic-gate static void meta_sp_list_insert(mdsetname_t *sp, mdname_t *np,
140*0Sstevel@tonic-gate     sp_ext_node_t **head, sp_ext_offset_t offset, sp_ext_length_t length,
141*0Sstevel@tonic-gate     sp_ext_type_t type, uint_t seq, uint_t flags, ext_cmpfunc_t compare);
142*0Sstevel@tonic-gate static void meta_sp_list_free(sp_ext_node_t **head);
143*0Sstevel@tonic-gate static void meta_sp_list_remove(sp_ext_node_t **head, sp_ext_node_t *ext);
144*0Sstevel@tonic-gate static sp_ext_length_t meta_sp_list_size(sp_ext_node_t *head,
145*0Sstevel@tonic-gate     sp_ext_type_t exttype, int exclude_wm);
146*0Sstevel@tonic-gate static sp_ext_node_t *meta_sp_list_find(sp_ext_node_t *head,
147*0Sstevel@tonic-gate     sp_ext_offset_t offset);
148*0Sstevel@tonic-gate static void meta_sp_list_freefill(sp_ext_node_t **extlist,
149*0Sstevel@tonic-gate     sp_ext_length_t size);
150*0Sstevel@tonic-gate static void meta_sp_list_dump(sp_ext_node_t *head);
151*0Sstevel@tonic-gate static int meta_sp_list_overlaps(sp_ext_node_t *head);
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate /* Extent List Query Functions */
154*0Sstevel@tonic-gate static boolean_t meta_sp_enough_space(int desired_number_of_sps,
155*0Sstevel@tonic-gate 	blkcnt_t desired_sp_size, sp_ext_node_t **extent_listpp,
156*0Sstevel@tonic-gate 	sp_ext_length_t alignment);
157*0Sstevel@tonic-gate static boolean_t meta_sp_get_extent_list(mdsetname_t *mdsetnamep,
158*0Sstevel@tonic-gate 	mdname_t *device_mdnamep, sp_ext_node_t **extent_listpp,
159*0Sstevel@tonic-gate 	md_error_t *ep);
160*0Sstevel@tonic-gate static boolean_t meta_sp_get_extent_list_for_drive(mdsetname_t *mdsetnamep,
161*0Sstevel@tonic-gate 	mddrivename_t *mddrivenamep, sp_ext_node_t **extent_listpp);
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate /* Extent Allocation Functions */
165*0Sstevel@tonic-gate static void meta_sp_alloc_by_ext(mdsetname_t *sp, mdname_t *np,
166*0Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_node_t *free_ext,
167*0Sstevel@tonic-gate     sp_ext_offset_t alloc_offset, sp_ext_length_t alloc_length, uint_t seq);
168*0Sstevel@tonic-gate static int meta_sp_alloc_by_len(mdsetname_t *sp, mdname_t *np,
169*0Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_length_t *lp,
170*0Sstevel@tonic-gate     sp_ext_offset_t last_off, sp_ext_length_t alignment);
171*0Sstevel@tonic-gate static int meta_sp_alloc_by_list(mdsetname_t *sp, mdname_t *np,
172*0Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_node_t *oblist);
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate /* Extent List Population Functions */
175*0Sstevel@tonic-gate static int meta_sp_extlist_from_namelist(mdsetname_t *sp, mdnamelist_t *spnlp,
176*0Sstevel@tonic-gate     sp_ext_node_t **extlist, md_error_t *ep);
177*0Sstevel@tonic-gate static int meta_sp_extlist_from_wm(mdsetname_t *sp, mdname_t *compnp,
178*0Sstevel@tonic-gate     sp_ext_node_t **extlist, ext_cmpfunc_t compare, md_error_t *ep);
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /* Print (metastat) Functions */
181*0Sstevel@tonic-gate static int meta_sp_short_print(md_sp_t *msp, char *fname, FILE *fp,
182*0Sstevel@tonic-gate     mdprtopts_t options, md_error_t *ep);
183*0Sstevel@tonic-gate static char *meta_sp_status_to_name(xsp_status_t xsp_status, uint_t tstate);
184*0Sstevel@tonic-gate static int meta_sp_report(mdsetname_t *sp, md_sp_t *msp, mdnamelist_t **nlpp,
185*0Sstevel@tonic-gate     char *fname, FILE *fp, mdprtopts_t options, md_error_t *ep);
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate /* Watermark Manipulation Functions */
188*0Sstevel@tonic-gate static int meta_sp_update_wm(mdsetname_t *sp, md_sp_t *msp,
189*0Sstevel@tonic-gate     sp_ext_node_t *extlist, md_error_t *ep);
190*0Sstevel@tonic-gate static int meta_sp_clear_wm(mdsetname_t *sp, md_sp_t *msp, md_error_t *ep);
191*0Sstevel@tonic-gate static int meta_sp_read_wm(mdsetname_t *sp, mdname_t *compnp,
192*0Sstevel@tonic-gate     mp_watermark_t *wm, sp_ext_offset_t offset,  md_error_t *ep);
193*0Sstevel@tonic-gate static diskaddr_t meta_sp_get_start(mdsetname_t *sp, mdname_t *compnp,
194*0Sstevel@tonic-gate     md_error_t *ep);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate /* Unit Structure Manipulation Functions */
197*0Sstevel@tonic-gate static void meta_sp_fillextarray(mp_unit_t *mp, sp_ext_node_t *extlist);
198*0Sstevel@tonic-gate static mp_unit_t *meta_sp_createunit(mdname_t *np, mdname_t *compnp,
199*0Sstevel@tonic-gate     sp_ext_node_t *extlist, int numexts, sp_ext_length_t len,
200*0Sstevel@tonic-gate     sp_status_t status, md_error_t *ep);
201*0Sstevel@tonic-gate static mp_unit_t *meta_sp_updateunit(mdname_t *np,  mp_unit_t *old_un,
202*0Sstevel@tonic-gate     sp_ext_node_t *extlist, sp_ext_length_t grow_len, int numexts,
203*0Sstevel@tonic-gate     md_error_t *ep);
204*0Sstevel@tonic-gate static int meta_create_sp(mdsetname_t *sp, md_sp_t *msp, sp_ext_node_t *oblist,
205*0Sstevel@tonic-gate     mdcmdopts_t options, sp_ext_length_t alignment, md_error_t *ep);
206*0Sstevel@tonic-gate static int meta_check_sp(mdsetname_t *sp, md_sp_t *msp, mdcmdopts_t options,
207*0Sstevel@tonic-gate     int *repart_options, md_error_t *ep);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate /* Reset (metaclear) Functions */
210*0Sstevel@tonic-gate static int meta_sp_reset_common(mdsetname_t *sp, mdname_t *np, md_sp_t *msp,
211*0Sstevel@tonic-gate     md_sp_reset_t reset_params, mdcmdopts_t options, md_error_t *ep);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate /* Recovery (metarecover) Functions */
214*0Sstevel@tonic-gate static void meta_sp_display_exthdr(void);
215*0Sstevel@tonic-gate static void meta_sp_display_ext(sp_ext_node_t *ext);
216*0Sstevel@tonic-gate static int meta_sp_checkseq(sp_ext_node_t *extlist);
217*0Sstevel@tonic-gate static int meta_sp_resolve_name_conflict(mdsetname_t *, mdname_t *,
218*0Sstevel@tonic-gate     mdname_t **, md_error_t *);
219*0Sstevel@tonic-gate static int meta_sp_validate_wm(mdsetname_t *sp, mdname_t *np,
220*0Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
221*0Sstevel@tonic-gate static int meta_sp_validate_unit(mdsetname_t *sp, mdname_t *compnp,
222*0Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
223*0Sstevel@tonic-gate static int meta_sp_validate_wm_and_unit(mdsetname_t *sp, mdname_t *np,
224*0Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
225*0Sstevel@tonic-gate static int meta_sp_validate_exts(mdname_t *np, sp_ext_node_t *wmext,
226*0Sstevel@tonic-gate     sp_ext_node_t *unitext, md_error_t *ep);
227*0Sstevel@tonic-gate static int meta_sp_recover_from_wm(mdsetname_t *sp, mdname_t *compnp,
228*0Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
229*0Sstevel@tonic-gate static int meta_sp_recover_from_unit(mdsetname_t *sp, mdname_t *np,
230*0Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate /*
233*0Sstevel@tonic-gate  * Private Constants
234*0Sstevel@tonic-gate  */
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate static const int FORCE_RELOAD_CACHE = 1;
237*0Sstevel@tonic-gate static const uint_t NO_FLAGS = 0;
238*0Sstevel@tonic-gate static const sp_ext_offset_t NO_OFFSET = 0ULL;
239*0Sstevel@tonic-gate static const uint_t NO_SEQUENCE_NUMBER = 0;
240*0Sstevel@tonic-gate static const int ONE_SOFT_PARTITION = 1;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate static unsigned long sp_parent_printed[BT_BITOUL(MD_MAXUNITS)];
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate #define	TEST_SOFT_PARTITION_NAMEP NULL
245*0Sstevel@tonic-gate #define	TEST_SETNAMEP NULL
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate #define	EXCLUDE_WM	(1)
248*0Sstevel@tonic-gate #define	INCLUDE_WM	(0)
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate #define	SP_UNALIGNED	(0LL)
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate /*
253*0Sstevel@tonic-gate  * **************************************************************************
254*0Sstevel@tonic-gate  *                          Debugging Functions                             *
255*0Sstevel@tonic-gate  * **************************************************************************
256*0Sstevel@tonic-gate  */
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate /*PRINTFLIKE1*/
259*0Sstevel@tonic-gate static void
260*0Sstevel@tonic-gate meta_sp_debug(char *format, ...)
261*0Sstevel@tonic-gate {
262*0Sstevel@tonic-gate 	static int debug;
263*0Sstevel@tonic-gate 	static int debug_set = 0;
264*0Sstevel@tonic-gate 	va_list ap;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (!debug_set) {
267*0Sstevel@tonic-gate 		debug = getenv(META_SP_DEBUG) ? 1 : 0;
268*0Sstevel@tonic-gate 		debug_set = 1;
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	if (debug) {
272*0Sstevel@tonic-gate 		va_start(ap, format);
273*0Sstevel@tonic-gate 		(void) vfprintf(stderr, format, ap);
274*0Sstevel@tonic-gate 		va_end(ap);
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate static void
279*0Sstevel@tonic-gate meta_sp_printunit(mp_unit_t *mp)
280*0Sstevel@tonic-gate {
281*0Sstevel@tonic-gate 	int i;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	if (mp == NULL)
284*0Sstevel@tonic-gate 		return;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	/* print the common fields we know about */
287*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_type: %d\n", mp->c.un_type);
288*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_size: %u\n", mp->c.un_size);
289*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_self_id: %lu\n", MD_SID(mp));
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	/* sp-specific fields */
292*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_status: %u\n", mp->un_status);
293*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_numexts: %u\n", mp->un_numexts);
294*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_length: %llu\n", mp->un_length);
295*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_dev(32): 0x%llx\n", mp->un_dev);
296*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_dev(64): 0x%llx\n", mp->un_dev);
297*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_key: %d\n", mp->un_key);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	/* print extent information */
300*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\tExt#\tvoff\t\tpoff\t\tLen\n");
301*0Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
302*0Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%d\t%llu\t\t%llu\t\t%llu\n", i,
303*0Sstevel@tonic-gate 		    mp->un_ext[i].un_voff, mp->un_ext[i].un_poff,
304*0Sstevel@tonic-gate 		    mp->un_ext[i].un_len);
305*0Sstevel@tonic-gate 	}
306*0Sstevel@tonic-gate }
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate /*
309*0Sstevel@tonic-gate  * FUNCTION:    meta_sp_parsesize()
310*0Sstevel@tonic-gate  * INPUT:       s       - the string to parse
311*0Sstevel@tonic-gate  * OUTPUT:      *szp    - disk block count (0 for "all")
312*0Sstevel@tonic-gate  * RETURNS:     -1 for error, 0 for success
313*0Sstevel@tonic-gate  * PURPOSE:     parses the command line parameter that specifies the
314*0Sstevel@tonic-gate  *              requested size of a soft partition.  The input string
315*0Sstevel@tonic-gate  *              is either the literal "all" or a numeric value
316*0Sstevel@tonic-gate  *              followed by a single character, b for disk blocks, k
317*0Sstevel@tonic-gate  *              for kilobytes, m for megabytes, g for gigabytes, or t
318*0Sstevel@tonic-gate  *              for terabytes.  p for petabytes and e for exabytes
319*0Sstevel@tonic-gate  *              have been added as undocumented features for future
320*0Sstevel@tonic-gate  *              expansion.  For example, 100m is 100 megabytes, while
321*0Sstevel@tonic-gate  *              50g is 50 gigabytes.  All values are rounded up to the
322*0Sstevel@tonic-gate  *              nearest block size.
323*0Sstevel@tonic-gate  */
324*0Sstevel@tonic-gate int
325*0Sstevel@tonic-gate meta_sp_parsesize(char *s, sp_ext_length_t *szp)
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	if (s == NULL || szp == NULL) {
328*0Sstevel@tonic-gate 		return (-1);
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	/* Check for literal "all" */
332*0Sstevel@tonic-gate 	if (strcasecmp(s, "all") == 0) {
333*0Sstevel@tonic-gate 		*szp = 0;
334*0Sstevel@tonic-gate 		return (0);
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	return (meta_sp_parsesizestring(s, szp));
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate /*
341*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_parsesizestring()
342*0Sstevel@tonic-gate  * INPUT:	s	- the string to parse
343*0Sstevel@tonic-gate  * OUTPUT:	*szp	- disk block count
344*0Sstevel@tonic-gate  * RETURNS:	-1 for error, 0 for success
345*0Sstevel@tonic-gate  * PURPOSE:	parses a string that specifies size. The input string is a
346*0Sstevel@tonic-gate  *		numeric value followed by a single character, b for disk blocks,
347*0Sstevel@tonic-gate  *		k for kilobytes, m for megabytes, g for gigabytes, or t for
348*0Sstevel@tonic-gate  *		terabytes.  p for petabytes and e for exabytes have been added
349*0Sstevel@tonic-gate  *		as undocumented features for future expansion.  For example,
350*0Sstevel@tonic-gate  *		100m is 100 megabytes, while 50g is 50 gigabytes.  All values
351*0Sstevel@tonic-gate  *		are rounded up to the nearest block size.
352*0Sstevel@tonic-gate  */
353*0Sstevel@tonic-gate static int
354*0Sstevel@tonic-gate meta_sp_parsesizestring(char *s, sp_ext_length_t *szp)
355*0Sstevel@tonic-gate {
356*0Sstevel@tonic-gate 	sp_ext_length_t	len = 0;
357*0Sstevel@tonic-gate 	char		len_type[2];
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	if (s == NULL || szp == NULL) {
360*0Sstevel@tonic-gate 		return (-1);
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/*
364*0Sstevel@tonic-gate 	 * make sure block offset does not overflow 2^64 bytes.
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 	if ((sscanf(s, "%llu%1[BbKkMmGgTt]", &len, len_type) != 2) ||
367*0Sstevel@tonic-gate 	    (len == 0LL) ||
368*0Sstevel@tonic-gate 	    (len > (1LL << (64 - DEV_BSHIFT))))
369*0Sstevel@tonic-gate 		return (-1);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	switch (len_type[0]) {
372*0Sstevel@tonic-gate 	case 'B':
373*0Sstevel@tonic-gate 	case 'b':
374*0Sstevel@tonic-gate 		len = lbtodb(roundup(len * DEV_BSIZE, DEV_BSIZE));
375*0Sstevel@tonic-gate 		break;
376*0Sstevel@tonic-gate 	case 'K':
377*0Sstevel@tonic-gate 	case 'k':
378*0Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL, DEV_BSIZE));
379*0Sstevel@tonic-gate 		break;
380*0Sstevel@tonic-gate 	case 'M':
381*0Sstevel@tonic-gate 	case 'm':
382*0Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL, DEV_BSIZE));
383*0Sstevel@tonic-gate 		break;
384*0Sstevel@tonic-gate 	case 'g':
385*0Sstevel@tonic-gate 	case 'G':
386*0Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL*1024ULL, DEV_BSIZE));
387*0Sstevel@tonic-gate 		break;
388*0Sstevel@tonic-gate 	case 't':
389*0Sstevel@tonic-gate 	case 'T':
390*0Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL*1024ULL*1024ULL,
391*0Sstevel@tonic-gate 		    DEV_BSIZE));
392*0Sstevel@tonic-gate 		break;
393*0Sstevel@tonic-gate 	case 'p':
394*0Sstevel@tonic-gate 	case 'P':
395*0Sstevel@tonic-gate 		len = lbtodb(roundup(
396*0Sstevel@tonic-gate 		    len * 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL,
397*0Sstevel@tonic-gate 		    DEV_BSIZE));
398*0Sstevel@tonic-gate 		break;
399*0Sstevel@tonic-gate 	case 'e':
400*0Sstevel@tonic-gate 	case 'E':
401*0Sstevel@tonic-gate 		len = lbtodb(roundup(
402*0Sstevel@tonic-gate 		    len * 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL,
403*0Sstevel@tonic-gate 		    DEV_BSIZE));
404*0Sstevel@tonic-gate 		break;
405*0Sstevel@tonic-gate 	default:
406*0Sstevel@tonic-gate 		/* error */
407*0Sstevel@tonic-gate 		return (-1);
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	*szp = len;
411*0Sstevel@tonic-gate 	return (0);
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_setgeom()
416*0Sstevel@tonic-gate  * INPUT:	np      - the underlying device to setup geometry for
417*0Sstevel@tonic-gate  *		compnp	- the underlying device to setup geometry for
418*0Sstevel@tonic-gate  *		mp	- the unit structure to set the geometry for
419*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
420*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 otherwise
421*0Sstevel@tonic-gate  * PURPOSE:	establishes geometry information for a device
422*0Sstevel@tonic-gate  */
423*0Sstevel@tonic-gate static int
424*0Sstevel@tonic-gate meta_sp_setgeom(
425*0Sstevel@tonic-gate 	mdname_t	*np,
426*0Sstevel@tonic-gate 	mdname_t	*compnp,
427*0Sstevel@tonic-gate 	mp_unit_t	*mp,
428*0Sstevel@tonic-gate 	md_error_t	*ep
429*0Sstevel@tonic-gate )
430*0Sstevel@tonic-gate {
431*0Sstevel@tonic-gate 	mdgeom_t	*geomp;
432*0Sstevel@tonic-gate 	uint_t		round_cyl = 0;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	if ((geomp = metagetgeom(compnp, ep)) == NULL)
435*0Sstevel@tonic-gate 		return (-1);
436*0Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)mp, np, geomp, geomp->write_reinstruct,
437*0Sstevel@tonic-gate 	    geomp->read_reinstruct, round_cyl, ep) != 0)
438*0Sstevel@tonic-gate 		return (-1);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	return (0);
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate /*
444*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_setstatus()
445*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the devices to set the status on
446*0Sstevel@tonic-gate  *		minors	- an array of minor numbers of devices to set status on
447*0Sstevel@tonic-gate  *		num_units - number of entries in the array
448*0Sstevel@tonic-gate  *		status	- status value to set all units to
449*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
450*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
451*0Sstevel@tonic-gate  * PURPOSE:	sets the status of one or more soft partitions to the
452*0Sstevel@tonic-gate  *		requested value
453*0Sstevel@tonic-gate  */
454*0Sstevel@tonic-gate int
455*0Sstevel@tonic-gate meta_sp_setstatus(
456*0Sstevel@tonic-gate 	mdsetname_t	*sp,
457*0Sstevel@tonic-gate 	minor_t		*minors,
458*0Sstevel@tonic-gate 	int		num_units,
459*0Sstevel@tonic-gate 	sp_status_t	status,
460*0Sstevel@tonic-gate 	md_error_t	*ep
461*0Sstevel@tonic-gate )
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	md_sp_statusset_t	status_params;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	assert(minors != NULL);
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/* update status of all soft partitions to the status passed in */
468*0Sstevel@tonic-gate 	(void) memset(&status_params, 0, sizeof (status_params));
469*0Sstevel@tonic-gate 	status_params.num_units = num_units;
470*0Sstevel@tonic-gate 	status_params.new_status = status;
471*0Sstevel@tonic-gate 	status_params.size = num_units * sizeof (minor_t);
472*0Sstevel@tonic-gate 	status_params.minors = (uintptr_t)minors;
473*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&status_params, MD_SP, sp->setno);
474*0Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPSTATUS, &status_params, &status_params.mde,
475*0Sstevel@tonic-gate 	    NULL) != 0) {
476*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &status_params.mde);
477*0Sstevel@tonic-gate 		return (-1);
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 	return (0);
480*0Sstevel@tonic-gate }
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate /*
483*0Sstevel@tonic-gate  * FUNCTION:	meta_get_sp_names()
484*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to get soft partitions from
485*0Sstevel@tonic-gate  *		options	- options from the command line
486*0Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all soft partition names
487*0Sstevel@tonic-gate  *		ep	- return error pointer
488*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
489*0Sstevel@tonic-gate  * PURPOSE:	returns a list of all soft partitions in the metadb
490*0Sstevel@tonic-gate  *		for all devices in the specified set
491*0Sstevel@tonic-gate  */
492*0Sstevel@tonic-gate int
493*0Sstevel@tonic-gate meta_get_sp_names(
494*0Sstevel@tonic-gate 	mdsetname_t	*sp,
495*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
496*0Sstevel@tonic-gate 	int		options,
497*0Sstevel@tonic-gate 	md_error_t	*ep
498*0Sstevel@tonic-gate )
499*0Sstevel@tonic-gate {
500*0Sstevel@tonic-gate 	return (meta_get_names(MD_SP, sp, nlpp, options, ep));
501*0Sstevel@tonic-gate }
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate /*
504*0Sstevel@tonic-gate  * FUNCTION:	meta_get_by_component()
505*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to get soft partitions from
506*0Sstevel@tonic-gate  *		compnp	- the name of the device containing the soft
507*0Sstevel@tonic-gate  *			  partitions that will be returned
508*0Sstevel@tonic-gate  *		force	- 0 - reads cached namelist if available,
509*0Sstevel@tonic-gate  *			  1 - reloads cached namelist, frees old namelist
510*0Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all soft partition names
511*0Sstevel@tonic-gate  *		ep	- return error pointer
512*0Sstevel@tonic-gate  * RETURNS:	int	- -1 error, otherwise the number of soft partitions
513*0Sstevel@tonic-gate  *			  found on the component (0 = none found).
514*0Sstevel@tonic-gate  * PURPOSE:	returns a list of all soft partitions on a given device
515*0Sstevel@tonic-gate  *		from the metadb information
516*0Sstevel@tonic-gate  */
517*0Sstevel@tonic-gate static int
518*0Sstevel@tonic-gate meta_sp_get_by_component(
519*0Sstevel@tonic-gate 	mdsetname_t	*sp,
520*0Sstevel@tonic-gate 	mdname_t	*compnp,
521*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
522*0Sstevel@tonic-gate 	int		force,
523*0Sstevel@tonic-gate 	md_error_t	*ep
524*0Sstevel@tonic-gate )
525*0Sstevel@tonic-gate {
526*0Sstevel@tonic-gate 	static mdnamelist_t	*cached_list = NULL;	/* cached namelist */
527*0Sstevel@tonic-gate 	static int		cached_count = 0;	/* cached count */
528*0Sstevel@tonic-gate 	mdnamelist_t		*spnlp = NULL;		/* all sp names */
529*0Sstevel@tonic-gate 	mdnamelist_t		*namep;			/* list iterator */
530*0Sstevel@tonic-gate 	mdnamelist_t		**tailpp = nlpp;	/* namelist tail */
531*0Sstevel@tonic-gate 	mdnamelist_t		**cachetailpp;		/* cache tail */
532*0Sstevel@tonic-gate 	md_sp_t			*msp;			/* unit structure */
533*0Sstevel@tonic-gate 	int			count = 0;		/* count of sp's */
534*0Sstevel@tonic-gate 	int			err;
535*0Sstevel@tonic-gate 	mdname_t		*curnp;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	if ((cached_list != NULL) && (!force)) {
538*0Sstevel@tonic-gate 		/* return a copy of the cached list */
539*0Sstevel@tonic-gate 		for (namep = cached_list; namep != NULL; namep = namep->next)
540*0Sstevel@tonic-gate 			tailpp = meta_namelist_append_wrapper(tailpp,
541*0Sstevel@tonic-gate 			    namep->namep);
542*0Sstevel@tonic-gate 		return (cached_count);
543*0Sstevel@tonic-gate 	}
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	/* free the cache and reset values to zeros to prepare for a new list */
546*0Sstevel@tonic-gate 	metafreenamelist(cached_list);
547*0Sstevel@tonic-gate 	cached_count = 0;
548*0Sstevel@tonic-gate 	cached_list = NULL;
549*0Sstevel@tonic-gate 	cachetailpp = &cached_list;
550*0Sstevel@tonic-gate 	*nlpp = NULL;
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	/* get all the softpartitions first of all */
553*0Sstevel@tonic-gate 	if (meta_get_sp_names(sp, &spnlp, 0, ep) < 0)
554*0Sstevel@tonic-gate 		return (-1);
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	/*
557*0Sstevel@tonic-gate 	 * Now for each sp, see if it resides on the component we
558*0Sstevel@tonic-gate 	 * are interested in, if so then add it to our list
559*0Sstevel@tonic-gate 	 */
560*0Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
561*0Sstevel@tonic-gate 		curnp = namep->namep;
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 		/* get the unit structure */
564*0Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
565*0Sstevel@tonic-gate 			continue;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 		/*
568*0Sstevel@tonic-gate 		 * If the current soft partition is not on the same
569*0Sstevel@tonic-gate 		 * component, continue the search.  If it is on the same
570*0Sstevel@tonic-gate 		 * component, add it to our namelist.
571*0Sstevel@tonic-gate 		 */
572*0Sstevel@tonic-gate 		err = meta_check_samedrive(compnp, msp->compnamep, ep);
573*0Sstevel@tonic-gate 		if (err <= 0) {
574*0Sstevel@tonic-gate 			/* not on the same device, check the next one */
575*0Sstevel@tonic-gate 			continue;
576*0Sstevel@tonic-gate 		}
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 		/* it's on the same drive */
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		/*
581*0Sstevel@tonic-gate 		 * Check for overlapping partitions if the component is not
582*0Sstevel@tonic-gate 		 * a metadevice.
583*0Sstevel@tonic-gate 		 */
584*0Sstevel@tonic-gate 		if (!metaismeta(msp->compnamep)) {
585*0Sstevel@tonic-gate 			/*
586*0Sstevel@tonic-gate 			 * if they're on the same drive, neither
587*0Sstevel@tonic-gate 			 * should be a metadevice if one isn't
588*0Sstevel@tonic-gate 			 */
589*0Sstevel@tonic-gate 			assert(!metaismeta(compnp));
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 			if (meta_check_overlap(msp->compnamep->cname,
592*0Sstevel@tonic-gate 			    compnp, 0, -1, msp->compnamep, 0, -1, ep) == 0)
593*0Sstevel@tonic-gate 				continue;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 			/* in this case it's not an error for them to overlap */
596*0Sstevel@tonic-gate 			mdclrerror(ep);
597*0Sstevel@tonic-gate 		}
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 		/* Component is on the same device, add to the used list */
600*0Sstevel@tonic-gate 		tailpp = meta_namelist_append_wrapper(tailpp, curnp);
601*0Sstevel@tonic-gate 		cachetailpp = meta_namelist_append_wrapper(cachetailpp,
602*0Sstevel@tonic-gate 		    curnp);
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 		++count;
605*0Sstevel@tonic-gate 		++cached_count;
606*0Sstevel@tonic-gate 	}
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	assert(count == cached_count);
609*0Sstevel@tonic-gate 	return (count);
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate out:
612*0Sstevel@tonic-gate 	metafreenamelist(*nlpp);
613*0Sstevel@tonic-gate 	*nlpp = NULL;
614*0Sstevel@tonic-gate 	return (-1);
615*0Sstevel@tonic-gate }
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate /*
618*0Sstevel@tonic-gate  * FUNCTION:    meta_sp_get_default_alignment()
619*0Sstevel@tonic-gate  * INPUT:       sp      - the pertinent set name
620*0Sstevel@tonic-gate  *              compnp  - the name of the underlying component
621*0Sstevel@tonic-gate  * OUTPUT:      ep      - return error pointer
622*0Sstevel@tonic-gate  * RETURNS:     sp_ext_length_t =0: no default alignment
623*0Sstevel@tonic-gate  *                              >0: default alignment
624*0Sstevel@tonic-gate  * PURPOSE:     returns the default alignment for soft partitions to
625*0Sstevel@tonic-gate  *              be built on top of the specified component or
626*0Sstevel@tonic-gate  *              metadevice
627*0Sstevel@tonic-gate  */
628*0Sstevel@tonic-gate static sp_ext_length_t
629*0Sstevel@tonic-gate meta_sp_get_default_alignment(
630*0Sstevel@tonic-gate 	mdsetname_t	*sp,
631*0Sstevel@tonic-gate 	mdname_t	*compnp,
632*0Sstevel@tonic-gate 	md_error_t	*ep
633*0Sstevel@tonic-gate )
634*0Sstevel@tonic-gate {
635*0Sstevel@tonic-gate 	sp_ext_length_t	a = SP_UNALIGNED;
636*0Sstevel@tonic-gate 	char		*mname;
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	assert(compnp != NULL);
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	/*
641*0Sstevel@tonic-gate 	 * We treat raw devices as opaque, and assume nothing about
642*0Sstevel@tonic-gate 	 * their alignment requirements.
643*0Sstevel@tonic-gate 	 */
644*0Sstevel@tonic-gate 	if (!metaismeta(compnp))
645*0Sstevel@tonic-gate 		return (SP_UNALIGNED);
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	/*
648*0Sstevel@tonic-gate 	 * We already know it's a metadevice from the previous test;
649*0Sstevel@tonic-gate 	 * metagetmiscname() will tell us which metadevice type we
650*0Sstevel@tonic-gate 	 * have
651*0Sstevel@tonic-gate 	 */
652*0Sstevel@tonic-gate 	mname = metagetmiscname(compnp, ep);
653*0Sstevel@tonic-gate 	if (mname == NULL)
654*0Sstevel@tonic-gate 		goto out;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	/*
657*0Sstevel@tonic-gate 	 * For a mirror, we want to deal with the stripe that is the
658*0Sstevel@tonic-gate 	 * primary side.  If it happens to be asymmetrically
659*0Sstevel@tonic-gate 	 * configured, there is no simple way to fake a universal
660*0Sstevel@tonic-gate 	 * alignment.  There's a chance that the least common
661*0Sstevel@tonic-gate 	 * denominator of the set of interlaces from all stripes of
662*0Sstevel@tonic-gate 	 * all submirrors would do it, but nobody that really cared
663*0Sstevel@tonic-gate 	 * that much about this issue would create an asymmetric
664*0Sstevel@tonic-gate 	 * config to start with.
665*0Sstevel@tonic-gate 	 *
666*0Sstevel@tonic-gate 	 * If the component underlying the soft partition is a mirror,
667*0Sstevel@tonic-gate 	 * then at the exit of this loop, compnp will have been
668*0Sstevel@tonic-gate 	 * updated to describe the first active submirror.
669*0Sstevel@tonic-gate 	 */
670*0Sstevel@tonic-gate 	if (strcmp(mname, MD_MIRROR) == 0) {
671*0Sstevel@tonic-gate 		md_mirror_t	*mp;
672*0Sstevel@tonic-gate 		int		smi;
673*0Sstevel@tonic-gate 		md_submirror_t	*smp;
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		mp = meta_get_mirror(sp, compnp, ep);
676*0Sstevel@tonic-gate 		if (mp == NULL)
677*0Sstevel@tonic-gate 			goto out;
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 		for (smi = 0; smi < NMIRROR; smi++) {
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 			smp = &mp->submirrors[smi];
682*0Sstevel@tonic-gate 			if (smp->state == SMS_UNUSED)
683*0Sstevel@tonic-gate 				continue;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 			compnp = smp->submirnamep;
686*0Sstevel@tonic-gate 			assert(compnp != NULL);
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 			mname = metagetmiscname(compnp, ep);
689*0Sstevel@tonic-gate 			if (mname == NULL)
690*0Sstevel@tonic-gate 				goto out;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 			break;
693*0Sstevel@tonic-gate 		}
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 		if (smi == NMIRROR)
696*0Sstevel@tonic-gate 			goto out;
697*0Sstevel@tonic-gate 	}
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	/*
700*0Sstevel@tonic-gate 	 * Handle stripes and submirrors identically; just return the
701*0Sstevel@tonic-gate 	 * interlace of the first row.
702*0Sstevel@tonic-gate 	 */
703*0Sstevel@tonic-gate 	if (strcmp(mname, MD_STRIPE) == 0) {
704*0Sstevel@tonic-gate 		md_stripe_t	*stp;
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 		stp = meta_get_stripe(sp, compnp, ep);
707*0Sstevel@tonic-gate 		if (stp == NULL)
708*0Sstevel@tonic-gate 			goto out;
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 		a = stp->rows.rows_val[0].interlace;
711*0Sstevel@tonic-gate 		goto out;
712*0Sstevel@tonic-gate 	}
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	/*
715*0Sstevel@tonic-gate 	 * Raid is even more straightforward; the interlace applies to
716*0Sstevel@tonic-gate 	 * the entire device.
717*0Sstevel@tonic-gate 	 */
718*0Sstevel@tonic-gate 	if (strcmp(mname, MD_RAID) == 0) {
719*0Sstevel@tonic-gate 		md_raid_t	*rp;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 		rp = meta_get_raid(sp, compnp, ep);
722*0Sstevel@tonic-gate 		if (rp == NULL)
723*0Sstevel@tonic-gate 			goto out;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		a = rp->interlace;
726*0Sstevel@tonic-gate 		goto out;
727*0Sstevel@tonic-gate 	}
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	/*
730*0Sstevel@tonic-gate 	 * If we have arrived here with the alignment still not set,
731*0Sstevel@tonic-gate 	 * then we expect the error to have been set by one of the
732*0Sstevel@tonic-gate 	 * routines we called.  If neither is the case, something has
733*0Sstevel@tonic-gate 	 * really gone wrong above.  (Probably the submirror walk
734*0Sstevel@tonic-gate 	 * failed to produce a valid submirror, but that would be
735*0Sstevel@tonic-gate 	 * really bad...)
736*0Sstevel@tonic-gate 	 */
737*0Sstevel@tonic-gate out:
738*0Sstevel@tonic-gate 	meta_sp_debug("meta_sp_get_default_alignment: miscname %s, "
739*0Sstevel@tonic-gate 	    "alignment %lld\n", (mname == NULL) ? "NULL" : mname, a);
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG) && !mdisok(ep)) {
742*0Sstevel@tonic-gate 		mde_perror(ep, NULL);
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	assert((a > 0) || (!mdisok(ep)));
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	return (a);
748*0Sstevel@tonic-gate }
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate /*
753*0Sstevel@tonic-gate  * FUNCTION:	meta_check_insp()
754*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to check
755*0Sstevel@tonic-gate  *		np	- the name of the device to check
756*0Sstevel@tonic-gate  *		slblk	- the starting offset of the device to check
757*0Sstevel@tonic-gate  *		nblks	- the number of blocks in the device to check
758*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
759*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - device contains soft partitions
760*0Sstevel@tonic-gate  *			  -1 - device does not contain soft partitions
761*0Sstevel@tonic-gate  * PURPOSE:	determines whether a device contains any soft partitions
762*0Sstevel@tonic-gate  */
763*0Sstevel@tonic-gate /* ARGSUSED */
764*0Sstevel@tonic-gate int
765*0Sstevel@tonic-gate meta_check_insp(
766*0Sstevel@tonic-gate 	mdsetname_t	*sp,
767*0Sstevel@tonic-gate 	mdname_t	*np,
768*0Sstevel@tonic-gate 	diskaddr_t	slblk,
769*0Sstevel@tonic-gate 	diskaddr_t	nblks,
770*0Sstevel@tonic-gate 	md_error_t	*ep
771*0Sstevel@tonic-gate )
772*0Sstevel@tonic-gate {
773*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;	/* soft partition name list */
774*0Sstevel@tonic-gate 	int		count;
775*0Sstevel@tonic-gate 	int		rval;
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	/* check set pointer */
778*0Sstevel@tonic-gate 	assert(sp != NULL);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	/* find all soft partitions on the component */
781*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, np, &spnlp, 0, ep);
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	if (count == -1) {
784*0Sstevel@tonic-gate 		rval = -1;
785*0Sstevel@tonic-gate 	} else if (count > 0) {
786*0Sstevel@tonic-gate 		rval = mduseerror(ep, MDE_ALREADY, np->dev,
787*0Sstevel@tonic-gate 		    spnlp->namep->cname, np->cname);
788*0Sstevel@tonic-gate 	} else {
789*0Sstevel@tonic-gate 		rval = 0;
790*0Sstevel@tonic-gate 	}
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	metafreenamelist(spnlp);
793*0Sstevel@tonic-gate 	return (rval);
794*0Sstevel@tonic-gate }
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate /*
797*0Sstevel@tonic-gate  * **************************************************************************
798*0Sstevel@tonic-gate  *                    Extent List Manipulation Functions                    *
799*0Sstevel@tonic-gate  * **************************************************************************
800*0Sstevel@tonic-gate  */
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate /*
803*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_cmp_by_nameseq()
804*0Sstevel@tonic-gate  * INPUT:	e1	- first node to compare
805*0Sstevel@tonic-gate  *		e2	- second node to compare
806*0Sstevel@tonic-gate  * OUTPUT:	none
807*0Sstevel@tonic-gate  * RETURNS:	int	- =0 - nodes are equal
808*0Sstevel@tonic-gate  *			  <0 - e1 should go before e2
809*0Sstevel@tonic-gate  *			  >0 - e1 should go after e2
810*0Sstevel@tonic-gate  * PURPOSE:	used for sorted list inserts to build a list sorted by
811*0Sstevel@tonic-gate  *		name first and sequence number second.
812*0Sstevel@tonic-gate  */
813*0Sstevel@tonic-gate static int
814*0Sstevel@tonic-gate meta_sp_cmp_by_nameseq(sp_ext_node_t *e1, sp_ext_node_t *e2)
815*0Sstevel@tonic-gate {
816*0Sstevel@tonic-gate 	int rval;
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	if (e1->ext_namep == NULL)
819*0Sstevel@tonic-gate 		return (1);
820*0Sstevel@tonic-gate 	if (e2->ext_namep == NULL)
821*0Sstevel@tonic-gate 		return (-1);
822*0Sstevel@tonic-gate 	if ((rval = strcmp(e1->ext_namep->cname, e2->ext_namep->cname)) != 0)
823*0Sstevel@tonic-gate 		return (rval);
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	/* the names are equal, compare sequence numbers */
826*0Sstevel@tonic-gate 	if (e1->ext_seq > e2->ext_seq)
827*0Sstevel@tonic-gate 		return (1);
828*0Sstevel@tonic-gate 	if (e1->ext_seq < e2->ext_seq)
829*0Sstevel@tonic-gate 		return (-1);
830*0Sstevel@tonic-gate 	/* sequence numbers are also equal */
831*0Sstevel@tonic-gate 	return (0);
832*0Sstevel@tonic-gate }
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate /*
835*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_cmp_by_offset()
836*0Sstevel@tonic-gate  * INPUT:	e1	- first node to compare
837*0Sstevel@tonic-gate  *		e2	- second node to compare
838*0Sstevel@tonic-gate  * OUTPUT:	none
839*0Sstevel@tonic-gate  * RETURNS:	int	- =0 - nodes are equal
840*0Sstevel@tonic-gate  *			  <0 - e1 should go before e2
841*0Sstevel@tonic-gate  *			  >0 - e1 should go after e2
842*0Sstevel@tonic-gate  * PURPOSE:	used for sorted list inserts to build a list sorted by offset
843*0Sstevel@tonic-gate  */
844*0Sstevel@tonic-gate static int
845*0Sstevel@tonic-gate meta_sp_cmp_by_offset(sp_ext_node_t *e1, sp_ext_node_t *e2)
846*0Sstevel@tonic-gate {
847*0Sstevel@tonic-gate 	if (e1->ext_offset > e2->ext_offset)
848*0Sstevel@tonic-gate 		return (1);
849*0Sstevel@tonic-gate 	if (e1->ext_offset < e2->ext_offset)
850*0Sstevel@tonic-gate 		return (-1);
851*0Sstevel@tonic-gate 	/* offsets are equal */
852*0Sstevel@tonic-gate 	return (0);
853*0Sstevel@tonic-gate }
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate /*
856*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_insert()
857*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
858*0Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
859*0Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
860*0Sstevel@tonic-gate  *		offset	- the physical offset of this extent in sectors
861*0Sstevel@tonic-gate  *		length	- the length of this extent in sectors
862*0Sstevel@tonic-gate  *		type	- the type of the extent being inserted
863*0Sstevel@tonic-gate  *		seq	- the sequence number of the extent being inserted
864*0Sstevel@tonic-gate  *		flags	- extent flags (eg. whether it needs to be updated)
865*0Sstevel@tonic-gate  *		compare	- the compare function to use
866*0Sstevel@tonic-gate  * OUTPUT:	head	- points to the new head if a node was inserted
867*0Sstevel@tonic-gate  *			  at the beginning
868*0Sstevel@tonic-gate  * RETURNS:	void
869*0Sstevel@tonic-gate  * PURPOSE:	inserts an extent node into a sorted doubly linked list.
870*0Sstevel@tonic-gate  *		The sort order is determined by the compare function.
871*0Sstevel@tonic-gate  *		Memory is allocated for the node in this function and it
872*0Sstevel@tonic-gate  *		is up to the caller to free it, possibly using
873*0Sstevel@tonic-gate  *		meta_sp_list_free().  If a node is inserted at the
874*0Sstevel@tonic-gate  *		beginning of the list, the head pointer is updated to
875*0Sstevel@tonic-gate  *		point to the new first node.
876*0Sstevel@tonic-gate  */
877*0Sstevel@tonic-gate static void
878*0Sstevel@tonic-gate meta_sp_list_insert(
879*0Sstevel@tonic-gate 	mdsetname_t	*sp,
880*0Sstevel@tonic-gate 	mdname_t	*np,
881*0Sstevel@tonic-gate 	sp_ext_node_t	**head,
882*0Sstevel@tonic-gate 	sp_ext_offset_t	offset,
883*0Sstevel@tonic-gate 	sp_ext_length_t	length,
884*0Sstevel@tonic-gate 	sp_ext_type_t	type,
885*0Sstevel@tonic-gate 	uint_t		seq,
886*0Sstevel@tonic-gate 	uint_t		flags,
887*0Sstevel@tonic-gate 	ext_cmpfunc_t	compare
888*0Sstevel@tonic-gate )
889*0Sstevel@tonic-gate {
890*0Sstevel@tonic-gate 	sp_ext_node_t	*newext;
891*0Sstevel@tonic-gate 	sp_ext_node_t	*curext;
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	assert(head != NULL);
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	/* Don't bother adding zero length nodes */
896*0Sstevel@tonic-gate 	if (length == 0ULL)
897*0Sstevel@tonic-gate 		return;
898*0Sstevel@tonic-gate 
899*0Sstevel@tonic-gate 	/* allocate and fill in new ext_node */
900*0Sstevel@tonic-gate 	newext = Zalloc(sizeof (sp_ext_node_t));
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	newext->ext_offset = offset;
903*0Sstevel@tonic-gate 	newext->ext_length = length;
904*0Sstevel@tonic-gate 	newext->ext_flags = flags;
905*0Sstevel@tonic-gate 	newext->ext_type = type;
906*0Sstevel@tonic-gate 	newext->ext_seq = seq;
907*0Sstevel@tonic-gate 	newext->ext_setp = sp;
908*0Sstevel@tonic-gate 	newext->ext_namep = np;
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	/* first node in the list */
911*0Sstevel@tonic-gate 	if (*head == NULL) {
912*0Sstevel@tonic-gate 		newext->ext_next = newext->ext_prev = NULL;
913*0Sstevel@tonic-gate 		*head = newext;
914*0Sstevel@tonic-gate 	} else if ((*compare)(*head, newext) >= 0) {
915*0Sstevel@tonic-gate 		/* the first node has a bigger offset, so insert before it */
916*0Sstevel@tonic-gate 		assert((*head)->ext_prev == NULL);
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 		newext->ext_prev = NULL;
919*0Sstevel@tonic-gate 		newext->ext_next = *head;
920*0Sstevel@tonic-gate 		(*head)->ext_prev = newext;
921*0Sstevel@tonic-gate 		*head = newext;
922*0Sstevel@tonic-gate 	} else {
923*0Sstevel@tonic-gate 		/*
924*0Sstevel@tonic-gate 		 * find the next node whose offset is greater than
925*0Sstevel@tonic-gate 		 * the one we want to insert, or the end of the list.
926*0Sstevel@tonic-gate 		 */
927*0Sstevel@tonic-gate 		for (curext = *head;
928*0Sstevel@tonic-gate 		    (curext->ext_next != NULL) &&
929*0Sstevel@tonic-gate 		    ((*compare)(curext->ext_next, newext) < 0);
930*0Sstevel@tonic-gate 		    (curext = curext->ext_next))
931*0Sstevel@tonic-gate 			;
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 		/* link the new node in after the current node */
934*0Sstevel@tonic-gate 		newext->ext_next = curext->ext_next;
935*0Sstevel@tonic-gate 		newext->ext_prev = curext;
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 		if (curext->ext_next != NULL)
938*0Sstevel@tonic-gate 			curext->ext_next->ext_prev = newext;
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate 		curext->ext_next = newext;
941*0Sstevel@tonic-gate 	}
942*0Sstevel@tonic-gate }
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate /*
945*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_free()
946*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
947*0Sstevel@tonic-gate  * OUTPUT:	head	- points to NULL on return
948*0Sstevel@tonic-gate  * RETURNS:	void
949*0Sstevel@tonic-gate  * PURPOSE:	walks a double linked extent list and frees each node
950*0Sstevel@tonic-gate  */
951*0Sstevel@tonic-gate static void
952*0Sstevel@tonic-gate meta_sp_list_free(sp_ext_node_t **head)
953*0Sstevel@tonic-gate {
954*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
955*0Sstevel@tonic-gate 	sp_ext_node_t	*next;
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	assert(head != NULL);
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	ext = *head;
960*0Sstevel@tonic-gate 	while (ext) {
961*0Sstevel@tonic-gate 		next = ext->ext_next;
962*0Sstevel@tonic-gate 		Free(ext);
963*0Sstevel@tonic-gate 		ext = next;
964*0Sstevel@tonic-gate 	}
965*0Sstevel@tonic-gate 	*head = NULL;
966*0Sstevel@tonic-gate }
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate /*
969*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_remove()
970*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
971*0Sstevel@tonic-gate  *		ext	- the extent to remove, must be a member of the list
972*0Sstevel@tonic-gate  * OUTPUT:	head	- points to the new head of the list
973*0Sstevel@tonic-gate  * RETURNS:	void
974*0Sstevel@tonic-gate  * PURPOSE:	unlinks the node specified by ext from the list and
975*0Sstevel@tonic-gate  *		frees it, possibly moving the head pointer forward if
976*0Sstevel@tonic-gate  *		the head is the node being removed.
977*0Sstevel@tonic-gate  */
978*0Sstevel@tonic-gate static void
979*0Sstevel@tonic-gate meta_sp_list_remove(sp_ext_node_t **head, sp_ext_node_t *ext)
980*0Sstevel@tonic-gate {
981*0Sstevel@tonic-gate 	assert(head != NULL);
982*0Sstevel@tonic-gate 	assert(*head != NULL);
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	if (*head == ext)
985*0Sstevel@tonic-gate 		*head = ext->ext_next;
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	if (ext->ext_prev != NULL)
988*0Sstevel@tonic-gate 		ext->ext_prev->ext_next = ext->ext_next;
989*0Sstevel@tonic-gate 	if (ext->ext_next != NULL)
990*0Sstevel@tonic-gate 		ext->ext_next->ext_prev = ext->ext_prev;
991*0Sstevel@tonic-gate 	Free(ext);
992*0Sstevel@tonic-gate }
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate /*
995*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_size()
996*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
997*0Sstevel@tonic-gate  *		exttype	- the type of the extents to sum
998*0Sstevel@tonic-gate  *		exclude_wm - subtract space for extent headers from total
999*0Sstevel@tonic-gate  * OUTPUT:	none
1000*0Sstevel@tonic-gate  * RETURNS:	sp_ext_length_t	- the sum of all of the lengths
1001*0Sstevel@tonic-gate  * PURPOSE:	sums the lengths of all extents in the list matching the
1002*0Sstevel@tonic-gate  *		specified type.  This could be used for computing the
1003*0Sstevel@tonic-gate  *		amount of free or used space, for example.
1004*0Sstevel@tonic-gate  */
1005*0Sstevel@tonic-gate static sp_ext_length_t
1006*0Sstevel@tonic-gate meta_sp_list_size(sp_ext_node_t *head, sp_ext_type_t exttype, int exclude_wm)
1007*0Sstevel@tonic-gate {
1008*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
1009*0Sstevel@tonic-gate 	sp_ext_length_t	size = 0LL;
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next)
1012*0Sstevel@tonic-gate 		if (ext->ext_type == exttype)
1013*0Sstevel@tonic-gate 			size += ext->ext_length -
1014*0Sstevel@tonic-gate 			    ((exclude_wm) ? MD_SP_WMSIZE : 0);
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 	return (size);
1017*0Sstevel@tonic-gate }
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate /*
1020*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_find()
1021*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
1022*0Sstevel@tonic-gate  *		offset	- the offset contained by the node to find
1023*0Sstevel@tonic-gate  * OUTPUT:	none
1024*0Sstevel@tonic-gate  * RETURNS:	sp_ext_node_t *	- the node containing the requested offset
1025*0Sstevel@tonic-gate  *				  or NULL if no such nodes were found.
1026*0Sstevel@tonic-gate  * PURPOSE:	finds a node in a list containing the requested offset
1027*0Sstevel@tonic-gate  *		(inclusive).  If multiple nodes contain this offset then
1028*0Sstevel@tonic-gate  *		only the first will be returned, though typically these
1029*0Sstevel@tonic-gate  *		lists are managed with non-overlapping nodes.
1030*0Sstevel@tonic-gate  *
1031*0Sstevel@tonic-gate  *		*The list MUST be sorted by offset for this function to work.*
1032*0Sstevel@tonic-gate  */
1033*0Sstevel@tonic-gate static sp_ext_node_t *
1034*0Sstevel@tonic-gate meta_sp_list_find(
1035*0Sstevel@tonic-gate 	sp_ext_node_t	*head,
1036*0Sstevel@tonic-gate 	sp_ext_offset_t	offset
1037*0Sstevel@tonic-gate )
1038*0Sstevel@tonic-gate {
1039*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next) {
1042*0Sstevel@tonic-gate 		/* check if the offset lies within this extent */
1043*0Sstevel@tonic-gate 		if ((offset >= ext->ext_offset) &&
1044*0Sstevel@tonic-gate 		    (offset < ext->ext_offset + ext->ext_length)) {
1045*0Sstevel@tonic-gate 			/*
1046*0Sstevel@tonic-gate 			 * the requested extent should always be a
1047*0Sstevel@tonic-gate 			 * subset of an extent in the list.
1048*0Sstevel@tonic-gate 			 */
1049*0Sstevel@tonic-gate 			return (ext);
1050*0Sstevel@tonic-gate 		}
1051*0Sstevel@tonic-gate 	}
1052*0Sstevel@tonic-gate 	return (NULL);
1053*0Sstevel@tonic-gate }
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate /*
1056*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_freefill()
1057*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
1058*0Sstevel@tonic-gate  *		size	- the size of the volume this extent list is
1059*0Sstevel@tonic-gate  *			  representing
1060*0Sstevel@tonic-gate  * OUTPUT:	head	- the new head of the list
1061*0Sstevel@tonic-gate  * RETURNS:	void
1062*0Sstevel@tonic-gate  * PURPOSE:	finds gaps in the extent list and fills them with a free
1063*0Sstevel@tonic-gate  *		node.  If there is a gap at the beginning the head
1064*0Sstevel@tonic-gate  *		pointer will be changed to point to the new free node.
1065*0Sstevel@tonic-gate  *		If there is free space at the end, the last free extent
1066*0Sstevel@tonic-gate  *		will extend all the way out to the size specified.
1067*0Sstevel@tonic-gate  *
1068*0Sstevel@tonic-gate  *		*The list MUST be sorted by offset for this function to work.*
1069*0Sstevel@tonic-gate  */
1070*0Sstevel@tonic-gate static void
1071*0Sstevel@tonic-gate meta_sp_list_freefill(
1072*0Sstevel@tonic-gate 	sp_ext_node_t	**head,
1073*0Sstevel@tonic-gate 	sp_ext_length_t	size
1074*0Sstevel@tonic-gate )
1075*0Sstevel@tonic-gate {
1076*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
1077*0Sstevel@tonic-gate 	sp_ext_offset_t	curoff = 0LL;
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 	for (ext = *head; ext != NULL; ext = ext->ext_next) {
1080*0Sstevel@tonic-gate 		if (curoff < ext->ext_offset)
1081*0Sstevel@tonic-gate 			meta_sp_list_insert(NULL, NULL, head,
1082*0Sstevel@tonic-gate 			    curoff, ext->ext_offset - curoff,
1083*0Sstevel@tonic-gate 			    EXTTYP_FREE, 0, 0, meta_sp_cmp_by_offset);
1084*0Sstevel@tonic-gate 		curoff = ext->ext_offset + ext->ext_length;
1085*0Sstevel@tonic-gate 	}
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	/* pad inverse list out to the end */
1088*0Sstevel@tonic-gate 	if (curoff < size)
1089*0Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, curoff, size - curoff,
1090*0Sstevel@tonic-gate 		    EXTTYP_FREE, 0, 0, meta_sp_cmp_by_offset);
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
1093*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_list_freefill: Extent list with "
1094*0Sstevel@tonic-gate 		    "holes freefilled:\n");
1095*0Sstevel@tonic-gate 		meta_sp_list_dump(*head);
1096*0Sstevel@tonic-gate 	}
1097*0Sstevel@tonic-gate }
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate /*
1100*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_dump()
1101*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
1102*0Sstevel@tonic-gate  * OUTPUT:	none
1103*0Sstevel@tonic-gate  * RETURNS:	void
1104*0Sstevel@tonic-gate  * PURPOSE:	dumps the entire extent list to stdout for easy debugging
1105*0Sstevel@tonic-gate  */
1106*0Sstevel@tonic-gate static void
1107*0Sstevel@tonic-gate meta_sp_list_dump(sp_ext_node_t *head)
1108*0Sstevel@tonic-gate {
1109*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate 	meta_sp_debug("meta_sp_list_dump: dumping extent list:\n");
1112*0Sstevel@tonic-gate 	meta_sp_debug("%5s %10s %5s %7s %10s %10s %5s %10s %10s\n", "Name",
1113*0Sstevel@tonic-gate 	    "Addr", "Seq#", "Type", "Offset", "Length", "Flags", "Prev",
1114*0Sstevel@tonic-gate 	    "Next");
1115*0Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next) {
1116*0Sstevel@tonic-gate 		if (ext->ext_namep != NULL)
1117*0Sstevel@tonic-gate 			meta_sp_debug("%5s", ext->ext_namep->cname);
1118*0Sstevel@tonic-gate 		else
1119*0Sstevel@tonic-gate 			meta_sp_debug("%5s", "NONE");
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 		meta_sp_debug("%10p %5u ", (void *) ext, ext->ext_seq);
1122*0Sstevel@tonic-gate 		switch (ext->ext_type) {
1123*0Sstevel@tonic-gate 		case EXTTYP_ALLOC:
1124*0Sstevel@tonic-gate 			meta_sp_debug("%7s ", "ALLOC");
1125*0Sstevel@tonic-gate 			break;
1126*0Sstevel@tonic-gate 		case EXTTYP_FREE:
1127*0Sstevel@tonic-gate 			meta_sp_debug("%7s ", "FREE");
1128*0Sstevel@tonic-gate 			break;
1129*0Sstevel@tonic-gate 		case EXTTYP_END:
1130*0Sstevel@tonic-gate 			meta_sp_debug("%7s ", "END");
1131*0Sstevel@tonic-gate 			break;
1132*0Sstevel@tonic-gate 		case EXTTYP_RESERVED:
1133*0Sstevel@tonic-gate 			meta_sp_debug("%7s ", "RESV");
1134*0Sstevel@tonic-gate 			break;
1135*0Sstevel@tonic-gate 		default:
1136*0Sstevel@tonic-gate 			meta_sp_debug("%7s ", "INVLD");
1137*0Sstevel@tonic-gate 			break;
1138*0Sstevel@tonic-gate 		}
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 		meta_sp_debug("%10llu %10llu %5u %10p %10p\n",
1141*0Sstevel@tonic-gate 		    ext->ext_offset, ext->ext_length,
1142*0Sstevel@tonic-gate 		    ext->ext_flags, (void *) ext->ext_prev,
1143*0Sstevel@tonic-gate 		    (void *) ext->ext_next);
1144*0Sstevel@tonic-gate 	}
1145*0Sstevel@tonic-gate 	meta_sp_debug("\n");
1146*0Sstevel@tonic-gate }
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate /*
1149*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_overlaps()
1150*0Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
1151*0Sstevel@tonic-gate  * OUTPUT:	none
1152*0Sstevel@tonic-gate  * RETURNS:	int	- 1 if extents overlap, 0 if ok
1153*0Sstevel@tonic-gate  * PURPOSE:	checks a list for overlaps.  The list MUST be sorted by
1154*0Sstevel@tonic-gate  *		offset for this function to work properly.
1155*0Sstevel@tonic-gate  */
1156*0Sstevel@tonic-gate static int
1157*0Sstevel@tonic-gate meta_sp_list_overlaps(sp_ext_node_t *head)
1158*0Sstevel@tonic-gate {
1159*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate 	for (ext = head; ext->ext_next != NULL; ext = ext->ext_next) {
1162*0Sstevel@tonic-gate 		if (ext->ext_offset + ext->ext_length >
1163*0Sstevel@tonic-gate 		    ext->ext_next->ext_offset)
1164*0Sstevel@tonic-gate 			return (1);
1165*0Sstevel@tonic-gate 	}
1166*0Sstevel@tonic-gate 	return (0);
1167*0Sstevel@tonic-gate }
1168*0Sstevel@tonic-gate 
1169*0Sstevel@tonic-gate /*
1170*0Sstevel@tonic-gate  * **************************************************************************
1171*0Sstevel@tonic-gate  *                        Extent Allocation Functions                       *
1172*0Sstevel@tonic-gate  * **************************************************************************
1173*0Sstevel@tonic-gate  */
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate /*
1176*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_ext()
1177*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
1178*0Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
1179*0Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
1180*0Sstevel@tonic-gate  *		free_ext	- the free extent being allocated from
1181*0Sstevel@tonic-gate  *		alloc_offset	- the offset of the allocation
1182*0Sstevel@tonic-gate  *		alloc_len	- the length of the allocation
1183*0Sstevel@tonic-gate  *		seq		- the sequence number of the allocation
1184*0Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
1185*0Sstevel@tonic-gate  * RETURNS:	void
1186*0Sstevel@tonic-gate  * PURPOSE:	allocates a portion of the free extent free_ext.  The
1187*0Sstevel@tonic-gate  *		allocated portion starts at alloc_offset and is
1188*0Sstevel@tonic-gate  *		alloc_length long.  Both (alloc_offset) and (alloc_offset +
1189*0Sstevel@tonic-gate  *		alloc_length) must be contained within the free extent.
1190*0Sstevel@tonic-gate  *
1191*0Sstevel@tonic-gate  *		The free extent is split into as many as 3 pieces - a
1192*0Sstevel@tonic-gate  *		free extent containing [ free_offset .. alloc_offset ), an
1193*0Sstevel@tonic-gate  *		allocated extent containing the range [ alloc_offset ..
1194*0Sstevel@tonic-gate  *		alloc_end ], and another free extent containing the
1195*0Sstevel@tonic-gate  *		range ( alloc_end .. free_end ].  If either of the two
1196*0Sstevel@tonic-gate  *		new free extents would be zero length, they are not created.
1197*0Sstevel@tonic-gate  *
1198*0Sstevel@tonic-gate  *		Finally, the original free extent is removed.  All newly
1199*0Sstevel@tonic-gate  *		created extents have the EXTFLG_UPDATE flag set.
1200*0Sstevel@tonic-gate  */
1201*0Sstevel@tonic-gate static void
1202*0Sstevel@tonic-gate meta_sp_alloc_by_ext(
1203*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1204*0Sstevel@tonic-gate 	mdname_t	*np,
1205*0Sstevel@tonic-gate 	sp_ext_node_t	**head,
1206*0Sstevel@tonic-gate 	sp_ext_node_t	*free_ext,
1207*0Sstevel@tonic-gate 	sp_ext_offset_t	alloc_offset,
1208*0Sstevel@tonic-gate 	sp_ext_length_t	alloc_length,
1209*0Sstevel@tonic-gate 	uint_t		seq
1210*0Sstevel@tonic-gate )
1211*0Sstevel@tonic-gate {
1212*0Sstevel@tonic-gate 	sp_ext_offset_t	free_offset = free_ext->ext_offset;
1213*0Sstevel@tonic-gate 	sp_ext_length_t	free_length = free_ext->ext_length;
1214*0Sstevel@tonic-gate 
1215*0Sstevel@tonic-gate 	sp_ext_offset_t	alloc_end = alloc_offset + alloc_length;
1216*0Sstevel@tonic-gate 	sp_ext_offset_t	free_end  = free_offset  + free_length;
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	/* allocated extent must be a subset of the free extent */
1219*0Sstevel@tonic-gate 	assert(free_offset <= alloc_offset);
1220*0Sstevel@tonic-gate 	assert(free_end >= alloc_end);
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate 	meta_sp_list_remove(head, free_ext);
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	if (free_offset < alloc_offset) {
1225*0Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, free_offset,
1226*0Sstevel@tonic-gate 		    (alloc_offset - free_offset), EXTTYP_FREE, 0,
1227*0Sstevel@tonic-gate 		    EXTFLG_UPDATE, meta_sp_cmp_by_offset);
1228*0Sstevel@tonic-gate 	}
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 	if (free_end > alloc_end) {
1231*0Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, alloc_end,
1232*0Sstevel@tonic-gate 		    (free_end - alloc_end), EXTTYP_FREE, 0, EXTFLG_UPDATE,
1233*0Sstevel@tonic-gate 		    meta_sp_cmp_by_offset);
1234*0Sstevel@tonic-gate 	}
1235*0Sstevel@tonic-gate 
1236*0Sstevel@tonic-gate 	meta_sp_list_insert(sp, np, head, alloc_offset, alloc_length,
1237*0Sstevel@tonic-gate 	    EXTTYP_ALLOC, seq, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
1240*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_ext: extent list:\n");
1241*0Sstevel@tonic-gate 		meta_sp_list_dump(*head);
1242*0Sstevel@tonic-gate 	}
1243*0Sstevel@tonic-gate }
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate /*
1246*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_len()
1247*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
1248*0Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
1249*0Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
1250*0Sstevel@tonic-gate  *		*lp	- the requested length to allocate
1251*0Sstevel@tonic-gate  *		last_off	- the last offset already allocated.
1252*0Sstevel@tonic-gate  *		alignment	- the desired extent alignmeent
1253*0Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
1254*0Sstevel@tonic-gate  *		*lp	- the length allocated
1255*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, the number of new extents on success
1256*0Sstevel@tonic-gate  * PURPOSE:	allocates extents from free space to satisfy the requested
1257*0Sstevel@tonic-gate  *		length.  If requested length is zero, allocates all
1258*0Sstevel@tonic-gate  *		remaining free space.  This function provides the meat
1259*0Sstevel@tonic-gate  *		of the extent allocation algorithm.  Allocation is a
1260*0Sstevel@tonic-gate  *		three tier process:
1261*0Sstevel@tonic-gate  *
1262*0Sstevel@tonic-gate  *		1. If last_off is nonzero and there is free space following
1263*0Sstevel@tonic-gate  *		   that node, then it is extended to allocate as much of that
1264*0Sstevel@tonic-gate  *		   free space as possible.  This is useful for metattach.
1265*0Sstevel@tonic-gate  *		2. If a free extent can be found to satisfy the remaining
1266*0Sstevel@tonic-gate  *		   requested space, then satisfy the rest of the request
1267*0Sstevel@tonic-gate  *		   from that extent.
1268*0Sstevel@tonic-gate  *		3. Start allocating space from any remaining free extents until
1269*0Sstevel@tonic-gate  *		   the remainder of the request is satisified.
1270*0Sstevel@tonic-gate  *
1271*0Sstevel@tonic-gate  *              If alignment is non-zero, then every extent modified
1272*0Sstevel@tonic-gate  *              or newly allocated will be aligned modulo alignment,
1273*0Sstevel@tonic-gate  *              with a length that is an integer multiple of
1274*0Sstevel@tonic-gate  *              alignment.
1275*0Sstevel@tonic-gate  *
1276*0Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is set for all nodes (free and
1277*0Sstevel@tonic-gate  *		allocated) that require updated watermarks.
1278*0Sstevel@tonic-gate  *
1279*0Sstevel@tonic-gate  *		This algorithm may have a negative impact on fragmentation
1280*0Sstevel@tonic-gate  *		in pathological cases and may be improved if it turns out
1281*0Sstevel@tonic-gate  *		to be a problem.  This may be exacerbated by particularly
1282*0Sstevel@tonic-gate  *		large alignments.
1283*0Sstevel@tonic-gate  *
1284*0Sstevel@tonic-gate  * NOTE:	It's confusing, so it demands an explanation:
1285*0Sstevel@tonic-gate  *		- len is used to represent requested data space; it
1286*0Sstevel@tonic-gate  *		  does not include room for a watermark.  On each full
1287*0Sstevel@tonic-gate  *		  or partial allocation, len will be decremented by
1288*0Sstevel@tonic-gate  *		  alloc_len (see next paragraph) until it reaches
1289*0Sstevel@tonic-gate  *		  zero.
1290*0Sstevel@tonic-gate  *		- alloc_len is used to represent data space allocated
1291*0Sstevel@tonic-gate  *		  from a particular extent; it does not include space
1292*0Sstevel@tonic-gate  *		  for a watermark.  In the rare event that a_length
1293*0Sstevel@tonic-gate  *		  (see next paragraph) is equal to MD_SP_WMSIZE,
1294*0Sstevel@tonic-gate  *		  alloc_len will be zero and the resulting MD_SP_WMSIZE
1295*0Sstevel@tonic-gate  *		  fragment of space will be utterly unusable.
1296*0Sstevel@tonic-gate  *		- a_length is used to represent all space to be
1297*0Sstevel@tonic-gate  *		  allocated from a particular extent; it DOES include
1298*0Sstevel@tonic-gate  *		  space for a watermark.
1299*0Sstevel@tonic-gate  */
1300*0Sstevel@tonic-gate static int
1301*0Sstevel@tonic-gate meta_sp_alloc_by_len(
1302*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1303*0Sstevel@tonic-gate 	mdname_t	*np,
1304*0Sstevel@tonic-gate 	sp_ext_node_t	**head,
1305*0Sstevel@tonic-gate 	sp_ext_length_t	*lp,
1306*0Sstevel@tonic-gate 	sp_ext_offset_t	last_off,
1307*0Sstevel@tonic-gate 	sp_ext_offset_t	alignment
1308*0Sstevel@tonic-gate )
1309*0Sstevel@tonic-gate {
1310*0Sstevel@tonic-gate 	sp_ext_node_t	*free_ext;
1311*0Sstevel@tonic-gate 	sp_ext_node_t	*alloc_ext;
1312*0Sstevel@tonic-gate 	uint_t		last_seq = 0;
1313*0Sstevel@tonic-gate 	uint_t		numexts = 0;
1314*0Sstevel@tonic-gate 	sp_ext_length_t	freespace;
1315*0Sstevel@tonic-gate 	sp_ext_length_t	alloc_len;
1316*0Sstevel@tonic-gate 	sp_ext_length_t	len;
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate 	/* We're DOA if we can't read *lp */
1319*0Sstevel@tonic-gate 	assert(lp != NULL);
1320*0Sstevel@tonic-gate 	len = *lp;
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 	/*
1323*0Sstevel@tonic-gate 	 * Process the nominal case first: we've been given an actual
1324*0Sstevel@tonic-gate 	 * size argument, rather than the literal "all"
1325*0Sstevel@tonic-gate 	 */
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	if (len != 0) {
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 		/*
1330*0Sstevel@tonic-gate 		 * Short circuit the check for free space.  This may
1331*0Sstevel@tonic-gate 		 * tell us we have enough space when we really don't
1332*0Sstevel@tonic-gate 		 * because each extent loses space to a watermark, but
1333*0Sstevel@tonic-gate 		 * it will always tell us there isn't enough space
1334*0Sstevel@tonic-gate 		 * correctly.  Worst case we do some extra work.
1335*0Sstevel@tonic-gate 		 */
1336*0Sstevel@tonic-gate 		freespace = meta_sp_list_size(*head, EXTTYP_FREE,
1337*0Sstevel@tonic-gate 		    INCLUDE_WM);
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 		if (freespace < len)
1340*0Sstevel@tonic-gate 			return (-1);
1341*0Sstevel@tonic-gate 
1342*0Sstevel@tonic-gate 		/*
1343*0Sstevel@tonic-gate 		 * First see if we can extend the last extent for an
1344*0Sstevel@tonic-gate 		 * attach.
1345*0Sstevel@tonic-gate 		 */
1346*0Sstevel@tonic-gate 		if (last_off != 0LL) {
1347*0Sstevel@tonic-gate 			int align = 0;
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 			alloc_ext =
1350*0Sstevel@tonic-gate 			    meta_sp_list_find(*head, last_off);
1351*0Sstevel@tonic-gate 			assert(alloc_ext != NULL);
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 			/*
1354*0Sstevel@tonic-gate 			 * The offset test reflects the
1355*0Sstevel@tonic-gate 			 * inclusion of the watermark in the extent
1356*0Sstevel@tonic-gate 			 */
1357*0Sstevel@tonic-gate 			align = (alignment > 0) &&
1358*0Sstevel@tonic-gate 			    (((alloc_ext->ext_offset + MD_SP_WMSIZE) %
1359*0Sstevel@tonic-gate 				alignment) == 0);
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 			/*
1362*0Sstevel@tonic-gate 			 * If we decided not to align here, we should
1363*0Sstevel@tonic-gate 			 * also reset "alignment" so we don't bother
1364*0Sstevel@tonic-gate 			 * later, either.
1365*0Sstevel@tonic-gate 			 */
1366*0Sstevel@tonic-gate 			if (!align) {
1367*0Sstevel@tonic-gate 				alignment = 0;
1368*0Sstevel@tonic-gate 			}
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate 			last_seq = alloc_ext->ext_seq;
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate 			free_ext = meta_sp_list_find(*head,
1373*0Sstevel@tonic-gate 			    alloc_ext->ext_offset +
1374*0Sstevel@tonic-gate 			    alloc_ext->ext_length);
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate 			/*
1377*0Sstevel@tonic-gate 			 * If a free extent follows our last allocated
1378*0Sstevel@tonic-gate 			 * extent, then remove the last allocated
1379*0Sstevel@tonic-gate 			 * extent and increase the size of the free
1380*0Sstevel@tonic-gate 			 * extent to overlap it, then allocate the
1381*0Sstevel@tonic-gate 			 * total space from the new free extent.
1382*0Sstevel@tonic-gate 			 */
1383*0Sstevel@tonic-gate 			if (free_ext != NULL &&
1384*0Sstevel@tonic-gate 			    free_ext->ext_type == EXTTYP_FREE) {
1385*0Sstevel@tonic-gate 				assert(free_ext->ext_offset ==
1386*0Sstevel@tonic-gate 				    alloc_ext->ext_offset +
1387*0Sstevel@tonic-gate 				    alloc_ext->ext_length);
1388*0Sstevel@tonic-gate 
1389*0Sstevel@tonic-gate 				alloc_len =
1390*0Sstevel@tonic-gate 				    MIN(len, free_ext->ext_length);
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate 				if (align && (alloc_len < len)) {
1393*0Sstevel@tonic-gate 					/* No watermark space needed */
1394*0Sstevel@tonic-gate 					alloc_len -= alloc_len % alignment;
1395*0Sstevel@tonic-gate 				}
1396*0Sstevel@tonic-gate 
1397*0Sstevel@tonic-gate 				if (alloc_len > 0) {
1398*0Sstevel@tonic-gate 					free_ext->ext_offset -=
1399*0Sstevel@tonic-gate 					    alloc_ext->ext_length;
1400*0Sstevel@tonic-gate 					free_ext->ext_length +=
1401*0Sstevel@tonic-gate 					    alloc_ext->ext_length;
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 					meta_sp_alloc_by_ext(sp, np, head,
1404*0Sstevel@tonic-gate 					    free_ext, free_ext->ext_offset,
1405*0Sstevel@tonic-gate 					    alloc_ext->ext_length + alloc_len,
1406*0Sstevel@tonic-gate 					    last_seq);
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 					/*
1409*0Sstevel@tonic-gate 					 * now remove the original allocated
1410*0Sstevel@tonic-gate 					 * node.  We may have overlapping
1411*0Sstevel@tonic-gate 					 * extents for a short time before
1412*0Sstevel@tonic-gate 					 * this node is removed.
1413*0Sstevel@tonic-gate 					 */
1414*0Sstevel@tonic-gate 					meta_sp_list_remove(head, alloc_ext);
1415*0Sstevel@tonic-gate 					len -= alloc_len;
1416*0Sstevel@tonic-gate 				}
1417*0Sstevel@tonic-gate 			}
1418*0Sstevel@tonic-gate 			last_seq++;
1419*0Sstevel@tonic-gate 		}
1420*0Sstevel@tonic-gate 
1421*0Sstevel@tonic-gate 		if (len == 0LL)
1422*0Sstevel@tonic-gate 			goto out;
1423*0Sstevel@tonic-gate 
1424*0Sstevel@tonic-gate 		/*
1425*0Sstevel@tonic-gate 		 * Next, see if we can find a single allocation for
1426*0Sstevel@tonic-gate 		 * the remainder.  This may make fragmentation worse
1427*0Sstevel@tonic-gate 		 * in some cases, but there's no good way to allocate
1428*0Sstevel@tonic-gate 		 * that doesn't have a highly fragmented corner case.
1429*0Sstevel@tonic-gate 		 */
1430*0Sstevel@tonic-gate 		for (free_ext = *head; free_ext != NULL;
1431*0Sstevel@tonic-gate 			free_ext = free_ext->ext_next) {
1432*0Sstevel@tonic-gate 			sp_ext_offset_t	a_offset;
1433*0Sstevel@tonic-gate 			sp_ext_offset_t	a_length;
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 			if (free_ext->ext_type != EXTTYP_FREE)
1436*0Sstevel@tonic-gate 				continue;
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate 			/*
1439*0Sstevel@tonic-gate 			 * The length test should include space for
1440*0Sstevel@tonic-gate 			 * the watermark
1441*0Sstevel@tonic-gate 			 */
1442*0Sstevel@tonic-gate 
1443*0Sstevel@tonic-gate 			a_offset = free_ext->ext_offset;
1444*0Sstevel@tonic-gate 			a_length = free_ext->ext_length;
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 			if (alignment > 0) {
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate 				/*
1449*0Sstevel@tonic-gate 				 * Shortcut for extents that have been
1450*0Sstevel@tonic-gate 				 * previously added to pad out the
1451*0Sstevel@tonic-gate 				 * data space
1452*0Sstevel@tonic-gate 				 */
1453*0Sstevel@tonic-gate 				if (a_length < alignment) {
1454*0Sstevel@tonic-gate 					continue;
1455*0Sstevel@tonic-gate 				}
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 				/*
1458*0Sstevel@tonic-gate 				 * Round up so the data space begins
1459*0Sstevel@tonic-gate 				 * on a properly aligned boundary.
1460*0Sstevel@tonic-gate 				 */
1461*0Sstevel@tonic-gate 				a_offset += alignment -
1462*0Sstevel@tonic-gate 				    (a_offset % alignment) - MD_SP_WMSIZE;
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 				/*
1465*0Sstevel@tonic-gate 				 * This is only necessary in case the
1466*0Sstevel@tonic-gate 				 * watermark size is ever greater than
1467*0Sstevel@tonic-gate 				 * one.  It'll never happen, of
1468*0Sstevel@tonic-gate 				 * course; we'll get rid of watermarks
1469*0Sstevel@tonic-gate 				 * before we make 'em bigger.
1470*0Sstevel@tonic-gate 				 */
1471*0Sstevel@tonic-gate 				if (a_offset < free_ext->ext_offset) {
1472*0Sstevel@tonic-gate 					a_offset += alignment;
1473*0Sstevel@tonic-gate 				}
1474*0Sstevel@tonic-gate 
1475*0Sstevel@tonic-gate 				/*
1476*0Sstevel@tonic-gate 				 * Adjust the length to account for
1477*0Sstevel@tonic-gate 				 * the space lost above (if any)
1478*0Sstevel@tonic-gate 				 */
1479*0Sstevel@tonic-gate 				a_length -=
1480*0Sstevel@tonic-gate 					(a_offset - free_ext->ext_offset);
1481*0Sstevel@tonic-gate 			}
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate 			if (a_length >= len + MD_SP_WMSIZE) {
1484*0Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
1485*0Sstevel@tonic-gate 					free_ext, a_offset,
1486*0Sstevel@tonic-gate 					len + MD_SP_WMSIZE, last_seq);
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 				len = 0LL;
1489*0Sstevel@tonic-gate 				numexts++;
1490*0Sstevel@tonic-gate 				break;
1491*0Sstevel@tonic-gate 			}
1492*0Sstevel@tonic-gate 		}
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate 		if (len == 0LL)
1495*0Sstevel@tonic-gate 			goto out;
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate 		/*
1499*0Sstevel@tonic-gate 		 * If the request could not be satisfied by extending
1500*0Sstevel@tonic-gate 		 * the last extent or by a single extent, then put
1501*0Sstevel@tonic-gate 		 * multiple smaller extents together until the request
1502*0Sstevel@tonic-gate 		 * is satisfied.
1503*0Sstevel@tonic-gate 		 */
1504*0Sstevel@tonic-gate 		for (free_ext = *head; (free_ext != NULL) && (len > 0);
1505*0Sstevel@tonic-gate 			free_ext = free_ext->ext_next) {
1506*0Sstevel@tonic-gate 			sp_ext_offset_t a_offset;
1507*0Sstevel@tonic-gate 			sp_ext_length_t a_length;
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate 			if (free_ext->ext_type != EXTTYP_FREE)
1510*0Sstevel@tonic-gate 				continue;
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate 			a_offset = free_ext->ext_offset;
1513*0Sstevel@tonic-gate 			a_length = free_ext->ext_length;
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 			if (alignment > 0) {
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 				/*
1518*0Sstevel@tonic-gate 				 * Shortcut for extents that have been
1519*0Sstevel@tonic-gate 				 * previously added to pad out the
1520*0Sstevel@tonic-gate 				 * data space
1521*0Sstevel@tonic-gate 				 */
1522*0Sstevel@tonic-gate 				if (a_length < alignment) {
1523*0Sstevel@tonic-gate 					continue;
1524*0Sstevel@tonic-gate 				}
1525*0Sstevel@tonic-gate 
1526*0Sstevel@tonic-gate 				/*
1527*0Sstevel@tonic-gate 				 * Round up so the data space begins
1528*0Sstevel@tonic-gate 				 * on a properly aligned boundary.
1529*0Sstevel@tonic-gate 				 */
1530*0Sstevel@tonic-gate 				a_offset += alignment -
1531*0Sstevel@tonic-gate 					(a_offset % alignment) - MD_SP_WMSIZE;
1532*0Sstevel@tonic-gate 
1533*0Sstevel@tonic-gate 				/*
1534*0Sstevel@tonic-gate 				 * This is only necessary in case the
1535*0Sstevel@tonic-gate 				 * watermark size is ever greater than
1536*0Sstevel@tonic-gate 				 * one.  It'll never happen, of
1537*0Sstevel@tonic-gate 				 * course; we'll get rid of watermarks
1538*0Sstevel@tonic-gate 				 * before we make 'em bigger.
1539*0Sstevel@tonic-gate 				 */
1540*0Sstevel@tonic-gate 				if (a_offset < free_ext->ext_offset) {
1541*0Sstevel@tonic-gate 					a_offset += alignment;
1542*0Sstevel@tonic-gate 				}
1543*0Sstevel@tonic-gate 
1544*0Sstevel@tonic-gate 				/*
1545*0Sstevel@tonic-gate 				 * Adjust the length to account for
1546*0Sstevel@tonic-gate 				 * the space lost above (if any)
1547*0Sstevel@tonic-gate 				 */
1548*0Sstevel@tonic-gate 				a_length -=
1549*0Sstevel@tonic-gate 					(a_offset - free_ext->ext_offset);
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 				/*
1552*0Sstevel@tonic-gate 				 * Adjust the length to be properly
1553*0Sstevel@tonic-gate 				 * aligned if it is NOT to be the
1554*0Sstevel@tonic-gate 				 * last extent in the soft partition.
1555*0Sstevel@tonic-gate 				 */
1556*0Sstevel@tonic-gate 				if ((a_length - MD_SP_WMSIZE) < len)
1557*0Sstevel@tonic-gate 					a_length -=
1558*0Sstevel@tonic-gate 						(a_length - MD_SP_WMSIZE)
1559*0Sstevel@tonic-gate 						% alignment;
1560*0Sstevel@tonic-gate 			}
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate 			alloc_len = MIN(len, a_length - MD_SP_WMSIZE);
1563*0Sstevel@tonic-gate 			if (alloc_len == 0)
1564*0Sstevel@tonic-gate 				continue;
1565*0Sstevel@tonic-gate 
1566*0Sstevel@tonic-gate 			/*
1567*0Sstevel@tonic-gate 			 * meta_sp_alloc_by_ext() expects the
1568*0Sstevel@tonic-gate 			 * allocation length to include the watermark
1569*0Sstevel@tonic-gate 			 * size, which is why we don't simply pass in
1570*0Sstevel@tonic-gate 			 * alloc_len here.
1571*0Sstevel@tonic-gate 			 */
1572*0Sstevel@tonic-gate 			meta_sp_alloc_by_ext(sp, np, head, free_ext,
1573*0Sstevel@tonic-gate 				a_offset, MIN(len + MD_SP_WMSIZE, a_length),
1574*0Sstevel@tonic-gate 				last_seq);
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 			len -= alloc_len;
1577*0Sstevel@tonic-gate 			numexts++;
1578*0Sstevel@tonic-gate 			last_seq++;
1579*0Sstevel@tonic-gate 		}
1580*0Sstevel@tonic-gate 
1581*0Sstevel@tonic-gate 
1582*0Sstevel@tonic-gate 		/*
1583*0Sstevel@tonic-gate 		 * If there was not enough space we can throw it all
1584*0Sstevel@tonic-gate 		 * away since no real work has been done yet.
1585*0Sstevel@tonic-gate 		 */
1586*0Sstevel@tonic-gate 		if (len != 0) {
1587*0Sstevel@tonic-gate 			meta_sp_list_free(head);
1588*0Sstevel@tonic-gate 			return (-1);
1589*0Sstevel@tonic-gate 		}
1590*0Sstevel@tonic-gate 	}
1591*0Sstevel@tonic-gate 
1592*0Sstevel@tonic-gate 	/*
1593*0Sstevel@tonic-gate 	 * Otherwise, the literal "all" was specified: allocate all
1594*0Sstevel@tonic-gate 	 * available free space.  Don't bother with alignment.
1595*0Sstevel@tonic-gate 	 */
1596*0Sstevel@tonic-gate 	else {
1597*0Sstevel@tonic-gate 		/* First, extend the last extent if this is a grow */
1598*0Sstevel@tonic-gate 		if (last_off != 0LL) {
1599*0Sstevel@tonic-gate 			alloc_ext =
1600*0Sstevel@tonic-gate 				meta_sp_list_find(*head, last_off);
1601*0Sstevel@tonic-gate 			assert(alloc_ext != NULL);
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 			last_seq = alloc_ext->ext_seq;
1604*0Sstevel@tonic-gate 
1605*0Sstevel@tonic-gate 			free_ext = meta_sp_list_find(*head,
1606*0Sstevel@tonic-gate 				alloc_ext->ext_offset +
1607*0Sstevel@tonic-gate 				alloc_ext->ext_length);
1608*0Sstevel@tonic-gate 
1609*0Sstevel@tonic-gate 			/*
1610*0Sstevel@tonic-gate 			 * If a free extent follows our last allocated
1611*0Sstevel@tonic-gate 			 * extent, then remove the last allocated
1612*0Sstevel@tonic-gate 			 * extent and increase the size of the free
1613*0Sstevel@tonic-gate 			 * extent to overlap it, then allocate the
1614*0Sstevel@tonic-gate 			 * total space from the new free extent.
1615*0Sstevel@tonic-gate 			 */
1616*0Sstevel@tonic-gate 			if (free_ext != NULL &&
1617*0Sstevel@tonic-gate 			    free_ext->ext_type == EXTTYP_FREE) {
1618*0Sstevel@tonic-gate 				assert(free_ext->ext_offset ==
1619*0Sstevel@tonic-gate 				    alloc_ext->ext_offset +
1620*0Sstevel@tonic-gate 				    alloc_ext->ext_length);
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate 				len = alloc_len =
1623*0Sstevel@tonic-gate 				    free_ext->ext_length;
1624*0Sstevel@tonic-gate 
1625*0Sstevel@tonic-gate 				free_ext->ext_offset -=
1626*0Sstevel@tonic-gate 				    alloc_ext->ext_length;
1627*0Sstevel@tonic-gate 				free_ext->ext_length +=
1628*0Sstevel@tonic-gate 				    alloc_ext->ext_length;
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
1631*0Sstevel@tonic-gate 				    free_ext, free_ext->ext_offset,
1632*0Sstevel@tonic-gate 				    alloc_ext->ext_length + alloc_len,
1633*0Sstevel@tonic-gate 				    last_seq);
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 				/*
1636*0Sstevel@tonic-gate 				 * now remove the original allocated
1637*0Sstevel@tonic-gate 				 * node.  We may have overlapping
1638*0Sstevel@tonic-gate 				 * extents for a short time before
1639*0Sstevel@tonic-gate 				 * this node is removed.
1640*0Sstevel@tonic-gate 				 */
1641*0Sstevel@tonic-gate 				meta_sp_list_remove(head, alloc_ext);
1642*0Sstevel@tonic-gate 			}
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 			last_seq++;
1645*0Sstevel@tonic-gate 		}
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 		/* Next, grab all remaining free space */
1648*0Sstevel@tonic-gate 		for (free_ext = *head; free_ext != NULL;
1649*0Sstevel@tonic-gate 			free_ext = free_ext->ext_next) {
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 			if (free_ext->ext_type == EXTTYP_FREE) {
1652*0Sstevel@tonic-gate 				alloc_len =
1653*0Sstevel@tonic-gate 				    free_ext->ext_length - MD_SP_WMSIZE;
1654*0Sstevel@tonic-gate 				if (alloc_len == 0)
1655*0Sstevel@tonic-gate 					continue;
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 				/*
1658*0Sstevel@tonic-gate 				 * meta_sp_alloc_by_ext() expects the
1659*0Sstevel@tonic-gate 				 * allocation length to include the
1660*0Sstevel@tonic-gate 				 * watermark size, which is why we
1661*0Sstevel@tonic-gate 				 * don't simply pass in alloc_len
1662*0Sstevel@tonic-gate 				 * here.
1663*0Sstevel@tonic-gate 				 */
1664*0Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
1665*0Sstevel@tonic-gate 				    free_ext, free_ext->ext_offset,
1666*0Sstevel@tonic-gate 				    free_ext->ext_length,
1667*0Sstevel@tonic-gate 				    last_seq);
1668*0Sstevel@tonic-gate 
1669*0Sstevel@tonic-gate 				len += alloc_len;
1670*0Sstevel@tonic-gate 				numexts++;
1671*0Sstevel@tonic-gate 				last_seq++;
1672*0Sstevel@tonic-gate 			}
1673*0Sstevel@tonic-gate 		}
1674*0Sstevel@tonic-gate 	}
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate out:
1677*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
1678*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_len: Extent list after "
1679*0Sstevel@tonic-gate 		    "allocation:\n");
1680*0Sstevel@tonic-gate 		meta_sp_list_dump(*head);
1681*0Sstevel@tonic-gate 	}
1682*0Sstevel@tonic-gate 
1683*0Sstevel@tonic-gate 	if (*lp == 0) {
1684*0Sstevel@tonic-gate 		*lp = len;
1685*0Sstevel@tonic-gate 
1686*0Sstevel@tonic-gate 		/*
1687*0Sstevel@tonic-gate 		 * Make sure the callers hit a no space error if we
1688*0Sstevel@tonic-gate 		 * didn't actually find anything.
1689*0Sstevel@tonic-gate 		 */
1690*0Sstevel@tonic-gate 		if (len == 0) {
1691*0Sstevel@tonic-gate 			return (-1);
1692*0Sstevel@tonic-gate 		}
1693*0Sstevel@tonic-gate 	}
1694*0Sstevel@tonic-gate 
1695*0Sstevel@tonic-gate 	return (numexts);
1696*0Sstevel@tonic-gate }
1697*0Sstevel@tonic-gate 
1698*0Sstevel@tonic-gate /*
1699*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_list()
1700*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
1701*0Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
1702*0Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
1703*0Sstevel@tonic-gate  *		oblist	- an extent list containing requested nodes to allocate
1704*0Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
1705*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, the number of new extents on success
1706*0Sstevel@tonic-gate  * PURPOSE:	allocates extents from free space to satisfy the requested
1707*0Sstevel@tonic-gate  *		extent list.  This is primarily used for the -o/-b options
1708*0Sstevel@tonic-gate  *		where the user may specifically request extents to allocate.
1709*0Sstevel@tonic-gate  *		Each extent in the oblist must be a subset (inclusive) of a
1710*0Sstevel@tonic-gate  *		free extent and may not overlap each other.  This
1711*0Sstevel@tonic-gate  *		function sets the EXTFLG_UPDATE flag for each node that
1712*0Sstevel@tonic-gate  *		requires a watermark update after allocating.
1713*0Sstevel@tonic-gate  */
1714*0Sstevel@tonic-gate static int
1715*0Sstevel@tonic-gate meta_sp_alloc_by_list(
1716*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1717*0Sstevel@tonic-gate 	mdname_t	*np,
1718*0Sstevel@tonic-gate 	sp_ext_node_t	**head,
1719*0Sstevel@tonic-gate 	sp_ext_node_t	*oblist
1720*0Sstevel@tonic-gate )
1721*0Sstevel@tonic-gate {
1722*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
1723*0Sstevel@tonic-gate 	sp_ext_node_t	*free_ext;
1724*0Sstevel@tonic-gate 	uint_t		numexts = 0;
1725*0Sstevel@tonic-gate 
1726*0Sstevel@tonic-gate 	for (ext = oblist; ext != NULL; ext = ext->ext_next) {
1727*0Sstevel@tonic-gate 
1728*0Sstevel@tonic-gate 		free_ext = meta_sp_list_find(*head,
1729*0Sstevel@tonic-gate 		    ext->ext_offset - MD_SP_WMSIZE);
1730*0Sstevel@tonic-gate 
1731*0Sstevel@tonic-gate 		/* Make sure the allocation is within the free extent */
1732*0Sstevel@tonic-gate 		if ((free_ext == NULL) ||
1733*0Sstevel@tonic-gate 		    (ext->ext_offset + ext->ext_length >
1734*0Sstevel@tonic-gate 		    free_ext->ext_offset + free_ext->ext_length) ||
1735*0Sstevel@tonic-gate 		    (free_ext->ext_type != EXTTYP_FREE))
1736*0Sstevel@tonic-gate 			return (-1);
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate 		meta_sp_alloc_by_ext(sp, np, head, free_ext,
1739*0Sstevel@tonic-gate 		    ext->ext_offset - MD_SP_WMSIZE,
1740*0Sstevel@tonic-gate 		    ext->ext_length + MD_SP_WMSIZE, ext->ext_seq);
1741*0Sstevel@tonic-gate 
1742*0Sstevel@tonic-gate 		numexts++;
1743*0Sstevel@tonic-gate 	}
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate 	assert(meta_sp_list_overlaps(*head) == 0);
1746*0Sstevel@tonic-gate 
1747*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
1748*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_list: Extent list after "
1749*0Sstevel@tonic-gate 		    "allocation:\n");
1750*0Sstevel@tonic-gate 		meta_sp_list_dump(*head);
1751*0Sstevel@tonic-gate 	}
1752*0Sstevel@tonic-gate 
1753*0Sstevel@tonic-gate 	return (numexts);
1754*0Sstevel@tonic-gate }
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate /*
1757*0Sstevel@tonic-gate  * **************************************************************************
1758*0Sstevel@tonic-gate  *                     Extent List Population Functions                     *
1759*0Sstevel@tonic-gate  * **************************************************************************
1760*0Sstevel@tonic-gate  */
1761*0Sstevel@tonic-gate 
1762*0Sstevel@tonic-gate /*
1763*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_extlist_from_namelist()
1764*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
1765*0Sstevel@tonic-gate  *		spnplp	- the namelist of soft partitions to build a list from
1766*0Sstevel@tonic-gate  * OUTPUT:	extlist	- the extent list built from the SPs in the namelist
1767*0Sstevel@tonic-gate  *		ep	- return error pointer
1768*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
1769*0Sstevel@tonic-gate  * PURPOSE:	builds an extent list representing the soft partitions
1770*0Sstevel@tonic-gate  *		specified in the namelist.  Each extent in each soft
1771*0Sstevel@tonic-gate  *		partition is added to the list with the type EXTTYP_ALLOC.
1772*0Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is not set on any nodes.  Each
1773*0Sstevel@tonic-gate  *		extent in the list includes the space occupied by the
1774*0Sstevel@tonic-gate  *		watermark, which is not included in the unit structures.
1775*0Sstevel@tonic-gate  */
1776*0Sstevel@tonic-gate static int
1777*0Sstevel@tonic-gate meta_sp_extlist_from_namelist(
1778*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1779*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp,
1780*0Sstevel@tonic-gate 	sp_ext_node_t	**extlist,
1781*0Sstevel@tonic-gate 	md_error_t	*ep
1782*0Sstevel@tonic-gate )
1783*0Sstevel@tonic-gate {
1784*0Sstevel@tonic-gate 	int		extn;
1785*0Sstevel@tonic-gate 	md_sp_t		*msp;		/* unit structure of the sp's */
1786*0Sstevel@tonic-gate 	mdnamelist_t	*namep;
1787*0Sstevel@tonic-gate 
1788*0Sstevel@tonic-gate 	assert(sp != NULL);
1789*0Sstevel@tonic-gate 
1790*0Sstevel@tonic-gate 	/*
1791*0Sstevel@tonic-gate 	 * Now go through the soft partitions and add a node to the used
1792*0Sstevel@tonic-gate 	 * list for each allocated extent.
1793*0Sstevel@tonic-gate 	 */
1794*0Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
1795*0Sstevel@tonic-gate 		mdname_t	*curnp = namep->namep;
1796*0Sstevel@tonic-gate 
1797*0Sstevel@tonic-gate 		/* get the unit structure */
1798*0Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
1799*0Sstevel@tonic-gate 			return (-1);
1800*0Sstevel@tonic-gate 
1801*0Sstevel@tonic-gate 		for (extn = 0; (extn < msp->ext.ext_len); extn++) {
1802*0Sstevel@tonic-gate 			md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 			/*
1805*0Sstevel@tonic-gate 			 * subtract from offset and add to the length
1806*0Sstevel@tonic-gate 			 * to account for the watermark, which is not
1807*0Sstevel@tonic-gate 			 * contained in the extents in the unit structure.
1808*0Sstevel@tonic-gate 			 */
1809*0Sstevel@tonic-gate 			meta_sp_list_insert(sp, curnp, extlist,
1810*0Sstevel@tonic-gate 			    extp->poff - MD_SP_WMSIZE, extp->len + MD_SP_WMSIZE,
1811*0Sstevel@tonic-gate 			    EXTTYP_ALLOC, extn, 0, meta_sp_cmp_by_offset);
1812*0Sstevel@tonic-gate 		}
1813*0Sstevel@tonic-gate 	}
1814*0Sstevel@tonic-gate 	return (0);
1815*0Sstevel@tonic-gate }
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate /*
1818*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_extlist_from_wm()
1819*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
1820*0Sstevel@tonic-gate  *		compnp	- the name of the device to scan watermarks on
1821*0Sstevel@tonic-gate  * OUTPUT:	extlist	- the extent list built from the SPs in the namelist
1822*0Sstevel@tonic-gate  *		ep	- return error pointer
1823*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
1824*0Sstevel@tonic-gate  * PURPOSE:	builds an extent list representing the soft partitions
1825*0Sstevel@tonic-gate  *		specified in the namelist.  Each extent in each soft
1826*0Sstevel@tonic-gate  *		partition is added to the list with the type EXTTYP_ALLOC.
1827*0Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is not set on any nodes.  Each
1828*0Sstevel@tonic-gate  *		extent in the list includes the space occupied by the
1829*0Sstevel@tonic-gate  *		watermark, which is not included in the unit structures.
1830*0Sstevel@tonic-gate  */
1831*0Sstevel@tonic-gate static int
1832*0Sstevel@tonic-gate meta_sp_extlist_from_wm(
1833*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1834*0Sstevel@tonic-gate 	mdname_t	*compnp,
1835*0Sstevel@tonic-gate 	sp_ext_node_t	**extlist,
1836*0Sstevel@tonic-gate 	ext_cmpfunc_t	compare,
1837*0Sstevel@tonic-gate 	md_error_t	*ep
1838*0Sstevel@tonic-gate )
1839*0Sstevel@tonic-gate {
1840*0Sstevel@tonic-gate 	mp_watermark_t	wm;
1841*0Sstevel@tonic-gate 	mdname_t	*np = NULL;
1842*0Sstevel@tonic-gate 	mdsetname_t	*spsetp = NULL;
1843*0Sstevel@tonic-gate 	sp_ext_offset_t	cur_off;
1844*0Sstevel@tonic-gate 
1845*0Sstevel@tonic-gate 	if ((cur_off = meta_sp_get_start(sp, compnp, ep)) == MD_DISKADDR_ERROR)
1846*0Sstevel@tonic-gate 		return (-1);
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 	for (;;) {
1849*0Sstevel@tonic-gate 		if (meta_sp_read_wm(sp, compnp, &wm, cur_off, ep) != 0) {
1850*0Sstevel@tonic-gate 			return (-1);
1851*0Sstevel@tonic-gate 		}
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate 		/* get the set and name pointers */
1854*0Sstevel@tonic-gate 		if (strcmp(wm.wm_setname, MD_SP_LOCALSETNAME) != 0) {
1855*0Sstevel@tonic-gate 			if ((spsetp = metasetname(wm.wm_setname, ep)) == NULL) {
1856*0Sstevel@tonic-gate 				return (-1);
1857*0Sstevel@tonic-gate 			}
1858*0Sstevel@tonic-gate 		}
1859*0Sstevel@tonic-gate 
1860*0Sstevel@tonic-gate 		if (strcmp(wm.wm_mdname, MD_SP_FREEWMNAME) != 0) {
1861*0Sstevel@tonic-gate 			if (meta_init_make_device(&sp, wm.wm_mdname, ep) != 0)
1862*0Sstevel@tonic-gate 				return (-1);
1863*0Sstevel@tonic-gate 			np = metaname(&spsetp, wm.wm_mdname, ep);
1864*0Sstevel@tonic-gate 			if (np == NULL) {
1865*0Sstevel@tonic-gate 				return (-1);
1866*0Sstevel@tonic-gate 			}
1867*0Sstevel@tonic-gate 		}
1868*0Sstevel@tonic-gate 
1869*0Sstevel@tonic-gate 		/* insert watermark into extent list */
1870*0Sstevel@tonic-gate 		meta_sp_list_insert(spsetp, np, extlist, cur_off,
1871*0Sstevel@tonic-gate 		    wm.wm_length + MD_SP_WMSIZE, wm.wm_type, wm.wm_seq,
1872*0Sstevel@tonic-gate 		    EXTFLG_UPDATE, compare);
1873*0Sstevel@tonic-gate 
1874*0Sstevel@tonic-gate 		/* if we see the end watermark, we're done */
1875*0Sstevel@tonic-gate 		if (wm.wm_type == EXTTYP_END)
1876*0Sstevel@tonic-gate 			break;
1877*0Sstevel@tonic-gate 
1878*0Sstevel@tonic-gate 		cur_off += wm.wm_length + 1;
1879*0Sstevel@tonic-gate 
1880*0Sstevel@tonic-gate 		/* clear out set and name pointers for next iteration */
1881*0Sstevel@tonic-gate 		np = NULL;
1882*0Sstevel@tonic-gate 		spsetp = NULL;
1883*0Sstevel@tonic-gate 	}
1884*0Sstevel@tonic-gate 
1885*0Sstevel@tonic-gate 	return (0);
1886*0Sstevel@tonic-gate }
1887*0Sstevel@tonic-gate 
1888*0Sstevel@tonic-gate /*
1889*0Sstevel@tonic-gate  * **************************************************************************
1890*0Sstevel@tonic-gate  *                        Print (metastat) Functions                        *
1891*0Sstevel@tonic-gate  * **************************************************************************
1892*0Sstevel@tonic-gate  */
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate /*
1895*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_short_print()
1896*0Sstevel@tonic-gate  * INPUT:	msp	- the unit structure to display
1897*0Sstevel@tonic-gate  *		fp	- the file pointer to send output to
1898*0Sstevel@tonic-gate  *		options	- print options from the command line processor
1899*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
1900*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
1901*0Sstevel@tonic-gate  * PURPOSE:	display a short report of the soft partition in md.tab
1902*0Sstevel@tonic-gate  *		form, primarily used for metastat -p.
1903*0Sstevel@tonic-gate  */
1904*0Sstevel@tonic-gate static int
1905*0Sstevel@tonic-gate meta_sp_short_print(
1906*0Sstevel@tonic-gate 	md_sp_t		*msp,
1907*0Sstevel@tonic-gate 	char		*fname,
1908*0Sstevel@tonic-gate 	FILE		*fp,
1909*0Sstevel@tonic-gate 	mdprtopts_t	options,
1910*0Sstevel@tonic-gate 	md_error_t	*ep
1911*0Sstevel@tonic-gate )
1912*0Sstevel@tonic-gate {
1913*0Sstevel@tonic-gate 	int	extn;
1914*0Sstevel@tonic-gate 
1915*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
1916*0Sstevel@tonic-gate 		if (msp->common.revision != MD_64BIT_META_DEV)
1917*0Sstevel@tonic-gate 			return (0);
1918*0Sstevel@tonic-gate 	}
1919*0Sstevel@tonic-gate 
1920*0Sstevel@tonic-gate 	/* print name and -p */
1921*0Sstevel@tonic-gate 	if (fprintf(fp, "%s -p", msp->common.namep->cname) == EOF)
1922*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
1923*0Sstevel@tonic-gate 
1924*0Sstevel@tonic-gate 	/* print the component */
1925*0Sstevel@tonic-gate 	/*
1926*0Sstevel@tonic-gate 	 * If the path is our standard /dev/rdsk or /dev/md/rdsk
1927*0Sstevel@tonic-gate 	 * then just print out the cxtxdxsx or the dx, metainit
1928*0Sstevel@tonic-gate 	 * will assume the default, otherwise we need the full
1929*0Sstevel@tonic-gate 	 * pathname to make sure this works as we intend.
1930*0Sstevel@tonic-gate 	 */
1931*0Sstevel@tonic-gate 	if ((strstr(msp->compnamep->rname, "/dev/rdsk") == NULL) &&
1932*0Sstevel@tonic-gate 	    (strstr(msp->compnamep->rname, "/dev/md/rdsk") == NULL) &&
1933*0Sstevel@tonic-gate 	    (strstr(msp->compnamep->rname, "/dev/td/") == NULL)) {
1934*0Sstevel@tonic-gate 		/* not standard path so print full pathname */
1935*0Sstevel@tonic-gate 		if (fprintf(fp, " %s", msp->compnamep->rname) == EOF)
1936*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
1937*0Sstevel@tonic-gate 	} else {
1938*0Sstevel@tonic-gate 		/* standard path so print ctds or d number */
1939*0Sstevel@tonic-gate 		if (fprintf(fp, " %s", msp->compnamep->cname) == EOF)
1940*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
1941*0Sstevel@tonic-gate 	}
1942*0Sstevel@tonic-gate 
1943*0Sstevel@tonic-gate 	/* print out each extent */
1944*0Sstevel@tonic-gate 	for (extn = 0; (extn < msp->ext.ext_len); extn++) {
1945*0Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
1946*0Sstevel@tonic-gate 		if (fprintf(fp, " -o %llu -b %llu ", extp->poff,
1947*0Sstevel@tonic-gate 		    extp->len) == EOF)
1948*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
1949*0Sstevel@tonic-gate 	}
1950*0Sstevel@tonic-gate 
1951*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
1952*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
1953*0Sstevel@tonic-gate 
1954*0Sstevel@tonic-gate 	/* success */
1955*0Sstevel@tonic-gate 	return (0);
1956*0Sstevel@tonic-gate }
1957*0Sstevel@tonic-gate 
1958*0Sstevel@tonic-gate /*
1959*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_status_to_name()
1960*0Sstevel@tonic-gate  * INPUT:	xsp_status	- the status value to convert to a string
1961*0Sstevel@tonic-gate  *		tstate		- transient errored device state. If set the
1962*0Sstevel@tonic-gate  *				  device is Unavailable
1963*0Sstevel@tonic-gate  * OUTPUT:	none
1964*0Sstevel@tonic-gate  * RETURNS:	char *	- a pointer to the string representing the status value
1965*0Sstevel@tonic-gate  * PURPOSE:	return an internationalized string representing the
1966*0Sstevel@tonic-gate  *		status value for a soft partition.  The strings are
1967*0Sstevel@tonic-gate  *		strdup'd and must be freed by the caller.
1968*0Sstevel@tonic-gate  */
1969*0Sstevel@tonic-gate static char *
1970*0Sstevel@tonic-gate meta_sp_status_to_name(
1971*0Sstevel@tonic-gate 	xsp_status_t	xsp_status,
1972*0Sstevel@tonic-gate 	uint_t		tstate
1973*0Sstevel@tonic-gate )
1974*0Sstevel@tonic-gate {
1975*0Sstevel@tonic-gate 	char *rval = NULL;
1976*0Sstevel@tonic-gate 
1977*0Sstevel@tonic-gate 	/*
1978*0Sstevel@tonic-gate 	 * Check to see if we have MD_INACCESSIBLE set. This is the only valid
1979*0Sstevel@tonic-gate 	 * value for an 'Unavailable' return. tstate can be set because of
1980*0Sstevel@tonic-gate 	 * other multi-node reasons (e.g. ABR being set)
1981*0Sstevel@tonic-gate 	 */
1982*0Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
1983*0Sstevel@tonic-gate 		return (Strdup(dgettext(TEXT_DOMAIN, "Unavailable")));
1984*0Sstevel@tonic-gate 	}
1985*0Sstevel@tonic-gate 
1986*0Sstevel@tonic-gate 	switch (xsp_status) {
1987*0Sstevel@tonic-gate 	case MD_SP_CREATEPEND:
1988*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Creating"));
1989*0Sstevel@tonic-gate 		break;
1990*0Sstevel@tonic-gate 	case MD_SP_GROWPEND:
1991*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Growing"));
1992*0Sstevel@tonic-gate 		break;
1993*0Sstevel@tonic-gate 	case MD_SP_DELPEND:
1994*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Deleting"));
1995*0Sstevel@tonic-gate 		break;
1996*0Sstevel@tonic-gate 	case MD_SP_OK:
1997*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Okay"));
1998*0Sstevel@tonic-gate 		break;
1999*0Sstevel@tonic-gate 	case MD_SP_ERR:
2000*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Errored"));
2001*0Sstevel@tonic-gate 		break;
2002*0Sstevel@tonic-gate 	case MD_SP_RECOVER:
2003*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Recovering"));
2004*0Sstevel@tonic-gate 		break;
2005*0Sstevel@tonic-gate 	}
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate 	if (rval == NULL)
2008*0Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Invalid"));
2009*0Sstevel@tonic-gate 
2010*0Sstevel@tonic-gate 	return (rval);
2011*0Sstevel@tonic-gate }
2012*0Sstevel@tonic-gate 
2013*0Sstevel@tonic-gate /*
2014*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_report()
2015*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the unit being displayed
2016*0Sstevel@tonic-gate  *		msp	- the unit structure to display
2017*0Sstevel@tonic-gate  *		nlpp	- pass back the large devs
2018*0Sstevel@tonic-gate  *		fp	- the file pointer to send output to
2019*0Sstevel@tonic-gate  *		options	- print options from the command line processor
2020*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
2021*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
2022*0Sstevel@tonic-gate  * PURPOSE:	print a full report of the device specified
2023*0Sstevel@tonic-gate  */
2024*0Sstevel@tonic-gate static int
2025*0Sstevel@tonic-gate meta_sp_report(
2026*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2027*0Sstevel@tonic-gate 	md_sp_t		*msp,
2028*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
2029*0Sstevel@tonic-gate 	char		*fname,
2030*0Sstevel@tonic-gate 	FILE		*fp,
2031*0Sstevel@tonic-gate 	mdprtopts_t	options,
2032*0Sstevel@tonic-gate 	md_error_t	*ep
2033*0Sstevel@tonic-gate )
2034*0Sstevel@tonic-gate {
2035*0Sstevel@tonic-gate 	uint_t		extn;
2036*0Sstevel@tonic-gate 	char		*status;
2037*0Sstevel@tonic-gate 	char		*devid = "";
2038*0Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
2039*0Sstevel@tonic-gate 	ddi_devid_t	dtp;
2040*0Sstevel@tonic-gate 	int		len;
2041*0Sstevel@tonic-gate 	uint_t		tstate = 0;
2042*0Sstevel@tonic-gate 
2043*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
2044*0Sstevel@tonic-gate 		if (msp->common.revision != MD_64BIT_META_DEV) {
2045*0Sstevel@tonic-gate 			return (0);
2046*0Sstevel@tonic-gate 		} else {
2047*0Sstevel@tonic-gate 			if (meta_getdevs(sp, msp->common.namep, nlpp, ep) != 0)
2048*0Sstevel@tonic-gate 				return (-1);
2049*0Sstevel@tonic-gate 		}
2050*0Sstevel@tonic-gate 	}
2051*0Sstevel@tonic-gate 
2052*0Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
2053*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Soft Partition\n"),
2054*0Sstevel@tonic-gate 		    msp->common.namep->cname) == EOF)
2055*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
2056*0Sstevel@tonic-gate 	}
2057*0Sstevel@tonic-gate 
2058*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Device: %s\n"),
2059*0Sstevel@tonic-gate 	    msp->compnamep->cname) == EOF)
2060*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
2061*0Sstevel@tonic-gate 
2062*0Sstevel@tonic-gate 	/* Determine if device is available before displaying status */
2063*0Sstevel@tonic-gate 	if (metaismeta(msp->common.namep)) {
2064*0Sstevel@tonic-gate 		if (meta_get_tstate(msp->common.namep->dev, &tstate, ep) != 0)
2065*0Sstevel@tonic-gate 			return (-1);
2066*0Sstevel@tonic-gate 	}
2067*0Sstevel@tonic-gate 	status = meta_sp_status_to_name(msp->status, tstate & MD_DEV_ERRORED);
2068*0Sstevel@tonic-gate 
2069*0Sstevel@tonic-gate 	/* print out "State" to be consistent with other metadevices */
2070*0Sstevel@tonic-gate 	if (tstate & MD_ABR_CAP) {
2071*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
2072*0Sstevel@tonic-gate 		    "    State: %s - Application Based Recovery (ABR)\n"),
2073*0Sstevel@tonic-gate 		    status) == EOF) {
2074*0Sstevel@tonic-gate 			Free(status);
2075*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
2076*0Sstevel@tonic-gate 		}
2077*0Sstevel@tonic-gate 	} else {
2078*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
2079*0Sstevel@tonic-gate 		    "    State: %s\n"), status) == EOF) {
2080*0Sstevel@tonic-gate 			Free(status);
2081*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
2082*0Sstevel@tonic-gate 		}
2083*0Sstevel@tonic-gate 	}
2084*0Sstevel@tonic-gate 	free(status);
2085*0Sstevel@tonic-gate 
2086*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %llu blocks (%s)\n"),
2087*0Sstevel@tonic-gate 	    msp->common.size,
2088*0Sstevel@tonic-gate 	    meta_number_to_string(msp->common.size, DEV_BSIZE)) == EOF)
2089*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
2090*0Sstevel@tonic-gate 
2091*0Sstevel@tonic-gate 	/* print component details */
2092*0Sstevel@tonic-gate 	if (! metaismeta(msp->compnamep)) {
2093*0Sstevel@tonic-gate 		diskaddr_t	start_blk;
2094*0Sstevel@tonic-gate 		int		has_mddb;
2095*0Sstevel@tonic-gate 		char		*has_mddb_str;
2096*0Sstevel@tonic-gate 
2097*0Sstevel@tonic-gate 		/* print header */
2098*0Sstevel@tonic-gate 		/*
2099*0Sstevel@tonic-gate 		 * Building a format string on the fly that will
2100*0Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
2101*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
2102*0Sstevel@tonic-gate 		 * looking horrible.
2103*0Sstevel@tonic-gate 		 */
2104*0Sstevel@tonic-gate 		len = strlen(msp->compnamep->cname);
2105*0Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
2106*0Sstevel@tonic-gate 		len += 2;
2107*0Sstevel@tonic-gate 		if (fprintf(fp,
2108*0Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %s\n",
2109*0Sstevel@tonic-gate 		    len, len,
2110*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
2111*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
2112*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
2113*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
2114*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
2115*0Sstevel@tonic-gate 		}
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate 
2118*0Sstevel@tonic-gate 		/* get info */
2119*0Sstevel@tonic-gate 		if ((start_blk = meta_sp_get_start(sp, msp->compnamep, ep)) ==
2120*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
2121*0Sstevel@tonic-gate 			return (-1);
2122*0Sstevel@tonic-gate 
2123*0Sstevel@tonic-gate 		if ((has_mddb = metahasmddb(sp, msp->compnamep, ep)) < 0)
2124*0Sstevel@tonic-gate 			return (-1);
2125*0Sstevel@tonic-gate 
2126*0Sstevel@tonic-gate 		if (has_mddb)
2127*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
2128*0Sstevel@tonic-gate 		else
2129*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
2130*0Sstevel@tonic-gate 
2131*0Sstevel@tonic-gate 		/* populate the key in the name_p structure */
2132*0Sstevel@tonic-gate 		didnp = metadevname(&sp, msp->compnamep->dev, ep);
2133*0Sstevel@tonic-gate 		if (didnp == NULL) {
2134*0Sstevel@tonic-gate 			return (-1);
2135*0Sstevel@tonic-gate 		}
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate 		/* determine if devid does NOT exist */
2138*0Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
2139*0Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
2140*0Sstevel@tonic-gate 					didnp->key, ep)) == NULL)
2141*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
2142*0Sstevel@tonic-gate 			else {
2143*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
2144*0Sstevel@tonic-gate 				free(dtp);
2145*0Sstevel@tonic-gate 			}
2146*0Sstevel@tonic-gate 		}
2147*0Sstevel@tonic-gate 
2148*0Sstevel@tonic-gate 		/* print info */
2149*0Sstevel@tonic-gate 		/*
2150*0Sstevel@tonic-gate 		 * This allows the length
2151*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
2152*0Sstevel@tonic-gate 		 * looking horrible.
2153*0Sstevel@tonic-gate 		 */
2154*0Sstevel@tonic-gate 		if (fprintf(fp, "\t%-*s %8lld     %-5.5s %s\n",
2155*0Sstevel@tonic-gate 		    len, msp->compnamep->cname,
2156*0Sstevel@tonic-gate 		    start_blk, has_mddb_str, devid) == EOF) {
2157*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
2158*0Sstevel@tonic-gate 		}
2159*0Sstevel@tonic-gate 		(void) fprintf(fp, "\n");
2160*0Sstevel@tonic-gate 	}
2161*0Sstevel@tonic-gate 
2162*0Sstevel@tonic-gate 
2163*0Sstevel@tonic-gate 	/* print the headers */
2164*0Sstevel@tonic-gate 	if (fprintf(fp, "\t%6.6s %24.24s %24.24s\n",
2165*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Extent"),
2166*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Start Block"),
2167*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Block count")) == EOF)
2168*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
2169*0Sstevel@tonic-gate 
2170*0Sstevel@tonic-gate 	/* print out each extent */
2171*0Sstevel@tonic-gate 	for (extn = 0; (extn < msp->ext.ext_len); extn++) {
2172*0Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
2173*0Sstevel@tonic-gate 
2174*0Sstevel@tonic-gate 		/* If PRINT_TIMES option is ever supported, add output here */
2175*0Sstevel@tonic-gate 		if (fprintf(fp, "\t%6u %24llu %24llu\n",
2176*0Sstevel@tonic-gate 		    extn, extp->poff, extp->len) == EOF)
2177*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
2178*0Sstevel@tonic-gate 	}
2179*0Sstevel@tonic-gate 
2180*0Sstevel@tonic-gate 	/* separate records with a newline */
2181*0Sstevel@tonic-gate 	(void) fprintf(fp, "\n");
2182*0Sstevel@tonic-gate 	return (0);
2183*0Sstevel@tonic-gate }
2184*0Sstevel@tonic-gate 
2185*0Sstevel@tonic-gate /*
2186*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_print()
2187*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the unit being displayed
2188*0Sstevel@tonic-gate  *		np	- the name of the device to print
2189*0Sstevel@tonic-gate  *		fname	- ??? not used
2190*0Sstevel@tonic-gate  *		fp	- the file pointer to send output to
2191*0Sstevel@tonic-gate  *		options	- print options from the command line processor
2192*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
2193*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
2194*0Sstevel@tonic-gate  * PURPOSE:	print a full report of the device specified by metastat.
2195*0Sstevel@tonic-gate  *		This is the main entry point for printing.
2196*0Sstevel@tonic-gate  */
2197*0Sstevel@tonic-gate int
2198*0Sstevel@tonic-gate meta_sp_print(
2199*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2200*0Sstevel@tonic-gate 	mdname_t	*np,
2201*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
2202*0Sstevel@tonic-gate 	char		*fname,
2203*0Sstevel@tonic-gate 	FILE		*fp,
2204*0Sstevel@tonic-gate 	mdprtopts_t	options,
2205*0Sstevel@tonic-gate 	md_error_t	*ep
2206*0Sstevel@tonic-gate )
2207*0Sstevel@tonic-gate {
2208*0Sstevel@tonic-gate 	md_sp_t		*msp;
2209*0Sstevel@tonic-gate 	md_unit_t	*mdp;
2210*0Sstevel@tonic-gate 	int		rval = 0;
2211*0Sstevel@tonic-gate 
2212*0Sstevel@tonic-gate 	/* should always have the same set */
2213*0Sstevel@tonic-gate 	assert(sp != NULL);
2214*0Sstevel@tonic-gate 
2215*0Sstevel@tonic-gate 	/* print all the soft partitions */
2216*0Sstevel@tonic-gate 	if (np == NULL) {
2217*0Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
2218*0Sstevel@tonic-gate 		mdnamelist_t	*p;
2219*0Sstevel@tonic-gate 		int		cnt;
2220*0Sstevel@tonic-gate 
2221*0Sstevel@tonic-gate 		if ((cnt = meta_get_sp_names(sp, &nlp, options, ep)) < 0)
2222*0Sstevel@tonic-gate 			return (-1);
2223*0Sstevel@tonic-gate 		else if (cnt == 0)
2224*0Sstevel@tonic-gate 			return (0);
2225*0Sstevel@tonic-gate 
2226*0Sstevel@tonic-gate 		/* recusively print them out */
2227*0Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
2228*0Sstevel@tonic-gate 			mdname_t	*curnp = p->namep;
2229*0Sstevel@tonic-gate 
2230*0Sstevel@tonic-gate 			/*
2231*0Sstevel@tonic-gate 			 * one problem with the rval of -1 here is that
2232*0Sstevel@tonic-gate 			 * the error gets "lost" when the next device is
2233*0Sstevel@tonic-gate 			 * printed, but we want to print them all anyway.
2234*0Sstevel@tonic-gate 			 */
2235*0Sstevel@tonic-gate 			rval = meta_sp_print(sp, curnp, nlpp, fname, fp,
2236*0Sstevel@tonic-gate 			    options, ep);
2237*0Sstevel@tonic-gate 		}
2238*0Sstevel@tonic-gate 
2239*0Sstevel@tonic-gate 		/* clean up, return success */
2240*0Sstevel@tonic-gate 		metafreenamelist(nlp);
2241*0Sstevel@tonic-gate 		return (rval);
2242*0Sstevel@tonic-gate 	}
2243*0Sstevel@tonic-gate 
2244*0Sstevel@tonic-gate 	/* get the unit structure */
2245*0Sstevel@tonic-gate 	if ((msp = meta_get_sp_common(sp, np,
2246*0Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
2247*0Sstevel@tonic-gate 		return (-1);
2248*0Sstevel@tonic-gate 
2249*0Sstevel@tonic-gate 	/* check for parented */
2250*0Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
2251*0Sstevel@tonic-gate 	    (MD_HAS_PARENT(msp->common.parent))) {
2252*0Sstevel@tonic-gate 		return (0);
2253*0Sstevel@tonic-gate 	}
2254*0Sstevel@tonic-gate 
2255*0Sstevel@tonic-gate 	/* print appropriate detail */
2256*0Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
2257*0Sstevel@tonic-gate 		if (meta_sp_short_print(msp, fname, fp, options, ep) != 0)
2258*0Sstevel@tonic-gate 			return (-1);
2259*0Sstevel@tonic-gate 	} else {
2260*0Sstevel@tonic-gate 		if (meta_sp_report(sp, msp, nlpp, fname, fp, options, ep) != 0)
2261*0Sstevel@tonic-gate 			return (-1);
2262*0Sstevel@tonic-gate 	}
2263*0Sstevel@tonic-gate 
2264*0Sstevel@tonic-gate 	/*
2265*0Sstevel@tonic-gate 	 * Print underlying metadevices if they are parented to us and
2266*0Sstevel@tonic-gate 	 * if the info for the underlying metadevice has not been printed.
2267*0Sstevel@tonic-gate 	 */
2268*0Sstevel@tonic-gate 	if (metaismeta(msp->compnamep)) {
2269*0Sstevel@tonic-gate 		/* get the unit structure for the subdevice */
2270*0Sstevel@tonic-gate 		if ((mdp = meta_get_mdunit(sp, msp->compnamep, ep)) == NULL)
2271*0Sstevel@tonic-gate 			return (-1);
2272*0Sstevel@tonic-gate 
2273*0Sstevel@tonic-gate 		/* If info not already printed, recurse */
2274*0Sstevel@tonic-gate 		if (!BT_TEST(sp_parent_printed, MD_MIN2UNIT(MD_SID(mdp)))) {
2275*0Sstevel@tonic-gate 			if (meta_print_name(sp, msp->compnamep, nlpp, fname, fp,
2276*0Sstevel@tonic-gate 			    (options | PRINT_HEADER | PRINT_SUBDEVS),
2277*0Sstevel@tonic-gate 			    NULL, ep) != 0) {
2278*0Sstevel@tonic-gate 				return (-1);
2279*0Sstevel@tonic-gate 			}
2280*0Sstevel@tonic-gate 			BT_SET(sp_parent_printed, MD_MIN2UNIT(MD_SID(mdp)));
2281*0Sstevel@tonic-gate 		}
2282*0Sstevel@tonic-gate 	}
2283*0Sstevel@tonic-gate 	return (0);
2284*0Sstevel@tonic-gate }
2285*0Sstevel@tonic-gate 
2286*0Sstevel@tonic-gate /*
2287*0Sstevel@tonic-gate  * **************************************************************************
2288*0Sstevel@tonic-gate  *                     Watermark Manipulation Functions                     *
2289*0Sstevel@tonic-gate  * **************************************************************************
2290*0Sstevel@tonic-gate  */
2291*0Sstevel@tonic-gate 
2292*0Sstevel@tonic-gate /*
2293*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_start()
2294*0Sstevel@tonic-gate  * INPUT:	sp	- the operating set
2295*0Sstevel@tonic-gate  *		np 	- device upon which the sp is being built
2296*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
2297*0Sstevel@tonic-gate  * RETURNS:	daddr_t	- -1 if error, otherwise the start block
2298*0Sstevel@tonic-gate  * PURPOSE:	Encapsulate the determination of the start block of the
2299*0Sstevel@tonic-gate  *		device upon which the sp is built or being built.
2300*0Sstevel@tonic-gate  *		This is done to hide the ugliness of the algorithm.  In
2301*0Sstevel@tonic-gate  *		the case where a sp is being built upon a stripe of > 1
2302*0Sstevel@tonic-gate  *		TB that is made up of a set of disks in which the first
2303*0Sstevel@tonic-gate  *		has a VTOC label the result returned from the call to
2304*0Sstevel@tonic-gate  *		metagetstart is incorrect.  The reason being that a > 1
2305*0Sstevel@tonic-gate  *		TB metadevice will manufacture an EFI label in which the
2306*0Sstevel@tonic-gate  *		start address is zero.  This is irrespective of the underlying
2307*0Sstevel@tonic-gate  *		devices.  The long term fix for this is to fix
2308*0Sstevel@tonic-gate  *		meta_efi_to_mdvtoc and meta_efi_to mdgeom so that they return
2309*0Sstevel@tonic-gate  *		values that are indicative of the first underlying device in
2310*0Sstevel@tonic-gate  *		metadevice.
2311*0Sstevel@tonic-gate  */
2312*0Sstevel@tonic-gate static diskaddr_t
2313*0Sstevel@tonic-gate meta_sp_get_start(
2314*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2315*0Sstevel@tonic-gate 	mdname_t	*np,
2316*0Sstevel@tonic-gate 	md_error_t	*ep
2317*0Sstevel@tonic-gate )
2318*0Sstevel@tonic-gate {
2319*0Sstevel@tonic-gate 	daddr_t		start_block;
2320*0Sstevel@tonic-gate 
2321*0Sstevel@tonic-gate 	if ((start_block = metagetstart(sp, np, ep)) != MD_DISKADDR_ERROR) {
2322*0Sstevel@tonic-gate 		start_block += MD_SP_START;
2323*0Sstevel@tonic-gate 		/*
2324*0Sstevel@tonic-gate 		 * In the case that the device upon which the sp is being
2325*0Sstevel@tonic-gate 		 * created is a metadevice then ensure that in the case that
2326*0Sstevel@tonic-gate 		 * the first underlying device has a vtoc label that it is
2327*0Sstevel@tonic-gate 		 * not overwritten with a watermark by setting the start block
2328*0Sstevel@tonic-gate 		 * to point just past the vtoc label
2329*0Sstevel@tonic-gate 		 */
2330*0Sstevel@tonic-gate 		if (start_block < VTOC_SIZE && metaismeta(np))
2331*0Sstevel@tonic-gate 			start_block = VTOC_SIZE;
2332*0Sstevel@tonic-gate 	}
2333*0Sstevel@tonic-gate 
2334*0Sstevel@tonic-gate 	return (start_block);
2335*0Sstevel@tonic-gate }
2336*0Sstevel@tonic-gate 
2337*0Sstevel@tonic-gate /*
2338*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_update_wm()
2339*0Sstevel@tonic-gate  * INPUT:	sp	- the operating set
2340*0Sstevel@tonic-gate  *		msp	- a pointer to the XDR unit structure
2341*0Sstevel@tonic-gate  *		extlist	- the extent list specifying watermarks to update
2342*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
2343*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
2344*0Sstevel@tonic-gate  * PURPOSE:	steps backwards through the extent list updating
2345*0Sstevel@tonic-gate  *		watermarks for all extents with the EXTFLG_UPDATE flag
2346*0Sstevel@tonic-gate  *		set.  Writing the watermarks guarantees consistency when
2347*0Sstevel@tonic-gate  *		extents must be broken into pieces since the original
2348*0Sstevel@tonic-gate  *		watermark will be the last to be updated, and will be
2349*0Sstevel@tonic-gate  *		changed to point to a new watermark that is already
2350*0Sstevel@tonic-gate  *		known to be consistent.  If one of the writes fails, the
2351*0Sstevel@tonic-gate  *		original watermark stays intact and none of the changes
2352*0Sstevel@tonic-gate  *		are realized.
2353*0Sstevel@tonic-gate  */
2354*0Sstevel@tonic-gate static int
2355*0Sstevel@tonic-gate meta_sp_update_wm(
2356*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2357*0Sstevel@tonic-gate 	md_sp_t		*msp,
2358*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
2359*0Sstevel@tonic-gate 	md_error_t	*ep
2360*0Sstevel@tonic-gate )
2361*0Sstevel@tonic-gate {
2362*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
2363*0Sstevel@tonic-gate 	sp_ext_node_t	*tail;
2364*0Sstevel@tonic-gate 	mp_watermark_t	*wmp, *watermarks;
2365*0Sstevel@tonic-gate 	xsp_offset_t	*osp, *offsets;
2366*0Sstevel@tonic-gate 	int		update_count = 0;
2367*0Sstevel@tonic-gate 	int		rval = 0;
2368*0Sstevel@tonic-gate 	md_unit_t	*mdp;
2369*0Sstevel@tonic-gate 	md_sp_update_wm_t	update_params;
2370*0Sstevel@tonic-gate 
2371*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
2372*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_update_wm: Updating watermarks:\n");
2373*0Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
2374*0Sstevel@tonic-gate 	}
2375*0Sstevel@tonic-gate 
2376*0Sstevel@tonic-gate 	/*
2377*0Sstevel@tonic-gate 	 * find the last node so we can write the watermarks backwards
2378*0Sstevel@tonic-gate 	 * and count watermarks to update so we can allocate space
2379*0Sstevel@tonic-gate 	 */
2380*0Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
2381*0Sstevel@tonic-gate 		if ((ext->ext_flags & EXTFLG_UPDATE) != 0) {
2382*0Sstevel@tonic-gate 			update_count++;
2383*0Sstevel@tonic-gate 		}
2384*0Sstevel@tonic-gate 
2385*0Sstevel@tonic-gate 		if (ext->ext_next == NULL) {
2386*0Sstevel@tonic-gate 			tail = ext;
2387*0Sstevel@tonic-gate 		}
2388*0Sstevel@tonic-gate 	}
2389*0Sstevel@tonic-gate 	ext = tail;
2390*0Sstevel@tonic-gate 
2391*0Sstevel@tonic-gate 	wmp = watermarks =
2392*0Sstevel@tonic-gate 	    Zalloc(update_count * sizeof (mp_watermark_t));
2393*0Sstevel@tonic-gate 	osp = offsets =
2394*0Sstevel@tonic-gate 	    Zalloc(update_count * sizeof (sp_ext_offset_t));
2395*0Sstevel@tonic-gate 
2396*0Sstevel@tonic-gate 	while (ext != NULL) {
2397*0Sstevel@tonic-gate 		if ((ext->ext_flags & EXTFLG_UPDATE) != 0) {
2398*0Sstevel@tonic-gate 			/* update watermark */
2399*0Sstevel@tonic-gate 			wmp->wm_magic = MD_SP_MAGIC;
2400*0Sstevel@tonic-gate 			wmp->wm_version = MD_SP_VERSION;
2401*0Sstevel@tonic-gate 			wmp->wm_type = ext->ext_type;
2402*0Sstevel@tonic-gate 			wmp->wm_seq = ext->ext_seq;
2403*0Sstevel@tonic-gate 			wmp->wm_length = ext->ext_length - MD_SP_WMSIZE;
2404*0Sstevel@tonic-gate 
2405*0Sstevel@tonic-gate 			/* fill in the volume name and set name */
2406*0Sstevel@tonic-gate 			if (ext->ext_namep != NULL)
2407*0Sstevel@tonic-gate 				(void) strcpy(wmp->wm_mdname,
2408*0Sstevel@tonic-gate 				    ext->ext_namep->cname);
2409*0Sstevel@tonic-gate 			else
2410*0Sstevel@tonic-gate 				(void) strcpy(wmp->wm_mdname, MD_SP_FREEWMNAME);
2411*0Sstevel@tonic-gate 			if (ext->ext_setp != NULL &&
2412*0Sstevel@tonic-gate 			    ext->ext_setp->setno != MD_LOCAL_SET)
2413*0Sstevel@tonic-gate 				(void) strcpy(wmp->wm_setname,
2414*0Sstevel@tonic-gate 				    ext->ext_setp->setname);
2415*0Sstevel@tonic-gate 			else
2416*0Sstevel@tonic-gate 				(void) strcpy(wmp->wm_setname,
2417*0Sstevel@tonic-gate 				    MD_SP_LOCALSETNAME);
2418*0Sstevel@tonic-gate 
2419*0Sstevel@tonic-gate 			/* Generate the checksum */
2420*0Sstevel@tonic-gate 			wmp->wm_checksum = 0;
2421*0Sstevel@tonic-gate 			crcgen((uchar_t *)wmp, (uint_t *)&wmp->wm_checksum,
2422*0Sstevel@tonic-gate 			    sizeof (*wmp), NULL);
2423*0Sstevel@tonic-gate 
2424*0Sstevel@tonic-gate 			/* record the extent offset */
2425*0Sstevel@tonic-gate 			*osp = ext->ext_offset;
2426*0Sstevel@tonic-gate 
2427*0Sstevel@tonic-gate 			/* Advance the placeholders */
2428*0Sstevel@tonic-gate 			osp++; wmp++;
2429*0Sstevel@tonic-gate 		}
2430*0Sstevel@tonic-gate 		ext = ext->ext_prev;
2431*0Sstevel@tonic-gate 	}
2432*0Sstevel@tonic-gate 
2433*0Sstevel@tonic-gate 	mdp = meta_get_mdunit(sp, msp->common.namep, ep);
2434*0Sstevel@tonic-gate 	if (mdp == NULL) {
2435*0Sstevel@tonic-gate 		rval = -1;
2436*0Sstevel@tonic-gate 		goto out;
2437*0Sstevel@tonic-gate 	}
2438*0Sstevel@tonic-gate 
2439*0Sstevel@tonic-gate 	(void) memset(&update_params, 0, sizeof (update_params));
2440*0Sstevel@tonic-gate 	update_params.mnum = MD_SID(mdp);
2441*0Sstevel@tonic-gate 	update_params.count = update_count;
2442*0Sstevel@tonic-gate 	update_params.wmp = (uintptr_t)watermarks;
2443*0Sstevel@tonic-gate 	update_params.osp = (uintptr_t)offsets;
2444*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&update_params, MD_SP,
2445*0Sstevel@tonic-gate 	    MD_MIN2SET(update_params.mnum));
2446*0Sstevel@tonic-gate 
2447*0Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPUPDATEWM, &update_params,
2448*0Sstevel@tonic-gate 	    &update_params.mde, msp->common.namep->cname) != 0) {
2449*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &update_params.mde);
2450*0Sstevel@tonic-gate 		rval = -1;
2451*0Sstevel@tonic-gate 		goto out;
2452*0Sstevel@tonic-gate 	}
2453*0Sstevel@tonic-gate 
2454*0Sstevel@tonic-gate out:
2455*0Sstevel@tonic-gate 	Free(watermarks);
2456*0Sstevel@tonic-gate 	Free(offsets);
2457*0Sstevel@tonic-gate 
2458*0Sstevel@tonic-gate 	return (rval);
2459*0Sstevel@tonic-gate }
2460*0Sstevel@tonic-gate 
2461*0Sstevel@tonic-gate /*
2462*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_clear_wm()
2463*0Sstevel@tonic-gate  * INPUT:	sp	- the operating set
2464*0Sstevel@tonic-gate  *		msp	- the unit structure for the soft partition to clear
2465*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
2466*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
2467*0Sstevel@tonic-gate  * PURPOSE:	steps through the extents for a soft partition unit and
2468*0Sstevel@tonic-gate  *		creates an extent list designed to mark all of the
2469*0Sstevel@tonic-gate  *		watermarks for those extents as free.  The extent list
2470*0Sstevel@tonic-gate  *		is then passed to meta_sp_update_wm() to actually write
2471*0Sstevel@tonic-gate  *		the watermarks out.
2472*0Sstevel@tonic-gate  */
2473*0Sstevel@tonic-gate static int
2474*0Sstevel@tonic-gate meta_sp_clear_wm(
2475*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2476*0Sstevel@tonic-gate 	md_sp_t		*msp,
2477*0Sstevel@tonic-gate 	md_error_t	*ep
2478*0Sstevel@tonic-gate )
2479*0Sstevel@tonic-gate {
2480*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
2481*0Sstevel@tonic-gate 	int		numexts = msp->ext.ext_len;
2482*0Sstevel@tonic-gate 	uint_t		i;
2483*0Sstevel@tonic-gate 	int		rval = 0;
2484*0Sstevel@tonic-gate 
2485*0Sstevel@tonic-gate 	/* for each watermark must set the flag to SP_FREE */
2486*0Sstevel@tonic-gate 	for (i = 0; i < numexts; i++) {
2487*0Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[i];
2488*0Sstevel@tonic-gate 
2489*0Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, &extlist,
2490*0Sstevel@tonic-gate 		    extp->poff - MD_SP_WMSIZE, extp->len + MD_SP_WMSIZE,
2491*0Sstevel@tonic-gate 		    EXTTYP_FREE, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
2492*0Sstevel@tonic-gate 	}
2493*0Sstevel@tonic-gate 
2494*0Sstevel@tonic-gate 	/* update watermarks */
2495*0Sstevel@tonic-gate 	rval = meta_sp_update_wm(sp, msp, extlist, ep);
2496*0Sstevel@tonic-gate 
2497*0Sstevel@tonic-gate 	meta_sp_list_free(&extlist);
2498*0Sstevel@tonic-gate 	return (rval);
2499*0Sstevel@tonic-gate }
2500*0Sstevel@tonic-gate 
2501*0Sstevel@tonic-gate /*
2502*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_read_wm()
2503*0Sstevel@tonic-gate  * INPUT:	sp	- setname for component
2504*0Sstevel@tonic-gate  *		compnp	- mdname_t for component
2505*0Sstevel@tonic-gate  *		offset	- the offset of the watermark to read (sectors)
2506*0Sstevel@tonic-gate  * OUTPUT:	wm	- the watermark structure to read into
2507*0Sstevel@tonic-gate  *		ep	- return error pointer
2508*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
2509*0Sstevel@tonic-gate  * PURPOSE:	seeks out to the requested offset and reads a watermark.
2510*0Sstevel@tonic-gate  *		It then verifies that the magic number is correct and
2511*0Sstevel@tonic-gate  *		that the checksum is valid, returning an error if either
2512*0Sstevel@tonic-gate  *		is wrong.
2513*0Sstevel@tonic-gate  */
2514*0Sstevel@tonic-gate static int
2515*0Sstevel@tonic-gate meta_sp_read_wm(
2516*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2517*0Sstevel@tonic-gate 	mdname_t	*compnp,
2518*0Sstevel@tonic-gate 	mp_watermark_t	*wm,
2519*0Sstevel@tonic-gate 	sp_ext_offset_t	offset,
2520*0Sstevel@tonic-gate 	md_error_t	*ep
2521*0Sstevel@tonic-gate )
2522*0Sstevel@tonic-gate {
2523*0Sstevel@tonic-gate 	md_sp_read_wm_t	read_params;
2524*0Sstevel@tonic-gate 
2525*0Sstevel@tonic-gate 	/*
2526*0Sstevel@tonic-gate 	 * make sure block offset does not overflow 2^64 bytes and it's a
2527*0Sstevel@tonic-gate 	 * multiple of the block size.
2528*0Sstevel@tonic-gate 	 */
2529*0Sstevel@tonic-gate 	assert(offset <= (1LL << (64 - DEV_BSHIFT)));
2530*0Sstevel@tonic-gate 	/* LINTED */
2531*0Sstevel@tonic-gate 	assert((sizeof (*wm) % DEV_BSIZE) == 0);
2532*0Sstevel@tonic-gate 
2533*0Sstevel@tonic-gate 	(void) memset(wm, 0, sizeof (*wm));
2534*0Sstevel@tonic-gate 
2535*0Sstevel@tonic-gate 	(void) memset(&read_params, 0, sizeof (read_params));
2536*0Sstevel@tonic-gate 	read_params.rdev = compnp->dev;
2537*0Sstevel@tonic-gate 	read_params.wmp = (uintptr_t)wm;
2538*0Sstevel@tonic-gate 	read_params.offset = offset;
2539*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&read_params, MD_SP, sp->setno);
2540*0Sstevel@tonic-gate 
2541*0Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPREADWM, &read_params,
2542*0Sstevel@tonic-gate 	    &read_params.mde, compnp->cname) != 0) {
2543*0Sstevel@tonic-gate 
2544*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2545*0Sstevel@tonic-gate 		    "Extent header read failed, block %llu.\n"), offset);
2546*0Sstevel@tonic-gate 		return (mdstealerror(ep, &read_params.mde));
2547*0Sstevel@tonic-gate 	}
2548*0Sstevel@tonic-gate 
2549*0Sstevel@tonic-gate 	/* make sure magic number is correct */
2550*0Sstevel@tonic-gate 	if (wm->wm_magic != MD_SP_MAGIC) {
2551*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2552*0Sstevel@tonic-gate 		    "found incorrect magic number %x, expected %x.\n"),
2553*0Sstevel@tonic-gate 		    wm->wm_magic, MD_SP_MAGIC);
2554*0Sstevel@tonic-gate 		/*
2555*0Sstevel@tonic-gate 		 * Pass NULL for the device name as we don't have
2556*0Sstevel@tonic-gate 		 * valid watermark contents.
2557*0Sstevel@tonic-gate 		 */
2558*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BADWMMAGIC, 0, NULL));
2559*0Sstevel@tonic-gate 	}
2560*0Sstevel@tonic-gate 
2561*0Sstevel@tonic-gate 	if (crcchk((uchar_t *)wm, (uint_t *)&wm->wm_checksum,
2562*0Sstevel@tonic-gate 	    sizeof (*wm), NULL)) {
2563*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2564*0Sstevel@tonic-gate 		    "found incorrect checksum %x.\n"),
2565*0Sstevel@tonic-gate 		    wm->wm_checksum);
2566*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BADWMCRC, 0, wm->wm_mdname));
2567*0Sstevel@tonic-gate 	}
2568*0Sstevel@tonic-gate 
2569*0Sstevel@tonic-gate 	return (0);
2570*0Sstevel@tonic-gate }
2571*0Sstevel@tonic-gate 
2572*0Sstevel@tonic-gate /*
2573*0Sstevel@tonic-gate  * **************************************************************************
2574*0Sstevel@tonic-gate  *                  Query Functions
2575*0Sstevel@tonic-gate  * **************************************************************************
2576*0Sstevel@tonic-gate  */
2577*0Sstevel@tonic-gate 
2578*0Sstevel@tonic-gate /*
2579*0Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that assumes that
2580*0Sstevel@tonic-gate  *		   its input parameters have been checked and
2581*0Sstevel@tonic-gate  *		   have valid values that lie within acceptable
2582*0Sstevel@tonic-gate  *		   ranges.
2583*0Sstevel@tonic-gate  *
2584*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_enough_space()
2585*0Sstevel@tonic-gate  * INPUT:	desired_number_of_sps - the number of soft partitions desired;
2586*0Sstevel@tonic-gate  *					must be > 0
2587*0Sstevel@tonic-gate  *		desired_sp_size - the desired soft partition size in blocks;
2588*0Sstevel@tonic-gate  *				  must be > 0
2589*0Sstevel@tonic-gate  *		extent_listpp - a reference to a reference to an extent
2590*0Sstevel@tonic-gate  *				list that lists the extents on a device;
2591*0Sstevel@tonic-gate  *				must be a reference to a reference to a
2592*0Sstevel@tonic-gate  *				valid extent list
2593*0Sstevel@tonic-gate  *		alignment - the desired data space alignment for the sp's
2594*0Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
2595*0Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if there's enough space in the extent
2596*0Sstevel@tonic-gate  *			    list to create the desired soft partitions,
2597*0Sstevel@tonic-gate  *			    B_FALSE if there's not enough space
2598*0Sstevel@tonic-gate  * PURPOSE:	determines whether there's enough free space in an extent
2599*0Sstevel@tonic-gate  *		list to allow creation of a set of soft partitions
2600*0Sstevel@tonic-gate  */
2601*0Sstevel@tonic-gate static boolean_t
2602*0Sstevel@tonic-gate meta_sp_enough_space(
2603*0Sstevel@tonic-gate 	int		desired_number_of_sps,
2604*0Sstevel@tonic-gate 	blkcnt_t	desired_sp_size,
2605*0Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp,
2606*0Sstevel@tonic-gate 	sp_ext_length_t	alignment
2607*0Sstevel@tonic-gate )
2608*0Sstevel@tonic-gate {
2609*0Sstevel@tonic-gate 	boolean_t		enough_space;
2610*0Sstevel@tonic-gate 	int			number_of_sps;
2611*0Sstevel@tonic-gate 	int			number_of_extents_used;
2612*0Sstevel@tonic-gate 	sp_ext_length_t		desired_ext_length = desired_sp_size;
2613*0Sstevel@tonic-gate 
2614*0Sstevel@tonic-gate 	enough_space = B_TRUE;
2615*0Sstevel@tonic-gate 	number_of_sps = 0;
2616*0Sstevel@tonic-gate 	while ((enough_space == B_TRUE) &&
2617*0Sstevel@tonic-gate 		(number_of_sps < desired_number_of_sps)) {
2618*0Sstevel@tonic-gate 		/*
2619*0Sstevel@tonic-gate 		 * Use the extent allocation algorithm implemented by
2620*0Sstevel@tonic-gate 		 * meta_sp_alloc_by_len() to test whether the free
2621*0Sstevel@tonic-gate 		 * extents in the extent list referenced by *extent_listpp
2622*0Sstevel@tonic-gate 		 * contain enough space to accomodate a soft partition
2623*0Sstevel@tonic-gate 		 * of size desired_ext_length.
2624*0Sstevel@tonic-gate 		 *
2625*0Sstevel@tonic-gate 		 * Repeat the test <desired_number_of_sps> times
2626*0Sstevel@tonic-gate 		 * or until it fails, whichever comes first,
2627*0Sstevel@tonic-gate 		 * each time allocating the extents required to
2628*0Sstevel@tonic-gate 		 * create the soft partition without actually
2629*0Sstevel@tonic-gate 		 * creating the soft partition.
2630*0Sstevel@tonic-gate 		 */
2631*0Sstevel@tonic-gate 		number_of_extents_used = meta_sp_alloc_by_len(
2632*0Sstevel@tonic-gate 						TEST_SETNAMEP,
2633*0Sstevel@tonic-gate 						TEST_SOFT_PARTITION_NAMEP,
2634*0Sstevel@tonic-gate 						extent_listpp,
2635*0Sstevel@tonic-gate 						&desired_ext_length,
2636*0Sstevel@tonic-gate 						NO_OFFSET,
2637*0Sstevel@tonic-gate 						alignment);
2638*0Sstevel@tonic-gate 		if (number_of_extents_used == -1) {
2639*0Sstevel@tonic-gate 			enough_space = B_FALSE;
2640*0Sstevel@tonic-gate 		} else {
2641*0Sstevel@tonic-gate 			number_of_sps++;
2642*0Sstevel@tonic-gate 		}
2643*0Sstevel@tonic-gate 	}
2644*0Sstevel@tonic-gate 	return (enough_space);
2645*0Sstevel@tonic-gate }
2646*0Sstevel@tonic-gate 
2647*0Sstevel@tonic-gate /*
2648*0Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that calls other functions
2649*0Sstevel@tonic-gate  *		   that check its mdsetnamep and device_mdnamep
2650*0Sstevel@tonic-gate  *		   input parameters, but expects extent_listpp to
2651*0Sstevel@tonic-gate  *		   be a initialized to a valid address to which
2652*0Sstevel@tonic-gate  *		   it can write a reference to the extent list that
2653*0Sstevel@tonic-gate  *		   it creates.
2654*0Sstevel@tonic-gate  *
2655*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_extent_list()
2656*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
2657*0Sstevel@tonic-gate  *			     for the set containing the device for
2658*0Sstevel@tonic-gate  *			     which the extents are to be listed
2659*0Sstevel@tonic-gate  *		device_mdnamep - a reference to the mdname_t structure
2660*0Sstevel@tonic-gate  *				 for the device for which the extents
2661*0Sstevel@tonic-gate  *				 are to be listed
2662*0Sstevel@tonic-gate  * OUTPUT:	*extent_listpp - a reference to the extent list for
2663*0Sstevel@tonic-gate  *				 the device; NULL if the function fails
2664*0Sstevel@tonic-gate  *		*ep - the libmeta error encountered, if any
2665*0Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the function call was successful,
2666*0Sstevel@tonic-gate  *			    B_FALSE if not
2667*0Sstevel@tonic-gate  * PURPOSE:	gets the extent list for a device
2668*0Sstevel@tonic-gate  */
2669*0Sstevel@tonic-gate static boolean_t
2670*0Sstevel@tonic-gate meta_sp_get_extent_list(
2671*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
2672*0Sstevel@tonic-gate 	mdname_t	*device_mdnamep,
2673*0Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp,
2674*0Sstevel@tonic-gate 	md_error_t	*ep
2675*0Sstevel@tonic-gate )
2676*0Sstevel@tonic-gate {
2677*0Sstevel@tonic-gate 	diskaddr_t		device_size_in_blocks;
2678*0Sstevel@tonic-gate 	mdnamelist_t		*sp_name_listp;
2679*0Sstevel@tonic-gate 	diskaddr_t		start_block_address_in_blocks;
2680*0Sstevel@tonic-gate 
2681*0Sstevel@tonic-gate 	*extent_listpp = NULL;
2682*0Sstevel@tonic-gate 	sp_name_listp = NULL;
2683*0Sstevel@tonic-gate 
2684*0Sstevel@tonic-gate 	start_block_address_in_blocks = meta_sp_get_start(mdsetnamep,
2685*0Sstevel@tonic-gate 						device_mdnamep,
2686*0Sstevel@tonic-gate 						ep);
2687*0Sstevel@tonic-gate 	if (start_block_address_in_blocks == MD_DISKADDR_ERROR) {
2688*0Sstevel@tonic-gate 	    if (getenv(META_SP_DEBUG)) {
2689*0Sstevel@tonic-gate 		mde_perror(ep, "meta_sp_get_extent_list:meta_sp_get_start");
2690*0Sstevel@tonic-gate 	    }
2691*0Sstevel@tonic-gate 	    return (B_FALSE);
2692*0Sstevel@tonic-gate 	}
2693*0Sstevel@tonic-gate 
2694*0Sstevel@tonic-gate 	device_size_in_blocks = metagetsize(device_mdnamep, ep);
2695*0Sstevel@tonic-gate 	if (device_size_in_blocks == MD_DISKADDR_ERROR) {
2696*0Sstevel@tonic-gate 	    if (getenv(META_SP_DEBUG)) {
2697*0Sstevel@tonic-gate 		mde_perror(ep,
2698*0Sstevel@tonic-gate 		    "meta_sp_get_extent_list:metagetsize");
2699*0Sstevel@tonic-gate 	    }
2700*0Sstevel@tonic-gate 	    return (B_FALSE);
2701*0Sstevel@tonic-gate 	}
2702*0Sstevel@tonic-gate 
2703*0Sstevel@tonic-gate 	/*
2704*0Sstevel@tonic-gate 	 * Sanity check: the start block will have skipped an integer
2705*0Sstevel@tonic-gate 	 * number of cylinders, C.  C will usually be zero.  If (C > 0),
2706*0Sstevel@tonic-gate 	 * and the disk slice happens to only be C cylinders in total
2707*0Sstevel@tonic-gate 	 * size, we'll fail this check.
2708*0Sstevel@tonic-gate 	 */
2709*0Sstevel@tonic-gate 	if (device_size_in_blocks <=
2710*0Sstevel@tonic-gate 	    (start_block_address_in_blocks + MD_SP_WMSIZE)) {
2711*0Sstevel@tonic-gate 	    (void) mdmderror(ep, MDE_SP_NOSPACE, 0, device_mdnamep->cname);
2712*0Sstevel@tonic-gate 	    return (B_FALSE);
2713*0Sstevel@tonic-gate 	}
2714*0Sstevel@tonic-gate 
2715*0Sstevel@tonic-gate 	/*
2716*0Sstevel@tonic-gate 	 * After this point, we will have allocated resources, so any
2717*0Sstevel@tonic-gate 	 * failure returns must be through the supplied "fail" label
2718*0Sstevel@tonic-gate 	 * to properly deallocate things.
2719*0Sstevel@tonic-gate 	 */
2720*0Sstevel@tonic-gate 
2721*0Sstevel@tonic-gate 	/*
2722*0Sstevel@tonic-gate 	 * Create an empty extent list that starts one watermark past
2723*0Sstevel@tonic-gate 	 * the start block of the device and ends one watermark before
2724*0Sstevel@tonic-gate 	 * the end of the device.
2725*0Sstevel@tonic-gate 	 */
2726*0Sstevel@tonic-gate 	meta_sp_list_insert(TEST_SETNAMEP,
2727*0Sstevel@tonic-gate 			    TEST_SOFT_PARTITION_NAMEP,
2728*0Sstevel@tonic-gate 			    extent_listpp,
2729*0Sstevel@tonic-gate 			    NO_OFFSET,
2730*0Sstevel@tonic-gate 			    (sp_ext_length_t)start_block_address_in_blocks,
2731*0Sstevel@tonic-gate 			    EXTTYP_RESERVED,
2732*0Sstevel@tonic-gate 			    NO_SEQUENCE_NUMBER,
2733*0Sstevel@tonic-gate 			    NO_FLAGS,
2734*0Sstevel@tonic-gate 			    meta_sp_cmp_by_offset);
2735*0Sstevel@tonic-gate 	meta_sp_list_insert(TEST_SETNAMEP,
2736*0Sstevel@tonic-gate 			    TEST_SOFT_PARTITION_NAMEP,
2737*0Sstevel@tonic-gate 			    extent_listpp,
2738*0Sstevel@tonic-gate 			    (sp_ext_offset_t)(device_size_in_blocks -
2739*0Sstevel@tonic-gate 				MD_SP_WMSIZE),
2740*0Sstevel@tonic-gate 			    MD_SP_WMSIZE,
2741*0Sstevel@tonic-gate 			    EXTTYP_END,
2742*0Sstevel@tonic-gate 			    NO_SEQUENCE_NUMBER,
2743*0Sstevel@tonic-gate 			    NO_FLAGS,
2744*0Sstevel@tonic-gate 			    meta_sp_cmp_by_offset);
2745*0Sstevel@tonic-gate 
2746*0Sstevel@tonic-gate 	/*
2747*0Sstevel@tonic-gate 	 * Get the list of soft partitions that are already on the
2748*0Sstevel@tonic-gate 	 * device.
2749*0Sstevel@tonic-gate 	 */
2750*0Sstevel@tonic-gate 	if (meta_sp_get_by_component(mdsetnamep, device_mdnamep,
2751*0Sstevel@tonic-gate 	    &sp_name_listp, FORCE_RELOAD_CACHE, ep) < 1) {
2752*0Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
2753*0Sstevel@tonic-gate 			mde_perror(ep,
2754*0Sstevel@tonic-gate 			    "meta_sp_get_extent_list:meta_sp_get_by_component");
2755*0Sstevel@tonic-gate 		}
2756*0Sstevel@tonic-gate 		goto fail;
2757*0Sstevel@tonic-gate 	}
2758*0Sstevel@tonic-gate 
2759*0Sstevel@tonic-gate 	if (sp_name_listp != NULL) {
2760*0Sstevel@tonic-gate 		/*
2761*0Sstevel@tonic-gate 		 * If there are soft partitions on the device, add the
2762*0Sstevel@tonic-gate 		 * extents used in them to the extent list.
2763*0Sstevel@tonic-gate 		 */
2764*0Sstevel@tonic-gate 		if (meta_sp_extlist_from_namelist(mdsetnamep, sp_name_listp,
2765*0Sstevel@tonic-gate 		    extent_listpp, ep) == -1) {
2766*0Sstevel@tonic-gate 			if (getenv(META_SP_DEBUG)) {
2767*0Sstevel@tonic-gate 				mde_perror(ep, "meta_sp_get_extent_list:"
2768*0Sstevel@tonic-gate 				    "meta_sp_extlist_from_namelist");
2769*0Sstevel@tonic-gate 			}
2770*0Sstevel@tonic-gate 			goto fail;
2771*0Sstevel@tonic-gate 		}
2772*0Sstevel@tonic-gate 		metafreenamelist(sp_name_listp);
2773*0Sstevel@tonic-gate 	}
2774*0Sstevel@tonic-gate 
2775*0Sstevel@tonic-gate 	/*
2776*0Sstevel@tonic-gate 	 * Add free extents to the extent list to represent
2777*0Sstevel@tonic-gate 	 * the remaining regions of free space on the
2778*0Sstevel@tonic-gate 	 * device.
2779*0Sstevel@tonic-gate 	 */
2780*0Sstevel@tonic-gate 	meta_sp_list_freefill(extent_listpp, device_size_in_blocks);
2781*0Sstevel@tonic-gate 	return (B_TRUE);
2782*0Sstevel@tonic-gate 
2783*0Sstevel@tonic-gate fail:
2784*0Sstevel@tonic-gate 	if (sp_name_listp != NULL) {
2785*0Sstevel@tonic-gate 		metafreenamelist(sp_name_listp);
2786*0Sstevel@tonic-gate 	}
2787*0Sstevel@tonic-gate 
2788*0Sstevel@tonic-gate 	if (*extent_listpp != NULL) {
2789*0Sstevel@tonic-gate 		/*
2790*0Sstevel@tonic-gate 		 * meta_sp_list_free sets *extent_listpp to NULL.
2791*0Sstevel@tonic-gate 		 */
2792*0Sstevel@tonic-gate 		meta_sp_list_free(extent_listpp);
2793*0Sstevel@tonic-gate 	}
2794*0Sstevel@tonic-gate 	return (B_FALSE);
2795*0Sstevel@tonic-gate }
2796*0Sstevel@tonic-gate 
2797*0Sstevel@tonic-gate /*
2798*0Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that calls other functions
2799*0Sstevel@tonic-gate  *		   that check its mdsetnamep and mddrivenamep
2800*0Sstevel@tonic-gate  *		   input parameters, but expects extent_listpp to
2801*0Sstevel@tonic-gate  *		   be a initialized to a valid address to which
2802*0Sstevel@tonic-gate  *		   it can write a reference to the extent list that
2803*0Sstevel@tonic-gate  *		   it creates.
2804*0Sstevel@tonic-gate  *
2805*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_extent_list_for_drive()
2806*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
2807*0Sstevel@tonic-gate  *			     for the set containing the drive for
2808*0Sstevel@tonic-gate  *			     which the extents are to be listed
2809*0Sstevel@tonic-gate  *		mddrivenamep   - a reference to the mddrivename_t structure
2810*0Sstevel@tonic-gate  *				 for the drive for which the extents
2811*0Sstevel@tonic-gate  *				 are to be listed
2812*0Sstevel@tonic-gate  * OUTPUT:	*extent_listpp - a reference to the extent list for
2813*0Sstevel@tonic-gate  *				 the drive; NULL if the function fails
2814*0Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the function call was successful,
2815*0Sstevel@tonic-gate  *			    B_FALSE if not
2816*0Sstevel@tonic-gate  * PURPOSE:	gets the extent list for a drive when the entire drive
2817*0Sstevel@tonic-gate  *		is to be soft partitioned
2818*0Sstevel@tonic-gate  */
2819*0Sstevel@tonic-gate static boolean_t
2820*0Sstevel@tonic-gate meta_sp_get_extent_list_for_drive(
2821*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
2822*0Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
2823*0Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp
2824*0Sstevel@tonic-gate )
2825*0Sstevel@tonic-gate {
2826*0Sstevel@tonic-gate 	boolean_t		can_use;
2827*0Sstevel@tonic-gate 	diskaddr_t		free_space;
2828*0Sstevel@tonic-gate 	md_error_t		mderror;
2829*0Sstevel@tonic-gate 	mdvtoc_t		proposed_vtoc;
2830*0Sstevel@tonic-gate 	int			repartition_options;
2831*0Sstevel@tonic-gate 	int			return_value;
2832*0Sstevel@tonic-gate 	md_sp_t			test_sp_struct;
2833*0Sstevel@tonic-gate 
2834*0Sstevel@tonic-gate 	can_use = B_TRUE;
2835*0Sstevel@tonic-gate 	*extent_listpp = NULL;
2836*0Sstevel@tonic-gate 	mderror = mdnullerror;
2837*0Sstevel@tonic-gate 	test_sp_struct.compnamep = metaslicename(mddrivenamep, MD_SLICE0,
2838*0Sstevel@tonic-gate 					&mderror);
2839*0Sstevel@tonic-gate 	if (test_sp_struct.compnamep == NULL) {
2840*0Sstevel@tonic-gate 		can_use = B_FALSE;
2841*0Sstevel@tonic-gate 	}
2842*0Sstevel@tonic-gate 
2843*0Sstevel@tonic-gate 	if (can_use == B_TRUE) {
2844*0Sstevel@tonic-gate 		mderror = mdnullerror;
2845*0Sstevel@tonic-gate 		repartition_options = 0;
2846*0Sstevel@tonic-gate 		return_value = meta_check_sp(mdsetnamep, &test_sp_struct,
2847*0Sstevel@tonic-gate 				MDCMD_USE_WHOLE_DISK, &repartition_options,
2848*0Sstevel@tonic-gate 				&mderror);
2849*0Sstevel@tonic-gate 		if (return_value != 0) {
2850*0Sstevel@tonic-gate 			can_use = B_FALSE;
2851*0Sstevel@tonic-gate 		}
2852*0Sstevel@tonic-gate 	}
2853*0Sstevel@tonic-gate 
2854*0Sstevel@tonic-gate 	if (can_use == B_TRUE) {
2855*0Sstevel@tonic-gate 		mderror = mdnullerror;
2856*0Sstevel@tonic-gate 		repartition_options = repartition_options |
2857*0Sstevel@tonic-gate 			(MD_REPART_FORCE | MD_REPART_DONT_LABEL);
2858*0Sstevel@tonic-gate 		return_value = meta_repartition_drive(mdsetnamep, mddrivenamep,
2859*0Sstevel@tonic-gate 				repartition_options, &proposed_vtoc, &mderror);
2860*0Sstevel@tonic-gate 		if (return_value != 0) {
2861*0Sstevel@tonic-gate 			can_use = B_FALSE;
2862*0Sstevel@tonic-gate 		}
2863*0Sstevel@tonic-gate 	}
2864*0Sstevel@tonic-gate 
2865*0Sstevel@tonic-gate 	if (can_use == B_TRUE) {
2866*0Sstevel@tonic-gate 		free_space = proposed_vtoc.parts[MD_SLICE0].size;
2867*0Sstevel@tonic-gate 		if (free_space <= (MD_SP_START + MD_SP_WMSIZE)) {
2868*0Sstevel@tonic-gate 			can_use = B_FALSE;
2869*0Sstevel@tonic-gate 		}
2870*0Sstevel@tonic-gate 	}
2871*0Sstevel@tonic-gate 
2872*0Sstevel@tonic-gate 	if (can_use == B_TRUE) {
2873*0Sstevel@tonic-gate 		/*
2874*0Sstevel@tonic-gate 		 * Create an extent list that starts with
2875*0Sstevel@tonic-gate 		 * a reserved extent that ends at the start
2876*0Sstevel@tonic-gate 		 * of the usable space on slice zero of the
2877*0Sstevel@tonic-gate 		 * proposed VTOC, ends with an extent that
2878*0Sstevel@tonic-gate 		 * reserves space for a watermark at the end
2879*0Sstevel@tonic-gate 		 * of slice zero, and contains a single free
2880*0Sstevel@tonic-gate 		 * extent that occupies the rest of the space
2881*0Sstevel@tonic-gate 		 * on the slice.
2882*0Sstevel@tonic-gate 		 *
2883*0Sstevel@tonic-gate 		 * NOTE:
2884*0Sstevel@tonic-gate 		 *
2885*0Sstevel@tonic-gate 		 * Don't use metagetstart() or metagetsize() to
2886*0Sstevel@tonic-gate 		 * find the usable space.  They query the mdname_t
2887*0Sstevel@tonic-gate 		 * structure that represents an actual device to
2888*0Sstevel@tonic-gate 		 * determine the amount of space on the device that
2889*0Sstevel@tonic-gate 		 * contains metadata and the total amount of space
2890*0Sstevel@tonic-gate 		 * on the device.  Since this function creates a
2891*0Sstevel@tonic-gate 		 * proposed extent list that doesn't reflect the
2892*0Sstevel@tonic-gate 		 * state of an actual device, there's no mdname_t
2893*0Sstevel@tonic-gate 		 * structure to be queried.
2894*0Sstevel@tonic-gate 		 *
2895*0Sstevel@tonic-gate 		 * When a drive is reformatted to prepare for
2896*0Sstevel@tonic-gate 		 * soft partitioning, all of slice seven is
2897*0Sstevel@tonic-gate 		 * reserved for metadata, all of slice zero is
2898*0Sstevel@tonic-gate 		 * available for soft partitioning, and all other
2899*0Sstevel@tonic-gate 		 * slices on the drive are empty.  The proposed
2900*0Sstevel@tonic-gate 		 * extent list for the drive therefore contains
2901*0Sstevel@tonic-gate 		 * only three extents: a reserved extent that ends
2902*0Sstevel@tonic-gate 		 * at the start of the usable space on slice zero,
2903*0Sstevel@tonic-gate 		 * a single free extent that occupies all the usable
2904*0Sstevel@tonic-gate 		 * space on slice zero, and an ending extent that
2905*0Sstevel@tonic-gate 		 * reserves space for a watermark at the end of
2906*0Sstevel@tonic-gate 		 * slice zero.
2907*0Sstevel@tonic-gate 		 */
2908*0Sstevel@tonic-gate 		meta_sp_list_insert(TEST_SETNAMEP,
2909*0Sstevel@tonic-gate 			TEST_SOFT_PARTITION_NAMEP,
2910*0Sstevel@tonic-gate 			extent_listpp,
2911*0Sstevel@tonic-gate 			NO_OFFSET,
2912*0Sstevel@tonic-gate 			(sp_ext_length_t)(MD_SP_START),
2913*0Sstevel@tonic-gate 			EXTTYP_RESERVED,
2914*0Sstevel@tonic-gate 			NO_SEQUENCE_NUMBER,
2915*0Sstevel@tonic-gate 			NO_FLAGS,
2916*0Sstevel@tonic-gate 			meta_sp_cmp_by_offset);
2917*0Sstevel@tonic-gate 		meta_sp_list_insert(TEST_SETNAMEP,
2918*0Sstevel@tonic-gate 			TEST_SOFT_PARTITION_NAMEP,
2919*0Sstevel@tonic-gate 			extent_listpp,
2920*0Sstevel@tonic-gate 			(sp_ext_offset_t)(free_space - MD_SP_WMSIZE),
2921*0Sstevel@tonic-gate 			MD_SP_WMSIZE,
2922*0Sstevel@tonic-gate 			EXTTYP_END,
2923*0Sstevel@tonic-gate 			NO_SEQUENCE_NUMBER,
2924*0Sstevel@tonic-gate 			NO_FLAGS,
2925*0Sstevel@tonic-gate 			meta_sp_cmp_by_offset);
2926*0Sstevel@tonic-gate 		meta_sp_list_freefill(extent_listpp, free_space);
2927*0Sstevel@tonic-gate 	}
2928*0Sstevel@tonic-gate 	return (can_use);
2929*0Sstevel@tonic-gate }
2930*0Sstevel@tonic-gate 
2931*0Sstevel@tonic-gate /*
2932*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_can_create_sps()
2933*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
2934*0Sstevel@tonic-gate  *			     for the set containing the device for
2935*0Sstevel@tonic-gate  *			     which the extents are to be listed
2936*0Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
2937*0Sstevel@tonic-gate  *			  on which the soft parititions are to be created
2938*0Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
2939*0Sstevel@tonic-gate  *		sp_size - the desired soft partition size
2940*0Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
2941*0Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the soft partitionns can be created,
2942*0Sstevel@tonic-gate  *			    B_FALSE if not
2943*0Sstevel@tonic-gate  * PURPOSE:	determines whether a set of soft partitions can be created
2944*0Sstevel@tonic-gate  *		on a device
2945*0Sstevel@tonic-gate  */
2946*0Sstevel@tonic-gate boolean_t
2947*0Sstevel@tonic-gate meta_sp_can_create_sps(
2948*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
2949*0Sstevel@tonic-gate 	mdname_t	*mdnamep,
2950*0Sstevel@tonic-gate 	int		number_of_sps,
2951*0Sstevel@tonic-gate 	blkcnt_t	sp_size
2952*0Sstevel@tonic-gate )
2953*0Sstevel@tonic-gate {
2954*0Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
2955*0Sstevel@tonic-gate 	boolean_t	succeeded;
2956*0Sstevel@tonic-gate 	md_error_t	mde;
2957*0Sstevel@tonic-gate 
2958*0Sstevel@tonic-gate 	if ((number_of_sps > 0) && (sp_size > 0)) {
2959*0Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list(mdsetnamep, mdnamep,
2960*0Sstevel@tonic-gate 						    &extent_listp, &mde);
2961*0Sstevel@tonic-gate 	} else {
2962*0Sstevel@tonic-gate 		succeeded = B_FALSE;
2963*0Sstevel@tonic-gate 	}
2964*0Sstevel@tonic-gate 
2965*0Sstevel@tonic-gate 	/*
2966*0Sstevel@tonic-gate 	 * We don't really care about an error return from the
2967*0Sstevel@tonic-gate 	 * alignment call; that will just result in passing zero,
2968*0Sstevel@tonic-gate 	 * which will be interpreted as no alignment.
2969*0Sstevel@tonic-gate 	 */
2970*0Sstevel@tonic-gate 
2971*0Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
2972*0Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(number_of_sps,
2973*0Sstevel@tonic-gate 		    sp_size, &extent_listp,
2974*0Sstevel@tonic-gate 		    meta_sp_get_default_alignment(mdsetnamep, mdnamep, &mde));
2975*0Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
2976*0Sstevel@tonic-gate 	}
2977*0Sstevel@tonic-gate 	return (succeeded);
2978*0Sstevel@tonic-gate }
2979*0Sstevel@tonic-gate 
2980*0Sstevel@tonic-gate /*
2981*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_can_create_sps_on_drive()
2982*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
2983*0Sstevel@tonic-gate  *			     for the set containing the drive for
2984*0Sstevel@tonic-gate  *			     which the extents are to be listed
2985*0Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
2986*0Sstevel@tonic-gate  *			       on which the soft parititions are to be created
2987*0Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
2988*0Sstevel@tonic-gate  *		sp_size - the desired soft partition size
2989*0Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
2990*0Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the soft partitionns can be created,
2991*0Sstevel@tonic-gate  *			    B_FALSE if not
2992*0Sstevel@tonic-gate  * PURPOSE:	determines whether a set of soft partitions can be created
2993*0Sstevel@tonic-gate  *		on a drive if the entire drive is soft partitioned
2994*0Sstevel@tonic-gate  */
2995*0Sstevel@tonic-gate boolean_t
2996*0Sstevel@tonic-gate meta_sp_can_create_sps_on_drive(
2997*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
2998*0Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
2999*0Sstevel@tonic-gate 	int		number_of_sps,
3000*0Sstevel@tonic-gate 	blkcnt_t	sp_size
3001*0Sstevel@tonic-gate )
3002*0Sstevel@tonic-gate {
3003*0Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
3004*0Sstevel@tonic-gate 	boolean_t	succeeded;
3005*0Sstevel@tonic-gate 
3006*0Sstevel@tonic-gate 	if ((number_of_sps > 0) && (sp_size > 0)) {
3007*0Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
3008*0Sstevel@tonic-gate 							mddrivenamep,
3009*0Sstevel@tonic-gate 							&extent_listp);
3010*0Sstevel@tonic-gate 	} else {
3011*0Sstevel@tonic-gate 		succeeded = B_FALSE;
3012*0Sstevel@tonic-gate 	}
3013*0Sstevel@tonic-gate 
3014*0Sstevel@tonic-gate 	/*
3015*0Sstevel@tonic-gate 	 * We don't care about alignment on the space call because
3016*0Sstevel@tonic-gate 	 * we're specifically dealing with a drive, which will have no
3017*0Sstevel@tonic-gate 	 * inherent alignment.
3018*0Sstevel@tonic-gate 	 */
3019*0Sstevel@tonic-gate 
3020*0Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
3021*0Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(number_of_sps, sp_size,
3022*0Sstevel@tonic-gate 		    &extent_listp, SP_UNALIGNED);
3023*0Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
3024*0Sstevel@tonic-gate 	}
3025*0Sstevel@tonic-gate 	return (succeeded);
3026*0Sstevel@tonic-gate }
3027*0Sstevel@tonic-gate 
3028*0Sstevel@tonic-gate /*
3029*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_free_space()
3030*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
3031*0Sstevel@tonic-gate  *			     for the set containing the device for
3032*0Sstevel@tonic-gate  *			     which the free space is to be returned
3033*0Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
3034*0Sstevel@tonic-gate  *			  for which the free space is to be returned
3035*0Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
3036*0Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the number of blocks of free space on the device
3037*0Sstevel@tonic-gate  * PURPOSE:	returns the number of blocks of free space on a device
3038*0Sstevel@tonic-gate  */
3039*0Sstevel@tonic-gate blkcnt_t
3040*0Sstevel@tonic-gate meta_sp_get_free_space(
3041*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
3042*0Sstevel@tonic-gate 	mdname_t	*mdnamep
3043*0Sstevel@tonic-gate )
3044*0Sstevel@tonic-gate {
3045*0Sstevel@tonic-gate 	sp_ext_node_t		*extent_listp;
3046*0Sstevel@tonic-gate 	sp_ext_length_t		free_blocks;
3047*0Sstevel@tonic-gate 	boolean_t		succeeded;
3048*0Sstevel@tonic-gate 	md_error_t		mde;
3049*0Sstevel@tonic-gate 
3050*0Sstevel@tonic-gate 	extent_listp = NULL;
3051*0Sstevel@tonic-gate 	free_blocks = 0;
3052*0Sstevel@tonic-gate 	succeeded = meta_sp_get_extent_list(mdsetnamep, mdnamep,
3053*0Sstevel@tonic-gate 					    &extent_listp, &mde);
3054*0Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
3055*0Sstevel@tonic-gate 		free_blocks = meta_sp_list_size(extent_listp,
3056*0Sstevel@tonic-gate 		    EXTTYP_FREE, INCLUDE_WM);
3057*0Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
3058*0Sstevel@tonic-gate 		if (free_blocks > (10 * MD_SP_WMSIZE)) {
3059*0Sstevel@tonic-gate 			/*
3060*0Sstevel@tonic-gate 			 * Subtract a safety margin for watermarks when
3061*0Sstevel@tonic-gate 			 * computing the number of blocks available for
3062*0Sstevel@tonic-gate 			 * use.  The actual number of watermarks can't
3063*0Sstevel@tonic-gate 			 * be calculated without knowing the exact numbers
3064*0Sstevel@tonic-gate 			 * and sizes of both the free extents and the soft
3065*0Sstevel@tonic-gate 			 * partitions to be created.  The calculation is
3066*0Sstevel@tonic-gate 			 * highly complex and error-prone even if those
3067*0Sstevel@tonic-gate 			 * quantities are known.  The approximate value
3068*0Sstevel@tonic-gate 			 * 10 * MD_SP_WMSIZE is within a few blocks of the
3069*0Sstevel@tonic-gate 			 * correct value in all practical cases.
3070*0Sstevel@tonic-gate 			 */
3071*0Sstevel@tonic-gate 			free_blocks = free_blocks - (10 * MD_SP_WMSIZE);
3072*0Sstevel@tonic-gate 		} else {
3073*0Sstevel@tonic-gate 			free_blocks = 0;
3074*0Sstevel@tonic-gate 		}
3075*0Sstevel@tonic-gate 	} else {
3076*0Sstevel@tonic-gate 	    mdclrerror(&mde);
3077*0Sstevel@tonic-gate 	}
3078*0Sstevel@tonic-gate 
3079*0Sstevel@tonic-gate 	return (free_blocks);
3080*0Sstevel@tonic-gate }
3081*0Sstevel@tonic-gate 
3082*0Sstevel@tonic-gate /*
3083*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_free_space_on_drive()
3084*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
3085*0Sstevel@tonic-gate  *			     for the set containing the drive for
3086*0Sstevel@tonic-gate  *			     which the free space is to be returned
3087*0Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
3088*0Sstevel@tonic-gate  *			       for which the free space is to be returned
3089*0Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
3090*0Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the number of blocks of free space on the drive
3091*0Sstevel@tonic-gate  * PURPOSE:	returns the number of blocks of space usable for soft
3092*0Sstevel@tonic-gate  *		partitions on an entire drive, if the entire drive is
3093*0Sstevel@tonic-gate  *		soft partitioned
3094*0Sstevel@tonic-gate  */
3095*0Sstevel@tonic-gate blkcnt_t
3096*0Sstevel@tonic-gate meta_sp_get_free_space_on_drive(
3097*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
3098*0Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep
3099*0Sstevel@tonic-gate )
3100*0Sstevel@tonic-gate {
3101*0Sstevel@tonic-gate 	sp_ext_node_t		*extent_listp;
3102*0Sstevel@tonic-gate 	sp_ext_length_t		free_blocks;
3103*0Sstevel@tonic-gate 	boolean_t		succeeded;
3104*0Sstevel@tonic-gate 
3105*0Sstevel@tonic-gate 	extent_listp = NULL;
3106*0Sstevel@tonic-gate 	free_blocks = 0;
3107*0Sstevel@tonic-gate 	succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
3108*0Sstevel@tonic-gate 			mddrivenamep, &extent_listp);
3109*0Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
3110*0Sstevel@tonic-gate 		free_blocks = meta_sp_list_size(extent_listp,
3111*0Sstevel@tonic-gate 		    EXTTYP_FREE, INCLUDE_WM);
3112*0Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
3113*0Sstevel@tonic-gate 		if (free_blocks > (10 * MD_SP_WMSIZE)) {
3114*0Sstevel@tonic-gate 			/*
3115*0Sstevel@tonic-gate 			 * Subtract a safety margin for watermarks when
3116*0Sstevel@tonic-gate 			 * computing the number of blocks available for
3117*0Sstevel@tonic-gate 			 * use.  The actual number of watermarks can't
3118*0Sstevel@tonic-gate 			 * be calculated without knowing the exact numbers
3119*0Sstevel@tonic-gate 			 * and sizes of both the free extents and the soft
3120*0Sstevel@tonic-gate 			 * partitions to be created.  The calculation is
3121*0Sstevel@tonic-gate 			 * highly complex and error-prone even if those
3122*0Sstevel@tonic-gate 			 * quantities are known.  The approximate value
3123*0Sstevel@tonic-gate 			 * 10 * MD_SP_WMSIZE is within a few blocks of the
3124*0Sstevel@tonic-gate 			 * correct value in all practical cases.
3125*0Sstevel@tonic-gate 			 */
3126*0Sstevel@tonic-gate 			free_blocks = free_blocks - (10 * MD_SP_WMSIZE);
3127*0Sstevel@tonic-gate 		} else {
3128*0Sstevel@tonic-gate 			free_blocks = 0;
3129*0Sstevel@tonic-gate 		}
3130*0Sstevel@tonic-gate 	}
3131*0Sstevel@tonic-gate 	return (free_blocks);
3132*0Sstevel@tonic-gate }
3133*0Sstevel@tonic-gate 
3134*0Sstevel@tonic-gate /*
3135*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_number_of_possible_sps()
3136*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
3137*0Sstevel@tonic-gate  *			     for the set containing the device for
3138*0Sstevel@tonic-gate  *			     which the number of possible soft partitions
3139*0Sstevel@tonic-gate  *			     is to be returned
3140*0Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
3141*0Sstevel@tonic-gate  *			  for which the number of possible soft partitions
3142*0Sstevel@tonic-gate  *			  is to be returned
3143*0Sstevel@tonic-gate  * OUTPUT:	int return value
3144*0Sstevel@tonic-gate  * RETURNS:	int - the number of soft partitions of the desired size
3145*0Sstevel@tonic-gate  *		      that can be created on the device
3146*0Sstevel@tonic-gate  * PURPOSE:	returns the number of soft partitions of a given size
3147*0Sstevel@tonic-gate  *		that can be created on a device
3148*0Sstevel@tonic-gate  */
3149*0Sstevel@tonic-gate int
3150*0Sstevel@tonic-gate meta_sp_get_number_of_possible_sps(
3151*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
3152*0Sstevel@tonic-gate 	mdname_t	*mdnamep,
3153*0Sstevel@tonic-gate 	blkcnt_t	sp_size
3154*0Sstevel@tonic-gate )
3155*0Sstevel@tonic-gate {
3156*0Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
3157*0Sstevel@tonic-gate 	int		number_of_possible_sps;
3158*0Sstevel@tonic-gate 	boolean_t	succeeded;
3159*0Sstevel@tonic-gate 	md_error_t	mde;
3160*0Sstevel@tonic-gate 	sp_ext_length_t	alignment;
3161*0Sstevel@tonic-gate 
3162*0Sstevel@tonic-gate 	extent_listp = NULL;
3163*0Sstevel@tonic-gate 	number_of_possible_sps = 0;
3164*0Sstevel@tonic-gate 	if (sp_size > 0) {
3165*0Sstevel@tonic-gate 	    if ((succeeded = meta_sp_get_extent_list(mdsetnamep,
3166*0Sstevel@tonic-gate 		mdnamep, &extent_listp, &mde)) == B_FALSE)
3167*0Sstevel@tonic-gate 		mdclrerror(&mde);
3168*0Sstevel@tonic-gate 	} else {
3169*0Sstevel@tonic-gate 		succeeded = B_FALSE;
3170*0Sstevel@tonic-gate 	}
3171*0Sstevel@tonic-gate 
3172*0Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
3173*0Sstevel@tonic-gate 		alignment = meta_sp_get_default_alignment(mdsetnamep,
3174*0Sstevel@tonic-gate 		    mdnamep, &mde);
3175*0Sstevel@tonic-gate 	}
3176*0Sstevel@tonic-gate 
3177*0Sstevel@tonic-gate 	while (succeeded == B_TRUE) {
3178*0Sstevel@tonic-gate 		/*
3179*0Sstevel@tonic-gate 		 * Keep allocating space from the extent list
3180*0Sstevel@tonic-gate 		 * for soft partitions of the desired size until
3181*0Sstevel@tonic-gate 		 * there's not enough free space left in the list
3182*0Sstevel@tonic-gate 		 * for another soft partiition of that size.
3183*0Sstevel@tonic-gate 		 * Add one to the number of possible soft partitions
3184*0Sstevel@tonic-gate 		 * for each soft partition for which there is
3185*0Sstevel@tonic-gate 		 * enough free space left.
3186*0Sstevel@tonic-gate 		 */
3187*0Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(ONE_SOFT_PARTITION,
3188*0Sstevel@tonic-gate 		    sp_size, &extent_listp, alignment);
3189*0Sstevel@tonic-gate 		if (succeeded == B_TRUE) {
3190*0Sstevel@tonic-gate 			number_of_possible_sps++;
3191*0Sstevel@tonic-gate 		}
3192*0Sstevel@tonic-gate 	}
3193*0Sstevel@tonic-gate 	if (extent_listp != NULL) {
3194*0Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
3195*0Sstevel@tonic-gate 	}
3196*0Sstevel@tonic-gate 	return (number_of_possible_sps);
3197*0Sstevel@tonic-gate }
3198*0Sstevel@tonic-gate 
3199*0Sstevel@tonic-gate /*
3200*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_number_of_possible_sps_on_drive()
3201*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
3202*0Sstevel@tonic-gate  *			     for the set containing the drive for
3203*0Sstevel@tonic-gate  *			     which the number of possible soft partitions
3204*0Sstevel@tonic-gate  *			     is to be returned
3205*0Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
3206*0Sstevel@tonic-gate  *			       for which the number of possible soft partitions
3207*0Sstevel@tonic-gate  *			       is to be returned
3208*0Sstevel@tonic-gate  *		sp_size - the size in blocks of the proposed soft partitions
3209*0Sstevel@tonic-gate  * OUTPUT:	int return value
3210*0Sstevel@tonic-gate  * RETURNS:	int - the number of soft partitions of the desired size
3211*0Sstevel@tonic-gate  *		      that can be created on the drive
3212*0Sstevel@tonic-gate  * PURPOSE:	returns the number of soft partitions of a given size
3213*0Sstevel@tonic-gate  *		that can be created on a drive, if the entire drive is
3214*0Sstevel@tonic-gate  *		soft partitioned
3215*0Sstevel@tonic-gate  */
3216*0Sstevel@tonic-gate int
3217*0Sstevel@tonic-gate meta_sp_get_number_of_possible_sps_on_drive(
3218*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
3219*0Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
3220*0Sstevel@tonic-gate 	blkcnt_t	sp_size
3221*0Sstevel@tonic-gate )
3222*0Sstevel@tonic-gate {
3223*0Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
3224*0Sstevel@tonic-gate 	int		number_of_possible_sps;
3225*0Sstevel@tonic-gate 	boolean_t	succeeded;
3226*0Sstevel@tonic-gate 
3227*0Sstevel@tonic-gate 	extent_listp = NULL;
3228*0Sstevel@tonic-gate 	number_of_possible_sps = 0;
3229*0Sstevel@tonic-gate 	if (sp_size > 0) {
3230*0Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
3231*0Sstevel@tonic-gate 					mddrivenamep, &extent_listp);
3232*0Sstevel@tonic-gate 	} else {
3233*0Sstevel@tonic-gate 		succeeded = B_FALSE;
3234*0Sstevel@tonic-gate 	}
3235*0Sstevel@tonic-gate 	while (succeeded == B_TRUE) {
3236*0Sstevel@tonic-gate 		/*
3237*0Sstevel@tonic-gate 		 * Keep allocating space from the extent list
3238*0Sstevel@tonic-gate 		 * for soft partitions of the desired size until
3239*0Sstevel@tonic-gate 		 * there's not enough free space left in the list
3240*0Sstevel@tonic-gate 		 * for another soft partition of that size.
3241*0Sstevel@tonic-gate 		 * Add one to the number of possible soft partitions
3242*0Sstevel@tonic-gate 		 * for each soft partition for which there is
3243*0Sstevel@tonic-gate 		 * enough free space left.
3244*0Sstevel@tonic-gate 		 *
3245*0Sstevel@tonic-gate 		 * Since it's a drive, not a metadevice, make no
3246*0Sstevel@tonic-gate 		 * assumptions about alignment.
3247*0Sstevel@tonic-gate 		 */
3248*0Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(ONE_SOFT_PARTITION,
3249*0Sstevel@tonic-gate 		    sp_size, &extent_listp, SP_UNALIGNED);
3250*0Sstevel@tonic-gate 		if (succeeded == B_TRUE) {
3251*0Sstevel@tonic-gate 			number_of_possible_sps++;
3252*0Sstevel@tonic-gate 		}
3253*0Sstevel@tonic-gate 	}
3254*0Sstevel@tonic-gate 	if (extent_listp != NULL) {
3255*0Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
3256*0Sstevel@tonic-gate 	}
3257*0Sstevel@tonic-gate 	return (number_of_possible_sps);
3258*0Sstevel@tonic-gate }
3259*0Sstevel@tonic-gate 
3260*0Sstevel@tonic-gate /*
3261*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_possible_sp_size()
3262*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
3263*0Sstevel@tonic-gate  *			     for the set containing the device for
3264*0Sstevel@tonic-gate  *			     which the possible soft partition size
3265*0Sstevel@tonic-gate  *			     is to be returned
3266*0Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
3267*0Sstevel@tonic-gate  *			  for which the possible soft partition size
3268*0Sstevel@tonic-gate  *			  is to be returned
3269*0Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
3270*0Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
3271*0Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the possible soft partition size in blocks
3272*0Sstevel@tonic-gate  * PURPOSE:	returns the maximum possible size of each of a given number of
3273*0Sstevel@tonic-gate  *		soft partitions of equal size that can be created on a device
3274*0Sstevel@tonic-gate  */
3275*0Sstevel@tonic-gate blkcnt_t
3276*0Sstevel@tonic-gate meta_sp_get_possible_sp_size(
3277*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
3278*0Sstevel@tonic-gate 	mdname_t	*mdnamep,
3279*0Sstevel@tonic-gate 	int		number_of_sps
3280*0Sstevel@tonic-gate )
3281*0Sstevel@tonic-gate {
3282*0Sstevel@tonic-gate 	blkcnt_t	free_blocks;
3283*0Sstevel@tonic-gate 	blkcnt_t	sp_size;
3284*0Sstevel@tonic-gate 	boolean_t	succeeded;
3285*0Sstevel@tonic-gate 
3286*0Sstevel@tonic-gate 	sp_size = 0;
3287*0Sstevel@tonic-gate 	if (number_of_sps > 0) {
3288*0Sstevel@tonic-gate 		free_blocks = meta_sp_get_free_space(mdsetnamep, mdnamep);
3289*0Sstevel@tonic-gate 		sp_size = free_blocks / number_of_sps;
3290*0Sstevel@tonic-gate 		succeeded = meta_sp_can_create_sps(mdsetnamep, mdnamep,
3291*0Sstevel@tonic-gate 						number_of_sps, sp_size);
3292*0Sstevel@tonic-gate 		while ((succeeded == B_FALSE) && (sp_size > 0)) {
3293*0Sstevel@tonic-gate 			/*
3294*0Sstevel@tonic-gate 			 * To compensate for space that may have been
3295*0Sstevel@tonic-gate 			 * occupied by watermarks, reduce sp_size by a
3296*0Sstevel@tonic-gate 			 * number of blocks equal to the number of soft
3297*0Sstevel@tonic-gate 			 * partitions desired, and test again to see
3298*0Sstevel@tonic-gate 			 * whether the desired number of soft partitions
3299*0Sstevel@tonic-gate 			 * can be created.
3300*0Sstevel@tonic-gate 			 */
3301*0Sstevel@tonic-gate 			sp_size = sp_size - ((blkcnt_t)number_of_sps);
3302*0Sstevel@tonic-gate 			succeeded = meta_sp_can_create_sps(mdsetnamep, mdnamep,
3303*0Sstevel@tonic-gate 							number_of_sps, sp_size);
3304*0Sstevel@tonic-gate 		}
3305*0Sstevel@tonic-gate 		if (sp_size < 0) {
3306*0Sstevel@tonic-gate 			sp_size = 0;
3307*0Sstevel@tonic-gate 		}
3308*0Sstevel@tonic-gate 	}
3309*0Sstevel@tonic-gate 	return (sp_size);
3310*0Sstevel@tonic-gate }
3311*0Sstevel@tonic-gate 
3312*0Sstevel@tonic-gate /*
3313*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_possible_sp_size_on_drive()
3314*0Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
3315*0Sstevel@tonic-gate  *			     for the set containing the drive for
3316*0Sstevel@tonic-gate  *			     which the possible soft partition size
3317*0Sstevel@tonic-gate  *			     is to be returned
3318*0Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
3319*0Sstevel@tonic-gate  *			       for which the possible soft partition size
3320*0Sstevel@tonic-gate  *			       is to be returned
3321*0Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
3322*0Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
3323*0Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the possible soft partition size in blocks
3324*0Sstevel@tonic-gate  * PURPOSE:	returns the maximum possible size of each of a given number of
3325*0Sstevel@tonic-gate  *		soft partitions of equal size that can be created on a drive
3326*0Sstevel@tonic-gate  *              if the entire drive is soft partitioned
3327*0Sstevel@tonic-gate  */
3328*0Sstevel@tonic-gate blkcnt_t
3329*0Sstevel@tonic-gate meta_sp_get_possible_sp_size_on_drive(
3330*0Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
3331*0Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
3332*0Sstevel@tonic-gate 	int		number_of_sps
3333*0Sstevel@tonic-gate )
3334*0Sstevel@tonic-gate {
3335*0Sstevel@tonic-gate 	blkcnt_t	free_blocks;
3336*0Sstevel@tonic-gate 	blkcnt_t	sp_size;
3337*0Sstevel@tonic-gate 	boolean_t	succeeded;
3338*0Sstevel@tonic-gate 
3339*0Sstevel@tonic-gate 	sp_size = 0;
3340*0Sstevel@tonic-gate 	if (number_of_sps > 0) {
3341*0Sstevel@tonic-gate 		free_blocks = meta_sp_get_free_space_on_drive(mdsetnamep,
3342*0Sstevel@tonic-gate 								mddrivenamep);
3343*0Sstevel@tonic-gate 		sp_size = free_blocks / number_of_sps;
3344*0Sstevel@tonic-gate 		succeeded = meta_sp_can_create_sps_on_drive(mdsetnamep,
3345*0Sstevel@tonic-gate 						mddrivenamep,
3346*0Sstevel@tonic-gate 						number_of_sps, sp_size);
3347*0Sstevel@tonic-gate 		while ((succeeded == B_FALSE) && (sp_size > 0)) {
3348*0Sstevel@tonic-gate 			/*
3349*0Sstevel@tonic-gate 			 * To compensate for space that may have been
3350*0Sstevel@tonic-gate 			 * occupied by watermarks, reduce sp_size by a
3351*0Sstevel@tonic-gate 			 * number of blocks equal to the number of soft
3352*0Sstevel@tonic-gate 			 * partitions desired, and test again to see
3353*0Sstevel@tonic-gate 			 * whether the desired number of soft partitions
3354*0Sstevel@tonic-gate 			 * can be created.
3355*0Sstevel@tonic-gate 			 */
3356*0Sstevel@tonic-gate 			sp_size = sp_size - ((blkcnt_t)number_of_sps);
3357*0Sstevel@tonic-gate 			succeeded = meta_sp_can_create_sps_on_drive(mdsetnamep,
3358*0Sstevel@tonic-gate 							mddrivenamep,
3359*0Sstevel@tonic-gate 							number_of_sps, sp_size);
3360*0Sstevel@tonic-gate 		}
3361*0Sstevel@tonic-gate 		if (sp_size < 0) {
3362*0Sstevel@tonic-gate 			sp_size = 0;
3363*0Sstevel@tonic-gate 		}
3364*0Sstevel@tonic-gate 	}
3365*0Sstevel@tonic-gate 	return (sp_size);
3366*0Sstevel@tonic-gate }
3367*0Sstevel@tonic-gate 
3368*0Sstevel@tonic-gate /*
3369*0Sstevel@tonic-gate  * **************************************************************************
3370*0Sstevel@tonic-gate  *                  Unit Structure Manipulation Functions                   *
3371*0Sstevel@tonic-gate  * **************************************************************************
3372*0Sstevel@tonic-gate  */
3373*0Sstevel@tonic-gate 
3374*0Sstevel@tonic-gate /*
3375*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_fillextarray()
3376*0Sstevel@tonic-gate  * INPUT:	mp	- the unit structure to fill
3377*0Sstevel@tonic-gate  *		extlist	- the list of extents to fill with
3378*0Sstevel@tonic-gate  * OUTPUT:	none
3379*0Sstevel@tonic-gate  * RETURNS:	void
3380*0Sstevel@tonic-gate  * PURPOSE:	fills in the unit structure extent list with the extents
3381*0Sstevel@tonic-gate  *		specified by extlist.  Only extents in extlist with the
3382*0Sstevel@tonic-gate  *		EXTFLG_UPDATE flag are changed in the unit structure,
3383*0Sstevel@tonic-gate  *		and the index into the unit structure is the sequence
3384*0Sstevel@tonic-gate  *		number in the extent list.  After all of the nodes have
3385*0Sstevel@tonic-gate  *		been updated the virtual offsets in the unit structure
3386*0Sstevel@tonic-gate  *		are updated to reflect the new lengths.
3387*0Sstevel@tonic-gate  */
3388*0Sstevel@tonic-gate static void
3389*0Sstevel@tonic-gate meta_sp_fillextarray(
3390*0Sstevel@tonic-gate 	mp_unit_t	*mp,
3391*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist
3392*0Sstevel@tonic-gate )
3393*0Sstevel@tonic-gate {
3394*0Sstevel@tonic-gate 	int	i;
3395*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
3396*0Sstevel@tonic-gate 	sp_ext_offset_t	curvoff = 0LL;
3397*0Sstevel@tonic-gate 
3398*0Sstevel@tonic-gate 	assert(mp != NULL);
3399*0Sstevel@tonic-gate 
3400*0Sstevel@tonic-gate 	/* go through the allocation list and fill in our unit structure */
3401*0Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
3402*0Sstevel@tonic-gate 		if ((ext->ext_type == EXTTYP_ALLOC) &&
3403*0Sstevel@tonic-gate 		    (ext->ext_flags & EXTFLG_UPDATE) != 0) {
3404*0Sstevel@tonic-gate 			mp->un_ext[ext->ext_seq].un_poff =
3405*0Sstevel@tonic-gate 			    ext->ext_offset + MD_SP_WMSIZE;
3406*0Sstevel@tonic-gate 			mp->un_ext[ext->ext_seq].un_len =
3407*0Sstevel@tonic-gate 			    ext->ext_length - MD_SP_WMSIZE;
3408*0Sstevel@tonic-gate 		}
3409*0Sstevel@tonic-gate 	}
3410*0Sstevel@tonic-gate 
3411*0Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
3412*0Sstevel@tonic-gate 		assert(mp->un_ext[i].un_poff != 0);
3413*0Sstevel@tonic-gate 		assert(mp->un_ext[i].un_len  != 0);
3414*0Sstevel@tonic-gate 		mp->un_ext[i].un_voff = curvoff;
3415*0Sstevel@tonic-gate 		curvoff += mp->un_ext[i].un_len;
3416*0Sstevel@tonic-gate 	}
3417*0Sstevel@tonic-gate }
3418*0Sstevel@tonic-gate 
3419*0Sstevel@tonic-gate /*
3420*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_createunit()
3421*0Sstevel@tonic-gate  * INPUT:	np	- the name of the device to create a unit structure for
3422*0Sstevel@tonic-gate  *		compnp	- the name of the device the soft partition is on
3423*0Sstevel@tonic-gate  *		extlist	- the extent list to populate the new unit with
3424*0Sstevel@tonic-gate  *		numexts	- the number of extents in the extent list
3425*0Sstevel@tonic-gate  *		len	- the total size of the soft partition (sectors)
3426*0Sstevel@tonic-gate  *		status	- the initial status of the unit structure
3427*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
3428*0Sstevel@tonic-gate  * RETURNS:	mp_unit_t * - the new unit structure.
3429*0Sstevel@tonic-gate  * PURPOSE:	allocates and fills in a new soft partition unit
3430*0Sstevel@tonic-gate  *		structure to be passed to the soft partitioning driver
3431*0Sstevel@tonic-gate  *		for creation.
3432*0Sstevel@tonic-gate  */
3433*0Sstevel@tonic-gate static mp_unit_t *
3434*0Sstevel@tonic-gate meta_sp_createunit(
3435*0Sstevel@tonic-gate 	mdname_t	*np,
3436*0Sstevel@tonic-gate 	mdname_t	*compnp,
3437*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
3438*0Sstevel@tonic-gate 	int		numexts,
3439*0Sstevel@tonic-gate 	sp_ext_length_t	len,
3440*0Sstevel@tonic-gate 	sp_status_t	status,
3441*0Sstevel@tonic-gate 	md_error_t	*ep
3442*0Sstevel@tonic-gate )
3443*0Sstevel@tonic-gate {
3444*0Sstevel@tonic-gate 	mp_unit_t	*mp;
3445*0Sstevel@tonic-gate 	uint_t		ms_size;
3446*0Sstevel@tonic-gate 
3447*0Sstevel@tonic-gate 	ms_size = (sizeof (*mp) - sizeof (mp->un_ext[0])) +
3448*0Sstevel@tonic-gate 	    (numexts * sizeof (mp->un_ext[0]));
3449*0Sstevel@tonic-gate 
3450*0Sstevel@tonic-gate 	mp = Zalloc(ms_size);
3451*0Sstevel@tonic-gate 
3452*0Sstevel@tonic-gate 	/* fill in fields in common unit structure */
3453*0Sstevel@tonic-gate 	mp->c.un_type = MD_METASP;
3454*0Sstevel@tonic-gate 	mp->c.un_size = ms_size;
3455*0Sstevel@tonic-gate 	MD_SID(mp) = meta_getminor(np->dev);
3456*0Sstevel@tonic-gate 	mp->c.un_total_blocks = len;
3457*0Sstevel@tonic-gate 	mp->c.un_actual_tb = len;
3458*0Sstevel@tonic-gate 
3459*0Sstevel@tonic-gate 	/* set up geometry */
3460*0Sstevel@tonic-gate 	(void) meta_sp_setgeom(np, compnp, mp, ep);
3461*0Sstevel@tonic-gate 
3462*0Sstevel@tonic-gate 	/* if we're building on metadevice we can't parent */
3463*0Sstevel@tonic-gate 	if (metaismeta(compnp))
3464*0Sstevel@tonic-gate 		MD_CAPAB(mp) = MD_CANT_PARENT;
3465*0Sstevel@tonic-gate 	else
3466*0Sstevel@tonic-gate 		MD_CAPAB(mp) = MD_CAN_PARENT;
3467*0Sstevel@tonic-gate 
3468*0Sstevel@tonic-gate 	/* fill soft partition-specific fields */
3469*0Sstevel@tonic-gate 	mp->un_dev = compnp->dev;
3470*0Sstevel@tonic-gate 	mp->un_key = compnp->key;
3471*0Sstevel@tonic-gate 
3472*0Sstevel@tonic-gate 	/* mdname_t start_blk field is not 64-bit! */
3473*0Sstevel@tonic-gate 	mp->un_start_blk = (sp_ext_offset_t)compnp->start_blk;
3474*0Sstevel@tonic-gate 	mp->un_status = status;
3475*0Sstevel@tonic-gate 	mp->un_numexts = numexts;
3476*0Sstevel@tonic-gate 	mp->un_length = len;
3477*0Sstevel@tonic-gate 
3478*0Sstevel@tonic-gate 	/* fill in the extent array */
3479*0Sstevel@tonic-gate 	meta_sp_fillextarray(mp, extlist);
3480*0Sstevel@tonic-gate 
3481*0Sstevel@tonic-gate 	return (mp);
3482*0Sstevel@tonic-gate }
3483*0Sstevel@tonic-gate 
3484*0Sstevel@tonic-gate /*
3485*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_updateunit()
3486*0Sstevel@tonic-gate  * INPUT:	np       - name structure for the metadevice being updated
3487*0Sstevel@tonic-gate  *		old_un	 - the original unit structure that is being updated
3488*0Sstevel@tonic-gate  *		extlist	 - the extent list to populate the new unit with
3489*0Sstevel@tonic-gate  *		grow_len - the amount by which the partition is being grown
3490*0Sstevel@tonic-gate  *		numexts	 - the number of extents in the extent list
3491*0Sstevel@tonic-gate  *		ep       - return error pointer
3492*0Sstevel@tonic-gate  * OUTPUT:	none
3493*0Sstevel@tonic-gate  * RETURNS:	mp_unit_t * - the updated unit structure
3494*0Sstevel@tonic-gate  * PURPOSE:	allocates and fills in a new soft partition unit structure to
3495*0Sstevel@tonic-gate  *		be passed to the soft partitioning driver for creation.  The
3496*0Sstevel@tonic-gate  *		old unit structure is first copied in, and then the updated
3497*0Sstevel@tonic-gate  *		extents are changed in the new unit structure.  This is
3498*0Sstevel@tonic-gate  *		typically used when the size of an existing unit is changed.
3499*0Sstevel@tonic-gate  */
3500*0Sstevel@tonic-gate static mp_unit_t *
3501*0Sstevel@tonic-gate meta_sp_updateunit(
3502*0Sstevel@tonic-gate 	mdname_t	*np,
3503*0Sstevel@tonic-gate 	mp_unit_t	*old_un,
3504*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
3505*0Sstevel@tonic-gate 	sp_ext_length_t	grow_len,
3506*0Sstevel@tonic-gate 	int		numexts,
3507*0Sstevel@tonic-gate 	md_error_t	*ep
3508*0Sstevel@tonic-gate )
3509*0Sstevel@tonic-gate {
3510*0Sstevel@tonic-gate 	mp_unit_t	*new_un;
3511*0Sstevel@tonic-gate 	sp_ext_length_t	new_len;
3512*0Sstevel@tonic-gate 	uint_t		new_size;
3513*0Sstevel@tonic-gate 
3514*0Sstevel@tonic-gate 	assert(old_un != NULL);
3515*0Sstevel@tonic-gate 	assert(extlist != NULL);
3516*0Sstevel@tonic-gate 
3517*0Sstevel@tonic-gate 	/* allocate new unit structure and copy in old unit */
3518*0Sstevel@tonic-gate 	new_size = (sizeof (*old_un) - sizeof (old_un->un_ext[0])) +
3519*0Sstevel@tonic-gate 	    ((old_un->un_numexts + numexts) * sizeof (old_un->un_ext[0]));
3520*0Sstevel@tonic-gate 	new_len = old_un->un_length + grow_len;
3521*0Sstevel@tonic-gate 	new_un = Zalloc(new_size);
3522*0Sstevel@tonic-gate 	bcopy(old_un, new_un, old_un->c.un_size);
3523*0Sstevel@tonic-gate 
3524*0Sstevel@tonic-gate 	/* update size and geometry information */
3525*0Sstevel@tonic-gate 	new_un->c.un_size = new_size;
3526*0Sstevel@tonic-gate 	new_un->un_length = new_len;
3527*0Sstevel@tonic-gate 	new_un->c.un_total_blocks = new_len;
3528*0Sstevel@tonic-gate 	new_un->c.un_actual_tb = new_len;
3529*0Sstevel@tonic-gate 	if (meta_adjust_geom((md_unit_t *)new_un, np,
3530*0Sstevel@tonic-gate 	    old_un->c.un_wr_reinstruct, old_un->c.un_rd_reinstruct,
3531*0Sstevel@tonic-gate 	    0, ep) != 0) {
3532*0Sstevel@tonic-gate 		Free(new_un);
3533*0Sstevel@tonic-gate 		return (NULL);
3534*0Sstevel@tonic-gate 	}
3535*0Sstevel@tonic-gate 
3536*0Sstevel@tonic-gate 	/* update extent information */
3537*0Sstevel@tonic-gate 	new_un->un_numexts += numexts;
3538*0Sstevel@tonic-gate 
3539*0Sstevel@tonic-gate 	meta_sp_fillextarray(new_un, extlist);
3540*0Sstevel@tonic-gate 
3541*0Sstevel@tonic-gate 	return (new_un);
3542*0Sstevel@tonic-gate }
3543*0Sstevel@tonic-gate 
3544*0Sstevel@tonic-gate /*
3545*0Sstevel@tonic-gate  * FUNCTION:	meta_get_sp()
3546*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to get
3547*0Sstevel@tonic-gate  *		np	- the name of the device to get
3548*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
3549*0Sstevel@tonic-gate  * RETURNS:	md_sp_t * - the XDR unit structure for the soft partition
3550*0Sstevel@tonic-gate  * PURPOSE:	interface to the rest of libmeta for fetching a unit structure
3551*0Sstevel@tonic-gate  *		for the named device.  Just a wrapper for meta_get_sp_common().
3552*0Sstevel@tonic-gate  */
3553*0Sstevel@tonic-gate md_sp_t *
3554*0Sstevel@tonic-gate meta_get_sp(
3555*0Sstevel@tonic-gate 	mdsetname_t	*sp,
3556*0Sstevel@tonic-gate 	mdname_t	*np,
3557*0Sstevel@tonic-gate 	md_error_t	*ep
3558*0Sstevel@tonic-gate )
3559*0Sstevel@tonic-gate {
3560*0Sstevel@tonic-gate 	return (meta_get_sp_common(sp, np, 0, ep));
3561*0Sstevel@tonic-gate }
3562*0Sstevel@tonic-gate 
3563*0Sstevel@tonic-gate /*
3564*0Sstevel@tonic-gate  * FUNCTION:	meta_get_sp_common()
3565*0Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to get
3566*0Sstevel@tonic-gate  *		np	- the name of the device to get
3567*0Sstevel@tonic-gate  *		fast	- whether to use the cache or not (NOT IMPLEMENTED!)
3568*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
3569*0Sstevel@tonic-gate  * RETURNS:	md_sp_t * - the XDR unit structure for the soft partition,
3570*0Sstevel@tonic-gate  *			    NULL if np is not a soft partition
3571*0Sstevel@tonic-gate  * PURPOSE:	common routine for fetching a soft partition unit structure
3572*0Sstevel@tonic-gate  */
3573*0Sstevel@tonic-gate md_sp_t *
3574*0Sstevel@tonic-gate meta_get_sp_common(
3575*0Sstevel@tonic-gate 	mdsetname_t	*sp,
3576*0Sstevel@tonic-gate 	mdname_t	*np,
3577*0Sstevel@tonic-gate 	int		fast,
3578*0Sstevel@tonic-gate 	md_error_t	*ep
3579*0Sstevel@tonic-gate )
3580*0Sstevel@tonic-gate {
3581*0Sstevel@tonic-gate 	mddrivename_t	*dnp = np->drivenamep;
3582*0Sstevel@tonic-gate 	char		*miscname;
3583*0Sstevel@tonic-gate 	mp_unit_t	*mp;
3584*0Sstevel@tonic-gate 	md_sp_t		*msp;
3585*0Sstevel@tonic-gate 	int		i;
3586*0Sstevel@tonic-gate 
3587*0Sstevel@tonic-gate 	/* must have set */
3588*0Sstevel@tonic-gate 	assert(sp != NULL);
3589*0Sstevel@tonic-gate 
3590*0Sstevel@tonic-gate 	/* short circuit */
3591*0Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
3592*0Sstevel@tonic-gate 		if (dnp->unitp->type != MD_METASP)
3593*0Sstevel@tonic-gate 			return (NULL);
3594*0Sstevel@tonic-gate 		return ((md_sp_t *)dnp->unitp);
3595*0Sstevel@tonic-gate 	}
3596*0Sstevel@tonic-gate 	/* get miscname and unit */
3597*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
3598*0Sstevel@tonic-gate 		return (NULL);
3599*0Sstevel@tonic-gate 
3600*0Sstevel@tonic-gate 	if (strcmp(miscname, MD_SP) != 0) {
3601*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_SP, 0, np->cname);
3602*0Sstevel@tonic-gate 		return (NULL);
3603*0Sstevel@tonic-gate 	}
3604*0Sstevel@tonic-gate 
3605*0Sstevel@tonic-gate 	if ((mp = (mp_unit_t *)meta_get_mdunit(sp, np, ep)) == NULL)
3606*0Sstevel@tonic-gate 		return (NULL);
3607*0Sstevel@tonic-gate 
3608*0Sstevel@tonic-gate 	assert(mp->c.un_type == MD_METASP);
3609*0Sstevel@tonic-gate 
3610*0Sstevel@tonic-gate 	/* allocate soft partition */
3611*0Sstevel@tonic-gate 	msp = Zalloc(sizeof (*msp));
3612*0Sstevel@tonic-gate 
3613*0Sstevel@tonic-gate 	/* get the common information */
3614*0Sstevel@tonic-gate 	msp->common.namep = np;
3615*0Sstevel@tonic-gate 	msp->common.type = mp->c.un_type;
3616*0Sstevel@tonic-gate 	msp->common.state = mp->c.un_status;
3617*0Sstevel@tonic-gate 	msp->common.capabilities = mp->c.un_capabilities;
3618*0Sstevel@tonic-gate 	msp->common.parent = mp->c.un_parent;
3619*0Sstevel@tonic-gate 	msp->common.size = mp->c.un_total_blocks;
3620*0Sstevel@tonic-gate 	msp->common.user_flags = mp->c.un_user_flags;
3621*0Sstevel@tonic-gate 	msp->common.revision = mp->c.un_revision;
3622*0Sstevel@tonic-gate 
3623*0Sstevel@tonic-gate 	/* get soft partition information */
3624*0Sstevel@tonic-gate 	if ((msp->compnamep = metakeyname(&sp, mp->un_key, fast, ep)) == NULL)
3625*0Sstevel@tonic-gate 		goto out;
3626*0Sstevel@tonic-gate 
3627*0Sstevel@tonic-gate 	/*
3628*0Sstevel@tonic-gate 	 * Fill in the key and the start block.  Note that the start
3629*0Sstevel@tonic-gate 	 * block in the unit structure is 64 bits but the name pointer
3630*0Sstevel@tonic-gate 	 * only supports 32 bits.
3631*0Sstevel@tonic-gate 	 */
3632*0Sstevel@tonic-gate 	msp->compnamep->key = mp->un_key;
3633*0Sstevel@tonic-gate 	msp->compnamep->start_blk = mp->un_start_blk;
3634*0Sstevel@tonic-gate 
3635*0Sstevel@tonic-gate 	/* fill in status field */
3636*0Sstevel@tonic-gate 	msp->status = mp->un_status;
3637*0Sstevel@tonic-gate 
3638*0Sstevel@tonic-gate 	/* allocate the extents */
3639*0Sstevel@tonic-gate 	msp->ext.ext_val = Zalloc(mp->un_numexts * sizeof (*msp->ext.ext_val));
3640*0Sstevel@tonic-gate 	msp->ext.ext_len = mp->un_numexts;
3641*0Sstevel@tonic-gate 
3642*0Sstevel@tonic-gate 	/* do the extents for this soft partition */
3643*0Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
3644*0Sstevel@tonic-gate 		struct mp_ext	*mde = &mp->un_ext[i];
3645*0Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[i];
3646*0Sstevel@tonic-gate 
3647*0Sstevel@tonic-gate 		extp->voff = mde->un_voff;
3648*0Sstevel@tonic-gate 		extp->poff = mde->un_poff;
3649*0Sstevel@tonic-gate 		extp->len = mde->un_len;
3650*0Sstevel@tonic-gate 	}
3651*0Sstevel@tonic-gate 
3652*0Sstevel@tonic-gate 	/* cleanup, return success */
3653*0Sstevel@tonic-gate 	Free(mp);
3654*0Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)msp;
3655*0Sstevel@tonic-gate 	return (msp);
3656*0Sstevel@tonic-gate 
3657*0Sstevel@tonic-gate out:
3658*0Sstevel@tonic-gate 	/* clean up and return error */
3659*0Sstevel@tonic-gate 	Free(mp);
3660*0Sstevel@tonic-gate 	Free(msp);
3661*0Sstevel@tonic-gate 	return (NULL);
3662*0Sstevel@tonic-gate }
3663*0Sstevel@tonic-gate 
3664*0Sstevel@tonic-gate 
3665*0Sstevel@tonic-gate /*
3666*0Sstevel@tonic-gate  * FUNCTION:	meta_init_sp()
3667*0Sstevel@tonic-gate  * INPUT:	spp	- the set name for the new device
3668*0Sstevel@tonic-gate  *		argc	- the remaining argument count for the metainit cmdline
3669*0Sstevel@tonic-gate  *		argv	- the remainder of the unparsed command line
3670*0Sstevel@tonic-gate  *		options	- global options parsed by metainit
3671*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
3672*0Sstevel@tonic-gate  * RETURNS:	int	- -1 failure, 0 success
3673*0Sstevel@tonic-gate  * PURPOSE:	provides the command line parsing and name management overhead
3674*0Sstevel@tonic-gate  *		for creating a new soft partition.  Ultimately this calls
3675*0Sstevel@tonic-gate  *		meta_create_sp() which does the real work of allocating space
3676*0Sstevel@tonic-gate  *		for the new soft partition.
3677*0Sstevel@tonic-gate  */
3678*0Sstevel@tonic-gate int
3679*0Sstevel@tonic-gate meta_init_sp(
3680*0Sstevel@tonic-gate 	mdsetname_t	**spp,
3681*0Sstevel@tonic-gate 	int		argc,
3682*0Sstevel@tonic-gate 	char		*argv[],
3683*0Sstevel@tonic-gate 	mdcmdopts_t	options,
3684*0Sstevel@tonic-gate 	md_error_t	*ep
3685*0Sstevel@tonic-gate )
3686*0Sstevel@tonic-gate {
3687*0Sstevel@tonic-gate 	char		*compname = NULL;
3688*0Sstevel@tonic-gate 	mdname_t	*spcompnp = NULL;	/* name of component volume */
3689*0Sstevel@tonic-gate 	char		*devname = argv[0];	/* unit name */
3690*0Sstevel@tonic-gate 	mdname_t	*np = NULL;		/* name of soft partition */
3691*0Sstevel@tonic-gate 	md_sp_t		*msp = NULL;
3692*0Sstevel@tonic-gate 	int		c;
3693*0Sstevel@tonic-gate 	int		old_optind;
3694*0Sstevel@tonic-gate 	sp_ext_length_t	len = 0LL;
3695*0Sstevel@tonic-gate 	int		rval = -1;
3696*0Sstevel@tonic-gate 	uint_t		seq;
3697*0Sstevel@tonic-gate 	int		oflag;
3698*0Sstevel@tonic-gate 	int		failed;
3699*0Sstevel@tonic-gate 	mddrivename_t	*dnp = NULL;
3700*0Sstevel@tonic-gate 	sp_ext_length_t	alignment = 0LL;
3701*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
3702*0Sstevel@tonic-gate 
3703*0Sstevel@tonic-gate 	assert(argc > 0);
3704*0Sstevel@tonic-gate 
3705*0Sstevel@tonic-gate 	/* expect sp name, -p, optional -e, compname, and size parameters */
3706*0Sstevel@tonic-gate 	/* grab soft partition name */
3707*0Sstevel@tonic-gate 	if ((np = metaname(spp, devname, ep)) == NULL)
3708*0Sstevel@tonic-gate 		goto out;
3709*0Sstevel@tonic-gate 
3710*0Sstevel@tonic-gate 	/* see if it exists already */
3711*0Sstevel@tonic-gate 	if (metagetmiscname(np, ep) != NULL) {
3712*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
3713*0Sstevel@tonic-gate 		    meta_getminor(np->dev), devname);
3714*0Sstevel@tonic-gate 		goto out;
3715*0Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
3716*0Sstevel@tonic-gate 		goto out;
3717*0Sstevel@tonic-gate 	} else {
3718*0Sstevel@tonic-gate 		mdclrerror(ep);
3719*0Sstevel@tonic-gate 	}
3720*0Sstevel@tonic-gate 	--argc, ++argv;
3721*0Sstevel@tonic-gate 
3722*0Sstevel@tonic-gate 	if (argc == 0)
3723*0Sstevel@tonic-gate 		goto syntax;
3724*0Sstevel@tonic-gate 
3725*0Sstevel@tonic-gate 	/* grab -p */
3726*0Sstevel@tonic-gate 	if (strcmp(argv[0], "-p") != 0)
3727*0Sstevel@tonic-gate 		goto syntax;
3728*0Sstevel@tonic-gate 	--argc, ++argv;
3729*0Sstevel@tonic-gate 
3730*0Sstevel@tonic-gate 	if (argc == 0)
3731*0Sstevel@tonic-gate 		goto syntax;
3732*0Sstevel@tonic-gate 
3733*0Sstevel@tonic-gate 	/* see if -e is there */
3734*0Sstevel@tonic-gate 	if (strcmp(argv[0], "-e") == 0) {
3735*0Sstevel@tonic-gate 		/* use the whole disk */
3736*0Sstevel@tonic-gate 		options |= MDCMD_USE_WHOLE_DISK;
3737*0Sstevel@tonic-gate 		--argc, ++argv;
3738*0Sstevel@tonic-gate 	}
3739*0Sstevel@tonic-gate 
3740*0Sstevel@tonic-gate 	if (argc == 0)
3741*0Sstevel@tonic-gate 		goto syntax;
3742*0Sstevel@tonic-gate 
3743*0Sstevel@tonic-gate 	/* get component name */
3744*0Sstevel@tonic-gate 	compname = Strdup(argv[0]);
3745*0Sstevel@tonic-gate 
3746*0Sstevel@tonic-gate 	if (options & MDCMD_USE_WHOLE_DISK) {
3747*0Sstevel@tonic-gate 		if ((dnp = metadrivename(spp, compname, ep)) == NULL) {
3748*0Sstevel@tonic-gate 			goto out;
3749*0Sstevel@tonic-gate 		}
3750*0Sstevel@tonic-gate 		if ((spcompnp = metaslicename(dnp, 0, ep)) == NULL) {
3751*0Sstevel@tonic-gate 			goto out;
3752*0Sstevel@tonic-gate 		}
3753*0Sstevel@tonic-gate 	} else if ((spcompnp = metaname(spp, compname, ep)) == NULL) {
3754*0Sstevel@tonic-gate 		goto out;
3755*0Sstevel@tonic-gate 	}
3756*0Sstevel@tonic-gate 	assert(*spp != NULL);
3757*0Sstevel@tonic-gate 
3758*0Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
3759*0Sstevel@tonic-gate 		/* grab set lock */
3760*0Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
3761*0Sstevel@tonic-gate 			goto out;
3762*0Sstevel@tonic-gate 
3763*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
3764*0Sstevel@tonic-gate 			goto out;
3765*0Sstevel@tonic-gate 	}
3766*0Sstevel@tonic-gate 
3767*0Sstevel@tonic-gate 	/* allocate the soft partition */
3768*0Sstevel@tonic-gate 	msp = Zalloc(sizeof (*msp));
3769*0Sstevel@tonic-gate 
3770*0Sstevel@tonic-gate 	/* setup common */
3771*0Sstevel@tonic-gate 	msp->common.namep = np;
3772*0Sstevel@tonic-gate 	msp->common.type = MD_METASP;
3773*0Sstevel@tonic-gate 
3774*0Sstevel@tonic-gate 	compname = spcompnp->cname;
3775*0Sstevel@tonic-gate 
3776*0Sstevel@tonic-gate 	assert(spcompnp->rname != NULL);
3777*0Sstevel@tonic-gate 	--argc, ++argv;
3778*0Sstevel@tonic-gate 
3779*0Sstevel@tonic-gate 	if (argc == 0) {
3780*0Sstevel@tonic-gate 		goto syntax;
3781*0Sstevel@tonic-gate 	}
3782*0Sstevel@tonic-gate 
3783*0Sstevel@tonic-gate 	if (*argv[0] == '-') {
3784*0Sstevel@tonic-gate 		/*
3785*0Sstevel@tonic-gate 		 * parse any other command line options, this includes
3786*0Sstevel@tonic-gate 		 * the recovery options -o and -b. The special thing
3787*0Sstevel@tonic-gate 		 * with these options is that the len needs to be
3788*0Sstevel@tonic-gate 		 * kept track of otherwise when the geometry of the
3789*0Sstevel@tonic-gate 		 * "device" is built it will create an invalid geometry
3790*0Sstevel@tonic-gate 		 */
3791*0Sstevel@tonic-gate 		old_optind = optind = 0;
3792*0Sstevel@tonic-gate 		opterr = 0;
3793*0Sstevel@tonic-gate 		oflag = 0;
3794*0Sstevel@tonic-gate 		seq = 0;
3795*0Sstevel@tonic-gate 		failed = 0;
3796*0Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "A:o:b:")) != -1) {
3797*0Sstevel@tonic-gate 			sp_ext_offset_t	offset;
3798*0Sstevel@tonic-gate 			sp_ext_length_t	length;
3799*0Sstevel@tonic-gate 			longlong_t	tmp_size;
3800*0Sstevel@tonic-gate 
3801*0Sstevel@tonic-gate 			switch (c) {
3802*0Sstevel@tonic-gate 			case 'A':	/* data alignment */
3803*0Sstevel@tonic-gate 				if (meta_sp_parsesizestring(optarg,
3804*0Sstevel@tonic-gate 					&alignment) == -1) {
3805*0Sstevel@tonic-gate 					failed = 1;
3806*0Sstevel@tonic-gate 				}
3807*0Sstevel@tonic-gate 				break;
3808*0Sstevel@tonic-gate 			case 'o':	/* offset in the partition */
3809*0Sstevel@tonic-gate 				if (oflag == 1) {
3810*0Sstevel@tonic-gate 					failed = 1;
3811*0Sstevel@tonic-gate 				} else {
3812*0Sstevel@tonic-gate 					tmp_size = atoll(optarg);
3813*0Sstevel@tonic-gate 					if (tmp_size <= 0) {
3814*0Sstevel@tonic-gate 						failed = 1;
3815*0Sstevel@tonic-gate 					} else {
3816*0Sstevel@tonic-gate 						oflag = 1;
3817*0Sstevel@tonic-gate 						options |= MDCMD_DIRECT;
3818*0Sstevel@tonic-gate 
3819*0Sstevel@tonic-gate 						offset = tmp_size;
3820*0Sstevel@tonic-gate 					}
3821*0Sstevel@tonic-gate 				}
3822*0Sstevel@tonic-gate 
3823*0Sstevel@tonic-gate 				break;
3824*0Sstevel@tonic-gate 			case 'b':	/* number of blocks */
3825*0Sstevel@tonic-gate 				if (oflag == 0) {
3826*0Sstevel@tonic-gate 					failed = 1;
3827*0Sstevel@tonic-gate 				} else {
3828*0Sstevel@tonic-gate 					tmp_size = atoll(optarg);
3829*0Sstevel@tonic-gate 					if (tmp_size <= 0) {
3830*0Sstevel@tonic-gate 						failed = 1;
3831*0Sstevel@tonic-gate 					} else {
3832*0Sstevel@tonic-gate 						oflag = 0;
3833*0Sstevel@tonic-gate 
3834*0Sstevel@tonic-gate 						length = tmp_size;
3835*0Sstevel@tonic-gate 
3836*0Sstevel@tonic-gate 						/* we have a pair of values */
3837*0Sstevel@tonic-gate 						meta_sp_list_insert(*spp, np,
3838*0Sstevel@tonic-gate 							&extlist, offset,
3839*0Sstevel@tonic-gate 							length, EXTTYP_ALLOC,
3840*0Sstevel@tonic-gate 							seq++, EXTFLG_UPDATE,
3841*0Sstevel@tonic-gate 							meta_sp_cmp_by_offset);
3842*0Sstevel@tonic-gate 						len += length;
3843*0Sstevel@tonic-gate 					}
3844*0Sstevel@tonic-gate 				}
3845*0Sstevel@tonic-gate 
3846*0Sstevel@tonic-gate 				break;
3847*0Sstevel@tonic-gate 			default:
3848*0Sstevel@tonic-gate 				argc -= old_optind;
3849*0Sstevel@tonic-gate 				argv += old_optind;
3850*0Sstevel@tonic-gate 				goto options;
3851*0Sstevel@tonic-gate 			}
3852*0Sstevel@tonic-gate 
3853*0Sstevel@tonic-gate 			if (failed) {
3854*0Sstevel@tonic-gate 				argc -= old_optind;
3855*0Sstevel@tonic-gate 				argv += old_optind;
3856*0Sstevel@tonic-gate 				goto syntax;
3857*0Sstevel@tonic-gate 			}
3858*0Sstevel@tonic-gate 
3859*0Sstevel@tonic-gate 			old_optind = optind;
3860*0Sstevel@tonic-gate 		}
3861*0Sstevel@tonic-gate 		argc -= optind;
3862*0Sstevel@tonic-gate 		argv += optind;
3863*0Sstevel@tonic-gate 
3864*0Sstevel@tonic-gate 		/*
3865*0Sstevel@tonic-gate 		 * Must have matching pairs of -o and -b flags
3866*0Sstevel@tonic-gate 		 */
3867*0Sstevel@tonic-gate 		if (oflag != 0)
3868*0Sstevel@tonic-gate 			goto syntax;
3869*0Sstevel@tonic-gate 
3870*0Sstevel@tonic-gate 		/*
3871*0Sstevel@tonic-gate 		 * Can't specify both layout (indicated indirectly by
3872*0Sstevel@tonic-gate 		 * len being set by thye -o/-b cases above) AND
3873*0Sstevel@tonic-gate 		 * alignment
3874*0Sstevel@tonic-gate 		 */
3875*0Sstevel@tonic-gate 		if ((len > 0LL) && (alignment > 0LL))
3876*0Sstevel@tonic-gate 			goto syntax;
3877*0Sstevel@tonic-gate 
3878*0Sstevel@tonic-gate 		/*
3879*0Sstevel@tonic-gate 		 * sanity check the allocation list
3880*0Sstevel@tonic-gate 		 */
3881*0Sstevel@tonic-gate 		if ((extlist != NULL) && meta_sp_list_overlaps(extlist))
3882*0Sstevel@tonic-gate 			goto syntax;
3883*0Sstevel@tonic-gate 	}
3884*0Sstevel@tonic-gate 
3885*0Sstevel@tonic-gate 	if (len == 0LL) {
3886*0Sstevel@tonic-gate 		if (argc == 0)
3887*0Sstevel@tonic-gate 			goto syntax;
3888*0Sstevel@tonic-gate 		if (meta_sp_parsesize(argv[0], &len) == -1)
3889*0Sstevel@tonic-gate 			goto syntax;
3890*0Sstevel@tonic-gate 		--argc, ++argv;
3891*0Sstevel@tonic-gate 	}
3892*0Sstevel@tonic-gate 
3893*0Sstevel@tonic-gate 	msp->ext.ext_val = Zalloc(sizeof (*msp->ext.ext_val));
3894*0Sstevel@tonic-gate 	msp->ext.ext_val->len = len;
3895*0Sstevel@tonic-gate 	msp->compnamep = spcompnp;
3896*0Sstevel@tonic-gate 
3897*0Sstevel@tonic-gate 	/* we should be at the end */
3898*0Sstevel@tonic-gate 	if (argc != 0)
3899*0Sstevel@tonic-gate 		goto syntax;
3900*0Sstevel@tonic-gate 
3901*0Sstevel@tonic-gate 	/* create soft partition */
3902*0Sstevel@tonic-gate 	if (meta_create_sp(*spp, msp, extlist, options, alignment, ep) != 0)
3903*0Sstevel@tonic-gate 		goto out;
3904*0Sstevel@tonic-gate 	rval = 0;
3905*0Sstevel@tonic-gate 
3906*0Sstevel@tonic-gate 	/* let em know */
3907*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
3908*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
3909*0Sstevel@tonic-gate 		    "%s: Soft Partition is setup\n"),
3910*0Sstevel@tonic-gate 		    devname);
3911*0Sstevel@tonic-gate 		(void) fflush(stdout);
3912*0Sstevel@tonic-gate 	}
3913*0Sstevel@tonic-gate 	goto out;
3914*0Sstevel@tonic-gate 
3915*0Sstevel@tonic-gate syntax:
3916*0Sstevel@tonic-gate 	/* syntax error */
3917*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, compname, argc, argv);
3918*0Sstevel@tonic-gate 	goto out;
3919*0Sstevel@tonic-gate 
3920*0Sstevel@tonic-gate options:
3921*0Sstevel@tonic-gate 	/* options error */
3922*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, compname, argc, argv);
3923*0Sstevel@tonic-gate 	goto out;
3924*0Sstevel@tonic-gate 
3925*0Sstevel@tonic-gate out:
3926*0Sstevel@tonic-gate 	if (msp != NULL) {
3927*0Sstevel@tonic-gate 		if (msp->ext.ext_val != NULL) {
3928*0Sstevel@tonic-gate 			Free(msp->ext.ext_val);
3929*0Sstevel@tonic-gate 		}
3930*0Sstevel@tonic-gate 		Free(msp);
3931*0Sstevel@tonic-gate 	}
3932*0Sstevel@tonic-gate 
3933*0Sstevel@tonic-gate 	return (rval);
3934*0Sstevel@tonic-gate }
3935*0Sstevel@tonic-gate 
3936*0Sstevel@tonic-gate /*
3937*0Sstevel@tonic-gate  * FUNCTION:	meta_free_sp()
3938*0Sstevel@tonic-gate  * INPUT:	msp	- the soft partition unit to free
3939*0Sstevel@tonic-gate  * OUTPUT:	none
3940*0Sstevel@tonic-gate  * RETURNS:	void
3941*0Sstevel@tonic-gate  * PURPOSE:	provides an interface from the rest of libmeta for freeing a
3942*0Sstevel@tonic-gate  *		soft partition unit
3943*0Sstevel@tonic-gate  */
3944*0Sstevel@tonic-gate void
3945*0Sstevel@tonic-gate meta_free_sp(md_sp_t *msp)
3946*0Sstevel@tonic-gate {
3947*0Sstevel@tonic-gate 	Free(msp);
3948*0Sstevel@tonic-gate }
3949*0Sstevel@tonic-gate 
3950*0Sstevel@tonic-gate /*
3951*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_issp()
3952*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to check
3953*0Sstevel@tonic-gate  *		np	- the name to check
3954*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
3955*0Sstevel@tonic-gate  * RETURNS:	int	- 0 means sp,np is a soft partition
3956*0Sstevel@tonic-gate  *			  1 means sp,np is not a soft partition
3957*0Sstevel@tonic-gate  * PURPOSE:	determines whether the given device is a soft partition
3958*0Sstevel@tonic-gate  *		device.  This is called by other metadevice check routines.
3959*0Sstevel@tonic-gate  */
3960*0Sstevel@tonic-gate int
3961*0Sstevel@tonic-gate meta_sp_issp(
3962*0Sstevel@tonic-gate 	mdsetname_t	*sp,
3963*0Sstevel@tonic-gate 	mdname_t	*np,
3964*0Sstevel@tonic-gate 	md_error_t	*ep
3965*0Sstevel@tonic-gate )
3966*0Sstevel@tonic-gate {
3967*0Sstevel@tonic-gate 	if (meta_get_sp_common(sp, np, 0, ep) == NULL)
3968*0Sstevel@tonic-gate 		return (1);
3969*0Sstevel@tonic-gate 
3970*0Sstevel@tonic-gate 	return (0);
3971*0Sstevel@tonic-gate }
3972*0Sstevel@tonic-gate 
3973*0Sstevel@tonic-gate /*
3974*0Sstevel@tonic-gate  * FUNCTION:	meta_check_sp()
3975*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to check
3976*0Sstevel@tonic-gate  *		msp	- the unit structure to check
3977*0Sstevel@tonic-gate  *		options	- creation options
3978*0Sstevel@tonic-gate  * OUTPUT:	repart_options - options to be passed to
3979*0Sstevel@tonic-gate  *				meta_repartition_drive()
3980*0Sstevel@tonic-gate  *		ep	- return error pointer
3981*0Sstevel@tonic-gate  * RETURNS:	int	-  0 ok to create on this component
3982*0Sstevel@tonic-gate  *			  -1 error or not ok to create on this component
3983*0Sstevel@tonic-gate  * PURPOSE:	Checks to determine whether the rules for creation of
3984*0Sstevel@tonic-gate  *		soft partitions allow creation of a soft partition on
3985*0Sstevel@tonic-gate  *		the device described by the mdname_t structure referred
3986*0Sstevel@tonic-gate  *		to by msp->compnamep.
3987*0Sstevel@tonic-gate  *
3988*0Sstevel@tonic-gate  *		NOTE: Does NOT check to determine whether the extents
3989*0Sstevel@tonic-gate  *		      described in the md_sp_t structure referred to by
3990*0Sstevel@tonic-gate  *		      msp will fit on the device described by the mdname_t
3991*0Sstevel@tonic-gate  *		      structure located at msp->compnamep.
3992*0Sstevel@tonic-gate  */
3993*0Sstevel@tonic-gate static int
3994*0Sstevel@tonic-gate meta_check_sp(
3995*0Sstevel@tonic-gate 	mdsetname_t	*sp,
3996*0Sstevel@tonic-gate 	md_sp_t		*msp,
3997*0Sstevel@tonic-gate 	mdcmdopts_t	options,
3998*0Sstevel@tonic-gate 	int		*repart_options,
3999*0Sstevel@tonic-gate 	md_error_t	*ep
4000*0Sstevel@tonic-gate )
4001*0Sstevel@tonic-gate {
4002*0Sstevel@tonic-gate 	md_common_t	*mdp;
4003*0Sstevel@tonic-gate 	mdname_t	*compnp = msp->compnamep;
4004*0Sstevel@tonic-gate 	uint_t		slice;
4005*0Sstevel@tonic-gate 	mddrivename_t	*dnp;
4006*0Sstevel@tonic-gate 	mdname_t	*slicenp;
4007*0Sstevel@tonic-gate 	mdvtoc_t	*vtocp;
4008*0Sstevel@tonic-gate 
4009*0Sstevel@tonic-gate 	/* make sure it is in the set */
4010*0Sstevel@tonic-gate 	if (meta_check_inset(sp, compnp, ep) != 0)
4011*0Sstevel@tonic-gate 		return (-1);
4012*0Sstevel@tonic-gate 
4013*0Sstevel@tonic-gate 	if ((options & MDCMD_USE_WHOLE_DISK) != 0) {
4014*0Sstevel@tonic-gate 		uint_t	rep_slice;
4015*0Sstevel@tonic-gate 
4016*0Sstevel@tonic-gate 		/*
4017*0Sstevel@tonic-gate 		 * check to make sure we can partition this drive.
4018*0Sstevel@tonic-gate 		 * we cannot continue if any of the following are
4019*0Sstevel@tonic-gate 		 * true:
4020*0Sstevel@tonic-gate 		 * The drive is a metadevice.
4021*0Sstevel@tonic-gate 		 * The drive contains a mounted slice.
4022*0Sstevel@tonic-gate 		 * The drive contains a slice being swapped to.
4023*0Sstevel@tonic-gate 		 * The drive contains slices which are part of other
4024*0Sstevel@tonic-gate 		 * metadevices.
4025*0Sstevel@tonic-gate 		 * The drive contains a metadb.
4026*0Sstevel@tonic-gate 		 */
4027*0Sstevel@tonic-gate 		if (metaismeta(compnp))
4028*0Sstevel@tonic-gate 			return (mddeverror(ep, MDE_IS_META, compnp->dev,
4029*0Sstevel@tonic-gate 			    compnp->cname));
4030*0Sstevel@tonic-gate 
4031*0Sstevel@tonic-gate 		assert(compnp->drivenamep != NULL);
4032*0Sstevel@tonic-gate 
4033*0Sstevel@tonic-gate 		/*
4034*0Sstevel@tonic-gate 		 * ensure that we have slice 0 since the disk will be
4035*0Sstevel@tonic-gate 		 * repartitioned in the USE_WHOLE_DISK case.  this check
4036*0Sstevel@tonic-gate 		 * is redundant unless the user incorrectly specifies a
4037*0Sstevel@tonic-gate 		 * a fully qualified drive AND slice name (i.e.,
4038*0Sstevel@tonic-gate 		 * /dev/dsk/cXtXdXsX), which will be incorrectly
4039*0Sstevel@tonic-gate 		 * recognized as a drive name by the metaname code.
4040*0Sstevel@tonic-gate 		 */
4041*0Sstevel@tonic-gate 
4042*0Sstevel@tonic-gate 		if ((vtocp = metagetvtoc(compnp, FALSE, &slice, ep)) == NULL)
4043*0Sstevel@tonic-gate 			return (-1);
4044*0Sstevel@tonic-gate 		if (slice != MD_SLICE0)
4045*0Sstevel@tonic-gate 			return (mderror(ep, MDE_NOT_DRIVENAME, compnp->cname));
4046*0Sstevel@tonic-gate 
4047*0Sstevel@tonic-gate 		dnp = compnp->drivenamep;
4048*0Sstevel@tonic-gate 		if (meta_replicaslice(dnp, &rep_slice, ep) != 0)
4049*0Sstevel@tonic-gate 			return (-1);
4050*0Sstevel@tonic-gate 
4051*0Sstevel@tonic-gate 		for (slice = 0; slice < vtocp->nparts; slice++) {
4052*0Sstevel@tonic-gate 
4053*0Sstevel@tonic-gate 			/* only check if the slice really exists */
4054*0Sstevel@tonic-gate 			if (vtocp->parts[slice].size == 0)
4055*0Sstevel@tonic-gate 				continue;
4056*0Sstevel@tonic-gate 
4057*0Sstevel@tonic-gate 			slicenp = metaslicename(dnp, slice, ep);
4058*0Sstevel@tonic-gate 			if (slicenp == NULL)
4059*0Sstevel@tonic-gate 				return (-1);
4060*0Sstevel@tonic-gate 
4061*0Sstevel@tonic-gate 			/* check to ensure that it is not already in use */
4062*0Sstevel@tonic-gate 			if (meta_check_inuse(sp,
4063*0Sstevel@tonic-gate 			    slicenp, MDCHK_INUSE, ep) != 0) {
4064*0Sstevel@tonic-gate 				return (-1);
4065*0Sstevel@tonic-gate 			}
4066*0Sstevel@tonic-gate 
4067*0Sstevel@tonic-gate 			/*
4068*0Sstevel@tonic-gate 			 * Up to this point, tests are applied to all
4069*0Sstevel@tonic-gate 			 * slices uniformly.
4070*0Sstevel@tonic-gate 			 */
4071*0Sstevel@tonic-gate 
4072*0Sstevel@tonic-gate 			if (slice == rep_slice) {
4073*0Sstevel@tonic-gate 				/*
4074*0Sstevel@tonic-gate 				 * Tests inside the body of this
4075*0Sstevel@tonic-gate 				 * conditional are applied only to
4076*0Sstevel@tonic-gate 				 * slice seven.
4077*0Sstevel@tonic-gate 				 */
4078*0Sstevel@tonic-gate 				if (meta_check_inmeta(sp, slicenp,
4079*0Sstevel@tonic-gate 				    options | MDCHK_ALLOW_MDDB |
4080*0Sstevel@tonic-gate 				    MDCHK_ALLOW_REPSLICE, 0, -1, ep) != 0)
4081*0Sstevel@tonic-gate 					return (-1);
4082*0Sstevel@tonic-gate 
4083*0Sstevel@tonic-gate 				/*
4084*0Sstevel@tonic-gate 				 * For slice seven, a metadb is NOT an
4085*0Sstevel@tonic-gate 				 * automatic failure. It merely means
4086*0Sstevel@tonic-gate 				 * that we're not allowed to muck
4087*0Sstevel@tonic-gate 				 * about with the partitioning of that
4088*0Sstevel@tonic-gate 				 * slice.  We indicate this by masking
4089*0Sstevel@tonic-gate 				 * in the MD_REPART_LEAVE_REP flag.
4090*0Sstevel@tonic-gate 				 */
4091*0Sstevel@tonic-gate 				if (metahasmddb(sp, slicenp, ep)) {
4092*0Sstevel@tonic-gate 					assert(repart_options !=
4093*0Sstevel@tonic-gate 					    NULL);
4094*0Sstevel@tonic-gate 					*repart_options |=
4095*0Sstevel@tonic-gate 					    MD_REPART_LEAVE_REP;
4096*0Sstevel@tonic-gate 				}
4097*0Sstevel@tonic-gate 
4098*0Sstevel@tonic-gate 				/*
4099*0Sstevel@tonic-gate 				 * Skip the remaining tests for slice
4100*0Sstevel@tonic-gate 				 * seven
4101*0Sstevel@tonic-gate 				 */
4102*0Sstevel@tonic-gate 				continue;
4103*0Sstevel@tonic-gate 			}
4104*0Sstevel@tonic-gate 
4105*0Sstevel@tonic-gate 			/*
4106*0Sstevel@tonic-gate 			 * Tests below this point will be applied to
4107*0Sstevel@tonic-gate 			 * all slices EXCEPT for the replica slice.
4108*0Sstevel@tonic-gate 			 */
4109*0Sstevel@tonic-gate 
4110*0Sstevel@tonic-gate 
4111*0Sstevel@tonic-gate 			/* check if component is in a metadevice */
4112*0Sstevel@tonic-gate 			if (meta_check_inmeta(sp, slicenp, options, 0,
4113*0Sstevel@tonic-gate 			    -1, ep) != 0)
4114*0Sstevel@tonic-gate 				return (-1);
4115*0Sstevel@tonic-gate 
4116*0Sstevel@tonic-gate 			/* check to see if component has a metadb */
4117*0Sstevel@tonic-gate 			if (metahasmddb(sp, slicenp, ep))
4118*0Sstevel@tonic-gate 				return (mddeverror(ep, MDE_HAS_MDDB,
4119*0Sstevel@tonic-gate 				    slicenp->dev, slicenp->cname));
4120*0Sstevel@tonic-gate 		}
4121*0Sstevel@tonic-gate 		/*
4122*0Sstevel@tonic-gate 		 * This should be all of the testing necessary when
4123*0Sstevel@tonic-gate 		 * the MDCMD_USE_WHOLE_DISK flag is set; the rest of
4124*0Sstevel@tonic-gate 		 * meta_check_sp() is oriented towards component
4125*0Sstevel@tonic-gate 		 * arguments instead of disks.
4126*0Sstevel@tonic-gate 		 */
4127*0Sstevel@tonic-gate 		goto meta_check_sp_ok;
4128*0Sstevel@tonic-gate 
4129*0Sstevel@tonic-gate 	}
4130*0Sstevel@tonic-gate 
4131*0Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
4132*0Sstevel@tonic-gate 	if (meta_check_inuse(sp, compnp, MDCHK_INUSE, ep) != 0) {
4133*0Sstevel@tonic-gate 		return (-1);
4134*0Sstevel@tonic-gate 	}
4135*0Sstevel@tonic-gate 
4136*0Sstevel@tonic-gate 	if (!metaismeta(compnp)) {	/* handle non-metadevices */
4137*0Sstevel@tonic-gate 
4138*0Sstevel@tonic-gate 		/*
4139*0Sstevel@tonic-gate 		 * The component can have one or more soft partitions on it
4140*0Sstevel@tonic-gate 		 * already, but can't be part of any other type of metadevice,
4141*0Sstevel@tonic-gate 		 * so if it is used for a metadevice, but the metadevice
4142*0Sstevel@tonic-gate 		 * isn't a soft partition, return failure.
4143*0Sstevel@tonic-gate 		 */
4144*0Sstevel@tonic-gate 
4145*0Sstevel@tonic-gate 		if (meta_check_inmeta(sp, compnp, options, 0, -1, ep) != 0 &&
4146*0Sstevel@tonic-gate 		    meta_check_insp(sp, compnp, 0, -1, ep) == 0) {
4147*0Sstevel@tonic-gate 			return (-1);
4148*0Sstevel@tonic-gate 		}
4149*0Sstevel@tonic-gate 	} else {			/* handle metadevices */
4150*0Sstevel@tonic-gate 		/* get underlying unit & check capabilities */
4151*0Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, compnp, ep)) == NULL)
4152*0Sstevel@tonic-gate 			return (-1);
4153*0Sstevel@tonic-gate 
4154*0Sstevel@tonic-gate 		if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
4155*0Sstevel@tonic-gate 		    (! (mdp->capabilities & MD_CAN_SP)))
4156*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT,
4157*0Sstevel@tonic-gate 			    meta_getminor(compnp->dev), compnp->cname));
4158*0Sstevel@tonic-gate 	}
4159*0Sstevel@tonic-gate 
4160*0Sstevel@tonic-gate meta_check_sp_ok:
4161*0Sstevel@tonic-gate 	mdclrerror(ep);
4162*0Sstevel@tonic-gate 	return (0);
4163*0Sstevel@tonic-gate }
4164*0Sstevel@tonic-gate 
4165*0Sstevel@tonic-gate /*
4166*0Sstevel@tonic-gate  * FUNCTION:	meta_create_sp()
4167*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to create in
4168*0Sstevel@tonic-gate  *		msp	- the unit structure to create
4169*0Sstevel@tonic-gate  *		oblist	- an optional list of requested extents (-o/-b options)
4170*0Sstevel@tonic-gate  *		options	- creation options
4171*0Sstevel@tonic-gate  *		alignment - data alignment
4172*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4173*0Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
4174*0Sstevel@tonic-gate  * PURPOSE:	does most of the work for creating a soft partition.  If
4175*0Sstevel@tonic-gate  *		metainit -p -e was used, first partition the drive.  Then
4176*0Sstevel@tonic-gate  *		create an extent list based on the existing soft partitions
4177*0Sstevel@tonic-gate  *		and assume all space not used by them is free.  Storage for
4178*0Sstevel@tonic-gate  *		the new soft partition is allocated from the free extents
4179*0Sstevel@tonic-gate  *		based on the length specified on the command line or the
4180*0Sstevel@tonic-gate  *		oblist passed in.  The unit structure is then committed and
4181*0Sstevel@tonic-gate  *		the watermarks are updated.  Finally, the status is changed to
4182*0Sstevel@tonic-gate  *		Okay and the process is complete.
4183*0Sstevel@tonic-gate  */
4184*0Sstevel@tonic-gate static int
4185*0Sstevel@tonic-gate meta_create_sp(
4186*0Sstevel@tonic-gate 	mdsetname_t	*sp,
4187*0Sstevel@tonic-gate 	md_sp_t		*msp,
4188*0Sstevel@tonic-gate 	sp_ext_node_t	*oblist,
4189*0Sstevel@tonic-gate 	mdcmdopts_t	options,
4190*0Sstevel@tonic-gate 	sp_ext_length_t	alignment,
4191*0Sstevel@tonic-gate 	md_error_t	*ep
4192*0Sstevel@tonic-gate )
4193*0Sstevel@tonic-gate {
4194*0Sstevel@tonic-gate 	mdname_t	*np = msp->common.namep;
4195*0Sstevel@tonic-gate 	mdname_t	*compnp = msp->compnamep;
4196*0Sstevel@tonic-gate 	mp_unit_t	*mp = NULL;
4197*0Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL, *spnlp = NULL;
4198*0Sstevel@tonic-gate 	md_set_params_t	set_params;
4199*0Sstevel@tonic-gate 	int		rval = -1;
4200*0Sstevel@tonic-gate 	diskaddr_t	comp_size;
4201*0Sstevel@tonic-gate 	diskaddr_t	sp_start;
4202*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
4203*0Sstevel@tonic-gate 	int		numexts = 0;	/* number of extents */
4204*0Sstevel@tonic-gate 	int		count = 0;
4205*0Sstevel@tonic-gate 	int		committed = 0;
4206*0Sstevel@tonic-gate 	int		repart_options = MD_REPART_FORCE;
4207*0Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
4208*0Sstevel@tonic-gate 
4209*0Sstevel@tonic-gate 	md_set_desc	*sd;
4210*0Sstevel@tonic-gate 	mm_unit_t	*mm;
4211*0Sstevel@tonic-gate 	md_set_mmown_params_t	*ownpar = NULL;
4212*0Sstevel@tonic-gate 	int		comp_is_mirror = 0;
4213*0Sstevel@tonic-gate 
4214*0Sstevel@tonic-gate 	/* validate soft partition */
4215*0Sstevel@tonic-gate 	if (meta_check_sp(sp, msp, options, &repart_options, ep) != 0)
4216*0Sstevel@tonic-gate 		return (-1);
4217*0Sstevel@tonic-gate 
4218*0Sstevel@tonic-gate 	if ((options & MDCMD_USE_WHOLE_DISK) != 0) {
4219*0Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) != 0) {
4220*0Sstevel@tonic-gate 			if (meta_repartition_drive(sp,
4221*0Sstevel@tonic-gate 			    compnp->drivenamep,
4222*0Sstevel@tonic-gate 			    repart_options,
4223*0Sstevel@tonic-gate 			    NULL, /* Don't return the VTOC */
4224*0Sstevel@tonic-gate 			    ep) != 0)
4225*0Sstevel@tonic-gate 
4226*0Sstevel@tonic-gate 				return (-1);
4227*0Sstevel@tonic-gate 		} else {
4228*0Sstevel@tonic-gate 			/*
4229*0Sstevel@tonic-gate 			 * If -n and -e are both specified, it doesn't make
4230*0Sstevel@tonic-gate 			 * sense to continue without actually partitioning
4231*0Sstevel@tonic-gate 			 * the drive.
4232*0Sstevel@tonic-gate 			 */
4233*0Sstevel@tonic-gate 			return (0);
4234*0Sstevel@tonic-gate 		}
4235*0Sstevel@tonic-gate 	}
4236*0Sstevel@tonic-gate 
4237*0Sstevel@tonic-gate 	/* populate the start_blk field of the component name */
4238*0Sstevel@tonic-gate 	if ((sp_start = meta_sp_get_start(sp, compnp, ep)) ==
4239*0Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
4240*0Sstevel@tonic-gate 		rval = -1;
4241*0Sstevel@tonic-gate 		goto out;
4242*0Sstevel@tonic-gate 	}
4243*0Sstevel@tonic-gate 
4244*0Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
4245*0Sstevel@tonic-gate 		/* store name in namespace */
4246*0Sstevel@tonic-gate 		if (add_key_name(sp, compnp, &keynlp, ep) != 0) {
4247*0Sstevel@tonic-gate 			rval = -1;
4248*0Sstevel@tonic-gate 			goto out;
4249*0Sstevel@tonic-gate 		}
4250*0Sstevel@tonic-gate 	}
4251*0Sstevel@tonic-gate 
4252*0Sstevel@tonic-gate 	/*
4253*0Sstevel@tonic-gate 	 * Get a list of the soft partitions that currently reside on
4254*0Sstevel@tonic-gate 	 * the component.  We should ALWAYS force reload the cache,
4255*0Sstevel@tonic-gate 	 * because if this is a single creation, there will not BE a
4256*0Sstevel@tonic-gate 	 * cached list, and if we're using the md.tab, we must rebuild
4257*0Sstevel@tonic-gate 	 * the list because it won't contain the previous (if any)
4258*0Sstevel@tonic-gate 	 * soft partition.
4259*0Sstevel@tonic-gate 	 */
4260*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 1, ep);
4261*0Sstevel@tonic-gate 	if (count < 0) {
4262*0Sstevel@tonic-gate 		/* error occured */
4263*0Sstevel@tonic-gate 		rval = -1;
4264*0Sstevel@tonic-gate 		goto out;
4265*0Sstevel@tonic-gate 	}
4266*0Sstevel@tonic-gate 
4267*0Sstevel@tonic-gate 	/*
4268*0Sstevel@tonic-gate 	 * get the size of the underlying device.  if the size is smaller
4269*0Sstevel@tonic-gate 	 * than or equal to the watermark size, we know there isn't
4270*0Sstevel@tonic-gate 	 * enough space.
4271*0Sstevel@tonic-gate 	 */
4272*0Sstevel@tonic-gate 	if ((comp_size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR) {
4273*0Sstevel@tonic-gate 		rval = -1;
4274*0Sstevel@tonic-gate 		goto out;
4275*0Sstevel@tonic-gate 	} else if (comp_size <= MD_SP_WMSIZE) {
4276*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_SP_NOSPACE, 0, compnp->cname);
4277*0Sstevel@tonic-gate 		rval = -1;
4278*0Sstevel@tonic-gate 		goto out;
4279*0Sstevel@tonic-gate 	}
4280*0Sstevel@tonic-gate 	/*
4281*0Sstevel@tonic-gate 	 * seed extlist with reserved space at the beginning of the volume and
4282*0Sstevel@tonic-gate 	 * enough space for the end watermark.  The end watermark always gets
4283*0Sstevel@tonic-gate 	 * updated, but if the underlying device changes size it may not be
4284*0Sstevel@tonic-gate 	 * pointed to until the extent before it is updated.  Since the
4285*0Sstevel@tonic-gate 	 * end of the reserved space is where the first watermark starts,
4286*0Sstevel@tonic-gate 	 * the reserved extent should never be marked for updating.
4287*0Sstevel@tonic-gate 	 */
4288*0Sstevel@tonic-gate 
4289*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
4290*0Sstevel@tonic-gate 	    0ULL, sp_start, EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
4291*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
4292*0Sstevel@tonic-gate 	    (sp_ext_offset_t)(comp_size - MD_SP_WMSIZE), MD_SP_WMSIZE,
4293*0Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
4294*0Sstevel@tonic-gate 
4295*0Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
4296*0Sstevel@tonic-gate 		rval = -1;
4297*0Sstevel@tonic-gate 		goto out;
4298*0Sstevel@tonic-gate 	}
4299*0Sstevel@tonic-gate 
4300*0Sstevel@tonic-gate 	metafreenamelist(spnlp);
4301*0Sstevel@tonic-gate 
4302*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
4303*0Sstevel@tonic-gate 		meta_sp_debug("meta_create_sp: list of used extents:\n");
4304*0Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
4305*0Sstevel@tonic-gate 	}
4306*0Sstevel@tonic-gate 
4307*0Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
4308*0Sstevel@tonic-gate 
4309*0Sstevel@tonic-gate 	/* get extent list from -o/-b options or from free space */
4310*0Sstevel@tonic-gate 	if (options & MDCMD_DIRECT) {
4311*0Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
4312*0Sstevel@tonic-gate 			meta_sp_debug("meta_create_sp: Dumping -o/-b list:\n");
4313*0Sstevel@tonic-gate 			meta_sp_list_dump(oblist);
4314*0Sstevel@tonic-gate 		}
4315*0Sstevel@tonic-gate 
4316*0Sstevel@tonic-gate 		numexts = meta_sp_alloc_by_list(sp, np, &extlist, oblist);
4317*0Sstevel@tonic-gate 		if (numexts == -1) {
4318*0Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_SP_OVERLAP, 0, np->cname);
4319*0Sstevel@tonic-gate 			rval = -1;
4320*0Sstevel@tonic-gate 			goto out;
4321*0Sstevel@tonic-gate 		}
4322*0Sstevel@tonic-gate 	} else {
4323*0Sstevel@tonic-gate 		numexts = meta_sp_alloc_by_len(sp, np, &extlist,
4324*0Sstevel@tonic-gate 		    &msp->ext.ext_val->len, 0LL, (alignment > 0) ? alignment :
4325*0Sstevel@tonic-gate 		    meta_sp_get_default_alignment(sp, compnp, ep));
4326*0Sstevel@tonic-gate 		if (numexts == -1) {
4327*0Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_SP_NOSPACE, 0, np->cname);
4328*0Sstevel@tonic-gate 			rval = -1;
4329*0Sstevel@tonic-gate 			goto out;
4330*0Sstevel@tonic-gate 		}
4331*0Sstevel@tonic-gate 	}
4332*0Sstevel@tonic-gate 
4333*0Sstevel@tonic-gate 	assert(extlist != NULL);
4334*0Sstevel@tonic-gate 
4335*0Sstevel@tonic-gate 	/* create soft partition */
4336*0Sstevel@tonic-gate 	mp = meta_sp_createunit(msp->common.namep, msp->compnamep,
4337*0Sstevel@tonic-gate 	    extlist, numexts, msp->ext.ext_val->len, MD_SP_CREATEPEND, ep);
4338*0Sstevel@tonic-gate 
4339*0Sstevel@tonic-gate 	create_flag = meta_check_devicesize(mp->c.un_total_blocks);
4340*0Sstevel@tonic-gate 
4341*0Sstevel@tonic-gate 	/* if we're not doing anything (metainit -n), return success */
4342*0Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
4343*0Sstevel@tonic-gate 		rval = 0;	/* success */
4344*0Sstevel@tonic-gate 		goto out;
4345*0Sstevel@tonic-gate 	}
4346*0Sstevel@tonic-gate 
4347*0Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
4348*0Sstevel@tonic-gate 
4349*0Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
4350*0Sstevel@tonic-gate 		mp->c.un_revision = MD_64BIT_META_DEV;
4351*0Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
4352*0Sstevel@tonic-gate 	} else {
4353*0Sstevel@tonic-gate 		mp->c.un_revision = MD_32BIT_META_DEV;
4354*0Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
4355*0Sstevel@tonic-gate 	}
4356*0Sstevel@tonic-gate 
4357*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
4358*0Sstevel@tonic-gate 		meta_sp_debug("meta_create_sp: printing unit structure\n");
4359*0Sstevel@tonic-gate 		meta_sp_printunit(mp);
4360*0Sstevel@tonic-gate 	}
4361*0Sstevel@tonic-gate 
4362*0Sstevel@tonic-gate 	/*
4363*0Sstevel@tonic-gate 	 * Check to see if we're trying to create a partition on a mirror. If so
4364*0Sstevel@tonic-gate 	 * we may have to enforce an ownership change before writing the
4365*0Sstevel@tonic-gate 	 * watermark out.
4366*0Sstevel@tonic-gate 	 */
4367*0Sstevel@tonic-gate 	if (metaismeta(compnp)) {
4368*0Sstevel@tonic-gate 		char *miscname;
4369*0Sstevel@tonic-gate 
4370*0Sstevel@tonic-gate 		miscname = metagetmiscname(compnp, ep);
4371*0Sstevel@tonic-gate 		if (miscname != NULL)
4372*0Sstevel@tonic-gate 			comp_is_mirror = (strcmp(miscname, MD_MIRROR) == 0);
4373*0Sstevel@tonic-gate 		else
4374*0Sstevel@tonic-gate 			comp_is_mirror = 0;
4375*0Sstevel@tonic-gate 	} else {
4376*0Sstevel@tonic-gate 		comp_is_mirror = 0;
4377*0Sstevel@tonic-gate 	}
4378*0Sstevel@tonic-gate 
4379*0Sstevel@tonic-gate 	/*
4380*0Sstevel@tonic-gate 	 * For a multi-node environment we have to ensure that the master
4381*0Sstevel@tonic-gate 	 * node owns an underlying mirror before we issue the MD_IOCSET ioctl.
4382*0Sstevel@tonic-gate 	 * If the master does not own the device we will deadlock as the
4383*0Sstevel@tonic-gate 	 * implicit write of the watermarks (in sp_ioctl.c) will cause an
4384*0Sstevel@tonic-gate 	 * ownership change that will block as the MD_IOCSET is still in
4385*0Sstevel@tonic-gate 	 * progress. To close this window we force an owner change to occur
4386*0Sstevel@tonic-gate 	 * before issuing the MD_IOCSET. We cannot simply open the device and
4387*0Sstevel@tonic-gate 	 * write to it as this will only work for the first soft-partition
4388*0Sstevel@tonic-gate 	 * creation.
4389*0Sstevel@tonic-gate 	 */
4390*0Sstevel@tonic-gate 
4391*0Sstevel@tonic-gate 	if (comp_is_mirror && !metaislocalset(sp)) {
4392*0Sstevel@tonic-gate 
4393*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
4394*0Sstevel@tonic-gate 			rval = -1;
4395*0Sstevel@tonic-gate 			goto out;
4396*0Sstevel@tonic-gate 		}
4397*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd) && sd->sd_mn_am_i_master) {
4398*0Sstevel@tonic-gate 			mm = (mm_unit_t *)meta_get_unit(sp, compnp, ep);
4399*0Sstevel@tonic-gate 			if (mm == NULL) {
4400*0Sstevel@tonic-gate 				rval = -1;
4401*0Sstevel@tonic-gate 				goto out;
4402*0Sstevel@tonic-gate 			} else {
4403*0Sstevel@tonic-gate 				rval = meta_mn_change_owner(&ownpar, sp->setno,
4404*0Sstevel@tonic-gate 					meta_getminor(compnp->dev),
4405*0Sstevel@tonic-gate 					sd->sd_mn_mynode->nd_nodeid,
4406*0Sstevel@tonic-gate 					MD_MN_MM_PREVENT_CHANGE |
4407*0Sstevel@tonic-gate 					    MD_MN_MM_SPAWN_THREAD);
4408*0Sstevel@tonic-gate 				if (rval == -1)
4409*0Sstevel@tonic-gate 					goto out;
4410*0Sstevel@tonic-gate 			}
4411*0Sstevel@tonic-gate 		}
4412*0Sstevel@tonic-gate 	}
4413*0Sstevel@tonic-gate 
4414*0Sstevel@tonic-gate 	set_params.mnum = MD_SID(mp);
4415*0Sstevel@tonic-gate 	set_params.size = mp->c.un_size;
4416*0Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)mp;
4417*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_SP, MD_MIN2SET(set_params.mnum));
4418*0Sstevel@tonic-gate 
4419*0Sstevel@tonic-gate 	/* first phase of commit. */
4420*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
4421*0Sstevel@tonic-gate 	    np->cname) != 0) {
4422*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
4423*0Sstevel@tonic-gate 		rval = -1;
4424*0Sstevel@tonic-gate 		goto out;
4425*0Sstevel@tonic-gate 	}
4426*0Sstevel@tonic-gate 
4427*0Sstevel@tonic-gate 	/* we've successfully committed the record */
4428*0Sstevel@tonic-gate 	committed = 1;
4429*0Sstevel@tonic-gate 
4430*0Sstevel@tonic-gate 	/* write watermarks */
4431*0Sstevel@tonic-gate 	if (meta_sp_update_wm(sp, msp, extlist, ep) < 0) {
4432*0Sstevel@tonic-gate 		rval = -1;
4433*0Sstevel@tonic-gate 		goto out;
4434*0Sstevel@tonic-gate 	}
4435*0Sstevel@tonic-gate 
4436*0Sstevel@tonic-gate 	/*
4437*0Sstevel@tonic-gate 	 * Allow mirror ownership to change. If we don't succeed in this
4438*0Sstevel@tonic-gate 	 * ioctl it isn't fatal, but the cluster will probably hang fairly
4439*0Sstevel@tonic-gate 	 * soon as the mirror owner won't change. However, we have
4440*0Sstevel@tonic-gate 	 * successfully written the watermarks out to the device so the
4441*0Sstevel@tonic-gate 	 * softpart creation has succeeded
4442*0Sstevel@tonic-gate 	 */
4443*0Sstevel@tonic-gate 	if (ownpar) {
4444*0Sstevel@tonic-gate 		(void) meta_mn_change_owner(&ownpar, sp->setno, ownpar->d.mnum,
4445*0Sstevel@tonic-gate 		    ownpar->d.owner,
4446*0Sstevel@tonic-gate 		    MD_MN_MM_ALLOW_CHANGE | MD_MN_MM_SPAWN_THREAD);
4447*0Sstevel@tonic-gate 	}
4448*0Sstevel@tonic-gate 
4449*0Sstevel@tonic-gate 	/* second phase of commit, set status to MD_SP_OK */
4450*0Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &(MD_SID(mp)), 1, MD_SP_OK, ep) < 0) {
4451*0Sstevel@tonic-gate 		rval = -1;
4452*0Sstevel@tonic-gate 		goto out;
4453*0Sstevel@tonic-gate 	}
4454*0Sstevel@tonic-gate 	rval = 0;
4455*0Sstevel@tonic-gate out:
4456*0Sstevel@tonic-gate 	Free(mp);
4457*0Sstevel@tonic-gate 	if (ownpar)
4458*0Sstevel@tonic-gate 		Free(ownpar);
4459*0Sstevel@tonic-gate 
4460*0Sstevel@tonic-gate 	if (extlist != NULL)
4461*0Sstevel@tonic-gate 		meta_sp_list_free(&extlist);
4462*0Sstevel@tonic-gate 
4463*0Sstevel@tonic-gate 	if (rval != 0 && keynlp != NULL && committed != 1)
4464*0Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
4465*0Sstevel@tonic-gate 
4466*0Sstevel@tonic-gate 	metafreenamelist(keynlp);
4467*0Sstevel@tonic-gate 
4468*0Sstevel@tonic-gate 	return (rval);
4469*0Sstevel@tonic-gate }
4470*0Sstevel@tonic-gate 
4471*0Sstevel@tonic-gate /*
4472*0Sstevel@tonic-gate  * **************************************************************************
4473*0Sstevel@tonic-gate  *                      Reset (metaclear) Functions                         *
4474*0Sstevel@tonic-gate  * **************************************************************************
4475*0Sstevel@tonic-gate  */
4476*0Sstevel@tonic-gate 
4477*0Sstevel@tonic-gate /*
4478*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset_common()
4479*0Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
4480*0Sstevel@tonic-gate  *		np	- the name of the device to reset
4481*0Sstevel@tonic-gate  *		msp	- the unit structure to reset
4482*0Sstevel@tonic-gate  *		options	- metaclear options
4483*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4484*0Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
4485*0Sstevel@tonic-gate  * PURPOSE:	"resets", or more accurately deletes, the soft partition
4486*0Sstevel@tonic-gate  *		specified.  First the state is set to "deleting" and then the
4487*0Sstevel@tonic-gate  *		watermarks are all cleared out.  Once the watermarks have been
4488*0Sstevel@tonic-gate  *		updated, the unit structure is deleted from the metadb.
4489*0Sstevel@tonic-gate  */
4490*0Sstevel@tonic-gate static int
4491*0Sstevel@tonic-gate meta_sp_reset_common(
4492*0Sstevel@tonic-gate 	mdsetname_t	*sp,
4493*0Sstevel@tonic-gate 	mdname_t	*np,
4494*0Sstevel@tonic-gate 	md_sp_t		*msp,
4495*0Sstevel@tonic-gate 	md_sp_reset_t	reset_params,
4496*0Sstevel@tonic-gate 	mdcmdopts_t	options,
4497*0Sstevel@tonic-gate 	md_error_t	*ep
4498*0Sstevel@tonic-gate )
4499*0Sstevel@tonic-gate {
4500*0Sstevel@tonic-gate 	char	*miscname;
4501*0Sstevel@tonic-gate 	int	rval = -1;
4502*0Sstevel@tonic-gate 	int	is_open = 0;
4503*0Sstevel@tonic-gate 
4504*0Sstevel@tonic-gate 	/* make sure that nobody owns us */
4505*0Sstevel@tonic-gate 	if (MD_HAS_PARENT(msp->common.parent))
4506*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(np->dev),
4507*0Sstevel@tonic-gate 					np->cname));
4508*0Sstevel@tonic-gate 
4509*0Sstevel@tonic-gate 	/* make sure that the soft partition isn't open */
4510*0Sstevel@tonic-gate 	if ((is_open = meta_isopen(sp, np, ep, options)) < 0)
4511*0Sstevel@tonic-gate 		return (-1);
4512*0Sstevel@tonic-gate 	else if (is_open)
4513*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IS_OPEN, meta_getminor(np->dev),
4514*0Sstevel@tonic-gate 					np->cname));
4515*0Sstevel@tonic-gate 
4516*0Sstevel@tonic-gate 	/* get miscname */
4517*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
4518*0Sstevel@tonic-gate 		return (-1);
4519*0Sstevel@tonic-gate 
4520*0Sstevel@tonic-gate 	/* fill in reset params */
4521*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&reset_params, miscname, sp->setno);
4522*0Sstevel@tonic-gate 	reset_params.mnum = meta_getminor(np->dev);
4523*0Sstevel@tonic-gate 	reset_params.force = (options & MDCMD_FORCE) ? 1 : 0;
4524*0Sstevel@tonic-gate 
4525*0Sstevel@tonic-gate 	/*
4526*0Sstevel@tonic-gate 	 * clear soft partition - phase one.
4527*0Sstevel@tonic-gate 	 * place the soft partition into the "delete pending" state.
4528*0Sstevel@tonic-gate 	 */
4529*0Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &reset_params.mnum, 1, MD_SP_DELPEND, ep) < 0)
4530*0Sstevel@tonic-gate 		return (-1);
4531*0Sstevel@tonic-gate 
4532*0Sstevel@tonic-gate 	/*
4533*0Sstevel@tonic-gate 	 * Now clear the watermarks.  If the force flag is specified,
4534*0Sstevel@tonic-gate 	 * ignore any errors writing the watermarks and delete the unit
4535*0Sstevel@tonic-gate 	 * structure anyway.  An error may leave the on-disk format in a
4536*0Sstevel@tonic-gate 	 * corrupt state.  If force is not specified and we fail here,
4537*0Sstevel@tonic-gate 	 * the soft partition will remain in the "delete pending" state.
4538*0Sstevel@tonic-gate 	 */
4539*0Sstevel@tonic-gate 	if ((meta_sp_clear_wm(sp, msp, ep) < 0) &&
4540*0Sstevel@tonic-gate 	    ((options & MDCMD_FORCE) == 0))
4541*0Sstevel@tonic-gate 		goto out;
4542*0Sstevel@tonic-gate 
4543*0Sstevel@tonic-gate 	/*
4544*0Sstevel@tonic-gate 	 * clear soft partition - phase two.
4545*0Sstevel@tonic-gate 	 * the driver removes the soft partition from the metadb and
4546*0Sstevel@tonic-gate 	 * zeros out incore version.
4547*0Sstevel@tonic-gate 	 */
4548*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCRESET, &reset_params,
4549*0Sstevel@tonic-gate 	    &reset_params.mde, np->cname) != 0) {
4550*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &reset_params.mde);
4551*0Sstevel@tonic-gate 		goto out;
4552*0Sstevel@tonic-gate 	}
4553*0Sstevel@tonic-gate 	rval = 0;	/* success */
4554*0Sstevel@tonic-gate 
4555*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
4556*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
4557*0Sstevel@tonic-gate 		    "%s: Soft Partition is cleared\n"),
4558*0Sstevel@tonic-gate 		    np->cname);
4559*0Sstevel@tonic-gate 		(void) fflush(stdout);
4560*0Sstevel@tonic-gate 	}
4561*0Sstevel@tonic-gate 
4562*0Sstevel@tonic-gate 	/*
4563*0Sstevel@tonic-gate 	 * if told to recurse and on a metadevice, then attempt to
4564*0Sstevel@tonic-gate 	 * clear the subdevices.  Indicate failure if the clear fails.
4565*0Sstevel@tonic-gate 	 */
4566*0Sstevel@tonic-gate 	if ((options & MDCMD_RECURSE) &&
4567*0Sstevel@tonic-gate 	    (metaismeta(msp->compnamep)) &&
4568*0Sstevel@tonic-gate 	    (meta_reset_by_name(sp, msp->compnamep, options, ep) != 0))
4569*0Sstevel@tonic-gate 		rval = -1;
4570*0Sstevel@tonic-gate 
4571*0Sstevel@tonic-gate out:
4572*0Sstevel@tonic-gate 	meta_invalidate_name(np);
4573*0Sstevel@tonic-gate 	return (rval);
4574*0Sstevel@tonic-gate }
4575*0Sstevel@tonic-gate 
4576*0Sstevel@tonic-gate /*
4577*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset()
4578*0Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
4579*0Sstevel@tonic-gate  *		np	- the name of the device to reset
4580*0Sstevel@tonic-gate  *		options	- metaclear options
4581*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4582*0Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
4583*0Sstevel@tonic-gate  * PURPOSE:	provides the entry point to the rest of libmeta for deleting a
4584*0Sstevel@tonic-gate  *		soft partition.  If np is NULL, then soft partitions are
4585*0Sstevel@tonic-gate  *		all deleted at the current level and then recursively deleted.
4586*0Sstevel@tonic-gate  *		Otherwise, if a name is specified either directly or as a
4587*0Sstevel@tonic-gate  *		result of a recursive operation, it deletes only that name.
4588*0Sstevel@tonic-gate  *		Since something sitting under a soft partition may be parented
4589*0Sstevel@tonic-gate  *		to it, we have to reparent that other device to another soft
4590*0Sstevel@tonic-gate  *		partition on the same component if we're deleting the one it's
4591*0Sstevel@tonic-gate  *		parented to.
4592*0Sstevel@tonic-gate  */
4593*0Sstevel@tonic-gate int
4594*0Sstevel@tonic-gate meta_sp_reset(
4595*0Sstevel@tonic-gate 	mdsetname_t	*sp,
4596*0Sstevel@tonic-gate 	mdname_t	*np,
4597*0Sstevel@tonic-gate 	mdcmdopts_t	options,
4598*0Sstevel@tonic-gate 	md_error_t	*ep
4599*0Sstevel@tonic-gate )
4600*0Sstevel@tonic-gate {
4601*0Sstevel@tonic-gate 	md_sp_t		*msp;
4602*0Sstevel@tonic-gate 	int		rval = -1;
4603*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL, *nlp = NULL;
4604*0Sstevel@tonic-gate 	md_sp_reset_t	reset_params;
4605*0Sstevel@tonic-gate 	int		num_sp;
4606*0Sstevel@tonic-gate 
4607*0Sstevel@tonic-gate 	assert(sp != NULL);
4608*0Sstevel@tonic-gate 
4609*0Sstevel@tonic-gate 	/* reset/delete all soft paritions */
4610*0Sstevel@tonic-gate 	if (np == NULL) {
4611*0Sstevel@tonic-gate 		/*
4612*0Sstevel@tonic-gate 		 * meta_reset_all sets MDCMD_RECURSE, but this behavior
4613*0Sstevel@tonic-gate 		 * is incorrect for soft partitions.  We want to clear
4614*0Sstevel@tonic-gate 		 * all soft partitions at a particular level in the
4615*0Sstevel@tonic-gate 		 * metadevice stack before moving to the next level.
4616*0Sstevel@tonic-gate 		 * Thus, we clear MDCMD_RECURSE from the options.
4617*0Sstevel@tonic-gate 		 */
4618*0Sstevel@tonic-gate 		options &= ~MDCMD_RECURSE;
4619*0Sstevel@tonic-gate 
4620*0Sstevel@tonic-gate 		/* for each soft partition */
4621*0Sstevel@tonic-gate 		rval = 0;
4622*0Sstevel@tonic-gate 		if (meta_get_sp_names(sp, &spnlp, 0, ep) < 0)
4623*0Sstevel@tonic-gate 			rval = -1;
4624*0Sstevel@tonic-gate 
4625*0Sstevel@tonic-gate 		for (nlp = spnlp; (nlp != NULL); nlp = nlp->next) {
4626*0Sstevel@tonic-gate 			np = nlp->namep;
4627*0Sstevel@tonic-gate 			if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
4628*0Sstevel@tonic-gate 				rval = -1;
4629*0Sstevel@tonic-gate 				break;
4630*0Sstevel@tonic-gate 			}
4631*0Sstevel@tonic-gate 			/*
4632*0Sstevel@tonic-gate 			 * meta_reset_all calls us twice to get soft
4633*0Sstevel@tonic-gate 			 * partitions at the top and bottom of the stack.
4634*0Sstevel@tonic-gate 			 * thus, if we have a parent, we'll get deleted
4635*0Sstevel@tonic-gate 			 * on the next call.
4636*0Sstevel@tonic-gate 			 */
4637*0Sstevel@tonic-gate 			if (MD_HAS_PARENT(msp->common.parent))
4638*0Sstevel@tonic-gate 				continue;
4639*0Sstevel@tonic-gate 			/*
4640*0Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
4641*0Sstevel@tonic-gate 			 * of individual metaclear commands.
4642*0Sstevel@tonic-gate 			 */
4643*0Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
4644*0Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
4645*0Sstevel@tonic-gate 				    np->cname, options, 0, ep) != 0) {
4646*0Sstevel@tonic-gate 					rval = -1;
4647*0Sstevel@tonic-gate 					break;
4648*0Sstevel@tonic-gate 				}
4649*0Sstevel@tonic-gate 			} else {
4650*0Sstevel@tonic-gate 				if (meta_sp_reset(sp, np, options, ep) != 0) {
4651*0Sstevel@tonic-gate 					rval = -1;
4652*0Sstevel@tonic-gate 					break;
4653*0Sstevel@tonic-gate 				}
4654*0Sstevel@tonic-gate 			}
4655*0Sstevel@tonic-gate 		}
4656*0Sstevel@tonic-gate 		/* cleanup return status */
4657*0Sstevel@tonic-gate 		metafreenamelist(spnlp);
4658*0Sstevel@tonic-gate 		return (rval);
4659*0Sstevel@tonic-gate 	}
4660*0Sstevel@tonic-gate 
4661*0Sstevel@tonic-gate 	/* check the name */
4662*0Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
4663*0Sstevel@tonic-gate 		return (-1);
4664*0Sstevel@tonic-gate 
4665*0Sstevel@tonic-gate 	/* get the unit structure */
4666*0Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, np, ep)) == NULL)
4667*0Sstevel@tonic-gate 		return (-1);
4668*0Sstevel@tonic-gate 
4669*0Sstevel@tonic-gate 	/* clear out reset parameters */
4670*0Sstevel@tonic-gate 	(void) memset(&reset_params, 0, sizeof (reset_params));
4671*0Sstevel@tonic-gate 
4672*0Sstevel@tonic-gate 	/* if our child is a metadevice, we need to deparent/reparent it */
4673*0Sstevel@tonic-gate 	if (metaismeta(msp->compnamep)) {
4674*0Sstevel@tonic-gate 		/* get sp's on this component */
4675*0Sstevel@tonic-gate 		if ((num_sp = meta_sp_get_by_component(sp, msp->compnamep,
4676*0Sstevel@tonic-gate 		    &spnlp, 1, ep)) <= 0)
4677*0Sstevel@tonic-gate 			/* no sp's on this device.  error! */
4678*0Sstevel@tonic-gate 			return (-1);
4679*0Sstevel@tonic-gate 		else if (num_sp == 1)
4680*0Sstevel@tonic-gate 			/* last sp on this device, so we deparent */
4681*0Sstevel@tonic-gate 			reset_params.new_parent = MD_NO_PARENT;
4682*0Sstevel@tonic-gate 		else {
4683*0Sstevel@tonic-gate 			/* have to reparent this metadevice */
4684*0Sstevel@tonic-gate 			for (nlp = spnlp; nlp != NULL; nlp = nlp->next) {
4685*0Sstevel@tonic-gate 				if (meta_getminor(nlp->namep->dev) ==
4686*0Sstevel@tonic-gate 					meta_getminor(np->dev))
4687*0Sstevel@tonic-gate 					continue;
4688*0Sstevel@tonic-gate 				/*
4689*0Sstevel@tonic-gate 				 * this isn't the softpart we are deleting,
4690*0Sstevel@tonic-gate 				 * so use this device as the new parent.
4691*0Sstevel@tonic-gate 				 */
4692*0Sstevel@tonic-gate 				reset_params.new_parent =
4693*0Sstevel@tonic-gate 				    meta_getminor(nlp->namep->dev);
4694*0Sstevel@tonic-gate 				break;
4695*0Sstevel@tonic-gate 			}
4696*0Sstevel@tonic-gate 		}
4697*0Sstevel@tonic-gate 		metafreenamelist(spnlp);
4698*0Sstevel@tonic-gate 	}
4699*0Sstevel@tonic-gate 
4700*0Sstevel@tonic-gate 	if (meta_sp_reset_common(sp, np, msp, reset_params, options, ep) != 0)
4701*0Sstevel@tonic-gate 		return (-1);
4702*0Sstevel@tonic-gate 
4703*0Sstevel@tonic-gate 	return (0);
4704*0Sstevel@tonic-gate }
4705*0Sstevel@tonic-gate 
4706*0Sstevel@tonic-gate /*
4707*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset_component()
4708*0Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
4709*0Sstevel@tonic-gate  *		name	- the string name of the device to reset
4710*0Sstevel@tonic-gate  *		options	- metaclear options
4711*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4712*0Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
4713*0Sstevel@tonic-gate  * PURPOSE:	provides the ability to delete all soft partitions on a
4714*0Sstevel@tonic-gate  *		specified device (metaclear -p).  It first gets all of the
4715*0Sstevel@tonic-gate  *		soft partitions on the component and then deletes each one
4716*0Sstevel@tonic-gate  *		individually.
4717*0Sstevel@tonic-gate  */
4718*0Sstevel@tonic-gate int
4719*0Sstevel@tonic-gate meta_sp_reset_component(
4720*0Sstevel@tonic-gate 	mdsetname_t	*sp,
4721*0Sstevel@tonic-gate 	char		*name,
4722*0Sstevel@tonic-gate 	mdcmdopts_t	options,
4723*0Sstevel@tonic-gate 	md_error_t	*ep
4724*0Sstevel@tonic-gate )
4725*0Sstevel@tonic-gate {
4726*0Sstevel@tonic-gate 	mdname_t	*compnp, *np;
4727*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
4728*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
4729*0Sstevel@tonic-gate 	md_sp_t		*msp;
4730*0Sstevel@tonic-gate 	int		count;
4731*0Sstevel@tonic-gate 	md_sp_reset_t	reset_params;
4732*0Sstevel@tonic-gate 
4733*0Sstevel@tonic-gate 	if ((compnp = metaname(&sp, name, ep)) == NULL)
4734*0Sstevel@tonic-gate 		return (-1);
4735*0Sstevel@tonic-gate 
4736*0Sstevel@tonic-gate 	/* If we're starting out with no soft partitions, it's an error */
4737*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 1, ep);
4738*0Sstevel@tonic-gate 	if (count == 0)
4739*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_NOSP, 0, compnp->cname));
4740*0Sstevel@tonic-gate 	else if (count < 0)
4741*0Sstevel@tonic-gate 		return (-1);
4742*0Sstevel@tonic-gate 
4743*0Sstevel@tonic-gate 	/*
4744*0Sstevel@tonic-gate 	 * clear all soft partitions on this component.
4745*0Sstevel@tonic-gate 	 * NOTE: we reparent underlying metadevices as we go so that
4746*0Sstevel@tonic-gate 	 * things stay sane.  Also, if we encounter an error, we stop
4747*0Sstevel@tonic-gate 	 * and go no further in case recovery might be needed.
4748*0Sstevel@tonic-gate 	 */
4749*0Sstevel@tonic-gate 	for (nlp = spnlp; nlp != NULL; nlp = nlp->next) {
4750*0Sstevel@tonic-gate 		/* clear out reset parameters */
4751*0Sstevel@tonic-gate 		(void) memset(&reset_params, 0, sizeof (reset_params));
4752*0Sstevel@tonic-gate 
4753*0Sstevel@tonic-gate 		/* check the name */
4754*0Sstevel@tonic-gate 		np = nlp->namep;
4755*0Sstevel@tonic-gate 
4756*0Sstevel@tonic-gate 		if (metachkmeta(np, ep) != 0) {
4757*0Sstevel@tonic-gate 			metafreenamelist(spnlp);
4758*0Sstevel@tonic-gate 			return (-1);
4759*0Sstevel@tonic-gate 		}
4760*0Sstevel@tonic-gate 
4761*0Sstevel@tonic-gate 		/* get the unit structure */
4762*0Sstevel@tonic-gate 		if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
4763*0Sstevel@tonic-gate 			metafreenamelist(spnlp);
4764*0Sstevel@tonic-gate 			return (-1);
4765*0Sstevel@tonic-gate 		}
4766*0Sstevel@tonic-gate 
4767*0Sstevel@tonic-gate 		/* have to deparent/reparent metadevices */
4768*0Sstevel@tonic-gate 		if (metaismeta(compnp)) {
4769*0Sstevel@tonic-gate 			if (nlp->next == NULL)
4770*0Sstevel@tonic-gate 				reset_params.new_parent = MD_NO_PARENT;
4771*0Sstevel@tonic-gate 			else
4772*0Sstevel@tonic-gate 				reset_params.new_parent =
4773*0Sstevel@tonic-gate 				    meta_getminor(spnlp->next->namep->dev);
4774*0Sstevel@tonic-gate 		}
4775*0Sstevel@tonic-gate 
4776*0Sstevel@tonic-gate 		/* clear soft partition */
4777*0Sstevel@tonic-gate 		if (meta_sp_reset_common(sp, np, msp, reset_params,
4778*0Sstevel@tonic-gate 		    options, ep) < 0) {
4779*0Sstevel@tonic-gate 			metafreenamelist(spnlp);
4780*0Sstevel@tonic-gate 			return (-1);
4781*0Sstevel@tonic-gate 		}
4782*0Sstevel@tonic-gate 	}
4783*0Sstevel@tonic-gate 	metafreenamelist(spnlp);
4784*0Sstevel@tonic-gate 	return (0);
4785*0Sstevel@tonic-gate }
4786*0Sstevel@tonic-gate 
4787*0Sstevel@tonic-gate /*
4788*0Sstevel@tonic-gate  * **************************************************************************
4789*0Sstevel@tonic-gate  *                      Grow (metattach) Functions                          *
4790*0Sstevel@tonic-gate  * **************************************************************************
4791*0Sstevel@tonic-gate  */
4792*0Sstevel@tonic-gate 
4793*0Sstevel@tonic-gate /*
4794*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_attach()
4795*0Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to attach to
4796*0Sstevel@tonic-gate  *		np	- the name of the device to attach to
4797*0Sstevel@tonic-gate  *		addsize	- the unparsed string holding the amount of space to add
4798*0Sstevel@tonic-gate  *		options	- metattach options
4799*0Sstevel@tonic-gate  *		alignment - data alignment
4800*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4801*0Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
4802*0Sstevel@tonic-gate  * PURPOSE:	grows a soft partition by reading in the existing unit
4803*0Sstevel@tonic-gate  *		structure and setting its state to Growing, allocating more
4804*0Sstevel@tonic-gate  *		space (similar to meta_create_sp()), updating the watermarks,
4805*0Sstevel@tonic-gate  *		and then writing out the new unit structure in the Okay state.
4806*0Sstevel@tonic-gate  */
4807*0Sstevel@tonic-gate int
4808*0Sstevel@tonic-gate meta_sp_attach(
4809*0Sstevel@tonic-gate 	mdsetname_t	*sp,
4810*0Sstevel@tonic-gate 	mdname_t	*np,
4811*0Sstevel@tonic-gate 	char		*addsize,
4812*0Sstevel@tonic-gate 	mdcmdopts_t	options,
4813*0Sstevel@tonic-gate 	sp_ext_length_t	alignment,
4814*0Sstevel@tonic-gate 	md_error_t	*ep
4815*0Sstevel@tonic-gate )
4816*0Sstevel@tonic-gate {
4817*0Sstevel@tonic-gate 	md_grow_params_t	grow_params;
4818*0Sstevel@tonic-gate 	sp_ext_length_t		grow_len;	/* amount to grow */
4819*0Sstevel@tonic-gate 	mp_unit_t		*mp, *new_un;
4820*0Sstevel@tonic-gate 	mdname_t		*compnp = NULL;
4821*0Sstevel@tonic-gate 
4822*0Sstevel@tonic-gate 	sp_ext_node_t		*extlist = NULL;
4823*0Sstevel@tonic-gate 	int			numexts;
4824*0Sstevel@tonic-gate 	mdnamelist_t		*spnlp = NULL;
4825*0Sstevel@tonic-gate 	int			count;
4826*0Sstevel@tonic-gate 	md_sp_t			*msp;
4827*0Sstevel@tonic-gate 	daddr_t			start_block;
4828*0Sstevel@tonic-gate 
4829*0Sstevel@tonic-gate 	/* should have the same set */
4830*0Sstevel@tonic-gate 	assert(sp != NULL);
4831*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(np->dev)));
4832*0Sstevel@tonic-gate 
4833*0Sstevel@tonic-gate 	/* check name */
4834*0Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
4835*0Sstevel@tonic-gate 		return (-1);
4836*0Sstevel@tonic-gate 
4837*0Sstevel@tonic-gate 	if (meta_sp_parsesize(addsize, &grow_len) == -1) {
4838*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BAD_LENGTH, 0, np->cname));
4839*0Sstevel@tonic-gate 	}
4840*0Sstevel@tonic-gate 
4841*0Sstevel@tonic-gate 	if ((mp = (mp_unit_t *)meta_get_mdunit(sp, np, ep)) == NULL)
4842*0Sstevel@tonic-gate 		return (-1);
4843*0Sstevel@tonic-gate 
4844*0Sstevel@tonic-gate 	/* make sure we don't have a parent */
4845*0Sstevel@tonic-gate 	if (MD_HAS_PARENT(mp->c.un_parent)) {
4846*0Sstevel@tonic-gate 		Free(mp);
4847*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_INVAL_UNIT, 0, np->cname));
4848*0Sstevel@tonic-gate 	}
4849*0Sstevel@tonic-gate 
4850*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
4851*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: Unit structure before new "
4852*0Sstevel@tonic-gate 		    "space:\n");
4853*0Sstevel@tonic-gate 		meta_sp_printunit(mp);
4854*0Sstevel@tonic-gate 	}
4855*0Sstevel@tonic-gate 
4856*0Sstevel@tonic-gate 	/*
4857*0Sstevel@tonic-gate 	 * NOTE: the fast option to metakeyname is 0 as opposed to 1
4858*0Sstevel@tonic-gate 	 * If this was not the case we would suffer the following
4859*0Sstevel@tonic-gate 	 * assertion failure:
4860*0Sstevel@tonic-gate 	 * Assertion failed: type1 != MDT_FAST_META && type1 != MDT_FAST_COMP
4861*0Sstevel@tonic-gate 	 * file meta_check.x, line 315
4862*0Sstevel@tonic-gate 	 * I guess this is because we have not "seen" this drive before
4863*0Sstevel@tonic-gate 	 * and hence hit the failure - this is of course the attach routine
4864*0Sstevel@tonic-gate 	 */
4865*0Sstevel@tonic-gate 	if ((compnp = metakeyname(&sp, mp->un_key, 0, ep)) == NULL) {
4866*0Sstevel@tonic-gate 		Free(mp);
4867*0Sstevel@tonic-gate 		return (-1);
4868*0Sstevel@tonic-gate 	}
4869*0Sstevel@tonic-gate 
4870*0Sstevel@tonic-gate 	/* metakeyname does not fill in the key. */
4871*0Sstevel@tonic-gate 	compnp->key = mp->un_key;
4872*0Sstevel@tonic-gate 
4873*0Sstevel@tonic-gate 	/* work out the space on the component that we are dealing with */
4874*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
4875*0Sstevel@tonic-gate 
4876*0Sstevel@tonic-gate 	/*
4877*0Sstevel@tonic-gate 	 * see if the component has been soft partitioned yet, or if an
4878*0Sstevel@tonic-gate 	 * error occurred.
4879*0Sstevel@tonic-gate 	 */
4880*0Sstevel@tonic-gate 	if (count == 0) {
4881*0Sstevel@tonic-gate 		Free(mp);
4882*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_NOT_SP, 0, np->cname));
4883*0Sstevel@tonic-gate 	} else if (count < 0) {
4884*0Sstevel@tonic-gate 		Free(mp);
4885*0Sstevel@tonic-gate 		return (-1);
4886*0Sstevel@tonic-gate 	}
4887*0Sstevel@tonic-gate 
4888*0Sstevel@tonic-gate 	/*
4889*0Sstevel@tonic-gate 	 * seed extlist with reserved space at the beginning of the volume and
4890*0Sstevel@tonic-gate 	 * enough space for the end watermark.  The end watermark always gets
4891*0Sstevel@tonic-gate 	 * updated, but if the underlying device changes size it may not be
4892*0Sstevel@tonic-gate 	 * pointed to until the extent before it is updated.  Since the
4893*0Sstevel@tonic-gate 	 * end of the reserved space is where the first watermark starts,
4894*0Sstevel@tonic-gate 	 * the reserved extent should never be marked for updating.
4895*0Sstevel@tonic-gate 	 */
4896*0Sstevel@tonic-gate 	if ((start_block = meta_sp_get_start(sp, compnp, ep)) ==
4897*0Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
4898*0Sstevel@tonic-gate 		Free(mp);
4899*0Sstevel@tonic-gate 		return (-1);
4900*0Sstevel@tonic-gate 	}
4901*0Sstevel@tonic-gate 
4902*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist, 0ULL, start_block,
4903*0Sstevel@tonic-gate 	    EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
4904*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
4905*0Sstevel@tonic-gate 	    metagetsize(compnp, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
4906*0Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
4907*0Sstevel@tonic-gate 
4908*0Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
4909*0Sstevel@tonic-gate 		Free(mp);
4910*0Sstevel@tonic-gate 		return (-1);
4911*0Sstevel@tonic-gate 	}
4912*0Sstevel@tonic-gate 
4913*0Sstevel@tonic-gate 	metafreenamelist(spnlp);
4914*0Sstevel@tonic-gate 
4915*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
4916*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: list of used extents:\n");
4917*0Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
4918*0Sstevel@tonic-gate 	}
4919*0Sstevel@tonic-gate 
4920*0Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
4921*0Sstevel@tonic-gate 
4922*0Sstevel@tonic-gate 	assert(mp->un_numexts >= 1);
4923*0Sstevel@tonic-gate 	numexts = meta_sp_alloc_by_len(sp, np, &extlist, &grow_len,
4924*0Sstevel@tonic-gate 	    mp->un_ext[mp->un_numexts - 1].un_poff,
4925*0Sstevel@tonic-gate 	    (alignment > 0) ? alignment :
4926*0Sstevel@tonic-gate 	    meta_sp_get_default_alignment(sp, compnp, ep));
4927*0Sstevel@tonic-gate 
4928*0Sstevel@tonic-gate 	if (numexts == -1) {
4929*0Sstevel@tonic-gate 		Free(mp);
4930*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_NOSPACE, 0, np->cname));
4931*0Sstevel@tonic-gate 	}
4932*0Sstevel@tonic-gate 
4933*0Sstevel@tonic-gate 	/* allocate new unit structure and copy in old unit */
4934*0Sstevel@tonic-gate 	if ((new_un = meta_sp_updateunit(np, mp, extlist,
4935*0Sstevel@tonic-gate 	    grow_len, numexts, ep)) == NULL) {
4936*0Sstevel@tonic-gate 		Free(mp);
4937*0Sstevel@tonic-gate 		return (-1);
4938*0Sstevel@tonic-gate 	}
4939*0Sstevel@tonic-gate 	Free(mp);
4940*0Sstevel@tonic-gate 
4941*0Sstevel@tonic-gate 	/* If running in dryrun mode (-n option), we're done here */
4942*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
4943*0Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
4944*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
4945*0Sstevel@tonic-gate 			    "%s: Soft Partition would grow\n"),
4946*0Sstevel@tonic-gate 			    np->cname);
4947*0Sstevel@tonic-gate 			(void) fflush(stdout);
4948*0Sstevel@tonic-gate 		}
4949*0Sstevel@tonic-gate 		return (0);
4950*0Sstevel@tonic-gate 	}
4951*0Sstevel@tonic-gate 
4952*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
4953*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: updated unit structure:\n");
4954*0Sstevel@tonic-gate 		meta_sp_printunit(new_un);
4955*0Sstevel@tonic-gate 	}
4956*0Sstevel@tonic-gate 
4957*0Sstevel@tonic-gate 	assert(new_un != NULL);
4958*0Sstevel@tonic-gate 
4959*0Sstevel@tonic-gate 	(void) memset(&grow_params, 0, sizeof (grow_params));
4960*0Sstevel@tonic-gate 	if (new_un->c.un_total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) {
4961*0Sstevel@tonic-gate 		grow_params.options = MD_CRO_64BIT;
4962*0Sstevel@tonic-gate 		new_un->c.un_revision = MD_64BIT_META_DEV;
4963*0Sstevel@tonic-gate 	} else {
4964*0Sstevel@tonic-gate 		grow_params.options = MD_CRO_32BIT;
4965*0Sstevel@tonic-gate 		new_un->c.un_revision = MD_32BIT_META_DEV;
4966*0Sstevel@tonic-gate 	}
4967*0Sstevel@tonic-gate 	grow_params.mnum = MD_SID(new_un);
4968*0Sstevel@tonic-gate 	grow_params.size = new_un->c.un_size;
4969*0Sstevel@tonic-gate 	grow_params.mdp = (uintptr_t)new_un;
4970*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&grow_params, MD_SP, MD_MIN2SET(grow_params.mnum));
4971*0Sstevel@tonic-gate 
4972*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGROW, &grow_params, &grow_params.mde,
4973*0Sstevel@tonic-gate 	    np->cname) != 0) {
4974*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &grow_params.mde);
4975*0Sstevel@tonic-gate 		return (-1);
4976*0Sstevel@tonic-gate 	}
4977*0Sstevel@tonic-gate 
4978*0Sstevel@tonic-gate 	/* update all watermarks */
4979*0Sstevel@tonic-gate 
4980*0Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, np, ep)) == NULL)
4981*0Sstevel@tonic-gate 		return (-1);
4982*0Sstevel@tonic-gate 	if (meta_sp_update_wm(sp, msp, extlist, ep) < 0)
4983*0Sstevel@tonic-gate 		return (-1);
4984*0Sstevel@tonic-gate 
4985*0Sstevel@tonic-gate 
4986*0Sstevel@tonic-gate 	/* second phase of commit, set status to MD_SP_OK */
4987*0Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &(MD_SID(new_un)), 1, MD_SP_OK, ep) < 0)
4988*0Sstevel@tonic-gate 		return (-1);
4989*0Sstevel@tonic-gate 
4990*0Sstevel@tonic-gate 	meta_invalidate_name(np);
4991*0Sstevel@tonic-gate 
4992*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
4993*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
4994*0Sstevel@tonic-gate 		    "%s: Soft Partition has been grown\n"),
4995*0Sstevel@tonic-gate 		    np->cname);
4996*0Sstevel@tonic-gate 		(void) fflush(stdout);
4997*0Sstevel@tonic-gate 	}
4998*0Sstevel@tonic-gate 
4999*0Sstevel@tonic-gate 	return (0);
5000*0Sstevel@tonic-gate }
5001*0Sstevel@tonic-gate 
5002*0Sstevel@tonic-gate /*
5003*0Sstevel@tonic-gate  * **************************************************************************
5004*0Sstevel@tonic-gate  *                    Recovery (metarecover) Functions                      *
5005*0Sstevel@tonic-gate  * **************************************************************************
5006*0Sstevel@tonic-gate  */
5007*0Sstevel@tonic-gate 
5008*0Sstevel@tonic-gate /*
5009*0Sstevel@tonic-gate  * FUNCTION:	meta_recover_sp()
5010*0Sstevel@tonic-gate  * INPUT:	sp	- the name of the set we are recovering on
5011*0Sstevel@tonic-gate  *		compnp	- name pointer for device we are recovering on
5012*0Sstevel@tonic-gate  *		argc	- argument count
5013*0Sstevel@tonic-gate  *		argv	- left over arguments not parsed by metarecover command
5014*0Sstevel@tonic-gate  *		options	- metarecover options
5015*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
5016*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
5017*0Sstevel@tonic-gate  * PURPOSE:	parse soft partitioning-specific metarecover options and
5018*0Sstevel@tonic-gate  *		dispatch to the appropriate function to handle recovery.
5019*0Sstevel@tonic-gate  */
5020*0Sstevel@tonic-gate int
5021*0Sstevel@tonic-gate meta_recover_sp(
5022*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5023*0Sstevel@tonic-gate 	mdname_t	*compnp,
5024*0Sstevel@tonic-gate 	int		argc,
5025*0Sstevel@tonic-gate 	char		*argv[],
5026*0Sstevel@tonic-gate 	mdcmdopts_t	options,
5027*0Sstevel@tonic-gate 	md_error_t	*ep
5028*0Sstevel@tonic-gate )
5029*0Sstevel@tonic-gate {
5030*0Sstevel@tonic-gate 	md_set_desc	*sd;
5031*0Sstevel@tonic-gate 
5032*0Sstevel@tonic-gate 	if (argc > 1) {
5033*0Sstevel@tonic-gate 		(void) meta_cook_syntax(ep, MDE_SYNTAX, compnp->cname,
5034*0Sstevel@tonic-gate 		    argc, argv);
5035*0Sstevel@tonic-gate 		return (-1);
5036*0Sstevel@tonic-gate 	}
5037*0Sstevel@tonic-gate 
5038*0Sstevel@tonic-gate 	/*
5039*0Sstevel@tonic-gate 	 * For a MN set, this operation must be performed on the master
5040*0Sstevel@tonic-gate 	 * as it is responsible for maintaining the watermarks
5041*0Sstevel@tonic-gate 	 */
5042*0Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
5043*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
5044*0Sstevel@tonic-gate 			return (-1);
5045*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd) && !sd->sd_mn_am_i_master) {
5046*0Sstevel@tonic-gate 			(void) mddserror(ep, MDE_DS_MASTER_ONLY, sp->setno,
5047*0Sstevel@tonic-gate 			    sd->sd_mn_master_nodenm, NULL, NULL);
5048*0Sstevel@tonic-gate 			return (-1);
5049*0Sstevel@tonic-gate 		}
5050*0Sstevel@tonic-gate 	}
5051*0Sstevel@tonic-gate 	if (argc == 0) {
5052*0Sstevel@tonic-gate 		/*
5053*0Sstevel@tonic-gate 		 * if no additional arguments are passed, metarecover should
5054*0Sstevel@tonic-gate 		 * validate both on-disk and metadb structures as well as
5055*0Sstevel@tonic-gate 		 * checking that both are consistent with each other
5056*0Sstevel@tonic-gate 		 */
5057*0Sstevel@tonic-gate 		if (meta_sp_validate_wm(sp, compnp, options, ep) < 0)
5058*0Sstevel@tonic-gate 			return (-1);
5059*0Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) < 0)
5060*0Sstevel@tonic-gate 			return (-1);
5061*0Sstevel@tonic-gate 		if (meta_sp_validate_wm_and_unit(sp, compnp, options, ep) < 0)
5062*0Sstevel@tonic-gate 			return (-1);
5063*0Sstevel@tonic-gate 	} else if (strcmp(argv[0], "-d") == 0) {
5064*0Sstevel@tonic-gate 		/*
5065*0Sstevel@tonic-gate 		 * Ensure that there is no existing valid record for this
5066*0Sstevel@tonic-gate 		 * soft-partition. If there is we have nothing to do.
5067*0Sstevel@tonic-gate 		 */
5068*0Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) == 0)
5069*0Sstevel@tonic-gate 			return (-1);
5070*0Sstevel@tonic-gate 		/* validate and recover from on-disk structures */
5071*0Sstevel@tonic-gate 		if (meta_sp_validate_wm(sp, compnp, options, ep) < 0)
5072*0Sstevel@tonic-gate 			return (-1);
5073*0Sstevel@tonic-gate 		if (meta_sp_recover_from_wm(sp, compnp, options, ep) < 0)
5074*0Sstevel@tonic-gate 			return (-1);
5075*0Sstevel@tonic-gate 	} else if (strcmp(argv[0], "-m") == 0) {
5076*0Sstevel@tonic-gate 		/* validate and recover from metadb structures */
5077*0Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) < 0)
5078*0Sstevel@tonic-gate 			return (-1);
5079*0Sstevel@tonic-gate 		if (meta_sp_recover_from_unit(sp, compnp, options, ep) < 0)
5080*0Sstevel@tonic-gate 			return (-1);
5081*0Sstevel@tonic-gate 	} else {
5082*0Sstevel@tonic-gate 		/* syntax error */
5083*0Sstevel@tonic-gate 		(void) meta_cook_syntax(ep, MDE_SYNTAX, compnp->cname,
5084*0Sstevel@tonic-gate 		    argc, argv);
5085*0Sstevel@tonic-gate 		return (-1);
5086*0Sstevel@tonic-gate 	}
5087*0Sstevel@tonic-gate 
5088*0Sstevel@tonic-gate 	return (0);
5089*0Sstevel@tonic-gate }
5090*0Sstevel@tonic-gate 
5091*0Sstevel@tonic-gate /*
5092*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_display_exthdr()
5093*0Sstevel@tonic-gate  * INPUT:	none
5094*0Sstevel@tonic-gate  * OUTPUT:	none
5095*0Sstevel@tonic-gate  * RETURNS:	void
5096*0Sstevel@tonic-gate  * PURPOSE:	print header line for sp_ext_node_t information.  to be used
5097*0Sstevel@tonic-gate  *		in conjunction with meta_sp_display_ext().
5098*0Sstevel@tonic-gate  */
5099*0Sstevel@tonic-gate static void
5100*0Sstevel@tonic-gate meta_sp_display_exthdr(void)
5101*0Sstevel@tonic-gate {
5102*0Sstevel@tonic-gate 	(void) printf("%20s %5s %7s %20s %20s\n",
5103*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Name"),
5104*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Seq#"),
5105*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Type"),
5106*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Offset"),
5107*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Length"));
5108*0Sstevel@tonic-gate }
5109*0Sstevel@tonic-gate 
5110*0Sstevel@tonic-gate 
5111*0Sstevel@tonic-gate /*
5112*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_display_ext()
5113*0Sstevel@tonic-gate  * INPUT:	ext	- extent to display
5114*0Sstevel@tonic-gate  * OUTPUT:	none
5115*0Sstevel@tonic-gate  * RETURNS:	void
5116*0Sstevel@tonic-gate  * PURPOSE:	print selected fields from sp_ext_node_t.
5117*0Sstevel@tonic-gate  */
5118*0Sstevel@tonic-gate static void
5119*0Sstevel@tonic-gate meta_sp_display_ext(sp_ext_node_t *ext)
5120*0Sstevel@tonic-gate {
5121*0Sstevel@tonic-gate 	/* print extent information */
5122*0Sstevel@tonic-gate 	if (ext->ext_namep != NULL)
5123*0Sstevel@tonic-gate 		(void) printf("%20s ", ext->ext_namep->cname);
5124*0Sstevel@tonic-gate 	else
5125*0Sstevel@tonic-gate 		(void) printf("%20s ", "NONE");
5126*0Sstevel@tonic-gate 
5127*0Sstevel@tonic-gate 	(void) printf("%5u ", ext->ext_seq);
5128*0Sstevel@tonic-gate 
5129*0Sstevel@tonic-gate 	switch (ext->ext_type) {
5130*0Sstevel@tonic-gate 	case EXTTYP_ALLOC:
5131*0Sstevel@tonic-gate 		(void) printf("%7s ", "ALLOC");
5132*0Sstevel@tonic-gate 		break;
5133*0Sstevel@tonic-gate 	case EXTTYP_FREE:
5134*0Sstevel@tonic-gate 		(void) printf("%7s ", "FREE");
5135*0Sstevel@tonic-gate 		break;
5136*0Sstevel@tonic-gate 	case EXTTYP_RESERVED:
5137*0Sstevel@tonic-gate 		(void) printf("%7s ", "RESV");
5138*0Sstevel@tonic-gate 		break;
5139*0Sstevel@tonic-gate 	case EXTTYP_END:
5140*0Sstevel@tonic-gate 		(void) printf("%7s ", "END");
5141*0Sstevel@tonic-gate 		break;
5142*0Sstevel@tonic-gate 	default:
5143*0Sstevel@tonic-gate 		(void) printf("%7s ", "INVLD");
5144*0Sstevel@tonic-gate 		break;
5145*0Sstevel@tonic-gate 	}
5146*0Sstevel@tonic-gate 
5147*0Sstevel@tonic-gate 	(void) printf("%20llu %20llu\n", ext->ext_offset, ext->ext_length);
5148*0Sstevel@tonic-gate }
5149*0Sstevel@tonic-gate 
5150*0Sstevel@tonic-gate 
5151*0Sstevel@tonic-gate /*
5152*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_checkseq()
5153*0Sstevel@tonic-gate  * INPUT:	extlist	- list of extents to be checked
5154*0Sstevel@tonic-gate  * OUTPUT:	none
5155*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
5156*0Sstevel@tonic-gate  * PURPOSE:	check soft partition sequence numbers.  this function assumes
5157*0Sstevel@tonic-gate  *		that a list of extents representing 1 or more soft partitions
5158*0Sstevel@tonic-gate  *		is passed in sorted in sequence number order.  within a
5159*0Sstevel@tonic-gate  *		single soft partition, there may not be any missing or
5160*0Sstevel@tonic-gate  *		duplicate sequence numbers.
5161*0Sstevel@tonic-gate  */
5162*0Sstevel@tonic-gate static int
5163*0Sstevel@tonic-gate meta_sp_checkseq(sp_ext_node_t *extlist)
5164*0Sstevel@tonic-gate {
5165*0Sstevel@tonic-gate 	sp_ext_node_t *ext;
5166*0Sstevel@tonic-gate 
5167*0Sstevel@tonic-gate 	assert(extlist != NULL);
5168*0Sstevel@tonic-gate 
5169*0Sstevel@tonic-gate 	for (ext = extlist;
5170*0Sstevel@tonic-gate 	    ext->ext_next != NULL && ext->ext_next->ext_type == EXTTYP_ALLOC;
5171*0Sstevel@tonic-gate 	    ext = ext->ext_next) {
5172*0Sstevel@tonic-gate 		if (ext->ext_next->ext_namep != NULL &&
5173*0Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
5174*0Sstevel@tonic-gate 			ext->ext_namep->cname) != 0)
5175*0Sstevel@tonic-gate 				continue;
5176*0Sstevel@tonic-gate 
5177*0Sstevel@tonic-gate 		if (ext->ext_next->ext_seq != ext->ext_seq + 1) {
5178*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5179*0Sstevel@tonic-gate 			    "%s: sequence numbers are "
5180*0Sstevel@tonic-gate 			    "incorrect: %d should be %d\n"),
5181*0Sstevel@tonic-gate 			    ext->ext_next->ext_namep->cname,
5182*0Sstevel@tonic-gate 			    ext->ext_next->ext_seq, ext->ext_seq + 1);
5183*0Sstevel@tonic-gate 			return (-1);
5184*0Sstevel@tonic-gate 		}
5185*0Sstevel@tonic-gate 	}
5186*0Sstevel@tonic-gate 	return (0);
5187*0Sstevel@tonic-gate }
5188*0Sstevel@tonic-gate 
5189*0Sstevel@tonic-gate 
5190*0Sstevel@tonic-gate /*
5191*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_resolve_name_conflict()
5192*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we're are recovering in.
5193*0Sstevel@tonic-gate  *		old_np	- name pointer of soft partition we found on disk.
5194*0Sstevel@tonic-gate  * OUTPUT:	new_np	- name pointer for new soft partition name.
5195*0Sstevel@tonic-gate  *		ep	- error pointer returned.
5196*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - name not replace, 1 - name replaced, -1 - error
5197*0Sstevel@tonic-gate  * PURPOSE:	Check to see if the name of one of the soft partitions we found
5198*0Sstevel@tonic-gate  *		on disk already exists in the metadb.  If so, prompt for a new
5199*0Sstevel@tonic-gate  *		name.  In addition, we keep a static array of names that
5200*0Sstevel@tonic-gate  *		will be recovered from this device since these names don't
5201*0Sstevel@tonic-gate  *		exist in the configuration at this point but cannot be
5202*0Sstevel@tonic-gate  *		recovered more than once.
5203*0Sstevel@tonic-gate  */
5204*0Sstevel@tonic-gate static int
5205*0Sstevel@tonic-gate meta_sp_resolve_name_conflict(
5206*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5207*0Sstevel@tonic-gate 	mdname_t	*old_np,
5208*0Sstevel@tonic-gate 	mdname_t	**new_np,
5209*0Sstevel@tonic-gate 	md_error_t	*ep
5210*0Sstevel@tonic-gate )
5211*0Sstevel@tonic-gate {
5212*0Sstevel@tonic-gate 	char		yesno[255];
5213*0Sstevel@tonic-gate 	char		*yes;
5214*0Sstevel@tonic-gate 	char		newname[MD_SP_MAX_DEVNAME_PLUS_1];
5215*0Sstevel@tonic-gate 	int		nunits;
5216*0Sstevel@tonic-gate 	static int	*used_names = NULL;
5217*0Sstevel@tonic-gate 
5218*0Sstevel@tonic-gate 	assert(old_np != NULL);
5219*0Sstevel@tonic-gate 
5220*0Sstevel@tonic-gate 	if (used_names == NULL) {
5221*0Sstevel@tonic-gate 		if ((nunits = meta_get_nunits(ep)) < 0)
5222*0Sstevel@tonic-gate 			return (-1);
5223*0Sstevel@tonic-gate 		used_names = Zalloc(nunits * sizeof (int));
5224*0Sstevel@tonic-gate 	}
5225*0Sstevel@tonic-gate 
5226*0Sstevel@tonic-gate 	/* see if it exists already */
5227*0Sstevel@tonic-gate 	if (used_names[MD_MIN2UNIT(meta_getminor(old_np->dev))] == 0 &&
5228*0Sstevel@tonic-gate 	    metagetmiscname(old_np, ep) == NULL) {
5229*0Sstevel@tonic-gate 		if (! mdismderror(ep, MDE_UNIT_NOT_SETUP))
5230*0Sstevel@tonic-gate 			return (-1);
5231*0Sstevel@tonic-gate 		else {
5232*0Sstevel@tonic-gate 			used_names[MD_MIN2UNIT(meta_getminor(old_np->dev))] = 1;
5233*0Sstevel@tonic-gate 			mdclrerror(ep);
5234*0Sstevel@tonic-gate 			return (0);
5235*0Sstevel@tonic-gate 		}
5236*0Sstevel@tonic-gate 	}
5237*0Sstevel@tonic-gate 
5238*0Sstevel@tonic-gate 	/* name exists, ask the user for a new one */
5239*0Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
5240*0Sstevel@tonic-gate 	    "WARNING: A soft partition named %s was found in the extent\n"
5241*0Sstevel@tonic-gate 	    "headers, but this name already exists in the metadb "
5242*0Sstevel@tonic-gate 	    "configuration.\n"
5243*0Sstevel@tonic-gate 	    "In order to continue recovery you must supply\n"
5244*0Sstevel@tonic-gate 	    "a new name for this soft partition.\n"), old_np->cname);
5245*0Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
5246*0Sstevel@tonic-gate 	    "Would you like to continue and supply a new name? (yes/no) "));
5247*0Sstevel@tonic-gate 
5248*0Sstevel@tonic-gate 	(void) fflush(stdout);
5249*0Sstevel@tonic-gate 	if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
5250*0Sstevel@tonic-gate 	    (strlen(yesno) == 1))
5251*0Sstevel@tonic-gate 		(void) snprintf(yesno, sizeof (yesno), "%s\n",
5252*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "no"));
5253*0Sstevel@tonic-gate 	yes = dgettext(TEXT_DOMAIN, "yes");
5254*0Sstevel@tonic-gate 	if (strncasecmp(yesno, yes, strlen(yesno) - 1) != 0) {
5255*0Sstevel@tonic-gate 		return (-1);
5256*0Sstevel@tonic-gate 	}
5257*0Sstevel@tonic-gate 
5258*0Sstevel@tonic-gate 	(void) fflush(stdin);
5259*0Sstevel@tonic-gate 
5260*0Sstevel@tonic-gate 	/* get the new name */
5261*0Sstevel@tonic-gate 	for (;;) {
5262*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "Please enter a new name "
5263*0Sstevel@tonic-gate 		    "for this soft partition (dXXXX) "));
5264*0Sstevel@tonic-gate 		(void) fflush(stdout);
5265*0Sstevel@tonic-gate 		if (fgets(newname, MD_SP_MAX_DEVNAME_PLUS_1, stdin) == NULL)
5266*0Sstevel@tonic-gate 			(void) strcpy(newname, "");
5267*0Sstevel@tonic-gate 
5268*0Sstevel@tonic-gate 		/* remove newline character */
5269*0Sstevel@tonic-gate 		if (newname[strlen(newname) - 1] == '\n')
5270*0Sstevel@tonic-gate 			newname[strlen(newname) - 1] = '\0';
5271*0Sstevel@tonic-gate 
5272*0Sstevel@tonic-gate 		if (!(is_metaname(newname)) ||
5273*0Sstevel@tonic-gate 		    (meta_init_make_device(&sp, newname, ep) != 0)) {
5274*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5275*0Sstevel@tonic-gate 			    "Invalid metadevice name\n"));
5276*0Sstevel@tonic-gate 			(void) fflush(stderr);
5277*0Sstevel@tonic-gate 			continue;
5278*0Sstevel@tonic-gate 		}
5279*0Sstevel@tonic-gate 
5280*0Sstevel@tonic-gate 		if ((*new_np = metaname(&sp, newname, ep)) == NULL) {
5281*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5282*0Sstevel@tonic-gate 			    "Invalid metadevice name\n"));
5283*0Sstevel@tonic-gate 			(void) fflush(stderr);
5284*0Sstevel@tonic-gate 			continue;
5285*0Sstevel@tonic-gate 		}
5286*0Sstevel@tonic-gate 
5287*0Sstevel@tonic-gate 		assert(MD_MIN2UNIT(meta_getminor((*new_np)->dev)) < nunits);
5288*0Sstevel@tonic-gate 		/* make sure the name isn't already being used */
5289*0Sstevel@tonic-gate 		if (used_names[MD_MIN2UNIT(meta_getminor((*new_np)->dev))] ||
5290*0Sstevel@tonic-gate 		    metagetmiscname(*new_np, ep) != NULL) {
5291*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5292*0Sstevel@tonic-gate 			    "That name already exists\n"));
5293*0Sstevel@tonic-gate 			continue;
5294*0Sstevel@tonic-gate 		} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP))
5295*0Sstevel@tonic-gate 			return (-1);
5296*0Sstevel@tonic-gate 
5297*0Sstevel@tonic-gate 		break;
5298*0Sstevel@tonic-gate 	}
5299*0Sstevel@tonic-gate 
5300*0Sstevel@tonic-gate 	/* got a new name, place in used array and return */
5301*0Sstevel@tonic-gate 	used_names[MD_MIN2UNIT(meta_getminor((*new_np)->dev))] = 1;
5302*0Sstevel@tonic-gate 	mdclrerror(ep);
5303*0Sstevel@tonic-gate 	return (1);
5304*0Sstevel@tonic-gate }
5305*0Sstevel@tonic-gate 
5306*0Sstevel@tonic-gate /*
5307*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_wm()
5308*0Sstevel@tonic-gate  * INPUT:	sp	- set name we are recovering in
5309*0Sstevel@tonic-gate  *		compnp	- name pointer for device we are recovering from
5310*0Sstevel@tonic-gate  *		options	- metarecover options
5311*0Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
5312*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
5313*0Sstevel@tonic-gate  * PURPOSE:	validate and display watermark configuration.  walk the
5314*0Sstevel@tonic-gate  *		on-disk watermark structures and validate the information
5315*0Sstevel@tonic-gate  *		found within.  since a watermark configuration is
5316*0Sstevel@tonic-gate  *		"self-defining", the act of traversing the watermarks
5317*0Sstevel@tonic-gate  *		is part of the validation process.
5318*0Sstevel@tonic-gate  */
5319*0Sstevel@tonic-gate static int
5320*0Sstevel@tonic-gate meta_sp_validate_wm(
5321*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5322*0Sstevel@tonic-gate 	mdname_t	*compnp,
5323*0Sstevel@tonic-gate 	mdcmdopts_t	options,
5324*0Sstevel@tonic-gate 	md_error_t	*ep
5325*0Sstevel@tonic-gate )
5326*0Sstevel@tonic-gate {
5327*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
5328*0Sstevel@tonic-gate 	sp_ext_node_t	*ext;
5329*0Sstevel@tonic-gate 	int		num_sps = 0;
5330*0Sstevel@tonic-gate 	int		rval;
5331*0Sstevel@tonic-gate 
5332*0Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
5333*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5334*0Sstevel@tonic-gate 		    "Verifying on-disk structures on %s.\n"),
5335*0Sstevel@tonic-gate 		    compnp->cname);
5336*0Sstevel@tonic-gate 
5337*0Sstevel@tonic-gate 	/*
5338*0Sstevel@tonic-gate 	 * for each watermark, build an ext_node, place on list.
5339*0Sstevel@tonic-gate 	 */
5340*0Sstevel@tonic-gate 	rval = meta_sp_extlist_from_wm(sp, compnp, &extlist,
5341*0Sstevel@tonic-gate 	    meta_sp_cmp_by_nameseq, ep);
5342*0Sstevel@tonic-gate 
5343*0Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0) {
5344*0Sstevel@tonic-gate 		/* print out what we found */
5345*0Sstevel@tonic-gate 		if (extlist == NULL)
5346*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5347*0Sstevel@tonic-gate 			    "No extent headers found on %s.\n"),
5348*0Sstevel@tonic-gate 			    compnp->cname);
5349*0Sstevel@tonic-gate 		else {
5350*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5351*0Sstevel@tonic-gate 			    "The following extent headers were found on %s.\n"),
5352*0Sstevel@tonic-gate 			    compnp->cname);
5353*0Sstevel@tonic-gate 			meta_sp_display_exthdr();
5354*0Sstevel@tonic-gate 		}
5355*0Sstevel@tonic-gate 		for (ext = extlist; ext != NULL; ext = ext->ext_next)
5356*0Sstevel@tonic-gate 			meta_sp_display_ext(ext);
5357*0Sstevel@tonic-gate 	}
5358*0Sstevel@tonic-gate 
5359*0Sstevel@tonic-gate 	if (rval < 0) {
5360*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5361*0Sstevel@tonic-gate 		    "%s: On-disk structures invalid or "
5362*0Sstevel@tonic-gate 		    "no soft partitions found.\n"),
5363*0Sstevel@tonic-gate 		    compnp->cname);
5364*0Sstevel@tonic-gate 		return (-1);
5365*0Sstevel@tonic-gate 	}
5366*0Sstevel@tonic-gate 
5367*0Sstevel@tonic-gate 	assert(extlist != NULL);
5368*0Sstevel@tonic-gate 
5369*0Sstevel@tonic-gate 	/* count number of soft partitions */
5370*0Sstevel@tonic-gate 	for (ext = extlist;
5371*0Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
5372*0Sstevel@tonic-gate 	    ext = ext->ext_next) {
5373*0Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
5374*0Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
5375*0Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
5376*0Sstevel@tonic-gate 			ext->ext_namep->cname) == 0)
5377*0Sstevel@tonic-gate 				continue;
5378*0Sstevel@tonic-gate 		num_sps++;
5379*0Sstevel@tonic-gate 	}
5380*0Sstevel@tonic-gate 
5381*0Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
5382*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5383*0Sstevel@tonic-gate 		    "Found %d soft partition(s) on %s.\n"), num_sps,
5384*0Sstevel@tonic-gate 		    compnp->cname);
5385*0Sstevel@tonic-gate 
5386*0Sstevel@tonic-gate 	if (num_sps == 0) {
5387*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5388*0Sstevel@tonic-gate 		    "%s: No soft partitions.\n"), compnp->cname);
5389*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5390*0Sstevel@tonic-gate 	}
5391*0Sstevel@tonic-gate 
5392*0Sstevel@tonic-gate 	/* check sequence numbers */
5393*0Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
5394*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5395*0Sstevel@tonic-gate 		    "Checking sequence numbers.\n"));
5396*0Sstevel@tonic-gate 
5397*0Sstevel@tonic-gate 	if (meta_sp_checkseq(extlist) != 0)
5398*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5399*0Sstevel@tonic-gate 
5400*0Sstevel@tonic-gate 	return (0);
5401*0Sstevel@tonic-gate }
5402*0Sstevel@tonic-gate 
5403*0Sstevel@tonic-gate /*
5404*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_unit()
5405*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
5406*0Sstevel@tonic-gate  *		compnp	- name of component we are recovering from
5407*0Sstevel@tonic-gate  *		options	- metarecover options
5408*0Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
5409*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
5410*0Sstevel@tonic-gate  * PURPOSE:	validate and display metadb configuration.  begin by getting
5411*0Sstevel@tonic-gate  *		all soft partitions built on the specified component.  get
5412*0Sstevel@tonic-gate  *		the unit structure for each one and validate the fields within.
5413*0Sstevel@tonic-gate  */
5414*0Sstevel@tonic-gate static int
5415*0Sstevel@tonic-gate meta_sp_validate_unit(
5416*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5417*0Sstevel@tonic-gate 	mdname_t	*compnp,
5418*0Sstevel@tonic-gate 	mdcmdopts_t	options,
5419*0Sstevel@tonic-gate 	md_error_t	*ep
5420*0Sstevel@tonic-gate )
5421*0Sstevel@tonic-gate {
5422*0Sstevel@tonic-gate 	md_sp_t		*msp;
5423*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
5424*0Sstevel@tonic-gate 	mdnamelist_t	*namep = NULL;
5425*0Sstevel@tonic-gate 	int		count;
5426*0Sstevel@tonic-gate 	uint_t		extn;
5427*0Sstevel@tonic-gate 	sp_ext_length_t	size;
5428*0Sstevel@tonic-gate 
5429*0Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
5430*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5431*0Sstevel@tonic-gate 		    "%s: Validating soft partition metadb entries.\n"),
5432*0Sstevel@tonic-gate 		    compnp->cname);
5433*0Sstevel@tonic-gate 
5434*0Sstevel@tonic-gate 	if ((size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR)
5435*0Sstevel@tonic-gate 		return (-1);
5436*0Sstevel@tonic-gate 
5437*0Sstevel@tonic-gate 	/* get all soft partitions on component */
5438*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
5439*0Sstevel@tonic-gate 
5440*0Sstevel@tonic-gate 	if (count == 0) {
5441*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5442*0Sstevel@tonic-gate 		    "%s: No soft partitions.\n"), compnp->cname);
5443*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5444*0Sstevel@tonic-gate 	} else if (count < 0) {
5445*0Sstevel@tonic-gate 		return (-1);
5446*0Sstevel@tonic-gate 	}
5447*0Sstevel@tonic-gate 
5448*0Sstevel@tonic-gate 	/* Now go through the soft partitions and check each one */
5449*0Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
5450*0Sstevel@tonic-gate 		mdname_t	*curnp = namep->namep;
5451*0Sstevel@tonic-gate 		sp_ext_offset_t	curvoff;
5452*0Sstevel@tonic-gate 
5453*0Sstevel@tonic-gate 		/* get the unit structure */
5454*0Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
5455*0Sstevel@tonic-gate 			return (-1);
5456*0Sstevel@tonic-gate 
5457*0Sstevel@tonic-gate 		/* verify generic unit structure parameters */
5458*0Sstevel@tonic-gate 		if ((options & MDCMD_VERBOSE) != 0)
5459*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5460*0Sstevel@tonic-gate 			    "\nVerifying device %s.\n"),
5461*0Sstevel@tonic-gate 			    curnp->cname);
5462*0Sstevel@tonic-gate 
5463*0Sstevel@tonic-gate 		/*
5464*0Sstevel@tonic-gate 		 * MD_SP_LAST is an invalid state and is always the
5465*0Sstevel@tonic-gate 		 * highest numbered.
5466*0Sstevel@tonic-gate 		 */
5467*0Sstevel@tonic-gate 		if (msp->status >= MD_SP_LAST) {
5468*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5469*0Sstevel@tonic-gate 			    "%s: status value %u is out of range.\n"),
5470*0Sstevel@tonic-gate 			    curnp->cname, msp->status);
5471*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
5472*0Sstevel@tonic-gate 			    0, curnp->cname));
5473*0Sstevel@tonic-gate 		} else if ((options & MDCMD_VERBOSE) != 0) {
5474*0Sstevel@tonic-gate 			uint_t	tstate = 0;
5475*0Sstevel@tonic-gate 
5476*0Sstevel@tonic-gate 			if (metaismeta(msp->compnamep)) {
5477*0Sstevel@tonic-gate 				if (meta_get_tstate(msp->common.namep->dev,
5478*0Sstevel@tonic-gate 				    &tstate, ep) != 0)
5479*0Sstevel@tonic-gate 					return (-1);
5480*0Sstevel@tonic-gate 			}
5481*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5482*0Sstevel@tonic-gate 			    "%s: Status \"%s\" is valid.\n"),
5483*0Sstevel@tonic-gate 			    curnp->cname, meta_sp_status_to_name(msp->status,
5484*0Sstevel@tonic-gate 			    tstate & MD_DEV_ERRORED));
5485*0Sstevel@tonic-gate 		}
5486*0Sstevel@tonic-gate 
5487*0Sstevel@tonic-gate 		/* Now verify each extent */
5488*0Sstevel@tonic-gate 		if ((options & MDCMD_VERBOSE) != 0)
5489*0Sstevel@tonic-gate 			(void) printf("%14s %21s %21s %21s\n",
5490*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Extent Number"),
5491*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Virtual Offset"),
5492*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Physical Offset"),
5493*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"));
5494*0Sstevel@tonic-gate 
5495*0Sstevel@tonic-gate 		curvoff = 0ULL;
5496*0Sstevel@tonic-gate 		for (extn = 0; extn < msp->ext.ext_len; extn++) {
5497*0Sstevel@tonic-gate 			md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
5498*0Sstevel@tonic-gate 
5499*0Sstevel@tonic-gate 			if ((options & MDCMD_VERBOSE) != 0)
5500*0Sstevel@tonic-gate 				(void) printf("%14u %21llu %21llu %21llu\n",
5501*0Sstevel@tonic-gate 				    extn, extp->voff, extp->poff, extp->len);
5502*0Sstevel@tonic-gate 
5503*0Sstevel@tonic-gate 			if (extp->voff != curvoff) {
5504*0Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5505*0Sstevel@tonic-gate 				    "%s: virtual offset for extent %u "
5506*0Sstevel@tonic-gate 				    "is inconsistent, expected %llu, "
5507*0Sstevel@tonic-gate 				    "got %llu.\n"), curnp->cname, extn,
5508*0Sstevel@tonic-gate 				    curvoff, extp->voff);
5509*0Sstevel@tonic-gate 				return (mdmderror(ep, MDE_RECOVER_FAILED,
5510*0Sstevel@tonic-gate 				    0, compnp->cname));
5511*0Sstevel@tonic-gate 			}
5512*0Sstevel@tonic-gate 
5513*0Sstevel@tonic-gate 			/* make sure extent does not drop off the end */
5514*0Sstevel@tonic-gate 			if ((extp->poff + extp->len) == size) {
5515*0Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5516*0Sstevel@tonic-gate 				    "%s: extent %u at offset %llu, "
5517*0Sstevel@tonic-gate 				    "length %llu exceeds the size of the "
5518*0Sstevel@tonic-gate 				    "device, %llu.\n"), curnp->cname,
5519*0Sstevel@tonic-gate 				    extn, extp->poff, extp->len, size);
5520*0Sstevel@tonic-gate 				return (mdmderror(ep, MDE_RECOVER_FAILED,
5521*0Sstevel@tonic-gate 				    0, compnp->cname));
5522*0Sstevel@tonic-gate 			}
5523*0Sstevel@tonic-gate 
5524*0Sstevel@tonic-gate 			curvoff += extp->len;
5525*0Sstevel@tonic-gate 		}
5526*0Sstevel@tonic-gate 	}
5527*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
5528*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
5529*0Sstevel@tonic-gate 		    "%s: Soft Partition metadb configuration is valid\n"),
5530*0Sstevel@tonic-gate 		    compnp->cname);
5531*0Sstevel@tonic-gate 	}
5532*0Sstevel@tonic-gate 	return (0);
5533*0Sstevel@tonic-gate }
5534*0Sstevel@tonic-gate 
5535*0Sstevel@tonic-gate /*
5536*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_wm_and_unit()
5537*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
5538*0Sstevel@tonic-gate  *		compnp	- name of device we are recovering from
5539*0Sstevel@tonic-gate  *		options	- metarecover options
5540*0Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
5541*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 error
5542*0Sstevel@tonic-gate  * PURPOSE:	cross-validate and display watermarks and metadb records.
5543*0Sstevel@tonic-gate  *		get both the unit structures for the soft partitions built
5544*0Sstevel@tonic-gate  *		on the specified component and the watermarks found on that
5545*0Sstevel@tonic-gate  *		component and check to make sure they are consistent with
5546*0Sstevel@tonic-gate  *		each other.
5547*0Sstevel@tonic-gate  */
5548*0Sstevel@tonic-gate static int
5549*0Sstevel@tonic-gate meta_sp_validate_wm_and_unit(
5550*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5551*0Sstevel@tonic-gate 	mdname_t	*np,
5552*0Sstevel@tonic-gate 	mdcmdopts_t	options,
5553*0Sstevel@tonic-gate 	md_error_t	*ep
5554*0Sstevel@tonic-gate )
5555*0Sstevel@tonic-gate {
5556*0Sstevel@tonic-gate 	sp_ext_node_t	*wmlist = NULL;
5557*0Sstevel@tonic-gate 	sp_ext_node_t	*unitlist = NULL;
5558*0Sstevel@tonic-gate 	sp_ext_node_t	*unitext;
5559*0Sstevel@tonic-gate 	sp_ext_node_t	*wmext;
5560*0Sstevel@tonic-gate 	sp_ext_offset_t	tmpunitoff;
5561*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
5562*0Sstevel@tonic-gate 	int		count;
5563*0Sstevel@tonic-gate 	int		rval = 0;
5564*0Sstevel@tonic-gate 	int		verbose = (options & MDCMD_VERBOSE);
5565*0Sstevel@tonic-gate 
5566*0Sstevel@tonic-gate 	/* get unit structure list */
5567*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, np, &spnlp, 0, ep);
5568*0Sstevel@tonic-gate 	if (count <= 0)
5569*0Sstevel@tonic-gate 		return (-1);
5570*0Sstevel@tonic-gate 
5571*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &unitlist,
5572*0Sstevel@tonic-gate 	    metagetsize(np, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
5573*0Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
5574*0Sstevel@tonic-gate 
5575*0Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &unitlist, ep) == -1) {
5576*0Sstevel@tonic-gate 		metafreenamelist(spnlp);
5577*0Sstevel@tonic-gate 		return (-1);
5578*0Sstevel@tonic-gate 	}
5579*0Sstevel@tonic-gate 
5580*0Sstevel@tonic-gate 	metafreenamelist(spnlp);
5581*0Sstevel@tonic-gate 
5582*0Sstevel@tonic-gate 	meta_sp_list_freefill(&unitlist, metagetsize(np, ep));
5583*0Sstevel@tonic-gate 
5584*0Sstevel@tonic-gate 	if (meta_sp_extlist_from_wm(sp, np, &wmlist,
5585*0Sstevel@tonic-gate 	    meta_sp_cmp_by_offset, ep) < 0) {
5586*0Sstevel@tonic-gate 		meta_sp_list_free(&unitlist);
5587*0Sstevel@tonic-gate 		return (-1);
5588*0Sstevel@tonic-gate 	}
5589*0Sstevel@tonic-gate 
5590*0Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
5591*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_validate_wm_and_unit: unit list:\n");
5592*0Sstevel@tonic-gate 		meta_sp_list_dump(unitlist);
5593*0Sstevel@tonic-gate 		meta_sp_debug("meta_sp_validate_wm_and_unit: wm list:\n");
5594*0Sstevel@tonic-gate 		meta_sp_list_dump(wmlist);
5595*0Sstevel@tonic-gate 	}
5596*0Sstevel@tonic-gate 
5597*0Sstevel@tonic-gate 	/*
5598*0Sstevel@tonic-gate 	 * step through both lists and compare allocated nodes.  Free
5599*0Sstevel@tonic-gate 	 * nodes and end watermarks may differ between the two but
5600*0Sstevel@tonic-gate 	 * that's generally ok, and if they're wrong will typically
5601*0Sstevel@tonic-gate 	 * cause misplaced allocated extents.
5602*0Sstevel@tonic-gate 	 */
5603*0Sstevel@tonic-gate 	if (verbose)
5604*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "\n%s: Verifying metadb "
5605*0Sstevel@tonic-gate 		    "allocations match extent headers.\n"), np->cname);
5606*0Sstevel@tonic-gate 
5607*0Sstevel@tonic-gate 	unitext = unitlist;
5608*0Sstevel@tonic-gate 	wmext = wmlist;
5609*0Sstevel@tonic-gate 	while ((wmext != NULL) && (unitext != NULL)) {
5610*0Sstevel@tonic-gate 		/* find next allocated extents in each list */
5611*0Sstevel@tonic-gate 		while (wmext != NULL && wmext->ext_type != EXTTYP_ALLOC)
5612*0Sstevel@tonic-gate 			wmext = wmext->ext_next;
5613*0Sstevel@tonic-gate 
5614*0Sstevel@tonic-gate 		while (unitext != NULL && unitext->ext_type != EXTTYP_ALLOC)
5615*0Sstevel@tonic-gate 			unitext = unitext->ext_next;
5616*0Sstevel@tonic-gate 
5617*0Sstevel@tonic-gate 		if (wmext == NULL || unitext == NULL)
5618*0Sstevel@tonic-gate 			break;
5619*0Sstevel@tonic-gate 
5620*0Sstevel@tonic-gate 		if (verbose) {
5621*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5622*0Sstevel@tonic-gate 			    "Metadb extent:\n"));
5623*0Sstevel@tonic-gate 			meta_sp_display_exthdr();
5624*0Sstevel@tonic-gate 			meta_sp_display_ext(unitext);
5625*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5626*0Sstevel@tonic-gate 			    "Extent header extent:\n"));
5627*0Sstevel@tonic-gate 			meta_sp_display_exthdr();
5628*0Sstevel@tonic-gate 			meta_sp_display_ext(wmext);
5629*0Sstevel@tonic-gate 			(void) printf("\n");
5630*0Sstevel@tonic-gate 		}
5631*0Sstevel@tonic-gate 
5632*0Sstevel@tonic-gate 		if (meta_sp_validate_exts(np, wmext, unitext, ep) < 0)
5633*0Sstevel@tonic-gate 			rval = -1;
5634*0Sstevel@tonic-gate 
5635*0Sstevel@tonic-gate 		/*
5636*0Sstevel@tonic-gate 		 * if the offsets aren't equal, only increment the
5637*0Sstevel@tonic-gate 		 * lowest one in hopes of getting the lists back in sync.
5638*0Sstevel@tonic-gate 		 */
5639*0Sstevel@tonic-gate 		tmpunitoff = unitext->ext_offset;
5640*0Sstevel@tonic-gate 		if (unitext->ext_offset <= wmext->ext_offset)
5641*0Sstevel@tonic-gate 			unitext = unitext->ext_next;
5642*0Sstevel@tonic-gate 		if (wmext->ext_offset <= tmpunitoff)
5643*0Sstevel@tonic-gate 			wmext = wmext->ext_next;
5644*0Sstevel@tonic-gate 	}
5645*0Sstevel@tonic-gate 
5646*0Sstevel@tonic-gate 	/*
5647*0Sstevel@tonic-gate 	 * if both lists aren't at the end then there are extra
5648*0Sstevel@tonic-gate 	 * allocated nodes in one of them.
5649*0Sstevel@tonic-gate 	 */
5650*0Sstevel@tonic-gate 	if (wmext != NULL) {
5651*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5652*0Sstevel@tonic-gate 		    "%s: extent headers contain allocations not in "
5653*0Sstevel@tonic-gate 		    "the metadb\n\n"), np->cname);
5654*0Sstevel@tonic-gate 		rval = -1;
5655*0Sstevel@tonic-gate 	}
5656*0Sstevel@tonic-gate 
5657*0Sstevel@tonic-gate 	if (unitext != NULL) {
5658*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5659*0Sstevel@tonic-gate 		    "%s: metadb contains allocations not in the extent "
5660*0Sstevel@tonic-gate 		    "headers\n\n"), np->cname);
5661*0Sstevel@tonic-gate 		rval = -1;
5662*0Sstevel@tonic-gate 	}
5663*0Sstevel@tonic-gate 
5664*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
5665*0Sstevel@tonic-gate 		if (rval == 0) {
5666*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5667*0Sstevel@tonic-gate 			    "%s: Soft Partition metadb matches extent "
5668*0Sstevel@tonic-gate 			    "header configuration\n"), np->cname);
5669*0Sstevel@tonic-gate 		} else {
5670*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
5671*0Sstevel@tonic-gate 			    "%s: Soft Partition metadb does not match extent "
5672*0Sstevel@tonic-gate 			    "header configuration\n"), np->cname);
5673*0Sstevel@tonic-gate 		}
5674*0Sstevel@tonic-gate 	}
5675*0Sstevel@tonic-gate 
5676*0Sstevel@tonic-gate 	return (rval);
5677*0Sstevel@tonic-gate }
5678*0Sstevel@tonic-gate 
5679*0Sstevel@tonic-gate /*
5680*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_exts()
5681*0Sstevel@tonic-gate  * INPUT:	compnp	- name pointer for device we are recovering from
5682*0Sstevel@tonic-gate  *		wmext	- extent node representing watermark
5683*0Sstevel@tonic-gate  *		unitext	- extent node from unit structure
5684*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
5685*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - succes, mdmderror return code - error
5686*0Sstevel@tonic-gate  * PURPOSE:	Takes two extent nodes and checks them against each other.
5687*0Sstevel@tonic-gate  *		offset, length, sequence number, set, and name are compared.
5688*0Sstevel@tonic-gate  */
5689*0Sstevel@tonic-gate static int
5690*0Sstevel@tonic-gate meta_sp_validate_exts(
5691*0Sstevel@tonic-gate 	mdname_t	*compnp,
5692*0Sstevel@tonic-gate 	sp_ext_node_t	*wmext,
5693*0Sstevel@tonic-gate 	sp_ext_node_t	*unitext,
5694*0Sstevel@tonic-gate 	md_error_t	*ep
5695*0Sstevel@tonic-gate )
5696*0Sstevel@tonic-gate {
5697*0Sstevel@tonic-gate 	if (wmext->ext_offset != unitext->ext_offset) {
5698*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5699*0Sstevel@tonic-gate 		    "%s: unit structure and extent header offsets differ.\n"),
5700*0Sstevel@tonic-gate 		    compnp->cname);
5701*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5702*0Sstevel@tonic-gate 	}
5703*0Sstevel@tonic-gate 
5704*0Sstevel@tonic-gate 	if (wmext->ext_length != unitext->ext_length) {
5705*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5706*0Sstevel@tonic-gate 		    "%s: unit structure and extent header lengths differ.\n"),
5707*0Sstevel@tonic-gate 		    compnp->cname);
5708*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5709*0Sstevel@tonic-gate 	}
5710*0Sstevel@tonic-gate 
5711*0Sstevel@tonic-gate 	if (wmext->ext_seq != unitext->ext_seq) {
5712*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5713*0Sstevel@tonic-gate 		    "%s: unit structure and extent header sequence numbers "
5714*0Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
5715*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5716*0Sstevel@tonic-gate 	}
5717*0Sstevel@tonic-gate 
5718*0Sstevel@tonic-gate 	if (wmext->ext_type != unitext->ext_type) {
5719*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5720*0Sstevel@tonic-gate 		    "%s: unit structure and extent header types differ.\n"),
5721*0Sstevel@tonic-gate 		    compnp->cname);
5722*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5723*0Sstevel@tonic-gate 	}
5724*0Sstevel@tonic-gate 
5725*0Sstevel@tonic-gate 	/*
5726*0Sstevel@tonic-gate 	 * If one has a set pointer and the other doesn't, error.
5727*0Sstevel@tonic-gate 	 * If both extents have setnames, then make sure they match
5728*0Sstevel@tonic-gate 	 * If both are NULL, it's ok, they match.
5729*0Sstevel@tonic-gate 	 */
5730*0Sstevel@tonic-gate 	if ((unitext->ext_setp == NULL) ^ (wmext->ext_setp == NULL)) {
5731*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5732*0Sstevel@tonic-gate 		    "%s: unit structure and extent header set values "
5733*0Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
5734*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5735*0Sstevel@tonic-gate 	}
5736*0Sstevel@tonic-gate 
5737*0Sstevel@tonic-gate 	if (unitext->ext_setp != NULL) {
5738*0Sstevel@tonic-gate 		if (strcmp(unitext->ext_setp->setname,
5739*0Sstevel@tonic-gate 		    wmext->ext_setp->setname) != 0) {
5740*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5741*0Sstevel@tonic-gate 			    "%s: unit structure and extent header set names "
5742*0Sstevel@tonic-gate 			    "differ.\n"), compnp->cname);
5743*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
5744*0Sstevel@tonic-gate 			    0, compnp->cname));
5745*0Sstevel@tonic-gate 		}
5746*0Sstevel@tonic-gate 	}
5747*0Sstevel@tonic-gate 
5748*0Sstevel@tonic-gate 	/*
5749*0Sstevel@tonic-gate 	 * If one has a name pointer and the other doesn't, error.
5750*0Sstevel@tonic-gate 	 * If both extents have names, then make sure they match
5751*0Sstevel@tonic-gate 	 * If both are NULL, it's ok, they match.
5752*0Sstevel@tonic-gate 	 */
5753*0Sstevel@tonic-gate 	if ((unitext->ext_namep == NULL) ^ (wmext->ext_namep == NULL)) {
5754*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5755*0Sstevel@tonic-gate 		    "%s: unit structure and extent header name values "
5756*0Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
5757*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5758*0Sstevel@tonic-gate 	}
5759*0Sstevel@tonic-gate 
5760*0Sstevel@tonic-gate 	if (unitext->ext_namep != NULL) {
5761*0Sstevel@tonic-gate 		if (strcmp(wmext->ext_namep->cname,
5762*0Sstevel@tonic-gate 		    unitext->ext_namep->cname) != 0) {
5763*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5764*0Sstevel@tonic-gate 			    "%s: unit structure and extent header names "
5765*0Sstevel@tonic-gate 			    "differ.\n"), compnp->cname);
5766*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
5767*0Sstevel@tonic-gate 			    0, compnp->cname));
5768*0Sstevel@tonic-gate 		}
5769*0Sstevel@tonic-gate 	}
5770*0Sstevel@tonic-gate 
5771*0Sstevel@tonic-gate 	return (0);
5772*0Sstevel@tonic-gate }
5773*0Sstevel@tonic-gate 
5774*0Sstevel@tonic-gate /*
5775*0Sstevel@tonic-gate  * FUNCTION:	update_sp_status()
5776*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
5777*0Sstevel@tonic-gate  *		minors	- pointer to an array of soft partition minor numbers
5778*0Sstevel@tonic-gate  *		num_sps	- number of minor numbers in array
5779*0Sstevel@tonic-gate  *		status	- new status to be applied to all soft parts in array
5780*0Sstevel@tonic-gate  *		mn_set	- set if current set is a multi-node set
5781*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
5782*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
5783*0Sstevel@tonic-gate  * PURPOSE:	update  status of soft partitions to new status. minors is an
5784*0Sstevel@tonic-gate  *		array of minor numbers to apply the new status to.
5785*0Sstevel@tonic-gate  *		If mn_set is set, a message is sent to all nodes in the
5786*0Sstevel@tonic-gate  *		cluster to update the status locally.
5787*0Sstevel@tonic-gate  */
5788*0Sstevel@tonic-gate static int
5789*0Sstevel@tonic-gate update_sp_status(
5790*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5791*0Sstevel@tonic-gate 	minor_t		*minors,
5792*0Sstevel@tonic-gate 	int		num_sps,
5793*0Sstevel@tonic-gate 	sp_status_t	status,
5794*0Sstevel@tonic-gate 	bool_t		mn_set,
5795*0Sstevel@tonic-gate 	md_error_t	*ep
5796*0Sstevel@tonic-gate )
5797*0Sstevel@tonic-gate {
5798*0Sstevel@tonic-gate 	int	i;
5799*0Sstevel@tonic-gate 	int	err = 0;
5800*0Sstevel@tonic-gate 
5801*0Sstevel@tonic-gate 	if (mn_set) {
5802*0Sstevel@tonic-gate 		md_mn_msg_sp_setstat_t	sp_setstat_params;
5803*0Sstevel@tonic-gate 		int			result;
5804*0Sstevel@tonic-gate 		md_mn_result_t		*resp = NULL;
5805*0Sstevel@tonic-gate 
5806*0Sstevel@tonic-gate 		for (i = 0; i < num_sps; i++) {
5807*0Sstevel@tonic-gate 			sp_setstat_params.sp_setstat_mnum = minors[i];
5808*0Sstevel@tonic-gate 			sp_setstat_params.sp_setstat_status = status;
5809*0Sstevel@tonic-gate 
5810*0Sstevel@tonic-gate 			result = mdmn_send_message(sp->setno,
5811*0Sstevel@tonic-gate 			    MD_MN_MSG_SP_SETSTAT, MD_MSGF_DEFAULT_FLAGS,
5812*0Sstevel@tonic-gate 			    (char *)&sp_setstat_params,
5813*0Sstevel@tonic-gate 			    sizeof (sp_setstat_params),
5814*0Sstevel@tonic-gate 			    &resp, ep);
5815*0Sstevel@tonic-gate 			if (resp != NULL) {
5816*0Sstevel@tonic-gate 				if (resp->mmr_exitval != 0)
5817*0Sstevel@tonic-gate 					err = -1;
5818*0Sstevel@tonic-gate 				free_result(resp);
5819*0Sstevel@tonic-gate 			}
5820*0Sstevel@tonic-gate 			if (result != 0) {
5821*0Sstevel@tonic-gate 				err = -1;
5822*0Sstevel@tonic-gate 			}
5823*0Sstevel@tonic-gate 		}
5824*0Sstevel@tonic-gate 	} else {
5825*0Sstevel@tonic-gate 		if (meta_sp_setstatus(sp, minors, num_sps, status, ep) < 0)
5826*0Sstevel@tonic-gate 			err = -1;
5827*0Sstevel@tonic-gate 	}
5828*0Sstevel@tonic-gate 	if (err < 0) {
5829*0Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
5830*0Sstevel@tonic-gate 		    "Error updating status on recovered soft "
5831*0Sstevel@tonic-gate 		    "partitions.\n"));
5832*0Sstevel@tonic-gate 	}
5833*0Sstevel@tonic-gate 	return (err);
5834*0Sstevel@tonic-gate }
5835*0Sstevel@tonic-gate 
5836*0Sstevel@tonic-gate /*
5837*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_recover_from_wm()
5838*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
5839*0Sstevel@tonic-gate  *		compnp	- name pointer for component we are recovering from
5840*0Sstevel@tonic-gate  *		options	- metarecover options
5841*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
5842*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
5843*0Sstevel@tonic-gate  * PURPOSE:	update metadb records to match watermarks.  begin by getting
5844*0Sstevel@tonic-gate  *		an extlist representing all soft partitions on the component.
5845*0Sstevel@tonic-gate  *		then build a unit structure for each soft partition.
5846*0Sstevel@tonic-gate  *		notify user of changes, then commit each soft partition to
5847*0Sstevel@tonic-gate  *		the metadb one at a time in the "recovering" state.  update
5848*0Sstevel@tonic-gate  *		any watermarks that may need it	(to reflect possible name
5849*0Sstevel@tonic-gate  *		changes), and, finally, set the status of all recovered
5850*0Sstevel@tonic-gate  *		partitions to the "OK" state at once.
5851*0Sstevel@tonic-gate  */
5852*0Sstevel@tonic-gate static int
5853*0Sstevel@tonic-gate meta_sp_recover_from_wm(
5854*0Sstevel@tonic-gate 	mdsetname_t	*sp,
5855*0Sstevel@tonic-gate 	mdname_t	*compnp,
5856*0Sstevel@tonic-gate 	mdcmdopts_t	options,
5857*0Sstevel@tonic-gate 	md_error_t	*ep
5858*0Sstevel@tonic-gate )
5859*0Sstevel@tonic-gate {
5860*0Sstevel@tonic-gate 	sp_ext_node_t		*extlist = NULL;
5861*0Sstevel@tonic-gate 	sp_ext_node_t		*sp_list = NULL;
5862*0Sstevel@tonic-gate 	sp_ext_node_t		*update_list = NULL;
5863*0Sstevel@tonic-gate 	sp_ext_node_t		*ext;
5864*0Sstevel@tonic-gate 	sp_ext_node_t		*sp_ext;
5865*0Sstevel@tonic-gate 	mp_unit_t		*mp;
5866*0Sstevel@tonic-gate 	mp_unit_t		**un_array;
5867*0Sstevel@tonic-gate 	int			numexts = 0, num_sps = 0, i = 0;
5868*0Sstevel@tonic-gate 	int			err = 0;
5869*0Sstevel@tonic-gate 	int			not_recovered = 0;
5870*0Sstevel@tonic-gate 	int			committed = 0;
5871*0Sstevel@tonic-gate 	sp_ext_length_t		sp_length = 0LL;
5872*0Sstevel@tonic-gate 	mdnamelist_t		*keynlp = NULL;
5873*0Sstevel@tonic-gate 	mdname_t		*np;
5874*0Sstevel@tonic-gate 	mdname_t		*new_np;
5875*0Sstevel@tonic-gate 	int			new_name;
5876*0Sstevel@tonic-gate 	md_set_params_t		set_params;
5877*0Sstevel@tonic-gate 	minor_t			*minors = NULL;
5878*0Sstevel@tonic-gate 	char			yesno[255];
5879*0Sstevel@tonic-gate 	char			*yes;
5880*0Sstevel@tonic-gate 	bool_t			mn_set = 0;
5881*0Sstevel@tonic-gate 	md_set_desc		*sd;
5882*0Sstevel@tonic-gate 	mm_unit_t		*mm;
5883*0Sstevel@tonic-gate 	md_set_mmown_params_t	*ownpar = NULL;
5884*0Sstevel@tonic-gate 	int			comp_is_mirror = 0;
5885*0Sstevel@tonic-gate 
5886*0Sstevel@tonic-gate 	/*
5887*0Sstevel@tonic-gate 	 * if this component appears in another metadevice already, do
5888*0Sstevel@tonic-gate 	 * NOT recover from it.
5889*0Sstevel@tonic-gate 	 */
5890*0Sstevel@tonic-gate 	if (meta_check_inmeta(sp, compnp, options, 0, -1, ep) != 0)
5891*0Sstevel@tonic-gate 		return (-1);
5892*0Sstevel@tonic-gate 
5893*0Sstevel@tonic-gate 	/* set flag if dealing with a MN set */
5894*0Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
5895*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
5896*0Sstevel@tonic-gate 			return (-1);
5897*0Sstevel@tonic-gate 		}
5898*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
5899*0Sstevel@tonic-gate 			mn_set = 1;
5900*0Sstevel@tonic-gate 	}
5901*0Sstevel@tonic-gate 	/*
5902*0Sstevel@tonic-gate 	 * for each watermark, build an ext_node, place on list.
5903*0Sstevel@tonic-gate 	 */
5904*0Sstevel@tonic-gate 	if (meta_sp_extlist_from_wm(sp, compnp, &extlist,
5905*0Sstevel@tonic-gate 	    meta_sp_cmp_by_nameseq, ep) < 0)
5906*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
5907*0Sstevel@tonic-gate 
5908*0Sstevel@tonic-gate 	assert(extlist != NULL);
5909*0Sstevel@tonic-gate 
5910*0Sstevel@tonic-gate 	/* count number of soft partitions */
5911*0Sstevel@tonic-gate 	for (ext = extlist;
5912*0Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
5913*0Sstevel@tonic-gate 	    ext = ext->ext_next) {
5914*0Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
5915*0Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
5916*0Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
5917*0Sstevel@tonic-gate 			ext->ext_namep->cname) == 0)
5918*0Sstevel@tonic-gate 				continue;
5919*0Sstevel@tonic-gate 		num_sps++;
5920*0Sstevel@tonic-gate 	}
5921*0Sstevel@tonic-gate 
5922*0Sstevel@tonic-gate 	/* allocate array of unit structure pointers */
5923*0Sstevel@tonic-gate 	un_array = Zalloc(num_sps * sizeof (mp_unit_t *));
5924*0Sstevel@tonic-gate 
5925*0Sstevel@tonic-gate 	/*
5926*0Sstevel@tonic-gate 	 * build unit structures from list of ext_nodes.
5927*0Sstevel@tonic-gate 	 */
5928*0Sstevel@tonic-gate 	for (ext = extlist;
5929*0Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
5930*0Sstevel@tonic-gate 	    ext = ext->ext_next) {
5931*0Sstevel@tonic-gate 		meta_sp_list_insert(ext->ext_setp, ext->ext_namep,
5932*0Sstevel@tonic-gate 		    &sp_list, ext->ext_offset, ext->ext_length,
5933*0Sstevel@tonic-gate 		    ext->ext_type, ext->ext_seq, ext->ext_flags,
5934*0Sstevel@tonic-gate 		    meta_sp_cmp_by_nameseq);
5935*0Sstevel@tonic-gate 
5936*0Sstevel@tonic-gate 		numexts++;
5937*0Sstevel@tonic-gate 		sp_length += ext->ext_length - MD_SP_WMSIZE;
5938*0Sstevel@tonic-gate 
5939*0Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
5940*0Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
5941*0Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
5942*0Sstevel@tonic-gate 			ext->ext_namep->cname) == 0)
5943*0Sstevel@tonic-gate 				continue;
5944*0Sstevel@tonic-gate 
5945*0Sstevel@tonic-gate 		/*
5946*0Sstevel@tonic-gate 		 * if we made it here, we are at a soft partition
5947*0Sstevel@tonic-gate 		 * boundary in the list.
5948*0Sstevel@tonic-gate 		 */
5949*0Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
5950*0Sstevel@tonic-gate 			meta_sp_debug("meta_recover_from_wm: dumping wm "
5951*0Sstevel@tonic-gate 			    "list:\n");
5952*0Sstevel@tonic-gate 			meta_sp_list_dump(sp_list);
5953*0Sstevel@tonic-gate 		}
5954*0Sstevel@tonic-gate 
5955*0Sstevel@tonic-gate 		assert(sp_list != NULL);
5956*0Sstevel@tonic-gate 		assert(sp_list->ext_namep != NULL);
5957*0Sstevel@tonic-gate 
5958*0Sstevel@tonic-gate 		if ((new_name = meta_sp_resolve_name_conflict(sp,
5959*0Sstevel@tonic-gate 		    sp_list->ext_namep, &new_np, ep)) < 0) {
5960*0Sstevel@tonic-gate 			err = 1;
5961*0Sstevel@tonic-gate 			goto out;
5962*0Sstevel@tonic-gate 		} else if (new_name) {
5963*0Sstevel@tonic-gate 			for (sp_ext = sp_list;
5964*0Sstevel@tonic-gate 			    sp_ext != NULL;
5965*0Sstevel@tonic-gate 			    sp_ext = sp_ext->ext_next) {
5966*0Sstevel@tonic-gate 				/*
5967*0Sstevel@tonic-gate 				 * insert into the update list for
5968*0Sstevel@tonic-gate 				 * watermark update.
5969*0Sstevel@tonic-gate 				 */
5970*0Sstevel@tonic-gate 				meta_sp_list_insert(sp_ext->ext_setp,
5971*0Sstevel@tonic-gate 				    new_np, &update_list, sp_ext->ext_offset,
5972*0Sstevel@tonic-gate 				    sp_ext->ext_length, sp_ext->ext_type,
5973*0Sstevel@tonic-gate 				    sp_ext->ext_seq, EXTFLG_UPDATE,
5974*0Sstevel@tonic-gate 				    meta_sp_cmp_by_offset);
5975*0Sstevel@tonic-gate 			}
5976*0Sstevel@tonic-gate 
5977*0Sstevel@tonic-gate 		}
5978*0Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
5979*0Sstevel@tonic-gate 			/* store name in namespace */
5980*0Sstevel@tonic-gate 			if (mn_set) {
5981*0Sstevel@tonic-gate 				/* send message to all nodes to return key */
5982*0Sstevel@tonic-gate 				md_mn_msg_addkeyname_t	*send_params;
5983*0Sstevel@tonic-gate 				int			result;
5984*0Sstevel@tonic-gate 				md_mn_result_t		*resp = NULL;
5985*0Sstevel@tonic-gate 				int			message_size;
5986*0Sstevel@tonic-gate 
5987*0Sstevel@tonic-gate 				message_size =  sizeof (*send_params) +
5988*0Sstevel@tonic-gate 				    strlen(compnp->cname) + 1;
5989*0Sstevel@tonic-gate 				send_params = Zalloc(message_size);
5990*0Sstevel@tonic-gate 				send_params->addkeyname_setno = sp->setno;
5991*0Sstevel@tonic-gate 				(void) strcpy(&send_params->addkeyname_name[0],
5992*0Sstevel@tonic-gate 				    compnp->cname);
5993*0Sstevel@tonic-gate 				result = mdmn_send_message(sp->setno,
5994*0Sstevel@tonic-gate 				    MD_MN_MSG_ADDKEYNAME, MD_MSGF_DEFAULT_FLAGS,
5995*0Sstevel@tonic-gate 				    (char *)send_params, message_size, &resp,
5996*0Sstevel@tonic-gate 				    ep);
5997*0Sstevel@tonic-gate 				Free(send_params);
5998*0Sstevel@tonic-gate 				if (resp != NULL) {
5999*0Sstevel@tonic-gate 					if (resp->mmr_exitval >= 0) {
6000*0Sstevel@tonic-gate 						compnp->key =
6001*0Sstevel@tonic-gate 						    (mdkey_t)resp->mmr_exitval;
6002*0Sstevel@tonic-gate 					} else {
6003*0Sstevel@tonic-gate 						err = 1;
6004*0Sstevel@tonic-gate 						free_result(resp);
6005*0Sstevel@tonic-gate 						goto out;
6006*0Sstevel@tonic-gate 					}
6007*0Sstevel@tonic-gate 					free_result(resp);
6008*0Sstevel@tonic-gate 				}
6009*0Sstevel@tonic-gate 				if (result != 0) {
6010*0Sstevel@tonic-gate 					err = 1;
6011*0Sstevel@tonic-gate 					goto out;
6012*0Sstevel@tonic-gate 				}
6013*0Sstevel@tonic-gate 				(void) metanamelist_append(&keynlp, compnp);
6014*0Sstevel@tonic-gate 			} else {
6015*0Sstevel@tonic-gate 				if (add_key_name(sp, compnp, &keynlp,
6016*0Sstevel@tonic-gate 				    ep) != 0) {
6017*0Sstevel@tonic-gate 					err = 1;
6018*0Sstevel@tonic-gate 					goto out;
6019*0Sstevel@tonic-gate 				}
6020*0Sstevel@tonic-gate 			}
6021*0Sstevel@tonic-gate 		}
6022*0Sstevel@tonic-gate 
6023*0Sstevel@tonic-gate 		/* create the unit structure */
6024*0Sstevel@tonic-gate 		if ((mp = meta_sp_createunit(
6025*0Sstevel@tonic-gate 		    (new_name) ? new_np : sp_list->ext_namep, compnp,
6026*0Sstevel@tonic-gate 		    sp_list, numexts, sp_length, MD_SP_RECOVER, ep)) == NULL) {
6027*0Sstevel@tonic-gate 			err = 1;
6028*0Sstevel@tonic-gate 			goto out;
6029*0Sstevel@tonic-gate 		}
6030*0Sstevel@tonic-gate 
6031*0Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
6032*0Sstevel@tonic-gate 			meta_sp_debug("meta_sp_recover_from_wm: "
6033*0Sstevel@tonic-gate 			    "printing newly created unit structure");
6034*0Sstevel@tonic-gate 			meta_sp_printunit(mp);
6035*0Sstevel@tonic-gate 		}
6036*0Sstevel@tonic-gate 
6037*0Sstevel@tonic-gate 		/* place in unit structure array */
6038*0Sstevel@tonic-gate 		un_array[i++] = mp;
6039*0Sstevel@tonic-gate 
6040*0Sstevel@tonic-gate 		/* free sp_list */
6041*0Sstevel@tonic-gate 		meta_sp_list_free(&sp_list);
6042*0Sstevel@tonic-gate 		sp_list = NULL;
6043*0Sstevel@tonic-gate 		numexts = 0;
6044*0Sstevel@tonic-gate 		sp_length = 0LL;
6045*0Sstevel@tonic-gate 	}
6046*0Sstevel@tonic-gate 
6047*0Sstevel@tonic-gate 	/* display configuration updates */
6048*0Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
6049*0Sstevel@tonic-gate 	    "The following soft partitions were found and will be added to\n"
6050*0Sstevel@tonic-gate 	    "your metadevice configuration.\n"));
6051*0Sstevel@tonic-gate 	(void) printf("%5s %15s %18s\n",
6052*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Name"),
6053*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Size"),
6054*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "No. of Extents"));
6055*0Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++) {
6056*0Sstevel@tonic-gate 		(void) printf("%5s%lu %15llu %9d\n", "d",
6057*0Sstevel@tonic-gate 		    MD_MIN2UNIT(MD_SID(un_array[i])),
6058*0Sstevel@tonic-gate 		    un_array[i]->un_length, un_array[i]->un_numexts);
6059*0Sstevel@tonic-gate 	}
6060*0Sstevel@tonic-gate 
6061*0Sstevel@tonic-gate 	if (!(options & MDCMD_DOIT)) {
6062*0Sstevel@tonic-gate 		not_recovered = 1;
6063*0Sstevel@tonic-gate 		goto out;
6064*0Sstevel@tonic-gate 	}
6065*0Sstevel@tonic-gate 
6066*0Sstevel@tonic-gate 	/* ask user for confirmation */
6067*0Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
6068*0Sstevel@tonic-gate 	    "WARNING: You are about to add one or more soft partition\n"
6069*0Sstevel@tonic-gate 	    "metadevices to your metadevice configuration.  If there\n"
6070*0Sstevel@tonic-gate 	    "appears to be an error in the soft partition(s) displayed\n"
6071*0Sstevel@tonic-gate 	    "above, do NOT proceed with this recovery operation.\n"));
6072*0Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
6073*0Sstevel@tonic-gate 	    "Are you sure you want to do this (yes/no)? "));
6074*0Sstevel@tonic-gate 
6075*0Sstevel@tonic-gate 	(void) fflush(stdout);
6076*0Sstevel@tonic-gate 	if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
6077*0Sstevel@tonic-gate 	    (strlen(yesno) == 1))
6078*0Sstevel@tonic-gate 		(void) snprintf(yesno, sizeof (yesno), "%s\n",
6079*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "no"));
6080*0Sstevel@tonic-gate 	yes = dgettext(TEXT_DOMAIN, "yes");
6081*0Sstevel@tonic-gate 	if (strncasecmp(yesno, yes, strlen(yesno) - 1) != 0) {
6082*0Sstevel@tonic-gate 		not_recovered = 1;
6083*0Sstevel@tonic-gate 		goto out;
6084*0Sstevel@tonic-gate 	}
6085*0Sstevel@tonic-gate 
6086*0Sstevel@tonic-gate 	/* commit records one at a time */
6087*0Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++) {
6088*0Sstevel@tonic-gate 		(void) memset(&set_params, 0, sizeof (set_params));
6089*0Sstevel@tonic-gate 		set_params.mnum = MD_SID(un_array[i]);
6090*0Sstevel@tonic-gate 		set_params.size = (un_array[i])->c.un_size;
6091*0Sstevel@tonic-gate 		set_params.mdp = (uintptr_t)(un_array[i]);
6092*0Sstevel@tonic-gate 		set_params.options =
6093*0Sstevel@tonic-gate 				meta_check_devicesize(un_array[i]->un_length);
6094*0Sstevel@tonic-gate 		if (set_params.options == MD_CRO_64BIT) {
6095*0Sstevel@tonic-gate 			un_array[i]->c.un_revision = MD_64BIT_META_DEV;
6096*0Sstevel@tonic-gate 		} else {
6097*0Sstevel@tonic-gate 			un_array[i]->c.un_revision = MD_32BIT_META_DEV;
6098*0Sstevel@tonic-gate 		}
6099*0Sstevel@tonic-gate 		MD_SETDRIVERNAME(&set_params, MD_SP,
6100*0Sstevel@tonic-gate 		    MD_MIN2SET(set_params.mnum));
6101*0Sstevel@tonic-gate 
6102*0Sstevel@tonic-gate 		np = metamnumname(&sp, MD_SID(un_array[i]), 0, ep);
6103*0Sstevel@tonic-gate 
6104*0Sstevel@tonic-gate 		/*
6105*0Sstevel@tonic-gate 		 * If this is an MN set, send the MD_IOCSET ioctl to all nodes
6106*0Sstevel@tonic-gate 		 */
6107*0Sstevel@tonic-gate 		if (mn_set) {
6108*0Sstevel@tonic-gate 			md_mn_msg_iocset_t	send_params;
6109*0Sstevel@tonic-gate 			int			result;
6110*0Sstevel@tonic-gate 			md_mn_result_t		*resp = NULL;
6111*0Sstevel@tonic-gate 			int			mess_size;
6112*0Sstevel@tonic-gate 
6113*0Sstevel@tonic-gate 			/*
6114*0Sstevel@tonic-gate 			 * Calculate message size. md_mn_msg_iocset_t only
6115*0Sstevel@tonic-gate 			 * contains one extent, so increment the size to
6116*0Sstevel@tonic-gate 			 * include all extents
6117*0Sstevel@tonic-gate 			 */
6118*0Sstevel@tonic-gate 			mess_size = sizeof (send_params) -
6119*0Sstevel@tonic-gate 			    sizeof (mp_ext_t) +
6120*0Sstevel@tonic-gate 			    (un_array[i]->un_numexts * sizeof (mp_ext_t));
6121*0Sstevel@tonic-gate 
6122*0Sstevel@tonic-gate 			send_params.iocset_params = set_params;
6123*0Sstevel@tonic-gate 			(void) memcpy(&send_params.unit, un_array[i],
6124*0Sstevel@tonic-gate 			    sizeof (*un_array[i]) - sizeof (mp_ext_t) +
6125*0Sstevel@tonic-gate 			    (un_array[i]->un_numexts * sizeof (mp_ext_t)));
6126*0Sstevel@tonic-gate 			result = mdmn_send_message(sp->setno,
6127*0Sstevel@tonic-gate 			    MD_MN_MSG_IOCSET, MD_MSGF_DEFAULT_FLAGS,
6128*0Sstevel@tonic-gate 			    (char *)&send_params, mess_size, &resp,
6129*0Sstevel@tonic-gate 			    ep);
6130*0Sstevel@tonic-gate 			if (resp != NULL) {
6131*0Sstevel@tonic-gate 				if (resp->mmr_exitval != 0)
6132*0Sstevel@tonic-gate 					err = 1;
6133*0Sstevel@tonic-gate 				free_result(resp);
6134*0Sstevel@tonic-gate 			}
6135*0Sstevel@tonic-gate 			if (result != 0) {
6136*0Sstevel@tonic-gate 				err = 1;
6137*0Sstevel@tonic-gate 			}
6138*0Sstevel@tonic-gate 		} else {
6139*0Sstevel@tonic-gate 			if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
6140*0Sstevel@tonic-gate 			    np->cname) != 0) {
6141*0Sstevel@tonic-gate 				err = 1;
6142*0Sstevel@tonic-gate 			}
6143*0Sstevel@tonic-gate 		}
6144*0Sstevel@tonic-gate 
6145*0Sstevel@tonic-gate 		if (err == 1) {
6146*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
6147*0Sstevel@tonic-gate 			    "%s: Error committing record to metadb.\n"),
6148*0Sstevel@tonic-gate 			    np->cname);
6149*0Sstevel@tonic-gate 			goto out;
6150*0Sstevel@tonic-gate 		}
6151*0Sstevel@tonic-gate 
6152*0Sstevel@tonic-gate 		/* note that we've committed a record */
6153*0Sstevel@tonic-gate 		if (!committed)
6154*0Sstevel@tonic-gate 			committed = 1;
6155*0Sstevel@tonic-gate 
6156*0Sstevel@tonic-gate 		/* update any watermarks that need it */
6157*0Sstevel@tonic-gate 		if (update_list != NULL) {
6158*0Sstevel@tonic-gate 			md_sp_t *msp;
6159*0Sstevel@tonic-gate 
6160*0Sstevel@tonic-gate 			/*
6161*0Sstevel@tonic-gate 			 * Check to see if we're trying to create a partition
6162*0Sstevel@tonic-gate 			 * on a mirror. If so we may have to enforce an
6163*0Sstevel@tonic-gate 			 * ownership change before writing the watermark out.
6164*0Sstevel@tonic-gate 			 */
6165*0Sstevel@tonic-gate 			if (metaismeta(compnp)) {
6166*0Sstevel@tonic-gate 				char *miscname;
6167*0Sstevel@tonic-gate 
6168*0Sstevel@tonic-gate 				miscname = metagetmiscname(compnp, ep);
6169*0Sstevel@tonic-gate 				if (miscname != NULL)
6170*0Sstevel@tonic-gate 					comp_is_mirror = (strcmp(miscname,
6171*0Sstevel@tonic-gate 					    MD_MIRROR) == 0);
6172*0Sstevel@tonic-gate 				else
6173*0Sstevel@tonic-gate 					comp_is_mirror = 0;
6174*0Sstevel@tonic-gate 			}
6175*0Sstevel@tonic-gate 			/*
6176*0Sstevel@tonic-gate 			 * If this is a MN set and the component is a mirror,
6177*0Sstevel@tonic-gate 			 * change ownership to this node in order to write the
6178*0Sstevel@tonic-gate 			 * watermarks
6179*0Sstevel@tonic-gate 			 */
6180*0Sstevel@tonic-gate 			if (mn_set && comp_is_mirror) {
6181*0Sstevel@tonic-gate 				mm = (mm_unit_t *)meta_get_unit(sp, compnp, ep);
6182*0Sstevel@tonic-gate 				if (mm == NULL) {
6183*0Sstevel@tonic-gate 					err = 1;
6184*0Sstevel@tonic-gate 					goto out;
6185*0Sstevel@tonic-gate 				} else {
6186*0Sstevel@tonic-gate 					err = meta_mn_change_owner(&ownpar,
6187*0Sstevel@tonic-gate 						sp->setno,
6188*0Sstevel@tonic-gate 						meta_getminor(compnp->dev),
6189*0Sstevel@tonic-gate 						sd->sd_mn_mynode->nd_nodeid,
6190*0Sstevel@tonic-gate 						MD_MN_MM_PREVENT_CHANGE |
6191*0Sstevel@tonic-gate 						    MD_MN_MM_SPAWN_THREAD);
6192*0Sstevel@tonic-gate 					if (err != 0)
6193*0Sstevel@tonic-gate 						goto out;
6194*0Sstevel@tonic-gate 				}
6195*0Sstevel@tonic-gate 			}
6196*0Sstevel@tonic-gate 
6197*0Sstevel@tonic-gate 			if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
6198*0Sstevel@tonic-gate 				err = 1;
6199*0Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
6200*0Sstevel@tonic-gate 				    "%s: Error updating extent headers.\n"),
6201*0Sstevel@tonic-gate 				    np->cname);
6202*0Sstevel@tonic-gate 				goto out;
6203*0Sstevel@tonic-gate 			}
6204*0Sstevel@tonic-gate 			if (meta_sp_update_wm(sp, msp, update_list, ep) < 0) {
6205*0Sstevel@tonic-gate 				err = 1;
6206*0Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
6207*0Sstevel@tonic-gate 				    "%s: Error updating extent headers "
6208*0Sstevel@tonic-gate 				    "on disk.\n"), np->cname);
6209*0Sstevel@tonic-gate 				goto out;
6210*0Sstevel@tonic-gate 			}
6211*0Sstevel@tonic-gate 		}
6212*0Sstevel@tonic-gate 		/*
6213*0Sstevel@tonic-gate 		 * If we have changed ownership earlier and prevented any
6214*0Sstevel@tonic-gate 		 * ownership changes, we can now allow ownership changes
6215*0Sstevel@tonic-gate 		 * again.
6216*0Sstevel@tonic-gate 		 */
6217*0Sstevel@tonic-gate 		if (ownpar) {
6218*0Sstevel@tonic-gate 			(void) meta_mn_change_owner(&ownpar, sp->setno,
6219*0Sstevel@tonic-gate 			    ownpar->d.mnum,
6220*0Sstevel@tonic-gate 			    ownpar->d.owner,
6221*0Sstevel@tonic-gate 			    MD_MN_MM_ALLOW_CHANGE | MD_MN_MM_SPAWN_THREAD);
6222*0Sstevel@tonic-gate 		}
6223*0Sstevel@tonic-gate 	}
6224*0Sstevel@tonic-gate 
6225*0Sstevel@tonic-gate 	/* update status of all soft partitions to OK */
6226*0Sstevel@tonic-gate 	minors = Zalloc(num_sps * sizeof (minor_t));
6227*0Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++)
6228*0Sstevel@tonic-gate 		minors[i] = MD_SID(un_array[i]);
6229*0Sstevel@tonic-gate 
6230*0Sstevel@tonic-gate 	err = update_sp_status(sp, minors, num_sps, MD_SP_OK, mn_set, ep);
6231*0Sstevel@tonic-gate 	if (err != 0)
6232*0Sstevel@tonic-gate 		goto out;
6233*0Sstevel@tonic-gate 
6234*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT)
6235*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: "
6236*0Sstevel@tonic-gate 		    "Soft Partitions recovered from device.\n"),
6237*0Sstevel@tonic-gate 		    compnp->cname);
6238*0Sstevel@tonic-gate out:
6239*0Sstevel@tonic-gate 	/* free memory */
6240*0Sstevel@tonic-gate 	if (extlist != NULL)
6241*0Sstevel@tonic-gate 		meta_sp_list_free(&extlist);
6242*0Sstevel@tonic-gate 	if (sp_list != NULL)
6243*0Sstevel@tonic-gate 		meta_sp_list_free(&sp_list);
6244*0Sstevel@tonic-gate 	if (update_list != NULL)
6245*0Sstevel@tonic-gate 		meta_sp_list_free(&update_list);
6246*0Sstevel@tonic-gate 	if (un_array != NULL)	{
6247*0Sstevel@tonic-gate 		for (i = 0; i < num_sps; i++)
6248*0Sstevel@tonic-gate 			Free(un_array[i]);
6249*0Sstevel@tonic-gate 		Free(un_array);
6250*0Sstevel@tonic-gate 	}
6251*0Sstevel@tonic-gate 	if (minors != NULL)
6252*0Sstevel@tonic-gate 		Free(minors);
6253*0Sstevel@tonic-gate 	if (ownpar != NULL)
6254*0Sstevel@tonic-gate 		Free(ownpar);
6255*0Sstevel@tonic-gate 	(void) fflush(stdout);
6256*0Sstevel@tonic-gate 
6257*0Sstevel@tonic-gate 	if ((keynlp != NULL) && (committed != 1)) {
6258*0Sstevel@tonic-gate 		/*
6259*0Sstevel@tonic-gate 		 * if we haven't committed any softparts, either because of an
6260*0Sstevel@tonic-gate 		 * error or because the user decided not to proceed, delete
6261*0Sstevel@tonic-gate 		 * namelist key for the component
6262*0Sstevel@tonic-gate 		 */
6263*0Sstevel@tonic-gate 		if (mn_set) {
6264*0Sstevel@tonic-gate 			mdnamelist_t	*p;
6265*0Sstevel@tonic-gate 
6266*0Sstevel@tonic-gate 			for (p = keynlp; (p != NULL); p = p->next) {
6267*0Sstevel@tonic-gate 				mdname_t		*np = p->namep;
6268*0Sstevel@tonic-gate 				md_mn_msg_delkeyname_t	send_params;
6269*0Sstevel@tonic-gate 				md_mn_result_t		*resp = NULL;
6270*0Sstevel@tonic-gate 
6271*0Sstevel@tonic-gate 				send_params.delkeyname_dev = np->dev;
6272*0Sstevel@tonic-gate 				send_params.delkeyname_setno = sp->setno;
6273*0Sstevel@tonic-gate 				send_params.delkeyname_key = np->key;
6274*0Sstevel@tonic-gate 				(void) mdmn_send_message(sp->setno,
6275*0Sstevel@tonic-gate 				    MD_MN_MSG_DELKEYNAME, MD_MSGF_DEFAULT_FLAGS,
6276*0Sstevel@tonic-gate 				    (char *)&send_params, sizeof (send_params),
6277*0Sstevel@tonic-gate 				    &resp, ep);
6278*0Sstevel@tonic-gate 				if (resp != NULL) {
6279*0Sstevel@tonic-gate 					free_result(resp);
6280*0Sstevel@tonic-gate 				}
6281*0Sstevel@tonic-gate 			}
6282*0Sstevel@tonic-gate 		} else {
6283*0Sstevel@tonic-gate 			(void) del_key_names(sp, keynlp, NULL);
6284*0Sstevel@tonic-gate 		}
6285*0Sstevel@tonic-gate 	}
6286*0Sstevel@tonic-gate 
6287*0Sstevel@tonic-gate 	metafreenamelist(keynlp);
6288*0Sstevel@tonic-gate 
6289*0Sstevel@tonic-gate 	if (err)
6290*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
6291*0Sstevel@tonic-gate 
6292*0Sstevel@tonic-gate 	if (not_recovered)
6293*0Sstevel@tonic-gate 		if (options & MDCMD_PRINT)
6294*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN, "%s: "
6295*0Sstevel@tonic-gate 			    "Soft Partitions NOT recovered from device.\n"),
6296*0Sstevel@tonic-gate 			    compnp->cname);
6297*0Sstevel@tonic-gate 	return (0);
6298*0Sstevel@tonic-gate }
6299*0Sstevel@tonic-gate 
6300*0Sstevel@tonic-gate /*
6301*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_recover_from_unit()
6302*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
6303*0Sstevel@tonic-gate  *		compnp	- name of component we are recovering from
6304*0Sstevel@tonic-gate  *		options	- metarecover options
6305*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
6306*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
6307*0Sstevel@tonic-gate  * PURPOSE:	update watermarks to match metadb records.  begin by getting
6308*0Sstevel@tonic-gate  *		a namelist representing all soft partitions on the specified
6309*0Sstevel@tonic-gate  *		component.  then, build an extlist representing the soft
6310*0Sstevel@tonic-gate  *		partitions, filling in the freespace extents.  notify user
6311*0Sstevel@tonic-gate  *		of changes, place all soft partitions into the "recovering"
6312*0Sstevel@tonic-gate  *		state and update the watermarks.  finally, return all soft
6313*0Sstevel@tonic-gate  *		partitions to the "OK" state.
6314*0Sstevel@tonic-gate  */
6315*0Sstevel@tonic-gate static int
6316*0Sstevel@tonic-gate meta_sp_recover_from_unit(
6317*0Sstevel@tonic-gate 	mdsetname_t	*sp,
6318*0Sstevel@tonic-gate 	mdname_t	*compnp,
6319*0Sstevel@tonic-gate 	mdcmdopts_t	options,
6320*0Sstevel@tonic-gate 	md_error_t	*ep
6321*0Sstevel@tonic-gate )
6322*0Sstevel@tonic-gate {
6323*0Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
6324*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
6325*0Sstevel@tonic-gate 	sp_ext_node_t	*ext = NULL;
6326*0Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
6327*0Sstevel@tonic-gate 	int		count;
6328*0Sstevel@tonic-gate 	char		yesno[255];
6329*0Sstevel@tonic-gate 	char		*yes;
6330*0Sstevel@tonic-gate 	int		rval = 0;
6331*0Sstevel@tonic-gate 	minor_t		*minors = NULL;
6332*0Sstevel@tonic-gate 	int		i;
6333*0Sstevel@tonic-gate 	md_sp_t		*msp;
6334*0Sstevel@tonic-gate 	md_set_desc	*sd;
6335*0Sstevel@tonic-gate 	bool_t		mn_set = 0;
6336*0Sstevel@tonic-gate 	daddr_t		start_block;
6337*0Sstevel@tonic-gate 
6338*0Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
6339*0Sstevel@tonic-gate 	if (count <= 0)
6340*0Sstevel@tonic-gate 		return (-1);
6341*0Sstevel@tonic-gate 
6342*0Sstevel@tonic-gate 	/* set flag if dealing with a MN set */
6343*0Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
6344*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
6345*0Sstevel@tonic-gate 			return (-1);
6346*0Sstevel@tonic-gate 		}
6347*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
6348*0Sstevel@tonic-gate 			mn_set = 1;
6349*0Sstevel@tonic-gate 	}
6350*0Sstevel@tonic-gate 	/*
6351*0Sstevel@tonic-gate 	 * Save the XDR unit structure for one of the soft partitions;
6352*0Sstevel@tonic-gate 	 * we'll use this later to provide metadevice context to
6353*0Sstevel@tonic-gate 	 * update the watermarks so the device can be resolved by
6354*0Sstevel@tonic-gate 	 * devid instead of dev_t.
6355*0Sstevel@tonic-gate 	 */
6356*0Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, spnlp->namep, ep)) == NULL) {
6357*0Sstevel@tonic-gate 		metafreenamelist(spnlp);
6358*0Sstevel@tonic-gate 		return (-1);
6359*0Sstevel@tonic-gate 	}
6360*0Sstevel@tonic-gate 
6361*0Sstevel@tonic-gate 	if ((start_block = meta_sp_get_start(sp, compnp, ep)) ==
6362*0Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
6363*0Sstevel@tonic-gate 		return (-1);
6364*0Sstevel@tonic-gate 	}
6365*0Sstevel@tonic-gate 
6366*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist, 0ULL, start_block,
6367*0Sstevel@tonic-gate 	    EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
6368*0Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
6369*0Sstevel@tonic-gate 	    metagetsize(compnp, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
6370*0Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
6371*0Sstevel@tonic-gate 
6372*0Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
6373*0Sstevel@tonic-gate 		metafreenamelist(spnlp);
6374*0Sstevel@tonic-gate 		return (-1);
6375*0Sstevel@tonic-gate 	}
6376*0Sstevel@tonic-gate 
6377*0Sstevel@tonic-gate 	assert(extlist != NULL);
6378*0Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0) {
6379*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
6380*0Sstevel@tonic-gate 		    "Updating extent headers on device %s from metadb.\n\n"),
6381*0Sstevel@tonic-gate 		    compnp->cname);
6382*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
6383*0Sstevel@tonic-gate 		    "The following extent headers will be written:\n"));
6384*0Sstevel@tonic-gate 		meta_sp_display_exthdr();
6385*0Sstevel@tonic-gate 	}
6386*0Sstevel@tonic-gate 
6387*0Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
6388*0Sstevel@tonic-gate 
6389*0Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
6390*0Sstevel@tonic-gate 
6391*0Sstevel@tonic-gate 		/* mark every node for updating except the reserved space */
6392*0Sstevel@tonic-gate 		if (ext->ext_type != EXTTYP_RESERVED) {
6393*0Sstevel@tonic-gate 			ext->ext_flags |= EXTFLG_UPDATE;
6394*0Sstevel@tonic-gate 
6395*0Sstevel@tonic-gate 			/* print extent information */
6396*0Sstevel@tonic-gate 			if ((options & MDCMD_VERBOSE) != 0)
6397*0Sstevel@tonic-gate 				meta_sp_display_ext(ext);
6398*0Sstevel@tonic-gate 		}
6399*0Sstevel@tonic-gate 	}
6400*0Sstevel@tonic-gate 
6401*0Sstevel@tonic-gate 	/* request verification and then update all watermarks */
6402*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) != 0) {
6403*0Sstevel@tonic-gate 
6404*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
6405*0Sstevel@tonic-gate 		    "\nWARNING: You are about to overwrite portions of %s\n"
6406*0Sstevel@tonic-gate 		    "with soft partition metadata. The extent headers will be\n"
6407*0Sstevel@tonic-gate 		    "written to match the existing metadb configuration.  If\n"
6408*0Sstevel@tonic-gate 		    "the device was not previously setup with this\n"
6409*0Sstevel@tonic-gate 		    "configuration, data loss may result.\n\n"),
6410*0Sstevel@tonic-gate 		    compnp->cname);
6411*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
6412*0Sstevel@tonic-gate 		    "Are you sure you want to do this (yes/no)? "));
6413*0Sstevel@tonic-gate 
6414*0Sstevel@tonic-gate 		(void) fflush(stdout);
6415*0Sstevel@tonic-gate 		if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
6416*0Sstevel@tonic-gate 		    (strlen(yesno) == 1))
6417*0Sstevel@tonic-gate 			(void) snprintf(yesno, sizeof (yesno),
6418*0Sstevel@tonic-gate 			    "%s\n", dgettext(TEXT_DOMAIN, "no"));
6419*0Sstevel@tonic-gate 		yes = dgettext(TEXT_DOMAIN, "yes");
6420*0Sstevel@tonic-gate 		if (strncasecmp(yesno, yes, strlen(yesno) - 1) == 0) {
6421*0Sstevel@tonic-gate 			/* place soft partitions into recovering state */
6422*0Sstevel@tonic-gate 			minors = Zalloc(count * sizeof (minor_t));
6423*0Sstevel@tonic-gate 			for (nlp = spnlp, i = 0;
6424*0Sstevel@tonic-gate 			    nlp != NULL && i < count;
6425*0Sstevel@tonic-gate 			    nlp = nlp->next, i++) {
6426*0Sstevel@tonic-gate 				assert(nlp->namep != NULL);
6427*0Sstevel@tonic-gate 				minors[i] = meta_getminor(nlp->namep->dev);
6428*0Sstevel@tonic-gate 			}
6429*0Sstevel@tonic-gate 			if (update_sp_status(sp, minors, count,
6430*0Sstevel@tonic-gate 			    MD_SP_RECOVER, mn_set, ep) != 0) {
6431*0Sstevel@tonic-gate 				rval = -1;
6432*0Sstevel@tonic-gate 				goto out;
6433*0Sstevel@tonic-gate 			}
6434*0Sstevel@tonic-gate 
6435*0Sstevel@tonic-gate 			/* update the watermarks */
6436*0Sstevel@tonic-gate 			if (meta_sp_update_wm(sp, msp, extlist, ep) < 0) {
6437*0Sstevel@tonic-gate 				rval = -1;
6438*0Sstevel@tonic-gate 				goto out;
6439*0Sstevel@tonic-gate 			}
6440*0Sstevel@tonic-gate 
6441*0Sstevel@tonic-gate 			if (options & MDCMD_PRINT) {
6442*0Sstevel@tonic-gate 				(void) printf(dgettext(TEXT_DOMAIN, "%s: "
6443*0Sstevel@tonic-gate 				    "Soft Partitions recovered from metadb\n"),
6444*0Sstevel@tonic-gate 				    compnp->cname);
6445*0Sstevel@tonic-gate 			}
6446*0Sstevel@tonic-gate 
6447*0Sstevel@tonic-gate 			/* return soft partitions to the OK state */
6448*0Sstevel@tonic-gate 			if (update_sp_status(sp, minors, count,
6449*0Sstevel@tonic-gate 			    MD_SP_OK, mn_set, ep) != 0) {
6450*0Sstevel@tonic-gate 				rval = -1;
6451*0Sstevel@tonic-gate 				goto out;
6452*0Sstevel@tonic-gate 			}
6453*0Sstevel@tonic-gate 
6454*0Sstevel@tonic-gate 			rval = 0;
6455*0Sstevel@tonic-gate 			goto out;
6456*0Sstevel@tonic-gate 		}
6457*0Sstevel@tonic-gate 	}
6458*0Sstevel@tonic-gate 
6459*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
6460*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
6461*0Sstevel@tonic-gate 		    "%s: Soft Partitions NOT recovered from metadb\n"),
6462*0Sstevel@tonic-gate 		    compnp->cname);
6463*0Sstevel@tonic-gate 	}
6464*0Sstevel@tonic-gate 
6465*0Sstevel@tonic-gate out:
6466*0Sstevel@tonic-gate 	if (minors != NULL)
6467*0Sstevel@tonic-gate 		Free(minors);
6468*0Sstevel@tonic-gate 	metafreenamelist(spnlp);
6469*0Sstevel@tonic-gate 	meta_sp_list_free(&extlist);
6470*0Sstevel@tonic-gate 	(void) fflush(stdout);
6471*0Sstevel@tonic-gate 	return (rval);
6472*0Sstevel@tonic-gate }
6473*0Sstevel@tonic-gate 
6474*0Sstevel@tonic-gate 
6475*0Sstevel@tonic-gate /*
6476*0Sstevel@tonic-gate  * FUNCTION:	meta_sp_update_abr()
6477*0Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
6478*0Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
6479*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
6480*0Sstevel@tonic-gate  * PURPOSE:	update the ABR state for all soft partitions in the set. This
6481*0Sstevel@tonic-gate  *		is called when joining a set. It sends a message to the master
6482*0Sstevel@tonic-gate  *		node for each soft partition to get the value of tstate and
6483*0Sstevel@tonic-gate  *		then sets ABR ,if required, by opening the sp, setting ABR
6484*0Sstevel@tonic-gate  *		and then closing the sp. This approach is taken rather that
6485*0Sstevel@tonic-gate  *		just issuing the MD_MN_SET_CAP ioctl, in order to deal with
6486*0Sstevel@tonic-gate  *		the case when we have another node simultaneously unsetting ABR.
6487*0Sstevel@tonic-gate  */
6488*0Sstevel@tonic-gate int
6489*0Sstevel@tonic-gate meta_sp_update_abr(
6490*0Sstevel@tonic-gate 	mdsetname_t	*sp,
6491*0Sstevel@tonic-gate 	md_error_t	*ep
6492*0Sstevel@tonic-gate )
6493*0Sstevel@tonic-gate {
6494*0Sstevel@tonic-gate 	mdnamelist_t	*devnlp = NULL;
6495*0Sstevel@tonic-gate 	mdnamelist_t	*p;
6496*0Sstevel@tonic-gate 	mdname_t	*devnp = NULL;
6497*0Sstevel@tonic-gate 	md_unit_t	*un;
6498*0Sstevel@tonic-gate 	char		fname[MAXPATHLEN];
6499*0Sstevel@tonic-gate 	int		mnum, fd;
6500*0Sstevel@tonic-gate 	volcap_t	vc;
6501*0Sstevel@tonic-gate 	uint_t		tstate;
6502*0Sstevel@tonic-gate 
6503*0Sstevel@tonic-gate 
6504*0Sstevel@tonic-gate 	if (meta_get_sp_names(sp, &devnlp, 0, ep) < 0) {
6505*0Sstevel@tonic-gate 		return (-1);
6506*0Sstevel@tonic-gate 	}
6507*0Sstevel@tonic-gate 
6508*0Sstevel@tonic-gate 	/* Exit if no soft partitions in this set */
6509*0Sstevel@tonic-gate 	if (devnlp == NULL)
6510*0Sstevel@tonic-gate 		return (0);
6511*0Sstevel@tonic-gate 
6512*0Sstevel@tonic-gate 	/* For each soft partition */
6513*0Sstevel@tonic-gate 	for (p = devnlp; (p != NULL); p = p->next) {
6514*0Sstevel@tonic-gate 		devnp = p->namep;
6515*0Sstevel@tonic-gate 
6516*0Sstevel@tonic-gate 		/* check if this is a top level metadevice */
6517*0Sstevel@tonic-gate 		if ((un = meta_get_mdunit(sp, devnp, ep)) == NULL)
6518*0Sstevel@tonic-gate 			goto out;
6519*0Sstevel@tonic-gate 		if (MD_HAS_PARENT(MD_PARENT(un))) {
6520*0Sstevel@tonic-gate 			Free(un);
6521*0Sstevel@tonic-gate 			continue;
6522*0Sstevel@tonic-gate 		}
6523*0Sstevel@tonic-gate 		Free(un);
6524*0Sstevel@tonic-gate 
6525*0Sstevel@tonic-gate 		/* Get tstate from Master */
6526*0Sstevel@tonic-gate 		if (meta_mn_send_get_tstate(devnp->dev, &tstate, ep) != 0) {
6527*0Sstevel@tonic-gate 			mdname_t	*np;
6528*0Sstevel@tonic-gate 			np = metamnumname(&sp, meta_getminor(devnp->dev), 0,
6529*0Sstevel@tonic-gate 			    ep);
6530*0Sstevel@tonic-gate 			if (np) {
6531*0Sstevel@tonic-gate 				md_perror(dgettext(TEXT_DOMAIN,
6532*0Sstevel@tonic-gate 				    "Unable to get tstate for %s"), np->cname);
6533*0Sstevel@tonic-gate 			}
6534*0Sstevel@tonic-gate 			continue;
6535*0Sstevel@tonic-gate 		}
6536*0Sstevel@tonic-gate 		/* If not set on the master, nothing to do */
6537*0Sstevel@tonic-gate 		if (!(tstate & MD_ABR_CAP))
6538*0Sstevel@tonic-gate 			continue;
6539*0Sstevel@tonic-gate 
6540*0Sstevel@tonic-gate 		mnum = meta_getminor(devnp->dev);
6541*0Sstevel@tonic-gate 		(void) snprintf(fname, MAXPATHLEN, "/dev/md/%s/rdsk/d%u",
6542*0Sstevel@tonic-gate 		    sp->setname, (unsigned)MD_MIN2UNIT(mnum));
6543*0Sstevel@tonic-gate 		if ((fd = open(fname, O_RDWR, 0)) < 0) {
6544*0Sstevel@tonic-gate 			md_perror(dgettext(TEXT_DOMAIN,
6545*0Sstevel@tonic-gate 			    "Could not open device %s"), fname);
6546*0Sstevel@tonic-gate 			continue;
6547*0Sstevel@tonic-gate 		}
6548*0Sstevel@tonic-gate 
6549*0Sstevel@tonic-gate 		/* Set ABR state */
6550*0Sstevel@tonic-gate 		vc.vc_info = 0;
6551*0Sstevel@tonic-gate 		vc.vc_set = 0;
6552*0Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGETVOLCAP, &vc) < 0) {
6553*0Sstevel@tonic-gate 			(void) close(fd);
6554*0Sstevel@tonic-gate 			continue;
6555*0Sstevel@tonic-gate 		}
6556*0Sstevel@tonic-gate 
6557*0Sstevel@tonic-gate 		vc.vc_set = DKV_ABR_CAP;
6558*0Sstevel@tonic-gate 		if (ioctl(fd, DKIOCSETVOLCAP, &vc) < 0) {
6559*0Sstevel@tonic-gate 			(void) close(fd);
6560*0Sstevel@tonic-gate 			goto out;
6561*0Sstevel@tonic-gate 		}
6562*0Sstevel@tonic-gate 
6563*0Sstevel@tonic-gate 		(void) close(fd);
6564*0Sstevel@tonic-gate 	}
6565*0Sstevel@tonic-gate 	metafreenamelist(devnlp);
6566*0Sstevel@tonic-gate 	return (0);
6567*0Sstevel@tonic-gate out:
6568*0Sstevel@tonic-gate 	metafreenamelist(devnlp);
6569*0Sstevel@tonic-gate 	return (-1);
6570*0Sstevel@tonic-gate }
6571*0Sstevel@tonic-gate 
6572*0Sstevel@tonic-gate /*
6573*0Sstevel@tonic-gate  * FUNCTION:	meta_mn_sp_update_abr()
6574*0Sstevel@tonic-gate  * INPUT:	arg	- Given set.
6575*0Sstevel@tonic-gate  * PURPOSE:	update the ABR state for all soft partitions in the set by
6576*0Sstevel@tonic-gate  *		forking a process to call meta_sp_update_abr()
6577*0Sstevel@tonic-gate  *		This function is only called via rpc.metad when adding a node
6578*0Sstevel@tonic-gate  *		to a set, ie this node is beong joined to the set by another
6579*0Sstevel@tonic-gate  *		node.
6580*0Sstevel@tonic-gate  */
6581*0Sstevel@tonic-gate void *
6582*0Sstevel@tonic-gate meta_mn_sp_update_abr(void *arg)
6583*0Sstevel@tonic-gate {
6584*0Sstevel@tonic-gate 	set_t		setno = *((set_t *)arg);
6585*0Sstevel@tonic-gate 	mdsetname_t	*sp;
6586*0Sstevel@tonic-gate 	md_error_t	mde = mdnullerror;
6587*0Sstevel@tonic-gate 	int		fval;
6588*0Sstevel@tonic-gate 
6589*0Sstevel@tonic-gate 	/* should have a set */
6590*0Sstevel@tonic-gate 	assert(setno != NULL);
6591*0Sstevel@tonic-gate 
6592*0Sstevel@tonic-gate 	if ((sp = metasetnosetname(setno, &mde)) == NULL) {
6593*0Sstevel@tonic-gate 		mde_perror(&mde, "");
6594*0Sstevel@tonic-gate 		return (NULL);
6595*0Sstevel@tonic-gate 	}
6596*0Sstevel@tonic-gate 
6597*0Sstevel@tonic-gate 	if (!(meta_is_mn_set(sp, &mde))) {
6598*0Sstevel@tonic-gate 		mde_perror(&mde, "");
6599*0Sstevel@tonic-gate 		return (NULL);
6600*0Sstevel@tonic-gate 	}
6601*0Sstevel@tonic-gate 
6602*0Sstevel@tonic-gate 	/* fork a process */
6603*0Sstevel@tonic-gate 	if ((fval = md_daemonize(sp, &mde)) != 0) {
6604*0Sstevel@tonic-gate 		/*
6605*0Sstevel@tonic-gate 		 * md_daemonize will fork off a process.  The is the
6606*0Sstevel@tonic-gate 		 * parent or error.
6607*0Sstevel@tonic-gate 		 */
6608*0Sstevel@tonic-gate 		if (fval > 0) {
6609*0Sstevel@tonic-gate 			return (NULL);
6610*0Sstevel@tonic-gate 		}
6611*0Sstevel@tonic-gate 		mde_perror(&mde, "");
6612*0Sstevel@tonic-gate 		return (NULL);
6613*0Sstevel@tonic-gate 	}
6614*0Sstevel@tonic-gate 	/*
6615*0Sstevel@tonic-gate 	 * Child process should never return back to rpc.metad, but
6616*0Sstevel@tonic-gate 	 * should exit.
6617*0Sstevel@tonic-gate 	 * Flush all internally cached data inherited from parent process
6618*0Sstevel@tonic-gate 	 * since cached data will be cleared when parent process RPC request
6619*0Sstevel@tonic-gate 	 * has completed (which is possibly before this child process
6620*0Sstevel@tonic-gate 	 * can complete).
6621*0Sstevel@tonic-gate 	 * Child process can retrieve and cache its own copy of data from
6622*0Sstevel@tonic-gate 	 * rpc.metad that won't be changed by the parent process.
6623*0Sstevel@tonic-gate 	 *
6624*0Sstevel@tonic-gate 	 * Reset md_in_daemon since this child will be a client of rpc.metad
6625*0Sstevel@tonic-gate 	 * not part of the rpc.metad daemon itself.
6626*0Sstevel@tonic-gate 	 * md_in_daemon is used by rpc.metad so that libmeta can tell if
6627*0Sstevel@tonic-gate 	 * this thread is rpc.metad or any other thread.  (If this thread
6628*0Sstevel@tonic-gate 	 * was rpc.metad it could use some short circuit code to get data
6629*0Sstevel@tonic-gate 	 * directly from rpc.metad instead of doing an RPC call to rpc.metad).
6630*0Sstevel@tonic-gate 	 */
6631*0Sstevel@tonic-gate 	md_in_daemon = 0;
6632*0Sstevel@tonic-gate 	metaflushsetname(sp);
6633*0Sstevel@tonic-gate 	sr_cache_flush_setno(setno);
6634*0Sstevel@tonic-gate 	if ((sp = metasetnosetname(setno, &mde)) == NULL) {
6635*0Sstevel@tonic-gate 		mde_perror(&mde, "");
6636*0Sstevel@tonic-gate 		md_exit(sp, 1);
6637*0Sstevel@tonic-gate 	}
6638*0Sstevel@tonic-gate 
6639*0Sstevel@tonic-gate 
6640*0Sstevel@tonic-gate 	/*
6641*0Sstevel@tonic-gate 	 * Closing stdin/out/err here.
6642*0Sstevel@tonic-gate 	 */
6643*0Sstevel@tonic-gate 	(void) close(0);
6644*0Sstevel@tonic-gate 	(void) close(1);
6645*0Sstevel@tonic-gate 	(void) close(2);
6646*0Sstevel@tonic-gate 	assert(fval == 0);
6647*0Sstevel@tonic-gate 
6648*0Sstevel@tonic-gate 	(void) meta_sp_update_abr(sp, &mde);
6649*0Sstevel@tonic-gate 
6650*0Sstevel@tonic-gate 	md_exit(sp, 0);
6651*0Sstevel@tonic-gate 	/*NOTREACHED*/
6652*0Sstevel@tonic-gate }
6653