2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Just in case we're not in a build environment, make sure that
2N/A * TEXT_DOMAIN gets set to something.
2N/A */
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*
2N/A * mirror operations
2N/A */
2N/A
2N/A#include <meta.h>
2N/A#include <sys/lvm/md_mirror.h>
2N/A#include <sys/lvm/md_convert.h>
2N/A
2N/A#include <ctype.h>
2N/A#include <stddef.h>
2N/A
2N/A/*
2N/A * FUNCTION: meta_get_mirror_names()
2N/A * INPUT: sp - the set name to get mirrors from
2N/A * options - options from the command line
2N/A * OUTPUT: nlpp - list of all mirror names
2N/A * ep - return error pointer
2N/A * RETURNS: int - -1 if error, 0 success
2N/A * PURPOSE: returns a list of all mirrors in the metadb
2N/A * for all devices in the specified set
2N/A */
2N/Aint
2N/Ameta_get_mirror_names(
2N/A mdsetname_t *sp,
2N/A mdnamelist_t **nlpp,
2N/A int options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (meta_get_names(MD_MIRROR, sp, nlpp, options, ep));
2N/A}
2N/A
2N/A/*
2N/A * free mirror unit
2N/A */
2N/Avoid
2N/Ameta_free_mirror(
2N/A md_mirror_t *mirrorp
2N/A)
2N/A{
2N/A Free(mirrorp);
2N/A}
2N/A
2N/A/*
2N/A * get mirror unit
2N/A */
2N/Astatic md_mirror_t *
2N/Ameta_get_mirror_common(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A int fast,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mddrivename_t *dnp = mirnp->drivenamep;
2N/A char *miscname;
2N/A mm_unit_t *mm;
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi, nsm;
2N/A md_resync_ioctl_t ri;
2N/A
2N/A /* must have set */
2N/A assert(sp != NULL);
2N/A
2N/A /* short circuit */
2N/A if (dnp->unitp != NULL) {
2N/A assert(dnp->unitp->type == MD_METAMIRROR);
2N/A return ((md_mirror_t *)dnp->unitp);
2N/A }
2N/A
2N/A /* get miscname and unit */
2N/A if ((miscname = metagetmiscname(mirnp, ep)) == NULL)
2N/A return (NULL);
2N/A if (strcmp(miscname, MD_MIRROR) != 0) {
2N/A (void) mdmderror(ep, MDE_NOT_MM, meta_getminor(mirnp->dev),
2N/A mirnp->cname);
2N/A return (NULL);
2N/A }
2N/A if ((mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, ep)) == NULL)
2N/A return (NULL);
2N/A assert(mm->c.un_type == MD_METAMIRROR);
2N/A
2N/A /* allocate mirror */
2N/A mirrorp = Zalloc(sizeof (*mirrorp));
2N/A
2N/A /* get common info */
2N/A mirrorp->common.namep = mirnp;
2N/A mirrorp->common.type = mm->c.un_type;
2N/A mirrorp->common.state = mm->c.un_status;
2N/A mirrorp->common.capabilities = mm->c.un_capabilities;
2N/A mirrorp->common.parent = mm->c.un_parent;
2N/A mirrorp->common.size = mm->c.un_total_blocks;
2N/A mirrorp->common.user_flags = mm->c.un_user_flags;
2N/A mirrorp->common.revision = mm->c.un_revision;
2N/A
2N/A /* get options */
2N/A mirrorp->read_option = mm->un_read_option;
2N/A mirrorp->write_option = mm->un_write_option;
2N/A mirrorp->pass_num = mm->un_pass_num;
2N/A
2N/A /* get submirrors */
2N/A for (smi = 0, nsm = 0; (smi < NMIRROR); ++smi) {
2N/A mm_submirror_t *mmsp = &mm->un_sm[smi];
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A
2N/A /* get submirror state */
2N/A mdsp->state = mmsp->sm_state;
2N/A if (mdsp->state == SMS_UNUSED)
2N/A continue;
2N/A ++nsm;
2N/A
2N/A /* get submirror time of last state change */
2N/A mdsp->timestamp = mmsp->sm_timestamp;
2N/A
2N/A /* get submirror flags */
2N/A mdsp->flags = mmsp->sm_flags;
2N/A
2N/A /* get submirror name */
2N/A mdsp->submirnamep = metakeyname(&sp, mmsp->sm_key, fast, ep);
2N/A if (mdsp->submirnamep == NULL)
2N/A goto out;
2N/A }
2N/A assert(nsm == mm->un_nsm);
2N/A
2N/A /* get resync info */
2N/A (void) memset(&ri, 0, sizeof (ri));
2N/A ri.ri_mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&ri, MD_MIRROR, sp->setno);
2N/A if (metaioctl(MD_IOCGETSYNC, &ri, &ri.mde, mirnp->cname) != 0) {
2N/A (void) mdstealerror(ep, &ri.mde);
2N/A goto out;
2N/A }
2N/A mirrorp->percent_done = ri.ri_percent_done;
2N/A mirrorp->percent_dirty = ri.ri_percent_dirty;
2N/A
2N/A /* cleanup, return success */
2N/A Free(mm);
2N/A dnp->unitp = (md_common_t *)mirrorp;
2N/A return (mirrorp);
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A Free(mm);
2N/A meta_free_mirror(mirrorp);
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * get mirror unit
2N/A */
2N/Amd_mirror_t *
2N/Ameta_get_mirror(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (meta_get_mirror_common(sp, mirnp, 0, ep));
2N/A}
2N/A
2N/A/*
2N/A * check mirror for dev
2N/A */
2N/Astatic int
2N/Ain_mirror(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *np,
2N/A diskaddr_t slblk,
2N/A diskaddr_t nblks,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi;
2N/A
2N/A /* should be in the same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* get unit */
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* look in submirrors */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnp == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A /* check overlap */
2N/A if (metaismeta(submirnp))
2N/A continue;
2N/A if (meta_check_overlap(mirnp->cname, np, slblk, nblks,
2N/A submirnp, 0, -1, ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check to see if we're in a mirror
2N/A */
2N/Aint
2N/Ameta_check_inmirror(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A diskaddr_t slblk,
2N/A diskaddr_t nblks,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdnamelist_t *mirrornlp = NULL;
2N/A mdnamelist_t *p;
2N/A int rval = 0;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A
2N/A /* for each mirror */
2N/A if (meta_get_mirror_names(sp, &mirrornlp, 0, ep) < 0)
2N/A return (-1);
2N/A for (p = mirrornlp; (p != NULL); p = p->next) {
2N/A mdname_t *mirnp = p->namep;
2N/A
2N/A /* check mirror */
2N/A if (in_mirror(sp, mirnp, np, slblk, nblks, ep) != 0) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/A metafreenamelist(mirrornlp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * Check to see if the primary mirror is built on top of a
2N/A * root slice which is mounted. This check is primarily to
2N/A * account for this case -
2N/A *
2N/A * # metainit -f d1 1 1 <root slice>
2N/A * # metainit d0 -m d1
2N/A * # metainit d2 1 1 ctds
2N/A * # metattach d0 d2
2N/A *
2N/A * The metattach here needs to fail if the root slice is
2N/A * being mirrored; otherwise there is a potential for
2N/A * data corruption.
2N/A */
2N/Astatic int
2N/Ameta_check_primary_mirror(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A int smi;
2N/A char *curroot;
2N/A char *temproot;
2N/A mdname_t *rootnp;
2N/A md_mirror_t *mirrorp;
2N/A md_stripe_t *stripep;
2N/A md_row_t *rp;
2N/A md_comp_t *cp;
2N/A
2N/A if ((curroot = meta_get_current_root(ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /*
2N/A * We need to take the canonical name here otherwise the call to
2N/A * metaname will add a bad entry to the drivelistp cache and
2N/A * things will get nasty later on.
2N/A * However we also need to trap the case where we have a logical
2N/A * device name and meta_canonicalize returns NULL.
2N/A */
2N/A temproot = meta_canonicalize(sp, curroot);
2N/A if (temproot != NULL) {
2N/A curroot = Strdup(temproot);
2N/A Free(temproot);
2N/A }
2N/A
2N/A /*
2N/A * Get device name of current root metadevice. If root
2N/A * is net mounted as happens if we're part of the
2N/A * install process, rootnp will be set to NULL and we
2N/A * return success.
2N/A *
2N/A * Since curroot should be a complete path, we only
2N/A * need to check whether the device is a logical device.
2N/A * The metaname below returns NULL if curroot is not a logical
2N/A * device.
2N/A */
2N/A if ((rootnp = metaname(&sp, curroot, LOGICAL_DEVICE, ep)) == NULL)
2N/A return (0);
2N/A /*
2N/A * If we're here, the curroot is a mounted on a logical device.
2N/A * Make sure this mirror is not on the root logical device.
2N/A */
2N/A if (metaismeta(mirnp)) {
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A /* Check all submirrors */
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep = mdsp->submirnamep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnamep == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A /* check if submirror is a stripe or not */
2N/A if (strcmp(metagetmiscname(submirnamep, ep), MD_STRIPE)
2N/A != 0)
2N/A return (-1);
2N/A if ((stripep = meta_get_stripe(sp, submirnamep, ep))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A /*
2N/A * Examine the first component of the first row and
2N/A * check to see if it has a mounted root slice
2N/A */
2N/A rp = &stripep->rows.rows_val[0];
2N/A cp = &rp->comps.comps_val[0];
2N/A /*
2N/A * we just care about the component built on
2N/A * top of a raw device
2N/A */
2N/A if (!metaismeta(cp->compnamep)) {
2N/A /*
2N/A * If root device is the 1st component of
2N/A * the stripe, then fail.
2N/A */
2N/A if (strcmp(rootnp->cname, cp->compnamep->cname)
2N/A == 0) {
2N/A (void) mduseerror(ep, MDE_IS_MOUNTED,
2N/A rootnp->dev, "/", rootnp->cname);
2N/A return (-1);
2N/A }
2N/A }
2N/A }
2N/A }
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check submirror
2N/A */
2N/Aint
2N/Ameta_check_submirror(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A mdname_t *mirnp,
2N/A int force,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdchkopts_t options = 0;
2N/A md_common_t *mdp;
2N/A
2N/A /* make sure we have a metadevice disk */
2N/A if (metachkmeta(np, ep) != 0)
2N/A return (-1);
2N/A
2N/A /*
2N/A * Check to see if the primary mirror consists of a root
2N/A * mounted device
2N/A */
2N/A if (mirnp && (!force) && ((meta_check_primary_mirror(sp, mirnp, ep)
2N/A != 0)))
2N/A return (-1);
2N/A
2N/A /* check to ensure that it is not already in use */
2N/A if ((! force) &&
2N/A (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0)) {
2N/A return (-1);
2N/A }
2N/A
2N/A /* make sure it is in the set */
2N/A if (meta_check_inset(sp, np, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* make sure its not in a metadevice */
2N/A if (! metaismeta(np)) { /* Non-metadevices */
2N/A if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
2N/A return (-1);
2N/A } else { /* Metadevices only! */
2N/A /* make sure it can be parented */
2N/A if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
2N/A (! (mdp->capabilities & MD_CAN_SUB_MIRROR)) ||
2N/A (mdp->parent != MD_NO_PARENT)) {
2N/A return (mdmderror(ep, MDE_INVAL_UNIT,
2N/A meta_getminor(np->dev), np->cname));
2N/A }
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * convert read options
2N/A */
2N/Achar *
2N/Ard_opt_to_name(
2N/A mm_rd_opt_t opt
2N/A)
2N/A{
2N/A switch (opt) {
2N/A case RD_LOAD_BAL:
2N/A return ("roundrobin");
2N/A case RD_GEOMETRY:
2N/A return ("geometric");
2N/A case RD_FIRST:
2N/A return ("first");
2N/A default:
2N/A assert(0);
2N/A return (dgettext(TEXT_DOMAIN, "invalid"));
2N/A }
2N/A}
2N/A
2N/Astatic char *
2N/Ard_opt_to_opt(
2N/A mm_rd_opt_t opt
2N/A)
2N/A{
2N/A switch (opt) {
2N/A case RD_LOAD_BAL:
2N/A return (NULL); /* default */
2N/A case RD_GEOMETRY:
2N/A return ("-g");
2N/A case RD_FIRST:
2N/A return ("-r");
2N/A default:
2N/A assert(0);
2N/A return (dgettext(TEXT_DOMAIN, "invalid"));
2N/A }
2N/A}
2N/A
2N/Aint
2N/Aname_to_rd_opt(
2N/A char *uname,
2N/A char *name,
2N/A mm_rd_opt_t *optp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if (strcasecmp(name, "roundrobin") == 0) {
2N/A *optp = RD_LOAD_BAL;
2N/A return (0);
2N/A }
2N/A if (strcasecmp(name, "geometric") == 0) {
2N/A *optp = RD_GEOMETRY;
2N/A return (0);
2N/A }
2N/A if (strcasecmp(name, "first") == 0) {
2N/A *optp = RD_FIRST;
2N/A return (0);
2N/A }
2N/A return (meta_cook_syntax(ep, MDE_BAD_RD_OPT, uname, 1, &name));
2N/A}
2N/A
2N/A/*
2N/A * convert write options
2N/A */
2N/Achar *
2N/Awr_opt_to_name(
2N/A mm_wr_opt_t opt
2N/A)
2N/A{
2N/A switch (opt) {
2N/A case WR_PARALLEL:
2N/A return ("parallel");
2N/A case WR_SERIAL:
2N/A return ("serial");
2N/A default:
2N/A assert(0);
2N/A return (dgettext(TEXT_DOMAIN, "invalid"));
2N/A }
2N/A}
2N/A
2N/Astatic char *
2N/Awr_opt_to_opt(
2N/A mm_wr_opt_t opt
2N/A)
2N/A{
2N/A switch (opt) {
2N/A case WR_PARALLEL:
2N/A return (NULL); /* default */
2N/A case WR_SERIAL:
2N/A return ("-S");
2N/A default:
2N/A assert(0);
2N/A return (dgettext(TEXT_DOMAIN, "invalid"));
2N/A }
2N/A}
2N/A
2N/Aint
2N/Aname_to_wr_opt(
2N/A char *uname,
2N/A char *name,
2N/A mm_wr_opt_t *optp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if (strcasecmp(name, "parallel") == 0) {
2N/A *optp = WR_PARALLEL;
2N/A return (0);
2N/A }
2N/A if (strcasecmp(name, "serial") == 0) {
2N/A *optp = WR_SERIAL;
2N/A return (0);
2N/A }
2N/A return (meta_cook_syntax(ep, MDE_BAD_WR_OPT, uname, 1, &name));
2N/A}
2N/A
2N/A/*
2N/A * convert pass numbers
2N/A */
2N/Aint
2N/Aname_to_pass_num(
2N/A char *uname,
2N/A char *name,
2N/A mm_pass_num_t *passp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if ((sscanf(name, "%hd", passp) != 1) ||
2N/A (*passp < 0) || (*passp > MD_PASS_MAX)) {
2N/A return (meta_cook_syntax(ep, MDE_BAD_PASS_NUM,
2N/A uname, 1, &name));
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * convert resync option
2N/A */
2N/A
2N/Astatic char *
2N/Aresync_opt_to_name(
2N/A uint_t tstate
2N/A)
2N/A{
2N/A if (tstate & MD_ABR_CAP)
2N/A return (dgettext(TEXT_DOMAIN, "application based"));
2N/A else
2N/A return (dgettext(TEXT_DOMAIN, "optimized resync"));
2N/A}
2N/A
2N/A/*
2N/A * print mirror
2N/A */
2N/Astatic int
2N/Amirror_print(
2N/A md_mirror_t *mirrorp,
2N/A char *fname,
2N/A FILE *fp,
2N/A mdprtopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t smi;
2N/A char *p;
2N/A int rval = -1;
2N/A
2N/A
2N/A if (options & PRINT_LARGEDEVICES) {
2N/A if ((mirrorp->common.revision & MD_64BIT_META_DEV) == 0) {
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (options & PRINT_FN) {
2N/A if ((mirrorp->common.revision & MD_FN_META_DEV) == 0) {
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print name and -m */
2N/A if (fprintf(fp, "%s -m", mirrorp->common.namep->cname) == EOF)
2N/A goto out;
2N/A
2N/A /* print submirrors */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep = mdsp->submirnamep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnamep == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A /* print submirror */
2N/A if (fprintf(fp, " %s", submirnamep->rname) == EOF)
2N/A goto out;
2N/A }
2N/A
2N/A /* print options */
2N/A if ((p = rd_opt_to_opt(mirrorp->read_option)) != NULL) {
2N/A if (fprintf(fp, " %s", p) == EOF)
2N/A goto out;
2N/A }
2N/A if ((p = wr_opt_to_opt(mirrorp->write_option)) != NULL) {
2N/A if (fprintf(fp, " %s", p) == EOF)
2N/A goto out;
2N/A }
2N/A if (fprintf(fp, " %u\n", mirrorp->pass_num) == EOF)
2N/A goto out;
2N/A
2N/A /* success */
2N/A rval = 0;
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (rval != 0)
2N/A (void) mdsyserror(ep, errno, fname);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * convert submirror state to name
2N/A */
2N/Achar *
2N/Asm_state_to_name(
2N/A md_submirror_t *mdsp,
2N/A md_status_t mirror_status,
2N/A md_timeval32_t *tvp,
2N/A uint_t tstate
2N/A)
2N/A{
2N/A static char state_to_str[100];
2N/A sm_state_t state = mdsp->state;
2N/A uint_t is_target = mdsp->flags & MD_SM_RESYNC_TARGET;
2N/A
2N/A /* grab time */
2N/A if (tvp != NULL)
2N/A *tvp = mdsp->timestamp;
2N/A
2N/A /*
2N/A * Only return Unavailable if there is no flagged error on the
2N/A * submirror. If the mirror has received any writes since the submirror
2N/A * went into Unavailable state a resync is required. To alert the
2N/A * administrator to this we return a 'Needs maintenance' message.
2N/A */
2N/A if ((tstate != 0) && (state & SMS_RUNNING)) {
2N/A return (dgettext(TEXT_DOMAIN, "Unavailable"));
2N/A }
2N/A
2N/A /* all is well */
2N/A if (state & SMS_RUNNING) {
2N/A if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
2N/A ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target)) {
2N/A return (dgettext(TEXT_DOMAIN, "Okay"));
2N/A }
2N/A }
2N/A
2N/A /* resyncing, needs repair */
2N/A if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
2N/A SMS_OFFLINE_RESYNC)) ||
2N/A (mirror_status & MD_UN_OPT_NOT_DONE)) {
2N/A if (mirror_status & MD_UN_RESYNC_ACTIVE) {
2N/A return (dgettext(TEXT_DOMAIN, "Resyncing"));
2N/A }
2N/A if (mirror_status & MD_UN_RESYNC_CANCEL) {
2N/A return (dgettext(TEXT_DOMAIN, "Resync cancelled"));
2N/A }
2N/A return (dgettext(TEXT_DOMAIN, "Needs maintenance"));
2N/A }
2N/A
2N/A /* needs repair */
2N/A if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) {
2N/A if (mirror_status & MD_UN_RESYNC_CANCEL) {
2N/A return (dgettext(TEXT_DOMAIN, "Resync cancelled"));
2N/A }
2N/A return (dgettext(TEXT_DOMAIN, "Needs maintenance"));
2N/A }
2N/A
2N/A /* unknown */
2N/A assert(0);
2N/A (void) sprintf(state_to_str, "0x%x", state);
2N/A return (state_to_str);
2N/A}
2N/A
2N/A/*
2N/A * convert submirror state to repair action
2N/A */
2N/Aint
2N/Asm_state_to_action(
2N/A mdsetname_t *sp,
2N/A md_submirror_t *mdsp,
2N/A md_status_t mirror_status,
2N/A md_mirror_t *mirrorp,
2N/A char **actionp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A static char buf[1024];
2N/A mdname_t *submirnamep = mdsp->submirnamep;
2N/A sm_state_t state = mdsp->state;
2N/A char *miscname;
2N/A
2N/A /* all is well */
2N/A *actionp = NULL;
2N/A if (mirror_status & MD_UN_RESYNC_ACTIVE)
2N/A return (0);
2N/A if ((state == SMS_RUNNING) && !(mirror_status & MD_UN_OPT_NOT_DONE))
2N/A return (0);
2N/A
2N/A /* complete cancelled resync */
2N/A if (mirror_status & MD_UN_RESYNC_CANCEL) {
2N/A (void) snprintf(buf, sizeof (buf),
2N/A dgettext(TEXT_DOMAIN, "metasync %s"),
2N/A mirrorp->common.namep->cname);
2N/A *actionp = buf;
2N/A return (0);
2N/A }
2N/A
2N/A /* replace stripe component */
2N/A if ((metaismeta(submirnamep)) && (state & SMS_COMP_ERRED)) {
2N/A if ((miscname = metagetmiscname(submirnamep, ep)) == NULL)
2N/A return (-1);
2N/A if (strcmp(miscname, MD_STRIPE) == 0) {
2N/A mdname_t *compnamep;
2N/A comp_state_t compstate;
2N/A
2N/A if (meta_find_erred_comp(sp, submirnamep,
2N/A &compnamep, &compstate, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A if (compstate != CS_LAST_ERRED)
2N/A (void) snprintf(buf, sizeof (buf),
2N/A "metareplace %s %s <%s>",
2N/A mirrorp->common.namep->cname,
2N/A compnamep->cname,
2N/A dgettext(TEXT_DOMAIN, "new device"));
2N/A else
2N/A (void) snprintf(buf, sizeof (buf),
2N/A dgettext(TEXT_DOMAIN,
2N/A "after replacing \"Maintenance\" "
2N/A "components:\n"
2N/A "\t\tmetareplace %s %s <new device>"),
2N/A mirrorp->common.namep->cname,
2N/A compnamep->cname);
2N/A *actionp = buf;
2N/A return (0);
2N/A }
2N/A }
2N/A
2N/A /* resync mirror */
2N/A if ((state & (SMS_ATTACHED_RESYNC | SMS_OFFLINE_RESYNC |
2N/A SMS_COMP_RESYNC | SMS_ATTACHED)) ||
2N/A (mirror_status & MD_UN_OPT_NOT_DONE)) {
2N/A (void) snprintf(buf, sizeof (buf), "metasync %s",
2N/A mirrorp->common.namep->cname);
2N/A *actionp = buf;
2N/A return (0);
2N/A }
2N/A
2N/A /* online submirror */
2N/A if (state & SMS_OFFLINE) {
2N/A (void) snprintf(buf, sizeof (buf), "metaonline %s %s",
2N/A mirrorp->common.namep->cname, submirnamep->cname);
2N/A *actionp = buf;
2N/A return (0);
2N/A }
2N/A
2N/A /* unknown action */
2N/A *actionp = dgettext(TEXT_DOMAIN, "???");
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * print mirror options
2N/A */
2N/Aint
2N/Ameta_print_mirror_options(
2N/A mm_rd_opt_t read_option,
2N/A mm_wr_opt_t write_option,
2N/A mm_pass_num_t pass_num,
2N/A uint_t tstate,
2N/A char *fname,
2N/A mdsetname_t *sp,
2N/A FILE *fp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *p;
2N/A int rval = -1;
2N/A
2N/A /* print options */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Pass: %u\n"),
2N/A pass_num) == EOF) {
2N/A goto out;
2N/A }
2N/A if ((p = rd_opt_to_opt(read_option)) == NULL)
2N/A p = dgettext(TEXT_DOMAIN, "default");
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Read option: %s (%s)\n"),
2N/A rd_opt_to_name(read_option), p) == EOF) {
2N/A goto out;
2N/A }
2N/A if ((p = wr_opt_to_opt(write_option)) == NULL)
2N/A p = dgettext(TEXT_DOMAIN, "default");
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Write option: %s (%s)\n"),
2N/A wr_opt_to_name(write_option), p) == EOF) {
2N/A goto out;
2N/A }
2N/A /* Display resync option for mirror, if MultiNode set */
2N/A if (meta_is_mn_set(sp, ep)) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync option: %s\n"),
2N/A resync_opt_to_name(tstate)) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* success */
2N/A rval = 0;
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (rval != 0)
2N/A (void) mdsyserror(ep, errno, fname);
2N/A return (rval);
2N/A}
2N/A
2N/Astatic char *
2N/Aget_node_name(uint_t nid, md_error_t *ep)
2N/A{
2N/A mndiskset_membershiplist_t *nl, *p;
2N/A int n;
2N/A char *node_nm;
2N/A
2N/A /* get the known membership list */
2N/A if (meta_read_nodelist(&n, &nl, ep)) {
2N/A return (NULL);
2N/A }
2N/A
2N/A /* find the matching node and return the name */
2N/A for (p = nl; (p != NULL); p = p->next) {
2N/A if (nid == p->msl_node_id) {
2N/A /* match found */
2N/A node_nm = Strdup(p->msl_node_name);
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* match not found */
2N/A node_nm = Strdup(dgettext(TEXT_DOMAIN, "None"));
2N/A
2N/Aout:
2N/A meta_free_nodelist(nl);
2N/A return (node_nm);
2N/A}
2N/A
2N/A/*
2N/A * report mirror
2N/A */
2N/Astatic int
2N/Amirror_report(
2N/A mdsetname_t *sp,
2N/A md_mirror_t *mirrorp,
2N/A mdnamelist_t **nlpp,
2N/A char *fname,
2N/A FILE *fp,
2N/A mdprtopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_status_t status = mirrorp->common.state;
2N/A uint_t smi;
2N/A char *p;
2N/A int rval = -1;
2N/A uint_t tstate = 0;
2N/A
2N/A /*
2N/A * check for the -B option. If -B and the metadevice is
2N/A * a 64 bit device, get the dev for relocation information
2N/A * printout. If not a 64 bit device, just don't print this
2N/A * information out but you need to go down to the subdevice
2N/A * level and print there if appropriate.
2N/A */
2N/A if (options & PRINT_LARGEDEVICES) {
2N/A if ((mirrorp->common.revision & MD_64BIT_META_DEV) == 0) {
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp =
2N/A &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep =
2N/A mdsp->submirnamep;
2N/A if (submirnamep == NULL) {
2N/A continue;
2N/A }
2N/A if ((metaismeta(submirnamep)) &&
2N/A (meta_print_name(sp, submirnamep, nlpp,
2N/A fname, fp, options | PRINT_SUBDEVS, NULL,
2N/A ep) != 0)) {
2N/A return (-1);
2N/A }
2N/A }
2N/A rval = 0;
2N/A goto out;
2N/A } else {
2N/A if (meta_getdevs(sp, mirrorp->common.namep,
2N/A nlpp, ep) != 0)
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * check for the -D option. If -D and the name is
2N/A * a descriptive name, get the dev for relocation information
2N/A * printout. If not a descriptive name, don't print this
2N/A * information out but you need to go down to the subdevice
2N/A * level and print there if appropriate.
2N/A */
2N/A if (options & PRINT_FN) {
2N/A if ((mirrorp->common.revision & MD_FN_META_DEV) == 0) {
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp =
2N/A &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep =
2N/A mdsp->submirnamep;
2N/A if (submirnamep == NULL) {
2N/A continue;
2N/A }
2N/A if ((metaismeta(submirnamep)) &&
2N/A (meta_print_name(sp, submirnamep, nlpp,
2N/A fname, fp, options | PRINT_SUBDEVS, NULL,
2N/A ep) != 0)) {
2N/A return (-1);
2N/A }
2N/A }
2N/A rval = 0;
2N/A goto out;
2N/A } else {
2N/A if (meta_getdevs(sp, mirrorp->common.namep,
2N/A nlpp, ep) != 0)
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print header */
2N/A if (options & PRINT_HEADER) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Mirror\n"),
2N/A mirrorp->common.namep->cname) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print submirrors, adjust status */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep = mdsp->submirnamep;
2N/A char *sm_state;
2N/A md_timeval32_t tv;
2N/A char *timep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnamep == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A if (mdsp->state & SMS_OFFLINE)
2N/A status &= ~MD_UN_OPT_NOT_DONE;
2N/A
2N/A /* print submirror */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Submirror %u: %s\n"),
2N/A smi, submirnamep->cname) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* print state */
2N/A if (metaismeta(mdsp->submirnamep)) {
2N/A if (meta_get_tstate(mdsp->submirnamep->dev, &tstate,
2N/A ep) != 0)
2N/A return (-1);
2N/A }
2N/A sm_state = sm_state_to_name(mdsp, status, &tv,
2N/A tstate & MD_DEV_ERRORED);
2N/A if (options & PRINT_TIMES) {
2N/A timep = meta_print_time(&tv);
2N/A } else {
2N/A timep = "";
2N/A }
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " State: %-12s %s\n"),
2N/A sm_state, timep) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print resync status */
2N/A if (status & MD_UN_RESYNC_CANCEL) {
2N/A /* Resync was cancelled but is restartable */
2N/A if (mirrorp->common.revision & MD_64BIT_META_DEV) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync cancelled: %2d.%1d %% done\n"),
2N/A mirrorp->percent_done/10,
2N/A mirrorp->percent_done%10) == EOF) {
2N/A goto out;
2N/A }
2N/A } else {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync cancelled: %d %% done\n"),
2N/A mirrorp->percent_done) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A } else if (status & MD_UN_RESYNC_ACTIVE) {
2N/A if (mirrorp->common.revision & MD_64BIT_META_DEV) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync in progress: %2d.%1d %% done\n"),
2N/A mirrorp->percent_done/10,
2N/A mirrorp->percent_done%10) == EOF) {
2N/A goto out;
2N/A }
2N/A } else {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync in progress: %d %% done\n"),
2N/A mirrorp->percent_done) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* print options */
2N/A if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
2N/A return (-1);
2N/A
2N/A if (meta_print_mirror_options(mirrorp->read_option,
2N/A mirrorp->write_option, mirrorp->pass_num,
2N/A tstate, fname, sp, fp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* print mirror owner for multi-node metadevice */
2N/A if (meta_is_mn_set(sp, ep)) {
2N/A md_set_mmown_params_t ownpar;
2N/A mdname_t *mirnp = mirrorp->common.namep;
2N/A char *node_name;
2N/A
2N/A (void) memset(&ownpar, 0, sizeof (ownpar));
2N/A ownpar.d.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&ownpar, MD_MIRROR, sp->setno);
2N/A
2N/A if (metaioctl(MD_MN_GET_MM_OWNER, &ownpar, ep,
2N/A "MD_MN_GET_MM_OWNER") != 0) {
2N/A return (-1);
2N/A }
2N/A
2N/A node_name = get_node_name(ownpar.d.owner, ep);
2N/A if (node_name == NULL)
2N/A return (-1);
2N/A else if (fprintf(fp, dgettext(TEXT_DOMAIN, " Owner: %s\n"),
2N/A node_name) == EOF) {
2N/A Free(node_name);
2N/A goto out;
2N/A }
2N/A Free(node_name);
2N/A
2N/A }
2N/A
2N/A /* print size */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %lld blocks (%s)\n"),
2N/A mirrorp->common.size,
2N/A meta_number_to_string(mirrorp->common.size, DEV_BSIZE))
2N/A == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* MD_DEBUG stuff */
2N/A if (options & PRINT_DEBUG) {
2N/A mdname_t *mirnp = mirrorp->common.namep;
2N/A mm_unit_t *mm;
2N/A mddb_optloc_t optloc;
2N/A uint_t i;
2N/A
2N/A /* get real mirror unit */
2N/A if ((mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, ep))
2N/A == NULL) {
2N/A return (-1);
2N/A }
2N/A assert(mm->c.un_type == MD_METAMIRROR);
2N/A
2N/A /* print dirty regions */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A" Regions which are dirty: %d%% (blksize %d num %d)\n"),
2N/A mirrorp->percent_dirty, mm->un_rrd_blksize,
2N/A mm->un_rrd_num) == EOF) {
2N/A Free(mm);
2N/A goto out;
2N/A }
2N/A
2N/A /* print optimized resync record locations */
2N/A (void) memset(&optloc, 0, sizeof (optloc));
2N/A optloc.recid = mm->un_rr_dirty_recid;
2N/A if (metaioctl(MD_DB_GETOPTLOC, &optloc, ep,
2N/A "MD_DB_GETOPTLOC") != 0) {
2N/A Free(mm);
2N/A return (-1);
2N/A }
2N/A for (i = 0; (i < ((sizeof optloc.li) / sizeof (optloc.li[0])));
2N/A ++i) {
2N/A mddb_config_t dbconf;
2N/A char *devname;
2N/A
2N/A (void) memset(&dbconf, 0, sizeof (dbconf));
2N/A dbconf.c_id = optloc.li[i];
2N/A dbconf.c_setno = sp->setno;
2N/A dbconf.c_subcmd = MDDB_CONFIG_ABS;
2N/A /* Don't need device id information from this ioctl */
2N/A dbconf.c_locator.l_devid = (uint64_t)0;
2N/A dbconf.c_locator.l_devid_flags = 0;
2N/A if (metaioctl(MD_DB_ENDDEV, &dbconf, &dbconf.c_mde,
2N/A "MD_DB_ENDDEV") != 0) {
2N/A Free(mm);
2N/A return (mdstealerror(ep, &dbconf.c_mde));
2N/A }
2N/A if ((devname = splicename(&dbconf.c_devname))
2N/A == NULL) {
2N/A devname = Strdup(dgettext(TEXT_DOMAIN,
2N/A "unknown"));
2N/A }
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync record[%u]: %d (%s %d %d)\n"), i,
2N/A optloc.li[i], devname, dbconf.c_locator.l_blkno,
2N/A (dbconf.c_dbend - dbconf.c_locator.l_blkno + 1))
2N/A == EOF) {
2N/A Free(mm);
2N/A Free(devname);
2N/A goto out;
2N/A }
2N/A Free(devname);
2N/A }
2N/A Free(mm);
2N/A }
2N/A
2N/A /* print submirror details */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep = mdsp->submirnamep;
2N/A char *sm_state;
2N/A md_timeval32_t tv;
2N/A char *timep;
2N/A md_stripe_t *stripep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnamep == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A if (options & PRINT_FN) {
2N/A /* get unit structure */
2N/A if ((stripep = meta_get_stripe_common(sp, submirnamep,
2N/A ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
2N/A goto out;
2N/A
2N/A if ((stripep->common.revision & MD_FN_META_DEV)
2N/A == 0)
2N/A continue;
2N/A }
2N/A
2N/A /* add extra line */
2N/A if (fprintf(fp, "\n") == EOF)
2N/A goto out;
2N/A
2N/A /* print submirror */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A "%s: Submirror of %s\n"),
2N/A submirnamep->cname,
2N/A mirrorp->common.namep->cname) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* print state */
2N/A if (metaismeta(mdsp->submirnamep)) {
2N/A if (meta_get_tstate(mdsp->submirnamep->dev, &tstate, ep)
2N/A != 0)
2N/A return (-1);
2N/A }
2N/A sm_state = sm_state_to_name(mdsp, status, &tv, NULL);
2N/A if (options & PRINT_TIMES) {
2N/A timep = meta_print_time(&tv);
2N/A } else {
2N/A timep = "";
2N/A }
2N/A
2N/A if ((tstate & MD_DEV_ERRORED) == 0) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " State: %-12s %s\n"),
2N/A sm_state, timep) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* print what to do */
2N/A if (sm_state_to_action(sp, mdsp, status,
2N/A mirrorp, &p, ep) != 0)
2N/A return (-1);
2N/A if ((p != NULL) &&
2N/A (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Invoke: %s\n"), p) == EOF)) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print underlying metadevice */
2N/A if ((metaismeta(submirnamep)) &&
2N/A (meta_print_name(sp, submirnamep, nlpp, fname, fp,
2N/A ((options & ~PRINT_HEADER) | PRINT_SUBDEVS),
2N/A NULL, ep) != 0)) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* add extra line */
2N/A if (fprintf(fp, "\n") == EOF)
2N/A goto out;
2N/A
2N/A /* success */
2N/A rval = 0;
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (rval != 0)
2N/A (void) mdsyserror(ep, errno, fname);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * print/report mirror
2N/A */
2N/Aint
2N/Ameta_mirror_print(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdnamelist_t **nlpp,
2N/A char *fname,
2N/A FILE *fp,
2N/A mdprtopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert((mirnp == NULL) ||
2N/A (sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev))));
2N/A
2N/A /* print all mirrors */
2N/A if (mirnp == NULL) {
2N/A mdnamelist_t *nlp = NULL;
2N/A mdnamelist_t *p;
2N/A int cnt;
2N/A int rval = 0;
2N/A
2N/A /* get list */
2N/A if ((cnt = meta_get_mirror_names(sp, &nlp, options, ep)) < 0)
2N/A return (-1);
2N/A else if (cnt == 0)
2N/A return (0);
2N/A
2N/A /* recurse */
2N/A for (p = nlp; (p != NULL); p = p->next) {
2N/A mdname_t *np = p->namep;
2N/A
2N/A if (meta_mirror_print(sp, np, nlpp, fname, fp,
2N/A options, ep) != 0)
2N/A rval = -1;
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/A metafreenamelist(nlp);
2N/A return (rval);
2N/A }
2N/A
2N/A /* get unit structure */
2N/A if ((mirrorp = meta_get_mirror_common(sp, mirnp,
2N/A ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* check for parented */
2N/A if ((! (options & PRINT_SUBDEVS)) &&
2N/A (MD_HAS_PARENT(mirrorp->common.parent))) {
2N/A return (0);
2N/A }
2N/A
2N/A /* print appropriate detail */
2N/A if (options & PRINT_SHORT) {
2N/A /* print mirror */
2N/A if (mirror_print(mirrorp, fname, fp, options, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* print underlying metadevices */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep = mdsp->submirnamep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnamep == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A /* print submirror */
2N/A if (metaismeta(submirnamep)) {
2N/A if (meta_print_name(sp, submirnamep, nlpp,
2N/A fname, fp, (options | PRINT_SUBDEVS), NULL,
2N/A ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A } else {
2N/A return (mirror_report(sp, mirrorp, nlpp, fname, fp,
2N/A options, ep));
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * online submirror
2N/A */
2N/Aint
2N/Ameta_mirror_online(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *submirnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_i_off_on_t mio;
2N/A md_mirror_t *mirrorp;
2N/A md_set_desc *sd;
2N/A uint_t tstate;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* Only valid for mirror without ABR set */
2N/A if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
2N/A return (-1);
2N/A if (tstate & MD_ABR_CAP) {
2N/A (void) mderror(ep, MDE_ABR_SET, NULL);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * In a MN set, the master always executes the online command first.
2N/A * Before the master executes the IOC_ONLINE ioctl,
2N/A * the master sends a message to all nodes to suspend writes to
2N/A * this mirror. Then the master executes the IOC_ONLINE ioctl
2N/A * which resumes writes to this mirror from the master node.
2N/A * As each slave executes the online command, each slave will
2N/A * call the IOC_ONLINE ioctl which will resume writes to this mirror
2N/A * from that slave node.
2N/A */
2N/A if (! metaislocalset(sp)) {
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
2N/A if (meta_mn_send_suspend_writes(
2N/A meta_getminor(mirnp->dev), ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* online submirror */
2N/A (void) memset(&mio, 0, sizeof (mio));
2N/A mio.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&mio, MD_MIRROR, sp->setno);
2N/A mio.submirror = submirnp->dev;
2N/A if (metaioctl(MD_IOCONLINE, &mio, &mio.mde, NULL) != 0)
2N/A return (mdstealerror(ep, &mio.mde));
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(mirnp);
2N/A meta_invalidate_name(submirnp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: submirror %s is onlined\n"),
2N/A mirnp->cname, submirnp->cname);
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * offline submirror
2N/A */
2N/Aint
2N/Ameta_mirror_offline(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *submirnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A int force = ((options & MDCMD_FORCE) ? 1 : 0);
2N/A md_i_off_on_t mio;
2N/A md_mirror_t *mirrorp;
2N/A md_set_desc *sd;
2N/A uint_t tstate;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* Only valid for mirror without ABR set */
2N/A if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
2N/A return (-1);
2N/A if (tstate & MD_ABR_CAP) {
2N/A (void) mderror(ep, MDE_ABR_SET, NULL);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * In a MN set, the master always executes the offline command first.
2N/A * Before the master executes the IOC_OFFLINE ioctl,
2N/A * the master sends a message to all nodes to suspend writes to
2N/A * this mirror. Then the master executes the IOC_OFFLINE ioctl
2N/A * which resumes writes to this mirror from the master node.
2N/A * As each slave executes the offline command, each slave will
2N/A * call the IOC_OFFLINE ioctl which will resume writes to this mirror
2N/A * from that slave node.
2N/A */
2N/A if (! metaislocalset(sp)) {
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
2N/A if (meta_mn_send_suspend_writes(
2N/A meta_getminor(mirnp->dev), ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* offline submirror */
2N/A (void) memset(&mio, 0, sizeof (mio));
2N/A mio.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&mio, MD_MIRROR, sp->setno);
2N/A mio.submirror = submirnp->dev;
2N/A mio.force_offline = force;
2N/A if (metaioctl(MD_IOCOFFLINE, &mio, &mio.mde, NULL) != 0)
2N/A return (mdstealerror(ep, &mio.mde));
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(mirnp);
2N/A meta_invalidate_name(submirnp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: submirror %s is offlined\n"),
2N/A mirnp->cname, submirnp->cname);
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * attach submirror to mirror
2N/A * we actually never have to worry about crossing a thresh hold here.
2N/A * 2 cases 1) attach and the only way the mirror can be 64 bit is if
2N/A * one of the submirrors already is. 2) grow and the only way the mirror
2N/A * is 64 bit is if one of the submirror's already is.
2N/A */
2N/Aint
2N/Ameta_mirror_attach(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *submirnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_att_struct_t att;
2N/A md_set_desc *sd;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* just grow */
2N/A if (submirnp == NULL) {
2N/A return (meta_concat_generic(sp, mirnp, NULL, ep));
2N/A }
2N/A
2N/A /* check submirror */
2N/A if (meta_check_submirror(sp, submirnp, mirnp, 0, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* In dryrun mode (DOIT not set) we must not alter the mddb */
2N/A if (options & MDCMD_DOIT) {
2N/A /* store name in namespace */
2N/A if (add_key_name(sp, submirnp, NULL, ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * In a MN set, the master always executes the attach command first.
2N/A * Before the master executes the IOC_ATTACH ioctl, in non-DRYRUN mode
2N/A * the master sends a message to all nodes to suspend writes to
2N/A * this mirror. Then the master executes the IOC_ATTACH ioctl
2N/A * which resumes writes to this mirror from the master node.
2N/A * As each slave executes the attach command, each slave will
2N/A * call the IOC_ATTACH ioctl which will resume writes to this mirror
2N/A * from that slave node.
2N/A */
2N/A if (! metaislocalset(sp)) {
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
2N/A sd->sd_mn_am_i_master)
2N/A if (meta_mn_send_suspend_writes(
2N/A meta_getminor(mirnp->dev), ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* attach submirror */
2N/A (void) memset(&att, 0, sizeof (att));
2N/A att.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&att, MD_MIRROR, sp->setno);
2N/A att.submirror = submirnp->dev;
2N/A att.key = submirnp->key;
2N/A /* if the comamnd was issued with -n option, use dryrun mode */
2N/A if ((options & MDCMD_DOIT) == 0) {
2N/A att.options = MDIOCTL_DRYRUN;
2N/A }
2N/A if (metaioctl(MD_IOCATTACH, &att, &att.mde, NULL) != 0) {
2N/A /* In dryrun mode (DOIT not set) we must not alter the mddb */
2N/A if (options & MDCMD_DOIT) {
2N/A (void) del_key_name(sp, submirnp, ep);
2N/A }
2N/A return (mdstealerror(ep, &att.mde));
2N/A }
2N/A
2N/A /* In dryrun mode (DOIT not set) we must not alter the mddb */
2N/A if (options & MDCMD_DOIT) {
2N/A /* clear cache */
2N/A meta_invalidate_name(mirnp);
2N/A meta_invalidate_name(submirnp);
2N/A }
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: submirror %s %s\n"), mirnp->cname, submirnp->cname,
2N/A (options & MDCMD_DOIT) ? "is attached" : "would attach");
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * detach submirror
2N/A */
2N/Aint
2N/Ameta_mirror_detach(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *submirnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A int force = ((options & MDCMD_FORCE) ? 1 : 0);
2N/A md_detach_params_t detach;
2N/A md_set_desc *sd;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /*
2N/A * In a MN set, the master always executes the detach command first.
2N/A * Before the master executes the IOC_DETACH ioctl,
2N/A * the master sends a message to all nodes to suspend writes to
2N/A * this mirror. Then the master executes the IOC_DETACH ioctl
2N/A * which resumes writes to this mirror from the master node.
2N/A * As each slave executes the detach command, each slave will
2N/A * call the IOC_DETACH ioctl which will resume writes to this mirror
2N/A * from that slave node.
2N/A */
2N/A if (! metaislocalset(sp)) {
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
2N/A if (meta_mn_send_suspend_writes(
2N/A meta_getminor(mirnp->dev), ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* detach submirror */
2N/A (void) memset(&detach, 0, sizeof (detach));
2N/A detach.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&detach, MD_MIRROR, sp->setno);
2N/A detach.submirror = submirnp->dev;
2N/A detach.force_detach = force;
2N/A if (metaioctl(MD_IOCDETACH, &detach, &detach.mde, NULL) != 0)
2N/A return (mdstealerror(ep, &detach.mde));
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(mirnp);
2N/A meta_invalidate_name(submirnp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: submirror %s is detached\n"),
2N/A mirnp->cname, submirnp->cname);
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * get mirror parameters
2N/A */
2N/Aint
2N/Ameta_mirror_get_params(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mm_params_t *paramsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get unit */
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* return parameters */
2N/A (void) memset(paramsp, 0, sizeof (*paramsp));
2N/A paramsp->read_option = mirrorp->read_option;
2N/A paramsp->write_option = mirrorp->write_option;
2N/A paramsp->pass_num = mirrorp->pass_num;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * set mirror parameters
2N/A */
2N/Aint
2N/Ameta_mirror_set_params(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mm_params_t *paramsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_params_t mmp;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* set parameters */
2N/A (void) memset(&mmp, 0, sizeof (mmp));
2N/A MD_SETDRIVERNAME(&mmp, MD_MIRROR, sp->setno);
2N/A mmp.mnum = meta_getminor(mirnp->dev);
2N/A mmp.params = *paramsp;
2N/A if (metaioctl(MD_IOCCHANGE, &mmp, &mmp.mde, mirnp->cname) != 0)
2N/A return (mdstealerror(ep, &mmp.mde));
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(mirnp);
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * invalidate submirror names
2N/A */
2N/Astatic int
2N/Ainvalidate_submirrors(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi;
2N/A
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A if (submirnp == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A meta_invalidate_name(submirnp);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * replace mirror component
2N/A */
2N/Aint
2N/Ameta_mirror_replace(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *oldnp,
2N/A mdname_t *newnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi;
2N/A replace_params_t params;
2N/A diskaddr_t size, label, start_blk;
2N/A md_dev64_t old_dev, new_dev;
2N/A diskaddr_t new_start_blk, new_end_blk;
2N/A int rebind;
2N/A md_set_desc *sd;
2N/A char *new_devidp = NULL;
2N/A int ret;
2N/A md_error_t xep = mdnullerror;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* save new binding incase this is a rebind where oldnp==newnp */
2N/A new_dev = newnp->dev;
2N/A new_start_blk = newnp->start_blk;
2N/A new_end_blk = newnp->end_blk;
2N/A
2N/A /* invalidate, then get the mirror (fill in oldnp from metadb) */
2N/A meta_invalidate_name(mirnp);
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A if (submirnp == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A if (! metaismeta(submirnp))
2N/A continue;
2N/A
2N/A meta_invalidate_name(submirnp);
2N/A if (meta_get_unit(sp, submirnp, ep) == NULL)
2N/A return (-1);
2N/A }
2N/A
2N/A /* the old device binding is now established */
2N/A if ((old_dev = oldnp->dev) == NODEV64)
2N/A return (mdsyserror(ep, ENODEV, oldnp->cname));
2N/A
2N/A /*
2N/A * check for the case where oldnp and newnp indicate the same
2N/A * device, but the dev_t of the device has changed between old
2N/A * and new. This is called a rebind. On entry the dev_t
2N/A * represents the new device binding determined from the
2N/A * filesystem (meta_getdev). After calling meta_get_unit
2N/A * oldnp (and maybe newnp if this is a rebind) is updated based
2N/A * to the old binding from the metadb (done by metakeyname).
2N/A */
2N/A if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
2N/A (old_dev != new_dev)) {
2N/A rebind = 1;
2N/A } else {
2N/A rebind = 0;
2N/A }
2N/A if (rebind) {
2N/A newnp->dev = new_dev;
2N/A newnp->start_blk = new_start_blk;
2N/A newnp->end_blk = new_end_blk;
2N/A }
2N/A
2N/A /*
2N/A * Save a copy of the devid associated with the new disk, the reason
2N/A * is that if we are rebinding then the call to meta_check_component()
2N/A * will cause the devid of the disk to be overwritten with what is in
2N/A * the replica namespace. The function that actually overwrites the
2N/A * devid is dr2drivedesc().
2N/A */
2N/A if (newnp->drivenamep->devid != NULL)
2N/A new_devidp = Strdup(newnp->drivenamep->devid);
2N/A
2N/A /* if it's a multi-node diskset clear new_devidp */
2N/A if (!metaislocalset(sp)) {
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A }
2N/A
2N/A /* check it out (dup on rebind is ok) */
2N/A if (meta_check_component(sp, newnp, 0, ep) != 0) {
2N/A if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
2N/A Free(new_devidp);
2N/A return (-1);
2N/A }
2N/A mdclrerror(ep);
2N/A }
2N/A if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
2N/A Free(new_devidp);
2N/A return (-1);
2N/A }
2N/A if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
2N/A Free(new_devidp);
2N/A return (-1);
2N/A }
2N/A if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
2N/A Free(new_devidp);
2N/A return (-1);
2N/A }
2N/A if (start_blk >= size) {
2N/A (void) mdsyserror(ep, ENOSPC, newnp->cname);
2N/A Free(new_devidp);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Copy back the saved devid.
2N/A */
2N/A Free(newnp->drivenamep->devid);
2N/A if (new_devidp != NULL) {
2N/A newnp->drivenamep->devid = Strdup(new_devidp);
2N/A Free(new_devidp);
2N/A }
2N/A
2N/A /* store name in namespace, allocate new key */
2N/A if (add_key_name(sp, newnp, NULL, ep) != 0)
2N/A return (-1);
2N/A
2N/A /*
2N/A * In a MN set, the master always executes the replace command first.
2N/A * Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
2N/A * the master sends a message to all nodes to suspend writes to
2N/A * this mirror. Then the master executes the IOC_REPLACE ioctl
2N/A * which resumes writes to this mirror from the master node.
2N/A * As each slave executes the replace command, each slave will
2N/A * call the IOC_REPLACE ioctl which will resume writes to this mirror
2N/A * from that slave node.
2N/A */
2N/A if (! metaislocalset(sp)) {
2N/A if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
2N/A sd->sd_mn_am_i_master)
2N/A if (meta_mn_send_suspend_writes(
2N/A meta_getminor(mirnp->dev), ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A if (rebind && !metaislocalset(sp)) {
2N/A /*
2N/A * We are 'rebind'ing a disk that is in a diskset so as well
2N/A * as updating the diskset's namespace the local set needs
2N/A * to be updated because it also contains a reference to
2N/A * the disk in question.
2N/A */
2N/A ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
2N/A newnp->cname, ep);
2N/A
2N/A if (ret != METADEVADM_SUCCESS) {
2N/A (void) del_key_name(sp, newnp, &xep);
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* replace component */
2N/A (void) memset(&params, 0, sizeof (params));
2N/A params.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&params, MD_MIRROR, sp->setno);
2N/A params.cmd = REPLACE_COMP;
2N/A params.old_dev = old_dev;
2N/A params.new_dev = new_dev;
2N/A params.start_blk = start_blk;
2N/A params.has_label = ((label > 0) ? 1 : 0);
2N/A params.number_blks = size;
2N/A params.new_key = newnp->key;
2N/A /* Is this just a dryrun ? */
2N/A if ((options & MDCMD_DOIT) == 0) {
2N/A params.options |= MDIOCTL_DRYRUN;
2N/A }
2N/A if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
2N/A (void) del_key_name(sp, newnp, ep);
2N/A return (mdstealerror(ep, &params.mde));
2N/A }
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(oldnp);
2N/A meta_invalidate_name(newnp);
2N/A if (invalidate_submirrors(sp, mirnp, ep) != 0) {
2N/A meta_invalidate_name(mirnp);
2N/A return (-1);
2N/A }
2N/A meta_invalidate_name(mirnp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: device %s is replaced with %s\n"),
2N/A mirnp->cname, oldnp->cname, newnp->cname);
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * enable mirror component
2N/A */
2N/Aint
2N/Ameta_mirror_enable(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdname_t *compnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi;
2N/A replace_params_t params;
2N/A diskaddr_t size, label, start_blk;
2N/A md_dev64_t fs_dev;
2N/A md_set_desc *sd;
2N/A int ret;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get the file_system dev binding */
2N/A if (meta_getdev(sp, compnp, ep) != 0)
2N/A return (-1);
2N/A fs_dev = compnp->dev;
2N/A
2N/A /* get the mirror unit (fill in compnp->dev with metadb version) */
2N/A meta_invalidate_name(mirnp);
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A if (submirnp == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A if (! metaismeta(submirnp))
2N/A continue;
2N/A
2N/A meta_invalidate_name(submirnp);
2N/A if (meta_get_unit(sp, submirnp, ep) == NULL)
2N/A return (-1);
2N/A }
2N/A
2N/A /* the metadb device binding is now established */
2N/A if (compnp->dev == NODEV64)
2N/A return (mdsyserror(ep, ENODEV, compnp->cname));
2N/A
2N/A /*
2N/A * check for the case where the dev_t has changed between the
2N/A * filesystem and the metadb. This is called a rebind, and
2N/A * is handled by meta_mirror_replace.
2N/A */
2N/A if (fs_dev != compnp->dev) {
2N/A /* establish file system binding with invalid start/end */
2N/A compnp->dev = fs_dev;
2N/A compnp->start_blk = -1;
2N/A compnp->end_blk = -1;
2N/A return (meta_mirror_replace(sp, mirnp,
2N/A compnp, compnp, options, ep));
2N/A }
2N/A
2N/A /* setup mirror info */
2N/A (void) memset(&params, 0, sizeof (params));
2N/A params.mnum = meta_getminor(mirnp->dev);
2N/A MD_SETDRIVERNAME(&params, MD_MIRROR, sp->setno);
2N/A params.cmd = ENABLE_COMP;
2N/A
2N/A /* check it out */
2N/A if (meta_check_component(sp, compnp, 0, ep) != 0) {
2N/A if (! mdisuseerror(ep, MDE_ALREADY))
2N/A return (-1);
2N/A mdclrerror(ep);
2N/A }
2N/A
2N/A if ((size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((label = metagetlabel(compnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((start_blk = metagetstart(sp, compnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if (start_blk >= size) {
2N/A (void) mdsyserror(ep, ENOSPC, compnp->cname);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * In a MN set, the master always executes the replace command first.
2N/A * Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
2N/A * the master sends a message to all nodes to suspend writes to
2N/A * this mirror. Then the master executes the IOC_REPLACE ioctl
2N/A * which resumes writes to this mirror from the master node.
2N/A * As each slave executes the replace command, each slave will
2N/A * call the IOC_REPLACE ioctl which will resume writes to this mirror
2N/A * from that slave node.
2N/A */
2N/A if (! metaislocalset(sp)) {
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
2N/A sd->sd_mn_am_i_master)
2N/A if (meta_mn_send_suspend_writes(
2N/A meta_getminor(mirnp->dev), ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* enable component */
2N/A params.old_dev = compnp->dev;
2N/A params.new_dev = compnp->dev;
2N/A params.start_blk = start_blk;
2N/A params.has_label = ((label > 0) ? 1 : 0);
2N/A params.number_blks = size;
2N/A
2N/A /* Is this just a dryrun ? */
2N/A if ((options & MDCMD_DOIT) == 0) {
2N/A params.options |= MDIOCTL_DRYRUN;
2N/A }
2N/A if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0)
2N/A return (mdstealerror(ep, &params.mde));
2N/A
2N/A /*
2N/A * Are we dealing with a non-local set? If so need to update the
2N/A * local namespace so that the disk record has the correct devid.
2N/A */
2N/A if (!metaislocalset(sp)) {
2N/A ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, compnp->cname,
2N/A ep);
2N/A
2N/A if (ret != METADEVADM_SUCCESS) {
2N/A /*
2N/A * Failed to update the local set. Nothing to do here
2N/A * apart from report the error. The namespace is
2N/A * most likely broken and some form of remedial
2N/A * recovery is going to be required.
2N/A */
2N/A mde_perror(ep, "");
2N/A mdclrerror(ep);
2N/A }
2N/A }
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(compnp);
2N/A if (invalidate_submirrors(sp, mirnp, ep) != 0) {
2N/A meta_invalidate_name(mirnp);
2N/A return (-1);
2N/A }
2N/A meta_invalidate_name(mirnp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: device %s is enabled\n"),
2N/A mirnp->cname, compnp->cname);
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check for dups in the mirror itself
2N/A */
2N/Astatic int
2N/Acheck_twice(
2N/A md_mirror_t *mirrorp,
2N/A uint_t smi,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *mirnp = mirrorp->common.namep;
2N/A mdname_t *thisnp;
2N/A uint_t s;
2N/A
2N/A thisnp = mirrorp->submirrors[smi].submirnamep;
2N/A for (s = 0; (s < smi); ++s) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[s];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A if (submirnp == NULL)
2N/A continue;
2N/A
2N/A if (meta_check_overlap(mirnp->cname, thisnp, 0, -1,
2N/A submirnp, 0, -1, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check mirror
2N/A */
2N/Aint
2N/Ameta_check_mirror(
2N/A mdsetname_t *sp,
2N/A md_mirror_t *mirrorp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *mirnp = mirrorp->common.namep;
2N/A int force = ((options & MDCMD_FORCE) ? 1 : 0);
2N/A int doit = ((options & MDCMD_DOIT) ? 1 : 0);
2N/A uint_t nsm = 0;
2N/A uint_t smi;
2N/A
2N/A /* check submirrors */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A if (submirnp == NULL)
2N/A continue;
2N/A ++nsm;
2N/A }
2N/A if (nsm < 1) {
2N/A return (mdmderror(ep, MDE_BAD_MIRROR,
2N/A meta_getminor(mirnp->dev), mirnp->cname));
2N/A }
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A diskaddr_t size;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnp == NULL) {
2N/A if (mdsp->state != SMS_UNUSED) {
2N/A return (mdmderror(ep, MDE_BAD_MIRROR,
2N/A meta_getminor(mirnp->dev), mirnp->cname));
2N/A }
2N/A continue;
2N/A }
2N/A
2N/A /* check submirror */
2N/A if (doit) {
2N/A if (meta_check_submirror(sp, submirnp, NULL, force,
2N/A ep) != 0)
2N/A return (-1);
2N/A if ((size = metagetsize(submirnp, ep)) ==
2N/A MD_DISKADDR_ERROR) {
2N/A return (-1);
2N/A } else if (size == 0) {
2N/A return (mdsyserror(ep, ENOSPC,
2N/A submirnp->cname));
2N/A }
2N/A }
2N/A
2N/A /* check this mirror too */
2N/A if (check_twice(mirrorp, smi, ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* check read option */
2N/A switch (mirrorp->read_option) {
2N/A case RD_LOAD_BAL:
2N/A case RD_GEOMETRY:
2N/A case RD_FIRST:
2N/A break;
2N/A default:
2N/A return (mderror(ep, MDE_BAD_RD_OPT, mirnp->cname));
2N/A }
2N/A
2N/A /* check write option */
2N/A switch (mirrorp->write_option) {
2N/A case WR_PARALLEL:
2N/A case WR_SERIAL:
2N/A break;
2N/A default:
2N/A return (mderror(ep, MDE_BAD_WR_OPT, mirnp->cname));
2N/A }
2N/A
2N/A /* check pass number */
2N/A if ((mirrorp->pass_num < 0) || (mirrorp->pass_num > MD_PASS_MAX))
2N/A return (mderror(ep, MDE_BAD_PASS_NUM, mirnp->cname));
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * setup mirror geometry
2N/A */
2N/Astatic int
2N/Amirror_geom(
2N/A md_mirror_t *mirrorp,
2N/A mm_unit_t *mm,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t write_reinstruct = 0;
2N/A uint_t read_reinstruct = 0;
2N/A uint_t round_cyl = 1;
2N/A mdname_t *smnp = NULL;
2N/A uint_t smi;
2N/A mdgeom_t *geomp;
2N/A
2N/A /* get worst reinstructs */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A if (submirnp == NULL)
2N/A continue;
2N/A
2N/A if ((geomp = metagetgeom(submirnp, ep)) == NULL)
2N/A return (-1);
2N/A if (geomp->write_reinstruct > write_reinstruct)
2N/A write_reinstruct = geomp->write_reinstruct;
2N/A if (geomp->read_reinstruct > read_reinstruct)
2N/A read_reinstruct = geomp->read_reinstruct;
2N/A
2N/A if (smnp == NULL)
2N/A smnp = submirnp;
2N/A }
2N/A
2N/A /* setup geometry from first submirror */
2N/A assert(smnp != NULL);
2N/A if ((geomp = metagetgeom(smnp, ep)) == NULL)
2N/A return (-1);
2N/A if (meta_setup_geom((md_unit_t *)mm, mirrorp->common.namep, geomp,
2N/A write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * create mirror
2N/A */
2N/Aint
2N/Ameta_create_mirror(
2N/A mdsetname_t *sp,
2N/A md_mirror_t *mirrorp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *mirnp = mirrorp->common.namep;
2N/A mm_unit_t *mm;
2N/A diskaddr_t submir_size = MD_DISKADDR_ERROR;
2N/A ushort_t nsm = 0;
2N/A uint_t smi;
2N/A mdnamelist_t *keynlp = NULL;
2N/A md_set_params_t set_params;
2N/A int rval = -1;
2N/A md_timeval32_t creation_time;
2N/A int create_flag = MD_CRO_32BIT;
2N/A
2N/A /* validate mirror */
2N/A if (meta_check_mirror(sp, mirrorp, options, ep) != 0)
2N/A return (-1);
2N/A
2N/A
2N/A /* allocate mirror unit */
2N/A mm = Zalloc(sizeof (*mm));
2N/A
2N/A if (meta_gettimeofday(&creation_time) == -1)
2N/A return (mdsyserror(ep, errno, NULL));
2N/A
2N/A /* do submirrors */
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A mm_submirror_t *mmsp = &mm->un_sm[smi];
2N/A diskaddr_t size;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnp == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A ++nsm;
2N/A
2N/A /* get size */
2N/A if ((size = metagetsize(submirnp, ep)) == MD_DISKADDR_ERROR)
2N/A goto out;
2N/A assert(size > 0);
2N/A
2N/A /* adjust for smallest submirror */
2N/A if (submir_size == MD_DISKADDR_ERROR) {
2N/A submir_size = size;
2N/A } else if (size < submir_size) {
2N/A submir_size = size;
2N/A }
2N/A
2N/A if (options & MDCMD_DOIT) {
2N/A /* store name in namespace */
2N/A if (add_key_name(sp, submirnp, &keynlp, ep) != 0)
2N/A goto out;
2N/A }
2N/A
2N/A /* setup submirror */
2N/A mmsp->sm_key = submirnp->key;
2N/A mmsp->sm_dev = submirnp->dev;
2N/A mmsp->sm_state = SMS_RUNNING;
2N/A mmsp->sm_timestamp = creation_time;
2N/A }
2N/A
2N/A /* setup unit */
2N/A mm->c.un_type = MD_METAMIRROR;
2N/A MD_SID(mm) = meta_getminor(mirnp->dev);
2N/A mm->c.un_actual_tb = submir_size;
2N/A mm->c.un_size = offsetof(mm_unit_t, un_smic);
2N/A mm->un_nsm = nsm;
2N/A mm->un_read_option = mirrorp->read_option;
2N/A mm->un_write_option = mirrorp->write_option;
2N/A mm->un_pass_num = mirrorp->pass_num;
2N/A if (mirror_geom(mirrorp, mm, ep) != 0)
2N/A goto out;
2N/A
2N/A /* fill in the size of the mirror */
2N/A if (options & MDCMD_UPDATE) {
2N/A mirrorp->common.size = mm->c.un_total_blocks;
2N/A }
2N/A
2N/A /* if we're not doing anything, return success */
2N/A if (! (options & MDCMD_DOIT)) {
2N/A rval = 0; /* success */
2N/A goto out;
2N/A }
2N/A
2N/A /* create mirror */
2N/A (void) memset(&set_params, 0, sizeof (set_params));
2N/A /* did the user tell us to generate a large device? */
2N/A create_flag = meta_check_devicesize(mm->c.un_total_blocks);
2N/A if (create_flag == MD_CRO_64BIT) {
2N/A mm->c.un_revision |= MD_64BIT_META_DEV;
2N/A set_params.options = MD_CRO_64BIT;
2N/A } else {
2N/A mm->c.un_revision &= ~MD_64BIT_META_DEV;
2N/A set_params.options = MD_CRO_32BIT;
2N/A }
2N/A set_params.mnum = MD_SID(mm);
2N/A set_params.size = mm->c.un_size;
2N/A set_params.mdp = (uintptr_t)mm;
2N/A MD_SETDRIVERNAME(&set_params, MD_MIRROR, MD_MIN2SET(set_params.mnum));
2N/A if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
2N/A mirnp->cname) != 0) {
2N/A (void) mdstealerror(ep, &set_params.mde);
2N/A goto out;
2N/A }
2N/A rval = 0; /* success */
2N/A
2N/A /* cleanup, return success */
2N/Aout:
2N/A Free(mm);
2N/A if (rval != 0) {
2N/A (void) del_key_names(sp, keynlp, NULL);
2N/A }
2N/A metafreenamelist(keynlp);
2N/A if ((rval == 0) && (options & MDCMD_DOIT)) {
2N/A if (invalidate_submirrors(sp, mirnp, ep) != 0)
2N/A rval = -1;
2N/A meta_invalidate_name(mirnp);
2N/A }
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * initialize mirror
2N/A * NOTE: this functions is metainit(1m)'s command line parser!
2N/A */
2N/Aint
2N/Ameta_init_mirror(
2N/A mdsetname_t **spp,
2N/A int argc,
2N/A char *argv[],
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *uname = argv[0];
2N/A mdname_t *mirnp = NULL;
2N/A int old_optind;
2N/A int c;
2N/A md_mirror_t *mirrorp = NULL;
2N/A uint_t smi;
2N/A int rval = -1;
2N/A
2N/A /* get mirror name */
2N/A assert(argc > 0);
2N/A if (argc < 1)
2N/A goto syntax;
2N/A if ((mirnp = metaname(spp, uname, META_DEVICE, ep)) == NULL)
2N/A goto out;
2N/A assert(*spp != NULL);
2N/A uname = mirnp->cname;
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A goto out;
2N/A
2N/A if (!(options & MDCMD_NOLOCK)) {
2N/A /* grab set lock */
2N/A if (meta_lock(*spp, TRUE, ep) != 0)
2N/A goto out;
2N/A
2N/A if (meta_check_ownership(*spp, ep) != 0)
2N/A goto out;
2N/A }
2N/A
2N/A /* see if it exists already */
2N/A if (metagetmiscname(mirnp, ep) != NULL) {
2N/A (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
2N/A meta_getminor(mirnp->dev), uname);
2N/A goto out;
2N/A } else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
2N/A goto out;
2N/A } else {
2N/A mdclrerror(ep);
2N/A }
2N/A --argc, ++argv;
2N/A
2N/A /* grab -m */
2N/A if ((argc < 1) || (strcmp(argv[0], "-m") != 0))
2N/A goto syntax;
2N/A --argc, ++argv;
2N/A
2N/A if (argc == 0)
2N/A goto syntax;
2N/A
2N/A /* parse general options */
2N/A optind = 0;
2N/A opterr = 0;
2N/A if (getopt(argc, argv, "") != -1)
2N/A goto options;
2N/A
2N/A /* allocate mirror */
2N/A mirrorp = Zalloc(sizeof (*mirrorp));
2N/A
2N/A /* setup common */
2N/A mirrorp->common.namep = mirnp;
2N/A mirrorp->common.type = MD_METAMIRROR;
2N/A
2N/A /* parse submirrors */
2N/A for (smi = 0; ((argc > 0) && (argv[0][0] != '-') &&
2N/A (! isdigit(argv[0][0]))); ++smi) {
2N/A md_submirror_t *mdsm = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnamep;
2N/A
2N/A /* check for room */
2N/A if (smi >= NMIRROR) {
2N/A (void) mdmderror(ep, MDE_MIRROR_FULL,
2N/A meta_getminor(mirnp->dev), uname);
2N/A goto out;
2N/A }
2N/A
2N/A /* parse submirror name */
2N/A if ((submirnamep = metaname(spp, argv[0],
2N/A META_DEVICE, ep)) == NULL)
2N/A goto out;
2N/A mdsm->submirnamep = submirnamep;
2N/A --argc, ++argv;
2N/A }
2N/A if (smi == 0) {
2N/A (void) mdmderror(ep, MDE_NSUBMIRS, meta_getminor(mirnp->dev),
2N/A uname);
2N/A goto out;
2N/A }
2N/A
2N/A /* dangerous n-way mirror creation */
2N/A if ((smi > 1) && (options & MDCMD_PRINT)) {
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A"%s: WARNING: This form of metainit is not recommended.\n"
2N/A"The submirrors may not have the same data.\n"
2N/A"Please see ERRORS in metainit(1M) for additional information.\n"),
2N/A uname);
2N/A }
2N/A
2N/A /* parse mirror options */
2N/A mirrorp->read_option = RD_LOAD_BAL;
2N/A mirrorp->write_option = WR_PARALLEL;
2N/A mirrorp->pass_num = MD_PASS_DEFAULT;
2N/A old_optind = optind = 0;
2N/A opterr = 0;
2N/A while ((c = getopt(argc, argv, "grS")) != -1) {
2N/A switch (c) {
2N/A case 'g':
2N/A if (mirrorp->read_option != RD_LOAD_BAL) {
2N/A (void) mderror(ep, MDE_BAD_RD_OPT, uname);
2N/A goto out;
2N/A }
2N/A mirrorp->read_option = RD_GEOMETRY;
2N/A break;
2N/A
2N/A case 'r':
2N/A if (mirrorp->read_option != RD_LOAD_BAL) {
2N/A (void) mderror(ep, MDE_BAD_RD_OPT, uname);
2N/A goto out;
2N/A }
2N/A mirrorp->read_option = RD_FIRST;
2N/A break;
2N/A
2N/A case 'S':
2N/A if (mirrorp->write_option != WR_PARALLEL) {
2N/A (void) mderror(ep, MDE_BAD_WR_OPT, uname);
2N/A goto out;
2N/A }
2N/A mirrorp->write_option = WR_SERIAL;
2N/A break;
2N/A
2N/A default:
2N/A argc -= old_optind;
2N/A argv += old_optind;
2N/A goto options;
2N/A }
2N/A old_optind = optind;
2N/A }
2N/A argc -= optind;
2N/A argv += optind;
2N/A
2N/A /* parse pass number */
2N/A if ((argc > 0) && (isdigit(argv[0][0]))) {
2N/A if (name_to_pass_num(uname, argv[0],
2N/A &mirrorp->pass_num, ep) != 0) {
2N/A goto out;
2N/A }
2N/A --argc, ++argv;
2N/A }
2N/A
2N/A /* we should be at the end */
2N/A if (argc != 0)
2N/A goto syntax;
2N/A
2N/A /* create mirror */
2N/A if (meta_create_mirror(*spp, mirrorp, options, ep) != 0)
2N/A goto out;
2N/A rval = 0; /* success */
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: Mirror is setup\n"),
2N/A uname);
2N/A (void) fflush(stdout);
2N/A }
2N/A goto out;
2N/A
2N/A /* syntax error */
2N/Asyntax:
2N/A rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
2N/A goto out;
2N/A
2N/A /* options error */
2N/Aoptions:
2N/A rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
2N/A goto out;
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (mirrorp != NULL)
2N/A meta_free_mirror(mirrorp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * reset mirrors
2N/A */
2N/Aint
2N/Ameta_mirror_reset(
2N/A mdsetname_t *sp,
2N/A mdname_t *mirnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_mirror_t *mirrorp;
2N/A uint_t smi;
2N/A int rval = -1;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert((mirnp == NULL) ||
2N/A (sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev))));
2N/A
2N/A /* reset all mirrors */
2N/A if (mirnp == NULL) {
2N/A mdnamelist_t *mirrornlp = NULL;
2N/A mdnamelist_t *p;
2N/A
2N/A /* for each mirror */
2N/A rval = 0;
2N/A if (meta_get_mirror_names(sp, &mirrornlp, 0, ep) < 0)
2N/A return (-1);
2N/A for (p = mirrornlp; (p != NULL); p = p->next) {
2N/A /* reset mirror */
2N/A mirnp = p->namep;
2N/A /*
2N/A * If this is a multi-node set, we send a series
2N/A * of individual metaclear commands.
2N/A */
2N/A if (meta_is_mn_set(sp, ep)) {
2N/A if (meta_mn_send_metaclear_command(sp,
2N/A mirnp->cname, options, 0, ep) != 0) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A } else {
2N/A if (meta_mirror_reset(sp, mirnp, options,
2N/A ep) != 0) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* cleanup return success */
2N/A metafreenamelist(mirrornlp);
2N/A return (rval);
2N/A }
2N/A
2N/A /* check name */
2N/A if (metachkmeta(mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get unit structure */
2N/A if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* make sure nobody owns us */
2N/A if (MD_HAS_PARENT(mirrorp->common.parent)) {
2N/A return (mdmderror(ep, MDE_IN_USE, meta_getminor(mirnp->dev),
2N/A mirnp->cname));
2N/A }
2N/A
2N/A /* clear subdevices cache */
2N/A if (invalidate_submirrors(sp, mirnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* clear metadevice */
2N/A if (meta_reset(sp, mirnp, options, ep) != 0)
2N/A goto out;
2N/A rval = 0; /* success */
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: Mirror is cleared\n"), mirnp->cname);
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* clear subdevices */
2N/A if (! (options & MDCMD_RECURSE))
2N/A goto out;
2N/A for (smi = 0; (smi < NMIRROR); ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A mdname_t *submirnp = mdsp->submirnamep;
2N/A
2N/A /* skip unused submirrors */
2N/A if (submirnp == NULL) {
2N/A assert(mdsp->state == SMS_UNUSED);
2N/A continue;
2N/A }
2N/A
2N/A /* make sure we have a metadevice */
2N/A if (! metaismeta(submirnp))
2N/A continue;
2N/A
2N/A /* clear submirror */
2N/A if (meta_reset_by_name(sp, submirnp, options, ep) != 0)
2N/A rval = -1;
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/Aout:
2N/A meta_invalidate_name(mirnp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * reports TRUE if any mirror component is in error
2N/A */
2N/Aint
2N/Ameta_mirror_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *mirror_names)
2N/A{
2N/A mdnamelist_t *nlp;
2N/A md_error_t status = mdnullerror;
2N/A md_error_t *ep = &status;
2N/A int any_errs = FALSE;
2N/A
2N/A for (nlp = mirror_names; nlp; nlp = nlp->next) {
2N/A md_mirror_t *mirrorp;
2N/A int smi;
2N/A
2N/A if ((mirrorp = meta_get_mirror(sp, nlp->namep, ep)) == NULL) {
2N/A any_errs |= TRUE;
2N/A goto out;
2N/A }
2N/A
2N/A for (smi = 0; smi < NMIRROR; ++smi) {
2N/A md_submirror_t *mdsp = &mirrorp->submirrors[smi];
2N/A
2N/A if (mdsp->state &
2N/A (SMS_COMP_ERRED|SMS_ATTACHED|SMS_OFFLINE)) {
2N/A any_errs |= TRUE;
2N/A goto out;
2N/A }
2N/A }
2N/A }
2N/Aout:
2N/A if (!mdisok(ep))
2N/A mdclrerror(ep);
2N/A
2N/A return (any_errs);
2N/A}