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