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 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
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 * stripe operations
2N/A */
2N/A
2N/A#include <limits.h>
2N/A#include <stdlib.h>
2N/A#include <meta.h>
2N/A#include <sys/lvm/md_stripe.h>
2N/A#include <sys/lvm/md_convert.h>
2N/A
2N/A#define QUOTE(x) #x
2N/A#define VAL2STR(x) QUOTE(x)
2N/A
2N/A/*
2N/A * replace stripe/concat
2N/A */
2N/Aint
2N/Ameta_stripe_replace(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
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 replace_params_t params;
2N/A md_dev64_t old_dev, new_dev;
2N/A diskaddr_t new_start_blk;
2N/A diskaddr_t new_end_blk, label, size, start_blk;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
2N/A
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 meta_invalidate_name(stripenp);
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 if (((strcmp(oldnp->rname, newnp->rname) == 0) &&
2N/A (old_dev != new_dev))) {
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 if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if (start_blk >= size) {
2N/A (void) mdsyserror(ep, ENOSPC, newnp->cname);
2N/A return (-1);
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 if (add_key_name(sp, newnp, NULL, ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * There is no need to call meta_fixdevid() here as this function is
2N/A * only called by the metareplace -c command which actually does
2N/A * nothing (in terms of a resync) and thus does nothing with the devid.
2N/A */
2N/A
2N/A (void) memset(&params, 0, sizeof (params));
2N/A params.mnum = meta_getminor(stripenp->dev);
2N/A MD_SETDRIVERNAME(&params, MD_STRIPE, sp->setno);
2N/A
2N/A params.cmd = REPLACE_COMP;
2N/A params.old_dev = old_dev;
2N/A params.new_dev = new_dev;
2N/A params.new_key = newnp->key;
2N/A params.start_blk = newnp->start_blk;
2N/A params.number_blks = size;
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 (label == 0)
2N/A params.has_label = 0;
2N/A else
2N/A params.has_label = 1;
2N/A if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
2N/A if (options & MDCMD_DOIT)
2N/A (void) del_key_name(sp, newnp, ep);
2N/A return (mdstealerror(ep, &params.mde));
2N/A }
2N/A meta_invalidate_name(oldnp);
2N/A meta_invalidate_name(newnp);
2N/A meta_invalidate_name(stripenp);
2N/A
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 stripenp->cname, oldnp->cname, newnp->cname);
2N/A
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * FUNCTION: meta_get_stripe_names()
2N/A * INPUT: sp - the set name to get stripes from
2N/A * options - options from the command line
2N/A * OUTPUT: nlpp - list of all stripe names
2N/A * ep - return error pointer
2N/A * RETURNS: int - -1 if error, 0 success
2N/A * PURPOSE: returns a list of all stripes in the metadb
2N/A * for all devices in the specified set
2N/A */
2N/Aint
2N/Ameta_get_stripe_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_STRIPE, sp, nlpp, options, ep));
2N/A}
2N/A
2N/A/*
2N/A * free stripe
2N/A */
2N/Avoid
2N/Ameta_free_stripe(
2N/A md_stripe_t *stripep
2N/A)
2N/A{
2N/A uint_t row;
2N/A
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A
2N/A if (rp->comps.comps_val != NULL) {
2N/A assert(rp->comps.comps_len > 0);
2N/A Free(rp->comps.comps_val);
2N/A }
2N/A }
2N/A if (stripep->rows.rows_val != NULL) {
2N/A assert(stripep->rows.rows_len > 0);
2N/A Free(stripep->rows.rows_val);
2N/A }
2N/A Free(stripep);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * get stripe (common)
2N/A */
2N/Amd_stripe_t *
2N/Ameta_get_stripe_common(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A int fast,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mddrivename_t *dnp = stripenp->drivenamep;
2N/A char *miscname;
2N/A ms_unit_t *ms;
2N/A md_stripe_t *stripep;
2N/A uint_t row;
2N/A
2N/A /* must have set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
2N/A
2N/A /* short circuit */
2N/A if (dnp->unitp != NULL) {
2N/A assert(dnp->unitp->type == MD_DEVICE);
2N/A return ((md_stripe_t *)dnp->unitp);
2N/A }
2N/A
2N/A /* get miscname and unit */
2N/A if ((miscname = metagetmiscname(stripenp, ep)) == NULL)
2N/A return (NULL);
2N/A if (strcmp(miscname, MD_STRIPE) != 0) {
2N/A (void) mdmderror(ep, MDE_NOT_STRIPE,
2N/A meta_getminor(stripenp->dev), stripenp->cname);
2N/A return (NULL);
2N/A }
2N/A if ((ms = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL)
2N/A return (NULL);
2N/A assert(ms->c.un_type == MD_DEVICE);
2N/A
2N/A /* allocate stripe */
2N/A stripep = Zalloc(sizeof (*stripep));
2N/A
2N/A /* allocate rows */
2N/A assert(ms->un_nrows > 0);
2N/A stripep->rows.rows_len = ms->un_nrows;
2N/A stripep->rows.rows_val = Zalloc(stripep->rows.rows_len *
2N/A sizeof (*stripep->rows.rows_val));
2N/A
2N/A /* get common info */
2N/A stripep->common.namep = stripenp;
2N/A stripep->common.type = ms->c.un_type;
2N/A stripep->common.state = ms->c.un_status;
2N/A stripep->common.capabilities = ms->c.un_capabilities;
2N/A stripep->common.parent = ms->c.un_parent;
2N/A stripep->common.size = ms->c.un_total_blocks;
2N/A stripep->common.user_flags = ms->c.un_user_flags;
2N/A stripep->common.revision = ms->c.un_revision;
2N/A
2N/A /* get options */
2N/A if ((ms->un_hsp_id != MD_HSP_NONE) &&
2N/A ((stripep->hspnamep = metahsphspname(&sp, ms->un_hsp_id,
2N/A ep)) == NULL)) {
2N/A goto out;
2N/A }
2N/A
2N/A /* get rows */
2N/A for (row = 0; (row < ms->un_nrows); ++row) {
2N/A struct ms_row *mdr = &ms->un_row[row];
2N/A struct ms_comp *mdcomp = (void *)&((char *)ms)[ms->un_ocomp];
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp, c;
2N/A
2N/A /* get interlace */
2N/A rp->interlace = mdr->un_interlace;
2N/A
2N/A /* allocate comps */
2N/A assert(mdr->un_ncomp > 0);
2N/A rp->comps.comps_len = mdr->un_ncomp;
2N/A rp->comps.comps_val = Zalloc(rp->comps.comps_len *
2N/A sizeof (*rp->comps.comps_val));
2N/A
2N/A /* get components */
2N/A for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp);
2N/A ++comp, ++c) {
2N/A struct ms_comp *mdc = &mdcomp[c];
2N/A diskaddr_t comp_start_blk = mdc->un_start_block;
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A
2N/A /* get the component name */
2N/A cp->compnamep = metakeyname(&sp, mdc->un_key, fast, ep);
2N/A if (cp->compnamep == NULL)
2N/A goto out;
2N/A
2N/A /* if hotspared */
2N/A if (mdc->un_mirror.ms_hs_id != 0) {
2N/A diskaddr_t hs_start_blk = mdc->un_start_block;
2N/A
2N/A /* get the hotspare name */
2N/A cp->hsnamep = metakeyname(&sp,
2N/A mdc->un_mirror.ms_hs_key, fast, ep);
2N/A if (cp->hsnamep == NULL)
2N/A goto out;
2N/A
2N/A if (getenv("META_DEBUG_START_BLK") != NULL) {
2N/A if (metagetstart(sp, cp->hsnamep,
2N/A ep) == MD_DISKADDR_ERROR)
2N/A mdclrerror(ep);
2N/A
2N/A if ((cp->hsnamep->start_blk == 0) &&
2N/A (hs_start_blk != 0))
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "%s: suspected bad"
2N/A "start block,"
2N/A " seems labelled"
2N/A "[stripe/hs]\n"),
2N/A cp->hsnamep->cname);
2N/A
2N/A if ((cp->hsnamep->start_blk > 0) &&
2N/A (hs_start_blk == 0) &&
2N/A ! ((row == 0) && (comp == 0)))
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "%s: suspected bad"
2N/A "start block, "
2N/A "seems unlabelled"
2N/A "[stripe/hs]\n"),
2N/A cp->hsnamep->cname);
2N/A }
2N/A /* override any start_blk */
2N/A cp->hsnamep->start_blk = hs_start_blk;
2N/A
2N/A /* get the right component start_blk */
2N/A comp_start_blk = mdc->un_mirror.ms_orig_blk;
2N/A } else {
2N/A if (getenv("META_DEBUG_START_BLK") != NULL) {
2N/A if (metagetstart(sp, cp->compnamep,
2N/A ep) == MD_DISKADDR_ERROR)
2N/A mdclrerror(ep);
2N/A
2N/A if ((cp->compnamep->start_blk == 0) &&
2N/A (comp_start_blk != 0))
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "%s: suspected bad"
2N/A "start block,"
2N/A " seems labelled"
2N/A "[stripe]"),
2N/A cp->compnamep->cname);
2N/A
2N/A if ((cp->compnamep->start_blk > 0) &&
2N/A (comp_start_blk == 0) &&
2N/A ! ((row == 0) && (comp == 0)))
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "%s: suspected bad"
2N/A "start block, "
2N/A "seems unlabelled"
2N/A "[stripe]"),
2N/A cp->compnamep->cname);
2N/A }
2N/A }
2N/A
2N/A /* override any start_blk */
2N/A cp->compnamep->start_blk = comp_start_blk;
2N/A
2N/A /* get state */
2N/A cp->state = mdc->un_mirror.ms_state;
2N/A
2N/A /* get time of last state change */
2N/A cp->timestamp = mdc->un_mirror.ms_timestamp;
2N/A
2N/A /* get lasterr count */
2N/A cp->lasterrcnt = mdc->un_mirror.ms_lasterrcnt;
2N/A }
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/A Free(ms);
2N/A dnp->unitp = (md_common_t *)stripep;
2N/A return (stripep);
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A Free(ms);
2N/A meta_free_stripe(stripep);
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * get stripe
2N/A */
2N/Amd_stripe_t *
2N/Ameta_get_stripe(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (meta_get_stripe_common(sp, stripenp, 0, ep));
2N/A}
2N/A
2N/A/*
2N/A * check stripe for dev
2N/A */
2N/Astatic int
2N/Ain_stripe(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
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_stripe_t *stripep;
2N/A uint_t row;
2N/A
2N/A /* should be in the same set */
2N/A assert(sp != NULL);
2N/A
2N/A /* get unit */
2N/A if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* look in rows */
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A /* look in columns */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A diskaddr_t comp_sblk;
2N/A int err;
2N/A
2N/A /* check same drive since metagetstart() can fail */
2N/A if ((err = meta_check_samedrive(np, compnp, ep)) < 0)
2N/A return (-1);
2N/A else if (err == 0)
2N/A continue;
2N/A
2N/A /* check overlap */
2N/A if ((comp_sblk = metagetstart(sp, compnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if (meta_check_overlap(stripenp->cname, np,
2N/A slblk, nblks, compnp, comp_sblk, -1,
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}
2N/A
2N/A/*
2N/A * check to see if we're in a stripe
2N/A */
2N/Aint
2N/Ameta_check_instripe(
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 *stripenlp = 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 stripe */
2N/A if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0)
2N/A return (-1);
2N/A for (p = stripenlp; (p != NULL); p = p->next) {
2N/A mdname_t *stripenp = p->namep;
2N/A
2N/A /* check stripe */
2N/A if (in_stripe(sp, stripenp, 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(stripenlp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * check component
2N/A */
2N/Aint
2N/Ameta_check_component(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A int force,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdchkopts_t options = (MDCHK_ALLOW_MDDB);
2N/A md_common_t *mdp;
2N/A
2N/A /*
2N/A * See if we are a soft partition: meta_sp_issp() returns 0 if
2N/A * np points to a soft partition, so the if and else clauses
2N/A * here represent "not a soft partition" and "soft partition,"
2N/A * respectively.
2N/A */
2N/A if (meta_sp_issp(sp, np, ep) != 0) {
2N/A /* make sure we have a disk */
2N/A if (metachkcomp(np, ep) != 0)
2N/A return (-1);
2N/A } else {
2N/A /* make sure soft partition can parent & doesn't have parent */
2N/A if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
2N/A return (mdmderror(ep, MDE_INVAL_UNIT, NULL,
2N/A np->cname));
2N/A if (mdp->capabilities == MD_CANT_PARENT)
2N/A return (mdmderror(ep, MDE_INVAL_UNIT, NULL,
2N/A np->cname));
2N/A if (MD_HAS_PARENT(mdp->parent)) {
2N/A mdname_t *pnp;
2N/A
2N/A pnp = metamnumname(&sp, mdp->parent, 0, ep);
2N/A if (pnp == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A return (mduseerror(ep, MDE_ALREADY, np->dev,
2N/A pnp->cname, np->cname));
2N/A }
2N/A }
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 (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * print stripe
2N/A */
2N/Astatic int
2N/Astripe_print(
2N/A md_stripe_t *stripep,
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 row;
2N/A int rval = -1;
2N/A
2N/A if (options & PRINT_LARGEDEVICES) {
2N/A if (stripep->common.revision != MD_64BIT_META_DEV) {
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (options & PRINT_FN) {
2N/A if (stripep->common.revision != MD_FN_META_DEV) {
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print name and num rows */
2N/A if (fprintf(fp, "%s %u",
2N/A stripep->common.namep->cname, stripep->rows.rows_len) == EOF)
2N/A goto out;
2N/A
2N/A /* print rows */
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A /* print num components */
2N/A if (fprintf(fp, " %u", rp->comps.comps_len) == EOF)
2N/A goto out;
2N/A
2N/A /*
2N/A * Print components. Always print the full path name.
2N/A */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A
2N/A if (fprintf(fp, " %s", cp->compnamep->rname) == EOF)
2N/A goto out;
2N/A }
2N/A
2N/A /* print interlace */
2N/A if (rp->comps.comps_len > 1)
2N/A if (fprintf(fp, " -i %lldb", rp->interlace) == EOF)
2N/A goto out;
2N/A
2N/A /* print continuation */
2N/A if (row != (stripep->rows.rows_len - 1))
2N/A if (fprintf(fp, " \\\n\t") == EOF)
2N/A goto out;
2N/A }
2N/A
2N/A /* print hotspare name */
2N/A if (stripep->hspnamep != NULL)
2N/A if (fprintf(fp, " -h %s", stripep->hspnamep->hspname) == EOF)
2N/A goto out;
2N/A
2N/A /* terminate last 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 * convert component state to name
2N/A */
2N/Achar *
2N/Acomp_state_to_name(
2N/A md_comp_t *mdcp,
2N/A md_timeval32_t *tvp,
2N/A uint_t tstate /* Errored tstate flags */
2N/A)
2N/A{
2N/A comp_state_t state = mdcp->state;
2N/A
2N/A /* grab time */
2N/A if (tvp != NULL)
2N/A *tvp = mdcp->timestamp;
2N/A
2N/A if (tstate != 0) {
2N/A return (dgettext(TEXT_DOMAIN, "Unavailable"));
2N/A }
2N/A
2N/A /* return state */
2N/A switch (state) {
2N/A case CS_OKAY:
2N/A return (dgettext(TEXT_DOMAIN, "Okay"));
2N/A case CS_ERRED:
2N/A return (dgettext(TEXT_DOMAIN, "Maintenance"));
2N/A case CS_LAST_ERRED:
2N/A return (dgettext(TEXT_DOMAIN, "Last Erred"));
2N/A case CS_RESYNC:
2N/A return (dgettext(TEXT_DOMAIN, "Resyncing"));
2N/A default:
2N/A return (dgettext(TEXT_DOMAIN, "invalid"));
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * print subdevice stripe row
2N/A */
2N/Astatic int
2N/Asubdev_row_report(
2N/A mdsetname_t *sp,
2N/A md_row_t *rp,
2N/A char *fname,
2N/A FILE *fp,
2N/A mdprtopts_t options,
2N/A uint_t top_tstate, /* Errored tstate flags */
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t comp;
2N/A int rval = -1;
2N/A ddi_devid_t dtp;
2N/A int len = 0;
2N/A
2N/A
2N/A /*
2N/A * building a format string on the fly that will be used
2N/A * in fprintf. This is to allow really really long ctd names
2N/A */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A char *cname = cp->compnamep->cname;
2N/A
2N/A len = max(len, strlen(cname));
2N/A }
2N/A
2N/A len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
2N/A len += 2;
2N/A /* print header */
2N/A if (! (options & PRINT_TIMES)) {
2N/A if (fprintf(fp,
2N/A "\t%-*.*s %-12.12s %5.5s %12.12s %5.5s %s\n",
2N/A len, len,
2N/A dgettext(TEXT_DOMAIN, "Device"),
2N/A dgettext(TEXT_DOMAIN, "Start Block"),
2N/A dgettext(TEXT_DOMAIN, "Dbase"),
2N/A dgettext(TEXT_DOMAIN, "State"),
2N/A dgettext(TEXT_DOMAIN, "Reloc"),
2N/A dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
2N/A goto out;
2N/A }
2N/A } else {
2N/A if (fprintf(fp,
2N/A "\t%-*s %5s %5s %-11s %-5s %-9s %s\n",
2N/A len,
2N/A dgettext(TEXT_DOMAIN, "Device"),
2N/A dgettext(TEXT_DOMAIN, "Start"),
2N/A dgettext(TEXT_DOMAIN, "Dbase"),
2N/A dgettext(TEXT_DOMAIN, "State"),
2N/A dgettext(TEXT_DOMAIN, "Reloc"),
2N/A dgettext(TEXT_DOMAIN, "Hot Spare"),
2N/A dgettext(TEXT_DOMAIN, "Time")) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A
2N/A /* print components */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *namep = cp->compnamep;
2N/A char *cname = namep->cname;
2N/A diskaddr_t start_blk;
2N/A int has_mddb;
2N/A char *has_mddb_str;
2N/A char *comp_state;
2N/A md_timeval32_t tv;
2N/A char *hsname = ((cp->hsnamep != NULL) ?
2N/A cp->hsnamep->cname : "");
2N/A char *devid = " ";
2N/A mdname_t *didnp = NULL;
2N/A uint_t tstate = 0;
2N/A
2N/A /* get info */
2N/A if ((start_blk = metagetstart(sp, namep, ep)) ==
2N/A MD_DISKADDR_ERROR) {
2N/A return (-1);
2N/A }
2N/A if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) {
2N/A return (-1);
2N/A }
2N/A if (has_mddb)
2N/A has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
2N/A else
2N/A has_mddb_str = dgettext(TEXT_DOMAIN, "No");
2N/A
2N/A /*
2N/A * If the component is a metadevice, print out either
2N/A * unavailable or the state of the metadevice, if not
2N/A * a metadevice, print nothing if the state of the
2N/A * stripe is unavailable
2N/A */
2N/A if (metaismeta(namep)) {
2N/A if (meta_get_tstate(namep->dev, &tstate, ep) != 0)
2N/A return (-1);
2N/A comp_state = comp_state_to_name(cp, &tv, tstate &
2N/A MD_DEV_ERRORED);
2N/A } else {
2N/A /*
2N/A * if top_tstate is set, that implies that you have
2N/A * a ctd type device with an unavailable metadevice
2N/A * on top of it. If so, print a - for it's state
2N/A */
2N/A if (top_tstate != 0)
2N/A comp_state = "-";
2N/A else
2N/A comp_state = comp_state_to_name(cp, &tv,
2N/A tstate & MD_DEV_ERRORED);
2N/A }
2N/A
2N/A /* populate the key in the name_p structure */
2N/A if ((didnp = metadevname(&sp, namep->dev, ep))
2N/A == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A /* determine if devid does NOT exist */
2N/A if (options & PRINT_DEVID) {
2N/A if ((dtp = meta_getdidbykey(sp->setno,
2N/A getmyside(sp, ep), didnp->key, ep)) == NULL)
2N/A devid = dgettext(TEXT_DOMAIN, "No ");
2N/A else {
2N/A devid = dgettext(TEXT_DOMAIN, "Yes");
2N/A free(dtp);
2N/A }
2N/A }
2N/A /* print info */
2N/A /*
2N/A * building a format string on the fly that will be used
2N/A * in fprintf. This is to allow really really long ctd names
2N/A */
2N/A if (! (options & PRINT_TIMES)) {
2N/A if (fprintf(fp,
2N/A "\t%-*s %8lld %-5.5s %12.12s %5.5s %s\n",
2N/A len, cname, start_blk,
2N/A has_mddb_str, comp_state, devid, hsname) == EOF) {
2N/A goto out;
2N/A }
2N/A } else {
2N/A char *timep = meta_print_time(&tv);
2N/A
2N/A if (fprintf(fp,
2N/A "\t%-*s %5lld %-5s %-11s %-5s %-9s %s\n",
2N/A len, cname, start_blk,
2N/A has_mddb_str, comp_state, devid, hsname,
2N/A timep) == EOF) {
2N/A goto out;
2N/A }
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/A/*
2N/A * print toplevel stripe row
2N/A */
2N/A/*ARGSUSED4*/
2N/Astatic int
2N/Atoplev_row_report(
2N/A mdsetname_t *sp,
2N/A md_row_t *rp,
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 comp;
2N/A int rval = -1;
2N/A char *devid = " ";
2N/A mdname_t *didnp = NULL;
2N/A int len = 0;
2N/A
2N/A /*
2N/A * building a format string on the fly that will be used
2N/A * in fprintf. This is to allow really really long ctd names
2N/A */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A len = max(len,
2N/A strlen(rp->comps.comps_val[comp].compnamep->cname));
2N/A }
2N/A
2N/A len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
2N/A len += 2;
2N/A /* print header */
2N/A if (fprintf(fp,
2N/A "\t%-*.*s %-12.12s %-5.5s\t%s\n",
2N/A len, len,
2N/A dgettext(TEXT_DOMAIN, "Device"),
2N/A dgettext(TEXT_DOMAIN, "Start Block"),
2N/A dgettext(TEXT_DOMAIN, "Dbase"),
2N/A dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* print components */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *namep = cp->compnamep;
2N/A char *cname = namep->cname;
2N/A diskaddr_t start_blk;
2N/A int has_mddb;
2N/A char *has_mddb_str;
2N/A ddi_devid_t dtp;
2N/A
2N/A /* get info */
2N/A if ((start_blk = metagetstart(sp, namep, ep)) ==
2N/A MD_DISKADDR_ERROR) {
2N/A return (-1);
2N/A }
2N/A if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) {
2N/A return (-1);
2N/A }
2N/A if (has_mddb)
2N/A has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
2N/A else
2N/A has_mddb_str = dgettext(TEXT_DOMAIN, "No");
2N/A
2N/A /* populate the key in the name_p structure */
2N/A if ((didnp = metadevname(&sp, namep->dev, ep))
2N/A == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A /* determine if devid does NOT exist */
2N/A if (options & PRINT_DEVID) {
2N/A if ((dtp = meta_getdidbykey(sp->setno,
2N/A getmyside(sp, ep), didnp->key, ep)) == NULL) {
2N/A devid = dgettext(TEXT_DOMAIN, "No ");
2N/A } else {
2N/A devid = dgettext(TEXT_DOMAIN, "Yes");
2N/A free(dtp);
2N/A }
2N/A }
2N/A /* print info */
2N/A /*
2N/A * building a format string on the fly that will be used
2N/A * in fprintf. This is to allow really really long ctd names
2N/A */
2N/A if (fprintf(fp,
2N/A "\t%-*s %8lld %-5.5s\t%s\n", len,
2N/A cname, start_blk, has_mddb_str, devid) == 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/A/*
2N/A * print stripe options
2N/A */
2N/Aint
2N/Ameta_print_stripe_options(
2N/A mdhspname_t *hspnamep,
2N/A char *fname,
2N/A FILE *fp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *hspname = ((hspnamep != NULL) ? hspnamep->hspname :
2N/A dgettext(TEXT_DOMAIN, "none"));
2N/A int rval = -1;
2N/A
2N/A /* print options */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Hot spare pool: %s\n"), hspname) == EOF) {
2N/A goto out;
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/A/*
2N/A * report stripe
2N/A */
2N/Astatic int
2N/Astripe_report(
2N/A mdsetname_t *sp,
2N/A md_stripe_t *stripep,
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 uint_t row;
2N/A int rval = -1;
2N/A uint_t tstate = 0;
2N/A
2N/A /*
2N/A * if the -B option has been specified check to see if the
2N/A * metadevice is s "big" one and print if so, also if a
2N/A * big device we need to store the ctd involved for use in
2N/A * printing out the relocation information.
2N/A */
2N/A if (options & PRINT_LARGEDEVICES) {
2N/A if ((stripep->common.revision & MD_64BIT_META_DEV) == 0) {
2N/A rval = 0;
2N/A goto out;
2N/A } else {
2N/A if (meta_getdevs(sp, stripep->common.namep,
2N/A nlpp, ep) != 0)
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * if the -D option has been specified check to see if the
2N/A * metadevice has a descriptive name and print if so, also if a
2N/A * descriptive device name we need to store the ctd involved
2N/A * for use in printing out the relocation information.
2N/A */
2N/A if (options & PRINT_FN) {
2N/A if ((stripep->common.revision & MD_FN_META_DEV) == 0) {
2N/A rval = 0;
2N/A goto out;
2N/A } else {
2N/A if (meta_getdevs(sp, stripep->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, "%s: Concat/Stripe\n",
2N/A stripep->common.namep->cname) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A }
2N/A
2N/A /* print hotspare pool */
2N/A if (stripep->hspnamep != NULL) {
2N/A if (meta_print_stripe_options(stripep->hspnamep,
2N/A fname, fp, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A if (metaismeta(stripep->common.namep)) {
2N/A if (meta_get_tstate(stripep->common.namep->dev, &tstate, ep)
2N/A != 0)
2N/A return (-1);
2N/A }
2N/A if ((tstate & MD_DEV_ERRORED) != 0) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " State: Unavailable\n"
2N/A " Reconnect disk and invoke: metastat -i\n")) == EOF) {
2N/A goto out;
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 stripep->common.size,
2N/A meta_number_to_string(stripep->common.size, DEV_BSIZE))
2N/A == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* print rows */
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A
2N/A /* print stripe and interlace */
2N/A if (rp->comps.comps_len > 1) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Stripe %u: (interlace: %lld blocks)\n"),
2N/A row, rp->interlace) == EOF) {
2N/A goto out;
2N/A }
2N/A } else {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Stripe %u:\n"),
2N/A row) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* print components appropriately */
2N/A if (MD_HAS_PARENT(stripep->common.parent)) {
2N/A if (subdev_row_report(sp, rp, fname, fp, options,
2N/A tstate & MD_DEV_ERRORED, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A } else {
2N/A if (toplev_row_report(sp, rp, fname, fp, options,
2N/A ep) != 0) {
2N/A return (-1);
2N/A }
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 stripe
2N/A */
2N/Aint
2N/Ameta_stripe_print(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
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_stripe_t *stripep;
2N/A int row, comp;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert((stripenp == NULL) ||
2N/A (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))));
2N/A
2N/A /* print all stripes */
2N/A if (stripenp == 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_stripe_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_stripe_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 ((stripep = meta_get_stripe_common(sp, stripenp,
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(stripep->common.parent))) {
2N/A return (0);
2N/A }
2N/A
2N/A /* print appropriate detail */
2N/A if (options & PRINT_SHORT) {
2N/A if (stripe_print(stripep, fname, fp, options, ep) != 0)
2N/A return (-1);
2N/A } else {
2N/A if (stripe_report(sp, stripep, nlpp, fname, fp, options,
2N/A ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* Recurse on components that are metadevices */
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A
2N/A /* look for components that are metadevices */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *namep = cp->compnamep;
2N/A
2N/A if ((metaismeta(namep)) &&
2N/A (meta_print_name(sp, namep, 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 return (0);
2N/A}
2N/A
2N/A/*
2N/A * find stripe component to replace
2N/A */
2N/Aint
2N/Ameta_find_erred_comp(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A mdname_t **compnpp,
2N/A comp_state_t *compstate,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_stripe_t *stripep;
2N/A md_comp_t *compp = NULL;
2N/A uint_t lasterrcnt = 0;
2N/A uint_t row;
2N/A
2N/A /* get stripe */
2N/A *compnpp = NULL;
2N/A if ((stripep = meta_get_stripe_common(sp, stripenp, 1, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /*
2N/A * Try to find the first erred component.
2N/A * If there is not one, then look for the
2N/A * first last_erred component.
2N/A */
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A
2N/A if ((cp->state == CS_ERRED) && ((compp == NULL) ||
2N/A (cp->lasterrcnt < lasterrcnt))) {
2N/A compp = cp;
2N/A lasterrcnt = cp->lasterrcnt;
2N/A }
2N/A }
2N/A }
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A
2N/A if ((cp->state == CS_LAST_ERRED) && ((compp == NULL) ||
2N/A (cp->lasterrcnt < lasterrcnt))) {
2N/A compp = cp;
2N/A lasterrcnt = cp->lasterrcnt;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* return component */
2N/A if (compp != NULL) {
2N/A *compnpp = compp->compnamep;
2N/A *compstate = compp->state;
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * invalidate component names
2N/A */
2N/Astatic int
2N/Ainvalidate_components(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_stripe_t *stripep;
2N/A uint_t row;
2N/A
2N/A if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
2N/A return (-1);
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A
2N/A meta_invalidate_name(compnp);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * attach components to stripe
2N/A */
2N/Aint
2N/Ameta_stripe_attach(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A mdnamelist_t *nlp,
2N/A diskaddr_t interlace,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdnamelist_t *lp;
2N/A ms_unit_t *old_un, *new_un;
2N/A struct ms_row *mdr, *new_mdr;
2N/A uint_t newcomps, ncomps, icomp;
2N/A uint_t row;
2N/A size_t mdsize, first_comp;
2N/A diskaddr_t new_blks;
2N/A diskaddr_t limit;
2N/A diskaddr_t disk_size = 0;
2N/A ms_comp_t *mdcomp, *new_comp;
2N/A uint_t write_reinstruct = 0;
2N/A uint_t read_reinstruct = 0;
2N/A mdnamelist_t *keynlp = NULL;
2N/A uint_t round_cyl = 1;
2N/A minor_t parent;
2N/A md_grow_params_t mgp;
2N/A int rval = -1;
2N/A md_timeval32_t creation_time;
2N/A int create_flag = MD_CRO_32BIT;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
2N/A
2N/A /* check type */
2N/A if (metachkmeta(stripenp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* check and count components */
2N/A assert(nlp != NULL);
2N/A newcomps = 0;
2N/A for (lp = nlp; (lp != NULL); lp = lp->next) {
2N/A mdname_t *np = lp->namep;
2N/A mdnamelist_t *p;
2N/A
2N/A /* check against existing devices */
2N/A if (meta_check_component(sp, np, 0, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* check against ourselves */
2N/A for (p = lp->next; (p != NULL); p = p->next) {
2N/A if (meta_check_overlap(np->cname, np, 0, -1,
2N/A p->namep, 0, -1, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* count */
2N/A ++newcomps;
2N/A }
2N/A
2N/A /* get old unit */
2N/A if ((old_un = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* if zero, inherit the last rows interlace value */
2N/A if (interlace == 0) {
2N/A mdr = &old_un->un_row[old_un->un_nrows - 1];
2N/A interlace = mdr->un_interlace;
2N/A }
2N/A
2N/A /*
2N/A * calculate size of new unit structure
2N/A */
2N/A
2N/A /* unit + rows */
2N/A mdsize = sizeof (ms_unit_t) - sizeof (struct ms_row);
2N/A mdsize += sizeof (struct ms_row) * (old_un->un_nrows + 1);
2N/A
2N/A /* number of new components being added */
2N/A ncomps = newcomps;
2N/A
2N/A /* count the # of components in the old unit */
2N/A mdr = &old_un->un_row[0];
2N/A for (row = 0; (row < old_un->un_nrows); row++)
2N/A ncomps += mdr[row].un_ncomp;
2N/A first_comp = roundup(mdsize, sizeof (long long));
2N/A mdsize += sizeof (ms_comp_t) * ncomps + (first_comp - mdsize);
2N/A
2N/A /* allocate new unit */
2N/A new_un = Zalloc(mdsize);
2N/A new_un->un_ocomp = first_comp;
2N/A
2N/A /* compute new data */
2N/A new_mdr = &new_un->un_row[old_un->un_nrows];
2N/A new_mdr->un_icomp = ncomps - newcomps;
2N/A new_mdr->un_ncomp = newcomps;
2N/A new_mdr->un_blocks = 0;
2N/A new_mdr->un_cum_blocks =
2N/A old_un->un_row[old_un->un_nrows - 1].un_cum_blocks;
2N/A new_mdr->un_interlace = interlace;
2N/A
2N/A /* for each new device */
2N/A mdcomp = (struct ms_comp *)(void *)&((char *)new_un)[new_un->un_ocomp];
2N/A icomp = new_mdr->un_icomp;
2N/A if (meta_gettimeofday(&creation_time) == -1)
2N/A return (mdsyserror(ep, errno, NULL));
2N/A for (lp = nlp; (lp != NULL); lp = lp->next) {
2N/A mdname_t *np = lp->namep;
2N/A diskaddr_t size, start_blk;
2N/A mdgeom_t *geomp;
2N/A
2N/A /* figure out how big */
2N/A if ((size = metagetsize(np, ep)) == MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((start_blk = metagetstart(sp, np, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if (start_blk >= size) {
2N/A (void) mdsyserror(ep, ENOSPC, np->cname);
2N/A goto out;
2N/A }
2N/A size -= start_blk;
2N/A if (newcomps > 1)
2N/A size = rounddown(size, interlace);
2N/A
2N/A /* adjust for smallest disk */
2N/A if (disk_size == 0) {
2N/A disk_size = size;
2N/A } else if (size < disk_size) {
2N/A disk_size = size;
2N/A }
2N/A
2N/A /* get worst reinstructs */
2N/A if ((geomp = metagetgeom(np, ep)) == NULL)
2N/A goto out;
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 /* 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, np, &keynlp, ep) != 0)
2N/A goto out;
2N/A }
2N/A
2N/A /* build new component */
2N/A new_comp = &mdcomp[icomp++];
2N/A new_comp->un_key = np->key;
2N/A new_comp->un_dev = np->dev;
2N/A new_comp->un_start_block = start_blk;
2N/A new_comp->un_mirror.ms_state = CS_OKAY;
2N/A new_comp->un_mirror.ms_timestamp = creation_time;
2N/A }
2N/A
2N/A limit = LLONG_MAX;
2N/A
2N/A /* compute new size */
2N/A new_mdr->un_blocks = new_mdr->un_ncomp * disk_size;
2N/A new_blks = new_mdr->un_cum_blocks + new_mdr->un_blocks;
2N/A if (new_blks > limit) {
2N/A new_mdr->un_cum_blocks = limit;
2N/A new_blks = limit;
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "unit size overflow, limit is %lld blocks\n"),
2N/A limit);
2N/A } else {
2N/A new_mdr->un_cum_blocks += new_mdr->un_blocks;
2N/A }
2N/A new_un->c.un_actual_tb = new_mdr->un_cum_blocks;
2N/A new_un->un_nrows = old_un->un_nrows + 1;
2N/A
2N/A /* adjust geometry */
2N/A new_un->c.un_nhead = old_un->c.un_nhead;
2N/A new_un->c.un_nsect = old_un->c.un_nsect;
2N/A new_un->c.un_rpm = old_un->c.un_rpm;
2N/A new_un->c.un_wr_reinstruct = old_un->c.un_wr_reinstruct;
2N/A new_un->c.un_rd_reinstruct = old_un->c.un_rd_reinstruct;
2N/A if (meta_adjust_geom((md_unit_t *)new_un, stripenp,
2N/A write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
2N/A goto out;
2N/A
2N/A /* if in dryrun mode, we are done here. */
2N/A if ((options & MDCMD_DOIT) == 0) {
2N/A if (options & MDCMD_PRINT) {
2N/A if (newcomps == 1) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: attaching component would suceed\n"),
2N/A stripenp->cname);
2N/A } else {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: attaching components would suceed\n"),
2N/A stripenp->cname);
2N/A }
2N/A }
2N/A rval = 0; /* success */
2N/A goto out;
2N/A }
2N/A
2N/A create_flag = meta_check_devicesize(new_un->c.un_total_blocks);
2N/A
2N/A /* grow stripe */
2N/A (void) memset(&mgp, 0, sizeof (mgp));
2N/A mgp.mnum = MD_SID(old_un);
2N/A MD_SETDRIVERNAME(&mgp, MD_STRIPE, sp->setno);
2N/A mgp.size = mdsize;
2N/A mgp.mdp = (uintptr_t)new_un;
2N/A mgp.nrows = old_un->un_nrows;
2N/A if (create_flag == MD_CRO_32BIT) {
2N/A mgp.options = MD_CRO_32BIT;
2N/A new_un->c.un_revision &= ~MD_64BIT_META_DEV;
2N/A } else {
2N/A mgp.options = MD_CRO_64BIT;
2N/A new_un->c.un_revision |= MD_64BIT_META_DEV;
2N/A }
2N/A
2N/A if ((MD_HAS_PARENT(old_un->c.un_parent)) &&
2N/A (old_un->c.un_parent != MD_MULTI_PARENT)) {
2N/A mgp.npar = 1;
2N/A parent = old_un->c.un_parent;
2N/A mgp.par = (uintptr_t)(&parent);
2N/A }
2N/A
2N/A if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, NULL) != 0) {
2N/A (void) mdstealerror(ep, &mgp.mde);
2N/A goto out;
2N/A }
2N/A
2N/A /* clear cache */
2N/A if (invalidate_components(sp, stripenp, ep) != 0)
2N/A goto out;
2N/A meta_invalidate_name(stripenp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A if (newcomps == 1) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: component is attached\n"), stripenp->cname);
2N/A } else {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: components are attached\n"), stripenp->cname);
2N/A }
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A /* grow any parents */
2N/A if (meta_concat_parent(sp, stripenp, ep) != 0)
2N/A return (-1);
2N/A
2N/A rval = 0; /* success */
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A Free(old_un);
2N/A Free(new_un);
2N/A if (options & MDCMD_DOIT) {
2N/A if (rval != 0)
2N/A (void) del_key_names(sp, keynlp, NULL);
2N/A metafreenamelist(keynlp);
2N/A }
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * get stripe parameters
2N/A */
2N/Aint
2N/Ameta_stripe_get_params(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A ms_params_t *paramsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_stripe_t *stripep;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(stripenp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get unit */
2N/A if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* return parameters */
2N/A (void) memset(paramsp, 0, sizeof (*paramsp));
2N/A if (stripep->hspnamep == NULL)
2N/A paramsp->hsp_id = MD_HSP_NONE;
2N/A else
2N/A paramsp->hsp_id = stripep->hspnamep->hsp;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * set stripe parameters
2N/A */
2N/Aint
2N/Ameta_stripe_set_params(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A ms_params_t *paramsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_stripe_params_t msp;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(stripenp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* set parameters */
2N/A (void) memset(&msp, 0, sizeof (msp));
2N/A MD_SETDRIVERNAME(&msp, MD_STRIPE, sp->setno);
2N/A msp.mnum = meta_getminor(stripenp->dev);
2N/A msp.params = *paramsp;
2N/A if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, stripenp->cname) != 0)
2N/A return (mdstealerror(ep, &msp.mde));
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(stripenp);
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check for dups in the stripe itself
2N/A */
2N/Astatic int
2N/Acheck_twice(
2N/A md_stripe_t *stripep,
2N/A uint_t row,
2N/A uint_t comp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *stripenp = stripep->common.namep;
2N/A mdname_t *thisnp;
2N/A uint_t r;
2N/A
2N/A thisnp = stripep->rows.rows_val[row].comps.comps_val[comp].compnamep;
2N/A for (r = 0; (r <= row); ++r) {
2N/A md_row_t *rp = &stripep->rows.rows_val[r];
2N/A uint_t e = ((r == row) ? comp : rp->comps.comps_len);
2N/A uint_t c;
2N/A
2N/A for (c = 0; (c < e); ++c) {
2N/A md_comp_t *cp = &rp->comps.comps_val[c];
2N/A mdname_t *compnp = cp->compnamep;
2N/A
2N/A if (meta_check_overlap(stripenp->cname, thisnp, 0, -1,
2N/A compnp, 0, -1, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * default stripe interlace
2N/A */
2N/Adiskaddr_t
2N/Ameta_default_stripe_interlace(void)
2N/A{
2N/A diskaddr_t interlace;
2N/A
2N/A /* default to 512k, round up if necessary */
2N/A interlace = btodb(512 * 1024);
2N/A if (interlace < btodb(MININTERLACE))
2N/A interlace = roundup(MININTERLACE, interlace);
2N/A return (interlace);
2N/A}
2N/A
2N/A/*
2N/A * convert interlaces
2N/A */
2N/Aint
2N/Ameta_stripe_check_interlace(
2N/A diskaddr_t interlace,
2N/A char *uname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if ((interlace < btodb(MININTERLACE)) ||
2N/A (interlace > btodb(MAXINTERLACE))) {
2N/A return (mderror(ep, MDE_BAD_INTERLACE, uname));
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * check stripe
2N/A */
2N/Aint
2N/Ameta_check_stripe(
2N/A mdsetname_t *sp,
2N/A md_stripe_t *stripep,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *stripenp = stripep->common.namep;
2N/A int force = ((options & MDCMD_FORCE) ? 1 : 0);
2N/A int doit = ((options & MDCMD_DOIT) ? 1 : 0);
2N/A int updateit = ((options & MDCMD_UPDATE) ? 1 : 0);
2N/A uint_t row;
2N/A
2N/A /* check rows */
2N/A if (stripep->rows.rows_len < 1) {
2N/A return (mdmderror(ep, MDE_BAD_STRIPE,
2N/A meta_getminor(stripenp->dev), stripenp->cname));
2N/A }
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A /* check number */
2N/A if (rp->comps.comps_len < 1) {
2N/A return (mdmderror(ep, MDE_BAD_STRIPE,
2N/A meta_getminor(stripenp->dev), stripenp->cname));
2N/A }
2N/A
2N/A /* compute default interlace */
2N/A if (rp->interlace == 0) {
2N/A rp->interlace = meta_default_stripe_interlace();
2N/A }
2N/A
2N/A /* check interlace */
2N/A if (meta_stripe_check_interlace(rp->interlace, stripenp->cname,
2N/A ep) != 0) {
2N/A return (-1);
2N/A }
2N/A
2N/A /* check components */
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A diskaddr_t start_blk, size;
2N/A
2N/A /* check component */
2N/A if (!updateit) {
2N/A if (meta_check_component(sp, compnp,
2N/A force, ep) != 0)
2N/A return (-1);
2N/A if (((start_blk = metagetstart(sp, compnp,
2N/A ep)) == MD_DISKADDR_ERROR) ||
2N/A ((size = metagetsize(compnp, ep)) ==
2N/A MD_DISKADDR_ERROR)) {
2N/A return (-1);
2N/A }
2N/A if (start_blk >= size)
2N/A return (mdsyserror(ep, ENOSPC,
2N/A compnp->cname));
2N/A size -= start_blk;
2N/A size = rounddown(size, rp->interlace);
2N/A if (size == 0)
2N/A return (mdsyserror(ep, ENOSPC,
2N/A compnp->cname));
2N/A }
2N/A
2N/A /* check this stripe too */
2N/A if (check_twice(stripep, row, comp, ep) != 0)
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* check hotspare pool name */
2N/A if (doit) {
2N/A if ((stripep->hspnamep != NULL) &&
2N/A (metachkhsp(sp, stripep->hspnamep, ep) != 0)) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * setup stripe geometry
2N/A */
2N/Astatic int
2N/Astripe_geom(
2N/A md_stripe_t *stripep,
2N/A ms_unit_t *ms,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t nrow = stripep->rows.rows_len;
2N/A uint_t write_reinstruct = 0;
2N/A uint_t read_reinstruct = 0;
2N/A uint_t round_cyl = 1;
2N/A uint_t row;
2N/A mdgeom_t *geomp;
2N/A diskaddr_t first_row_size = 0;
2N/A char *miscname;
2N/A int is_sp = 0;
2N/A
2N/A /* get worst reinstructs */
2N/A for (row = 0; (row < nrow); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t ncomp = rp->comps.comps_len;
2N/A uint_t comp;
2N/A
2N/A for (comp = 0; (comp < ncomp); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A
2N/A if ((geomp = metagetgeom(compnp, 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 }
2N/A
2N/A if ((geomp = metagetgeom(
2N/A stripep->rows.rows_val[0].comps.comps_val[0].compnamep,
2N/A ep)) == NULL) {
2N/A return (-1);
2N/A }
2N/A /*
2N/A * Figure out if the first component is a softpartition as the
2N/A * truncation check only occurs on them.
2N/A */
2N/A if ((miscname = metagetmiscname(
2N/A stripep->rows.rows_val[0].comps.comps_val[0].compnamep,
2N/A ep)) == NULL) {
2N/A if (!mdisdeverror(ep, MDE_NOT_META))
2N/A return (-1);
2N/A } else if (strcmp(miscname, MD_SP) == 0) {
2N/A is_sp = 1;
2N/A }
2N/A
2N/A /*
2N/A * If the stripe is to be multi-terabyte we should
2N/A * use EFI geometries, else we can get rounding errors
2N/A * in meta_setup_geom().
2N/A */
2N/A
2N/A if (ms->c.un_actual_tb > MD_MAX_BLKS_FOR_SMALL_DEVS) {
2N/A geomp->nhead = MD_EFI_FG_HEADS;
2N/A geomp->nsect = MD_EFI_FG_SECTORS;
2N/A geomp->rpm = MD_EFI_FG_RPM;
2N/A }
2N/A
2N/A /* setup geometry from first device */
2N/A if (meta_setup_geom((md_unit_t *)ms, stripep->common.namep, geomp,
2N/A write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
2N/A return (-1);
2N/A
2N/A /*
2N/A * Here we want to make sure that any truncation did not
2N/A * result in lost data (or, more appropriately, inaccessible
2N/A * data).
2N/A *
2N/A * This is mainly a danger for (1, 1) concats, but it is
2N/A * mathematically possible for other somewhat contrived
2N/A * arrangements where in the sum of the lengths of each row
2N/A * beyond the first is smaller than the cylinder size of the
2N/A * only component in the first row.
2N/A *
2N/A * It is tempting to simply test for truncation here, by
2N/A * (md->c.un_total_blocks < md->c.un_actual_tb). That does
2N/A * not tell us, however, if rounding resulted in data loss,
2N/A * rather only that it occurred. The somewhat less obvious
2N/A * test below covers both the obvious (1, 1) case and the
2N/A * aforementioned corner case.
2N/A */
2N/A first_row_size = ms->un_row[0].un_blocks;
2N/A if (is_sp == 1) {
2N/A md_unit_t *md = (md_unit_t *)ms;
2N/A
2N/A if (md->c.un_total_blocks < first_row_size) {
2N/A char buf[] = VAL2STR(ULLONG_MAX);
2N/A
2N/A /*
2N/A * The only difference here is the text of the error
2N/A * message, since the remediation is slightly
2N/A * different in the one-component versus
2N/A * multiple-component cases.
2N/A */
2N/A if (nrow == 1) {
2N/A (void) mderror(ep, MDE_STRIPE_TRUNC_SINGLE,
2N/A stripep->common.namep->cname);
2N/A } else {
2N/A (void) mderror(ep, MDE_STRIPE_TRUNC_MULTIPLE,
2N/A stripep->common.namep->cname);
2N/A }
2N/A
2N/A /*
2N/A * By the size comparison above and the initialization
2N/A * of buf[] in terms of ULLONG_MAX, we guarantee that
2N/A * the value arg is non-negative and that we won't
2N/A * overflow the container.
2N/A */
2N/A mderrorextra(ep, ulltostr((md->c.un_total_blocks +
2N/A (geomp->nhead * geomp->nsect))
2N/A - first_row_size, &buf[sizeof (buf) - 1]));
2N/A
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * create stripe
2N/A */
2N/Aint
2N/Ameta_create_stripe(
2N/A mdsetname_t *sp,
2N/A md_stripe_t *stripep,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *stripenp = stripep->common.namep;
2N/A int force = ((options & MDCMD_FORCE) ? 1 : 0);
2N/A int doall = ((options & MDCMD_ALLOPTION) ? 1 : 0);
2N/A uint_t nrow = stripep->rows.rows_len;
2N/A uint_t ncomp = 0;
2N/A uint_t icomp = 0;
2N/A diskaddr_t cum_blocks = 0;
2N/A diskaddr_t limit;
2N/A size_t mdsize, first_comp;
2N/A uint_t row;
2N/A ms_unit_t *ms;
2N/A ms_comp_t *mdcomp;
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 stripe */
2N/A if (meta_check_stripe(sp, stripep, options, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* allocate stripe unit */
2N/A mdsize = sizeof (*ms) - sizeof (ms->un_row[0]);
2N/A mdsize += sizeof (ms->un_row) * nrow;
2N/A for (row = 0; (row < nrow); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A
2N/A ncomp += rp->comps.comps_len;
2N/A }
2N/A first_comp = roundup(mdsize, sizeof (long long));
2N/A mdsize += (first_comp - mdsize) + (ncomp * sizeof (ms_comp_t));
2N/A ms = Zalloc(mdsize);
2N/A ms->un_ocomp = first_comp;
2N/A if (meta_gettimeofday(&creation_time) == -1)
2N/A return (mdsyserror(ep, errno, NULL));
2N/A
2N/A /* do rows */
2N/A mdcomp = (ms_comp_t *)(void *)&((char *)ms)[ms->un_ocomp];
2N/A for (row = 0; (row < nrow); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t ncomp = rp->comps.comps_len;
2N/A struct ms_row *mdr = &ms->un_row[row];
2N/A diskaddr_t disk_size = 0;
2N/A uint_t comp;
2N/A
2N/A /* setup component count and offfset */
2N/A mdr->un_icomp = icomp;
2N/A mdr->un_ncomp = ncomp;
2N/A
2N/A /* do components */
2N/A for (comp = 0; (comp < ncomp); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A ms_comp_t *mdc = &mdcomp[icomp++];
2N/A diskaddr_t size, start_blk;
2N/A
2N/A /*
2N/A * get start and size
2N/A * if first component is labelled, include label
2N/A */
2N/A if ((size = metagetsize(compnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((start_blk = metagetstart(sp, compnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((row == 0) && (comp == 0)) {
2N/A diskaddr_t label;
2N/A int has_db;
2N/A
2N/A if ((has_db = metahasmddb(sp, compnp, ep)) < 0)
2N/A goto out;
2N/A if ((label = metagetlabel(compnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((has_db == 0) && (label != 0)) {
2N/A ms->c.un_flag |= MD_LABELED;
2N/A start_blk = compnp->start_blk = 0;
2N/A }
2N/A }
2N/A /* make sure we still have something left */
2N/A if (start_blk >= size) {
2N/A (void) mdsyserror(ep, ENOSPC, compnp->cname);
2N/A goto out;
2N/A }
2N/A size -= start_blk;
2N/A
2N/A /*
2N/A * round down by interlace: this only applies
2N/A * if this row is a stripe, as indicated by
2N/A * (ncomp > 1)
2N/A */
2N/A if (ncomp > 1)
2N/A size = rounddown(size, rp->interlace);
2N/A
2N/A if (size == 0) {
2N/A (void) mdsyserror(ep, ENOSPC, compnp->cname);
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * adjust for smallest disk: for a concat (any
2N/A * row with only one component), this will
2N/A * never hit the second conditional.
2N/A */
2N/A if (disk_size == 0) {
2N/A disk_size = size;
2N/A } else if (size < disk_size) {
2N/A disk_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, compnp, &keynlp, ep) != 0)
2N/A goto out;
2N/A }
2N/A
2N/A /* setup component */
2N/A mdc->un_key = compnp->key;
2N/A mdc->un_dev = compnp->dev;
2N/A mdc->un_start_block = start_blk;
2N/A mdc->un_mirror.ms_state = CS_OKAY;
2N/A mdc->un_mirror.ms_timestamp = creation_time;
2N/A }
2N/A limit = LLONG_MAX;
2N/A
2N/A /* setup row */
2N/A mdr->un_blocks = mdr->un_ncomp * disk_size;
2N/A cum_blocks += mdr->un_blocks;
2N/A if (cum_blocks > limit) {
2N/A cum_blocks = limit;
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "unit size overflow, limit is %lld blocks\n"),
2N/A limit);
2N/A }
2N/A mdr->un_cum_blocks = cum_blocks;
2N/A mdr->un_interlace = rp->interlace;
2N/A }
2N/A
2N/A /* setup unit */
2N/A ms->c.un_type = MD_DEVICE;
2N/A MD_SID(ms) = meta_getminor(stripenp->dev);
2N/A ms->c.un_actual_tb = cum_blocks;
2N/A ms->c.un_size = mdsize;
2N/A if (stripep->hspnamep != NULL)
2N/A ms->un_hsp_id = stripep->hspnamep->hsp;
2N/A else
2N/A ms->un_hsp_id = MD_HSP_NONE;
2N/A ms->un_nrows = nrow;
2N/A
2N/A /* fill in the size of the stripe */
2N/A if (options & MDCMD_UPDATE) {
2N/A stripep->common.size = ms->c.un_total_blocks;
2N/A for (row = 0; (row < nrow); ++row) {
2N/A stripep->rows.rows_val[row].row_size =
2N/A ms->un_row[row].un_blocks;
2N/A }
2N/A }
2N/A
2N/A if (stripe_geom(stripep, ms, ep) != 0) {
2N/A /*
2N/A * If the device is being truncated then only allow this
2N/A * if the user is aware (using the -f option) or they
2N/A * are in a recovery/complete build situation (using the -a
2N/A * option).
2N/A */
2N/A if ((mdiserror(ep, MDE_STRIPE_TRUNC_SINGLE) ||
2N/A mdiserror(ep, MDE_STRIPE_TRUNC_MULTIPLE)) &&
2N/A (force || doall)) {
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A"%s: WARNING: This form of metainit is not recommended.\n"
2N/A"The stripe is truncating the size of the underlying device.\n"
2N/A"Please see ERRORS in metainit(1M) for additional information.\n"),
2N/A stripenp->cname);
2N/A mdclrerror(ep);
2N/A } else {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A create_flag = meta_check_devicesize(ms->c.un_total_blocks);
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 stripe */
2N/A (void) memset(&set_params, 0, sizeof (set_params));
2N/A
2N/A /* did the user tell us to generate a large device? */
2N/A if (create_flag == MD_CRO_64BIT) {
2N/A ms->c.un_revision |= MD_64BIT_META_DEV;
2N/A set_params.options = MD_CRO_64BIT;
2N/A } else {
2N/A ms->c.un_revision &= ~MD_64BIT_META_DEV;
2N/A set_params.options = MD_CRO_32BIT;
2N/A }
2N/A
2N/A set_params.mnum = MD_SID(ms);
2N/A set_params.size = ms->c.un_size;
2N/A set_params.mdp = (uintptr_t)ms;
2N/A MD_SETDRIVERNAME(&set_params, MD_STRIPE, MD_MIN2SET(set_params.mnum));
2N/A if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
2N/A stripenp->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(ms);
2N/A if (rval != 0) {
2N/A (void) del_key_names(sp, keynlp, NULL);
2N/A }
2N/A
2N/A metafreenamelist(keynlp);
2N/A if ((rval == 0) && (options & MDCMD_DOIT)) {
2N/A if (invalidate_components(sp, stripenp, ep) != 0)
2N/A rval = -1;
2N/A meta_invalidate_name(stripenp);
2N/A }
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * initialize stripe
2N/A * NOTE: this functions is metainit(1m)'s command line parser!
2N/A */
2N/Aint
2N/Ameta_init_stripe(
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 *stripenp = NULL;
2N/A int old_optind;
2N/A int c;
2N/A md_stripe_t *stripep = NULL;
2N/A uint_t nrow, row;
2N/A int rval = -1;
2N/A
2N/A /* get stripe name */
2N/A assert(argc > 0);
2N/A if (argc < 1)
2N/A goto syntax;
2N/A
2N/A if ((stripenp = metaname(spp, uname, META_DEVICE, ep)) == NULL)
2N/A goto out;
2N/A assert(*spp != NULL);
2N/A uname = stripenp->cname;
2N/A if (metachkmeta(stripenp, 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))
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(stripenp, ep) != NULL) {
2N/A (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
2N/A meta_getminor(stripenp->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 /* 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 stripe */
2N/A stripep = Zalloc(sizeof (*stripep));
2N/A
2N/A /* setup common */
2N/A stripep->common.namep = stripenp;
2N/A stripep->common.type = MD_DEVICE;
2N/A
2N/A /* allocate and parse rows */
2N/A if (argc < 1) {
2N/A (void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev),
2N/A uname);
2N/A goto out;
2N/A } else if ((sscanf(argv[0], "%u", &nrow) != 1) || ((int)nrow < 0)) {
2N/A goto syntax;
2N/A } else if (nrow < 1) {
2N/A (void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev),
2N/A uname);
2N/A goto out;
2N/A }
2N/A --argc, ++argv;
2N/A stripep->rows.rows_len = nrow;
2N/A stripep->rows.rows_val =
2N/A Zalloc(nrow * sizeof (*stripep->rows.rows_val));
2N/A for (row = 0; (row < nrow); ++row) {
2N/A md_row_t *mdr = &stripep->rows.rows_val[row];
2N/A uint_t ncomp, comp;
2N/A
2N/A /* allocate and parse components */
2N/A if (argc < 1) {
2N/A (void) mdmderror(ep, MDE_NROWS,
2N/A meta_getminor(stripenp->dev), uname);
2N/A goto out;
2N/A } else if ((sscanf(argv[0], "%u", &ncomp) != 1) ||
2N/A ((int)ncomp < 0)) {
2N/A goto syntax;
2N/A } else if (ncomp < 1) {
2N/A (void) mdmderror(ep, MDE_NCOMPS,
2N/A meta_getminor(stripenp->dev), uname);
2N/A goto out;
2N/A }
2N/A --argc, ++argv;
2N/A mdr->comps.comps_len = ncomp;
2N/A mdr->comps.comps_val =
2N/A Zalloc(ncomp * sizeof (*mdr->comps.comps_val));
2N/A for (comp = 0; (comp < ncomp); ++comp) {
2N/A md_comp_t *mdc = &mdr->comps.comps_val[comp];
2N/A mdname_t *compnp;
2N/A
2N/A /* parse component name */
2N/A if (argc < 1) {
2N/A (void) mdmderror(ep, MDE_NCOMPS,
2N/A meta_getminor(stripenp->dev), uname);
2N/A goto out;
2N/A }
2N/A if ((compnp = metaname(spp, argv[0], UNKNOWN,
2N/A ep)) == NULL) {
2N/A goto out;
2N/A }
2N/A /* check for soft partition */
2N/A if (meta_sp_issp(*spp, compnp, ep) != 0) {
2N/A /* check disk */
2N/A if (metachkcomp(compnp, ep) != 0) {
2N/A goto out;
2N/A }
2N/A }
2N/A mdc->compnamep = compnp;
2N/A --argc, ++argv;
2N/A }
2N/A
2N/A /* parse row options */
2N/A old_optind = optind = 0;
2N/A opterr = 0;
2N/A while ((c = getopt(argc, argv, "i:")) != -1) {
2N/A switch (c) {
2N/A case 'i':
2N/A if (parse_interlace(uname, optarg,
2N/A &mdr->interlace, ep) != 0) {
2N/A goto out;
2N/A }
2N/A if (meta_stripe_check_interlace(mdr->interlace,
2N/A uname, ep))
2N/A goto out;
2N/A break;
2N/A
2N/A default:
2N/A optind = old_optind; /* bomb out later */
2N/A goto done_row_opts;
2N/A }
2N/A old_optind = optind;
2N/A }
2N/Adone_row_opts:
2N/A argc -= optind;
2N/A argv += optind;
2N/A }
2N/A
2N/A /* parse stripe options */
2N/A old_optind = optind = 0;
2N/A opterr = 0;
2N/A while ((c = getopt(argc, argv, "h:")) != -1) {
2N/A switch (c) {
2N/A case 'h':
2N/A if ((stripep->hspnamep = metahspname(spp, optarg,
2N/A ep)) == NULL) {
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Get out if the specified hotspare pool really
2N/A * doesn't exist.
2N/A */
2N/A if (stripep->hspnamep->hsp == MD_HSP_NONE) {
2N/A (void) mdhsperror(ep, MDE_INVAL_HSP,
2N/A stripep->hspnamep->hsp, optarg);
2N/A goto out;
2N/A }
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 /* we should be at the end */
2N/A if (argc != 0)
2N/A goto syntax;
2N/A
2N/A /* create stripe */
2N/A if (meta_create_stripe(*spp, stripep, 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: Concat/Stripe 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 (stripep != NULL)
2N/A meta_free_stripe(stripep);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * reset stripes
2N/A */
2N/Aint
2N/Ameta_stripe_reset(
2N/A mdsetname_t *sp,
2N/A mdname_t *stripenp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_stripe_t *stripep;
2N/A int rval = -1;
2N/A int row, comp;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert((stripenp == NULL) ||
2N/A (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))));
2N/A
2N/A /* reset all stripes */
2N/A if (stripenp == NULL) {
2N/A mdnamelist_t *stripenlp = NULL;
2N/A mdnamelist_t *p;
2N/A
2N/A /* for each stripe */
2N/A rval = 0;
2N/A if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0)
2N/A return (-1);
2N/A for (p = stripenlp; (p != NULL); p = p->next) {
2N/A /* reset stripe */
2N/A stripenp = p->namep;
2N/A
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 stripenp->cname, options, 0, ep) != 0) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A } else {
2N/A if (meta_stripe_reset(sp, stripenp,
2N/A options, 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(stripenlp);
2N/A return (rval);
2N/A }
2N/A
2N/A /* check name */
2N/A if (metachkmeta(stripenp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get unit structure */
2N/A if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* make sure nobody owns us */
2N/A if (MD_HAS_PARENT(stripep->common.parent)) {
2N/A return (mdmderror(ep, MDE_IN_USE, meta_getminor(stripenp->dev),
2N/A stripenp->cname));
2N/A }
2N/A
2N/A /* clear subdevices cache */
2N/A if (invalidate_components(sp, stripenp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* clear metadevice */
2N/A if (meta_reset(sp, stripenp, 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: Concat/Stripe is cleared\n"),
2N/A stripenp->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
2N/A for (row = 0; (row < stripep->rows.rows_len); ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A
2N/A /* only recurse on metadevices */
2N/A if (! metaismeta(compnp))
2N/A continue;
2N/A
2N/A if (meta_reset_by_name(sp, compnp, options, ep) != 0)
2N/A rval = -1;
2N/A }
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/Aout:
2N/A meta_invalidate_name(stripenp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * reports TRUE if any stripe component is in error
2N/A */
2N/Aint
2N/Ameta_stripe_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *stripe_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 = stripe_names; nlp; nlp = nlp->next) {
2N/A md_stripe_t *stripep;
2N/A int row;
2N/A
2N/A if ((stripep = meta_get_stripe(sp, nlp->namep, ep)) == NULL) {
2N/A any_errs |= TRUE;
2N/A goto out;
2N/A }
2N/A
2N/A for (row = 0; row < stripep->rows.rows_len; ++row) {
2N/A md_row_t *rp = &stripep->rows.rows_val[row];
2N/A uint_t comp;
2N/A
2N/A for (comp = 0; comp < rp->comps.comps_len; ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A
2N/A if (cp->state != CS_OKAY) {
2N/A any_errs |= TRUE;
2N/A goto out;
2N/A }
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}
2N/A
2N/Aint
2N/Ameta_stripe_check_component(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A md_dev64_t mydevs,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_stripe_t *stripe;
2N/A mdnm_params_t nm;
2N/A md_getdevs_params_t mgd;
2N/A side_t sideno;
2N/A char *miscname;
2N/A md_dev64_t *mydev = NULL;
2N/A mdkey_t key;
2N/A char *pname = NULL, *t;
2N/A char *ctd_name = NULL;
2N/A char *devname = NULL;
2N/A int len;
2N/A int cnt, i;
2N/A int rval = -1;
2N/A
2N/A (void) memset(&nm, '\0', sizeof (nm));
2N/A if ((stripe = meta_get_stripe_common(sp, np, 0, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if ((miscname = metagetmiscname(np, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A sideno = getmyside(sp, ep);
2N/A
2N/A
2N/A /* get count of underlying devices */
2N/A
2N/A (void) memset(&mgd, '\0', sizeof (mgd));
2N/A MD_SETDRIVERNAME(&mgd, miscname, sp->setno);
2N/A mgd.mnum = meta_getminor(np->dev);
2N/A mgd.cnt = 0;
2N/A mgd.devs = NULL;
2N/A if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, np->cname) != 0) {
2N/A (void) mdstealerror(ep, &mgd.mde);
2N/A rval = 0;
2N/A goto out;
2N/A } else if (mgd.cnt <= 0) {
2N/A assert(mgd.cnt >= 0);
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Now get the data from the unit structure.
2N/A * The compnamep stuff contains the data from
2N/A * the namespace and we need the un_dev
2N/A * from the unit structure.
2N/A */
2N/A mydev = Zalloc(sizeof (*mydev) * mgd.cnt);
2N/A mgd.devs = (uintptr_t)mydev;
2N/A if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, np->cname) != 0) {
2N/A (void) mdstealerror(ep, &mgd.mde);
2N/A rval = 0;
2N/A goto out;
2N/A } else if (mgd.cnt <= 0) {
2N/A assert(mgd.cnt >= 0);
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A
2N/A for (cnt = 0, i = 0; i < stripe->rows.rows_len; i++) {
2N/A md_row_t *rp = &stripe->rows.rows_val[i];
2N/A uint_t comp;
2N/A for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2N/A md_comp_t *cp = &rp->comps.comps_val[comp];
2N/A mdname_t *compnp = cp->compnamep;
2N/A
2N/A if (mydevs == mydev[cnt]) {
2N/A /* Get the devname from the name space. */
2N/A if ((devname = meta_getnmentbydev(sp->setno,
2N/A sideno, compnp->dev, NULL, NULL,
2N/A &key, ep)) == NULL) {
2N/A goto out;
2N/A }
2N/A
2N/A if (compnp->dev != meta_getminor(mydev[cnt])) {
2N/A /*
2N/A * The minor numbers are different.
2N/A * Update the namespace with the
2N/A * information from the component.
2N/A */
2N/A
2N/A t = strrchr(devname, '/');
2N/A t++;
2N/A ctd_name = Strdup(t);
2N/A
2N/A len = strlen(devname);
2N/A t = strrchr(devname, '/');
2N/A t++;
2N/A pname = Zalloc((len - strlen(t)) + 1);
2N/A (void) strncpy(pname, devname,
2N/A (len - strlen(t)));
2N/A
2N/A if (meta_update_namespace(sp->setno,
2N/A sideno, ctd_name, mydev[i],
2N/A key, pname, ep) != 0) {
2N/A goto out;
2N/A }
2N/A }
2N/A rval = 0;
2N/A break;
2N/A } /* End of if (mydevs == mydev[i]) */
2N/A cnt++;
2N/A } /* End of second for loop */
2N/A } /* End of first for loop */
2N/Aout:
2N/A if (pname != NULL)
2N/A Free(pname);
2N/A if (ctd_name != NULL)
2N/A Free(ctd_name);
2N/A if (devname != NULL)
2N/A Free(devname);
2N/A if (mydev != NULL)
2N/A Free(mydev);
2N/A return (rval);
2N/A}