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