10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
310Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
340Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
350Sstevel@tonic-gate #endif
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * soft partition operations
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * Soft Partitions provide a virtual disk mechanism which is used to
410Sstevel@tonic-gate  * divide a large volume into many small pieces, each appearing as a
420Sstevel@tonic-gate  * separate device.  A soft partition consists of a series of extents,
430Sstevel@tonic-gate  * each having an offset and a length.  The extents are logically
440Sstevel@tonic-gate  * contiguous, so where the first extent leaves off the second extent
450Sstevel@tonic-gate  * picks up.  Which extent a given "virtual offset" belongs to is
460Sstevel@tonic-gate  * dependent on the size of all the previous extents in the soft
470Sstevel@tonic-gate  * partition.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * Soft partitions are represented in memory by an extent node
500Sstevel@tonic-gate  * (sp_ext_node_t) which contains all of the information necessary to
510Sstevel@tonic-gate  * create a unit structure and update the on-disk format, called
520Sstevel@tonic-gate  * "watermarks".  These extent nodes are typically kept in a doubly
530Sstevel@tonic-gate  * linked list and are manipulated by list manipulation routines.  A
540Sstevel@tonic-gate  * list of extents may represent all of the soft partitions on a volume,
550Sstevel@tonic-gate  * a single soft partition, or perhaps just a set of extents that need
560Sstevel@tonic-gate  * to be updated.  Extent lists may be sorted by extent or by name/seq#,
570Sstevel@tonic-gate  * depending on which compare function is used.  Most of the routines
580Sstevel@tonic-gate  * require the list be sorted by offset to work, and that's the typical
590Sstevel@tonic-gate  * configuration.
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  * In order to do an allocation, knowledge of all soft partitions on the
620Sstevel@tonic-gate  * volume is required.  Then free space is determined from the space
630Sstevel@tonic-gate  * that is not allocated, and new allocations can be made from the free
640Sstevel@tonic-gate  * space.  Once the new allocations are made, a unit structure is created
650Sstevel@tonic-gate  * and the watermarks are updated.  The status is then changed to "okay"
660Sstevel@tonic-gate  * on the unit structure to commit the transaction.  If updating the
670Sstevel@tonic-gate  * watermarks fails, the unit structure is in an intermediate state and
680Sstevel@tonic-gate  * the driver will not allow access to the device.
690Sstevel@tonic-gate  *
700Sstevel@tonic-gate  * A typical sequence of events is:
710Sstevel@tonic-gate  *     1. Fetch the list of names for all soft partitions on a volume
720Sstevel@tonic-gate  *         meta_sp_get_by_component()
730Sstevel@tonic-gate  *     2. Construct an extent list from the name list
740Sstevel@tonic-gate  *         meta_sp_extlist_from_namelist()
750Sstevel@tonic-gate  *     3. Fill the gaps in the extent list with free extents
760Sstevel@tonic-gate  *         meta_sp_list_freefill()
770Sstevel@tonic-gate  *     4. Allocate from the free extents
780Sstevel@tonic-gate  *         meta_sp_alloc_by_len()
790Sstevel@tonic-gate  *         meta_sp_alloc_by_list()
800Sstevel@tonic-gate  *     5. Create the unit structure from the extent list
810Sstevel@tonic-gate  *         meta_sp_createunit()
820Sstevel@tonic-gate  *         meta_sp_updateunit()
830Sstevel@tonic-gate  *     6. Write out the watermarks
840Sstevel@tonic-gate  *         meta_sp_update_wm()
850Sstevel@tonic-gate  *     7. Set the status to "Okay"
860Sstevel@tonic-gate  *         meta_sp_setstatus()
870Sstevel@tonic-gate  *
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #include <stdio.h>
910Sstevel@tonic-gate #include <meta.h>
920Sstevel@tonic-gate #include "meta_repartition.h"
930Sstevel@tonic-gate #include <sys/lvm/md_sp.h>
940Sstevel@tonic-gate #include <sys/lvm/md_crc.h>
950Sstevel@tonic-gate #include <strings.h>
960Sstevel@tonic-gate #include <sys/lvm/md_mirror.h>
970Sstevel@tonic-gate #include <sys/bitmap.h>
980Sstevel@tonic-gate 
990Sstevel@tonic-gate extern int	md_in_daemon;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate typedef struct sp_ext_node {
1020Sstevel@tonic-gate 	struct sp_ext_node	*ext_next;	/* next element */
1030Sstevel@tonic-gate 	struct sp_ext_node	*ext_prev;	/* previous element */
1040Sstevel@tonic-gate 	sp_ext_type_t		ext_type;	/* type of extent */
1050Sstevel@tonic-gate 	sp_ext_offset_t		ext_offset;	/* starting offset */
1060Sstevel@tonic-gate 	sp_ext_length_t		ext_length;	/* length of this node */
1070Sstevel@tonic-gate 	uint_t			ext_flags;	/* extent flags */
1080Sstevel@tonic-gate 	uint32_t		ext_seq;	/* watermark seq no */
1090Sstevel@tonic-gate 	mdname_t		*ext_namep;	/* name pointer */
1100Sstevel@tonic-gate 	mdsetname_t		*ext_setp;	/* set pointer */
1110Sstevel@tonic-gate } sp_ext_node_t;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /* extent flags */
1140Sstevel@tonic-gate #define	EXTFLG_UPDATE	(1)
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /* Extent node compare function for list sorting */
1170Sstevel@tonic-gate typedef int (*ext_cmpfunc_t)(sp_ext_node_t *, sp_ext_node_t *);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /* Function Prototypes */
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /* Debugging Functions */
1230Sstevel@tonic-gate static void meta_sp_debug(char *format, ...);
1240Sstevel@tonic-gate static void meta_sp_printunit(mp_unit_t *mp);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /* Misc Support Functions */
1270Sstevel@tonic-gate int meta_sp_parsesize(char *s, sp_ext_length_t *szp);
1280Sstevel@tonic-gate static int meta_sp_parsesizestring(char *s, sp_ext_length_t *szp);
1290Sstevel@tonic-gate static int meta_sp_setgeom(mdname_t *np, mdname_t *compnp, mp_unit_t *mp,
1300Sstevel@tonic-gate 	md_error_t *ep);
1310Sstevel@tonic-gate static int meta_sp_get_by_component(mdsetname_t *sp, mdname_t *compnp,
1320Sstevel@tonic-gate     mdnamelist_t **nlpp, int force, md_error_t *ep);
1330Sstevel@tonic-gate static sp_ext_length_t meta_sp_get_default_alignment(mdsetname_t *sp,
1340Sstevel@tonic-gate     mdname_t *compnp, md_error_t *ep);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /* Extent List Manipulation Functions */
1370Sstevel@tonic-gate static int meta_sp_cmp_by_nameseq(sp_ext_node_t *e1, sp_ext_node_t *e2);
1380Sstevel@tonic-gate static int meta_sp_cmp_by_offset(sp_ext_node_t *e1, sp_ext_node_t *e2);
1390Sstevel@tonic-gate static void meta_sp_list_insert(mdsetname_t *sp, mdname_t *np,
1400Sstevel@tonic-gate     sp_ext_node_t **head, sp_ext_offset_t offset, sp_ext_length_t length,
1410Sstevel@tonic-gate     sp_ext_type_t type, uint_t seq, uint_t flags, ext_cmpfunc_t compare);
1420Sstevel@tonic-gate static void meta_sp_list_free(sp_ext_node_t **head);
1430Sstevel@tonic-gate static void meta_sp_list_remove(sp_ext_node_t **head, sp_ext_node_t *ext);
1440Sstevel@tonic-gate static sp_ext_length_t meta_sp_list_size(sp_ext_node_t *head,
1450Sstevel@tonic-gate     sp_ext_type_t exttype, int exclude_wm);
1460Sstevel@tonic-gate static sp_ext_node_t *meta_sp_list_find(sp_ext_node_t *head,
1470Sstevel@tonic-gate     sp_ext_offset_t offset);
1480Sstevel@tonic-gate static void meta_sp_list_freefill(sp_ext_node_t **extlist,
1490Sstevel@tonic-gate     sp_ext_length_t size);
1500Sstevel@tonic-gate static void meta_sp_list_dump(sp_ext_node_t *head);
1510Sstevel@tonic-gate static int meta_sp_list_overlaps(sp_ext_node_t *head);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /* Extent List Query Functions */
1540Sstevel@tonic-gate static boolean_t meta_sp_enough_space(int desired_number_of_sps,
1550Sstevel@tonic-gate 	blkcnt_t desired_sp_size, sp_ext_node_t **extent_listpp,
1560Sstevel@tonic-gate 	sp_ext_length_t alignment);
1570Sstevel@tonic-gate static boolean_t meta_sp_get_extent_list(mdsetname_t *mdsetnamep,
1580Sstevel@tonic-gate 	mdname_t *device_mdnamep, sp_ext_node_t **extent_listpp,
1590Sstevel@tonic-gate 	md_error_t *ep);
1600Sstevel@tonic-gate static boolean_t meta_sp_get_extent_list_for_drive(mdsetname_t *mdsetnamep,
1610Sstevel@tonic-gate 	mddrivename_t *mddrivenamep, sp_ext_node_t **extent_listpp);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /* Extent Allocation Functions */
1650Sstevel@tonic-gate static void meta_sp_alloc_by_ext(mdsetname_t *sp, mdname_t *np,
1660Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_node_t *free_ext,
1670Sstevel@tonic-gate     sp_ext_offset_t alloc_offset, sp_ext_length_t alloc_length, uint_t seq);
1680Sstevel@tonic-gate static int meta_sp_alloc_by_len(mdsetname_t *sp, mdname_t *np,
1690Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_length_t *lp,
1700Sstevel@tonic-gate     sp_ext_offset_t last_off, sp_ext_length_t alignment);
1710Sstevel@tonic-gate static int meta_sp_alloc_by_list(mdsetname_t *sp, mdname_t *np,
1720Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_node_t *oblist);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /* Extent List Population Functions */
1750Sstevel@tonic-gate static int meta_sp_extlist_from_namelist(mdsetname_t *sp, mdnamelist_t *spnlp,
1760Sstevel@tonic-gate     sp_ext_node_t **extlist, md_error_t *ep);
1770Sstevel@tonic-gate static int meta_sp_extlist_from_wm(mdsetname_t *sp, mdname_t *compnp,
1780Sstevel@tonic-gate     sp_ext_node_t **extlist, ext_cmpfunc_t compare, md_error_t *ep);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /* Print (metastat) Functions */
1810Sstevel@tonic-gate static int meta_sp_short_print(md_sp_t *msp, char *fname, FILE *fp,
1820Sstevel@tonic-gate     mdprtopts_t options, md_error_t *ep);
1830Sstevel@tonic-gate static char *meta_sp_status_to_name(xsp_status_t xsp_status, uint_t tstate);
1840Sstevel@tonic-gate static int meta_sp_report(mdsetname_t *sp, md_sp_t *msp, mdnamelist_t **nlpp,
1850Sstevel@tonic-gate     char *fname, FILE *fp, mdprtopts_t options, md_error_t *ep);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /* Watermark Manipulation Functions */
1880Sstevel@tonic-gate static int meta_sp_update_wm(mdsetname_t *sp, md_sp_t *msp,
1890Sstevel@tonic-gate     sp_ext_node_t *extlist, md_error_t *ep);
1900Sstevel@tonic-gate static int meta_sp_clear_wm(mdsetname_t *sp, md_sp_t *msp, md_error_t *ep);
1910Sstevel@tonic-gate static int meta_sp_read_wm(mdsetname_t *sp, mdname_t *compnp,
1920Sstevel@tonic-gate     mp_watermark_t *wm, sp_ext_offset_t offset,  md_error_t *ep);
1930Sstevel@tonic-gate static diskaddr_t meta_sp_get_start(mdsetname_t *sp, mdname_t *compnp,
1940Sstevel@tonic-gate     md_error_t *ep);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /* Unit Structure Manipulation Functions */
1970Sstevel@tonic-gate static void meta_sp_fillextarray(mp_unit_t *mp, sp_ext_node_t *extlist);
1980Sstevel@tonic-gate static mp_unit_t *meta_sp_createunit(mdname_t *np, mdname_t *compnp,
1990Sstevel@tonic-gate     sp_ext_node_t *extlist, int numexts, sp_ext_length_t len,
2000Sstevel@tonic-gate     sp_status_t status, md_error_t *ep);
2010Sstevel@tonic-gate static mp_unit_t *meta_sp_updateunit(mdname_t *np,  mp_unit_t *old_un,
2020Sstevel@tonic-gate     sp_ext_node_t *extlist, sp_ext_length_t grow_len, int numexts,
2030Sstevel@tonic-gate     md_error_t *ep);
2040Sstevel@tonic-gate static int meta_create_sp(mdsetname_t *sp, md_sp_t *msp, sp_ext_node_t *oblist,
2050Sstevel@tonic-gate     mdcmdopts_t options, sp_ext_length_t alignment, md_error_t *ep);
2060Sstevel@tonic-gate static int meta_check_sp(mdsetname_t *sp, md_sp_t *msp, mdcmdopts_t options,
2070Sstevel@tonic-gate     int *repart_options, md_error_t *ep);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /* Reset (metaclear) Functions */
2100Sstevel@tonic-gate static int meta_sp_reset_common(mdsetname_t *sp, mdname_t *np, md_sp_t *msp,
2110Sstevel@tonic-gate     md_sp_reset_t reset_params, mdcmdopts_t options, md_error_t *ep);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /* Recovery (metarecover) Functions */
2140Sstevel@tonic-gate static void meta_sp_display_exthdr(void);
2150Sstevel@tonic-gate static void meta_sp_display_ext(sp_ext_node_t *ext);
2160Sstevel@tonic-gate static int meta_sp_checkseq(sp_ext_node_t *extlist);
2170Sstevel@tonic-gate static int meta_sp_resolve_name_conflict(mdsetname_t *, mdname_t *,
2180Sstevel@tonic-gate     mdname_t **, md_error_t *);
2190Sstevel@tonic-gate static int meta_sp_validate_wm(mdsetname_t *sp, mdname_t *np,
2200Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2210Sstevel@tonic-gate static int meta_sp_validate_unit(mdsetname_t *sp, mdname_t *compnp,
2220Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2230Sstevel@tonic-gate static int meta_sp_validate_wm_and_unit(mdsetname_t *sp, mdname_t *np,
2240Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2250Sstevel@tonic-gate static int meta_sp_validate_exts(mdname_t *np, sp_ext_node_t *wmext,
2260Sstevel@tonic-gate     sp_ext_node_t *unitext, md_error_t *ep);
2270Sstevel@tonic-gate static int meta_sp_recover_from_wm(mdsetname_t *sp, mdname_t *compnp,
2280Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2290Sstevel@tonic-gate static int meta_sp_recover_from_unit(mdsetname_t *sp, mdname_t *np,
2300Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Private Constants
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate static const int FORCE_RELOAD_CACHE = 1;
2370Sstevel@tonic-gate static const uint_t NO_FLAGS = 0;
2380Sstevel@tonic-gate static const sp_ext_offset_t NO_OFFSET = 0ULL;
2390Sstevel@tonic-gate static const uint_t NO_SEQUENCE_NUMBER = 0;
2400Sstevel@tonic-gate static const int ONE_SOFT_PARTITION = 1;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate static unsigned long sp_parent_printed[BT_BITOUL(MD_MAXUNITS)];
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate #define	TEST_SOFT_PARTITION_NAMEP NULL
2450Sstevel@tonic-gate #define	TEST_SETNAMEP NULL
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate #define	EXCLUDE_WM	(1)
2480Sstevel@tonic-gate #define	INCLUDE_WM	(0)
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate #define	SP_UNALIGNED	(0LL)
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate  * **************************************************************************
2540Sstevel@tonic-gate  *                          Debugging Functions                             *
2550Sstevel@tonic-gate  * **************************************************************************
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate /*PRINTFLIKE1*/
2590Sstevel@tonic-gate static void
2600Sstevel@tonic-gate meta_sp_debug(char *format, ...)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	static int debug;
2630Sstevel@tonic-gate 	static int debug_set = 0;
2640Sstevel@tonic-gate 	va_list ap;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if (!debug_set) {
2670Sstevel@tonic-gate 		debug = getenv(META_SP_DEBUG) ? 1 : 0;
2680Sstevel@tonic-gate 		debug_set = 1;
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	if (debug) {
2720Sstevel@tonic-gate 		va_start(ap, format);
2730Sstevel@tonic-gate 		(void) vfprintf(stderr, format, ap);
2740Sstevel@tonic-gate 		va_end(ap);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate static void
2790Sstevel@tonic-gate meta_sp_printunit(mp_unit_t *mp)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	int i;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	if (mp == NULL)
2840Sstevel@tonic-gate 		return;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	/* print the common fields we know about */
2870Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_type: %d\n", mp->c.un_type);
2880Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_size: %u\n", mp->c.un_size);
2890Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_self_id: %lu\n", MD_SID(mp));
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/* sp-specific fields */
2920Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_status: %u\n", mp->un_status);
2930Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_numexts: %u\n", mp->un_numexts);
2940Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_length: %llu\n", mp->un_length);
2950Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_dev(32): 0x%llx\n", mp->un_dev);
2960Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_dev(64): 0x%llx\n", mp->un_dev);
2970Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_key: %d\n", mp->un_key);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/* print extent information */
3000Sstevel@tonic-gate 	(void) fprintf(stderr, "\tExt#\tvoff\t\tpoff\t\tLen\n");
3010Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
3020Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%d\t%llu\t\t%llu\t\t%llu\n", i,
3030Sstevel@tonic-gate 		    mp->un_ext[i].un_voff, mp->un_ext[i].un_poff,
3040Sstevel@tonic-gate 		    mp->un_ext[i].un_len);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate /*
3090Sstevel@tonic-gate  * FUNCTION:    meta_sp_parsesize()
3100Sstevel@tonic-gate  * INPUT:       s       - the string to parse
3110Sstevel@tonic-gate  * OUTPUT:      *szp    - disk block count (0 for "all")
3120Sstevel@tonic-gate  * RETURNS:     -1 for error, 0 for success
3130Sstevel@tonic-gate  * PURPOSE:     parses the command line parameter that specifies the
3140Sstevel@tonic-gate  *              requested size of a soft partition.  The input string
3150Sstevel@tonic-gate  *              is either the literal "all" or a numeric value
3160Sstevel@tonic-gate  *              followed by a single character, b for disk blocks, k
3170Sstevel@tonic-gate  *              for kilobytes, m for megabytes, g for gigabytes, or t
3180Sstevel@tonic-gate  *              for terabytes.  p for petabytes and e for exabytes
3190Sstevel@tonic-gate  *              have been added as undocumented features for future
3200Sstevel@tonic-gate  *              expansion.  For example, 100m is 100 megabytes, while
3210Sstevel@tonic-gate  *              50g is 50 gigabytes.  All values are rounded up to the
3220Sstevel@tonic-gate  *              nearest block size.
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate int
3250Sstevel@tonic-gate meta_sp_parsesize(char *s, sp_ext_length_t *szp)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate 	if (s == NULL || szp == NULL) {
3280Sstevel@tonic-gate 		return (-1);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	/* Check for literal "all" */
3320Sstevel@tonic-gate 	if (strcasecmp(s, "all") == 0) {
3330Sstevel@tonic-gate 		*szp = 0;
3340Sstevel@tonic-gate 		return (0);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	return (meta_sp_parsesizestring(s, szp));
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate /*
3410Sstevel@tonic-gate  * FUNCTION:	meta_sp_parsesizestring()
3420Sstevel@tonic-gate  * INPUT:	s	- the string to parse
3430Sstevel@tonic-gate  * OUTPUT:	*szp	- disk block count
3440Sstevel@tonic-gate  * RETURNS:	-1 for error, 0 for success
3450Sstevel@tonic-gate  * PURPOSE:	parses a string that specifies size. The input string is a
3460Sstevel@tonic-gate  *		numeric value followed by a single character, b for disk blocks,
3470Sstevel@tonic-gate  *		k for kilobytes, m for megabytes, g for gigabytes, or t for
3480Sstevel@tonic-gate  *		terabytes.  p for petabytes and e for exabytes have been added
3490Sstevel@tonic-gate  *		as undocumented features for future expansion.  For example,
3500Sstevel@tonic-gate  *		100m is 100 megabytes, while 50g is 50 gigabytes.  All values
3510Sstevel@tonic-gate  *		are rounded up to the nearest block size.
3520Sstevel@tonic-gate  */
3530Sstevel@tonic-gate static int
3540Sstevel@tonic-gate meta_sp_parsesizestring(char *s, sp_ext_length_t *szp)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	sp_ext_length_t	len = 0;
3570Sstevel@tonic-gate 	char		len_type[2];
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if (s == NULL || szp == NULL) {
3600Sstevel@tonic-gate 		return (-1);
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * make sure block offset does not overflow 2^64 bytes.
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	if ((sscanf(s, "%llu%1[BbKkMmGgTt]", &len, len_type) != 2) ||
3670Sstevel@tonic-gate 	    (len == 0LL) ||
3680Sstevel@tonic-gate 	    (len > (1LL << (64 - DEV_BSHIFT))))
3690Sstevel@tonic-gate 		return (-1);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	switch (len_type[0]) {
3720Sstevel@tonic-gate 	case 'B':
3730Sstevel@tonic-gate 	case 'b':
3740Sstevel@tonic-gate 		len = lbtodb(roundup(len * DEV_BSIZE, DEV_BSIZE));
3750Sstevel@tonic-gate 		break;
3760Sstevel@tonic-gate 	case 'K':
3770Sstevel@tonic-gate 	case 'k':
3780Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL, DEV_BSIZE));
3790Sstevel@tonic-gate 		break;
3800Sstevel@tonic-gate 	case 'M':
3810Sstevel@tonic-gate 	case 'm':
3820Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL, DEV_BSIZE));
3830Sstevel@tonic-gate 		break;
3840Sstevel@tonic-gate 	case 'g':
3850Sstevel@tonic-gate 	case 'G':
3860Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL*1024ULL, DEV_BSIZE));
3870Sstevel@tonic-gate 		break;
3880Sstevel@tonic-gate 	case 't':
3890Sstevel@tonic-gate 	case 'T':
3900Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL*1024ULL*1024ULL,
3910Sstevel@tonic-gate 		    DEV_BSIZE));
3920Sstevel@tonic-gate 		break;
3930Sstevel@tonic-gate 	case 'p':
3940Sstevel@tonic-gate 	case 'P':
3950Sstevel@tonic-gate 		len = lbtodb(roundup(
3960Sstevel@tonic-gate 		    len * 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL,
3970Sstevel@tonic-gate 		    DEV_BSIZE));
3980Sstevel@tonic-gate 		break;
3990Sstevel@tonic-gate 	case 'e':
4000Sstevel@tonic-gate 	case 'E':
4010Sstevel@tonic-gate 		len = lbtodb(roundup(
4020Sstevel@tonic-gate 		    len * 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL,
4030Sstevel@tonic-gate 		    DEV_BSIZE));
4040Sstevel@tonic-gate 		break;
4050Sstevel@tonic-gate 	default:
4060Sstevel@tonic-gate 		/* error */
4070Sstevel@tonic-gate 		return (-1);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	*szp = len;
4110Sstevel@tonic-gate 	return (0);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate  * FUNCTION:	meta_sp_setgeom()
4160Sstevel@tonic-gate  * INPUT:	np      - the underlying device to setup geometry for
4170Sstevel@tonic-gate  *		compnp	- the underlying device to setup geometry for
4180Sstevel@tonic-gate  *		mp	- the unit structure to set the geometry for
4190Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4200Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 otherwise
4210Sstevel@tonic-gate  * PURPOSE:	establishes geometry information for a device
4220Sstevel@tonic-gate  */
4230Sstevel@tonic-gate static int
4240Sstevel@tonic-gate meta_sp_setgeom(
4250Sstevel@tonic-gate 	mdname_t	*np,
4260Sstevel@tonic-gate 	mdname_t	*compnp,
4270Sstevel@tonic-gate 	mp_unit_t	*mp,
4280Sstevel@tonic-gate 	md_error_t	*ep
4290Sstevel@tonic-gate )
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	mdgeom_t	*geomp;
4320Sstevel@tonic-gate 	uint_t		round_cyl = 0;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if ((geomp = metagetgeom(compnp, ep)) == NULL)
4350Sstevel@tonic-gate 		return (-1);
4360Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)mp, np, geomp, geomp->write_reinstruct,
4370Sstevel@tonic-gate 	    geomp->read_reinstruct, round_cyl, ep) != 0)
4380Sstevel@tonic-gate 		return (-1);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	return (0);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate /*
4440Sstevel@tonic-gate  * FUNCTION:	meta_sp_setstatus()
4450Sstevel@tonic-gate  * INPUT:	sp	- the set name for the devices to set the status on
4460Sstevel@tonic-gate  *		minors	- an array of minor numbers of devices to set status on
4470Sstevel@tonic-gate  *		num_units - number of entries in the array
4480Sstevel@tonic-gate  *		status	- status value to set all units to
4490Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4500Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
4510Sstevel@tonic-gate  * PURPOSE:	sets the status of one or more soft partitions to the
4520Sstevel@tonic-gate  *		requested value
4530Sstevel@tonic-gate  */
4540Sstevel@tonic-gate int
4550Sstevel@tonic-gate meta_sp_setstatus(
4560Sstevel@tonic-gate 	mdsetname_t	*sp,
4570Sstevel@tonic-gate 	minor_t		*minors,
4580Sstevel@tonic-gate 	int		num_units,
4590Sstevel@tonic-gate 	sp_status_t	status,
4600Sstevel@tonic-gate 	md_error_t	*ep
4610Sstevel@tonic-gate )
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate 	md_sp_statusset_t	status_params;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	assert(minors != NULL);
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	/* update status of all soft partitions to the status passed in */
4680Sstevel@tonic-gate 	(void) memset(&status_params, 0, sizeof (status_params));
4690Sstevel@tonic-gate 	status_params.num_units = num_units;
4700Sstevel@tonic-gate 	status_params.new_status = status;
4710Sstevel@tonic-gate 	status_params.size = num_units * sizeof (minor_t);
4720Sstevel@tonic-gate 	status_params.minors = (uintptr_t)minors;
4730Sstevel@tonic-gate 	MD_SETDRIVERNAME(&status_params, MD_SP, sp->setno);
4740Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPSTATUS, &status_params, &status_params.mde,
4750Sstevel@tonic-gate 	    NULL) != 0) {
4760Sstevel@tonic-gate 		(void) mdstealerror(ep, &status_params.mde);
4770Sstevel@tonic-gate 		return (-1);
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 	return (0);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate  * FUNCTION:	meta_get_sp_names()
4840Sstevel@tonic-gate  * INPUT:	sp	- the set name to get soft partitions from
4850Sstevel@tonic-gate  *		options	- options from the command line
4860Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all soft partition names
4870Sstevel@tonic-gate  *		ep	- return error pointer
4880Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
4890Sstevel@tonic-gate  * PURPOSE:	returns a list of all soft partitions in the metadb
4900Sstevel@tonic-gate  *		for all devices in the specified set
4910Sstevel@tonic-gate  */
4920Sstevel@tonic-gate int
4930Sstevel@tonic-gate meta_get_sp_names(
4940Sstevel@tonic-gate 	mdsetname_t	*sp,
4950Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
4960Sstevel@tonic-gate 	int		options,
4970Sstevel@tonic-gate 	md_error_t	*ep
4980Sstevel@tonic-gate )
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	return (meta_get_names(MD_SP, sp, nlpp, options, ep));
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate /*
5040Sstevel@tonic-gate  * FUNCTION:	meta_get_by_component()
5050Sstevel@tonic-gate  * INPUT:	sp	- the set name to get soft partitions from
5060Sstevel@tonic-gate  *		compnp	- the name of the device containing the soft
5070Sstevel@tonic-gate  *			  partitions that will be returned
5080Sstevel@tonic-gate  *		force	- 0 - reads cached namelist if available,
5090Sstevel@tonic-gate  *			  1 - reloads cached namelist, frees old namelist
5100Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all soft partition names
5110Sstevel@tonic-gate  *		ep	- return error pointer
5120Sstevel@tonic-gate  * RETURNS:	int	- -1 error, otherwise the number of soft partitions
5130Sstevel@tonic-gate  *			  found on the component (0 = none found).
5140Sstevel@tonic-gate  * PURPOSE:	returns a list of all soft partitions on a given device
5150Sstevel@tonic-gate  *		from the metadb information
5160Sstevel@tonic-gate  */
5170Sstevel@tonic-gate static int
5180Sstevel@tonic-gate meta_sp_get_by_component(
5190Sstevel@tonic-gate 	mdsetname_t	*sp,
5200Sstevel@tonic-gate 	mdname_t	*compnp,
5210Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
5220Sstevel@tonic-gate 	int		force,
5230Sstevel@tonic-gate 	md_error_t	*ep
5240Sstevel@tonic-gate )
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	static mdnamelist_t	*cached_list = NULL;	/* cached namelist */
5270Sstevel@tonic-gate 	static int		cached_count = 0;	/* cached count */
5280Sstevel@tonic-gate 	mdnamelist_t		*spnlp = NULL;		/* all sp names */
5290Sstevel@tonic-gate 	mdnamelist_t		*namep;			/* list iterator */
5300Sstevel@tonic-gate 	mdnamelist_t		**tailpp = nlpp;	/* namelist tail */
5310Sstevel@tonic-gate 	mdnamelist_t		**cachetailpp;		/* cache tail */
5320Sstevel@tonic-gate 	md_sp_t			*msp;			/* unit structure */
5330Sstevel@tonic-gate 	int			count = 0;		/* count of sp's */
5340Sstevel@tonic-gate 	int			err;
5350Sstevel@tonic-gate 	mdname_t		*curnp;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	if ((cached_list != NULL) && (!force)) {
5380Sstevel@tonic-gate 		/* return a copy of the cached list */
5390Sstevel@tonic-gate 		for (namep = cached_list; namep != NULL; namep = namep->next)
5400Sstevel@tonic-gate 			tailpp = meta_namelist_append_wrapper(tailpp,
5410Sstevel@tonic-gate 			    namep->namep);
5420Sstevel@tonic-gate 		return (cached_count);
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/* free the cache and reset values to zeros to prepare for a new list */
5460Sstevel@tonic-gate 	metafreenamelist(cached_list);
5470Sstevel@tonic-gate 	cached_count = 0;
5480Sstevel@tonic-gate 	cached_list = NULL;
5490Sstevel@tonic-gate 	cachetailpp = &cached_list;
5500Sstevel@tonic-gate 	*nlpp = NULL;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	/* get all the softpartitions first of all */
5530Sstevel@tonic-gate 	if (meta_get_sp_names(sp, &spnlp, 0, ep) < 0)
5540Sstevel@tonic-gate 		return (-1);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/*
5570Sstevel@tonic-gate 	 * Now for each sp, see if it resides on the component we
5580Sstevel@tonic-gate 	 * are interested in, if so then add it to our list
5590Sstevel@tonic-gate 	 */
5600Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
5610Sstevel@tonic-gate 		curnp = namep->namep;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		/* get the unit structure */
5640Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
5650Sstevel@tonic-gate 			continue;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		/*
5680Sstevel@tonic-gate 		 * If the current soft partition is not on the same
5690Sstevel@tonic-gate 		 * component, continue the search.  If it is on the same
5700Sstevel@tonic-gate 		 * component, add it to our namelist.
5710Sstevel@tonic-gate 		 */
5720Sstevel@tonic-gate 		err = meta_check_samedrive(compnp, msp->compnamep, ep);
5730Sstevel@tonic-gate 		if (err <= 0) {
5740Sstevel@tonic-gate 			/* not on the same device, check the next one */
5750Sstevel@tonic-gate 			continue;
5760Sstevel@tonic-gate 		}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		/* it's on the same drive */
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 		/*
5810Sstevel@tonic-gate 		 * Check for overlapping partitions if the component is not
5820Sstevel@tonic-gate 		 * a metadevice.
5830Sstevel@tonic-gate 		 */
5840Sstevel@tonic-gate 		if (!metaismeta(msp->compnamep)) {
5850Sstevel@tonic-gate 			/*
5860Sstevel@tonic-gate 			 * if they're on the same drive, neither
5870Sstevel@tonic-gate 			 * should be a metadevice if one isn't
5880Sstevel@tonic-gate 			 */
5890Sstevel@tonic-gate 			assert(!metaismeta(compnp));
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 			if (meta_check_overlap(msp->compnamep->cname,
5920Sstevel@tonic-gate 			    compnp, 0, -1, msp->compnamep, 0, -1, ep) == 0)
5930Sstevel@tonic-gate 				continue;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 			/* in this case it's not an error for them to overlap */
5960Sstevel@tonic-gate 			mdclrerror(ep);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 		/* Component is on the same device, add to the used list */
6000Sstevel@tonic-gate 		tailpp = meta_namelist_append_wrapper(tailpp, curnp);
6010Sstevel@tonic-gate 		cachetailpp = meta_namelist_append_wrapper(cachetailpp,
6020Sstevel@tonic-gate 		    curnp);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		++count;
6050Sstevel@tonic-gate 		++cached_count;
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	assert(count == cached_count);
6090Sstevel@tonic-gate 	return (count);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate out:
6120Sstevel@tonic-gate 	metafreenamelist(*nlpp);
6130Sstevel@tonic-gate 	*nlpp = NULL;
6140Sstevel@tonic-gate 	return (-1);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /*
6180Sstevel@tonic-gate  * FUNCTION:    meta_sp_get_default_alignment()
6190Sstevel@tonic-gate  * INPUT:       sp      - the pertinent set name
6200Sstevel@tonic-gate  *              compnp  - the name of the underlying component
6210Sstevel@tonic-gate  * OUTPUT:      ep      - return error pointer
6220Sstevel@tonic-gate  * RETURNS:     sp_ext_length_t =0: no default alignment
6230Sstevel@tonic-gate  *                              >0: default alignment
6240Sstevel@tonic-gate  * PURPOSE:     returns the default alignment for soft partitions to
6250Sstevel@tonic-gate  *              be built on top of the specified component or
6260Sstevel@tonic-gate  *              metadevice
6270Sstevel@tonic-gate  */
6280Sstevel@tonic-gate static sp_ext_length_t
6290Sstevel@tonic-gate meta_sp_get_default_alignment(
6300Sstevel@tonic-gate 	mdsetname_t	*sp,
6310Sstevel@tonic-gate 	mdname_t	*compnp,
6320Sstevel@tonic-gate 	md_error_t	*ep
6330Sstevel@tonic-gate )
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate 	sp_ext_length_t	a = SP_UNALIGNED;
6360Sstevel@tonic-gate 	char		*mname;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	assert(compnp != NULL);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	/*
6410Sstevel@tonic-gate 	 * We treat raw devices as opaque, and assume nothing about
6420Sstevel@tonic-gate 	 * their alignment requirements.
6430Sstevel@tonic-gate 	 */
6440Sstevel@tonic-gate 	if (!metaismeta(compnp))
6450Sstevel@tonic-gate 		return (SP_UNALIGNED);
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	/*
6480Sstevel@tonic-gate 	 * We already know it's a metadevice from the previous test;
6490Sstevel@tonic-gate 	 * metagetmiscname() will tell us which metadevice type we
6500Sstevel@tonic-gate 	 * have
6510Sstevel@tonic-gate 	 */
6520Sstevel@tonic-gate 	mname = metagetmiscname(compnp, ep);
6530Sstevel@tonic-gate 	if (mname == NULL)
6540Sstevel@tonic-gate 		goto out;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/*
6570Sstevel@tonic-gate 	 * For a mirror, we want to deal with the stripe that is the
6580Sstevel@tonic-gate 	 * primary side.  If it happens to be asymmetrically
6590Sstevel@tonic-gate 	 * configured, there is no simple way to fake a universal
6600Sstevel@tonic-gate 	 * alignment.  There's a chance that the least common
6610Sstevel@tonic-gate 	 * denominator of the set of interlaces from all stripes of
6620Sstevel@tonic-gate 	 * all submirrors would do it, but nobody that really cared
6630Sstevel@tonic-gate 	 * that much about this issue would create an asymmetric
6640Sstevel@tonic-gate 	 * config to start with.
6650Sstevel@tonic-gate 	 *
6660Sstevel@tonic-gate 	 * If the component underlying the soft partition is a mirror,
6670Sstevel@tonic-gate 	 * then at the exit of this loop, compnp will have been
6680Sstevel@tonic-gate 	 * updated to describe the first active submirror.
6690Sstevel@tonic-gate 	 */
6700Sstevel@tonic-gate 	if (strcmp(mname, MD_MIRROR) == 0) {
6710Sstevel@tonic-gate 		md_mirror_t	*mp;
6720Sstevel@tonic-gate 		int		smi;
6730Sstevel@tonic-gate 		md_submirror_t	*smp;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 		mp = meta_get_mirror(sp, compnp, ep);
6760Sstevel@tonic-gate 		if (mp == NULL)
6770Sstevel@tonic-gate 			goto out;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 		for (smi = 0; smi < NMIRROR; smi++) {
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 			smp = &mp->submirrors[smi];
6820Sstevel@tonic-gate 			if (smp->state == SMS_UNUSED)
6830Sstevel@tonic-gate 				continue;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 			compnp = smp->submirnamep;
6860Sstevel@tonic-gate 			assert(compnp != NULL);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 			mname = metagetmiscname(compnp, ep);
6890Sstevel@tonic-gate 			if (mname == NULL)
6900Sstevel@tonic-gate 				goto out;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 			break;
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 		if (smi == NMIRROR)
6960Sstevel@tonic-gate 			goto out;
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	/*
7000Sstevel@tonic-gate 	 * Handle stripes and submirrors identically; just return the
7010Sstevel@tonic-gate 	 * interlace of the first row.
7020Sstevel@tonic-gate 	 */
7030Sstevel@tonic-gate 	if (strcmp(mname, MD_STRIPE) == 0) {
7040Sstevel@tonic-gate 		md_stripe_t	*stp;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		stp = meta_get_stripe(sp, compnp, ep);
7070Sstevel@tonic-gate 		if (stp == NULL)
7080Sstevel@tonic-gate 			goto out;
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 		a = stp->rows.rows_val[0].interlace;
7110Sstevel@tonic-gate 		goto out;
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	/*
7150Sstevel@tonic-gate 	 * Raid is even more straightforward; the interlace applies to
7160Sstevel@tonic-gate 	 * the entire device.
7170Sstevel@tonic-gate 	 */
7180Sstevel@tonic-gate 	if (strcmp(mname, MD_RAID) == 0) {
7190Sstevel@tonic-gate 		md_raid_t	*rp;
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		rp = meta_get_raid(sp, compnp, ep);
7220Sstevel@tonic-gate 		if (rp == NULL)
7230Sstevel@tonic-gate 			goto out;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		a = rp->interlace;
7260Sstevel@tonic-gate 		goto out;
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * If we have arrived here with the alignment still not set,
7310Sstevel@tonic-gate 	 * then we expect the error to have been set by one of the
7320Sstevel@tonic-gate 	 * routines we called.  If neither is the case, something has
7330Sstevel@tonic-gate 	 * really gone wrong above.  (Probably the submirror walk
7340Sstevel@tonic-gate 	 * failed to produce a valid submirror, but that would be
7350Sstevel@tonic-gate 	 * really bad...)
7360Sstevel@tonic-gate 	 */
7370Sstevel@tonic-gate out:
7380Sstevel@tonic-gate 	meta_sp_debug("meta_sp_get_default_alignment: miscname %s, "
7390Sstevel@tonic-gate 	    "alignment %lld\n", (mname == NULL) ? "NULL" : mname, a);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG) && !mdisok(ep)) {
7420Sstevel@tonic-gate 		mde_perror(ep, NULL);
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	assert((a > 0) || (!mdisok(ep)));
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	return (a);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate /*
7530Sstevel@tonic-gate  * FUNCTION:	meta_check_insp()
7540Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to check
7550Sstevel@tonic-gate  *		np	- the name of the device to check
7560Sstevel@tonic-gate  *		slblk	- the starting offset of the device to check
7570Sstevel@tonic-gate  *		nblks	- the number of blocks in the device to check
7580Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
7590Sstevel@tonic-gate  * RETURNS:	int	-  0 - device contains soft partitions
7600Sstevel@tonic-gate  *			  -1 - device does not contain soft partitions
7610Sstevel@tonic-gate  * PURPOSE:	determines whether a device contains any soft partitions
7620Sstevel@tonic-gate  */
7630Sstevel@tonic-gate /* ARGSUSED */
7640Sstevel@tonic-gate int
7650Sstevel@tonic-gate meta_check_insp(
7660Sstevel@tonic-gate 	mdsetname_t	*sp,
7670Sstevel@tonic-gate 	mdname_t	*np,
7680Sstevel@tonic-gate 	diskaddr_t	slblk,
7690Sstevel@tonic-gate 	diskaddr_t	nblks,
7700Sstevel@tonic-gate 	md_error_t	*ep
7710Sstevel@tonic-gate )
7720Sstevel@tonic-gate {
7730Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;	/* soft partition name list */
7740Sstevel@tonic-gate 	int		count;
7750Sstevel@tonic-gate 	int		rval;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	/* check set pointer */
7780Sstevel@tonic-gate 	assert(sp != NULL);
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	/* find all soft partitions on the component */
7810Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, np, &spnlp, 0, ep);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	if (count == -1) {
7840Sstevel@tonic-gate 		rval = -1;
7850Sstevel@tonic-gate 	} else if (count > 0) {
7860Sstevel@tonic-gate 		rval = mduseerror(ep, MDE_ALREADY, np->dev,
7870Sstevel@tonic-gate 		    spnlp->namep->cname, np->cname);
7880Sstevel@tonic-gate 	} else {
7890Sstevel@tonic-gate 		rval = 0;
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	metafreenamelist(spnlp);
7930Sstevel@tonic-gate 	return (rval);
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate /*
7970Sstevel@tonic-gate  * **************************************************************************
7980Sstevel@tonic-gate  *                    Extent List Manipulation Functions                    *
7990Sstevel@tonic-gate  * **************************************************************************
8000Sstevel@tonic-gate  */
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate /*
8030Sstevel@tonic-gate  * FUNCTION:	meta_sp_cmp_by_nameseq()
8040Sstevel@tonic-gate  * INPUT:	e1	- first node to compare
8050Sstevel@tonic-gate  *		e2	- second node to compare
8060Sstevel@tonic-gate  * OUTPUT:	none
8070Sstevel@tonic-gate  * RETURNS:	int	- =0 - nodes are equal
8080Sstevel@tonic-gate  *			  <0 - e1 should go before e2
8090Sstevel@tonic-gate  *			  >0 - e1 should go after e2
8100Sstevel@tonic-gate  * PURPOSE:	used for sorted list inserts to build a list sorted by
8110Sstevel@tonic-gate  *		name first and sequence number second.
8120Sstevel@tonic-gate  */
8130Sstevel@tonic-gate static int
8140Sstevel@tonic-gate meta_sp_cmp_by_nameseq(sp_ext_node_t *e1, sp_ext_node_t *e2)
8150Sstevel@tonic-gate {
8160Sstevel@tonic-gate 	int rval;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	if (e1->ext_namep == NULL)
8190Sstevel@tonic-gate 		return (1);
8200Sstevel@tonic-gate 	if (e2->ext_namep == NULL)
8210Sstevel@tonic-gate 		return (-1);
8220Sstevel@tonic-gate 	if ((rval = strcmp(e1->ext_namep->cname, e2->ext_namep->cname)) != 0)
8230Sstevel@tonic-gate 		return (rval);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	/* the names are equal, compare sequence numbers */
8260Sstevel@tonic-gate 	if (e1->ext_seq > e2->ext_seq)
8270Sstevel@tonic-gate 		return (1);
8280Sstevel@tonic-gate 	if (e1->ext_seq < e2->ext_seq)
8290Sstevel@tonic-gate 		return (-1);
8300Sstevel@tonic-gate 	/* sequence numbers are also equal */
8310Sstevel@tonic-gate 	return (0);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  * FUNCTION:	meta_sp_cmp_by_offset()
8360Sstevel@tonic-gate  * INPUT:	e1	- first node to compare
8370Sstevel@tonic-gate  *		e2	- second node to compare
8380Sstevel@tonic-gate  * OUTPUT:	none
8390Sstevel@tonic-gate  * RETURNS:	int	- =0 - nodes are equal
8400Sstevel@tonic-gate  *			  <0 - e1 should go before e2
8410Sstevel@tonic-gate  *			  >0 - e1 should go after e2
8420Sstevel@tonic-gate  * PURPOSE:	used for sorted list inserts to build a list sorted by offset
8430Sstevel@tonic-gate  */
8440Sstevel@tonic-gate static int
8450Sstevel@tonic-gate meta_sp_cmp_by_offset(sp_ext_node_t *e1, sp_ext_node_t *e2)
8460Sstevel@tonic-gate {
8470Sstevel@tonic-gate 	if (e1->ext_offset > e2->ext_offset)
8480Sstevel@tonic-gate 		return (1);
8490Sstevel@tonic-gate 	if (e1->ext_offset < e2->ext_offset)
8500Sstevel@tonic-gate 		return (-1);
8510Sstevel@tonic-gate 	/* offsets are equal */
8520Sstevel@tonic-gate 	return (0);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate /*
8560Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_insert()
8570Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
8580Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
8590Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
8600Sstevel@tonic-gate  *		offset	- the physical offset of this extent in sectors
8610Sstevel@tonic-gate  *		length	- the length of this extent in sectors
8620Sstevel@tonic-gate  *		type	- the type of the extent being inserted
8630Sstevel@tonic-gate  *		seq	- the sequence number of the extent being inserted
8640Sstevel@tonic-gate  *		flags	- extent flags (eg. whether it needs to be updated)
8650Sstevel@tonic-gate  *		compare	- the compare function to use
8660Sstevel@tonic-gate  * OUTPUT:	head	- points to the new head if a node was inserted
8670Sstevel@tonic-gate  *			  at the beginning
8680Sstevel@tonic-gate  * RETURNS:	void
8690Sstevel@tonic-gate  * PURPOSE:	inserts an extent node into a sorted doubly linked list.
8700Sstevel@tonic-gate  *		The sort order is determined by the compare function.
8710Sstevel@tonic-gate  *		Memory is allocated for the node in this function and it
8720Sstevel@tonic-gate  *		is up to the caller to free it, possibly using
8730Sstevel@tonic-gate  *		meta_sp_list_free().  If a node is inserted at the
8740Sstevel@tonic-gate  *		beginning of the list, the head pointer is updated to
8750Sstevel@tonic-gate  *		point to the new first node.
8760Sstevel@tonic-gate  */
8770Sstevel@tonic-gate static void
8780Sstevel@tonic-gate meta_sp_list_insert(
8790Sstevel@tonic-gate 	mdsetname_t	*sp,
8800Sstevel@tonic-gate 	mdname_t	*np,
8810Sstevel@tonic-gate 	sp_ext_node_t	**head,
8820Sstevel@tonic-gate 	sp_ext_offset_t	offset,
8830Sstevel@tonic-gate 	sp_ext_length_t	length,
8840Sstevel@tonic-gate 	sp_ext_type_t	type,
8850Sstevel@tonic-gate 	uint_t		seq,
8860Sstevel@tonic-gate 	uint_t		flags,
8870Sstevel@tonic-gate 	ext_cmpfunc_t	compare
8880Sstevel@tonic-gate )
8890Sstevel@tonic-gate {
8900Sstevel@tonic-gate 	sp_ext_node_t	*newext;
8910Sstevel@tonic-gate 	sp_ext_node_t	*curext;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	assert(head != NULL);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	/* Don't bother adding zero length nodes */
8960Sstevel@tonic-gate 	if (length == 0ULL)
8970Sstevel@tonic-gate 		return;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	/* allocate and fill in new ext_node */
9000Sstevel@tonic-gate 	newext = Zalloc(sizeof (sp_ext_node_t));
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	newext->ext_offset = offset;
9030Sstevel@tonic-gate 	newext->ext_length = length;
9040Sstevel@tonic-gate 	newext->ext_flags = flags;
9050Sstevel@tonic-gate 	newext->ext_type = type;
9060Sstevel@tonic-gate 	newext->ext_seq = seq;
9070Sstevel@tonic-gate 	newext->ext_setp = sp;
9080Sstevel@tonic-gate 	newext->ext_namep = np;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	/* first node in the list */
9110Sstevel@tonic-gate 	if (*head == NULL) {
9120Sstevel@tonic-gate 		newext->ext_next = newext->ext_prev = NULL;
9130Sstevel@tonic-gate 		*head = newext;
9140Sstevel@tonic-gate 	} else if ((*compare)(*head, newext) >= 0) {
9150Sstevel@tonic-gate 		/* the first node has a bigger offset, so insert before it */
9160Sstevel@tonic-gate 		assert((*head)->ext_prev == NULL);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 		newext->ext_prev = NULL;
9190Sstevel@tonic-gate 		newext->ext_next = *head;
9200Sstevel@tonic-gate 		(*head)->ext_prev = newext;
9210Sstevel@tonic-gate 		*head = newext;
9220Sstevel@tonic-gate 	} else {
9230Sstevel@tonic-gate 		/*
9240Sstevel@tonic-gate 		 * find the next node whose offset is greater than
9250Sstevel@tonic-gate 		 * the one we want to insert, or the end of the list.
9260Sstevel@tonic-gate 		 */
9270Sstevel@tonic-gate 		for (curext = *head;
9280Sstevel@tonic-gate 		    (curext->ext_next != NULL) &&
9290Sstevel@tonic-gate 		    ((*compare)(curext->ext_next, newext) < 0);
9300Sstevel@tonic-gate 		    (curext = curext->ext_next))
9310Sstevel@tonic-gate 			;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		/* link the new node in after the current node */
9340Sstevel@tonic-gate 		newext->ext_next = curext->ext_next;
9350Sstevel@tonic-gate 		newext->ext_prev = curext;
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 		if (curext->ext_next != NULL)
9380Sstevel@tonic-gate 			curext->ext_next->ext_prev = newext;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		curext->ext_next = newext;
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate /*
9450Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_free()
9460Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
9470Sstevel@tonic-gate  * OUTPUT:	head	- points to NULL on return
9480Sstevel@tonic-gate  * RETURNS:	void
9490Sstevel@tonic-gate  * PURPOSE:	walks a double linked extent list and frees each node
9500Sstevel@tonic-gate  */
9510Sstevel@tonic-gate static void
9520Sstevel@tonic-gate meta_sp_list_free(sp_ext_node_t **head)
9530Sstevel@tonic-gate {
9540Sstevel@tonic-gate 	sp_ext_node_t	*ext;
9550Sstevel@tonic-gate 	sp_ext_node_t	*next;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	assert(head != NULL);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	ext = *head;
9600Sstevel@tonic-gate 	while (ext) {
9610Sstevel@tonic-gate 		next = ext->ext_next;
9620Sstevel@tonic-gate 		Free(ext);
9630Sstevel@tonic-gate 		ext = next;
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 	*head = NULL;
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_remove()
9700Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
9710Sstevel@tonic-gate  *		ext	- the extent to remove, must be a member of the list
9720Sstevel@tonic-gate  * OUTPUT:	head	- points to the new head of the list
9730Sstevel@tonic-gate  * RETURNS:	void
9740Sstevel@tonic-gate  * PURPOSE:	unlinks the node specified by ext from the list and
9750Sstevel@tonic-gate  *		frees it, possibly moving the head pointer forward if
9760Sstevel@tonic-gate  *		the head is the node being removed.
9770Sstevel@tonic-gate  */
9780Sstevel@tonic-gate static void
9790Sstevel@tonic-gate meta_sp_list_remove(sp_ext_node_t **head, sp_ext_node_t *ext)
9800Sstevel@tonic-gate {
9810Sstevel@tonic-gate 	assert(head != NULL);
9820Sstevel@tonic-gate 	assert(*head != NULL);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	if (*head == ext)
9850Sstevel@tonic-gate 		*head = ext->ext_next;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	if (ext->ext_prev != NULL)
9880Sstevel@tonic-gate 		ext->ext_prev->ext_next = ext->ext_next;
9890Sstevel@tonic-gate 	if (ext->ext_next != NULL)
9900Sstevel@tonic-gate 		ext->ext_next->ext_prev = ext->ext_prev;
9910Sstevel@tonic-gate 	Free(ext);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_size()
9960Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
9970Sstevel@tonic-gate  *		exttype	- the type of the extents to sum
9980Sstevel@tonic-gate  *		exclude_wm - subtract space for extent headers from total
9990Sstevel@tonic-gate  * OUTPUT:	none
10000Sstevel@tonic-gate  * RETURNS:	sp_ext_length_t	- the sum of all of the lengths
10010Sstevel@tonic-gate  * PURPOSE:	sums the lengths of all extents in the list matching the
10020Sstevel@tonic-gate  *		specified type.  This could be used for computing the
10030Sstevel@tonic-gate  *		amount of free or used space, for example.
10040Sstevel@tonic-gate  */
10050Sstevel@tonic-gate static sp_ext_length_t
10060Sstevel@tonic-gate meta_sp_list_size(sp_ext_node_t *head, sp_ext_type_t exttype, int exclude_wm)
10070Sstevel@tonic-gate {
10080Sstevel@tonic-gate 	sp_ext_node_t	*ext;
10090Sstevel@tonic-gate 	sp_ext_length_t	size = 0LL;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next)
10120Sstevel@tonic-gate 		if (ext->ext_type == exttype)
10130Sstevel@tonic-gate 			size += ext->ext_length -
10140Sstevel@tonic-gate 			    ((exclude_wm) ? MD_SP_WMSIZE : 0);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	return (size);
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate /*
10200Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_find()
10210Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
10220Sstevel@tonic-gate  *		offset	- the offset contained by the node to find
10230Sstevel@tonic-gate  * OUTPUT:	none
10240Sstevel@tonic-gate  * RETURNS:	sp_ext_node_t *	- the node containing the requested offset
10250Sstevel@tonic-gate  *				  or NULL if no such nodes were found.
10260Sstevel@tonic-gate  * PURPOSE:	finds a node in a list containing the requested offset
10270Sstevel@tonic-gate  *		(inclusive).  If multiple nodes contain this offset then
10280Sstevel@tonic-gate  *		only the first will be returned, though typically these
10290Sstevel@tonic-gate  *		lists are managed with non-overlapping nodes.
10300Sstevel@tonic-gate  *
10310Sstevel@tonic-gate  *		*The list MUST be sorted by offset for this function to work.*
10320Sstevel@tonic-gate  */
10330Sstevel@tonic-gate static sp_ext_node_t *
10340Sstevel@tonic-gate meta_sp_list_find(
10350Sstevel@tonic-gate 	sp_ext_node_t	*head,
10360Sstevel@tonic-gate 	sp_ext_offset_t	offset
10370Sstevel@tonic-gate )
10380Sstevel@tonic-gate {
10390Sstevel@tonic-gate 	sp_ext_node_t	*ext;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next) {
10420Sstevel@tonic-gate 		/* check if the offset lies within this extent */
10430Sstevel@tonic-gate 		if ((offset >= ext->ext_offset) &&
10440Sstevel@tonic-gate 		    (offset < ext->ext_offset + ext->ext_length)) {
10450Sstevel@tonic-gate 			/*
10460Sstevel@tonic-gate 			 * the requested extent should always be a
10470Sstevel@tonic-gate 			 * subset of an extent in the list.
10480Sstevel@tonic-gate 			 */
10490Sstevel@tonic-gate 			return (ext);
10500Sstevel@tonic-gate 		}
10510Sstevel@tonic-gate 	}
10520Sstevel@tonic-gate 	return (NULL);
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate /*
10560Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_freefill()
10570Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
10580Sstevel@tonic-gate  *		size	- the size of the volume this extent list is
10590Sstevel@tonic-gate  *			  representing
10600Sstevel@tonic-gate  * OUTPUT:	head	- the new head of the list
10610Sstevel@tonic-gate  * RETURNS:	void
10620Sstevel@tonic-gate  * PURPOSE:	finds gaps in the extent list and fills them with a free
10630Sstevel@tonic-gate  *		node.  If there is a gap at the beginning the head
10640Sstevel@tonic-gate  *		pointer will be changed to point to the new free node.
10650Sstevel@tonic-gate  *		If there is free space at the end, the last free extent
10660Sstevel@tonic-gate  *		will extend all the way out to the size specified.
10670Sstevel@tonic-gate  *
10680Sstevel@tonic-gate  *		*The list MUST be sorted by offset for this function to work.*
10690Sstevel@tonic-gate  */
10700Sstevel@tonic-gate static void
10710Sstevel@tonic-gate meta_sp_list_freefill(
10720Sstevel@tonic-gate 	sp_ext_node_t	**head,
10730Sstevel@tonic-gate 	sp_ext_length_t	size
10740Sstevel@tonic-gate )
10750Sstevel@tonic-gate {
10760Sstevel@tonic-gate 	sp_ext_node_t	*ext;
10770Sstevel@tonic-gate 	sp_ext_offset_t	curoff = 0LL;
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	for (ext = *head; ext != NULL; ext = ext->ext_next) {
10800Sstevel@tonic-gate 		if (curoff < ext->ext_offset)
10810Sstevel@tonic-gate 			meta_sp_list_insert(NULL, NULL, head,
10820Sstevel@tonic-gate 			    curoff, ext->ext_offset - curoff,
10830Sstevel@tonic-gate 			    EXTTYP_FREE, 0, 0, meta_sp_cmp_by_offset);
10840Sstevel@tonic-gate 		curoff = ext->ext_offset + ext->ext_length;
10850Sstevel@tonic-gate 	}
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	/* pad inverse list out to the end */
10880Sstevel@tonic-gate 	if (curoff < size)
10890Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, curoff, size - curoff,
10900Sstevel@tonic-gate 		    EXTTYP_FREE, 0, 0, meta_sp_cmp_by_offset);
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
10930Sstevel@tonic-gate 		meta_sp_debug("meta_sp_list_freefill: Extent list with "
10940Sstevel@tonic-gate 		    "holes freefilled:\n");
10950Sstevel@tonic-gate 		meta_sp_list_dump(*head);
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate /*
11000Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_dump()
11010Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
11020Sstevel@tonic-gate  * OUTPUT:	none
11030Sstevel@tonic-gate  * RETURNS:	void
11040Sstevel@tonic-gate  * PURPOSE:	dumps the entire extent list to stdout for easy debugging
11050Sstevel@tonic-gate  */
11060Sstevel@tonic-gate static void
11070Sstevel@tonic-gate meta_sp_list_dump(sp_ext_node_t *head)
11080Sstevel@tonic-gate {
11090Sstevel@tonic-gate 	sp_ext_node_t	*ext;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	meta_sp_debug("meta_sp_list_dump: dumping extent list:\n");
11120Sstevel@tonic-gate 	meta_sp_debug("%5s %10s %5s %7s %10s %10s %5s %10s %10s\n", "Name",
11130Sstevel@tonic-gate 	    "Addr", "Seq#", "Type", "Offset", "Length", "Flags", "Prev",
11140Sstevel@tonic-gate 	    "Next");
11150Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next) {
11160Sstevel@tonic-gate 		if (ext->ext_namep != NULL)
11170Sstevel@tonic-gate 			meta_sp_debug("%5s", ext->ext_namep->cname);
11180Sstevel@tonic-gate 		else
11190Sstevel@tonic-gate 			meta_sp_debug("%5s", "NONE");
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 		meta_sp_debug("%10p %5u ", (void *) ext, ext->ext_seq);
11220Sstevel@tonic-gate 		switch (ext->ext_type) {
11230Sstevel@tonic-gate 		case EXTTYP_ALLOC:
11240Sstevel@tonic-gate 			meta_sp_debug("%7s ", "ALLOC");
11250Sstevel@tonic-gate 			break;
11260Sstevel@tonic-gate 		case EXTTYP_FREE:
11270Sstevel@tonic-gate 			meta_sp_debug("%7s ", "FREE");
11280Sstevel@tonic-gate 			break;
11290Sstevel@tonic-gate 		case EXTTYP_END:
11300Sstevel@tonic-gate 			meta_sp_debug("%7s ", "END");
11310Sstevel@tonic-gate 			break;
11320Sstevel@tonic-gate 		case EXTTYP_RESERVED:
11330Sstevel@tonic-gate 			meta_sp_debug("%7s ", "RESV");
11340Sstevel@tonic-gate 			break;
11350Sstevel@tonic-gate 		default:
11360Sstevel@tonic-gate 			meta_sp_debug("%7s ", "INVLD");
11370Sstevel@tonic-gate 			break;
11380Sstevel@tonic-gate 		}
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 		meta_sp_debug("%10llu %10llu %5u %10p %10p\n",
11410Sstevel@tonic-gate 		    ext->ext_offset, ext->ext_length,
11420Sstevel@tonic-gate 		    ext->ext_flags, (void *) ext->ext_prev,
11430Sstevel@tonic-gate 		    (void *) ext->ext_next);
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 	meta_sp_debug("\n");
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate /*
11490Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_overlaps()
11500Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
11510Sstevel@tonic-gate  * OUTPUT:	none
11520Sstevel@tonic-gate  * RETURNS:	int	- 1 if extents overlap, 0 if ok
11530Sstevel@tonic-gate  * PURPOSE:	checks a list for overlaps.  The list MUST be sorted by
11540Sstevel@tonic-gate  *		offset for this function to work properly.
11550Sstevel@tonic-gate  */
11560Sstevel@tonic-gate static int
11570Sstevel@tonic-gate meta_sp_list_overlaps(sp_ext_node_t *head)
11580Sstevel@tonic-gate {
11590Sstevel@tonic-gate 	sp_ext_node_t	*ext;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	for (ext = head; ext->ext_next != NULL; ext = ext->ext_next) {
11620Sstevel@tonic-gate 		if (ext->ext_offset + ext->ext_length >
11630Sstevel@tonic-gate 		    ext->ext_next->ext_offset)
11640Sstevel@tonic-gate 			return (1);
11650Sstevel@tonic-gate 	}
11660Sstevel@tonic-gate 	return (0);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate /*
11700Sstevel@tonic-gate  * **************************************************************************
11710Sstevel@tonic-gate  *                        Extent Allocation Functions                       *
11720Sstevel@tonic-gate  * **************************************************************************
11730Sstevel@tonic-gate  */
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate /*
11760Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_ext()
11770Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
11780Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
11790Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
11800Sstevel@tonic-gate  *		free_ext	- the free extent being allocated from
11810Sstevel@tonic-gate  *		alloc_offset	- the offset of the allocation
11820Sstevel@tonic-gate  *		alloc_len	- the length of the allocation
11830Sstevel@tonic-gate  *		seq		- the sequence number of the allocation
11840Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
11850Sstevel@tonic-gate  * RETURNS:	void
11860Sstevel@tonic-gate  * PURPOSE:	allocates a portion of the free extent free_ext.  The
11870Sstevel@tonic-gate  *		allocated portion starts at alloc_offset and is
11880Sstevel@tonic-gate  *		alloc_length long.  Both (alloc_offset) and (alloc_offset +
11890Sstevel@tonic-gate  *		alloc_length) must be contained within the free extent.
11900Sstevel@tonic-gate  *
11910Sstevel@tonic-gate  *		The free extent is split into as many as 3 pieces - a
11920Sstevel@tonic-gate  *		free extent containing [ free_offset .. alloc_offset ), an
11930Sstevel@tonic-gate  *		allocated extent containing the range [ alloc_offset ..
11940Sstevel@tonic-gate  *		alloc_end ], and another free extent containing the
11950Sstevel@tonic-gate  *		range ( alloc_end .. free_end ].  If either of the two
11960Sstevel@tonic-gate  *		new free extents would be zero length, they are not created.
11970Sstevel@tonic-gate  *
11980Sstevel@tonic-gate  *		Finally, the original free extent is removed.  All newly
11990Sstevel@tonic-gate  *		created extents have the EXTFLG_UPDATE flag set.
12000Sstevel@tonic-gate  */
12010Sstevel@tonic-gate static void
12020Sstevel@tonic-gate meta_sp_alloc_by_ext(
12030Sstevel@tonic-gate 	mdsetname_t	*sp,
12040Sstevel@tonic-gate 	mdname_t	*np,
12050Sstevel@tonic-gate 	sp_ext_node_t	**head,
12060Sstevel@tonic-gate 	sp_ext_node_t	*free_ext,
12070Sstevel@tonic-gate 	sp_ext_offset_t	alloc_offset,
12080Sstevel@tonic-gate 	sp_ext_length_t	alloc_length,
12090Sstevel@tonic-gate 	uint_t		seq
12100Sstevel@tonic-gate )
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	sp_ext_offset_t	free_offset = free_ext->ext_offset;
12130Sstevel@tonic-gate 	sp_ext_length_t	free_length = free_ext->ext_length;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	sp_ext_offset_t	alloc_end = alloc_offset + alloc_length;
12160Sstevel@tonic-gate 	sp_ext_offset_t	free_end  = free_offset  + free_length;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/* allocated extent must be a subset of the free extent */
12190Sstevel@tonic-gate 	assert(free_offset <= alloc_offset);
12200Sstevel@tonic-gate 	assert(free_end >= alloc_end);
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	meta_sp_list_remove(head, free_ext);
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	if (free_offset < alloc_offset) {
12250Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, free_offset,
12260Sstevel@tonic-gate 		    (alloc_offset - free_offset), EXTTYP_FREE, 0,
12270Sstevel@tonic-gate 		    EXTFLG_UPDATE, meta_sp_cmp_by_offset);
12280Sstevel@tonic-gate 	}
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	if (free_end > alloc_end) {
12310Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, alloc_end,
12320Sstevel@tonic-gate 		    (free_end - alloc_end), EXTTYP_FREE, 0, EXTFLG_UPDATE,
12330Sstevel@tonic-gate 		    meta_sp_cmp_by_offset);
12340Sstevel@tonic-gate 	}
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	meta_sp_list_insert(sp, np, head, alloc_offset, alloc_length,
12370Sstevel@tonic-gate 	    EXTTYP_ALLOC, seq, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
12400Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_ext: extent list:\n");
12410Sstevel@tonic-gate 		meta_sp_list_dump(*head);
12420Sstevel@tonic-gate 	}
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate /*
12460Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_len()
12470Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
12480Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
12490Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
12500Sstevel@tonic-gate  *		*lp	- the requested length to allocate
12510Sstevel@tonic-gate  *		last_off	- the last offset already allocated.
12520Sstevel@tonic-gate  *		alignment	- the desired extent alignmeent
12530Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
12540Sstevel@tonic-gate  *		*lp	- the length allocated
12550Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, the number of new extents on success
12560Sstevel@tonic-gate  * PURPOSE:	allocates extents from free space to satisfy the requested
12570Sstevel@tonic-gate  *		length.  If requested length is zero, allocates all
12580Sstevel@tonic-gate  *		remaining free space.  This function provides the meat
12590Sstevel@tonic-gate  *		of the extent allocation algorithm.  Allocation is a
12600Sstevel@tonic-gate  *		three tier process:
12610Sstevel@tonic-gate  *
12620Sstevel@tonic-gate  *		1. If last_off is nonzero and there is free space following
12630Sstevel@tonic-gate  *		   that node, then it is extended to allocate as much of that
12640Sstevel@tonic-gate  *		   free space as possible.  This is useful for metattach.
12650Sstevel@tonic-gate  *		2. If a free extent can be found to satisfy the remaining
12660Sstevel@tonic-gate  *		   requested space, then satisfy the rest of the request
12670Sstevel@tonic-gate  *		   from that extent.
12680Sstevel@tonic-gate  *		3. Start allocating space from any remaining free extents until
12690Sstevel@tonic-gate  *		   the remainder of the request is satisified.
12700Sstevel@tonic-gate  *
12710Sstevel@tonic-gate  *              If alignment is non-zero, then every extent modified
12720Sstevel@tonic-gate  *              or newly allocated will be aligned modulo alignment,
12730Sstevel@tonic-gate  *              with a length that is an integer multiple of
12740Sstevel@tonic-gate  *              alignment.
12750Sstevel@tonic-gate  *
12760Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is set for all nodes (free and
12770Sstevel@tonic-gate  *		allocated) that require updated watermarks.
12780Sstevel@tonic-gate  *
12790Sstevel@tonic-gate  *		This algorithm may have a negative impact on fragmentation
12800Sstevel@tonic-gate  *		in pathological cases and may be improved if it turns out
12810Sstevel@tonic-gate  *		to be a problem.  This may be exacerbated by particularly
12820Sstevel@tonic-gate  *		large alignments.
12830Sstevel@tonic-gate  *
12840Sstevel@tonic-gate  * NOTE:	It's confusing, so it demands an explanation:
12850Sstevel@tonic-gate  *		- len is used to represent requested data space; it
12860Sstevel@tonic-gate  *		  does not include room for a watermark.  On each full
12870Sstevel@tonic-gate  *		  or partial allocation, len will be decremented by
12880Sstevel@tonic-gate  *		  alloc_len (see next paragraph) until it reaches
12890Sstevel@tonic-gate  *		  zero.
12900Sstevel@tonic-gate  *		- alloc_len is used to represent data space allocated
12910Sstevel@tonic-gate  *		  from a particular extent; it does not include space
12920Sstevel@tonic-gate  *		  for a watermark.  In the rare event that a_length
12930Sstevel@tonic-gate  *		  (see next paragraph) is equal to MD_SP_WMSIZE,
12940Sstevel@tonic-gate  *		  alloc_len will be zero and the resulting MD_SP_WMSIZE
12950Sstevel@tonic-gate  *		  fragment of space will be utterly unusable.
12960Sstevel@tonic-gate  *		- a_length is used to represent all space to be
12970Sstevel@tonic-gate  *		  allocated from a particular extent; it DOES include
12980Sstevel@tonic-gate  *		  space for a watermark.
12990Sstevel@tonic-gate  */
13000Sstevel@tonic-gate static int
13010Sstevel@tonic-gate meta_sp_alloc_by_len(
13020Sstevel@tonic-gate 	mdsetname_t	*sp,
13030Sstevel@tonic-gate 	mdname_t	*np,
13040Sstevel@tonic-gate 	sp_ext_node_t	**head,
13050Sstevel@tonic-gate 	sp_ext_length_t	*lp,
13060Sstevel@tonic-gate 	sp_ext_offset_t	last_off,
13070Sstevel@tonic-gate 	sp_ext_offset_t	alignment
13080Sstevel@tonic-gate )
13090Sstevel@tonic-gate {
13100Sstevel@tonic-gate 	sp_ext_node_t	*free_ext;
13110Sstevel@tonic-gate 	sp_ext_node_t	*alloc_ext;
13120Sstevel@tonic-gate 	uint_t		last_seq = 0;
13130Sstevel@tonic-gate 	uint_t		numexts = 0;
13140Sstevel@tonic-gate 	sp_ext_length_t	freespace;
13150Sstevel@tonic-gate 	sp_ext_length_t	alloc_len;
13160Sstevel@tonic-gate 	sp_ext_length_t	len;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	/* We're DOA if we can't read *lp */
13190Sstevel@tonic-gate 	assert(lp != NULL);
13200Sstevel@tonic-gate 	len = *lp;
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	/*
13230Sstevel@tonic-gate 	 * Process the nominal case first: we've been given an actual
13240Sstevel@tonic-gate 	 * size argument, rather than the literal "all"
13250Sstevel@tonic-gate 	 */
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	if (len != 0) {
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 		/*
13300Sstevel@tonic-gate 		 * Short circuit the check for free space.  This may
13310Sstevel@tonic-gate 		 * tell us we have enough space when we really don't
13320Sstevel@tonic-gate 		 * because each extent loses space to a watermark, but
13330Sstevel@tonic-gate 		 * it will always tell us there isn't enough space
13340Sstevel@tonic-gate 		 * correctly.  Worst case we do some extra work.
13350Sstevel@tonic-gate 		 */
13360Sstevel@tonic-gate 		freespace = meta_sp_list_size(*head, EXTTYP_FREE,
13370Sstevel@tonic-gate 		    INCLUDE_WM);
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 		if (freespace < len)
13400Sstevel@tonic-gate 			return (-1);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 		/*
13430Sstevel@tonic-gate 		 * First see if we can extend the last extent for an
13440Sstevel@tonic-gate 		 * attach.
13450Sstevel@tonic-gate 		 */
13460Sstevel@tonic-gate 		if (last_off != 0LL) {
13470Sstevel@tonic-gate 			int align = 0;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 			alloc_ext =
13500Sstevel@tonic-gate 			    meta_sp_list_find(*head, last_off);
13510Sstevel@tonic-gate 			assert(alloc_ext != NULL);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 			/*
13540Sstevel@tonic-gate 			 * The offset test reflects the
13550Sstevel@tonic-gate 			 * inclusion of the watermark in the extent
13560Sstevel@tonic-gate 			 */
13570Sstevel@tonic-gate 			align = (alignment > 0) &&
13580Sstevel@tonic-gate 			    (((alloc_ext->ext_offset + MD_SP_WMSIZE) %
13590Sstevel@tonic-gate 				alignment) == 0);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 			/*
13620Sstevel@tonic-gate 			 * If we decided not to align here, we should
13630Sstevel@tonic-gate 			 * also reset "alignment" so we don't bother
13640Sstevel@tonic-gate 			 * later, either.
13650Sstevel@tonic-gate 			 */
13660Sstevel@tonic-gate 			if (!align) {
13670Sstevel@tonic-gate 				alignment = 0;
13680Sstevel@tonic-gate 			}
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 			last_seq = alloc_ext->ext_seq;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 			free_ext = meta_sp_list_find(*head,
13730Sstevel@tonic-gate 			    alloc_ext->ext_offset +
13740Sstevel@tonic-gate 			    alloc_ext->ext_length);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 			/*
13770Sstevel@tonic-gate 			 * If a free extent follows our last allocated
13780Sstevel@tonic-gate 			 * extent, then remove the last allocated
13790Sstevel@tonic-gate 			 * extent and increase the size of the free
13800Sstevel@tonic-gate 			 * extent to overlap it, then allocate the
13810Sstevel@tonic-gate 			 * total space from the new free extent.
13820Sstevel@tonic-gate 			 */
13830Sstevel@tonic-gate 			if (free_ext != NULL &&
13840Sstevel@tonic-gate 			    free_ext->ext_type == EXTTYP_FREE) {
13850Sstevel@tonic-gate 				assert(free_ext->ext_offset ==
13860Sstevel@tonic-gate 				    alloc_ext->ext_offset +
13870Sstevel@tonic-gate 				    alloc_ext->ext_length);
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 				alloc_len =
13900Sstevel@tonic-gate 				    MIN(len, free_ext->ext_length);
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 				if (align && (alloc_len < len)) {
13930Sstevel@tonic-gate 					/* No watermark space needed */
13940Sstevel@tonic-gate 					alloc_len -= alloc_len % alignment;
13950Sstevel@tonic-gate 				}
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 				if (alloc_len > 0) {
13980Sstevel@tonic-gate 					free_ext->ext_offset -=
13990Sstevel@tonic-gate 					    alloc_ext->ext_length;
14000Sstevel@tonic-gate 					free_ext->ext_length +=
14010Sstevel@tonic-gate 					    alloc_ext->ext_length;
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 					meta_sp_alloc_by_ext(sp, np, head,
14040Sstevel@tonic-gate 					    free_ext, free_ext->ext_offset,
14050Sstevel@tonic-gate 					    alloc_ext->ext_length + alloc_len,
14060Sstevel@tonic-gate 					    last_seq);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 					/*
14090Sstevel@tonic-gate 					 * now remove the original allocated
14100Sstevel@tonic-gate 					 * node.  We may have overlapping
14110Sstevel@tonic-gate 					 * extents for a short time before
14120Sstevel@tonic-gate 					 * this node is removed.
14130Sstevel@tonic-gate 					 */
14140Sstevel@tonic-gate 					meta_sp_list_remove(head, alloc_ext);
14150Sstevel@tonic-gate 					len -= alloc_len;
14160Sstevel@tonic-gate 				}
14170Sstevel@tonic-gate 			}
14180Sstevel@tonic-gate 			last_seq++;
14190Sstevel@tonic-gate 		}
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 		if (len == 0LL)
14220Sstevel@tonic-gate 			goto out;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 		/*
14250Sstevel@tonic-gate 		 * Next, see if we can find a single allocation for
14260Sstevel@tonic-gate 		 * the remainder.  This may make fragmentation worse
14270Sstevel@tonic-gate 		 * in some cases, but there's no good way to allocate
14280Sstevel@tonic-gate 		 * that doesn't have a highly fragmented corner case.
14290Sstevel@tonic-gate 		 */
14300Sstevel@tonic-gate 		for (free_ext = *head; free_ext != NULL;
14310Sstevel@tonic-gate 			free_ext = free_ext->ext_next) {
14320Sstevel@tonic-gate 			sp_ext_offset_t	a_offset;
14330Sstevel@tonic-gate 			sp_ext_offset_t	a_length;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 			if (free_ext->ext_type != EXTTYP_FREE)
14360Sstevel@tonic-gate 				continue;
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 			/*
14390Sstevel@tonic-gate 			 * The length test should include space for
14400Sstevel@tonic-gate 			 * the watermark
14410Sstevel@tonic-gate 			 */
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 			a_offset = free_ext->ext_offset;
14440Sstevel@tonic-gate 			a_length = free_ext->ext_length;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 			if (alignment > 0) {
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 				/*
14490Sstevel@tonic-gate 				 * Shortcut for extents that have been
14500Sstevel@tonic-gate 				 * previously added to pad out the
14510Sstevel@tonic-gate 				 * data space
14520Sstevel@tonic-gate 				 */
14530Sstevel@tonic-gate 				if (a_length < alignment) {
14540Sstevel@tonic-gate 					continue;
14550Sstevel@tonic-gate 				}
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 				/*
14580Sstevel@tonic-gate 				 * Round up so the data space begins
14590Sstevel@tonic-gate 				 * on a properly aligned boundary.
14600Sstevel@tonic-gate 				 */
14610Sstevel@tonic-gate 				a_offset += alignment -
14620Sstevel@tonic-gate 				    (a_offset % alignment) - MD_SP_WMSIZE;
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 				/*
14650Sstevel@tonic-gate 				 * This is only necessary in case the
14660Sstevel@tonic-gate 				 * watermark size is ever greater than
14670Sstevel@tonic-gate 				 * one.  It'll never happen, of
14680Sstevel@tonic-gate 				 * course; we'll get rid of watermarks
14690Sstevel@tonic-gate 				 * before we make 'em bigger.
14700Sstevel@tonic-gate 				 */
14710Sstevel@tonic-gate 				if (a_offset < free_ext->ext_offset) {
14720Sstevel@tonic-gate 					a_offset += alignment;
14730Sstevel@tonic-gate 				}
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 				/*
14760Sstevel@tonic-gate 				 * Adjust the length to account for
14770Sstevel@tonic-gate 				 * the space lost above (if any)
14780Sstevel@tonic-gate 				 */
14790Sstevel@tonic-gate 				a_length -=
14800Sstevel@tonic-gate 					(a_offset - free_ext->ext_offset);
14810Sstevel@tonic-gate 			}
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 			if (a_length >= len + MD_SP_WMSIZE) {
14840Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
14850Sstevel@tonic-gate 					free_ext, a_offset,
14860Sstevel@tonic-gate 					len + MD_SP_WMSIZE, last_seq);
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 				len = 0LL;
14890Sstevel@tonic-gate 				numexts++;
14900Sstevel@tonic-gate 				break;
14910Sstevel@tonic-gate 			}
14920Sstevel@tonic-gate 		}
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 		if (len == 0LL)
14950Sstevel@tonic-gate 			goto out;
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 		/*
14990Sstevel@tonic-gate 		 * If the request could not be satisfied by extending
15000Sstevel@tonic-gate 		 * the last extent or by a single extent, then put
15010Sstevel@tonic-gate 		 * multiple smaller extents together until the request
15020Sstevel@tonic-gate 		 * is satisfied.
15030Sstevel@tonic-gate 		 */
15040Sstevel@tonic-gate 		for (free_ext = *head; (free_ext != NULL) && (len > 0);
15050Sstevel@tonic-gate 			free_ext = free_ext->ext_next) {
15060Sstevel@tonic-gate 			sp_ext_offset_t a_offset;
15070Sstevel@tonic-gate 			sp_ext_length_t a_length;
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 			if (free_ext->ext_type != EXTTYP_FREE)
15100Sstevel@tonic-gate 				continue;
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 			a_offset = free_ext->ext_offset;
15130Sstevel@tonic-gate 			a_length = free_ext->ext_length;
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 			if (alignment > 0) {
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 				/*
15180Sstevel@tonic-gate 				 * Shortcut for extents that have been
15190Sstevel@tonic-gate 				 * previously added to pad out the
15200Sstevel@tonic-gate 				 * data space
15210Sstevel@tonic-gate 				 */
15220Sstevel@tonic-gate 				if (a_length < alignment) {
15230Sstevel@tonic-gate 					continue;
15240Sstevel@tonic-gate 				}
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 				/*
15270Sstevel@tonic-gate 				 * Round up so the data space begins
15280Sstevel@tonic-gate 				 * on a properly aligned boundary.
15290Sstevel@tonic-gate 				 */
15300Sstevel@tonic-gate 				a_offset += alignment -
15310Sstevel@tonic-gate 					(a_offset % alignment) - MD_SP_WMSIZE;
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 				/*
15340Sstevel@tonic-gate 				 * This is only necessary in case the
15350Sstevel@tonic-gate 				 * watermark size is ever greater than
15360Sstevel@tonic-gate 				 * one.  It'll never happen, of
15370Sstevel@tonic-gate 				 * course; we'll get rid of watermarks
15380Sstevel@tonic-gate 				 * before we make 'em bigger.
15390Sstevel@tonic-gate 				 */
15400Sstevel@tonic-gate 				if (a_offset < free_ext->ext_offset) {
15410Sstevel@tonic-gate 					a_offset += alignment;
15420Sstevel@tonic-gate 				}
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 				/*
15450Sstevel@tonic-gate 				 * Adjust the length to account for
15460Sstevel@tonic-gate 				 * the space lost above (if any)
15470Sstevel@tonic-gate 				 */
15480Sstevel@tonic-gate 				a_length -=
15490Sstevel@tonic-gate 					(a_offset - free_ext->ext_offset);
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 				/*
15520Sstevel@tonic-gate 				 * Adjust the length to be properly
15530Sstevel@tonic-gate 				 * aligned if it is NOT to be the
15540Sstevel@tonic-gate 				 * last extent in the soft partition.
15550Sstevel@tonic-gate 				 */
15560Sstevel@tonic-gate 				if ((a_length - MD_SP_WMSIZE) < len)
15570Sstevel@tonic-gate 					a_length -=
15580Sstevel@tonic-gate 						(a_length - MD_SP_WMSIZE)
15590Sstevel@tonic-gate 						% alignment;
15600Sstevel@tonic-gate 			}
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 			alloc_len = MIN(len, a_length - MD_SP_WMSIZE);
15630Sstevel@tonic-gate 			if (alloc_len == 0)
15640Sstevel@tonic-gate 				continue;
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 			/*
15670Sstevel@tonic-gate 			 * meta_sp_alloc_by_ext() expects the
15680Sstevel@tonic-gate 			 * allocation length to include the watermark
15690Sstevel@tonic-gate 			 * size, which is why we don't simply pass in
15700Sstevel@tonic-gate 			 * alloc_len here.
15710Sstevel@tonic-gate 			 */
15720Sstevel@tonic-gate 			meta_sp_alloc_by_ext(sp, np, head, free_ext,
15730Sstevel@tonic-gate 				a_offset, MIN(len + MD_SP_WMSIZE, a_length),
15740Sstevel@tonic-gate 				last_seq);
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 			len -= alloc_len;
15770Sstevel@tonic-gate 			numexts++;
15780Sstevel@tonic-gate 			last_seq++;
15790Sstevel@tonic-gate 		}
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 		/*
15830Sstevel@tonic-gate 		 * If there was not enough space we can throw it all
15840Sstevel@tonic-gate 		 * away since no real work has been done yet.
15850Sstevel@tonic-gate 		 */
15860Sstevel@tonic-gate 		if (len != 0) {
15870Sstevel@tonic-gate 			meta_sp_list_free(head);
15880Sstevel@tonic-gate 			return (-1);
15890Sstevel@tonic-gate 		}
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	/*
15930Sstevel@tonic-gate 	 * Otherwise, the literal "all" was specified: allocate all
15940Sstevel@tonic-gate 	 * available free space.  Don't bother with alignment.
15950Sstevel@tonic-gate 	 */
15960Sstevel@tonic-gate 	else {
15970Sstevel@tonic-gate 		/* First, extend the last extent if this is a grow */
15980Sstevel@tonic-gate 		if (last_off != 0LL) {
15990Sstevel@tonic-gate 			alloc_ext =
16000Sstevel@tonic-gate 				meta_sp_list_find(*head, last_off);
16010Sstevel@tonic-gate 			assert(alloc_ext != NULL);
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 			last_seq = alloc_ext->ext_seq;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 			free_ext = meta_sp_list_find(*head,
16060Sstevel@tonic-gate 				alloc_ext->ext_offset +
16070Sstevel@tonic-gate 				alloc_ext->ext_length);
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 			/*
16100Sstevel@tonic-gate 			 * If a free extent follows our last allocated
16110Sstevel@tonic-gate 			 * extent, then remove the last allocated
16120Sstevel@tonic-gate 			 * extent and increase the size of the free
16130Sstevel@tonic-gate 			 * extent to overlap it, then allocate the
16140Sstevel@tonic-gate 			 * total space from the new free extent.
16150Sstevel@tonic-gate 			 */
16160Sstevel@tonic-gate 			if (free_ext != NULL &&
16170Sstevel@tonic-gate 			    free_ext->ext_type == EXTTYP_FREE) {
16180Sstevel@tonic-gate 				assert(free_ext->ext_offset ==
16190Sstevel@tonic-gate 				    alloc_ext->ext_offset +
16200Sstevel@tonic-gate 				    alloc_ext->ext_length);
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 				len = alloc_len =
16230Sstevel@tonic-gate 				    free_ext->ext_length;
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 				free_ext->ext_offset -=
16260Sstevel@tonic-gate 				    alloc_ext->ext_length;
16270Sstevel@tonic-gate 				free_ext->ext_length +=
16280Sstevel@tonic-gate 				    alloc_ext->ext_length;
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
16310Sstevel@tonic-gate 				    free_ext, free_ext->ext_offset,
16320Sstevel@tonic-gate 				    alloc_ext->ext_length + alloc_len,
16330Sstevel@tonic-gate 				    last_seq);
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 				/*
16360Sstevel@tonic-gate 				 * now remove the original allocated
16370Sstevel@tonic-gate 				 * node.  We may have overlapping
16380Sstevel@tonic-gate 				 * extents for a short time before
16390Sstevel@tonic-gate 				 * this node is removed.
16400Sstevel@tonic-gate 				 */
16410Sstevel@tonic-gate 				meta_sp_list_remove(head, alloc_ext);
16420Sstevel@tonic-gate 			}
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 			last_seq++;
16450Sstevel@tonic-gate 		}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 		/* Next, grab all remaining free space */
16480Sstevel@tonic-gate 		for (free_ext = *head; free_ext != NULL;
16490Sstevel@tonic-gate 			free_ext = free_ext->ext_next) {
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 			if (free_ext->ext_type == EXTTYP_FREE) {
16520Sstevel@tonic-gate 				alloc_len =
16530Sstevel@tonic-gate 				    free_ext->ext_length - MD_SP_WMSIZE;
16540Sstevel@tonic-gate 				if (alloc_len == 0)
16550Sstevel@tonic-gate 					continue;
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 				/*
16580Sstevel@tonic-gate 				 * meta_sp_alloc_by_ext() expects the
16590Sstevel@tonic-gate 				 * allocation length to include the
16600Sstevel@tonic-gate 				 * watermark size, which is why we
16610Sstevel@tonic-gate 				 * don't simply pass in alloc_len
16620Sstevel@tonic-gate 				 * here.
16630Sstevel@tonic-gate 				 */
16640Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
16650Sstevel@tonic-gate 				    free_ext, free_ext->ext_offset,
16660Sstevel@tonic-gate 				    free_ext->ext_length,
16670Sstevel@tonic-gate 				    last_seq);
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 				len += alloc_len;
16700Sstevel@tonic-gate 				numexts++;
16710Sstevel@tonic-gate 				last_seq++;
16720Sstevel@tonic-gate 			}
16730Sstevel@tonic-gate 		}
16740Sstevel@tonic-gate 	}
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate out:
16770Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
16780Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_len: Extent list after "
16790Sstevel@tonic-gate 		    "allocation:\n");
16800Sstevel@tonic-gate 		meta_sp_list_dump(*head);
16810Sstevel@tonic-gate 	}
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	if (*lp == 0) {
16840Sstevel@tonic-gate 		*lp = len;
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 		/*
16870Sstevel@tonic-gate 		 * Make sure the callers hit a no space error if we
16880Sstevel@tonic-gate 		 * didn't actually find anything.
16890Sstevel@tonic-gate 		 */
16900Sstevel@tonic-gate 		if (len == 0) {
16910Sstevel@tonic-gate 			return (-1);
16920Sstevel@tonic-gate 		}
16930Sstevel@tonic-gate 	}
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	return (numexts);
16960Sstevel@tonic-gate }
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate /*
16990Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_list()
17000Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
17010Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
17020Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
17030Sstevel@tonic-gate  *		oblist	- an extent list containing requested nodes to allocate
17040Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
17050Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, the number of new extents on success
17060Sstevel@tonic-gate  * PURPOSE:	allocates extents from free space to satisfy the requested
17070Sstevel@tonic-gate  *		extent list.  This is primarily used for the -o/-b options
17080Sstevel@tonic-gate  *		where the user may specifically request extents to allocate.
17090Sstevel@tonic-gate  *		Each extent in the oblist must be a subset (inclusive) of a
17100Sstevel@tonic-gate  *		free extent and may not overlap each other.  This
17110Sstevel@tonic-gate  *		function sets the EXTFLG_UPDATE flag for each node that
17120Sstevel@tonic-gate  *		requires a watermark update after allocating.
17130Sstevel@tonic-gate  */
17140Sstevel@tonic-gate static int
17150Sstevel@tonic-gate meta_sp_alloc_by_list(
17160Sstevel@tonic-gate 	mdsetname_t	*sp,
17170Sstevel@tonic-gate 	mdname_t	*np,
17180Sstevel@tonic-gate 	sp_ext_node_t	**head,
17190Sstevel@tonic-gate 	sp_ext_node_t	*oblist
17200Sstevel@tonic-gate )
17210Sstevel@tonic-gate {
17220Sstevel@tonic-gate 	sp_ext_node_t	*ext;
17230Sstevel@tonic-gate 	sp_ext_node_t	*free_ext;
17240Sstevel@tonic-gate 	uint_t		numexts = 0;
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	for (ext = oblist; ext != NULL; ext = ext->ext_next) {
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 		free_ext = meta_sp_list_find(*head,
17290Sstevel@tonic-gate 		    ext->ext_offset - MD_SP_WMSIZE);
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 		/* Make sure the allocation is within the free extent */
17320Sstevel@tonic-gate 		if ((free_ext == NULL) ||
17330Sstevel@tonic-gate 		    (ext->ext_offset + ext->ext_length >
17340Sstevel@tonic-gate 		    free_ext->ext_offset + free_ext->ext_length) ||
17350Sstevel@tonic-gate 		    (free_ext->ext_type != EXTTYP_FREE))
17360Sstevel@tonic-gate 			return (-1);
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 		meta_sp_alloc_by_ext(sp, np, head, free_ext,
17390Sstevel@tonic-gate 		    ext->ext_offset - MD_SP_WMSIZE,
17400Sstevel@tonic-gate 		    ext->ext_length + MD_SP_WMSIZE, ext->ext_seq);
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 		numexts++;
17430Sstevel@tonic-gate 	}
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	assert(meta_sp_list_overlaps(*head) == 0);
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
17480Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_list: Extent list after "
17490Sstevel@tonic-gate 		    "allocation:\n");
17500Sstevel@tonic-gate 		meta_sp_list_dump(*head);
17510Sstevel@tonic-gate 	}
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	return (numexts);
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate /*
17570Sstevel@tonic-gate  * **************************************************************************
17580Sstevel@tonic-gate  *                     Extent List Population Functions                     *
17590Sstevel@tonic-gate  * **************************************************************************
17600Sstevel@tonic-gate  */
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate /*
17630Sstevel@tonic-gate  * FUNCTION:	meta_sp_extlist_from_namelist()
17640Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
17650Sstevel@tonic-gate  *		spnplp	- the namelist of soft partitions to build a list from
17660Sstevel@tonic-gate  * OUTPUT:	extlist	- the extent list built from the SPs in the namelist
17670Sstevel@tonic-gate  *		ep	- return error pointer
17680Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
17690Sstevel@tonic-gate  * PURPOSE:	builds an extent list representing the soft partitions
17700Sstevel@tonic-gate  *		specified in the namelist.  Each extent in each soft
17710Sstevel@tonic-gate  *		partition is added to the list with the type EXTTYP_ALLOC.
17720Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is not set on any nodes.  Each
17730Sstevel@tonic-gate  *		extent in the list includes the space occupied by the
17740Sstevel@tonic-gate  *		watermark, which is not included in the unit structures.
17750Sstevel@tonic-gate  */
17760Sstevel@tonic-gate static int
17770Sstevel@tonic-gate meta_sp_extlist_from_namelist(
17780Sstevel@tonic-gate 	mdsetname_t	*sp,
17790Sstevel@tonic-gate 	mdnamelist_t	*spnlp,
17800Sstevel@tonic-gate 	sp_ext_node_t	**extlist,
17810Sstevel@tonic-gate 	md_error_t	*ep
17820Sstevel@tonic-gate )
17830Sstevel@tonic-gate {
17840Sstevel@tonic-gate 	int		extn;
17850Sstevel@tonic-gate 	md_sp_t		*msp;		/* unit structure of the sp's */
17860Sstevel@tonic-gate 	mdnamelist_t	*namep;
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	assert(sp != NULL);
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 	/*
17910Sstevel@tonic-gate 	 * Now go through the soft partitions and add a node to the used
17920Sstevel@tonic-gate 	 * list for each allocated extent.
17930Sstevel@tonic-gate 	 */
17940Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
17950Sstevel@tonic-gate 		mdname_t	*curnp = namep->namep;
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 		/* get the unit structure */
17980Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
17990Sstevel@tonic-gate 			return (-1);
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 		for (extn = 0; (extn < msp->ext.ext_len); extn++) {
18020Sstevel@tonic-gate 			md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 			/*
18050Sstevel@tonic-gate 			 * subtract from offset and add to the length
18060Sstevel@tonic-gate 			 * to account for the watermark, which is not
18070Sstevel@tonic-gate 			 * contained in the extents in the unit structure.
18080Sstevel@tonic-gate 			 */
18090Sstevel@tonic-gate 			meta_sp_list_insert(sp, curnp, extlist,
18100Sstevel@tonic-gate 			    extp->poff - MD_SP_WMSIZE, extp->len + MD_SP_WMSIZE,
18110Sstevel@tonic-gate 			    EXTTYP_ALLOC, extn, 0, meta_sp_cmp_by_offset);
18120Sstevel@tonic-gate 		}
18130Sstevel@tonic-gate 	}
18140Sstevel@tonic-gate 	return (0);
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate /*
18180Sstevel@tonic-gate  * FUNCTION:	meta_sp_extlist_from_wm()
18190Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
18200Sstevel@tonic-gate  *		compnp	- the name of the device to scan watermarks on
18210Sstevel@tonic-gate  * OUTPUT:	extlist	- the extent list built from the SPs in the namelist
18220Sstevel@tonic-gate  *		ep	- return error pointer
18230Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
18240Sstevel@tonic-gate  * PURPOSE:	builds an extent list representing the soft partitions
18250Sstevel@tonic-gate  *		specified in the namelist.  Each extent in each soft
18260Sstevel@tonic-gate  *		partition is added to the list with the type EXTTYP_ALLOC.
18270Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is not set on any nodes.  Each
18280Sstevel@tonic-gate  *		extent in the list includes the space occupied by the
18290Sstevel@tonic-gate  *		watermark, which is not included in the unit structures.
18300Sstevel@tonic-gate  */
18310Sstevel@tonic-gate static int
18320Sstevel@tonic-gate meta_sp_extlist_from_wm(
18330Sstevel@tonic-gate 	mdsetname_t	*sp,
18340Sstevel@tonic-gate 	mdname_t	*compnp,
18350Sstevel@tonic-gate 	sp_ext_node_t	**extlist,
18360Sstevel@tonic-gate 	ext_cmpfunc_t	compare,
18370Sstevel@tonic-gate 	md_error_t	*ep
18380Sstevel@tonic-gate )
18390Sstevel@tonic-gate {
18400Sstevel@tonic-gate 	mp_watermark_t	wm;
18410Sstevel@tonic-gate 	mdname_t	*np = NULL;
18420Sstevel@tonic-gate 	mdsetname_t	*spsetp = NULL;
18430Sstevel@tonic-gate 	sp_ext_offset_t	cur_off;
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 	if ((cur_off = meta_sp_get_start(sp, compnp, ep)) == MD_DISKADDR_ERROR)
18460Sstevel@tonic-gate 		return (-1);
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	for (;;) {
18490Sstevel@tonic-gate 		if (meta_sp_read_wm(sp, compnp, &wm, cur_off, ep) != 0) {
18500Sstevel@tonic-gate 			return (-1);
18510Sstevel@tonic-gate 		}
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 		/* get the set and name pointers */
18540Sstevel@tonic-gate 		if (strcmp(wm.wm_setname, MD_SP_LOCALSETNAME) != 0) {
18550Sstevel@tonic-gate 			if ((spsetp = metasetname(wm.wm_setname, ep)) == NULL) {
18560Sstevel@tonic-gate 				return (-1);
18570Sstevel@tonic-gate 			}
18580Sstevel@tonic-gate 		}
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 		if (strcmp(wm.wm_mdname, MD_SP_FREEWMNAME) != 0) {
18610Sstevel@tonic-gate 			if (meta_init_make_device(&sp, wm.wm_mdname, ep) != 0)
18620Sstevel@tonic-gate 				return (-1);
18630Sstevel@tonic-gate 			np = metaname(&spsetp, wm.wm_mdname, ep);
18640Sstevel@tonic-gate 			if (np == NULL) {
18650Sstevel@tonic-gate 				return (-1);
18660Sstevel@tonic-gate 			}
18670Sstevel@tonic-gate 		}
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 		/* insert watermark into extent list */
18700Sstevel@tonic-gate 		meta_sp_list_insert(spsetp, np, extlist, cur_off,
18710Sstevel@tonic-gate 		    wm.wm_length + MD_SP_WMSIZE, wm.wm_type, wm.wm_seq,
18720Sstevel@tonic-gate 		    EXTFLG_UPDATE, compare);
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 		/* if we see the end watermark, we're done */
18750Sstevel@tonic-gate 		if (wm.wm_type == EXTTYP_END)
18760Sstevel@tonic-gate 			break;
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 		cur_off += wm.wm_length + 1;
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 		/* clear out set and name pointers for next iteration */
18810Sstevel@tonic-gate 		np = NULL;
18820Sstevel@tonic-gate 		spsetp = NULL;
18830Sstevel@tonic-gate 	}
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	return (0);
18860Sstevel@tonic-gate }
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate /*
18890Sstevel@tonic-gate  * **************************************************************************
18900Sstevel@tonic-gate  *                        Print (metastat) Functions                        *
18910Sstevel@tonic-gate  * **************************************************************************
18920Sstevel@tonic-gate  */
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate /*
18950Sstevel@tonic-gate  * FUNCTION:	meta_sp_short_print()
18960Sstevel@tonic-gate  * INPUT:	msp	- the unit structure to display
18970Sstevel@tonic-gate  *		fp	- the file pointer to send output to
18980Sstevel@tonic-gate  *		options	- print options from the command line processor
18990Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
19000Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
19010Sstevel@tonic-gate  * PURPOSE:	display a short report of the soft partition in md.tab
19020Sstevel@tonic-gate  *		form, primarily used for metastat -p.
19030Sstevel@tonic-gate  */
19040Sstevel@tonic-gate static int
19050Sstevel@tonic-gate meta_sp_short_print(
19060Sstevel@tonic-gate 	md_sp_t		*msp,
19070Sstevel@tonic-gate 	char		*fname,
19080Sstevel@tonic-gate 	FILE		*fp,
19090Sstevel@tonic-gate 	mdprtopts_t	options,
19100Sstevel@tonic-gate 	md_error_t	*ep
19110Sstevel@tonic-gate )
19120Sstevel@tonic-gate {
19130Sstevel@tonic-gate 	int	extn;
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
19160Sstevel@tonic-gate 		if (msp->common.revision != MD_64BIT_META_DEV)
19170Sstevel@tonic-gate 			return (0);
19180Sstevel@tonic-gate 	}
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	/* print name and -p */
19210Sstevel@tonic-gate 	if (fprintf(fp, "%s -p", msp->common.namep->cname) == EOF)
19220Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	/* print the component */
19250Sstevel@tonic-gate 	/*
19260Sstevel@tonic-gate 	 * If the path is our standard /dev/rdsk or /dev/md/rdsk
19270Sstevel@tonic-gate 	 * then just print out the cxtxdxsx or the dx, metainit
19280Sstevel@tonic-gate 	 * will assume the default, otherwise we need the full
19290Sstevel@tonic-gate 	 * pathname to make sure this works as we intend.
19300Sstevel@tonic-gate 	 */
19310Sstevel@tonic-gate 	if ((strstr(msp->compnamep->rname, "/dev/rdsk") == NULL) &&
19320Sstevel@tonic-gate 	    (strstr(msp->compnamep->rname, "/dev/md/rdsk") == NULL) &&
19330Sstevel@tonic-gate 	    (strstr(msp->compnamep->rname, "/dev/td/") == NULL)) {
19340Sstevel@tonic-gate 		/* not standard path so print full pathname */
19350Sstevel@tonic-gate 		if (fprintf(fp, " %s", msp->compnamep->rname) == EOF)
19360Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
19370Sstevel@tonic-gate 	} else {
19380Sstevel@tonic-gate 		/* standard path so print ctds or d number */
19390Sstevel@tonic-gate 		if (fprintf(fp, " %s", msp->compnamep->cname) == EOF)
19400Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
19410Sstevel@tonic-gate 	}
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	/* print out each extent */
19440Sstevel@tonic-gate 	for (extn = 0; (extn < msp->ext.ext_len); extn++) {
19450Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
19460Sstevel@tonic-gate 		if (fprintf(fp, " -o %llu -b %llu ", extp->poff,
19470Sstevel@tonic-gate 		    extp->len) == EOF)
19480Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
19490Sstevel@tonic-gate 	}
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
19520Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 	/* success */
19550Sstevel@tonic-gate 	return (0);
19560Sstevel@tonic-gate }
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate /*
19590Sstevel@tonic-gate  * FUNCTION:	meta_sp_status_to_name()
19600Sstevel@tonic-gate  * INPUT:	xsp_status	- the status value to convert to a string
19610Sstevel@tonic-gate  *		tstate		- transient errored device state. If set the
19620Sstevel@tonic-gate  *				  device is Unavailable
19630Sstevel@tonic-gate  * OUTPUT:	none
19640Sstevel@tonic-gate  * RETURNS:	char *	- a pointer to the string representing the status value
19650Sstevel@tonic-gate  * PURPOSE:	return an internationalized string representing the
19660Sstevel@tonic-gate  *		status value for a soft partition.  The strings are
19670Sstevel@tonic-gate  *		strdup'd and must be freed by the caller.
19680Sstevel@tonic-gate  */
19690Sstevel@tonic-gate static char *
19700Sstevel@tonic-gate meta_sp_status_to_name(
19710Sstevel@tonic-gate 	xsp_status_t	xsp_status,
19720Sstevel@tonic-gate 	uint_t		tstate
19730Sstevel@tonic-gate )
19740Sstevel@tonic-gate {
19750Sstevel@tonic-gate 	char *rval = NULL;
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	/*
19780Sstevel@tonic-gate 	 * Check to see if we have MD_INACCESSIBLE set. This is the only valid
19790Sstevel@tonic-gate 	 * value for an 'Unavailable' return. tstate can be set because of
19800Sstevel@tonic-gate 	 * other multi-node reasons (e.g. ABR being set)
19810Sstevel@tonic-gate 	 */
19820Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
19830Sstevel@tonic-gate 		return (Strdup(dgettext(TEXT_DOMAIN, "Unavailable")));
19840Sstevel@tonic-gate 	}
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	switch (xsp_status) {
19870Sstevel@tonic-gate 	case MD_SP_CREATEPEND:
19880Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Creating"));
19890Sstevel@tonic-gate 		break;
19900Sstevel@tonic-gate 	case MD_SP_GROWPEND:
19910Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Growing"));
19920Sstevel@tonic-gate 		break;
19930Sstevel@tonic-gate 	case MD_SP_DELPEND:
19940Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Deleting"));
19950Sstevel@tonic-gate 		break;
19960Sstevel@tonic-gate 	case MD_SP_OK:
19970Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Okay"));
19980Sstevel@tonic-gate 		break;
19990Sstevel@tonic-gate 	case MD_SP_ERR:
20000Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Errored"));
20010Sstevel@tonic-gate 		break;
20020Sstevel@tonic-gate 	case MD_SP_RECOVER:
20030Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Recovering"));
20040Sstevel@tonic-gate 		break;
20050Sstevel@tonic-gate 	}
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 	if (rval == NULL)
20080Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Invalid"));
20090Sstevel@tonic-gate 
20100Sstevel@tonic-gate 	return (rval);
20110Sstevel@tonic-gate }
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate /*
20140Sstevel@tonic-gate  * FUNCTION:	meta_sp_report()
20150Sstevel@tonic-gate  * INPUT:	sp	- the set name for the unit being displayed
20160Sstevel@tonic-gate  *		msp	- the unit structure to display
20170Sstevel@tonic-gate  *		nlpp	- pass back the large devs
20180Sstevel@tonic-gate  *		fp	- the file pointer to send output to
20190Sstevel@tonic-gate  *		options	- print options from the command line processor
20200Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
20210Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
20220Sstevel@tonic-gate  * PURPOSE:	print a full report of the device specified
20230Sstevel@tonic-gate  */
20240Sstevel@tonic-gate static int
20250Sstevel@tonic-gate meta_sp_report(
20260Sstevel@tonic-gate 	mdsetname_t	*sp,
20270Sstevel@tonic-gate 	md_sp_t		*msp,
20280Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
20290Sstevel@tonic-gate 	char		*fname,
20300Sstevel@tonic-gate 	FILE		*fp,
20310Sstevel@tonic-gate 	mdprtopts_t	options,
20320Sstevel@tonic-gate 	md_error_t	*ep
20330Sstevel@tonic-gate )
20340Sstevel@tonic-gate {
20350Sstevel@tonic-gate 	uint_t		extn;
20360Sstevel@tonic-gate 	char		*status;
20370Sstevel@tonic-gate 	char		*devid = "";
20380Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
20390Sstevel@tonic-gate 	ddi_devid_t	dtp;
20400Sstevel@tonic-gate 	int		len;
20410Sstevel@tonic-gate 	uint_t		tstate = 0;
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
20440Sstevel@tonic-gate 		if (msp->common.revision != MD_64BIT_META_DEV) {
20450Sstevel@tonic-gate 			return (0);
20460Sstevel@tonic-gate 		} else {
20470Sstevel@tonic-gate 			if (meta_getdevs(sp, msp->common.namep, nlpp, ep) != 0)
20480Sstevel@tonic-gate 				return (-1);
20490Sstevel@tonic-gate 		}
20500Sstevel@tonic-gate 	}
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
20530Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Soft Partition\n"),
20540Sstevel@tonic-gate 		    msp->common.namep->cname) == EOF)
20550Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
20560Sstevel@tonic-gate 	}
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Device: %s\n"),
20590Sstevel@tonic-gate 	    msp->compnamep->cname) == EOF)
20600Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	/* Determine if device is available before displaying status */
20630Sstevel@tonic-gate 	if (metaismeta(msp->common.namep)) {
20640Sstevel@tonic-gate 		if (meta_get_tstate(msp->common.namep->dev, &tstate, ep) != 0)
20650Sstevel@tonic-gate 			return (-1);
20660Sstevel@tonic-gate 	}
20670Sstevel@tonic-gate 	status = meta_sp_status_to_name(msp->status, tstate & MD_DEV_ERRORED);
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 	/* print out "State" to be consistent with other metadevices */
20700Sstevel@tonic-gate 	if (tstate & MD_ABR_CAP) {
20710Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
20720Sstevel@tonic-gate 		    "    State: %s - Application Based Recovery (ABR)\n"),
20730Sstevel@tonic-gate 		    status) == EOF) {
20740Sstevel@tonic-gate 			Free(status);
20750Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
20760Sstevel@tonic-gate 		}
20770Sstevel@tonic-gate 	} else {
20780Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
20790Sstevel@tonic-gate 		    "    State: %s\n"), status) == EOF) {
20800Sstevel@tonic-gate 			Free(status);
20810Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
20820Sstevel@tonic-gate 		}
20830Sstevel@tonic-gate 	}
20840Sstevel@tonic-gate 	free(status);
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %llu blocks (%s)\n"),
20870Sstevel@tonic-gate 	    msp->common.size,
20880Sstevel@tonic-gate 	    meta_number_to_string(msp->common.size, DEV_BSIZE)) == EOF)
20890Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
20900Sstevel@tonic-gate 
20910Sstevel@tonic-gate 	/* print component details */
20920Sstevel@tonic-gate 	if (! metaismeta(msp->compnamep)) {
20930Sstevel@tonic-gate 		diskaddr_t	start_blk;
20940Sstevel@tonic-gate 		int		has_mddb;
20950Sstevel@tonic-gate 		char		*has_mddb_str;
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 		/* print header */
20980Sstevel@tonic-gate 		/*
20990Sstevel@tonic-gate 		 * Building a format string on the fly that will
21000Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
21010Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
21020Sstevel@tonic-gate 		 * looking horrible.
21030Sstevel@tonic-gate 		 */
21040Sstevel@tonic-gate 		len = strlen(msp->compnamep->cname);
21050Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
21060Sstevel@tonic-gate 		len += 2;
21070Sstevel@tonic-gate 		if (fprintf(fp,
21080Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %s\n",
21090Sstevel@tonic-gate 		    len, len,
21100Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
21110Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
21120Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
21130Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
21140Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21150Sstevel@tonic-gate 		}
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 		/* get info */
21190Sstevel@tonic-gate 		if ((start_blk = meta_sp_get_start(sp, msp->compnamep, ep)) ==
21200Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
21210Sstevel@tonic-gate 			return (-1);
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate 		if ((has_mddb = metahasmddb(sp, msp->compnamep, ep)) < 0)
21240Sstevel@tonic-gate 			return (-1);
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 		if (has_mddb)
21270Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
21280Sstevel@tonic-gate 		else
21290Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 		/* populate the key in the name_p structure */
21320Sstevel@tonic-gate 		didnp = metadevname(&sp, msp->compnamep->dev, ep);
21330Sstevel@tonic-gate 		if (didnp == NULL) {
21340Sstevel@tonic-gate 			return (-1);
21350Sstevel@tonic-gate 		}
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 		/* determine if devid does NOT exist */
21380Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
21390Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
21400Sstevel@tonic-gate 					didnp->key, ep)) == NULL)
21410Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
21420Sstevel@tonic-gate 			else {
21430Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
21440Sstevel@tonic-gate 				free(dtp);
21450Sstevel@tonic-gate 			}
21460Sstevel@tonic-gate 		}
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 		/* print info */
21490Sstevel@tonic-gate 		/*
21500Sstevel@tonic-gate 		 * This allows the length
21510Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
21520Sstevel@tonic-gate 		 * looking horrible.
21530Sstevel@tonic-gate 		 */
21540Sstevel@tonic-gate 		if (fprintf(fp, "\t%-*s %8lld     %-5.5s %s\n",
21550Sstevel@tonic-gate 		    len, msp->compnamep->cname,
21560Sstevel@tonic-gate 		    start_blk, has_mddb_str, devid) == EOF) {
21570Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21580Sstevel@tonic-gate 		}
21590Sstevel@tonic-gate 		(void) fprintf(fp, "\n");
21600Sstevel@tonic-gate 	}
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	/* print the headers */
21640Sstevel@tonic-gate 	if (fprintf(fp, "\t%6.6s %24.24s %24.24s\n",
21650Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Extent"),
21660Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Start Block"),
21670Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Block count")) == EOF)
21680Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 	/* print out each extent */
21710Sstevel@tonic-gate 	for (extn = 0; (extn < msp->ext.ext_len); extn++) {
21720Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 		/* If PRINT_TIMES option is ever supported, add output here */
21750Sstevel@tonic-gate 		if (fprintf(fp, "\t%6u %24llu %24llu\n",
21760Sstevel@tonic-gate 		    extn, extp->poff, extp->len) == EOF)
21770Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21780Sstevel@tonic-gate 	}
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 	/* separate records with a newline */
21810Sstevel@tonic-gate 	(void) fprintf(fp, "\n");
21820Sstevel@tonic-gate 	return (0);
21830Sstevel@tonic-gate }
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate /*
21860Sstevel@tonic-gate  * FUNCTION:	meta_sp_print()
21870Sstevel@tonic-gate  * INPUT:	sp	- the set name for the unit being displayed
21880Sstevel@tonic-gate  *		np	- the name of the device to print
21890Sstevel@tonic-gate  *		fname	- ??? not used
21900Sstevel@tonic-gate  *		fp	- the file pointer to send output to
21910Sstevel@tonic-gate  *		options	- print options from the command line processor
21920Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
21930Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
21940Sstevel@tonic-gate  * PURPOSE:	print a full report of the device specified by metastat.
21950Sstevel@tonic-gate  *		This is the main entry point for printing.
21960Sstevel@tonic-gate  */
21970Sstevel@tonic-gate int
21980Sstevel@tonic-gate meta_sp_print(
21990Sstevel@tonic-gate 	mdsetname_t	*sp,
22000Sstevel@tonic-gate 	mdname_t	*np,
22010Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
22020Sstevel@tonic-gate 	char		*fname,
22030Sstevel@tonic-gate 	FILE		*fp,
22040Sstevel@tonic-gate 	mdprtopts_t	options,
22050Sstevel@tonic-gate 	md_error_t	*ep
22060Sstevel@tonic-gate )
22070Sstevel@tonic-gate {
22080Sstevel@tonic-gate 	md_sp_t		*msp;
22090Sstevel@tonic-gate 	md_unit_t	*mdp;
22100Sstevel@tonic-gate 	int		rval = 0;
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 	/* should always have the same set */
22130Sstevel@tonic-gate 	assert(sp != NULL);
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 	/* print all the soft partitions */
22160Sstevel@tonic-gate 	if (np == NULL) {
22170Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
22180Sstevel@tonic-gate 		mdnamelist_t	*p;
22190Sstevel@tonic-gate 		int		cnt;
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 		if ((cnt = meta_get_sp_names(sp, &nlp, options, ep)) < 0)
22220Sstevel@tonic-gate 			return (-1);
22230Sstevel@tonic-gate 		else if (cnt == 0)
22240Sstevel@tonic-gate 			return (0);
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 		/* recusively print them out */
22270Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
22280Sstevel@tonic-gate 			mdname_t	*curnp = p->namep;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 			/*
22310Sstevel@tonic-gate 			 * one problem with the rval of -1 here is that
22320Sstevel@tonic-gate 			 * the error gets "lost" when the next device is
22330Sstevel@tonic-gate 			 * printed, but we want to print them all anyway.
22340Sstevel@tonic-gate 			 */
22350Sstevel@tonic-gate 			rval = meta_sp_print(sp, curnp, nlpp, fname, fp,
22360Sstevel@tonic-gate 			    options, ep);
22370Sstevel@tonic-gate 		}
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 		/* clean up, return success */
22400Sstevel@tonic-gate 		metafreenamelist(nlp);
22410Sstevel@tonic-gate 		return (rval);
22420Sstevel@tonic-gate 	}
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	/* get the unit structure */
22450Sstevel@tonic-gate 	if ((msp = meta_get_sp_common(sp, np,
22460Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
22470Sstevel@tonic-gate 		return (-1);
22480Sstevel@tonic-gate 
22490Sstevel@tonic-gate 	/* check for parented */
22500Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
22510Sstevel@tonic-gate 	    (MD_HAS_PARENT(msp->common.parent))) {
22520Sstevel@tonic-gate 		return (0);
22530Sstevel@tonic-gate 	}
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 	/* print appropriate detail */
22560Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
22570Sstevel@tonic-gate 		if (meta_sp_short_print(msp, fname, fp, options, ep) != 0)
22580Sstevel@tonic-gate 			return (-1);
22590Sstevel@tonic-gate 	} else {
22600Sstevel@tonic-gate 		if (meta_sp_report(sp, msp, nlpp, fname, fp, options, ep) != 0)
22610Sstevel@tonic-gate 			return (-1);
22620Sstevel@tonic-gate 	}
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	/*
22650Sstevel@tonic-gate 	 * Print underlying metadevices if they are parented to us and
22660Sstevel@tonic-gate 	 * if the info for the underlying metadevice has not been printed.
22670Sstevel@tonic-gate 	 */
22680Sstevel@tonic-gate 	if (metaismeta(msp->compnamep)) {
22690Sstevel@tonic-gate 		/* get the unit structure for the subdevice */
22700Sstevel@tonic-gate 		if ((mdp = meta_get_mdunit(sp, msp->compnamep, ep)) == NULL)
22710Sstevel@tonic-gate 			return (-1);
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 		/* If info not already printed, recurse */
22740Sstevel@tonic-gate 		if (!BT_TEST(sp_parent_printed, MD_MIN2UNIT(MD_SID(mdp)))) {
22750Sstevel@tonic-gate 			if (meta_print_name(sp, msp->compnamep, nlpp, fname, fp,
22760Sstevel@tonic-gate 			    (options | PRINT_HEADER | PRINT_SUBDEVS),
22770Sstevel@tonic-gate 			    NULL, ep) != 0) {
22780Sstevel@tonic-gate 				return (-1);
22790Sstevel@tonic-gate 			}
22800Sstevel@tonic-gate 			BT_SET(sp_parent_printed, MD_MIN2UNIT(MD_SID(mdp)));
22810Sstevel@tonic-gate 		}
22820Sstevel@tonic-gate 	}
22830Sstevel@tonic-gate 	return (0);
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate /*
22870Sstevel@tonic-gate  * **************************************************************************
22880Sstevel@tonic-gate  *                     Watermark Manipulation Functions                     *
22890Sstevel@tonic-gate  * **************************************************************************
22900Sstevel@tonic-gate  */
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate /*
22930Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_start()
22940Sstevel@tonic-gate  * INPUT:	sp	- the operating set
22950Sstevel@tonic-gate  *		np 	- device upon which the sp is being built
22960Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
22970Sstevel@tonic-gate  * RETURNS:	daddr_t	- -1 if error, otherwise the start block
22980Sstevel@tonic-gate  * PURPOSE:	Encapsulate the determination of the start block of the
22990Sstevel@tonic-gate  *		device upon which the sp is built or being built.
23000Sstevel@tonic-gate  *		This is done to hide the ugliness of the algorithm.  In
23010Sstevel@tonic-gate  *		the case where a sp is being built upon a stripe of > 1
23020Sstevel@tonic-gate  *		TB that is made up of a set of disks in which the first
23030Sstevel@tonic-gate  *		has a VTOC label the result returned from the call to
23040Sstevel@tonic-gate  *		metagetstart is incorrect.  The reason being that a > 1
23050Sstevel@tonic-gate  *		TB metadevice will manufacture an EFI label in which the
23060Sstevel@tonic-gate  *		start address is zero.  This is irrespective of the underlying
23070Sstevel@tonic-gate  *		devices.  The long term fix for this is to fix
23080Sstevel@tonic-gate  *		meta_efi_to_mdvtoc and meta_efi_to mdgeom so that they return
23090Sstevel@tonic-gate  *		values that are indicative of the first underlying device in
23100Sstevel@tonic-gate  *		metadevice.
23110Sstevel@tonic-gate  */
23120Sstevel@tonic-gate static diskaddr_t
23130Sstevel@tonic-gate meta_sp_get_start(
23140Sstevel@tonic-gate 	mdsetname_t	*sp,
23150Sstevel@tonic-gate 	mdname_t	*np,
23160Sstevel@tonic-gate 	md_error_t	*ep
23170Sstevel@tonic-gate )
23180Sstevel@tonic-gate {
23190Sstevel@tonic-gate 	daddr_t		start_block;
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	if ((start_block = metagetstart(sp, np, ep)) != MD_DISKADDR_ERROR) {
23220Sstevel@tonic-gate 		start_block += MD_SP_START;
23230Sstevel@tonic-gate 		/*
23240Sstevel@tonic-gate 		 * In the case that the device upon which the sp is being
23250Sstevel@tonic-gate 		 * created is a metadevice then ensure that in the case that
23260Sstevel@tonic-gate 		 * the first underlying device has a vtoc label that it is
23270Sstevel@tonic-gate 		 * not overwritten with a watermark by setting the start block
23280Sstevel@tonic-gate 		 * to point just past the vtoc label
23290Sstevel@tonic-gate 		 */
23300Sstevel@tonic-gate 		if (start_block < VTOC_SIZE && metaismeta(np))
23310Sstevel@tonic-gate 			start_block = VTOC_SIZE;
23320Sstevel@tonic-gate 	}
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate 	return (start_block);
23350Sstevel@tonic-gate }
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate /*
23380Sstevel@tonic-gate  * FUNCTION:	meta_sp_update_wm()
23390Sstevel@tonic-gate  * INPUT:	sp	- the operating set
23400Sstevel@tonic-gate  *		msp	- a pointer to the XDR unit structure
23410Sstevel@tonic-gate  *		extlist	- the extent list specifying watermarks to update
23420Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
23430Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
23440Sstevel@tonic-gate  * PURPOSE:	steps backwards through the extent list updating
23450Sstevel@tonic-gate  *		watermarks for all extents with the EXTFLG_UPDATE flag
23460Sstevel@tonic-gate  *		set.  Writing the watermarks guarantees consistency when
23470Sstevel@tonic-gate  *		extents must be broken into pieces since the original
23480Sstevel@tonic-gate  *		watermark will be the last to be updated, and will be
23490Sstevel@tonic-gate  *		changed to point to a new watermark that is already
23500Sstevel@tonic-gate  *		known to be consistent.  If one of the writes fails, the
23510Sstevel@tonic-gate  *		original watermark stays intact and none of the changes
23520Sstevel@tonic-gate  *		are realized.
23530Sstevel@tonic-gate  */
23540Sstevel@tonic-gate static int
23550Sstevel@tonic-gate meta_sp_update_wm(
23560Sstevel@tonic-gate 	mdsetname_t	*sp,
23570Sstevel@tonic-gate 	md_sp_t		*msp,
23580Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
23590Sstevel@tonic-gate 	md_error_t	*ep
23600Sstevel@tonic-gate )
23610Sstevel@tonic-gate {
23620Sstevel@tonic-gate 	sp_ext_node_t	*ext;
23630Sstevel@tonic-gate 	sp_ext_node_t	*tail;
23640Sstevel@tonic-gate 	mp_watermark_t	*wmp, *watermarks;
23650Sstevel@tonic-gate 	xsp_offset_t	*osp, *offsets;
23660Sstevel@tonic-gate 	int		update_count = 0;
23670Sstevel@tonic-gate 	int		rval = 0;
23680Sstevel@tonic-gate 	md_unit_t	*mdp;
23690Sstevel@tonic-gate 	md_sp_update_wm_t	update_params;
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
23720Sstevel@tonic-gate 		meta_sp_debug("meta_sp_update_wm: Updating watermarks:\n");
23730Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
23740Sstevel@tonic-gate 	}
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 	/*
23770Sstevel@tonic-gate 	 * find the last node so we can write the watermarks backwards
23780Sstevel@tonic-gate 	 * and count watermarks to update so we can allocate space
23790Sstevel@tonic-gate 	 */
23800Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
23810Sstevel@tonic-gate 		if ((ext->ext_flags & EXTFLG_UPDATE) != 0) {
23820Sstevel@tonic-gate 			update_count++;
23830Sstevel@tonic-gate 		}
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 		if (ext->ext_next == NULL) {
23860Sstevel@tonic-gate 			tail = ext;
23870Sstevel@tonic-gate 		}
23880Sstevel@tonic-gate 	}
23890Sstevel@tonic-gate 	ext = tail;
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 	wmp = watermarks =
23920Sstevel@tonic-gate 	    Zalloc(update_count * sizeof (mp_watermark_t));
23930Sstevel@tonic-gate 	osp = offsets =
23940Sstevel@tonic-gate 	    Zalloc(update_count * sizeof (sp_ext_offset_t));
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate 	while (ext != NULL) {
23970Sstevel@tonic-gate 		if ((ext->ext_flags & EXTFLG_UPDATE) != 0) {
23980Sstevel@tonic-gate 			/* update watermark */
23990Sstevel@tonic-gate 			wmp->wm_magic = MD_SP_MAGIC;
24000Sstevel@tonic-gate 			wmp->wm_version = MD_SP_VERSION;
24010Sstevel@tonic-gate 			wmp->wm_type = ext->ext_type;
24020Sstevel@tonic-gate 			wmp->wm_seq = ext->ext_seq;
24030Sstevel@tonic-gate 			wmp->wm_length = ext->ext_length - MD_SP_WMSIZE;
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 			/* fill in the volume name and set name */
24060Sstevel@tonic-gate 			if (ext->ext_namep != NULL)
24070Sstevel@tonic-gate 				(void) strcpy(wmp->wm_mdname,
24080Sstevel@tonic-gate 				    ext->ext_namep->cname);
24090Sstevel@tonic-gate 			else
24100Sstevel@tonic-gate 				(void) strcpy(wmp->wm_mdname, MD_SP_FREEWMNAME);
24110Sstevel@tonic-gate 			if (ext->ext_setp != NULL &&
24120Sstevel@tonic-gate 			    ext->ext_setp->setno != MD_LOCAL_SET)
24130Sstevel@tonic-gate 				(void) strcpy(wmp->wm_setname,
24140Sstevel@tonic-gate 				    ext->ext_setp->setname);
24150Sstevel@tonic-gate 			else
24160Sstevel@tonic-gate 				(void) strcpy(wmp->wm_setname,
24170Sstevel@tonic-gate 				    MD_SP_LOCALSETNAME);
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate 			/* Generate the checksum */
24200Sstevel@tonic-gate 			wmp->wm_checksum = 0;
24210Sstevel@tonic-gate 			crcgen((uchar_t *)wmp, (uint_t *)&wmp->wm_checksum,
24220Sstevel@tonic-gate 			    sizeof (*wmp), NULL);
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 			/* record the extent offset */
24250Sstevel@tonic-gate 			*osp = ext->ext_offset;
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate 			/* Advance the placeholders */
24280Sstevel@tonic-gate 			osp++; wmp++;
24290Sstevel@tonic-gate 		}
24300Sstevel@tonic-gate 		ext = ext->ext_prev;
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	mdp = meta_get_mdunit(sp, msp->common.namep, ep);
24340Sstevel@tonic-gate 	if (mdp == NULL) {
24350Sstevel@tonic-gate 		rval = -1;
24360Sstevel@tonic-gate 		goto out;
24370Sstevel@tonic-gate 	}
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 	(void) memset(&update_params, 0, sizeof (update_params));
24400Sstevel@tonic-gate 	update_params.mnum = MD_SID(mdp);
24410Sstevel@tonic-gate 	update_params.count = update_count;
24420Sstevel@tonic-gate 	update_params.wmp = (uintptr_t)watermarks;
24430Sstevel@tonic-gate 	update_params.osp = (uintptr_t)offsets;
24440Sstevel@tonic-gate 	MD_SETDRIVERNAME(&update_params, MD_SP,
24450Sstevel@tonic-gate 	    MD_MIN2SET(update_params.mnum));
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPUPDATEWM, &update_params,
24480Sstevel@tonic-gate 	    &update_params.mde, msp->common.namep->cname) != 0) {
24490Sstevel@tonic-gate 		(void) mdstealerror(ep, &update_params.mde);
24500Sstevel@tonic-gate 		rval = -1;
24510Sstevel@tonic-gate 		goto out;
24520Sstevel@tonic-gate 	}
24530Sstevel@tonic-gate 
24540Sstevel@tonic-gate out:
24550Sstevel@tonic-gate 	Free(watermarks);
24560Sstevel@tonic-gate 	Free(offsets);
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	return (rval);
24590Sstevel@tonic-gate }
24600Sstevel@tonic-gate 
24610Sstevel@tonic-gate /*
24620Sstevel@tonic-gate  * FUNCTION:	meta_sp_clear_wm()
24630Sstevel@tonic-gate  * INPUT:	sp	- the operating set
24640Sstevel@tonic-gate  *		msp	- the unit structure for the soft partition to clear
24650Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
24660Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
24670Sstevel@tonic-gate  * PURPOSE:	steps through the extents for a soft partition unit and
24680Sstevel@tonic-gate  *		creates an extent list designed to mark all of the
24690Sstevel@tonic-gate  *		watermarks for those extents as free.  The extent list
24700Sstevel@tonic-gate  *		is then passed to meta_sp_update_wm() to actually write
24710Sstevel@tonic-gate  *		the watermarks out.
24720Sstevel@tonic-gate  */
24730Sstevel@tonic-gate static int
24740Sstevel@tonic-gate meta_sp_clear_wm(
24750Sstevel@tonic-gate 	mdsetname_t	*sp,
24760Sstevel@tonic-gate 	md_sp_t		*msp,
24770Sstevel@tonic-gate 	md_error_t	*ep
24780Sstevel@tonic-gate )
24790Sstevel@tonic-gate {
24800Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
24810Sstevel@tonic-gate 	int		numexts = msp->ext.ext_len;
24820Sstevel@tonic-gate 	uint_t		i;
24830Sstevel@tonic-gate 	int		rval = 0;
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	/* for each watermark must set the flag to SP_FREE */
24860Sstevel@tonic-gate 	for (i = 0; i < numexts; i++) {
24870Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[i];
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, &extlist,
24900Sstevel@tonic-gate 		    extp->poff - MD_SP_WMSIZE, extp->len + MD_SP_WMSIZE,
24910Sstevel@tonic-gate 		    EXTTYP_FREE, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
24920Sstevel@tonic-gate 	}
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 	/* update watermarks */
24950Sstevel@tonic-gate 	rval = meta_sp_update_wm(sp, msp, extlist, ep);
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	meta_sp_list_free(&extlist);
24980Sstevel@tonic-gate 	return (rval);
24990Sstevel@tonic-gate }
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate /*
25020Sstevel@tonic-gate  * FUNCTION:	meta_sp_read_wm()
25030Sstevel@tonic-gate  * INPUT:	sp	- setname for component
25040Sstevel@tonic-gate  *		compnp	- mdname_t for component
25050Sstevel@tonic-gate  *		offset	- the offset of the watermark to read (sectors)
25060Sstevel@tonic-gate  * OUTPUT:	wm	- the watermark structure to read into
25070Sstevel@tonic-gate  *		ep	- return error pointer
25080Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
25090Sstevel@tonic-gate  * PURPOSE:	seeks out to the requested offset and reads a watermark.
25100Sstevel@tonic-gate  *		It then verifies that the magic number is correct and
25110Sstevel@tonic-gate  *		that the checksum is valid, returning an error if either
25120Sstevel@tonic-gate  *		is wrong.
25130Sstevel@tonic-gate  */
25140Sstevel@tonic-gate static int
25150Sstevel@tonic-gate meta_sp_read_wm(
25160Sstevel@tonic-gate 	mdsetname_t	*sp,
25170Sstevel@tonic-gate 	mdname_t	*compnp,
25180Sstevel@tonic-gate 	mp_watermark_t	*wm,
25190Sstevel@tonic-gate 	sp_ext_offset_t	offset,
25200Sstevel@tonic-gate 	md_error_t	*ep
25210Sstevel@tonic-gate )
25220Sstevel@tonic-gate {
25230Sstevel@tonic-gate 	md_sp_read_wm_t	read_params;
25240Sstevel@tonic-gate 
25250Sstevel@tonic-gate 	/*
25260Sstevel@tonic-gate 	 * make sure block offset does not overflow 2^64 bytes and it's a
25270Sstevel@tonic-gate 	 * multiple of the block size.
25280Sstevel@tonic-gate 	 */
25290Sstevel@tonic-gate 	assert(offset <= (1LL << (64 - DEV_BSHIFT)));
25300Sstevel@tonic-gate 	/* LINTED */
25310Sstevel@tonic-gate 	assert((sizeof (*wm) % DEV_BSIZE) == 0);
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	(void) memset(wm, 0, sizeof (*wm));
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 	(void) memset(&read_params, 0, sizeof (read_params));
25360Sstevel@tonic-gate 	read_params.rdev = compnp->dev;
25370Sstevel@tonic-gate 	read_params.wmp = (uintptr_t)wm;
25380Sstevel@tonic-gate 	read_params.offset = offset;
25390Sstevel@tonic-gate 	MD_SETDRIVERNAME(&read_params, MD_SP, sp->setno);
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPREADWM, &read_params,
25420Sstevel@tonic-gate 	    &read_params.mde, compnp->cname) != 0) {
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
25450Sstevel@tonic-gate 		    "Extent header read failed, block %llu.\n"), offset);
25460Sstevel@tonic-gate 		return (mdstealerror(ep, &read_params.mde));
25470Sstevel@tonic-gate 	}
25480Sstevel@tonic-gate 
25490Sstevel@tonic-gate 	/* make sure magic number is correct */
25500Sstevel@tonic-gate 	if (wm->wm_magic != MD_SP_MAGIC) {
25510Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
25520Sstevel@tonic-gate 		    "found incorrect magic number %x, expected %x.\n"),
25530Sstevel@tonic-gate 		    wm->wm_magic, MD_SP_MAGIC);
25540Sstevel@tonic-gate 		/*
25550Sstevel@tonic-gate 		 * Pass NULL for the device name as we don't have
25560Sstevel@tonic-gate 		 * valid watermark contents.
25570Sstevel@tonic-gate 		 */
25580Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BADWMMAGIC, 0, NULL));
25590Sstevel@tonic-gate 	}
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	if (crcchk((uchar_t *)wm, (uint_t *)&wm->wm_checksum,
25620Sstevel@tonic-gate 	    sizeof (*wm), NULL)) {
25630Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
25640Sstevel@tonic-gate 		    "found incorrect checksum %x.\n"),
25650Sstevel@tonic-gate 		    wm->wm_checksum);
25660Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BADWMCRC, 0, wm->wm_mdname));
25670Sstevel@tonic-gate 	}
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate 	return (0);
25700Sstevel@tonic-gate }
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate /*
25730Sstevel@tonic-gate  * **************************************************************************
25740Sstevel@tonic-gate  *                  Query Functions
25750Sstevel@tonic-gate  * **************************************************************************
25760Sstevel@tonic-gate  */
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate /*
25790Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that assumes that
25800Sstevel@tonic-gate  *		   its input parameters have been checked and
25810Sstevel@tonic-gate  *		   have valid values that lie within acceptable
25820Sstevel@tonic-gate  *		   ranges.
25830Sstevel@tonic-gate  *
25840Sstevel@tonic-gate  * FUNCTION:	meta_sp_enough_space()
25850Sstevel@tonic-gate  * INPUT:	desired_number_of_sps - the number of soft partitions desired;
25860Sstevel@tonic-gate  *					must be > 0
25870Sstevel@tonic-gate  *		desired_sp_size - the desired soft partition size in blocks;
25880Sstevel@tonic-gate  *				  must be > 0
25890Sstevel@tonic-gate  *		extent_listpp - a reference to a reference to an extent
25900Sstevel@tonic-gate  *				list that lists the extents on a device;
25910Sstevel@tonic-gate  *				must be a reference to a reference to a
25920Sstevel@tonic-gate  *				valid extent list
25930Sstevel@tonic-gate  *		alignment - the desired data space alignment for the sp's
25940Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
25950Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if there's enough space in the extent
25960Sstevel@tonic-gate  *			    list to create the desired soft partitions,
25970Sstevel@tonic-gate  *			    B_FALSE if there's not enough space
25980Sstevel@tonic-gate  * PURPOSE:	determines whether there's enough free space in an extent
25990Sstevel@tonic-gate  *		list to allow creation of a set of soft partitions
26000Sstevel@tonic-gate  */
26010Sstevel@tonic-gate static boolean_t
26020Sstevel@tonic-gate meta_sp_enough_space(
26030Sstevel@tonic-gate 	int		desired_number_of_sps,
26040Sstevel@tonic-gate 	blkcnt_t	desired_sp_size,
26050Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp,
26060Sstevel@tonic-gate 	sp_ext_length_t	alignment
26070Sstevel@tonic-gate )
26080Sstevel@tonic-gate {
26090Sstevel@tonic-gate 	boolean_t		enough_space;
26100Sstevel@tonic-gate 	int			number_of_sps;
26110Sstevel@tonic-gate 	int			number_of_extents_used;
26120Sstevel@tonic-gate 	sp_ext_length_t		desired_ext_length = desired_sp_size;
26130Sstevel@tonic-gate 
26140Sstevel@tonic-gate 	enough_space = B_TRUE;
26150Sstevel@tonic-gate 	number_of_sps = 0;
26160Sstevel@tonic-gate 	while ((enough_space == B_TRUE) &&
26170Sstevel@tonic-gate 		(number_of_sps < desired_number_of_sps)) {
26180Sstevel@tonic-gate 		/*
26190Sstevel@tonic-gate 		 * Use the extent allocation algorithm implemented by
26200Sstevel@tonic-gate 		 * meta_sp_alloc_by_len() to test whether the free
26210Sstevel@tonic-gate 		 * extents in the extent list referenced by *extent_listpp
26220Sstevel@tonic-gate 		 * contain enough space to accomodate a soft partition
26230Sstevel@tonic-gate 		 * of size desired_ext_length.
26240Sstevel@tonic-gate 		 *
26250Sstevel@tonic-gate 		 * Repeat the test <desired_number_of_sps> times
26260Sstevel@tonic-gate 		 * or until it fails, whichever comes first,
26270Sstevel@tonic-gate 		 * each time allocating the extents required to
26280Sstevel@tonic-gate 		 * create the soft partition without actually
26290Sstevel@tonic-gate 		 * creating the soft partition.
26300Sstevel@tonic-gate 		 */
26310Sstevel@tonic-gate 		number_of_extents_used = meta_sp_alloc_by_len(
26320Sstevel@tonic-gate 						TEST_SETNAMEP,
26330Sstevel@tonic-gate 						TEST_SOFT_PARTITION_NAMEP,
26340Sstevel@tonic-gate 						extent_listpp,
26350Sstevel@tonic-gate 						&desired_ext_length,
26360Sstevel@tonic-gate 						NO_OFFSET,
26370Sstevel@tonic-gate 						alignment);
26380Sstevel@tonic-gate 		if (number_of_extents_used == -1) {
26390Sstevel@tonic-gate 			enough_space = B_FALSE;
26400Sstevel@tonic-gate 		} else {
26410Sstevel@tonic-gate 			number_of_sps++;
26420Sstevel@tonic-gate 		}
26430Sstevel@tonic-gate 	}
26440Sstevel@tonic-gate 	return (enough_space);
26450Sstevel@tonic-gate }
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate /*
26480Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that calls other functions
26490Sstevel@tonic-gate  *		   that check its mdsetnamep and device_mdnamep
26500Sstevel@tonic-gate  *		   input parameters, but expects extent_listpp to
26510Sstevel@tonic-gate  *		   be a initialized to a valid address to which
26520Sstevel@tonic-gate  *		   it can write a reference to the extent list that
26530Sstevel@tonic-gate  *		   it creates.
26540Sstevel@tonic-gate  *
26550Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_extent_list()
26560Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
26570Sstevel@tonic-gate  *			     for the set containing the device for
26580Sstevel@tonic-gate  *			     which the extents are to be listed
26590Sstevel@tonic-gate  *		device_mdnamep - a reference to the mdname_t structure
26600Sstevel@tonic-gate  *				 for the device for which the extents
26610Sstevel@tonic-gate  *				 are to be listed
26620Sstevel@tonic-gate  * OUTPUT:	*extent_listpp - a reference to the extent list for
26630Sstevel@tonic-gate  *				 the device; NULL if the function fails
26640Sstevel@tonic-gate  *		*ep - the libmeta error encountered, if any
26650Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the function call was successful,
26660Sstevel@tonic-gate  *			    B_FALSE if not
26670Sstevel@tonic-gate  * PURPOSE:	gets the extent list for a device
26680Sstevel@tonic-gate  */
26690Sstevel@tonic-gate static boolean_t
26700Sstevel@tonic-gate meta_sp_get_extent_list(
26710Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
26720Sstevel@tonic-gate 	mdname_t	*device_mdnamep,
26730Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp,
26740Sstevel@tonic-gate 	md_error_t	*ep
26750Sstevel@tonic-gate )
26760Sstevel@tonic-gate {
26770Sstevel@tonic-gate 	diskaddr_t		device_size_in_blocks;
26780Sstevel@tonic-gate 	mdnamelist_t		*sp_name_listp;
26790Sstevel@tonic-gate 	diskaddr_t		start_block_address_in_blocks;
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 	*extent_listpp = NULL;
26820Sstevel@tonic-gate 	sp_name_listp = NULL;
26830Sstevel@tonic-gate 
26840Sstevel@tonic-gate 	start_block_address_in_blocks = meta_sp_get_start(mdsetnamep,
26850Sstevel@tonic-gate 						device_mdnamep,
26860Sstevel@tonic-gate 						ep);
26870Sstevel@tonic-gate 	if (start_block_address_in_blocks == MD_DISKADDR_ERROR) {
26880Sstevel@tonic-gate 	    if (getenv(META_SP_DEBUG)) {
26890Sstevel@tonic-gate 		mde_perror(ep, "meta_sp_get_extent_list:meta_sp_get_start");
26900Sstevel@tonic-gate 	    }
26910Sstevel@tonic-gate 	    return (B_FALSE);
26920Sstevel@tonic-gate 	}
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	device_size_in_blocks = metagetsize(device_mdnamep, ep);
26950Sstevel@tonic-gate 	if (device_size_in_blocks == MD_DISKADDR_ERROR) {
26960Sstevel@tonic-gate 	    if (getenv(META_SP_DEBUG)) {
26970Sstevel@tonic-gate 		mde_perror(ep,
26980Sstevel@tonic-gate 		    "meta_sp_get_extent_list:metagetsize");
26990Sstevel@tonic-gate 	    }
27000Sstevel@tonic-gate 	    return (B_FALSE);
27010Sstevel@tonic-gate 	}
27020Sstevel@tonic-gate 
27030Sstevel@tonic-gate 	/*
27040Sstevel@tonic-gate 	 * Sanity check: the start block will have skipped an integer
27050Sstevel@tonic-gate 	 * number of cylinders, C.  C will usually be zero.  If (C > 0),
27060Sstevel@tonic-gate 	 * and the disk slice happens to only be C cylinders in total
27070Sstevel@tonic-gate 	 * size, we'll fail this check.
27080Sstevel@tonic-gate 	 */
27090Sstevel@tonic-gate 	if (device_size_in_blocks <=
27100Sstevel@tonic-gate 	    (start_block_address_in_blocks + MD_SP_WMSIZE)) {
27110Sstevel@tonic-gate 	    (void) mdmderror(ep, MDE_SP_NOSPACE, 0, device_mdnamep->cname);
27120Sstevel@tonic-gate 	    return (B_FALSE);
27130Sstevel@tonic-gate 	}
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate 	/*
27160Sstevel@tonic-gate 	 * After this point, we will have allocated resources, so any
27170Sstevel@tonic-gate 	 * failure returns must be through the supplied "fail" label
27180Sstevel@tonic-gate 	 * to properly deallocate things.
27190Sstevel@tonic-gate 	 */
27200Sstevel@tonic-gate 
27210Sstevel@tonic-gate 	/*
27220Sstevel@tonic-gate 	 * Create an empty extent list that starts one watermark past
27230Sstevel@tonic-gate 	 * the start block of the device and ends one watermark before
27240Sstevel@tonic-gate 	 * the end of the device.
27250Sstevel@tonic-gate 	 */
27260Sstevel@tonic-gate 	meta_sp_list_insert(TEST_SETNAMEP,
27270Sstevel@tonic-gate 			    TEST_SOFT_PARTITION_NAMEP,
27280Sstevel@tonic-gate 			    extent_listpp,
27290Sstevel@tonic-gate 			    NO_OFFSET,
27300Sstevel@tonic-gate 			    (sp_ext_length_t)start_block_address_in_blocks,
27310Sstevel@tonic-gate 			    EXTTYP_RESERVED,
27320Sstevel@tonic-gate 			    NO_SEQUENCE_NUMBER,
27330Sstevel@tonic-gate 			    NO_FLAGS,
27340Sstevel@tonic-gate 			    meta_sp_cmp_by_offset);
27350Sstevel@tonic-gate 	meta_sp_list_insert(TEST_SETNAMEP,
27360Sstevel@tonic-gate 			    TEST_SOFT_PARTITION_NAMEP,
27370Sstevel@tonic-gate 			    extent_listpp,
27380Sstevel@tonic-gate 			    (sp_ext_offset_t)(device_size_in_blocks -
27390Sstevel@tonic-gate 				MD_SP_WMSIZE),
27400Sstevel@tonic-gate 			    MD_SP_WMSIZE,
27410Sstevel@tonic-gate 			    EXTTYP_END,
27420Sstevel@tonic-gate 			    NO_SEQUENCE_NUMBER,
27430Sstevel@tonic-gate 			    NO_FLAGS,
27440Sstevel@tonic-gate 			    meta_sp_cmp_by_offset);
27450Sstevel@tonic-gate 
27460Sstevel@tonic-gate 	/*
27470Sstevel@tonic-gate 	 * Get the list of soft partitions that are already on the
27480Sstevel@tonic-gate 	 * device.
27490Sstevel@tonic-gate 	 */
27500Sstevel@tonic-gate 	if (meta_sp_get_by_component(mdsetnamep, device_mdnamep,
27510Sstevel@tonic-gate 	    &sp_name_listp, FORCE_RELOAD_CACHE, ep) < 1) {
27520Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
27530Sstevel@tonic-gate 			mde_perror(ep,
27540Sstevel@tonic-gate 			    "meta_sp_get_extent_list:meta_sp_get_by_component");
27550Sstevel@tonic-gate 		}
27560Sstevel@tonic-gate 		goto fail;
27570Sstevel@tonic-gate 	}
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	if (sp_name_listp != NULL) {
27600Sstevel@tonic-gate 		/*
27610Sstevel@tonic-gate 		 * If there are soft partitions on the device, add the
27620Sstevel@tonic-gate 		 * extents used in them to the extent list.
27630Sstevel@tonic-gate 		 */
27640Sstevel@tonic-gate 		if (meta_sp_extlist_from_namelist(mdsetnamep, sp_name_listp,
27650Sstevel@tonic-gate 		    extent_listpp, ep) == -1) {
27660Sstevel@tonic-gate 			if (getenv(META_SP_DEBUG)) {
27670Sstevel@tonic-gate 				mde_perror(ep, "meta_sp_get_extent_list:"
27680Sstevel@tonic-gate 				    "meta_sp_extlist_from_namelist");
27690Sstevel@tonic-gate 			}
27700Sstevel@tonic-gate 			goto fail;
27710Sstevel@tonic-gate 		}
27720Sstevel@tonic-gate 		metafreenamelist(sp_name_listp);
27730Sstevel@tonic-gate 	}
27740Sstevel@tonic-gate 
27750Sstevel@tonic-gate 	/*
27760Sstevel@tonic-gate 	 * Add free extents to the extent list to represent
27770Sstevel@tonic-gate 	 * the remaining regions of free space on the
27780Sstevel@tonic-gate 	 * device.
27790Sstevel@tonic-gate 	 */
27800Sstevel@tonic-gate 	meta_sp_list_freefill(extent_listpp, device_size_in_blocks);
27810Sstevel@tonic-gate 	return (B_TRUE);
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate fail:
27840Sstevel@tonic-gate 	if (sp_name_listp != NULL) {
27850Sstevel@tonic-gate 		metafreenamelist(sp_name_listp);
27860Sstevel@tonic-gate 	}
27870Sstevel@tonic-gate 
27880Sstevel@tonic-gate 	if (*extent_listpp != NULL) {
27890Sstevel@tonic-gate 		/*
27900Sstevel@tonic-gate 		 * meta_sp_list_free sets *extent_listpp to NULL.
27910Sstevel@tonic-gate 		 */
27920Sstevel@tonic-gate 		meta_sp_list_free(extent_listpp);
27930Sstevel@tonic-gate 	}
27940Sstevel@tonic-gate 	return (B_FALSE);
27950Sstevel@tonic-gate }
27960Sstevel@tonic-gate 
27970Sstevel@tonic-gate /*
27980Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that calls other functions
27990Sstevel@tonic-gate  *		   that check its mdsetnamep and mddrivenamep
28000Sstevel@tonic-gate  *		   input parameters, but expects extent_listpp to
28010Sstevel@tonic-gate  *		   be a initialized to a valid address to which
28020Sstevel@tonic-gate  *		   it can write a reference to the extent list that
28030Sstevel@tonic-gate  *		   it creates.
28040Sstevel@tonic-gate  *
28050Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_extent_list_for_drive()
28060Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
28070Sstevel@tonic-gate  *			     for the set containing the drive for
28080Sstevel@tonic-gate  *			     which the extents are to be listed
28090Sstevel@tonic-gate  *		mddrivenamep   - a reference to the mddrivename_t structure
28100Sstevel@tonic-gate  *				 for the drive for which the extents
28110Sstevel@tonic-gate  *				 are to be listed
28120Sstevel@tonic-gate  * OUTPUT:	*extent_listpp - a reference to the extent list for
28130Sstevel@tonic-gate  *				 the drive; NULL if the function fails
28140Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the function call was successful,
28150Sstevel@tonic-gate  *			    B_FALSE if not
28160Sstevel@tonic-gate  * PURPOSE:	gets the extent list for a drive when the entire drive
28170Sstevel@tonic-gate  *		is to be soft partitioned
28180Sstevel@tonic-gate  */
28190Sstevel@tonic-gate static boolean_t
28200Sstevel@tonic-gate meta_sp_get_extent_list_for_drive(
28210Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
28220Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
28230Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp
28240Sstevel@tonic-gate )
28250Sstevel@tonic-gate {
28260Sstevel@tonic-gate 	boolean_t		can_use;
28270Sstevel@tonic-gate 	diskaddr_t		free_space;
28280Sstevel@tonic-gate 	md_error_t		mderror;
28290Sstevel@tonic-gate 	mdvtoc_t		proposed_vtoc;
28300Sstevel@tonic-gate 	int			repartition_options;
28310Sstevel@tonic-gate 	int			return_value;
28320Sstevel@tonic-gate 	md_sp_t			test_sp_struct;
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate 	can_use = B_TRUE;
28350Sstevel@tonic-gate 	*extent_listpp = NULL;
28360Sstevel@tonic-gate 	mderror = mdnullerror;
28370Sstevel@tonic-gate 	test_sp_struct.compnamep = metaslicename(mddrivenamep, MD_SLICE0,
28380Sstevel@tonic-gate 					&mderror);
28390Sstevel@tonic-gate 	if (test_sp_struct.compnamep == NULL) {
28400Sstevel@tonic-gate 		can_use = B_FALSE;
28410Sstevel@tonic-gate 	}
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate 	if (can_use == B_TRUE) {
28440Sstevel@tonic-gate 		mderror = mdnullerror;
28450Sstevel@tonic-gate 		repartition_options = 0;
28460Sstevel@tonic-gate 		return_value = meta_check_sp(mdsetnamep, &test_sp_struct,
28470Sstevel@tonic-gate 				MDCMD_USE_WHOLE_DISK, &repartition_options,
28480Sstevel@tonic-gate 				&mderror);
28490Sstevel@tonic-gate 		if (return_value != 0) {
28500Sstevel@tonic-gate 			can_use = B_FALSE;
28510Sstevel@tonic-gate 		}
28520Sstevel@tonic-gate 	}
28530Sstevel@tonic-gate 
28540Sstevel@tonic-gate 	if (can_use == B_TRUE) {
28550Sstevel@tonic-gate 		mderror = mdnullerror;
28560Sstevel@tonic-gate 		repartition_options = repartition_options |
28570Sstevel@tonic-gate 			(MD_REPART_FORCE | MD_REPART_DONT_LABEL);
28580Sstevel@tonic-gate 		return_value = meta_repartition_drive(mdsetnamep, mddrivenamep,
28590Sstevel@tonic-gate 				repartition_options, &proposed_vtoc, &mderror);
28600Sstevel@tonic-gate 		if (return_value != 0) {
28610Sstevel@tonic-gate 			can_use = B_FALSE;
28620Sstevel@tonic-gate 		}
28630Sstevel@tonic-gate 	}
28640Sstevel@tonic-gate 
28650Sstevel@tonic-gate 	if (can_use == B_TRUE) {
28660Sstevel@tonic-gate 		free_space = proposed_vtoc.parts[MD_SLICE0].size;
28670Sstevel@tonic-gate 		if (free_space <= (MD_SP_START + MD_SP_WMSIZE)) {
28680Sstevel@tonic-gate 			can_use = B_FALSE;
28690Sstevel@tonic-gate 		}
28700Sstevel@tonic-gate 	}
28710Sstevel@tonic-gate 
28720Sstevel@tonic-gate 	if (can_use == B_TRUE) {
28730Sstevel@tonic-gate 		/*
28740Sstevel@tonic-gate 		 * Create an extent list that starts with
28750Sstevel@tonic-gate 		 * a reserved extent that ends at the start
28760Sstevel@tonic-gate 		 * of the usable space on slice zero of the
28770Sstevel@tonic-gate 		 * proposed VTOC, ends with an extent that
28780Sstevel@tonic-gate 		 * reserves space for a watermark at the end
28790Sstevel@tonic-gate 		 * of slice zero, and contains a single free
28800Sstevel@tonic-gate 		 * extent that occupies the rest of the space
28810Sstevel@tonic-gate 		 * on the slice.
28820Sstevel@tonic-gate 		 *
28830Sstevel@tonic-gate 		 * NOTE:
28840Sstevel@tonic-gate 		 *
28850Sstevel@tonic-gate 		 * Don't use metagetstart() or metagetsize() to
28860Sstevel@tonic-gate 		 * find the usable space.  They query the mdname_t
28870Sstevel@tonic-gate 		 * structure that represents an actual device to
28880Sstevel@tonic-gate 		 * determine the amount of space on the device that
28890Sstevel@tonic-gate 		 * contains metadata and the total amount of space
28900Sstevel@tonic-gate 		 * on the device.  Since this function creates a
28910Sstevel@tonic-gate 		 * proposed extent list that doesn't reflect the
28920Sstevel@tonic-gate 		 * state of an actual device, there's no mdname_t
28930Sstevel@tonic-gate 		 * structure to be queried.
28940Sstevel@tonic-gate 		 *
28950Sstevel@tonic-gate 		 * When a drive is reformatted to prepare for
28960Sstevel@tonic-gate 		 * soft partitioning, all of slice seven is
28970Sstevel@tonic-gate 		 * reserved for metadata, all of slice zero is
28980Sstevel@tonic-gate 		 * available for soft partitioning, and all other
28990Sstevel@tonic-gate 		 * slices on the drive are empty.  The proposed
29000Sstevel@tonic-gate 		 * extent list for the drive therefore contains
29010Sstevel@tonic-gate 		 * only three extents: a reserved extent that ends
29020Sstevel@tonic-gate 		 * at the start of the usable space on slice zero,
29030Sstevel@tonic-gate 		 * a single free extent that occupies all the usable
29040Sstevel@tonic-gate 		 * space on slice zero, and an ending extent that
29050Sstevel@tonic-gate 		 * reserves space for a watermark at the end of
29060Sstevel@tonic-gate 		 * slice zero.
29070Sstevel@tonic-gate 		 */
29080Sstevel@tonic-gate 		meta_sp_list_insert(TEST_SETNAMEP,
29090Sstevel@tonic-gate 			TEST_SOFT_PARTITION_NAMEP,
29100Sstevel@tonic-gate 			extent_listpp,
29110Sstevel@tonic-gate 			NO_OFFSET,
29120Sstevel@tonic-gate 			(sp_ext_length_t)(MD_SP_START),
29130Sstevel@tonic-gate 			EXTTYP_RESERVED,
29140Sstevel@tonic-gate 			NO_SEQUENCE_NUMBER,
29150Sstevel@tonic-gate 			NO_FLAGS,
29160Sstevel@tonic-gate 			meta_sp_cmp_by_offset);
29170Sstevel@tonic-gate 		meta_sp_list_insert(TEST_SETNAMEP,
29180Sstevel@tonic-gate 			TEST_SOFT_PARTITION_NAMEP,
29190Sstevel@tonic-gate 			extent_listpp,
29200Sstevel@tonic-gate 			(sp_ext_offset_t)(free_space - MD_SP_WMSIZE),
29210Sstevel@tonic-gate 			MD_SP_WMSIZE,
29220Sstevel@tonic-gate 			EXTTYP_END,
29230Sstevel@tonic-gate 			NO_SEQUENCE_NUMBER,
29240Sstevel@tonic-gate 			NO_FLAGS,
29250Sstevel@tonic-gate 			meta_sp_cmp_by_offset);
29260Sstevel@tonic-gate 		meta_sp_list_freefill(extent_listpp, free_space);
29270Sstevel@tonic-gate 	}
29280Sstevel@tonic-gate 	return (can_use);
29290Sstevel@tonic-gate }
29300Sstevel@tonic-gate 
29310Sstevel@tonic-gate /*
29320Sstevel@tonic-gate  * FUNCTION:	meta_sp_can_create_sps()
29330Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
29340Sstevel@tonic-gate  *			     for the set containing the device for
29350Sstevel@tonic-gate  *			     which the extents are to be listed
29360Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
29370Sstevel@tonic-gate  *			  on which the soft parititions are to be created
29380Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
29390Sstevel@tonic-gate  *		sp_size - the desired soft partition size
29400Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
29410Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the soft partitionns can be created,
29420Sstevel@tonic-gate  *			    B_FALSE if not
29430Sstevel@tonic-gate  * PURPOSE:	determines whether a set of soft partitions can be created
29440Sstevel@tonic-gate  *		on a device
29450Sstevel@tonic-gate  */
29460Sstevel@tonic-gate boolean_t
29470Sstevel@tonic-gate meta_sp_can_create_sps(
29480Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
29490Sstevel@tonic-gate 	mdname_t	*mdnamep,
29500Sstevel@tonic-gate 	int		number_of_sps,
29510Sstevel@tonic-gate 	blkcnt_t	sp_size
29520Sstevel@tonic-gate )
29530Sstevel@tonic-gate {
29540Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
29550Sstevel@tonic-gate 	boolean_t	succeeded;
29560Sstevel@tonic-gate 	md_error_t	mde;
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 	if ((number_of_sps > 0) && (sp_size > 0)) {
29590Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list(mdsetnamep, mdnamep,
29600Sstevel@tonic-gate 						    &extent_listp, &mde);
29610Sstevel@tonic-gate 	} else {
29620Sstevel@tonic-gate 		succeeded = B_FALSE;
29630Sstevel@tonic-gate 	}
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	/*
29660Sstevel@tonic-gate 	 * We don't really care about an error return from the
29670Sstevel@tonic-gate 	 * alignment call; that will just result in passing zero,
29680Sstevel@tonic-gate 	 * which will be interpreted as no alignment.
29690Sstevel@tonic-gate 	 */
29700Sstevel@tonic-gate 
29710Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
29720Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(number_of_sps,
29730Sstevel@tonic-gate 		    sp_size, &extent_listp,
29740Sstevel@tonic-gate 		    meta_sp_get_default_alignment(mdsetnamep, mdnamep, &mde));
29750Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
29760Sstevel@tonic-gate 	}
29770Sstevel@tonic-gate 	return (succeeded);
29780Sstevel@tonic-gate }
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate /*
29810Sstevel@tonic-gate  * FUNCTION:	meta_sp_can_create_sps_on_drive()
29820Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
29830Sstevel@tonic-gate  *			     for the set containing the drive for
29840Sstevel@tonic-gate  *			     which the extents are to be listed
29850Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
29860Sstevel@tonic-gate  *			       on which the soft parititions are to be created
29870Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
29880Sstevel@tonic-gate  *		sp_size - the desired soft partition size
29890Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
29900Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the soft partitionns can be created,
29910Sstevel@tonic-gate  *			    B_FALSE if not
29920Sstevel@tonic-gate  * PURPOSE:	determines whether a set of soft partitions can be created
29930Sstevel@tonic-gate  *		on a drive if the entire drive is soft partitioned
29940Sstevel@tonic-gate  */
29950Sstevel@tonic-gate boolean_t
29960Sstevel@tonic-gate meta_sp_can_create_sps_on_drive(
29970Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
29980Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
29990Sstevel@tonic-gate 	int		number_of_sps,
30000Sstevel@tonic-gate 	blkcnt_t	sp_size
30010Sstevel@tonic-gate )
30020Sstevel@tonic-gate {
30030Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
30040Sstevel@tonic-gate 	boolean_t	succeeded;
30050Sstevel@tonic-gate 
30060Sstevel@tonic-gate 	if ((number_of_sps > 0) && (sp_size > 0)) {
30070Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
30080Sstevel@tonic-gate 							mddrivenamep,
30090Sstevel@tonic-gate 							&extent_listp);
30100Sstevel@tonic-gate 	} else {
30110Sstevel@tonic-gate 		succeeded = B_FALSE;
30120Sstevel@tonic-gate 	}
30130Sstevel@tonic-gate 
30140Sstevel@tonic-gate 	/*
30150Sstevel@tonic-gate 	 * We don't care about alignment on the space call because
30160Sstevel@tonic-gate 	 * we're specifically dealing with a drive, which will have no
30170Sstevel@tonic-gate 	 * inherent alignment.
30180Sstevel@tonic-gate 	 */
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
30210Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(number_of_sps, sp_size,
30220Sstevel@tonic-gate 		    &extent_listp, SP_UNALIGNED);
30230Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
30240Sstevel@tonic-gate 	}
30250Sstevel@tonic-gate 	return (succeeded);
30260Sstevel@tonic-gate }
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate /*
30290Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_free_space()
30300Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
30310Sstevel@tonic-gate  *			     for the set containing the device for
30320Sstevel@tonic-gate  *			     which the free space is to be returned
30330Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
30340Sstevel@tonic-gate  *			  for which the free space is to be returned
30350Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
30360Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the number of blocks of free space on the device
30370Sstevel@tonic-gate  * PURPOSE:	returns the number of blocks of free space on a device
30380Sstevel@tonic-gate  */
30390Sstevel@tonic-gate blkcnt_t
30400Sstevel@tonic-gate meta_sp_get_free_space(
30410Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
30420Sstevel@tonic-gate 	mdname_t	*mdnamep
30430Sstevel@tonic-gate )
30440Sstevel@tonic-gate {
30450Sstevel@tonic-gate 	sp_ext_node_t		*extent_listp;
30460Sstevel@tonic-gate 	sp_ext_length_t		free_blocks;
30470Sstevel@tonic-gate 	boolean_t		succeeded;
30480Sstevel@tonic-gate 	md_error_t		mde;
30490Sstevel@tonic-gate 
30500Sstevel@tonic-gate 	extent_listp = NULL;
30510Sstevel@tonic-gate 	free_blocks = 0;
30520Sstevel@tonic-gate 	succeeded = meta_sp_get_extent_list(mdsetnamep, mdnamep,
30530Sstevel@tonic-gate 					    &extent_listp, &mde);
30540Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
30550Sstevel@tonic-gate 		free_blocks = meta_sp_list_size(extent_listp,
30560Sstevel@tonic-gate 		    EXTTYP_FREE, INCLUDE_WM);
30570Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
30580Sstevel@tonic-gate 		if (free_blocks > (10 * MD_SP_WMSIZE)) {
30590Sstevel@tonic-gate 			/*
30600Sstevel@tonic-gate 			 * Subtract a safety margin for watermarks when
30610Sstevel@tonic-gate 			 * computing the number of blocks available for
30620Sstevel@tonic-gate 			 * use.  The actual number of watermarks can't
30630Sstevel@tonic-gate 			 * be calculated without knowing the exact numbers
30640Sstevel@tonic-gate 			 * and sizes of both the free extents and the soft
30650Sstevel@tonic-gate 			 * partitions to be created.  The calculation is
30660Sstevel@tonic-gate 			 * highly complex and error-prone even if those
30670Sstevel@tonic-gate 			 * quantities are known.  The approximate value
30680Sstevel@tonic-gate 			 * 10 * MD_SP_WMSIZE is within a few blocks of the
30690Sstevel@tonic-gate 			 * correct value in all practical cases.
30700Sstevel@tonic-gate 			 */
30710Sstevel@tonic-gate 			free_blocks = free_blocks - (10 * MD_SP_WMSIZE);
30720Sstevel@tonic-gate 		} else {
30730Sstevel@tonic-gate 			free_blocks = 0;
30740Sstevel@tonic-gate 		}
30750Sstevel@tonic-gate 	} else {
30760Sstevel@tonic-gate 	    mdclrerror(&mde);
30770Sstevel@tonic-gate 	}
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate 	return (free_blocks);
30800Sstevel@tonic-gate }
30810Sstevel@tonic-gate 
30820Sstevel@tonic-gate /*
30830Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_free_space_on_drive()
30840Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
30850Sstevel@tonic-gate  *			     for the set containing the drive for
30860Sstevel@tonic-gate  *			     which the free space is to be returned
30870Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
30880Sstevel@tonic-gate  *			       for which the free space is to be returned
30890Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
30900Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the number of blocks of free space on the drive
30910Sstevel@tonic-gate  * PURPOSE:	returns the number of blocks of space usable for soft
30920Sstevel@tonic-gate  *		partitions on an entire drive, if the entire drive is
30930Sstevel@tonic-gate  *		soft partitioned
30940Sstevel@tonic-gate  */
30950Sstevel@tonic-gate blkcnt_t
30960Sstevel@tonic-gate meta_sp_get_free_space_on_drive(
30970Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
30980Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep
30990Sstevel@tonic-gate )
31000Sstevel@tonic-gate {
31010Sstevel@tonic-gate 	sp_ext_node_t		*extent_listp;
31020Sstevel@tonic-gate 	sp_ext_length_t		free_blocks;
31030Sstevel@tonic-gate 	boolean_t		succeeded;
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate 	extent_listp = NULL;
31060Sstevel@tonic-gate 	free_blocks = 0;
31070Sstevel@tonic-gate 	succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
31080Sstevel@tonic-gate 			mddrivenamep, &extent_listp);
31090Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
31100Sstevel@tonic-gate 		free_blocks = meta_sp_list_size(extent_listp,
31110Sstevel@tonic-gate 		    EXTTYP_FREE, INCLUDE_WM);
31120Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
31130Sstevel@tonic-gate 		if (free_blocks > (10 * MD_SP_WMSIZE)) {
31140Sstevel@tonic-gate 			/*
31150Sstevel@tonic-gate 			 * Subtract a safety margin for watermarks when
31160Sstevel@tonic-gate 			 * computing the number of blocks available for
31170Sstevel@tonic-gate 			 * use.  The actual number of watermarks can't
31180Sstevel@tonic-gate 			 * be calculated without knowing the exact numbers
31190Sstevel@tonic-gate 			 * and sizes of both the free extents and the soft
31200Sstevel@tonic-gate 			 * partitions to be created.  The calculation is
31210Sstevel@tonic-gate 			 * highly complex and error-prone even if those
31220Sstevel@tonic-gate 			 * quantities are known.  The approximate value
31230Sstevel@tonic-gate 			 * 10 * MD_SP_WMSIZE is within a few blocks of the
31240Sstevel@tonic-gate 			 * correct value in all practical cases.
31250Sstevel@tonic-gate 			 */
31260Sstevel@tonic-gate 			free_blocks = free_blocks - (10 * MD_SP_WMSIZE);
31270Sstevel@tonic-gate 		} else {
31280Sstevel@tonic-gate 			free_blocks = 0;
31290Sstevel@tonic-gate 		}
31300Sstevel@tonic-gate 	}
31310Sstevel@tonic-gate 	return (free_blocks);
31320Sstevel@tonic-gate }
31330Sstevel@tonic-gate 
31340Sstevel@tonic-gate /*
31350Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_number_of_possible_sps()
31360Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
31370Sstevel@tonic-gate  *			     for the set containing the device for
31380Sstevel@tonic-gate  *			     which the number of possible soft partitions
31390Sstevel@tonic-gate  *			     is to be returned
31400Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
31410Sstevel@tonic-gate  *			  for which the number of possible soft partitions
31420Sstevel@tonic-gate  *			  is to be returned
31430Sstevel@tonic-gate  * OUTPUT:	int return value
31440Sstevel@tonic-gate  * RETURNS:	int - the number of soft partitions of the desired size
31450Sstevel@tonic-gate  *		      that can be created on the device
31460Sstevel@tonic-gate  * PURPOSE:	returns the number of soft partitions of a given size
31470Sstevel@tonic-gate  *		that can be created on a device
31480Sstevel@tonic-gate  */
31490Sstevel@tonic-gate int
31500Sstevel@tonic-gate meta_sp_get_number_of_possible_sps(
31510Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
31520Sstevel@tonic-gate 	mdname_t	*mdnamep,
31530Sstevel@tonic-gate 	blkcnt_t	sp_size
31540Sstevel@tonic-gate )
31550Sstevel@tonic-gate {
31560Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
31570Sstevel@tonic-gate 	int		number_of_possible_sps;
31580Sstevel@tonic-gate 	boolean_t	succeeded;
31590Sstevel@tonic-gate 	md_error_t	mde;
31600Sstevel@tonic-gate 	sp_ext_length_t	alignment;
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate 	extent_listp = NULL;
31630Sstevel@tonic-gate 	number_of_possible_sps = 0;
31640Sstevel@tonic-gate 	if (sp_size > 0) {
31650Sstevel@tonic-gate 	    if ((succeeded = meta_sp_get_extent_list(mdsetnamep,
31660Sstevel@tonic-gate 		mdnamep, &extent_listp, &mde)) == B_FALSE)
31670Sstevel@tonic-gate 		mdclrerror(&mde);
31680Sstevel@tonic-gate 	} else {
31690Sstevel@tonic-gate 		succeeded = B_FALSE;
31700Sstevel@tonic-gate 	}
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
31730Sstevel@tonic-gate 		alignment = meta_sp_get_default_alignment(mdsetnamep,
31740Sstevel@tonic-gate 		    mdnamep, &mde);
31750Sstevel@tonic-gate 	}
31760Sstevel@tonic-gate 
31770Sstevel@tonic-gate 	while (succeeded == B_TRUE) {
31780Sstevel@tonic-gate 		/*
31790Sstevel@tonic-gate 		 * Keep allocating space from the extent list
31800Sstevel@tonic-gate 		 * for soft partitions of the desired size until
31810Sstevel@tonic-gate 		 * there's not enough free space left in the list
31820Sstevel@tonic-gate 		 * for another soft partiition of that size.
31830Sstevel@tonic-gate 		 * Add one to the number of possible soft partitions
31840Sstevel@tonic-gate 		 * for each soft partition for which there is
31850Sstevel@tonic-gate 		 * enough free space left.
31860Sstevel@tonic-gate 		 */
31870Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(ONE_SOFT_PARTITION,
31880Sstevel@tonic-gate 		    sp_size, &extent_listp, alignment);
31890Sstevel@tonic-gate 		if (succeeded == B_TRUE) {
31900Sstevel@tonic-gate 			number_of_possible_sps++;
31910Sstevel@tonic-gate 		}
31920Sstevel@tonic-gate 	}
31930Sstevel@tonic-gate 	if (extent_listp != NULL) {
31940Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
31950Sstevel@tonic-gate 	}
31960Sstevel@tonic-gate 	return (number_of_possible_sps);
31970Sstevel@tonic-gate }
31980Sstevel@tonic-gate 
31990Sstevel@tonic-gate /*
32000Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_number_of_possible_sps_on_drive()
32010Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
32020Sstevel@tonic-gate  *			     for the set containing the drive for
32030Sstevel@tonic-gate  *			     which the number of possible soft partitions
32040Sstevel@tonic-gate  *			     is to be returned
32050Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
32060Sstevel@tonic-gate  *			       for which the number of possible soft partitions
32070Sstevel@tonic-gate  *			       is to be returned
32080Sstevel@tonic-gate  *		sp_size - the size in blocks of the proposed soft partitions
32090Sstevel@tonic-gate  * OUTPUT:	int return value
32100Sstevel@tonic-gate  * RETURNS:	int - the number of soft partitions of the desired size
32110Sstevel@tonic-gate  *		      that can be created on the drive
32120Sstevel@tonic-gate  * PURPOSE:	returns the number of soft partitions of a given size
32130Sstevel@tonic-gate  *		that can be created on a drive, if the entire drive is
32140Sstevel@tonic-gate  *		soft partitioned
32150Sstevel@tonic-gate  */
32160Sstevel@tonic-gate int
32170Sstevel@tonic-gate meta_sp_get_number_of_possible_sps_on_drive(
32180Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
32190Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
32200Sstevel@tonic-gate 	blkcnt_t	sp_size
32210Sstevel@tonic-gate )
32220Sstevel@tonic-gate {
32230Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
32240Sstevel@tonic-gate 	int		number_of_possible_sps;
32250Sstevel@tonic-gate 	boolean_t	succeeded;
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate 	extent_listp = NULL;
32280Sstevel@tonic-gate 	number_of_possible_sps = 0;
32290Sstevel@tonic-gate 	if (sp_size > 0) {
32300Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
32310Sstevel@tonic-gate 					mddrivenamep, &extent_listp);
32320Sstevel@tonic-gate 	} else {
32330Sstevel@tonic-gate 		succeeded = B_FALSE;
32340Sstevel@tonic-gate 	}
32350Sstevel@tonic-gate 	while (succeeded == B_TRUE) {
32360Sstevel@tonic-gate 		/*
32370Sstevel@tonic-gate 		 * Keep allocating space from the extent list
32380Sstevel@tonic-gate 		 * for soft partitions of the desired size until
32390Sstevel@tonic-gate 		 * there's not enough free space left in the list
32400Sstevel@tonic-gate 		 * for another soft partition of that size.
32410Sstevel@tonic-gate 		 * Add one to the number of possible soft partitions
32420Sstevel@tonic-gate 		 * for each soft partition for which there is
32430Sstevel@tonic-gate 		 * enough free space left.
32440Sstevel@tonic-gate 		 *
32450Sstevel@tonic-gate 		 * Since it's a drive, not a metadevice, make no
32460Sstevel@tonic-gate 		 * assumptions about alignment.
32470Sstevel@tonic-gate 		 */
32480Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(ONE_SOFT_PARTITION,
32490Sstevel@tonic-gate 		    sp_size, &extent_listp, SP_UNALIGNED);
32500Sstevel@tonic-gate 		if (succeeded == B_TRUE) {
32510Sstevel@tonic-gate 			number_of_possible_sps++;
32520Sstevel@tonic-gate 		}
32530Sstevel@tonic-gate 	}
32540Sstevel@tonic-gate 	if (extent_listp != NULL) {
32550Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
32560Sstevel@tonic-gate 	}
32570Sstevel@tonic-gate 	return (number_of_possible_sps);
32580Sstevel@tonic-gate }
32590Sstevel@tonic-gate 
32600Sstevel@tonic-gate /*
32610Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_possible_sp_size()
32620Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
32630Sstevel@tonic-gate  *			     for the set containing the device for
32640Sstevel@tonic-gate  *			     which the possible soft partition size
32650Sstevel@tonic-gate  *			     is to be returned
32660Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
32670Sstevel@tonic-gate  *			  for which the possible soft partition size
32680Sstevel@tonic-gate  *			  is to be returned
32690Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
32700Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
32710Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the possible soft partition size in blocks
32720Sstevel@tonic-gate  * PURPOSE:	returns the maximum possible size of each of a given number of
32730Sstevel@tonic-gate  *		soft partitions of equal size that can be created on a device
32740Sstevel@tonic-gate  */
32750Sstevel@tonic-gate blkcnt_t
32760Sstevel@tonic-gate meta_sp_get_possible_sp_size(
32770Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
32780Sstevel@tonic-gate 	mdname_t	*mdnamep,
32790Sstevel@tonic-gate 	int		number_of_sps
32800Sstevel@tonic-gate )
32810Sstevel@tonic-gate {
32820Sstevel@tonic-gate 	blkcnt_t	free_blocks;
32830Sstevel@tonic-gate 	blkcnt_t	sp_size;
32840Sstevel@tonic-gate 	boolean_t	succeeded;
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate 	sp_size = 0;
32870Sstevel@tonic-gate 	if (number_of_sps > 0) {
32880Sstevel@tonic-gate 		free_blocks = meta_sp_get_free_space(mdsetnamep, mdnamep);
32890Sstevel@tonic-gate 		sp_size = free_blocks / number_of_sps;
32900Sstevel@tonic-gate 		succeeded = meta_sp_can_create_sps(mdsetnamep, mdnamep,
32910Sstevel@tonic-gate 						number_of_sps, sp_size);
32920Sstevel@tonic-gate 		while ((succeeded == B_FALSE) && (sp_size > 0)) {
32930Sstevel@tonic-gate 			/*
32940Sstevel@tonic-gate 			 * To compensate for space that may have been
32950Sstevel@tonic-gate 			 * occupied by watermarks, reduce sp_size by a
32960Sstevel@tonic-gate 			 * number of blocks equal to the number of soft
32970Sstevel@tonic-gate 			 * partitions desired, and test again to see
32980Sstevel@tonic-gate 			 * whether the desired number of soft partitions
32990Sstevel@tonic-gate 			 * can be created.
33000Sstevel@tonic-gate 			 */
33010Sstevel@tonic-gate 			sp_size = sp_size - ((blkcnt_t)number_of_sps);
33020Sstevel@tonic-gate 			succeeded = meta_sp_can_create_sps(mdsetnamep, mdnamep,
33030Sstevel@tonic-gate 							number_of_sps, sp_size);
33040Sstevel@tonic-gate 		}
33050Sstevel@tonic-gate 		if (sp_size < 0) {
33060Sstevel@tonic-gate 			sp_size = 0;
33070Sstevel@tonic-gate 		}
33080Sstevel@tonic-gate 	}
33090Sstevel@tonic-gate 	return (sp_size);
33100Sstevel@tonic-gate }
33110Sstevel@tonic-gate 
33120Sstevel@tonic-gate /*
33130Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_possible_sp_size_on_drive()
33140Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
33150Sstevel@tonic-gate  *			     for the set containing the drive for
33160Sstevel@tonic-gate  *			     which the possible soft partition size
33170Sstevel@tonic-gate  *			     is to be returned
33180Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
33190Sstevel@tonic-gate  *			       for which the possible soft partition size
33200Sstevel@tonic-gate  *			       is to be returned
33210Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
33220Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
33230Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the possible soft partition size in blocks
33240Sstevel@tonic-gate  * PURPOSE:	returns the maximum possible size of each of a given number of
33250Sstevel@tonic-gate  *		soft partitions of equal size that can be created on a drive
33260Sstevel@tonic-gate  *              if the entire drive is soft partitioned
33270Sstevel@tonic-gate  */
33280Sstevel@tonic-gate blkcnt_t
33290Sstevel@tonic-gate meta_sp_get_possible_sp_size_on_drive(
33300Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
33310Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
33320Sstevel@tonic-gate 	int		number_of_sps
33330Sstevel@tonic-gate )
33340Sstevel@tonic-gate {
33350Sstevel@tonic-gate 	blkcnt_t	free_blocks;
33360Sstevel@tonic-gate 	blkcnt_t	sp_size;
33370Sstevel@tonic-gate 	boolean_t	succeeded;
33380Sstevel@tonic-gate 
33390Sstevel@tonic-gate 	sp_size = 0;
33400Sstevel@tonic-gate 	if (number_of_sps > 0) {
33410Sstevel@tonic-gate 		free_blocks = meta_sp_get_free_space_on_drive(mdsetnamep,
33420Sstevel@tonic-gate 								mddrivenamep);
33430Sstevel@tonic-gate 		sp_size = free_blocks / number_of_sps;
33440Sstevel@tonic-gate 		succeeded = meta_sp_can_create_sps_on_drive(mdsetnamep,
33450Sstevel@tonic-gate 						mddrivenamep,
33460Sstevel@tonic-gate 						number_of_sps, sp_size);
33470Sstevel@tonic-gate 		while ((succeeded == B_FALSE) && (sp_size > 0)) {
33480Sstevel@tonic-gate 			/*
33490Sstevel@tonic-gate 			 * To compensate for space that may have been
33500Sstevel@tonic-gate 			 * occupied by watermarks, reduce sp_size by a
33510Sstevel@tonic-gate 			 * number of blocks equal to the number of soft
33520Sstevel@tonic-gate 			 * partitions desired, and test again to see
33530Sstevel@tonic-gate 			 * whether the desired number of soft partitions
33540Sstevel@tonic-gate 			 * can be created.
33550Sstevel@tonic-gate 			 */
33560Sstevel@tonic-gate 			sp_size = sp_size - ((blkcnt_t)number_of_sps);
33570Sstevel@tonic-gate 			succeeded = meta_sp_can_create_sps_on_drive(mdsetnamep,
33580Sstevel@tonic-gate 							mddrivenamep,
33590Sstevel@tonic-gate 							number_of_sps, sp_size);
33600Sstevel@tonic-gate 		}
33610Sstevel@tonic-gate 		if (sp_size < 0) {
33620Sstevel@tonic-gate 			sp_size = 0;
33630Sstevel@tonic-gate 		}
33640Sstevel@tonic-gate 	}
33650Sstevel@tonic-gate 	return (sp_size);
33660Sstevel@tonic-gate }
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate /*
33690Sstevel@tonic-gate  * **************************************************************************
33700Sstevel@tonic-gate  *                  Unit Structure Manipulation Functions                   *
33710Sstevel@tonic-gate  * **************************************************************************
33720Sstevel@tonic-gate  */
33730Sstevel@tonic-gate 
33740Sstevel@tonic-gate /*
33750Sstevel@tonic-gate  * FUNCTION:	meta_sp_fillextarray()
33760Sstevel@tonic-gate  * INPUT:	mp	- the unit structure to fill
33770Sstevel@tonic-gate  *		extlist	- the list of extents to fill with
33780Sstevel@tonic-gate  * OUTPUT:	none
33790Sstevel@tonic-gate  * RETURNS:	void
33800Sstevel@tonic-gate  * PURPOSE:	fills in the unit structure extent list with the extents
33810Sstevel@tonic-gate  *		specified by extlist.  Only extents in extlist with the
33820Sstevel@tonic-gate  *		EXTFLG_UPDATE flag are changed in the unit structure,
33830Sstevel@tonic-gate  *		and the index into the unit structure is the sequence
33840Sstevel@tonic-gate  *		number in the extent list.  After all of the nodes have
33850Sstevel@tonic-gate  *		been updated the virtual offsets in the unit structure
33860Sstevel@tonic-gate  *		are updated to reflect the new lengths.
33870Sstevel@tonic-gate  */
33880Sstevel@tonic-gate static void
33890Sstevel@tonic-gate meta_sp_fillextarray(
33900Sstevel@tonic-gate 	mp_unit_t	*mp,
33910Sstevel@tonic-gate 	sp_ext_node_t	*extlist
33920Sstevel@tonic-gate )
33930Sstevel@tonic-gate {
33940Sstevel@tonic-gate 	int	i;
33950Sstevel@tonic-gate 	sp_ext_node_t	*ext;
33960Sstevel@tonic-gate 	sp_ext_offset_t	curvoff = 0LL;
33970Sstevel@tonic-gate 
33980Sstevel@tonic-gate 	assert(mp != NULL);
33990Sstevel@tonic-gate 
34000Sstevel@tonic-gate 	/* go through the allocation list and fill in our unit structure */
34010Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
34020Sstevel@tonic-gate 		if ((ext->ext_type == EXTTYP_ALLOC) &&
34030Sstevel@tonic-gate 		    (ext->ext_flags & EXTFLG_UPDATE) != 0) {
34040Sstevel@tonic-gate 			mp->un_ext[ext->ext_seq].un_poff =
34050Sstevel@tonic-gate 			    ext->ext_offset + MD_SP_WMSIZE;
34060Sstevel@tonic-gate 			mp->un_ext[ext->ext_seq].un_len =
34070Sstevel@tonic-gate 			    ext->ext_length - MD_SP_WMSIZE;
34080Sstevel@tonic-gate 		}
34090Sstevel@tonic-gate 	}
34100Sstevel@tonic-gate 
34110Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
34120Sstevel@tonic-gate 		assert(mp->un_ext[i].un_poff != 0);
34130Sstevel@tonic-gate 		assert(mp->un_ext[i].un_len  != 0);
34140Sstevel@tonic-gate 		mp->un_ext[i].un_voff = curvoff;
34150Sstevel@tonic-gate 		curvoff += mp->un_ext[i].un_len;
34160Sstevel@tonic-gate 	}
34170Sstevel@tonic-gate }
34180Sstevel@tonic-gate 
34190Sstevel@tonic-gate /*
34200Sstevel@tonic-gate  * FUNCTION:	meta_sp_createunit()
34210Sstevel@tonic-gate  * INPUT:	np	- the name of the device to create a unit structure for
34220Sstevel@tonic-gate  *		compnp	- the name of the device the soft partition is on
34230Sstevel@tonic-gate  *		extlist	- the extent list to populate the new unit with
34240Sstevel@tonic-gate  *		numexts	- the number of extents in the extent list
34250Sstevel@tonic-gate  *		len	- the total size of the soft partition (sectors)
34260Sstevel@tonic-gate  *		status	- the initial status of the unit structure
34270Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
34280Sstevel@tonic-gate  * RETURNS:	mp_unit_t * - the new unit structure.
34290Sstevel@tonic-gate  * PURPOSE:	allocates and fills in a new soft partition unit
34300Sstevel@tonic-gate  *		structure to be passed to the soft partitioning driver
34310Sstevel@tonic-gate  *		for creation.
34320Sstevel@tonic-gate  */
34330Sstevel@tonic-gate static mp_unit_t *
34340Sstevel@tonic-gate meta_sp_createunit(
34350Sstevel@tonic-gate 	mdname_t	*np,
34360Sstevel@tonic-gate 	mdname_t	*compnp,
34370Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
34380Sstevel@tonic-gate 	int		numexts,
34390Sstevel@tonic-gate 	sp_ext_length_t	len,
34400Sstevel@tonic-gate 	sp_status_t	status,
34410Sstevel@tonic-gate 	md_error_t	*ep
34420Sstevel@tonic-gate )
34430Sstevel@tonic-gate {
34440Sstevel@tonic-gate 	mp_unit_t	*mp;
34450Sstevel@tonic-gate 	uint_t		ms_size;
34460Sstevel@tonic-gate 
34470Sstevel@tonic-gate 	ms_size = (sizeof (*mp) - sizeof (mp->un_ext[0])) +
34480Sstevel@tonic-gate 	    (numexts * sizeof (mp->un_ext[0]));
34490Sstevel@tonic-gate 
34500Sstevel@tonic-gate 	mp = Zalloc(ms_size);
34510Sstevel@tonic-gate 
34520Sstevel@tonic-gate 	/* fill in fields in common unit structure */
34530Sstevel@tonic-gate 	mp->c.un_type = MD_METASP;
34540Sstevel@tonic-gate 	mp->c.un_size = ms_size;
34550Sstevel@tonic-gate 	MD_SID(mp) = meta_getminor(np->dev);
34560Sstevel@tonic-gate 	mp->c.un_total_blocks = len;
34570Sstevel@tonic-gate 	mp->c.un_actual_tb = len;
34580Sstevel@tonic-gate 
34590Sstevel@tonic-gate 	/* set up geometry */
34600Sstevel@tonic-gate 	(void) meta_sp_setgeom(np, compnp, mp, ep);
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate 	/* if we're building on metadevice we can't parent */
34630Sstevel@tonic-gate 	if (metaismeta(compnp))
34640Sstevel@tonic-gate 		MD_CAPAB(mp) = MD_CANT_PARENT;
34650Sstevel@tonic-gate 	else
34660Sstevel@tonic-gate 		MD_CAPAB(mp) = MD_CAN_PARENT;
34670Sstevel@tonic-gate 
34680Sstevel@tonic-gate 	/* fill soft partition-specific fields */
34690Sstevel@tonic-gate 	mp->un_dev = compnp->dev;
34700Sstevel@tonic-gate 	mp->un_key = compnp->key;
34710Sstevel@tonic-gate 
34720Sstevel@tonic-gate 	/* mdname_t start_blk field is not 64-bit! */
34730Sstevel@tonic-gate 	mp->un_start_blk = (sp_ext_offset_t)compnp->start_blk;
34740Sstevel@tonic-gate 	mp->un_status = status;
34750Sstevel@tonic-gate 	mp->un_numexts = numexts;
34760Sstevel@tonic-gate 	mp->un_length = len;
34770Sstevel@tonic-gate 
34780Sstevel@tonic-gate 	/* fill in the extent array */
34790Sstevel@tonic-gate 	meta_sp_fillextarray(mp, extlist);
34800Sstevel@tonic-gate 
34810Sstevel@tonic-gate 	return (mp);
34820Sstevel@tonic-gate }
34830Sstevel@tonic-gate 
34840Sstevel@tonic-gate /*
34850Sstevel@tonic-gate  * FUNCTION:	meta_sp_updateunit()
34860Sstevel@tonic-gate  * INPUT:	np       - name structure for the metadevice being updated
34870Sstevel@tonic-gate  *		old_un	 - the original unit structure that is being updated
34880Sstevel@tonic-gate  *		extlist	 - the extent list to populate the new unit with
34890Sstevel@tonic-gate  *		grow_len - the amount by which the partition is being grown
34900Sstevel@tonic-gate  *		numexts	 - the number of extents in the extent list
34910Sstevel@tonic-gate  *		ep       - return error pointer
34920Sstevel@tonic-gate  * OUTPUT:	none
34930Sstevel@tonic-gate  * RETURNS:	mp_unit_t * - the updated unit structure
34940Sstevel@tonic-gate  * PURPOSE:	allocates and fills in a new soft partition unit structure to
34950Sstevel@tonic-gate  *		be passed to the soft partitioning driver for creation.  The
34960Sstevel@tonic-gate  *		old unit structure is first copied in, and then the updated
34970Sstevel@tonic-gate  *		extents are changed in the new unit structure.  This is
34980Sstevel@tonic-gate  *		typically used when the size of an existing unit is changed.
34990Sstevel@tonic-gate  */
35000Sstevel@tonic-gate static mp_unit_t *
35010Sstevel@tonic-gate meta_sp_updateunit(
35020Sstevel@tonic-gate 	mdname_t	*np,
35030Sstevel@tonic-gate 	mp_unit_t	*old_un,
35040Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
35050Sstevel@tonic-gate 	sp_ext_length_t	grow_len,
35060Sstevel@tonic-gate 	int		numexts,
35070Sstevel@tonic-gate 	md_error_t	*ep
35080Sstevel@tonic-gate )
35090Sstevel@tonic-gate {
35100Sstevel@tonic-gate 	mp_unit_t	*new_un;
35110Sstevel@tonic-gate 	sp_ext_length_t	new_len;
35120Sstevel@tonic-gate 	uint_t		new_size;
35130Sstevel@tonic-gate 
35140Sstevel@tonic-gate 	assert(old_un != NULL);
35150Sstevel@tonic-gate 	assert(extlist != NULL);
35160Sstevel@tonic-gate 
35170Sstevel@tonic-gate 	/* allocate new unit structure and copy in old unit */
35180Sstevel@tonic-gate 	new_size = (sizeof (*old_un) - sizeof (old_un->un_ext[0])) +
35190Sstevel@tonic-gate 	    ((old_un->un_numexts + numexts) * sizeof (old_un->un_ext[0]));
35200Sstevel@tonic-gate 	new_len = old_un->un_length + grow_len;
35210Sstevel@tonic-gate 	new_un = Zalloc(new_size);
35220Sstevel@tonic-gate 	bcopy(old_un, new_un, old_un->c.un_size);
35230Sstevel@tonic-gate 
35240Sstevel@tonic-gate 	/* update size and geometry information */
35250Sstevel@tonic-gate 	new_un->c.un_size = new_size;
35260Sstevel@tonic-gate 	new_un->un_length = new_len;
35270Sstevel@tonic-gate 	new_un->c.un_total_blocks = new_len;
35280Sstevel@tonic-gate 	new_un->c.un_actual_tb = new_len;
35290Sstevel@tonic-gate 	if (meta_adjust_geom((md_unit_t *)new_un, np,
35300Sstevel@tonic-gate 	    old_un->c.un_wr_reinstruct, old_un->c.un_rd_reinstruct,
35310Sstevel@tonic-gate 	    0, ep) != 0) {
35320Sstevel@tonic-gate 		Free(new_un);
35330Sstevel@tonic-gate 		return (NULL);
35340Sstevel@tonic-gate 	}
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 	/* update extent information */
35370Sstevel@tonic-gate 	new_un->un_numexts += numexts;
35380Sstevel@tonic-gate 
35390Sstevel@tonic-gate 	meta_sp_fillextarray(new_un, extlist);
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate 	return (new_un);
35420Sstevel@tonic-gate }
35430Sstevel@tonic-gate 
35440Sstevel@tonic-gate /*
35450Sstevel@tonic-gate  * FUNCTION:	meta_get_sp()
35460Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to get
35470Sstevel@tonic-gate  *		np	- the name of the device to get
35480Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
35490Sstevel@tonic-gate  * RETURNS:	md_sp_t * - the XDR unit structure for the soft partition
35500Sstevel@tonic-gate  * PURPOSE:	interface to the rest of libmeta for fetching a unit structure
35510Sstevel@tonic-gate  *		for the named device.  Just a wrapper for meta_get_sp_common().
35520Sstevel@tonic-gate  */
35530Sstevel@tonic-gate md_sp_t *
35540Sstevel@tonic-gate meta_get_sp(
35550Sstevel@tonic-gate 	mdsetname_t	*sp,
35560Sstevel@tonic-gate 	mdname_t	*np,
35570Sstevel@tonic-gate 	md_error_t	*ep
35580Sstevel@tonic-gate )
35590Sstevel@tonic-gate {
35600Sstevel@tonic-gate 	return (meta_get_sp_common(sp, np, 0, ep));
35610Sstevel@tonic-gate }
35620Sstevel@tonic-gate 
35630Sstevel@tonic-gate /*
35640Sstevel@tonic-gate  * FUNCTION:	meta_get_sp_common()
35650Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to get
35660Sstevel@tonic-gate  *		np	- the name of the device to get
35670Sstevel@tonic-gate  *		fast	- whether to use the cache or not (NOT IMPLEMENTED!)
35680Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
35690Sstevel@tonic-gate  * RETURNS:	md_sp_t * - the XDR unit structure for the soft partition,
35700Sstevel@tonic-gate  *			    NULL if np is not a soft partition
35710Sstevel@tonic-gate  * PURPOSE:	common routine for fetching a soft partition unit structure
35720Sstevel@tonic-gate  */
35730Sstevel@tonic-gate md_sp_t *
35740Sstevel@tonic-gate meta_get_sp_common(
35750Sstevel@tonic-gate 	mdsetname_t	*sp,
35760Sstevel@tonic-gate 	mdname_t	*np,
35770Sstevel@tonic-gate 	int		fast,
35780Sstevel@tonic-gate 	md_error_t	*ep
35790Sstevel@tonic-gate )
35800Sstevel@tonic-gate {
35810Sstevel@tonic-gate 	mddrivename_t	*dnp = np->drivenamep;
35820Sstevel@tonic-gate 	char		*miscname;
35830Sstevel@tonic-gate 	mp_unit_t	*mp;
35840Sstevel@tonic-gate 	md_sp_t		*msp;
35850Sstevel@tonic-gate 	int		i;
35860Sstevel@tonic-gate 
35870Sstevel@tonic-gate 	/* must have set */
35880Sstevel@tonic-gate 	assert(sp != NULL);
35890Sstevel@tonic-gate 
35900Sstevel@tonic-gate 	/* short circuit */
35910Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
35920Sstevel@tonic-gate 		if (dnp->unitp->type != MD_METASP)
35930Sstevel@tonic-gate 			return (NULL);
35940Sstevel@tonic-gate 		return ((md_sp_t *)dnp->unitp);
35950Sstevel@tonic-gate 	}
35960Sstevel@tonic-gate 	/* get miscname and unit */
35970Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
35980Sstevel@tonic-gate 		return (NULL);
35990Sstevel@tonic-gate 
36000Sstevel@tonic-gate 	if (strcmp(miscname, MD_SP) != 0) {
36010Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_SP, 0, np->cname);
36020Sstevel@tonic-gate 		return (NULL);
36030Sstevel@tonic-gate 	}
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 	if ((mp = (mp_unit_t *)meta_get_mdunit(sp, np, ep)) == NULL)
36060Sstevel@tonic-gate 		return (NULL);
36070Sstevel@tonic-gate 
36080Sstevel@tonic-gate 	assert(mp->c.un_type == MD_METASP);
36090Sstevel@tonic-gate 
36100Sstevel@tonic-gate 	/* allocate soft partition */
36110Sstevel@tonic-gate 	msp = Zalloc(sizeof (*msp));
36120Sstevel@tonic-gate 
36130Sstevel@tonic-gate 	/* get the common information */
36140Sstevel@tonic-gate 	msp->common.namep = np;
36150Sstevel@tonic-gate 	msp->common.type = mp->c.un_type;
36160Sstevel@tonic-gate 	msp->common.state = mp->c.un_status;
36170Sstevel@tonic-gate 	msp->common.capabilities = mp->c.un_capabilities;
36180Sstevel@tonic-gate 	msp->common.parent = mp->c.un_parent;
36190Sstevel@tonic-gate 	msp->common.size = mp->c.un_total_blocks;
36200Sstevel@tonic-gate 	msp->common.user_flags = mp->c.un_user_flags;
36210Sstevel@tonic-gate 	msp->common.revision = mp->c.un_revision;
36220Sstevel@tonic-gate 
36230Sstevel@tonic-gate 	/* get soft partition information */
36240Sstevel@tonic-gate 	if ((msp->compnamep = metakeyname(&sp, mp->un_key, fast, ep)) == NULL)
36250Sstevel@tonic-gate 		goto out;
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 	/*
36280Sstevel@tonic-gate 	 * Fill in the key and the start block.  Note that the start
36290Sstevel@tonic-gate 	 * block in the unit structure is 64 bits but the name pointer
36300Sstevel@tonic-gate 	 * only supports 32 bits.
36310Sstevel@tonic-gate 	 */
36320Sstevel@tonic-gate 	msp->compnamep->key = mp->un_key;
36330Sstevel@tonic-gate 	msp->compnamep->start_blk = mp->un_start_blk;
36340Sstevel@tonic-gate 
36350Sstevel@tonic-gate 	/* fill in status field */
36360Sstevel@tonic-gate 	msp->status = mp->un_status;
36370Sstevel@tonic-gate 
36380Sstevel@tonic-gate 	/* allocate the extents */
36390Sstevel@tonic-gate 	msp->ext.ext_val = Zalloc(mp->un_numexts * sizeof (*msp->ext.ext_val));
36400Sstevel@tonic-gate 	msp->ext.ext_len = mp->un_numexts;
36410Sstevel@tonic-gate 
36420Sstevel@tonic-gate 	/* do the extents for this soft partition */
36430Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
36440Sstevel@tonic-gate 		struct mp_ext	*mde = &mp->un_ext[i];
36450Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[i];
36460Sstevel@tonic-gate 
36470Sstevel@tonic-gate 		extp->voff = mde->un_voff;
36480Sstevel@tonic-gate 		extp->poff = mde->un_poff;
36490Sstevel@tonic-gate 		extp->len = mde->un_len;
36500Sstevel@tonic-gate 	}
36510Sstevel@tonic-gate 
36520Sstevel@tonic-gate 	/* cleanup, return success */
36530Sstevel@tonic-gate 	Free(mp);
36540Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)msp;
36550Sstevel@tonic-gate 	return (msp);
36560Sstevel@tonic-gate 
36570Sstevel@tonic-gate out:
36580Sstevel@tonic-gate 	/* clean up and return error */
36590Sstevel@tonic-gate 	Free(mp);
36600Sstevel@tonic-gate 	Free(msp);
36610Sstevel@tonic-gate 	return (NULL);
36620Sstevel@tonic-gate }
36630Sstevel@tonic-gate 
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate /*
36660Sstevel@tonic-gate  * FUNCTION:	meta_init_sp()
36670Sstevel@tonic-gate  * INPUT:	spp	- the set name for the new device
36680Sstevel@tonic-gate  *		argc	- the remaining argument count for the metainit cmdline
36690Sstevel@tonic-gate  *		argv	- the remainder of the unparsed command line
36700Sstevel@tonic-gate  *		options	- global options parsed by metainit
36710Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
36720Sstevel@tonic-gate  * RETURNS:	int	- -1 failure, 0 success
36730Sstevel@tonic-gate  * PURPOSE:	provides the command line parsing and name management overhead
36740Sstevel@tonic-gate  *		for creating a new soft partition.  Ultimately this calls
36750Sstevel@tonic-gate  *		meta_create_sp() which does the real work of allocating space
36760Sstevel@tonic-gate  *		for the new soft partition.
36770Sstevel@tonic-gate  */
36780Sstevel@tonic-gate int
36790Sstevel@tonic-gate meta_init_sp(
36800Sstevel@tonic-gate 	mdsetname_t	**spp,
36810Sstevel@tonic-gate 	int		argc,
36820Sstevel@tonic-gate 	char		*argv[],
36830Sstevel@tonic-gate 	mdcmdopts_t	options,
36840Sstevel@tonic-gate 	md_error_t	*ep
36850Sstevel@tonic-gate )
36860Sstevel@tonic-gate {
36870Sstevel@tonic-gate 	char		*compname = NULL;
36880Sstevel@tonic-gate 	mdname_t	*spcompnp = NULL;	/* name of component volume */
36890Sstevel@tonic-gate 	char		*devname = argv[0];	/* unit name */
36900Sstevel@tonic-gate 	mdname_t	*np = NULL;		/* name of soft partition */
36910Sstevel@tonic-gate 	md_sp_t		*msp = NULL;
36920Sstevel@tonic-gate 	int		c;
36930Sstevel@tonic-gate 	int		old_optind;
36940Sstevel@tonic-gate 	sp_ext_length_t	len = 0LL;
36950Sstevel@tonic-gate 	int		rval = -1;
36960Sstevel@tonic-gate 	uint_t		seq;
36970Sstevel@tonic-gate 	int		oflag;
36980Sstevel@tonic-gate 	int		failed;
36990Sstevel@tonic-gate 	mddrivename_t	*dnp = NULL;
37000Sstevel@tonic-gate 	sp_ext_length_t	alignment = 0LL;
37010Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
37020Sstevel@tonic-gate 
37030Sstevel@tonic-gate 	assert(argc > 0);
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 	/* expect sp name, -p, optional -e, compname, and size parameters */
37060Sstevel@tonic-gate 	/* grab soft partition name */
37070Sstevel@tonic-gate 	if ((np = metaname(spp, devname, ep)) == NULL)
37080Sstevel@tonic-gate 		goto out;
37090Sstevel@tonic-gate 
37100Sstevel@tonic-gate 	/* see if it exists already */
37110Sstevel@tonic-gate 	if (metagetmiscname(np, ep) != NULL) {
37120Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
37130Sstevel@tonic-gate 		    meta_getminor(np->dev), devname);
37140Sstevel@tonic-gate 		goto out;
37150Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
37160Sstevel@tonic-gate 		goto out;
37170Sstevel@tonic-gate 	} else {
37180Sstevel@tonic-gate 		mdclrerror(ep);
37190Sstevel@tonic-gate 	}
37200Sstevel@tonic-gate 	--argc, ++argv;
37210Sstevel@tonic-gate 
37220Sstevel@tonic-gate 	if (argc == 0)
37230Sstevel@tonic-gate 		goto syntax;
37240Sstevel@tonic-gate 
37250Sstevel@tonic-gate 	/* grab -p */
37260Sstevel@tonic-gate 	if (strcmp(argv[0], "-p") != 0)
37270Sstevel@tonic-gate 		goto syntax;
37280Sstevel@tonic-gate 	--argc, ++argv;
37290Sstevel@tonic-gate 
37300Sstevel@tonic-gate 	if (argc == 0)
37310Sstevel@tonic-gate 		goto syntax;
37320Sstevel@tonic-gate 
37330Sstevel@tonic-gate 	/* see if -e is there */
37340Sstevel@tonic-gate 	if (strcmp(argv[0], "-e") == 0) {
37350Sstevel@tonic-gate 		/* use the whole disk */
37360Sstevel@tonic-gate 		options |= MDCMD_USE_WHOLE_DISK;
37370Sstevel@tonic-gate 		--argc, ++argv;
37380Sstevel@tonic-gate 	}
37390Sstevel@tonic-gate 
37400Sstevel@tonic-gate 	if (argc == 0)
37410Sstevel@tonic-gate 		goto syntax;
37420Sstevel@tonic-gate 
37430Sstevel@tonic-gate 	/* get component name */
37440Sstevel@tonic-gate 	compname = Strdup(argv[0]);
37450Sstevel@tonic-gate 
37460Sstevel@tonic-gate 	if (options & MDCMD_USE_WHOLE_DISK) {
37470Sstevel@tonic-gate 		if ((dnp = metadrivename(spp, compname, ep)) == NULL) {
37480Sstevel@tonic-gate 			goto out;
37490Sstevel@tonic-gate 		}
37500Sstevel@tonic-gate 		if ((spcompnp = metaslicename(dnp, 0, ep)) == NULL) {
37510Sstevel@tonic-gate 			goto out;
37520Sstevel@tonic-gate 		}
37530Sstevel@tonic-gate 	} else if ((spcompnp = metaname(spp, compname, ep)) == NULL) {
37540Sstevel@tonic-gate 		goto out;
37550Sstevel@tonic-gate 	}
37560Sstevel@tonic-gate 	assert(*spp != NULL);
37570Sstevel@tonic-gate 
37580Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
37590Sstevel@tonic-gate 		/* grab set lock */
37600Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
37610Sstevel@tonic-gate 			goto out;
37620Sstevel@tonic-gate 
37630Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
37640Sstevel@tonic-gate 			goto out;
37650Sstevel@tonic-gate 	}
37660Sstevel@tonic-gate 
37670Sstevel@tonic-gate 	/* allocate the soft partition */
37680Sstevel@tonic-gate 	msp = Zalloc(sizeof (*msp));
37690Sstevel@tonic-gate 
37700Sstevel@tonic-gate 	/* setup common */
37710Sstevel@tonic-gate 	msp->common.namep = np;
37720Sstevel@tonic-gate 	msp->common.type = MD_METASP;
37730Sstevel@tonic-gate 
37740Sstevel@tonic-gate 	compname = spcompnp->cname;
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 	assert(spcompnp->rname != NULL);
37770Sstevel@tonic-gate 	--argc, ++argv;
37780Sstevel@tonic-gate 
37790Sstevel@tonic-gate 	if (argc == 0) {
37800Sstevel@tonic-gate 		goto syntax;
37810Sstevel@tonic-gate 	}
37820Sstevel@tonic-gate 
37830Sstevel@tonic-gate 	if (*argv[0] == '-') {
37840Sstevel@tonic-gate 		/*
37850Sstevel@tonic-gate 		 * parse any other command line options, this includes
37860Sstevel@tonic-gate 		 * the recovery options -o and -b. The special thing
37870Sstevel@tonic-gate 		 * with these options is that the len needs to be
37880Sstevel@tonic-gate 		 * kept track of otherwise when the geometry of the
37890Sstevel@tonic-gate 		 * "device" is built it will create an invalid geometry
37900Sstevel@tonic-gate 		 */
37910Sstevel@tonic-gate 		old_optind = optind = 0;
37920Sstevel@tonic-gate 		opterr = 0;
37930Sstevel@tonic-gate 		oflag = 0;
37940Sstevel@tonic-gate 		seq = 0;
37950Sstevel@tonic-gate 		failed = 0;
37960Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "A:o:b:")) != -1) {
37970Sstevel@tonic-gate 			sp_ext_offset_t	offset;
37980Sstevel@tonic-gate 			sp_ext_length_t	length;
37990Sstevel@tonic-gate 			longlong_t	tmp_size;
38000Sstevel@tonic-gate 
38010Sstevel@tonic-gate 			switch (c) {
38020Sstevel@tonic-gate 			case 'A':	/* data alignment */
38030Sstevel@tonic-gate 				if (meta_sp_parsesizestring(optarg,
38040Sstevel@tonic-gate 					&alignment) == -1) {
38050Sstevel@tonic-gate 					failed = 1;
38060Sstevel@tonic-gate 				}
38070Sstevel@tonic-gate 				break;
38080Sstevel@tonic-gate 			case 'o':	/* offset in the partition */
38090Sstevel@tonic-gate 				if (oflag == 1) {
38100Sstevel@tonic-gate 					failed = 1;
38110Sstevel@tonic-gate 				} else {
38120Sstevel@tonic-gate 					tmp_size = atoll(optarg);
38130Sstevel@tonic-gate 					if (tmp_size <= 0) {
38140Sstevel@tonic-gate 						failed = 1;
38150Sstevel@tonic-gate 					} else {
38160Sstevel@tonic-gate 						oflag = 1;
38170Sstevel@tonic-gate 						options |= MDCMD_DIRECT;
38180Sstevel@tonic-gate 
38190Sstevel@tonic-gate 						offset = tmp_size;
38200Sstevel@tonic-gate 					}
38210Sstevel@tonic-gate 				}
38220Sstevel@tonic-gate 
38230Sstevel@tonic-gate 				break;
38240Sstevel@tonic-gate 			case 'b':	/* number of blocks */
38250Sstevel@tonic-gate 				if (oflag == 0) {
38260Sstevel@tonic-gate 					failed = 1;
38270Sstevel@tonic-gate 				} else {
38280Sstevel@tonic-gate 					tmp_size = atoll(optarg);
38290Sstevel@tonic-gate 					if (tmp_size <= 0) {
38300Sstevel@tonic-gate 						failed = 1;
38310Sstevel@tonic-gate 					} else {
38320Sstevel@tonic-gate 						oflag = 0;
38330Sstevel@tonic-gate 
38340Sstevel@tonic-gate 						length = tmp_size;
38350Sstevel@tonic-gate 
38360Sstevel@tonic-gate 						/* we have a pair of values */
38370Sstevel@tonic-gate 						meta_sp_list_insert(*spp, np,
38380Sstevel@tonic-gate 							&extlist, offset,
38390Sstevel@tonic-gate 							length, EXTTYP_ALLOC,
38400Sstevel@tonic-gate 							seq++, EXTFLG_UPDATE,
38410Sstevel@tonic-gate 							meta_sp_cmp_by_offset);
38420Sstevel@tonic-gate 						len += length;
38430Sstevel@tonic-gate 					}
38440Sstevel@tonic-gate 				}
38450Sstevel@tonic-gate 
38460Sstevel@tonic-gate 				break;
38470Sstevel@tonic-gate 			default:
38480Sstevel@tonic-gate 				argc -= old_optind;
38490Sstevel@tonic-gate 				argv += old_optind;
38500Sstevel@tonic-gate 				goto options;
38510Sstevel@tonic-gate 			}
38520Sstevel@tonic-gate 
38530Sstevel@tonic-gate 			if (failed) {
38540Sstevel@tonic-gate 				argc -= old_optind;
38550Sstevel@tonic-gate 				argv += old_optind;
38560Sstevel@tonic-gate 				goto syntax;
38570Sstevel@tonic-gate 			}
38580Sstevel@tonic-gate 
38590Sstevel@tonic-gate 			old_optind = optind;
38600Sstevel@tonic-gate 		}
38610Sstevel@tonic-gate 		argc -= optind;
38620Sstevel@tonic-gate 		argv += optind;
38630Sstevel@tonic-gate 
38640Sstevel@tonic-gate 		/*
38650Sstevel@tonic-gate 		 * Must have matching pairs of -o and -b flags
38660Sstevel@tonic-gate 		 */
38670Sstevel@tonic-gate 		if (oflag != 0)
38680Sstevel@tonic-gate 			goto syntax;
38690Sstevel@tonic-gate 
38700Sstevel@tonic-gate 		/*
38710Sstevel@tonic-gate 		 * Can't specify both layout (indicated indirectly by
38720Sstevel@tonic-gate 		 * len being set by thye -o/-b cases above) AND
38730Sstevel@tonic-gate 		 * alignment
38740Sstevel@tonic-gate 		 */
38750Sstevel@tonic-gate 		if ((len > 0LL) && (alignment > 0LL))
38760Sstevel@tonic-gate 			goto syntax;
38770Sstevel@tonic-gate 
38780Sstevel@tonic-gate 		/*
38790Sstevel@tonic-gate 		 * sanity check the allocation list
38800Sstevel@tonic-gate 		 */
38810Sstevel@tonic-gate 		if ((extlist != NULL) && meta_sp_list_overlaps(extlist))
38820Sstevel@tonic-gate 			goto syntax;
38830Sstevel@tonic-gate 	}
38840Sstevel@tonic-gate 
38850Sstevel@tonic-gate 	if (len == 0LL) {
38860Sstevel@tonic-gate 		if (argc == 0)
38870Sstevel@tonic-gate 			goto syntax;
38880Sstevel@tonic-gate 		if (meta_sp_parsesize(argv[0], &len) == -1)
38890Sstevel@tonic-gate 			goto syntax;
38900Sstevel@tonic-gate 		--argc, ++argv;
38910Sstevel@tonic-gate 	}
38920Sstevel@tonic-gate 
38930Sstevel@tonic-gate 	msp->ext.ext_val = Zalloc(sizeof (*msp->ext.ext_val));
38940Sstevel@tonic-gate 	msp->ext.ext_val->len = len;
38950Sstevel@tonic-gate 	msp->compnamep = spcompnp;
38960Sstevel@tonic-gate 
38970Sstevel@tonic-gate 	/* we should be at the end */
38980Sstevel@tonic-gate 	if (argc != 0)
38990Sstevel@tonic-gate 		goto syntax;
39000Sstevel@tonic-gate 
39010Sstevel@tonic-gate 	/* create soft partition */
39020Sstevel@tonic-gate 	if (meta_create_sp(*spp, msp, extlist, options, alignment, ep) != 0)
39030Sstevel@tonic-gate 		goto out;
39040Sstevel@tonic-gate 	rval = 0;
39050Sstevel@tonic-gate 
39060Sstevel@tonic-gate 	/* let em know */
39070Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
39080Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
39090Sstevel@tonic-gate 		    "%s: Soft Partition is setup\n"),
39100Sstevel@tonic-gate 		    devname);
39110Sstevel@tonic-gate 		(void) fflush(stdout);
39120Sstevel@tonic-gate 	}
39130Sstevel@tonic-gate 	goto out;
39140Sstevel@tonic-gate 
39150Sstevel@tonic-gate syntax:
39160Sstevel@tonic-gate 	/* syntax error */
39170Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, compname, argc, argv);
39180Sstevel@tonic-gate 	goto out;
39190Sstevel@tonic-gate 
39200Sstevel@tonic-gate options:
39210Sstevel@tonic-gate 	/* options error */
39220Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, compname, argc, argv);
39230Sstevel@tonic-gate 	goto out;
39240Sstevel@tonic-gate 
39250Sstevel@tonic-gate out:
39260Sstevel@tonic-gate 	if (msp != NULL) {
39270Sstevel@tonic-gate 		if (msp->ext.ext_val != NULL) {
39280Sstevel@tonic-gate 			Free(msp->ext.ext_val);
39290Sstevel@tonic-gate 		}
39300Sstevel@tonic-gate 		Free(msp);
39310Sstevel@tonic-gate 	}
39320Sstevel@tonic-gate 
39330Sstevel@tonic-gate 	return (rval);
39340Sstevel@tonic-gate }
39350Sstevel@tonic-gate 
39360Sstevel@tonic-gate /*
39370Sstevel@tonic-gate  * FUNCTION:	meta_free_sp()
39380Sstevel@tonic-gate  * INPUT:	msp	- the soft partition unit to free
39390Sstevel@tonic-gate  * OUTPUT:	none
39400Sstevel@tonic-gate  * RETURNS:	void
39410Sstevel@tonic-gate  * PURPOSE:	provides an interface from the rest of libmeta for freeing a
39420Sstevel@tonic-gate  *		soft partition unit
39430Sstevel@tonic-gate  */
39440Sstevel@tonic-gate void
39450Sstevel@tonic-gate meta_free_sp(md_sp_t *msp)
39460Sstevel@tonic-gate {
39470Sstevel@tonic-gate 	Free(msp);
39480Sstevel@tonic-gate }
39490Sstevel@tonic-gate 
39500Sstevel@tonic-gate /*
39510Sstevel@tonic-gate  * FUNCTION:	meta_sp_issp()
39520Sstevel@tonic-gate  * INPUT:	sp	- the set name to check
39530Sstevel@tonic-gate  *		np	- the name to check
39540Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
39550Sstevel@tonic-gate  * RETURNS:	int	- 0 means sp,np is a soft partition
39560Sstevel@tonic-gate  *			  1 means sp,np is not a soft partition
39570Sstevel@tonic-gate  * PURPOSE:	determines whether the given device is a soft partition
39580Sstevel@tonic-gate  *		device.  This is called by other metadevice check routines.
39590Sstevel@tonic-gate  */
39600Sstevel@tonic-gate int
39610Sstevel@tonic-gate meta_sp_issp(
39620Sstevel@tonic-gate 	mdsetname_t	*sp,
39630Sstevel@tonic-gate 	mdname_t	*np,
39640Sstevel@tonic-gate 	md_error_t	*ep
39650Sstevel@tonic-gate )
39660Sstevel@tonic-gate {
39670Sstevel@tonic-gate 	if (meta_get_sp_common(sp, np, 0, ep) == NULL)
39680Sstevel@tonic-gate 		return (1);
39690Sstevel@tonic-gate 
39700Sstevel@tonic-gate 	return (0);
39710Sstevel@tonic-gate }
39720Sstevel@tonic-gate 
39730Sstevel@tonic-gate /*
39740Sstevel@tonic-gate  * FUNCTION:	meta_check_sp()
39750Sstevel@tonic-gate  * INPUT:	sp	- the set name to check
39760Sstevel@tonic-gate  *		msp	- the unit structure to check
39770Sstevel@tonic-gate  *		options	- creation options
39780Sstevel@tonic-gate  * OUTPUT:	repart_options - options to be passed to
39790Sstevel@tonic-gate  *				meta_repartition_drive()
39800Sstevel@tonic-gate  *		ep	- return error pointer
39810Sstevel@tonic-gate  * RETURNS:	int	-  0 ok to create on this component
39820Sstevel@tonic-gate  *			  -1 error or not ok to create on this component
39830Sstevel@tonic-gate  * PURPOSE:	Checks to determine whether the rules for creation of
39840Sstevel@tonic-gate  *		soft partitions allow creation of a soft partition on
39850Sstevel@tonic-gate  *		the device described by the mdname_t structure referred
39860Sstevel@tonic-gate  *		to by msp->compnamep.
39870Sstevel@tonic-gate  *
39880Sstevel@tonic-gate  *		NOTE: Does NOT check to determine whether the extents
39890Sstevel@tonic-gate  *		      described in the md_sp_t structure referred to by
39900Sstevel@tonic-gate  *		      msp will fit on the device described by the mdname_t
39910Sstevel@tonic-gate  *		      structure located at msp->compnamep.
39920Sstevel@tonic-gate  */
39930Sstevel@tonic-gate static int
39940Sstevel@tonic-gate meta_check_sp(
39950Sstevel@tonic-gate 	mdsetname_t	*sp,
39960Sstevel@tonic-gate 	md_sp_t		*msp,
39970Sstevel@tonic-gate 	mdcmdopts_t	options,
39980Sstevel@tonic-gate 	int		*repart_options,
39990Sstevel@tonic-gate 	md_error_t	*ep
40000Sstevel@tonic-gate )
40010Sstevel@tonic-gate {
40020Sstevel@tonic-gate 	md_common_t	*mdp;
40030Sstevel@tonic-gate 	mdname_t	*compnp = msp->compnamep;
40040Sstevel@tonic-gate 	uint_t		slice;
40050Sstevel@tonic-gate 	mddrivename_t	*dnp;
40060Sstevel@tonic-gate 	mdname_t	*slicenp;
40070Sstevel@tonic-gate 	mdvtoc_t	*vtocp;
40080Sstevel@tonic-gate 
40090Sstevel@tonic-gate 	/* make sure it is in the set */
40100Sstevel@tonic-gate 	if (meta_check_inset(sp, compnp, ep) != 0)
40110Sstevel@tonic-gate 		return (-1);
40120Sstevel@tonic-gate 
40130Sstevel@tonic-gate 	if ((options & MDCMD_USE_WHOLE_DISK) != 0) {
40140Sstevel@tonic-gate 		uint_t	rep_slice;
40150Sstevel@tonic-gate 
40160Sstevel@tonic-gate 		/*
40170Sstevel@tonic-gate 		 * check to make sure we can partition this drive.
40180Sstevel@tonic-gate 		 * we cannot continue if any of the following are
40190Sstevel@tonic-gate 		 * true:
40200Sstevel@tonic-gate 		 * The drive is a metadevice.
40210Sstevel@tonic-gate 		 * The drive contains a mounted slice.
40220Sstevel@tonic-gate 		 * The drive contains a slice being swapped to.
40230Sstevel@tonic-gate 		 * The drive contains slices which are part of other
40240Sstevel@tonic-gate 		 * metadevices.
40250Sstevel@tonic-gate 		 * The drive contains a metadb.
40260Sstevel@tonic-gate 		 */
40270Sstevel@tonic-gate 		if (metaismeta(compnp))
40280Sstevel@tonic-gate 			return (mddeverror(ep, MDE_IS_META, compnp->dev,
40290Sstevel@tonic-gate 			    compnp->cname));
40300Sstevel@tonic-gate 
40310Sstevel@tonic-gate 		assert(compnp->drivenamep != NULL);
40320Sstevel@tonic-gate 
40330Sstevel@tonic-gate 		/*
40340Sstevel@tonic-gate 		 * ensure that we have slice 0 since the disk will be
40350Sstevel@tonic-gate 		 * repartitioned in the USE_WHOLE_DISK case.  this check
40360Sstevel@tonic-gate 		 * is redundant unless the user incorrectly specifies a
40370Sstevel@tonic-gate 		 * a fully qualified drive AND slice name (i.e.,
40380Sstevel@tonic-gate 		 * /dev/dsk/cXtXdXsX), which will be incorrectly
40390Sstevel@tonic-gate 		 * recognized as a drive name by the metaname code.
40400Sstevel@tonic-gate 		 */
40410Sstevel@tonic-gate 
40420Sstevel@tonic-gate 		if ((vtocp = metagetvtoc(compnp, FALSE, &slice, ep)) == NULL)
40430Sstevel@tonic-gate 			return (-1);
40440Sstevel@tonic-gate 		if (slice != MD_SLICE0)
40450Sstevel@tonic-gate 			return (mderror(ep, MDE_NOT_DRIVENAME, compnp->cname));
40460Sstevel@tonic-gate 
40470Sstevel@tonic-gate 		dnp = compnp->drivenamep;
40480Sstevel@tonic-gate 		if (meta_replicaslice(dnp, &rep_slice, ep) != 0)
40490Sstevel@tonic-gate 			return (-1);
40500Sstevel@tonic-gate 
40510Sstevel@tonic-gate 		for (slice = 0; slice < vtocp->nparts; slice++) {
40520Sstevel@tonic-gate 
40530Sstevel@tonic-gate 			/* only check if the slice really exists */
40540Sstevel@tonic-gate 			if (vtocp->parts[slice].size == 0)
40550Sstevel@tonic-gate 				continue;
40560Sstevel@tonic-gate 
40570Sstevel@tonic-gate 			slicenp = metaslicename(dnp, slice, ep);
40580Sstevel@tonic-gate 			if (slicenp == NULL)
40590Sstevel@tonic-gate 				return (-1);
40600Sstevel@tonic-gate 
40610Sstevel@tonic-gate 			/* check to ensure that it is not already in use */
40620Sstevel@tonic-gate 			if (meta_check_inuse(sp,
40630Sstevel@tonic-gate 			    slicenp, MDCHK_INUSE, ep) != 0) {
40640Sstevel@tonic-gate 				return (-1);
40650Sstevel@tonic-gate 			}
40660Sstevel@tonic-gate 
40670Sstevel@tonic-gate 			/*
40680Sstevel@tonic-gate 			 * Up to this point, tests are applied to all
40690Sstevel@tonic-gate 			 * slices uniformly.
40700Sstevel@tonic-gate 			 */
40710Sstevel@tonic-gate 
40720Sstevel@tonic-gate 			if (slice == rep_slice) {
40730Sstevel@tonic-gate 				/*
40740Sstevel@tonic-gate 				 * Tests inside the body of this
40750Sstevel@tonic-gate 				 * conditional are applied only to
40760Sstevel@tonic-gate 				 * slice seven.
40770Sstevel@tonic-gate 				 */
40780Sstevel@tonic-gate 				if (meta_check_inmeta(sp, slicenp,
40790Sstevel@tonic-gate 				    options | MDCHK_ALLOW_MDDB |
40800Sstevel@tonic-gate 				    MDCHK_ALLOW_REPSLICE, 0, -1, ep) != 0)
40810Sstevel@tonic-gate 					return (-1);
40820Sstevel@tonic-gate 
40830Sstevel@tonic-gate 				/*
40840Sstevel@tonic-gate 				 * For slice seven, a metadb is NOT an
40850Sstevel@tonic-gate 				 * automatic failure. It merely means
40860Sstevel@tonic-gate 				 * that we're not allowed to muck
40870Sstevel@tonic-gate 				 * about with the partitioning of that
40880Sstevel@tonic-gate 				 * slice.  We indicate this by masking
40890Sstevel@tonic-gate 				 * in the MD_REPART_LEAVE_REP flag.
40900Sstevel@tonic-gate 				 */
40910Sstevel@tonic-gate 				if (metahasmddb(sp, slicenp, ep)) {
40920Sstevel@tonic-gate 					assert(repart_options !=
40930Sstevel@tonic-gate 					    NULL);
40940Sstevel@tonic-gate 					*repart_options |=
40950Sstevel@tonic-gate 					    MD_REPART_LEAVE_REP;
40960Sstevel@tonic-gate 				}
40970Sstevel@tonic-gate 
40980Sstevel@tonic-gate 				/*
40990Sstevel@tonic-gate 				 * Skip the remaining tests for slice
41000Sstevel@tonic-gate 				 * seven
41010Sstevel@tonic-gate 				 */
41020Sstevel@tonic-gate 				continue;
41030Sstevel@tonic-gate 			}
41040Sstevel@tonic-gate 
41050Sstevel@tonic-gate 			/*
41060Sstevel@tonic-gate 			 * Tests below this point will be applied to
41070Sstevel@tonic-gate 			 * all slices EXCEPT for the replica slice.
41080Sstevel@tonic-gate 			 */
41090Sstevel@tonic-gate 
41100Sstevel@tonic-gate 
41110Sstevel@tonic-gate 			/* check if component is in a metadevice */
41120Sstevel@tonic-gate 			if (meta_check_inmeta(sp, slicenp, options, 0,
41130Sstevel@tonic-gate 			    -1, ep) != 0)
41140Sstevel@tonic-gate 				return (-1);
41150Sstevel@tonic-gate 
41160Sstevel@tonic-gate 			/* check to see if component has a metadb */
41170Sstevel@tonic-gate 			if (metahasmddb(sp, slicenp, ep))
41180Sstevel@tonic-gate 				return (mddeverror(ep, MDE_HAS_MDDB,
41190Sstevel@tonic-gate 				    slicenp->dev, slicenp->cname));
41200Sstevel@tonic-gate 		}
41210Sstevel@tonic-gate 		/*
41220Sstevel@tonic-gate 		 * This should be all of the testing necessary when
41230Sstevel@tonic-gate 		 * the MDCMD_USE_WHOLE_DISK flag is set; the rest of
41240Sstevel@tonic-gate 		 * meta_check_sp() is oriented towards component
41250Sstevel@tonic-gate 		 * arguments instead of disks.
41260Sstevel@tonic-gate 		 */
41270Sstevel@tonic-gate 		goto meta_check_sp_ok;
41280Sstevel@tonic-gate 
41290Sstevel@tonic-gate 	}
41300Sstevel@tonic-gate 
41310Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
41320Sstevel@tonic-gate 	if (meta_check_inuse(sp, compnp, MDCHK_INUSE, ep) != 0) {
41330Sstevel@tonic-gate 		return (-1);
41340Sstevel@tonic-gate 	}
41350Sstevel@tonic-gate 
41360Sstevel@tonic-gate 	if (!metaismeta(compnp)) {	/* handle non-metadevices */
41370Sstevel@tonic-gate 
41380Sstevel@tonic-gate 		/*
41390Sstevel@tonic-gate 		 * The component can have one or more soft partitions on it
41400Sstevel@tonic-gate 		 * already, but can't be part of any other type of metadevice,
41410Sstevel@tonic-gate 		 * so if it is used for a metadevice, but the metadevice
41420Sstevel@tonic-gate 		 * isn't a soft partition, return failure.
41430Sstevel@tonic-gate 		 */
41440Sstevel@tonic-gate 
41450Sstevel@tonic-gate 		if (meta_check_inmeta(sp, compnp, options, 0, -1, ep) != 0 &&
41460Sstevel@tonic-gate 		    meta_check_insp(sp, compnp, 0, -1, ep) == 0) {
41470Sstevel@tonic-gate 			return (-1);
41480Sstevel@tonic-gate 		}
41490Sstevel@tonic-gate 	} else {			/* handle metadevices */
41500Sstevel@tonic-gate 		/* get underlying unit & check capabilities */
41510Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, compnp, ep)) == NULL)
41520Sstevel@tonic-gate 			return (-1);
41530Sstevel@tonic-gate 
41540Sstevel@tonic-gate 		if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
41550Sstevel@tonic-gate 		    (! (mdp->capabilities & MD_CAN_SP)))
41560Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT,
41570Sstevel@tonic-gate 			    meta_getminor(compnp->dev), compnp->cname));
41580Sstevel@tonic-gate 	}
41590Sstevel@tonic-gate 
41600Sstevel@tonic-gate meta_check_sp_ok:
41610Sstevel@tonic-gate 	mdclrerror(ep);
41620Sstevel@tonic-gate 	return (0);
41630Sstevel@tonic-gate }
41640Sstevel@tonic-gate 
41650Sstevel@tonic-gate /*
41660Sstevel@tonic-gate  * FUNCTION:	meta_create_sp()
41670Sstevel@tonic-gate  * INPUT:	sp	- the set name to create in
41680Sstevel@tonic-gate  *		msp	- the unit structure to create
41690Sstevel@tonic-gate  *		oblist	- an optional list of requested extents (-o/-b options)
41700Sstevel@tonic-gate  *		options	- creation options
41710Sstevel@tonic-gate  *		alignment - data alignment
41720Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
41730Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
41740Sstevel@tonic-gate  * PURPOSE:	does most of the work for creating a soft partition.  If
41750Sstevel@tonic-gate  *		metainit -p -e was used, first partition the drive.  Then
41760Sstevel@tonic-gate  *		create an extent list based on the existing soft partitions
41770Sstevel@tonic-gate  *		and assume all space not used by them is free.  Storage for
41780Sstevel@tonic-gate  *		the new soft partition is allocated from the free extents
41790Sstevel@tonic-gate  *		based on the length specified on the command line or the
41800Sstevel@tonic-gate  *		oblist passed in.  The unit structure is then committed and
41810Sstevel@tonic-gate  *		the watermarks are updated.  Finally, the status is changed to
41820Sstevel@tonic-gate  *		Okay and the process is complete.
41830Sstevel@tonic-gate  */
41840Sstevel@tonic-gate static int
41850Sstevel@tonic-gate meta_create_sp(
41860Sstevel@tonic-gate 	mdsetname_t	*sp,
41870Sstevel@tonic-gate 	md_sp_t		*msp,
41880Sstevel@tonic-gate 	sp_ext_node_t	*oblist,
41890Sstevel@tonic-gate 	mdcmdopts_t	options,
41900Sstevel@tonic-gate 	sp_ext_length_t	alignment,
41910Sstevel@tonic-gate 	md_error_t	*ep
41920Sstevel@tonic-gate )
41930Sstevel@tonic-gate {
41940Sstevel@tonic-gate 	mdname_t	*np = msp->common.namep;
41950Sstevel@tonic-gate 	mdname_t	*compnp = msp->compnamep;
41960Sstevel@tonic-gate 	mp_unit_t	*mp = NULL;
41970Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL, *spnlp = NULL;
41980Sstevel@tonic-gate 	md_set_params_t	set_params;
41990Sstevel@tonic-gate 	int		rval = -1;
42000Sstevel@tonic-gate 	diskaddr_t	comp_size;
42010Sstevel@tonic-gate 	diskaddr_t	sp_start;
42020Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
42030Sstevel@tonic-gate 	int		numexts = 0;	/* number of extents */
42040Sstevel@tonic-gate 	int		count = 0;
42050Sstevel@tonic-gate 	int		committed = 0;
42060Sstevel@tonic-gate 	int		repart_options = MD_REPART_FORCE;
42070Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
42080Sstevel@tonic-gate 
42090Sstevel@tonic-gate 	md_set_desc	*sd;
42100Sstevel@tonic-gate 	mm_unit_t	*mm;
42110Sstevel@tonic-gate 	md_set_mmown_params_t	*ownpar = NULL;
42120Sstevel@tonic-gate 	int		comp_is_mirror = 0;
42130Sstevel@tonic-gate 
42140Sstevel@tonic-gate 	/* validate soft partition */
42150Sstevel@tonic-gate 	if (meta_check_sp(sp, msp, options, &repart_options, ep) != 0)
42160Sstevel@tonic-gate 		return (-1);
42170Sstevel@tonic-gate 
42180Sstevel@tonic-gate 	if ((options & MDCMD_USE_WHOLE_DISK) != 0) {
42190Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) != 0) {
42200Sstevel@tonic-gate 			if (meta_repartition_drive(sp,
42210Sstevel@tonic-gate 			    compnp->drivenamep,
42220Sstevel@tonic-gate 			    repart_options,
42230Sstevel@tonic-gate 			    NULL, /* Don't return the VTOC */
42240Sstevel@tonic-gate 			    ep) != 0)
42250Sstevel@tonic-gate 
42260Sstevel@tonic-gate 				return (-1);
42270Sstevel@tonic-gate 		} else {
42280Sstevel@tonic-gate 			/*
42290Sstevel@tonic-gate 			 * If -n and -e are both specified, it doesn't make
42300Sstevel@tonic-gate 			 * sense to continue without actually partitioning
42310Sstevel@tonic-gate 			 * the drive.
42320Sstevel@tonic-gate 			 */
42330Sstevel@tonic-gate 			return (0);
42340Sstevel@tonic-gate 		}
42350Sstevel@tonic-gate 	}
42360Sstevel@tonic-gate 
42370Sstevel@tonic-gate 	/* populate the start_blk field of the component name */
42380Sstevel@tonic-gate 	if ((sp_start = meta_sp_get_start(sp, compnp, ep)) ==
42390Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
42400Sstevel@tonic-gate 		rval = -1;
42410Sstevel@tonic-gate 		goto out;
42420Sstevel@tonic-gate 	}
42430Sstevel@tonic-gate 
42440Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
42450Sstevel@tonic-gate 		/* store name in namespace */
42460Sstevel@tonic-gate 		if (add_key_name(sp, compnp, &keynlp, ep) != 0) {
42470Sstevel@tonic-gate 			rval = -1;
42480Sstevel@tonic-gate 			goto out;
42490Sstevel@tonic-gate 		}
42500Sstevel@tonic-gate 	}
42510Sstevel@tonic-gate 
42520Sstevel@tonic-gate 	/*
42530Sstevel@tonic-gate 	 * Get a list of the soft partitions that currently reside on
42540Sstevel@tonic-gate 	 * the component.  We should ALWAYS force reload the cache,
42550Sstevel@tonic-gate 	 * because if this is a single creation, there will not BE a
42560Sstevel@tonic-gate 	 * cached list, and if we're using the md.tab, we must rebuild
42570Sstevel@tonic-gate 	 * the list because it won't contain the previous (if any)
42580Sstevel@tonic-gate 	 * soft partition.
42590Sstevel@tonic-gate 	 */
42600Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 1, ep);
42610Sstevel@tonic-gate 	if (count < 0) {
42620Sstevel@tonic-gate 		/* error occured */
42630Sstevel@tonic-gate 		rval = -1;
42640Sstevel@tonic-gate 		goto out;
42650Sstevel@tonic-gate 	}
42660Sstevel@tonic-gate 
42670Sstevel@tonic-gate 	/*
42680Sstevel@tonic-gate 	 * get the size of the underlying device.  if the size is smaller
42690Sstevel@tonic-gate 	 * than or equal to the watermark size, we know there isn't
42700Sstevel@tonic-gate 	 * enough space.
42710Sstevel@tonic-gate 	 */
42720Sstevel@tonic-gate 	if ((comp_size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR) {
42730Sstevel@tonic-gate 		rval = -1;
42740Sstevel@tonic-gate 		goto out;
42750Sstevel@tonic-gate 	} else if (comp_size <= MD_SP_WMSIZE) {
42760Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_SP_NOSPACE, 0, compnp->cname);
42770Sstevel@tonic-gate 		rval = -1;
42780Sstevel@tonic-gate 		goto out;
42790Sstevel@tonic-gate 	}
42800Sstevel@tonic-gate 	/*
42810Sstevel@tonic-gate 	 * seed extlist with reserved space at the beginning of the volume and
42820Sstevel@tonic-gate 	 * enough space for the end watermark.  The end watermark always gets
42830Sstevel@tonic-gate 	 * updated, but if the underlying device changes size it may not be
42840Sstevel@tonic-gate 	 * pointed to until the extent before it is updated.  Since the
42850Sstevel@tonic-gate 	 * end of the reserved space is where the first watermark starts,
42860Sstevel@tonic-gate 	 * the reserved extent should never be marked for updating.
42870Sstevel@tonic-gate 	 */
42880Sstevel@tonic-gate 
42890Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
42900Sstevel@tonic-gate 	    0ULL, sp_start, EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
42910Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
42920Sstevel@tonic-gate 	    (sp_ext_offset_t)(comp_size - MD_SP_WMSIZE), MD_SP_WMSIZE,
42930Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
42940Sstevel@tonic-gate 
42950Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
42960Sstevel@tonic-gate 		rval = -1;
42970Sstevel@tonic-gate 		goto out;
42980Sstevel@tonic-gate 	}
42990Sstevel@tonic-gate 
43000Sstevel@tonic-gate 	metafreenamelist(spnlp);
43010Sstevel@tonic-gate 
43020Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
43030Sstevel@tonic-gate 		meta_sp_debug("meta_create_sp: list of used extents:\n");
43040Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
43050Sstevel@tonic-gate 	}
43060Sstevel@tonic-gate 
43070Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
43080Sstevel@tonic-gate 
43090Sstevel@tonic-gate 	/* get extent list from -o/-b options or from free space */
43100Sstevel@tonic-gate 	if (options & MDCMD_DIRECT) {
43110Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
43120Sstevel@tonic-gate 			meta_sp_debug("meta_create_sp: Dumping -o/-b list:\n");
43130Sstevel@tonic-gate 			meta_sp_list_dump(oblist);
43140Sstevel@tonic-gate 		}
43150Sstevel@tonic-gate 
43160Sstevel@tonic-gate 		numexts = meta_sp_alloc_by_list(sp, np, &extlist, oblist);
43170Sstevel@tonic-gate 		if (numexts == -1) {
43180Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_SP_OVERLAP, 0, np->cname);
43190Sstevel@tonic-gate 			rval = -1;
43200Sstevel@tonic-gate 			goto out;
43210Sstevel@tonic-gate 		}
43220Sstevel@tonic-gate 	} else {
43230Sstevel@tonic-gate 		numexts = meta_sp_alloc_by_len(sp, np, &extlist,
43240Sstevel@tonic-gate 		    &msp->ext.ext_val->len, 0LL, (alignment > 0) ? alignment :
43250Sstevel@tonic-gate 		    meta_sp_get_default_alignment(sp, compnp, ep));
43260Sstevel@tonic-gate 		if (numexts == -1) {
43270Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_SP_NOSPACE, 0, np->cname);
43280Sstevel@tonic-gate 			rval = -1;
43290Sstevel@tonic-gate 			goto out;
43300Sstevel@tonic-gate 		}
43310Sstevel@tonic-gate 	}
43320Sstevel@tonic-gate 
43330Sstevel@tonic-gate 	assert(extlist != NULL);
43340Sstevel@tonic-gate 
43350Sstevel@tonic-gate 	/* create soft partition */
43360Sstevel@tonic-gate 	mp = meta_sp_createunit(msp->common.namep, msp->compnamep,
43370Sstevel@tonic-gate 	    extlist, numexts, msp->ext.ext_val->len, MD_SP_CREATEPEND, ep);
43380Sstevel@tonic-gate 
43390Sstevel@tonic-gate 	create_flag = meta_check_devicesize(mp->c.un_total_blocks);
43400Sstevel@tonic-gate 
43410Sstevel@tonic-gate 	/* if we're not doing anything (metainit -n), return success */
43420Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
43430Sstevel@tonic-gate 		rval = 0;	/* success */
43440Sstevel@tonic-gate 		goto out;
43450Sstevel@tonic-gate 	}
43460Sstevel@tonic-gate 
43470Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
43480Sstevel@tonic-gate 
43490Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
43500Sstevel@tonic-gate 		mp->c.un_revision = MD_64BIT_META_DEV;
43510Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
43520Sstevel@tonic-gate 	} else {
43530Sstevel@tonic-gate 		mp->c.un_revision = MD_32BIT_META_DEV;
43540Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
43550Sstevel@tonic-gate 	}
43560Sstevel@tonic-gate 
43570Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
43580Sstevel@tonic-gate 		meta_sp_debug("meta_create_sp: printing unit structure\n");
43590Sstevel@tonic-gate 		meta_sp_printunit(mp);
43600Sstevel@tonic-gate 	}
43610Sstevel@tonic-gate 
43620Sstevel@tonic-gate 	/*
43630Sstevel@tonic-gate 	 * Check to see if we're trying to create a partition on a mirror. If so
43640Sstevel@tonic-gate 	 * we may have to enforce an ownership change before writing the
43650Sstevel@tonic-gate 	 * watermark out.
43660Sstevel@tonic-gate 	 */
43670Sstevel@tonic-gate 	if (metaismeta(compnp)) {
43680Sstevel@tonic-gate 		char *miscname;
43690Sstevel@tonic-gate 
43700Sstevel@tonic-gate 		miscname = metagetmiscname(compnp, ep);
43710Sstevel@tonic-gate 		if (miscname != NULL)
43720Sstevel@tonic-gate 			comp_is_mirror = (strcmp(miscname, MD_MIRROR) == 0);
43730Sstevel@tonic-gate 		else
43740Sstevel@tonic-gate 			comp_is_mirror = 0;
43750Sstevel@tonic-gate 	} else {
43760Sstevel@tonic-gate 		comp_is_mirror = 0;
43770Sstevel@tonic-gate 	}
43780Sstevel@tonic-gate 
43790Sstevel@tonic-gate 	/*
43800Sstevel@tonic-gate 	 * For a multi-node environment we have to ensure that the master
43810Sstevel@tonic-gate 	 * node owns an underlying mirror before we issue the MD_IOCSET ioctl.
43820Sstevel@tonic-gate 	 * If the master does not own the device we will deadlock as the
43830Sstevel@tonic-gate 	 * implicit write of the watermarks (in sp_ioctl.c) will cause an
43840Sstevel@tonic-gate 	 * ownership change that will block as the MD_IOCSET is still in
43850Sstevel@tonic-gate 	 * progress. To close this window we force an owner change to occur
43860Sstevel@tonic-gate 	 * before issuing the MD_IOCSET. We cannot simply open the device and
43870Sstevel@tonic-gate 	 * write to it as this will only work for the first soft-partition
43880Sstevel@tonic-gate 	 * creation.
43890Sstevel@tonic-gate 	 */
43900Sstevel@tonic-gate 
43910Sstevel@tonic-gate 	if (comp_is_mirror && !metaislocalset(sp)) {
43920Sstevel@tonic-gate 
43930Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
43940Sstevel@tonic-gate 			rval = -1;
43950Sstevel@tonic-gate 			goto out;
43960Sstevel@tonic-gate 		}
43970Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd) && sd->sd_mn_am_i_master) {
43980Sstevel@tonic-gate 			mm = (mm_unit_t *)meta_get_unit(sp, compnp, ep);
43990Sstevel@tonic-gate 			if (mm == NULL) {
44000Sstevel@tonic-gate 				rval = -1;
44010Sstevel@tonic-gate 				goto out;
44020Sstevel@tonic-gate 			} else {
44030Sstevel@tonic-gate 				rval = meta_mn_change_owner(&ownpar, sp->setno,
44040Sstevel@tonic-gate 					meta_getminor(compnp->dev),
44050Sstevel@tonic-gate 					sd->sd_mn_mynode->nd_nodeid,
44060Sstevel@tonic-gate 					MD_MN_MM_PREVENT_CHANGE |
44070Sstevel@tonic-gate 					    MD_MN_MM_SPAWN_THREAD);
44080Sstevel@tonic-gate 				if (rval == -1)
44090Sstevel@tonic-gate 					goto out;
44100Sstevel@tonic-gate 			}
44110Sstevel@tonic-gate 		}
44120Sstevel@tonic-gate 	}
44130Sstevel@tonic-gate 
44140Sstevel@tonic-gate 	set_params.mnum = MD_SID(mp);
44150Sstevel@tonic-gate 	set_params.size = mp->c.un_size;
44160Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)mp;
44170Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_SP, MD_MIN2SET(set_params.mnum));
44180Sstevel@tonic-gate 
44190Sstevel@tonic-gate 	/* first phase of commit. */
44200Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
44210Sstevel@tonic-gate 	    np->cname) != 0) {
44220Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
44230Sstevel@tonic-gate 		rval = -1;
44240Sstevel@tonic-gate 		goto out;
44250Sstevel@tonic-gate 	}
44260Sstevel@tonic-gate 
44270Sstevel@tonic-gate 	/* we've successfully committed the record */
44280Sstevel@tonic-gate 	committed = 1;
44290Sstevel@tonic-gate 
44300Sstevel@tonic-gate 	/* write watermarks */
44310Sstevel@tonic-gate 	if (meta_sp_update_wm(sp, msp, extlist, ep) < 0) {
44320Sstevel@tonic-gate 		rval = -1;
44330Sstevel@tonic-gate 		goto out;
44340Sstevel@tonic-gate 	}
44350Sstevel@tonic-gate 
44360Sstevel@tonic-gate 	/*
44370Sstevel@tonic-gate 	 * Allow mirror ownership to change. If we don't succeed in this
44380Sstevel@tonic-gate 	 * ioctl it isn't fatal, but the cluster will probably hang fairly
44390Sstevel@tonic-gate 	 * soon as the mirror owner won't change. However, we have
44400Sstevel@tonic-gate 	 * successfully written the watermarks out to the device so the
44410Sstevel@tonic-gate 	 * softpart creation has succeeded
44420Sstevel@tonic-gate 	 */
44430Sstevel@tonic-gate 	if (ownpar) {
44440Sstevel@tonic-gate 		(void) meta_mn_change_owner(&ownpar, sp->setno, ownpar->d.mnum,
44450Sstevel@tonic-gate 		    ownpar->d.owner,
44460Sstevel@tonic-gate 		    MD_MN_MM_ALLOW_CHANGE | MD_MN_MM_SPAWN_THREAD);
44470Sstevel@tonic-gate 	}
44480Sstevel@tonic-gate 
44490Sstevel@tonic-gate 	/* second phase of commit, set status to MD_SP_OK */
44500Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &(MD_SID(mp)), 1, MD_SP_OK, ep) < 0) {
44510Sstevel@tonic-gate 		rval = -1;
44520Sstevel@tonic-gate 		goto out;
44530Sstevel@tonic-gate 	}
44540Sstevel@tonic-gate 	rval = 0;
44550Sstevel@tonic-gate out:
44560Sstevel@tonic-gate 	Free(mp);
44570Sstevel@tonic-gate 	if (ownpar)
44580Sstevel@tonic-gate 		Free(ownpar);
44590Sstevel@tonic-gate 
44600Sstevel@tonic-gate 	if (extlist != NULL)
44610Sstevel@tonic-gate 		meta_sp_list_free(&extlist);
44620Sstevel@tonic-gate 
44630Sstevel@tonic-gate 	if (rval != 0 && keynlp != NULL && committed != 1)
44640Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
44650Sstevel@tonic-gate 
44660Sstevel@tonic-gate 	metafreenamelist(keynlp);
44670Sstevel@tonic-gate 
44680Sstevel@tonic-gate 	return (rval);
44690Sstevel@tonic-gate }
44700Sstevel@tonic-gate 
44710Sstevel@tonic-gate /*
44720Sstevel@tonic-gate  * **************************************************************************
44730Sstevel@tonic-gate  *                      Reset (metaclear) Functions                         *
44740Sstevel@tonic-gate  * **************************************************************************
44750Sstevel@tonic-gate  */
44760Sstevel@tonic-gate 
44770Sstevel@tonic-gate /*
44780Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset_common()
44790Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
44800Sstevel@tonic-gate  *		np	- the name of the device to reset
44810Sstevel@tonic-gate  *		msp	- the unit structure to reset
44820Sstevel@tonic-gate  *		options	- metaclear options
44830Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
44840Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
44850Sstevel@tonic-gate  * PURPOSE:	"resets", or more accurately deletes, the soft partition
44860Sstevel@tonic-gate  *		specified.  First the state is set to "deleting" and then the
44870Sstevel@tonic-gate  *		watermarks are all cleared out.  Once the watermarks have been
44880Sstevel@tonic-gate  *		updated, the unit structure is deleted from the metadb.
44890Sstevel@tonic-gate  */
44900Sstevel@tonic-gate static int
44910Sstevel@tonic-gate meta_sp_reset_common(
44920Sstevel@tonic-gate 	mdsetname_t	*sp,
44930Sstevel@tonic-gate 	mdname_t	*np,
44940Sstevel@tonic-gate 	md_sp_t		*msp,
44950Sstevel@tonic-gate 	md_sp_reset_t	reset_params,
44960Sstevel@tonic-gate 	mdcmdopts_t	options,
44970Sstevel@tonic-gate 	md_error_t	*ep
44980Sstevel@tonic-gate )
44990Sstevel@tonic-gate {
45000Sstevel@tonic-gate 	char	*miscname;
45010Sstevel@tonic-gate 	int	rval = -1;
45020Sstevel@tonic-gate 	int	is_open = 0;
45030Sstevel@tonic-gate 
45040Sstevel@tonic-gate 	/* make sure that nobody owns us */
45050Sstevel@tonic-gate 	if (MD_HAS_PARENT(msp->common.parent))
45060Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(np->dev),
45070Sstevel@tonic-gate 					np->cname));
45080Sstevel@tonic-gate 
45090Sstevel@tonic-gate 	/* make sure that the soft partition isn't open */
45100Sstevel@tonic-gate 	if ((is_open = meta_isopen(sp, np, ep, options)) < 0)
45110Sstevel@tonic-gate 		return (-1);
45120Sstevel@tonic-gate 	else if (is_open)
45130Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IS_OPEN, meta_getminor(np->dev),
45140Sstevel@tonic-gate 					np->cname));
45150Sstevel@tonic-gate 
45160Sstevel@tonic-gate 	/* get miscname */
45170Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
45180Sstevel@tonic-gate 		return (-1);
45190Sstevel@tonic-gate 
45200Sstevel@tonic-gate 	/* fill in reset params */
45210Sstevel@tonic-gate 	MD_SETDRIVERNAME(&reset_params, miscname, sp->setno);
45220Sstevel@tonic-gate 	reset_params.mnum = meta_getminor(np->dev);
45230Sstevel@tonic-gate 	reset_params.force = (options & MDCMD_FORCE) ? 1 : 0;
45240Sstevel@tonic-gate 
45250Sstevel@tonic-gate 	/*
45260Sstevel@tonic-gate 	 * clear soft partition - phase one.
45270Sstevel@tonic-gate 	 * place the soft partition into the "delete pending" state.
45280Sstevel@tonic-gate 	 */
45290Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &reset_params.mnum, 1, MD_SP_DELPEND, ep) < 0)
45300Sstevel@tonic-gate 		return (-1);
45310Sstevel@tonic-gate 
45320Sstevel@tonic-gate 	/*
45330Sstevel@tonic-gate 	 * Now clear the watermarks.  If the force flag is specified,
45340Sstevel@tonic-gate 	 * ignore any errors writing the watermarks and delete the unit
45350Sstevel@tonic-gate 	 * structure anyway.  An error may leave the on-disk format in a
45360Sstevel@tonic-gate 	 * corrupt state.  If force is not specified and we fail here,
45370Sstevel@tonic-gate 	 * the soft partition will remain in the "delete pending" state.
45380Sstevel@tonic-gate 	 */
45390Sstevel@tonic-gate 	if ((meta_sp_clear_wm(sp, msp, ep) < 0) &&
45400Sstevel@tonic-gate 	    ((options & MDCMD_FORCE) == 0))
45410Sstevel@tonic-gate 		goto out;
45420Sstevel@tonic-gate 
45430Sstevel@tonic-gate 	/*
45440Sstevel@tonic-gate 	 * clear soft partition - phase two.
45450Sstevel@tonic-gate 	 * the driver removes the soft partition from the metadb and
45460Sstevel@tonic-gate 	 * zeros out incore version.
45470Sstevel@tonic-gate 	 */
45480Sstevel@tonic-gate 	if (metaioctl(MD_IOCRESET, &reset_params,
45490Sstevel@tonic-gate 	    &reset_params.mde, np->cname) != 0) {
45500Sstevel@tonic-gate 		(void) mdstealerror(ep, &reset_params.mde);
45510Sstevel@tonic-gate 		goto out;
45520Sstevel@tonic-gate 	}
45530Sstevel@tonic-gate 	rval = 0;	/* success */
45540Sstevel@tonic-gate 
45550Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
45560Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
45570Sstevel@tonic-gate 		    "%s: Soft Partition is cleared\n"),
45580Sstevel@tonic-gate 		    np->cname);
45590Sstevel@tonic-gate 		(void) fflush(stdout);
45600Sstevel@tonic-gate 	}
45610Sstevel@tonic-gate 
45620Sstevel@tonic-gate 	/*
45630Sstevel@tonic-gate 	 * if told to recurse and on a metadevice, then attempt to
45640Sstevel@tonic-gate 	 * clear the subdevices.  Indicate failure if the clear fails.
45650Sstevel@tonic-gate 	 */
45660Sstevel@tonic-gate 	if ((options & MDCMD_RECURSE) &&
45670Sstevel@tonic-gate 	    (metaismeta(msp->compnamep)) &&
45680Sstevel@tonic-gate 	    (meta_reset_by_name(sp, msp->compnamep, options, ep) != 0))
45690Sstevel@tonic-gate 		rval = -1;
45700Sstevel@tonic-gate 
45710Sstevel@tonic-gate out:
45720Sstevel@tonic-gate 	meta_invalidate_name(np);
45730Sstevel@tonic-gate 	return (rval);
45740Sstevel@tonic-gate }
45750Sstevel@tonic-gate 
45760Sstevel@tonic-gate /*
45770Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset()
45780Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
45790Sstevel@tonic-gate  *		np	- the name of the device to reset
45800Sstevel@tonic-gate  *		options	- metaclear options
45810Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
45820Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
45830Sstevel@tonic-gate  * PURPOSE:	provides the entry point to the rest of libmeta for deleting a
45840Sstevel@tonic-gate  *		soft partition.  If np is NULL, then soft partitions are
45850Sstevel@tonic-gate  *		all deleted at the current level and then recursively deleted.
45860Sstevel@tonic-gate  *		Otherwise, if a name is specified either directly or as a
45870Sstevel@tonic-gate  *		result of a recursive operation, it deletes only that name.
45880Sstevel@tonic-gate  *		Since something sitting under a soft partition may be parented
45890Sstevel@tonic-gate  *		to it, we have to reparent that other device to another soft
45900Sstevel@tonic-gate  *		partition on the same component if we're deleting the one it's
45910Sstevel@tonic-gate  *		parented to.
45920Sstevel@tonic-gate  */
45930Sstevel@tonic-gate int
45940Sstevel@tonic-gate meta_sp_reset(
45950Sstevel@tonic-gate 	mdsetname_t	*sp,
45960Sstevel@tonic-gate 	mdname_t	*np,
45970Sstevel@tonic-gate 	mdcmdopts_t	options,
45980Sstevel@tonic-gate 	md_error_t	*ep
45990Sstevel@tonic-gate )
46000Sstevel@tonic-gate {
46010Sstevel@tonic-gate 	md_sp_t		*msp;
46020Sstevel@tonic-gate 	int		rval = -1;
46030Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL, *nlp = NULL;
46040Sstevel@tonic-gate 	md_sp_reset_t	reset_params;
46050Sstevel@tonic-gate 	int		num_sp;
46060Sstevel@tonic-gate 
46070Sstevel@tonic-gate 	assert(sp != NULL);
46080Sstevel@tonic-gate 
46090Sstevel@tonic-gate 	/* reset/delete all soft paritions */
46100Sstevel@tonic-gate 	if (np == NULL) {
46110Sstevel@tonic-gate 		/*
46120Sstevel@tonic-gate 		 * meta_reset_all sets MDCMD_RECURSE, but this behavior
46130Sstevel@tonic-gate 		 * is incorrect for soft partitions.  We want to clear
46140Sstevel@tonic-gate 		 * all soft partitions at a particular level in the
46150Sstevel@tonic-gate 		 * metadevice stack before moving to the next level.
46160Sstevel@tonic-gate 		 * Thus, we clear MDCMD_RECURSE from the options.
46170Sstevel@tonic-gate 		 */
46180Sstevel@tonic-gate 		options &= ~MDCMD_RECURSE;
46190Sstevel@tonic-gate 
46200Sstevel@tonic-gate 		/* for each soft partition */
46210Sstevel@tonic-gate 		rval = 0;
46220Sstevel@tonic-gate 		if (meta_get_sp_names(sp, &spnlp, 0, ep) < 0)
46230Sstevel@tonic-gate 			rval = -1;
46240Sstevel@tonic-gate 
46250Sstevel@tonic-gate 		for (nlp = spnlp; (nlp != NULL); nlp = nlp->next) {
46260Sstevel@tonic-gate 			np = nlp->namep;
46270Sstevel@tonic-gate 			if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
46280Sstevel@tonic-gate 				rval = -1;
46290Sstevel@tonic-gate 				break;
46300Sstevel@tonic-gate 			}
46310Sstevel@tonic-gate 			/*
46320Sstevel@tonic-gate 			 * meta_reset_all calls us twice to get soft
46330Sstevel@tonic-gate 			 * partitions at the top and bottom of the stack.
46340Sstevel@tonic-gate 			 * thus, if we have a parent, we'll get deleted
46350Sstevel@tonic-gate 			 * on the next call.
46360Sstevel@tonic-gate 			 */
46370Sstevel@tonic-gate 			if (MD_HAS_PARENT(msp->common.parent))
46380Sstevel@tonic-gate 				continue;
46390Sstevel@tonic-gate 			/*
46400Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
46410Sstevel@tonic-gate 			 * of individual metaclear commands.
46420Sstevel@tonic-gate 			 */
46430Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
46440Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
46450Sstevel@tonic-gate 				    np->cname, options, 0, ep) != 0) {
46460Sstevel@tonic-gate 					rval = -1;
46470Sstevel@tonic-gate 					break;
46480Sstevel@tonic-gate 				}
46490Sstevel@tonic-gate 			} else {
46500Sstevel@tonic-gate 				if (meta_sp_reset(sp, np, options, ep) != 0) {
46510Sstevel@tonic-gate 					rval = -1;
46520Sstevel@tonic-gate 					break;
46530Sstevel@tonic-gate 				}
46540Sstevel@tonic-gate 			}
46550Sstevel@tonic-gate 		}
46560Sstevel@tonic-gate 		/* cleanup return status */
46570Sstevel@tonic-gate 		metafreenamelist(spnlp);
46580Sstevel@tonic-gate 		return (rval);
46590Sstevel@tonic-gate 	}
46600Sstevel@tonic-gate 
46610Sstevel@tonic-gate 	/* check the name */
46620Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
46630Sstevel@tonic-gate 		return (-1);
46640Sstevel@tonic-gate 
46650Sstevel@tonic-gate 	/* get the unit structure */
46660Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, np, ep)) == NULL)
46670Sstevel@tonic-gate 		return (-1);
46680Sstevel@tonic-gate 
46690Sstevel@tonic-gate 	/* clear out reset parameters */
46700Sstevel@tonic-gate 	(void) memset(&reset_params, 0, sizeof (reset_params));
46710Sstevel@tonic-gate 
46720Sstevel@tonic-gate 	/* if our child is a metadevice, we need to deparent/reparent it */
46730Sstevel@tonic-gate 	if (metaismeta(msp->compnamep)) {
46740Sstevel@tonic-gate 		/* get sp's on this component */
46750Sstevel@tonic-gate 		if ((num_sp = meta_sp_get_by_component(sp, msp->compnamep,
46760Sstevel@tonic-gate 		    &spnlp, 1, ep)) <= 0)
46770Sstevel@tonic-gate 			/* no sp's on this device.  error! */
46780Sstevel@tonic-gate 			return (-1);
46790Sstevel@tonic-gate 		else if (num_sp == 1)
46800Sstevel@tonic-gate 			/* last sp on this device, so we deparent */
46810Sstevel@tonic-gate 			reset_params.new_parent = MD_NO_PARENT;
46820Sstevel@tonic-gate 		else {
46830Sstevel@tonic-gate 			/* have to reparent this metadevice */
46840Sstevel@tonic-gate 			for (nlp = spnlp; nlp != NULL; nlp = nlp->next) {
46850Sstevel@tonic-gate 				if (meta_getminor(nlp->namep->dev) ==
46860Sstevel@tonic-gate 					meta_getminor(np->dev))
46870Sstevel@tonic-gate 					continue;
46880Sstevel@tonic-gate 				/*
46890Sstevel@tonic-gate 				 * this isn't the softpart we are deleting,
46900Sstevel@tonic-gate 				 * so use this device as the new parent.
46910Sstevel@tonic-gate 				 */
46920Sstevel@tonic-gate 				reset_params.new_parent =
46930Sstevel@tonic-gate 				    meta_getminor(nlp->namep->dev);
46940Sstevel@tonic-gate 				break;
46950Sstevel@tonic-gate 			}
46960Sstevel@tonic-gate 		}
46970Sstevel@tonic-gate 		metafreenamelist(spnlp);
46980Sstevel@tonic-gate 	}
46990Sstevel@tonic-gate 
47000Sstevel@tonic-gate 	if (meta_sp_reset_common(sp, np, msp, reset_params, options, ep) != 0)
47010Sstevel@tonic-gate 		return (-1);
47020Sstevel@tonic-gate 
47030Sstevel@tonic-gate 	return (0);
47040Sstevel@tonic-gate }
47050Sstevel@tonic-gate 
47060Sstevel@tonic-gate /*
47070Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset_component()
47080Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
47090Sstevel@tonic-gate  *		name	- the string name of the device to reset
47100Sstevel@tonic-gate  *		options	- metaclear options
47110Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
47120Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
47130Sstevel@tonic-gate  * PURPOSE:	provides the ability to delete all soft partitions on a
47140Sstevel@tonic-gate  *		specified device (metaclear -p).  It first gets all of the
47150Sstevel@tonic-gate  *		soft partitions on the component and then deletes each one
47160Sstevel@tonic-gate  *		individually.
47170Sstevel@tonic-gate  */
47180Sstevel@tonic-gate int
47190Sstevel@tonic-gate meta_sp_reset_component(
47200Sstevel@tonic-gate 	mdsetname_t	*sp,
47210Sstevel@tonic-gate 	char		*name,
47220Sstevel@tonic-gate 	mdcmdopts_t	options,
47230Sstevel@tonic-gate 	md_error_t	*ep
47240Sstevel@tonic-gate )
47250Sstevel@tonic-gate {
47260Sstevel@tonic-gate 	mdname_t	*compnp, *np;
47270Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
47280Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
47290Sstevel@tonic-gate 	md_sp_t		*msp;
47300Sstevel@tonic-gate 	int		count;
47310Sstevel@tonic-gate 	md_sp_reset_t	reset_params;
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate 	if ((compnp = metaname(&sp, name, ep)) == NULL)
47340Sstevel@tonic-gate 		return (-1);
47350Sstevel@tonic-gate 
47360Sstevel@tonic-gate 	/* If we're starting out with no soft partitions, it's an error */
47370Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 1, ep);
47380Sstevel@tonic-gate 	if (count == 0)
47390Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_NOSP, 0, compnp->cname));
47400Sstevel@tonic-gate 	else if (count < 0)
47410Sstevel@tonic-gate 		return (-1);
47420Sstevel@tonic-gate 
47430Sstevel@tonic-gate 	/*
47440Sstevel@tonic-gate 	 * clear all soft partitions on this component.
47450Sstevel@tonic-gate 	 * NOTE: we reparent underlying metadevices as we go so that
47460Sstevel@tonic-gate 	 * things stay sane.  Also, if we encounter an error, we stop
47470Sstevel@tonic-gate 	 * and go no further in case recovery might be needed.
47480Sstevel@tonic-gate 	 */
47490Sstevel@tonic-gate 	for (nlp = spnlp; nlp != NULL; nlp = nlp->next) {
47500Sstevel@tonic-gate 		/* clear out reset parameters */
47510Sstevel@tonic-gate 		(void) memset(&reset_params, 0, sizeof (reset_params));
47520Sstevel@tonic-gate 
47530Sstevel@tonic-gate 		/* check the name */
47540Sstevel@tonic-gate 		np = nlp->namep;
47550Sstevel@tonic-gate 
47560Sstevel@tonic-gate 		if (metachkmeta(np, ep) != 0) {
47570Sstevel@tonic-gate 			metafreenamelist(spnlp);
47580Sstevel@tonic-gate 			return (-1);
47590Sstevel@tonic-gate 		}
47600Sstevel@tonic-gate 
47610Sstevel@tonic-gate 		/* get the unit structure */
47620Sstevel@tonic-gate 		if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
47630Sstevel@tonic-gate 			metafreenamelist(spnlp);
47640Sstevel@tonic-gate 			return (-1);
47650Sstevel@tonic-gate 		}
47660Sstevel@tonic-gate 
47670Sstevel@tonic-gate 		/* have to deparent/reparent metadevices */
47680Sstevel@tonic-gate 		if (metaismeta(compnp)) {
47690Sstevel@tonic-gate 			if (nlp->next == NULL)
47700Sstevel@tonic-gate 				reset_params.new_parent = MD_NO_PARENT;
47710Sstevel@tonic-gate 			else
47720Sstevel@tonic-gate 				reset_params.new_parent =
47730Sstevel@tonic-gate 				    meta_getminor(spnlp->next->namep->dev);
47740Sstevel@tonic-gate 		}
47750Sstevel@tonic-gate 
47760Sstevel@tonic-gate 		/* clear soft partition */
47770Sstevel@tonic-gate 		if (meta_sp_reset_common(sp, np, msp, reset_params,
47780Sstevel@tonic-gate 		    options, ep) < 0) {
47790Sstevel@tonic-gate 			metafreenamelist(spnlp);
47800Sstevel@tonic-gate 			return (-1);
47810Sstevel@tonic-gate 		}
47820Sstevel@tonic-gate 	}
47830Sstevel@tonic-gate 	metafreenamelist(spnlp);
47840Sstevel@tonic-gate 	return (0);
47850Sstevel@tonic-gate }
47860Sstevel@tonic-gate 
47870Sstevel@tonic-gate /*
47880Sstevel@tonic-gate  * **************************************************************************
47890Sstevel@tonic-gate  *                      Grow (metattach) Functions                          *
47900Sstevel@tonic-gate  * **************************************************************************
47910Sstevel@tonic-gate  */
47920Sstevel@tonic-gate 
47930Sstevel@tonic-gate /*
47940Sstevel@tonic-gate  * FUNCTION:	meta_sp_attach()
47950Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to attach to
47960Sstevel@tonic-gate  *		np	- the name of the device to attach to
47970Sstevel@tonic-gate  *		addsize	- the unparsed string holding the amount of space to add
47980Sstevel@tonic-gate  *		options	- metattach options
47990Sstevel@tonic-gate  *		alignment - data alignment
48000Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
48010Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
48020Sstevel@tonic-gate  * PURPOSE:	grows a soft partition by reading in the existing unit
48030Sstevel@tonic-gate  *		structure and setting its state to Growing, allocating more
48040Sstevel@tonic-gate  *		space (similar to meta_create_sp()), updating the watermarks,
48050Sstevel@tonic-gate  *		and then writing out the new unit structure in the Okay state.
48060Sstevel@tonic-gate  */
48070Sstevel@tonic-gate int
48080Sstevel@tonic-gate meta_sp_attach(
48090Sstevel@tonic-gate 	mdsetname_t	*sp,
48100Sstevel@tonic-gate 	mdname_t	*np,
48110Sstevel@tonic-gate 	char		*addsize,
48120Sstevel@tonic-gate 	mdcmdopts_t	options,
48130Sstevel@tonic-gate 	sp_ext_length_t	alignment,
48140Sstevel@tonic-gate 	md_error_t	*ep
48150Sstevel@tonic-gate )
48160Sstevel@tonic-gate {
48170Sstevel@tonic-gate 	md_grow_params_t	grow_params;
48180Sstevel@tonic-gate 	sp_ext_length_t		grow_len;	/* amount to grow */
48190Sstevel@tonic-gate 	mp_unit_t		*mp, *new_un;
48200Sstevel@tonic-gate 	mdname_t		*compnp = NULL;
48210Sstevel@tonic-gate 
48220Sstevel@tonic-gate 	sp_ext_node_t		*extlist = NULL;
48230Sstevel@tonic-gate 	int			numexts;
48240Sstevel@tonic-gate 	mdnamelist_t		*spnlp = NULL;
48250Sstevel@tonic-gate 	int			count;
48260Sstevel@tonic-gate 	md_sp_t			*msp;
48270Sstevel@tonic-gate 	daddr_t			start_block;
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate 	/* should have the same set */
48300Sstevel@tonic-gate 	assert(sp != NULL);
48310Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(np->dev)));
48320Sstevel@tonic-gate 
48330Sstevel@tonic-gate 	/* check name */
48340Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
48350Sstevel@tonic-gate 		return (-1);
48360Sstevel@tonic-gate 
48370Sstevel@tonic-gate 	if (meta_sp_parsesize(addsize, &grow_len) == -1) {
48380Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BAD_LENGTH, 0, np->cname));
48390Sstevel@tonic-gate 	}
48400Sstevel@tonic-gate 
48410Sstevel@tonic-gate 	if ((mp = (mp_unit_t *)meta_get_mdunit(sp, np, ep)) == NULL)
48420Sstevel@tonic-gate 		return (-1);
48430Sstevel@tonic-gate 
48440Sstevel@tonic-gate 	/* make sure we don't have a parent */
48450Sstevel@tonic-gate 	if (MD_HAS_PARENT(mp->c.un_parent)) {
48460Sstevel@tonic-gate 		Free(mp);
48470Sstevel@tonic-gate 		return (mdmderror(ep, MDE_INVAL_UNIT, 0, np->cname));
48480Sstevel@tonic-gate 	}
48490Sstevel@tonic-gate 
48500Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
48510Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: Unit structure before new "
48520Sstevel@tonic-gate 		    "space:\n");
48530Sstevel@tonic-gate 		meta_sp_printunit(mp);
48540Sstevel@tonic-gate 	}
48550Sstevel@tonic-gate 
48560Sstevel@tonic-gate 	/*
48570Sstevel@tonic-gate 	 * NOTE: the fast option to metakeyname is 0 as opposed to 1
48580Sstevel@tonic-gate 	 * If this was not the case we would suffer the following
48590Sstevel@tonic-gate 	 * assertion failure:
48600Sstevel@tonic-gate 	 * Assertion failed: type1 != MDT_FAST_META && type1 != MDT_FAST_COMP
48610Sstevel@tonic-gate 	 * file meta_check.x, line 315
48620Sstevel@tonic-gate 	 * I guess this is because we have not "seen" this drive before
48630Sstevel@tonic-gate 	 * and hence hit the failure - this is of course the attach routine
48640Sstevel@tonic-gate 	 */
48650Sstevel@tonic-gate 	if ((compnp = metakeyname(&sp, mp->un_key, 0, ep)) == NULL) {
48660Sstevel@tonic-gate 		Free(mp);
48670Sstevel@tonic-gate 		return (-1);
48680Sstevel@tonic-gate 	}
48690Sstevel@tonic-gate 
48700Sstevel@tonic-gate 	/* metakeyname does not fill in the key. */
48710Sstevel@tonic-gate 	compnp->key = mp->un_key;
48720Sstevel@tonic-gate 
48730Sstevel@tonic-gate 	/* work out the space on the component that we are dealing with */
48740Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
48750Sstevel@tonic-gate 
48760Sstevel@tonic-gate 	/*
48770Sstevel@tonic-gate 	 * see if the component has been soft partitioned yet, or if an
48780Sstevel@tonic-gate 	 * error occurred.
48790Sstevel@tonic-gate 	 */
48800Sstevel@tonic-gate 	if (count == 0) {
48810Sstevel@tonic-gate 		Free(mp);
48820Sstevel@tonic-gate 		return (mdmderror(ep, MDE_NOT_SP, 0, np->cname));
48830Sstevel@tonic-gate 	} else if (count < 0) {
48840Sstevel@tonic-gate 		Free(mp);
48850Sstevel@tonic-gate 		return (-1);
48860Sstevel@tonic-gate 	}
48870Sstevel@tonic-gate 
48880Sstevel@tonic-gate 	/*
48890Sstevel@tonic-gate 	 * seed extlist with reserved space at the beginning of the volume and
48900Sstevel@tonic-gate 	 * enough space for the end watermark.  The end watermark always gets
48910Sstevel@tonic-gate 	 * updated, but if the underlying device changes size it may not be
48920Sstevel@tonic-gate 	 * pointed to until the extent before it is updated.  Since the
48930Sstevel@tonic-gate 	 * end of the reserved space is where the first watermark starts,
48940Sstevel@tonic-gate 	 * the reserved extent should never be marked for updating.
48950Sstevel@tonic-gate 	 */
48960Sstevel@tonic-gate 	if ((start_block = meta_sp_get_start(sp, compnp, ep)) ==
48970Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
48980Sstevel@tonic-gate 		Free(mp);
48990Sstevel@tonic-gate 		return (-1);
49000Sstevel@tonic-gate 	}
49010Sstevel@tonic-gate 
49020Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist, 0ULL, start_block,
49030Sstevel@tonic-gate 	    EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
49040Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
49050Sstevel@tonic-gate 	    metagetsize(compnp, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
49060Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
49070Sstevel@tonic-gate 
49080Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
49090Sstevel@tonic-gate 		Free(mp);
49100Sstevel@tonic-gate 		return (-1);
49110Sstevel@tonic-gate 	}
49120Sstevel@tonic-gate 
49130Sstevel@tonic-gate 	metafreenamelist(spnlp);
49140Sstevel@tonic-gate 
49150Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
49160Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: list of used extents:\n");
49170Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
49180Sstevel@tonic-gate 	}
49190Sstevel@tonic-gate 
49200Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
49210Sstevel@tonic-gate 
49220Sstevel@tonic-gate 	assert(mp->un_numexts >= 1);
49230Sstevel@tonic-gate 	numexts = meta_sp_alloc_by_len(sp, np, &extlist, &grow_len,
49240Sstevel@tonic-gate 	    mp->un_ext[mp->un_numexts - 1].un_poff,
49250Sstevel@tonic-gate 	    (alignment > 0) ? alignment :
49260Sstevel@tonic-gate 	    meta_sp_get_default_alignment(sp, compnp, ep));
49270Sstevel@tonic-gate 
49280Sstevel@tonic-gate 	if (numexts == -1) {
49290Sstevel@tonic-gate 		Free(mp);
49300Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_NOSPACE, 0, np->cname));
49310Sstevel@tonic-gate 	}
49320Sstevel@tonic-gate 
49330Sstevel@tonic-gate 	/* allocate new unit structure and copy in old unit */
49340Sstevel@tonic-gate 	if ((new_un = meta_sp_updateunit(np, mp, extlist,
49350Sstevel@tonic-gate 	    grow_len, numexts, ep)) == NULL) {
49360Sstevel@tonic-gate 		Free(mp);
49370Sstevel@tonic-gate 		return (-1);
49380Sstevel@tonic-gate 	}
49390Sstevel@tonic-gate 	Free(mp);
49400Sstevel@tonic-gate 
49410Sstevel@tonic-gate 	/* If running in dryrun mode (-n option), we're done here */
49420Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
49430Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
49440Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
49450Sstevel@tonic-gate 			    "%s: Soft Partition would grow\n"),
49460Sstevel@tonic-gate 			    np->cname);
49470Sstevel@tonic-gate 			(void) fflush(stdout);
49480Sstevel@tonic-gate 		}
49490Sstevel@tonic-gate 		return (0);
49500Sstevel@tonic-gate 	}
49510Sstevel@tonic-gate 
49520Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
49530Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: updated unit structure:\n");
49540Sstevel@tonic-gate 		meta_sp_printunit(new_un);
49550Sstevel@tonic-gate 	}
49560Sstevel@tonic-gate 
49570Sstevel@tonic-gate 	assert(new_un != NULL);
49580Sstevel@tonic-gate 
49590Sstevel@tonic-gate 	(void) memset(&grow_params, 0, sizeof (grow_params));
49600Sstevel@tonic-gate 	if (new_un->c.un_total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) {
49610Sstevel@tonic-gate 		grow_params.options = MD_CRO_64BIT;
49620Sstevel@tonic-gate 		new_un->c.un_revision = MD_64BIT_META_DEV;
49630Sstevel@tonic-gate 	} else {
49640Sstevel@tonic-gate 		grow_params.options = MD_CRO_32BIT;
49650Sstevel@tonic-gate 		new_un->c.un_revision = MD_32BIT_META_DEV;
49660Sstevel@tonic-gate 	}
49670Sstevel@tonic-gate 	grow_params.mnum = MD_SID(new_un);
49680Sstevel@tonic-gate 	grow_params.size = new_un->c.un_size;
49690Sstevel@tonic-gate 	grow_params.mdp = (uintptr_t)new_un;
49700Sstevel@tonic-gate 	MD_SETDRIVERNAME(&grow_params, MD_SP, MD_MIN2SET(grow_params.mnum));
49710Sstevel@tonic-gate 
49720Sstevel@tonic-gate 	if (metaioctl(MD_IOCGROW, &grow_params, &grow_params.mde,
49730Sstevel@tonic-gate 	    np->cname) != 0) {
49740Sstevel@tonic-gate 		(void) mdstealerror(ep, &grow_params.mde);
49750Sstevel@tonic-gate 		return (-1);
49760Sstevel@tonic-gate 	}
49770Sstevel@tonic-gate 
49780Sstevel@tonic-gate 	/* update all watermarks */
49790Sstevel@tonic-gate 
49800Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, np, ep)) == NULL)
49810Sstevel@tonic-gate 		return (-1);
49820Sstevel@tonic-gate 	if (meta_sp_update_wm(sp, msp, extlist, ep) < 0)
49830Sstevel@tonic-gate 		return (-1);
49840Sstevel@tonic-gate 
49850Sstevel@tonic-gate 
49860Sstevel@tonic-gate 	/* second phase of commit, set status to MD_SP_OK */
49870Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &(MD_SID(new_un)), 1, MD_SP_OK, ep) < 0)
49880Sstevel@tonic-gate 		return (-1);
49890Sstevel@tonic-gate 
49900Sstevel@tonic-gate 	meta_invalidate_name(np);
49910Sstevel@tonic-gate 
49920Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
49930Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
49940Sstevel@tonic-gate 		    "%s: Soft Partition has been grown\n"),
49950Sstevel@tonic-gate 		    np->cname);
49960Sstevel@tonic-gate 		(void) fflush(stdout);
49970Sstevel@tonic-gate 	}
49980Sstevel@tonic-gate 
49990Sstevel@tonic-gate 	return (0);
50000Sstevel@tonic-gate }
50010Sstevel@tonic-gate 
50020Sstevel@tonic-gate /*
50030Sstevel@tonic-gate  * **************************************************************************
50040Sstevel@tonic-gate  *                    Recovery (metarecover) Functions                      *
50050Sstevel@tonic-gate  * **************************************************************************
50060Sstevel@tonic-gate  */
50070Sstevel@tonic-gate 
50080Sstevel@tonic-gate /*
50090Sstevel@tonic-gate  * FUNCTION:	meta_recover_sp()
50100Sstevel@tonic-gate  * INPUT:	sp	- the name of the set we are recovering on
50110Sstevel@tonic-gate  *		compnp	- name pointer for device we are recovering on
50120Sstevel@tonic-gate  *		argc	- argument count
50130Sstevel@tonic-gate  *		argv	- left over arguments not parsed by metarecover command
50140Sstevel@tonic-gate  *		options	- metarecover options
50150Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
50160Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
50170Sstevel@tonic-gate  * PURPOSE:	parse soft partitioning-specific metarecover options and
50180Sstevel@tonic-gate  *		dispatch to the appropriate function to handle recovery.
50190Sstevel@tonic-gate  */
50200Sstevel@tonic-gate int
50210Sstevel@tonic-gate meta_recover_sp(
50220Sstevel@tonic-gate 	mdsetname_t	*sp,
50230Sstevel@tonic-gate 	mdname_t	*compnp,
50240Sstevel@tonic-gate 	int		argc,
50250Sstevel@tonic-gate 	char		*argv[],
50260Sstevel@tonic-gate 	mdcmdopts_t	options,
50270Sstevel@tonic-gate 	md_error_t	*ep
50280Sstevel@tonic-gate )
50290Sstevel@tonic-gate {
50300Sstevel@tonic-gate 	md_set_desc	*sd;
50310Sstevel@tonic-gate 
50320Sstevel@tonic-gate 	if (argc > 1) {
50330Sstevel@tonic-gate 		(void) meta_cook_syntax(ep, MDE_SYNTAX, compnp->cname,
50340Sstevel@tonic-gate 		    argc, argv);
50350Sstevel@tonic-gate 		return (-1);
50360Sstevel@tonic-gate 	}
50370Sstevel@tonic-gate 
50380Sstevel@tonic-gate 	/*
50390Sstevel@tonic-gate 	 * For a MN set, this operation must be performed on the master
50400Sstevel@tonic-gate 	 * as it is responsible for maintaining the watermarks
50410Sstevel@tonic-gate 	 */
50420Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
50430Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
50440Sstevel@tonic-gate 			return (-1);
50450Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd) && !sd->sd_mn_am_i_master) {
50460Sstevel@tonic-gate 			(void) mddserror(ep, MDE_DS_MASTER_ONLY, sp->setno,
50470Sstevel@tonic-gate 			    sd->sd_mn_master_nodenm, NULL, NULL);
50480Sstevel@tonic-gate 			return (-1);
50490Sstevel@tonic-gate 		}
50500Sstevel@tonic-gate 	}
50510Sstevel@tonic-gate 	if (argc == 0) {
50520Sstevel@tonic-gate 		/*
50530Sstevel@tonic-gate 		 * if no additional arguments are passed, metarecover should
50540Sstevel@tonic-gate 		 * validate both on-disk and metadb structures as well as
50550Sstevel@tonic-gate 		 * checking that both are consistent with each other
50560Sstevel@tonic-gate 		 */
50570Sstevel@tonic-gate 		if (meta_sp_validate_wm(sp, compnp, options, ep) < 0)
50580Sstevel@tonic-gate 			return (-1);
50590Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) < 0)
50600Sstevel@tonic-gate 			return (-1);
50610Sstevel@tonic-gate 		if (meta_sp_validate_wm_and_unit(sp, compnp, options, ep) < 0)
50620Sstevel@tonic-gate 			return (-1);
50630Sstevel@tonic-gate 	} else if (strcmp(argv[0], "-d") == 0) {
50640Sstevel@tonic-gate 		/*
50650Sstevel@tonic-gate 		 * Ensure that there is no existing valid record for this
50660Sstevel@tonic-gate 		 * soft-partition. If there is we have nothing to do.
50670Sstevel@tonic-gate 		 */
50680Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) == 0)
50690Sstevel@tonic-gate 			return (-1);
50700Sstevel@tonic-gate 		/* validate and recover from on-disk structures */
50710Sstevel@tonic-gate 		if (meta_sp_validate_wm(sp, compnp, options, ep) < 0)
50720Sstevel@tonic-gate 			return (-1);
50730Sstevel@tonic-gate 		if (meta_sp_recover_from_wm(sp, compnp, options, ep) < 0)
50740Sstevel@tonic-gate 			return (-1);
50750Sstevel@tonic-gate 	} else if (strcmp(argv[0], "-m") == 0) {
50760Sstevel@tonic-gate 		/* validate and recover from metadb structures */
50770Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) < 0)
50780Sstevel@tonic-gate 			return (-1);
50790Sstevel@tonic-gate 		if (meta_sp_recover_from_unit(sp, compnp, options, ep) < 0)
50800Sstevel@tonic-gate 			return (-1);
50810Sstevel@tonic-gate 	} else {
50820Sstevel@tonic-gate 		/* syntax error */
50830Sstevel@tonic-gate 		(void) meta_cook_syntax(ep, MDE_SYNTAX, compnp->cname,
50840Sstevel@tonic-gate 		    argc, argv);
50850Sstevel@tonic-gate 		return (-1);
50860Sstevel@tonic-gate 	}
50870Sstevel@tonic-gate 
50880Sstevel@tonic-gate 	return (0);
50890Sstevel@tonic-gate }
50900Sstevel@tonic-gate 
50910Sstevel@tonic-gate /*
50920Sstevel@tonic-gate  * FUNCTION:	meta_sp_display_exthdr()
50930Sstevel@tonic-gate  * INPUT:	none
50940Sstevel@tonic-gate  * OUTPUT:	none
50950Sstevel@tonic-gate  * RETURNS:	void
50960Sstevel@tonic-gate  * PURPOSE:	print header line for sp_ext_node_t information.  to be used
50970Sstevel@tonic-gate  *		in conjunction with meta_sp_display_ext().
50980Sstevel@tonic-gate  */
50990Sstevel@tonic-gate static void
51000Sstevel@tonic-gate meta_sp_display_exthdr(void)
51010Sstevel@tonic-gate {
51020Sstevel@tonic-gate 	(void) printf("%20s %5s %7s %20s %20s\n",
51030Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Name"),
51040Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Seq#"),
51050Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Type"),
51060Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Offset"),
51070Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Length"));
51080Sstevel@tonic-gate }
51090Sstevel@tonic-gate 
51100Sstevel@tonic-gate 
51110Sstevel@tonic-gate /*
51120Sstevel@tonic-gate  * FUNCTION:	meta_sp_display_ext()
51130Sstevel@tonic-gate  * INPUT:	ext	- extent to display
51140Sstevel@tonic-gate  * OUTPUT:	none
51150Sstevel@tonic-gate  * RETURNS:	void
51160Sstevel@tonic-gate  * PURPOSE:	print selected fields from sp_ext_node_t.
51170Sstevel@tonic-gate  */
51180Sstevel@tonic-gate static void
51190Sstevel@tonic-gate meta_sp_display_ext(sp_ext_node_t *ext)
51200Sstevel@tonic-gate {
51210Sstevel@tonic-gate 	/* print extent information */
51220Sstevel@tonic-gate 	if (ext->ext_namep != NULL)
51230Sstevel@tonic-gate 		(void) printf("%20s ", ext->ext_namep->cname);
51240Sstevel@tonic-gate 	else
51250Sstevel@tonic-gate 		(void) printf("%20s ", "NONE");
51260Sstevel@tonic-gate 
51270Sstevel@tonic-gate 	(void) printf("%5u ", ext->ext_seq);
51280Sstevel@tonic-gate 
51290Sstevel@tonic-gate 	switch (ext->ext_type) {
51300Sstevel@tonic-gate 	case EXTTYP_ALLOC:
51310Sstevel@tonic-gate 		(void) printf("%7s ", "ALLOC");
51320Sstevel@tonic-gate 		break;
51330Sstevel@tonic-gate 	case EXTTYP_FREE:
51340Sstevel@tonic-gate 		(void) printf("%7s ", "FREE");
51350Sstevel@tonic-gate 		break;
51360Sstevel@tonic-gate 	case EXTTYP_RESERVED:
51370Sstevel@tonic-gate 		(void) printf("%7s ", "RESV");
51380Sstevel@tonic-gate 		break;
51390Sstevel@tonic-gate 	case EXTTYP_END:
51400Sstevel@tonic-gate 		(void) printf("%7s ", "END");
51410Sstevel@tonic-gate 		break;
51420Sstevel@tonic-gate 	default:
51430Sstevel@tonic-gate 		(void) printf("%7s ", "INVLD");
51440Sstevel@tonic-gate 		break;
51450Sstevel@tonic-gate 	}
51460Sstevel@tonic-gate 
51470Sstevel@tonic-gate 	(void) printf("%20llu %20llu\n", ext->ext_offset, ext->ext_length);
51480Sstevel@tonic-gate }
51490Sstevel@tonic-gate 
51500Sstevel@tonic-gate 
51510Sstevel@tonic-gate /*
51520Sstevel@tonic-gate  * FUNCTION:	meta_sp_checkseq()
51530Sstevel@tonic-gate  * INPUT:	extlist	- list of extents to be checked
51540Sstevel@tonic-gate  * OUTPUT:	none
51550Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
51560Sstevel@tonic-gate  * PURPOSE:	check soft partition sequence numbers.  this function assumes
51570Sstevel@tonic-gate  *		that a list of extents representing 1 or more soft partitions
51580Sstevel@tonic-gate  *		is passed in sorted in sequence number order.  within a
51590Sstevel@tonic-gate  *		single soft partition, there may not be any missing or
51600Sstevel@tonic-gate  *		duplicate sequence numbers.
51610Sstevel@tonic-gate  */
51620Sstevel@tonic-gate static int
51630Sstevel@tonic-gate meta_sp_checkseq(sp_ext_node_t *extlist)
51640Sstevel@tonic-gate {
51650Sstevel@tonic-gate 	sp_ext_node_t *ext;
51660Sstevel@tonic-gate 
51670Sstevel@tonic-gate 	assert(extlist != NULL);
51680Sstevel@tonic-gate 
51690Sstevel@tonic-gate 	for (ext = extlist;
51700Sstevel@tonic-gate 	    ext->ext_next != NULL && ext->ext_next->ext_type == EXTTYP_ALLOC;
51710Sstevel@tonic-gate 	    ext = ext->ext_next) {
51720Sstevel@tonic-gate 		if (ext->ext_next->ext_namep != NULL &&
51730Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
51740Sstevel@tonic-gate 			ext->ext_namep->cname) != 0)
51750Sstevel@tonic-gate 				continue;
51760Sstevel@tonic-gate 
51770Sstevel@tonic-gate 		if (ext->ext_next->ext_seq != ext->ext_seq + 1) {
51780Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
51790Sstevel@tonic-gate 			    "%s: sequence numbers are "
51800Sstevel@tonic-gate 			    "incorrect: %d should be %d\n"),
51810Sstevel@tonic-gate 			    ext->ext_next->ext_namep->cname,
51820Sstevel@tonic-gate 			    ext->ext_next->ext_seq, ext->ext_seq + 1);
51830Sstevel@tonic-gate 			return (-1);
51840Sstevel@tonic-gate 		}
51850Sstevel@tonic-gate 	}
51860Sstevel@tonic-gate 	return (0);
51870Sstevel@tonic-gate }
51880Sstevel@tonic-gate 
51890Sstevel@tonic-gate 
51900Sstevel@tonic-gate /*
51910Sstevel@tonic-gate  * FUNCTION:	meta_sp_resolve_name_conflict()
51920Sstevel@tonic-gate  * INPUT:	sp	- name of set we're are recovering in.
51930Sstevel@tonic-gate  *		old_np	- name pointer of soft partition we found on disk.
51940Sstevel@tonic-gate  * OUTPUT:	new_np	- name pointer for new soft partition name.
51950Sstevel@tonic-gate  *		ep	- error pointer returned.
51960Sstevel@tonic-gate  * RETURNS:	int	- 0 - name not replace, 1 - name replaced, -1 - error
51970Sstevel@tonic-gate  * PURPOSE:	Check to see if the name of one of the soft partitions we found
51980Sstevel@tonic-gate  *		on disk already exists in the metadb.  If so, prompt for a new
51990Sstevel@tonic-gate  *		name.  In addition, we keep a static array of names that
52000Sstevel@tonic-gate  *		will be recovered from this device since these names don't
52010Sstevel@tonic-gate  *		exist in the configuration at this point but cannot be
52020Sstevel@tonic-gate  *		recovered more than once.
52030Sstevel@tonic-gate  */
52040Sstevel@tonic-gate static int
52050Sstevel@tonic-gate meta_sp_resolve_name_conflict(
52060Sstevel@tonic-gate 	mdsetname_t	*sp,
52070Sstevel@tonic-gate 	mdname_t	*old_np,
52080Sstevel@tonic-gate 	mdname_t	**new_np,
52090Sstevel@tonic-gate 	md_error_t	*ep
52100Sstevel@tonic-gate )
52110Sstevel@tonic-gate {
52120Sstevel@tonic-gate 	char		yesno[255];
52130Sstevel@tonic-gate 	char		*yes;
52140Sstevel@tonic-gate 	char		newname[MD_SP_MAX_DEVNAME_PLUS_1];
52150Sstevel@tonic-gate 	int		nunits;
52160Sstevel@tonic-gate 	static int	*used_names = NULL;
52170Sstevel@tonic-gate 
52180Sstevel@tonic-gate 	assert(old_np != NULL);
52190Sstevel@tonic-gate 
52200Sstevel@tonic-gate 	if (used_names == NULL) {
52210Sstevel@tonic-gate 		if ((nunits = meta_get_nunits(ep)) < 0)
52220Sstevel@tonic-gate 			return (-1);
52230Sstevel@tonic-gate 		used_names = Zalloc(nunits * sizeof (int));
52240Sstevel@tonic-gate 	}
52250Sstevel@tonic-gate 
52260Sstevel@tonic-gate 	/* see if it exists already */
52270Sstevel@tonic-gate 	if (used_names[MD_MIN2UNIT(meta_getminor(old_np->dev))] == 0 &&
52280Sstevel@tonic-gate 	    metagetmiscname(old_np, ep) == NULL) {
52290Sstevel@tonic-gate 		if (! mdismderror(ep, MDE_UNIT_NOT_SETUP))
52300Sstevel@tonic-gate 			return (-1);
52310Sstevel@tonic-gate 		else {
52320Sstevel@tonic-gate 			used_names[MD_MIN2UNIT(meta_getminor(old_np->dev))] = 1;
52330Sstevel@tonic-gate 			mdclrerror(ep);
52340Sstevel@tonic-gate 			return (0);
52350Sstevel@tonic-gate 		}
52360Sstevel@tonic-gate 	}
52370Sstevel@tonic-gate 
52380Sstevel@tonic-gate 	/* name exists, ask the user for a new one */
52390Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
52400Sstevel@tonic-gate 	    "WARNING: A soft partition named %s was found in the extent\n"
52410Sstevel@tonic-gate 	    "headers, but this name already exists in the metadb "
52420Sstevel@tonic-gate 	    "configuration.\n"
52430Sstevel@tonic-gate 	    "In order to continue recovery you must supply\n"
52440Sstevel@tonic-gate 	    "a new name for this soft partition.\n"), old_np->cname);
52450Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
52460Sstevel@tonic-gate 	    "Would you like to continue and supply a new name? (yes/no) "));
52470Sstevel@tonic-gate 
52480Sstevel@tonic-gate 	(void) fflush(stdout);
52490Sstevel@tonic-gate 	if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
52500Sstevel@tonic-gate 	    (strlen(yesno) == 1))
52510Sstevel@tonic-gate 		(void) snprintf(yesno, sizeof (yesno), "%s\n",
52520Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "no"));
52530Sstevel@tonic-gate 	yes = dgettext(TEXT_DOMAIN, "yes");
52540Sstevel@tonic-gate 	if (strncasecmp(yesno, yes, strlen(yesno) - 1) != 0) {
52550Sstevel@tonic-gate 		return (-1);
52560Sstevel@tonic-gate 	}
52570Sstevel@tonic-gate 
52580Sstevel@tonic-gate 	(void) fflush(stdin);
52590Sstevel@tonic-gate 
52600Sstevel@tonic-gate 	/* get the new name */
52610Sstevel@tonic-gate 	for (;;) {
52620Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "Please enter a new name "
52630Sstevel@tonic-gate 		    "for this soft partition (dXXXX) "));
52640Sstevel@tonic-gate 		(void) fflush(stdout);
52650Sstevel@tonic-gate 		if (fgets(newname, MD_SP_MAX_DEVNAME_PLUS_1, stdin) == NULL)
52660Sstevel@tonic-gate 			(void) strcpy(newname, "");
52670Sstevel@tonic-gate 
52680Sstevel@tonic-gate 		/* remove newline character */
52690Sstevel@tonic-gate 		if (newname[strlen(newname) - 1] == '\n')
52700Sstevel@tonic-gate 			newname[strlen(newname) - 1] = '\0';
52710Sstevel@tonic-gate 
52720Sstevel@tonic-gate 		if (!(is_metaname(newname)) ||
52730Sstevel@tonic-gate 		    (meta_init_make_device(&sp, newname, ep) != 0)) {
52740Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
52750Sstevel@tonic-gate 			    "Invalid metadevice name\n"));
52760Sstevel@tonic-gate 			(void) fflush(stderr);
52770Sstevel@tonic-gate 			continue;
52780Sstevel@tonic-gate 		}
52790Sstevel@tonic-gate 
52800Sstevel@tonic-gate 		if ((*new_np = metaname(&sp, newname, ep)) == NULL) {
52810Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
52820Sstevel@tonic-gate 			    "Invalid metadevice name\n"));
52830Sstevel@tonic-gate 			(void) fflush(stderr);
52840Sstevel@tonic-gate 			continue;
52850Sstevel@tonic-gate 		}
52860Sstevel@tonic-gate 
52870Sstevel@tonic-gate 		assert(MD_MIN2UNIT(meta_getminor((*new_np)->dev)) < nunits);
52880Sstevel@tonic-gate 		/* make sure the name isn't already being used */
52890Sstevel@tonic-gate 		if (used_names[MD_MIN2UNIT(meta_getminor((*new_np)->dev))] ||
52900Sstevel@tonic-gate 		    metagetmiscname(*new_np, ep) != NULL) {
52910Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
52920Sstevel@tonic-gate 			    "That name already exists\n"));
52930Sstevel@tonic-gate 			continue;
52940Sstevel@tonic-gate 		} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP))
52950Sstevel@tonic-gate 			return (-1);
52960Sstevel@tonic-gate 
52970Sstevel@tonic-gate 		break;
52980Sstevel@tonic-gate 	}
52990Sstevel@tonic-gate 
53000Sstevel@tonic-gate 	/* got a new name, place in used array and return */
53010Sstevel@tonic-gate 	used_names[MD_MIN2UNIT(meta_getminor((*new_np)->dev))] = 1;
53020Sstevel@tonic-gate 	mdclrerror(ep);
53030Sstevel@tonic-gate 	return (1);
53040Sstevel@tonic-gate }
53050Sstevel@tonic-gate 
53060Sstevel@tonic-gate /*
53070Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_wm()
53080Sstevel@tonic-gate  * INPUT:	sp	- set name we are recovering in
53090Sstevel@tonic-gate  *		compnp	- name pointer for device we are recovering from
53100Sstevel@tonic-gate  *		options	- metarecover options
53110Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
53120Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
53130Sstevel@tonic-gate  * PURPOSE:	validate and display watermark configuration.  walk the
53140Sstevel@tonic-gate  *		on-disk watermark structures and validate the information
53150Sstevel@tonic-gate  *		found within.  since a watermark configuration is
53160Sstevel@tonic-gate  *		"self-defining", the act of traversing the watermarks
53170Sstevel@tonic-gate  *		is part of the validation process.
53180Sstevel@tonic-gate  */
53190Sstevel@tonic-gate static int
53200Sstevel@tonic-gate meta_sp_validate_wm(
53210Sstevel@tonic-gate 	mdsetname_t	*sp,
53220Sstevel@tonic-gate 	mdname_t	*compnp,
53230Sstevel@tonic-gate 	mdcmdopts_t	options,
53240Sstevel@tonic-gate 	md_error_t	*ep
53250Sstevel@tonic-gate )
53260Sstevel@tonic-gate {
53270Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
53280Sstevel@tonic-gate 	sp_ext_node_t	*ext;
53290Sstevel@tonic-gate 	int		num_sps = 0;
53300Sstevel@tonic-gate 	int		rval;
53310Sstevel@tonic-gate 
53320Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
53330Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
53340Sstevel@tonic-gate 		    "Verifying on-disk structures on %s.\n"),
53350Sstevel@tonic-gate 		    compnp->cname);
53360Sstevel@tonic-gate 
53370Sstevel@tonic-gate 	/*
53380Sstevel@tonic-gate 	 * for each watermark, build an ext_node, place on list.
53390Sstevel@tonic-gate 	 */
53400Sstevel@tonic-gate 	rval = meta_sp_extlist_from_wm(sp, compnp, &extlist,
53410Sstevel@tonic-gate 	    meta_sp_cmp_by_nameseq, ep);
53420Sstevel@tonic-gate 
53430Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0) {
53440Sstevel@tonic-gate 		/* print out what we found */
53450Sstevel@tonic-gate 		if (extlist == NULL)
53460Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
53470Sstevel@tonic-gate 			    "No extent headers found on %s.\n"),
53480Sstevel@tonic-gate 			    compnp->cname);
53490Sstevel@tonic-gate 		else {
53500Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
53510Sstevel@tonic-gate 			    "The following extent headers were found on %s.\n"),
53520Sstevel@tonic-gate 			    compnp->cname);
53530Sstevel@tonic-gate 			meta_sp_display_exthdr();
53540Sstevel@tonic-gate 		}
53550Sstevel@tonic-gate 		for (ext = extlist; ext != NULL; ext = ext->ext_next)
53560Sstevel@tonic-gate 			meta_sp_display_ext(ext);
53570Sstevel@tonic-gate 	}
53580Sstevel@tonic-gate 
53590Sstevel@tonic-gate 	if (rval < 0) {
53600Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
53610Sstevel@tonic-gate 		    "%s: On-disk structures invalid or "
53620Sstevel@tonic-gate 		    "no soft partitions found.\n"),
53630Sstevel@tonic-gate 		    compnp->cname);
53640Sstevel@tonic-gate 		return (-1);
53650Sstevel@tonic-gate 	}
53660Sstevel@tonic-gate 
53670Sstevel@tonic-gate 	assert(extlist != NULL);
53680Sstevel@tonic-gate 
53690Sstevel@tonic-gate 	/* count number of soft partitions */
53700Sstevel@tonic-gate 	for (ext = extlist;
53710Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
53720Sstevel@tonic-gate 	    ext = ext->ext_next) {
53730Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
53740Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
53750Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
53760Sstevel@tonic-gate 			ext->ext_namep->cname) == 0)
53770Sstevel@tonic-gate 				continue;
53780Sstevel@tonic-gate 		num_sps++;
53790Sstevel@tonic-gate 	}
53800Sstevel@tonic-gate 
53810Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
53820Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
53830Sstevel@tonic-gate 		    "Found %d soft partition(s) on %s.\n"), num_sps,
53840Sstevel@tonic-gate 		    compnp->cname);
53850Sstevel@tonic-gate 
53860Sstevel@tonic-gate 	if (num_sps == 0) {
53870Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
53880Sstevel@tonic-gate 		    "%s: No soft partitions.\n"), compnp->cname);
53890Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
53900Sstevel@tonic-gate 	}
53910Sstevel@tonic-gate 
53920Sstevel@tonic-gate 	/* check sequence numbers */
53930Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
53940Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
53950Sstevel@tonic-gate 		    "Checking sequence numbers.\n"));
53960Sstevel@tonic-gate 
53970Sstevel@tonic-gate 	if (meta_sp_checkseq(extlist) != 0)
53980Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
53990Sstevel@tonic-gate 
54000Sstevel@tonic-gate 	return (0);
54010Sstevel@tonic-gate }
54020Sstevel@tonic-gate 
54030Sstevel@tonic-gate /*
54040Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_unit()
54050Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
54060Sstevel@tonic-gate  *		compnp	- name of component we are recovering from
54070Sstevel@tonic-gate  *		options	- metarecover options
54080Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
54090Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
54100Sstevel@tonic-gate  * PURPOSE:	validate and display metadb configuration.  begin by getting
54110Sstevel@tonic-gate  *		all soft partitions built on the specified component.  get
54120Sstevel@tonic-gate  *		the unit structure for each one and validate the fields within.
54130Sstevel@tonic-gate  */
54140Sstevel@tonic-gate static int
54150Sstevel@tonic-gate meta_sp_validate_unit(
54160Sstevel@tonic-gate 	mdsetname_t	*sp,
54170Sstevel@tonic-gate 	mdname_t	*compnp,
54180Sstevel@tonic-gate 	mdcmdopts_t	options,
54190Sstevel@tonic-gate 	md_error_t	*ep
54200Sstevel@tonic-gate )
54210Sstevel@tonic-gate {
54220Sstevel@tonic-gate 	md_sp_t		*msp;
54230Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
54240Sstevel@tonic-gate 	mdnamelist_t	*namep = NULL;
54250Sstevel@tonic-gate 	int		count;
54260Sstevel@tonic-gate 	uint_t		extn;
54270Sstevel@tonic-gate 	sp_ext_length_t	size;
54280Sstevel@tonic-gate 
54290Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
54300Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54310Sstevel@tonic-gate 		    "%s: Validating soft partition metadb entries.\n"),
54320Sstevel@tonic-gate 		    compnp->cname);
54330Sstevel@tonic-gate 
54340Sstevel@tonic-gate 	if ((size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR)
54350Sstevel@tonic-gate 		return (-1);
54360Sstevel@tonic-gate 
54370Sstevel@tonic-gate 	/* get all soft partitions on component */
54380Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
54390Sstevel@tonic-gate 
54400Sstevel@tonic-gate 	if (count == 0) {
54410Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54420Sstevel@tonic-gate 		    "%s: No soft partitions.\n"), compnp->cname);
54430Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
54440Sstevel@tonic-gate 	} else if (count < 0) {
54450Sstevel@tonic-gate 		return (-1);
54460Sstevel@tonic-gate 	}
54470Sstevel@tonic-gate 
54480Sstevel@tonic-gate 	/* Now go through the soft partitions and check each one */
54490Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
54500Sstevel@tonic-gate 		mdname_t	*curnp = namep->namep;
54510Sstevel@tonic-gate 		sp_ext_offset_t	curvoff;
54520Sstevel@tonic-gate 
54530Sstevel@tonic-gate 		/* get the unit structure */
54540Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
54550Sstevel@tonic-gate 			return (-1);
54560Sstevel@tonic-gate 
54570Sstevel@tonic-gate 		/* verify generic unit structure parameters */
54580Sstevel@tonic-gate 		if ((options & MDCMD_VERBOSE) != 0)
54590Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
54600Sstevel@tonic-gate 			    "\nVerifying device %s.\n"),
54610Sstevel@tonic-gate 			    curnp->cname);
54620Sstevel@tonic-gate 
54630Sstevel@tonic-gate 		/*
54640Sstevel@tonic-gate 		 * MD_SP_LAST is an invalid state and is always the
54650Sstevel@tonic-gate 		 * highest numbered.
54660Sstevel@tonic-gate 		 */
54670Sstevel@tonic-gate 		if (msp->status >= MD_SP_LAST) {
54680Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
54690Sstevel@tonic-gate 			    "%s: status value %u is out of range.\n"),
54700Sstevel@tonic-gate 			    curnp->cname, msp->status);
54710Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
54720Sstevel@tonic-gate 			    0, curnp->cname));
54730Sstevel@tonic-gate 		} else if ((options & MDCMD_VERBOSE) != 0) {
54740Sstevel@tonic-gate 			uint_t	tstate = 0;
54750Sstevel@tonic-gate 
54760Sstevel@tonic-gate 			if (metaismeta(msp->compnamep)) {
54770Sstevel@tonic-gate 				if (meta_get_tstate(msp->common.namep->dev,
54780Sstevel@tonic-gate 				    &tstate, ep) != 0)
54790Sstevel@tonic-gate 					return (-1);
54800Sstevel@tonic-gate 			}
54810Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
54820Sstevel@tonic-gate 			    "%s: Status \"%s\" is valid.\n"),
54830Sstevel@tonic-gate 			    curnp->cname, meta_sp_status_to_name(msp->status,
54840Sstevel@tonic-gate 			    tstate & MD_DEV_ERRORED));
54850Sstevel@tonic-gate 		}
54860Sstevel@tonic-gate 
54870Sstevel@tonic-gate 		/* Now verify each extent */
54880Sstevel@tonic-gate 		if ((options & MDCMD_VERBOSE) != 0)
54890Sstevel@tonic-gate 			(void) printf("%14s %21s %21s %21s\n",
54900Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Extent Number"),
54910Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Virtual Offset"),
54920Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Physical Offset"),
54930Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"));
54940Sstevel@tonic-gate 
54950Sstevel@tonic-gate 		curvoff = 0ULL;
54960Sstevel@tonic-gate 		for (extn = 0; extn < msp->ext.ext_len; extn++) {
54970Sstevel@tonic-gate 			md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
54980Sstevel@tonic-gate 
54990Sstevel@tonic-gate 			if ((options & MDCMD_VERBOSE) != 0)
55000Sstevel@tonic-gate 				(void) printf("%14u %21llu %21llu %21llu\n",
55010Sstevel@tonic-gate 				    extn, extp->voff, extp->poff, extp->len);
55020Sstevel@tonic-gate 
55030Sstevel@tonic-gate 			if (extp->voff != curvoff) {
55040Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
55050Sstevel@tonic-gate 				    "%s: virtual offset for extent %u "
55060Sstevel@tonic-gate 				    "is inconsistent, expected %llu, "
55070Sstevel@tonic-gate 				    "got %llu.\n"), curnp->cname, extn,
55080Sstevel@tonic-gate 				    curvoff, extp->voff);
55090Sstevel@tonic-gate 				return (mdmderror(ep, MDE_RECOVER_FAILED,
55100Sstevel@tonic-gate 				    0, compnp->cname));
55110Sstevel@tonic-gate 			}
55120Sstevel@tonic-gate 
55130Sstevel@tonic-gate 			/* make sure extent does not drop off the end */
55140Sstevel@tonic-gate 			if ((extp->poff + extp->len) == size) {
55150Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
55160Sstevel@tonic-gate 				    "%s: extent %u at offset %llu, "
55170Sstevel@tonic-gate 				    "length %llu exceeds the size of the "
55180Sstevel@tonic-gate 				    "device, %llu.\n"), curnp->cname,
55190Sstevel@tonic-gate 				    extn, extp->poff, extp->len, size);
55200Sstevel@tonic-gate 				return (mdmderror(ep, MDE_RECOVER_FAILED,
55210Sstevel@tonic-gate 				    0, compnp->cname));
55220Sstevel@tonic-gate 			}
55230Sstevel@tonic-gate 
55240Sstevel@tonic-gate 			curvoff += extp->len;
55250Sstevel@tonic-gate 		}
55260Sstevel@tonic-gate 	}
55270Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
55280Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
55290Sstevel@tonic-gate 		    "%s: Soft Partition metadb configuration is valid\n"),
55300Sstevel@tonic-gate 		    compnp->cname);
55310Sstevel@tonic-gate 	}
55320Sstevel@tonic-gate 	return (0);
55330Sstevel@tonic-gate }
55340Sstevel@tonic-gate 
55350Sstevel@tonic-gate /*
55360Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_wm_and_unit()
55370Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
55380Sstevel@tonic-gate  *		compnp	- name of device we are recovering from
55390Sstevel@tonic-gate  *		options	- metarecover options
55400Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
55410Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 error
55420Sstevel@tonic-gate  * PURPOSE:	cross-validate and display watermarks and metadb records.
55430Sstevel@tonic-gate  *		get both the unit structures for the soft partitions built
55440Sstevel@tonic-gate  *		on the specified component and the watermarks found on that
55450Sstevel@tonic-gate  *		component and check to make sure they are consistent with
55460Sstevel@tonic-gate  *		each other.
55470Sstevel@tonic-gate  */
55480Sstevel@tonic-gate static int
55490Sstevel@tonic-gate meta_sp_validate_wm_and_unit(
55500Sstevel@tonic-gate 	mdsetname_t	*sp,
55510Sstevel@tonic-gate 	mdname_t	*np,
55520Sstevel@tonic-gate 	mdcmdopts_t	options,
55530Sstevel@tonic-gate 	md_error_t	*ep
55540Sstevel@tonic-gate )
55550Sstevel@tonic-gate {
55560Sstevel@tonic-gate 	sp_ext_node_t	*wmlist = NULL;
55570Sstevel@tonic-gate 	sp_ext_node_t	*unitlist = NULL;
55580Sstevel@tonic-gate 	sp_ext_node_t	*unitext;
55590Sstevel@tonic-gate 	sp_ext_node_t	*wmext;
55600Sstevel@tonic-gate 	sp_ext_offset_t	tmpunitoff;
55610Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
55620Sstevel@tonic-gate 	int		count;
55630Sstevel@tonic-gate 	int		rval = 0;
55640Sstevel@tonic-gate 	int		verbose = (options & MDCMD_VERBOSE);
55650Sstevel@tonic-gate 
55660Sstevel@tonic-gate 	/* get unit structure list */
55670Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, np, &spnlp, 0, ep);
55680Sstevel@tonic-gate 	if (count <= 0)
55690Sstevel@tonic-gate 		return (-1);
55700Sstevel@tonic-gate 
55710Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &unitlist,
55720Sstevel@tonic-gate 	    metagetsize(np, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
55730Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
55740Sstevel@tonic-gate 
55750Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &unitlist, ep) == -1) {
55760Sstevel@tonic-gate 		metafreenamelist(spnlp);
55770Sstevel@tonic-gate 		return (-1);
55780Sstevel@tonic-gate 	}
55790Sstevel@tonic-gate 
55800Sstevel@tonic-gate 	metafreenamelist(spnlp);
55810Sstevel@tonic-gate 
55820Sstevel@tonic-gate 	meta_sp_list_freefill(&unitlist, metagetsize(np, ep));
55830Sstevel@tonic-gate 
55840Sstevel@tonic-gate 	if (meta_sp_extlist_from_wm(sp, np, &wmlist,
55850Sstevel@tonic-gate 	    meta_sp_cmp_by_offset, ep) < 0) {
55860Sstevel@tonic-gate 		meta_sp_list_free(&unitlist);
55870Sstevel@tonic-gate 		return (-1);
55880Sstevel@tonic-gate 	}
55890Sstevel@tonic-gate 
55900Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
55910Sstevel@tonic-gate 		meta_sp_debug("meta_sp_validate_wm_and_unit: unit list:\n");
55920Sstevel@tonic-gate 		meta_sp_list_dump(unitlist);
55930Sstevel@tonic-gate 		meta_sp_debug("meta_sp_validate_wm_and_unit: wm list:\n");
55940Sstevel@tonic-gate 		meta_sp_list_dump(wmlist);
55950Sstevel@tonic-gate 	}
55960Sstevel@tonic-gate 
55970Sstevel@tonic-gate 	/*
55980Sstevel@tonic-gate 	 * step through both lists and compare allocated nodes.  Free
55990Sstevel@tonic-gate 	 * nodes and end watermarks may differ between the two but
56000Sstevel@tonic-gate 	 * that's generally ok, and if they're wrong will typically
56010Sstevel@tonic-gate 	 * cause misplaced allocated extents.
56020Sstevel@tonic-gate 	 */
56030Sstevel@tonic-gate 	if (verbose)
56040Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "\n%s: Verifying metadb "
56050Sstevel@tonic-gate 		    "allocations match extent headers.\n"), np->cname);
56060Sstevel@tonic-gate 
56070Sstevel@tonic-gate 	unitext = unitlist;
56080Sstevel@tonic-gate 	wmext = wmlist;
56090Sstevel@tonic-gate 	while ((wmext != NULL) && (unitext != NULL)) {
56100Sstevel@tonic-gate 		/* find next allocated extents in each list */
56110Sstevel@tonic-gate 		while (wmext != NULL && wmext->ext_type != EXTTYP_ALLOC)
56120Sstevel@tonic-gate 			wmext = wmext->ext_next;
56130Sstevel@tonic-gate 
56140Sstevel@tonic-gate 		while (unitext != NULL && unitext->ext_type != EXTTYP_ALLOC)
56150Sstevel@tonic-gate 			unitext = unitext->ext_next;
56160Sstevel@tonic-gate 
56170Sstevel@tonic-gate 		if (wmext == NULL || unitext == NULL)
56180Sstevel@tonic-gate 			break;
56190Sstevel@tonic-gate 
56200Sstevel@tonic-gate 		if (verbose) {
56210Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
56220Sstevel@tonic-gate 			    "Metadb extent:\n"));
56230Sstevel@tonic-gate 			meta_sp_display_exthdr();
56240Sstevel@tonic-gate 			meta_sp_display_ext(unitext);
56250Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
56260Sstevel@tonic-gate 			    "Extent header extent:\n"));
56270Sstevel@tonic-gate 			meta_sp_display_exthdr();
56280Sstevel@tonic-gate 			meta_sp_display_ext(wmext);
56290Sstevel@tonic-gate 			(void) printf("\n");
56300Sstevel@tonic-gate 		}
56310Sstevel@tonic-gate 
56320Sstevel@tonic-gate 		if (meta_sp_validate_exts(np, wmext, unitext, ep) < 0)
56330Sstevel@tonic-gate 			rval = -1;
56340Sstevel@tonic-gate 
56350Sstevel@tonic-gate 		/*
56360Sstevel@tonic-gate 		 * if the offsets aren't equal, only increment the
56370Sstevel@tonic-gate 		 * lowest one in hopes of getting the lists back in sync.
56380Sstevel@tonic-gate 		 */
56390Sstevel@tonic-gate 		tmpunitoff = unitext->ext_offset;
56400Sstevel@tonic-gate 		if (unitext->ext_offset <= wmext->ext_offset)
56410Sstevel@tonic-gate 			unitext = unitext->ext_next;
56420Sstevel@tonic-gate 		if (wmext->ext_offset <= tmpunitoff)
56430Sstevel@tonic-gate 			wmext = wmext->ext_next;
56440Sstevel@tonic-gate 	}
56450Sstevel@tonic-gate 
56460Sstevel@tonic-gate 	/*
56470Sstevel@tonic-gate 	 * if both lists aren't at the end then there are extra
56480Sstevel@tonic-gate 	 * allocated nodes in one of them.
56490Sstevel@tonic-gate 	 */
56500Sstevel@tonic-gate 	if (wmext != NULL) {
56510Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
56520Sstevel@tonic-gate 		    "%s: extent headers contain allocations not in "
56530Sstevel@tonic-gate 		    "the metadb\n\n"), np->cname);
56540Sstevel@tonic-gate 		rval = -1;
56550Sstevel@tonic-gate 	}
56560Sstevel@tonic-gate 
56570Sstevel@tonic-gate 	if (unitext != NULL) {
56580Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
56590Sstevel@tonic-gate 		    "%s: metadb contains allocations not in the extent "
56600Sstevel@tonic-gate 		    "headers\n\n"), np->cname);
56610Sstevel@tonic-gate 		rval = -1;
56620Sstevel@tonic-gate 	}
56630Sstevel@tonic-gate 
56640Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
56650Sstevel@tonic-gate 		if (rval == 0) {
56660Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
56670Sstevel@tonic-gate 			    "%s: Soft Partition metadb matches extent "
56680Sstevel@tonic-gate 			    "header configuration\n"), np->cname);
56690Sstevel@tonic-gate 		} else {
56700Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
56710Sstevel@tonic-gate 			    "%s: Soft Partition metadb does not match extent "
56720Sstevel@tonic-gate 			    "header configuration\n"), np->cname);
56730Sstevel@tonic-gate 		}
56740Sstevel@tonic-gate 	}
56750Sstevel@tonic-gate 
56760Sstevel@tonic-gate 	return (rval);
56770Sstevel@tonic-gate }
56780Sstevel@tonic-gate 
56790Sstevel@tonic-gate /*
56800Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_exts()
56810Sstevel@tonic-gate  * INPUT:	compnp	- name pointer for device we are recovering from
56820Sstevel@tonic-gate  *		wmext	- extent node representing watermark
56830Sstevel@tonic-gate  *		unitext	- extent node from unit structure
56840Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
56850Sstevel@tonic-gate  * RETURNS:	int	- 0 - succes, mdmderror return code - error
56860Sstevel@tonic-gate  * PURPOSE:	Takes two extent nodes and checks them against each other.
56870Sstevel@tonic-gate  *		offset, length, sequence number, set, and name are compared.
56880Sstevel@tonic-gate  */
56890Sstevel@tonic-gate static int
56900Sstevel@tonic-gate meta_sp_validate_exts(
56910Sstevel@tonic-gate 	mdname_t	*compnp,
56920Sstevel@tonic-gate 	sp_ext_node_t	*wmext,
56930Sstevel@tonic-gate 	sp_ext_node_t	*unitext,
56940Sstevel@tonic-gate 	md_error_t	*ep
56950Sstevel@tonic-gate )
56960Sstevel@tonic-gate {
56970Sstevel@tonic-gate 	if (wmext->ext_offset != unitext->ext_offset) {
56980Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
56990Sstevel@tonic-gate 		    "%s: unit structure and extent header offsets differ.\n"),
57000Sstevel@tonic-gate 		    compnp->cname);
57010Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57020Sstevel@tonic-gate 	}
57030Sstevel@tonic-gate 
57040Sstevel@tonic-gate 	if (wmext->ext_length != unitext->ext_length) {
57050Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57060Sstevel@tonic-gate 		    "%s: unit structure and extent header lengths differ.\n"),
57070Sstevel@tonic-gate 		    compnp->cname);
57080Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57090Sstevel@tonic-gate 	}
57100Sstevel@tonic-gate 
57110Sstevel@tonic-gate 	if (wmext->ext_seq != unitext->ext_seq) {
57120Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57130Sstevel@tonic-gate 		    "%s: unit structure and extent header sequence numbers "
57140Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
57150Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57160Sstevel@tonic-gate 	}
57170Sstevel@tonic-gate 
57180Sstevel@tonic-gate 	if (wmext->ext_type != unitext->ext_type) {
57190Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57200Sstevel@tonic-gate 		    "%s: unit structure and extent header types differ.\n"),
57210Sstevel@tonic-gate 		    compnp->cname);
57220Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57230Sstevel@tonic-gate 	}
57240Sstevel@tonic-gate 
57250Sstevel@tonic-gate 	/*
57260Sstevel@tonic-gate 	 * If one has a set pointer and the other doesn't, error.
57270Sstevel@tonic-gate 	 * If both extents have setnames, then make sure they match
57280Sstevel@tonic-gate 	 * If both are NULL, it's ok, they match.
57290Sstevel@tonic-gate 	 */
57300Sstevel@tonic-gate 	if ((unitext->ext_setp == NULL) ^ (wmext->ext_setp == NULL)) {
57310Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57320Sstevel@tonic-gate 		    "%s: unit structure and extent header set values "
57330Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
57340Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57350Sstevel@tonic-gate 	}
57360Sstevel@tonic-gate 
57370Sstevel@tonic-gate 	if (unitext->ext_setp != NULL) {
57380Sstevel@tonic-gate 		if (strcmp(unitext->ext_setp->setname,
57390Sstevel@tonic-gate 		    wmext->ext_setp->setname) != 0) {
57400Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57410Sstevel@tonic-gate 			    "%s: unit structure and extent header set names "
57420Sstevel@tonic-gate 			    "differ.\n"), compnp->cname);
57430Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
57440Sstevel@tonic-gate 			    0, compnp->cname));
57450Sstevel@tonic-gate 		}
57460Sstevel@tonic-gate 	}
57470Sstevel@tonic-gate 
57480Sstevel@tonic-gate 	/*
57490Sstevel@tonic-gate 	 * If one has a name pointer and the other doesn't, error.
57500Sstevel@tonic-gate 	 * If both extents have names, then make sure they match
57510Sstevel@tonic-gate 	 * If both are NULL, it's ok, they match.
57520Sstevel@tonic-gate 	 */
57530Sstevel@tonic-gate 	if ((unitext->ext_namep == NULL) ^ (wmext->ext_namep == NULL)) {
57540Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57550Sstevel@tonic-gate 		    "%s: unit structure and extent header name values "
57560Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
57570Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57580Sstevel@tonic-gate 	}
57590Sstevel@tonic-gate 
57600Sstevel@tonic-gate 	if (unitext->ext_namep != NULL) {
57610Sstevel@tonic-gate 		if (strcmp(wmext->ext_namep->cname,
57620Sstevel@tonic-gate 		    unitext->ext_namep->cname) != 0) {
57630Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57640Sstevel@tonic-gate 			    "%s: unit structure and extent header names "
57650Sstevel@tonic-gate 			    "differ.\n"), compnp->cname);
57660Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
57670Sstevel@tonic-gate 			    0, compnp->cname));
57680Sstevel@tonic-gate 		}
57690Sstevel@tonic-gate 	}
57700Sstevel@tonic-gate 
57710Sstevel@tonic-gate 	return (0);
57720Sstevel@tonic-gate }
57730Sstevel@tonic-gate 
57740Sstevel@tonic-gate /*
57750Sstevel@tonic-gate  * FUNCTION:	update_sp_status()
57760Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
57770Sstevel@tonic-gate  *		minors	- pointer to an array of soft partition minor numbers
57780Sstevel@tonic-gate  *		num_sps	- number of minor numbers in array
57790Sstevel@tonic-gate  *		status	- new status to be applied to all soft parts in array
57800Sstevel@tonic-gate  *		mn_set	- set if current set is a multi-node set
57810Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
57820Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
57830Sstevel@tonic-gate  * PURPOSE:	update  status of soft partitions to new status. minors is an
57840Sstevel@tonic-gate  *		array of minor numbers to apply the new status to.
57850Sstevel@tonic-gate  *		If mn_set is set, a message is sent to all nodes in the
57860Sstevel@tonic-gate  *		cluster to update the status locally.
57870Sstevel@tonic-gate  */
57880Sstevel@tonic-gate static int
57890Sstevel@tonic-gate update_sp_status(
57900Sstevel@tonic-gate 	mdsetname_t	*sp,
57910Sstevel@tonic-gate 	minor_t		*minors,
57920Sstevel@tonic-gate 	int		num_sps,
57930Sstevel@tonic-gate 	sp_status_t	status,
57940Sstevel@tonic-gate 	bool_t		mn_set,
57950Sstevel@tonic-gate 	md_error_t	*ep
57960Sstevel@tonic-gate )
57970Sstevel@tonic-gate {
57980Sstevel@tonic-gate 	int	i;
57990Sstevel@tonic-gate 	int	err = 0;
58000Sstevel@tonic-gate 
58010Sstevel@tonic-gate 	if (mn_set) {
58020Sstevel@tonic-gate 		md_mn_msg_sp_setstat_t	sp_setstat_params;
58030Sstevel@tonic-gate 		int			result;
58040Sstevel@tonic-gate 		md_mn_result_t		*resp = NULL;
58050Sstevel@tonic-gate 
58060Sstevel@tonic-gate 		for (i = 0; i < num_sps; i++) {
58070Sstevel@tonic-gate 			sp_setstat_params.sp_setstat_mnum = minors[i];
58080Sstevel@tonic-gate 			sp_setstat_params.sp_setstat_status = status;
58090Sstevel@tonic-gate 
58100Sstevel@tonic-gate 			result = mdmn_send_message(sp->setno,
58110Sstevel@tonic-gate 			    MD_MN_MSG_SP_SETSTAT, MD_MSGF_DEFAULT_FLAGS,
58120Sstevel@tonic-gate 			    (char *)&sp_setstat_params,
58130Sstevel@tonic-gate 			    sizeof (sp_setstat_params),
58140Sstevel@tonic-gate 			    &resp, ep);
58150Sstevel@tonic-gate 			if (resp != NULL) {
58160Sstevel@tonic-gate 				if (resp->mmr_exitval != 0)
58170Sstevel@tonic-gate 					err = -1;
58180Sstevel@tonic-gate 				free_result(resp);
58190Sstevel@tonic-gate 			}
58200Sstevel@tonic-gate 			if (result != 0) {
58210Sstevel@tonic-gate 				err = -1;
58220Sstevel@tonic-gate 			}
58230Sstevel@tonic-gate 		}
58240Sstevel@tonic-gate 	} else {
58250Sstevel@tonic-gate 		if (meta_sp_setstatus(sp, minors, num_sps, status, ep) < 0)
58260Sstevel@tonic-gate 			err = -1;
58270Sstevel@tonic-gate 	}
58280Sstevel@tonic-gate 	if (err < 0) {
58290Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
58300Sstevel@tonic-gate 		    "Error updating status on recovered soft "
58310Sstevel@tonic-gate 		    "partitions.\n"));
58320Sstevel@tonic-gate 	}
58330Sstevel@tonic-gate 	return (err);
58340Sstevel@tonic-gate }
58350Sstevel@tonic-gate 
58360Sstevel@tonic-gate /*
58370Sstevel@tonic-gate  * FUNCTION:	meta_sp_recover_from_wm()
58380Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
58390Sstevel@tonic-gate  *		compnp	- name pointer for component we are recovering from
58400Sstevel@tonic-gate  *		options	- metarecover options
58410Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
58420Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
58430Sstevel@tonic-gate  * PURPOSE:	update metadb records to match watermarks.  begin by getting
58440Sstevel@tonic-gate  *		an extlist representing all soft partitions on the component.
58450Sstevel@tonic-gate  *		then build a unit structure for each soft partition.
58460Sstevel@tonic-gate  *		notify user of changes, then commit each soft partition to
58470Sstevel@tonic-gate  *		the metadb one at a time in the "recovering" state.  update
58480Sstevel@tonic-gate  *		any watermarks that may need it	(to reflect possible name
58490Sstevel@tonic-gate  *		changes), and, finally, set the status of all recovered
58500Sstevel@tonic-gate  *		partitions to the "OK" state at once.
58510Sstevel@tonic-gate  */
58520Sstevel@tonic-gate static int
58530Sstevel@tonic-gate meta_sp_recover_from_wm(
58540Sstevel@tonic-gate 	mdsetname_t	*sp,
58550Sstevel@tonic-gate 	mdname_t	*compnp,
58560Sstevel@tonic-gate 	mdcmdopts_t	options,
58570Sstevel@tonic-gate 	md_error_t	*ep
58580Sstevel@tonic-gate )
58590Sstevel@tonic-gate {
58600Sstevel@tonic-gate 	sp_ext_node_t		*extlist = NULL;
58610Sstevel@tonic-gate 	sp_ext_node_t		*sp_list = NULL;
58620Sstevel@tonic-gate 	sp_ext_node_t		*update_list = NULL;
58630Sstevel@tonic-gate 	sp_ext_node_t		*ext;
58640Sstevel@tonic-gate 	sp_ext_node_t		*sp_ext;
58650Sstevel@tonic-gate 	mp_unit_t		*mp;
58660Sstevel@tonic-gate 	mp_unit_t		**un_array;
58670Sstevel@tonic-gate 	int			numexts = 0, num_sps = 0, i = 0;
58680Sstevel@tonic-gate 	int			err = 0;
58690Sstevel@tonic-gate 	int			not_recovered = 0;
58700Sstevel@tonic-gate 	int			committed = 0;
58710Sstevel@tonic-gate 	sp_ext_length_t		sp_length = 0LL;
58720Sstevel@tonic-gate 	mdnamelist_t		*keynlp = NULL;
58730Sstevel@tonic-gate 	mdname_t		*np;
58740Sstevel@tonic-gate 	mdname_t		*new_np;
58750Sstevel@tonic-gate 	int			new_name;
58760Sstevel@tonic-gate 	md_set_params_t		set_params;
58770Sstevel@tonic-gate 	minor_t			*minors = NULL;
58780Sstevel@tonic-gate 	char			yesno[255];
58790Sstevel@tonic-gate 	char			*yes;
58800Sstevel@tonic-gate 	bool_t			mn_set = 0;
58810Sstevel@tonic-gate 	md_set_desc		*sd;
58820Sstevel@tonic-gate 	mm_unit_t		*mm;
58830Sstevel@tonic-gate 	md_set_mmown_params_t	*ownpar = NULL;
58840Sstevel@tonic-gate 	int			comp_is_mirror = 0;
58850Sstevel@tonic-gate 
58860Sstevel@tonic-gate 	/*
58870Sstevel@tonic-gate 	 * if this component appears in another metadevice already, do
58880Sstevel@tonic-gate 	 * NOT recover from it.
58890Sstevel@tonic-gate 	 */
58900Sstevel@tonic-gate 	if (meta_check_inmeta(sp, compnp, options, 0, -1, ep) != 0)
58910Sstevel@tonic-gate 		return (-1);
58920Sstevel@tonic-gate 
58930Sstevel@tonic-gate 	/* set flag if dealing with a MN set */
58940Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
58950Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
58960Sstevel@tonic-gate 			return (-1);
58970Sstevel@tonic-gate 		}
58980Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
58990Sstevel@tonic-gate 			mn_set = 1;
59000Sstevel@tonic-gate 	}
59010Sstevel@tonic-gate 	/*
59020Sstevel@tonic-gate 	 * for each watermark, build an ext_node, place on list.
59030Sstevel@tonic-gate 	 */
59040Sstevel@tonic-gate 	if (meta_sp_extlist_from_wm(sp, compnp, &extlist,
59050Sstevel@tonic-gate 	    meta_sp_cmp_by_nameseq, ep) < 0)
59060Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
59070Sstevel@tonic-gate 
59080Sstevel@tonic-gate 	assert(extlist != NULL);
59090Sstevel@tonic-gate 
59100Sstevel@tonic-gate 	/* count number of soft partitions */
59110Sstevel@tonic-gate 	for (ext = extlist;
59120Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
59130Sstevel@tonic-gate 	    ext = ext->ext_next) {
59140Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
59150Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
59160Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
59170Sstevel@tonic-gate 			ext->ext_namep->cname) == 0)
59180Sstevel@tonic-gate 				continue;
59190Sstevel@tonic-gate 		num_sps++;
59200Sstevel@tonic-gate 	}
59210Sstevel@tonic-gate 
59220Sstevel@tonic-gate 	/* allocate array of unit structure pointers */
59230Sstevel@tonic-gate 	un_array = Zalloc(num_sps * sizeof (mp_unit_t *));
59240Sstevel@tonic-gate 
59250Sstevel@tonic-gate 	/*
59260Sstevel@tonic-gate 	 * build unit structures from list of ext_nodes.
59270Sstevel@tonic-gate 	 */
59280Sstevel@tonic-gate 	for (ext = extlist;
59290Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
59300Sstevel@tonic-gate 	    ext = ext->ext_next) {
59310Sstevel@tonic-gate 		meta_sp_list_insert(ext->ext_setp, ext->ext_namep,
59320Sstevel@tonic-gate 		    &sp_list, ext->ext_offset, ext->ext_length,
59330Sstevel@tonic-gate 		    ext->ext_type, ext->ext_seq, ext->ext_flags,
59340Sstevel@tonic-gate 		    meta_sp_cmp_by_nameseq);
59350Sstevel@tonic-gate 
59360Sstevel@tonic-gate 		numexts++;
59370Sstevel@tonic-gate 		sp_length += ext->ext_length - MD_SP_WMSIZE;
59380Sstevel@tonic-gate 
59390Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
59400Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
59410Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
59420Sstevel@tonic-gate 			ext->ext_namep->cname) == 0)
59430Sstevel@tonic-gate 				continue;
59440Sstevel@tonic-gate 
59450Sstevel@tonic-gate 		/*
59460Sstevel@tonic-gate 		 * if we made it here, we are at a soft partition
59470Sstevel@tonic-gate 		 * boundary in the list.
59480Sstevel@tonic-gate 		 */
59490Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
59500Sstevel@tonic-gate 			meta_sp_debug("meta_recover_from_wm: dumping wm "
59510Sstevel@tonic-gate 			    "list:\n");
59520Sstevel@tonic-gate 			meta_sp_list_dump(sp_list);
59530Sstevel@tonic-gate 		}
59540Sstevel@tonic-gate 
59550Sstevel@tonic-gate 		assert(sp_list != NULL);
59560Sstevel@tonic-gate 		assert(sp_list->ext_namep != NULL);
59570Sstevel@tonic-gate 
59580Sstevel@tonic-gate 		if ((new_name = meta_sp_resolve_name_conflict(sp,
59590Sstevel@tonic-gate 		    sp_list->ext_namep, &new_np, ep)) < 0) {
59600Sstevel@tonic-gate 			err = 1;
59610Sstevel@tonic-gate 			goto out;
59620Sstevel@tonic-gate 		} else if (new_name) {
59630Sstevel@tonic-gate 			for (sp_ext = sp_list;
59640Sstevel@tonic-gate 			    sp_ext != NULL;
59650Sstevel@tonic-gate 			    sp_ext = sp_ext->ext_next) {
59660Sstevel@tonic-gate 				/*
59670Sstevel@tonic-gate 				 * insert into the update list for
59680Sstevel@tonic-gate 				 * watermark update.
59690Sstevel@tonic-gate 				 */
59700Sstevel@tonic-gate 				meta_sp_list_insert(sp_ext->ext_setp,
59710Sstevel@tonic-gate 				    new_np, &update_list, sp_ext->ext_offset,
59720Sstevel@tonic-gate 				    sp_ext->ext_length, sp_ext->ext_type,
59730Sstevel@tonic-gate 				    sp_ext->ext_seq, EXTFLG_UPDATE,
59740Sstevel@tonic-gate 				    meta_sp_cmp_by_offset);
59750Sstevel@tonic-gate 			}
59760Sstevel@tonic-gate 
59770Sstevel@tonic-gate 		}
59780Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
59790Sstevel@tonic-gate 			/* store name in namespace */
59800Sstevel@tonic-gate 			if (mn_set) {
59810Sstevel@tonic-gate 				/* send message to all nodes to return key */
59820Sstevel@tonic-gate 				md_mn_msg_addkeyname_t	*send_params;
59830Sstevel@tonic-gate 				int			result;
59840Sstevel@tonic-gate 				md_mn_result_t		*resp = NULL;
59850Sstevel@tonic-gate 				int			message_size;
59860Sstevel@tonic-gate 
59870Sstevel@tonic-gate 				message_size =  sizeof (*send_params) +
59880Sstevel@tonic-gate 				    strlen(compnp->cname) + 1;
59890Sstevel@tonic-gate 				send_params = Zalloc(message_size);
59900Sstevel@tonic-gate 				send_params->addkeyname_setno = sp->setno;
59910Sstevel@tonic-gate 				(void) strcpy(&send_params->addkeyname_name[0],
59920Sstevel@tonic-gate 				    compnp->cname);
59930Sstevel@tonic-gate 				result = mdmn_send_message(sp->setno,
59940Sstevel@tonic-gate 				    MD_MN_MSG_ADDKEYNAME, MD_MSGF_DEFAULT_FLAGS,
59950Sstevel@tonic-gate 				    (char *)send_params, message_size, &resp,
59960Sstevel@tonic-gate 				    ep);
59970Sstevel@tonic-gate 				Free(send_params);
59980Sstevel@tonic-gate 				if (resp != NULL) {
59990Sstevel@tonic-gate 					if (resp->mmr_exitval >= 0) {
60000Sstevel@tonic-gate 						compnp->key =
60010Sstevel@tonic-gate 						    (mdkey_t)resp->mmr_exitval;
60020Sstevel@tonic-gate 					} else {
60030Sstevel@tonic-gate 						err = 1;
60040Sstevel@tonic-gate 						free_result(resp);
60050Sstevel@tonic-gate 						goto out;
60060Sstevel@tonic-gate 					}
60070Sstevel@tonic-gate 					free_result(resp);
60080Sstevel@tonic-gate 				}
60090Sstevel@tonic-gate 				if (result != 0) {
60100Sstevel@tonic-gate 					err = 1;
60110Sstevel@tonic-gate 					goto out;
60120Sstevel@tonic-gate 				}
60130Sstevel@tonic-gate 				(void) metanamelist_append(&keynlp, compnp);
60140Sstevel@tonic-gate 			} else {
60150Sstevel@tonic-gate 				if (add_key_name(sp, compnp, &keynlp,
60160Sstevel@tonic-gate 				    ep) != 0) {
60170Sstevel@tonic-gate 					err = 1;
60180Sstevel@tonic-gate 					goto out;
60190Sstevel@tonic-gate 				}
60200Sstevel@tonic-gate 			}
60210Sstevel@tonic-gate 		}
60220Sstevel@tonic-gate 
60230Sstevel@tonic-gate 		/* create the unit structure */
60240Sstevel@tonic-gate 		if ((mp = meta_sp_createunit(
60250Sstevel@tonic-gate 		    (new_name) ? new_np : sp_list->ext_namep, compnp,
60260Sstevel@tonic-gate 		    sp_list, numexts, sp_length, MD_SP_RECOVER, ep)) == NULL) {
60270Sstevel@tonic-gate 			err = 1;
60280Sstevel@tonic-gate 			goto out;
60290Sstevel@tonic-gate 		}
60300Sstevel@tonic-gate 
60310Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
60320Sstevel@tonic-gate 			meta_sp_debug("meta_sp_recover_from_wm: "
60330Sstevel@tonic-gate 			    "printing newly created unit structure");
60340Sstevel@tonic-gate 			meta_sp_printunit(mp);
60350Sstevel@tonic-gate 		}
60360Sstevel@tonic-gate 
60370Sstevel@tonic-gate 		/* place in unit structure array */
60380Sstevel@tonic-gate 		un_array[i++] = mp;
60390Sstevel@tonic-gate 
60400Sstevel@tonic-gate 		/* free sp_list */
60410Sstevel@tonic-gate 		meta_sp_list_free(&sp_list);
60420Sstevel@tonic-gate 		sp_list = NULL;
60430Sstevel@tonic-gate 		numexts = 0;
60440Sstevel@tonic-gate 		sp_length = 0LL;
60450Sstevel@tonic-gate 	}
60460Sstevel@tonic-gate 
60470Sstevel@tonic-gate 	/* display configuration updates */
60480Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
60490Sstevel@tonic-gate 	    "The following soft partitions were found and will be added to\n"
60500Sstevel@tonic-gate 	    "your metadevice configuration.\n"));
60510Sstevel@tonic-gate 	(void) printf("%5s %15s %18s\n",
60520Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Name"),
60530Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Size"),
60540Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "No. of Extents"));
60550Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++) {
60560Sstevel@tonic-gate 		(void) printf("%5s%lu %15llu %9d\n", "d",
60570Sstevel@tonic-gate 		    MD_MIN2UNIT(MD_SID(un_array[i])),
60580Sstevel@tonic-gate 		    un_array[i]->un_length, un_array[i]->un_numexts);
60590Sstevel@tonic-gate 	}
60600Sstevel@tonic-gate 
60610Sstevel@tonic-gate 	if (!(options & MDCMD_DOIT)) {
60620Sstevel@tonic-gate 		not_recovered = 1;
60630Sstevel@tonic-gate 		goto out;
60640Sstevel@tonic-gate 	}
60650Sstevel@tonic-gate 
60660Sstevel@tonic-gate 	/* ask user for confirmation */
60670Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
60680Sstevel@tonic-gate 	    "WARNING: You are about to add one or more soft partition\n"
60690Sstevel@tonic-gate 	    "metadevices to your metadevice configuration.  If there\n"
60700Sstevel@tonic-gate 	    "appears to be an error in the soft partition(s) displayed\n"
60710Sstevel@tonic-gate 	    "above, do NOT proceed with this recovery operation.\n"));
60720Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
60730Sstevel@tonic-gate 	    "Are you sure you want to do this (yes/no)? "));
60740Sstevel@tonic-gate 
60750Sstevel@tonic-gate 	(void) fflush(stdout);
60760Sstevel@tonic-gate 	if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
60770Sstevel@tonic-gate 	    (strlen(yesno) == 1))
60780Sstevel@tonic-gate 		(void) snprintf(yesno, sizeof (yesno), "%s\n",
60790Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "no"));
60800Sstevel@tonic-gate 	yes = dgettext(TEXT_DOMAIN, "yes");
60810Sstevel@tonic-gate 	if (strncasecmp(yesno, yes, strlen(yesno) - 1) != 0) {
60820Sstevel@tonic-gate 		not_recovered = 1;
60830Sstevel@tonic-gate 		goto out;
60840Sstevel@tonic-gate 	}
60850Sstevel@tonic-gate 
60860Sstevel@tonic-gate 	/* commit records one at a time */
60870Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++) {
60880Sstevel@tonic-gate 		(void) memset(&set_params, 0, sizeof (set_params));
60890Sstevel@tonic-gate 		set_params.mnum = MD_SID(un_array[i]);
60900Sstevel@tonic-gate 		set_params.size = (un_array[i])->c.un_size;
60910Sstevel@tonic-gate 		set_params.mdp = (uintptr_t)(un_array[i]);
60920Sstevel@tonic-gate 		set_params.options =
60930Sstevel@tonic-gate 				meta_check_devicesize(un_array[i]->un_length);
60940Sstevel@tonic-gate 		if (set_params.options == MD_CRO_64BIT) {
60950Sstevel@tonic-gate 			un_array[i]->c.un_revision = MD_64BIT_META_DEV;
60960Sstevel@tonic-gate 		} else {
60970Sstevel@tonic-gate 			un_array[i]->c.un_revision = MD_32BIT_META_DEV;
60980Sstevel@tonic-gate 		}
60990Sstevel@tonic-gate 		MD_SETDRIVERNAME(&set_params, MD_SP,
61000Sstevel@tonic-gate 		    MD_MIN2SET(set_params.mnum));
61010Sstevel@tonic-gate 
61020Sstevel@tonic-gate 		np = metamnumname(&sp, MD_SID(un_array[i]), 0, ep);
61030Sstevel@tonic-gate 
61040Sstevel@tonic-gate 		/*
61050Sstevel@tonic-gate 		 * If this is an MN set, send the MD_IOCSET ioctl to all nodes
61060Sstevel@tonic-gate 		 */
61070Sstevel@tonic-gate 		if (mn_set) {
61080Sstevel@tonic-gate 			md_mn_msg_iocset_t	send_params;
61090Sstevel@tonic-gate 			int			result;
61100Sstevel@tonic-gate 			md_mn_result_t		*resp = NULL;
61110Sstevel@tonic-gate 			int			mess_size;
61120Sstevel@tonic-gate 
61130Sstevel@tonic-gate 			/*
61140Sstevel@tonic-gate 			 * Calculate message size. md_mn_msg_iocset_t only
61150Sstevel@tonic-gate 			 * contains one extent, so increment the size to
61160Sstevel@tonic-gate 			 * include all extents
61170Sstevel@tonic-gate 			 */
61180Sstevel@tonic-gate 			mess_size = sizeof (send_params) -
61190Sstevel@tonic-gate 			    sizeof (mp_ext_t) +
61200Sstevel@tonic-gate 			    (un_array[i]->un_numexts * sizeof (mp_ext_t));
61210Sstevel@tonic-gate 
61220Sstevel@tonic-gate 			send_params.iocset_params = set_params;
61230Sstevel@tonic-gate 			(void) memcpy(&send_params.unit, un_array[i],
61240Sstevel@tonic-gate 			    sizeof (*un_array[i]) - sizeof (mp_ext_t) +
61250Sstevel@tonic-gate 			    (un_array[i]->un_numexts * sizeof (mp_ext_t)));
61260Sstevel@tonic-gate 			result = mdmn_send_message(sp->setno,
61270Sstevel@tonic-gate 			    MD_MN_MSG_IOCSET, MD_MSGF_DEFAULT_FLAGS,
61280Sstevel@tonic-gate 			    (char *)&send_params, mess_size, &resp,
61290Sstevel@tonic-gate 			    ep);
61300Sstevel@tonic-gate 			if (resp != NULL) {
61310Sstevel@tonic-gate 				if (resp->mmr_exitval != 0)
61320Sstevel@tonic-gate 					err = 1;
61330Sstevel@tonic-gate 				free_result(resp);
61340Sstevel@tonic-gate 			}
61350Sstevel@tonic-gate 			if (result != 0) {
61360Sstevel@tonic-gate 				err = 1;
61370Sstevel@tonic-gate 			}
61380Sstevel@tonic-gate 		} else {
61390Sstevel@tonic-gate 			if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
61400Sstevel@tonic-gate 			    np->cname) != 0) {
61410Sstevel@tonic-gate 				err = 1;
61420Sstevel@tonic-gate 			}
61430Sstevel@tonic-gate 		}
61440Sstevel@tonic-gate 
61450Sstevel@tonic-gate 		if (err == 1) {
61460Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
61470Sstevel@tonic-gate 			    "%s: Error committing record to metadb.\n"),
61480Sstevel@tonic-gate 			    np->cname);
61490Sstevel@tonic-gate 			goto out;
61500Sstevel@tonic-gate 		}
61510Sstevel@tonic-gate 
61520Sstevel@tonic-gate 		/* note that we've committed a record */
61530Sstevel@tonic-gate 		if (!committed)
61540Sstevel@tonic-gate 			committed = 1;
61550Sstevel@tonic-gate 
61560Sstevel@tonic-gate 		/* update any watermarks that need it */
61570Sstevel@tonic-gate 		if (update_list != NULL) {
61580Sstevel@tonic-gate 			md_sp_t *msp;
61590Sstevel@tonic-gate 
61600Sstevel@tonic-gate 			/*
61610Sstevel@tonic-gate 			 * Check to see if we're trying to create a partition
61620Sstevel@tonic-gate 			 * on a mirror. If so we may have to enforce an
61630Sstevel@tonic-gate 			 * ownership change before writing the watermark out.
61640Sstevel@tonic-gate 			 */
61650Sstevel@tonic-gate 			if (metaismeta(compnp)) {
61660Sstevel@tonic-gate 				char *miscname;
61670Sstevel@tonic-gate 
61680Sstevel@tonic-gate 				miscname = metagetmiscname(compnp, ep);
61690Sstevel@tonic-gate 				if (miscname != NULL)
61700Sstevel@tonic-gate 					comp_is_mirror = (strcmp(miscname,
61710Sstevel@tonic-gate 					    MD_MIRROR) == 0);
61720Sstevel@tonic-gate 				else
61730Sstevel@tonic-gate 					comp_is_mirror = 0;
61740Sstevel@tonic-gate 			}
61750Sstevel@tonic-gate 			/*
61760Sstevel@tonic-gate 			 * If this is a MN set and the component is a mirror,
61770Sstevel@tonic-gate 			 * change ownership to this node in order to write the
61780Sstevel@tonic-gate 			 * watermarks
61790Sstevel@tonic-gate 			 */
61800Sstevel@tonic-gate 			if (mn_set && comp_is_mirror) {
61810Sstevel@tonic-gate 				mm = (mm_unit_t *)meta_get_unit(sp, compnp, ep);
61820Sstevel@tonic-gate 				if (mm == NULL) {
61830Sstevel@tonic-gate 					err = 1;
61840Sstevel@tonic-gate 					goto out;
61850Sstevel@tonic-gate 				} else {
61860Sstevel@tonic-gate 					err = meta_mn_change_owner(&ownpar,
61870Sstevel@tonic-gate 						sp->setno,
61880Sstevel@tonic-gate 						meta_getminor(compnp->dev),
61890Sstevel@tonic-gate 						sd->sd_mn_mynode->nd_nodeid,
61900Sstevel@tonic-gate 						MD_MN_MM_PREVENT_CHANGE |
61910Sstevel@tonic-gate 						    MD_MN_MM_SPAWN_THREAD);
61920Sstevel@tonic-gate 					if (err != 0)
61930Sstevel@tonic-gate 						goto out;
61940Sstevel@tonic-gate 				}
61950Sstevel@tonic-gate 			}
61960Sstevel@tonic-gate 
61970Sstevel@tonic-gate 			if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
61980Sstevel@tonic-gate 				err = 1;
61990Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
62000Sstevel@tonic-gate 				    "%s: Error updating extent headers.\n"),
62010Sstevel@tonic-gate 				    np->cname);
62020Sstevel@tonic-gate 				goto out;
62030Sstevel@tonic-gate 			}
62040Sstevel@tonic-gate 			if (meta_sp_update_wm(sp, msp, update_list, ep) < 0) {
62050Sstevel@tonic-gate 				err = 1;
62060Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
62070Sstevel@tonic-gate 				    "%s: Error updating extent headers "
62080Sstevel@tonic-gate 				    "on disk.\n"), np->cname);
62090Sstevel@tonic-gate 				goto out;
62100Sstevel@tonic-gate 			}
62110Sstevel@tonic-gate 		}
62120Sstevel@tonic-gate 		/*
62130Sstevel@tonic-gate 		 * If we have changed ownership earlier and prevented any
62140Sstevel@tonic-gate 		 * ownership changes, we can now allow ownership changes
62150Sstevel@tonic-gate 		 * again.
62160Sstevel@tonic-gate 		 */
62170Sstevel@tonic-gate 		if (ownpar) {
62180Sstevel@tonic-gate 			(void) meta_mn_change_owner(&ownpar, sp->setno,
62190Sstevel@tonic-gate 			    ownpar->d.mnum,
62200Sstevel@tonic-gate 			    ownpar->d.owner,
62210Sstevel@tonic-gate 			    MD_MN_MM_ALLOW_CHANGE | MD_MN_MM_SPAWN_THREAD);
62220Sstevel@tonic-gate 		}
62230Sstevel@tonic-gate 	}
62240Sstevel@tonic-gate 
62250Sstevel@tonic-gate 	/* update status of all soft partitions to OK */
62260Sstevel@tonic-gate 	minors = Zalloc(num_sps * sizeof (minor_t));
62270Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++)
62280Sstevel@tonic-gate 		minors[i] = MD_SID(un_array[i]);
62290Sstevel@tonic-gate 
62300Sstevel@tonic-gate 	err = update_sp_status(sp, minors, num_sps, MD_SP_OK, mn_set, ep);
62310Sstevel@tonic-gate 	if (err != 0)
62320Sstevel@tonic-gate 		goto out;
62330Sstevel@tonic-gate 
62340Sstevel@tonic-gate 	if (options & MDCMD_PRINT)
62350Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: "
62360Sstevel@tonic-gate 		    "Soft Partitions recovered from device.\n"),
62370Sstevel@tonic-gate 		    compnp->cname);
62380Sstevel@tonic-gate out:
62390Sstevel@tonic-gate 	/* free memory */
62400Sstevel@tonic-gate 	if (extlist != NULL)
62410Sstevel@tonic-gate 		meta_sp_list_free(&extlist);
62420Sstevel@tonic-gate 	if (sp_list != NULL)
62430Sstevel@tonic-gate 		meta_sp_list_free(&sp_list);
62440Sstevel@tonic-gate 	if (update_list != NULL)
62450Sstevel@tonic-gate 		meta_sp_list_free(&update_list);
62460Sstevel@tonic-gate 	if (un_array != NULL)	{
62470Sstevel@tonic-gate 		for (i = 0; i < num_sps; i++)
62480Sstevel@tonic-gate 			Free(un_array[i]);
62490Sstevel@tonic-gate 		Free(un_array);
62500Sstevel@tonic-gate 	}
62510Sstevel@tonic-gate 	if (minors != NULL)
62520Sstevel@tonic-gate 		Free(minors);
62530Sstevel@tonic-gate 	if (ownpar != NULL)
62540Sstevel@tonic-gate 		Free(ownpar);
62550Sstevel@tonic-gate 	(void) fflush(stdout);
62560Sstevel@tonic-gate 
62570Sstevel@tonic-gate 	if ((keynlp != NULL) && (committed != 1)) {
62580Sstevel@tonic-gate 		/*
62590Sstevel@tonic-gate 		 * if we haven't committed any softparts, either because of an
62600Sstevel@tonic-gate 		 * error or because the user decided not to proceed, delete
62610Sstevel@tonic-gate 		 * namelist key for the component
62620Sstevel@tonic-gate 		 */
62630Sstevel@tonic-gate 		if (mn_set) {
62640Sstevel@tonic-gate 			mdnamelist_t	*p;
62650Sstevel@tonic-gate 
62660Sstevel@tonic-gate 			for (p = keynlp; (p != NULL); p = p->next) {
62670Sstevel@tonic-gate 				mdname_t		*np = p->namep;
62680Sstevel@tonic-gate 				md_mn_msg_delkeyname_t	send_params;
62690Sstevel@tonic-gate 				md_mn_result_t		*resp = NULL;
62700Sstevel@tonic-gate 
62710Sstevel@tonic-gate 				send_params.delkeyname_dev = np->dev;
62720Sstevel@tonic-gate 				send_params.delkeyname_setno = sp->setno;
62730Sstevel@tonic-gate 				send_params.delkeyname_key = np->key;
62740Sstevel@tonic-gate 				(void) mdmn_send_message(sp->setno,
62750Sstevel@tonic-gate 				    MD_MN_MSG_DELKEYNAME, MD_MSGF_DEFAULT_FLAGS,
62760Sstevel@tonic-gate 				    (char *)&send_params, sizeof (send_params),
62770Sstevel@tonic-gate 				    &resp, ep);
62780Sstevel@tonic-gate 				if (resp != NULL) {
62790Sstevel@tonic-gate 					free_result(resp);
62800Sstevel@tonic-gate 				}
62810Sstevel@tonic-gate 			}
62820Sstevel@tonic-gate 		} else {
62830Sstevel@tonic-gate 			(void) del_key_names(sp, keynlp, NULL);
62840Sstevel@tonic-gate 		}
62850Sstevel@tonic-gate 	}
62860Sstevel@tonic-gate 
62870Sstevel@tonic-gate 	metafreenamelist(keynlp);
62880Sstevel@tonic-gate 
62890Sstevel@tonic-gate 	if (err)
62900Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
62910Sstevel@tonic-gate 
62920Sstevel@tonic-gate 	if (not_recovered)
62930Sstevel@tonic-gate 		if (options & MDCMD_PRINT)
62940Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN, "%s: "
62950Sstevel@tonic-gate 			    "Soft Partitions NOT recovered from device.\n"),
62960Sstevel@tonic-gate 			    compnp->cname);
62970Sstevel@tonic-gate 	return (0);
62980Sstevel@tonic-gate }
62990Sstevel@tonic-gate 
63000Sstevel@tonic-gate /*
63010Sstevel@tonic-gate  * FUNCTION:	meta_sp_recover_from_unit()
63020Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
63030Sstevel@tonic-gate  *		compnp	- name of component we are recovering from
63040Sstevel@tonic-gate  *		options	- metarecover options
63050Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
63060Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
63070Sstevel@tonic-gate  * PURPOSE:	update watermarks to match metadb records.  begin by getting
63080Sstevel@tonic-gate  *		a namelist representing all soft partitions on the specified
63090Sstevel@tonic-gate  *		component.  then, build an extlist representing the soft
63100Sstevel@tonic-gate  *		partitions, filling in the freespace extents.  notify user
63110Sstevel@tonic-gate  *		of changes, place all soft partitions into the "recovering"
63120Sstevel@tonic-gate  *		state and update the watermarks.  finally, return all soft
63130Sstevel@tonic-gate  *		partitions to the "OK" state.
63140Sstevel@tonic-gate  */
63150Sstevel@tonic-gate static int
63160Sstevel@tonic-gate meta_sp_recover_from_unit(
63170Sstevel@tonic-gate 	mdsetname_t	*sp,
63180Sstevel@tonic-gate 	mdname_t	*compnp,
63190Sstevel@tonic-gate 	mdcmdopts_t	options,
63200Sstevel@tonic-gate 	md_error_t	*ep
63210Sstevel@tonic-gate )
63220Sstevel@tonic-gate {
63230Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
63240Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
63250Sstevel@tonic-gate 	sp_ext_node_t	*ext = NULL;
63260Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
63270Sstevel@tonic-gate 	int		count;
63280Sstevel@tonic-gate 	char		yesno[255];
63290Sstevel@tonic-gate 	char		*yes;
63300Sstevel@tonic-gate 	int		rval = 0;
63310Sstevel@tonic-gate 	minor_t		*minors = NULL;
63320Sstevel@tonic-gate 	int		i;
63330Sstevel@tonic-gate 	md_sp_t		*msp;
63340Sstevel@tonic-gate 	md_set_desc	*sd;
63350Sstevel@tonic-gate 	bool_t		mn_set = 0;
63360Sstevel@tonic-gate 	daddr_t		start_block;
63370Sstevel@tonic-gate 
63380Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
63390Sstevel@tonic-gate 	if (count <= 0)
63400Sstevel@tonic-gate 		return (-1);
63410Sstevel@tonic-gate 
63420Sstevel@tonic-gate 	/* set flag if dealing with a MN set */
63430Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
63440Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
63450Sstevel@tonic-gate 			return (-1);
63460Sstevel@tonic-gate 		}
63470Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
63480Sstevel@tonic-gate 			mn_set = 1;
63490Sstevel@tonic-gate 	}
63500Sstevel@tonic-gate 	/*
63510Sstevel@tonic-gate 	 * Save the XDR unit structure for one of the soft partitions;
63520Sstevel@tonic-gate 	 * we'll use this later to provide metadevice context to
63530Sstevel@tonic-gate 	 * update the watermarks so the device can be resolved by
63540Sstevel@tonic-gate 	 * devid instead of dev_t.
63550Sstevel@tonic-gate 	 */
63560Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, spnlp->namep, ep)) == NULL) {
63570Sstevel@tonic-gate 		metafreenamelist(spnlp);
63580Sstevel@tonic-gate 		return (-1);
63590Sstevel@tonic-gate 	}
63600Sstevel@tonic-gate 
63610Sstevel@tonic-gate 	if ((start_block = meta_sp_get_start(sp, compnp, ep)) ==
63620Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
63630Sstevel@tonic-gate 		return (-1);
63640Sstevel@tonic-gate 	}
63650Sstevel@tonic-gate 
63660Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist, 0ULL, start_block,
63670Sstevel@tonic-gate 	    EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
63680Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
63690Sstevel@tonic-gate 	    metagetsize(compnp, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
63700Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
63710Sstevel@tonic-gate 
63720Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
63730Sstevel@tonic-gate 		metafreenamelist(spnlp);
63740Sstevel@tonic-gate 		return (-1);
63750Sstevel@tonic-gate 	}
63760Sstevel@tonic-gate 
63770Sstevel@tonic-gate 	assert(extlist != NULL);
63780Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0) {
63790Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
63800Sstevel@tonic-gate 		    "Updating extent headers on device %s from metadb.\n\n"),
63810Sstevel@tonic-gate 		    compnp->cname);
63820Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
63830Sstevel@tonic-gate 		    "The following extent headers will be written:\n"));
63840Sstevel@tonic-gate 		meta_sp_display_exthdr();
63850Sstevel@tonic-gate 	}
63860Sstevel@tonic-gate 
63870Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
63880Sstevel@tonic-gate 
63890Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
63900Sstevel@tonic-gate 
63910Sstevel@tonic-gate 		/* mark every node for updating except the reserved space */
63920Sstevel@tonic-gate 		if (ext->ext_type != EXTTYP_RESERVED) {
63930Sstevel@tonic-gate 			ext->ext_flags |= EXTFLG_UPDATE;
63940Sstevel@tonic-gate 
63950Sstevel@tonic-gate 			/* print extent information */
63960Sstevel@tonic-gate 			if ((options & MDCMD_VERBOSE) != 0)
63970Sstevel@tonic-gate 				meta_sp_display_ext(ext);
63980Sstevel@tonic-gate 		}
63990Sstevel@tonic-gate 	}
64000Sstevel@tonic-gate 
64010Sstevel@tonic-gate 	/* request verification and then update all watermarks */
64020Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) != 0) {
64030Sstevel@tonic-gate 
64040Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64050Sstevel@tonic-gate 		    "\nWARNING: You are about to overwrite portions of %s\n"
64060Sstevel@tonic-gate 		    "with soft partition metadata. The extent headers will be\n"
64070Sstevel@tonic-gate 		    "written to match the existing metadb configuration.  If\n"
64080Sstevel@tonic-gate 		    "the device was not previously setup with this\n"
64090Sstevel@tonic-gate 		    "configuration, data loss may result.\n\n"),
64100Sstevel@tonic-gate 		    compnp->cname);
64110Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64120Sstevel@tonic-gate 		    "Are you sure you want to do this (yes/no)? "));
64130Sstevel@tonic-gate 
64140Sstevel@tonic-gate 		(void) fflush(stdout);
64150Sstevel@tonic-gate 		if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
64160Sstevel@tonic-gate 		    (strlen(yesno) == 1))
64170Sstevel@tonic-gate 			(void) snprintf(yesno, sizeof (yesno),
64180Sstevel@tonic-gate 			    "%s\n", dgettext(TEXT_DOMAIN, "no"));
64190Sstevel@tonic-gate 		yes = dgettext(TEXT_DOMAIN, "yes");
64200Sstevel@tonic-gate 		if (strncasecmp(yesno, yes, strlen(yesno) - 1) == 0) {
64210Sstevel@tonic-gate 			/* place soft partitions into recovering state */
64220Sstevel@tonic-gate 			minors = Zalloc(count * sizeof (minor_t));
64230Sstevel@tonic-gate 			for (nlp = spnlp, i = 0;
64240Sstevel@tonic-gate 			    nlp != NULL && i < count;
64250Sstevel@tonic-gate 			    nlp = nlp->next, i++) {
64260Sstevel@tonic-gate 				assert(nlp->namep != NULL);
64270Sstevel@tonic-gate 				minors[i] = meta_getminor(nlp->namep->dev);
64280Sstevel@tonic-gate 			}
64290Sstevel@tonic-gate 			if (update_sp_status(sp, minors, count,
64300Sstevel@tonic-gate 			    MD_SP_RECOVER, mn_set, ep) != 0) {
64310Sstevel@tonic-gate 				rval = -1;
64320Sstevel@tonic-gate 				goto out;
64330Sstevel@tonic-gate 			}
64340Sstevel@tonic-gate 
64350Sstevel@tonic-gate 			/* update the watermarks */
64360Sstevel@tonic-gate 			if (meta_sp_update_wm(sp, msp, extlist, ep) < 0) {
64370Sstevel@tonic-gate 				rval = -1;
64380Sstevel@tonic-gate 				goto out;
64390Sstevel@tonic-gate 			}
64400Sstevel@tonic-gate 
64410Sstevel@tonic-gate 			if (options & MDCMD_PRINT) {
64420Sstevel@tonic-gate 				(void) printf(dgettext(TEXT_DOMAIN, "%s: "
64430Sstevel@tonic-gate 				    "Soft Partitions recovered from metadb\n"),
64440Sstevel@tonic-gate 				    compnp->cname);
64450Sstevel@tonic-gate 			}
64460Sstevel@tonic-gate 
64470Sstevel@tonic-gate 			/* return soft partitions to the OK state */
64480Sstevel@tonic-gate 			if (update_sp_status(sp, minors, count,
64490Sstevel@tonic-gate 			    MD_SP_OK, mn_set, ep) != 0) {
64500Sstevel@tonic-gate 				rval = -1;
64510Sstevel@tonic-gate 				goto out;
64520Sstevel@tonic-gate 			}
64530Sstevel@tonic-gate 
64540Sstevel@tonic-gate 			rval = 0;
64550Sstevel@tonic-gate 			goto out;
64560Sstevel@tonic-gate 		}
64570Sstevel@tonic-gate 	}
64580Sstevel@tonic-gate 
64590Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
64600Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64610Sstevel@tonic-gate 		    "%s: Soft Partitions NOT recovered from metadb\n"),
64620Sstevel@tonic-gate 		    compnp->cname);
64630Sstevel@tonic-gate 	}
64640Sstevel@tonic-gate 
64650Sstevel@tonic-gate out:
64660Sstevel@tonic-gate 	if (minors != NULL)
64670Sstevel@tonic-gate 		Free(minors);
64680Sstevel@tonic-gate 	metafreenamelist(spnlp);
64690Sstevel@tonic-gate 	meta_sp_list_free(&extlist);
64700Sstevel@tonic-gate 	(void) fflush(stdout);
64710Sstevel@tonic-gate 	return (rval);
64720Sstevel@tonic-gate }
64730Sstevel@tonic-gate 
64740Sstevel@tonic-gate 
64750Sstevel@tonic-gate /*
64760Sstevel@tonic-gate  * FUNCTION:	meta_sp_update_abr()
64770Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
64780Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
64790Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
64800Sstevel@tonic-gate  * PURPOSE:	update the ABR state for all soft partitions in the set. This
64810Sstevel@tonic-gate  *		is called when joining a set. It sends a message to the master
64820Sstevel@tonic-gate  *		node for each soft partition to get the value of tstate and
64830Sstevel@tonic-gate  *		then sets ABR ,if required, by opening the sp, setting ABR
64840Sstevel@tonic-gate  *		and then closing the sp. This approach is taken rather that
64850Sstevel@tonic-gate  *		just issuing the MD_MN_SET_CAP ioctl, in order to deal with
64860Sstevel@tonic-gate  *		the case when we have another node simultaneously unsetting ABR.
64870Sstevel@tonic-gate  */
64880Sstevel@tonic-gate int
64890Sstevel@tonic-gate meta_sp_update_abr(
64900Sstevel@tonic-gate 	mdsetname_t	*sp,
64910Sstevel@tonic-gate 	md_error_t	*ep
64920Sstevel@tonic-gate )
64930Sstevel@tonic-gate {
64940Sstevel@tonic-gate 	mdnamelist_t	*devnlp = NULL;
64950Sstevel@tonic-gate 	mdnamelist_t	*p;
64960Sstevel@tonic-gate 	mdname_t	*devnp = NULL;
64970Sstevel@tonic-gate 	md_unit_t	*un;
64980Sstevel@tonic-gate 	char		fname[MAXPATHLEN];
64990Sstevel@tonic-gate 	int		mnum, fd;
65000Sstevel@tonic-gate 	volcap_t	vc;
65010Sstevel@tonic-gate 	uint_t		tstate;
65020Sstevel@tonic-gate 
65030Sstevel@tonic-gate 
65040Sstevel@tonic-gate 	if (meta_get_sp_names(sp, &devnlp, 0, ep) < 0) {
65050Sstevel@tonic-gate 		return (-1);
65060Sstevel@tonic-gate 	}
65070Sstevel@tonic-gate 
65080Sstevel@tonic-gate 	/* Exit if no soft partitions in this set */
65090Sstevel@tonic-gate 	if (devnlp == NULL)
65100Sstevel@tonic-gate 		return (0);
65110Sstevel@tonic-gate 
65120Sstevel@tonic-gate 	/* For each soft partition */
65130Sstevel@tonic-gate 	for (p = devnlp; (p != NULL); p = p->next) {
65140Sstevel@tonic-gate 		devnp = p->namep;
65150Sstevel@tonic-gate 
65160Sstevel@tonic-gate 		/* check if this is a top level metadevice */
65170Sstevel@tonic-gate 		if ((un = meta_get_mdunit(sp, devnp, ep)) == NULL)
65180Sstevel@tonic-gate 			goto out;
65190Sstevel@tonic-gate 		if (MD_HAS_PARENT(MD_PARENT(un))) {
65200Sstevel@tonic-gate 			Free(un);
65210Sstevel@tonic-gate 			continue;
65220Sstevel@tonic-gate 		}
65230Sstevel@tonic-gate 		Free(un);
65240Sstevel@tonic-gate 
65250Sstevel@tonic-gate 		/* Get tstate from Master */
65260Sstevel@tonic-gate 		if (meta_mn_send_get_tstate(devnp->dev, &tstate, ep) != 0) {
65270Sstevel@tonic-gate 			mdname_t	*np;
65280Sstevel@tonic-gate 			np = metamnumname(&sp, meta_getminor(devnp->dev), 0,
65290Sstevel@tonic-gate 			    ep);
65300Sstevel@tonic-gate 			if (np) {
65310Sstevel@tonic-gate 				md_perror(dgettext(TEXT_DOMAIN,
65320Sstevel@tonic-gate 				    "Unable to get tstate for %s"), np->cname);
65330Sstevel@tonic-gate 			}
65340Sstevel@tonic-gate 			continue;
65350Sstevel@tonic-gate 		}
65360Sstevel@tonic-gate 		/* If not set on the master, nothing to do */
65370Sstevel@tonic-gate 		if (!(tstate & MD_ABR_CAP))
65380Sstevel@tonic-gate 			continue;
65390Sstevel@tonic-gate 
65400Sstevel@tonic-gate 		mnum = meta_getminor(devnp->dev);
65410Sstevel@tonic-gate 		(void) snprintf(fname, MAXPATHLEN, "/dev/md/%s/rdsk/d%u",
65420Sstevel@tonic-gate 		    sp->setname, (unsigned)MD_MIN2UNIT(mnum));
65430Sstevel@tonic-gate 		if ((fd = open(fname, O_RDWR, 0)) < 0) {
65440Sstevel@tonic-gate 			md_perror(dgettext(TEXT_DOMAIN,
65450Sstevel@tonic-gate 			    "Could not open device %s"), fname);
65460Sstevel@tonic-gate 			continue;
65470Sstevel@tonic-gate 		}
65480Sstevel@tonic-gate 
65490Sstevel@tonic-gate 		/* Set ABR state */
65500Sstevel@tonic-gate 		vc.vc_info = 0;
65510Sstevel@tonic-gate 		vc.vc_set = 0;
65520Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGETVOLCAP, &vc) < 0) {
65530Sstevel@tonic-gate 			(void) close(fd);
65540Sstevel@tonic-gate 			continue;
65550Sstevel@tonic-gate 		}
65560Sstevel@tonic-gate 
65570Sstevel@tonic-gate 		vc.vc_set = DKV_ABR_CAP;
65580Sstevel@tonic-gate 		if (ioctl(fd, DKIOCSETVOLCAP, &vc) < 0) {
65590Sstevel@tonic-gate 			(void) close(fd);
65600Sstevel@tonic-gate 			goto out;
65610Sstevel@tonic-gate 		}
65620Sstevel@tonic-gate 
65630Sstevel@tonic-gate 		(void) close(fd);
65640Sstevel@tonic-gate 	}
65650Sstevel@tonic-gate 	metafreenamelist(devnlp);
65660Sstevel@tonic-gate 	return (0);
65670Sstevel@tonic-gate out:
65680Sstevel@tonic-gate 	metafreenamelist(devnlp);
65690Sstevel@tonic-gate 	return (-1);
65700Sstevel@tonic-gate }
65710Sstevel@tonic-gate 
65720Sstevel@tonic-gate /*
65730Sstevel@tonic-gate  * FUNCTION:	meta_mn_sp_update_abr()
65740Sstevel@tonic-gate  * INPUT:	arg	- Given set.
65750Sstevel@tonic-gate  * PURPOSE:	update the ABR state for all soft partitions in the set by
65760Sstevel@tonic-gate  *		forking a process to call meta_sp_update_abr()
65770Sstevel@tonic-gate  *		This function is only called via rpc.metad when adding a node
65780Sstevel@tonic-gate  *		to a set, ie this node is beong joined to the set by another
65790Sstevel@tonic-gate  *		node.
65800Sstevel@tonic-gate  */
65810Sstevel@tonic-gate void *
65820Sstevel@tonic-gate meta_mn_sp_update_abr(void *arg)
65830Sstevel@tonic-gate {
65840Sstevel@tonic-gate 	set_t		setno = *((set_t *)arg);
65850Sstevel@tonic-gate 	mdsetname_t	*sp;
65860Sstevel@tonic-gate 	md_error_t	mde = mdnullerror;
65870Sstevel@tonic-gate 	int		fval;
65880Sstevel@tonic-gate 
65890Sstevel@tonic-gate 	/* should have a set */
65900Sstevel@tonic-gate 	assert(setno != NULL);
65910Sstevel@tonic-gate 
65920Sstevel@tonic-gate 	if ((sp = metasetnosetname(setno, &mde)) == NULL) {
65930Sstevel@tonic-gate 		mde_perror(&mde, "");
65940Sstevel@tonic-gate 		return (NULL);
65950Sstevel@tonic-gate 	}
65960Sstevel@tonic-gate 
65970Sstevel@tonic-gate 	if (!(meta_is_mn_set(sp, &mde))) {
65980Sstevel@tonic-gate 		mde_perror(&mde, "");
65990Sstevel@tonic-gate 		return (NULL);
66000Sstevel@tonic-gate 	}
66010Sstevel@tonic-gate 
66020Sstevel@tonic-gate 	/* fork a process */
66030Sstevel@tonic-gate 	if ((fval = md_daemonize(sp, &mde)) != 0) {
66040Sstevel@tonic-gate 		/*
66050Sstevel@tonic-gate 		 * md_daemonize will fork off a process.  The is the
66060Sstevel@tonic-gate 		 * parent or error.
66070Sstevel@tonic-gate 		 */
66080Sstevel@tonic-gate 		if (fval > 0) {
66090Sstevel@tonic-gate 			return (NULL);
66100Sstevel@tonic-gate 		}
66110Sstevel@tonic-gate 		mde_perror(&mde, "");
66120Sstevel@tonic-gate 		return (NULL);
66130Sstevel@tonic-gate 	}
66140Sstevel@tonic-gate 	/*
66150Sstevel@tonic-gate 	 * Child process should never return back to rpc.metad, but
66160Sstevel@tonic-gate 	 * should exit.
66170Sstevel@tonic-gate 	 * Flush all internally cached data inherited from parent process
66180Sstevel@tonic-gate 	 * since cached data will be cleared when parent process RPC request
66190Sstevel@tonic-gate 	 * has completed (which is possibly before this child process
66200Sstevel@tonic-gate 	 * can complete).
66210Sstevel@tonic-gate 	 * Child process can retrieve and cache its own copy of data from
66220Sstevel@tonic-gate 	 * rpc.metad that won't be changed by the parent process.
66230Sstevel@tonic-gate 	 *
66240Sstevel@tonic-gate 	 * Reset md_in_daemon since this child will be a client of rpc.metad
66250Sstevel@tonic-gate 	 * not part of the rpc.metad daemon itself.
66260Sstevel@tonic-gate 	 * md_in_daemon is used by rpc.metad so that libmeta can tell if
66270Sstevel@tonic-gate 	 * this thread is rpc.metad or any other thread.  (If this thread
66280Sstevel@tonic-gate 	 * was rpc.metad it could use some short circuit code to get data
66290Sstevel@tonic-gate 	 * directly from rpc.metad instead of doing an RPC call to rpc.metad).
66300Sstevel@tonic-gate 	 */
66310Sstevel@tonic-gate 	md_in_daemon = 0;
66320Sstevel@tonic-gate 	metaflushsetname(sp);
66330Sstevel@tonic-gate 	sr_cache_flush_setno(setno);
66340Sstevel@tonic-gate 	if ((sp = metasetnosetname(setno, &mde)) == NULL) {
66350Sstevel@tonic-gate 		mde_perror(&mde, "");
66360Sstevel@tonic-gate 		md_exit(sp, 1);
66370Sstevel@tonic-gate 	}
66380Sstevel@tonic-gate 
66390Sstevel@tonic-gate 
66400Sstevel@tonic-gate 	/*
66410Sstevel@tonic-gate 	 * Closing stdin/out/err here.
66420Sstevel@tonic-gate 	 */
66430Sstevel@tonic-gate 	(void) close(0);
66440Sstevel@tonic-gate 	(void) close(1);
66450Sstevel@tonic-gate 	(void) close(2);
66460Sstevel@tonic-gate 	assert(fval == 0);
66470Sstevel@tonic-gate 
66480Sstevel@tonic-gate 	(void) meta_sp_update_abr(sp, &mde);
66490Sstevel@tonic-gate 
66500Sstevel@tonic-gate 	md_exit(sp, 0);
66510Sstevel@tonic-gate 	/*NOTREACHED*/
6652*62Sjeanm 	return (NULL);
66530Sstevel@tonic-gate }
6654