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 */
210Sstevel@tonic-gate /*
22*4150Sjmf * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * Just in case we're not in a build environment, make sure that
300Sstevel@tonic-gate * TEXT_DOMAIN gets set to something.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
330Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate * mirror operations
380Sstevel@tonic-gate */
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <meta.h>
410Sstevel@tonic-gate #include <sys/lvm/md_mirror.h>
420Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate #include <ctype.h>
450Sstevel@tonic-gate #include <stddef.h>
460Sstevel@tonic-gate
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate * FUNCTION: meta_get_mirror_names()
490Sstevel@tonic-gate * INPUT: sp - the set name to get mirrors from
500Sstevel@tonic-gate * options - options from the command line
510Sstevel@tonic-gate * OUTPUT: nlpp - list of all mirror names
520Sstevel@tonic-gate * ep - return error pointer
530Sstevel@tonic-gate * RETURNS: int - -1 if error, 0 success
540Sstevel@tonic-gate * PURPOSE: returns a list of all mirrors in the metadb
550Sstevel@tonic-gate * for all devices in the specified set
560Sstevel@tonic-gate */
570Sstevel@tonic-gate int
meta_get_mirror_names(mdsetname_t * sp,mdnamelist_t ** nlpp,int options,md_error_t * ep)580Sstevel@tonic-gate meta_get_mirror_names(
590Sstevel@tonic-gate mdsetname_t *sp,
600Sstevel@tonic-gate mdnamelist_t **nlpp,
610Sstevel@tonic-gate int options,
620Sstevel@tonic-gate md_error_t *ep
630Sstevel@tonic-gate )
640Sstevel@tonic-gate {
650Sstevel@tonic-gate return (meta_get_names(MD_MIRROR, sp, nlpp, options, ep));
660Sstevel@tonic-gate }
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * free mirror unit
700Sstevel@tonic-gate */
710Sstevel@tonic-gate void
meta_free_mirror(md_mirror_t * mirrorp)720Sstevel@tonic-gate meta_free_mirror(
730Sstevel@tonic-gate md_mirror_t *mirrorp
740Sstevel@tonic-gate )
750Sstevel@tonic-gate {
760Sstevel@tonic-gate Free(mirrorp);
770Sstevel@tonic-gate }
780Sstevel@tonic-gate
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate * get mirror unit
810Sstevel@tonic-gate */
820Sstevel@tonic-gate static md_mirror_t *
meta_get_mirror_common(mdsetname_t * sp,mdname_t * mirnp,int fast,md_error_t * ep)830Sstevel@tonic-gate meta_get_mirror_common(
840Sstevel@tonic-gate mdsetname_t *sp,
850Sstevel@tonic-gate mdname_t *mirnp,
860Sstevel@tonic-gate int fast,
870Sstevel@tonic-gate md_error_t *ep
880Sstevel@tonic-gate )
890Sstevel@tonic-gate {
900Sstevel@tonic-gate mddrivename_t *dnp = mirnp->drivenamep;
910Sstevel@tonic-gate char *miscname;
920Sstevel@tonic-gate mm_unit_t *mm;
930Sstevel@tonic-gate md_mirror_t *mirrorp;
940Sstevel@tonic-gate uint_t smi, nsm;
950Sstevel@tonic-gate md_resync_ioctl_t ri;
960Sstevel@tonic-gate
970Sstevel@tonic-gate /* must have set */
980Sstevel@tonic-gate assert(sp != NULL);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate /* short circuit */
1010Sstevel@tonic-gate if (dnp->unitp != NULL) {
1020Sstevel@tonic-gate assert(dnp->unitp->type == MD_METAMIRROR);
1030Sstevel@tonic-gate return ((md_mirror_t *)dnp->unitp);
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /* get miscname and unit */
1070Sstevel@tonic-gate if ((miscname = metagetmiscname(mirnp, ep)) == NULL)
1080Sstevel@tonic-gate return (NULL);
1090Sstevel@tonic-gate if (strcmp(miscname, MD_MIRROR) != 0) {
1100Sstevel@tonic-gate (void) mdmderror(ep, MDE_NOT_MM, meta_getminor(mirnp->dev),
1110Sstevel@tonic-gate mirnp->cname);
1120Sstevel@tonic-gate return (NULL);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate if ((mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, ep)) == NULL)
1150Sstevel@tonic-gate return (NULL);
1160Sstevel@tonic-gate assert(mm->c.un_type == MD_METAMIRROR);
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate /* allocate mirror */
1190Sstevel@tonic-gate mirrorp = Zalloc(sizeof (*mirrorp));
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /* get common info */
1220Sstevel@tonic-gate mirrorp->common.namep = mirnp;
1230Sstevel@tonic-gate mirrorp->common.type = mm->c.un_type;
1240Sstevel@tonic-gate mirrorp->common.state = mm->c.un_status;
1250Sstevel@tonic-gate mirrorp->common.capabilities = mm->c.un_capabilities;
1260Sstevel@tonic-gate mirrorp->common.parent = mm->c.un_parent;
1270Sstevel@tonic-gate mirrorp->common.size = mm->c.un_total_blocks;
1280Sstevel@tonic-gate mirrorp->common.user_flags = mm->c.un_user_flags;
1290Sstevel@tonic-gate mirrorp->common.revision = mm->c.un_revision;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /* get options */
1320Sstevel@tonic-gate mirrorp->read_option = mm->un_read_option;
1330Sstevel@tonic-gate mirrorp->write_option = mm->un_write_option;
1340Sstevel@tonic-gate mirrorp->pass_num = mm->un_pass_num;
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate /* get submirrors */
1370Sstevel@tonic-gate for (smi = 0, nsm = 0; (smi < NMIRROR); ++smi) {
1380Sstevel@tonic-gate mm_submirror_t *mmsp = &mm->un_sm[smi];
1390Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /* get submirror state */
1420Sstevel@tonic-gate mdsp->state = mmsp->sm_state;
1430Sstevel@tonic-gate if (mdsp->state == SMS_UNUSED)
1440Sstevel@tonic-gate continue;
1450Sstevel@tonic-gate ++nsm;
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /* get submirror time of last state change */
1480Sstevel@tonic-gate mdsp->timestamp = mmsp->sm_timestamp;
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate /* get submirror flags */
1510Sstevel@tonic-gate mdsp->flags = mmsp->sm_flags;
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate /* get submirror name */
1540Sstevel@tonic-gate mdsp->submirnamep = metakeyname(&sp, mmsp->sm_key, fast, ep);
1550Sstevel@tonic-gate if (mdsp->submirnamep == NULL)
1560Sstevel@tonic-gate goto out;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate assert(nsm == mm->un_nsm);
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate /* get resync info */
1610Sstevel@tonic-gate (void) memset(&ri, 0, sizeof (ri));
1620Sstevel@tonic-gate ri.ri_mnum = meta_getminor(mirnp->dev);
1630Sstevel@tonic-gate MD_SETDRIVERNAME(&ri, MD_MIRROR, sp->setno);
1640Sstevel@tonic-gate if (metaioctl(MD_IOCGETSYNC, &ri, &ri.mde, mirnp->cname) != 0) {
1650Sstevel@tonic-gate (void) mdstealerror(ep, &ri.mde);
1660Sstevel@tonic-gate goto out;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate mirrorp->percent_done = ri.ri_percent_done;
1690Sstevel@tonic-gate mirrorp->percent_dirty = ri.ri_percent_dirty;
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate /* cleanup, return success */
1720Sstevel@tonic-gate Free(mm);
1730Sstevel@tonic-gate dnp->unitp = (md_common_t *)mirrorp;
1740Sstevel@tonic-gate return (mirrorp);
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /* cleanup, return error */
1770Sstevel@tonic-gate out:
1780Sstevel@tonic-gate Free(mm);
1790Sstevel@tonic-gate meta_free_mirror(mirrorp);
1800Sstevel@tonic-gate return (NULL);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * get mirror unit
1850Sstevel@tonic-gate */
1860Sstevel@tonic-gate md_mirror_t *
meta_get_mirror(mdsetname_t * sp,mdname_t * mirnp,md_error_t * ep)1870Sstevel@tonic-gate meta_get_mirror(
1880Sstevel@tonic-gate mdsetname_t *sp,
1890Sstevel@tonic-gate mdname_t *mirnp,
1900Sstevel@tonic-gate md_error_t *ep
1910Sstevel@tonic-gate )
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate return (meta_get_mirror_common(sp, mirnp, 0, ep));
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate * check mirror for dev
1980Sstevel@tonic-gate */
1990Sstevel@tonic-gate static int
in_mirror(mdsetname_t * sp,mdname_t * mirnp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)2000Sstevel@tonic-gate in_mirror(
2010Sstevel@tonic-gate mdsetname_t *sp,
2020Sstevel@tonic-gate mdname_t *mirnp,
2030Sstevel@tonic-gate mdname_t *np,
2040Sstevel@tonic-gate diskaddr_t slblk,
2050Sstevel@tonic-gate diskaddr_t nblks,
2060Sstevel@tonic-gate md_error_t *ep
2070Sstevel@tonic-gate )
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate md_mirror_t *mirrorp;
2100Sstevel@tonic-gate uint_t smi;
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /* should be in the same set */
2130Sstevel@tonic-gate assert(sp != NULL);
2140Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /* get unit */
2170Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2180Sstevel@tonic-gate return (-1);
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate /* look in submirrors */
2210Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
2220Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2230Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate /* skip unused submirrors */
2260Sstevel@tonic-gate if (submirnp == NULL) {
2270Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
2280Sstevel@tonic-gate continue;
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate /* check overlap */
2320Sstevel@tonic-gate if (metaismeta(submirnp))
2330Sstevel@tonic-gate continue;
2340Sstevel@tonic-gate if (meta_check_overlap(mirnp->cname, np, slblk, nblks,
2350Sstevel@tonic-gate submirnp, 0, -1, ep) != 0)
2360Sstevel@tonic-gate return (-1);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /* return success */
2400Sstevel@tonic-gate return (0);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate * check to see if we're in a mirror
2450Sstevel@tonic-gate */
2460Sstevel@tonic-gate int
meta_check_inmirror(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)2470Sstevel@tonic-gate meta_check_inmirror(
2480Sstevel@tonic-gate mdsetname_t *sp,
2490Sstevel@tonic-gate mdname_t *np,
2500Sstevel@tonic-gate diskaddr_t slblk,
2510Sstevel@tonic-gate diskaddr_t nblks,
2520Sstevel@tonic-gate md_error_t *ep
2530Sstevel@tonic-gate )
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate mdnamelist_t *mirrornlp = NULL;
2560Sstevel@tonic-gate mdnamelist_t *p;
2570Sstevel@tonic-gate int rval = 0;
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate /* should have a set */
2600Sstevel@tonic-gate assert(sp != NULL);
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /* for each mirror */
2630Sstevel@tonic-gate if (meta_get_mirror_names(sp, &mirrornlp, 0, ep) < 0)
2640Sstevel@tonic-gate return (-1);
2650Sstevel@tonic-gate for (p = mirrornlp; (p != NULL); p = p->next) {
2660Sstevel@tonic-gate mdname_t *mirnp = p->namep;
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /* check mirror */
2690Sstevel@tonic-gate if (in_mirror(sp, mirnp, np, slblk, nblks, ep) != 0) {
2700Sstevel@tonic-gate rval = -1;
2710Sstevel@tonic-gate break;
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate /* cleanup, return success */
2760Sstevel@tonic-gate metafreenamelist(mirrornlp);
2770Sstevel@tonic-gate return (rval);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate * Check to see if the primary mirror is built on top of a
2820Sstevel@tonic-gate * root slice which is mounted. This check is primarily to
2830Sstevel@tonic-gate * account for this case -
2840Sstevel@tonic-gate *
2850Sstevel@tonic-gate * # metainit -f d1 1 1 <root slice>
2860Sstevel@tonic-gate * # metainit d0 -m d1
2870Sstevel@tonic-gate * # metainit d2 1 1 ctds
2880Sstevel@tonic-gate * # metattach d0 d2
2890Sstevel@tonic-gate *
2900Sstevel@tonic-gate * The metattach here needs to fail if the root slice is
2910Sstevel@tonic-gate * being mirrored; otherwise there is a potential for
2920Sstevel@tonic-gate * data corruption.
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate static int
meta_check_primary_mirror(mdsetname_t * sp,mdname_t * mirnp,md_error_t * ep)2950Sstevel@tonic-gate meta_check_primary_mirror(
2960Sstevel@tonic-gate mdsetname_t *sp,
2970Sstevel@tonic-gate mdname_t *mirnp,
2980Sstevel@tonic-gate md_error_t *ep
2990Sstevel@tonic-gate )
3000Sstevel@tonic-gate {
3010Sstevel@tonic-gate int smi;
3020Sstevel@tonic-gate char *curroot;
303*4150Sjmf char *temproot;
3040Sstevel@tonic-gate mdname_t *rootnp;
3050Sstevel@tonic-gate md_mirror_t *mirrorp;
3060Sstevel@tonic-gate md_stripe_t *stripep;
3070Sstevel@tonic-gate md_row_t *rp;
3080Sstevel@tonic-gate md_comp_t *cp;
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate if ((curroot = meta_get_current_root(ep)) == NULL)
3110Sstevel@tonic-gate return (-1);
312*4150Sjmf
313*4150Sjmf /*
314*4150Sjmf * We need to take the canonical name here otherwise the call to
315*4150Sjmf * metaname will add a bad entry to the drivelistp cache and
316*4150Sjmf * things will get nasty later on.
317*4150Sjmf * However we also need to trap the case where we have a logical
318*4150Sjmf * device name and meta_canonicalize returns NULL.
319*4150Sjmf */
320*4150Sjmf temproot = meta_canonicalize(sp, curroot);
321*4150Sjmf if (temproot != NULL) {
322*4150Sjmf curroot = Strdup(temproot);
323*4150Sjmf Free(temproot);
324*4150Sjmf }
325*4150Sjmf
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate * Get device name of current root metadevice. If root
3280Sstevel@tonic-gate * is net mounted as happens if we're part of the
3290Sstevel@tonic-gate * install process, rootnp will be set to NULL and we
3300Sstevel@tonic-gate * return success.
3311623Stw21770 *
3321623Stw21770 * Since curroot should be a complete path, we only
3331623Stw21770 * need to check whether the device is a logical device.
3341623Stw21770 * The metaname below returns NULL if curroot is not a logical
3351623Stw21770 * device.
3360Sstevel@tonic-gate */
3371623Stw21770 if ((rootnp = metaname(&sp, curroot, LOGICAL_DEVICE, ep)) == NULL)
3380Sstevel@tonic-gate return (0);
3390Sstevel@tonic-gate /*
3401623Stw21770 * If we're here, the curroot is a mounted on a logical device.
3411623Stw21770 * Make sure this mirror is not on the root logical device.
3420Sstevel@tonic-gate */
3431623Stw21770 if (metaismeta(mirnp)) {
3440Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
3450Sstevel@tonic-gate return (-1);
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
3480Sstevel@tonic-gate /* Check all submirrors */
3490Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
3500Sstevel@tonic-gate mdname_t *submirnamep = mdsp->submirnamep;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate /* skip unused submirrors */
3530Sstevel@tonic-gate if (submirnamep == NULL) {
3540Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
3550Sstevel@tonic-gate continue;
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate /* check if submirror is a stripe or not */
3580Sstevel@tonic-gate if (strcmp(metagetmiscname(submirnamep, ep), MD_STRIPE)
3590Sstevel@tonic-gate != 0)
3600Sstevel@tonic-gate return (-1);
3610Sstevel@tonic-gate if ((stripep = meta_get_stripe(sp, submirnamep, ep))
3620Sstevel@tonic-gate == NULL)
3630Sstevel@tonic-gate return (-1);
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * Examine the first component of the first row and
3670Sstevel@tonic-gate * check to see if it has a mounted root slice
3680Sstevel@tonic-gate */
3690Sstevel@tonic-gate rp = &stripep->rows.rows_val[0];
3700Sstevel@tonic-gate cp = &rp->comps.comps_val[0];
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate * we just care about the component built on
3730Sstevel@tonic-gate * top of a raw device
3740Sstevel@tonic-gate */
3750Sstevel@tonic-gate if (!metaismeta(cp->compnamep)) {
3760Sstevel@tonic-gate /*
3770Sstevel@tonic-gate * If root device is the 1st component of
3780Sstevel@tonic-gate * the stripe, then fail.
3790Sstevel@tonic-gate */
3800Sstevel@tonic-gate if (strcmp(rootnp->cname, cp->compnamep->cname)
3810Sstevel@tonic-gate == 0) {
3820Sstevel@tonic-gate (void) mduseerror(ep, MDE_IS_MOUNTED,
3830Sstevel@tonic-gate rootnp->dev, "/", rootnp->cname);
3840Sstevel@tonic-gate return (-1);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate /* return success */
3900Sstevel@tonic-gate return (0);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate * check submirror
3950Sstevel@tonic-gate */
3960Sstevel@tonic-gate int
meta_check_submirror(mdsetname_t * sp,mdname_t * np,mdname_t * mirnp,int force,md_error_t * ep)3970Sstevel@tonic-gate meta_check_submirror(
3980Sstevel@tonic-gate mdsetname_t *sp,
3990Sstevel@tonic-gate mdname_t *np,
4000Sstevel@tonic-gate mdname_t *mirnp,
4010Sstevel@tonic-gate int force,
4020Sstevel@tonic-gate md_error_t *ep
4030Sstevel@tonic-gate )
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate mdchkopts_t options = 0;
4060Sstevel@tonic-gate md_common_t *mdp;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate /* make sure we have a metadevice disk */
4090Sstevel@tonic-gate if (metachkmeta(np, ep) != 0)
4100Sstevel@tonic-gate return (-1);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate * Check to see if the primary mirror consists of a root
4140Sstevel@tonic-gate * mounted device
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate if (mirnp && (!force) && ((meta_check_primary_mirror(sp, mirnp, ep)
4170Sstevel@tonic-gate != 0)))
4180Sstevel@tonic-gate return (-1);
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate /* check to ensure that it is not already in use */
4210Sstevel@tonic-gate if ((! force) &&
4220Sstevel@tonic-gate (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0)) {
4230Sstevel@tonic-gate return (-1);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate /* make sure it is in the set */
4270Sstevel@tonic-gate if (meta_check_inset(sp, np, ep) != 0)
4280Sstevel@tonic-gate return (-1);
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate /* make sure its not in a metadevice */
4310Sstevel@tonic-gate if (! metaismeta(np)) { /* Non-metadevices */
4320Sstevel@tonic-gate if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
4330Sstevel@tonic-gate return (-1);
4340Sstevel@tonic-gate } else { /* Metadevices only! */
4350Sstevel@tonic-gate /* make sure it can be parented */
4360Sstevel@tonic-gate if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
4370Sstevel@tonic-gate return (-1);
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
4400Sstevel@tonic-gate (! (mdp->capabilities & MD_CAN_SUB_MIRROR)) ||
4410Sstevel@tonic-gate (mdp->parent != MD_NO_PARENT)) {
4420Sstevel@tonic-gate return (mdmderror(ep, MDE_INVAL_UNIT,
4430Sstevel@tonic-gate meta_getminor(np->dev), np->cname));
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate /* return success */
4480Sstevel@tonic-gate return (0);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate /*
4520Sstevel@tonic-gate * convert read options
4530Sstevel@tonic-gate */
4540Sstevel@tonic-gate char *
rd_opt_to_name(mm_rd_opt_t opt)4550Sstevel@tonic-gate rd_opt_to_name(
4560Sstevel@tonic-gate mm_rd_opt_t opt
4570Sstevel@tonic-gate )
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate switch (opt) {
4600Sstevel@tonic-gate case RD_LOAD_BAL:
4610Sstevel@tonic-gate return ("roundrobin");
4620Sstevel@tonic-gate case RD_GEOMETRY:
4630Sstevel@tonic-gate return ("geometric");
4640Sstevel@tonic-gate case RD_FIRST:
4650Sstevel@tonic-gate return ("first");
4660Sstevel@tonic-gate default:
4670Sstevel@tonic-gate assert(0);
4680Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "invalid"));
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate static char *
rd_opt_to_opt(mm_rd_opt_t opt)4730Sstevel@tonic-gate rd_opt_to_opt(
4740Sstevel@tonic-gate mm_rd_opt_t opt
4750Sstevel@tonic-gate )
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate switch (opt) {
4780Sstevel@tonic-gate case RD_LOAD_BAL:
4790Sstevel@tonic-gate return (NULL); /* default */
4800Sstevel@tonic-gate case RD_GEOMETRY:
4810Sstevel@tonic-gate return ("-g");
4820Sstevel@tonic-gate case RD_FIRST:
4830Sstevel@tonic-gate return ("-r");
4840Sstevel@tonic-gate default:
4850Sstevel@tonic-gate assert(0);
4860Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "invalid"));
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate int
name_to_rd_opt(char * uname,char * name,mm_rd_opt_t * optp,md_error_t * ep)4910Sstevel@tonic-gate name_to_rd_opt(
4920Sstevel@tonic-gate char *uname,
4930Sstevel@tonic-gate char *name,
4940Sstevel@tonic-gate mm_rd_opt_t *optp,
4950Sstevel@tonic-gate md_error_t *ep
4960Sstevel@tonic-gate )
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate if (strcasecmp(name, "roundrobin") == 0) {
4990Sstevel@tonic-gate *optp = RD_LOAD_BAL;
5000Sstevel@tonic-gate return (0);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate if (strcasecmp(name, "geometric") == 0) {
5030Sstevel@tonic-gate *optp = RD_GEOMETRY;
5040Sstevel@tonic-gate return (0);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate if (strcasecmp(name, "first") == 0) {
5070Sstevel@tonic-gate *optp = RD_FIRST;
5080Sstevel@tonic-gate return (0);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate return (meta_cook_syntax(ep, MDE_BAD_RD_OPT, uname, 1, &name));
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate /*
5140Sstevel@tonic-gate * convert write options
5150Sstevel@tonic-gate */
5160Sstevel@tonic-gate char *
wr_opt_to_name(mm_wr_opt_t opt)5170Sstevel@tonic-gate wr_opt_to_name(
5180Sstevel@tonic-gate mm_wr_opt_t opt
5190Sstevel@tonic-gate )
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate switch (opt) {
5220Sstevel@tonic-gate case WR_PARALLEL:
5230Sstevel@tonic-gate return ("parallel");
5240Sstevel@tonic-gate case WR_SERIAL:
5250Sstevel@tonic-gate return ("serial");
5260Sstevel@tonic-gate default:
5270Sstevel@tonic-gate assert(0);
5280Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "invalid"));
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate static char *
wr_opt_to_opt(mm_wr_opt_t opt)5330Sstevel@tonic-gate wr_opt_to_opt(
5340Sstevel@tonic-gate mm_wr_opt_t opt
5350Sstevel@tonic-gate )
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate switch (opt) {
5380Sstevel@tonic-gate case WR_PARALLEL:
5390Sstevel@tonic-gate return (NULL); /* default */
5400Sstevel@tonic-gate case WR_SERIAL:
5410Sstevel@tonic-gate return ("-S");
5420Sstevel@tonic-gate default:
5430Sstevel@tonic-gate assert(0);
5440Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "invalid"));
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate int
name_to_wr_opt(char * uname,char * name,mm_wr_opt_t * optp,md_error_t * ep)5490Sstevel@tonic-gate name_to_wr_opt(
5500Sstevel@tonic-gate char *uname,
5510Sstevel@tonic-gate char *name,
5520Sstevel@tonic-gate mm_wr_opt_t *optp,
5530Sstevel@tonic-gate md_error_t *ep
5540Sstevel@tonic-gate )
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate if (strcasecmp(name, "parallel") == 0) {
5570Sstevel@tonic-gate *optp = WR_PARALLEL;
5580Sstevel@tonic-gate return (0);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate if (strcasecmp(name, "serial") == 0) {
5610Sstevel@tonic-gate *optp = WR_SERIAL;
5620Sstevel@tonic-gate return (0);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate return (meta_cook_syntax(ep, MDE_BAD_WR_OPT, uname, 1, &name));
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate * convert pass numbers
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate int
name_to_pass_num(char * uname,char * name,mm_pass_num_t * passp,md_error_t * ep)5710Sstevel@tonic-gate name_to_pass_num(
5720Sstevel@tonic-gate char *uname,
5730Sstevel@tonic-gate char *name,
5740Sstevel@tonic-gate mm_pass_num_t *passp,
5750Sstevel@tonic-gate md_error_t *ep
5760Sstevel@tonic-gate )
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate if ((sscanf(name, "%hd", passp) != 1) ||
5790Sstevel@tonic-gate (*passp < 0) || (*passp > MD_PASS_MAX)) {
5800Sstevel@tonic-gate return (meta_cook_syntax(ep, MDE_BAD_PASS_NUM,
5810Sstevel@tonic-gate uname, 1, &name));
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate return (0);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate /*
5870Sstevel@tonic-gate * convert resync option
5880Sstevel@tonic-gate */
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate static char *
resync_opt_to_name(uint_t tstate)5910Sstevel@tonic-gate resync_opt_to_name(
5920Sstevel@tonic-gate uint_t tstate
5930Sstevel@tonic-gate )
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate if (tstate & MD_ABR_CAP)
5960Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "application based"));
5970Sstevel@tonic-gate else
5980Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "optimized resync"));
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate * print mirror
6030Sstevel@tonic-gate */
6040Sstevel@tonic-gate static int
mirror_print(md_mirror_t * mirrorp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)6050Sstevel@tonic-gate mirror_print(
6060Sstevel@tonic-gate md_mirror_t *mirrorp,
6070Sstevel@tonic-gate char *fname,
6080Sstevel@tonic-gate FILE *fp,
6090Sstevel@tonic-gate mdprtopts_t options,
6100Sstevel@tonic-gate md_error_t *ep
6110Sstevel@tonic-gate )
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate uint_t smi;
6140Sstevel@tonic-gate char *p;
6150Sstevel@tonic-gate int rval = -1;
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate if (options & PRINT_LARGEDEVICES) {
6191623Stw21770 if ((mirrorp->common.revision & MD_64BIT_META_DEV) == 0) {
6201623Stw21770 rval = 0;
6211623Stw21770 goto out;
6221623Stw21770 }
6231623Stw21770 }
6241623Stw21770
6251623Stw21770 if (options & PRINT_FN) {
6261623Stw21770 if ((mirrorp->common.revision & MD_FN_META_DEV) == 0) {
6270Sstevel@tonic-gate rval = 0;
6280Sstevel@tonic-gate goto out;
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /* print name and -m */
6330Sstevel@tonic-gate if (fprintf(fp, "%s -m", mirrorp->common.namep->cname) == EOF)
6340Sstevel@tonic-gate goto out;
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate /* print submirrors */
6370Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
6380Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
6390Sstevel@tonic-gate mdname_t *submirnamep = mdsp->submirnamep;
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate /* skip unused submirrors */
6420Sstevel@tonic-gate if (submirnamep == NULL) {
6430Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
6440Sstevel@tonic-gate continue;
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate /* print submirror */
6481623Stw21770 if (fprintf(fp, " %s", submirnamep->rname) == EOF)
6490Sstevel@tonic-gate goto out;
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate /* print options */
6530Sstevel@tonic-gate if ((p = rd_opt_to_opt(mirrorp->read_option)) != NULL) {
6540Sstevel@tonic-gate if (fprintf(fp, " %s", p) == EOF)
6550Sstevel@tonic-gate goto out;
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate if ((p = wr_opt_to_opt(mirrorp->write_option)) != NULL) {
6580Sstevel@tonic-gate if (fprintf(fp, " %s", p) == EOF)
6590Sstevel@tonic-gate goto out;
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate if (fprintf(fp, " %u\n", mirrorp->pass_num) == EOF)
6620Sstevel@tonic-gate goto out;
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate /* success */
6650Sstevel@tonic-gate rval = 0;
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /* cleanup, return error */
6680Sstevel@tonic-gate out:
6690Sstevel@tonic-gate if (rval != 0)
6700Sstevel@tonic-gate (void) mdsyserror(ep, errno, fname);
6710Sstevel@tonic-gate return (rval);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate * convert submirror state to name
6760Sstevel@tonic-gate */
6770Sstevel@tonic-gate char *
sm_state_to_name(md_submirror_t * mdsp,md_status_t mirror_status,md_timeval32_t * tvp,uint_t tstate)6780Sstevel@tonic-gate sm_state_to_name(
6790Sstevel@tonic-gate md_submirror_t *mdsp,
6800Sstevel@tonic-gate md_status_t mirror_status,
6810Sstevel@tonic-gate md_timeval32_t *tvp,
6820Sstevel@tonic-gate uint_t tstate
6830Sstevel@tonic-gate )
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate static char state_to_str[100];
6860Sstevel@tonic-gate sm_state_t state = mdsp->state;
6870Sstevel@tonic-gate uint_t is_target = mdsp->flags & MD_SM_RESYNC_TARGET;
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate /* grab time */
6900Sstevel@tonic-gate if (tvp != NULL)
6910Sstevel@tonic-gate *tvp = mdsp->timestamp;
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate /*
6940Sstevel@tonic-gate * Only return Unavailable if there is no flagged error on the
6950Sstevel@tonic-gate * submirror. If the mirror has received any writes since the submirror
6960Sstevel@tonic-gate * went into Unavailable state a resync is required. To alert the
6970Sstevel@tonic-gate * administrator to this we return a 'Needs maintenance' message.
6980Sstevel@tonic-gate */
6990Sstevel@tonic-gate if ((tstate != 0) && (state & SMS_RUNNING)) {
7000Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Unavailable"));
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate /* all is well */
7040Sstevel@tonic-gate if (state & SMS_RUNNING) {
7050Sstevel@tonic-gate if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
7060Sstevel@tonic-gate ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target)) {
7070Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Okay"));
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate /* resyncing, needs repair */
7120Sstevel@tonic-gate if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
7130Sstevel@tonic-gate SMS_OFFLINE_RESYNC)) ||
7140Sstevel@tonic-gate (mirror_status & MD_UN_OPT_NOT_DONE)) {
7150Sstevel@tonic-gate if (mirror_status & MD_UN_RESYNC_ACTIVE) {
7160Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Resyncing"));
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate if (mirror_status & MD_UN_RESYNC_CANCEL) {
7190Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Resync cancelled"));
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Needs maintenance"));
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate /* needs repair */
7250Sstevel@tonic-gate if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) {
7260Sstevel@tonic-gate if (mirror_status & MD_UN_RESYNC_CANCEL) {
7270Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Resync cancelled"));
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Needs maintenance"));
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate /* unknown */
7330Sstevel@tonic-gate assert(0);
7340Sstevel@tonic-gate (void) sprintf(state_to_str, "0x%x", state);
7350Sstevel@tonic-gate return (state_to_str);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate * convert submirror state to repair action
7400Sstevel@tonic-gate */
7410Sstevel@tonic-gate int
sm_state_to_action(mdsetname_t * sp,md_submirror_t * mdsp,md_status_t mirror_status,md_mirror_t * mirrorp,char ** actionp,md_error_t * ep)7420Sstevel@tonic-gate sm_state_to_action(
7430Sstevel@tonic-gate mdsetname_t *sp,
7440Sstevel@tonic-gate md_submirror_t *mdsp,
7450Sstevel@tonic-gate md_status_t mirror_status,
7460Sstevel@tonic-gate md_mirror_t *mirrorp,
7470Sstevel@tonic-gate char **actionp,
7480Sstevel@tonic-gate md_error_t *ep
7490Sstevel@tonic-gate )
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate static char buf[1024];
7520Sstevel@tonic-gate mdname_t *submirnamep = mdsp->submirnamep;
7530Sstevel@tonic-gate sm_state_t state = mdsp->state;
7540Sstevel@tonic-gate char *miscname;
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate /* all is well */
7570Sstevel@tonic-gate *actionp = NULL;
7580Sstevel@tonic-gate if (mirror_status & MD_UN_RESYNC_ACTIVE)
7590Sstevel@tonic-gate return (0);
7600Sstevel@tonic-gate if ((state == SMS_RUNNING) && !(mirror_status & MD_UN_OPT_NOT_DONE))
7610Sstevel@tonic-gate return (0);
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate /* complete cancelled resync */
7640Sstevel@tonic-gate if (mirror_status & MD_UN_RESYNC_CANCEL) {
7650Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf),
7660Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "metasync %s"),
7670Sstevel@tonic-gate mirrorp->common.namep->cname);
7680Sstevel@tonic-gate *actionp = buf;
7690Sstevel@tonic-gate return (0);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate /* replace stripe component */
7730Sstevel@tonic-gate if ((metaismeta(submirnamep)) && (state & SMS_COMP_ERRED)) {
7740Sstevel@tonic-gate if ((miscname = metagetmiscname(submirnamep, ep)) == NULL)
7750Sstevel@tonic-gate return (-1);
7760Sstevel@tonic-gate if (strcmp(miscname, MD_STRIPE) == 0) {
7770Sstevel@tonic-gate mdname_t *compnamep;
7780Sstevel@tonic-gate comp_state_t compstate;
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate if (meta_find_erred_comp(sp, submirnamep,
7810Sstevel@tonic-gate &compnamep, &compstate, ep) != 0) {
7820Sstevel@tonic-gate return (-1);
7830Sstevel@tonic-gate }
7840Sstevel@tonic-gate if (compstate != CS_LAST_ERRED)
7850Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf),
7860Sstevel@tonic-gate "metareplace %s %s <%s>",
7870Sstevel@tonic-gate mirrorp->common.namep->cname,
7880Sstevel@tonic-gate compnamep->cname,
7890Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "new device"));
7900Sstevel@tonic-gate else
7910Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf),
7920Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
7930Sstevel@tonic-gate "after replacing \"Maintenance\" "
7940Sstevel@tonic-gate "components:\n"
7950Sstevel@tonic-gate "\t\tmetareplace %s %s <new device>"),
7960Sstevel@tonic-gate mirrorp->common.namep->cname,
7970Sstevel@tonic-gate compnamep->cname);
7980Sstevel@tonic-gate *actionp = buf;
7990Sstevel@tonic-gate return (0);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate /* resync mirror */
8040Sstevel@tonic-gate if ((state & (SMS_ATTACHED_RESYNC | SMS_OFFLINE_RESYNC |
8050Sstevel@tonic-gate SMS_COMP_RESYNC | SMS_ATTACHED)) ||
8060Sstevel@tonic-gate (mirror_status & MD_UN_OPT_NOT_DONE)) {
8070Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "metasync %s",
8080Sstevel@tonic-gate mirrorp->common.namep->cname);
8090Sstevel@tonic-gate *actionp = buf;
8100Sstevel@tonic-gate return (0);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate /* online submirror */
8140Sstevel@tonic-gate if (state & SMS_OFFLINE) {
8150Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "metaonline %s %s",
8160Sstevel@tonic-gate mirrorp->common.namep->cname, submirnamep->cname);
8170Sstevel@tonic-gate *actionp = buf;
8180Sstevel@tonic-gate return (0);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate
8210Sstevel@tonic-gate /* unknown action */
8220Sstevel@tonic-gate *actionp = dgettext(TEXT_DOMAIN, "???");
8230Sstevel@tonic-gate return (0);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate * print mirror options
8280Sstevel@tonic-gate */
8290Sstevel@tonic-gate int
meta_print_mirror_options(mm_rd_opt_t read_option,mm_wr_opt_t write_option,mm_pass_num_t pass_num,uint_t tstate,char * fname,mdsetname_t * sp,FILE * fp,md_error_t * ep)8300Sstevel@tonic-gate meta_print_mirror_options(
8310Sstevel@tonic-gate mm_rd_opt_t read_option,
8320Sstevel@tonic-gate mm_wr_opt_t write_option,
8330Sstevel@tonic-gate mm_pass_num_t pass_num,
8340Sstevel@tonic-gate uint_t tstate,
8350Sstevel@tonic-gate char *fname,
8360Sstevel@tonic-gate mdsetname_t *sp,
8370Sstevel@tonic-gate FILE *fp,
8380Sstevel@tonic-gate md_error_t *ep
8390Sstevel@tonic-gate )
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate char *p;
8420Sstevel@tonic-gate int rval = -1;
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate /* print options */
8450Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, " Pass: %u\n"),
8460Sstevel@tonic-gate pass_num) == EOF) {
8470Sstevel@tonic-gate goto out;
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate if ((p = rd_opt_to_opt(read_option)) == NULL)
8500Sstevel@tonic-gate p = dgettext(TEXT_DOMAIN, "default");
8510Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, " Read option: %s (%s)\n"),
8520Sstevel@tonic-gate rd_opt_to_name(read_option), p) == EOF) {
8530Sstevel@tonic-gate goto out;
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate if ((p = wr_opt_to_opt(write_option)) == NULL)
8560Sstevel@tonic-gate p = dgettext(TEXT_DOMAIN, "default");
8570Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, " Write option: %s (%s)\n"),
8580Sstevel@tonic-gate wr_opt_to_name(write_option), p) == EOF) {
8590Sstevel@tonic-gate goto out;
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate /* Display resync option for mirror, if MultiNode set */
8620Sstevel@tonic-gate if (meta_is_mn_set(sp, ep)) {
8630Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
8640Sstevel@tonic-gate " Resync option: %s\n"),
8650Sstevel@tonic-gate resync_opt_to_name(tstate)) == EOF) {
8660Sstevel@tonic-gate goto out;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate /* success */
8710Sstevel@tonic-gate rval = 0;
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate /* cleanup, return error */
8740Sstevel@tonic-gate out:
8750Sstevel@tonic-gate if (rval != 0)
8760Sstevel@tonic-gate (void) mdsyserror(ep, errno, fname);
8770Sstevel@tonic-gate return (rval);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate static char *
get_node_name(uint_t nid,md_error_t * ep)8810Sstevel@tonic-gate get_node_name(uint_t nid, md_error_t *ep)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate mndiskset_membershiplist_t *nl, *p;
8840Sstevel@tonic-gate int n;
8850Sstevel@tonic-gate char *node_nm;
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate /* get the known membership list */
8880Sstevel@tonic-gate if (meta_read_nodelist(&n, &nl, ep)) {
8890Sstevel@tonic-gate return (NULL);
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate /* find the matching node and return the name */
8930Sstevel@tonic-gate for (p = nl; (p != NULL); p = p->next) {
8940Sstevel@tonic-gate if (nid == p->msl_node_id) {
8950Sstevel@tonic-gate /* match found */
8960Sstevel@tonic-gate node_nm = Strdup(p->msl_node_name);
8970Sstevel@tonic-gate goto out;
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate /* match not found */
9020Sstevel@tonic-gate node_nm = Strdup(dgettext(TEXT_DOMAIN, "None"));
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate out:
9050Sstevel@tonic-gate meta_free_nodelist(nl);
9060Sstevel@tonic-gate return (node_nm);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * report mirror
9110Sstevel@tonic-gate */
9120Sstevel@tonic-gate static int
mirror_report(mdsetname_t * sp,md_mirror_t * mirrorp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)9130Sstevel@tonic-gate mirror_report(
9140Sstevel@tonic-gate mdsetname_t *sp,
9150Sstevel@tonic-gate md_mirror_t *mirrorp,
9160Sstevel@tonic-gate mdnamelist_t **nlpp,
9170Sstevel@tonic-gate char *fname,
9180Sstevel@tonic-gate FILE *fp,
9190Sstevel@tonic-gate mdprtopts_t options,
9200Sstevel@tonic-gate md_error_t *ep
9210Sstevel@tonic-gate )
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate md_status_t status = mirrorp->common.state;
9240Sstevel@tonic-gate uint_t smi;
9250Sstevel@tonic-gate char *p;
9260Sstevel@tonic-gate int rval = -1;
9270Sstevel@tonic-gate uint_t tstate = 0;
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate /*
9300Sstevel@tonic-gate * check for the -B option. If -B and the metadevice is
9310Sstevel@tonic-gate * a 64 bit device, get the dev for relocation information
9320Sstevel@tonic-gate * printout. If not a 64 bit device, just don't print this
9330Sstevel@tonic-gate * information out but you need to go down to the subdevice
9340Sstevel@tonic-gate * level and print there if appropriate.
9350Sstevel@tonic-gate */
9360Sstevel@tonic-gate if (options & PRINT_LARGEDEVICES) {
9371623Stw21770 if ((mirrorp->common.revision & MD_64BIT_META_DEV) == 0) {
9381623Stw21770 for (smi = 0; (smi < NMIRROR); ++smi) {
9391623Stw21770 md_submirror_t *mdsp =
9401623Stw21770 &mirrorp->submirrors[smi];
9411623Stw21770 mdname_t *submirnamep =
9421623Stw21770 mdsp->submirnamep;
9431623Stw21770 if (submirnamep == NULL) {
9441623Stw21770 continue;
9451623Stw21770 }
9461623Stw21770 if ((metaismeta(submirnamep)) &&
9471623Stw21770 (meta_print_name(sp, submirnamep, nlpp,
9481623Stw21770 fname, fp, options | PRINT_SUBDEVS, NULL,
9491623Stw21770 ep) != 0)) {
9501623Stw21770 return (-1);
9511623Stw21770 }
9521623Stw21770 }
9531623Stw21770 rval = 0;
9541623Stw21770 goto out;
9551623Stw21770 } else {
9561623Stw21770 if (meta_getdevs(sp, mirrorp->common.namep,
9571623Stw21770 nlpp, ep) != 0)
9581623Stw21770 goto out;
9591623Stw21770 }
9601623Stw21770 }
9611623Stw21770
9621623Stw21770 /*
9631623Stw21770 * check for the -D option. If -D and the name is
9641623Stw21770 * a descriptive name, get the dev for relocation information
9651623Stw21770 * printout. If not a descriptive name, don't print this
9661623Stw21770 * information out but you need to go down to the subdevice
9671623Stw21770 * level and print there if appropriate.
9681623Stw21770 */
9691623Stw21770 if (options & PRINT_FN) {
9701623Stw21770 if ((mirrorp->common.revision & MD_FN_META_DEV) == 0) {
9710Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
9720Sstevel@tonic-gate md_submirror_t *mdsp =
9730Sstevel@tonic-gate &mirrorp->submirrors[smi];
9740Sstevel@tonic-gate mdname_t *submirnamep =
9750Sstevel@tonic-gate mdsp->submirnamep;
9760Sstevel@tonic-gate if (submirnamep == NULL) {
9770Sstevel@tonic-gate continue;
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate if ((metaismeta(submirnamep)) &&
9800Sstevel@tonic-gate (meta_print_name(sp, submirnamep, nlpp,
9810Sstevel@tonic-gate fname, fp, options | PRINT_SUBDEVS, NULL,
9820Sstevel@tonic-gate ep) != 0)) {
9830Sstevel@tonic-gate return (-1);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate rval = 0;
9870Sstevel@tonic-gate goto out;
9880Sstevel@tonic-gate } else {
9890Sstevel@tonic-gate if (meta_getdevs(sp, mirrorp->common.namep,
9900Sstevel@tonic-gate nlpp, ep) != 0)
9910Sstevel@tonic-gate goto out;
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate /* print header */
9960Sstevel@tonic-gate if (options & PRINT_HEADER) {
9970Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Mirror\n"),
9980Sstevel@tonic-gate mirrorp->common.namep->cname) == EOF) {
9990Sstevel@tonic-gate goto out;
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate /* print submirrors, adjust status */
10040Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
10050Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
10060Sstevel@tonic-gate mdname_t *submirnamep = mdsp->submirnamep;
10070Sstevel@tonic-gate char *sm_state;
10080Sstevel@tonic-gate md_timeval32_t tv;
10090Sstevel@tonic-gate char *timep;
10100Sstevel@tonic-gate
10110Sstevel@tonic-gate /* skip unused submirrors */
10120Sstevel@tonic-gate if (submirnamep == NULL) {
10130Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
10140Sstevel@tonic-gate continue;
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate if (mdsp->state & SMS_OFFLINE)
10180Sstevel@tonic-gate status &= ~MD_UN_OPT_NOT_DONE;
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate /* print submirror */
10210Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, " Submirror %u: %s\n"),
10220Sstevel@tonic-gate smi, submirnamep->cname) == EOF) {
10230Sstevel@tonic-gate goto out;
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate /* print state */
10270Sstevel@tonic-gate if (metaismeta(mdsp->submirnamep)) {
10280Sstevel@tonic-gate if (meta_get_tstate(mdsp->submirnamep->dev, &tstate,
10290Sstevel@tonic-gate ep) != 0)
10300Sstevel@tonic-gate return (-1);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate sm_state = sm_state_to_name(mdsp, status, &tv,
10330Sstevel@tonic-gate tstate & MD_DEV_ERRORED);
10340Sstevel@tonic-gate if (options & PRINT_TIMES) {
10350Sstevel@tonic-gate timep = meta_print_time(&tv);
10360Sstevel@tonic-gate } else {
10370Sstevel@tonic-gate timep = "";
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
10400Sstevel@tonic-gate " State: %-12s %s\n"),
10410Sstevel@tonic-gate sm_state, timep) == EOF) {
10420Sstevel@tonic-gate goto out;
10430Sstevel@tonic-gate }
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate /* print resync status */
10470Sstevel@tonic-gate if (status & MD_UN_RESYNC_CANCEL) {
10480Sstevel@tonic-gate /* Resync was cancelled but is restartable */
10491623Stw21770 if (mirrorp->common.revision & MD_64BIT_META_DEV) {
10500Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
10510Sstevel@tonic-gate " Resync cancelled: %2d.%1d %% done\n"),
10520Sstevel@tonic-gate mirrorp->percent_done/10,
10530Sstevel@tonic-gate mirrorp->percent_done%10) == EOF) {
10540Sstevel@tonic-gate goto out;
10550Sstevel@tonic-gate }
10560Sstevel@tonic-gate } else {
10570Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
10580Sstevel@tonic-gate " Resync cancelled: %d %% done\n"),
10590Sstevel@tonic-gate mirrorp->percent_done) == EOF) {
10600Sstevel@tonic-gate goto out;
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate } else if (status & MD_UN_RESYNC_ACTIVE) {
10641623Stw21770 if (mirrorp->common.revision & MD_64BIT_META_DEV) {
10650Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
10660Sstevel@tonic-gate " Resync in progress: %2d.%1d %% done\n"),
10670Sstevel@tonic-gate mirrorp->percent_done/10,
10680Sstevel@tonic-gate mirrorp->percent_done%10) == EOF) {
10690Sstevel@tonic-gate goto out;
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate } else {
10720Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
10730Sstevel@tonic-gate " Resync in progress: %d %% done\n"),
10740Sstevel@tonic-gate mirrorp->percent_done) == EOF) {
10750Sstevel@tonic-gate goto out;
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate /* print options */
10810Sstevel@tonic-gate if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
10820Sstevel@tonic-gate return (-1);
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate if (meta_print_mirror_options(mirrorp->read_option,
10850Sstevel@tonic-gate mirrorp->write_option, mirrorp->pass_num,
10860Sstevel@tonic-gate tstate, fname, sp, fp, ep) != 0)
10870Sstevel@tonic-gate return (-1);
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate /* print mirror owner for multi-node metadevice */
10900Sstevel@tonic-gate if (meta_is_mn_set(sp, ep)) {
10910Sstevel@tonic-gate md_set_mmown_params_t ownpar;
10920Sstevel@tonic-gate mdname_t *mirnp = mirrorp->common.namep;
10930Sstevel@tonic-gate char *node_name;
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate (void) memset(&ownpar, 0, sizeof (ownpar));
10960Sstevel@tonic-gate ownpar.d.mnum = meta_getminor(mirnp->dev);
10970Sstevel@tonic-gate MD_SETDRIVERNAME(&ownpar, MD_MIRROR, sp->setno);
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate if (metaioctl(MD_MN_GET_MM_OWNER, &ownpar, ep,
11000Sstevel@tonic-gate "MD_MN_GET_MM_OWNER") != 0) {
11010Sstevel@tonic-gate return (-1);
11020Sstevel@tonic-gate }
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate node_name = get_node_name(ownpar.d.owner, ep);
11050Sstevel@tonic-gate if (node_name == NULL)
11060Sstevel@tonic-gate return (-1);
11070Sstevel@tonic-gate else if (fprintf(fp, dgettext(TEXT_DOMAIN, " Owner: %s\n"),
11080Sstevel@tonic-gate node_name) == EOF) {
11090Sstevel@tonic-gate Free(node_name);
11100Sstevel@tonic-gate goto out;
11110Sstevel@tonic-gate }
11120Sstevel@tonic-gate Free(node_name);
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate /* print size */
11170Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %lld blocks (%s)\n"),
11180Sstevel@tonic-gate mirrorp->common.size,
11190Sstevel@tonic-gate meta_number_to_string(mirrorp->common.size, DEV_BSIZE))
11200Sstevel@tonic-gate == EOF) {
11210Sstevel@tonic-gate goto out;
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate /* MD_DEBUG stuff */
11250Sstevel@tonic-gate if (options & PRINT_DEBUG) {
11260Sstevel@tonic-gate mdname_t *mirnp = mirrorp->common.namep;
11270Sstevel@tonic-gate mm_unit_t *mm;
11280Sstevel@tonic-gate mddb_optloc_t optloc;
11290Sstevel@tonic-gate uint_t i;
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate /* get real mirror unit */
11320Sstevel@tonic-gate if ((mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, ep))
11330Sstevel@tonic-gate == NULL) {
11340Sstevel@tonic-gate return (-1);
11350Sstevel@tonic-gate }
11360Sstevel@tonic-gate assert(mm->c.un_type == MD_METAMIRROR);
11370Sstevel@tonic-gate
11380Sstevel@tonic-gate /* print dirty regions */
11390Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
11400Sstevel@tonic-gate " Regions which are dirty: %d%% (blksize %d num %d)\n"),
11410Sstevel@tonic-gate mirrorp->percent_dirty, mm->un_rrd_blksize,
11420Sstevel@tonic-gate mm->un_rrd_num) == EOF) {
11430Sstevel@tonic-gate Free(mm);
11440Sstevel@tonic-gate goto out;
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate /* print optimized resync record locations */
11480Sstevel@tonic-gate (void) memset(&optloc, 0, sizeof (optloc));
11490Sstevel@tonic-gate optloc.recid = mm->un_rr_dirty_recid;
11500Sstevel@tonic-gate if (metaioctl(MD_DB_GETOPTLOC, &optloc, ep,
11510Sstevel@tonic-gate "MD_DB_GETOPTLOC") != 0) {
11520Sstevel@tonic-gate Free(mm);
11530Sstevel@tonic-gate return (-1);
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate for (i = 0; (i < ((sizeof optloc.li) / sizeof (optloc.li[0])));
11560Sstevel@tonic-gate ++i) {
11570Sstevel@tonic-gate mddb_config_t dbconf;
11580Sstevel@tonic-gate char *devname;
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate (void) memset(&dbconf, 0, sizeof (dbconf));
11610Sstevel@tonic-gate dbconf.c_id = optloc.li[i];
11620Sstevel@tonic-gate dbconf.c_setno = sp->setno;
11630Sstevel@tonic-gate dbconf.c_subcmd = MDDB_CONFIG_ABS;
11640Sstevel@tonic-gate /* Don't need device id information from this ioctl */
11650Sstevel@tonic-gate dbconf.c_locator.l_devid = (uint64_t)0;
11660Sstevel@tonic-gate dbconf.c_locator.l_devid_flags = 0;
11670Sstevel@tonic-gate if (metaioctl(MD_DB_ENDDEV, &dbconf, &dbconf.c_mde,
11680Sstevel@tonic-gate "MD_DB_ENDDEV") != 0) {
11690Sstevel@tonic-gate Free(mm);
11700Sstevel@tonic-gate return (mdstealerror(ep, &dbconf.c_mde));
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate if ((devname = splicename(&dbconf.c_devname))
11730Sstevel@tonic-gate == NULL) {
11740Sstevel@tonic-gate devname = Strdup(dgettext(TEXT_DOMAIN,
11750Sstevel@tonic-gate "unknown"));
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
11780Sstevel@tonic-gate " Resync record[%u]: %d (%s %d %d)\n"), i,
11790Sstevel@tonic-gate optloc.li[i], devname, dbconf.c_locator.l_blkno,
11800Sstevel@tonic-gate (dbconf.c_dbend - dbconf.c_locator.l_blkno + 1))
11810Sstevel@tonic-gate == EOF) {
11820Sstevel@tonic-gate Free(mm);
11830Sstevel@tonic-gate Free(devname);
11840Sstevel@tonic-gate goto out;
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate Free(devname);
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate Free(mm);
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate /* print submirror details */
11920Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
11930Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
11940Sstevel@tonic-gate mdname_t *submirnamep = mdsp->submirnamep;
11950Sstevel@tonic-gate char *sm_state;
11960Sstevel@tonic-gate md_timeval32_t tv;
11970Sstevel@tonic-gate char *timep;
11981623Stw21770 md_stripe_t *stripep;
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate /* skip unused submirrors */
12010Sstevel@tonic-gate if (submirnamep == NULL) {
12020Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
12030Sstevel@tonic-gate continue;
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate
12061623Stw21770 if (options & PRINT_FN) {
12071623Stw21770 /* get unit structure */
12081623Stw21770 if ((stripep = meta_get_stripe_common(sp, submirnamep,
12091623Stw21770 ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
12101623Stw21770 goto out;
12111623Stw21770
12121623Stw21770 if ((stripep->common.revision & MD_FN_META_DEV)
12131623Stw21770 == 0)
12141623Stw21770 continue;
12151623Stw21770 }
12161623Stw21770
12170Sstevel@tonic-gate /* add extra line */
12180Sstevel@tonic-gate if (fprintf(fp, "\n") == EOF)
12190Sstevel@tonic-gate goto out;
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate /* print submirror */
12220Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
12230Sstevel@tonic-gate "%s: Submirror of %s\n"),
12240Sstevel@tonic-gate submirnamep->cname,
12250Sstevel@tonic-gate mirrorp->common.namep->cname) == EOF) {
12260Sstevel@tonic-gate goto out;
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate /* print state */
12300Sstevel@tonic-gate if (metaismeta(mdsp->submirnamep)) {
12310Sstevel@tonic-gate if (meta_get_tstate(mdsp->submirnamep->dev, &tstate, ep)
12320Sstevel@tonic-gate != 0)
12330Sstevel@tonic-gate return (-1);
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate sm_state = sm_state_to_name(mdsp, status, &tv, NULL);
12360Sstevel@tonic-gate if (options & PRINT_TIMES) {
12370Sstevel@tonic-gate timep = meta_print_time(&tv);
12380Sstevel@tonic-gate } else {
12390Sstevel@tonic-gate timep = "";
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate if ((tstate & MD_DEV_ERRORED) == 0) {
12430Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN,
12440Sstevel@tonic-gate " State: %-12s %s\n"),
12450Sstevel@tonic-gate sm_state, timep) == EOF) {
12460Sstevel@tonic-gate goto out;
12470Sstevel@tonic-gate }
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate /* print what to do */
12500Sstevel@tonic-gate if (sm_state_to_action(sp, mdsp, status,
12510Sstevel@tonic-gate mirrorp, &p, ep) != 0)
12520Sstevel@tonic-gate return (-1);
12530Sstevel@tonic-gate if ((p != NULL) &&
12540Sstevel@tonic-gate (fprintf(fp, dgettext(TEXT_DOMAIN,
12550Sstevel@tonic-gate " Invoke: %s\n"), p) == EOF)) {
12560Sstevel@tonic-gate goto out;
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate /* print underlying metadevice */
12610Sstevel@tonic-gate if ((metaismeta(submirnamep)) &&
12620Sstevel@tonic-gate (meta_print_name(sp, submirnamep, nlpp, fname, fp,
12630Sstevel@tonic-gate ((options & ~PRINT_HEADER) | PRINT_SUBDEVS),
12640Sstevel@tonic-gate NULL, ep) != 0)) {
12650Sstevel@tonic-gate return (-1);
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate /* add extra line */
12700Sstevel@tonic-gate if (fprintf(fp, "\n") == EOF)
12710Sstevel@tonic-gate goto out;
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate /* success */
12740Sstevel@tonic-gate rval = 0;
12750Sstevel@tonic-gate
12760Sstevel@tonic-gate /* cleanup, return error */
12770Sstevel@tonic-gate out:
12780Sstevel@tonic-gate if (rval != 0)
12790Sstevel@tonic-gate (void) mdsyserror(ep, errno, fname);
12800Sstevel@tonic-gate return (rval);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate /*
12840Sstevel@tonic-gate * print/report mirror
12850Sstevel@tonic-gate */
12860Sstevel@tonic-gate int
meta_mirror_print(mdsetname_t * sp,mdname_t * mirnp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)12870Sstevel@tonic-gate meta_mirror_print(
12880Sstevel@tonic-gate mdsetname_t *sp,
12890Sstevel@tonic-gate mdname_t *mirnp,
12900Sstevel@tonic-gate mdnamelist_t **nlpp,
12910Sstevel@tonic-gate char *fname,
12920Sstevel@tonic-gate FILE *fp,
12930Sstevel@tonic-gate mdprtopts_t options,
12940Sstevel@tonic-gate md_error_t *ep
12950Sstevel@tonic-gate )
12960Sstevel@tonic-gate {
12970Sstevel@tonic-gate md_mirror_t *mirrorp;
12980Sstevel@tonic-gate uint_t smi;
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate /* should have same set */
13010Sstevel@tonic-gate assert(sp != NULL);
13020Sstevel@tonic-gate assert((mirnp == NULL) ||
13030Sstevel@tonic-gate (sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev))));
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate /* print all mirrors */
13060Sstevel@tonic-gate if (mirnp == NULL) {
13070Sstevel@tonic-gate mdnamelist_t *nlp = NULL;
13080Sstevel@tonic-gate mdnamelist_t *p;
13090Sstevel@tonic-gate int cnt;
13100Sstevel@tonic-gate int rval = 0;
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate /* get list */
13130Sstevel@tonic-gate if ((cnt = meta_get_mirror_names(sp, &nlp, options, ep)) < 0)
13140Sstevel@tonic-gate return (-1);
13150Sstevel@tonic-gate else if (cnt == 0)
13160Sstevel@tonic-gate return (0);
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate /* recurse */
13190Sstevel@tonic-gate for (p = nlp; (p != NULL); p = p->next) {
13200Sstevel@tonic-gate mdname_t *np = p->namep;
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate if (meta_mirror_print(sp, np, nlpp, fname, fp,
13230Sstevel@tonic-gate options, ep) != 0)
13240Sstevel@tonic-gate rval = -1;
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate /* cleanup, return success */
13280Sstevel@tonic-gate metafreenamelist(nlp);
13290Sstevel@tonic-gate return (rval);
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate /* get unit structure */
13330Sstevel@tonic-gate if ((mirrorp = meta_get_mirror_common(sp, mirnp,
13340Sstevel@tonic-gate ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
13350Sstevel@tonic-gate return (-1);
13360Sstevel@tonic-gate
13370Sstevel@tonic-gate /* check for parented */
13380Sstevel@tonic-gate if ((! (options & PRINT_SUBDEVS)) &&
13390Sstevel@tonic-gate (MD_HAS_PARENT(mirrorp->common.parent))) {
13400Sstevel@tonic-gate return (0);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate /* print appropriate detail */
13440Sstevel@tonic-gate if (options & PRINT_SHORT) {
13450Sstevel@tonic-gate /* print mirror */
13460Sstevel@tonic-gate if (mirror_print(mirrorp, fname, fp, options, ep) != 0)
13470Sstevel@tonic-gate return (-1);
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate /* print underlying metadevices */
13500Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
13510Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
13520Sstevel@tonic-gate mdname_t *submirnamep = mdsp->submirnamep;
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate /* skip unused submirrors */
13550Sstevel@tonic-gate if (submirnamep == NULL) {
13560Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
13570Sstevel@tonic-gate continue;
13580Sstevel@tonic-gate }
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate /* print submirror */
13610Sstevel@tonic-gate if (metaismeta(submirnamep)) {
13620Sstevel@tonic-gate if (meta_print_name(sp, submirnamep, nlpp,
13630Sstevel@tonic-gate fname, fp, (options | PRINT_SUBDEVS), NULL,
13640Sstevel@tonic-gate ep) != 0) {
13650Sstevel@tonic-gate return (-1);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate /* return success */
13710Sstevel@tonic-gate return (0);
13720Sstevel@tonic-gate } else {
13730Sstevel@tonic-gate return (mirror_report(sp, mirrorp, nlpp, fname, fp,
13740Sstevel@tonic-gate options, ep));
13750Sstevel@tonic-gate }
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate /*
13790Sstevel@tonic-gate * online submirror
13800Sstevel@tonic-gate */
13810Sstevel@tonic-gate int
meta_mirror_online(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)13820Sstevel@tonic-gate meta_mirror_online(
13830Sstevel@tonic-gate mdsetname_t *sp,
13840Sstevel@tonic-gate mdname_t *mirnp,
13850Sstevel@tonic-gate mdname_t *submirnp,
13860Sstevel@tonic-gate mdcmdopts_t options,
13870Sstevel@tonic-gate md_error_t *ep
13880Sstevel@tonic-gate )
13890Sstevel@tonic-gate {
13900Sstevel@tonic-gate md_i_off_on_t mio;
13910Sstevel@tonic-gate md_mirror_t *mirrorp;
13920Sstevel@tonic-gate md_set_desc *sd;
13930Sstevel@tonic-gate uint_t tstate;
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate /* should have same set */
13960Sstevel@tonic-gate assert(sp != NULL);
13970Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate /* check name */
14000Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
14010Sstevel@tonic-gate return (-1);
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
14040Sstevel@tonic-gate return (-1);
14050Sstevel@tonic-gate
14060Sstevel@tonic-gate /* Only valid for mirror without ABR set */
14070Sstevel@tonic-gate if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
14080Sstevel@tonic-gate return (-1);
14090Sstevel@tonic-gate if (tstate & MD_ABR_CAP) {
14100Sstevel@tonic-gate (void) mderror(ep, MDE_ABR_SET, NULL);
14110Sstevel@tonic-gate return (-1);
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate * In a MN set, the master always executes the online command first.
14160Sstevel@tonic-gate * Before the master executes the IOC_ONLINE ioctl,
14170Sstevel@tonic-gate * the master sends a message to all nodes to suspend writes to
14180Sstevel@tonic-gate * this mirror. Then the master executes the IOC_ONLINE ioctl
14190Sstevel@tonic-gate * which resumes writes to this mirror from the master node.
14200Sstevel@tonic-gate * As each slave executes the online command, each slave will
14210Sstevel@tonic-gate * call the IOC_ONLINE ioctl which will resume writes to this mirror
14220Sstevel@tonic-gate * from that slave node.
14230Sstevel@tonic-gate */
14240Sstevel@tonic-gate if (! metaislocalset(sp)) {
14250Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL)
14260Sstevel@tonic-gate return (-1);
14270Sstevel@tonic-gate if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
14280Sstevel@tonic-gate if (meta_mn_send_suspend_writes(
14290Sstevel@tonic-gate meta_getminor(mirnp->dev), ep) != 0)
14300Sstevel@tonic-gate return (-1);
14310Sstevel@tonic-gate }
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate /* online submirror */
14340Sstevel@tonic-gate (void) memset(&mio, 0, sizeof (mio));
14350Sstevel@tonic-gate mio.mnum = meta_getminor(mirnp->dev);
14360Sstevel@tonic-gate MD_SETDRIVERNAME(&mio, MD_MIRROR, sp->setno);
14370Sstevel@tonic-gate mio.submirror = submirnp->dev;
14380Sstevel@tonic-gate if (metaioctl(MD_IOCONLINE, &mio, &mio.mde, NULL) != 0)
14390Sstevel@tonic-gate return (mdstealerror(ep, &mio.mde));
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate /* clear cache */
14420Sstevel@tonic-gate meta_invalidate_name(mirnp);
14430Sstevel@tonic-gate meta_invalidate_name(submirnp);
14440Sstevel@tonic-gate
14450Sstevel@tonic-gate /* let em know */
14460Sstevel@tonic-gate if (options & MDCMD_PRINT) {
14470Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
14480Sstevel@tonic-gate "%s: submirror %s is onlined\n"),
14490Sstevel@tonic-gate mirnp->cname, submirnp->cname);
14500Sstevel@tonic-gate (void) fflush(stdout);
14510Sstevel@tonic-gate }
14520Sstevel@tonic-gate
14530Sstevel@tonic-gate /* return success */
14540Sstevel@tonic-gate return (0);
14550Sstevel@tonic-gate }
14560Sstevel@tonic-gate
14570Sstevel@tonic-gate /*
14580Sstevel@tonic-gate * offline submirror
14590Sstevel@tonic-gate */
14600Sstevel@tonic-gate int
meta_mirror_offline(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)14610Sstevel@tonic-gate meta_mirror_offline(
14620Sstevel@tonic-gate mdsetname_t *sp,
14630Sstevel@tonic-gate mdname_t *mirnp,
14640Sstevel@tonic-gate mdname_t *submirnp,
14650Sstevel@tonic-gate mdcmdopts_t options,
14660Sstevel@tonic-gate md_error_t *ep
14670Sstevel@tonic-gate )
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate int force = ((options & MDCMD_FORCE) ? 1 : 0);
14700Sstevel@tonic-gate md_i_off_on_t mio;
14710Sstevel@tonic-gate md_mirror_t *mirrorp;
14720Sstevel@tonic-gate md_set_desc *sd;
14730Sstevel@tonic-gate uint_t tstate;
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate /* should have same set */
14760Sstevel@tonic-gate assert(sp != NULL);
14770Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /* check name */
14800Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
14810Sstevel@tonic-gate return (-1);
14820Sstevel@tonic-gate
14830Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
14840Sstevel@tonic-gate return (-1);
14850Sstevel@tonic-gate
14860Sstevel@tonic-gate /* Only valid for mirror without ABR set */
14870Sstevel@tonic-gate if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
14880Sstevel@tonic-gate return (-1);
14890Sstevel@tonic-gate if (tstate & MD_ABR_CAP) {
14900Sstevel@tonic-gate (void) mderror(ep, MDE_ABR_SET, NULL);
14910Sstevel@tonic-gate return (-1);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate /*
14950Sstevel@tonic-gate * In a MN set, the master always executes the offline command first.
14960Sstevel@tonic-gate * Before the master executes the IOC_OFFLINE ioctl,
14970Sstevel@tonic-gate * the master sends a message to all nodes to suspend writes to
14980Sstevel@tonic-gate * this mirror. Then the master executes the IOC_OFFLINE ioctl
14990Sstevel@tonic-gate * which resumes writes to this mirror from the master node.
15000Sstevel@tonic-gate * As each slave executes the offline command, each slave will
15010Sstevel@tonic-gate * call the IOC_OFFLINE ioctl which will resume writes to this mirror
15020Sstevel@tonic-gate * from that slave node.
15030Sstevel@tonic-gate */
15040Sstevel@tonic-gate if (! metaislocalset(sp)) {
15050Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL)
15060Sstevel@tonic-gate return (-1);
15070Sstevel@tonic-gate if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
15080Sstevel@tonic-gate if (meta_mn_send_suspend_writes(
15090Sstevel@tonic-gate meta_getminor(mirnp->dev), ep) != 0)
15100Sstevel@tonic-gate return (-1);
15110Sstevel@tonic-gate }
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate /* offline submirror */
15140Sstevel@tonic-gate (void) memset(&mio, 0, sizeof (mio));
15150Sstevel@tonic-gate mio.mnum = meta_getminor(mirnp->dev);
15160Sstevel@tonic-gate MD_SETDRIVERNAME(&mio, MD_MIRROR, sp->setno);
15170Sstevel@tonic-gate mio.submirror = submirnp->dev;
15180Sstevel@tonic-gate mio.force_offline = force;
15190Sstevel@tonic-gate if (metaioctl(MD_IOCOFFLINE, &mio, &mio.mde, NULL) != 0)
15200Sstevel@tonic-gate return (mdstealerror(ep, &mio.mde));
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate /* clear cache */
15230Sstevel@tonic-gate meta_invalidate_name(mirnp);
15240Sstevel@tonic-gate meta_invalidate_name(submirnp);
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate /* let em know */
15270Sstevel@tonic-gate if (options & MDCMD_PRINT) {
15280Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
15290Sstevel@tonic-gate "%s: submirror %s is offlined\n"),
15300Sstevel@tonic-gate mirnp->cname, submirnp->cname);
15310Sstevel@tonic-gate (void) fflush(stdout);
15320Sstevel@tonic-gate }
15330Sstevel@tonic-gate
15340Sstevel@tonic-gate /* return success */
15350Sstevel@tonic-gate return (0);
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate /*
15390Sstevel@tonic-gate * attach submirror to mirror
15400Sstevel@tonic-gate * we actually never have to worry about crossing a thresh hold here.
15410Sstevel@tonic-gate * 2 cases 1) attach and the only way the mirror can be 64 bit is if
15420Sstevel@tonic-gate * one of the submirrors already is. 2) grow and the only way the mirror
15430Sstevel@tonic-gate * is 64 bit is if one of the submirror's already is.
15440Sstevel@tonic-gate */
15450Sstevel@tonic-gate int
meta_mirror_attach(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)15460Sstevel@tonic-gate meta_mirror_attach(
15470Sstevel@tonic-gate mdsetname_t *sp,
15480Sstevel@tonic-gate mdname_t *mirnp,
15490Sstevel@tonic-gate mdname_t *submirnp,
15500Sstevel@tonic-gate mdcmdopts_t options,
15510Sstevel@tonic-gate md_error_t *ep
15520Sstevel@tonic-gate )
15530Sstevel@tonic-gate {
15540Sstevel@tonic-gate md_att_struct_t att;
15550Sstevel@tonic-gate md_set_desc *sd;
15560Sstevel@tonic-gate
15570Sstevel@tonic-gate /* should have same set */
15580Sstevel@tonic-gate assert(sp != NULL);
15590Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate /* check name */
15620Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
15630Sstevel@tonic-gate return (-1);
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate /* just grow */
15660Sstevel@tonic-gate if (submirnp == NULL) {
15670Sstevel@tonic-gate return (meta_concat_generic(sp, mirnp, NULL, ep));
15680Sstevel@tonic-gate }
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate /* check submirror */
15710Sstevel@tonic-gate if (meta_check_submirror(sp, submirnp, mirnp, 0, ep) != 0)
15720Sstevel@tonic-gate return (-1);
15730Sstevel@tonic-gate
15740Sstevel@tonic-gate /* In dryrun mode (DOIT not set) we must not alter the mddb */
15750Sstevel@tonic-gate if (options & MDCMD_DOIT) {
15760Sstevel@tonic-gate /* store name in namespace */
15770Sstevel@tonic-gate if (add_key_name(sp, submirnp, NULL, ep) != 0)
15780Sstevel@tonic-gate return (-1);
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate
15810Sstevel@tonic-gate /*
15820Sstevel@tonic-gate * In a MN set, the master always executes the attach command first.
15830Sstevel@tonic-gate * Before the master executes the IOC_ATTACH ioctl, in non-DRYRUN mode
15840Sstevel@tonic-gate * the master sends a message to all nodes to suspend writes to
15850Sstevel@tonic-gate * this mirror. Then the master executes the IOC_ATTACH ioctl
15860Sstevel@tonic-gate * which resumes writes to this mirror from the master node.
15870Sstevel@tonic-gate * As each slave executes the attach command, each slave will
15880Sstevel@tonic-gate * call the IOC_ATTACH ioctl which will resume writes to this mirror
15890Sstevel@tonic-gate * from that slave node.
15900Sstevel@tonic-gate */
15910Sstevel@tonic-gate if (! metaislocalset(sp)) {
15920Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL)
15930Sstevel@tonic-gate return (-1);
15940Sstevel@tonic-gate if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
15950Sstevel@tonic-gate sd->sd_mn_am_i_master)
15960Sstevel@tonic-gate if (meta_mn_send_suspend_writes(
15970Sstevel@tonic-gate meta_getminor(mirnp->dev), ep) != 0)
15980Sstevel@tonic-gate return (-1);
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate /* attach submirror */
16020Sstevel@tonic-gate (void) memset(&att, 0, sizeof (att));
16030Sstevel@tonic-gate att.mnum = meta_getminor(mirnp->dev);
16040Sstevel@tonic-gate MD_SETDRIVERNAME(&att, MD_MIRROR, sp->setno);
16050Sstevel@tonic-gate att.submirror = submirnp->dev;
16060Sstevel@tonic-gate att.key = submirnp->key;
16070Sstevel@tonic-gate /* if the comamnd was issued with -n option, use dryrun mode */
16080Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
16090Sstevel@tonic-gate att.options = MDIOCTL_DRYRUN;
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate if (metaioctl(MD_IOCATTACH, &att, &att.mde, NULL) != 0) {
16120Sstevel@tonic-gate /* In dryrun mode (DOIT not set) we must not alter the mddb */
16130Sstevel@tonic-gate if (options & MDCMD_DOIT) {
16140Sstevel@tonic-gate (void) del_key_name(sp, submirnp, ep);
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate return (mdstealerror(ep, &att.mde));
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate /* In dryrun mode (DOIT not set) we must not alter the mddb */
16200Sstevel@tonic-gate if (options & MDCMD_DOIT) {
16210Sstevel@tonic-gate /* clear cache */
16220Sstevel@tonic-gate meta_invalidate_name(mirnp);
16230Sstevel@tonic-gate meta_invalidate_name(submirnp);
16240Sstevel@tonic-gate }
16250Sstevel@tonic-gate
16260Sstevel@tonic-gate /* let em know */
16270Sstevel@tonic-gate if (options & MDCMD_PRINT) {
16280Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
16290Sstevel@tonic-gate "%s: submirror %s %s\n"), mirnp->cname, submirnp->cname,
16300Sstevel@tonic-gate (options & MDCMD_DOIT) ? "is attached" : "would attach");
16310Sstevel@tonic-gate (void) fflush(stdout);
16320Sstevel@tonic-gate }
16330Sstevel@tonic-gate
16340Sstevel@tonic-gate /* return success */
16350Sstevel@tonic-gate return (0);
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate
16380Sstevel@tonic-gate /*
16390Sstevel@tonic-gate * detach submirror
16400Sstevel@tonic-gate */
16410Sstevel@tonic-gate int
meta_mirror_detach(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)16420Sstevel@tonic-gate meta_mirror_detach(
16430Sstevel@tonic-gate mdsetname_t *sp,
16440Sstevel@tonic-gate mdname_t *mirnp,
16450Sstevel@tonic-gate mdname_t *submirnp,
16460Sstevel@tonic-gate mdcmdopts_t options,
16470Sstevel@tonic-gate md_error_t *ep
16480Sstevel@tonic-gate )
16490Sstevel@tonic-gate {
16500Sstevel@tonic-gate int force = ((options & MDCMD_FORCE) ? 1 : 0);
16510Sstevel@tonic-gate md_detach_params_t detach;
16520Sstevel@tonic-gate md_set_desc *sd;
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate /* should have same set */
16550Sstevel@tonic-gate assert(sp != NULL);
16560Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate /* check name */
16590Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
16600Sstevel@tonic-gate return (-1);
16610Sstevel@tonic-gate
16620Sstevel@tonic-gate /*
16630Sstevel@tonic-gate * In a MN set, the master always executes the detach command first.
16640Sstevel@tonic-gate * Before the master executes the IOC_DETACH ioctl,
16650Sstevel@tonic-gate * the master sends a message to all nodes to suspend writes to
16660Sstevel@tonic-gate * this mirror. Then the master executes the IOC_DETACH ioctl
16670Sstevel@tonic-gate * which resumes writes to this mirror from the master node.
16680Sstevel@tonic-gate * As each slave executes the detach command, each slave will
16690Sstevel@tonic-gate * call the IOC_DETACH ioctl which will resume writes to this mirror
16700Sstevel@tonic-gate * from that slave node.
16710Sstevel@tonic-gate */
16720Sstevel@tonic-gate if (! metaislocalset(sp)) {
16730Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL)
16740Sstevel@tonic-gate return (-1);
16750Sstevel@tonic-gate if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
16760Sstevel@tonic-gate if (meta_mn_send_suspend_writes(
16770Sstevel@tonic-gate meta_getminor(mirnp->dev), ep) != 0)
16780Sstevel@tonic-gate return (-1);
16790Sstevel@tonic-gate }
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate /* detach submirror */
16820Sstevel@tonic-gate (void) memset(&detach, 0, sizeof (detach));
16830Sstevel@tonic-gate detach.mnum = meta_getminor(mirnp->dev);
16840Sstevel@tonic-gate MD_SETDRIVERNAME(&detach, MD_MIRROR, sp->setno);
16850Sstevel@tonic-gate detach.submirror = submirnp->dev;
16860Sstevel@tonic-gate detach.force_detach = force;
16870Sstevel@tonic-gate if (metaioctl(MD_IOCDETACH, &detach, &detach.mde, NULL) != 0)
16880Sstevel@tonic-gate return (mdstealerror(ep, &detach.mde));
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate /* clear cache */
16910Sstevel@tonic-gate meta_invalidate_name(mirnp);
16920Sstevel@tonic-gate meta_invalidate_name(submirnp);
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /* let em know */
16950Sstevel@tonic-gate if (options & MDCMD_PRINT) {
16960Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
16970Sstevel@tonic-gate "%s: submirror %s is detached\n"),
16980Sstevel@tonic-gate mirnp->cname, submirnp->cname);
16990Sstevel@tonic-gate (void) fflush(stdout);
17000Sstevel@tonic-gate }
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate /* return success */
17030Sstevel@tonic-gate return (0);
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate /*
17070Sstevel@tonic-gate * get mirror parameters
17080Sstevel@tonic-gate */
17090Sstevel@tonic-gate int
meta_mirror_get_params(mdsetname_t * sp,mdname_t * mirnp,mm_params_t * paramsp,md_error_t * ep)17100Sstevel@tonic-gate meta_mirror_get_params(
17110Sstevel@tonic-gate mdsetname_t *sp,
17120Sstevel@tonic-gate mdname_t *mirnp,
17130Sstevel@tonic-gate mm_params_t *paramsp,
17140Sstevel@tonic-gate md_error_t *ep
17150Sstevel@tonic-gate )
17160Sstevel@tonic-gate {
17170Sstevel@tonic-gate md_mirror_t *mirrorp;
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate /* should have a set */
17200Sstevel@tonic-gate assert(sp != NULL);
17210Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
17220Sstevel@tonic-gate
17230Sstevel@tonic-gate /* check name */
17240Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
17250Sstevel@tonic-gate return (-1);
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate /* get unit */
17280Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
17290Sstevel@tonic-gate return (-1);
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate /* return parameters */
17320Sstevel@tonic-gate (void) memset(paramsp, 0, sizeof (*paramsp));
17330Sstevel@tonic-gate paramsp->read_option = mirrorp->read_option;
17340Sstevel@tonic-gate paramsp->write_option = mirrorp->write_option;
17350Sstevel@tonic-gate paramsp->pass_num = mirrorp->pass_num;
17360Sstevel@tonic-gate return (0);
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate
17390Sstevel@tonic-gate /*
17400Sstevel@tonic-gate * set mirror parameters
17410Sstevel@tonic-gate */
17420Sstevel@tonic-gate int
meta_mirror_set_params(mdsetname_t * sp,mdname_t * mirnp,mm_params_t * paramsp,md_error_t * ep)17430Sstevel@tonic-gate meta_mirror_set_params(
17440Sstevel@tonic-gate mdsetname_t *sp,
17450Sstevel@tonic-gate mdname_t *mirnp,
17460Sstevel@tonic-gate mm_params_t *paramsp,
17470Sstevel@tonic-gate md_error_t *ep
17480Sstevel@tonic-gate )
17490Sstevel@tonic-gate {
17500Sstevel@tonic-gate md_mirror_params_t mmp;
17510Sstevel@tonic-gate
17520Sstevel@tonic-gate /* should have a set */
17530Sstevel@tonic-gate assert(sp != NULL);
17540Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate /* check name */
17570Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
17580Sstevel@tonic-gate return (-1);
17590Sstevel@tonic-gate
17600Sstevel@tonic-gate /* set parameters */
17610Sstevel@tonic-gate (void) memset(&mmp, 0, sizeof (mmp));
17620Sstevel@tonic-gate MD_SETDRIVERNAME(&mmp, MD_MIRROR, sp->setno);
17630Sstevel@tonic-gate mmp.mnum = meta_getminor(mirnp->dev);
17640Sstevel@tonic-gate mmp.params = *paramsp;
17650Sstevel@tonic-gate if (metaioctl(MD_IOCCHANGE, &mmp, &mmp.mde, mirnp->cname) != 0)
17660Sstevel@tonic-gate return (mdstealerror(ep, &mmp.mde));
17670Sstevel@tonic-gate
17680Sstevel@tonic-gate /* clear cache */
17690Sstevel@tonic-gate meta_invalidate_name(mirnp);
17700Sstevel@tonic-gate
17710Sstevel@tonic-gate /* return success */
17720Sstevel@tonic-gate return (0);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate /*
17760Sstevel@tonic-gate * invalidate submirror names
17770Sstevel@tonic-gate */
17780Sstevel@tonic-gate static int
invalidate_submirrors(mdsetname_t * sp,mdname_t * mirnp,md_error_t * ep)17790Sstevel@tonic-gate invalidate_submirrors(
17800Sstevel@tonic-gate mdsetname_t *sp,
17810Sstevel@tonic-gate mdname_t *mirnp,
17820Sstevel@tonic-gate md_error_t *ep
17830Sstevel@tonic-gate )
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate md_mirror_t *mirrorp;
17860Sstevel@tonic-gate uint_t smi;
17870Sstevel@tonic-gate
17880Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
17890Sstevel@tonic-gate return (-1);
17900Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
17910Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
17920Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
17930Sstevel@tonic-gate
17940Sstevel@tonic-gate if (submirnp == NULL) {
17950Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
17960Sstevel@tonic-gate continue;
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate meta_invalidate_name(submirnp);
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate return (0);
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate /*
18040Sstevel@tonic-gate * replace mirror component
18050Sstevel@tonic-gate */
18060Sstevel@tonic-gate int
meta_mirror_replace(mdsetname_t * sp,mdname_t * mirnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)18070Sstevel@tonic-gate meta_mirror_replace(
18080Sstevel@tonic-gate mdsetname_t *sp,
18090Sstevel@tonic-gate mdname_t *mirnp,
18100Sstevel@tonic-gate mdname_t *oldnp,
18110Sstevel@tonic-gate mdname_t *newnp,
18120Sstevel@tonic-gate mdcmdopts_t options,
18130Sstevel@tonic-gate md_error_t *ep
18140Sstevel@tonic-gate )
18150Sstevel@tonic-gate {
18160Sstevel@tonic-gate md_mirror_t *mirrorp;
18170Sstevel@tonic-gate uint_t smi;
18180Sstevel@tonic-gate replace_params_t params;
18190Sstevel@tonic-gate diskaddr_t size, label, start_blk;
18200Sstevel@tonic-gate md_dev64_t old_dev, new_dev;
18210Sstevel@tonic-gate diskaddr_t new_start_blk, new_end_blk;
18220Sstevel@tonic-gate int rebind;
18230Sstevel@tonic-gate md_set_desc *sd;
18240Sstevel@tonic-gate char *new_devidp = NULL;
18250Sstevel@tonic-gate int ret;
18260Sstevel@tonic-gate md_error_t xep = mdnullerror;
18270Sstevel@tonic-gate
18280Sstevel@tonic-gate /* should have same set */
18290Sstevel@tonic-gate assert(sp != NULL);
18300Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate /* check name */
18330Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
18340Sstevel@tonic-gate return (-1);
18350Sstevel@tonic-gate
18360Sstevel@tonic-gate /* save new binding incase this is a rebind where oldnp==newnp */
18370Sstevel@tonic-gate new_dev = newnp->dev;
18380Sstevel@tonic-gate new_start_blk = newnp->start_blk;
18390Sstevel@tonic-gate new_end_blk = newnp->end_blk;
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate /* invalidate, then get the mirror (fill in oldnp from metadb) */
18420Sstevel@tonic-gate meta_invalidate_name(mirnp);
18430Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
18440Sstevel@tonic-gate return (-1);
18450Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
18460Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
18470Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate if (submirnp == NULL) {
18500Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
18510Sstevel@tonic-gate continue;
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate if (! metaismeta(submirnp))
18550Sstevel@tonic-gate continue;
18560Sstevel@tonic-gate
18570Sstevel@tonic-gate meta_invalidate_name(submirnp);
18580Sstevel@tonic-gate if (meta_get_unit(sp, submirnp, ep) == NULL)
18590Sstevel@tonic-gate return (-1);
18600Sstevel@tonic-gate }
18610Sstevel@tonic-gate
18620Sstevel@tonic-gate /* the old device binding is now established */
18630Sstevel@tonic-gate if ((old_dev = oldnp->dev) == NODEV64)
18640Sstevel@tonic-gate return (mdsyserror(ep, ENODEV, oldnp->cname));
18650Sstevel@tonic-gate
18660Sstevel@tonic-gate /*
18670Sstevel@tonic-gate * check for the case where oldnp and newnp indicate the same
18680Sstevel@tonic-gate * device, but the dev_t of the device has changed between old
18690Sstevel@tonic-gate * and new. This is called a rebind. On entry the dev_t
18700Sstevel@tonic-gate * represents the new device binding determined from the
18710Sstevel@tonic-gate * filesystem (meta_getdev). After calling meta_get_unit
18720Sstevel@tonic-gate * oldnp (and maybe newnp if this is a rebind) is updated based
18730Sstevel@tonic-gate * to the old binding from the metadb (done by metakeyname).
18740Sstevel@tonic-gate */
18750Sstevel@tonic-gate if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
18760Sstevel@tonic-gate (old_dev != new_dev)) {
18770Sstevel@tonic-gate rebind = 1;
18780Sstevel@tonic-gate } else {
18790Sstevel@tonic-gate rebind = 0;
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate if (rebind) {
18820Sstevel@tonic-gate newnp->dev = new_dev;
18830Sstevel@tonic-gate newnp->start_blk = new_start_blk;
18840Sstevel@tonic-gate newnp->end_blk = new_end_blk;
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate /*
18880Sstevel@tonic-gate * Save a copy of the devid associated with the new disk, the reason
18890Sstevel@tonic-gate * is that if we are rebinding then the call to meta_check_component()
18900Sstevel@tonic-gate * will cause the devid of the disk to be overwritten with what is in
18910Sstevel@tonic-gate * the replica namespace. The function that actually overwrites the
18920Sstevel@tonic-gate * devid is dr2drivedesc().
18930Sstevel@tonic-gate */
18940Sstevel@tonic-gate if (newnp->drivenamep->devid != NULL)
18950Sstevel@tonic-gate new_devidp = Strdup(newnp->drivenamep->devid);
18960Sstevel@tonic-gate
18970Sstevel@tonic-gate /* if it's a multi-node diskset clear new_devidp */
18980Sstevel@tonic-gate if (!metaislocalset(sp)) {
18990Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL)
19000Sstevel@tonic-gate return (-1);
19010Sstevel@tonic-gate if (MD_MNSET_DESC(sd))
19020Sstevel@tonic-gate new_devidp = NULL;
19030Sstevel@tonic-gate }
19040Sstevel@tonic-gate
19050Sstevel@tonic-gate /* check it out (dup on rebind is ok) */
19060Sstevel@tonic-gate if (meta_check_component(sp, newnp, 0, ep) != 0) {
19070Sstevel@tonic-gate if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
19080Sstevel@tonic-gate Free(new_devidp);
19090Sstevel@tonic-gate return (-1);
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate mdclrerror(ep);
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
19140Sstevel@tonic-gate Free(new_devidp);
19150Sstevel@tonic-gate return (-1);
19160Sstevel@tonic-gate }
19170Sstevel@tonic-gate if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
19180Sstevel@tonic-gate Free(new_devidp);
19190Sstevel@tonic-gate return (-1);
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
19220Sstevel@tonic-gate Free(new_devidp);
19230Sstevel@tonic-gate return (-1);
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate if (start_blk >= size) {
19260Sstevel@tonic-gate (void) mdsyserror(ep, ENOSPC, newnp->cname);
19270Sstevel@tonic-gate Free(new_devidp);
19280Sstevel@tonic-gate return (-1);
19290Sstevel@tonic-gate }
19300Sstevel@tonic-gate
19310Sstevel@tonic-gate /*
19320Sstevel@tonic-gate * Copy back the saved devid.
19330Sstevel@tonic-gate */
19340Sstevel@tonic-gate Free(newnp->drivenamep->devid);
19350Sstevel@tonic-gate if (new_devidp != NULL) {
19360Sstevel@tonic-gate newnp->drivenamep->devid = Strdup(new_devidp);
19370Sstevel@tonic-gate Free(new_devidp);
19380Sstevel@tonic-gate }
19390Sstevel@tonic-gate
19400Sstevel@tonic-gate /* store name in namespace, allocate new key */
19410Sstevel@tonic-gate if (add_key_name(sp, newnp, NULL, ep) != 0)
19420Sstevel@tonic-gate return (-1);
19430Sstevel@tonic-gate
19440Sstevel@tonic-gate /*
19450Sstevel@tonic-gate * In a MN set, the master always executes the replace command first.
19460Sstevel@tonic-gate * Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
19470Sstevel@tonic-gate * the master sends a message to all nodes to suspend writes to
19480Sstevel@tonic-gate * this mirror. Then the master executes the IOC_REPLACE ioctl
19490Sstevel@tonic-gate * which resumes writes to this mirror from the master node.
19500Sstevel@tonic-gate * As each slave executes the replace command, each slave will
19510Sstevel@tonic-gate * call the IOC_REPLACE ioctl which will resume writes to this mirror
19520Sstevel@tonic-gate * from that slave node.
19530Sstevel@tonic-gate */
19540Sstevel@tonic-gate if (! metaislocalset(sp)) {
19550Sstevel@tonic-gate if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
19560Sstevel@tonic-gate sd->sd_mn_am_i_master)
19570Sstevel@tonic-gate if (meta_mn_send_suspend_writes(
19580Sstevel@tonic-gate meta_getminor(mirnp->dev), ep) != 0)
19590Sstevel@tonic-gate return (-1);
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate
19620Sstevel@tonic-gate if (rebind && !metaislocalset(sp)) {
19630Sstevel@tonic-gate /*
19640Sstevel@tonic-gate * We are 'rebind'ing a disk that is in a diskset so as well
19650Sstevel@tonic-gate * as updating the diskset's namespace the local set needs
19660Sstevel@tonic-gate * to be updated because it also contains a reference to
19670Sstevel@tonic-gate * the disk in question.
19680Sstevel@tonic-gate */
19690Sstevel@tonic-gate ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
19700Sstevel@tonic-gate newnp->cname, ep);
19710Sstevel@tonic-gate
19720Sstevel@tonic-gate if (ret != METADEVADM_SUCCESS) {
19730Sstevel@tonic-gate (void) del_key_name(sp, newnp, &xep);
19740Sstevel@tonic-gate return (-1);
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate }
19770Sstevel@tonic-gate
19780Sstevel@tonic-gate /* replace component */
19790Sstevel@tonic-gate (void) memset(¶ms, 0, sizeof (params));
19800Sstevel@tonic-gate params.mnum = meta_getminor(mirnp->dev);
19810Sstevel@tonic-gate MD_SETDRIVERNAME(¶ms, MD_MIRROR, sp->setno);
19820Sstevel@tonic-gate params.cmd = REPLACE_COMP;
19830Sstevel@tonic-gate params.old_dev = old_dev;
19840Sstevel@tonic-gate params.new_dev = new_dev;
19850Sstevel@tonic-gate params.start_blk = start_blk;
19860Sstevel@tonic-gate params.has_label = ((label > 0) ? 1 : 0);
19870Sstevel@tonic-gate params.number_blks = size;
19880Sstevel@tonic-gate params.new_key = newnp->key;
19890Sstevel@tonic-gate /* Is this just a dryrun ? */
19900Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
19910Sstevel@tonic-gate params.options |= MDIOCTL_DRYRUN;
19920Sstevel@tonic-gate }
19930Sstevel@tonic-gate if (metaioctl(MD_IOCREPLACE, ¶ms, ¶ms.mde, NULL) != 0) {
19940Sstevel@tonic-gate (void) del_key_name(sp, newnp, ep);
19950Sstevel@tonic-gate return (mdstealerror(ep, ¶ms.mde));
19960Sstevel@tonic-gate }
19970Sstevel@tonic-gate
19980Sstevel@tonic-gate /* clear cache */
19990Sstevel@tonic-gate meta_invalidate_name(oldnp);
20000Sstevel@tonic-gate meta_invalidate_name(newnp);
20010Sstevel@tonic-gate if (invalidate_submirrors(sp, mirnp, ep) != 0) {
20020Sstevel@tonic-gate meta_invalidate_name(mirnp);
20030Sstevel@tonic-gate return (-1);
20040Sstevel@tonic-gate }
20050Sstevel@tonic-gate meta_invalidate_name(mirnp);
20060Sstevel@tonic-gate
20070Sstevel@tonic-gate /* let em know */
20080Sstevel@tonic-gate if (options & MDCMD_PRINT) {
20090Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
20100Sstevel@tonic-gate "%s: device %s is replaced with %s\n"),
20110Sstevel@tonic-gate mirnp->cname, oldnp->cname, newnp->cname);
20120Sstevel@tonic-gate (void) fflush(stdout);
20130Sstevel@tonic-gate }
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate /* return success */
20160Sstevel@tonic-gate return (0);
20170Sstevel@tonic-gate }
20180Sstevel@tonic-gate
20190Sstevel@tonic-gate /*
20200Sstevel@tonic-gate * enable mirror component
20210Sstevel@tonic-gate */
20220Sstevel@tonic-gate int
meta_mirror_enable(mdsetname_t * sp,mdname_t * mirnp,mdname_t * compnp,mdcmdopts_t options,md_error_t * ep)20230Sstevel@tonic-gate meta_mirror_enable(
20240Sstevel@tonic-gate mdsetname_t *sp,
20250Sstevel@tonic-gate mdname_t *mirnp,
20260Sstevel@tonic-gate mdname_t *compnp,
20270Sstevel@tonic-gate mdcmdopts_t options,
20280Sstevel@tonic-gate md_error_t *ep
20290Sstevel@tonic-gate )
20300Sstevel@tonic-gate {
20310Sstevel@tonic-gate md_mirror_t *mirrorp;
20320Sstevel@tonic-gate uint_t smi;
20330Sstevel@tonic-gate replace_params_t params;
20340Sstevel@tonic-gate diskaddr_t size, label, start_blk;
20350Sstevel@tonic-gate md_dev64_t fs_dev;
20360Sstevel@tonic-gate md_set_desc *sd;
20370Sstevel@tonic-gate int ret;
20380Sstevel@tonic-gate
20390Sstevel@tonic-gate /* should have same set */
20400Sstevel@tonic-gate assert(sp != NULL);
20410Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
20420Sstevel@tonic-gate
20430Sstevel@tonic-gate /* check name */
20440Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
20450Sstevel@tonic-gate return (-1);
20460Sstevel@tonic-gate
20470Sstevel@tonic-gate /* get the file_system dev binding */
20480Sstevel@tonic-gate if (meta_getdev(sp, compnp, ep) != 0)
20490Sstevel@tonic-gate return (-1);
20500Sstevel@tonic-gate fs_dev = compnp->dev;
20510Sstevel@tonic-gate
20520Sstevel@tonic-gate /* get the mirror unit (fill in compnp->dev with metadb version) */
20530Sstevel@tonic-gate meta_invalidate_name(mirnp);
20540Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
20550Sstevel@tonic-gate return (-1);
20560Sstevel@tonic-gate
20570Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
20580Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
20590Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
20600Sstevel@tonic-gate
20610Sstevel@tonic-gate if (submirnp == NULL) {
20620Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
20630Sstevel@tonic-gate continue;
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate if (! metaismeta(submirnp))
20670Sstevel@tonic-gate continue;
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate meta_invalidate_name(submirnp);
20700Sstevel@tonic-gate if (meta_get_unit(sp, submirnp, ep) == NULL)
20710Sstevel@tonic-gate return (-1);
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate /* the metadb device binding is now established */
20750Sstevel@tonic-gate if (compnp->dev == NODEV64)
20760Sstevel@tonic-gate return (mdsyserror(ep, ENODEV, compnp->cname));
20770Sstevel@tonic-gate
20780Sstevel@tonic-gate /*
20790Sstevel@tonic-gate * check for the case where the dev_t has changed between the
20800Sstevel@tonic-gate * filesystem and the metadb. This is called a rebind, and
20810Sstevel@tonic-gate * is handled by meta_mirror_replace.
20820Sstevel@tonic-gate */
20830Sstevel@tonic-gate if (fs_dev != compnp->dev) {
20840Sstevel@tonic-gate /* establish file system binding with invalid start/end */
20850Sstevel@tonic-gate compnp->dev = fs_dev;
20860Sstevel@tonic-gate compnp->start_blk = -1;
20870Sstevel@tonic-gate compnp->end_blk = -1;
20880Sstevel@tonic-gate return (meta_mirror_replace(sp, mirnp,
20890Sstevel@tonic-gate compnp, compnp, options, ep));
20900Sstevel@tonic-gate }
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate /* setup mirror info */
20930Sstevel@tonic-gate (void) memset(¶ms, 0, sizeof (params));
20940Sstevel@tonic-gate params.mnum = meta_getminor(mirnp->dev);
20950Sstevel@tonic-gate MD_SETDRIVERNAME(¶ms, MD_MIRROR, sp->setno);
20960Sstevel@tonic-gate params.cmd = ENABLE_COMP;
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate /* check it out */
20990Sstevel@tonic-gate if (meta_check_component(sp, compnp, 0, ep) != 0) {
21000Sstevel@tonic-gate if (! mdisuseerror(ep, MDE_ALREADY))
21010Sstevel@tonic-gate return (-1);
21020Sstevel@tonic-gate mdclrerror(ep);
21030Sstevel@tonic-gate }
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate if ((size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR)
21060Sstevel@tonic-gate return (-1);
21070Sstevel@tonic-gate if ((label = metagetlabel(compnp, ep)) == MD_DISKADDR_ERROR)
21080Sstevel@tonic-gate return (-1);
21090Sstevel@tonic-gate if ((start_blk = metagetstart(sp, compnp, ep)) == MD_DISKADDR_ERROR)
21100Sstevel@tonic-gate return (-1);
21110Sstevel@tonic-gate if (start_blk >= size) {
21120Sstevel@tonic-gate (void) mdsyserror(ep, ENOSPC, compnp->cname);
21130Sstevel@tonic-gate return (-1);
21140Sstevel@tonic-gate }
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate /*
21170Sstevel@tonic-gate * In a MN set, the master always executes the replace command first.
21180Sstevel@tonic-gate * Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
21190Sstevel@tonic-gate * the master sends a message to all nodes to suspend writes to
21200Sstevel@tonic-gate * this mirror. Then the master executes the IOC_REPLACE ioctl
21210Sstevel@tonic-gate * which resumes writes to this mirror from the master node.
21220Sstevel@tonic-gate * As each slave executes the replace command, each slave will
21230Sstevel@tonic-gate * call the IOC_REPLACE ioctl which will resume writes to this mirror
21240Sstevel@tonic-gate * from that slave node.
21250Sstevel@tonic-gate */
21260Sstevel@tonic-gate if (! metaislocalset(sp)) {
21270Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL)
21280Sstevel@tonic-gate return (-1);
21290Sstevel@tonic-gate if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
21300Sstevel@tonic-gate sd->sd_mn_am_i_master)
21310Sstevel@tonic-gate if (meta_mn_send_suspend_writes(
21320Sstevel@tonic-gate meta_getminor(mirnp->dev), ep) != 0)
21330Sstevel@tonic-gate return (-1);
21340Sstevel@tonic-gate }
21350Sstevel@tonic-gate
21360Sstevel@tonic-gate /* enable component */
21370Sstevel@tonic-gate params.old_dev = compnp->dev;
21380Sstevel@tonic-gate params.new_dev = compnp->dev;
21390Sstevel@tonic-gate params.start_blk = start_blk;
21400Sstevel@tonic-gate params.has_label = ((label > 0) ? 1 : 0);
21410Sstevel@tonic-gate params.number_blks = size;
21420Sstevel@tonic-gate
21430Sstevel@tonic-gate /* Is this just a dryrun ? */
21440Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
21450Sstevel@tonic-gate params.options |= MDIOCTL_DRYRUN;
21460Sstevel@tonic-gate }
21470Sstevel@tonic-gate if (metaioctl(MD_IOCREPLACE, ¶ms, ¶ms.mde, NULL) != 0)
21480Sstevel@tonic-gate return (mdstealerror(ep, ¶ms.mde));
21490Sstevel@tonic-gate
21500Sstevel@tonic-gate /*
21510Sstevel@tonic-gate * Are we dealing with a non-local set? If so need to update the
21520Sstevel@tonic-gate * local namespace so that the disk record has the correct devid.
21530Sstevel@tonic-gate */
21540Sstevel@tonic-gate if (!metaislocalset(sp)) {
21550Sstevel@tonic-gate ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, compnp->cname,
21560Sstevel@tonic-gate ep);
21570Sstevel@tonic-gate
21580Sstevel@tonic-gate if (ret != METADEVADM_SUCCESS) {
21590Sstevel@tonic-gate /*
21600Sstevel@tonic-gate * Failed to update the local set. Nothing to do here
21610Sstevel@tonic-gate * apart from report the error. The namespace is
21620Sstevel@tonic-gate * most likely broken and some form of remedial
21630Sstevel@tonic-gate * recovery is going to be required.
21640Sstevel@tonic-gate */
21650Sstevel@tonic-gate mde_perror(ep, "");
21660Sstevel@tonic-gate mdclrerror(ep);
21670Sstevel@tonic-gate }
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate
21700Sstevel@tonic-gate /* clear cache */
21710Sstevel@tonic-gate meta_invalidate_name(compnp);
21720Sstevel@tonic-gate if (invalidate_submirrors(sp, mirnp, ep) != 0) {
21730Sstevel@tonic-gate meta_invalidate_name(mirnp);
21740Sstevel@tonic-gate return (-1);
21750Sstevel@tonic-gate }
21760Sstevel@tonic-gate meta_invalidate_name(mirnp);
21770Sstevel@tonic-gate
21780Sstevel@tonic-gate /* let em know */
21790Sstevel@tonic-gate if (options & MDCMD_PRINT) {
21800Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
21810Sstevel@tonic-gate "%s: device %s is enabled\n"),
21820Sstevel@tonic-gate mirnp->cname, compnp->cname);
21830Sstevel@tonic-gate (void) fflush(stdout);
21840Sstevel@tonic-gate }
21850Sstevel@tonic-gate
21860Sstevel@tonic-gate /* return success */
21870Sstevel@tonic-gate return (0);
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate /*
21910Sstevel@tonic-gate * check for dups in the mirror itself
21920Sstevel@tonic-gate */
21930Sstevel@tonic-gate static int
check_twice(md_mirror_t * mirrorp,uint_t smi,md_error_t * ep)21940Sstevel@tonic-gate check_twice(
21950Sstevel@tonic-gate md_mirror_t *mirrorp,
21960Sstevel@tonic-gate uint_t smi,
21970Sstevel@tonic-gate md_error_t *ep
21980Sstevel@tonic-gate )
21990Sstevel@tonic-gate {
22000Sstevel@tonic-gate mdname_t *mirnp = mirrorp->common.namep;
22010Sstevel@tonic-gate mdname_t *thisnp;
22020Sstevel@tonic-gate uint_t s;
22030Sstevel@tonic-gate
22040Sstevel@tonic-gate thisnp = mirrorp->submirrors[smi].submirnamep;
22050Sstevel@tonic-gate for (s = 0; (s < smi); ++s) {
22060Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[s];
22070Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate if (submirnp == NULL)
22100Sstevel@tonic-gate continue;
22110Sstevel@tonic-gate
22120Sstevel@tonic-gate if (meta_check_overlap(mirnp->cname, thisnp, 0, -1,
22130Sstevel@tonic-gate submirnp, 0, -1, ep) != 0) {
22140Sstevel@tonic-gate return (-1);
22150Sstevel@tonic-gate }
22160Sstevel@tonic-gate }
22170Sstevel@tonic-gate return (0);
22180Sstevel@tonic-gate }
22190Sstevel@tonic-gate
22200Sstevel@tonic-gate /*
22210Sstevel@tonic-gate * check mirror
22220Sstevel@tonic-gate */
22230Sstevel@tonic-gate int
meta_check_mirror(mdsetname_t * sp,md_mirror_t * mirrorp,mdcmdopts_t options,md_error_t * ep)22240Sstevel@tonic-gate meta_check_mirror(
22250Sstevel@tonic-gate mdsetname_t *sp,
22260Sstevel@tonic-gate md_mirror_t *mirrorp,
22270Sstevel@tonic-gate mdcmdopts_t options,
22280Sstevel@tonic-gate md_error_t *ep
22290Sstevel@tonic-gate )
22300Sstevel@tonic-gate {
22310Sstevel@tonic-gate mdname_t *mirnp = mirrorp->common.namep;
22320Sstevel@tonic-gate int force = ((options & MDCMD_FORCE) ? 1 : 0);
22330Sstevel@tonic-gate int doit = ((options & MDCMD_DOIT) ? 1 : 0);
22340Sstevel@tonic-gate uint_t nsm = 0;
22350Sstevel@tonic-gate uint_t smi;
22360Sstevel@tonic-gate
22370Sstevel@tonic-gate /* check submirrors */
22380Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
22390Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
22400Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
22410Sstevel@tonic-gate
22420Sstevel@tonic-gate if (submirnp == NULL)
22430Sstevel@tonic-gate continue;
22440Sstevel@tonic-gate ++nsm;
22450Sstevel@tonic-gate }
22460Sstevel@tonic-gate if (nsm < 1) {
22470Sstevel@tonic-gate return (mdmderror(ep, MDE_BAD_MIRROR,
22480Sstevel@tonic-gate meta_getminor(mirnp->dev), mirnp->cname));
22490Sstevel@tonic-gate }
22500Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
22510Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
22520Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
22530Sstevel@tonic-gate diskaddr_t size;
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate /* skip unused submirrors */
22560Sstevel@tonic-gate if (submirnp == NULL) {
22570Sstevel@tonic-gate if (mdsp->state != SMS_UNUSED) {
22580Sstevel@tonic-gate return (mdmderror(ep, MDE_BAD_MIRROR,
22590Sstevel@tonic-gate meta_getminor(mirnp->dev), mirnp->cname));
22600Sstevel@tonic-gate }
22610Sstevel@tonic-gate continue;
22620Sstevel@tonic-gate }
22630Sstevel@tonic-gate
22640Sstevel@tonic-gate /* check submirror */
22650Sstevel@tonic-gate if (doit) {
22660Sstevel@tonic-gate if (meta_check_submirror(sp, submirnp, NULL, force,
22670Sstevel@tonic-gate ep) != 0)
22680Sstevel@tonic-gate return (-1);
22690Sstevel@tonic-gate if ((size = metagetsize(submirnp, ep)) ==
22700Sstevel@tonic-gate MD_DISKADDR_ERROR) {
22710Sstevel@tonic-gate return (-1);
22720Sstevel@tonic-gate } else if (size == 0) {
22730Sstevel@tonic-gate return (mdsyserror(ep, ENOSPC,
22740Sstevel@tonic-gate submirnp->cname));
22750Sstevel@tonic-gate }
22760Sstevel@tonic-gate }
22770Sstevel@tonic-gate
22780Sstevel@tonic-gate /* check this mirror too */
22790Sstevel@tonic-gate if (check_twice(mirrorp, smi, ep) != 0)
22800Sstevel@tonic-gate return (-1);
22810Sstevel@tonic-gate }
22820Sstevel@tonic-gate
22830Sstevel@tonic-gate /* check read option */
22840Sstevel@tonic-gate switch (mirrorp->read_option) {
22850Sstevel@tonic-gate case RD_LOAD_BAL:
22860Sstevel@tonic-gate case RD_GEOMETRY:
22870Sstevel@tonic-gate case RD_FIRST:
22880Sstevel@tonic-gate break;
22890Sstevel@tonic-gate default:
22900Sstevel@tonic-gate return (mderror(ep, MDE_BAD_RD_OPT, mirnp->cname));
22910Sstevel@tonic-gate }
22920Sstevel@tonic-gate
22930Sstevel@tonic-gate /* check write option */
22940Sstevel@tonic-gate switch (mirrorp->write_option) {
22950Sstevel@tonic-gate case WR_PARALLEL:
22960Sstevel@tonic-gate case WR_SERIAL:
22970Sstevel@tonic-gate break;
22980Sstevel@tonic-gate default:
22990Sstevel@tonic-gate return (mderror(ep, MDE_BAD_WR_OPT, mirnp->cname));
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate
23020Sstevel@tonic-gate /* check pass number */
23030Sstevel@tonic-gate if ((mirrorp->pass_num < 0) || (mirrorp->pass_num > MD_PASS_MAX))
23040Sstevel@tonic-gate return (mderror(ep, MDE_BAD_PASS_NUM, mirnp->cname));
23050Sstevel@tonic-gate
23060Sstevel@tonic-gate /* return success */
23070Sstevel@tonic-gate return (0);
23080Sstevel@tonic-gate }
23090Sstevel@tonic-gate
23100Sstevel@tonic-gate /*
23110Sstevel@tonic-gate * setup mirror geometry
23120Sstevel@tonic-gate */
23130Sstevel@tonic-gate static int
mirror_geom(md_mirror_t * mirrorp,mm_unit_t * mm,md_error_t * ep)23140Sstevel@tonic-gate mirror_geom(
23150Sstevel@tonic-gate md_mirror_t *mirrorp,
23160Sstevel@tonic-gate mm_unit_t *mm,
23170Sstevel@tonic-gate md_error_t *ep
23180Sstevel@tonic-gate )
23190Sstevel@tonic-gate {
23200Sstevel@tonic-gate uint_t write_reinstruct = 0;
23210Sstevel@tonic-gate uint_t read_reinstruct = 0;
23220Sstevel@tonic-gate uint_t round_cyl = 1;
23230Sstevel@tonic-gate mdname_t *smnp = NULL;
23240Sstevel@tonic-gate uint_t smi;
23250Sstevel@tonic-gate mdgeom_t *geomp;
23260Sstevel@tonic-gate
23270Sstevel@tonic-gate /* get worst reinstructs */
23280Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
23290Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
23300Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
23310Sstevel@tonic-gate
23320Sstevel@tonic-gate if (submirnp == NULL)
23330Sstevel@tonic-gate continue;
23340Sstevel@tonic-gate
23350Sstevel@tonic-gate if ((geomp = metagetgeom(submirnp, ep)) == NULL)
23360Sstevel@tonic-gate return (-1);
23370Sstevel@tonic-gate if (geomp->write_reinstruct > write_reinstruct)
23380Sstevel@tonic-gate write_reinstruct = geomp->write_reinstruct;
23390Sstevel@tonic-gate if (geomp->read_reinstruct > read_reinstruct)
23400Sstevel@tonic-gate read_reinstruct = geomp->read_reinstruct;
23410Sstevel@tonic-gate
23420Sstevel@tonic-gate if (smnp == NULL)
23430Sstevel@tonic-gate smnp = submirnp;
23440Sstevel@tonic-gate }
23450Sstevel@tonic-gate
23460Sstevel@tonic-gate /* setup geometry from first submirror */
23470Sstevel@tonic-gate assert(smnp != NULL);
23480Sstevel@tonic-gate if ((geomp = metagetgeom(smnp, ep)) == NULL)
23490Sstevel@tonic-gate return (-1);
23500Sstevel@tonic-gate if (meta_setup_geom((md_unit_t *)mm, mirrorp->common.namep, geomp,
23510Sstevel@tonic-gate write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
23520Sstevel@tonic-gate return (-1);
23530Sstevel@tonic-gate
23540Sstevel@tonic-gate /* return success */
23550Sstevel@tonic-gate return (0);
23560Sstevel@tonic-gate }
23570Sstevel@tonic-gate
23580Sstevel@tonic-gate /*
23590Sstevel@tonic-gate * create mirror
23600Sstevel@tonic-gate */
23610Sstevel@tonic-gate int
meta_create_mirror(mdsetname_t * sp,md_mirror_t * mirrorp,mdcmdopts_t options,md_error_t * ep)23620Sstevel@tonic-gate meta_create_mirror(
23630Sstevel@tonic-gate mdsetname_t *sp,
23640Sstevel@tonic-gate md_mirror_t *mirrorp,
23650Sstevel@tonic-gate mdcmdopts_t options,
23660Sstevel@tonic-gate md_error_t *ep
23670Sstevel@tonic-gate )
23680Sstevel@tonic-gate {
23690Sstevel@tonic-gate mdname_t *mirnp = mirrorp->common.namep;
23700Sstevel@tonic-gate mm_unit_t *mm;
23710Sstevel@tonic-gate diskaddr_t submir_size = MD_DISKADDR_ERROR;
23720Sstevel@tonic-gate ushort_t nsm = 0;
23730Sstevel@tonic-gate uint_t smi;
23740Sstevel@tonic-gate mdnamelist_t *keynlp = NULL;
23750Sstevel@tonic-gate md_set_params_t set_params;
23760Sstevel@tonic-gate int rval = -1;
23770Sstevel@tonic-gate md_timeval32_t creation_time;
23780Sstevel@tonic-gate int create_flag = MD_CRO_32BIT;
23790Sstevel@tonic-gate
23800Sstevel@tonic-gate /* validate mirror */
23810Sstevel@tonic-gate if (meta_check_mirror(sp, mirrorp, options, ep) != 0)
23820Sstevel@tonic-gate return (-1);
23830Sstevel@tonic-gate
23840Sstevel@tonic-gate
23850Sstevel@tonic-gate /* allocate mirror unit */
23860Sstevel@tonic-gate mm = Zalloc(sizeof (*mm));
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate if (meta_gettimeofday(&creation_time) == -1)
23890Sstevel@tonic-gate return (mdsyserror(ep, errno, NULL));
23900Sstevel@tonic-gate
23910Sstevel@tonic-gate /* do submirrors */
23920Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
23930Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
23940Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
23950Sstevel@tonic-gate mm_submirror_t *mmsp = &mm->un_sm[smi];
23960Sstevel@tonic-gate diskaddr_t size;
23970Sstevel@tonic-gate
23980Sstevel@tonic-gate /* skip unused submirrors */
23990Sstevel@tonic-gate if (submirnp == NULL) {
24000Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
24010Sstevel@tonic-gate continue;
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate ++nsm;
24040Sstevel@tonic-gate
24050Sstevel@tonic-gate /* get size */
24060Sstevel@tonic-gate if ((size = metagetsize(submirnp, ep)) == MD_DISKADDR_ERROR)
24070Sstevel@tonic-gate goto out;
24080Sstevel@tonic-gate assert(size > 0);
24090Sstevel@tonic-gate
24100Sstevel@tonic-gate /* adjust for smallest submirror */
24110Sstevel@tonic-gate if (submir_size == MD_DISKADDR_ERROR) {
24120Sstevel@tonic-gate submir_size = size;
24130Sstevel@tonic-gate } else if (size < submir_size) {
24140Sstevel@tonic-gate submir_size = size;
24150Sstevel@tonic-gate }
24160Sstevel@tonic-gate
24170Sstevel@tonic-gate if (options & MDCMD_DOIT) {
24180Sstevel@tonic-gate /* store name in namespace */
24190Sstevel@tonic-gate if (add_key_name(sp, submirnp, &keynlp, ep) != 0)
24200Sstevel@tonic-gate goto out;
24210Sstevel@tonic-gate }
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate /* setup submirror */
24240Sstevel@tonic-gate mmsp->sm_key = submirnp->key;
24250Sstevel@tonic-gate mmsp->sm_dev = submirnp->dev;
24260Sstevel@tonic-gate mmsp->sm_state = SMS_RUNNING;
24270Sstevel@tonic-gate mmsp->sm_timestamp = creation_time;
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate
24300Sstevel@tonic-gate /* setup unit */
24310Sstevel@tonic-gate mm->c.un_type = MD_METAMIRROR;
24320Sstevel@tonic-gate MD_SID(mm) = meta_getminor(mirnp->dev);
24330Sstevel@tonic-gate mm->c.un_actual_tb = submir_size;
24340Sstevel@tonic-gate mm->c.un_size = offsetof(mm_unit_t, un_smic);
24350Sstevel@tonic-gate mm->un_nsm = nsm;
24360Sstevel@tonic-gate mm->un_read_option = mirrorp->read_option;
24370Sstevel@tonic-gate mm->un_write_option = mirrorp->write_option;
24380Sstevel@tonic-gate mm->un_pass_num = mirrorp->pass_num;
24390Sstevel@tonic-gate if (mirror_geom(mirrorp, mm, ep) != 0)
24400Sstevel@tonic-gate goto out;
24410Sstevel@tonic-gate
24420Sstevel@tonic-gate /* fill in the size of the mirror */
24430Sstevel@tonic-gate if (options & MDCMD_UPDATE) {
24440Sstevel@tonic-gate mirrorp->common.size = mm->c.un_total_blocks;
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate
24470Sstevel@tonic-gate /* if we're not doing anything, return success */
24480Sstevel@tonic-gate if (! (options & MDCMD_DOIT)) {
24490Sstevel@tonic-gate rval = 0; /* success */
24500Sstevel@tonic-gate goto out;
24510Sstevel@tonic-gate }
24520Sstevel@tonic-gate
24530Sstevel@tonic-gate /* create mirror */
24540Sstevel@tonic-gate (void) memset(&set_params, 0, sizeof (set_params));
24550Sstevel@tonic-gate /* did the user tell us to generate a large device? */
24560Sstevel@tonic-gate create_flag = meta_check_devicesize(mm->c.un_total_blocks);
24570Sstevel@tonic-gate if (create_flag == MD_CRO_64BIT) {
24581623Stw21770 mm->c.un_revision |= MD_64BIT_META_DEV;
24590Sstevel@tonic-gate set_params.options = MD_CRO_64BIT;
24600Sstevel@tonic-gate } else {
24611623Stw21770 mm->c.un_revision &= ~MD_64BIT_META_DEV;
24620Sstevel@tonic-gate set_params.options = MD_CRO_32BIT;
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate set_params.mnum = MD_SID(mm);
24650Sstevel@tonic-gate set_params.size = mm->c.un_size;
24660Sstevel@tonic-gate set_params.mdp = (uintptr_t)mm;
24670Sstevel@tonic-gate MD_SETDRIVERNAME(&set_params, MD_MIRROR, MD_MIN2SET(set_params.mnum));
24680Sstevel@tonic-gate if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
24690Sstevel@tonic-gate mirnp->cname) != 0) {
24700Sstevel@tonic-gate (void) mdstealerror(ep, &set_params.mde);
24710Sstevel@tonic-gate goto out;
24720Sstevel@tonic-gate }
24730Sstevel@tonic-gate rval = 0; /* success */
24740Sstevel@tonic-gate
24750Sstevel@tonic-gate /* cleanup, return success */
24760Sstevel@tonic-gate out:
24770Sstevel@tonic-gate Free(mm);
24780Sstevel@tonic-gate if (rval != 0) {
24790Sstevel@tonic-gate (void) del_key_names(sp, keynlp, NULL);
24800Sstevel@tonic-gate }
24810Sstevel@tonic-gate metafreenamelist(keynlp);
24820Sstevel@tonic-gate if ((rval == 0) && (options & MDCMD_DOIT)) {
24830Sstevel@tonic-gate if (invalidate_submirrors(sp, mirnp, ep) != 0)
24840Sstevel@tonic-gate rval = -1;
24850Sstevel@tonic-gate meta_invalidate_name(mirnp);
24860Sstevel@tonic-gate }
24870Sstevel@tonic-gate return (rval);
24880Sstevel@tonic-gate }
24890Sstevel@tonic-gate
24900Sstevel@tonic-gate /*
24910Sstevel@tonic-gate * initialize mirror
24920Sstevel@tonic-gate * NOTE: this functions is metainit(1m)'s command line parser!
24930Sstevel@tonic-gate */
24940Sstevel@tonic-gate int
meta_init_mirror(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)24950Sstevel@tonic-gate meta_init_mirror(
24960Sstevel@tonic-gate mdsetname_t **spp,
24970Sstevel@tonic-gate int argc,
24980Sstevel@tonic-gate char *argv[],
24990Sstevel@tonic-gate mdcmdopts_t options,
25000Sstevel@tonic-gate md_error_t *ep
25010Sstevel@tonic-gate )
25020Sstevel@tonic-gate {
25030Sstevel@tonic-gate char *uname = argv[0];
25040Sstevel@tonic-gate mdname_t *mirnp = NULL;
25050Sstevel@tonic-gate int old_optind;
25060Sstevel@tonic-gate int c;
25070Sstevel@tonic-gate md_mirror_t *mirrorp = NULL;
25080Sstevel@tonic-gate uint_t smi;
25090Sstevel@tonic-gate int rval = -1;
25100Sstevel@tonic-gate
25110Sstevel@tonic-gate /* get mirror name */
25120Sstevel@tonic-gate assert(argc > 0);
25130Sstevel@tonic-gate if (argc < 1)
25140Sstevel@tonic-gate goto syntax;
25151623Stw21770 if ((mirnp = metaname(spp, uname, META_DEVICE, ep)) == NULL)
25160Sstevel@tonic-gate goto out;
25170Sstevel@tonic-gate assert(*spp != NULL);
25180Sstevel@tonic-gate uname = mirnp->cname;
25190Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
25200Sstevel@tonic-gate goto out;
25210Sstevel@tonic-gate
25220Sstevel@tonic-gate if (!(options & MDCMD_NOLOCK)) {
25230Sstevel@tonic-gate /* grab set lock */
25240Sstevel@tonic-gate if (meta_lock(*spp, TRUE, ep) != 0)
25250Sstevel@tonic-gate goto out;
25260Sstevel@tonic-gate
25270Sstevel@tonic-gate if (meta_check_ownership(*spp, ep) != 0)
25280Sstevel@tonic-gate goto out;
25290Sstevel@tonic-gate }
25300Sstevel@tonic-gate
25310Sstevel@tonic-gate /* see if it exists already */
25320Sstevel@tonic-gate if (metagetmiscname(mirnp, ep) != NULL) {
25330Sstevel@tonic-gate (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
25340Sstevel@tonic-gate meta_getminor(mirnp->dev), uname);
25350Sstevel@tonic-gate goto out;
25360Sstevel@tonic-gate } else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
25370Sstevel@tonic-gate goto out;
25380Sstevel@tonic-gate } else {
25390Sstevel@tonic-gate mdclrerror(ep);
25400Sstevel@tonic-gate }
25410Sstevel@tonic-gate --argc, ++argv;
25420Sstevel@tonic-gate
25430Sstevel@tonic-gate /* grab -m */
25440Sstevel@tonic-gate if ((argc < 1) || (strcmp(argv[0], "-m") != 0))
25450Sstevel@tonic-gate goto syntax;
25460Sstevel@tonic-gate --argc, ++argv;
25470Sstevel@tonic-gate
25480Sstevel@tonic-gate if (argc == 0)
25490Sstevel@tonic-gate goto syntax;
25500Sstevel@tonic-gate
25510Sstevel@tonic-gate /* parse general options */
25520Sstevel@tonic-gate optind = 0;
25530Sstevel@tonic-gate opterr = 0;
25540Sstevel@tonic-gate if (getopt(argc, argv, "") != -1)
25550Sstevel@tonic-gate goto options;
25560Sstevel@tonic-gate
25570Sstevel@tonic-gate /* allocate mirror */
25580Sstevel@tonic-gate mirrorp = Zalloc(sizeof (*mirrorp));
25590Sstevel@tonic-gate
25600Sstevel@tonic-gate /* setup common */
25610Sstevel@tonic-gate mirrorp->common.namep = mirnp;
25620Sstevel@tonic-gate mirrorp->common.type = MD_METAMIRROR;
25630Sstevel@tonic-gate
25640Sstevel@tonic-gate /* parse submirrors */
25650Sstevel@tonic-gate for (smi = 0; ((argc > 0) && (argv[0][0] != '-') &&
25660Sstevel@tonic-gate (! isdigit(argv[0][0]))); ++smi) {
25670Sstevel@tonic-gate md_submirror_t *mdsm = &mirrorp->submirrors[smi];
25680Sstevel@tonic-gate mdname_t *submirnamep;
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate /* check for room */
25710Sstevel@tonic-gate if (smi >= NMIRROR) {
25720Sstevel@tonic-gate (void) mdmderror(ep, MDE_MIRROR_FULL,
25730Sstevel@tonic-gate meta_getminor(mirnp->dev), uname);
25740Sstevel@tonic-gate goto out;
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate /* parse submirror name */
25781623Stw21770 if ((submirnamep = metaname(spp, argv[0],
25791623Stw21770 META_DEVICE, ep)) == NULL)
25800Sstevel@tonic-gate goto out;
25810Sstevel@tonic-gate mdsm->submirnamep = submirnamep;
25820Sstevel@tonic-gate --argc, ++argv;
25830Sstevel@tonic-gate }
25840Sstevel@tonic-gate if (smi == 0) {
25850Sstevel@tonic-gate (void) mdmderror(ep, MDE_NSUBMIRS, meta_getminor(mirnp->dev),
25860Sstevel@tonic-gate uname);
25870Sstevel@tonic-gate goto out;
25880Sstevel@tonic-gate }
25890Sstevel@tonic-gate
25900Sstevel@tonic-gate /* dangerous n-way mirror creation */
25910Sstevel@tonic-gate if ((smi > 1) && (options & MDCMD_PRINT)) {
25920Sstevel@tonic-gate md_eprintf(dgettext(TEXT_DOMAIN,
25930Sstevel@tonic-gate "%s: WARNING: This form of metainit is not recommended.\n"
25940Sstevel@tonic-gate "The submirrors may not have the same data.\n"
25950Sstevel@tonic-gate "Please see ERRORS in metainit(1M) for additional information.\n"),
25960Sstevel@tonic-gate uname);
25970Sstevel@tonic-gate }
25980Sstevel@tonic-gate
25990Sstevel@tonic-gate /* parse mirror options */
26000Sstevel@tonic-gate mirrorp->read_option = RD_LOAD_BAL;
26010Sstevel@tonic-gate mirrorp->write_option = WR_PARALLEL;
26020Sstevel@tonic-gate mirrorp->pass_num = MD_PASS_DEFAULT;
26030Sstevel@tonic-gate old_optind = optind = 0;
26040Sstevel@tonic-gate opterr = 0;
26050Sstevel@tonic-gate while ((c = getopt(argc, argv, "grS")) != -1) {
26060Sstevel@tonic-gate switch (c) {
26070Sstevel@tonic-gate case 'g':
26080Sstevel@tonic-gate if (mirrorp->read_option != RD_LOAD_BAL) {
26090Sstevel@tonic-gate (void) mderror(ep, MDE_BAD_RD_OPT, uname);
26100Sstevel@tonic-gate goto out;
26110Sstevel@tonic-gate }
26120Sstevel@tonic-gate mirrorp->read_option = RD_GEOMETRY;
26130Sstevel@tonic-gate break;
26140Sstevel@tonic-gate
26150Sstevel@tonic-gate case 'r':
26160Sstevel@tonic-gate if (mirrorp->read_option != RD_LOAD_BAL) {
26170Sstevel@tonic-gate (void) mderror(ep, MDE_BAD_RD_OPT, uname);
26180Sstevel@tonic-gate goto out;
26190Sstevel@tonic-gate }
26200Sstevel@tonic-gate mirrorp->read_option = RD_FIRST;
26210Sstevel@tonic-gate break;
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate case 'S':
26240Sstevel@tonic-gate if (mirrorp->write_option != WR_PARALLEL) {
26250Sstevel@tonic-gate (void) mderror(ep, MDE_BAD_WR_OPT, uname);
26260Sstevel@tonic-gate goto out;
26270Sstevel@tonic-gate }
26280Sstevel@tonic-gate mirrorp->write_option = WR_SERIAL;
26290Sstevel@tonic-gate break;
26300Sstevel@tonic-gate
26310Sstevel@tonic-gate default:
26320Sstevel@tonic-gate argc -= old_optind;
26330Sstevel@tonic-gate argv += old_optind;
26340Sstevel@tonic-gate goto options;
26350Sstevel@tonic-gate }
26360Sstevel@tonic-gate old_optind = optind;
26370Sstevel@tonic-gate }
26380Sstevel@tonic-gate argc -= optind;
26390Sstevel@tonic-gate argv += optind;
26400Sstevel@tonic-gate
26410Sstevel@tonic-gate /* parse pass number */
26420Sstevel@tonic-gate if ((argc > 0) && (isdigit(argv[0][0]))) {
26430Sstevel@tonic-gate if (name_to_pass_num(uname, argv[0],
26440Sstevel@tonic-gate &mirrorp->pass_num, ep) != 0) {
26450Sstevel@tonic-gate goto out;
26460Sstevel@tonic-gate }
26470Sstevel@tonic-gate --argc, ++argv;
26480Sstevel@tonic-gate }
26490Sstevel@tonic-gate
26500Sstevel@tonic-gate /* we should be at the end */
26510Sstevel@tonic-gate if (argc != 0)
26520Sstevel@tonic-gate goto syntax;
26530Sstevel@tonic-gate
26540Sstevel@tonic-gate /* create mirror */
26550Sstevel@tonic-gate if (meta_create_mirror(*spp, mirrorp, options, ep) != 0)
26560Sstevel@tonic-gate goto out;
26570Sstevel@tonic-gate rval = 0; /* success */
26580Sstevel@tonic-gate
26590Sstevel@tonic-gate /* let em know */
26600Sstevel@tonic-gate if (options & MDCMD_PRINT) {
26610Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
26620Sstevel@tonic-gate "%s: Mirror is setup\n"),
26630Sstevel@tonic-gate uname);
26640Sstevel@tonic-gate (void) fflush(stdout);
26650Sstevel@tonic-gate }
26660Sstevel@tonic-gate goto out;
26670Sstevel@tonic-gate
26680Sstevel@tonic-gate /* syntax error */
26690Sstevel@tonic-gate syntax:
26700Sstevel@tonic-gate rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
26710Sstevel@tonic-gate goto out;
26720Sstevel@tonic-gate
26730Sstevel@tonic-gate /* options error */
26740Sstevel@tonic-gate options:
26750Sstevel@tonic-gate rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
26760Sstevel@tonic-gate goto out;
26770Sstevel@tonic-gate
26780Sstevel@tonic-gate /* cleanup, return error */
26790Sstevel@tonic-gate out:
26800Sstevel@tonic-gate if (mirrorp != NULL)
26810Sstevel@tonic-gate meta_free_mirror(mirrorp);
26820Sstevel@tonic-gate return (rval);
26830Sstevel@tonic-gate }
26840Sstevel@tonic-gate
26850Sstevel@tonic-gate /*
26860Sstevel@tonic-gate * reset mirrors
26870Sstevel@tonic-gate */
26880Sstevel@tonic-gate int
meta_mirror_reset(mdsetname_t * sp,mdname_t * mirnp,mdcmdopts_t options,md_error_t * ep)26890Sstevel@tonic-gate meta_mirror_reset(
26900Sstevel@tonic-gate mdsetname_t *sp,
26910Sstevel@tonic-gate mdname_t *mirnp,
26920Sstevel@tonic-gate mdcmdopts_t options,
26930Sstevel@tonic-gate md_error_t *ep
26940Sstevel@tonic-gate )
26950Sstevel@tonic-gate {
26960Sstevel@tonic-gate md_mirror_t *mirrorp;
26970Sstevel@tonic-gate uint_t smi;
26980Sstevel@tonic-gate int rval = -1;
26990Sstevel@tonic-gate
27000Sstevel@tonic-gate /* should have same set */
27010Sstevel@tonic-gate assert(sp != NULL);
27020Sstevel@tonic-gate assert((mirnp == NULL) ||
27030Sstevel@tonic-gate (sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev))));
27040Sstevel@tonic-gate
27050Sstevel@tonic-gate /* reset all mirrors */
27060Sstevel@tonic-gate if (mirnp == NULL) {
27070Sstevel@tonic-gate mdnamelist_t *mirrornlp = NULL;
27080Sstevel@tonic-gate mdnamelist_t *p;
27090Sstevel@tonic-gate
27100Sstevel@tonic-gate /* for each mirror */
27110Sstevel@tonic-gate rval = 0;
27120Sstevel@tonic-gate if (meta_get_mirror_names(sp, &mirrornlp, 0, ep) < 0)
27130Sstevel@tonic-gate return (-1);
27140Sstevel@tonic-gate for (p = mirrornlp; (p != NULL); p = p->next) {
27150Sstevel@tonic-gate /* reset mirror */
27160Sstevel@tonic-gate mirnp = p->namep;
27170Sstevel@tonic-gate /*
27180Sstevel@tonic-gate * If this is a multi-node set, we send a series
27190Sstevel@tonic-gate * of individual metaclear commands.
27200Sstevel@tonic-gate */
27210Sstevel@tonic-gate if (meta_is_mn_set(sp, ep)) {
27220Sstevel@tonic-gate if (meta_mn_send_metaclear_command(sp,
27230Sstevel@tonic-gate mirnp->cname, options, 0, ep) != 0) {
27240Sstevel@tonic-gate rval = -1;
27250Sstevel@tonic-gate break;
27260Sstevel@tonic-gate }
27270Sstevel@tonic-gate } else {
27280Sstevel@tonic-gate if (meta_mirror_reset(sp, mirnp, options,
27290Sstevel@tonic-gate ep) != 0) {
27300Sstevel@tonic-gate rval = -1;
27310Sstevel@tonic-gate break;
27320Sstevel@tonic-gate }
27330Sstevel@tonic-gate }
27340Sstevel@tonic-gate }
27350Sstevel@tonic-gate
27360Sstevel@tonic-gate /* cleanup return success */
27370Sstevel@tonic-gate metafreenamelist(mirrornlp);
27380Sstevel@tonic-gate return (rval);
27390Sstevel@tonic-gate }
27400Sstevel@tonic-gate
27410Sstevel@tonic-gate /* check name */
27420Sstevel@tonic-gate if (metachkmeta(mirnp, ep) != 0)
27430Sstevel@tonic-gate return (-1);
27440Sstevel@tonic-gate
27450Sstevel@tonic-gate /* get unit structure */
27460Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
27470Sstevel@tonic-gate return (-1);
27480Sstevel@tonic-gate
27490Sstevel@tonic-gate /* make sure nobody owns us */
27500Sstevel@tonic-gate if (MD_HAS_PARENT(mirrorp->common.parent)) {
27510Sstevel@tonic-gate return (mdmderror(ep, MDE_IN_USE, meta_getminor(mirnp->dev),
27520Sstevel@tonic-gate mirnp->cname));
27530Sstevel@tonic-gate }
27540Sstevel@tonic-gate
27550Sstevel@tonic-gate /* clear subdevices cache */
27560Sstevel@tonic-gate if (invalidate_submirrors(sp, mirnp, ep) != 0)
27570Sstevel@tonic-gate return (-1);
27580Sstevel@tonic-gate
27590Sstevel@tonic-gate /* clear metadevice */
27600Sstevel@tonic-gate if (meta_reset(sp, mirnp, options, ep) != 0)
27610Sstevel@tonic-gate goto out;
27620Sstevel@tonic-gate rval = 0; /* success */
27630Sstevel@tonic-gate
27640Sstevel@tonic-gate /* let em know */
27650Sstevel@tonic-gate if (options & MDCMD_PRINT) {
27660Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
27670Sstevel@tonic-gate "%s: Mirror is cleared\n"), mirnp->cname);
27680Sstevel@tonic-gate (void) fflush(stdout);
27690Sstevel@tonic-gate }
27700Sstevel@tonic-gate
27710Sstevel@tonic-gate /* clear subdevices */
27720Sstevel@tonic-gate if (! (options & MDCMD_RECURSE))
27730Sstevel@tonic-gate goto out;
27740Sstevel@tonic-gate for (smi = 0; (smi < NMIRROR); ++smi) {
27750Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
27760Sstevel@tonic-gate mdname_t *submirnp = mdsp->submirnamep;
27770Sstevel@tonic-gate
27780Sstevel@tonic-gate /* skip unused submirrors */
27790Sstevel@tonic-gate if (submirnp == NULL) {
27800Sstevel@tonic-gate assert(mdsp->state == SMS_UNUSED);
27810Sstevel@tonic-gate continue;
27820Sstevel@tonic-gate }
27830Sstevel@tonic-gate
27840Sstevel@tonic-gate /* make sure we have a metadevice */
27850Sstevel@tonic-gate if (! metaismeta(submirnp))
27860Sstevel@tonic-gate continue;
27870Sstevel@tonic-gate
27880Sstevel@tonic-gate /* clear submirror */
27890Sstevel@tonic-gate if (meta_reset_by_name(sp, submirnp, options, ep) != 0)
27900Sstevel@tonic-gate rval = -1;
27910Sstevel@tonic-gate }
27920Sstevel@tonic-gate
27930Sstevel@tonic-gate /* cleanup, return success */
27940Sstevel@tonic-gate out:
27950Sstevel@tonic-gate meta_invalidate_name(mirnp);
27960Sstevel@tonic-gate return (rval);
27970Sstevel@tonic-gate }
27980Sstevel@tonic-gate
27990Sstevel@tonic-gate /*
28000Sstevel@tonic-gate * reports TRUE if any mirror component is in error
28010Sstevel@tonic-gate */
28020Sstevel@tonic-gate int
meta_mirror_anycomp_is_err(mdsetname_t * sp,mdnamelist_t * mirror_names)28030Sstevel@tonic-gate meta_mirror_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *mirror_names)
28040Sstevel@tonic-gate {
28050Sstevel@tonic-gate mdnamelist_t *nlp;
28060Sstevel@tonic-gate md_error_t status = mdnullerror;
28070Sstevel@tonic-gate md_error_t *ep = &status;
28080Sstevel@tonic-gate int any_errs = FALSE;
28090Sstevel@tonic-gate
28100Sstevel@tonic-gate for (nlp = mirror_names; nlp; nlp = nlp->next) {
28110Sstevel@tonic-gate md_mirror_t *mirrorp;
28120Sstevel@tonic-gate int smi;
28130Sstevel@tonic-gate
28140Sstevel@tonic-gate if ((mirrorp = meta_get_mirror(sp, nlp->namep, ep)) == NULL) {
28150Sstevel@tonic-gate any_errs |= TRUE;
28160Sstevel@tonic-gate goto out;
28170Sstevel@tonic-gate }
28180Sstevel@tonic-gate
28190Sstevel@tonic-gate for (smi = 0; smi < NMIRROR; ++smi) {
28200Sstevel@tonic-gate md_submirror_t *mdsp = &mirrorp->submirrors[smi];
28210Sstevel@tonic-gate
28220Sstevel@tonic-gate if (mdsp->state &
28230Sstevel@tonic-gate (SMS_COMP_ERRED|SMS_ATTACHED|SMS_OFFLINE)) {
28240Sstevel@tonic-gate any_errs |= TRUE;
28250Sstevel@tonic-gate goto out;
28260Sstevel@tonic-gate }
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate }
28290Sstevel@tonic-gate out:
28300Sstevel@tonic-gate if (!mdisok(ep))
28310Sstevel@tonic-gate mdclrerror(ep);
28320Sstevel@tonic-gate
28330Sstevel@tonic-gate return (any_errs);
28340Sstevel@tonic-gate }
2835