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