xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_sp.c (revision 704030f4517ac42005a5e3a4cb2fe578c959bfe2)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d7cd8252Stw21770  * Common Development and Distribution License (the "License").
6d7cd8252Stw21770  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21bf85a12bSJohn Wren Kennedy 
227c478bd9Sstevel@tonic-gate /*
23*704030f4SJames Hall  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
287c478bd9Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
317c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
327c478bd9Sstevel@tonic-gate #endif
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * soft partition operations
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * Soft Partitions provide a virtual disk mechanism which is used to
387c478bd9Sstevel@tonic-gate  * divide a large volume into many small pieces, each appearing as a
397c478bd9Sstevel@tonic-gate  * separate device.  A soft partition consists of a series of extents,
407c478bd9Sstevel@tonic-gate  * each having an offset and a length.  The extents are logically
417c478bd9Sstevel@tonic-gate  * contiguous, so where the first extent leaves off the second extent
427c478bd9Sstevel@tonic-gate  * picks up.  Which extent a given "virtual offset" belongs to is
437c478bd9Sstevel@tonic-gate  * dependent on the size of all the previous extents in the soft
447c478bd9Sstevel@tonic-gate  * partition.
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  * Soft partitions are represented in memory by an extent node
477c478bd9Sstevel@tonic-gate  * (sp_ext_node_t) which contains all of the information necessary to
487c478bd9Sstevel@tonic-gate  * create a unit structure and update the on-disk format, called
497c478bd9Sstevel@tonic-gate  * "watermarks".  These extent nodes are typically kept in a doubly
507c478bd9Sstevel@tonic-gate  * linked list and are manipulated by list manipulation routines.  A
517c478bd9Sstevel@tonic-gate  * list of extents may represent all of the soft partitions on a volume,
527c478bd9Sstevel@tonic-gate  * a single soft partition, or perhaps just a set of extents that need
537c478bd9Sstevel@tonic-gate  * to be updated.  Extent lists may be sorted by extent or by name/seq#,
547c478bd9Sstevel@tonic-gate  * depending on which compare function is used.  Most of the routines
557c478bd9Sstevel@tonic-gate  * require the list be sorted by offset to work, and that's the typical
567c478bd9Sstevel@tonic-gate  * configuration.
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  * In order to do an allocation, knowledge of all soft partitions on the
597c478bd9Sstevel@tonic-gate  * volume is required.  Then free space is determined from the space
607c478bd9Sstevel@tonic-gate  * that is not allocated, and new allocations can be made from the free
617c478bd9Sstevel@tonic-gate  * space.  Once the new allocations are made, a unit structure is created
627c478bd9Sstevel@tonic-gate  * and the watermarks are updated.  The status is then changed to "okay"
637c478bd9Sstevel@tonic-gate  * on the unit structure to commit the transaction.  If updating the
647c478bd9Sstevel@tonic-gate  * watermarks fails, the unit structure is in an intermediate state and
657c478bd9Sstevel@tonic-gate  * the driver will not allow access to the device.
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * A typical sequence of events is:
687c478bd9Sstevel@tonic-gate  *     1. Fetch the list of names for all soft partitions on a volume
697c478bd9Sstevel@tonic-gate  *         meta_sp_get_by_component()
707c478bd9Sstevel@tonic-gate  *     2. Construct an extent list from the name list
717c478bd9Sstevel@tonic-gate  *         meta_sp_extlist_from_namelist()
727c478bd9Sstevel@tonic-gate  *     3. Fill the gaps in the extent list with free extents
737c478bd9Sstevel@tonic-gate  *         meta_sp_list_freefill()
747c478bd9Sstevel@tonic-gate  *     4. Allocate from the free extents
757c478bd9Sstevel@tonic-gate  *         meta_sp_alloc_by_len()
767c478bd9Sstevel@tonic-gate  *         meta_sp_alloc_by_list()
777c478bd9Sstevel@tonic-gate  *     5. Create the unit structure from the extent list
787c478bd9Sstevel@tonic-gate  *         meta_sp_createunit()
797c478bd9Sstevel@tonic-gate  *         meta_sp_updateunit()
807c478bd9Sstevel@tonic-gate  *     6. Write out the watermarks
817c478bd9Sstevel@tonic-gate  *         meta_sp_update_wm()
827c478bd9Sstevel@tonic-gate  *     7. Set the status to "Okay"
837c478bd9Sstevel@tonic-gate  *         meta_sp_setstatus()
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #include <stdio.h>
887c478bd9Sstevel@tonic-gate #include <meta.h>
897c478bd9Sstevel@tonic-gate #include "meta_repartition.h"
907c478bd9Sstevel@tonic-gate #include <sys/lvm/md_sp.h>
917c478bd9Sstevel@tonic-gate #include <sys/lvm/md_crc.h>
927c478bd9Sstevel@tonic-gate #include <strings.h>
937c478bd9Sstevel@tonic-gate #include <sys/lvm/md_mirror.h>
947c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate extern int	md_in_daemon;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate typedef struct sp_ext_node {
997c478bd9Sstevel@tonic-gate 	struct sp_ext_node	*ext_next;	/* next element */
1007c478bd9Sstevel@tonic-gate 	struct sp_ext_node	*ext_prev;	/* previous element */
1017c478bd9Sstevel@tonic-gate 	sp_ext_type_t		ext_type;	/* type of extent */
1027c478bd9Sstevel@tonic-gate 	sp_ext_offset_t		ext_offset;	/* starting offset */
1037c478bd9Sstevel@tonic-gate 	sp_ext_length_t		ext_length;	/* length of this node */
1047c478bd9Sstevel@tonic-gate 	uint_t			ext_flags;	/* extent flags */
1057c478bd9Sstevel@tonic-gate 	uint32_t		ext_seq;	/* watermark seq no */
1067c478bd9Sstevel@tonic-gate 	mdname_t		*ext_namep;	/* name pointer */
1077c478bd9Sstevel@tonic-gate 	mdsetname_t		*ext_setp;	/* set pointer */
1087c478bd9Sstevel@tonic-gate } sp_ext_node_t;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /* extent flags */
1117c478bd9Sstevel@tonic-gate #define	EXTFLG_UPDATE	(1)
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* Extent node compare function for list sorting */
1147c478bd9Sstevel@tonic-gate typedef int (*ext_cmpfunc_t)(sp_ext_node_t *, sp_ext_node_t *);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /* Function Prototypes */
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /* Debugging Functions */
1207c478bd9Sstevel@tonic-gate static void meta_sp_debug(char *format, ...);
1217c478bd9Sstevel@tonic-gate static void meta_sp_printunit(mp_unit_t *mp);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /* Misc Support Functions */
1247c478bd9Sstevel@tonic-gate int meta_sp_parsesize(char *s, sp_ext_length_t *szp);
1257c478bd9Sstevel@tonic-gate static int meta_sp_parsesizestring(char *s, sp_ext_length_t *szp);
1267c478bd9Sstevel@tonic-gate static int meta_sp_setgeom(mdname_t *np, mdname_t *compnp, mp_unit_t *mp,
1277c478bd9Sstevel@tonic-gate 	md_error_t *ep);
1287c478bd9Sstevel@tonic-gate static int meta_sp_get_by_component(mdsetname_t *sp, mdname_t *compnp,
1297c478bd9Sstevel@tonic-gate     mdnamelist_t **nlpp, int force, md_error_t *ep);
1307c478bd9Sstevel@tonic-gate static sp_ext_length_t meta_sp_get_default_alignment(mdsetname_t *sp,
1317c478bd9Sstevel@tonic-gate     mdname_t *compnp, md_error_t *ep);
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /* Extent List Manipulation Functions */
1347c478bd9Sstevel@tonic-gate static int meta_sp_cmp_by_nameseq(sp_ext_node_t *e1, sp_ext_node_t *e2);
1357c478bd9Sstevel@tonic-gate static int meta_sp_cmp_by_offset(sp_ext_node_t *e1, sp_ext_node_t *e2);
1367c478bd9Sstevel@tonic-gate static void meta_sp_list_insert(mdsetname_t *sp, mdname_t *np,
1377c478bd9Sstevel@tonic-gate     sp_ext_node_t **head, sp_ext_offset_t offset, sp_ext_length_t length,
1387c478bd9Sstevel@tonic-gate     sp_ext_type_t type, uint_t seq, uint_t flags, ext_cmpfunc_t compare);
1397c478bd9Sstevel@tonic-gate static void meta_sp_list_free(sp_ext_node_t **head);
1407c478bd9Sstevel@tonic-gate static void meta_sp_list_remove(sp_ext_node_t **head, sp_ext_node_t *ext);
1417c478bd9Sstevel@tonic-gate static sp_ext_length_t meta_sp_list_size(sp_ext_node_t *head,
1427c478bd9Sstevel@tonic-gate     sp_ext_type_t exttype, int exclude_wm);
1437c478bd9Sstevel@tonic-gate static sp_ext_node_t *meta_sp_list_find(sp_ext_node_t *head,
1447c478bd9Sstevel@tonic-gate     sp_ext_offset_t offset);
1457c478bd9Sstevel@tonic-gate static void meta_sp_list_freefill(sp_ext_node_t **extlist,
1467c478bd9Sstevel@tonic-gate     sp_ext_length_t size);
1477c478bd9Sstevel@tonic-gate static void meta_sp_list_dump(sp_ext_node_t *head);
1487c478bd9Sstevel@tonic-gate static int meta_sp_list_overlaps(sp_ext_node_t *head);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /* Extent List Query Functions */
1517c478bd9Sstevel@tonic-gate static boolean_t meta_sp_enough_space(int desired_number_of_sps,
1527c478bd9Sstevel@tonic-gate 	blkcnt_t desired_sp_size, sp_ext_node_t **extent_listpp,
1537c478bd9Sstevel@tonic-gate 	sp_ext_length_t alignment);
1547c478bd9Sstevel@tonic-gate static boolean_t meta_sp_get_extent_list(mdsetname_t *mdsetnamep,
1557c478bd9Sstevel@tonic-gate 	mdname_t *device_mdnamep, sp_ext_node_t **extent_listpp,
1567c478bd9Sstevel@tonic-gate 	md_error_t *ep);
1577c478bd9Sstevel@tonic-gate static boolean_t meta_sp_get_extent_list_for_drive(mdsetname_t *mdsetnamep,
1587c478bd9Sstevel@tonic-gate 	mddrivename_t *mddrivenamep, sp_ext_node_t **extent_listpp);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /* Extent Allocation Functions */
1627c478bd9Sstevel@tonic-gate static void meta_sp_alloc_by_ext(mdsetname_t *sp, mdname_t *np,
1637c478bd9Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_node_t *free_ext,
1647c478bd9Sstevel@tonic-gate     sp_ext_offset_t alloc_offset, sp_ext_length_t alloc_length, uint_t seq);
1657c478bd9Sstevel@tonic-gate static int meta_sp_alloc_by_len(mdsetname_t *sp, mdname_t *np,
1667c478bd9Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_length_t *lp,
1677c478bd9Sstevel@tonic-gate     sp_ext_offset_t last_off, sp_ext_length_t alignment);
1687c478bd9Sstevel@tonic-gate static int meta_sp_alloc_by_list(mdsetname_t *sp, mdname_t *np,
1697c478bd9Sstevel@tonic-gate     sp_ext_node_t **extlist, sp_ext_node_t *oblist);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /* Extent List Population Functions */
1727c478bd9Sstevel@tonic-gate static int meta_sp_extlist_from_namelist(mdsetname_t *sp, mdnamelist_t *spnlp,
1737c478bd9Sstevel@tonic-gate     sp_ext_node_t **extlist, md_error_t *ep);
1747c478bd9Sstevel@tonic-gate static int meta_sp_extlist_from_wm(mdsetname_t *sp, mdname_t *compnp,
1757c478bd9Sstevel@tonic-gate     sp_ext_node_t **extlist, ext_cmpfunc_t compare, md_error_t *ep);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /* Print (metastat) Functions */
1787c478bd9Sstevel@tonic-gate static int meta_sp_short_print(md_sp_t *msp, char *fname, FILE *fp,
1797c478bd9Sstevel@tonic-gate     mdprtopts_t options, md_error_t *ep);
1807c478bd9Sstevel@tonic-gate static char *meta_sp_status_to_name(xsp_status_t xsp_status, uint_t tstate);
1817c478bd9Sstevel@tonic-gate static int meta_sp_report(mdsetname_t *sp, md_sp_t *msp, mdnamelist_t **nlpp,
1827c478bd9Sstevel@tonic-gate     char *fname, FILE *fp, mdprtopts_t options, md_error_t *ep);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /* Watermark Manipulation Functions */
1857c478bd9Sstevel@tonic-gate static int meta_sp_update_wm(mdsetname_t *sp, md_sp_t *msp,
1867c478bd9Sstevel@tonic-gate     sp_ext_node_t *extlist, md_error_t *ep);
1877c478bd9Sstevel@tonic-gate static int meta_sp_clear_wm(mdsetname_t *sp, md_sp_t *msp, md_error_t *ep);
1887c478bd9Sstevel@tonic-gate static int meta_sp_read_wm(mdsetname_t *sp, mdname_t *compnp,
1897c478bd9Sstevel@tonic-gate     mp_watermark_t *wm, sp_ext_offset_t offset,  md_error_t *ep);
1907c478bd9Sstevel@tonic-gate static diskaddr_t meta_sp_get_start(mdsetname_t *sp, mdname_t *compnp,
1917c478bd9Sstevel@tonic-gate     md_error_t *ep);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /* Unit Structure Manipulation Functions */
1947c478bd9Sstevel@tonic-gate static void meta_sp_fillextarray(mp_unit_t *mp, sp_ext_node_t *extlist);
1957c478bd9Sstevel@tonic-gate static mp_unit_t *meta_sp_createunit(mdname_t *np, mdname_t *compnp,
1967c478bd9Sstevel@tonic-gate     sp_ext_node_t *extlist, int numexts, sp_ext_length_t len,
1977c478bd9Sstevel@tonic-gate     sp_status_t status, md_error_t *ep);
1987c478bd9Sstevel@tonic-gate static mp_unit_t *meta_sp_updateunit(mdname_t *np,  mp_unit_t *old_un,
1997c478bd9Sstevel@tonic-gate     sp_ext_node_t *extlist, sp_ext_length_t grow_len, int numexts,
2007c478bd9Sstevel@tonic-gate     md_error_t *ep);
2017c478bd9Sstevel@tonic-gate static int meta_create_sp(mdsetname_t *sp, md_sp_t *msp, sp_ext_node_t *oblist,
2027c478bd9Sstevel@tonic-gate     mdcmdopts_t options, sp_ext_length_t alignment, md_error_t *ep);
2037c478bd9Sstevel@tonic-gate static int meta_check_sp(mdsetname_t *sp, md_sp_t *msp, mdcmdopts_t options,
2047c478bd9Sstevel@tonic-gate     int *repart_options, md_error_t *ep);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /* Reset (metaclear) Functions */
2077c478bd9Sstevel@tonic-gate static int meta_sp_reset_common(mdsetname_t *sp, mdname_t *np, md_sp_t *msp,
2087c478bd9Sstevel@tonic-gate     md_sp_reset_t reset_params, mdcmdopts_t options, md_error_t *ep);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /* Recovery (metarecover) Functions */
2117c478bd9Sstevel@tonic-gate static void meta_sp_display_exthdr(void);
2127c478bd9Sstevel@tonic-gate static void meta_sp_display_ext(sp_ext_node_t *ext);
2137c478bd9Sstevel@tonic-gate static int meta_sp_checkseq(sp_ext_node_t *extlist);
2147c478bd9Sstevel@tonic-gate static int meta_sp_resolve_name_conflict(mdsetname_t *, mdname_t *,
2157c478bd9Sstevel@tonic-gate     mdname_t **, md_error_t *);
2167c478bd9Sstevel@tonic-gate static int meta_sp_validate_wm(mdsetname_t *sp, mdname_t *np,
2177c478bd9Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2187c478bd9Sstevel@tonic-gate static int meta_sp_validate_unit(mdsetname_t *sp, mdname_t *compnp,
2197c478bd9Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2207c478bd9Sstevel@tonic-gate static int meta_sp_validate_wm_and_unit(mdsetname_t *sp, mdname_t *np,
2217c478bd9Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2227c478bd9Sstevel@tonic-gate static int meta_sp_validate_exts(mdname_t *np, sp_ext_node_t *wmext,
2237c478bd9Sstevel@tonic-gate     sp_ext_node_t *unitext, md_error_t *ep);
2247c478bd9Sstevel@tonic-gate static int meta_sp_recover_from_wm(mdsetname_t *sp, mdname_t *compnp,
2257c478bd9Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2267c478bd9Sstevel@tonic-gate static int meta_sp_recover_from_unit(mdsetname_t *sp, mdname_t *np,
2277c478bd9Sstevel@tonic-gate     mdcmdopts_t options, md_error_t *ep);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * Private Constants
2317c478bd9Sstevel@tonic-gate  */
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static const int FORCE_RELOAD_CACHE = 1;
2347c478bd9Sstevel@tonic-gate static const uint_t NO_FLAGS = 0;
2357c478bd9Sstevel@tonic-gate static const sp_ext_offset_t NO_OFFSET = 0ULL;
2367c478bd9Sstevel@tonic-gate static const uint_t NO_SEQUENCE_NUMBER = 0;
2377c478bd9Sstevel@tonic-gate static const int ONE_SOFT_PARTITION = 1;
2387c478bd9Sstevel@tonic-gate 
2392b637af7SJohn Harres static unsigned long *sp_parent_printed[MD_MAXSETS];
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate #define	TEST_SOFT_PARTITION_NAMEP NULL
2427c478bd9Sstevel@tonic-gate #define	TEST_SETNAMEP NULL
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate #define	EXCLUDE_WM	(1)
2457c478bd9Sstevel@tonic-gate #define	INCLUDE_WM	(0)
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate #define	SP_UNALIGNED	(0LL)
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate /*
2507c478bd9Sstevel@tonic-gate  * **************************************************************************
2517c478bd9Sstevel@tonic-gate  *                          Debugging Functions                             *
2527c478bd9Sstevel@tonic-gate  * **************************************************************************
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
2567c478bd9Sstevel@tonic-gate static void
meta_sp_debug(char * format,...)2577c478bd9Sstevel@tonic-gate meta_sp_debug(char *format, ...)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	static int debug;
2607c478bd9Sstevel@tonic-gate 	static int debug_set = 0;
2617c478bd9Sstevel@tonic-gate 	va_list ap;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (!debug_set) {
2647c478bd9Sstevel@tonic-gate 		debug = getenv(META_SP_DEBUG) ? 1 : 0;
2657c478bd9Sstevel@tonic-gate 		debug_set = 1;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (debug) {
2697c478bd9Sstevel@tonic-gate 		va_start(ap, format);
2707c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, format, ap);
2717c478bd9Sstevel@tonic-gate 		va_end(ap);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate static void
meta_sp_printunit(mp_unit_t * mp)2767c478bd9Sstevel@tonic-gate meta_sp_printunit(mp_unit_t *mp)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	int i;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	if (mp == NULL)
2817c478bd9Sstevel@tonic-gate 		return;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/* print the common fields we know about */
2847c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_type: %d\n", mp->c.un_type);
2857c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_size: %u\n", mp->c.un_size);
2867c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->c.un_self_id: %lu\n", MD_SID(mp));
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/* sp-specific fields */
2897c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_status: %u\n", mp->un_status);
2907c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_numexts: %u\n", mp->un_numexts);
2917c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_length: %llu\n", mp->un_length);
2927c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_dev(32): 0x%llx\n", mp->un_dev);
2937c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_dev(64): 0x%llx\n", mp->un_dev);
2947c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tmp->un_key: %d\n", mp->un_key);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/* print extent information */
2977c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tExt#\tvoff\t\tpoff\t\tLen\n");
2987c478bd9Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
2997c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%d\t%llu\t\t%llu\t\t%llu\n", i,
3007c478bd9Sstevel@tonic-gate 		    mp->un_ext[i].un_voff, mp->un_ext[i].un_poff,
3017c478bd9Sstevel@tonic-gate 		    mp->un_ext[i].un_len);
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate  * FUNCTION:    meta_sp_parsesize()
3077c478bd9Sstevel@tonic-gate  * INPUT:       s       - the string to parse
3087c478bd9Sstevel@tonic-gate  * OUTPUT:      *szp    - disk block count (0 for "all")
3097c478bd9Sstevel@tonic-gate  * RETURNS:     -1 for error, 0 for success
3107c478bd9Sstevel@tonic-gate  * PURPOSE:     parses the command line parameter that specifies the
3117c478bd9Sstevel@tonic-gate  *              requested size of a soft partition.  The input string
3127c478bd9Sstevel@tonic-gate  *              is either the literal "all" or a numeric value
3137c478bd9Sstevel@tonic-gate  *              followed by a single character, b for disk blocks, k
3147c478bd9Sstevel@tonic-gate  *              for kilobytes, m for megabytes, g for gigabytes, or t
3157c478bd9Sstevel@tonic-gate  *              for terabytes.  p for petabytes and e for exabytes
3167c478bd9Sstevel@tonic-gate  *              have been added as undocumented features for future
3177c478bd9Sstevel@tonic-gate  *              expansion.  For example, 100m is 100 megabytes, while
3187c478bd9Sstevel@tonic-gate  *              50g is 50 gigabytes.  All values are rounded up to the
3197c478bd9Sstevel@tonic-gate  *              nearest block size.
3207c478bd9Sstevel@tonic-gate  */
3217c478bd9Sstevel@tonic-gate int
meta_sp_parsesize(char * s,sp_ext_length_t * szp)3227c478bd9Sstevel@tonic-gate meta_sp_parsesize(char *s, sp_ext_length_t *szp)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	if (s == NULL || szp == NULL) {
3257c478bd9Sstevel@tonic-gate 		return (-1);
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/* Check for literal "all" */
3297c478bd9Sstevel@tonic-gate 	if (strcasecmp(s, "all") == 0) {
3307c478bd9Sstevel@tonic-gate 		*szp = 0;
3317c478bd9Sstevel@tonic-gate 		return (0);
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	return (meta_sp_parsesizestring(s, szp));
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_parsesizestring()
3397c478bd9Sstevel@tonic-gate  * INPUT:	s	- the string to parse
3407c478bd9Sstevel@tonic-gate  * OUTPUT:	*szp	- disk block count
3417c478bd9Sstevel@tonic-gate  * RETURNS:	-1 for error, 0 for success
3427c478bd9Sstevel@tonic-gate  * PURPOSE:	parses a string that specifies size. The input string is a
3437c478bd9Sstevel@tonic-gate  *		numeric value followed by a single character, b for disk blocks,
3447c478bd9Sstevel@tonic-gate  *		k for kilobytes, m for megabytes, g for gigabytes, or t for
3457c478bd9Sstevel@tonic-gate  *		terabytes.  p for petabytes and e for exabytes have been added
3467c478bd9Sstevel@tonic-gate  *		as undocumented features for future expansion.  For example,
3477c478bd9Sstevel@tonic-gate  *		100m is 100 megabytes, while 50g is 50 gigabytes.  All values
3487c478bd9Sstevel@tonic-gate  *		are rounded up to the nearest block size.
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate static int
meta_sp_parsesizestring(char * s,sp_ext_length_t * szp)3517c478bd9Sstevel@tonic-gate meta_sp_parsesizestring(char *s, sp_ext_length_t *szp)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	sp_ext_length_t	len = 0;
3547c478bd9Sstevel@tonic-gate 	char		len_type[2];
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	if (s == NULL || szp == NULL) {
3577c478bd9Sstevel@tonic-gate 		return (-1);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/*
3617c478bd9Sstevel@tonic-gate 	 * make sure block offset does not overflow 2^64 bytes.
3627c478bd9Sstevel@tonic-gate 	 */
3637c478bd9Sstevel@tonic-gate 	if ((sscanf(s, "%llu%1[BbKkMmGgTt]", &len, len_type) != 2) ||
3647c478bd9Sstevel@tonic-gate 	    (len == 0LL) ||
3657c478bd9Sstevel@tonic-gate 	    (len > (1LL << (64 - DEV_BSHIFT))))
3667c478bd9Sstevel@tonic-gate 		return (-1);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	switch (len_type[0]) {
3697c478bd9Sstevel@tonic-gate 	case 'B':
3707c478bd9Sstevel@tonic-gate 	case 'b':
3717c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(len * DEV_BSIZE, DEV_BSIZE));
3727c478bd9Sstevel@tonic-gate 		break;
3737c478bd9Sstevel@tonic-gate 	case 'K':
3747c478bd9Sstevel@tonic-gate 	case 'k':
3757c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL, DEV_BSIZE));
3767c478bd9Sstevel@tonic-gate 		break;
3777c478bd9Sstevel@tonic-gate 	case 'M':
3787c478bd9Sstevel@tonic-gate 	case 'm':
3797c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL, DEV_BSIZE));
3807c478bd9Sstevel@tonic-gate 		break;
3817c478bd9Sstevel@tonic-gate 	case 'g':
3827c478bd9Sstevel@tonic-gate 	case 'G':
3837c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL*1024ULL, DEV_BSIZE));
3847c478bd9Sstevel@tonic-gate 		break;
3857c478bd9Sstevel@tonic-gate 	case 't':
3867c478bd9Sstevel@tonic-gate 	case 'T':
3877c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(len * 1024ULL*1024ULL*1024ULL*1024ULL,
3887c478bd9Sstevel@tonic-gate 		    DEV_BSIZE));
3897c478bd9Sstevel@tonic-gate 		break;
3907c478bd9Sstevel@tonic-gate 	case 'p':
3917c478bd9Sstevel@tonic-gate 	case 'P':
3927c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(
3937c478bd9Sstevel@tonic-gate 		    len * 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL,
3947c478bd9Sstevel@tonic-gate 		    DEV_BSIZE));
3957c478bd9Sstevel@tonic-gate 		break;
3967c478bd9Sstevel@tonic-gate 	case 'e':
3977c478bd9Sstevel@tonic-gate 	case 'E':
3987c478bd9Sstevel@tonic-gate 		len = lbtodb(roundup(
3997c478bd9Sstevel@tonic-gate 		    len * 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL,
4007c478bd9Sstevel@tonic-gate 		    DEV_BSIZE));
4017c478bd9Sstevel@tonic-gate 		break;
4027c478bd9Sstevel@tonic-gate 	default:
4037c478bd9Sstevel@tonic-gate 		/* error */
4047c478bd9Sstevel@tonic-gate 		return (-1);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	*szp = len;
4087c478bd9Sstevel@tonic-gate 	return (0);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_setgeom()
4137c478bd9Sstevel@tonic-gate  * INPUT:	np      - the underlying device to setup geometry for
4147c478bd9Sstevel@tonic-gate  *		compnp	- the underlying device to setup geometry for
4157c478bd9Sstevel@tonic-gate  *		mp	- the unit structure to set the geometry for
4167c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4177c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 otherwise
4187c478bd9Sstevel@tonic-gate  * PURPOSE:	establishes geometry information for a device
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate static int
meta_sp_setgeom(mdname_t * np,mdname_t * compnp,mp_unit_t * mp,md_error_t * ep)4217c478bd9Sstevel@tonic-gate meta_sp_setgeom(
4227c478bd9Sstevel@tonic-gate 	mdname_t	*np,
4237c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
4247c478bd9Sstevel@tonic-gate 	mp_unit_t	*mp,
4257c478bd9Sstevel@tonic-gate 	md_error_t	*ep
4267c478bd9Sstevel@tonic-gate )
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	mdgeom_t	*geomp;
4297c478bd9Sstevel@tonic-gate 	uint_t		round_cyl = 0;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((geomp = metagetgeom(compnp, ep)) == NULL)
4327c478bd9Sstevel@tonic-gate 		return (-1);
4337c478bd9Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)mp, np, geomp, geomp->write_reinstruct,
4347c478bd9Sstevel@tonic-gate 	    geomp->read_reinstruct, round_cyl, ep) != 0)
4357c478bd9Sstevel@tonic-gate 		return (-1);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	return (0);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_setstatus()
4427c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the devices to set the status on
4437c478bd9Sstevel@tonic-gate  *		minors	- an array of minor numbers of devices to set status on
4447c478bd9Sstevel@tonic-gate  *		num_units - number of entries in the array
4457c478bd9Sstevel@tonic-gate  *		status	- status value to set all units to
4467c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
4477c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
4487c478bd9Sstevel@tonic-gate  * PURPOSE:	sets the status of one or more soft partitions to the
4497c478bd9Sstevel@tonic-gate  *		requested value
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate int
meta_sp_setstatus(mdsetname_t * sp,minor_t * minors,int num_units,sp_status_t status,md_error_t * ep)4527c478bd9Sstevel@tonic-gate meta_sp_setstatus(
4537c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
4547c478bd9Sstevel@tonic-gate 	minor_t		*minors,
4557c478bd9Sstevel@tonic-gate 	int		num_units,
4567c478bd9Sstevel@tonic-gate 	sp_status_t	status,
4577c478bd9Sstevel@tonic-gate 	md_error_t	*ep
4587c478bd9Sstevel@tonic-gate )
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate 	md_sp_statusset_t	status_params;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	assert(minors != NULL);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/* update status of all soft partitions to the status passed in */
4657c478bd9Sstevel@tonic-gate 	(void) memset(&status_params, 0, sizeof (status_params));
4667c478bd9Sstevel@tonic-gate 	status_params.num_units = num_units;
4677c478bd9Sstevel@tonic-gate 	status_params.new_status = status;
4687c478bd9Sstevel@tonic-gate 	status_params.size = num_units * sizeof (minor_t);
4697c478bd9Sstevel@tonic-gate 	status_params.minors = (uintptr_t)minors;
4707c478bd9Sstevel@tonic-gate 	MD_SETDRIVERNAME(&status_params, MD_SP, sp->setno);
4717c478bd9Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPSTATUS, &status_params, &status_params.mde,
4727c478bd9Sstevel@tonic-gate 	    NULL) != 0) {
4737c478bd9Sstevel@tonic-gate 		(void) mdstealerror(ep, &status_params.mde);
4747c478bd9Sstevel@tonic-gate 		return (-1);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 	return (0);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_get_sp_names()
4817c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name to get soft partitions from
4827c478bd9Sstevel@tonic-gate  *		options	- options from the command line
4837c478bd9Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all soft partition names
4847c478bd9Sstevel@tonic-gate  *		ep	- return error pointer
4857c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
4867c478bd9Sstevel@tonic-gate  * PURPOSE:	returns a list of all soft partitions in the metadb
4877c478bd9Sstevel@tonic-gate  *		for all devices in the specified set
4887c478bd9Sstevel@tonic-gate  */
4897c478bd9Sstevel@tonic-gate int
meta_get_sp_names(mdsetname_t * sp,mdnamelist_t ** nlpp,int options,md_error_t * ep)4907c478bd9Sstevel@tonic-gate meta_get_sp_names(
4917c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
4927c478bd9Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
4937c478bd9Sstevel@tonic-gate 	int		options,
4947c478bd9Sstevel@tonic-gate 	md_error_t	*ep
4957c478bd9Sstevel@tonic-gate )
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	return (meta_get_names(MD_SP, sp, nlpp, options, ep));
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_get_by_component()
5027c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name to get soft partitions from
5037c478bd9Sstevel@tonic-gate  *		compnp	- the name of the device containing the soft
5047c478bd9Sstevel@tonic-gate  *			  partitions that will be returned
5057c478bd9Sstevel@tonic-gate  *		force	- 0 - reads cached namelist if available,
5067c478bd9Sstevel@tonic-gate  *			  1 - reloads cached namelist, frees old namelist
5077c478bd9Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all soft partition names
5087c478bd9Sstevel@tonic-gate  *		ep	- return error pointer
5097c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 error, otherwise the number of soft partitions
5107c478bd9Sstevel@tonic-gate  *			  found on the component (0 = none found).
5117c478bd9Sstevel@tonic-gate  * PURPOSE:	returns a list of all soft partitions on a given device
5127c478bd9Sstevel@tonic-gate  *		from the metadb information
5137c478bd9Sstevel@tonic-gate  */
5147c478bd9Sstevel@tonic-gate static int
meta_sp_get_by_component(mdsetname_t * sp,mdname_t * compnp,mdnamelist_t ** nlpp,int force,md_error_t * ep)5157c478bd9Sstevel@tonic-gate meta_sp_get_by_component(
5167c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
5177c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
5187c478bd9Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
5197c478bd9Sstevel@tonic-gate 	int		force,
5207c478bd9Sstevel@tonic-gate 	md_error_t	*ep
5217c478bd9Sstevel@tonic-gate )
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	static mdnamelist_t	*cached_list = NULL;	/* cached namelist */
5247c478bd9Sstevel@tonic-gate 	static int		cached_count = 0;	/* cached count */
5257c478bd9Sstevel@tonic-gate 	mdnamelist_t		*spnlp = NULL;		/* all sp names */
5267c478bd9Sstevel@tonic-gate 	mdnamelist_t		*namep;			/* list iterator */
5277c478bd9Sstevel@tonic-gate 	mdnamelist_t		**tailpp = nlpp;	/* namelist tail */
5287c478bd9Sstevel@tonic-gate 	mdnamelist_t		**cachetailpp;		/* cache tail */
5297c478bd9Sstevel@tonic-gate 	md_sp_t			*msp;			/* unit structure */
5307c478bd9Sstevel@tonic-gate 	int			count = 0;		/* count of sp's */
5317c478bd9Sstevel@tonic-gate 	int			err;
5327c478bd9Sstevel@tonic-gate 	mdname_t		*curnp;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	if ((cached_list != NULL) && (!force)) {
5357c478bd9Sstevel@tonic-gate 		/* return a copy of the cached list */
5367c478bd9Sstevel@tonic-gate 		for (namep = cached_list; namep != NULL; namep = namep->next)
5377c478bd9Sstevel@tonic-gate 			tailpp = meta_namelist_append_wrapper(tailpp,
5387c478bd9Sstevel@tonic-gate 			    namep->namep);
5397c478bd9Sstevel@tonic-gate 		return (cached_count);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/* free the cache and reset values to zeros to prepare for a new list */
5437c478bd9Sstevel@tonic-gate 	metafreenamelist(cached_list);
5447c478bd9Sstevel@tonic-gate 	cached_count = 0;
5457c478bd9Sstevel@tonic-gate 	cached_list = NULL;
5467c478bd9Sstevel@tonic-gate 	cachetailpp = &cached_list;
5477c478bd9Sstevel@tonic-gate 	*nlpp = NULL;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	/* get all the softpartitions first of all */
5507c478bd9Sstevel@tonic-gate 	if (meta_get_sp_names(sp, &spnlp, 0, ep) < 0)
5517c478bd9Sstevel@tonic-gate 		return (-1);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/*
5547c478bd9Sstevel@tonic-gate 	 * Now for each sp, see if it resides on the component we
5557c478bd9Sstevel@tonic-gate 	 * are interested in, if so then add it to our list
5567c478bd9Sstevel@tonic-gate 	 */
5577c478bd9Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
5587c478bd9Sstevel@tonic-gate 		curnp = namep->namep;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		/* get the unit structure */
5617c478bd9Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
5627c478bd9Sstevel@tonic-gate 			continue;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		/*
5657c478bd9Sstevel@tonic-gate 		 * If the current soft partition is not on the same
5667c478bd9Sstevel@tonic-gate 		 * component, continue the search.  If it is on the same
5677c478bd9Sstevel@tonic-gate 		 * component, add it to our namelist.
5687c478bd9Sstevel@tonic-gate 		 */
5697c478bd9Sstevel@tonic-gate 		err = meta_check_samedrive(compnp, msp->compnamep, ep);
5707c478bd9Sstevel@tonic-gate 		if (err <= 0) {
5717c478bd9Sstevel@tonic-gate 			/* not on the same device, check the next one */
5727c478bd9Sstevel@tonic-gate 			continue;
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/* it's on the same drive */
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 		/*
5787c478bd9Sstevel@tonic-gate 		 * Check for overlapping partitions if the component is not
5797c478bd9Sstevel@tonic-gate 		 * a metadevice.
5807c478bd9Sstevel@tonic-gate 		 */
5817c478bd9Sstevel@tonic-gate 		if (!metaismeta(msp->compnamep)) {
5827c478bd9Sstevel@tonic-gate 			/*
5837c478bd9Sstevel@tonic-gate 			 * if they're on the same drive, neither
5847c478bd9Sstevel@tonic-gate 			 * should be a metadevice if one isn't
5857c478bd9Sstevel@tonic-gate 			 */
5867c478bd9Sstevel@tonic-gate 			assert(!metaismeta(compnp));
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 			if (meta_check_overlap(msp->compnamep->cname,
5897c478bd9Sstevel@tonic-gate 			    compnp, 0, -1, msp->compnamep, 0, -1, ep) == 0)
5907c478bd9Sstevel@tonic-gate 				continue;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 			/* in this case it's not an error for them to overlap */
5937c478bd9Sstevel@tonic-gate 			mdclrerror(ep);
5947c478bd9Sstevel@tonic-gate 		}
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 		/* Component is on the same device, add to the used list */
5977c478bd9Sstevel@tonic-gate 		tailpp = meta_namelist_append_wrapper(tailpp, curnp);
5987c478bd9Sstevel@tonic-gate 		cachetailpp = meta_namelist_append_wrapper(cachetailpp,
5997c478bd9Sstevel@tonic-gate 		    curnp);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 		++count;
6027c478bd9Sstevel@tonic-gate 		++cached_count;
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	assert(count == cached_count);
6067c478bd9Sstevel@tonic-gate 	return (count);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate out:
6097c478bd9Sstevel@tonic-gate 	metafreenamelist(*nlpp);
6107c478bd9Sstevel@tonic-gate 	*nlpp = NULL;
6117c478bd9Sstevel@tonic-gate 	return (-1);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate  * FUNCTION:    meta_sp_get_default_alignment()
6167c478bd9Sstevel@tonic-gate  * INPUT:       sp      - the pertinent set name
6177c478bd9Sstevel@tonic-gate  *              compnp  - the name of the underlying component
6187c478bd9Sstevel@tonic-gate  * OUTPUT:      ep      - return error pointer
6197c478bd9Sstevel@tonic-gate  * RETURNS:     sp_ext_length_t =0: no default alignment
6207c478bd9Sstevel@tonic-gate  *                              >0: default alignment
6217c478bd9Sstevel@tonic-gate  * PURPOSE:     returns the default alignment for soft partitions to
6227c478bd9Sstevel@tonic-gate  *              be built on top of the specified component or
6237c478bd9Sstevel@tonic-gate  *              metadevice
6247c478bd9Sstevel@tonic-gate  */
6257c478bd9Sstevel@tonic-gate static sp_ext_length_t
meta_sp_get_default_alignment(mdsetname_t * sp,mdname_t * compnp,md_error_t * ep)6267c478bd9Sstevel@tonic-gate meta_sp_get_default_alignment(
6277c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
6287c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
6297c478bd9Sstevel@tonic-gate 	md_error_t	*ep
6307c478bd9Sstevel@tonic-gate )
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate 	sp_ext_length_t	a = SP_UNALIGNED;
6337c478bd9Sstevel@tonic-gate 	char		*mname;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	assert(compnp != NULL);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/*
6387c478bd9Sstevel@tonic-gate 	 * We treat raw devices as opaque, and assume nothing about
6397c478bd9Sstevel@tonic-gate 	 * their alignment requirements.
6407c478bd9Sstevel@tonic-gate 	 */
6417c478bd9Sstevel@tonic-gate 	if (!metaismeta(compnp))
6427c478bd9Sstevel@tonic-gate 		return (SP_UNALIGNED);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/*
6457c478bd9Sstevel@tonic-gate 	 * We already know it's a metadevice from the previous test;
6467c478bd9Sstevel@tonic-gate 	 * metagetmiscname() will tell us which metadevice type we
6477c478bd9Sstevel@tonic-gate 	 * have
6487c478bd9Sstevel@tonic-gate 	 */
6497c478bd9Sstevel@tonic-gate 	mname = metagetmiscname(compnp, ep);
6507c478bd9Sstevel@tonic-gate 	if (mname == NULL)
6517c478bd9Sstevel@tonic-gate 		goto out;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/*
6547c478bd9Sstevel@tonic-gate 	 * For a mirror, we want to deal with the stripe that is the
6557c478bd9Sstevel@tonic-gate 	 * primary side.  If it happens to be asymmetrically
6567c478bd9Sstevel@tonic-gate 	 * configured, there is no simple way to fake a universal
6577c478bd9Sstevel@tonic-gate 	 * alignment.  There's a chance that the least common
6587c478bd9Sstevel@tonic-gate 	 * denominator of the set of interlaces from all stripes of
6597c478bd9Sstevel@tonic-gate 	 * all submirrors would do it, but nobody that really cared
6607c478bd9Sstevel@tonic-gate 	 * that much about this issue would create an asymmetric
6617c478bd9Sstevel@tonic-gate 	 * config to start with.
6627c478bd9Sstevel@tonic-gate 	 *
6637c478bd9Sstevel@tonic-gate 	 * If the component underlying the soft partition is a mirror,
6647c478bd9Sstevel@tonic-gate 	 * then at the exit of this loop, compnp will have been
6657c478bd9Sstevel@tonic-gate 	 * updated to describe the first active submirror.
6667c478bd9Sstevel@tonic-gate 	 */
6677c478bd9Sstevel@tonic-gate 	if (strcmp(mname, MD_MIRROR) == 0) {
6687c478bd9Sstevel@tonic-gate 		md_mirror_t	*mp;
6697c478bd9Sstevel@tonic-gate 		int		smi;
6707c478bd9Sstevel@tonic-gate 		md_submirror_t	*smp;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		mp = meta_get_mirror(sp, compnp, ep);
6737c478bd9Sstevel@tonic-gate 		if (mp == NULL)
6747c478bd9Sstevel@tonic-gate 			goto out;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		for (smi = 0; smi < NMIRROR; smi++) {
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 			smp = &mp->submirrors[smi];
6797c478bd9Sstevel@tonic-gate 			if (smp->state == SMS_UNUSED)
6807c478bd9Sstevel@tonic-gate 				continue;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 			compnp = smp->submirnamep;
6837c478bd9Sstevel@tonic-gate 			assert(compnp != NULL);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 			mname = metagetmiscname(compnp, ep);
6867c478bd9Sstevel@tonic-gate 			if (mname == NULL)
6877c478bd9Sstevel@tonic-gate 				goto out;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 			break;
6907c478bd9Sstevel@tonic-gate 		}
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 		if (smi == NMIRROR)
6937c478bd9Sstevel@tonic-gate 			goto out;
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * Handle stripes and submirrors identically; just return the
6987c478bd9Sstevel@tonic-gate 	 * interlace of the first row.
6997c478bd9Sstevel@tonic-gate 	 */
7007c478bd9Sstevel@tonic-gate 	if (strcmp(mname, MD_STRIPE) == 0) {
7017c478bd9Sstevel@tonic-gate 		md_stripe_t	*stp;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		stp = meta_get_stripe(sp, compnp, ep);
7047c478bd9Sstevel@tonic-gate 		if (stp == NULL)
7057c478bd9Sstevel@tonic-gate 			goto out;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 		a = stp->rows.rows_val[0].interlace;
7087c478bd9Sstevel@tonic-gate 		goto out;
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	/*
7127c478bd9Sstevel@tonic-gate 	 * Raid is even more straightforward; the interlace applies to
7137c478bd9Sstevel@tonic-gate 	 * the entire device.
7147c478bd9Sstevel@tonic-gate 	 */
7157c478bd9Sstevel@tonic-gate 	if (strcmp(mname, MD_RAID) == 0) {
7167c478bd9Sstevel@tonic-gate 		md_raid_t	*rp;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 		rp = meta_get_raid(sp, compnp, ep);
7197c478bd9Sstevel@tonic-gate 		if (rp == NULL)
7207c478bd9Sstevel@tonic-gate 			goto out;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		a = rp->interlace;
7237c478bd9Sstevel@tonic-gate 		goto out;
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	/*
7277c478bd9Sstevel@tonic-gate 	 * If we have arrived here with the alignment still not set,
7287c478bd9Sstevel@tonic-gate 	 * then we expect the error to have been set by one of the
7297c478bd9Sstevel@tonic-gate 	 * routines we called.  If neither is the case, something has
7307c478bd9Sstevel@tonic-gate 	 * really gone wrong above.  (Probably the submirror walk
7317c478bd9Sstevel@tonic-gate 	 * failed to produce a valid submirror, but that would be
7327c478bd9Sstevel@tonic-gate 	 * really bad...)
7337c478bd9Sstevel@tonic-gate 	 */
7347c478bd9Sstevel@tonic-gate out:
7357c478bd9Sstevel@tonic-gate 	meta_sp_debug("meta_sp_get_default_alignment: miscname %s, "
7367c478bd9Sstevel@tonic-gate 	    "alignment %lld\n", (mname == NULL) ? "NULL" : mname, a);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG) && !mdisok(ep)) {
7397c478bd9Sstevel@tonic-gate 		mde_perror(ep, NULL);
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	assert((a > 0) || (!mdisok(ep)));
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	return (a);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_check_insp()
7517c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to check
7527c478bd9Sstevel@tonic-gate  *		np	- the name of the device to check
7537c478bd9Sstevel@tonic-gate  *		slblk	- the starting offset of the device to check
7547c478bd9Sstevel@tonic-gate  *		nblks	- the number of blocks in the device to check
7557c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
7567c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - device contains soft partitions
7577c478bd9Sstevel@tonic-gate  *			  -1 - device does not contain soft partitions
7587c478bd9Sstevel@tonic-gate  * PURPOSE:	determines whether a device contains any soft partitions
7597c478bd9Sstevel@tonic-gate  */
7607c478bd9Sstevel@tonic-gate /* ARGSUSED */
7617c478bd9Sstevel@tonic-gate int
meta_check_insp(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)7627c478bd9Sstevel@tonic-gate meta_check_insp(
7637c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
7647c478bd9Sstevel@tonic-gate 	mdname_t	*np,
7657c478bd9Sstevel@tonic-gate 	diskaddr_t	slblk,
7667c478bd9Sstevel@tonic-gate 	diskaddr_t	nblks,
7677c478bd9Sstevel@tonic-gate 	md_error_t	*ep
7687c478bd9Sstevel@tonic-gate )
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;	/* soft partition name list */
7717c478bd9Sstevel@tonic-gate 	int		count;
7727c478bd9Sstevel@tonic-gate 	int		rval;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	/* check set pointer */
7757c478bd9Sstevel@tonic-gate 	assert(sp != NULL);
7767c478bd9Sstevel@tonic-gate 
777d7cd8252Stw21770 	/*
778d7cd8252Stw21770 	 * Get a list of the soft partitions that currently reside on
779d7cd8252Stw21770 	 * the component.  We should ALWAYS force reload the cache,
780d7cd8252Stw21770 	 * because if we're using the md.tab, we must rebuild
781d7cd8252Stw21770 	 * the list because it won't contain the previous (if any)
782d7cd8252Stw21770 	 * soft partition.
783d7cd8252Stw21770 	 */
7847c478bd9Sstevel@tonic-gate 	/* find all soft partitions on the component */
785d7cd8252Stw21770 	count = meta_sp_get_by_component(sp, np, &spnlp, 1, ep);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	if (count == -1) {
7887c478bd9Sstevel@tonic-gate 		rval = -1;
7897c478bd9Sstevel@tonic-gate 	} else if (count > 0) {
7907c478bd9Sstevel@tonic-gate 		rval = mduseerror(ep, MDE_ALREADY, np->dev,
7917c478bd9Sstevel@tonic-gate 		    spnlp->namep->cname, np->cname);
7927c478bd9Sstevel@tonic-gate 	} else {
7937c478bd9Sstevel@tonic-gate 		rval = 0;
7947c478bd9Sstevel@tonic-gate 	}
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	metafreenamelist(spnlp);
7977c478bd9Sstevel@tonic-gate 	return (rval);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate  * **************************************************************************
8027c478bd9Sstevel@tonic-gate  *                    Extent List Manipulation Functions                    *
8037c478bd9Sstevel@tonic-gate  * **************************************************************************
8047c478bd9Sstevel@tonic-gate  */
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate /*
8077c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_cmp_by_nameseq()
8087c478bd9Sstevel@tonic-gate  * INPUT:	e1	- first node to compare
8097c478bd9Sstevel@tonic-gate  *		e2	- second node to compare
8107c478bd9Sstevel@tonic-gate  * OUTPUT:	none
8117c478bd9Sstevel@tonic-gate  * RETURNS:	int	- =0 - nodes are equal
8127c478bd9Sstevel@tonic-gate  *			  <0 - e1 should go before e2
8137c478bd9Sstevel@tonic-gate  *			  >0 - e1 should go after e2
8147c478bd9Sstevel@tonic-gate  * PURPOSE:	used for sorted list inserts to build a list sorted by
8157c478bd9Sstevel@tonic-gate  *		name first and sequence number second.
8167c478bd9Sstevel@tonic-gate  */
8177c478bd9Sstevel@tonic-gate static int
meta_sp_cmp_by_nameseq(sp_ext_node_t * e1,sp_ext_node_t * e2)8187c478bd9Sstevel@tonic-gate meta_sp_cmp_by_nameseq(sp_ext_node_t *e1, sp_ext_node_t *e2)
8197c478bd9Sstevel@tonic-gate {
8207c478bd9Sstevel@tonic-gate 	int rval;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	if (e1->ext_namep == NULL)
8237c478bd9Sstevel@tonic-gate 		return (1);
8247c478bd9Sstevel@tonic-gate 	if (e2->ext_namep == NULL)
8257c478bd9Sstevel@tonic-gate 		return (-1);
8267c478bd9Sstevel@tonic-gate 	if ((rval = strcmp(e1->ext_namep->cname, e2->ext_namep->cname)) != 0)
8277c478bd9Sstevel@tonic-gate 		return (rval);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	/* the names are equal, compare sequence numbers */
8307c478bd9Sstevel@tonic-gate 	if (e1->ext_seq > e2->ext_seq)
8317c478bd9Sstevel@tonic-gate 		return (1);
8327c478bd9Sstevel@tonic-gate 	if (e1->ext_seq < e2->ext_seq)
8337c478bd9Sstevel@tonic-gate 		return (-1);
8347c478bd9Sstevel@tonic-gate 	/* sequence numbers are also equal */
8357c478bd9Sstevel@tonic-gate 	return (0);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_cmp_by_offset()
8407c478bd9Sstevel@tonic-gate  * INPUT:	e1	- first node to compare
8417c478bd9Sstevel@tonic-gate  *		e2	- second node to compare
8427c478bd9Sstevel@tonic-gate  * OUTPUT:	none
8437c478bd9Sstevel@tonic-gate  * RETURNS:	int	- =0 - nodes are equal
8447c478bd9Sstevel@tonic-gate  *			  <0 - e1 should go before e2
8457c478bd9Sstevel@tonic-gate  *			  >0 - e1 should go after e2
8467c478bd9Sstevel@tonic-gate  * PURPOSE:	used for sorted list inserts to build a list sorted by offset
8477c478bd9Sstevel@tonic-gate  */
8487c478bd9Sstevel@tonic-gate static int
meta_sp_cmp_by_offset(sp_ext_node_t * e1,sp_ext_node_t * e2)8497c478bd9Sstevel@tonic-gate meta_sp_cmp_by_offset(sp_ext_node_t *e1, sp_ext_node_t *e2)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate 	if (e1->ext_offset > e2->ext_offset)
8527c478bd9Sstevel@tonic-gate 		return (1);
8537c478bd9Sstevel@tonic-gate 	if (e1->ext_offset < e2->ext_offset)
8547c478bd9Sstevel@tonic-gate 		return (-1);
8557c478bd9Sstevel@tonic-gate 	/* offsets are equal */
8567c478bd9Sstevel@tonic-gate 	return (0);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_insert()
8617c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
8627c478bd9Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
8637c478bd9Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
8647c478bd9Sstevel@tonic-gate  *		offset	- the physical offset of this extent in sectors
8657c478bd9Sstevel@tonic-gate  *		length	- the length of this extent in sectors
8667c478bd9Sstevel@tonic-gate  *		type	- the type of the extent being inserted
8677c478bd9Sstevel@tonic-gate  *		seq	- the sequence number of the extent being inserted
8687c478bd9Sstevel@tonic-gate  *		flags	- extent flags (eg. whether it needs to be updated)
8697c478bd9Sstevel@tonic-gate  *		compare	- the compare function to use
8707c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- points to the new head if a node was inserted
8717c478bd9Sstevel@tonic-gate  *			  at the beginning
8727c478bd9Sstevel@tonic-gate  * RETURNS:	void
8737c478bd9Sstevel@tonic-gate  * PURPOSE:	inserts an extent node into a sorted doubly linked list.
8747c478bd9Sstevel@tonic-gate  *		The sort order is determined by the compare function.
8757c478bd9Sstevel@tonic-gate  *		Memory is allocated for the node in this function and it
8767c478bd9Sstevel@tonic-gate  *		is up to the caller to free it, possibly using
8777c478bd9Sstevel@tonic-gate  *		meta_sp_list_free().  If a node is inserted at the
8787c478bd9Sstevel@tonic-gate  *		beginning of the list, the head pointer is updated to
8797c478bd9Sstevel@tonic-gate  *		point to the new first node.
8807c478bd9Sstevel@tonic-gate  */
8817c478bd9Sstevel@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)8827c478bd9Sstevel@tonic-gate meta_sp_list_insert(
8837c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
8847c478bd9Sstevel@tonic-gate 	mdname_t	*np,
8857c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**head,
8867c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	offset,
8877c478bd9Sstevel@tonic-gate 	sp_ext_length_t	length,
8887c478bd9Sstevel@tonic-gate 	sp_ext_type_t	type,
8897c478bd9Sstevel@tonic-gate 	uint_t		seq,
8907c478bd9Sstevel@tonic-gate 	uint_t		flags,
8917c478bd9Sstevel@tonic-gate 	ext_cmpfunc_t	compare
8927c478bd9Sstevel@tonic-gate )
8937c478bd9Sstevel@tonic-gate {
8947c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*newext;
8957c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*curext;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	assert(head != NULL);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	/* Don't bother adding zero length nodes */
9007c478bd9Sstevel@tonic-gate 	if (length == 0ULL)
9017c478bd9Sstevel@tonic-gate 		return;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* allocate and fill in new ext_node */
9047c478bd9Sstevel@tonic-gate 	newext = Zalloc(sizeof (sp_ext_node_t));
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	newext->ext_offset = offset;
9077c478bd9Sstevel@tonic-gate 	newext->ext_length = length;
9087c478bd9Sstevel@tonic-gate 	newext->ext_flags = flags;
9097c478bd9Sstevel@tonic-gate 	newext->ext_type = type;
9107c478bd9Sstevel@tonic-gate 	newext->ext_seq = seq;
9117c478bd9Sstevel@tonic-gate 	newext->ext_setp = sp;
9127c478bd9Sstevel@tonic-gate 	newext->ext_namep = np;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/* first node in the list */
9157c478bd9Sstevel@tonic-gate 	if (*head == NULL) {
9167c478bd9Sstevel@tonic-gate 		newext->ext_next = newext->ext_prev = NULL;
9177c478bd9Sstevel@tonic-gate 		*head = newext;
9187c478bd9Sstevel@tonic-gate 	} else if ((*compare)(*head, newext) >= 0) {
9197c478bd9Sstevel@tonic-gate 		/* the first node has a bigger offset, so insert before it */
9207c478bd9Sstevel@tonic-gate 		assert((*head)->ext_prev == NULL);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 		newext->ext_prev = NULL;
9237c478bd9Sstevel@tonic-gate 		newext->ext_next = *head;
9247c478bd9Sstevel@tonic-gate 		(*head)->ext_prev = newext;
9257c478bd9Sstevel@tonic-gate 		*head = newext;
9267c478bd9Sstevel@tonic-gate 	} else {
9277c478bd9Sstevel@tonic-gate 		/*
9287c478bd9Sstevel@tonic-gate 		 * find the next node whose offset is greater than
9297c478bd9Sstevel@tonic-gate 		 * the one we want to insert, or the end of the list.
9307c478bd9Sstevel@tonic-gate 		 */
9317c478bd9Sstevel@tonic-gate 		for (curext = *head;
9327c478bd9Sstevel@tonic-gate 		    (curext->ext_next != NULL) &&
9337c478bd9Sstevel@tonic-gate 		    ((*compare)(curext->ext_next, newext) < 0);
9347c478bd9Sstevel@tonic-gate 		    (curext = curext->ext_next))
9357c478bd9Sstevel@tonic-gate 			;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 		/* link the new node in after the current node */
9387c478bd9Sstevel@tonic-gate 		newext->ext_next = curext->ext_next;
9397c478bd9Sstevel@tonic-gate 		newext->ext_prev = curext;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		if (curext->ext_next != NULL)
9427c478bd9Sstevel@tonic-gate 			curext->ext_next->ext_prev = newext;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 		curext->ext_next = newext;
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate /*
9497c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_free()
9507c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
9517c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- points to NULL on return
9527c478bd9Sstevel@tonic-gate  * RETURNS:	void
9537c478bd9Sstevel@tonic-gate  * PURPOSE:	walks a double linked extent list and frees each node
9547c478bd9Sstevel@tonic-gate  */
9557c478bd9Sstevel@tonic-gate static void
meta_sp_list_free(sp_ext_node_t ** head)9567c478bd9Sstevel@tonic-gate meta_sp_list_free(sp_ext_node_t **head)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
9597c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*next;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	assert(head != NULL);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	ext = *head;
9647c478bd9Sstevel@tonic-gate 	while (ext) {
9657c478bd9Sstevel@tonic-gate 		next = ext->ext_next;
9667c478bd9Sstevel@tonic-gate 		Free(ext);
9677c478bd9Sstevel@tonic-gate 		ext = next;
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 	*head = NULL;
9707c478bd9Sstevel@tonic-gate }
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate /*
9737c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_remove()
9747c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
9757c478bd9Sstevel@tonic-gate  *		ext	- the extent to remove, must be a member of the list
9767c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- points to the new head of the list
9777c478bd9Sstevel@tonic-gate  * RETURNS:	void
9787c478bd9Sstevel@tonic-gate  * PURPOSE:	unlinks the node specified by ext from the list and
9797c478bd9Sstevel@tonic-gate  *		frees it, possibly moving the head pointer forward if
9807c478bd9Sstevel@tonic-gate  *		the head is the node being removed.
9817c478bd9Sstevel@tonic-gate  */
9827c478bd9Sstevel@tonic-gate static void
meta_sp_list_remove(sp_ext_node_t ** head,sp_ext_node_t * ext)9837c478bd9Sstevel@tonic-gate meta_sp_list_remove(sp_ext_node_t **head, sp_ext_node_t *ext)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate 	assert(head != NULL);
9867c478bd9Sstevel@tonic-gate 	assert(*head != NULL);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	if (*head == ext)
9897c478bd9Sstevel@tonic-gate 		*head = ext->ext_next;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	if (ext->ext_prev != NULL)
9927c478bd9Sstevel@tonic-gate 		ext->ext_prev->ext_next = ext->ext_next;
9937c478bd9Sstevel@tonic-gate 	if (ext->ext_next != NULL)
9947c478bd9Sstevel@tonic-gate 		ext->ext_next->ext_prev = ext->ext_prev;
9957c478bd9Sstevel@tonic-gate 	Free(ext);
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_size()
10007c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
10017c478bd9Sstevel@tonic-gate  *		exttype	- the type of the extents to sum
10027c478bd9Sstevel@tonic-gate  *		exclude_wm - subtract space for extent headers from total
10037c478bd9Sstevel@tonic-gate  * OUTPUT:	none
10047c478bd9Sstevel@tonic-gate  * RETURNS:	sp_ext_length_t	- the sum of all of the lengths
10057c478bd9Sstevel@tonic-gate  * PURPOSE:	sums the lengths of all extents in the list matching the
10067c478bd9Sstevel@tonic-gate  *		specified type.  This could be used for computing the
10077c478bd9Sstevel@tonic-gate  *		amount of free or used space, for example.
10087c478bd9Sstevel@tonic-gate  */
10097c478bd9Sstevel@tonic-gate static sp_ext_length_t
meta_sp_list_size(sp_ext_node_t * head,sp_ext_type_t exttype,int exclude_wm)10107c478bd9Sstevel@tonic-gate meta_sp_list_size(sp_ext_node_t *head, sp_ext_type_t exttype, int exclude_wm)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
10137c478bd9Sstevel@tonic-gate 	sp_ext_length_t	size = 0LL;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next)
10167c478bd9Sstevel@tonic-gate 		if (ext->ext_type == exttype)
10177c478bd9Sstevel@tonic-gate 			size += ext->ext_length -
10187c478bd9Sstevel@tonic-gate 			    ((exclude_wm) ? MD_SP_WMSIZE : 0);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	return (size);
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate /*
10247c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_find()
10257c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
10267c478bd9Sstevel@tonic-gate  *		offset	- the offset contained by the node to find
10277c478bd9Sstevel@tonic-gate  * OUTPUT:	none
10287c478bd9Sstevel@tonic-gate  * RETURNS:	sp_ext_node_t *	- the node containing the requested offset
10297c478bd9Sstevel@tonic-gate  *				  or NULL if no such nodes were found.
10307c478bd9Sstevel@tonic-gate  * PURPOSE:	finds a node in a list containing the requested offset
10317c478bd9Sstevel@tonic-gate  *		(inclusive).  If multiple nodes contain this offset then
10327c478bd9Sstevel@tonic-gate  *		only the first will be returned, though typically these
10337c478bd9Sstevel@tonic-gate  *		lists are managed with non-overlapping nodes.
10347c478bd9Sstevel@tonic-gate  *
10357c478bd9Sstevel@tonic-gate  *		*The list MUST be sorted by offset for this function to work.*
10367c478bd9Sstevel@tonic-gate  */
10377c478bd9Sstevel@tonic-gate static sp_ext_node_t *
meta_sp_list_find(sp_ext_node_t * head,sp_ext_offset_t offset)10387c478bd9Sstevel@tonic-gate meta_sp_list_find(
10397c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*head,
10407c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	offset
10417c478bd9Sstevel@tonic-gate )
10427c478bd9Sstevel@tonic-gate {
10437c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next) {
10467c478bd9Sstevel@tonic-gate 		/* check if the offset lies within this extent */
10477c478bd9Sstevel@tonic-gate 		if ((offset >= ext->ext_offset) &&
10487c478bd9Sstevel@tonic-gate 		    (offset < ext->ext_offset + ext->ext_length)) {
10497c478bd9Sstevel@tonic-gate 			/*
10507c478bd9Sstevel@tonic-gate 			 * the requested extent should always be a
10517c478bd9Sstevel@tonic-gate 			 * subset of an extent in the list.
10527c478bd9Sstevel@tonic-gate 			 */
10537c478bd9Sstevel@tonic-gate 			return (ext);
10547c478bd9Sstevel@tonic-gate 		}
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 	return (NULL);
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate /*
10607c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_freefill()
10617c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
10627c478bd9Sstevel@tonic-gate  *		size	- the size of the volume this extent list is
10637c478bd9Sstevel@tonic-gate  *			  representing
10647c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- the new head of the list
10657c478bd9Sstevel@tonic-gate  * RETURNS:	void
10667c478bd9Sstevel@tonic-gate  * PURPOSE:	finds gaps in the extent list and fills them with a free
10677c478bd9Sstevel@tonic-gate  *		node.  If there is a gap at the beginning the head
10687c478bd9Sstevel@tonic-gate  *		pointer will be changed to point to the new free node.
10697c478bd9Sstevel@tonic-gate  *		If there is free space at the end, the last free extent
10707c478bd9Sstevel@tonic-gate  *		will extend all the way out to the size specified.
10717c478bd9Sstevel@tonic-gate  *
10727c478bd9Sstevel@tonic-gate  *		*The list MUST be sorted by offset for this function to work.*
10737c478bd9Sstevel@tonic-gate  */
10747c478bd9Sstevel@tonic-gate static void
meta_sp_list_freefill(sp_ext_node_t ** head,sp_ext_length_t size)10757c478bd9Sstevel@tonic-gate meta_sp_list_freefill(
10767c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**head,
10777c478bd9Sstevel@tonic-gate 	sp_ext_length_t	size
10787c478bd9Sstevel@tonic-gate )
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
10817c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	curoff = 0LL;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	for (ext = *head; ext != NULL; ext = ext->ext_next) {
10847c478bd9Sstevel@tonic-gate 		if (curoff < ext->ext_offset)
10857c478bd9Sstevel@tonic-gate 			meta_sp_list_insert(NULL, NULL, head,
10867c478bd9Sstevel@tonic-gate 			    curoff, ext->ext_offset - curoff,
10877c478bd9Sstevel@tonic-gate 			    EXTTYP_FREE, 0, 0, meta_sp_cmp_by_offset);
10887c478bd9Sstevel@tonic-gate 		curoff = ext->ext_offset + ext->ext_length;
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	/* pad inverse list out to the end */
10927c478bd9Sstevel@tonic-gate 	if (curoff < size)
10937c478bd9Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, curoff, size - curoff,
10947c478bd9Sstevel@tonic-gate 		    EXTTYP_FREE, 0, 0, meta_sp_cmp_by_offset);
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
10977c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_list_freefill: Extent list with "
10987c478bd9Sstevel@tonic-gate 		    "holes freefilled:\n");
10997c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(*head);
11007c478bd9Sstevel@tonic-gate 	}
11017c478bd9Sstevel@tonic-gate }
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate /*
11047c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_dump()
11057c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
11067c478bd9Sstevel@tonic-gate  * OUTPUT:	none
11077c478bd9Sstevel@tonic-gate  * RETURNS:	void
11087c478bd9Sstevel@tonic-gate  * PURPOSE:	dumps the entire extent list to stdout for easy debugging
11097c478bd9Sstevel@tonic-gate  */
11107c478bd9Sstevel@tonic-gate static void
meta_sp_list_dump(sp_ext_node_t * head)11117c478bd9Sstevel@tonic-gate meta_sp_list_dump(sp_ext_node_t *head)
11127c478bd9Sstevel@tonic-gate {
11137c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	meta_sp_debug("meta_sp_list_dump: dumping extent list:\n");
11167c478bd9Sstevel@tonic-gate 	meta_sp_debug("%5s %10s %5s %7s %10s %10s %5s %10s %10s\n", "Name",
11177c478bd9Sstevel@tonic-gate 	    "Addr", "Seq#", "Type", "Offset", "Length", "Flags", "Prev",
11187c478bd9Sstevel@tonic-gate 	    "Next");
11197c478bd9Sstevel@tonic-gate 	for (ext = head; ext != NULL; ext = ext->ext_next) {
11207c478bd9Sstevel@tonic-gate 		if (ext->ext_namep != NULL)
11217c478bd9Sstevel@tonic-gate 			meta_sp_debug("%5s", ext->ext_namep->cname);
11227c478bd9Sstevel@tonic-gate 		else
11237c478bd9Sstevel@tonic-gate 			meta_sp_debug("%5s", "NONE");
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		meta_sp_debug("%10p %5u ", (void *) ext, ext->ext_seq);
11267c478bd9Sstevel@tonic-gate 		switch (ext->ext_type) {
11277c478bd9Sstevel@tonic-gate 		case EXTTYP_ALLOC:
11287c478bd9Sstevel@tonic-gate 			meta_sp_debug("%7s ", "ALLOC");
11297c478bd9Sstevel@tonic-gate 			break;
11307c478bd9Sstevel@tonic-gate 		case EXTTYP_FREE:
11317c478bd9Sstevel@tonic-gate 			meta_sp_debug("%7s ", "FREE");
11327c478bd9Sstevel@tonic-gate 			break;
11337c478bd9Sstevel@tonic-gate 		case EXTTYP_END:
11347c478bd9Sstevel@tonic-gate 			meta_sp_debug("%7s ", "END");
11357c478bd9Sstevel@tonic-gate 			break;
11367c478bd9Sstevel@tonic-gate 		case EXTTYP_RESERVED:
11377c478bd9Sstevel@tonic-gate 			meta_sp_debug("%7s ", "RESV");
11387c478bd9Sstevel@tonic-gate 			break;
11397c478bd9Sstevel@tonic-gate 		default:
11407c478bd9Sstevel@tonic-gate 			meta_sp_debug("%7s ", "INVLD");
11417c478bd9Sstevel@tonic-gate 			break;
11427c478bd9Sstevel@tonic-gate 		}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 		meta_sp_debug("%10llu %10llu %5u %10p %10p\n",
11457c478bd9Sstevel@tonic-gate 		    ext->ext_offset, ext->ext_length,
11467c478bd9Sstevel@tonic-gate 		    ext->ext_flags, (void *) ext->ext_prev,
11477c478bd9Sstevel@tonic-gate 		    (void *) ext->ext_next);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 	meta_sp_debug("\n");
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate /*
11537c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_list_overlaps()
11547c478bd9Sstevel@tonic-gate  * INPUT:	head	- the head of the list, must be NULL for empty list
11557c478bd9Sstevel@tonic-gate  * OUTPUT:	none
11567c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 1 if extents overlap, 0 if ok
11577c478bd9Sstevel@tonic-gate  * PURPOSE:	checks a list for overlaps.  The list MUST be sorted by
11587c478bd9Sstevel@tonic-gate  *		offset for this function to work properly.
11597c478bd9Sstevel@tonic-gate  */
11607c478bd9Sstevel@tonic-gate static int
meta_sp_list_overlaps(sp_ext_node_t * head)11617c478bd9Sstevel@tonic-gate meta_sp_list_overlaps(sp_ext_node_t *head)
11627c478bd9Sstevel@tonic-gate {
11637c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	for (ext = head; ext->ext_next != NULL; ext = ext->ext_next) {
11667c478bd9Sstevel@tonic-gate 		if (ext->ext_offset + ext->ext_length >
11677c478bd9Sstevel@tonic-gate 		    ext->ext_next->ext_offset)
11687c478bd9Sstevel@tonic-gate 			return (1);
11697c478bd9Sstevel@tonic-gate 	}
11707c478bd9Sstevel@tonic-gate 	return (0);
11717c478bd9Sstevel@tonic-gate }
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate /*
11747c478bd9Sstevel@tonic-gate  * **************************************************************************
11757c478bd9Sstevel@tonic-gate  *                        Extent Allocation Functions                       *
11767c478bd9Sstevel@tonic-gate  * **************************************************************************
11777c478bd9Sstevel@tonic-gate  */
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate /*
11807c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_ext()
11817c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
11827c478bd9Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
11837c478bd9Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
11847c478bd9Sstevel@tonic-gate  *		free_ext	- the free extent being allocated from
11857c478bd9Sstevel@tonic-gate  *		alloc_offset	- the offset of the allocation
11867c478bd9Sstevel@tonic-gate  *		alloc_len	- the length of the allocation
11877c478bd9Sstevel@tonic-gate  *		seq		- the sequence number of the allocation
11887c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
11897c478bd9Sstevel@tonic-gate  * RETURNS:	void
11907c478bd9Sstevel@tonic-gate  * PURPOSE:	allocates a portion of the free extent free_ext.  The
11917c478bd9Sstevel@tonic-gate  *		allocated portion starts at alloc_offset and is
11927c478bd9Sstevel@tonic-gate  *		alloc_length long.  Both (alloc_offset) and (alloc_offset +
11937c478bd9Sstevel@tonic-gate  *		alloc_length) must be contained within the free extent.
11947c478bd9Sstevel@tonic-gate  *
11957c478bd9Sstevel@tonic-gate  *		The free extent is split into as many as 3 pieces - a
11967c478bd9Sstevel@tonic-gate  *		free extent containing [ free_offset .. alloc_offset ), an
11977c478bd9Sstevel@tonic-gate  *		allocated extent containing the range [ alloc_offset ..
11987c478bd9Sstevel@tonic-gate  *		alloc_end ], and another free extent containing the
11997c478bd9Sstevel@tonic-gate  *		range ( alloc_end .. free_end ].  If either of the two
12007c478bd9Sstevel@tonic-gate  *		new free extents would be zero length, they are not created.
12017c478bd9Sstevel@tonic-gate  *
12027c478bd9Sstevel@tonic-gate  *		Finally, the original free extent is removed.  All newly
12037c478bd9Sstevel@tonic-gate  *		created extents have the EXTFLG_UPDATE flag set.
12047c478bd9Sstevel@tonic-gate  */
12057c478bd9Sstevel@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)12067c478bd9Sstevel@tonic-gate meta_sp_alloc_by_ext(
12077c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
12087c478bd9Sstevel@tonic-gate 	mdname_t	*np,
12097c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**head,
12107c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*free_ext,
12117c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	alloc_offset,
12127c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alloc_length,
12137c478bd9Sstevel@tonic-gate 	uint_t		seq
12147c478bd9Sstevel@tonic-gate )
12157c478bd9Sstevel@tonic-gate {
12167c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	free_offset = free_ext->ext_offset;
12177c478bd9Sstevel@tonic-gate 	sp_ext_length_t	free_length = free_ext->ext_length;
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	alloc_end = alloc_offset + alloc_length;
12207c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	free_end  = free_offset  + free_length;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	/* allocated extent must be a subset of the free extent */
12237c478bd9Sstevel@tonic-gate 	assert(free_offset <= alloc_offset);
12247c478bd9Sstevel@tonic-gate 	assert(free_end >= alloc_end);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	meta_sp_list_remove(head, free_ext);
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	if (free_offset < alloc_offset) {
12297c478bd9Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, free_offset,
12307c478bd9Sstevel@tonic-gate 		    (alloc_offset - free_offset), EXTTYP_FREE, 0,
12317c478bd9Sstevel@tonic-gate 		    EXTFLG_UPDATE, meta_sp_cmp_by_offset);
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	if (free_end > alloc_end) {
12357c478bd9Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, head, alloc_end,
12367c478bd9Sstevel@tonic-gate 		    (free_end - alloc_end), EXTTYP_FREE, 0, EXTFLG_UPDATE,
12377c478bd9Sstevel@tonic-gate 		    meta_sp_cmp_by_offset);
12387c478bd9Sstevel@tonic-gate 	}
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(sp, np, head, alloc_offset, alloc_length,
12417c478bd9Sstevel@tonic-gate 	    EXTTYP_ALLOC, seq, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
12447c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_ext: extent list:\n");
12457c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(*head);
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate }
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate /*
12507c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_len()
12517c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
12527c478bd9Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
12537c478bd9Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
12547c478bd9Sstevel@tonic-gate  *		*lp	- the requested length to allocate
12557c478bd9Sstevel@tonic-gate  *		last_off	- the last offset already allocated.
12567c478bd9Sstevel@tonic-gate  *		alignment	- the desired extent alignmeent
12577c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
12587c478bd9Sstevel@tonic-gate  *		*lp	- the length allocated
12597c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, the number of new extents on success
12607c478bd9Sstevel@tonic-gate  * PURPOSE:	allocates extents from free space to satisfy the requested
12617c478bd9Sstevel@tonic-gate  *		length.  If requested length is zero, allocates all
12627c478bd9Sstevel@tonic-gate  *		remaining free space.  This function provides the meat
12637c478bd9Sstevel@tonic-gate  *		of the extent allocation algorithm.  Allocation is a
12647c478bd9Sstevel@tonic-gate  *		three tier process:
12657c478bd9Sstevel@tonic-gate  *
12667c478bd9Sstevel@tonic-gate  *		1. If last_off is nonzero and there is free space following
12677c478bd9Sstevel@tonic-gate  *		   that node, then it is extended to allocate as much of that
12687c478bd9Sstevel@tonic-gate  *		   free space as possible.  This is useful for metattach.
12697c478bd9Sstevel@tonic-gate  *		2. If a free extent can be found to satisfy the remaining
12707c478bd9Sstevel@tonic-gate  *		   requested space, then satisfy the rest of the request
12717c478bd9Sstevel@tonic-gate  *		   from that extent.
12727c478bd9Sstevel@tonic-gate  *		3. Start allocating space from any remaining free extents until
12737c478bd9Sstevel@tonic-gate  *		   the remainder of the request is satisified.
12747c478bd9Sstevel@tonic-gate  *
12757c478bd9Sstevel@tonic-gate  *              If alignment is non-zero, then every extent modified
12767c478bd9Sstevel@tonic-gate  *              or newly allocated will be aligned modulo alignment,
12777c478bd9Sstevel@tonic-gate  *              with a length that is an integer multiple of
12787c478bd9Sstevel@tonic-gate  *              alignment.
12797c478bd9Sstevel@tonic-gate  *
12807c478bd9Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is set for all nodes (free and
12817c478bd9Sstevel@tonic-gate  *		allocated) that require updated watermarks.
12827c478bd9Sstevel@tonic-gate  *
12837c478bd9Sstevel@tonic-gate  *		This algorithm may have a negative impact on fragmentation
12847c478bd9Sstevel@tonic-gate  *		in pathological cases and may be improved if it turns out
12857c478bd9Sstevel@tonic-gate  *		to be a problem.  This may be exacerbated by particularly
12867c478bd9Sstevel@tonic-gate  *		large alignments.
12877c478bd9Sstevel@tonic-gate  *
12887c478bd9Sstevel@tonic-gate  * NOTE:	It's confusing, so it demands an explanation:
12897c478bd9Sstevel@tonic-gate  *		- len is used to represent requested data space; it
12907c478bd9Sstevel@tonic-gate  *		  does not include room for a watermark.  On each full
12917c478bd9Sstevel@tonic-gate  *		  or partial allocation, len will be decremented by
12927c478bd9Sstevel@tonic-gate  *		  alloc_len (see next paragraph) until it reaches
12937c478bd9Sstevel@tonic-gate  *		  zero.
12947c478bd9Sstevel@tonic-gate  *		- alloc_len is used to represent data space allocated
12957c478bd9Sstevel@tonic-gate  *		  from a particular extent; it does not include space
12967c478bd9Sstevel@tonic-gate  *		  for a watermark.  In the rare event that a_length
12977c478bd9Sstevel@tonic-gate  *		  (see next paragraph) is equal to MD_SP_WMSIZE,
12987c478bd9Sstevel@tonic-gate  *		  alloc_len will be zero and the resulting MD_SP_WMSIZE
12997c478bd9Sstevel@tonic-gate  *		  fragment of space will be utterly unusable.
13007c478bd9Sstevel@tonic-gate  *		- a_length is used to represent all space to be
13017c478bd9Sstevel@tonic-gate  *		  allocated from a particular extent; it DOES include
13027c478bd9Sstevel@tonic-gate  *		  space for a watermark.
13037c478bd9Sstevel@tonic-gate  */
13047c478bd9Sstevel@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)13057c478bd9Sstevel@tonic-gate meta_sp_alloc_by_len(
13067c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
13077c478bd9Sstevel@tonic-gate 	mdname_t	*np,
13087c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**head,
13097c478bd9Sstevel@tonic-gate 	sp_ext_length_t	*lp,
13107c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	last_off,
13117c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	alignment
13127c478bd9Sstevel@tonic-gate )
13137c478bd9Sstevel@tonic-gate {
13147c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*free_ext;
13157c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*alloc_ext;
13167c478bd9Sstevel@tonic-gate 	uint_t		last_seq = 0;
13177c478bd9Sstevel@tonic-gate 	uint_t		numexts = 0;
13187c478bd9Sstevel@tonic-gate 	sp_ext_length_t	freespace;
13197c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alloc_len;
13207c478bd9Sstevel@tonic-gate 	sp_ext_length_t	len;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	/* We're DOA if we can't read *lp */
13237c478bd9Sstevel@tonic-gate 	assert(lp != NULL);
13247c478bd9Sstevel@tonic-gate 	len = *lp;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	/*
13277c478bd9Sstevel@tonic-gate 	 * Process the nominal case first: we've been given an actual
13287c478bd9Sstevel@tonic-gate 	 * size argument, rather than the literal "all"
13297c478bd9Sstevel@tonic-gate 	 */
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	if (len != 0) {
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 		/*
13347c478bd9Sstevel@tonic-gate 		 * Short circuit the check for free space.  This may
13357c478bd9Sstevel@tonic-gate 		 * tell us we have enough space when we really don't
13367c478bd9Sstevel@tonic-gate 		 * because each extent loses space to a watermark, but
13377c478bd9Sstevel@tonic-gate 		 * it will always tell us there isn't enough space
13387c478bd9Sstevel@tonic-gate 		 * correctly.  Worst case we do some extra work.
13397c478bd9Sstevel@tonic-gate 		 */
13407c478bd9Sstevel@tonic-gate 		freespace = meta_sp_list_size(*head, EXTTYP_FREE,
13417c478bd9Sstevel@tonic-gate 		    INCLUDE_WM);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		if (freespace < len)
13447c478bd9Sstevel@tonic-gate 			return (-1);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 		/*
13477c478bd9Sstevel@tonic-gate 		 * First see if we can extend the last extent for an
13487c478bd9Sstevel@tonic-gate 		 * attach.
13497c478bd9Sstevel@tonic-gate 		 */
13507c478bd9Sstevel@tonic-gate 		if (last_off != 0LL) {
13517c478bd9Sstevel@tonic-gate 			int align = 0;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 			alloc_ext =
13547c478bd9Sstevel@tonic-gate 			    meta_sp_list_find(*head, last_off);
13557c478bd9Sstevel@tonic-gate 			assert(alloc_ext != NULL);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 			/*
13587c478bd9Sstevel@tonic-gate 			 * The offset test reflects the
13597c478bd9Sstevel@tonic-gate 			 * inclusion of the watermark in the extent
13607c478bd9Sstevel@tonic-gate 			 */
13617c478bd9Sstevel@tonic-gate 			align = (alignment > 0) &&
13627c478bd9Sstevel@tonic-gate 			    (((alloc_ext->ext_offset + MD_SP_WMSIZE) %
13637c478bd9Sstevel@tonic-gate 			    alignment) == 0);
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 			/*
13667c478bd9Sstevel@tonic-gate 			 * If we decided not to align here, we should
13677c478bd9Sstevel@tonic-gate 			 * also reset "alignment" so we don't bother
13687c478bd9Sstevel@tonic-gate 			 * later, either.
13697c478bd9Sstevel@tonic-gate 			 */
13707c478bd9Sstevel@tonic-gate 			if (!align) {
13717c478bd9Sstevel@tonic-gate 				alignment = 0;
13727c478bd9Sstevel@tonic-gate 			}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 			last_seq = alloc_ext->ext_seq;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 			free_ext = meta_sp_list_find(*head,
13777c478bd9Sstevel@tonic-gate 			    alloc_ext->ext_offset +
13787c478bd9Sstevel@tonic-gate 			    alloc_ext->ext_length);
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 			/*
13817c478bd9Sstevel@tonic-gate 			 * If a free extent follows our last allocated
13827c478bd9Sstevel@tonic-gate 			 * extent, then remove the last allocated
13837c478bd9Sstevel@tonic-gate 			 * extent and increase the size of the free
13847c478bd9Sstevel@tonic-gate 			 * extent to overlap it, then allocate the
13857c478bd9Sstevel@tonic-gate 			 * total space from the new free extent.
13867c478bd9Sstevel@tonic-gate 			 */
13877c478bd9Sstevel@tonic-gate 			if (free_ext != NULL &&
13887c478bd9Sstevel@tonic-gate 			    free_ext->ext_type == EXTTYP_FREE) {
13897c478bd9Sstevel@tonic-gate 				assert(free_ext->ext_offset ==
13907c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_offset +
13917c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_length);
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 				alloc_len =
13947c478bd9Sstevel@tonic-gate 				    MIN(len, free_ext->ext_length);
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 				if (align && (alloc_len < len)) {
13977c478bd9Sstevel@tonic-gate 					/* No watermark space needed */
13987c478bd9Sstevel@tonic-gate 					alloc_len -= alloc_len % alignment;
13997c478bd9Sstevel@tonic-gate 				}
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 				if (alloc_len > 0) {
14027c478bd9Sstevel@tonic-gate 					free_ext->ext_offset -=
14037c478bd9Sstevel@tonic-gate 					    alloc_ext->ext_length;
14047c478bd9Sstevel@tonic-gate 					free_ext->ext_length +=
14057c478bd9Sstevel@tonic-gate 					    alloc_ext->ext_length;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 					meta_sp_alloc_by_ext(sp, np, head,
14087c478bd9Sstevel@tonic-gate 					    free_ext, free_ext->ext_offset,
14097c478bd9Sstevel@tonic-gate 					    alloc_ext->ext_length + alloc_len,
14107c478bd9Sstevel@tonic-gate 					    last_seq);
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 					/*
14137c478bd9Sstevel@tonic-gate 					 * now remove the original allocated
14147c478bd9Sstevel@tonic-gate 					 * node.  We may have overlapping
14157c478bd9Sstevel@tonic-gate 					 * extents for a short time before
14167c478bd9Sstevel@tonic-gate 					 * this node is removed.
14177c478bd9Sstevel@tonic-gate 					 */
14187c478bd9Sstevel@tonic-gate 					meta_sp_list_remove(head, alloc_ext);
14197c478bd9Sstevel@tonic-gate 					len -= alloc_len;
14207c478bd9Sstevel@tonic-gate 				}
14217c478bd9Sstevel@tonic-gate 			}
14227c478bd9Sstevel@tonic-gate 			last_seq++;
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 		if (len == 0LL)
14267c478bd9Sstevel@tonic-gate 			goto out;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		/*
14297c478bd9Sstevel@tonic-gate 		 * Next, see if we can find a single allocation for
14307c478bd9Sstevel@tonic-gate 		 * the remainder.  This may make fragmentation worse
14317c478bd9Sstevel@tonic-gate 		 * in some cases, but there's no good way to allocate
14327c478bd9Sstevel@tonic-gate 		 * that doesn't have a highly fragmented corner case.
14337c478bd9Sstevel@tonic-gate 		 */
14347c478bd9Sstevel@tonic-gate 		for (free_ext = *head; free_ext != NULL;
14357c478bd9Sstevel@tonic-gate 		    free_ext = free_ext->ext_next) {
14367c478bd9Sstevel@tonic-gate 			sp_ext_offset_t	a_offset;
14377c478bd9Sstevel@tonic-gate 			sp_ext_offset_t	a_length;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 			if (free_ext->ext_type != EXTTYP_FREE)
14407c478bd9Sstevel@tonic-gate 				continue;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 			/*
14437c478bd9Sstevel@tonic-gate 			 * The length test should include space for
14447c478bd9Sstevel@tonic-gate 			 * the watermark
14457c478bd9Sstevel@tonic-gate 			 */
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 			a_offset = free_ext->ext_offset;
14487c478bd9Sstevel@tonic-gate 			a_length = free_ext->ext_length;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 			if (alignment > 0) {
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 				/*
14537c478bd9Sstevel@tonic-gate 				 * Shortcut for extents that have been
14547c478bd9Sstevel@tonic-gate 				 * previously added to pad out the
14557c478bd9Sstevel@tonic-gate 				 * data space
14567c478bd9Sstevel@tonic-gate 				 */
14577c478bd9Sstevel@tonic-gate 				if (a_length < alignment) {
14587c478bd9Sstevel@tonic-gate 					continue;
14597c478bd9Sstevel@tonic-gate 				}
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 				/*
14627c478bd9Sstevel@tonic-gate 				 * Round up so the data space begins
14637c478bd9Sstevel@tonic-gate 				 * on a properly aligned boundary.
14647c478bd9Sstevel@tonic-gate 				 */
14657c478bd9Sstevel@tonic-gate 				a_offset += alignment -
14667c478bd9Sstevel@tonic-gate 				    (a_offset % alignment) - MD_SP_WMSIZE;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 				/*
14697c478bd9Sstevel@tonic-gate 				 * This is only necessary in case the
14707c478bd9Sstevel@tonic-gate 				 * watermark size is ever greater than
14717c478bd9Sstevel@tonic-gate 				 * one.  It'll never happen, of
14727c478bd9Sstevel@tonic-gate 				 * course; we'll get rid of watermarks
14737c478bd9Sstevel@tonic-gate 				 * before we make 'em bigger.
14747c478bd9Sstevel@tonic-gate 				 */
14757c478bd9Sstevel@tonic-gate 				if (a_offset < free_ext->ext_offset) {
14767c478bd9Sstevel@tonic-gate 					a_offset += alignment;
14777c478bd9Sstevel@tonic-gate 				}
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 				/*
14807c478bd9Sstevel@tonic-gate 				 * Adjust the length to account for
14817c478bd9Sstevel@tonic-gate 				 * the space lost above (if any)
14827c478bd9Sstevel@tonic-gate 				 */
14837c478bd9Sstevel@tonic-gate 				a_length -=
14847c478bd9Sstevel@tonic-gate 				    (a_offset - free_ext->ext_offset);
14857c478bd9Sstevel@tonic-gate 			}
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 			if (a_length >= len + MD_SP_WMSIZE) {
14887c478bd9Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
14897c478bd9Sstevel@tonic-gate 				    free_ext, a_offset,
14907c478bd9Sstevel@tonic-gate 				    len + MD_SP_WMSIZE, last_seq);
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 				len = 0LL;
14937c478bd9Sstevel@tonic-gate 				numexts++;
14947c478bd9Sstevel@tonic-gate 				break;
14957c478bd9Sstevel@tonic-gate 			}
14967c478bd9Sstevel@tonic-gate 		}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		if (len == 0LL)
14997c478bd9Sstevel@tonic-gate 			goto out;
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 		/*
15037c478bd9Sstevel@tonic-gate 		 * If the request could not be satisfied by extending
15047c478bd9Sstevel@tonic-gate 		 * the last extent or by a single extent, then put
15057c478bd9Sstevel@tonic-gate 		 * multiple smaller extents together until the request
15067c478bd9Sstevel@tonic-gate 		 * is satisfied.
15077c478bd9Sstevel@tonic-gate 		 */
15087c478bd9Sstevel@tonic-gate 		for (free_ext = *head; (free_ext != NULL) && (len > 0);
15097c478bd9Sstevel@tonic-gate 		    free_ext = free_ext->ext_next) {
15107c478bd9Sstevel@tonic-gate 			sp_ext_offset_t a_offset;
15117c478bd9Sstevel@tonic-gate 			sp_ext_length_t a_length;
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 			if (free_ext->ext_type != EXTTYP_FREE)
15147c478bd9Sstevel@tonic-gate 				continue;
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 			a_offset = free_ext->ext_offset;
15177c478bd9Sstevel@tonic-gate 			a_length = free_ext->ext_length;
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 			if (alignment > 0) {
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 				/*
15227c478bd9Sstevel@tonic-gate 				 * Shortcut for extents that have been
15237c478bd9Sstevel@tonic-gate 				 * previously added to pad out the
15247c478bd9Sstevel@tonic-gate 				 * data space
15257c478bd9Sstevel@tonic-gate 				 */
15267c478bd9Sstevel@tonic-gate 				if (a_length < alignment) {
15277c478bd9Sstevel@tonic-gate 					continue;
15287c478bd9Sstevel@tonic-gate 				}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 				/*
15317c478bd9Sstevel@tonic-gate 				 * Round up so the data space begins
15327c478bd9Sstevel@tonic-gate 				 * on a properly aligned boundary.
15337c478bd9Sstevel@tonic-gate 				 */
15347c478bd9Sstevel@tonic-gate 				a_offset += alignment -
15357c478bd9Sstevel@tonic-gate 				    (a_offset % alignment) - MD_SP_WMSIZE;
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 				/*
15387c478bd9Sstevel@tonic-gate 				 * This is only necessary in case the
15397c478bd9Sstevel@tonic-gate 				 * watermark size is ever greater than
15407c478bd9Sstevel@tonic-gate 				 * one.  It'll never happen, of
15417c478bd9Sstevel@tonic-gate 				 * course; we'll get rid of watermarks
15427c478bd9Sstevel@tonic-gate 				 * before we make 'em bigger.
15437c478bd9Sstevel@tonic-gate 				 */
15447c478bd9Sstevel@tonic-gate 				if (a_offset < free_ext->ext_offset) {
15457c478bd9Sstevel@tonic-gate 					a_offset += alignment;
15467c478bd9Sstevel@tonic-gate 				}
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 				/*
15497c478bd9Sstevel@tonic-gate 				 * Adjust the length to account for
15507c478bd9Sstevel@tonic-gate 				 * the space lost above (if any)
15517c478bd9Sstevel@tonic-gate 				 */
15527c478bd9Sstevel@tonic-gate 				a_length -=
15537c478bd9Sstevel@tonic-gate 				    (a_offset - free_ext->ext_offset);
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 				/*
15567c478bd9Sstevel@tonic-gate 				 * Adjust the length to be properly
15577c478bd9Sstevel@tonic-gate 				 * aligned if it is NOT to be the
15587c478bd9Sstevel@tonic-gate 				 * last extent in the soft partition.
15597c478bd9Sstevel@tonic-gate 				 */
15607c478bd9Sstevel@tonic-gate 				if ((a_length - MD_SP_WMSIZE) < len)
15617c478bd9Sstevel@tonic-gate 					a_length -=
15627c478bd9Sstevel@tonic-gate 					    (a_length - MD_SP_WMSIZE)
15637c478bd9Sstevel@tonic-gate 					    % alignment;
15647c478bd9Sstevel@tonic-gate 			}
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 			alloc_len = MIN(len, a_length - MD_SP_WMSIZE);
15677c478bd9Sstevel@tonic-gate 			if (alloc_len == 0)
15687c478bd9Sstevel@tonic-gate 				continue;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 			/*
15717c478bd9Sstevel@tonic-gate 			 * meta_sp_alloc_by_ext() expects the
15727c478bd9Sstevel@tonic-gate 			 * allocation length to include the watermark
15737c478bd9Sstevel@tonic-gate 			 * size, which is why we don't simply pass in
15747c478bd9Sstevel@tonic-gate 			 * alloc_len here.
15757c478bd9Sstevel@tonic-gate 			 */
15767c478bd9Sstevel@tonic-gate 			meta_sp_alloc_by_ext(sp, np, head, free_ext,
15777c478bd9Sstevel@tonic-gate 			    a_offset, MIN(len + MD_SP_WMSIZE, a_length),
15787c478bd9Sstevel@tonic-gate 			    last_seq);
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 			len -= alloc_len;
15817c478bd9Sstevel@tonic-gate 			numexts++;
15827c478bd9Sstevel@tonic-gate 			last_seq++;
15837c478bd9Sstevel@tonic-gate 		}
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 		/*
15877c478bd9Sstevel@tonic-gate 		 * If there was not enough space we can throw it all
15887c478bd9Sstevel@tonic-gate 		 * away since no real work has been done yet.
15897c478bd9Sstevel@tonic-gate 		 */
15907c478bd9Sstevel@tonic-gate 		if (len != 0) {
15917c478bd9Sstevel@tonic-gate 			meta_sp_list_free(head);
15927c478bd9Sstevel@tonic-gate 			return (-1);
15937c478bd9Sstevel@tonic-gate 		}
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	/*
15977c478bd9Sstevel@tonic-gate 	 * Otherwise, the literal "all" was specified: allocate all
15987c478bd9Sstevel@tonic-gate 	 * available free space.  Don't bother with alignment.
15997c478bd9Sstevel@tonic-gate 	 */
16007c478bd9Sstevel@tonic-gate 	else {
16017c478bd9Sstevel@tonic-gate 		/* First, extend the last extent if this is a grow */
16027c478bd9Sstevel@tonic-gate 		if (last_off != 0LL) {
16037c478bd9Sstevel@tonic-gate 			alloc_ext =
16047c478bd9Sstevel@tonic-gate 			    meta_sp_list_find(*head, last_off);
16057c478bd9Sstevel@tonic-gate 			assert(alloc_ext != NULL);
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 			last_seq = alloc_ext->ext_seq;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 			free_ext = meta_sp_list_find(*head,
16107c478bd9Sstevel@tonic-gate 			    alloc_ext->ext_offset +
16117c478bd9Sstevel@tonic-gate 			    alloc_ext->ext_length);
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 			/*
16147c478bd9Sstevel@tonic-gate 			 * If a free extent follows our last allocated
16157c478bd9Sstevel@tonic-gate 			 * extent, then remove the last allocated
16167c478bd9Sstevel@tonic-gate 			 * extent and increase the size of the free
16177c478bd9Sstevel@tonic-gate 			 * extent to overlap it, then allocate the
16187c478bd9Sstevel@tonic-gate 			 * total space from the new free extent.
16197c478bd9Sstevel@tonic-gate 			 */
16207c478bd9Sstevel@tonic-gate 			if (free_ext != NULL &&
16217c478bd9Sstevel@tonic-gate 			    free_ext->ext_type == EXTTYP_FREE) {
16227c478bd9Sstevel@tonic-gate 				assert(free_ext->ext_offset ==
16237c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_offset +
16247c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_length);
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 				len = alloc_len =
16277c478bd9Sstevel@tonic-gate 				    free_ext->ext_length;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 				free_ext->ext_offset -=
16307c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_length;
16317c478bd9Sstevel@tonic-gate 				free_ext->ext_length +=
16327c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_length;
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
16357c478bd9Sstevel@tonic-gate 				    free_ext, free_ext->ext_offset,
16367c478bd9Sstevel@tonic-gate 				    alloc_ext->ext_length + alloc_len,
16377c478bd9Sstevel@tonic-gate 				    last_seq);
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 				/*
16407c478bd9Sstevel@tonic-gate 				 * now remove the original allocated
16417c478bd9Sstevel@tonic-gate 				 * node.  We may have overlapping
16427c478bd9Sstevel@tonic-gate 				 * extents for a short time before
16437c478bd9Sstevel@tonic-gate 				 * this node is removed.
16447c478bd9Sstevel@tonic-gate 				 */
16457c478bd9Sstevel@tonic-gate 				meta_sp_list_remove(head, alloc_ext);
16467c478bd9Sstevel@tonic-gate 			}
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 			last_seq++;
16497c478bd9Sstevel@tonic-gate 		}
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 		/* Next, grab all remaining free space */
16527c478bd9Sstevel@tonic-gate 		for (free_ext = *head; free_ext != NULL;
16537c478bd9Sstevel@tonic-gate 		    free_ext = free_ext->ext_next) {
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 			if (free_ext->ext_type == EXTTYP_FREE) {
16567c478bd9Sstevel@tonic-gate 				alloc_len =
16577c478bd9Sstevel@tonic-gate 				    free_ext->ext_length - MD_SP_WMSIZE;
16587c478bd9Sstevel@tonic-gate 				if (alloc_len == 0)
16597c478bd9Sstevel@tonic-gate 					continue;
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 				/*
16627c478bd9Sstevel@tonic-gate 				 * meta_sp_alloc_by_ext() expects the
16637c478bd9Sstevel@tonic-gate 				 * allocation length to include the
16647c478bd9Sstevel@tonic-gate 				 * watermark size, which is why we
16657c478bd9Sstevel@tonic-gate 				 * don't simply pass in alloc_len
16667c478bd9Sstevel@tonic-gate 				 * here.
16677c478bd9Sstevel@tonic-gate 				 */
16687c478bd9Sstevel@tonic-gate 				meta_sp_alloc_by_ext(sp, np, head,
16697c478bd9Sstevel@tonic-gate 				    free_ext, free_ext->ext_offset,
16707c478bd9Sstevel@tonic-gate 				    free_ext->ext_length,
16717c478bd9Sstevel@tonic-gate 				    last_seq);
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 				len += alloc_len;
16747c478bd9Sstevel@tonic-gate 				numexts++;
16757c478bd9Sstevel@tonic-gate 				last_seq++;
16767c478bd9Sstevel@tonic-gate 			}
16777c478bd9Sstevel@tonic-gate 		}
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate out:
16817c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
16827c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_len: Extent list after "
16837c478bd9Sstevel@tonic-gate 		    "allocation:\n");
16847c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(*head);
16857c478bd9Sstevel@tonic-gate 	}
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	if (*lp == 0) {
16887c478bd9Sstevel@tonic-gate 		*lp = len;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 		/*
16917c478bd9Sstevel@tonic-gate 		 * Make sure the callers hit a no space error if we
16927c478bd9Sstevel@tonic-gate 		 * didn't actually find anything.
16937c478bd9Sstevel@tonic-gate 		 */
16947c478bd9Sstevel@tonic-gate 		if (len == 0) {
16957c478bd9Sstevel@tonic-gate 			return (-1);
16967c478bd9Sstevel@tonic-gate 		}
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	return (numexts);
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate /*
17037c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_alloc_by_list()
17047c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
17057c478bd9Sstevel@tonic-gate  *		np	- the name of the device the node belongs to
17067c478bd9Sstevel@tonic-gate  *		head	- the head of the list, must be NULL for empty list
17077c478bd9Sstevel@tonic-gate  *		oblist	- an extent list containing requested nodes to allocate
17087c478bd9Sstevel@tonic-gate  * OUTPUT:	head	- the new head pointer
17097c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, the number of new extents on success
17107c478bd9Sstevel@tonic-gate  * PURPOSE:	allocates extents from free space to satisfy the requested
17117c478bd9Sstevel@tonic-gate  *		extent list.  This is primarily used for the -o/-b options
17127c478bd9Sstevel@tonic-gate  *		where the user may specifically request extents to allocate.
17137c478bd9Sstevel@tonic-gate  *		Each extent in the oblist must be a subset (inclusive) of a
17147c478bd9Sstevel@tonic-gate  *		free extent and may not overlap each other.  This
17157c478bd9Sstevel@tonic-gate  *		function sets the EXTFLG_UPDATE flag for each node that
17167c478bd9Sstevel@tonic-gate  *		requires a watermark update after allocating.
17177c478bd9Sstevel@tonic-gate  */
17187c478bd9Sstevel@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)17197c478bd9Sstevel@tonic-gate meta_sp_alloc_by_list(
17207c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
17217c478bd9Sstevel@tonic-gate 	mdname_t	*np,
17227c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**head,
17237c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*oblist
17247c478bd9Sstevel@tonic-gate )
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
17277c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*free_ext;
17287c478bd9Sstevel@tonic-gate 	uint_t		numexts = 0;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	for (ext = oblist; ext != NULL; ext = ext->ext_next) {
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 		free_ext = meta_sp_list_find(*head,
17337c478bd9Sstevel@tonic-gate 		    ext->ext_offset - MD_SP_WMSIZE);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 		/* Make sure the allocation is within the free extent */
17367c478bd9Sstevel@tonic-gate 		if ((free_ext == NULL) ||
17377c478bd9Sstevel@tonic-gate 		    (ext->ext_offset + ext->ext_length >
17387c478bd9Sstevel@tonic-gate 		    free_ext->ext_offset + free_ext->ext_length) ||
17397c478bd9Sstevel@tonic-gate 		    (free_ext->ext_type != EXTTYP_FREE))
17407c478bd9Sstevel@tonic-gate 			return (-1);
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 		meta_sp_alloc_by_ext(sp, np, head, free_ext,
17437c478bd9Sstevel@tonic-gate 		    ext->ext_offset - MD_SP_WMSIZE,
17447c478bd9Sstevel@tonic-gate 		    ext->ext_length + MD_SP_WMSIZE, ext->ext_seq);
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 		numexts++;
17477c478bd9Sstevel@tonic-gate 	}
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	assert(meta_sp_list_overlaps(*head) == 0);
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
17527c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_alloc_by_list: Extent list after "
17537c478bd9Sstevel@tonic-gate 		    "allocation:\n");
17547c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(*head);
17557c478bd9Sstevel@tonic-gate 	}
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	return (numexts);
17587c478bd9Sstevel@tonic-gate }
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate  * **************************************************************************
17627c478bd9Sstevel@tonic-gate  *                     Extent List Population Functions                     *
17637c478bd9Sstevel@tonic-gate  * **************************************************************************
17647c478bd9Sstevel@tonic-gate  */
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate /*
17677c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_extlist_from_namelist()
17687c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
17697c478bd9Sstevel@tonic-gate  *		spnplp	- the namelist of soft partitions to build a list from
17707c478bd9Sstevel@tonic-gate  * OUTPUT:	extlist	- the extent list built from the SPs in the namelist
17717c478bd9Sstevel@tonic-gate  *		ep	- return error pointer
17727c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
17737c478bd9Sstevel@tonic-gate  * PURPOSE:	builds an extent list representing the soft partitions
17747c478bd9Sstevel@tonic-gate  *		specified in the namelist.  Each extent in each soft
17757c478bd9Sstevel@tonic-gate  *		partition is added to the list with the type EXTTYP_ALLOC.
17767c478bd9Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is not set on any nodes.  Each
17777c478bd9Sstevel@tonic-gate  *		extent in the list includes the space occupied by the
17787c478bd9Sstevel@tonic-gate  *		watermark, which is not included in the unit structures.
17797c478bd9Sstevel@tonic-gate  */
17807c478bd9Sstevel@tonic-gate static int
meta_sp_extlist_from_namelist(mdsetname_t * sp,mdnamelist_t * spnlp,sp_ext_node_t ** extlist,md_error_t * ep)17817c478bd9Sstevel@tonic-gate meta_sp_extlist_from_namelist(
17827c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
17837c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp,
17847c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**extlist,
17857c478bd9Sstevel@tonic-gate 	md_error_t	*ep
17867c478bd9Sstevel@tonic-gate )
17877c478bd9Sstevel@tonic-gate {
17887c478bd9Sstevel@tonic-gate 	int		extn;
17897c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;		/* unit structure of the sp's */
17907c478bd9Sstevel@tonic-gate 	mdnamelist_t	*namep;
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	assert(sp != NULL);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	/*
17957c478bd9Sstevel@tonic-gate 	 * Now go through the soft partitions and add a node to the used
17967c478bd9Sstevel@tonic-gate 	 * list for each allocated extent.
17977c478bd9Sstevel@tonic-gate 	 */
17987c478bd9Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
17997c478bd9Sstevel@tonic-gate 		mdname_t	*curnp = namep->namep;
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 		/* get the unit structure */
18027c478bd9Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
18037c478bd9Sstevel@tonic-gate 			return (-1);
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 		for (extn = 0; (extn < msp->ext.ext_len); extn++) {
18067c478bd9Sstevel@tonic-gate 			md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 			/*
18097c478bd9Sstevel@tonic-gate 			 * subtract from offset and add to the length
18107c478bd9Sstevel@tonic-gate 			 * to account for the watermark, which is not
18117c478bd9Sstevel@tonic-gate 			 * contained in the extents in the unit structure.
18127c478bd9Sstevel@tonic-gate 			 */
18137c478bd9Sstevel@tonic-gate 			meta_sp_list_insert(sp, curnp, extlist,
18147c478bd9Sstevel@tonic-gate 			    extp->poff - MD_SP_WMSIZE, extp->len + MD_SP_WMSIZE,
18157c478bd9Sstevel@tonic-gate 			    EXTTYP_ALLOC, extn, 0, meta_sp_cmp_by_offset);
18167c478bd9Sstevel@tonic-gate 		}
18177c478bd9Sstevel@tonic-gate 	}
18187c478bd9Sstevel@tonic-gate 	return (0);
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate /*
18227c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_extlist_from_wm()
18237c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device the node belongs to
18247c478bd9Sstevel@tonic-gate  *		compnp	- the name of the device to scan watermarks on
18257c478bd9Sstevel@tonic-gate  * OUTPUT:	extlist	- the extent list built from the SPs in the namelist
18267c478bd9Sstevel@tonic-gate  *		ep	- return error pointer
18277c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
18287c478bd9Sstevel@tonic-gate  * PURPOSE:	builds an extent list representing the soft partitions
18297c478bd9Sstevel@tonic-gate  *		specified in the namelist.  Each extent in each soft
18307c478bd9Sstevel@tonic-gate  *		partition is added to the list with the type EXTTYP_ALLOC.
18317c478bd9Sstevel@tonic-gate  *		The EXTFLG_UPDATE flag is not set on any nodes.  Each
18327c478bd9Sstevel@tonic-gate  *		extent in the list includes the space occupied by the
18337c478bd9Sstevel@tonic-gate  *		watermark, which is not included in the unit structures.
18347c478bd9Sstevel@tonic-gate  */
18357c478bd9Sstevel@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)18367c478bd9Sstevel@tonic-gate meta_sp_extlist_from_wm(
18377c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
18387c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
18397c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**extlist,
18407c478bd9Sstevel@tonic-gate 	ext_cmpfunc_t	compare,
18417c478bd9Sstevel@tonic-gate 	md_error_t	*ep
18427c478bd9Sstevel@tonic-gate )
18437c478bd9Sstevel@tonic-gate {
18447c478bd9Sstevel@tonic-gate 	mp_watermark_t	wm;
18457c478bd9Sstevel@tonic-gate 	mdname_t	*np = NULL;
18467c478bd9Sstevel@tonic-gate 	mdsetname_t	*spsetp = NULL;
18477c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	cur_off;
1848d7cd8252Stw21770 	md_set_desc	*sd;
1849d7cd8252Stw21770 	int		init = 0;
1850d7cd8252Stw21770 	mdkey_t		key;
1851d7cd8252Stw21770 	minor_t		mnum;
1852d7cd8252Stw21770 
1853d7cd8252Stw21770 	if (!metaislocalset(sp)) {
1854d7cd8252Stw21770 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
1855d7cd8252Stw21770 			return (-1);
1856d7cd8252Stw21770 	}
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if ((cur_off = meta_sp_get_start(sp, compnp, ep)) == MD_DISKADDR_ERROR)
18597c478bd9Sstevel@tonic-gate 		return (-1);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	for (;;) {
18627c478bd9Sstevel@tonic-gate 		if (meta_sp_read_wm(sp, compnp, &wm, cur_off, ep) != 0) {
18637c478bd9Sstevel@tonic-gate 			return (-1);
18647c478bd9Sstevel@tonic-gate 		}
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 		/* get the set and name pointers */
18677c478bd9Sstevel@tonic-gate 		if (strcmp(wm.wm_setname, MD_SP_LOCALSETNAME) != 0) {
18687c478bd9Sstevel@tonic-gate 			if ((spsetp = metasetname(wm.wm_setname, ep)) == NULL) {
18697c478bd9Sstevel@tonic-gate 				return (-1);
18707c478bd9Sstevel@tonic-gate 			}
18717c478bd9Sstevel@tonic-gate 		}
18727c478bd9Sstevel@tonic-gate 
1873d7cd8252Stw21770 		/*
1874d7cd8252Stw21770 		 * For the MN set, meta_init_make_device needs to
1875d7cd8252Stw21770 		 * be run on all the nodes so the entries for the
1876d7cd8252Stw21770 		 * softpart device name and its comp can be created
1877d7cd8252Stw21770 		 * in the same order in the replica namespace.  If
1878d7cd8252Stw21770 		 * we have it run on mdmn_do_iocset then the mddbs
1879d7cd8252Stw21770 		 * will be out of sync between master node and slave
1880d7cd8252Stw21770 		 * nodes.
1881d7cd8252Stw21770 		 */
18827c478bd9Sstevel@tonic-gate 		if (strcmp(wm.wm_mdname, MD_SP_FREEWMNAME) != 0) {
1883d7cd8252Stw21770 
1884d7cd8252Stw21770 			if (!metaislocalset(sp) && MD_MNSET_DESC(sd)) {
1885d7cd8252Stw21770 				md_mn_msg_addmdname_t	*send_params;
1886d7cd8252Stw21770 				int			result;
1887d7cd8252Stw21770 				md_mn_result_t		*resp = NULL;
1888d7cd8252Stw21770 				int			message_size;
1889d7cd8252Stw21770 
1890d7cd8252Stw21770 				message_size =  sizeof (*send_params) +
1891d7cd8252Stw21770 				    strlen(wm.wm_mdname) + 1;
1892d7cd8252Stw21770 				send_params = Zalloc(message_size);
1893d7cd8252Stw21770 				send_params->addmdname_setno = sp->setno;
1894d7cd8252Stw21770 				(void) strcpy(&send_params->addmdname_name[0],
1895d7cd8252Stw21770 				    wm.wm_mdname);
1896d7cd8252Stw21770 				result = mdmn_send_message(sp->setno,
1897d7cd8252Stw21770 				    MD_MN_MSG_ADDMDNAME,
1898bf85a12bSJohn Wren Kennedy 				    MD_MSGF_PANIC_WHEN_INCONSISTENT, 0,
1899d7cd8252Stw21770 				    (char *)send_params, message_size, &resp,
1900d7cd8252Stw21770 				    ep);
1901d7cd8252Stw21770 				Free(send_params);
1902d7cd8252Stw21770 				if (resp != NULL) {
1903d7cd8252Stw21770 					if (resp->mmr_exitval != 0) {
1904d7cd8252Stw21770 						free_result(resp);
19057c478bd9Sstevel@tonic-gate 						return (-1);
1906d7cd8252Stw21770 					}
1907d7cd8252Stw21770 					free_result(resp);
1908d7cd8252Stw21770 				}
1909d7cd8252Stw21770 				if (result != 0)
1910d7cd8252Stw21770 					return (-1);
1911d7cd8252Stw21770 			} else {
1912d7cd8252Stw21770 
1913d7cd8252Stw21770 				if (!is_existing_meta_hsp(sp, wm.wm_mdname)) {
1914d7cd8252Stw21770 					if ((key = meta_init_make_device(&sp,
1915d7cd8252Stw21770 					    wm.wm_mdname, ep)) <= 0) {
1916d7cd8252Stw21770 						return (-1);
1917d7cd8252Stw21770 					}
1918d7cd8252Stw21770 					init = 1;
1919d7cd8252Stw21770 				}
1920d7cd8252Stw21770 			}
1921d7cd8252Stw21770 
1922d7cd8252Stw21770 			np = metaname(&spsetp, wm.wm_mdname, META_DEVICE, ep);
19237c478bd9Sstevel@tonic-gate 			if (np == NULL) {
1924d7cd8252Stw21770 				if (init) {
19251cd3f00bSsk102515 					if (meta_getnmentbykey(sp->setno,
19261cd3f00bSsk102515 					    MD_SIDEWILD, key, NULL, &mnum,
19271cd3f00bSsk102515 					    NULL, ep) != NULL) {
19281cd3f00bSsk102515 						(void) metaioctl(MD_IOCREM_DEV,
19291cd3f00bSsk102515 						    &mnum, ep, NULL);
1930d7cd8252Stw21770 					}
1931d7cd8252Stw21770 					(void) del_self_name(sp, key, ep);
1932d7cd8252Stw21770 				}
19337c478bd9Sstevel@tonic-gate 				return (-1);
19347c478bd9Sstevel@tonic-gate 			}
19357c478bd9Sstevel@tonic-gate 		}
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 		/* insert watermark into extent list */
19387c478bd9Sstevel@tonic-gate 		meta_sp_list_insert(spsetp, np, extlist, cur_off,
19397c478bd9Sstevel@tonic-gate 		    wm.wm_length + MD_SP_WMSIZE, wm.wm_type, wm.wm_seq,
19407c478bd9Sstevel@tonic-gate 		    EXTFLG_UPDATE, compare);
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 		/* if we see the end watermark, we're done */
19437c478bd9Sstevel@tonic-gate 		if (wm.wm_type == EXTTYP_END)
19447c478bd9Sstevel@tonic-gate 			break;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 		cur_off += wm.wm_length + 1;
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 		/* clear out set and name pointers for next iteration */
19497c478bd9Sstevel@tonic-gate 		np = NULL;
19507c478bd9Sstevel@tonic-gate 		spsetp = NULL;
19517c478bd9Sstevel@tonic-gate 	}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	return (0);
19547c478bd9Sstevel@tonic-gate }
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate /*
19577c478bd9Sstevel@tonic-gate  * **************************************************************************
19587c478bd9Sstevel@tonic-gate  *                        Print (metastat) Functions                        *
19597c478bd9Sstevel@tonic-gate  * **************************************************************************
19607c478bd9Sstevel@tonic-gate  */
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate /*
19637c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_short_print()
19647c478bd9Sstevel@tonic-gate  * INPUT:	msp	- the unit structure to display
19657c478bd9Sstevel@tonic-gate  *		fp	- the file pointer to send output to
19667c478bd9Sstevel@tonic-gate  *		options	- print options from the command line processor
19677c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
19687c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
19697c478bd9Sstevel@tonic-gate  * PURPOSE:	display a short report of the soft partition in md.tab
19707c478bd9Sstevel@tonic-gate  *		form, primarily used for metastat -p.
19717c478bd9Sstevel@tonic-gate  */
19727c478bd9Sstevel@tonic-gate static int
meta_sp_short_print(md_sp_t * msp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)19737c478bd9Sstevel@tonic-gate meta_sp_short_print(
19747c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
19757c478bd9Sstevel@tonic-gate 	char		*fname,
19767c478bd9Sstevel@tonic-gate 	FILE		*fp,
19777c478bd9Sstevel@tonic-gate 	mdprtopts_t	options,
19787c478bd9Sstevel@tonic-gate 	md_error_t	*ep
19797c478bd9Sstevel@tonic-gate )
19807c478bd9Sstevel@tonic-gate {
19817c478bd9Sstevel@tonic-gate 	int	extn;
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
1984d7cd8252Stw21770 		if ((msp->common.revision & MD_64BIT_META_DEV) == 0)
1985d7cd8252Stw21770 			return (0);
1986d7cd8252Stw21770 	}
1987d7cd8252Stw21770 
1988d7cd8252Stw21770 	if (options & PRINT_FN) {
1989d7cd8252Stw21770 		if ((msp->common.revision & MD_FN_META_DEV) == 0)
19907c478bd9Sstevel@tonic-gate 			return (0);
19917c478bd9Sstevel@tonic-gate 	}
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	/* print name and -p */
19947c478bd9Sstevel@tonic-gate 	if (fprintf(fp, "%s -p", msp->common.namep->cname) == EOF)
19957c478bd9Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	/* print the component */
19987c478bd9Sstevel@tonic-gate 	/*
1999d7cd8252Stw21770 	 * Always print the full path name
20007c478bd9Sstevel@tonic-gate 	 */
20017c478bd9Sstevel@tonic-gate 	if (fprintf(fp, " %s", msp->compnamep->rname) == EOF)
20027c478bd9Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	/* print out each extent */
20057c478bd9Sstevel@tonic-gate 	for (extn = 0; (extn < msp->ext.ext_len); extn++) {
20067c478bd9Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
20077c478bd9Sstevel@tonic-gate 		if (fprintf(fp, " -o %llu -b %llu ", extp->poff,
20087c478bd9Sstevel@tonic-gate 		    extp->len) == EOF)
20097c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
20107c478bd9Sstevel@tonic-gate 	}
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
20137c478bd9Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	/* success */
20167c478bd9Sstevel@tonic-gate 	return (0);
20177c478bd9Sstevel@tonic-gate }
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate /*
20207c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_status_to_name()
20217c478bd9Sstevel@tonic-gate  * INPUT:	xsp_status	- the status value to convert to a string
20227c478bd9Sstevel@tonic-gate  *		tstate		- transient errored device state. If set the
20237c478bd9Sstevel@tonic-gate  *				  device is Unavailable
20247c478bd9Sstevel@tonic-gate  * OUTPUT:	none
20257c478bd9Sstevel@tonic-gate  * RETURNS:	char *	- a pointer to the string representing the status value
20267c478bd9Sstevel@tonic-gate  * PURPOSE:	return an internationalized string representing the
20277c478bd9Sstevel@tonic-gate  *		status value for a soft partition.  The strings are
20287c478bd9Sstevel@tonic-gate  *		strdup'd and must be freed by the caller.
20297c478bd9Sstevel@tonic-gate  */
20307c478bd9Sstevel@tonic-gate static char *
meta_sp_status_to_name(xsp_status_t xsp_status,uint_t tstate)20317c478bd9Sstevel@tonic-gate meta_sp_status_to_name(
20327c478bd9Sstevel@tonic-gate 	xsp_status_t	xsp_status,
20337c478bd9Sstevel@tonic-gate 	uint_t		tstate
20347c478bd9Sstevel@tonic-gate )
20357c478bd9Sstevel@tonic-gate {
20367c478bd9Sstevel@tonic-gate 	char *rval = NULL;
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	/*
20397c478bd9Sstevel@tonic-gate 	 * Check to see if we have MD_INACCESSIBLE set. This is the only valid
20407c478bd9Sstevel@tonic-gate 	 * value for an 'Unavailable' return. tstate can be set because of
20417c478bd9Sstevel@tonic-gate 	 * other multi-node reasons (e.g. ABR being set)
20427c478bd9Sstevel@tonic-gate 	 */
20437c478bd9Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
20447c478bd9Sstevel@tonic-gate 		return (Strdup(dgettext(TEXT_DOMAIN, "Unavailable")));
20457c478bd9Sstevel@tonic-gate 	}
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	switch (xsp_status) {
20487c478bd9Sstevel@tonic-gate 	case MD_SP_CREATEPEND:
20497c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Creating"));
20507c478bd9Sstevel@tonic-gate 		break;
20517c478bd9Sstevel@tonic-gate 	case MD_SP_GROWPEND:
20527c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Growing"));
20537c478bd9Sstevel@tonic-gate 		break;
20547c478bd9Sstevel@tonic-gate 	case MD_SP_DELPEND:
20557c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Deleting"));
20567c478bd9Sstevel@tonic-gate 		break;
20577c478bd9Sstevel@tonic-gate 	case MD_SP_OK:
20587c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Okay"));
20597c478bd9Sstevel@tonic-gate 		break;
20607c478bd9Sstevel@tonic-gate 	case MD_SP_ERR:
20617c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Errored"));
20627c478bd9Sstevel@tonic-gate 		break;
20637c478bd9Sstevel@tonic-gate 	case MD_SP_RECOVER:
20647c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Recovering"));
20657c478bd9Sstevel@tonic-gate 		break;
20667c478bd9Sstevel@tonic-gate 	}
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	if (rval == NULL)
20697c478bd9Sstevel@tonic-gate 		rval = Strdup(dgettext(TEXT_DOMAIN, "Invalid"));
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	return (rval);
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate /*
20757c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_report()
20767c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the unit being displayed
20777c478bd9Sstevel@tonic-gate  *		msp	- the unit structure to display
20787c478bd9Sstevel@tonic-gate  *		nlpp	- pass back the large devs
20797c478bd9Sstevel@tonic-gate  *		fp	- the file pointer to send output to
20807c478bd9Sstevel@tonic-gate  *		options	- print options from the command line processor
20817c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
20827c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
20837c478bd9Sstevel@tonic-gate  * PURPOSE:	print a full report of the device specified
20847c478bd9Sstevel@tonic-gate  */
20857c478bd9Sstevel@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)20867c478bd9Sstevel@tonic-gate meta_sp_report(
20877c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
20887c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
20897c478bd9Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
20907c478bd9Sstevel@tonic-gate 	char		*fname,
20917c478bd9Sstevel@tonic-gate 	FILE		*fp,
20927c478bd9Sstevel@tonic-gate 	mdprtopts_t	options,
20937c478bd9Sstevel@tonic-gate 	md_error_t	*ep
20947c478bd9Sstevel@tonic-gate )
20957c478bd9Sstevel@tonic-gate {
20967c478bd9Sstevel@tonic-gate 	uint_t		extn;
20977c478bd9Sstevel@tonic-gate 	char		*status;
20987c478bd9Sstevel@tonic-gate 	char		*devid = "";
20997c478bd9Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
21007c478bd9Sstevel@tonic-gate 	ddi_devid_t	dtp;
21017c478bd9Sstevel@tonic-gate 	int		len;
21027c478bd9Sstevel@tonic-gate 	uint_t		tstate = 0;
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
2105d7cd8252Stw21770 		if ((msp->common.revision & MD_64BIT_META_DEV) == 0) {
2106d7cd8252Stw21770 			return (0);
2107d7cd8252Stw21770 		} else {
2108d7cd8252Stw21770 			if (meta_getdevs(sp, msp->common.namep, nlpp, ep) != 0)
2109d7cd8252Stw21770 				return (-1);
2110d7cd8252Stw21770 		}
2111d7cd8252Stw21770 	}
2112d7cd8252Stw21770 
2113d7cd8252Stw21770 	if (options & PRINT_FN) {
2114d7cd8252Stw21770 		if ((msp->common.revision & MD_FN_META_DEV) == 0) {
21157c478bd9Sstevel@tonic-gate 			return (0);
21167c478bd9Sstevel@tonic-gate 		} else {
21177c478bd9Sstevel@tonic-gate 			if (meta_getdevs(sp, msp->common.namep, nlpp, ep) != 0)
21187c478bd9Sstevel@tonic-gate 				return (-1);
21197c478bd9Sstevel@tonic-gate 		}
21207c478bd9Sstevel@tonic-gate 	}
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
21237c478bd9Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Soft Partition\n"),
21247c478bd9Sstevel@tonic-gate 		    msp->common.namep->cname) == EOF)
21257c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21267c478bd9Sstevel@tonic-gate 	}
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Device: %s\n"),
21297c478bd9Sstevel@tonic-gate 	    msp->compnamep->cname) == EOF)
21307c478bd9Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	/* Determine if device is available before displaying status */
21337c478bd9Sstevel@tonic-gate 	if (metaismeta(msp->common.namep)) {
21347c478bd9Sstevel@tonic-gate 		if (meta_get_tstate(msp->common.namep->dev, &tstate, ep) != 0)
21357c478bd9Sstevel@tonic-gate 			return (-1);
21367c478bd9Sstevel@tonic-gate 	}
21377c478bd9Sstevel@tonic-gate 	status = meta_sp_status_to_name(msp->status, tstate & MD_DEV_ERRORED);
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	/* print out "State" to be consistent with other metadevices */
21407c478bd9Sstevel@tonic-gate 	if (tstate & MD_ABR_CAP) {
21417c478bd9Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
21427c478bd9Sstevel@tonic-gate 		    "    State: %s - Application Based Recovery (ABR)\n"),
21437c478bd9Sstevel@tonic-gate 		    status) == EOF) {
21447c478bd9Sstevel@tonic-gate 			Free(status);
21457c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21467c478bd9Sstevel@tonic-gate 		}
21477c478bd9Sstevel@tonic-gate 	} else {
21487c478bd9Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
21497c478bd9Sstevel@tonic-gate 		    "    State: %s\n"), status) == EOF) {
21507c478bd9Sstevel@tonic-gate 			Free(status);
21517c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21527c478bd9Sstevel@tonic-gate 		}
21537c478bd9Sstevel@tonic-gate 	}
21547c478bd9Sstevel@tonic-gate 	free(status);
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %llu blocks (%s)\n"),
21577c478bd9Sstevel@tonic-gate 	    msp->common.size,
21587c478bd9Sstevel@tonic-gate 	    meta_number_to_string(msp->common.size, DEV_BSIZE)) == EOF)
21597c478bd9Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	/* print component details */
21627c478bd9Sstevel@tonic-gate 	if (! metaismeta(msp->compnamep)) {
21637c478bd9Sstevel@tonic-gate 		diskaddr_t	start_blk;
21647c478bd9Sstevel@tonic-gate 		int		has_mddb;
21657c478bd9Sstevel@tonic-gate 		char		*has_mddb_str;
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 		/* print header */
21687c478bd9Sstevel@tonic-gate 		/*
21697c478bd9Sstevel@tonic-gate 		 * Building a format string on the fly that will
21707c478bd9Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
21717c478bd9Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
21727c478bd9Sstevel@tonic-gate 		 * looking horrible.
21737c478bd9Sstevel@tonic-gate 		 */
21747c478bd9Sstevel@tonic-gate 		len = strlen(msp->compnamep->cname);
21757c478bd9Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
21767c478bd9Sstevel@tonic-gate 		len += 2;
21777c478bd9Sstevel@tonic-gate 		if (fprintf(fp,
21787c478bd9Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %s\n",
21797c478bd9Sstevel@tonic-gate 		    len, len,
21807c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
21817c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
21827c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
21837c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
21847c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
21857c478bd9Sstevel@tonic-gate 		}
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 		/* get info */
21897c478bd9Sstevel@tonic-gate 		if ((start_blk = meta_sp_get_start(sp, msp->compnamep, ep)) ==
21907c478bd9Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
21917c478bd9Sstevel@tonic-gate 			return (-1);
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 		if ((has_mddb = metahasmddb(sp, msp->compnamep, ep)) < 0)
21947c478bd9Sstevel@tonic-gate 			return (-1);
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 		if (has_mddb)
21977c478bd9Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
21987c478bd9Sstevel@tonic-gate 		else
21997c478bd9Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate 		/* populate the key in the name_p structure */
22027c478bd9Sstevel@tonic-gate 		didnp = metadevname(&sp, msp->compnamep->dev, ep);
22037c478bd9Sstevel@tonic-gate 		if (didnp == NULL) {
22047c478bd9Sstevel@tonic-gate 			return (-1);
22057c478bd9Sstevel@tonic-gate 		}
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 		/* determine if devid does NOT exist */
22087c478bd9Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
22091cd3f00bSsk102515 			if ((dtp = meta_getdidbykey(sp->setno,
22101cd3f00bSsk102515 			    getmyside(sp, ep), didnp->key, ep)) == NULL)
22117c478bd9Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
22127c478bd9Sstevel@tonic-gate 			else {
22137c478bd9Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
22147c478bd9Sstevel@tonic-gate 				free(dtp);
22157c478bd9Sstevel@tonic-gate 			}
22167c478bd9Sstevel@tonic-gate 		}
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 		/* print info */
22197c478bd9Sstevel@tonic-gate 		/*
22207c478bd9Sstevel@tonic-gate 		 * This allows the length
22217c478bd9Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
22227c478bd9Sstevel@tonic-gate 		 * looking horrible.
22237c478bd9Sstevel@tonic-gate 		 */
22247c478bd9Sstevel@tonic-gate 		if (fprintf(fp, "\t%-*s %8lld     %-5.5s %s\n",
22257c478bd9Sstevel@tonic-gate 		    len, msp->compnamep->cname,
22267c478bd9Sstevel@tonic-gate 		    start_blk, has_mddb_str, devid) == EOF) {
22277c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
22287c478bd9Sstevel@tonic-gate 		}
22297c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\n");
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate 	/* print the headers */
22347c478bd9Sstevel@tonic-gate 	if (fprintf(fp, "\t%6.6s %24.24s %24.24s\n",
22357c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Extent"),
22367c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Start Block"),
22377c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Block count")) == EOF)
22387c478bd9Sstevel@tonic-gate 		return (mdsyserror(ep, errno, fname));
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	/* print out each extent */
22417c478bd9Sstevel@tonic-gate 	for (extn = 0; (extn < msp->ext.ext_len); extn++) {
22427c478bd9Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 		/* If PRINT_TIMES option is ever supported, add output here */
22457c478bd9Sstevel@tonic-gate 		if (fprintf(fp, "\t%6u %24llu %24llu\n",
22467c478bd9Sstevel@tonic-gate 		    extn, extp->poff, extp->len) == EOF)
22477c478bd9Sstevel@tonic-gate 			return (mdsyserror(ep, errno, fname));
22487c478bd9Sstevel@tonic-gate 	}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	/* separate records with a newline */
22517c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "\n");
22527c478bd9Sstevel@tonic-gate 	return (0);
22537c478bd9Sstevel@tonic-gate }
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate /*
22567c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_print()
22577c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the unit being displayed
22587c478bd9Sstevel@tonic-gate  *		np	- the name of the device to print
22597c478bd9Sstevel@tonic-gate  *		fname	- ??? not used
22607c478bd9Sstevel@tonic-gate  *		fp	- the file pointer to send output to
22617c478bd9Sstevel@tonic-gate  *		options	- print options from the command line processor
22627c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
22637c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
22647c478bd9Sstevel@tonic-gate  * PURPOSE:	print a full report of the device specified by metastat.
22657c478bd9Sstevel@tonic-gate  *		This is the main entry point for printing.
22667c478bd9Sstevel@tonic-gate  */
22677c478bd9Sstevel@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)22687c478bd9Sstevel@tonic-gate meta_sp_print(
22697c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
22707c478bd9Sstevel@tonic-gate 	mdname_t	*np,
22717c478bd9Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
22727c478bd9Sstevel@tonic-gate 	char		*fname,
22737c478bd9Sstevel@tonic-gate 	FILE		*fp,
22747c478bd9Sstevel@tonic-gate 	mdprtopts_t	options,
22757c478bd9Sstevel@tonic-gate 	md_error_t	*ep
22767c478bd9Sstevel@tonic-gate )
22777c478bd9Sstevel@tonic-gate {
22787c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;
22797c478bd9Sstevel@tonic-gate 	md_unit_t	*mdp;
22807c478bd9Sstevel@tonic-gate 	int		rval = 0;
22812b637af7SJohn Harres 	set_t		setno;
22822b637af7SJohn Harres 	minor_t		unit;
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate 	/* should always have the same set */
22857c478bd9Sstevel@tonic-gate 	assert(sp != NULL);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	/* print all the soft partitions */
22887c478bd9Sstevel@tonic-gate 	if (np == NULL) {
22897c478bd9Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
22907c478bd9Sstevel@tonic-gate 		mdnamelist_t	*p;
22917c478bd9Sstevel@tonic-gate 		int		cnt;
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 		if ((cnt = meta_get_sp_names(sp, &nlp, options, ep)) < 0)
22947c478bd9Sstevel@tonic-gate 			return (-1);
22957c478bd9Sstevel@tonic-gate 		else if (cnt == 0)
22967c478bd9Sstevel@tonic-gate 			return (0);
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 		/* recusively print them out */
22997c478bd9Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
23007c478bd9Sstevel@tonic-gate 			mdname_t	*curnp = p->namep;
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 			/*
23037c478bd9Sstevel@tonic-gate 			 * one problem with the rval of -1 here is that
23047c478bd9Sstevel@tonic-gate 			 * the error gets "lost" when the next device is
23057c478bd9Sstevel@tonic-gate 			 * printed, but we want to print them all anyway.
23067c478bd9Sstevel@tonic-gate 			 */
23077c478bd9Sstevel@tonic-gate 			rval = meta_sp_print(sp, curnp, nlpp, fname, fp,
23087c478bd9Sstevel@tonic-gate 			    options, ep);
23097c478bd9Sstevel@tonic-gate 		}
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate 		/* clean up, return success */
23127c478bd9Sstevel@tonic-gate 		metafreenamelist(nlp);
23137c478bd9Sstevel@tonic-gate 		return (rval);
23147c478bd9Sstevel@tonic-gate 	}
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	/* get the unit structure */
23177c478bd9Sstevel@tonic-gate 	if ((msp = meta_get_sp_common(sp, np,
23187c478bd9Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
23197c478bd9Sstevel@tonic-gate 		return (-1);
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 	/* check for parented */
23227c478bd9Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
23237c478bd9Sstevel@tonic-gate 	    (MD_HAS_PARENT(msp->common.parent))) {
23247c478bd9Sstevel@tonic-gate 		return (0);
23257c478bd9Sstevel@tonic-gate 	}
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	/* print appropriate detail */
23287c478bd9Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
23297c478bd9Sstevel@tonic-gate 		if (meta_sp_short_print(msp, fname, fp, options, ep) != 0)
23307c478bd9Sstevel@tonic-gate 			return (-1);
23317c478bd9Sstevel@tonic-gate 	} else {
23327c478bd9Sstevel@tonic-gate 		if (meta_sp_report(sp, msp, nlpp, fname, fp, options, ep) != 0)
23337c478bd9Sstevel@tonic-gate 			return (-1);
23347c478bd9Sstevel@tonic-gate 	}
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 	/*
23377c478bd9Sstevel@tonic-gate 	 * Print underlying metadevices if they are parented to us and
23387c478bd9Sstevel@tonic-gate 	 * if the info for the underlying metadevice has not been printed.
23397c478bd9Sstevel@tonic-gate 	 */
23407c478bd9Sstevel@tonic-gate 	if (metaismeta(msp->compnamep)) {
23417c478bd9Sstevel@tonic-gate 		/* get the unit structure for the subdevice */
23427c478bd9Sstevel@tonic-gate 		if ((mdp = meta_get_mdunit(sp, msp->compnamep, ep)) == NULL)
23437c478bd9Sstevel@tonic-gate 			return (-1);
23447c478bd9Sstevel@tonic-gate 
23452b637af7SJohn Harres 		setno = MD_MIN2SET(MD_SID(mdp));
23462b637af7SJohn Harres 		unit = MD_MIN2UNIT(MD_SID(mdp));
23472b637af7SJohn Harres 
23487c478bd9Sstevel@tonic-gate 		/* If info not already printed, recurse */
23492b637af7SJohn Harres 		if (sp_parent_printed[setno] == NULL ||
23502b637af7SJohn Harres 		    !BT_TEST(sp_parent_printed[setno], unit)) {
23517c478bd9Sstevel@tonic-gate 			if (meta_print_name(sp, msp->compnamep, nlpp, fname, fp,
23527c478bd9Sstevel@tonic-gate 			    (options | PRINT_HEADER | PRINT_SUBDEVS),
23537c478bd9Sstevel@tonic-gate 			    NULL, ep) != 0) {
23547c478bd9Sstevel@tonic-gate 				return (-1);
23557c478bd9Sstevel@tonic-gate 			}
23562b637af7SJohn Harres 			if (sp_parent_printed[setno] == NULL)
23572b637af7SJohn Harres 				sp_parent_printed[setno] =
2358*704030f4SJames Hall 				    Zalloc(BT_SIZEOFMAP(MD_MAXUNITS));
23592b637af7SJohn Harres 			BT_SET(sp_parent_printed[setno], unit);
23607c478bd9Sstevel@tonic-gate 		}
23617c478bd9Sstevel@tonic-gate 	}
23627c478bd9Sstevel@tonic-gate 	return (0);
23637c478bd9Sstevel@tonic-gate }
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate /*
23667c478bd9Sstevel@tonic-gate  * **************************************************************************
23677c478bd9Sstevel@tonic-gate  *                     Watermark Manipulation Functions                     *
23687c478bd9Sstevel@tonic-gate  * **************************************************************************
23697c478bd9Sstevel@tonic-gate  */
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate /*
23727c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_start()
23737c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the operating set
23747c478bd9Sstevel@tonic-gate  *		np 	- device upon which the sp is being built
23757c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
23767c478bd9Sstevel@tonic-gate  * RETURNS:	daddr_t	- -1 if error, otherwise the start block
23777c478bd9Sstevel@tonic-gate  * PURPOSE:	Encapsulate the determination of the start block of the
23787c478bd9Sstevel@tonic-gate  *		device upon which the sp is built or being built.
23797c478bd9Sstevel@tonic-gate  */
23807c478bd9Sstevel@tonic-gate static diskaddr_t
meta_sp_get_start(mdsetname_t * sp,mdname_t * np,md_error_t * ep)23817c478bd9Sstevel@tonic-gate meta_sp_get_start(
23827c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
23837c478bd9Sstevel@tonic-gate 	mdname_t	*np,
23847c478bd9Sstevel@tonic-gate 	md_error_t	*ep
23857c478bd9Sstevel@tonic-gate )
23867c478bd9Sstevel@tonic-gate {
23877c478bd9Sstevel@tonic-gate 	daddr_t		start_block;
23887c478bd9Sstevel@tonic-gate 
23890f5425cbSjkennedy 	if ((start_block = metagetstart(sp, np, ep)) != MD_DISKADDR_ERROR)
23907c478bd9Sstevel@tonic-gate 		start_block += MD_SP_START;
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate 	return (start_block);
23937c478bd9Sstevel@tonic-gate }
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate /*
2396bf85a12bSJohn Wren Kennedy  * FUNCTION:	meta_sp_update_wm_common()
23977c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the operating set
23987c478bd9Sstevel@tonic-gate  *		msp	- a pointer to the XDR unit structure
23997c478bd9Sstevel@tonic-gate  *		extlist	- the extent list specifying watermarks to update
2400bf85a12bSJohn Wren Kennedy  *		iocval	- either MD_IOC_SPUPDATEWM or MD_MN_IOC_SPUPDATEWM
24017c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
24027c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
24037c478bd9Sstevel@tonic-gate  * PURPOSE:	steps backwards through the extent list updating
24047c478bd9Sstevel@tonic-gate  *		watermarks for all extents with the EXTFLG_UPDATE flag
24057c478bd9Sstevel@tonic-gate  *		set.  Writing the watermarks guarantees consistency when
24067c478bd9Sstevel@tonic-gate  *		extents must be broken into pieces since the original
24077c478bd9Sstevel@tonic-gate  *		watermark will be the last to be updated, and will be
24087c478bd9Sstevel@tonic-gate  *		changed to point to a new watermark that is already
24097c478bd9Sstevel@tonic-gate  *		known to be consistent.  If one of the writes fails, the
24107c478bd9Sstevel@tonic-gate  *		original watermark stays intact and none of the changes
24117c478bd9Sstevel@tonic-gate  *		are realized.
24127c478bd9Sstevel@tonic-gate  */
24137c478bd9Sstevel@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)2414bf85a12bSJohn Wren Kennedy meta_sp_update_wm_common(
24157c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
24167c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
24177c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
2418bf85a12bSJohn Wren Kennedy 	int		iocval,
24197c478bd9Sstevel@tonic-gate 	md_error_t	*ep
24207c478bd9Sstevel@tonic-gate )
24217c478bd9Sstevel@tonic-gate {
24227c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
24237c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*tail;
24247c478bd9Sstevel@tonic-gate 	mp_watermark_t	*wmp, *watermarks;
24257c478bd9Sstevel@tonic-gate 	xsp_offset_t	*osp, *offsets;
24267c478bd9Sstevel@tonic-gate 	int		update_count = 0;
24277c478bd9Sstevel@tonic-gate 	int		rval = 0;
24287c478bd9Sstevel@tonic-gate 	md_unit_t	*mdp;
24297c478bd9Sstevel@tonic-gate 	md_sp_update_wm_t	update_params;
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
24327c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_update_wm: Updating watermarks:\n");
24337c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
24347c478bd9Sstevel@tonic-gate 	}
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	/*
24377c478bd9Sstevel@tonic-gate 	 * find the last node so we can write the watermarks backwards
24387c478bd9Sstevel@tonic-gate 	 * and count watermarks to update so we can allocate space
24397c478bd9Sstevel@tonic-gate 	 */
24407c478bd9Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
24417c478bd9Sstevel@tonic-gate 		if ((ext->ext_flags & EXTFLG_UPDATE) != 0) {
24427c478bd9Sstevel@tonic-gate 			update_count++;
24437c478bd9Sstevel@tonic-gate 		}
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 		if (ext->ext_next == NULL) {
24467c478bd9Sstevel@tonic-gate 			tail = ext;
24477c478bd9Sstevel@tonic-gate 		}
24487c478bd9Sstevel@tonic-gate 	}
24497c478bd9Sstevel@tonic-gate 	ext = tail;
24507c478bd9Sstevel@tonic-gate 
24517c478bd9Sstevel@tonic-gate 	wmp = watermarks =
24527c478bd9Sstevel@tonic-gate 	    Zalloc(update_count * sizeof (mp_watermark_t));
24537c478bd9Sstevel@tonic-gate 	osp = offsets =
24547c478bd9Sstevel@tonic-gate 	    Zalloc(update_count * sizeof (sp_ext_offset_t));
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	while (ext != NULL) {
24577c478bd9Sstevel@tonic-gate 		if ((ext->ext_flags & EXTFLG_UPDATE) != 0) {
24587c478bd9Sstevel@tonic-gate 			/* update watermark */
24597c478bd9Sstevel@tonic-gate 			wmp->wm_magic = MD_SP_MAGIC;
24607c478bd9Sstevel@tonic-gate 			wmp->wm_version = MD_SP_VERSION;
24617c478bd9Sstevel@tonic-gate 			wmp->wm_type = ext->ext_type;
24627c478bd9Sstevel@tonic-gate 			wmp->wm_seq = ext->ext_seq;
24637c478bd9Sstevel@tonic-gate 			wmp->wm_length = ext->ext_length - MD_SP_WMSIZE;
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 			/* fill in the volume name and set name */
24667c478bd9Sstevel@tonic-gate 			if (ext->ext_namep != NULL)
24677c478bd9Sstevel@tonic-gate 				(void) strcpy(wmp->wm_mdname,
24687c478bd9Sstevel@tonic-gate 				    ext->ext_namep->cname);
24697c478bd9Sstevel@tonic-gate 			else
24707c478bd9Sstevel@tonic-gate 				(void) strcpy(wmp->wm_mdname, MD_SP_FREEWMNAME);
24717c478bd9Sstevel@tonic-gate 			if (ext->ext_setp != NULL &&
24727c478bd9Sstevel@tonic-gate 			    ext->ext_setp->setno != MD_LOCAL_SET)
24737c478bd9Sstevel@tonic-gate 				(void) strcpy(wmp->wm_setname,
24747c478bd9Sstevel@tonic-gate 				    ext->ext_setp->setname);
24757c478bd9Sstevel@tonic-gate 			else
24767c478bd9Sstevel@tonic-gate 				(void) strcpy(wmp->wm_setname,
24777c478bd9Sstevel@tonic-gate 				    MD_SP_LOCALSETNAME);
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 			/* Generate the checksum */
24807c478bd9Sstevel@tonic-gate 			wmp->wm_checksum = 0;
24817c478bd9Sstevel@tonic-gate 			crcgen((uchar_t *)wmp, (uint_t *)&wmp->wm_checksum,
24827c478bd9Sstevel@tonic-gate 			    sizeof (*wmp), NULL);
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 			/* record the extent offset */
24857c478bd9Sstevel@tonic-gate 			*osp = ext->ext_offset;
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 			/* Advance the placeholders */
24887c478bd9Sstevel@tonic-gate 			osp++; wmp++;
24897c478bd9Sstevel@tonic-gate 		}
24907c478bd9Sstevel@tonic-gate 		ext = ext->ext_prev;
24917c478bd9Sstevel@tonic-gate 	}
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 	mdp = meta_get_mdunit(sp, msp->common.namep, ep);
24947c478bd9Sstevel@tonic-gate 	if (mdp == NULL) {
24957c478bd9Sstevel@tonic-gate 		rval = -1;
24967c478bd9Sstevel@tonic-gate 		goto out;
24977c478bd9Sstevel@tonic-gate 	}
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	(void) memset(&update_params, 0, sizeof (update_params));
25007c478bd9Sstevel@tonic-gate 	update_params.mnum = MD_SID(mdp);
25017c478bd9Sstevel@tonic-gate 	update_params.count = update_count;
25027c478bd9Sstevel@tonic-gate 	update_params.wmp = (uintptr_t)watermarks;
25037c478bd9Sstevel@tonic-gate 	update_params.osp = (uintptr_t)offsets;
25047c478bd9Sstevel@tonic-gate 	MD_SETDRIVERNAME(&update_params, MD_SP,
25057c478bd9Sstevel@tonic-gate 	    MD_MIN2SET(update_params.mnum));
25067c478bd9Sstevel@tonic-gate 
2507bf85a12bSJohn Wren Kennedy 	if (metaioctl(iocval, &update_params, &update_params.mde,
2508bf85a12bSJohn Wren Kennedy 	    msp->common.namep->cname) != 0) {
25097c478bd9Sstevel@tonic-gate 		(void) mdstealerror(ep, &update_params.mde);
25107c478bd9Sstevel@tonic-gate 		rval = -1;
25117c478bd9Sstevel@tonic-gate 		goto out;
25127c478bd9Sstevel@tonic-gate 	}
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate out:
25157c478bd9Sstevel@tonic-gate 	Free(watermarks);
25167c478bd9Sstevel@tonic-gate 	Free(offsets);
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 	return (rval);
25197c478bd9Sstevel@tonic-gate }
25207c478bd9Sstevel@tonic-gate 
2521bf85a12bSJohn Wren Kennedy static int
meta_sp_update_wm(mdsetname_t * sp,md_sp_t * msp,sp_ext_node_t * extlist,md_error_t * ep)2522bf85a12bSJohn Wren Kennedy meta_sp_update_wm(
2523bf85a12bSJohn Wren Kennedy 	mdsetname_t	*sp,
2524bf85a12bSJohn Wren Kennedy 	md_sp_t		*msp,
2525bf85a12bSJohn Wren Kennedy 	sp_ext_node_t	*extlist,
2526bf85a12bSJohn Wren Kennedy 	md_error_t	*ep
2527bf85a12bSJohn Wren Kennedy )
2528bf85a12bSJohn Wren Kennedy {
2529bf85a12bSJohn Wren Kennedy 	return (meta_sp_update_wm_common(sp, msp, extlist, MD_IOC_SPUPDATEWM,
2530bf85a12bSJohn Wren Kennedy 	    ep));
2531bf85a12bSJohn Wren Kennedy }
2532bf85a12bSJohn Wren Kennedy 
2533bf85a12bSJohn Wren Kennedy static int
meta_mn_sp_update_wm(mdsetname_t * sp,md_sp_t * msp,sp_ext_node_t * extlist,md_error_t * ep)2534bf85a12bSJohn Wren Kennedy meta_mn_sp_update_wm(
2535bf85a12bSJohn Wren Kennedy 	mdsetname_t	*sp,
2536bf85a12bSJohn Wren Kennedy 	md_sp_t		*msp,
2537bf85a12bSJohn Wren Kennedy 	sp_ext_node_t	*extlist,
2538bf85a12bSJohn Wren Kennedy 	md_error_t	*ep
2539bf85a12bSJohn Wren Kennedy )
2540bf85a12bSJohn Wren Kennedy {
2541bf85a12bSJohn Wren Kennedy 	return (meta_sp_update_wm_common(sp, msp, extlist, MD_MN_IOC_SPUPDATEWM,
2542bf85a12bSJohn Wren Kennedy 	    ep));
2543bf85a12bSJohn Wren Kennedy }
2544bf85a12bSJohn Wren Kennedy 
25457c478bd9Sstevel@tonic-gate /*
25467c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_clear_wm()
25477c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the operating set
25487c478bd9Sstevel@tonic-gate  *		msp	- the unit structure for the soft partition to clear
25497c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
25507c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
25517c478bd9Sstevel@tonic-gate  * PURPOSE:	steps through the extents for a soft partition unit and
25527c478bd9Sstevel@tonic-gate  *		creates an extent list designed to mark all of the
25537c478bd9Sstevel@tonic-gate  *		watermarks for those extents as free.  The extent list
25547c478bd9Sstevel@tonic-gate  *		is then passed to meta_sp_update_wm() to actually write
25557c478bd9Sstevel@tonic-gate  *		the watermarks out.
25567c478bd9Sstevel@tonic-gate  */
25577c478bd9Sstevel@tonic-gate static int
meta_sp_clear_wm(mdsetname_t * sp,md_sp_t * msp,md_error_t * ep)25587c478bd9Sstevel@tonic-gate meta_sp_clear_wm(
25597c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
25607c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
25617c478bd9Sstevel@tonic-gate 	md_error_t	*ep
25627c478bd9Sstevel@tonic-gate )
25637c478bd9Sstevel@tonic-gate {
25647c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
25657c478bd9Sstevel@tonic-gate 	int		numexts = msp->ext.ext_len;
25667c478bd9Sstevel@tonic-gate 	uint_t		i;
25677c478bd9Sstevel@tonic-gate 	int		rval = 0;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	/* for each watermark must set the flag to SP_FREE */
25707c478bd9Sstevel@tonic-gate 	for (i = 0; i < numexts; i++) {
25717c478bd9Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[i];
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 		meta_sp_list_insert(NULL, NULL, &extlist,
25747c478bd9Sstevel@tonic-gate 		    extp->poff - MD_SP_WMSIZE, extp->len + MD_SP_WMSIZE,
25757c478bd9Sstevel@tonic-gate 		    EXTTYP_FREE, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
25767c478bd9Sstevel@tonic-gate 	}
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	/* update watermarks */
25797c478bd9Sstevel@tonic-gate 	rval = meta_sp_update_wm(sp, msp, extlist, ep);
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate 	meta_sp_list_free(&extlist);
25827c478bd9Sstevel@tonic-gate 	return (rval);
25837c478bd9Sstevel@tonic-gate }
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate /*
25867c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_read_wm()
25877c478bd9Sstevel@tonic-gate  * INPUT:	sp	- setname for component
25887c478bd9Sstevel@tonic-gate  *		compnp	- mdname_t for component
25897c478bd9Sstevel@tonic-gate  *		offset	- the offset of the watermark to read (sectors)
25907c478bd9Sstevel@tonic-gate  * OUTPUT:	wm	- the watermark structure to read into
25917c478bd9Sstevel@tonic-gate  *		ep	- return error pointer
25927c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 on success
25937c478bd9Sstevel@tonic-gate  * PURPOSE:	seeks out to the requested offset and reads a watermark.
25947c478bd9Sstevel@tonic-gate  *		It then verifies that the magic number is correct and
25957c478bd9Sstevel@tonic-gate  *		that the checksum is valid, returning an error if either
25967c478bd9Sstevel@tonic-gate  *		is wrong.
25977c478bd9Sstevel@tonic-gate  */
25987c478bd9Sstevel@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)25997c478bd9Sstevel@tonic-gate meta_sp_read_wm(
26007c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
26017c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
26027c478bd9Sstevel@tonic-gate 	mp_watermark_t	*wm,
26037c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	offset,
26047c478bd9Sstevel@tonic-gate 	md_error_t	*ep
26057c478bd9Sstevel@tonic-gate )
26067c478bd9Sstevel@tonic-gate {
26077c478bd9Sstevel@tonic-gate 	md_sp_read_wm_t	read_params;
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 	/*
26107c478bd9Sstevel@tonic-gate 	 * make sure block offset does not overflow 2^64 bytes and it's a
26117c478bd9Sstevel@tonic-gate 	 * multiple of the block size.
26127c478bd9Sstevel@tonic-gate 	 */
26137c478bd9Sstevel@tonic-gate 	assert(offset <= (1LL << (64 - DEV_BSHIFT)));
26147c478bd9Sstevel@tonic-gate 	/* LINTED */
26157c478bd9Sstevel@tonic-gate 	assert((sizeof (*wm) % DEV_BSIZE) == 0);
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	(void) memset(wm, 0, sizeof (*wm));
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 	(void) memset(&read_params, 0, sizeof (read_params));
26207c478bd9Sstevel@tonic-gate 	read_params.rdev = compnp->dev;
26217c478bd9Sstevel@tonic-gate 	read_params.wmp = (uintptr_t)wm;
26227c478bd9Sstevel@tonic-gate 	read_params.offset = offset;
26237c478bd9Sstevel@tonic-gate 	MD_SETDRIVERNAME(&read_params, MD_SP, sp->setno);
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate 	if (metaioctl(MD_IOC_SPREADWM, &read_params,
26267c478bd9Sstevel@tonic-gate 	    &read_params.mde, compnp->cname) != 0) {
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
26297c478bd9Sstevel@tonic-gate 		    "Extent header read failed, block %llu.\n"), offset);
26307c478bd9Sstevel@tonic-gate 		return (mdstealerror(ep, &read_params.mde));
26317c478bd9Sstevel@tonic-gate 	}
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	/* make sure magic number is correct */
26347c478bd9Sstevel@tonic-gate 	if (wm->wm_magic != MD_SP_MAGIC) {
26357c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
26367c478bd9Sstevel@tonic-gate 		    "found incorrect magic number %x, expected %x.\n"),
26377c478bd9Sstevel@tonic-gate 		    wm->wm_magic, MD_SP_MAGIC);
26387c478bd9Sstevel@tonic-gate 		/*
26397c478bd9Sstevel@tonic-gate 		 * Pass NULL for the device name as we don't have
26407c478bd9Sstevel@tonic-gate 		 * valid watermark contents.
26417c478bd9Sstevel@tonic-gate 		 */
26427c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BADWMMAGIC, 0, NULL));
26437c478bd9Sstevel@tonic-gate 	}
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate 	if (crcchk((uchar_t *)wm, (uint_t *)&wm->wm_checksum,
26467c478bd9Sstevel@tonic-gate 	    sizeof (*wm), NULL)) {
26477c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
26487c478bd9Sstevel@tonic-gate 		    "found incorrect checksum %x.\n"),
26497c478bd9Sstevel@tonic-gate 		    wm->wm_checksum);
26507c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BADWMCRC, 0, wm->wm_mdname));
26517c478bd9Sstevel@tonic-gate 	}
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 	return (0);
26547c478bd9Sstevel@tonic-gate }
26557c478bd9Sstevel@tonic-gate 
26567c478bd9Sstevel@tonic-gate /*
26577c478bd9Sstevel@tonic-gate  * **************************************************************************
26587c478bd9Sstevel@tonic-gate  *                  Query Functions
26597c478bd9Sstevel@tonic-gate  * **************************************************************************
26607c478bd9Sstevel@tonic-gate  */
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate /*
26637c478bd9Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that assumes that
26647c478bd9Sstevel@tonic-gate  *		   its input parameters have been checked and
26657c478bd9Sstevel@tonic-gate  *		   have valid values that lie within acceptable
26667c478bd9Sstevel@tonic-gate  *		   ranges.
26677c478bd9Sstevel@tonic-gate  *
26687c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_enough_space()
26697c478bd9Sstevel@tonic-gate  * INPUT:	desired_number_of_sps - the number of soft partitions desired;
26707c478bd9Sstevel@tonic-gate  *					must be > 0
26717c478bd9Sstevel@tonic-gate  *		desired_sp_size - the desired soft partition size in blocks;
26727c478bd9Sstevel@tonic-gate  *				  must be > 0
26737c478bd9Sstevel@tonic-gate  *		extent_listpp - a reference to a reference to an extent
26747c478bd9Sstevel@tonic-gate  *				list that lists the extents on a device;
26757c478bd9Sstevel@tonic-gate  *				must be a reference to a reference to a
26767c478bd9Sstevel@tonic-gate  *				valid extent list
26777c478bd9Sstevel@tonic-gate  *		alignment - the desired data space alignment for the sp's
26787c478bd9Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
26797c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if there's enough space in the extent
26807c478bd9Sstevel@tonic-gate  *			    list to create the desired soft partitions,
26817c478bd9Sstevel@tonic-gate  *			    B_FALSE if there's not enough space
26827c478bd9Sstevel@tonic-gate  * PURPOSE:	determines whether there's enough free space in an extent
26837c478bd9Sstevel@tonic-gate  *		list to allow creation of a set of soft partitions
26847c478bd9Sstevel@tonic-gate  */
26857c478bd9Sstevel@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)26867c478bd9Sstevel@tonic-gate meta_sp_enough_space(
26877c478bd9Sstevel@tonic-gate 	int		desired_number_of_sps,
26887c478bd9Sstevel@tonic-gate 	blkcnt_t	desired_sp_size,
26897c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp,
26907c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alignment
26917c478bd9Sstevel@tonic-gate )
26927c478bd9Sstevel@tonic-gate {
26937c478bd9Sstevel@tonic-gate 	boolean_t		enough_space;
26947c478bd9Sstevel@tonic-gate 	int			number_of_sps;
26957c478bd9Sstevel@tonic-gate 	int			number_of_extents_used;
26967c478bd9Sstevel@tonic-gate 	sp_ext_length_t		desired_ext_length = desired_sp_size;
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 	enough_space = B_TRUE;
26997c478bd9Sstevel@tonic-gate 	number_of_sps = 0;
27007c478bd9Sstevel@tonic-gate 	while ((enough_space == B_TRUE) &&
27017c478bd9Sstevel@tonic-gate 	    (number_of_sps < desired_number_of_sps)) {
27027c478bd9Sstevel@tonic-gate 		/*
27037c478bd9Sstevel@tonic-gate 		 * Use the extent allocation algorithm implemented by
27047c478bd9Sstevel@tonic-gate 		 * meta_sp_alloc_by_len() to test whether the free
27057c478bd9Sstevel@tonic-gate 		 * extents in the extent list referenced by *extent_listpp
27067c478bd9Sstevel@tonic-gate 		 * contain enough space to accomodate a soft partition
27077c478bd9Sstevel@tonic-gate 		 * of size desired_ext_length.
27087c478bd9Sstevel@tonic-gate 		 *
27097c478bd9Sstevel@tonic-gate 		 * Repeat the test <desired_number_of_sps> times
27107c478bd9Sstevel@tonic-gate 		 * or until it fails, whichever comes first,
27117c478bd9Sstevel@tonic-gate 		 * each time allocating the extents required to
27127c478bd9Sstevel@tonic-gate 		 * create the soft partition without actually
27137c478bd9Sstevel@tonic-gate 		 * creating the soft partition.
27147c478bd9Sstevel@tonic-gate 		 */
27157c478bd9Sstevel@tonic-gate 		number_of_extents_used = meta_sp_alloc_by_len(
27161cd3f00bSsk102515 		    TEST_SETNAMEP, TEST_SOFT_PARTITION_NAMEP,
27171cd3f00bSsk102515 		    extent_listpp, &desired_ext_length,
27181cd3f00bSsk102515 		    NO_OFFSET, alignment);
27197c478bd9Sstevel@tonic-gate 		if (number_of_extents_used == -1) {
27207c478bd9Sstevel@tonic-gate 			enough_space = B_FALSE;
27217c478bd9Sstevel@tonic-gate 		} else {
27227c478bd9Sstevel@tonic-gate 			number_of_sps++;
27237c478bd9Sstevel@tonic-gate 		}
27247c478bd9Sstevel@tonic-gate 	}
27257c478bd9Sstevel@tonic-gate 	return (enough_space);
27267c478bd9Sstevel@tonic-gate }
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate /*
27297c478bd9Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that calls other functions
27307c478bd9Sstevel@tonic-gate  *		   that check its mdsetnamep and device_mdnamep
27317c478bd9Sstevel@tonic-gate  *		   input parameters, but expects extent_listpp to
27327c478bd9Sstevel@tonic-gate  *		   be a initialized to a valid address to which
27337c478bd9Sstevel@tonic-gate  *		   it can write a reference to the extent list that
27347c478bd9Sstevel@tonic-gate  *		   it creates.
27357c478bd9Sstevel@tonic-gate  *
27367c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_extent_list()
27377c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
27387c478bd9Sstevel@tonic-gate  *			     for the set containing the device for
27397c478bd9Sstevel@tonic-gate  *			     which the extents are to be listed
27407c478bd9Sstevel@tonic-gate  *		device_mdnamep - a reference to the mdname_t structure
27417c478bd9Sstevel@tonic-gate  *				 for the device for which the extents
27427c478bd9Sstevel@tonic-gate  *				 are to be listed
27437c478bd9Sstevel@tonic-gate  * OUTPUT:	*extent_listpp - a reference to the extent list for
27447c478bd9Sstevel@tonic-gate  *				 the device; NULL if the function fails
27457c478bd9Sstevel@tonic-gate  *		*ep - the libmeta error encountered, if any
27467c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the function call was successful,
27477c478bd9Sstevel@tonic-gate  *			    B_FALSE if not
27487c478bd9Sstevel@tonic-gate  * PURPOSE:	gets the extent list for a device
27497c478bd9Sstevel@tonic-gate  */
27507c478bd9Sstevel@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)27517c478bd9Sstevel@tonic-gate meta_sp_get_extent_list(
27527c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
27537c478bd9Sstevel@tonic-gate 	mdname_t	*device_mdnamep,
27547c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp,
27557c478bd9Sstevel@tonic-gate 	md_error_t	*ep
27567c478bd9Sstevel@tonic-gate )
27577c478bd9Sstevel@tonic-gate {
27587c478bd9Sstevel@tonic-gate 	diskaddr_t		device_size_in_blocks;
27597c478bd9Sstevel@tonic-gate 	mdnamelist_t		*sp_name_listp;
27607c478bd9Sstevel@tonic-gate 	diskaddr_t		start_block_address_in_blocks;
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 	*extent_listpp = NULL;
27637c478bd9Sstevel@tonic-gate 	sp_name_listp = NULL;
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	start_block_address_in_blocks = meta_sp_get_start(mdsetnamep,
27661cd3f00bSsk102515 	    device_mdnamep, ep);
27677c478bd9Sstevel@tonic-gate 	if (start_block_address_in_blocks == MD_DISKADDR_ERROR) {
27687c478bd9Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
27691cd3f00bSsk102515 			mde_perror(ep,
27701cd3f00bSsk102515 			    "meta_sp_get_extent_list:meta_sp_get_start");
27717c478bd9Sstevel@tonic-gate 		}
27727c478bd9Sstevel@tonic-gate 		return (B_FALSE);
27737c478bd9Sstevel@tonic-gate 	}
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate 	device_size_in_blocks = metagetsize(device_mdnamep, ep);
27767c478bd9Sstevel@tonic-gate 	if (device_size_in_blocks == MD_DISKADDR_ERROR) {
27777c478bd9Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
27787c478bd9Sstevel@tonic-gate 			mde_perror(ep,
27797c478bd9Sstevel@tonic-gate 			    "meta_sp_get_extent_list:metagetsize");
27807c478bd9Sstevel@tonic-gate 		}
27817c478bd9Sstevel@tonic-gate 		return (B_FALSE);
27827c478bd9Sstevel@tonic-gate 	}
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	/*
27857c478bd9Sstevel@tonic-gate 	 * Sanity check: the start block will have skipped an integer
27867c478bd9Sstevel@tonic-gate 	 * number of cylinders, C.  C will usually be zero.  If (C > 0),
27877c478bd9Sstevel@tonic-gate 	 * and the disk slice happens to only be C cylinders in total
27887c478bd9Sstevel@tonic-gate 	 * size, we'll fail this check.
27897c478bd9Sstevel@tonic-gate 	 */
27907c478bd9Sstevel@tonic-gate 	if (device_size_in_blocks <=
27917c478bd9Sstevel@tonic-gate 	    (start_block_address_in_blocks + MD_SP_WMSIZE)) {
27927c478bd9Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_SP_NOSPACE, 0, device_mdnamep->cname);
27937c478bd9Sstevel@tonic-gate 		return (B_FALSE);
27947c478bd9Sstevel@tonic-gate 	}
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 	/*
27977c478bd9Sstevel@tonic-gate 	 * After this point, we will have allocated resources, so any
27987c478bd9Sstevel@tonic-gate 	 * failure returns must be through the supplied "fail" label
27997c478bd9Sstevel@tonic-gate 	 * to properly deallocate things.
28007c478bd9Sstevel@tonic-gate 	 */
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 	/*
28037c478bd9Sstevel@tonic-gate 	 * Create an empty extent list that starts one watermark past
28047c478bd9Sstevel@tonic-gate 	 * the start block of the device and ends one watermark before
28057c478bd9Sstevel@tonic-gate 	 * the end of the device.
28067c478bd9Sstevel@tonic-gate 	 */
28071cd3f00bSsk102515 	meta_sp_list_insert(TEST_SETNAMEP, TEST_SOFT_PARTITION_NAMEP,
28081cd3f00bSsk102515 	    extent_listpp, NO_OFFSET,
28097c478bd9Sstevel@tonic-gate 	    (sp_ext_length_t)start_block_address_in_blocks,
28101cd3f00bSsk102515 	    EXTTYP_RESERVED, NO_SEQUENCE_NUMBER, NO_FLAGS,
28117c478bd9Sstevel@tonic-gate 	    meta_sp_cmp_by_offset);
28121cd3f00bSsk102515 	meta_sp_list_insert(TEST_SETNAMEP, TEST_SOFT_PARTITION_NAMEP,
28131cd3f00bSsk102515 	    extent_listpp, (sp_ext_offset_t)(device_size_in_blocks -
28141cd3f00bSsk102515 	    MD_SP_WMSIZE), MD_SP_WMSIZE, EXTTYP_END, NO_SEQUENCE_NUMBER,
28151cd3f00bSsk102515 	    NO_FLAGS, meta_sp_cmp_by_offset);
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	/*
28187c478bd9Sstevel@tonic-gate 	 * Get the list of soft partitions that are already on the
28197c478bd9Sstevel@tonic-gate 	 * device.
28207c478bd9Sstevel@tonic-gate 	 */
28217c478bd9Sstevel@tonic-gate 	if (meta_sp_get_by_component(mdsetnamep, device_mdnamep,
28227c478bd9Sstevel@tonic-gate 	    &sp_name_listp, FORCE_RELOAD_CACHE, ep) < 1) {
28237c478bd9Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
28247c478bd9Sstevel@tonic-gate 			mde_perror(ep,
28257c478bd9Sstevel@tonic-gate 			    "meta_sp_get_extent_list:meta_sp_get_by_component");
28267c478bd9Sstevel@tonic-gate 		}
28277c478bd9Sstevel@tonic-gate 		goto fail;
28287c478bd9Sstevel@tonic-gate 	}
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	if (sp_name_listp != NULL) {
28317c478bd9Sstevel@tonic-gate 		/*
28327c478bd9Sstevel@tonic-gate 		 * If there are soft partitions on the device, add the
28337c478bd9Sstevel@tonic-gate 		 * extents used in them to the extent list.
28347c478bd9Sstevel@tonic-gate 		 */
28357c478bd9Sstevel@tonic-gate 		if (meta_sp_extlist_from_namelist(mdsetnamep, sp_name_listp,
28367c478bd9Sstevel@tonic-gate 		    extent_listpp, ep) == -1) {
28377c478bd9Sstevel@tonic-gate 			if (getenv(META_SP_DEBUG)) {
28387c478bd9Sstevel@tonic-gate 				mde_perror(ep, "meta_sp_get_extent_list:"
28397c478bd9Sstevel@tonic-gate 				    "meta_sp_extlist_from_namelist");
28407c478bd9Sstevel@tonic-gate 			}
28417c478bd9Sstevel@tonic-gate 			goto fail;
28427c478bd9Sstevel@tonic-gate 		}
28437c478bd9Sstevel@tonic-gate 		metafreenamelist(sp_name_listp);
28447c478bd9Sstevel@tonic-gate 	}
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	/*
28477c478bd9Sstevel@tonic-gate 	 * Add free extents to the extent list to represent
28487c478bd9Sstevel@tonic-gate 	 * the remaining regions of free space on the
28497c478bd9Sstevel@tonic-gate 	 * device.
28507c478bd9Sstevel@tonic-gate 	 */
28517c478bd9Sstevel@tonic-gate 	meta_sp_list_freefill(extent_listpp, device_size_in_blocks);
28527c478bd9Sstevel@tonic-gate 	return (B_TRUE);
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate fail:
28557c478bd9Sstevel@tonic-gate 	if (sp_name_listp != NULL) {
28567c478bd9Sstevel@tonic-gate 		metafreenamelist(sp_name_listp);
28577c478bd9Sstevel@tonic-gate 	}
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	if (*extent_listpp != NULL) {
28607c478bd9Sstevel@tonic-gate 		/*
28617c478bd9Sstevel@tonic-gate 		 * meta_sp_list_free sets *extent_listpp to NULL.
28627c478bd9Sstevel@tonic-gate 		 */
28637c478bd9Sstevel@tonic-gate 		meta_sp_list_free(extent_listpp);
28647c478bd9Sstevel@tonic-gate 	}
28657c478bd9Sstevel@tonic-gate 	return (B_FALSE);
28667c478bd9Sstevel@tonic-gate }
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate /*
28697c478bd9Sstevel@tonic-gate  * IMPORTANT NOTE: This is a static function that calls other functions
28707c478bd9Sstevel@tonic-gate  *		   that check its mdsetnamep and mddrivenamep
28717c478bd9Sstevel@tonic-gate  *		   input parameters, but expects extent_listpp to
28727c478bd9Sstevel@tonic-gate  *		   be a initialized to a valid address to which
28737c478bd9Sstevel@tonic-gate  *		   it can write a reference to the extent list that
28747c478bd9Sstevel@tonic-gate  *		   it creates.
28757c478bd9Sstevel@tonic-gate  *
28767c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_extent_list_for_drive()
28777c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
28787c478bd9Sstevel@tonic-gate  *			     for the set containing the drive for
28797c478bd9Sstevel@tonic-gate  *			     which the extents are to be listed
28807c478bd9Sstevel@tonic-gate  *		mddrivenamep   - a reference to the mddrivename_t structure
28817c478bd9Sstevel@tonic-gate  *				 for the drive for which the extents
28827c478bd9Sstevel@tonic-gate  *				 are to be listed
28837c478bd9Sstevel@tonic-gate  * OUTPUT:	*extent_listpp - a reference to the extent list for
28847c478bd9Sstevel@tonic-gate  *				 the drive; NULL if the function fails
28857c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the function call was successful,
28867c478bd9Sstevel@tonic-gate  *			    B_FALSE if not
28877c478bd9Sstevel@tonic-gate  * PURPOSE:	gets the extent list for a drive when the entire drive
28887c478bd9Sstevel@tonic-gate  *		is to be soft partitioned
28897c478bd9Sstevel@tonic-gate  */
28907c478bd9Sstevel@tonic-gate static boolean_t
meta_sp_get_extent_list_for_drive(mdsetname_t * mdsetnamep,mddrivename_t * mddrivenamep,sp_ext_node_t ** extent_listpp)28917c478bd9Sstevel@tonic-gate meta_sp_get_extent_list_for_drive(
28927c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
28937c478bd9Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
28947c478bd9Sstevel@tonic-gate 	sp_ext_node_t	**extent_listpp
28957c478bd9Sstevel@tonic-gate )
28967c478bd9Sstevel@tonic-gate {
28977c478bd9Sstevel@tonic-gate 	boolean_t		can_use;
28987c478bd9Sstevel@tonic-gate 	diskaddr_t		free_space;
28997c478bd9Sstevel@tonic-gate 	md_error_t		mderror;
29007c478bd9Sstevel@tonic-gate 	mdvtoc_t		proposed_vtoc;
29017c478bd9Sstevel@tonic-gate 	int			repartition_options;
29027c478bd9Sstevel@tonic-gate 	int			return_value;
29037c478bd9Sstevel@tonic-gate 	md_sp_t			test_sp_struct;
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	can_use = B_TRUE;
29067c478bd9Sstevel@tonic-gate 	*extent_listpp = NULL;
29077c478bd9Sstevel@tonic-gate 	mderror = mdnullerror;
29087c478bd9Sstevel@tonic-gate 	test_sp_struct.compnamep = metaslicename(mddrivenamep, MD_SLICE0,
29097c478bd9Sstevel@tonic-gate 	    &mderror);
29107c478bd9Sstevel@tonic-gate 	if (test_sp_struct.compnamep == NULL) {
29117c478bd9Sstevel@tonic-gate 		can_use = B_FALSE;
29127c478bd9Sstevel@tonic-gate 	}
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate 	if (can_use == B_TRUE) {
29157c478bd9Sstevel@tonic-gate 		mderror = mdnullerror;
29167c478bd9Sstevel@tonic-gate 		repartition_options = 0;
29177c478bd9Sstevel@tonic-gate 		return_value = meta_check_sp(mdsetnamep, &test_sp_struct,
29181cd3f00bSsk102515 		    MDCMD_USE_WHOLE_DISK, &repartition_options, &mderror);
29197c478bd9Sstevel@tonic-gate 		if (return_value != 0) {
29207c478bd9Sstevel@tonic-gate 			can_use = B_FALSE;
29217c478bd9Sstevel@tonic-gate 		}
29227c478bd9Sstevel@tonic-gate 	}
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 	if (can_use == B_TRUE) {
29257c478bd9Sstevel@tonic-gate 		mderror = mdnullerror;
29267c478bd9Sstevel@tonic-gate 		repartition_options = repartition_options |
29277c478bd9Sstevel@tonic-gate 		    (MD_REPART_FORCE | MD_REPART_DONT_LABEL);
29287c478bd9Sstevel@tonic-gate 		return_value = meta_repartition_drive(mdsetnamep, mddrivenamep,
29297c478bd9Sstevel@tonic-gate 		    repartition_options, &proposed_vtoc, &mderror);
29307c478bd9Sstevel@tonic-gate 		if (return_value != 0) {
29317c478bd9Sstevel@tonic-gate 			can_use = B_FALSE;
29327c478bd9Sstevel@tonic-gate 		}
29337c478bd9Sstevel@tonic-gate 	}
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate 	if (can_use == B_TRUE) {
29367c478bd9Sstevel@tonic-gate 		free_space = proposed_vtoc.parts[MD_SLICE0].size;
29377c478bd9Sstevel@tonic-gate 		if (free_space <= (MD_SP_START + MD_SP_WMSIZE)) {
29387c478bd9Sstevel@tonic-gate 			can_use = B_FALSE;
29397c478bd9Sstevel@tonic-gate 		}
29407c478bd9Sstevel@tonic-gate 	}
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 	if (can_use == B_TRUE) {
29437c478bd9Sstevel@tonic-gate 		/*
29447c478bd9Sstevel@tonic-gate 		 * Create an extent list that starts with
29457c478bd9Sstevel@tonic-gate 		 * a reserved extent that ends at the start
29467c478bd9Sstevel@tonic-gate 		 * of the usable space on slice zero of the
29477c478bd9Sstevel@tonic-gate 		 * proposed VTOC, ends with an extent that
29487c478bd9Sstevel@tonic-gate 		 * reserves space for a watermark at the end
29497c478bd9Sstevel@tonic-gate 		 * of slice zero, and contains a single free
29507c478bd9Sstevel@tonic-gate 		 * extent that occupies the rest of the space
29517c478bd9Sstevel@tonic-gate 		 * on the slice.
29527c478bd9Sstevel@tonic-gate 		 *
29537c478bd9Sstevel@tonic-gate 		 * NOTE:
29547c478bd9Sstevel@tonic-gate 		 *
29557c478bd9Sstevel@tonic-gate 		 * Don't use metagetstart() or metagetsize() to
29567c478bd9Sstevel@tonic-gate 		 * find the usable space.  They query the mdname_t
29577c478bd9Sstevel@tonic-gate 		 * structure that represents an actual device to
29587c478bd9Sstevel@tonic-gate 		 * determine the amount of space on the device that
29597c478bd9Sstevel@tonic-gate 		 * contains metadata and the total amount of space
29607c478bd9Sstevel@tonic-gate 		 * on the device.  Since this function creates a
29617c478bd9Sstevel@tonic-gate 		 * proposed extent list that doesn't reflect the
29627c478bd9Sstevel@tonic-gate 		 * state of an actual device, there's no mdname_t
29637c478bd9Sstevel@tonic-gate 		 * structure to be queried.
29647c478bd9Sstevel@tonic-gate 		 *
29657c478bd9Sstevel@tonic-gate 		 * When a drive is reformatted to prepare for
29667c478bd9Sstevel@tonic-gate 		 * soft partitioning, all of slice seven is
29677c478bd9Sstevel@tonic-gate 		 * reserved for metadata, all of slice zero is
29687c478bd9Sstevel@tonic-gate 		 * available for soft partitioning, and all other
29697c478bd9Sstevel@tonic-gate 		 * slices on the drive are empty.  The proposed
29707c478bd9Sstevel@tonic-gate 		 * extent list for the drive therefore contains
29717c478bd9Sstevel@tonic-gate 		 * only three extents: a reserved extent that ends
29727c478bd9Sstevel@tonic-gate 		 * at the start of the usable space on slice zero,
29737c478bd9Sstevel@tonic-gate 		 * a single free extent that occupies all the usable
29747c478bd9Sstevel@tonic-gate 		 * space on slice zero, and an ending extent that
29757c478bd9Sstevel@tonic-gate 		 * reserves space for a watermark at the end of
29767c478bd9Sstevel@tonic-gate 		 * slice zero.
29777c478bd9Sstevel@tonic-gate 		 */
29781cd3f00bSsk102515 		meta_sp_list_insert(TEST_SETNAMEP, TEST_SOFT_PARTITION_NAMEP,
29791cd3f00bSsk102515 		    extent_listpp, NO_OFFSET, (sp_ext_length_t)(MD_SP_START),
29801cd3f00bSsk102515 		    EXTTYP_RESERVED, NO_SEQUENCE_NUMBER, NO_FLAGS,
29817c478bd9Sstevel@tonic-gate 		    meta_sp_cmp_by_offset);
29821cd3f00bSsk102515 		meta_sp_list_insert(TEST_SETNAMEP, TEST_SOFT_PARTITION_NAMEP,
29831cd3f00bSsk102515 		    extent_listpp, (sp_ext_offset_t)(free_space - MD_SP_WMSIZE),
29841cd3f00bSsk102515 		    MD_SP_WMSIZE, EXTTYP_END, NO_SEQUENCE_NUMBER, NO_FLAGS,
29857c478bd9Sstevel@tonic-gate 		    meta_sp_cmp_by_offset);
29867c478bd9Sstevel@tonic-gate 		meta_sp_list_freefill(extent_listpp, free_space);
29877c478bd9Sstevel@tonic-gate 	}
29887c478bd9Sstevel@tonic-gate 	return (can_use);
29897c478bd9Sstevel@tonic-gate }
29907c478bd9Sstevel@tonic-gate 
29917c478bd9Sstevel@tonic-gate /*
29927c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_can_create_sps()
29937c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
29947c478bd9Sstevel@tonic-gate  *			     for the set containing the device for
29957c478bd9Sstevel@tonic-gate  *			     which the extents are to be listed
29967c478bd9Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
29977c478bd9Sstevel@tonic-gate  *			  on which the soft parititions are to be created
29987c478bd9Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
29997c478bd9Sstevel@tonic-gate  *		sp_size - the desired soft partition size
30007c478bd9Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
30017c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the soft partitionns can be created,
30027c478bd9Sstevel@tonic-gate  *			    B_FALSE if not
30037c478bd9Sstevel@tonic-gate  * PURPOSE:	determines whether a set of soft partitions can be created
30047c478bd9Sstevel@tonic-gate  *		on a device
30057c478bd9Sstevel@tonic-gate  */
30067c478bd9Sstevel@tonic-gate boolean_t
meta_sp_can_create_sps(mdsetname_t * mdsetnamep,mdname_t * mdnamep,int number_of_sps,blkcnt_t sp_size)30077c478bd9Sstevel@tonic-gate meta_sp_can_create_sps(
30087c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
30097c478bd9Sstevel@tonic-gate 	mdname_t	*mdnamep,
30107c478bd9Sstevel@tonic-gate 	int		number_of_sps,
30117c478bd9Sstevel@tonic-gate 	blkcnt_t	sp_size
30127c478bd9Sstevel@tonic-gate )
30137c478bd9Sstevel@tonic-gate {
30147c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
30157c478bd9Sstevel@tonic-gate 	boolean_t	succeeded;
30167c478bd9Sstevel@tonic-gate 	md_error_t	mde;
30177c478bd9Sstevel@tonic-gate 
30187c478bd9Sstevel@tonic-gate 	if ((number_of_sps > 0) && (sp_size > 0)) {
30197c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list(mdsetnamep, mdnamep,
30207c478bd9Sstevel@tonic-gate 		    &extent_listp, &mde);
30217c478bd9Sstevel@tonic-gate 	} else {
30227c478bd9Sstevel@tonic-gate 		succeeded = B_FALSE;
30237c478bd9Sstevel@tonic-gate 	}
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	/*
30267c478bd9Sstevel@tonic-gate 	 * We don't really care about an error return from the
30277c478bd9Sstevel@tonic-gate 	 * alignment call; that will just result in passing zero,
30287c478bd9Sstevel@tonic-gate 	 * which will be interpreted as no alignment.
30297c478bd9Sstevel@tonic-gate 	 */
30307c478bd9Sstevel@tonic-gate 
30317c478bd9Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
30327c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(number_of_sps,
30337c478bd9Sstevel@tonic-gate 		    sp_size, &extent_listp,
30347c478bd9Sstevel@tonic-gate 		    meta_sp_get_default_alignment(mdsetnamep, mdnamep, &mde));
30357c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
30367c478bd9Sstevel@tonic-gate 	}
30377c478bd9Sstevel@tonic-gate 	return (succeeded);
30387c478bd9Sstevel@tonic-gate }
30397c478bd9Sstevel@tonic-gate 
30407c478bd9Sstevel@tonic-gate /*
30417c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_can_create_sps_on_drive()
30427c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
30437c478bd9Sstevel@tonic-gate  *			     for the set containing the drive for
30447c478bd9Sstevel@tonic-gate  *			     which the extents are to be listed
30457c478bd9Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
30467c478bd9Sstevel@tonic-gate  *			       on which the soft parititions are to be created
30477c478bd9Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
30487c478bd9Sstevel@tonic-gate  *		sp_size - the desired soft partition size
30497c478bd9Sstevel@tonic-gate  * OUTPUT:	boolean_t return value
30507c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the soft partitionns can be created,
30517c478bd9Sstevel@tonic-gate  *			    B_FALSE if not
30527c478bd9Sstevel@tonic-gate  * PURPOSE:	determines whether a set of soft partitions can be created
30537c478bd9Sstevel@tonic-gate  *		on a drive if the entire drive is soft partitioned
30547c478bd9Sstevel@tonic-gate  */
30557c478bd9Sstevel@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)30567c478bd9Sstevel@tonic-gate meta_sp_can_create_sps_on_drive(
30577c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
30587c478bd9Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
30597c478bd9Sstevel@tonic-gate 	int		number_of_sps,
30607c478bd9Sstevel@tonic-gate 	blkcnt_t	sp_size
30617c478bd9Sstevel@tonic-gate )
30627c478bd9Sstevel@tonic-gate {
30637c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
30647c478bd9Sstevel@tonic-gate 	boolean_t	succeeded;
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate 	if ((number_of_sps > 0) && (sp_size > 0)) {
30677c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
30681cd3f00bSsk102515 		    mddrivenamep, &extent_listp);
30697c478bd9Sstevel@tonic-gate 	} else {
30707c478bd9Sstevel@tonic-gate 		succeeded = B_FALSE;
30717c478bd9Sstevel@tonic-gate 	}
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate 	/*
30747c478bd9Sstevel@tonic-gate 	 * We don't care about alignment on the space call because
30757c478bd9Sstevel@tonic-gate 	 * we're specifically dealing with a drive, which will have no
30767c478bd9Sstevel@tonic-gate 	 * inherent alignment.
30777c478bd9Sstevel@tonic-gate 	 */
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
30807c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(number_of_sps, sp_size,
30817c478bd9Sstevel@tonic-gate 		    &extent_listp, SP_UNALIGNED);
30827c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
30837c478bd9Sstevel@tonic-gate 	}
30847c478bd9Sstevel@tonic-gate 	return (succeeded);
30857c478bd9Sstevel@tonic-gate }
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate /*
30887c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_free_space()
30897c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
30907c478bd9Sstevel@tonic-gate  *			     for the set containing the device for
30917c478bd9Sstevel@tonic-gate  *			     which the free space is to be returned
30927c478bd9Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
30937c478bd9Sstevel@tonic-gate  *			  for which the free space is to be returned
30947c478bd9Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
30957c478bd9Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the number of blocks of free space on the device
30967c478bd9Sstevel@tonic-gate  * PURPOSE:	returns the number of blocks of free space on a device
30977c478bd9Sstevel@tonic-gate  */
30987c478bd9Sstevel@tonic-gate blkcnt_t
meta_sp_get_free_space(mdsetname_t * mdsetnamep,mdname_t * mdnamep)30997c478bd9Sstevel@tonic-gate meta_sp_get_free_space(
31007c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
31017c478bd9Sstevel@tonic-gate 	mdname_t	*mdnamep
31027c478bd9Sstevel@tonic-gate )
31037c478bd9Sstevel@tonic-gate {
31047c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*extent_listp;
31057c478bd9Sstevel@tonic-gate 	sp_ext_length_t		free_blocks;
31067c478bd9Sstevel@tonic-gate 	boolean_t		succeeded;
31077c478bd9Sstevel@tonic-gate 	md_error_t		mde;
31087c478bd9Sstevel@tonic-gate 
31097c478bd9Sstevel@tonic-gate 	extent_listp = NULL;
31107c478bd9Sstevel@tonic-gate 	free_blocks = 0;
31117c478bd9Sstevel@tonic-gate 	succeeded = meta_sp_get_extent_list(mdsetnamep, mdnamep,
31127c478bd9Sstevel@tonic-gate 	    &extent_listp, &mde);
31137c478bd9Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
31147c478bd9Sstevel@tonic-gate 		free_blocks = meta_sp_list_size(extent_listp,
31157c478bd9Sstevel@tonic-gate 		    EXTTYP_FREE, INCLUDE_WM);
31167c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
31177c478bd9Sstevel@tonic-gate 		if (free_blocks > (10 * MD_SP_WMSIZE)) {
31187c478bd9Sstevel@tonic-gate 			/*
31197c478bd9Sstevel@tonic-gate 			 * Subtract a safety margin for watermarks when
31207c478bd9Sstevel@tonic-gate 			 * computing the number of blocks available for
31217c478bd9Sstevel@tonic-gate 			 * use.  The actual number of watermarks can't
31227c478bd9Sstevel@tonic-gate 			 * be calculated without knowing the exact numbers
31237c478bd9Sstevel@tonic-gate 			 * and sizes of both the free extents and the soft
31247c478bd9Sstevel@tonic-gate 			 * partitions to be created.  The calculation is
31257c478bd9Sstevel@tonic-gate 			 * highly complex and error-prone even if those
31267c478bd9Sstevel@tonic-gate 			 * quantities are known.  The approximate value
31277c478bd9Sstevel@tonic-gate 			 * 10 * MD_SP_WMSIZE is within a few blocks of the
31287c478bd9Sstevel@tonic-gate 			 * correct value in all practical cases.
31297c478bd9Sstevel@tonic-gate 			 */
31307c478bd9Sstevel@tonic-gate 			free_blocks = free_blocks - (10 * MD_SP_WMSIZE);
31317c478bd9Sstevel@tonic-gate 		} else {
31327c478bd9Sstevel@tonic-gate 			free_blocks = 0;
31337c478bd9Sstevel@tonic-gate 		}
31347c478bd9Sstevel@tonic-gate 	} else {
31357c478bd9Sstevel@tonic-gate 		mdclrerror(&mde);
31367c478bd9Sstevel@tonic-gate 	}
31377c478bd9Sstevel@tonic-gate 
31387c478bd9Sstevel@tonic-gate 	return (free_blocks);
31397c478bd9Sstevel@tonic-gate }
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate /*
31427c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_free_space_on_drive()
31437c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
31447c478bd9Sstevel@tonic-gate  *			     for the set containing the drive for
31457c478bd9Sstevel@tonic-gate  *			     which the free space is to be returned
31467c478bd9Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
31477c478bd9Sstevel@tonic-gate  *			       for which the free space is to be returned
31487c478bd9Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
31497c478bd9Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the number of blocks of free space on the drive
31507c478bd9Sstevel@tonic-gate  * PURPOSE:	returns the number of blocks of space usable for soft
31517c478bd9Sstevel@tonic-gate  *		partitions on an entire drive, if the entire drive is
31527c478bd9Sstevel@tonic-gate  *		soft partitioned
31537c478bd9Sstevel@tonic-gate  */
31547c478bd9Sstevel@tonic-gate blkcnt_t
meta_sp_get_free_space_on_drive(mdsetname_t * mdsetnamep,mddrivename_t * mddrivenamep)31557c478bd9Sstevel@tonic-gate meta_sp_get_free_space_on_drive(
31567c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
31577c478bd9Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep
31587c478bd9Sstevel@tonic-gate )
31597c478bd9Sstevel@tonic-gate {
31607c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*extent_listp;
31617c478bd9Sstevel@tonic-gate 	sp_ext_length_t		free_blocks;
31627c478bd9Sstevel@tonic-gate 	boolean_t		succeeded;
31637c478bd9Sstevel@tonic-gate 
31647c478bd9Sstevel@tonic-gate 	extent_listp = NULL;
31657c478bd9Sstevel@tonic-gate 	free_blocks = 0;
31667c478bd9Sstevel@tonic-gate 	succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
31677c478bd9Sstevel@tonic-gate 	    mddrivenamep, &extent_listp);
31687c478bd9Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
31697c478bd9Sstevel@tonic-gate 		free_blocks = meta_sp_list_size(extent_listp,
31707c478bd9Sstevel@tonic-gate 		    EXTTYP_FREE, INCLUDE_WM);
31717c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
31727c478bd9Sstevel@tonic-gate 		if (free_blocks > (10 * MD_SP_WMSIZE)) {
31737c478bd9Sstevel@tonic-gate 			/*
31747c478bd9Sstevel@tonic-gate 			 * Subtract a safety margin for watermarks when
31757c478bd9Sstevel@tonic-gate 			 * computing the number of blocks available for
31767c478bd9Sstevel@tonic-gate 			 * use.  The actual number of watermarks can't
31777c478bd9Sstevel@tonic-gate 			 * be calculated without knowing the exact numbers
31787c478bd9Sstevel@tonic-gate 			 * and sizes of both the free extents and the soft
31797c478bd9Sstevel@tonic-gate 			 * partitions to be created.  The calculation is
31807c478bd9Sstevel@tonic-gate 			 * highly complex and error-prone even if those
31817c478bd9Sstevel@tonic-gate 			 * quantities are known.  The approximate value
31827c478bd9Sstevel@tonic-gate 			 * 10 * MD_SP_WMSIZE is within a few blocks of the
31837c478bd9Sstevel@tonic-gate 			 * correct value in all practical cases.
31847c478bd9Sstevel@tonic-gate 			 */
31857c478bd9Sstevel@tonic-gate 			free_blocks = free_blocks - (10 * MD_SP_WMSIZE);
31867c478bd9Sstevel@tonic-gate 		} else {
31877c478bd9Sstevel@tonic-gate 			free_blocks = 0;
31887c478bd9Sstevel@tonic-gate 		}
31897c478bd9Sstevel@tonic-gate 	}
31907c478bd9Sstevel@tonic-gate 	return (free_blocks);
31917c478bd9Sstevel@tonic-gate }
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate /*
31947c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_number_of_possible_sps()
31957c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
31967c478bd9Sstevel@tonic-gate  *			     for the set containing the device for
31977c478bd9Sstevel@tonic-gate  *			     which the number of possible soft partitions
31987c478bd9Sstevel@tonic-gate  *			     is to be returned
31997c478bd9Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
32007c478bd9Sstevel@tonic-gate  *			  for which the number of possible soft partitions
32017c478bd9Sstevel@tonic-gate  *			  is to be returned
32027c478bd9Sstevel@tonic-gate  * OUTPUT:	int return value
32037c478bd9Sstevel@tonic-gate  * RETURNS:	int - the number of soft partitions of the desired size
32047c478bd9Sstevel@tonic-gate  *		      that can be created on the device
32057c478bd9Sstevel@tonic-gate  * PURPOSE:	returns the number of soft partitions of a given size
32067c478bd9Sstevel@tonic-gate  *		that can be created on a device
32077c478bd9Sstevel@tonic-gate  */
32087c478bd9Sstevel@tonic-gate int
meta_sp_get_number_of_possible_sps(mdsetname_t * mdsetnamep,mdname_t * mdnamep,blkcnt_t sp_size)32097c478bd9Sstevel@tonic-gate meta_sp_get_number_of_possible_sps(
32107c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
32117c478bd9Sstevel@tonic-gate 	mdname_t	*mdnamep,
32127c478bd9Sstevel@tonic-gate 	blkcnt_t	sp_size
32137c478bd9Sstevel@tonic-gate )
32147c478bd9Sstevel@tonic-gate {
32157c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
32167c478bd9Sstevel@tonic-gate 	int		number_of_possible_sps;
32177c478bd9Sstevel@tonic-gate 	boolean_t	succeeded;
32187c478bd9Sstevel@tonic-gate 	md_error_t	mde;
32197c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alignment;
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 	extent_listp = NULL;
32227c478bd9Sstevel@tonic-gate 	number_of_possible_sps = 0;
32237c478bd9Sstevel@tonic-gate 	if (sp_size > 0) {
32247c478bd9Sstevel@tonic-gate 		if ((succeeded = meta_sp_get_extent_list(mdsetnamep,
32257c478bd9Sstevel@tonic-gate 		    mdnamep, &extent_listp, &mde)) == B_FALSE)
32267c478bd9Sstevel@tonic-gate 			mdclrerror(&mde);
32277c478bd9Sstevel@tonic-gate 	} else {
32287c478bd9Sstevel@tonic-gate 		succeeded = B_FALSE;
32297c478bd9Sstevel@tonic-gate 	}
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 	if (succeeded == B_TRUE) {
32327c478bd9Sstevel@tonic-gate 		alignment = meta_sp_get_default_alignment(mdsetnamep,
32337c478bd9Sstevel@tonic-gate 		    mdnamep, &mde);
32347c478bd9Sstevel@tonic-gate 	}
32357c478bd9Sstevel@tonic-gate 
32367c478bd9Sstevel@tonic-gate 	while (succeeded == B_TRUE) {
32377c478bd9Sstevel@tonic-gate 		/*
32387c478bd9Sstevel@tonic-gate 		 * Keep allocating space from the extent list
32397c478bd9Sstevel@tonic-gate 		 * for soft partitions of the desired size until
32407c478bd9Sstevel@tonic-gate 		 * there's not enough free space left in the list
32417c478bd9Sstevel@tonic-gate 		 * for another soft partiition of that size.
32427c478bd9Sstevel@tonic-gate 		 * Add one to the number of possible soft partitions
32437c478bd9Sstevel@tonic-gate 		 * for each soft partition for which there is
32447c478bd9Sstevel@tonic-gate 		 * enough free space left.
32457c478bd9Sstevel@tonic-gate 		 */
32467c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(ONE_SOFT_PARTITION,
32477c478bd9Sstevel@tonic-gate 		    sp_size, &extent_listp, alignment);
32487c478bd9Sstevel@tonic-gate 		if (succeeded == B_TRUE) {
32497c478bd9Sstevel@tonic-gate 			number_of_possible_sps++;
32507c478bd9Sstevel@tonic-gate 		}
32517c478bd9Sstevel@tonic-gate 	}
32527c478bd9Sstevel@tonic-gate 	if (extent_listp != NULL) {
32537c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
32547c478bd9Sstevel@tonic-gate 	}
32557c478bd9Sstevel@tonic-gate 	return (number_of_possible_sps);
32567c478bd9Sstevel@tonic-gate }
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate /*
32597c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_number_of_possible_sps_on_drive()
32607c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
32617c478bd9Sstevel@tonic-gate  *			     for the set containing the drive for
32627c478bd9Sstevel@tonic-gate  *			     which the number of possible soft partitions
32637c478bd9Sstevel@tonic-gate  *			     is to be returned
32647c478bd9Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
32657c478bd9Sstevel@tonic-gate  *			       for which the number of possible soft partitions
32667c478bd9Sstevel@tonic-gate  *			       is to be returned
32677c478bd9Sstevel@tonic-gate  *		sp_size - the size in blocks of the proposed soft partitions
32687c478bd9Sstevel@tonic-gate  * OUTPUT:	int return value
32697c478bd9Sstevel@tonic-gate  * RETURNS:	int - the number of soft partitions of the desired size
32707c478bd9Sstevel@tonic-gate  *		      that can be created on the drive
32717c478bd9Sstevel@tonic-gate  * PURPOSE:	returns the number of soft partitions of a given size
32727c478bd9Sstevel@tonic-gate  *		that can be created on a drive, if the entire drive is
32737c478bd9Sstevel@tonic-gate  *		soft partitioned
32747c478bd9Sstevel@tonic-gate  */
32757c478bd9Sstevel@tonic-gate int
meta_sp_get_number_of_possible_sps_on_drive(mdsetname_t * mdsetnamep,mddrivename_t * mddrivenamep,blkcnt_t sp_size)32767c478bd9Sstevel@tonic-gate meta_sp_get_number_of_possible_sps_on_drive(
32777c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
32787c478bd9Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
32797c478bd9Sstevel@tonic-gate 	blkcnt_t	sp_size
32807c478bd9Sstevel@tonic-gate )
32817c478bd9Sstevel@tonic-gate {
32827c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extent_listp;
32837c478bd9Sstevel@tonic-gate 	int		number_of_possible_sps;
32847c478bd9Sstevel@tonic-gate 	boolean_t	succeeded;
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate 	extent_listp = NULL;
32877c478bd9Sstevel@tonic-gate 	number_of_possible_sps = 0;
32887c478bd9Sstevel@tonic-gate 	if (sp_size > 0) {
32897c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_get_extent_list_for_drive(mdsetnamep,
32907c478bd9Sstevel@tonic-gate 		    mddrivenamep, &extent_listp);
32917c478bd9Sstevel@tonic-gate 	} else {
32927c478bd9Sstevel@tonic-gate 		succeeded = B_FALSE;
32937c478bd9Sstevel@tonic-gate 	}
32947c478bd9Sstevel@tonic-gate 	while (succeeded == B_TRUE) {
32957c478bd9Sstevel@tonic-gate 		/*
32967c478bd9Sstevel@tonic-gate 		 * Keep allocating space from the extent list
32977c478bd9Sstevel@tonic-gate 		 * for soft partitions of the desired size until
32987c478bd9Sstevel@tonic-gate 		 * there's not enough free space left in the list
32997c478bd9Sstevel@tonic-gate 		 * for another soft partition of that size.
33007c478bd9Sstevel@tonic-gate 		 * Add one to the number of possible soft partitions
33017c478bd9Sstevel@tonic-gate 		 * for each soft partition for which there is
33027c478bd9Sstevel@tonic-gate 		 * enough free space left.
33037c478bd9Sstevel@tonic-gate 		 *
33047c478bd9Sstevel@tonic-gate 		 * Since it's a drive, not a metadevice, make no
33057c478bd9Sstevel@tonic-gate 		 * assumptions about alignment.
33067c478bd9Sstevel@tonic-gate 		 */
33077c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_enough_space(ONE_SOFT_PARTITION,
33087c478bd9Sstevel@tonic-gate 		    sp_size, &extent_listp, SP_UNALIGNED);
33097c478bd9Sstevel@tonic-gate 		if (succeeded == B_TRUE) {
33107c478bd9Sstevel@tonic-gate 			number_of_possible_sps++;
33117c478bd9Sstevel@tonic-gate 		}
33127c478bd9Sstevel@tonic-gate 	}
33137c478bd9Sstevel@tonic-gate 	if (extent_listp != NULL) {
33147c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extent_listp);
33157c478bd9Sstevel@tonic-gate 	}
33167c478bd9Sstevel@tonic-gate 	return (number_of_possible_sps);
33177c478bd9Sstevel@tonic-gate }
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate /*
33207c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_possible_sp_size()
33217c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
33227c478bd9Sstevel@tonic-gate  *			     for the set containing the device for
33237c478bd9Sstevel@tonic-gate  *			     which the possible soft partition size
33247c478bd9Sstevel@tonic-gate  *			     is to be returned
33257c478bd9Sstevel@tonic-gate  *		mdnamep - a reference to the mdname_t of the device
33267c478bd9Sstevel@tonic-gate  *			  for which the possible soft partition size
33277c478bd9Sstevel@tonic-gate  *			  is to be returned
33287c478bd9Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
33297c478bd9Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
33307c478bd9Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the possible soft partition size in blocks
33317c478bd9Sstevel@tonic-gate  * PURPOSE:	returns the maximum possible size of each of a given number of
33327c478bd9Sstevel@tonic-gate  *		soft partitions of equal size that can be created on a device
33337c478bd9Sstevel@tonic-gate  */
33347c478bd9Sstevel@tonic-gate blkcnt_t
meta_sp_get_possible_sp_size(mdsetname_t * mdsetnamep,mdname_t * mdnamep,int number_of_sps)33357c478bd9Sstevel@tonic-gate meta_sp_get_possible_sp_size(
33367c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
33377c478bd9Sstevel@tonic-gate 	mdname_t	*mdnamep,
33387c478bd9Sstevel@tonic-gate 	int		number_of_sps
33397c478bd9Sstevel@tonic-gate )
33407c478bd9Sstevel@tonic-gate {
33417c478bd9Sstevel@tonic-gate 	blkcnt_t	free_blocks;
33427c478bd9Sstevel@tonic-gate 	blkcnt_t	sp_size;
33437c478bd9Sstevel@tonic-gate 	boolean_t	succeeded;
33447c478bd9Sstevel@tonic-gate 
33457c478bd9Sstevel@tonic-gate 	sp_size = 0;
33467c478bd9Sstevel@tonic-gate 	if (number_of_sps > 0) {
33477c478bd9Sstevel@tonic-gate 		free_blocks = meta_sp_get_free_space(mdsetnamep, mdnamep);
33487c478bd9Sstevel@tonic-gate 		sp_size = free_blocks / number_of_sps;
33497c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_can_create_sps(mdsetnamep, mdnamep,
33507c478bd9Sstevel@tonic-gate 		    number_of_sps, sp_size);
33517c478bd9Sstevel@tonic-gate 		while ((succeeded == B_FALSE) && (sp_size > 0)) {
33527c478bd9Sstevel@tonic-gate 			/*
33537c478bd9Sstevel@tonic-gate 			 * To compensate for space that may have been
33547c478bd9Sstevel@tonic-gate 			 * occupied by watermarks, reduce sp_size by a
33557c478bd9Sstevel@tonic-gate 			 * number of blocks equal to the number of soft
33567c478bd9Sstevel@tonic-gate 			 * partitions desired, and test again to see
33577c478bd9Sstevel@tonic-gate 			 * whether the desired number of soft partitions
33587c478bd9Sstevel@tonic-gate 			 * can be created.
33597c478bd9Sstevel@tonic-gate 			 */
33607c478bd9Sstevel@tonic-gate 			sp_size = sp_size - ((blkcnt_t)number_of_sps);
33617c478bd9Sstevel@tonic-gate 			succeeded = meta_sp_can_create_sps(mdsetnamep, mdnamep,
33627c478bd9Sstevel@tonic-gate 			    number_of_sps, sp_size);
33637c478bd9Sstevel@tonic-gate 		}
33647c478bd9Sstevel@tonic-gate 		if (sp_size < 0) {
33657c478bd9Sstevel@tonic-gate 			sp_size = 0;
33667c478bd9Sstevel@tonic-gate 		}
33677c478bd9Sstevel@tonic-gate 	}
33687c478bd9Sstevel@tonic-gate 	return (sp_size);
33697c478bd9Sstevel@tonic-gate }
33707c478bd9Sstevel@tonic-gate 
33717c478bd9Sstevel@tonic-gate /*
33727c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_get_possible_sp_size_on_drive()
33737c478bd9Sstevel@tonic-gate  * INPUT:	mdsetnamep - a reference to the mdsetname_t structure
33747c478bd9Sstevel@tonic-gate  *			     for the set containing the drive for
33757c478bd9Sstevel@tonic-gate  *			     which the possible soft partition size
33767c478bd9Sstevel@tonic-gate  *			     is to be returned
33777c478bd9Sstevel@tonic-gate  *		mddrivenamep - a reference to the mddrivename_t of the drive
33787c478bd9Sstevel@tonic-gate  *			       for which the possible soft partition size
33797c478bd9Sstevel@tonic-gate  *			       is to be returned
33807c478bd9Sstevel@tonic-gate  *		number_of_sps - the desired number of soft partitions
33817c478bd9Sstevel@tonic-gate  * OUTPUT:	blkcnt_t return value
33827c478bd9Sstevel@tonic-gate  * RETURNS:	blkcnt_t - the possible soft partition size in blocks
33837c478bd9Sstevel@tonic-gate  * PURPOSE:	returns the maximum possible size of each of a given number of
33847c478bd9Sstevel@tonic-gate  *		soft partitions of equal size that can be created on a drive
33857c478bd9Sstevel@tonic-gate  *              if the entire drive is soft partitioned
33867c478bd9Sstevel@tonic-gate  */
33877c478bd9Sstevel@tonic-gate blkcnt_t
meta_sp_get_possible_sp_size_on_drive(mdsetname_t * mdsetnamep,mddrivename_t * mddrivenamep,int number_of_sps)33887c478bd9Sstevel@tonic-gate meta_sp_get_possible_sp_size_on_drive(
33897c478bd9Sstevel@tonic-gate 	mdsetname_t	*mdsetnamep,
33907c478bd9Sstevel@tonic-gate 	mddrivename_t	*mddrivenamep,
33917c478bd9Sstevel@tonic-gate 	int		number_of_sps
33927c478bd9Sstevel@tonic-gate )
33937c478bd9Sstevel@tonic-gate {
33947c478bd9Sstevel@tonic-gate 	blkcnt_t	free_blocks;
33957c478bd9Sstevel@tonic-gate 	blkcnt_t	sp_size;
33967c478bd9Sstevel@tonic-gate 	boolean_t	succeeded;
33977c478bd9Sstevel@tonic-gate 
33987c478bd9Sstevel@tonic-gate 	sp_size = 0;
33997c478bd9Sstevel@tonic-gate 	if (number_of_sps > 0) {
34007c478bd9Sstevel@tonic-gate 		free_blocks = meta_sp_get_free_space_on_drive(mdsetnamep,
34017c478bd9Sstevel@tonic-gate 		    mddrivenamep);
34027c478bd9Sstevel@tonic-gate 		sp_size = free_blocks / number_of_sps;
34037c478bd9Sstevel@tonic-gate 		succeeded = meta_sp_can_create_sps_on_drive(mdsetnamep,
34041cd3f00bSsk102515 		    mddrivenamep, number_of_sps, sp_size);
34057c478bd9Sstevel@tonic-gate 		while ((succeeded == B_FALSE) && (sp_size > 0)) {
34067c478bd9Sstevel@tonic-gate 			/*
34077c478bd9Sstevel@tonic-gate 			 * To compensate for space that may have been
34087c478bd9Sstevel@tonic-gate 			 * occupied by watermarks, reduce sp_size by a
34097c478bd9Sstevel@tonic-gate 			 * number of blocks equal to the number of soft
34107c478bd9Sstevel@tonic-gate 			 * partitions desired, and test again to see
34117c478bd9Sstevel@tonic-gate 			 * whether the desired number of soft partitions
34127c478bd9Sstevel@tonic-gate 			 * can be created.
34137c478bd9Sstevel@tonic-gate 			 */
34147c478bd9Sstevel@tonic-gate 			sp_size = sp_size - ((blkcnt_t)number_of_sps);
34157c478bd9Sstevel@tonic-gate 			succeeded = meta_sp_can_create_sps_on_drive(mdsetnamep,
34161cd3f00bSsk102515 			    mddrivenamep, number_of_sps, sp_size);
34177c478bd9Sstevel@tonic-gate 		}
34187c478bd9Sstevel@tonic-gate 		if (sp_size < 0) {
34197c478bd9Sstevel@tonic-gate 			sp_size = 0;
34207c478bd9Sstevel@tonic-gate 		}
34217c478bd9Sstevel@tonic-gate 	}
34227c478bd9Sstevel@tonic-gate 	return (sp_size);
34237c478bd9Sstevel@tonic-gate }
34247c478bd9Sstevel@tonic-gate 
34257c478bd9Sstevel@tonic-gate /*
34267c478bd9Sstevel@tonic-gate  * **************************************************************************
34277c478bd9Sstevel@tonic-gate  *                  Unit Structure Manipulation Functions                   *
34287c478bd9Sstevel@tonic-gate  * **************************************************************************
34297c478bd9Sstevel@tonic-gate  */
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate /*
34327c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_fillextarray()
34337c478bd9Sstevel@tonic-gate  * INPUT:	mp	- the unit structure to fill
34347c478bd9Sstevel@tonic-gate  *		extlist	- the list of extents to fill with
34357c478bd9Sstevel@tonic-gate  * OUTPUT:	none
34367c478bd9Sstevel@tonic-gate  * RETURNS:	void
34377c478bd9Sstevel@tonic-gate  * PURPOSE:	fills in the unit structure extent list with the extents
34387c478bd9Sstevel@tonic-gate  *		specified by extlist.  Only extents in extlist with the
34397c478bd9Sstevel@tonic-gate  *		EXTFLG_UPDATE flag are changed in the unit structure,
34407c478bd9Sstevel@tonic-gate  *		and the index into the unit structure is the sequence
34417c478bd9Sstevel@tonic-gate  *		number in the extent list.  After all of the nodes have
34427c478bd9Sstevel@tonic-gate  *		been updated the virtual offsets in the unit structure
34437c478bd9Sstevel@tonic-gate  *		are updated to reflect the new lengths.
34447c478bd9Sstevel@tonic-gate  */
34457c478bd9Sstevel@tonic-gate static void
meta_sp_fillextarray(mp_unit_t * mp,sp_ext_node_t * extlist)34467c478bd9Sstevel@tonic-gate meta_sp_fillextarray(
34477c478bd9Sstevel@tonic-gate 	mp_unit_t	*mp,
34487c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist
34497c478bd9Sstevel@tonic-gate )
34507c478bd9Sstevel@tonic-gate {
34517c478bd9Sstevel@tonic-gate 	int	i;
34527c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
34537c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	curvoff = 0LL;
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 	assert(mp != NULL);
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate 	/* go through the allocation list and fill in our unit structure */
34587c478bd9Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
34597c478bd9Sstevel@tonic-gate 		if ((ext->ext_type == EXTTYP_ALLOC) &&
34607c478bd9Sstevel@tonic-gate 		    (ext->ext_flags & EXTFLG_UPDATE) != 0) {
34617c478bd9Sstevel@tonic-gate 			mp->un_ext[ext->ext_seq].un_poff =
34627c478bd9Sstevel@tonic-gate 			    ext->ext_offset + MD_SP_WMSIZE;
34637c478bd9Sstevel@tonic-gate 			mp->un_ext[ext->ext_seq].un_len =
34647c478bd9Sstevel@tonic-gate 			    ext->ext_length - MD_SP_WMSIZE;
34657c478bd9Sstevel@tonic-gate 		}
34667c478bd9Sstevel@tonic-gate 	}
34677c478bd9Sstevel@tonic-gate 
34687c478bd9Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
34697c478bd9Sstevel@tonic-gate 		assert(mp->un_ext[i].un_poff != 0);
34707c478bd9Sstevel@tonic-gate 		assert(mp->un_ext[i].un_len  != 0);
34717c478bd9Sstevel@tonic-gate 		mp->un_ext[i].un_voff = curvoff;
34727c478bd9Sstevel@tonic-gate 		curvoff += mp->un_ext[i].un_len;
34737c478bd9Sstevel@tonic-gate 	}
34747c478bd9Sstevel@tonic-gate }
34757c478bd9Sstevel@tonic-gate 
34767c478bd9Sstevel@tonic-gate /*
34777c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_createunit()
34787c478bd9Sstevel@tonic-gate  * INPUT:	np	- the name of the device to create a unit structure for
34797c478bd9Sstevel@tonic-gate  *		compnp	- the name of the device the soft partition is on
34807c478bd9Sstevel@tonic-gate  *		extlist	- the extent list to populate the new unit with
34817c478bd9Sstevel@tonic-gate  *		numexts	- the number of extents in the extent list
34827c478bd9Sstevel@tonic-gate  *		len	- the total size of the soft partition (sectors)
34837c478bd9Sstevel@tonic-gate  *		status	- the initial status of the unit structure
34847c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
34857c478bd9Sstevel@tonic-gate  * RETURNS:	mp_unit_t * - the new unit structure.
34867c478bd9Sstevel@tonic-gate  * PURPOSE:	allocates and fills in a new soft partition unit
34877c478bd9Sstevel@tonic-gate  *		structure to be passed to the soft partitioning driver
34887c478bd9Sstevel@tonic-gate  *		for creation.
34897c478bd9Sstevel@tonic-gate  */
34907c478bd9Sstevel@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)34917c478bd9Sstevel@tonic-gate meta_sp_createunit(
34927c478bd9Sstevel@tonic-gate 	mdname_t	*np,
34937c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
34947c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
34957c478bd9Sstevel@tonic-gate 	int		numexts,
34967c478bd9Sstevel@tonic-gate 	sp_ext_length_t	len,
34977c478bd9Sstevel@tonic-gate 	sp_status_t	status,
34987c478bd9Sstevel@tonic-gate 	md_error_t	*ep
34997c478bd9Sstevel@tonic-gate )
35007c478bd9Sstevel@tonic-gate {
35017c478bd9Sstevel@tonic-gate 	mp_unit_t	*mp;
35027c478bd9Sstevel@tonic-gate 	uint_t		ms_size;
35037c478bd9Sstevel@tonic-gate 
35047c478bd9Sstevel@tonic-gate 	ms_size = (sizeof (*mp) - sizeof (mp->un_ext[0])) +
35057c478bd9Sstevel@tonic-gate 	    (numexts * sizeof (mp->un_ext[0]));
35067c478bd9Sstevel@tonic-gate 
35077c478bd9Sstevel@tonic-gate 	mp = Zalloc(ms_size);
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate 	/* fill in fields in common unit structure */
35107c478bd9Sstevel@tonic-gate 	mp->c.un_type = MD_METASP;
35117c478bd9Sstevel@tonic-gate 	mp->c.un_size = ms_size;
35127c478bd9Sstevel@tonic-gate 	MD_SID(mp) = meta_getminor(np->dev);
35137c478bd9Sstevel@tonic-gate 	mp->c.un_total_blocks = len;
35147c478bd9Sstevel@tonic-gate 	mp->c.un_actual_tb = len;
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate 	/* set up geometry */
35177c478bd9Sstevel@tonic-gate 	(void) meta_sp_setgeom(np, compnp, mp, ep);
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate 	/* if we're building on metadevice we can't parent */
35207c478bd9Sstevel@tonic-gate 	if (metaismeta(compnp))
35217c478bd9Sstevel@tonic-gate 		MD_CAPAB(mp) = MD_CANT_PARENT;
35227c478bd9Sstevel@tonic-gate 	else
35237c478bd9Sstevel@tonic-gate 		MD_CAPAB(mp) = MD_CAN_PARENT;
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 	/* fill soft partition-specific fields */
35267c478bd9Sstevel@tonic-gate 	mp->un_dev = compnp->dev;
35277c478bd9Sstevel@tonic-gate 	mp->un_key = compnp->key;
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 	/* mdname_t start_blk field is not 64-bit! */
35307c478bd9Sstevel@tonic-gate 	mp->un_start_blk = (sp_ext_offset_t)compnp->start_blk;
35317c478bd9Sstevel@tonic-gate 	mp->un_status = status;
35327c478bd9Sstevel@tonic-gate 	mp->un_numexts = numexts;
35337c478bd9Sstevel@tonic-gate 	mp->un_length = len;
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate 	/* fill in the extent array */
35367c478bd9Sstevel@tonic-gate 	meta_sp_fillextarray(mp, extlist);
35377c478bd9Sstevel@tonic-gate 
35387c478bd9Sstevel@tonic-gate 	return (mp);
35397c478bd9Sstevel@tonic-gate }
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate /*
35427c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_updateunit()
35437c478bd9Sstevel@tonic-gate  * INPUT:	np       - name structure for the metadevice being updated
35447c478bd9Sstevel@tonic-gate  *		old_un	 - the original unit structure that is being updated
35457c478bd9Sstevel@tonic-gate  *		extlist	 - the extent list to populate the new unit with
35467c478bd9Sstevel@tonic-gate  *		grow_len - the amount by which the partition is being grown
35477c478bd9Sstevel@tonic-gate  *		numexts	 - the number of extents in the extent list
35487c478bd9Sstevel@tonic-gate  *		ep       - return error pointer
35497c478bd9Sstevel@tonic-gate  * OUTPUT:	none
35507c478bd9Sstevel@tonic-gate  * RETURNS:	mp_unit_t * - the updated unit structure
35517c478bd9Sstevel@tonic-gate  * PURPOSE:	allocates and fills in a new soft partition unit structure to
35527c478bd9Sstevel@tonic-gate  *		be passed to the soft partitioning driver for creation.  The
35537c478bd9Sstevel@tonic-gate  *		old unit structure is first copied in, and then the updated
35547c478bd9Sstevel@tonic-gate  *		extents are changed in the new unit structure.  This is
35557c478bd9Sstevel@tonic-gate  *		typically used when the size of an existing unit is changed.
35567c478bd9Sstevel@tonic-gate  */
35577c478bd9Sstevel@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)35587c478bd9Sstevel@tonic-gate meta_sp_updateunit(
35597c478bd9Sstevel@tonic-gate 	mdname_t	*np,
35607c478bd9Sstevel@tonic-gate 	mp_unit_t	*old_un,
35617c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist,
35627c478bd9Sstevel@tonic-gate 	sp_ext_length_t	grow_len,
35637c478bd9Sstevel@tonic-gate 	int		numexts,
35647c478bd9Sstevel@tonic-gate 	md_error_t	*ep
35657c478bd9Sstevel@tonic-gate )
35667c478bd9Sstevel@tonic-gate {
35677c478bd9Sstevel@tonic-gate 	mp_unit_t	*new_un;
35687c478bd9Sstevel@tonic-gate 	sp_ext_length_t	new_len;
35697c478bd9Sstevel@tonic-gate 	uint_t		new_size;
35707c478bd9Sstevel@tonic-gate 
35717c478bd9Sstevel@tonic-gate 	assert(old_un != NULL);
35727c478bd9Sstevel@tonic-gate 	assert(extlist != NULL);
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate 	/* allocate new unit structure and copy in old unit */
35757c478bd9Sstevel@tonic-gate 	new_size = (sizeof (*old_un) - sizeof (old_un->un_ext[0])) +
35767c478bd9Sstevel@tonic-gate 	    ((old_un->un_numexts + numexts) * sizeof (old_un->un_ext[0]));
35777c478bd9Sstevel@tonic-gate 	new_len = old_un->un_length + grow_len;
35787c478bd9Sstevel@tonic-gate 	new_un = Zalloc(new_size);
35797c478bd9Sstevel@tonic-gate 	bcopy(old_un, new_un, old_un->c.un_size);
35807c478bd9Sstevel@tonic-gate 
35817c478bd9Sstevel@tonic-gate 	/* update size and geometry information */
35827c478bd9Sstevel@tonic-gate 	new_un->c.un_size = new_size;
35837c478bd9Sstevel@tonic-gate 	new_un->un_length = new_len;
35847c478bd9Sstevel@tonic-gate 	new_un->c.un_total_blocks = new_len;
35857c478bd9Sstevel@tonic-gate 	new_un->c.un_actual_tb = new_len;
35867c478bd9Sstevel@tonic-gate 	if (meta_adjust_geom((md_unit_t *)new_un, np,
35877c478bd9Sstevel@tonic-gate 	    old_un->c.un_wr_reinstruct, old_un->c.un_rd_reinstruct,
35887c478bd9Sstevel@tonic-gate 	    0, ep) != 0) {
35897c478bd9Sstevel@tonic-gate 		Free(new_un);
35907c478bd9Sstevel@tonic-gate 		return (NULL);
35917c478bd9Sstevel@tonic-gate 	}
35927c478bd9Sstevel@tonic-gate 
35937c478bd9Sstevel@tonic-gate 	/* update extent information */
35947c478bd9Sstevel@tonic-gate 	new_un->un_numexts += numexts;
35957c478bd9Sstevel@tonic-gate 
35967c478bd9Sstevel@tonic-gate 	meta_sp_fillextarray(new_un, extlist);
35977c478bd9Sstevel@tonic-gate 
35987c478bd9Sstevel@tonic-gate 	return (new_un);
35997c478bd9Sstevel@tonic-gate }
36007c478bd9Sstevel@tonic-gate 
36017c478bd9Sstevel@tonic-gate /*
36027c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_get_sp()
36037c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to get
36047c478bd9Sstevel@tonic-gate  *		np	- the name of the device to get
36057c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
36067c478bd9Sstevel@tonic-gate  * RETURNS:	md_sp_t * - the XDR unit structure for the soft partition
36077c478bd9Sstevel@tonic-gate  * PURPOSE:	interface to the rest of libmeta for fetching a unit structure
36087c478bd9Sstevel@tonic-gate  *		for the named device.  Just a wrapper for meta_get_sp_common().
36097c478bd9Sstevel@tonic-gate  */
36107c478bd9Sstevel@tonic-gate md_sp_t *
meta_get_sp(mdsetname_t * sp,mdname_t * np,md_error_t * ep)36117c478bd9Sstevel@tonic-gate meta_get_sp(
36127c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
36137c478bd9Sstevel@tonic-gate 	mdname_t	*np,
36147c478bd9Sstevel@tonic-gate 	md_error_t	*ep
36157c478bd9Sstevel@tonic-gate )
36167c478bd9Sstevel@tonic-gate {
36177c478bd9Sstevel@tonic-gate 	return (meta_get_sp_common(sp, np, 0, ep));
36187c478bd9Sstevel@tonic-gate }
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate /*
36217c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_get_sp_common()
36227c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name for the device to get
36237c478bd9Sstevel@tonic-gate  *		np	- the name of the device to get
36247c478bd9Sstevel@tonic-gate  *		fast	- whether to use the cache or not (NOT IMPLEMENTED!)
36257c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
36267c478bd9Sstevel@tonic-gate  * RETURNS:	md_sp_t * - the XDR unit structure for the soft partition,
36277c478bd9Sstevel@tonic-gate  *			    NULL if np is not a soft partition
36287c478bd9Sstevel@tonic-gate  * PURPOSE:	common routine for fetching a soft partition unit structure
36297c478bd9Sstevel@tonic-gate  */
36307c478bd9Sstevel@tonic-gate md_sp_t *
meta_get_sp_common(mdsetname_t * sp,mdname_t * np,int fast,md_error_t * ep)36317c478bd9Sstevel@tonic-gate meta_get_sp_common(
36327c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
36337c478bd9Sstevel@tonic-gate 	mdname_t	*np,
36347c478bd9Sstevel@tonic-gate 	int		fast,
36357c478bd9Sstevel@tonic-gate 	md_error_t	*ep
36367c478bd9Sstevel@tonic-gate )
36377c478bd9Sstevel@tonic-gate {
36387c478bd9Sstevel@tonic-gate 	mddrivename_t	*dnp = np->drivenamep;
36397c478bd9Sstevel@tonic-gate 	char		*miscname;
36407c478bd9Sstevel@tonic-gate 	mp_unit_t	*mp;
36417c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;
36427c478bd9Sstevel@tonic-gate 	int		i;
36437c478bd9Sstevel@tonic-gate 
36447c478bd9Sstevel@tonic-gate 	/* must have set */
36457c478bd9Sstevel@tonic-gate 	assert(sp != NULL);
36467c478bd9Sstevel@tonic-gate 
36477c478bd9Sstevel@tonic-gate 	/* short circuit */
36487c478bd9Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
36497c478bd9Sstevel@tonic-gate 		if (dnp->unitp->type != MD_METASP)
36507c478bd9Sstevel@tonic-gate 			return (NULL);
36517c478bd9Sstevel@tonic-gate 		return ((md_sp_t *)dnp->unitp);
36527c478bd9Sstevel@tonic-gate 	}
36537c478bd9Sstevel@tonic-gate 	/* get miscname and unit */
36547c478bd9Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
36557c478bd9Sstevel@tonic-gate 		return (NULL);
36567c478bd9Sstevel@tonic-gate 
36577c478bd9Sstevel@tonic-gate 	if (strcmp(miscname, MD_SP) != 0) {
36587c478bd9Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_SP, 0, np->cname);
36597c478bd9Sstevel@tonic-gate 		return (NULL);
36607c478bd9Sstevel@tonic-gate 	}
36617c478bd9Sstevel@tonic-gate 
36627c478bd9Sstevel@tonic-gate 	if ((mp = (mp_unit_t *)meta_get_mdunit(sp, np, ep)) == NULL)
36637c478bd9Sstevel@tonic-gate 		return (NULL);
36647c478bd9Sstevel@tonic-gate 
36657c478bd9Sstevel@tonic-gate 	assert(mp->c.un_type == MD_METASP);
36667c478bd9Sstevel@tonic-gate 
36677c478bd9Sstevel@tonic-gate 	/* allocate soft partition */
36687c478bd9Sstevel@tonic-gate 	msp = Zalloc(sizeof (*msp));
36697c478bd9Sstevel@tonic-gate 
36707c478bd9Sstevel@tonic-gate 	/* get the common information */
36717c478bd9Sstevel@tonic-gate 	msp->common.namep = np;
36727c478bd9Sstevel@tonic-gate 	msp->common.type = mp->c.un_type;
36737c478bd9Sstevel@tonic-gate 	msp->common.state = mp->c.un_status;
36747c478bd9Sstevel@tonic-gate 	msp->common.capabilities = mp->c.un_capabilities;
36757c478bd9Sstevel@tonic-gate 	msp->common.parent = mp->c.un_parent;
36767c478bd9Sstevel@tonic-gate 	msp->common.size = mp->c.un_total_blocks;
36777c478bd9Sstevel@tonic-gate 	msp->common.user_flags = mp->c.un_user_flags;
36787c478bd9Sstevel@tonic-gate 	msp->common.revision = mp->c.un_revision;
36797c478bd9Sstevel@tonic-gate 
36807c478bd9Sstevel@tonic-gate 	/* get soft partition information */
36817c478bd9Sstevel@tonic-gate 	if ((msp->compnamep = metakeyname(&sp, mp->un_key, fast, ep)) == NULL)
36827c478bd9Sstevel@tonic-gate 		goto out;
36837c478bd9Sstevel@tonic-gate 
36847c478bd9Sstevel@tonic-gate 	/*
36857c478bd9Sstevel@tonic-gate 	 * Fill in the key and the start block.  Note that the start
36867c478bd9Sstevel@tonic-gate 	 * block in the unit structure is 64 bits but the name pointer
36877c478bd9Sstevel@tonic-gate 	 * only supports 32 bits.
36887c478bd9Sstevel@tonic-gate 	 */
36897c478bd9Sstevel@tonic-gate 	msp->compnamep->key = mp->un_key;
36907c478bd9Sstevel@tonic-gate 	msp->compnamep->start_blk = mp->un_start_blk;
36917c478bd9Sstevel@tonic-gate 
36927c478bd9Sstevel@tonic-gate 	/* fill in status field */
36937c478bd9Sstevel@tonic-gate 	msp->status = mp->un_status;
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate 	/* allocate the extents */
36967c478bd9Sstevel@tonic-gate 	msp->ext.ext_val = Zalloc(mp->un_numexts * sizeof (*msp->ext.ext_val));
36977c478bd9Sstevel@tonic-gate 	msp->ext.ext_len = mp->un_numexts;
36987c478bd9Sstevel@tonic-gate 
36997c478bd9Sstevel@tonic-gate 	/* do the extents for this soft partition */
37007c478bd9Sstevel@tonic-gate 	for (i = 0; i < mp->un_numexts; i++) {
37017c478bd9Sstevel@tonic-gate 		struct mp_ext	*mde = &mp->un_ext[i];
37027c478bd9Sstevel@tonic-gate 		md_sp_ext_t	*extp = &msp->ext.ext_val[i];
37037c478bd9Sstevel@tonic-gate 
37047c478bd9Sstevel@tonic-gate 		extp->voff = mde->un_voff;
37057c478bd9Sstevel@tonic-gate 		extp->poff = mde->un_poff;
37067c478bd9Sstevel@tonic-gate 		extp->len = mde->un_len;
37077c478bd9Sstevel@tonic-gate 	}
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate 	/* cleanup, return success */
37107c478bd9Sstevel@tonic-gate 	Free(mp);
37117c478bd9Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)msp;
37127c478bd9Sstevel@tonic-gate 	return (msp);
37137c478bd9Sstevel@tonic-gate 
37147c478bd9Sstevel@tonic-gate out:
37157c478bd9Sstevel@tonic-gate 	/* clean up and return error */
37167c478bd9Sstevel@tonic-gate 	Free(mp);
37177c478bd9Sstevel@tonic-gate 	Free(msp);
37187c478bd9Sstevel@tonic-gate 	return (NULL);
37197c478bd9Sstevel@tonic-gate }
37207c478bd9Sstevel@tonic-gate 
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate /*
37237c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_init_sp()
37247c478bd9Sstevel@tonic-gate  * INPUT:	spp	- the set name for the new device
37257c478bd9Sstevel@tonic-gate  *		argc	- the remaining argument count for the metainit cmdline
37267c478bd9Sstevel@tonic-gate  *		argv	- the remainder of the unparsed command line
37277c478bd9Sstevel@tonic-gate  *		options	- global options parsed by metainit
37287c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
37297c478bd9Sstevel@tonic-gate  * RETURNS:	int	- -1 failure, 0 success
37307c478bd9Sstevel@tonic-gate  * PURPOSE:	provides the command line parsing and name management overhead
37317c478bd9Sstevel@tonic-gate  *		for creating a new soft partition.  Ultimately this calls
37327c478bd9Sstevel@tonic-gate  *		meta_create_sp() which does the real work of allocating space
37337c478bd9Sstevel@tonic-gate  *		for the new soft partition.
37347c478bd9Sstevel@tonic-gate  */
37357c478bd9Sstevel@tonic-gate int
meta_init_sp(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)37367c478bd9Sstevel@tonic-gate meta_init_sp(
37377c478bd9Sstevel@tonic-gate 	mdsetname_t	**spp,
37387c478bd9Sstevel@tonic-gate 	int		argc,
37397c478bd9Sstevel@tonic-gate 	char		*argv[],
37407c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
37417c478bd9Sstevel@tonic-gate 	md_error_t	*ep
37427c478bd9Sstevel@tonic-gate )
37437c478bd9Sstevel@tonic-gate {
37447c478bd9Sstevel@tonic-gate 	char		*compname = NULL;
37457c478bd9Sstevel@tonic-gate 	mdname_t	*spcompnp = NULL;	/* name of component volume */
37467c478bd9Sstevel@tonic-gate 	char		*devname = argv[0];	/* unit name */
37477c478bd9Sstevel@tonic-gate 	mdname_t	*np = NULL;		/* name of soft partition */
37487c478bd9Sstevel@tonic-gate 	md_sp_t		*msp = NULL;
37497c478bd9Sstevel@tonic-gate 	int		c;
37507c478bd9Sstevel@tonic-gate 	int		old_optind;
37517c478bd9Sstevel@tonic-gate 	sp_ext_length_t	len = 0LL;
37527c478bd9Sstevel@tonic-gate 	int		rval = -1;
37537c478bd9Sstevel@tonic-gate 	uint_t		seq;
37547c478bd9Sstevel@tonic-gate 	int		oflag;
37557c478bd9Sstevel@tonic-gate 	int		failed;
37567c478bd9Sstevel@tonic-gate 	mddrivename_t	*dnp = NULL;
37577c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alignment = 0LL;
37587c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate 	assert(argc > 0);
37617c478bd9Sstevel@tonic-gate 
37627c478bd9Sstevel@tonic-gate 	/* expect sp name, -p, optional -e, compname, and size parameters */
37637c478bd9Sstevel@tonic-gate 	/* grab soft partition name */
3764d7cd8252Stw21770 	if ((np = metaname(spp, devname, META_DEVICE, ep)) == NULL)
37657c478bd9Sstevel@tonic-gate 		goto out;
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate 	/* see if it exists already */
37687c478bd9Sstevel@tonic-gate 	if (metagetmiscname(np, ep) != NULL) {
37697c478bd9Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
37707c478bd9Sstevel@tonic-gate 		    meta_getminor(np->dev), devname);
37717c478bd9Sstevel@tonic-gate 		goto out;
37727c478bd9Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
37737c478bd9Sstevel@tonic-gate 		goto out;
37747c478bd9Sstevel@tonic-gate 	} else {
37757c478bd9Sstevel@tonic-gate 		mdclrerror(ep);
37767c478bd9Sstevel@tonic-gate 	}
37777c478bd9Sstevel@tonic-gate 	--argc, ++argv;
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate 	if (argc == 0)
37807c478bd9Sstevel@tonic-gate 		goto syntax;
37817c478bd9Sstevel@tonic-gate 
37827c478bd9Sstevel@tonic-gate 	/* grab -p */
37837c478bd9Sstevel@tonic-gate 	if (strcmp(argv[0], "-p") != 0)
37847c478bd9Sstevel@tonic-gate 		goto syntax;
37857c478bd9Sstevel@tonic-gate 	--argc, ++argv;
37867c478bd9Sstevel@tonic-gate 
37877c478bd9Sstevel@tonic-gate 	if (argc == 0)
37887c478bd9Sstevel@tonic-gate 		goto syntax;
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate 	/* see if -e is there */
37917c478bd9Sstevel@tonic-gate 	if (strcmp(argv[0], "-e") == 0) {
37927c478bd9Sstevel@tonic-gate 		/* use the whole disk */
37937c478bd9Sstevel@tonic-gate 		options |= MDCMD_USE_WHOLE_DISK;
37947c478bd9Sstevel@tonic-gate 		--argc, ++argv;
37957c478bd9Sstevel@tonic-gate 	}
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate 	if (argc == 0)
37987c478bd9Sstevel@tonic-gate 		goto syntax;
37997c478bd9Sstevel@tonic-gate 
38007c478bd9Sstevel@tonic-gate 	/* get component name */
38017c478bd9Sstevel@tonic-gate 	compname = Strdup(argv[0]);
38027c478bd9Sstevel@tonic-gate 
38037c478bd9Sstevel@tonic-gate 	if (options & MDCMD_USE_WHOLE_DISK) {
38047c478bd9Sstevel@tonic-gate 		if ((dnp = metadrivename(spp, compname, ep)) == NULL) {
38057c478bd9Sstevel@tonic-gate 			goto out;
38067c478bd9Sstevel@tonic-gate 		}
38077c478bd9Sstevel@tonic-gate 		if ((spcompnp = metaslicename(dnp, 0, ep)) == NULL) {
38087c478bd9Sstevel@tonic-gate 			goto out;
38097c478bd9Sstevel@tonic-gate 		}
3810d7cd8252Stw21770 	} else if ((spcompnp = metaname(spp, compname, UNKNOWN, ep)) == NULL) {
38117c478bd9Sstevel@tonic-gate 		goto out;
38127c478bd9Sstevel@tonic-gate 	}
38137c478bd9Sstevel@tonic-gate 	assert(*spp != NULL);
38147c478bd9Sstevel@tonic-gate 
38157c478bd9Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
38167c478bd9Sstevel@tonic-gate 		/* grab set lock */
38177c478bd9Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
38187c478bd9Sstevel@tonic-gate 			goto out;
38197c478bd9Sstevel@tonic-gate 
38207c478bd9Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
38217c478bd9Sstevel@tonic-gate 			goto out;
38227c478bd9Sstevel@tonic-gate 	}
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate 	/* allocate the soft partition */
38257c478bd9Sstevel@tonic-gate 	msp = Zalloc(sizeof (*msp));
38267c478bd9Sstevel@tonic-gate 
38277c478bd9Sstevel@tonic-gate 	/* setup common */
38287c478bd9Sstevel@tonic-gate 	msp->common.namep = np;
38297c478bd9Sstevel@tonic-gate 	msp->common.type = MD_METASP;
38307c478bd9Sstevel@tonic-gate 
38317c478bd9Sstevel@tonic-gate 	compname = spcompnp->cname;
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 	assert(spcompnp->rname != NULL);
38347c478bd9Sstevel@tonic-gate 	--argc, ++argv;
38357c478bd9Sstevel@tonic-gate 
38367c478bd9Sstevel@tonic-gate 	if (argc == 0) {
38377c478bd9Sstevel@tonic-gate 		goto syntax;
38387c478bd9Sstevel@tonic-gate 	}
38397c478bd9Sstevel@tonic-gate 
38407c478bd9Sstevel@tonic-gate 	if (*argv[0] == '-') {
38417c478bd9Sstevel@tonic-gate 		/*
38427c478bd9Sstevel@tonic-gate 		 * parse any other command line options, this includes
38437c478bd9Sstevel@tonic-gate 		 * the recovery options -o and -b. The special thing
38447c478bd9Sstevel@tonic-gate 		 * with these options is that the len needs to be
38457c478bd9Sstevel@tonic-gate 		 * kept track of otherwise when the geometry of the
38467c478bd9Sstevel@tonic-gate 		 * "device" is built it will create an invalid geometry
38477c478bd9Sstevel@tonic-gate 		 */
38487c478bd9Sstevel@tonic-gate 		old_optind = optind = 0;
38497c478bd9Sstevel@tonic-gate 		opterr = 0;
38507c478bd9Sstevel@tonic-gate 		oflag = 0;
38517c478bd9Sstevel@tonic-gate 		seq = 0;
38527c478bd9Sstevel@tonic-gate 		failed = 0;
38537c478bd9Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "A:o:b:")) != -1) {
38547c478bd9Sstevel@tonic-gate 			sp_ext_offset_t	offset;
38557c478bd9Sstevel@tonic-gate 			sp_ext_length_t	length;
38567c478bd9Sstevel@tonic-gate 			longlong_t	tmp_size;
38577c478bd9Sstevel@tonic-gate 
38587c478bd9Sstevel@tonic-gate 			switch (c) {
38597c478bd9Sstevel@tonic-gate 			case 'A':	/* data alignment */
38607c478bd9Sstevel@tonic-gate 				if (meta_sp_parsesizestring(optarg,
38617c478bd9Sstevel@tonic-gate 				    &alignment) == -1) {
38627c478bd9Sstevel@tonic-gate 					failed = 1;
38637c478bd9Sstevel@tonic-gate 				}
38647c478bd9Sstevel@tonic-gate 				break;
38657c478bd9Sstevel@tonic-gate 			case 'o':	/* offset in the partition */
38667c478bd9Sstevel@tonic-gate 				if (oflag == 1) {
38677c478bd9Sstevel@tonic-gate 					failed = 1;
38687c478bd9Sstevel@tonic-gate 				} else {
38697c478bd9Sstevel@tonic-gate 					tmp_size = atoll(optarg);
38707c478bd9Sstevel@tonic-gate 					if (tmp_size <= 0) {
38717c478bd9Sstevel@tonic-gate 						failed = 1;
38727c478bd9Sstevel@tonic-gate 					} else {
38737c478bd9Sstevel@tonic-gate 						oflag = 1;
38747c478bd9Sstevel@tonic-gate 						options |= MDCMD_DIRECT;
38757c478bd9Sstevel@tonic-gate 
38767c478bd9Sstevel@tonic-gate 						offset = tmp_size;
38777c478bd9Sstevel@tonic-gate 					}
38787c478bd9Sstevel@tonic-gate 				}
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate 				break;
38817c478bd9Sstevel@tonic-gate 			case 'b':	/* number of blocks */
38827c478bd9Sstevel@tonic-gate 				if (oflag == 0) {
38837c478bd9Sstevel@tonic-gate 					failed = 1;
38847c478bd9Sstevel@tonic-gate 				} else {
38857c478bd9Sstevel@tonic-gate 					tmp_size = atoll(optarg);
38867c478bd9Sstevel@tonic-gate 					if (tmp_size <= 0) {
38877c478bd9Sstevel@tonic-gate 						failed = 1;
38887c478bd9Sstevel@tonic-gate 					} else {
38897c478bd9Sstevel@tonic-gate 						oflag = 0;
38907c478bd9Sstevel@tonic-gate 
38917c478bd9Sstevel@tonic-gate 						length = tmp_size;
38927c478bd9Sstevel@tonic-gate 
38937c478bd9Sstevel@tonic-gate 						/* we have a pair of values */
38947c478bd9Sstevel@tonic-gate 						meta_sp_list_insert(*spp, np,
38951cd3f00bSsk102515 						    &extlist, offset, length,
38961cd3f00bSsk102515 						    EXTTYP_ALLOC, seq++,
38971cd3f00bSsk102515 						    EXTFLG_UPDATE,
38987c478bd9Sstevel@tonic-gate 						    meta_sp_cmp_by_offset);
38997c478bd9Sstevel@tonic-gate 						len += length;
39007c478bd9Sstevel@tonic-gate 					}
39017c478bd9Sstevel@tonic-gate 				}
39027c478bd9Sstevel@tonic-gate 
39037c478bd9Sstevel@tonic-gate 				break;
39047c478bd9Sstevel@tonic-gate 			default:
39057c478bd9Sstevel@tonic-gate 				argc -= old_optind;
39067c478bd9Sstevel@tonic-gate 				argv += old_optind;
39077c478bd9Sstevel@tonic-gate 				goto options;
39087c478bd9Sstevel@tonic-gate 			}
39097c478bd9Sstevel@tonic-gate 
39107c478bd9Sstevel@tonic-gate 			if (failed) {
39117c478bd9Sstevel@tonic-gate 				argc -= old_optind;
39127c478bd9Sstevel@tonic-gate 				argv += old_optind;
39137c478bd9Sstevel@tonic-gate 				goto syntax;
39147c478bd9Sstevel@tonic-gate 			}
39157c478bd9Sstevel@tonic-gate 
39167c478bd9Sstevel@tonic-gate 			old_optind = optind;
39177c478bd9Sstevel@tonic-gate 		}
39187c478bd9Sstevel@tonic-gate 		argc -= optind;
39197c478bd9Sstevel@tonic-gate 		argv += optind;
39207c478bd9Sstevel@tonic-gate 
39217c478bd9Sstevel@tonic-gate 		/*
39227c478bd9Sstevel@tonic-gate 		 * Must have matching pairs of -o and -b flags
39237c478bd9Sstevel@tonic-gate 		 */
39247c478bd9Sstevel@tonic-gate 		if (oflag != 0)
39257c478bd9Sstevel@tonic-gate 			goto syntax;
39267c478bd9Sstevel@tonic-gate 
39277c478bd9Sstevel@tonic-gate 		/*
39287c478bd9Sstevel@tonic-gate 		 * Can't specify both layout (indicated indirectly by
39297c478bd9Sstevel@tonic-gate 		 * len being set by thye -o/-b cases above) AND
39307c478bd9Sstevel@tonic-gate 		 * alignment
39317c478bd9Sstevel@tonic-gate 		 */
39327c478bd9Sstevel@tonic-gate 		if ((len > 0LL) && (alignment > 0LL))
39337c478bd9Sstevel@tonic-gate 			goto syntax;
39347c478bd9Sstevel@tonic-gate 
39357c478bd9Sstevel@tonic-gate 		/*
39367c478bd9Sstevel@tonic-gate 		 * sanity check the allocation list
39377c478bd9Sstevel@tonic-gate 		 */
39387c478bd9Sstevel@tonic-gate 		if ((extlist != NULL) && meta_sp_list_overlaps(extlist))
39397c478bd9Sstevel@tonic-gate 			goto syntax;
39407c478bd9Sstevel@tonic-gate 	}
39417c478bd9Sstevel@tonic-gate 
39427c478bd9Sstevel@tonic-gate 	if (len == 0LL) {
39437c478bd9Sstevel@tonic-gate 		if (argc == 0)
39447c478bd9Sstevel@tonic-gate 			goto syntax;
39457c478bd9Sstevel@tonic-gate 		if (meta_sp_parsesize(argv[0], &len) == -1)
39467c478bd9Sstevel@tonic-gate 			goto syntax;
39477c478bd9Sstevel@tonic-gate 		--argc, ++argv;
39487c478bd9Sstevel@tonic-gate 	}
39497c478bd9Sstevel@tonic-gate 
39507c478bd9Sstevel@tonic-gate 	msp->ext.ext_val = Zalloc(sizeof (*msp->ext.ext_val));
39517c478bd9Sstevel@tonic-gate 	msp->ext.ext_val->len = len;
39527c478bd9Sstevel@tonic-gate 	msp->compnamep = spcompnp;
39537c478bd9Sstevel@tonic-gate 
39547c478bd9Sstevel@tonic-gate 	/* we should be at the end */
39557c478bd9Sstevel@tonic-gate 	if (argc != 0)
39567c478bd9Sstevel@tonic-gate 		goto syntax;
39577c478bd9Sstevel@tonic-gate 
39587c478bd9Sstevel@tonic-gate 	/* create soft partition */
39597c478bd9Sstevel@tonic-gate 	if (meta_create_sp(*spp, msp, extlist, options, alignment, ep) != 0)
39607c478bd9Sstevel@tonic-gate 		goto out;
39617c478bd9Sstevel@tonic-gate 	rval = 0;
39627c478bd9Sstevel@tonic-gate 
39637c478bd9Sstevel@tonic-gate 	/* let em know */
39647c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
39657c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
39667c478bd9Sstevel@tonic-gate 		    "%s: Soft Partition is setup\n"),
39677c478bd9Sstevel@tonic-gate 		    devname);
39687c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
39697c478bd9Sstevel@tonic-gate 	}
39707c478bd9Sstevel@tonic-gate 	goto out;
39717c478bd9Sstevel@tonic-gate 
39727c478bd9Sstevel@tonic-gate syntax:
39737c478bd9Sstevel@tonic-gate 	/* syntax error */
39747c478bd9Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, compname, argc, argv);
39757c478bd9Sstevel@tonic-gate 	goto out;
39767c478bd9Sstevel@tonic-gate 
39777c478bd9Sstevel@tonic-gate options:
39787c478bd9Sstevel@tonic-gate 	/* options error */
39797c478bd9Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, compname, argc, argv);
39807c478bd9Sstevel@tonic-gate 	goto out;
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate out:
39837c478bd9Sstevel@tonic-gate 	if (msp != NULL) {
39847c478bd9Sstevel@tonic-gate 		if (msp->ext.ext_val != NULL) {
39857c478bd9Sstevel@tonic-gate 			Free(msp->ext.ext_val);
39867c478bd9Sstevel@tonic-gate 		}
39877c478bd9Sstevel@tonic-gate 		Free(msp);
39887c478bd9Sstevel@tonic-gate 	}
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate 	return (rval);
39917c478bd9Sstevel@tonic-gate }
39927c478bd9Sstevel@tonic-gate 
39937c478bd9Sstevel@tonic-gate /*
39947c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_free_sp()
39957c478bd9Sstevel@tonic-gate  * INPUT:	msp	- the soft partition unit to free
39967c478bd9Sstevel@tonic-gate  * OUTPUT:	none
39977c478bd9Sstevel@tonic-gate  * RETURNS:	void
39987c478bd9Sstevel@tonic-gate  * PURPOSE:	provides an interface from the rest of libmeta for freeing a
39997c478bd9Sstevel@tonic-gate  *		soft partition unit
40007c478bd9Sstevel@tonic-gate  */
40017c478bd9Sstevel@tonic-gate void
meta_free_sp(md_sp_t * msp)40027c478bd9Sstevel@tonic-gate meta_free_sp(md_sp_t *msp)
40037c478bd9Sstevel@tonic-gate {
40047c478bd9Sstevel@tonic-gate 	Free(msp);
40057c478bd9Sstevel@tonic-gate }
40067c478bd9Sstevel@tonic-gate 
40077c478bd9Sstevel@tonic-gate /*
40087c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_issp()
40097c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name to check
40107c478bd9Sstevel@tonic-gate  *		np	- the name to check
40117c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
40127c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 means sp,np is a soft partition
40137c478bd9Sstevel@tonic-gate  *			  1 means sp,np is not a soft partition
40147c478bd9Sstevel@tonic-gate  * PURPOSE:	determines whether the given device is a soft partition
40157c478bd9Sstevel@tonic-gate  *		device.  This is called by other metadevice check routines.
40167c478bd9Sstevel@tonic-gate  */
40177c478bd9Sstevel@tonic-gate int
meta_sp_issp(mdsetname_t * sp,mdname_t * np,md_error_t * ep)40187c478bd9Sstevel@tonic-gate meta_sp_issp(
40197c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
40207c478bd9Sstevel@tonic-gate 	mdname_t	*np,
40217c478bd9Sstevel@tonic-gate 	md_error_t	*ep
40227c478bd9Sstevel@tonic-gate )
40237c478bd9Sstevel@tonic-gate {
40247c478bd9Sstevel@tonic-gate 	if (meta_get_sp_common(sp, np, 0, ep) == NULL)
40257c478bd9Sstevel@tonic-gate 		return (1);
40267c478bd9Sstevel@tonic-gate 
40277c478bd9Sstevel@tonic-gate 	return (0);
40287c478bd9Sstevel@tonic-gate }
40297c478bd9Sstevel@tonic-gate 
40307c478bd9Sstevel@tonic-gate /*
40317c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_check_sp()
40327c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name to check
40337c478bd9Sstevel@tonic-gate  *		msp	- the unit structure to check
40347c478bd9Sstevel@tonic-gate  *		options	- creation options
40357c478bd9Sstevel@tonic-gate  * OUTPUT:	repart_options - options to be passed to
40367c478bd9Sstevel@tonic-gate  *				meta_repartition_drive()
40377c478bd9Sstevel@tonic-gate  *		ep	- return error pointer
40387c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 ok to create on this component
40397c478bd9Sstevel@tonic-gate  *			  -1 error or not ok to create on this component
40407c478bd9Sstevel@tonic-gate  * PURPOSE:	Checks to determine whether the rules for creation of
40417c478bd9Sstevel@tonic-gate  *		soft partitions allow creation of a soft partition on
40427c478bd9Sstevel@tonic-gate  *		the device described by the mdname_t structure referred
40437c478bd9Sstevel@tonic-gate  *		to by msp->compnamep.
40447c478bd9Sstevel@tonic-gate  *
40457c478bd9Sstevel@tonic-gate  *		NOTE: Does NOT check to determine whether the extents
40467c478bd9Sstevel@tonic-gate  *		      described in the md_sp_t structure referred to by
40477c478bd9Sstevel@tonic-gate  *		      msp will fit on the device described by the mdname_t
40487c478bd9Sstevel@tonic-gate  *		      structure located at msp->compnamep.
40497c478bd9Sstevel@tonic-gate  */
40507c478bd9Sstevel@tonic-gate static int
meta_check_sp(mdsetname_t * sp,md_sp_t * msp,mdcmdopts_t options,int * repart_options,md_error_t * ep)40517c478bd9Sstevel@tonic-gate meta_check_sp(
40527c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
40537c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
40547c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
40557c478bd9Sstevel@tonic-gate 	int		*repart_options,
40567c478bd9Sstevel@tonic-gate 	md_error_t	*ep
40577c478bd9Sstevel@tonic-gate )
40587c478bd9Sstevel@tonic-gate {
40597c478bd9Sstevel@tonic-gate 	md_common_t	*mdp;
40607c478bd9Sstevel@tonic-gate 	mdname_t	*compnp = msp->compnamep;
40617c478bd9Sstevel@tonic-gate 	uint_t		slice;
40627c478bd9Sstevel@tonic-gate 	mddrivename_t	*dnp;
40637c478bd9Sstevel@tonic-gate 	mdname_t	*slicenp;
40647c478bd9Sstevel@tonic-gate 	mdvtoc_t	*vtocp;
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate 	/* make sure it is in the set */
40677c478bd9Sstevel@tonic-gate 	if (meta_check_inset(sp, compnp, ep) != 0)
40687c478bd9Sstevel@tonic-gate 		return (-1);
40697c478bd9Sstevel@tonic-gate 
40707c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_USE_WHOLE_DISK) != 0) {
40717c478bd9Sstevel@tonic-gate 		uint_t	rep_slice;
40727c478bd9Sstevel@tonic-gate 
40737c478bd9Sstevel@tonic-gate 		/*
40747c478bd9Sstevel@tonic-gate 		 * check to make sure we can partition this drive.
40757c478bd9Sstevel@tonic-gate 		 * we cannot continue if any of the following are
40767c478bd9Sstevel@tonic-gate 		 * true:
40777c478bd9Sstevel@tonic-gate 		 * The drive is a metadevice.
40787c478bd9Sstevel@tonic-gate 		 * The drive contains a mounted slice.
40797c478bd9Sstevel@tonic-gate 		 * The drive contains a slice being swapped to.
40807c478bd9Sstevel@tonic-gate 		 * The drive contains slices which are part of other
40817c478bd9Sstevel@tonic-gate 		 * metadevices.
40827c478bd9Sstevel@tonic-gate 		 * The drive contains a metadb.
40837c478bd9Sstevel@tonic-gate 		 */
40847c478bd9Sstevel@tonic-gate 		if (metaismeta(compnp))
40857c478bd9Sstevel@tonic-gate 			return (mddeverror(ep, MDE_IS_META, compnp->dev,
40867c478bd9Sstevel@tonic-gate 			    compnp->cname));
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 		assert(compnp->drivenamep != NULL);
40897c478bd9Sstevel@tonic-gate 
40907c478bd9Sstevel@tonic-gate 		/*
40917c478bd9Sstevel@tonic-gate 		 * ensure that we have slice 0 since the disk will be
40927c478bd9Sstevel@tonic-gate 		 * repartitioned in the USE_WHOLE_DISK case.  this check
40937c478bd9Sstevel@tonic-gate 		 * is redundant unless the user incorrectly specifies a
40947c478bd9Sstevel@tonic-gate 		 * a fully qualified drive AND slice name (i.e.,
40957c478bd9Sstevel@tonic-gate 		 * /dev/dsk/cXtXdXsX), which will be incorrectly
40967c478bd9Sstevel@tonic-gate 		 * recognized as a drive name by the metaname code.
40977c478bd9Sstevel@tonic-gate 		 */
40987c478bd9Sstevel@tonic-gate 
40997c478bd9Sstevel@tonic-gate 		if ((vtocp = metagetvtoc(compnp, FALSE, &slice, ep)) == NULL)
41007c478bd9Sstevel@tonic-gate 			return (-1);
41017c478bd9Sstevel@tonic-gate 		if (slice != MD_SLICE0)
41027c478bd9Sstevel@tonic-gate 			return (mderror(ep, MDE_NOT_DRIVENAME, compnp->cname));
41037c478bd9Sstevel@tonic-gate 
41047c478bd9Sstevel@tonic-gate 		dnp = compnp->drivenamep;
41057c478bd9Sstevel@tonic-gate 		if (meta_replicaslice(dnp, &rep_slice, ep) != 0)
41067c478bd9Sstevel@tonic-gate 			return (-1);
41077c478bd9Sstevel@tonic-gate 
41087c478bd9Sstevel@tonic-gate 		for (slice = 0; slice < vtocp->nparts; slice++) {
41097c478bd9Sstevel@tonic-gate 
41107c478bd9Sstevel@tonic-gate 			/* only check if the slice really exists */
41117c478bd9Sstevel@tonic-gate 			if (vtocp->parts[slice].size == 0)
41127c478bd9Sstevel@tonic-gate 				continue;
41137c478bd9Sstevel@tonic-gate 
41147c478bd9Sstevel@tonic-gate 			slicenp = metaslicename(dnp, slice, ep);
41157c478bd9Sstevel@tonic-gate 			if (slicenp == NULL)
41167c478bd9Sstevel@tonic-gate 				return (-1);
41177c478bd9Sstevel@tonic-gate 
41187c478bd9Sstevel@tonic-gate 			/* check to ensure that it is not already in use */
41197c478bd9Sstevel@tonic-gate 			if (meta_check_inuse(sp,
41207c478bd9Sstevel@tonic-gate 			    slicenp, MDCHK_INUSE, ep) != 0) {
41217c478bd9Sstevel@tonic-gate 				return (-1);
41227c478bd9Sstevel@tonic-gate 			}
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate 			/*
41257c478bd9Sstevel@tonic-gate 			 * Up to this point, tests are applied to all
41267c478bd9Sstevel@tonic-gate 			 * slices uniformly.
41277c478bd9Sstevel@tonic-gate 			 */
41287c478bd9Sstevel@tonic-gate 
41297c478bd9Sstevel@tonic-gate 			if (slice == rep_slice) {
41307c478bd9Sstevel@tonic-gate 				/*
41317c478bd9Sstevel@tonic-gate 				 * Tests inside the body of this
41327c478bd9Sstevel@tonic-gate 				 * conditional are applied only to
41337c478bd9Sstevel@tonic-gate 				 * slice seven.
41347c478bd9Sstevel@tonic-gate 				 */
41357c478bd9Sstevel@tonic-gate 				if (meta_check_inmeta(sp, slicenp,
41367c478bd9Sstevel@tonic-gate 				    options | MDCHK_ALLOW_MDDB |
41377c478bd9Sstevel@tonic-gate 				    MDCHK_ALLOW_REPSLICE, 0, -1, ep) != 0)
41387c478bd9Sstevel@tonic-gate 					return (-1);
41397c478bd9Sstevel@tonic-gate 
41407c478bd9Sstevel@tonic-gate 				/*
41417c478bd9Sstevel@tonic-gate 				 * For slice seven, a metadb is NOT an
41427c478bd9Sstevel@tonic-gate 				 * automatic failure. It merely means
41437c478bd9Sstevel@tonic-gate 				 * that we're not allowed to muck
41447c478bd9Sstevel@tonic-gate 				 * about with the partitioning of that
41457c478bd9Sstevel@tonic-gate 				 * slice.  We indicate this by masking
41467c478bd9Sstevel@tonic-gate 				 * in the MD_REPART_LEAVE_REP flag.
41477c478bd9Sstevel@tonic-gate 				 */
41487c478bd9Sstevel@tonic-gate 				if (metahasmddb(sp, slicenp, ep)) {
41497c478bd9Sstevel@tonic-gate 					assert(repart_options !=
41507c478bd9Sstevel@tonic-gate 					    NULL);
41517c478bd9Sstevel@tonic-gate 					*repart_options |=
41527c478bd9Sstevel@tonic-gate 					    MD_REPART_LEAVE_REP;
41537c478bd9Sstevel@tonic-gate 				}
41547c478bd9Sstevel@tonic-gate 
41557c478bd9Sstevel@tonic-gate 				/*
41567c478bd9Sstevel@tonic-gate 				 * Skip the remaining tests for slice
41577c478bd9Sstevel@tonic-gate 				 * seven
41587c478bd9Sstevel@tonic-gate 				 */
41597c478bd9Sstevel@tonic-gate 				continue;
41607c478bd9Sstevel@tonic-gate 			}
41617c478bd9Sstevel@tonic-gate 
41627c478bd9Sstevel@tonic-gate 			/*
41637c478bd9Sstevel@tonic-gate 			 * Tests below this point will be applied to
41647c478bd9Sstevel@tonic-gate 			 * all slices EXCEPT for the replica slice.
41657c478bd9Sstevel@tonic-gate 			 */
41667c478bd9Sstevel@tonic-gate 
41677c478bd9Sstevel@tonic-gate 
41687c478bd9Sstevel@tonic-gate 			/* check if component is in a metadevice */
41697c478bd9Sstevel@tonic-gate 			if (meta_check_inmeta(sp, slicenp, options, 0,
41707c478bd9Sstevel@tonic-gate 			    -1, ep) != 0)
41717c478bd9Sstevel@tonic-gate 				return (-1);
41727c478bd9Sstevel@tonic-gate 
41737c478bd9Sstevel@tonic-gate 			/* check to see if component has a metadb */
41747c478bd9Sstevel@tonic-gate 			if (metahasmddb(sp, slicenp, ep))
41757c478bd9Sstevel@tonic-gate 				return (mddeverror(ep, MDE_HAS_MDDB,
41767c478bd9Sstevel@tonic-gate 				    slicenp->dev, slicenp->cname));
41777c478bd9Sstevel@tonic-gate 		}
41787c478bd9Sstevel@tonic-gate 		/*
41797c478bd9Sstevel@tonic-gate 		 * This should be all of the testing necessary when
41807c478bd9Sstevel@tonic-gate 		 * the MDCMD_USE_WHOLE_DISK flag is set; the rest of
41817c478bd9Sstevel@tonic-gate 		 * meta_check_sp() is oriented towards component
41827c478bd9Sstevel@tonic-gate 		 * arguments instead of disks.
41837c478bd9Sstevel@tonic-gate 		 */
41847c478bd9Sstevel@tonic-gate 		goto meta_check_sp_ok;
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate 	}
41877c478bd9Sstevel@tonic-gate 
41887c478bd9Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
41897c478bd9Sstevel@tonic-gate 	if (meta_check_inuse(sp, compnp, MDCHK_INUSE, ep) != 0) {
41907c478bd9Sstevel@tonic-gate 		return (-1);
41917c478bd9Sstevel@tonic-gate 	}
41927c478bd9Sstevel@tonic-gate 
41937c478bd9Sstevel@tonic-gate 	if (!metaismeta(compnp)) {	/* handle non-metadevices */
41947c478bd9Sstevel@tonic-gate 
41957c478bd9Sstevel@tonic-gate 		/*
41967c478bd9Sstevel@tonic-gate 		 * The component can have one or more soft partitions on it
41977c478bd9Sstevel@tonic-gate 		 * already, but can't be part of any other type of metadevice,
41987c478bd9Sstevel@tonic-gate 		 * so if it is used for a metadevice, but the metadevice
41997c478bd9Sstevel@tonic-gate 		 * isn't a soft partition, return failure.
42007c478bd9Sstevel@tonic-gate 		 */
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate 		if (meta_check_inmeta(sp, compnp, options, 0, -1, ep) != 0 &&
42037c478bd9Sstevel@tonic-gate 		    meta_check_insp(sp, compnp, 0, -1, ep) == 0) {
42047c478bd9Sstevel@tonic-gate 			return (-1);
42057c478bd9Sstevel@tonic-gate 		}
42067c478bd9Sstevel@tonic-gate 	} else {			/* handle metadevices */
42077c478bd9Sstevel@tonic-gate 		/* get underlying unit & check capabilities */
42087c478bd9Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, compnp, ep)) == NULL)
42097c478bd9Sstevel@tonic-gate 			return (-1);
42107c478bd9Sstevel@tonic-gate 
42117c478bd9Sstevel@tonic-gate 		if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
42127c478bd9Sstevel@tonic-gate 		    (! (mdp->capabilities & MD_CAN_SP)))
42137c478bd9Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT,
42147c478bd9Sstevel@tonic-gate 			    meta_getminor(compnp->dev), compnp->cname));
42157c478bd9Sstevel@tonic-gate 	}
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate meta_check_sp_ok:
42187c478bd9Sstevel@tonic-gate 	mdclrerror(ep);
42197c478bd9Sstevel@tonic-gate 	return (0);
42207c478bd9Sstevel@tonic-gate }
42217c478bd9Sstevel@tonic-gate 
42227c478bd9Sstevel@tonic-gate /*
42237c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_create_sp()
42247c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name to create in
42257c478bd9Sstevel@tonic-gate  *		msp	- the unit structure to create
42267c478bd9Sstevel@tonic-gate  *		oblist	- an optional list of requested extents (-o/-b options)
42277c478bd9Sstevel@tonic-gate  *		options	- creation options
42287c478bd9Sstevel@tonic-gate  *		alignment - data alignment
42297c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
42307c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
42317c478bd9Sstevel@tonic-gate  * PURPOSE:	does most of the work for creating a soft partition.  If
42327c478bd9Sstevel@tonic-gate  *		metainit -p -e was used, first partition the drive.  Then
42337c478bd9Sstevel@tonic-gate  *		create an extent list based on the existing soft partitions
42347c478bd9Sstevel@tonic-gate  *		and assume all space not used by them is free.  Storage for
42357c478bd9Sstevel@tonic-gate  *		the new soft partition is allocated from the free extents
42367c478bd9Sstevel@tonic-gate  *		based on the length specified on the command line or the
42377c478bd9Sstevel@tonic-gate  *		oblist passed in.  The unit structure is then committed and
42387c478bd9Sstevel@tonic-gate  *		the watermarks are updated.  Finally, the status is changed to
42397c478bd9Sstevel@tonic-gate  *		Okay and the process is complete.
42407c478bd9Sstevel@tonic-gate  */
42417c478bd9Sstevel@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)42427c478bd9Sstevel@tonic-gate meta_create_sp(
42437c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
42447c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
42457c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*oblist,
42467c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
42477c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alignment,
42487c478bd9Sstevel@tonic-gate 	md_error_t	*ep
42497c478bd9Sstevel@tonic-gate )
42507c478bd9Sstevel@tonic-gate {
42517c478bd9Sstevel@tonic-gate 	mdname_t	*np = msp->common.namep;
42527c478bd9Sstevel@tonic-gate 	mdname_t	*compnp = msp->compnamep;
42537c478bd9Sstevel@tonic-gate 	mp_unit_t	*mp = NULL;
42547c478bd9Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL, *spnlp = NULL;
42557c478bd9Sstevel@tonic-gate 	md_set_params_t	set_params;
42567c478bd9Sstevel@tonic-gate 	int		rval = -1;
42577c478bd9Sstevel@tonic-gate 	diskaddr_t	comp_size;
42587c478bd9Sstevel@tonic-gate 	diskaddr_t	sp_start;
42597c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
42607c478bd9Sstevel@tonic-gate 	int		numexts = 0;	/* number of extents */
42617c478bd9Sstevel@tonic-gate 	int		count = 0;
42627c478bd9Sstevel@tonic-gate 	int		committed = 0;
42637c478bd9Sstevel@tonic-gate 	int		repart_options = MD_REPART_FORCE;
42647c478bd9Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
4265bf85a12bSJohn Wren Kennedy 	int		mn_set_master = 0;
42667c478bd9Sstevel@tonic-gate 
42677c478bd9Sstevel@tonic-gate 	md_set_desc	*sd;
42687c478bd9Sstevel@tonic-gate 	md_set_mmown_params_t	*ownpar = NULL;
42697c478bd9Sstevel@tonic-gate 	int		comp_is_mirror = 0;
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate 	/* validate soft partition */
42727c478bd9Sstevel@tonic-gate 	if (meta_check_sp(sp, msp, options, &repart_options, ep) != 0)
42737c478bd9Sstevel@tonic-gate 		return (-1);
42747c478bd9Sstevel@tonic-gate 
42757c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_USE_WHOLE_DISK) != 0) {
42767c478bd9Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) != 0) {
42777c478bd9Sstevel@tonic-gate 			if (meta_repartition_drive(sp,
42787c478bd9Sstevel@tonic-gate 			    compnp->drivenamep,
42797c478bd9Sstevel@tonic-gate 			    repart_options,
42807c478bd9Sstevel@tonic-gate 			    NULL, /* Don't return the VTOC */
42817c478bd9Sstevel@tonic-gate 			    ep) != 0)
42827c478bd9Sstevel@tonic-gate 
42837c478bd9Sstevel@tonic-gate 				return (-1);
42847c478bd9Sstevel@tonic-gate 		} else {
42857c478bd9Sstevel@tonic-gate 			/*
42867c478bd9Sstevel@tonic-gate 			 * If -n and -e are both specified, it doesn't make
42877c478bd9Sstevel@tonic-gate 			 * sense to continue without actually partitioning
42887c478bd9Sstevel@tonic-gate 			 * the drive.
42897c478bd9Sstevel@tonic-gate 			 */
42907c478bd9Sstevel@tonic-gate 			return (0);
42917c478bd9Sstevel@tonic-gate 		}
42927c478bd9Sstevel@tonic-gate 	}
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate 	/* populate the start_blk field of the component name */
42957c478bd9Sstevel@tonic-gate 	if ((sp_start = meta_sp_get_start(sp, compnp, ep)) ==
42967c478bd9Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
42977c478bd9Sstevel@tonic-gate 		rval = -1;
42987c478bd9Sstevel@tonic-gate 		goto out;
42997c478bd9Sstevel@tonic-gate 	}
43007c478bd9Sstevel@tonic-gate 
43017c478bd9Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
43027c478bd9Sstevel@tonic-gate 		/* store name in namespace */
43037c478bd9Sstevel@tonic-gate 		if (add_key_name(sp, compnp, &keynlp, ep) != 0) {
43047c478bd9Sstevel@tonic-gate 			rval = -1;
43057c478bd9Sstevel@tonic-gate 			goto out;
43067c478bd9Sstevel@tonic-gate 		}
43077c478bd9Sstevel@tonic-gate 	}
43087c478bd9Sstevel@tonic-gate 
43097c478bd9Sstevel@tonic-gate 	/*
43107c478bd9Sstevel@tonic-gate 	 * Get a list of the soft partitions that currently reside on
43117c478bd9Sstevel@tonic-gate 	 * the component.  We should ALWAYS force reload the cache,
43127c478bd9Sstevel@tonic-gate 	 * because if this is a single creation, there will not BE a
43137c478bd9Sstevel@tonic-gate 	 * cached list, and if we're using the md.tab, we must rebuild
43147c478bd9Sstevel@tonic-gate 	 * the list because it won't contain the previous (if any)
43157c478bd9Sstevel@tonic-gate 	 * soft partition.
43167c478bd9Sstevel@tonic-gate 	 */
43177c478bd9Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 1, ep);
43187c478bd9Sstevel@tonic-gate 	if (count < 0) {
43197c478bd9Sstevel@tonic-gate 		/* error occured */
43207c478bd9Sstevel@tonic-gate 		rval = -1;
43217c478bd9Sstevel@tonic-gate 		goto out;
43227c478bd9Sstevel@tonic-gate 	}
43237c478bd9Sstevel@tonic-gate 
43247c478bd9Sstevel@tonic-gate 	/*
43257c478bd9Sstevel@tonic-gate 	 * get the size of the underlying device.  if the size is smaller
43267c478bd9Sstevel@tonic-gate 	 * than or equal to the watermark size, we know there isn't
43277c478bd9Sstevel@tonic-gate 	 * enough space.
43287c478bd9Sstevel@tonic-gate 	 */
43297c478bd9Sstevel@tonic-gate 	if ((comp_size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR) {
43307c478bd9Sstevel@tonic-gate 		rval = -1;
43317c478bd9Sstevel@tonic-gate 		goto out;
43327c478bd9Sstevel@tonic-gate 	} else if (comp_size <= MD_SP_WMSIZE) {
43337c478bd9Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_SP_NOSPACE, 0, compnp->cname);
43347c478bd9Sstevel@tonic-gate 		rval = -1;
43357c478bd9Sstevel@tonic-gate 		goto out;
43367c478bd9Sstevel@tonic-gate 	}
43377c478bd9Sstevel@tonic-gate 	/*
43387c478bd9Sstevel@tonic-gate 	 * seed extlist with reserved space at the beginning of the volume and
43397c478bd9Sstevel@tonic-gate 	 * enough space for the end watermark.  The end watermark always gets
43407c478bd9Sstevel@tonic-gate 	 * updated, but if the underlying device changes size it may not be
43417c478bd9Sstevel@tonic-gate 	 * pointed to until the extent before it is updated.  Since the
43427c478bd9Sstevel@tonic-gate 	 * end of the reserved space is where the first watermark starts,
43437c478bd9Sstevel@tonic-gate 	 * the reserved extent should never be marked for updating.
43447c478bd9Sstevel@tonic-gate 	 */
43457c478bd9Sstevel@tonic-gate 
43467c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
43477c478bd9Sstevel@tonic-gate 	    0ULL, sp_start, EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
43487c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
43497c478bd9Sstevel@tonic-gate 	    (sp_ext_offset_t)(comp_size - MD_SP_WMSIZE), MD_SP_WMSIZE,
43507c478bd9Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
43537c478bd9Sstevel@tonic-gate 		rval = -1;
43547c478bd9Sstevel@tonic-gate 		goto out;
43557c478bd9Sstevel@tonic-gate 	}
43567c478bd9Sstevel@tonic-gate 
43577c478bd9Sstevel@tonic-gate 	metafreenamelist(spnlp);
43587c478bd9Sstevel@tonic-gate 
43597c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
43607c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_create_sp: list of used extents:\n");
43617c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
43627c478bd9Sstevel@tonic-gate 	}
43637c478bd9Sstevel@tonic-gate 
43647c478bd9Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
43657c478bd9Sstevel@tonic-gate 
43667c478bd9Sstevel@tonic-gate 	/* get extent list from -o/-b options or from free space */
43677c478bd9Sstevel@tonic-gate 	if (options & MDCMD_DIRECT) {
43687c478bd9Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
43697c478bd9Sstevel@tonic-gate 			meta_sp_debug("meta_create_sp: Dumping -o/-b list:\n");
43707c478bd9Sstevel@tonic-gate 			meta_sp_list_dump(oblist);
43717c478bd9Sstevel@tonic-gate 		}
43727c478bd9Sstevel@tonic-gate 
43737c478bd9Sstevel@tonic-gate 		numexts = meta_sp_alloc_by_list(sp, np, &extlist, oblist);
43747c478bd9Sstevel@tonic-gate 		if (numexts == -1) {
43757c478bd9Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_SP_OVERLAP, 0, np->cname);
43767c478bd9Sstevel@tonic-gate 			rval = -1;
43777c478bd9Sstevel@tonic-gate 			goto out;
43787c478bd9Sstevel@tonic-gate 		}
43797c478bd9Sstevel@tonic-gate 	} else {
43807c478bd9Sstevel@tonic-gate 		numexts = meta_sp_alloc_by_len(sp, np, &extlist,
43817c478bd9Sstevel@tonic-gate 		    &msp->ext.ext_val->len, 0LL, (alignment > 0) ? alignment :
43827c478bd9Sstevel@tonic-gate 		    meta_sp_get_default_alignment(sp, compnp, ep));
43837c478bd9Sstevel@tonic-gate 		if (numexts == -1) {
43847c478bd9Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_SP_NOSPACE, 0, np->cname);
43857c478bd9Sstevel@tonic-gate 			rval = -1;
43867c478bd9Sstevel@tonic-gate 			goto out;
43877c478bd9Sstevel@tonic-gate 		}
43887c478bd9Sstevel@tonic-gate 	}
43897c478bd9Sstevel@tonic-gate 
43907c478bd9Sstevel@tonic-gate 	assert(extlist != NULL);
43917c478bd9Sstevel@tonic-gate 
43927c478bd9Sstevel@tonic-gate 	/* create soft partition */
43937c478bd9Sstevel@tonic-gate 	mp = meta_sp_createunit(msp->common.namep, msp->compnamep,
43947c478bd9Sstevel@tonic-gate 	    extlist, numexts, msp->ext.ext_val->len, MD_SP_CREATEPEND, ep);
43957c478bd9Sstevel@tonic-gate 
43967c478bd9Sstevel@tonic-gate 	create_flag = meta_check_devicesize(mp->c.un_total_blocks);
43977c478bd9Sstevel@tonic-gate 
43987c478bd9Sstevel@tonic-gate 	/* if we're not doing anything (metainit -n), return success */
43997c478bd9Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
44007c478bd9Sstevel@tonic-gate 		rval = 0;	/* success */
44017c478bd9Sstevel@tonic-gate 		goto out;
44027c478bd9Sstevel@tonic-gate 	}
44037c478bd9Sstevel@tonic-gate 
44047c478bd9Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
44057c478bd9Sstevel@tonic-gate 
44067c478bd9Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
4407d7cd8252Stw21770 		mp->c.un_revision |= MD_64BIT_META_DEV;
44087c478bd9Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
44097c478bd9Sstevel@tonic-gate 	} else {
4410d7cd8252Stw21770 		mp->c.un_revision &= ~MD_64BIT_META_DEV;
44117c478bd9Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
44127c478bd9Sstevel@tonic-gate 	}
44137c478bd9Sstevel@tonic-gate 
44147c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
44157c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_create_sp: printing unit structure\n");
44167c478bd9Sstevel@tonic-gate 		meta_sp_printunit(mp);
44177c478bd9Sstevel@tonic-gate 	}
44187c478bd9Sstevel@tonic-gate 
44197c478bd9Sstevel@tonic-gate 	/*
44207c478bd9Sstevel@tonic-gate 	 * Check to see if we're trying to create a partition on a mirror. If so
44217c478bd9Sstevel@tonic-gate 	 * we may have to enforce an ownership change before writing the
44227c478bd9Sstevel@tonic-gate 	 * watermark out.
44237c478bd9Sstevel@tonic-gate 	 */
44247c478bd9Sstevel@tonic-gate 	if (metaismeta(compnp)) {
44257c478bd9Sstevel@tonic-gate 		char *miscname;
44267c478bd9Sstevel@tonic-gate 
44277c478bd9Sstevel@tonic-gate 		miscname = metagetmiscname(compnp, ep);
44287c478bd9Sstevel@tonic-gate 		if (miscname != NULL)
44297c478bd9Sstevel@tonic-gate 			comp_is_mirror = (strcmp(miscname, MD_MIRROR) == 0);
44307c478bd9Sstevel@tonic-gate 		else
44317c478bd9Sstevel@tonic-gate 			comp_is_mirror = 0;
44327c478bd9Sstevel@tonic-gate 	} else {
44337c478bd9Sstevel@tonic-gate 		comp_is_mirror = 0;
44347c478bd9Sstevel@tonic-gate 	}
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 	/*
44377c478bd9Sstevel@tonic-gate 	 * For a multi-node environment we have to ensure that the master
44387c478bd9Sstevel@tonic-gate 	 * node owns an underlying mirror before we issue the MD_IOCSET ioctl.
44397c478bd9Sstevel@tonic-gate 	 * If the master does not own the device we will deadlock as the
44407c478bd9Sstevel@tonic-gate 	 * implicit write of the watermarks (in sp_ioctl.c) will cause an
44417c478bd9Sstevel@tonic-gate 	 * ownership change that will block as the MD_IOCSET is still in
44427c478bd9Sstevel@tonic-gate 	 * progress. To close this window we force an owner change to occur
44437c478bd9Sstevel@tonic-gate 	 * before issuing the MD_IOCSET. We cannot simply open the device and
44447c478bd9Sstevel@tonic-gate 	 * write to it as this will only work for the first soft-partition
44457c478bd9Sstevel@tonic-gate 	 * creation.
44467c478bd9Sstevel@tonic-gate 	 */
44477c478bd9Sstevel@tonic-gate 
44487c478bd9Sstevel@tonic-gate 	if (comp_is_mirror && !metaislocalset(sp)) {
44497c478bd9Sstevel@tonic-gate 
44507c478bd9Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
44517c478bd9Sstevel@tonic-gate 			rval = -1;
44527c478bd9Sstevel@tonic-gate 			goto out;
44537c478bd9Sstevel@tonic-gate 		}
44547c478bd9Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd) && sd->sd_mn_am_i_master) {
4455bf85a12bSJohn Wren Kennedy 			mn_set_master = 1;
44567c478bd9Sstevel@tonic-gate 		}
44577c478bd9Sstevel@tonic-gate 	}
44587c478bd9Sstevel@tonic-gate 
44597c478bd9Sstevel@tonic-gate 	set_params.mnum = MD_SID(mp);
44607c478bd9Sstevel@tonic-gate 	set_params.size = mp->c.un_size;
44617c478bd9Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)mp;
44627c478bd9Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_SP, MD_MIN2SET(set_params.mnum));
44637c478bd9Sstevel@tonic-gate 
44647c478bd9Sstevel@tonic-gate 	/* first phase of commit. */
44657c478bd9Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
44667c478bd9Sstevel@tonic-gate 	    np->cname) != 0) {
44677c478bd9Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
44687c478bd9Sstevel@tonic-gate 		rval = -1;
44697c478bd9Sstevel@tonic-gate 		goto out;
44707c478bd9Sstevel@tonic-gate 	}
44717c478bd9Sstevel@tonic-gate 
44727c478bd9Sstevel@tonic-gate 	/* we've successfully committed the record */
44737c478bd9Sstevel@tonic-gate 	committed = 1;
44747c478bd9Sstevel@tonic-gate 
44757c478bd9Sstevel@tonic-gate 	/* write watermarks */
4476bf85a12bSJohn Wren Kennedy 	/*
4477bf85a12bSJohn Wren Kennedy 	 * Special-case for Multi-node sets. As we now have a distributed DRL
4478bf85a12bSJohn Wren Kennedy 	 * update mechanism, we _will_ hit the ioctl-within-ioctl deadlock case
4479bf85a12bSJohn Wren Kennedy 	 * unless we use a 'special' MN-capable ioctl to stage the watermark
4480bf85a12bSJohn Wren Kennedy 	 * update. This only affects the master-node in an MN set.
4481bf85a12bSJohn Wren Kennedy 	 */
4482bf85a12bSJohn Wren Kennedy 	if (mn_set_master) {
4483bf85a12bSJohn Wren Kennedy 		if (meta_mn_sp_update_wm(sp, msp, extlist, ep) < 0) {
4484bf85a12bSJohn Wren Kennedy 			rval = -1;
4485bf85a12bSJohn Wren Kennedy 			goto out;
4486bf85a12bSJohn Wren Kennedy 		}
4487bf85a12bSJohn Wren Kennedy 	} else {
44887c478bd9Sstevel@tonic-gate 		if (meta_sp_update_wm(sp, msp, extlist, ep) < 0) {
44897c478bd9Sstevel@tonic-gate 			rval = -1;
44907c478bd9Sstevel@tonic-gate 			goto out;
44917c478bd9Sstevel@tonic-gate 		}
44927c478bd9Sstevel@tonic-gate 	}
44937c478bd9Sstevel@tonic-gate 
44947c478bd9Sstevel@tonic-gate 	/* second phase of commit, set status to MD_SP_OK */
44957c478bd9Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &(MD_SID(mp)), 1, MD_SP_OK, ep) < 0) {
44967c478bd9Sstevel@tonic-gate 		rval = -1;
44977c478bd9Sstevel@tonic-gate 		goto out;
44987c478bd9Sstevel@tonic-gate 	}
44997c478bd9Sstevel@tonic-gate 	rval = 0;
45007c478bd9Sstevel@tonic-gate out:
45017c478bd9Sstevel@tonic-gate 	Free(mp);
45027c478bd9Sstevel@tonic-gate 	if (ownpar)
45037c478bd9Sstevel@tonic-gate 		Free(ownpar);
45047c478bd9Sstevel@tonic-gate 
45057c478bd9Sstevel@tonic-gate 	if (extlist != NULL)
45067c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extlist);
45077c478bd9Sstevel@tonic-gate 
45087c478bd9Sstevel@tonic-gate 	if (rval != 0 && keynlp != NULL && committed != 1)
45097c478bd9Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
45107c478bd9Sstevel@tonic-gate 
45117c478bd9Sstevel@tonic-gate 	metafreenamelist(keynlp);
45127c478bd9Sstevel@tonic-gate 
45137c478bd9Sstevel@tonic-gate 	return (rval);
45147c478bd9Sstevel@tonic-gate }
45157c478bd9Sstevel@tonic-gate 
45167c478bd9Sstevel@tonic-gate /*
45177c478bd9Sstevel@tonic-gate  * **************************************************************************
45187c478bd9Sstevel@tonic-gate  *                      Reset (metaclear) Functions                         *
45197c478bd9Sstevel@tonic-gate  * **************************************************************************
45207c478bd9Sstevel@tonic-gate  */
45217c478bd9Sstevel@tonic-gate 
45227c478bd9Sstevel@tonic-gate /*
45237c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset_common()
45247c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
45257c478bd9Sstevel@tonic-gate  *		np	- the name of the device to reset
45267c478bd9Sstevel@tonic-gate  *		msp	- the unit structure to reset
45277c478bd9Sstevel@tonic-gate  *		options	- metaclear options
45287c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
45297c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
45307c478bd9Sstevel@tonic-gate  * PURPOSE:	"resets", or more accurately deletes, the soft partition
45317c478bd9Sstevel@tonic-gate  *		specified.  First the state is set to "deleting" and then the
45327c478bd9Sstevel@tonic-gate  *		watermarks are all cleared out.  Once the watermarks have been
45337c478bd9Sstevel@tonic-gate  *		updated, the unit structure is deleted from the metadb.
45347c478bd9Sstevel@tonic-gate  */
45357c478bd9Sstevel@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)45367c478bd9Sstevel@tonic-gate meta_sp_reset_common(
45377c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
45387c478bd9Sstevel@tonic-gate 	mdname_t	*np,
45397c478bd9Sstevel@tonic-gate 	md_sp_t		*msp,
45407c478bd9Sstevel@tonic-gate 	md_sp_reset_t	reset_params,
45417c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
45427c478bd9Sstevel@tonic-gate 	md_error_t	*ep
45437c478bd9Sstevel@tonic-gate )
45447c478bd9Sstevel@tonic-gate {
45457c478bd9Sstevel@tonic-gate 	char	*miscname;
45467c478bd9Sstevel@tonic-gate 	int	rval = -1;
45477c478bd9Sstevel@tonic-gate 	int	is_open = 0;
45487c478bd9Sstevel@tonic-gate 
45497c478bd9Sstevel@tonic-gate 	/* make sure that nobody owns us */
45507c478bd9Sstevel@tonic-gate 	if (MD_HAS_PARENT(msp->common.parent))
45517c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(np->dev),
45527c478bd9Sstevel@tonic-gate 		    np->cname));
45537c478bd9Sstevel@tonic-gate 
45547c478bd9Sstevel@tonic-gate 	/* make sure that the soft partition isn't open */
45557c478bd9Sstevel@tonic-gate 	if ((is_open = meta_isopen(sp, np, ep, options)) < 0)
45567c478bd9Sstevel@tonic-gate 		return (-1);
45577c478bd9Sstevel@tonic-gate 	else if (is_open)
45587c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IS_OPEN, meta_getminor(np->dev),
45597c478bd9Sstevel@tonic-gate 		    np->cname));
45607c478bd9Sstevel@tonic-gate 
45617c478bd9Sstevel@tonic-gate 	/* get miscname */
45627c478bd9Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
45637c478bd9Sstevel@tonic-gate 		return (-1);
45647c478bd9Sstevel@tonic-gate 
45657c478bd9Sstevel@tonic-gate 	/* fill in reset params */
45667c478bd9Sstevel@tonic-gate 	MD_SETDRIVERNAME(&reset_params, miscname, sp->setno);
45677c478bd9Sstevel@tonic-gate 	reset_params.mnum = meta_getminor(np->dev);
45687c478bd9Sstevel@tonic-gate 	reset_params.force = (options & MDCMD_FORCE) ? 1 : 0;
45697c478bd9Sstevel@tonic-gate 
45707c478bd9Sstevel@tonic-gate 	/*
45717c478bd9Sstevel@tonic-gate 	 * clear soft partition - phase one.
45727c478bd9Sstevel@tonic-gate 	 * place the soft partition into the "delete pending" state.
45737c478bd9Sstevel@tonic-gate 	 */
45747c478bd9Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &reset_params.mnum, 1, MD_SP_DELPEND, ep) < 0)
45757c478bd9Sstevel@tonic-gate 		return (-1);
45767c478bd9Sstevel@tonic-gate 
45777c478bd9Sstevel@tonic-gate 	/*
45787c478bd9Sstevel@tonic-gate 	 * Now clear the watermarks.  If the force flag is specified,
45797c478bd9Sstevel@tonic-gate 	 * ignore any errors writing the watermarks and delete the unit
45807c478bd9Sstevel@tonic-gate 	 * structure anyway.  An error may leave the on-disk format in a
45817c478bd9Sstevel@tonic-gate 	 * corrupt state.  If force is not specified and we fail here,
45827c478bd9Sstevel@tonic-gate 	 * the soft partition will remain in the "delete pending" state.
45837c478bd9Sstevel@tonic-gate 	 */
45847c478bd9Sstevel@tonic-gate 	if ((meta_sp_clear_wm(sp, msp, ep) < 0) &&
45857c478bd9Sstevel@tonic-gate 	    ((options & MDCMD_FORCE) == 0))
45867c478bd9Sstevel@tonic-gate 		goto out;
45877c478bd9Sstevel@tonic-gate 
45887c478bd9Sstevel@tonic-gate 	/*
45897c478bd9Sstevel@tonic-gate 	 * clear soft partition - phase two.
45907c478bd9Sstevel@tonic-gate 	 * the driver removes the soft partition from the metadb and
45917c478bd9Sstevel@tonic-gate 	 * zeros out incore version.
45927c478bd9Sstevel@tonic-gate 	 */
45937c478bd9Sstevel@tonic-gate 	if (metaioctl(MD_IOCRESET, &reset_params,
45947c478bd9Sstevel@tonic-gate 	    &reset_params.mde, np->cname) != 0) {
45957c478bd9Sstevel@tonic-gate 		(void) mdstealerror(ep, &reset_params.mde);
45967c478bd9Sstevel@tonic-gate 		goto out;
45977c478bd9Sstevel@tonic-gate 	}
4598c113cb38Stn143363 
4599c113cb38Stn143363 	/*
4600c113cb38Stn143363 	 * Wait for the /dev to be cleaned up. Ignore the return
4601c113cb38Stn143363 	 * value since there's not much we can do.
4602c113cb38Stn143363 	 */
4603c113cb38Stn143363 	(void) meta_update_devtree(meta_getminor(np->dev));
4604c113cb38Stn143363 
46057c478bd9Sstevel@tonic-gate 	rval = 0;	/* success */
46067c478bd9Sstevel@tonic-gate 
46077c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
46087c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
46097c478bd9Sstevel@tonic-gate 		    "%s: Soft Partition is cleared\n"),
46107c478bd9Sstevel@tonic-gate 		    np->cname);
46117c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
46127c478bd9Sstevel@tonic-gate 	}
46137c478bd9Sstevel@tonic-gate 
46147c478bd9Sstevel@tonic-gate 	/*
46157c478bd9Sstevel@tonic-gate 	 * if told to recurse and on a metadevice, then attempt to
46167c478bd9Sstevel@tonic-gate 	 * clear the subdevices.  Indicate failure if the clear fails.
46177c478bd9Sstevel@tonic-gate 	 */
46187c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_RECURSE) &&
46197c478bd9Sstevel@tonic-gate 	    (metaismeta(msp->compnamep)) &&
46207c478bd9Sstevel@tonic-gate 	    (meta_reset_by_name(sp, msp->compnamep, options, ep) != 0))
46217c478bd9Sstevel@tonic-gate 		rval = -1;
46227c478bd9Sstevel@tonic-gate 
46237c478bd9Sstevel@tonic-gate out:
46247c478bd9Sstevel@tonic-gate 	meta_invalidate_name(np);
46257c478bd9Sstevel@tonic-gate 	return (rval);
46267c478bd9Sstevel@tonic-gate }
46277c478bd9Sstevel@tonic-gate 
46287c478bd9Sstevel@tonic-gate /*
46297c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset()
46307c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
46317c478bd9Sstevel@tonic-gate  *		np	- the name of the device to reset
46327c478bd9Sstevel@tonic-gate  *		options	- metaclear options
46337c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
46347c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
46357c478bd9Sstevel@tonic-gate  * PURPOSE:	provides the entry point to the rest of libmeta for deleting a
46367c478bd9Sstevel@tonic-gate  *		soft partition.  If np is NULL, then soft partitions are
46377c478bd9Sstevel@tonic-gate  *		all deleted at the current level and then recursively deleted.
46387c478bd9Sstevel@tonic-gate  *		Otherwise, if a name is specified either directly or as a
46397c478bd9Sstevel@tonic-gate  *		result of a recursive operation, it deletes only that name.
46407c478bd9Sstevel@tonic-gate  *		Since something sitting under a soft partition may be parented
46417c478bd9Sstevel@tonic-gate  *		to it, we have to reparent that other device to another soft
46427c478bd9Sstevel@tonic-gate  *		partition on the same component if we're deleting the one it's
46437c478bd9Sstevel@tonic-gate  *		parented to.
46447c478bd9Sstevel@tonic-gate  */
46457c478bd9Sstevel@tonic-gate int
meta_sp_reset(mdsetname_t * sp,mdname_t * np,mdcmdopts_t options,md_error_t * ep)46467c478bd9Sstevel@tonic-gate meta_sp_reset(
46477c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
46487c478bd9Sstevel@tonic-gate 	mdname_t	*np,
46497c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
46507c478bd9Sstevel@tonic-gate 	md_error_t	*ep
46517c478bd9Sstevel@tonic-gate )
46527c478bd9Sstevel@tonic-gate {
46537c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;
46547c478bd9Sstevel@tonic-gate 	int		rval = -1;
46557c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL, *nlp = NULL;
46567c478bd9Sstevel@tonic-gate 	md_sp_reset_t	reset_params;
46577c478bd9Sstevel@tonic-gate 	int		num_sp;
46587c478bd9Sstevel@tonic-gate 
46597c478bd9Sstevel@tonic-gate 	assert(sp != NULL);
46607c478bd9Sstevel@tonic-gate 
46617c478bd9Sstevel@tonic-gate 	/* reset/delete all soft paritions */
46627c478bd9Sstevel@tonic-gate 	if (np == NULL) {
46637c478bd9Sstevel@tonic-gate 		/*
46647c478bd9Sstevel@tonic-gate 		 * meta_reset_all sets MDCMD_RECURSE, but this behavior
46657c478bd9Sstevel@tonic-gate 		 * is incorrect for soft partitions.  We want to clear
46667c478bd9Sstevel@tonic-gate 		 * all soft partitions at a particular level in the
46677c478bd9Sstevel@tonic-gate 		 * metadevice stack before moving to the next level.
46687c478bd9Sstevel@tonic-gate 		 * Thus, we clear MDCMD_RECURSE from the options.
46697c478bd9Sstevel@tonic-gate 		 */
46707c478bd9Sstevel@tonic-gate 		options &= ~MDCMD_RECURSE;
46717c478bd9Sstevel@tonic-gate 
46727c478bd9Sstevel@tonic-gate 		/* for each soft partition */
46737c478bd9Sstevel@tonic-gate 		rval = 0;
46747c478bd9Sstevel@tonic-gate 		if (meta_get_sp_names(sp, &spnlp, 0, ep) < 0)
46757c478bd9Sstevel@tonic-gate 			rval = -1;
46767c478bd9Sstevel@tonic-gate 
46777c478bd9Sstevel@tonic-gate 		for (nlp = spnlp; (nlp != NULL); nlp = nlp->next) {
46787c478bd9Sstevel@tonic-gate 			np = nlp->namep;
46797c478bd9Sstevel@tonic-gate 			if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
46807c478bd9Sstevel@tonic-gate 				rval = -1;
46817c478bd9Sstevel@tonic-gate 				break;
46827c478bd9Sstevel@tonic-gate 			}
46837c478bd9Sstevel@tonic-gate 			/*
46847c478bd9Sstevel@tonic-gate 			 * meta_reset_all calls us twice to get soft
46857c478bd9Sstevel@tonic-gate 			 * partitions at the top and bottom of the stack.
46867c478bd9Sstevel@tonic-gate 			 * thus, if we have a parent, we'll get deleted
46877c478bd9Sstevel@tonic-gate 			 * on the next call.
46887c478bd9Sstevel@tonic-gate 			 */
46897c478bd9Sstevel@tonic-gate 			if (MD_HAS_PARENT(msp->common.parent))
46907c478bd9Sstevel@tonic-gate 				continue;
46917c478bd9Sstevel@tonic-gate 			/*
46927c478bd9Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
46937c478bd9Sstevel@tonic-gate 			 * of individual metaclear commands.
46947c478bd9Sstevel@tonic-gate 			 */
46957c478bd9Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
46967c478bd9Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
46977c478bd9Sstevel@tonic-gate 				    np->cname, options, 0, ep) != 0) {
46987c478bd9Sstevel@tonic-gate 					rval = -1;
46997c478bd9Sstevel@tonic-gate 					break;
47007c478bd9Sstevel@tonic-gate 				}
47017c478bd9Sstevel@tonic-gate 			} else {
47027c478bd9Sstevel@tonic-gate 				if (meta_sp_reset(sp, np, options, ep) != 0) {
47037c478bd9Sstevel@tonic-gate 					rval = -1;
47047c478bd9Sstevel@tonic-gate 					break;
47057c478bd9Sstevel@tonic-gate 				}
47067c478bd9Sstevel@tonic-gate 			}
47077c478bd9Sstevel@tonic-gate 		}
47087c478bd9Sstevel@tonic-gate 		/* cleanup return status */
47097c478bd9Sstevel@tonic-gate 		metafreenamelist(spnlp);
47107c478bd9Sstevel@tonic-gate 		return (rval);
47117c478bd9Sstevel@tonic-gate 	}
47127c478bd9Sstevel@tonic-gate 
47137c478bd9Sstevel@tonic-gate 	/* check the name */
47147c478bd9Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
47157c478bd9Sstevel@tonic-gate 		return (-1);
47167c478bd9Sstevel@tonic-gate 
47177c478bd9Sstevel@tonic-gate 	/* get the unit structure */
47187c478bd9Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, np, ep)) == NULL)
47197c478bd9Sstevel@tonic-gate 		return (-1);
47207c478bd9Sstevel@tonic-gate 
47217c478bd9Sstevel@tonic-gate 	/* clear out reset parameters */
47227c478bd9Sstevel@tonic-gate 	(void) memset(&reset_params, 0, sizeof (reset_params));
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate 	/* if our child is a metadevice, we need to deparent/reparent it */
47257c478bd9Sstevel@tonic-gate 	if (metaismeta(msp->compnamep)) {
47267c478bd9Sstevel@tonic-gate 		/* get sp's on this component */
47277c478bd9Sstevel@tonic-gate 		if ((num_sp = meta_sp_get_by_component(sp, msp->compnamep,
47287c478bd9Sstevel@tonic-gate 		    &spnlp, 1, ep)) <= 0)
47297c478bd9Sstevel@tonic-gate 			/* no sp's on this device.  error! */
47307c478bd9Sstevel@tonic-gate 			return (-1);
47317c478bd9Sstevel@tonic-gate 		else if (num_sp == 1)
47327c478bd9Sstevel@tonic-gate 			/* last sp on this device, so we deparent */
47337c478bd9Sstevel@tonic-gate 			reset_params.new_parent = MD_NO_PARENT;
47347c478bd9Sstevel@tonic-gate 		else {
47357c478bd9Sstevel@tonic-gate 			/* have to reparent this metadevice */
47367c478bd9Sstevel@tonic-gate 			for (nlp = spnlp; nlp != NULL; nlp = nlp->next) {
47377c478bd9Sstevel@tonic-gate 				if (meta_getminor(nlp->namep->dev) ==
47387c478bd9Sstevel@tonic-gate 				    meta_getminor(np->dev))
47397c478bd9Sstevel@tonic-gate 					continue;
47407c478bd9Sstevel@tonic-gate 				/*
47417c478bd9Sstevel@tonic-gate 				 * this isn't the softpart we are deleting,
47427c478bd9Sstevel@tonic-gate 				 * so use this device as the new parent.
47437c478bd9Sstevel@tonic-gate 				 */
47447c478bd9Sstevel@tonic-gate 				reset_params.new_parent =
47457c478bd9Sstevel@tonic-gate 				    meta_getminor(nlp->namep->dev);
47467c478bd9Sstevel@tonic-gate 				break;
47477c478bd9Sstevel@tonic-gate 			}
47487c478bd9Sstevel@tonic-gate 		}
47497c478bd9Sstevel@tonic-gate 		metafreenamelist(spnlp);
47507c478bd9Sstevel@tonic-gate 	}
47517c478bd9Sstevel@tonic-gate 
47527c478bd9Sstevel@tonic-gate 	if (meta_sp_reset_common(sp, np, msp, reset_params, options, ep) != 0)
47537c478bd9Sstevel@tonic-gate 		return (-1);
47547c478bd9Sstevel@tonic-gate 
47557c478bd9Sstevel@tonic-gate 	return (0);
47567c478bd9Sstevel@tonic-gate }
47577c478bd9Sstevel@tonic-gate 
47587c478bd9Sstevel@tonic-gate /*
47597c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_reset_component()
47607c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to reset
47617c478bd9Sstevel@tonic-gate  *		name	- the string name of the device to reset
47627c478bd9Sstevel@tonic-gate  *		options	- metaclear options
47637c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
47647c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
47657c478bd9Sstevel@tonic-gate  * PURPOSE:	provides the ability to delete all soft partitions on a
47667c478bd9Sstevel@tonic-gate  *		specified device (metaclear -p).  It first gets all of the
47677c478bd9Sstevel@tonic-gate  *		soft partitions on the component and then deletes each one
47687c478bd9Sstevel@tonic-gate  *		individually.
47697c478bd9Sstevel@tonic-gate  */
47707c478bd9Sstevel@tonic-gate int
meta_sp_reset_component(mdsetname_t * sp,char * name,mdcmdopts_t options,md_error_t * ep)47717c478bd9Sstevel@tonic-gate meta_sp_reset_component(
47727c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
47737c478bd9Sstevel@tonic-gate 	char		*name,
47747c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
47757c478bd9Sstevel@tonic-gate 	md_error_t	*ep
47767c478bd9Sstevel@tonic-gate )
47777c478bd9Sstevel@tonic-gate {
47787c478bd9Sstevel@tonic-gate 	mdname_t	*compnp, *np;
47797c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
47807c478bd9Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
47817c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;
47827c478bd9Sstevel@tonic-gate 	int		count;
47837c478bd9Sstevel@tonic-gate 	md_sp_reset_t	reset_params;
47847c478bd9Sstevel@tonic-gate 
4785d7cd8252Stw21770 	if ((compnp = metaname(&sp, name, UNKNOWN, ep)) == NULL)
47867c478bd9Sstevel@tonic-gate 		return (-1);
47877c478bd9Sstevel@tonic-gate 
47887c478bd9Sstevel@tonic-gate 	/* If we're starting out with no soft partitions, it's an error */
47897c478bd9Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 1, ep);
47907c478bd9Sstevel@tonic-gate 	if (count == 0)
47917c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_NOSP, 0, compnp->cname));
47927c478bd9Sstevel@tonic-gate 	else if (count < 0)
47937c478bd9Sstevel@tonic-gate 		return (-1);
47947c478bd9Sstevel@tonic-gate 
47957c478bd9Sstevel@tonic-gate 	/*
47967c478bd9Sstevel@tonic-gate 	 * clear all soft partitions on this component.
47977c478bd9Sstevel@tonic-gate 	 * NOTE: we reparent underlying metadevices as we go so that
47987c478bd9Sstevel@tonic-gate 	 * things stay sane.  Also, if we encounter an error, we stop
47997c478bd9Sstevel@tonic-gate 	 * and go no further in case recovery might be needed.
48007c478bd9Sstevel@tonic-gate 	 */
48017c478bd9Sstevel@tonic-gate 	for (nlp = spnlp; nlp != NULL; nlp = nlp->next) {
48027c478bd9Sstevel@tonic-gate 		/* clear out reset parameters */
48037c478bd9Sstevel@tonic-gate 		(void) memset(&reset_params, 0, sizeof (reset_params));
48047c478bd9Sstevel@tonic-gate 
48057c478bd9Sstevel@tonic-gate 		/* check the name */
48067c478bd9Sstevel@tonic-gate 		np = nlp->namep;
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate 		if (metachkmeta(np, ep) != 0) {
48097c478bd9Sstevel@tonic-gate 			metafreenamelist(spnlp);
48107c478bd9Sstevel@tonic-gate 			return (-1);
48117c478bd9Sstevel@tonic-gate 		}
48127c478bd9Sstevel@tonic-gate 
48137c478bd9Sstevel@tonic-gate 		/* get the unit structure */
48147c478bd9Sstevel@tonic-gate 		if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
48157c478bd9Sstevel@tonic-gate 			metafreenamelist(spnlp);
48167c478bd9Sstevel@tonic-gate 			return (-1);
48177c478bd9Sstevel@tonic-gate 		}
48187c478bd9Sstevel@tonic-gate 
48197c478bd9Sstevel@tonic-gate 		/* have to deparent/reparent metadevices */
48207c478bd9Sstevel@tonic-gate 		if (metaismeta(compnp)) {
48217c478bd9Sstevel@tonic-gate 			if (nlp->next == NULL)
48227c478bd9Sstevel@tonic-gate 				reset_params.new_parent = MD_NO_PARENT;
48237c478bd9Sstevel@tonic-gate 			else
48247c478bd9Sstevel@tonic-gate 				reset_params.new_parent =
48257c478bd9Sstevel@tonic-gate 				    meta_getminor(spnlp->next->namep->dev);
48267c478bd9Sstevel@tonic-gate 		}
48277c478bd9Sstevel@tonic-gate 
48287c478bd9Sstevel@tonic-gate 		/* clear soft partition */
48297c478bd9Sstevel@tonic-gate 		if (meta_sp_reset_common(sp, np, msp, reset_params,
48307c478bd9Sstevel@tonic-gate 		    options, ep) < 0) {
48317c478bd9Sstevel@tonic-gate 			metafreenamelist(spnlp);
48327c478bd9Sstevel@tonic-gate 			return (-1);
48337c478bd9Sstevel@tonic-gate 		}
48347c478bd9Sstevel@tonic-gate 	}
48357c478bd9Sstevel@tonic-gate 	metafreenamelist(spnlp);
48367c478bd9Sstevel@tonic-gate 	return (0);
48377c478bd9Sstevel@tonic-gate }
48387c478bd9Sstevel@tonic-gate 
48397c478bd9Sstevel@tonic-gate /*
48407c478bd9Sstevel@tonic-gate  * **************************************************************************
48417c478bd9Sstevel@tonic-gate  *                      Grow (metattach) Functions                          *
48427c478bd9Sstevel@tonic-gate  * **************************************************************************
48437c478bd9Sstevel@tonic-gate  */
48447c478bd9Sstevel@tonic-gate 
48457c478bd9Sstevel@tonic-gate /*
48467c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_attach()
48477c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the set name of the device to attach to
48487c478bd9Sstevel@tonic-gate  *		np	- the name of the device to attach to
48497c478bd9Sstevel@tonic-gate  *		addsize	- the unparsed string holding the amount of space to add
48507c478bd9Sstevel@tonic-gate  *		options	- metattach options
48517c478bd9Sstevel@tonic-gate  *		alignment - data alignment
48527c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
48537c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 success, -1 error
48547c478bd9Sstevel@tonic-gate  * PURPOSE:	grows a soft partition by reading in the existing unit
48557c478bd9Sstevel@tonic-gate  *		structure and setting its state to Growing, allocating more
48567c478bd9Sstevel@tonic-gate  *		space (similar to meta_create_sp()), updating the watermarks,
48577c478bd9Sstevel@tonic-gate  *		and then writing out the new unit structure in the Okay state.
48587c478bd9Sstevel@tonic-gate  */
48597c478bd9Sstevel@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)48607c478bd9Sstevel@tonic-gate meta_sp_attach(
48617c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
48627c478bd9Sstevel@tonic-gate 	mdname_t	*np,
48637c478bd9Sstevel@tonic-gate 	char		*addsize,
48647c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
48657c478bd9Sstevel@tonic-gate 	sp_ext_length_t	alignment,
48667c478bd9Sstevel@tonic-gate 	md_error_t	*ep
48677c478bd9Sstevel@tonic-gate )
48687c478bd9Sstevel@tonic-gate {
48697c478bd9Sstevel@tonic-gate 	md_grow_params_t	grow_params;
48707c478bd9Sstevel@tonic-gate 	sp_ext_length_t		grow_len;	/* amount to grow */
48717c478bd9Sstevel@tonic-gate 	mp_unit_t		*mp, *new_un;
48727c478bd9Sstevel@tonic-gate 	mdname_t		*compnp = NULL;
48737c478bd9Sstevel@tonic-gate 
48747c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*extlist = NULL;
48757c478bd9Sstevel@tonic-gate 	int			numexts;
48767c478bd9Sstevel@tonic-gate 	mdnamelist_t		*spnlp = NULL;
48777c478bd9Sstevel@tonic-gate 	int			count;
48787c478bd9Sstevel@tonic-gate 	md_sp_t			*msp;
48797c478bd9Sstevel@tonic-gate 	daddr_t			start_block;
48807c478bd9Sstevel@tonic-gate 
48817c478bd9Sstevel@tonic-gate 	/* should have the same set */
48827c478bd9Sstevel@tonic-gate 	assert(sp != NULL);
48837c478bd9Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(np->dev)));
48847c478bd9Sstevel@tonic-gate 
48857c478bd9Sstevel@tonic-gate 	/* check name */
48867c478bd9Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
48877c478bd9Sstevel@tonic-gate 		return (-1);
48887c478bd9Sstevel@tonic-gate 
48897c478bd9Sstevel@tonic-gate 	if (meta_sp_parsesize(addsize, &grow_len) == -1) {
48907c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_BAD_LENGTH, 0, np->cname));
48917c478bd9Sstevel@tonic-gate 	}
48927c478bd9Sstevel@tonic-gate 
48937c478bd9Sstevel@tonic-gate 	if ((mp = (mp_unit_t *)meta_get_mdunit(sp, np, ep)) == NULL)
48947c478bd9Sstevel@tonic-gate 		return (-1);
48957c478bd9Sstevel@tonic-gate 
48967c478bd9Sstevel@tonic-gate 	/* make sure we don't have a parent */
48977c478bd9Sstevel@tonic-gate 	if (MD_HAS_PARENT(mp->c.un_parent)) {
48987c478bd9Sstevel@tonic-gate 		Free(mp);
48997c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_INVAL_UNIT, 0, np->cname));
49007c478bd9Sstevel@tonic-gate 	}
49017c478bd9Sstevel@tonic-gate 
49027c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
49037c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: Unit structure before new "
49047c478bd9Sstevel@tonic-gate 		    "space:\n");
49057c478bd9Sstevel@tonic-gate 		meta_sp_printunit(mp);
49067c478bd9Sstevel@tonic-gate 	}
49077c478bd9Sstevel@tonic-gate 
49087c478bd9Sstevel@tonic-gate 	/*
49097c478bd9Sstevel@tonic-gate 	 * NOTE: the fast option to metakeyname is 0 as opposed to 1
49107c478bd9Sstevel@tonic-gate 	 * If this was not the case we would suffer the following
49117c478bd9Sstevel@tonic-gate 	 * assertion failure:
49127c478bd9Sstevel@tonic-gate 	 * Assertion failed: type1 != MDT_FAST_META && type1 != MDT_FAST_COMP
49137c478bd9Sstevel@tonic-gate 	 * file meta_check.x, line 315
49147c478bd9Sstevel@tonic-gate 	 * I guess this is because we have not "seen" this drive before
49157c478bd9Sstevel@tonic-gate 	 * and hence hit the failure - this is of course the attach routine
49167c478bd9Sstevel@tonic-gate 	 */
49177c478bd9Sstevel@tonic-gate 	if ((compnp = metakeyname(&sp, mp->un_key, 0, ep)) == NULL) {
49187c478bd9Sstevel@tonic-gate 		Free(mp);
49197c478bd9Sstevel@tonic-gate 		return (-1);
49207c478bd9Sstevel@tonic-gate 	}
49217c478bd9Sstevel@tonic-gate 
49227c478bd9Sstevel@tonic-gate 	/* metakeyname does not fill in the key. */
49237c478bd9Sstevel@tonic-gate 	compnp->key = mp->un_key;
49247c478bd9Sstevel@tonic-gate 
49257c478bd9Sstevel@tonic-gate 	/* work out the space on the component that we are dealing with */
49267c478bd9Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
49277c478bd9Sstevel@tonic-gate 
49287c478bd9Sstevel@tonic-gate 	/*
49297c478bd9Sstevel@tonic-gate 	 * see if the component has been soft partitioned yet, or if an
49307c478bd9Sstevel@tonic-gate 	 * error occurred.
49317c478bd9Sstevel@tonic-gate 	 */
49327c478bd9Sstevel@tonic-gate 	if (count == 0) {
49337c478bd9Sstevel@tonic-gate 		Free(mp);
49347c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_NOT_SP, 0, np->cname));
49357c478bd9Sstevel@tonic-gate 	} else if (count < 0) {
49367c478bd9Sstevel@tonic-gate 		Free(mp);
49377c478bd9Sstevel@tonic-gate 		return (-1);
49387c478bd9Sstevel@tonic-gate 	}
49397c478bd9Sstevel@tonic-gate 
49407c478bd9Sstevel@tonic-gate 	/*
49417c478bd9Sstevel@tonic-gate 	 * seed extlist with reserved space at the beginning of the volume and
49427c478bd9Sstevel@tonic-gate 	 * enough space for the end watermark.  The end watermark always gets
49437c478bd9Sstevel@tonic-gate 	 * updated, but if the underlying device changes size it may not be
49447c478bd9Sstevel@tonic-gate 	 * pointed to until the extent before it is updated.  Since the
49457c478bd9Sstevel@tonic-gate 	 * end of the reserved space is where the first watermark starts,
49467c478bd9Sstevel@tonic-gate 	 * the reserved extent should never be marked for updating.
49477c478bd9Sstevel@tonic-gate 	 */
49487c478bd9Sstevel@tonic-gate 	if ((start_block = meta_sp_get_start(sp, compnp, ep)) ==
49497c478bd9Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
49507c478bd9Sstevel@tonic-gate 		Free(mp);
49517c478bd9Sstevel@tonic-gate 		return (-1);
49527c478bd9Sstevel@tonic-gate 	}
49537c478bd9Sstevel@tonic-gate 
49547c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist, 0ULL, start_block,
49557c478bd9Sstevel@tonic-gate 	    EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
49567c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
49577c478bd9Sstevel@tonic-gate 	    metagetsize(compnp, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
49587c478bd9Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
49597c478bd9Sstevel@tonic-gate 
49607c478bd9Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
49617c478bd9Sstevel@tonic-gate 		Free(mp);
49627c478bd9Sstevel@tonic-gate 		return (-1);
49637c478bd9Sstevel@tonic-gate 	}
49647c478bd9Sstevel@tonic-gate 
49657c478bd9Sstevel@tonic-gate 	metafreenamelist(spnlp);
49667c478bd9Sstevel@tonic-gate 
49677c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
49687c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: list of used extents:\n");
49697c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(extlist);
49707c478bd9Sstevel@tonic-gate 	}
49717c478bd9Sstevel@tonic-gate 
49727c478bd9Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
49737c478bd9Sstevel@tonic-gate 
49747c478bd9Sstevel@tonic-gate 	assert(mp->un_numexts >= 1);
49757c478bd9Sstevel@tonic-gate 	numexts = meta_sp_alloc_by_len(sp, np, &extlist, &grow_len,
49767c478bd9Sstevel@tonic-gate 	    mp->un_ext[mp->un_numexts - 1].un_poff,
49777c478bd9Sstevel@tonic-gate 	    (alignment > 0) ? alignment :
49787c478bd9Sstevel@tonic-gate 	    meta_sp_get_default_alignment(sp, compnp, ep));
49797c478bd9Sstevel@tonic-gate 
49807c478bd9Sstevel@tonic-gate 	if (numexts == -1) {
49817c478bd9Sstevel@tonic-gate 		Free(mp);
49827c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_SP_NOSPACE, 0, np->cname));
49837c478bd9Sstevel@tonic-gate 	}
49847c478bd9Sstevel@tonic-gate 
49857c478bd9Sstevel@tonic-gate 	/* allocate new unit structure and copy in old unit */
49867c478bd9Sstevel@tonic-gate 	if ((new_un = meta_sp_updateunit(np, mp, extlist,
49877c478bd9Sstevel@tonic-gate 	    grow_len, numexts, ep)) == NULL) {
49887c478bd9Sstevel@tonic-gate 		Free(mp);
49897c478bd9Sstevel@tonic-gate 		return (-1);
49907c478bd9Sstevel@tonic-gate 	}
49917c478bd9Sstevel@tonic-gate 	Free(mp);
49927c478bd9Sstevel@tonic-gate 
49937c478bd9Sstevel@tonic-gate 	/* If running in dryrun mode (-n option), we're done here */
49947c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
49957c478bd9Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
49967c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
49977c478bd9Sstevel@tonic-gate 			    "%s: Soft Partition would grow\n"),
49987c478bd9Sstevel@tonic-gate 			    np->cname);
49997c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
50007c478bd9Sstevel@tonic-gate 		}
50017c478bd9Sstevel@tonic-gate 		return (0);
50027c478bd9Sstevel@tonic-gate 	}
50037c478bd9Sstevel@tonic-gate 
50047c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
50057c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_attach: updated unit structure:\n");
50067c478bd9Sstevel@tonic-gate 		meta_sp_printunit(new_un);
50077c478bd9Sstevel@tonic-gate 	}
50087c478bd9Sstevel@tonic-gate 
50097c478bd9Sstevel@tonic-gate 	assert(new_un != NULL);
50107c478bd9Sstevel@tonic-gate 
50117c478bd9Sstevel@tonic-gate 	(void) memset(&grow_params, 0, sizeof (grow_params));
50127c478bd9Sstevel@tonic-gate 	if (new_un->c.un_total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) {
50137c478bd9Sstevel@tonic-gate 		grow_params.options = MD_CRO_64BIT;
5014d7cd8252Stw21770 		new_un->c.un_revision |= MD_64BIT_META_DEV;
50157c478bd9Sstevel@tonic-gate 	} else {
50167c478bd9Sstevel@tonic-gate 		grow_params.options = MD_CRO_32BIT;
5017d7cd8252Stw21770 		new_un->c.un_revision &= ~MD_64BIT_META_DEV;
50187c478bd9Sstevel@tonic-gate 	}
50197c478bd9Sstevel@tonic-gate 	grow_params.mnum = MD_SID(new_un);
50207c478bd9Sstevel@tonic-gate 	grow_params.size = new_un->c.un_size;
50217c478bd9Sstevel@tonic-gate 	grow_params.mdp = (uintptr_t)new_un;
50227c478bd9Sstevel@tonic-gate 	MD_SETDRIVERNAME(&grow_params, MD_SP, MD_MIN2SET(grow_params.mnum));
50237c478bd9Sstevel@tonic-gate 
50247c478bd9Sstevel@tonic-gate 	if (metaioctl(MD_IOCGROW, &grow_params, &grow_params.mde,
50257c478bd9Sstevel@tonic-gate 	    np->cname) != 0) {
50267c478bd9Sstevel@tonic-gate 		(void) mdstealerror(ep, &grow_params.mde);
50277c478bd9Sstevel@tonic-gate 		return (-1);
50287c478bd9Sstevel@tonic-gate 	}
50297c478bd9Sstevel@tonic-gate 
50307c478bd9Sstevel@tonic-gate 	/* update all watermarks */
50317c478bd9Sstevel@tonic-gate 
50327c478bd9Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, np, ep)) == NULL)
50337c478bd9Sstevel@tonic-gate 		return (-1);
50347c478bd9Sstevel@tonic-gate 	if (meta_sp_update_wm(sp, msp, extlist, ep) < 0)
50357c478bd9Sstevel@tonic-gate 		return (-1);
50367c478bd9Sstevel@tonic-gate 
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate 	/* second phase of commit, set status to MD_SP_OK */
50397c478bd9Sstevel@tonic-gate 	if (meta_sp_setstatus(sp, &(MD_SID(new_un)), 1, MD_SP_OK, ep) < 0)
50407c478bd9Sstevel@tonic-gate 		return (-1);
50417c478bd9Sstevel@tonic-gate 
50427c478bd9Sstevel@tonic-gate 	meta_invalidate_name(np);
50437c478bd9Sstevel@tonic-gate 
50447c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
50457c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
50467c478bd9Sstevel@tonic-gate 		    "%s: Soft Partition has been grown\n"),
50477c478bd9Sstevel@tonic-gate 		    np->cname);
50487c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
50497c478bd9Sstevel@tonic-gate 	}
50507c478bd9Sstevel@tonic-gate 
50517c478bd9Sstevel@tonic-gate 	return (0);
50527c478bd9Sstevel@tonic-gate }
50537c478bd9Sstevel@tonic-gate 
50547c478bd9Sstevel@tonic-gate /*
50557c478bd9Sstevel@tonic-gate  * **************************************************************************
50567c478bd9Sstevel@tonic-gate  *                    Recovery (metarecover) Functions                      *
50577c478bd9Sstevel@tonic-gate  * **************************************************************************
50587c478bd9Sstevel@tonic-gate  */
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate /*
50617c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_recover_sp()
50627c478bd9Sstevel@tonic-gate  * INPUT:	sp	- the name of the set we are recovering on
50637c478bd9Sstevel@tonic-gate  *		compnp	- name pointer for device we are recovering on
50647c478bd9Sstevel@tonic-gate  *		argc	- argument count
50657c478bd9Sstevel@tonic-gate  *		argv	- left over arguments not parsed by metarecover command
50667c478bd9Sstevel@tonic-gate  *		options	- metarecover options
50677c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
50687c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
50697c478bd9Sstevel@tonic-gate  * PURPOSE:	parse soft partitioning-specific metarecover options and
50707c478bd9Sstevel@tonic-gate  *		dispatch to the appropriate function to handle recovery.
50717c478bd9Sstevel@tonic-gate  */
50727c478bd9Sstevel@tonic-gate int
meta_recover_sp(mdsetname_t * sp,mdname_t * compnp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)50737c478bd9Sstevel@tonic-gate meta_recover_sp(
50747c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
50757c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
50767c478bd9Sstevel@tonic-gate 	int		argc,
50777c478bd9Sstevel@tonic-gate 	char		*argv[],
50787c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
50797c478bd9Sstevel@tonic-gate 	md_error_t	*ep
50807c478bd9Sstevel@tonic-gate )
50817c478bd9Sstevel@tonic-gate {
50827c478bd9Sstevel@tonic-gate 	md_set_desc	*sd;
50837c478bd9Sstevel@tonic-gate 
50847c478bd9Sstevel@tonic-gate 	if (argc > 1) {
50857c478bd9Sstevel@tonic-gate 		(void) meta_cook_syntax(ep, MDE_SYNTAX, compnp->cname,
50867c478bd9Sstevel@tonic-gate 		    argc, argv);
50877c478bd9Sstevel@tonic-gate 		return (-1);
50887c478bd9Sstevel@tonic-gate 	}
50897c478bd9Sstevel@tonic-gate 
50907c478bd9Sstevel@tonic-gate 	/*
50917c478bd9Sstevel@tonic-gate 	 * For a MN set, this operation must be performed on the master
50927c478bd9Sstevel@tonic-gate 	 * as it is responsible for maintaining the watermarks
50937c478bd9Sstevel@tonic-gate 	 */
50947c478bd9Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
50957c478bd9Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
50967c478bd9Sstevel@tonic-gate 			return (-1);
50977c478bd9Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd) && !sd->sd_mn_am_i_master) {
50987c478bd9Sstevel@tonic-gate 			(void) mddserror(ep, MDE_DS_MASTER_ONLY, sp->setno,
50997c478bd9Sstevel@tonic-gate 			    sd->sd_mn_master_nodenm, NULL, NULL);
51007c478bd9Sstevel@tonic-gate 			return (-1);
51017c478bd9Sstevel@tonic-gate 		}
51027c478bd9Sstevel@tonic-gate 	}
51037c478bd9Sstevel@tonic-gate 	if (argc == 0) {
51047c478bd9Sstevel@tonic-gate 		/*
51057c478bd9Sstevel@tonic-gate 		 * if no additional arguments are passed, metarecover should
51067c478bd9Sstevel@tonic-gate 		 * validate both on-disk and metadb structures as well as
51077c478bd9Sstevel@tonic-gate 		 * checking that both are consistent with each other
51087c478bd9Sstevel@tonic-gate 		 */
51097c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_wm(sp, compnp, options, ep) < 0)
51107c478bd9Sstevel@tonic-gate 			return (-1);
51117c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) < 0)
51127c478bd9Sstevel@tonic-gate 			return (-1);
51137c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_wm_and_unit(sp, compnp, options, ep) < 0)
51147c478bd9Sstevel@tonic-gate 			return (-1);
51157c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[0], "-d") == 0) {
51167c478bd9Sstevel@tonic-gate 		/*
51177c478bd9Sstevel@tonic-gate 		 * Ensure that there is no existing valid record for this
51187c478bd9Sstevel@tonic-gate 		 * soft-partition. If there is we have nothing to do.
51197c478bd9Sstevel@tonic-gate 		 */
51207c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) == 0)
51217c478bd9Sstevel@tonic-gate 			return (-1);
51227c478bd9Sstevel@tonic-gate 		/* validate and recover from on-disk structures */
51237c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_wm(sp, compnp, options, ep) < 0)
51247c478bd9Sstevel@tonic-gate 			return (-1);
51257c478bd9Sstevel@tonic-gate 		if (meta_sp_recover_from_wm(sp, compnp, options, ep) < 0)
51267c478bd9Sstevel@tonic-gate 			return (-1);
51277c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[0], "-m") == 0) {
51287c478bd9Sstevel@tonic-gate 		/* validate and recover from metadb structures */
51297c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_unit(sp, compnp, options, ep) < 0)
51307c478bd9Sstevel@tonic-gate 			return (-1);
51317c478bd9Sstevel@tonic-gate 		if (meta_sp_recover_from_unit(sp, compnp, options, ep) < 0)
51327c478bd9Sstevel@tonic-gate 			return (-1);
51337c478bd9Sstevel@tonic-gate 	} else {
51347c478bd9Sstevel@tonic-gate 		/* syntax error */
51357c478bd9Sstevel@tonic-gate 		(void) meta_cook_syntax(ep, MDE_SYNTAX, compnp->cname,
51367c478bd9Sstevel@tonic-gate 		    argc, argv);
51377c478bd9Sstevel@tonic-gate 		return (-1);
51387c478bd9Sstevel@tonic-gate 	}
51397c478bd9Sstevel@tonic-gate 
51407c478bd9Sstevel@tonic-gate 	return (0);
51417c478bd9Sstevel@tonic-gate }
51427c478bd9Sstevel@tonic-gate 
51437c478bd9Sstevel@tonic-gate /*
51447c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_display_exthdr()
51457c478bd9Sstevel@tonic-gate  * INPUT:	none
51467c478bd9Sstevel@tonic-gate  * OUTPUT:	none
51477c478bd9Sstevel@tonic-gate  * RETURNS:	void
51487c478bd9Sstevel@tonic-gate  * PURPOSE:	print header line for sp_ext_node_t information.  to be used
51497c478bd9Sstevel@tonic-gate  *		in conjunction with meta_sp_display_ext().
51507c478bd9Sstevel@tonic-gate  */
51517c478bd9Sstevel@tonic-gate static void
meta_sp_display_exthdr(void)51527c478bd9Sstevel@tonic-gate meta_sp_display_exthdr(void)
51537c478bd9Sstevel@tonic-gate {
51547c478bd9Sstevel@tonic-gate 	(void) printf("%20s %5s %7s %20s %20s\n",
51557c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Name"),
51567c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Seq#"),
51577c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Type"),
51587c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Offset"),
51597c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Length"));
51607c478bd9Sstevel@tonic-gate }
51617c478bd9Sstevel@tonic-gate 
51627c478bd9Sstevel@tonic-gate 
51637c478bd9Sstevel@tonic-gate /*
51647c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_display_ext()
51657c478bd9Sstevel@tonic-gate  * INPUT:	ext	- extent to display
51667c478bd9Sstevel@tonic-gate  * OUTPUT:	none
51677c478bd9Sstevel@tonic-gate  * RETURNS:	void
51687c478bd9Sstevel@tonic-gate  * PURPOSE:	print selected fields from sp_ext_node_t.
51697c478bd9Sstevel@tonic-gate  */
51707c478bd9Sstevel@tonic-gate static void
meta_sp_display_ext(sp_ext_node_t * ext)51717c478bd9Sstevel@tonic-gate meta_sp_display_ext(sp_ext_node_t *ext)
51727c478bd9Sstevel@tonic-gate {
51737c478bd9Sstevel@tonic-gate 	/* print extent information */
51747c478bd9Sstevel@tonic-gate 	if (ext->ext_namep != NULL)
51757c478bd9Sstevel@tonic-gate 		(void) printf("%20s ", ext->ext_namep->cname);
51767c478bd9Sstevel@tonic-gate 	else
51777c478bd9Sstevel@tonic-gate 		(void) printf("%20s ", "NONE");
51787c478bd9Sstevel@tonic-gate 
51797c478bd9Sstevel@tonic-gate 	(void) printf("%5u ", ext->ext_seq);
51807c478bd9Sstevel@tonic-gate 
51817c478bd9Sstevel@tonic-gate 	switch (ext->ext_type) {
51827c478bd9Sstevel@tonic-gate 	case EXTTYP_ALLOC:
51837c478bd9Sstevel@tonic-gate 		(void) printf("%7s ", "ALLOC");
51847c478bd9Sstevel@tonic-gate 		break;
51857c478bd9Sstevel@tonic-gate 	case EXTTYP_FREE:
51867c478bd9Sstevel@tonic-gate 		(void) printf("%7s ", "FREE");
51877c478bd9Sstevel@tonic-gate 		break;
51887c478bd9Sstevel@tonic-gate 	case EXTTYP_RESERVED:
51897c478bd9Sstevel@tonic-gate 		(void) printf("%7s ", "RESV");
51907c478bd9Sstevel@tonic-gate 		break;
51917c478bd9Sstevel@tonic-gate 	case EXTTYP_END:
51927c478bd9Sstevel@tonic-gate 		(void) printf("%7s ", "END");
51937c478bd9Sstevel@tonic-gate 		break;
51947c478bd9Sstevel@tonic-gate 	default:
51957c478bd9Sstevel@tonic-gate 		(void) printf("%7s ", "INVLD");
51967c478bd9Sstevel@tonic-gate 		break;
51977c478bd9Sstevel@tonic-gate 	}
51987c478bd9Sstevel@tonic-gate 
51997c478bd9Sstevel@tonic-gate 	(void) printf("%20llu %20llu\n", ext->ext_offset, ext->ext_length);
52007c478bd9Sstevel@tonic-gate }
52017c478bd9Sstevel@tonic-gate 
52027c478bd9Sstevel@tonic-gate 
52037c478bd9Sstevel@tonic-gate /*
52047c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_checkseq()
52057c478bd9Sstevel@tonic-gate  * INPUT:	extlist	- list of extents to be checked
52067c478bd9Sstevel@tonic-gate  * OUTPUT:	none
52077c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
52087c478bd9Sstevel@tonic-gate  * PURPOSE:	check soft partition sequence numbers.  this function assumes
52097c478bd9Sstevel@tonic-gate  *		that a list of extents representing 1 or more soft partitions
52107c478bd9Sstevel@tonic-gate  *		is passed in sorted in sequence number order.  within a
52117c478bd9Sstevel@tonic-gate  *		single soft partition, there may not be any missing or
52127c478bd9Sstevel@tonic-gate  *		duplicate sequence numbers.
52137c478bd9Sstevel@tonic-gate  */
52147c478bd9Sstevel@tonic-gate static int
meta_sp_checkseq(sp_ext_node_t * extlist)52157c478bd9Sstevel@tonic-gate meta_sp_checkseq(sp_ext_node_t *extlist)
52167c478bd9Sstevel@tonic-gate {
52177c478bd9Sstevel@tonic-gate 	sp_ext_node_t *ext;
52187c478bd9Sstevel@tonic-gate 
52197c478bd9Sstevel@tonic-gate 	assert(extlist != NULL);
52207c478bd9Sstevel@tonic-gate 
52217c478bd9Sstevel@tonic-gate 	for (ext = extlist;
52227c478bd9Sstevel@tonic-gate 	    ext->ext_next != NULL && ext->ext_next->ext_type == EXTTYP_ALLOC;
52237c478bd9Sstevel@tonic-gate 	    ext = ext->ext_next) {
52247c478bd9Sstevel@tonic-gate 		if (ext->ext_next->ext_namep != NULL &&
52257c478bd9Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
52267c478bd9Sstevel@tonic-gate 		    ext->ext_namep->cname) != 0)
52277c478bd9Sstevel@tonic-gate 				continue;
52287c478bd9Sstevel@tonic-gate 
52297c478bd9Sstevel@tonic-gate 		if (ext->ext_next->ext_seq != ext->ext_seq + 1) {
52307c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
52317c478bd9Sstevel@tonic-gate 			    "%s: sequence numbers are "
52327c478bd9Sstevel@tonic-gate 			    "incorrect: %d should be %d\n"),
52337c478bd9Sstevel@tonic-gate 			    ext->ext_next->ext_namep->cname,
52347c478bd9Sstevel@tonic-gate 			    ext->ext_next->ext_seq, ext->ext_seq + 1);
52357c478bd9Sstevel@tonic-gate 			return (-1);
52367c478bd9Sstevel@tonic-gate 		}
52377c478bd9Sstevel@tonic-gate 	}
52387c478bd9Sstevel@tonic-gate 	return (0);
52397c478bd9Sstevel@tonic-gate }
52407c478bd9Sstevel@tonic-gate 
52417c478bd9Sstevel@tonic-gate 
52427c478bd9Sstevel@tonic-gate /*
52437c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_resolve_name_conflict()
52447c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we're are recovering in.
52457c478bd9Sstevel@tonic-gate  *		old_np	- name pointer of soft partition we found on disk.
52467c478bd9Sstevel@tonic-gate  * OUTPUT:	new_np	- name pointer for new soft partition name.
52477c478bd9Sstevel@tonic-gate  *		ep	- error pointer returned.
52487c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - name not replace, 1 - name replaced, -1 - error
52497c478bd9Sstevel@tonic-gate  * PURPOSE:	Check to see if the name of one of the soft partitions we found
52507c478bd9Sstevel@tonic-gate  *		on disk already exists in the metadb.  If so, prompt for a new
52517c478bd9Sstevel@tonic-gate  *		name.  In addition, we keep a static array of names that
52527c478bd9Sstevel@tonic-gate  *		will be recovered from this device since these names don't
52537c478bd9Sstevel@tonic-gate  *		exist in the configuration at this point but cannot be
52547c478bd9Sstevel@tonic-gate  *		recovered more than once.
52557c478bd9Sstevel@tonic-gate  */
52567c478bd9Sstevel@tonic-gate static int
meta_sp_resolve_name_conflict(mdsetname_t * sp,mdname_t * old_np,mdname_t ** new_np,md_error_t * ep)52577c478bd9Sstevel@tonic-gate meta_sp_resolve_name_conflict(
52587c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
52597c478bd9Sstevel@tonic-gate 	mdname_t	*old_np,
52607c478bd9Sstevel@tonic-gate 	mdname_t	**new_np,
52617c478bd9Sstevel@tonic-gate 	md_error_t	*ep
52627c478bd9Sstevel@tonic-gate )
52637c478bd9Sstevel@tonic-gate {
52647c478bd9Sstevel@tonic-gate 	char		yesno[255];
52657c478bd9Sstevel@tonic-gate 	char		*yes;
52667c478bd9Sstevel@tonic-gate 	char		newname[MD_SP_MAX_DEVNAME_PLUS_1];
52677c478bd9Sstevel@tonic-gate 	int		nunits;
52687c478bd9Sstevel@tonic-gate 	static int	*used_names = NULL;
52697c478bd9Sstevel@tonic-gate 
52707c478bd9Sstevel@tonic-gate 	assert(old_np != NULL);
52717c478bd9Sstevel@tonic-gate 
52727c478bd9Sstevel@tonic-gate 	if (used_names == NULL) {
52737c478bd9Sstevel@tonic-gate 		if ((nunits = meta_get_nunits(ep)) < 0)
52747c478bd9Sstevel@tonic-gate 			return (-1);
52757c478bd9Sstevel@tonic-gate 		used_names = Zalloc(nunits * sizeof (int));
52767c478bd9Sstevel@tonic-gate 	}
52777c478bd9Sstevel@tonic-gate 
52787c478bd9Sstevel@tonic-gate 	/* see if it exists already */
52797c478bd9Sstevel@tonic-gate 	if (used_names[MD_MIN2UNIT(meta_getminor(old_np->dev))] == 0 &&
52807c478bd9Sstevel@tonic-gate 	    metagetmiscname(old_np, ep) == NULL) {
52817c478bd9Sstevel@tonic-gate 		if (! mdismderror(ep, MDE_UNIT_NOT_SETUP))
52827c478bd9Sstevel@tonic-gate 			return (-1);
52837c478bd9Sstevel@tonic-gate 		else {
52847c478bd9Sstevel@tonic-gate 			used_names[MD_MIN2UNIT(meta_getminor(old_np->dev))] = 1;
52857c478bd9Sstevel@tonic-gate 			mdclrerror(ep);
52867c478bd9Sstevel@tonic-gate 			return (0);
52877c478bd9Sstevel@tonic-gate 		}
52887c478bd9Sstevel@tonic-gate 	}
52897c478bd9Sstevel@tonic-gate 
52907c478bd9Sstevel@tonic-gate 	/* name exists, ask the user for a new one */
52917c478bd9Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
52927c478bd9Sstevel@tonic-gate 	    "WARNING: A soft partition named %s was found in the extent\n"
52937c478bd9Sstevel@tonic-gate 	    "headers, but this name already exists in the metadb "
52947c478bd9Sstevel@tonic-gate 	    "configuration.\n"
52957c478bd9Sstevel@tonic-gate 	    "In order to continue recovery you must supply\n"
52967c478bd9Sstevel@tonic-gate 	    "a new name for this soft partition.\n"), old_np->cname);
52977c478bd9Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
52987c478bd9Sstevel@tonic-gate 	    "Would you like to continue and supply a new name? (yes/no) "));
52997c478bd9Sstevel@tonic-gate 
53007c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
53017c478bd9Sstevel@tonic-gate 	if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
53027c478bd9Sstevel@tonic-gate 	    (strlen(yesno) == 1))
53037c478bd9Sstevel@tonic-gate 		(void) snprintf(yesno, sizeof (yesno), "%s\n",
53047c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "no"));
53057c478bd9Sstevel@tonic-gate 	yes = dgettext(TEXT_DOMAIN, "yes");
53067c478bd9Sstevel@tonic-gate 	if (strncasecmp(yesno, yes, strlen(yesno) - 1) != 0) {
53077c478bd9Sstevel@tonic-gate 		return (-1);
53087c478bd9Sstevel@tonic-gate 	}
53097c478bd9Sstevel@tonic-gate 
53107c478bd9Sstevel@tonic-gate 	(void) fflush(stdin);
53117c478bd9Sstevel@tonic-gate 
53127c478bd9Sstevel@tonic-gate 	/* get the new name */
53137c478bd9Sstevel@tonic-gate 	for (;;) {
53147c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "Please enter a new name "
53157c478bd9Sstevel@tonic-gate 		    "for this soft partition (dXXXX) "));
53167c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
53177c478bd9Sstevel@tonic-gate 		if (fgets(newname, MD_SP_MAX_DEVNAME_PLUS_1, stdin) == NULL)
53187c478bd9Sstevel@tonic-gate 			(void) strcpy(newname, "");
53197c478bd9Sstevel@tonic-gate 
53207c478bd9Sstevel@tonic-gate 		/* remove newline character */
53217c478bd9Sstevel@tonic-gate 		if (newname[strlen(newname) - 1] == '\n')
53227c478bd9Sstevel@tonic-gate 			newname[strlen(newname) - 1] = '\0';
53237c478bd9Sstevel@tonic-gate 
53247c478bd9Sstevel@tonic-gate 		if (!(is_metaname(newname)) ||
5325d7cd8252Stw21770 		    (meta_init_make_device(&sp, newname, ep) <= 0)) {
53267c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
53277c478bd9Sstevel@tonic-gate 			    "Invalid metadevice name\n"));
53287c478bd9Sstevel@tonic-gate 			(void) fflush(stderr);
53297c478bd9Sstevel@tonic-gate 			continue;
53307c478bd9Sstevel@tonic-gate 		}
53317c478bd9Sstevel@tonic-gate 
5332d7cd8252Stw21770 		if ((*new_np = metaname(&sp, newname,
5333d7cd8252Stw21770 		    META_DEVICE, ep)) == NULL) {
53347c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
53357c478bd9Sstevel@tonic-gate 			    "Invalid metadevice name\n"));
53367c478bd9Sstevel@tonic-gate 			(void) fflush(stderr);
53377c478bd9Sstevel@tonic-gate 			continue;
53387c478bd9Sstevel@tonic-gate 		}
53397c478bd9Sstevel@tonic-gate 
53407c478bd9Sstevel@tonic-gate 		assert(MD_MIN2UNIT(meta_getminor((*new_np)->dev)) < nunits);
53417c478bd9Sstevel@tonic-gate 		/* make sure the name isn't already being used */
53427c478bd9Sstevel@tonic-gate 		if (used_names[MD_MIN2UNIT(meta_getminor((*new_np)->dev))] ||
53437c478bd9Sstevel@tonic-gate 		    metagetmiscname(*new_np, ep) != NULL) {
53447c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
53457c478bd9Sstevel@tonic-gate 			    "That name already exists\n"));
53467c478bd9Sstevel@tonic-gate 			continue;
53477c478bd9Sstevel@tonic-gate 		} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP))
53487c478bd9Sstevel@tonic-gate 			return (-1);
53497c478bd9Sstevel@tonic-gate 
53507c478bd9Sstevel@tonic-gate 		break;
53517c478bd9Sstevel@tonic-gate 	}
53527c478bd9Sstevel@tonic-gate 
53537c478bd9Sstevel@tonic-gate 	/* got a new name, place in used array and return */
53547c478bd9Sstevel@tonic-gate 	used_names[MD_MIN2UNIT(meta_getminor((*new_np)->dev))] = 1;
53557c478bd9Sstevel@tonic-gate 	mdclrerror(ep);
53567c478bd9Sstevel@tonic-gate 	return (1);
53577c478bd9Sstevel@tonic-gate }
53587c478bd9Sstevel@tonic-gate 
53597c478bd9Sstevel@tonic-gate /*
53607c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_wm()
53617c478bd9Sstevel@tonic-gate  * INPUT:	sp	- set name we are recovering in
53627c478bd9Sstevel@tonic-gate  *		compnp	- name pointer for device we are recovering from
53637c478bd9Sstevel@tonic-gate  *		options	- metarecover options
53647c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
53657c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
53667c478bd9Sstevel@tonic-gate  * PURPOSE:	validate and display watermark configuration.  walk the
53677c478bd9Sstevel@tonic-gate  *		on-disk watermark structures and validate the information
53687c478bd9Sstevel@tonic-gate  *		found within.  since a watermark configuration is
53697c478bd9Sstevel@tonic-gate  *		"self-defining", the act of traversing the watermarks
53707c478bd9Sstevel@tonic-gate  *		is part of the validation process.
53717c478bd9Sstevel@tonic-gate  */
53727c478bd9Sstevel@tonic-gate static int
meta_sp_validate_wm(mdsetname_t * sp,mdname_t * compnp,mdcmdopts_t options,md_error_t * ep)53737c478bd9Sstevel@tonic-gate meta_sp_validate_wm(
53747c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
53757c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
53767c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
53777c478bd9Sstevel@tonic-gate 	md_error_t	*ep
53787c478bd9Sstevel@tonic-gate )
53797c478bd9Sstevel@tonic-gate {
53807c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
53817c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext;
53827c478bd9Sstevel@tonic-gate 	int		num_sps = 0;
53837c478bd9Sstevel@tonic-gate 	int		rval;
53847c478bd9Sstevel@tonic-gate 
53857c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
53867c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
53877c478bd9Sstevel@tonic-gate 		    "Verifying on-disk structures on %s.\n"),
53887c478bd9Sstevel@tonic-gate 		    compnp->cname);
53897c478bd9Sstevel@tonic-gate 
53907c478bd9Sstevel@tonic-gate 	/*
53917c478bd9Sstevel@tonic-gate 	 * for each watermark, build an ext_node, place on list.
53927c478bd9Sstevel@tonic-gate 	 */
53937c478bd9Sstevel@tonic-gate 	rval = meta_sp_extlist_from_wm(sp, compnp, &extlist,
53947c478bd9Sstevel@tonic-gate 	    meta_sp_cmp_by_nameseq, ep);
53957c478bd9Sstevel@tonic-gate 
53967c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0) {
53977c478bd9Sstevel@tonic-gate 		/* print out what we found */
53987c478bd9Sstevel@tonic-gate 		if (extlist == NULL)
53997c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
54007c478bd9Sstevel@tonic-gate 			    "No extent headers found on %s.\n"),
54017c478bd9Sstevel@tonic-gate 			    compnp->cname);
54027c478bd9Sstevel@tonic-gate 		else {
54037c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
54047c478bd9Sstevel@tonic-gate 			    "The following extent headers were found on %s.\n"),
54057c478bd9Sstevel@tonic-gate 			    compnp->cname);
54067c478bd9Sstevel@tonic-gate 			meta_sp_display_exthdr();
54077c478bd9Sstevel@tonic-gate 		}
54087c478bd9Sstevel@tonic-gate 		for (ext = extlist; ext != NULL; ext = ext->ext_next)
54097c478bd9Sstevel@tonic-gate 			meta_sp_display_ext(ext);
54107c478bd9Sstevel@tonic-gate 	}
54117c478bd9Sstevel@tonic-gate 
54127c478bd9Sstevel@tonic-gate 	if (rval < 0) {
54137c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54147c478bd9Sstevel@tonic-gate 		    "%s: On-disk structures invalid or "
54157c478bd9Sstevel@tonic-gate 		    "no soft partitions found.\n"),
54167c478bd9Sstevel@tonic-gate 		    compnp->cname);
54177c478bd9Sstevel@tonic-gate 		return (-1);
54187c478bd9Sstevel@tonic-gate 	}
54197c478bd9Sstevel@tonic-gate 
54207c478bd9Sstevel@tonic-gate 	assert(extlist != NULL);
54217c478bd9Sstevel@tonic-gate 
54227c478bd9Sstevel@tonic-gate 	/* count number of soft partitions */
54237c478bd9Sstevel@tonic-gate 	for (ext = extlist;
54247c478bd9Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
54257c478bd9Sstevel@tonic-gate 	    ext = ext->ext_next) {
54267c478bd9Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
54277c478bd9Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
54287c478bd9Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
54297c478bd9Sstevel@tonic-gate 		    ext->ext_namep->cname) == 0)
54307c478bd9Sstevel@tonic-gate 				continue;
54317c478bd9Sstevel@tonic-gate 		num_sps++;
54327c478bd9Sstevel@tonic-gate 	}
54337c478bd9Sstevel@tonic-gate 
54347c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
54357c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54367c478bd9Sstevel@tonic-gate 		    "Found %d soft partition(s) on %s.\n"), num_sps,
54377c478bd9Sstevel@tonic-gate 		    compnp->cname);
54387c478bd9Sstevel@tonic-gate 
54397c478bd9Sstevel@tonic-gate 	if (num_sps == 0) {
54407c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54417c478bd9Sstevel@tonic-gate 		    "%s: No soft partitions.\n"), compnp->cname);
54427c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
54437c478bd9Sstevel@tonic-gate 	}
54447c478bd9Sstevel@tonic-gate 
54457c478bd9Sstevel@tonic-gate 	/* check sequence numbers */
54467c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
54477c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54487c478bd9Sstevel@tonic-gate 		    "Checking sequence numbers.\n"));
54497c478bd9Sstevel@tonic-gate 
54507c478bd9Sstevel@tonic-gate 	if (meta_sp_checkseq(extlist) != 0)
54517c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
54527c478bd9Sstevel@tonic-gate 
54537c478bd9Sstevel@tonic-gate 	return (0);
54547c478bd9Sstevel@tonic-gate }
54557c478bd9Sstevel@tonic-gate 
54567c478bd9Sstevel@tonic-gate /*
54577c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_unit()
54587c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
54597c478bd9Sstevel@tonic-gate  *		compnp	- name of component we are recovering from
54607c478bd9Sstevel@tonic-gate  *		options	- metarecover options
54617c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
54627c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
54637c478bd9Sstevel@tonic-gate  * PURPOSE:	validate and display metadb configuration.  begin by getting
54647c478bd9Sstevel@tonic-gate  *		all soft partitions built on the specified component.  get
54657c478bd9Sstevel@tonic-gate  *		the unit structure for each one and validate the fields within.
54667c478bd9Sstevel@tonic-gate  */
54677c478bd9Sstevel@tonic-gate static int
meta_sp_validate_unit(mdsetname_t * sp,mdname_t * compnp,mdcmdopts_t options,md_error_t * ep)54687c478bd9Sstevel@tonic-gate meta_sp_validate_unit(
54697c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
54707c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
54717c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
54727c478bd9Sstevel@tonic-gate 	md_error_t	*ep
54737c478bd9Sstevel@tonic-gate )
54747c478bd9Sstevel@tonic-gate {
54757c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;
54767c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
54777c478bd9Sstevel@tonic-gate 	mdnamelist_t	*namep = NULL;
54787c478bd9Sstevel@tonic-gate 	int		count;
54797c478bd9Sstevel@tonic-gate 	uint_t		extn;
54807c478bd9Sstevel@tonic-gate 	sp_ext_length_t	size;
54817c478bd9Sstevel@tonic-gate 
54827c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0)
54837c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54847c478bd9Sstevel@tonic-gate 		    "%s: Validating soft partition metadb entries.\n"),
54857c478bd9Sstevel@tonic-gate 		    compnp->cname);
54867c478bd9Sstevel@tonic-gate 
54877c478bd9Sstevel@tonic-gate 	if ((size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR)
54887c478bd9Sstevel@tonic-gate 		return (-1);
54897c478bd9Sstevel@tonic-gate 
54907c478bd9Sstevel@tonic-gate 	/* get all soft partitions on component */
54917c478bd9Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
54927c478bd9Sstevel@tonic-gate 
54937c478bd9Sstevel@tonic-gate 	if (count == 0) {
54947c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
54957c478bd9Sstevel@tonic-gate 		    "%s: No soft partitions.\n"), compnp->cname);
54967c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
54977c478bd9Sstevel@tonic-gate 	} else if (count < 0) {
54987c478bd9Sstevel@tonic-gate 		return (-1);
54997c478bd9Sstevel@tonic-gate 	}
55007c478bd9Sstevel@tonic-gate 
55017c478bd9Sstevel@tonic-gate 	/* Now go through the soft partitions and check each one */
55027c478bd9Sstevel@tonic-gate 	for (namep = spnlp; namep != NULL; namep = namep->next) {
55037c478bd9Sstevel@tonic-gate 		mdname_t	*curnp = namep->namep;
55047c478bd9Sstevel@tonic-gate 		sp_ext_offset_t	curvoff;
55057c478bd9Sstevel@tonic-gate 
55067c478bd9Sstevel@tonic-gate 		/* get the unit structure */
55077c478bd9Sstevel@tonic-gate 		if ((msp = meta_get_sp_common(sp, curnp, 0, ep)) == NULL)
55087c478bd9Sstevel@tonic-gate 			return (-1);
55097c478bd9Sstevel@tonic-gate 
55107c478bd9Sstevel@tonic-gate 		/* verify generic unit structure parameters */
55117c478bd9Sstevel@tonic-gate 		if ((options & MDCMD_VERBOSE) != 0)
55127c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
55137c478bd9Sstevel@tonic-gate 			    "\nVerifying device %s.\n"),
55147c478bd9Sstevel@tonic-gate 			    curnp->cname);
55157c478bd9Sstevel@tonic-gate 
55167c478bd9Sstevel@tonic-gate 		/*
55177c478bd9Sstevel@tonic-gate 		 * MD_SP_LAST is an invalid state and is always the
55187c478bd9Sstevel@tonic-gate 		 * highest numbered.
55197c478bd9Sstevel@tonic-gate 		 */
55207c478bd9Sstevel@tonic-gate 		if (msp->status >= MD_SP_LAST) {
55217c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
55227c478bd9Sstevel@tonic-gate 			    "%s: status value %u is out of range.\n"),
55237c478bd9Sstevel@tonic-gate 			    curnp->cname, msp->status);
55247c478bd9Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
55257c478bd9Sstevel@tonic-gate 			    0, curnp->cname));
55267c478bd9Sstevel@tonic-gate 		} else if ((options & MDCMD_VERBOSE) != 0) {
55277c478bd9Sstevel@tonic-gate 			uint_t	tstate = 0;
55287c478bd9Sstevel@tonic-gate 
55297c478bd9Sstevel@tonic-gate 			if (metaismeta(msp->compnamep)) {
55307c478bd9Sstevel@tonic-gate 				if (meta_get_tstate(msp->common.namep->dev,
55317c478bd9Sstevel@tonic-gate 				    &tstate, ep) != 0)
55327c478bd9Sstevel@tonic-gate 					return (-1);
55337c478bd9Sstevel@tonic-gate 			}
55347c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
55357c478bd9Sstevel@tonic-gate 			    "%s: Status \"%s\" is valid.\n"),
55367c478bd9Sstevel@tonic-gate 			    curnp->cname, meta_sp_status_to_name(msp->status,
55377c478bd9Sstevel@tonic-gate 			    tstate & MD_DEV_ERRORED));
55387c478bd9Sstevel@tonic-gate 		}
55397c478bd9Sstevel@tonic-gate 
55407c478bd9Sstevel@tonic-gate 		/* Now verify each extent */
55417c478bd9Sstevel@tonic-gate 		if ((options & MDCMD_VERBOSE) != 0)
55427c478bd9Sstevel@tonic-gate 			(void) printf("%14s %21s %21s %21s\n",
55437c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Extent Number"),
55447c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Virtual Offset"),
55457c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Physical Offset"),
55467c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"));
55477c478bd9Sstevel@tonic-gate 
55487c478bd9Sstevel@tonic-gate 		curvoff = 0ULL;
55497c478bd9Sstevel@tonic-gate 		for (extn = 0; extn < msp->ext.ext_len; extn++) {
55507c478bd9Sstevel@tonic-gate 			md_sp_ext_t	*extp = &msp->ext.ext_val[extn];
55517c478bd9Sstevel@tonic-gate 
55527c478bd9Sstevel@tonic-gate 			if ((options & MDCMD_VERBOSE) != 0)
55537c478bd9Sstevel@tonic-gate 				(void) printf("%14u %21llu %21llu %21llu\n",
55547c478bd9Sstevel@tonic-gate 				    extn, extp->voff, extp->poff, extp->len);
55557c478bd9Sstevel@tonic-gate 
55567c478bd9Sstevel@tonic-gate 			if (extp->voff != curvoff) {
55577c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
55587c478bd9Sstevel@tonic-gate 				    "%s: virtual offset for extent %u "
55597c478bd9Sstevel@tonic-gate 				    "is inconsistent, expected %llu, "
55607c478bd9Sstevel@tonic-gate 				    "got %llu.\n"), curnp->cname, extn,
55617c478bd9Sstevel@tonic-gate 				    curvoff, extp->voff);
55627c478bd9Sstevel@tonic-gate 				return (mdmderror(ep, MDE_RECOVER_FAILED,
55637c478bd9Sstevel@tonic-gate 				    0, compnp->cname));
55647c478bd9Sstevel@tonic-gate 			}
55657c478bd9Sstevel@tonic-gate 
55667c478bd9Sstevel@tonic-gate 			/* make sure extent does not drop off the end */
55677c478bd9Sstevel@tonic-gate 			if ((extp->poff + extp->len) == size) {
55687c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
55697c478bd9Sstevel@tonic-gate 				    "%s: extent %u at offset %llu, "
55707c478bd9Sstevel@tonic-gate 				    "length %llu exceeds the size of the "
55717c478bd9Sstevel@tonic-gate 				    "device, %llu.\n"), curnp->cname,
55727c478bd9Sstevel@tonic-gate 				    extn, extp->poff, extp->len, size);
55737c478bd9Sstevel@tonic-gate 				return (mdmderror(ep, MDE_RECOVER_FAILED,
55747c478bd9Sstevel@tonic-gate 				    0, compnp->cname));
55757c478bd9Sstevel@tonic-gate 			}
55767c478bd9Sstevel@tonic-gate 
55777c478bd9Sstevel@tonic-gate 			curvoff += extp->len;
55787c478bd9Sstevel@tonic-gate 		}
55797c478bd9Sstevel@tonic-gate 	}
55807c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
55817c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
55827c478bd9Sstevel@tonic-gate 		    "%s: Soft Partition metadb configuration is valid\n"),
55837c478bd9Sstevel@tonic-gate 		    compnp->cname);
55847c478bd9Sstevel@tonic-gate 	}
55857c478bd9Sstevel@tonic-gate 	return (0);
55867c478bd9Sstevel@tonic-gate }
55877c478bd9Sstevel@tonic-gate 
55887c478bd9Sstevel@tonic-gate /*
55897c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_wm_and_unit()
55907c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
55917c478bd9Sstevel@tonic-gate  *		compnp	- name of device we are recovering from
55927c478bd9Sstevel@tonic-gate  *		options	- metarecover options
55937c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- error pointer returned
55947c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 error
55957c478bd9Sstevel@tonic-gate  * PURPOSE:	cross-validate and display watermarks and metadb records.
55967c478bd9Sstevel@tonic-gate  *		get both the unit structures for the soft partitions built
55977c478bd9Sstevel@tonic-gate  *		on the specified component and the watermarks found on that
55987c478bd9Sstevel@tonic-gate  *		component and check to make sure they are consistent with
55997c478bd9Sstevel@tonic-gate  *		each other.
56007c478bd9Sstevel@tonic-gate  */
56017c478bd9Sstevel@tonic-gate static int
meta_sp_validate_wm_and_unit(mdsetname_t * sp,mdname_t * np,mdcmdopts_t options,md_error_t * ep)56027c478bd9Sstevel@tonic-gate meta_sp_validate_wm_and_unit(
56037c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
56047c478bd9Sstevel@tonic-gate 	mdname_t	*np,
56057c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
56067c478bd9Sstevel@tonic-gate 	md_error_t	*ep
56077c478bd9Sstevel@tonic-gate )
56087c478bd9Sstevel@tonic-gate {
56097c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*wmlist = NULL;
56107c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*unitlist = NULL;
56117c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*unitext;
56127c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*wmext;
56137c478bd9Sstevel@tonic-gate 	sp_ext_offset_t	tmpunitoff;
56147c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
56157c478bd9Sstevel@tonic-gate 	int		count;
56167c478bd9Sstevel@tonic-gate 	int		rval = 0;
56177c478bd9Sstevel@tonic-gate 	int		verbose = (options & MDCMD_VERBOSE);
56187c478bd9Sstevel@tonic-gate 
56197c478bd9Sstevel@tonic-gate 	/* get unit structure list */
56207c478bd9Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, np, &spnlp, 0, ep);
56217c478bd9Sstevel@tonic-gate 	if (count <= 0)
56227c478bd9Sstevel@tonic-gate 		return (-1);
56237c478bd9Sstevel@tonic-gate 
56247c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &unitlist,
56257c478bd9Sstevel@tonic-gate 	    metagetsize(np, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
56267c478bd9Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
56277c478bd9Sstevel@tonic-gate 
56287c478bd9Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &unitlist, ep) == -1) {
56297c478bd9Sstevel@tonic-gate 		metafreenamelist(spnlp);
56307c478bd9Sstevel@tonic-gate 		return (-1);
56317c478bd9Sstevel@tonic-gate 	}
56327c478bd9Sstevel@tonic-gate 
56337c478bd9Sstevel@tonic-gate 	metafreenamelist(spnlp);
56347c478bd9Sstevel@tonic-gate 
56357c478bd9Sstevel@tonic-gate 	meta_sp_list_freefill(&unitlist, metagetsize(np, ep));
56367c478bd9Sstevel@tonic-gate 
56377c478bd9Sstevel@tonic-gate 	if (meta_sp_extlist_from_wm(sp, np, &wmlist,
56387c478bd9Sstevel@tonic-gate 	    meta_sp_cmp_by_offset, ep) < 0) {
56397c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&unitlist);
56407c478bd9Sstevel@tonic-gate 		return (-1);
56417c478bd9Sstevel@tonic-gate 	}
56427c478bd9Sstevel@tonic-gate 
56437c478bd9Sstevel@tonic-gate 	if (getenv(META_SP_DEBUG)) {
56447c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_validate_wm_and_unit: unit list:\n");
56457c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(unitlist);
56467c478bd9Sstevel@tonic-gate 		meta_sp_debug("meta_sp_validate_wm_and_unit: wm list:\n");
56477c478bd9Sstevel@tonic-gate 		meta_sp_list_dump(wmlist);
56487c478bd9Sstevel@tonic-gate 	}
56497c478bd9Sstevel@tonic-gate 
56507c478bd9Sstevel@tonic-gate 	/*
56517c478bd9Sstevel@tonic-gate 	 * step through both lists and compare allocated nodes.  Free
56527c478bd9Sstevel@tonic-gate 	 * nodes and end watermarks may differ between the two but
56537c478bd9Sstevel@tonic-gate 	 * that's generally ok, and if they're wrong will typically
56547c478bd9Sstevel@tonic-gate 	 * cause misplaced allocated extents.
56557c478bd9Sstevel@tonic-gate 	 */
56567c478bd9Sstevel@tonic-gate 	if (verbose)
56577c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "\n%s: Verifying metadb "
56587c478bd9Sstevel@tonic-gate 		    "allocations match extent headers.\n"), np->cname);
56597c478bd9Sstevel@tonic-gate 
56607c478bd9Sstevel@tonic-gate 	unitext = unitlist;
56617c478bd9Sstevel@tonic-gate 	wmext = wmlist;
56627c478bd9Sstevel@tonic-gate 	while ((wmext != NULL) && (unitext != NULL)) {
56637c478bd9Sstevel@tonic-gate 		/* find next allocated extents in each list */
56647c478bd9Sstevel@tonic-gate 		while (wmext != NULL && wmext->ext_type != EXTTYP_ALLOC)
56657c478bd9Sstevel@tonic-gate 			wmext = wmext->ext_next;
56667c478bd9Sstevel@tonic-gate 
56677c478bd9Sstevel@tonic-gate 		while (unitext != NULL && unitext->ext_type != EXTTYP_ALLOC)
56687c478bd9Sstevel@tonic-gate 			unitext = unitext->ext_next;
56697c478bd9Sstevel@tonic-gate 
56707c478bd9Sstevel@tonic-gate 		if (wmext == NULL || unitext == NULL)
56717c478bd9Sstevel@tonic-gate 			break;
56727c478bd9Sstevel@tonic-gate 
56737c478bd9Sstevel@tonic-gate 		if (verbose) {
56747c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
56757c478bd9Sstevel@tonic-gate 			    "Metadb extent:\n"));
56767c478bd9Sstevel@tonic-gate 			meta_sp_display_exthdr();
56777c478bd9Sstevel@tonic-gate 			meta_sp_display_ext(unitext);
56787c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
56797c478bd9Sstevel@tonic-gate 			    "Extent header extent:\n"));
56807c478bd9Sstevel@tonic-gate 			meta_sp_display_exthdr();
56817c478bd9Sstevel@tonic-gate 			meta_sp_display_ext(wmext);
56827c478bd9Sstevel@tonic-gate 			(void) printf("\n");
56837c478bd9Sstevel@tonic-gate 		}
56847c478bd9Sstevel@tonic-gate 
56857c478bd9Sstevel@tonic-gate 		if (meta_sp_validate_exts(np, wmext, unitext, ep) < 0)
56867c478bd9Sstevel@tonic-gate 			rval = -1;
56877c478bd9Sstevel@tonic-gate 
56887c478bd9Sstevel@tonic-gate 		/*
56897c478bd9Sstevel@tonic-gate 		 * if the offsets aren't equal, only increment the
56907c478bd9Sstevel@tonic-gate 		 * lowest one in hopes of getting the lists back in sync.
56917c478bd9Sstevel@tonic-gate 		 */
56927c478bd9Sstevel@tonic-gate 		tmpunitoff = unitext->ext_offset;
56937c478bd9Sstevel@tonic-gate 		if (unitext->ext_offset <= wmext->ext_offset)
56947c478bd9Sstevel@tonic-gate 			unitext = unitext->ext_next;
56957c478bd9Sstevel@tonic-gate 		if (wmext->ext_offset <= tmpunitoff)
56967c478bd9Sstevel@tonic-gate 			wmext = wmext->ext_next;
56977c478bd9Sstevel@tonic-gate 	}
56987c478bd9Sstevel@tonic-gate 
56997c478bd9Sstevel@tonic-gate 	/*
57007c478bd9Sstevel@tonic-gate 	 * if both lists aren't at the end then there are extra
57017c478bd9Sstevel@tonic-gate 	 * allocated nodes in one of them.
57027c478bd9Sstevel@tonic-gate 	 */
57037c478bd9Sstevel@tonic-gate 	if (wmext != NULL) {
57047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57057c478bd9Sstevel@tonic-gate 		    "%s: extent headers contain allocations not in "
57067c478bd9Sstevel@tonic-gate 		    "the metadb\n\n"), np->cname);
57077c478bd9Sstevel@tonic-gate 		rval = -1;
57087c478bd9Sstevel@tonic-gate 	}
57097c478bd9Sstevel@tonic-gate 
57107c478bd9Sstevel@tonic-gate 	if (unitext != NULL) {
57117c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57127c478bd9Sstevel@tonic-gate 		    "%s: metadb contains allocations not in the extent "
57137c478bd9Sstevel@tonic-gate 		    "headers\n\n"), np->cname);
57147c478bd9Sstevel@tonic-gate 		rval = -1;
57157c478bd9Sstevel@tonic-gate 	}
57167c478bd9Sstevel@tonic-gate 
57177c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
57187c478bd9Sstevel@tonic-gate 		if (rval == 0) {
57197c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
57207c478bd9Sstevel@tonic-gate 			    "%s: Soft Partition metadb matches extent "
57217c478bd9Sstevel@tonic-gate 			    "header configuration\n"), np->cname);
57227c478bd9Sstevel@tonic-gate 		} else {
57237c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
57247c478bd9Sstevel@tonic-gate 			    "%s: Soft Partition metadb does not match extent "
57257c478bd9Sstevel@tonic-gate 			    "header configuration\n"), np->cname);
57267c478bd9Sstevel@tonic-gate 		}
57277c478bd9Sstevel@tonic-gate 	}
57287c478bd9Sstevel@tonic-gate 
57297c478bd9Sstevel@tonic-gate 	return (rval);
57307c478bd9Sstevel@tonic-gate }
57317c478bd9Sstevel@tonic-gate 
57327c478bd9Sstevel@tonic-gate /*
57337c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_validate_exts()
57347c478bd9Sstevel@tonic-gate  * INPUT:	compnp	- name pointer for device we are recovering from
57357c478bd9Sstevel@tonic-gate  *		wmext	- extent node representing watermark
57367c478bd9Sstevel@tonic-gate  *		unitext	- extent node from unit structure
57377c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
57387c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - succes, mdmderror return code - error
57397c478bd9Sstevel@tonic-gate  * PURPOSE:	Takes two extent nodes and checks them against each other.
57407c478bd9Sstevel@tonic-gate  *		offset, length, sequence number, set, and name are compared.
57417c478bd9Sstevel@tonic-gate  */
57427c478bd9Sstevel@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)57437c478bd9Sstevel@tonic-gate meta_sp_validate_exts(
57447c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
57457c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*wmext,
57467c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*unitext,
57477c478bd9Sstevel@tonic-gate 	md_error_t	*ep
57487c478bd9Sstevel@tonic-gate )
57497c478bd9Sstevel@tonic-gate {
57507c478bd9Sstevel@tonic-gate 	if (wmext->ext_offset != unitext->ext_offset) {
57517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57527c478bd9Sstevel@tonic-gate 		    "%s: unit structure and extent header offsets differ.\n"),
57537c478bd9Sstevel@tonic-gate 		    compnp->cname);
57547c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57557c478bd9Sstevel@tonic-gate 	}
57567c478bd9Sstevel@tonic-gate 
57577c478bd9Sstevel@tonic-gate 	if (wmext->ext_length != unitext->ext_length) {
57587c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57597c478bd9Sstevel@tonic-gate 		    "%s: unit structure and extent header lengths differ.\n"),
57607c478bd9Sstevel@tonic-gate 		    compnp->cname);
57617c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57627c478bd9Sstevel@tonic-gate 	}
57637c478bd9Sstevel@tonic-gate 
57647c478bd9Sstevel@tonic-gate 	if (wmext->ext_seq != unitext->ext_seq) {
57657c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57667c478bd9Sstevel@tonic-gate 		    "%s: unit structure and extent header sequence numbers "
57677c478bd9Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
57687c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57697c478bd9Sstevel@tonic-gate 	}
57707c478bd9Sstevel@tonic-gate 
57717c478bd9Sstevel@tonic-gate 	if (wmext->ext_type != unitext->ext_type) {
57727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57737c478bd9Sstevel@tonic-gate 		    "%s: unit structure and extent header types differ.\n"),
57747c478bd9Sstevel@tonic-gate 		    compnp->cname);
57757c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57767c478bd9Sstevel@tonic-gate 	}
57777c478bd9Sstevel@tonic-gate 
57787c478bd9Sstevel@tonic-gate 	/*
57797c478bd9Sstevel@tonic-gate 	 * If one has a set pointer and the other doesn't, error.
57807c478bd9Sstevel@tonic-gate 	 * If both extents have setnames, then make sure they match
57817c478bd9Sstevel@tonic-gate 	 * If both are NULL, it's ok, they match.
57827c478bd9Sstevel@tonic-gate 	 */
57837c478bd9Sstevel@tonic-gate 	if ((unitext->ext_setp == NULL) ^ (wmext->ext_setp == NULL)) {
57847c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57857c478bd9Sstevel@tonic-gate 		    "%s: unit structure and extent header set values "
57867c478bd9Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
57877c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
57887c478bd9Sstevel@tonic-gate 	}
57897c478bd9Sstevel@tonic-gate 
57907c478bd9Sstevel@tonic-gate 	if (unitext->ext_setp != NULL) {
57917c478bd9Sstevel@tonic-gate 		if (strcmp(unitext->ext_setp->setname,
57927c478bd9Sstevel@tonic-gate 		    wmext->ext_setp->setname) != 0) {
57937c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
57947c478bd9Sstevel@tonic-gate 			    "%s: unit structure and extent header set names "
57957c478bd9Sstevel@tonic-gate 			    "differ.\n"), compnp->cname);
57967c478bd9Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
57977c478bd9Sstevel@tonic-gate 			    0, compnp->cname));
57987c478bd9Sstevel@tonic-gate 		}
57997c478bd9Sstevel@tonic-gate 	}
58007c478bd9Sstevel@tonic-gate 
58017c478bd9Sstevel@tonic-gate 	/*
58027c478bd9Sstevel@tonic-gate 	 * If one has a name pointer and the other doesn't, error.
58037c478bd9Sstevel@tonic-gate 	 * If both extents have names, then make sure they match
58047c478bd9Sstevel@tonic-gate 	 * If both are NULL, it's ok, they match.
58057c478bd9Sstevel@tonic-gate 	 */
58067c478bd9Sstevel@tonic-gate 	if ((unitext->ext_namep == NULL) ^ (wmext->ext_namep == NULL)) {
58077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
58087c478bd9Sstevel@tonic-gate 		    "%s: unit structure and extent header name values "
58097c478bd9Sstevel@tonic-gate 		    "differ.\n"), compnp->cname);
58107c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
58117c478bd9Sstevel@tonic-gate 	}
58127c478bd9Sstevel@tonic-gate 
58137c478bd9Sstevel@tonic-gate 	if (unitext->ext_namep != NULL) {
58147c478bd9Sstevel@tonic-gate 		if (strcmp(wmext->ext_namep->cname,
58157c478bd9Sstevel@tonic-gate 		    unitext->ext_namep->cname) != 0) {
58167c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
58177c478bd9Sstevel@tonic-gate 			    "%s: unit structure and extent header names "
58187c478bd9Sstevel@tonic-gate 			    "differ.\n"), compnp->cname);
58197c478bd9Sstevel@tonic-gate 			return (mdmderror(ep, MDE_RECOVER_FAILED,
58207c478bd9Sstevel@tonic-gate 			    0, compnp->cname));
58217c478bd9Sstevel@tonic-gate 		}
58227c478bd9Sstevel@tonic-gate 	}
58237c478bd9Sstevel@tonic-gate 
58247c478bd9Sstevel@tonic-gate 	return (0);
58257c478bd9Sstevel@tonic-gate }
58267c478bd9Sstevel@tonic-gate 
58277c478bd9Sstevel@tonic-gate /*
58287c478bd9Sstevel@tonic-gate  * FUNCTION:	update_sp_status()
58297c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
58307c478bd9Sstevel@tonic-gate  *		minors	- pointer to an array of soft partition minor numbers
58317c478bd9Sstevel@tonic-gate  *		num_sps	- number of minor numbers in array
58327c478bd9Sstevel@tonic-gate  *		status	- new status to be applied to all soft parts in array
58337c478bd9Sstevel@tonic-gate  *		mn_set	- set if current set is a multi-node set
58347c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
58357c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
58367c478bd9Sstevel@tonic-gate  * PURPOSE:	update  status of soft partitions to new status. minors is an
58377c478bd9Sstevel@tonic-gate  *		array of minor numbers to apply the new status to.
58387c478bd9Sstevel@tonic-gate  *		If mn_set is set, a message is sent to all nodes in the
58397c478bd9Sstevel@tonic-gate  *		cluster to update the status locally.
58407c478bd9Sstevel@tonic-gate  */
58417c478bd9Sstevel@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)58427c478bd9Sstevel@tonic-gate update_sp_status(
58437c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
58447c478bd9Sstevel@tonic-gate 	minor_t		*minors,
58457c478bd9Sstevel@tonic-gate 	int		num_sps,
58467c478bd9Sstevel@tonic-gate 	sp_status_t	status,
58477c478bd9Sstevel@tonic-gate 	bool_t		mn_set,
58487c478bd9Sstevel@tonic-gate 	md_error_t	*ep
58497c478bd9Sstevel@tonic-gate )
58507c478bd9Sstevel@tonic-gate {
58517c478bd9Sstevel@tonic-gate 	int	i;
58527c478bd9Sstevel@tonic-gate 	int	err = 0;
58537c478bd9Sstevel@tonic-gate 
58547c478bd9Sstevel@tonic-gate 	if (mn_set) {
58557c478bd9Sstevel@tonic-gate 		md_mn_msg_sp_setstat_t	sp_setstat_params;
58567c478bd9Sstevel@tonic-gate 		int			result;
58577c478bd9Sstevel@tonic-gate 		md_mn_result_t		*resp = NULL;
58587c478bd9Sstevel@tonic-gate 
58597c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_sps; i++) {
58607c478bd9Sstevel@tonic-gate 			sp_setstat_params.sp_setstat_mnum = minors[i];
58617c478bd9Sstevel@tonic-gate 			sp_setstat_params.sp_setstat_status = status;
58627c478bd9Sstevel@tonic-gate 
58637c478bd9Sstevel@tonic-gate 			result = mdmn_send_message(sp->setno,
5864bf85a12bSJohn Wren Kennedy 			    MD_MN_MSG_SP_SETSTAT, MD_MSGF_DEFAULT_FLAGS, 0,
58657c478bd9Sstevel@tonic-gate 			    (char *)&sp_setstat_params,
58667c478bd9Sstevel@tonic-gate 			    sizeof (sp_setstat_params),
58677c478bd9Sstevel@tonic-gate 			    &resp, ep);
58687c478bd9Sstevel@tonic-gate 			if (resp != NULL) {
58697c478bd9Sstevel@tonic-gate 				if (resp->mmr_exitval != 0)
58707c478bd9Sstevel@tonic-gate 					err = -1;
58717c478bd9Sstevel@tonic-gate 				free_result(resp);
58727c478bd9Sstevel@tonic-gate 			}
58737c478bd9Sstevel@tonic-gate 			if (result != 0) {
58747c478bd9Sstevel@tonic-gate 				err = -1;
58757c478bd9Sstevel@tonic-gate 			}
58767c478bd9Sstevel@tonic-gate 		}
58777c478bd9Sstevel@tonic-gate 	} else {
58787c478bd9Sstevel@tonic-gate 		if (meta_sp_setstatus(sp, minors, num_sps, status, ep) < 0)
58797c478bd9Sstevel@tonic-gate 			err = -1;
58807c478bd9Sstevel@tonic-gate 	}
58817c478bd9Sstevel@tonic-gate 	if (err < 0) {
58827c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
58837c478bd9Sstevel@tonic-gate 		    "Error updating status on recovered soft "
58847c478bd9Sstevel@tonic-gate 		    "partitions.\n"));
58857c478bd9Sstevel@tonic-gate 	}
58867c478bd9Sstevel@tonic-gate 	return (err);
58877c478bd9Sstevel@tonic-gate }
58887c478bd9Sstevel@tonic-gate 
58897c478bd9Sstevel@tonic-gate /*
58907c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_recover_from_wm()
58917c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
58927c478bd9Sstevel@tonic-gate  *		compnp	- name pointer for component we are recovering from
58937c478bd9Sstevel@tonic-gate  *		options	- metarecover options
58947c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
58957c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
58967c478bd9Sstevel@tonic-gate  * PURPOSE:	update metadb records to match watermarks.  begin by getting
58977c478bd9Sstevel@tonic-gate  *		an extlist representing all soft partitions on the component.
58987c478bd9Sstevel@tonic-gate  *		then build a unit structure for each soft partition.
58997c478bd9Sstevel@tonic-gate  *		notify user of changes, then commit each soft partition to
59007c478bd9Sstevel@tonic-gate  *		the metadb one at a time in the "recovering" state.  update
59017c478bd9Sstevel@tonic-gate  *		any watermarks that may need it	(to reflect possible name
59027c478bd9Sstevel@tonic-gate  *		changes), and, finally, set the status of all recovered
59037c478bd9Sstevel@tonic-gate  *		partitions to the "OK" state at once.
59047c478bd9Sstevel@tonic-gate  */
59057c478bd9Sstevel@tonic-gate static int
meta_sp_recover_from_wm(mdsetname_t * sp,mdname_t * compnp,mdcmdopts_t options,md_error_t * ep)59067c478bd9Sstevel@tonic-gate meta_sp_recover_from_wm(
59077c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
59087c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
59097c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
59107c478bd9Sstevel@tonic-gate 	md_error_t	*ep
59117c478bd9Sstevel@tonic-gate )
59127c478bd9Sstevel@tonic-gate {
59137c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*extlist = NULL;
59147c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*sp_list = NULL;
59157c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*update_list = NULL;
59167c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*ext;
59177c478bd9Sstevel@tonic-gate 	sp_ext_node_t		*sp_ext;
59187c478bd9Sstevel@tonic-gate 	mp_unit_t		*mp;
59197c478bd9Sstevel@tonic-gate 	mp_unit_t		**un_array;
59207c478bd9Sstevel@tonic-gate 	int			numexts = 0, num_sps = 0, i = 0;
59217c478bd9Sstevel@tonic-gate 	int			err = 0;
59227c478bd9Sstevel@tonic-gate 	int			not_recovered = 0;
59237c478bd9Sstevel@tonic-gate 	int			committed = 0;
59247c478bd9Sstevel@tonic-gate 	sp_ext_length_t		sp_length = 0LL;
59257c478bd9Sstevel@tonic-gate 	mdnamelist_t		*keynlp = NULL;
59267c478bd9Sstevel@tonic-gate 	mdname_t		*np;
59277c478bd9Sstevel@tonic-gate 	mdname_t		*new_np;
59287c478bd9Sstevel@tonic-gate 	int			new_name;
59297c478bd9Sstevel@tonic-gate 	md_set_params_t		set_params;
59307c478bd9Sstevel@tonic-gate 	minor_t			*minors = NULL;
59317c478bd9Sstevel@tonic-gate 	char			yesno[255];
59327c478bd9Sstevel@tonic-gate 	char			*yes;
59337c478bd9Sstevel@tonic-gate 	bool_t			mn_set = 0;
59347c478bd9Sstevel@tonic-gate 	md_set_desc		*sd;
59357c478bd9Sstevel@tonic-gate 	mm_unit_t		*mm;
59367c478bd9Sstevel@tonic-gate 	md_set_mmown_params_t	*ownpar = NULL;
59377c478bd9Sstevel@tonic-gate 	int			comp_is_mirror = 0;
59387c478bd9Sstevel@tonic-gate 
59397c478bd9Sstevel@tonic-gate 	/*
59407c478bd9Sstevel@tonic-gate 	 * if this component appears in another metadevice already, do
59417c478bd9Sstevel@tonic-gate 	 * NOT recover from it.
59427c478bd9Sstevel@tonic-gate 	 */
59437c478bd9Sstevel@tonic-gate 	if (meta_check_inmeta(sp, compnp, options, 0, -1, ep) != 0)
59447c478bd9Sstevel@tonic-gate 		return (-1);
59457c478bd9Sstevel@tonic-gate 
59467c478bd9Sstevel@tonic-gate 	/* set flag if dealing with a MN set */
59477c478bd9Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
59487c478bd9Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
59497c478bd9Sstevel@tonic-gate 			return (-1);
59507c478bd9Sstevel@tonic-gate 		}
59517c478bd9Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
59527c478bd9Sstevel@tonic-gate 			mn_set = 1;
59537c478bd9Sstevel@tonic-gate 	}
59547c478bd9Sstevel@tonic-gate 	/*
59557c478bd9Sstevel@tonic-gate 	 * for each watermark, build an ext_node, place on list.
59567c478bd9Sstevel@tonic-gate 	 */
59577c478bd9Sstevel@tonic-gate 	if (meta_sp_extlist_from_wm(sp, compnp, &extlist,
59587c478bd9Sstevel@tonic-gate 	    meta_sp_cmp_by_nameseq, ep) < 0)
59597c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
59607c478bd9Sstevel@tonic-gate 
59617c478bd9Sstevel@tonic-gate 	assert(extlist != NULL);
59627c478bd9Sstevel@tonic-gate 
59637c478bd9Sstevel@tonic-gate 	/* count number of soft partitions */
59647c478bd9Sstevel@tonic-gate 	for (ext = extlist;
59657c478bd9Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
59667c478bd9Sstevel@tonic-gate 	    ext = ext->ext_next) {
59677c478bd9Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
59687c478bd9Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
59697c478bd9Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
59707c478bd9Sstevel@tonic-gate 		    ext->ext_namep->cname) == 0)
59717c478bd9Sstevel@tonic-gate 				continue;
59727c478bd9Sstevel@tonic-gate 		num_sps++;
59737c478bd9Sstevel@tonic-gate 	}
59747c478bd9Sstevel@tonic-gate 
59757c478bd9Sstevel@tonic-gate 	/* allocate array of unit structure pointers */
59767c478bd9Sstevel@tonic-gate 	un_array = Zalloc(num_sps * sizeof (mp_unit_t *));
59777c478bd9Sstevel@tonic-gate 
59787c478bd9Sstevel@tonic-gate 	/*
59797c478bd9Sstevel@tonic-gate 	 * build unit structures from list of ext_nodes.
59807c478bd9Sstevel@tonic-gate 	 */
59817c478bd9Sstevel@tonic-gate 	for (ext = extlist;
59827c478bd9Sstevel@tonic-gate 	    ext != NULL && ext->ext_type == EXTTYP_ALLOC;
59837c478bd9Sstevel@tonic-gate 	    ext = ext->ext_next) {
59847c478bd9Sstevel@tonic-gate 		meta_sp_list_insert(ext->ext_setp, ext->ext_namep,
59857c478bd9Sstevel@tonic-gate 		    &sp_list, ext->ext_offset, ext->ext_length,
59867c478bd9Sstevel@tonic-gate 		    ext->ext_type, ext->ext_seq, ext->ext_flags,
59877c478bd9Sstevel@tonic-gate 		    meta_sp_cmp_by_nameseq);
59887c478bd9Sstevel@tonic-gate 
59897c478bd9Sstevel@tonic-gate 		numexts++;
59907c478bd9Sstevel@tonic-gate 		sp_length += ext->ext_length - MD_SP_WMSIZE;
59917c478bd9Sstevel@tonic-gate 
59927c478bd9Sstevel@tonic-gate 		if (ext->ext_next != NULL &&
59937c478bd9Sstevel@tonic-gate 		    ext->ext_next->ext_namep != NULL &&
59947c478bd9Sstevel@tonic-gate 		    strcmp(ext->ext_next->ext_namep->cname,
59957c478bd9Sstevel@tonic-gate 		    ext->ext_namep->cname) == 0)
59967c478bd9Sstevel@tonic-gate 				continue;
59977c478bd9Sstevel@tonic-gate 
59987c478bd9Sstevel@tonic-gate 		/*
59997c478bd9Sstevel@tonic-gate 		 * if we made it here, we are at a soft partition
60007c478bd9Sstevel@tonic-gate 		 * boundary in the list.
60017c478bd9Sstevel@tonic-gate 		 */
60027c478bd9Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
60037c478bd9Sstevel@tonic-gate 			meta_sp_debug("meta_recover_from_wm: dumping wm "
60047c478bd9Sstevel@tonic-gate 			    "list:\n");
60057c478bd9Sstevel@tonic-gate 			meta_sp_list_dump(sp_list);
60067c478bd9Sstevel@tonic-gate 		}
60077c478bd9Sstevel@tonic-gate 
60087c478bd9Sstevel@tonic-gate 		assert(sp_list != NULL);
60097c478bd9Sstevel@tonic-gate 		assert(sp_list->ext_namep != NULL);
60107c478bd9Sstevel@tonic-gate 
60117c478bd9Sstevel@tonic-gate 		if ((new_name = meta_sp_resolve_name_conflict(sp,
60127c478bd9Sstevel@tonic-gate 		    sp_list->ext_namep, &new_np, ep)) < 0) {
60137c478bd9Sstevel@tonic-gate 			err = 1;
60147c478bd9Sstevel@tonic-gate 			goto out;
60157c478bd9Sstevel@tonic-gate 		} else if (new_name) {
60167c478bd9Sstevel@tonic-gate 			for (sp_ext = sp_list;
60177c478bd9Sstevel@tonic-gate 			    sp_ext != NULL;
60187c478bd9Sstevel@tonic-gate 			    sp_ext = sp_ext->ext_next) {
60197c478bd9Sstevel@tonic-gate 				/*
60207c478bd9Sstevel@tonic-gate 				 * insert into the update list for
60217c478bd9Sstevel@tonic-gate 				 * watermark update.
60227c478bd9Sstevel@tonic-gate 				 */
60237c478bd9Sstevel@tonic-gate 				meta_sp_list_insert(sp_ext->ext_setp,
60247c478bd9Sstevel@tonic-gate 				    new_np, &update_list, sp_ext->ext_offset,
60257c478bd9Sstevel@tonic-gate 				    sp_ext->ext_length, sp_ext->ext_type,
60267c478bd9Sstevel@tonic-gate 				    sp_ext->ext_seq, EXTFLG_UPDATE,
60277c478bd9Sstevel@tonic-gate 				    meta_sp_cmp_by_offset);
60287c478bd9Sstevel@tonic-gate 			}
60297c478bd9Sstevel@tonic-gate 
60307c478bd9Sstevel@tonic-gate 		}
60317c478bd9Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
60327c478bd9Sstevel@tonic-gate 			/* store name in namespace */
60337c478bd9Sstevel@tonic-gate 			if (mn_set) {
60347c478bd9Sstevel@tonic-gate 				/* send message to all nodes to return key */
60357c478bd9Sstevel@tonic-gate 				md_mn_msg_addkeyname_t	*send_params;
60367c478bd9Sstevel@tonic-gate 				int			result;
60377c478bd9Sstevel@tonic-gate 				md_mn_result_t		*resp = NULL;
60387c478bd9Sstevel@tonic-gate 				int			message_size;
60397c478bd9Sstevel@tonic-gate 
60407c478bd9Sstevel@tonic-gate 				message_size =  sizeof (*send_params) +
60417c478bd9Sstevel@tonic-gate 				    strlen(compnp->cname) + 1;
60427c478bd9Sstevel@tonic-gate 				send_params = Zalloc(message_size);
60437c478bd9Sstevel@tonic-gate 				send_params->addkeyname_setno = sp->setno;
60447c478bd9Sstevel@tonic-gate 				(void) strcpy(&send_params->addkeyname_name[0],
60457c478bd9Sstevel@tonic-gate 				    compnp->cname);
60467c478bd9Sstevel@tonic-gate 				result = mdmn_send_message(sp->setno,
60477c478bd9Sstevel@tonic-gate 				    MD_MN_MSG_ADDKEYNAME, MD_MSGF_DEFAULT_FLAGS,
6048bf85a12bSJohn Wren Kennedy 				    0, (char *)send_params, message_size, &resp,
60497c478bd9Sstevel@tonic-gate 				    ep);
60507c478bd9Sstevel@tonic-gate 				Free(send_params);
60517c478bd9Sstevel@tonic-gate 				if (resp != NULL) {
60527c478bd9Sstevel@tonic-gate 					if (resp->mmr_exitval >= 0) {
60537c478bd9Sstevel@tonic-gate 						compnp->key =
60547c478bd9Sstevel@tonic-gate 						    (mdkey_t)resp->mmr_exitval;
60557c478bd9Sstevel@tonic-gate 					} else {
60567c478bd9Sstevel@tonic-gate 						err = 1;
60577c478bd9Sstevel@tonic-gate 						free_result(resp);
60587c478bd9Sstevel@tonic-gate 						goto out;
60597c478bd9Sstevel@tonic-gate 					}
60607c478bd9Sstevel@tonic-gate 					free_result(resp);
60617c478bd9Sstevel@tonic-gate 				}
60627c478bd9Sstevel@tonic-gate 				if (result != 0) {
60637c478bd9Sstevel@tonic-gate 					err = 1;
60647c478bd9Sstevel@tonic-gate 					goto out;
60657c478bd9Sstevel@tonic-gate 				}
60667c478bd9Sstevel@tonic-gate 				(void) metanamelist_append(&keynlp, compnp);
60677c478bd9Sstevel@tonic-gate 			} else {
60687c478bd9Sstevel@tonic-gate 				if (add_key_name(sp, compnp, &keynlp,
60697c478bd9Sstevel@tonic-gate 				    ep) != 0) {
60707c478bd9Sstevel@tonic-gate 					err = 1;
60717c478bd9Sstevel@tonic-gate 					goto out;
60727c478bd9Sstevel@tonic-gate 				}
60737c478bd9Sstevel@tonic-gate 			}
60747c478bd9Sstevel@tonic-gate 		}
60757c478bd9Sstevel@tonic-gate 
60767c478bd9Sstevel@tonic-gate 		/* create the unit structure */
60777c478bd9Sstevel@tonic-gate 		if ((mp = meta_sp_createunit(
60787c478bd9Sstevel@tonic-gate 		    (new_name) ? new_np : sp_list->ext_namep, compnp,
60797c478bd9Sstevel@tonic-gate 		    sp_list, numexts, sp_length, MD_SP_RECOVER, ep)) == NULL) {
60807c478bd9Sstevel@tonic-gate 			err = 1;
60817c478bd9Sstevel@tonic-gate 			goto out;
60827c478bd9Sstevel@tonic-gate 		}
60837c478bd9Sstevel@tonic-gate 
60847c478bd9Sstevel@tonic-gate 		if (getenv(META_SP_DEBUG)) {
60857c478bd9Sstevel@tonic-gate 			meta_sp_debug("meta_sp_recover_from_wm: "
60867c478bd9Sstevel@tonic-gate 			    "printing newly created unit structure");
60877c478bd9Sstevel@tonic-gate 			meta_sp_printunit(mp);
60887c478bd9Sstevel@tonic-gate 		}
60897c478bd9Sstevel@tonic-gate 
60907c478bd9Sstevel@tonic-gate 		/* place in unit structure array */
60917c478bd9Sstevel@tonic-gate 		un_array[i++] = mp;
60927c478bd9Sstevel@tonic-gate 
60937c478bd9Sstevel@tonic-gate 		/* free sp_list */
60947c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&sp_list);
60957c478bd9Sstevel@tonic-gate 		sp_list = NULL;
60967c478bd9Sstevel@tonic-gate 		numexts = 0;
60977c478bd9Sstevel@tonic-gate 		sp_length = 0LL;
60987c478bd9Sstevel@tonic-gate 	}
60997c478bd9Sstevel@tonic-gate 
61007c478bd9Sstevel@tonic-gate 	/* display configuration updates */
61017c478bd9Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
61027c478bd9Sstevel@tonic-gate 	    "The following soft partitions were found and will be added to\n"
61037c478bd9Sstevel@tonic-gate 	    "your metadevice configuration.\n"));
61047c478bd9Sstevel@tonic-gate 	(void) printf("%5s %15s %18s\n",
61057c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Name"),
61067c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Size"),
61077c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "No. of Extents"));
61087c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++) {
61097c478bd9Sstevel@tonic-gate 		(void) printf("%5s%lu %15llu %9d\n", "d",
61107c478bd9Sstevel@tonic-gate 		    MD_MIN2UNIT(MD_SID(un_array[i])),
61117c478bd9Sstevel@tonic-gate 		    un_array[i]->un_length, un_array[i]->un_numexts);
61127c478bd9Sstevel@tonic-gate 	}
61137c478bd9Sstevel@tonic-gate 
61147c478bd9Sstevel@tonic-gate 	if (!(options & MDCMD_DOIT)) {
61157c478bd9Sstevel@tonic-gate 		not_recovered = 1;
61167c478bd9Sstevel@tonic-gate 		goto out;
61177c478bd9Sstevel@tonic-gate 	}
61187c478bd9Sstevel@tonic-gate 
61197c478bd9Sstevel@tonic-gate 	/* ask user for confirmation */
61207c478bd9Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
61217c478bd9Sstevel@tonic-gate 	    "WARNING: You are about to add one or more soft partition\n"
61227c478bd9Sstevel@tonic-gate 	    "metadevices to your metadevice configuration.  If there\n"
61237c478bd9Sstevel@tonic-gate 	    "appears to be an error in the soft partition(s) displayed\n"
61247c478bd9Sstevel@tonic-gate 	    "above, do NOT proceed with this recovery operation.\n"));
61257c478bd9Sstevel@tonic-gate 	(void) printf(dgettext(TEXT_DOMAIN,
61267c478bd9Sstevel@tonic-gate 	    "Are you sure you want to do this (yes/no)? "));
61277c478bd9Sstevel@tonic-gate 
61287c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
61297c478bd9Sstevel@tonic-gate 	if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
61307c478bd9Sstevel@tonic-gate 	    (strlen(yesno) == 1))
61317c478bd9Sstevel@tonic-gate 		(void) snprintf(yesno, sizeof (yesno), "%s\n",
61327c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "no"));
61337c478bd9Sstevel@tonic-gate 	yes = dgettext(TEXT_DOMAIN, "yes");
61347c478bd9Sstevel@tonic-gate 	if (strncasecmp(yesno, yes, strlen(yesno) - 1) != 0) {
61357c478bd9Sstevel@tonic-gate 		not_recovered = 1;
61367c478bd9Sstevel@tonic-gate 		goto out;
61377c478bd9Sstevel@tonic-gate 	}
61387c478bd9Sstevel@tonic-gate 
61397c478bd9Sstevel@tonic-gate 	/* commit records one at a time */
61407c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++) {
61417c478bd9Sstevel@tonic-gate 		(void) memset(&set_params, 0, sizeof (set_params));
61427c478bd9Sstevel@tonic-gate 		set_params.mnum = MD_SID(un_array[i]);
61437c478bd9Sstevel@tonic-gate 		set_params.size = (un_array[i])->c.un_size;
61447c478bd9Sstevel@tonic-gate 		set_params.mdp = (uintptr_t)(un_array[i]);
61457c478bd9Sstevel@tonic-gate 		set_params.options =
61467c478bd9Sstevel@tonic-gate 		    meta_check_devicesize(un_array[i]->un_length);
61477c478bd9Sstevel@tonic-gate 		if (set_params.options == MD_CRO_64BIT) {
6148d7cd8252Stw21770 			un_array[i]->c.un_revision |= MD_64BIT_META_DEV;
61497c478bd9Sstevel@tonic-gate 		} else {
6150d7cd8252Stw21770 			un_array[i]->c.un_revision &= ~MD_64BIT_META_DEV;
61517c478bd9Sstevel@tonic-gate 		}
61527c478bd9Sstevel@tonic-gate 		MD_SETDRIVERNAME(&set_params, MD_SP,
61537c478bd9Sstevel@tonic-gate 		    MD_MIN2SET(set_params.mnum));
61547c478bd9Sstevel@tonic-gate 
61557c478bd9Sstevel@tonic-gate 		np = metamnumname(&sp, MD_SID(un_array[i]), 0, ep);
61567c478bd9Sstevel@tonic-gate 
61577c478bd9Sstevel@tonic-gate 		/*
61587c478bd9Sstevel@tonic-gate 		 * If this is an MN set, send the MD_IOCSET ioctl to all nodes
61597c478bd9Sstevel@tonic-gate 		 */
61607c478bd9Sstevel@tonic-gate 		if (mn_set) {
61617c478bd9Sstevel@tonic-gate 			md_mn_msg_iocset_t	send_params;
61627c478bd9Sstevel@tonic-gate 			int			result;
61637c478bd9Sstevel@tonic-gate 			md_mn_result_t		*resp = NULL;
61647c478bd9Sstevel@tonic-gate 			int			mess_size;
61657c478bd9Sstevel@tonic-gate 
61667c478bd9Sstevel@tonic-gate 			/*
61677c478bd9Sstevel@tonic-gate 			 * Calculate message size. md_mn_msg_iocset_t only
61687c478bd9Sstevel@tonic-gate 			 * contains one extent, so increment the size to
61697c478bd9Sstevel@tonic-gate 			 * include all extents
61707c478bd9Sstevel@tonic-gate 			 */
61717c478bd9Sstevel@tonic-gate 			mess_size = sizeof (send_params) -
61727c478bd9Sstevel@tonic-gate 			    sizeof (mp_ext_t) +
61737c478bd9Sstevel@tonic-gate 			    (un_array[i]->un_numexts * sizeof (mp_ext_t));
61747c478bd9Sstevel@tonic-gate 
61757c478bd9Sstevel@tonic-gate 			send_params.iocset_params = set_params;
61767c478bd9Sstevel@tonic-gate 			(void) memcpy(&send_params.unit, un_array[i],
61777c478bd9Sstevel@tonic-gate 			    sizeof (*un_array[i]) - sizeof (mp_ext_t) +
61787c478bd9Sstevel@tonic-gate 			    (un_array[i]->un_numexts * sizeof (mp_ext_t)));
61797c478bd9Sstevel@tonic-gate 			result = mdmn_send_message(sp->setno,
6180bf85a12bSJohn Wren Kennedy 			    MD_MN_MSG_IOCSET, MD_MSGF_DEFAULT_FLAGS, 0,
61817c478bd9Sstevel@tonic-gate 			    (char *)&send_params, mess_size, &resp,
61827c478bd9Sstevel@tonic-gate 			    ep);
61837c478bd9Sstevel@tonic-gate 			if (resp != NULL) {
61847c478bd9Sstevel@tonic-gate 				if (resp->mmr_exitval != 0)
61857c478bd9Sstevel@tonic-gate 					err = 1;
61867c478bd9Sstevel@tonic-gate 				free_result(resp);
61877c478bd9Sstevel@tonic-gate 			}
61887c478bd9Sstevel@tonic-gate 			if (result != 0) {
61897c478bd9Sstevel@tonic-gate 				err = 1;
61907c478bd9Sstevel@tonic-gate 			}
61917c478bd9Sstevel@tonic-gate 		} else {
61927c478bd9Sstevel@tonic-gate 			if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
61937c478bd9Sstevel@tonic-gate 			    np->cname) != 0) {
61947c478bd9Sstevel@tonic-gate 				err = 1;
61957c478bd9Sstevel@tonic-gate 			}
61967c478bd9Sstevel@tonic-gate 		}
61977c478bd9Sstevel@tonic-gate 
61987c478bd9Sstevel@tonic-gate 		if (err == 1) {
61997c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
62007c478bd9Sstevel@tonic-gate 			    "%s: Error committing record to metadb.\n"),
62017c478bd9Sstevel@tonic-gate 			    np->cname);
62027c478bd9Sstevel@tonic-gate 			goto out;
62037c478bd9Sstevel@tonic-gate 		}
62047c478bd9Sstevel@tonic-gate 
62057c478bd9Sstevel@tonic-gate 		/* note that we've committed a record */
62067c478bd9Sstevel@tonic-gate 		if (!committed)
62077c478bd9Sstevel@tonic-gate 			committed = 1;
62087c478bd9Sstevel@tonic-gate 
62097c478bd9Sstevel@tonic-gate 		/* update any watermarks that need it */
62107c478bd9Sstevel@tonic-gate 		if (update_list != NULL) {
62117c478bd9Sstevel@tonic-gate 			md_sp_t *msp;
62127c478bd9Sstevel@tonic-gate 
62137c478bd9Sstevel@tonic-gate 			/*
62147c478bd9Sstevel@tonic-gate 			 * Check to see if we're trying to create a partition
62157c478bd9Sstevel@tonic-gate 			 * on a mirror. If so we may have to enforce an
62167c478bd9Sstevel@tonic-gate 			 * ownership change before writing the watermark out.
62177c478bd9Sstevel@tonic-gate 			 */
62187c478bd9Sstevel@tonic-gate 			if (metaismeta(compnp)) {
62197c478bd9Sstevel@tonic-gate 				char *miscname;
62207c478bd9Sstevel@tonic-gate 
62217c478bd9Sstevel@tonic-gate 				miscname = metagetmiscname(compnp, ep);
62227c478bd9Sstevel@tonic-gate 				if (miscname != NULL)
62237c478bd9Sstevel@tonic-gate 					comp_is_mirror = (strcmp(miscname,
62247c478bd9Sstevel@tonic-gate 					    MD_MIRROR) == 0);
62257c478bd9Sstevel@tonic-gate 				else
62267c478bd9Sstevel@tonic-gate 					comp_is_mirror = 0;
62277c478bd9Sstevel@tonic-gate 			}
62287c478bd9Sstevel@tonic-gate 			/*
62297c478bd9Sstevel@tonic-gate 			 * If this is a MN set and the component is a mirror,
62307c478bd9Sstevel@tonic-gate 			 * change ownership to this node in order to write the
62317c478bd9Sstevel@tonic-gate 			 * watermarks
62327c478bd9Sstevel@tonic-gate 			 */
62337c478bd9Sstevel@tonic-gate 			if (mn_set && comp_is_mirror) {
62347c478bd9Sstevel@tonic-gate 				mm = (mm_unit_t *)meta_get_unit(sp, compnp, ep);
62357c478bd9Sstevel@tonic-gate 				if (mm == NULL) {
62367c478bd9Sstevel@tonic-gate 					err = 1;
62377c478bd9Sstevel@tonic-gate 					goto out;
62387c478bd9Sstevel@tonic-gate 				} else {
62397c478bd9Sstevel@tonic-gate 					err = meta_mn_change_owner(&ownpar,
62407c478bd9Sstevel@tonic-gate 					    sp->setno,
62417c478bd9Sstevel@tonic-gate 					    meta_getminor(compnp->dev),
62427c478bd9Sstevel@tonic-gate 					    sd->sd_mn_mynode->nd_nodeid,
62437c478bd9Sstevel@tonic-gate 					    MD_MN_MM_PREVENT_CHANGE |
62447c478bd9Sstevel@tonic-gate 					    MD_MN_MM_SPAWN_THREAD);
62457c478bd9Sstevel@tonic-gate 					if (err != 0)
62467c478bd9Sstevel@tonic-gate 						goto out;
62477c478bd9Sstevel@tonic-gate 				}
62487c478bd9Sstevel@tonic-gate 			}
62497c478bd9Sstevel@tonic-gate 
62507c478bd9Sstevel@tonic-gate 			if ((msp = meta_get_sp(sp, np, ep)) == NULL) {
62517c478bd9Sstevel@tonic-gate 				err = 1;
62527c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
62537c478bd9Sstevel@tonic-gate 				    "%s: Error updating extent headers.\n"),
62547c478bd9Sstevel@tonic-gate 				    np->cname);
62557c478bd9Sstevel@tonic-gate 				goto out;
62567c478bd9Sstevel@tonic-gate 			}
62577c478bd9Sstevel@tonic-gate 			if (meta_sp_update_wm(sp, msp, update_list, ep) < 0) {
62587c478bd9Sstevel@tonic-gate 				err = 1;
62597c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
62607c478bd9Sstevel@tonic-gate 				    "%s: Error updating extent headers "
62617c478bd9Sstevel@tonic-gate 				    "on disk.\n"), np->cname);
62627c478bd9Sstevel@tonic-gate 				goto out;
62637c478bd9Sstevel@tonic-gate 			}
62647c478bd9Sstevel@tonic-gate 		}
62657c478bd9Sstevel@tonic-gate 		/*
62667c478bd9Sstevel@tonic-gate 		 * If we have changed ownership earlier and prevented any
62677c478bd9Sstevel@tonic-gate 		 * ownership changes, we can now allow ownership changes
62687c478bd9Sstevel@tonic-gate 		 * again.
62697c478bd9Sstevel@tonic-gate 		 */
62707c478bd9Sstevel@tonic-gate 		if (ownpar) {
62717c478bd9Sstevel@tonic-gate 			(void) meta_mn_change_owner(&ownpar, sp->setno,
62727c478bd9Sstevel@tonic-gate 			    ownpar->d.mnum,
62737c478bd9Sstevel@tonic-gate 			    ownpar->d.owner,
62747c478bd9Sstevel@tonic-gate 			    MD_MN_MM_ALLOW_CHANGE | MD_MN_MM_SPAWN_THREAD);
62757c478bd9Sstevel@tonic-gate 		}
62767c478bd9Sstevel@tonic-gate 	}
62777c478bd9Sstevel@tonic-gate 
62787c478bd9Sstevel@tonic-gate 	/* update status of all soft partitions to OK */
62797c478bd9Sstevel@tonic-gate 	minors = Zalloc(num_sps * sizeof (minor_t));
62807c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_sps; i++)
62817c478bd9Sstevel@tonic-gate 		minors[i] = MD_SID(un_array[i]);
62827c478bd9Sstevel@tonic-gate 
62837c478bd9Sstevel@tonic-gate 	err = update_sp_status(sp, minors, num_sps, MD_SP_OK, mn_set, ep);
62847c478bd9Sstevel@tonic-gate 	if (err != 0)
62857c478bd9Sstevel@tonic-gate 		goto out;
62867c478bd9Sstevel@tonic-gate 
62877c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT)
62887c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: "
62897c478bd9Sstevel@tonic-gate 		    "Soft Partitions recovered from device.\n"),
62907c478bd9Sstevel@tonic-gate 		    compnp->cname);
62917c478bd9Sstevel@tonic-gate out:
62927c478bd9Sstevel@tonic-gate 	/* free memory */
62937c478bd9Sstevel@tonic-gate 	if (extlist != NULL)
62947c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&extlist);
62957c478bd9Sstevel@tonic-gate 	if (sp_list != NULL)
62967c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&sp_list);
62977c478bd9Sstevel@tonic-gate 	if (update_list != NULL)
62987c478bd9Sstevel@tonic-gate 		meta_sp_list_free(&update_list);
62997c478bd9Sstevel@tonic-gate 	if (un_array != NULL)	{
63007c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_sps; i++)
63017c478bd9Sstevel@tonic-gate 			Free(un_array[i]);
63027c478bd9Sstevel@tonic-gate 		Free(un_array);
63037c478bd9Sstevel@tonic-gate 	}
63047c478bd9Sstevel@tonic-gate 	if (minors != NULL)
63057c478bd9Sstevel@tonic-gate 		Free(minors);
63067c478bd9Sstevel@tonic-gate 	if (ownpar != NULL)
63077c478bd9Sstevel@tonic-gate 		Free(ownpar);
63087c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
63097c478bd9Sstevel@tonic-gate 
63107c478bd9Sstevel@tonic-gate 	if ((keynlp != NULL) && (committed != 1)) {
63117c478bd9Sstevel@tonic-gate 		/*
63127c478bd9Sstevel@tonic-gate 		 * if we haven't committed any softparts, either because of an
63137c478bd9Sstevel@tonic-gate 		 * error or because the user decided not to proceed, delete
63147c478bd9Sstevel@tonic-gate 		 * namelist key for the component
63157c478bd9Sstevel@tonic-gate 		 */
63167c478bd9Sstevel@tonic-gate 		if (mn_set) {
63177c478bd9Sstevel@tonic-gate 			mdnamelist_t	*p;
63187c478bd9Sstevel@tonic-gate 
63197c478bd9Sstevel@tonic-gate 			for (p = keynlp; (p != NULL); p = p->next) {
63207c478bd9Sstevel@tonic-gate 				mdname_t		*np = p->namep;
63217c478bd9Sstevel@tonic-gate 				md_mn_msg_delkeyname_t	send_params;
63227c478bd9Sstevel@tonic-gate 				md_mn_result_t		*resp = NULL;
63237c478bd9Sstevel@tonic-gate 
63247c478bd9Sstevel@tonic-gate 				send_params.delkeyname_dev = np->dev;
63257c478bd9Sstevel@tonic-gate 				send_params.delkeyname_setno = sp->setno;
63267c478bd9Sstevel@tonic-gate 				send_params.delkeyname_key = np->key;
63277c478bd9Sstevel@tonic-gate 				(void) mdmn_send_message(sp->setno,
63287c478bd9Sstevel@tonic-gate 				    MD_MN_MSG_DELKEYNAME, MD_MSGF_DEFAULT_FLAGS,
6329bf85a12bSJohn Wren Kennedy 				    0, (char *)&send_params,
6330bf85a12bSJohn Wren Kennedy 				    sizeof (send_params),
63317c478bd9Sstevel@tonic-gate 				    &resp, ep);
63327c478bd9Sstevel@tonic-gate 				if (resp != NULL) {
63337c478bd9Sstevel@tonic-gate 					free_result(resp);
63347c478bd9Sstevel@tonic-gate 				}
63357c478bd9Sstevel@tonic-gate 			}
63367c478bd9Sstevel@tonic-gate 		} else {
63377c478bd9Sstevel@tonic-gate 			(void) del_key_names(sp, keynlp, NULL);
63387c478bd9Sstevel@tonic-gate 		}
63397c478bd9Sstevel@tonic-gate 	}
63407c478bd9Sstevel@tonic-gate 
63417c478bd9Sstevel@tonic-gate 	metafreenamelist(keynlp);
63427c478bd9Sstevel@tonic-gate 
63437c478bd9Sstevel@tonic-gate 	if (err)
63447c478bd9Sstevel@tonic-gate 		return (mdmderror(ep, MDE_RECOVER_FAILED, 0, compnp->cname));
63457c478bd9Sstevel@tonic-gate 
63467c478bd9Sstevel@tonic-gate 	if (not_recovered)
63477c478bd9Sstevel@tonic-gate 		if (options & MDCMD_PRINT)
63487c478bd9Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN, "%s: "
63497c478bd9Sstevel@tonic-gate 			    "Soft Partitions NOT recovered from device.\n"),
63507c478bd9Sstevel@tonic-gate 			    compnp->cname);
63517c478bd9Sstevel@tonic-gate 	return (0);
63527c478bd9Sstevel@tonic-gate }
63537c478bd9Sstevel@tonic-gate 
63547c478bd9Sstevel@tonic-gate /*
63557c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_recover_from_unit()
63567c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
63577c478bd9Sstevel@tonic-gate  *		compnp	- name of component we are recovering from
63587c478bd9Sstevel@tonic-gate  *		options	- metarecover options
63597c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
63607c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
63617c478bd9Sstevel@tonic-gate  * PURPOSE:	update watermarks to match metadb records.  begin by getting
63627c478bd9Sstevel@tonic-gate  *		a namelist representing all soft partitions on the specified
63637c478bd9Sstevel@tonic-gate  *		component.  then, build an extlist representing the soft
63647c478bd9Sstevel@tonic-gate  *		partitions, filling in the freespace extents.  notify user
63657c478bd9Sstevel@tonic-gate  *		of changes, place all soft partitions into the "recovering"
63667c478bd9Sstevel@tonic-gate  *		state and update the watermarks.  finally, return all soft
63677c478bd9Sstevel@tonic-gate  *		partitions to the "OK" state.
63687c478bd9Sstevel@tonic-gate  */
63697c478bd9Sstevel@tonic-gate static int
meta_sp_recover_from_unit(mdsetname_t * sp,mdname_t * compnp,mdcmdopts_t options,md_error_t * ep)63707c478bd9Sstevel@tonic-gate meta_sp_recover_from_unit(
63717c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
63727c478bd9Sstevel@tonic-gate 	mdname_t	*compnp,
63737c478bd9Sstevel@tonic-gate 	mdcmdopts_t	options,
63747c478bd9Sstevel@tonic-gate 	md_error_t	*ep
63757c478bd9Sstevel@tonic-gate )
63767c478bd9Sstevel@tonic-gate {
63777c478bd9Sstevel@tonic-gate 	mdnamelist_t	*spnlp = NULL;
63787c478bd9Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
63797c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*ext = NULL;
63807c478bd9Sstevel@tonic-gate 	sp_ext_node_t	*extlist = NULL;
63817c478bd9Sstevel@tonic-gate 	int		count;
63827c478bd9Sstevel@tonic-gate 	char		yesno[255];
63837c478bd9Sstevel@tonic-gate 	char		*yes;
63847c478bd9Sstevel@tonic-gate 	int		rval = 0;
63857c478bd9Sstevel@tonic-gate 	minor_t		*minors = NULL;
63867c478bd9Sstevel@tonic-gate 	int		i;
63877c478bd9Sstevel@tonic-gate 	md_sp_t		*msp;
63887c478bd9Sstevel@tonic-gate 	md_set_desc	*sd;
63897c478bd9Sstevel@tonic-gate 	bool_t		mn_set = 0;
63907c478bd9Sstevel@tonic-gate 	daddr_t		start_block;
63917c478bd9Sstevel@tonic-gate 
63927c478bd9Sstevel@tonic-gate 	count = meta_sp_get_by_component(sp, compnp, &spnlp, 0, ep);
63937c478bd9Sstevel@tonic-gate 	if (count <= 0)
63947c478bd9Sstevel@tonic-gate 		return (-1);
63957c478bd9Sstevel@tonic-gate 
63967c478bd9Sstevel@tonic-gate 	/* set flag if dealing with a MN set */
63977c478bd9Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
63987c478bd9Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
63997c478bd9Sstevel@tonic-gate 			return (-1);
64007c478bd9Sstevel@tonic-gate 		}
64017c478bd9Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
64027c478bd9Sstevel@tonic-gate 			mn_set = 1;
64037c478bd9Sstevel@tonic-gate 	}
64047c478bd9Sstevel@tonic-gate 	/*
64057c478bd9Sstevel@tonic-gate 	 * Save the XDR unit structure for one of the soft partitions;
64067c478bd9Sstevel@tonic-gate 	 * we'll use this later to provide metadevice context to
64077c478bd9Sstevel@tonic-gate 	 * update the watermarks so the device can be resolved by
64087c478bd9Sstevel@tonic-gate 	 * devid instead of dev_t.
64097c478bd9Sstevel@tonic-gate 	 */
64107c478bd9Sstevel@tonic-gate 	if ((msp = meta_get_sp(sp, spnlp->namep, ep)) == NULL) {
64117c478bd9Sstevel@tonic-gate 		metafreenamelist(spnlp);
64127c478bd9Sstevel@tonic-gate 		return (-1);
64137c478bd9Sstevel@tonic-gate 	}
64147c478bd9Sstevel@tonic-gate 
64157c478bd9Sstevel@tonic-gate 	if ((start_block = meta_sp_get_start(sp, compnp, ep)) ==
64167c478bd9Sstevel@tonic-gate 	    MD_DISKADDR_ERROR) {
64177c478bd9Sstevel@tonic-gate 		return (-1);
64187c478bd9Sstevel@tonic-gate 	}
64197c478bd9Sstevel@tonic-gate 
64207c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist, 0ULL, start_block,
64217c478bd9Sstevel@tonic-gate 	    EXTTYP_RESERVED, 0, 0, meta_sp_cmp_by_offset);
64227c478bd9Sstevel@tonic-gate 	meta_sp_list_insert(NULL, NULL, &extlist,
64237c478bd9Sstevel@tonic-gate 	    metagetsize(compnp, ep) - MD_SP_WMSIZE, MD_SP_WMSIZE,
64247c478bd9Sstevel@tonic-gate 	    EXTTYP_END, 0, EXTFLG_UPDATE, meta_sp_cmp_by_offset);
64257c478bd9Sstevel@tonic-gate 
64267c478bd9Sstevel@tonic-gate 	if (meta_sp_extlist_from_namelist(sp, spnlp, &extlist, ep) == -1) {
64277c478bd9Sstevel@tonic-gate 		metafreenamelist(spnlp);
64287c478bd9Sstevel@tonic-gate 		return (-1);
64297c478bd9Sstevel@tonic-gate 	}
64307c478bd9Sstevel@tonic-gate 
64317c478bd9Sstevel@tonic-gate 	assert(extlist != NULL);
64327c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_VERBOSE) != 0) {
64337c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64347c478bd9Sstevel@tonic-gate 		    "Updating extent headers on device %s from metadb.\n\n"),
64357c478bd9Sstevel@tonic-gate 		    compnp->cname);
64367c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64377c478bd9Sstevel@tonic-gate 		    "The following extent headers will be written:\n"));
64387c478bd9Sstevel@tonic-gate 		meta_sp_display_exthdr();
64397c478bd9Sstevel@tonic-gate 	}
64407c478bd9Sstevel@tonic-gate 
64417c478bd9Sstevel@tonic-gate 	meta_sp_list_freefill(&extlist, metagetsize(compnp, ep));
64427c478bd9Sstevel@tonic-gate 
64437c478bd9Sstevel@tonic-gate 	for (ext = extlist; ext != NULL; ext = ext->ext_next) {
64447c478bd9Sstevel@tonic-gate 
64457c478bd9Sstevel@tonic-gate 		/* mark every node for updating except the reserved space */
64467c478bd9Sstevel@tonic-gate 		if (ext->ext_type != EXTTYP_RESERVED) {
64477c478bd9Sstevel@tonic-gate 			ext->ext_flags |= EXTFLG_UPDATE;
64487c478bd9Sstevel@tonic-gate 
64497c478bd9Sstevel@tonic-gate 			/* print extent information */
64507c478bd9Sstevel@tonic-gate 			if ((options & MDCMD_VERBOSE) != 0)
64517c478bd9Sstevel@tonic-gate 				meta_sp_display_ext(ext);
64527c478bd9Sstevel@tonic-gate 		}
64537c478bd9Sstevel@tonic-gate 	}
64547c478bd9Sstevel@tonic-gate 
64557c478bd9Sstevel@tonic-gate 	/* request verification and then update all watermarks */
64567c478bd9Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) != 0) {
64577c478bd9Sstevel@tonic-gate 
64587c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64597c478bd9Sstevel@tonic-gate 		    "\nWARNING: You are about to overwrite portions of %s\n"
64607c478bd9Sstevel@tonic-gate 		    "with soft partition metadata. The extent headers will be\n"
64617c478bd9Sstevel@tonic-gate 		    "written to match the existing metadb configuration.  If\n"
64627c478bd9Sstevel@tonic-gate 		    "the device was not previously setup with this\n"
64637c478bd9Sstevel@tonic-gate 		    "configuration, data loss may result.\n\n"),
64647c478bd9Sstevel@tonic-gate 		    compnp->cname);
64657c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
64667c478bd9Sstevel@tonic-gate 		    "Are you sure you want to do this (yes/no)? "));
64677c478bd9Sstevel@tonic-gate 
64687c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
64697c478bd9Sstevel@tonic-gate 		if ((fgets(yesno, sizeof (yesno), stdin) == NULL) ||
64707c478bd9Sstevel@tonic-gate 		    (strlen(yesno) == 1))
64717c478bd9Sstevel@tonic-gate 			(void) snprintf(yesno, sizeof (yesno),
64727c478bd9Sstevel@tonic-gate 			    "%s\n", dgettext(TEXT_DOMAIN, "no"));
64737c478bd9Sstevel@tonic-gate 		yes = dgettext(TEXT_DOMAIN, "yes");
64747c478bd9Sstevel@tonic-gate 		if (strncasecmp(yesno, yes, strlen(yesno) - 1) == 0) {
64757c478bd9Sstevel@tonic-gate 			/* place soft partitions into recovering state */
64767c478bd9Sstevel@tonic-gate 			minors = Zalloc(count * sizeof (minor_t));
64777c478bd9Sstevel@tonic-gate 			for (nlp = spnlp, i = 0;
64787c478bd9Sstevel@tonic-gate 			    nlp != NULL && i < count;
64797c478bd9Sstevel@tonic-gate 			    nlp = nlp->next, i++) {
64807c478bd9Sstevel@tonic-gate 				assert(nlp->namep != NULL);
64817c478bd9Sstevel@tonic-gate 				minors[i] = meta_getminor(nlp->namep->dev);
64827c478bd9Sstevel@tonic-gate 			}
64837c478bd9Sstevel@tonic-gate 			if (update_sp_status(sp, minors, count,
64847c478bd9Sstevel@tonic-gate 			    MD_SP_RECOVER, mn_set, ep) != 0) {
64857c478bd9Sstevel@tonic-gate 				rval = -1;
64867c478bd9Sstevel@tonic-gate 				goto out;
64877c478bd9Sstevel@tonic-gate 			}
64887c478bd9Sstevel@tonic-gate 
64897c478bd9Sstevel@tonic-gate 			/* update the watermarks */
64907c478bd9Sstevel@tonic-gate 			if (meta_sp_update_wm(sp, msp, extlist, ep) < 0) {
64917c478bd9Sstevel@tonic-gate 				rval = -1;
64927c478bd9Sstevel@tonic-gate 				goto out;
64937c478bd9Sstevel@tonic-gate 			}
64947c478bd9Sstevel@tonic-gate 
64957c478bd9Sstevel@tonic-gate 			if (options & MDCMD_PRINT) {
64967c478bd9Sstevel@tonic-gate 				(void) printf(dgettext(TEXT_DOMAIN, "%s: "
64977c478bd9Sstevel@tonic-gate 				    "Soft Partitions recovered from metadb\n"),
64987c478bd9Sstevel@tonic-gate 				    compnp->cname);
64997c478bd9Sstevel@tonic-gate 			}
65007c478bd9Sstevel@tonic-gate 
65017c478bd9Sstevel@tonic-gate 			/* return soft partitions to the OK state */
65027c478bd9Sstevel@tonic-gate 			if (update_sp_status(sp, minors, count,
65037c478bd9Sstevel@tonic-gate 			    MD_SP_OK, mn_set, ep) != 0) {
65047c478bd9Sstevel@tonic-gate 				rval = -1;
65057c478bd9Sstevel@tonic-gate 				goto out;
65067c478bd9Sstevel@tonic-gate 			}
65077c478bd9Sstevel@tonic-gate 
65087c478bd9Sstevel@tonic-gate 			rval = 0;
65097c478bd9Sstevel@tonic-gate 			goto out;
65107c478bd9Sstevel@tonic-gate 		}
65117c478bd9Sstevel@tonic-gate 	}
65127c478bd9Sstevel@tonic-gate 
65137c478bd9Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
65147c478bd9Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
65157c478bd9Sstevel@tonic-gate 		    "%s: Soft Partitions NOT recovered from metadb\n"),
65167c478bd9Sstevel@tonic-gate 		    compnp->cname);
65177c478bd9Sstevel@tonic-gate 	}
65187c478bd9Sstevel@tonic-gate 
65197c478bd9Sstevel@tonic-gate out:
65207c478bd9Sstevel@tonic-gate 	if (minors != NULL)
65217c478bd9Sstevel@tonic-gate 		Free(minors);
65227c478bd9Sstevel@tonic-gate 	metafreenamelist(spnlp);
65237c478bd9Sstevel@tonic-gate 	meta_sp_list_free(&extlist);
65247c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
65257c478bd9Sstevel@tonic-gate 	return (rval);
65267c478bd9Sstevel@tonic-gate }
65277c478bd9Sstevel@tonic-gate 
65287c478bd9Sstevel@tonic-gate 
65297c478bd9Sstevel@tonic-gate /*
65307c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_sp_update_abr()
65317c478bd9Sstevel@tonic-gate  * INPUT:	sp	- name of set we are recovering in
65327c478bd9Sstevel@tonic-gate  * OUTPUT:	ep	- return error pointer
65337c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - success, -1 - error
65347c478bd9Sstevel@tonic-gate  * PURPOSE:	update the ABR state for all soft partitions in the set. This
65357c478bd9Sstevel@tonic-gate  *		is called when joining a set. It sends a message to the master
65367c478bd9Sstevel@tonic-gate  *		node for each soft partition to get the value of tstate and
65377c478bd9Sstevel@tonic-gate  *		then sets ABR ,if required, by opening the sp, setting ABR
65387c478bd9Sstevel@tonic-gate  *		and then closing the sp. This approach is taken rather that
65397c478bd9Sstevel@tonic-gate  *		just issuing the MD_MN_SET_CAP ioctl, in order to deal with
65407c478bd9Sstevel@tonic-gate  *		the case when we have another node simultaneously unsetting ABR.
65417c478bd9Sstevel@tonic-gate  */
65427c478bd9Sstevel@tonic-gate int
meta_sp_update_abr(mdsetname_t * sp,md_error_t * ep)65437c478bd9Sstevel@tonic-gate meta_sp_update_abr(
65447c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp,
65457c478bd9Sstevel@tonic-gate 	md_error_t	*ep
65467c478bd9Sstevel@tonic-gate )
65477c478bd9Sstevel@tonic-gate {
65487c478bd9Sstevel@tonic-gate 	mdnamelist_t	*devnlp = NULL;
65497c478bd9Sstevel@tonic-gate 	mdnamelist_t	*p;
65507c478bd9Sstevel@tonic-gate 	mdname_t	*devnp = NULL;
65517c478bd9Sstevel@tonic-gate 	md_unit_t	*un;
65527c478bd9Sstevel@tonic-gate 	char		fname[MAXPATHLEN];
65537c478bd9Sstevel@tonic-gate 	int		mnum, fd;
65547c478bd9Sstevel@tonic-gate 	volcap_t	vc;
65557c478bd9Sstevel@tonic-gate 	uint_t		tstate;
65567c478bd9Sstevel@tonic-gate 
65577c478bd9Sstevel@tonic-gate 
65587c478bd9Sstevel@tonic-gate 	if (meta_get_sp_names(sp, &devnlp, 0, ep) < 0) {
65597c478bd9Sstevel@tonic-gate 		return (-1);
65607c478bd9Sstevel@tonic-gate 	}
65617c478bd9Sstevel@tonic-gate 
65627c478bd9Sstevel@tonic-gate 	/* Exit if no soft partitions in this set */
65637c478bd9Sstevel@tonic-gate 	if (devnlp == NULL)
65647c478bd9Sstevel@tonic-gate 		return (0);
65657c478bd9Sstevel@tonic-gate 
65667c478bd9Sstevel@tonic-gate 	/* For each soft partition */
65677c478bd9Sstevel@tonic-gate 	for (p = devnlp; (p != NULL); p = p->next) {
65687c478bd9Sstevel@tonic-gate 		devnp = p->namep;
65697c478bd9Sstevel@tonic-gate 
65707c478bd9Sstevel@tonic-gate 		/* check if this is a top level metadevice */
65717c478bd9Sstevel@tonic-gate 		if ((un = meta_get_mdunit(sp, devnp, ep)) == NULL)
65727c478bd9Sstevel@tonic-gate 			goto out;
65737c478bd9Sstevel@tonic-gate 		if (MD_HAS_PARENT(MD_PARENT(un))) {
65747c478bd9Sstevel@tonic-gate 			Free(un);
65757c478bd9Sstevel@tonic-gate 			continue;
65767c478bd9Sstevel@tonic-gate 		}
65777c478bd9Sstevel@tonic-gate 		Free(un);
65787c478bd9Sstevel@tonic-gate 
65797c478bd9Sstevel@tonic-gate 		/* Get tstate from Master */
65807c478bd9Sstevel@tonic-gate 		if (meta_mn_send_get_tstate(devnp->dev, &tstate, ep) != 0) {
65817c478bd9Sstevel@tonic-gate 			mdname_t	*np;
65827c478bd9Sstevel@tonic-gate 			np = metamnumname(&sp, meta_getminor(devnp->dev), 0,
65837c478bd9Sstevel@tonic-gate 			    ep);
65847c478bd9Sstevel@tonic-gate 			if (np) {
65857c478bd9Sstevel@tonic-gate 				md_perror(dgettext(TEXT_DOMAIN,
65867c478bd9Sstevel@tonic-gate 				    "Unable to get tstate for %s"), np->cname);
65877c478bd9Sstevel@tonic-gate 			}
65887c478bd9Sstevel@tonic-gate 			continue;
65897c478bd9Sstevel@tonic-gate 		}
65907c478bd9Sstevel@tonic-gate 		/* If not set on the master, nothing to do */
65917c478bd9Sstevel@tonic-gate 		if (!(tstate & MD_ABR_CAP))
65927c478bd9Sstevel@tonic-gate 			continue;
65937c478bd9Sstevel@tonic-gate 
65947c478bd9Sstevel@tonic-gate 		mnum = meta_getminor(devnp->dev);
65957c478bd9Sstevel@tonic-gate 		(void) snprintf(fname, MAXPATHLEN, "/dev/md/%s/rdsk/d%u",
65967c478bd9Sstevel@tonic-gate 		    sp->setname, (unsigned)MD_MIN2UNIT(mnum));
65977c478bd9Sstevel@tonic-gate 		if ((fd = open(fname, O_RDWR, 0)) < 0) {
65987c478bd9Sstevel@tonic-gate 			md_perror(dgettext(TEXT_DOMAIN,
65997c478bd9Sstevel@tonic-gate 			    "Could not open device %s"), fname);
66007c478bd9Sstevel@tonic-gate 			continue;
66017c478bd9Sstevel@tonic-gate 		}
66027c478bd9Sstevel@tonic-gate 
66037c478bd9Sstevel@tonic-gate 		/* Set ABR state */
66047c478bd9Sstevel@tonic-gate 		vc.vc_info = 0;
66057c478bd9Sstevel@tonic-gate 		vc.vc_set = 0;
66067c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGETVOLCAP, &vc) < 0) {
66077c478bd9Sstevel@tonic-gate 			(void) close(fd);
66087c478bd9Sstevel@tonic-gate 			continue;
66097c478bd9Sstevel@tonic-gate 		}
66107c478bd9Sstevel@tonic-gate 
66117c478bd9Sstevel@tonic-gate 		vc.vc_set = DKV_ABR_CAP;
66127c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCSETVOLCAP, &vc) < 0) {
66137c478bd9Sstevel@tonic-gate 			(void) close(fd);
66147c478bd9Sstevel@tonic-gate 			goto out;
66157c478bd9Sstevel@tonic-gate 		}
66167c478bd9Sstevel@tonic-gate 
66177c478bd9Sstevel@tonic-gate 		(void) close(fd);
66187c478bd9Sstevel@tonic-gate 	}
66197c478bd9Sstevel@tonic-gate 	metafreenamelist(devnlp);
66207c478bd9Sstevel@tonic-gate 	return (0);
66217c478bd9Sstevel@tonic-gate out:
66227c478bd9Sstevel@tonic-gate 	metafreenamelist(devnlp);
66237c478bd9Sstevel@tonic-gate 	return (-1);
66247c478bd9Sstevel@tonic-gate }
66257c478bd9Sstevel@tonic-gate 
66267c478bd9Sstevel@tonic-gate /*
66277c478bd9Sstevel@tonic-gate  * FUNCTION:	meta_mn_sp_update_abr()
66287c478bd9Sstevel@tonic-gate  * INPUT:	arg	- Given set.
66297c478bd9Sstevel@tonic-gate  * PURPOSE:	update the ABR state for all soft partitions in the set by
66307c478bd9Sstevel@tonic-gate  *		forking a process to call meta_sp_update_abr()
66317c478bd9Sstevel@tonic-gate  *		This function is only called via rpc.metad when adding a node
66327c478bd9Sstevel@tonic-gate  *		to a set, ie this node is beong joined to the set by another
66337c478bd9Sstevel@tonic-gate  *		node.
66347c478bd9Sstevel@tonic-gate  */
66357c478bd9Sstevel@tonic-gate void *
meta_mn_sp_update_abr(void * arg)66367c478bd9Sstevel@tonic-gate meta_mn_sp_update_abr(void *arg)
66377c478bd9Sstevel@tonic-gate {
66387c478bd9Sstevel@tonic-gate 	set_t		setno = *((set_t *)arg);
66397c478bd9Sstevel@tonic-gate 	mdsetname_t	*sp;
66407c478bd9Sstevel@tonic-gate 	md_error_t	mde = mdnullerror;
66417c478bd9Sstevel@tonic-gate 	int		fval;
66427c478bd9Sstevel@tonic-gate 
66437c478bd9Sstevel@tonic-gate 	/* should have a set */
66447c478bd9Sstevel@tonic-gate 	assert(setno != NULL);
66457c478bd9Sstevel@tonic-gate 
66467c478bd9Sstevel@tonic-gate 	if ((sp = metasetnosetname(setno, &mde)) == NULL) {
66477c478bd9Sstevel@tonic-gate 		mde_perror(&mde, "");
66487c478bd9Sstevel@tonic-gate 		return (NULL);
66497c478bd9Sstevel@tonic-gate 	}
66507c478bd9Sstevel@tonic-gate 
66517c478bd9Sstevel@tonic-gate 	if (!(meta_is_mn_set(sp, &mde))) {
66527c478bd9Sstevel@tonic-gate 		mde_perror(&mde, "");
66537c478bd9Sstevel@tonic-gate 		return (NULL);
66547c478bd9Sstevel@tonic-gate 	}
66557c478bd9Sstevel@tonic-gate 
66567c478bd9Sstevel@tonic-gate 	/* fork a process */
66577c478bd9Sstevel@tonic-gate 	if ((fval = md_daemonize(sp, &mde)) != 0) {
66587c478bd9Sstevel@tonic-gate 		/*
66597c478bd9Sstevel@tonic-gate 		 * md_daemonize will fork off a process.  The is the
66607c478bd9Sstevel@tonic-gate 		 * parent or error.
66617c478bd9Sstevel@tonic-gate 		 */
66627c478bd9Sstevel@tonic-gate 		if (fval > 0) {
66637c478bd9Sstevel@tonic-gate 			return (NULL);
66647c478bd9Sstevel@tonic-gate 		}
66657c478bd9Sstevel@tonic-gate 		mde_perror(&mde, "");
66667c478bd9Sstevel@tonic-gate 		return (NULL);
66677c478bd9Sstevel@tonic-gate 	}
66687c478bd9Sstevel@tonic-gate 	/*
66697c478bd9Sstevel@tonic-gate 	 * Child process should never return back to rpc.metad, but
66707c478bd9Sstevel@tonic-gate 	 * should exit.
66717c478bd9Sstevel@tonic-gate 	 * Flush all internally cached data inherited from parent process
66727c478bd9Sstevel@tonic-gate 	 * since cached data will be cleared when parent process RPC request
66737c478bd9Sstevel@tonic-gate 	 * has completed (which is possibly before this child process
66747c478bd9Sstevel@tonic-gate 	 * can complete).
66757c478bd9Sstevel@tonic-gate 	 * Child process can retrieve and cache its own copy of data from
66767c478bd9Sstevel@tonic-gate 	 * rpc.metad that won't be changed by the parent process.
66777c478bd9Sstevel@tonic-gate 	 *
66787c478bd9Sstevel@tonic-gate 	 * Reset md_in_daemon since this child will be a client of rpc.metad
66797c478bd9Sstevel@tonic-gate 	 * not part of the rpc.metad daemon itself.
66807c478bd9Sstevel@tonic-gate 	 * md_in_daemon is used by rpc.metad so that libmeta can tell if
66817c478bd9Sstevel@tonic-gate 	 * this thread is rpc.metad or any other thread.  (If this thread
66827c478bd9Sstevel@tonic-gate 	 * was rpc.metad it could use some short circuit code to get data
66837c478bd9Sstevel@tonic-gate 	 * directly from rpc.metad instead of doing an RPC call to rpc.metad).
66847c478bd9Sstevel@tonic-gate 	 */
66857c478bd9Sstevel@tonic-gate 	md_in_daemon = 0;
66867c478bd9Sstevel@tonic-gate 	metaflushsetname(sp);
66877c478bd9Sstevel@tonic-gate 	sr_cache_flush_setno(setno);
66887c478bd9Sstevel@tonic-gate 	if ((sp = metasetnosetname(setno, &mde)) == NULL) {
66897c478bd9Sstevel@tonic-gate 		mde_perror(&mde, "");
66907c478bd9Sstevel@tonic-gate 		md_exit(sp, 1);
66917c478bd9Sstevel@tonic-gate 	}
66927c478bd9Sstevel@tonic-gate 
66937c478bd9Sstevel@tonic-gate 
66947c478bd9Sstevel@tonic-gate 	/*
66957c478bd9Sstevel@tonic-gate 	 * Closing stdin/out/err here.
66967c478bd9Sstevel@tonic-gate 	 */
66977c478bd9Sstevel@tonic-gate 	(void) close(0);
66987c478bd9Sstevel@tonic-gate 	(void) close(1);
66997c478bd9Sstevel@tonic-gate 	(void) close(2);
67007c478bd9Sstevel@tonic-gate 	assert(fval == 0);
67017c478bd9Sstevel@tonic-gate 
67027c478bd9Sstevel@tonic-gate 	(void) meta_sp_update_abr(sp, &mde);
67037c478bd9Sstevel@tonic-gate 
67047c478bd9Sstevel@tonic-gate 	md_exit(sp, 0);
67057c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
6706b6c8bd52Sjeanm 	return (NULL);
67077c478bd9Sstevel@tonic-gate }
67081cd3f00bSsk102515 
67091cd3f00bSsk102515 int
meta_sp_check_component(mdsetname_t * sp,mdname_t * np,md_error_t * ep)67101cd3f00bSsk102515 meta_sp_check_component(
67111cd3f00bSsk102515 	mdsetname_t	*sp,
67121cd3f00bSsk102515 	mdname_t	*np,
67131cd3f00bSsk102515 	md_error_t	*ep
67141cd3f00bSsk102515 )
67151cd3f00bSsk102515 {
67161cd3f00bSsk102515 	md_sp_t	*msp;
67171cd3f00bSsk102515 	minor_t	mnum = 0;
67181cd3f00bSsk102515 	md_dev64_t	dev = 0;
67191cd3f00bSsk102515 	mdnm_params_t	nm;
67201cd3f00bSsk102515 	md_getdevs_params_t	mgd;
67211cd3f00bSsk102515 	side_t	sideno;
67221cd3f00bSsk102515 	char	*miscname;
67231cd3f00bSsk102515 	md_dev64_t	*mydev = NULL;
67242791f8b9SPeter Dennis - Sustaining Engineer 	char	*pname = NULL, *t;
67252791f8b9SPeter Dennis - Sustaining Engineer 	char	*ctd_name = NULL;
67262791f8b9SPeter Dennis - Sustaining Engineer 	char	*devname = NULL;
67271cd3f00bSsk102515 	int	len;
67281cd3f00bSsk102515 	int	rval = -1;
67291cd3f00bSsk102515 
67301cd3f00bSsk102515 	(void) memset(&nm, '\0', sizeof (nm));
67311cd3f00bSsk102515 	if ((msp = meta_get_sp_common(sp, np, 0, ep)) == NULL)
67321cd3f00bSsk102515 		return (-1);
67331cd3f00bSsk102515 
67341cd3f00bSsk102515 	if ((miscname = metagetmiscname(np, ep)) == NULL)
67351cd3f00bSsk102515 		return (-1);
67361cd3f00bSsk102515 
67371cd3f00bSsk102515 	sideno = getmyside(sp, ep);
67381cd3f00bSsk102515 
67391cd3f00bSsk102515 	meta_sp_debug("meta_sp_check_component: %s is on %s key: %d"
67401cd3f00bSsk102515 	    " dev: %llu\n",
67411cd3f00bSsk102515 	    np->cname, msp->compnamep->cname, msp->compnamep->key,
67421cd3f00bSsk102515 	    msp->compnamep->dev);
67431cd3f00bSsk102515 
67441cd3f00bSsk102515 	/*
67451cd3f00bSsk102515 	 * Now get the data from the unit structure. The compnamep stuff
67461cd3f00bSsk102515 	 * contains the data from the namespace and we need the un_dev
67471cd3f00bSsk102515 	 * from the unit structure.
67481cd3f00bSsk102515 	 */
67491cd3f00bSsk102515 	(void) memset(&mgd, '\0', sizeof (mgd));
67501cd3f00bSsk102515 	MD_SETDRIVERNAME(&mgd, miscname, sp->setno);
67511cd3f00bSsk102515 	mgd.cnt = 1;		    /* sp's only have one subdevice */
67521cd3f00bSsk102515 	mgd.mnum = meta_getminor(np->dev);
67531cd3f00bSsk102515 
67541cd3f00bSsk102515 	mydev = Zalloc(sizeof (*mydev));
67551cd3f00bSsk102515 	mgd.devs = (uintptr_t)mydev;
67561cd3f00bSsk102515 
67571cd3f00bSsk102515 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, np->cname) != 0) {
67581cd3f00bSsk102515 		meta_sp_debug("meta_sp_check_component: ioctl failed\n");
67591cd3f00bSsk102515 		(void) mdstealerror(ep, &mgd.mde);
67601cd3f00bSsk102515 		rval = 0;
67611cd3f00bSsk102515 		goto out;
67621cd3f00bSsk102515 	} else if (mgd.cnt <= 0) {
67631cd3f00bSsk102515 		assert(mgd.cnt >= 0);
67641cd3f00bSsk102515 		rval = 0;
67651cd3f00bSsk102515 		goto out;
67661cd3f00bSsk102515 	}
67671cd3f00bSsk102515 
67681cd3f00bSsk102515 	/* Get the devname from the name space. */
67691cd3f00bSsk102515 	if ((devname = meta_getnmentbykey(sp->setno, sideno,
67701cd3f00bSsk102515 	    msp->compnamep->key, NULL, &mnum, &dev, ep)) == NULL) {
67711cd3f00bSsk102515 		meta_sp_debug("meta_sp_check_component: key %d not"
67721cd3f00bSsk102515 		    "found\n", msp->compnamep->key);
67731cd3f00bSsk102515 		goto out;
67741cd3f00bSsk102515 	}
67751cd3f00bSsk102515 
67761cd3f00bSsk102515 	meta_sp_debug("dev %s from component: (%lu, %lu)\n",
67771cd3f00bSsk102515 	    devname,
67781cd3f00bSsk102515 	    meta_getmajor(*mydev),
67791cd3f00bSsk102515 	    meta_getminor(*mydev));
67801cd3f00bSsk102515 	meta_sp_debug("minor from the namespace: %lu\n", mnum);
67811cd3f00bSsk102515 
67821cd3f00bSsk102515 	if (mnum != meta_getminor(*mydev)) {
67831cd3f00bSsk102515 		/*
67841cd3f00bSsk102515 		 * The minor numbers are different. Update the namespace
67851cd3f00bSsk102515 		 * with the information from the component.
67861cd3f00bSsk102515 		 */
67871cd3f00bSsk102515 
67881cd3f00bSsk102515 		t = strrchr(devname, '/');
67891cd3f00bSsk102515 		t++;
67901cd3f00bSsk102515 		ctd_name = Strdup(t);
67911cd3f00bSsk102515 
67921cd3f00bSsk102515 		meta_sp_debug("meta_sp_check_component: ctd_name: %s\n",
67931cd3f00bSsk102515 		    ctd_name);
67941cd3f00bSsk102515 
67951cd3f00bSsk102515 		len = strlen(devname);
67961cd3f00bSsk102515 		t = strrchr(devname, '/');
67971cd3f00bSsk102515 		t++;
67981cd3f00bSsk102515 		pname = Zalloc((len - strlen(t)) + 1);
67991cd3f00bSsk102515 		(void) strncpy(pname, devname, (len - strlen(t)));
68001cd3f00bSsk102515 		meta_sp_debug("pathname: %s\n", pname);
68011cd3f00bSsk102515 
68021cd3f00bSsk102515 		meta_sp_debug("updating the minor number to %lu\n", nm.mnum);
68031cd3f00bSsk102515 
68041cd3f00bSsk102515 		if (meta_update_namespace(sp->setno, sideno,
68051cd3f00bSsk102515 		    ctd_name, *mydev, msp->compnamep->key, pname,
68061cd3f00bSsk102515 		    ep) != 0) {
68071cd3f00bSsk102515 			goto out;
68081cd3f00bSsk102515 		}
68091cd3f00bSsk102515 	}
68101cd3f00bSsk102515 out:
68111cd3f00bSsk102515 	if (pname != NULL)
68121cd3f00bSsk102515 		Free(pname);
68131cd3f00bSsk102515 	if (ctd_name != NULL)
68141cd3f00bSsk102515 		Free(ctd_name);
68151cd3f00bSsk102515 	if (devname != NULL)
68161cd3f00bSsk102515 		Free(devname);
68171cd3f00bSsk102515 	if (mydev != NULL)
68181cd3f00bSsk102515 		Free(mydev);
68191cd3f00bSsk102515 	return (rval);
68201cd3f00bSsk102515 }
6821