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) 1994, 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 * RAID operations
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <meta.h>
2N/A#include <sys/lvm/md_raid.h>
2N/A#include <sys/lvm/mdvar.h>
2N/A#include <sys/lvm/md_convert.h>
2N/A#include <stddef.h>
2N/A
2N/A/*
2N/A * FUNCTION: meta_get_raid_names()
2N/A * INPUT: sp - the set name to get raid from
2N/A * options - options from the command line
2N/A * OUTPUT: nlpp - list of all raid names
2N/A * ep - return error pointer
2N/A * RETURNS: int - -1 if error, 0 success
2N/A * PURPOSE: returns a list of all raid in the metadb
2N/A * for all devices in the specified set
2N/A */
2N/Aint
2N/Ameta_get_raid_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_RAID, sp, nlpp, options, ep));
2N/A}
2N/A
2N/A/*
2N/A * free raid unit
2N/A */
2N/Avoid
2N/Ameta_free_raid(
2N/A md_raid_t *raidp
2N/A)
2N/A{
2N/A if (raidp->cols.cols_val != NULL) {
2N/A assert(raidp->cols.cols_len > 0);
2N/A Free(raidp->cols.cols_val);
2N/A }
2N/A Free(raidp);
2N/A}
2N/A
2N/A/*
2N/A * get raid (common)
2N/A */
2N/Amd_raid_t *
2N/Ameta_get_raid_common(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A int fast,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mddrivename_t *dnp = raidnp->drivenamep;
2N/A char *miscname;
2N/A mr_unit_t *mr;
2N/A md_raid_t *raidp;
2N/A uint_t ncol;
2N/A uint_t col;
2N/A md_resync_ioctl_t ri;
2N/A
2N/A /* must have set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
2N/A
2N/A /* short circuit */
2N/A if (dnp->unitp != NULL) {
2N/A assert(dnp->unitp->type == MD_METARAID);
2N/A return ((md_raid_t *)dnp->unitp);
2N/A }
2N/A
2N/A /* get miscname and unit */
2N/A if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
2N/A return (NULL);
2N/A if (strcmp(miscname, MD_RAID) != 0) {
2N/A (void) mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
2N/A raidnp->cname);
2N/A return (NULL);
2N/A }
2N/A if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
2N/A return (NULL);
2N/A assert(mr->c.un_type == MD_METARAID);
2N/A
2N/A /* allocate raid */
2N/A raidp = Zalloc(sizeof (*raidp));
2N/A
2N/A /* allocate columns */
2N/A ncol = mr->un_totalcolumncnt;
2N/A assert(ncol >= MD_RAID_MIN);
2N/A raidp->cols.cols_len = ncol;
2N/A raidp->cols.cols_val = Zalloc(raidp->cols.cols_len *
2N/A sizeof (*raidp->cols.cols_val));
2N/A
2N/A /* get common info */
2N/A raidp->common.namep = raidnp;
2N/A raidp->common.type = mr->c.un_type;
2N/A raidp->common.state = mr->c.un_status;
2N/A raidp->common.capabilities = mr->c.un_capabilities;
2N/A raidp->common.parent = mr->c.un_parent;
2N/A raidp->common.size = mr->c.un_total_blocks;
2N/A raidp->common.user_flags = mr->c.un_user_flags;
2N/A raidp->common.revision = mr->c.un_revision;
2N/A
2N/A /* get options */
2N/A raidp->state = mr->un_state;
2N/A raidp->timestamp = mr->un_timestamp;
2N/A raidp->interlace = mr->un_segsize;
2N/A raidp->orig_ncol = mr->un_origcolumncnt;
2N/A raidp->column_size = mr->un_segsize * mr->un_segsincolumn;
2N/A raidp->pw_count = mr->un_pwcnt;
2N/A assert(raidp->orig_ncol <= ncol);
2N/A if ((mr->un_hsp_id != MD_HSP_NONE) &&
2N/A ((raidp->hspnamep = metahsphspname(&sp, mr->un_hsp_id,
2N/A ep)) == NULL)) {
2N/A goto out;
2N/A }
2N/A
2N/A /* get columns, update unit state */
2N/A for (col = 0; (col < ncol); ++col) {
2N/A mr_column_t *rcp = &mr->un_column[col];
2N/A md_raidcol_t *mdrcp = &raidp->cols.cols_val[col];
2N/A
2N/A /* get column name */
2N/A mdrcp->colnamep = metakeyname(&sp, rcp->un_orig_key, fast, ep);
2N/A if (mdrcp->colnamep == NULL)
2N/A goto out;
2N/A
2N/A /* override any start_blk */
2N/A#ifdef DEBUG
2N/A if (metagetstart(sp, mdrcp->colnamep, ep) !=
2N/A MD_DISKADDR_ERROR) {
2N/A assert(mdrcp->colnamep->start_blk <=
2N/A rcp->un_orig_devstart);
2N/A } else {
2N/A mdclrerror(ep);
2N/A }
2N/A#endif /* DEBUG */
2N/A mdrcp->colnamep->start_blk = rcp->un_orig_devstart;
2N/A
2N/A /* if hotspared */
2N/A if (HOTSPARED(mr, col)) {
2N/A /* get hotspare name */
2N/A mdrcp->hsnamep = metakeyname(&sp, rcp->un_hs_key,
2N/A fast, ep);
2N/A if (mdrcp->hsnamep == NULL)
2N/A goto out;
2N/A
2N/A if (getenv("META_DEBUG_START_BLK") != NULL) {
2N/A if (metagetstart(sp, mdrcp->hsnamep, ep) ==
2N/A MD_DISKADDR_ERROR)
2N/A mdclrerror(ep);
2N/A
2N/A if ((mdrcp->hsnamep->start_blk == 0) &&
2N/A (rcp->un_hs_pwstart != 0))
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "%s: suspected bad start block,"
2N/A " seems labelled [raid]\n"),
2N/A mdrcp->hsnamep->cname);
2N/A
2N/A if ((mdrcp->hsnamep->start_blk > 0) &&
2N/A (rcp->un_hs_pwstart == 0))
2N/A md_eprintf(dgettext(TEXT_DOMAIN,
2N/A "%s: suspected bad start block, "
2N/A " seems unlabelled [raid]\n"),
2N/A mdrcp->hsnamep->cname);
2N/A }
2N/A
2N/A /* override any start_blk */
2N/A mdrcp->hsnamep->start_blk = rcp->un_hs_devstart;
2N/A }
2N/A
2N/A /* get state, flags, and timestamp */
2N/A mdrcp->state = rcp->un_devstate;
2N/A mdrcp->flags = rcp->un_devflags;
2N/A mdrcp->timestamp = rcp->un_devtimestamp;
2N/A }
2N/A
2N/A /* get resync info */
2N/A (void) memset(&ri, 0, sizeof (ri));
2N/A ri.ri_mnum = meta_getminor(raidnp->dev);
2N/A MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
2N/A if (metaioctl(MD_IOCGETSYNC, &ri, &ri.mde, raidnp->cname) != 0) {
2N/A (void) mdstealerror(ep, &ri.mde);
2N/A goto out;
2N/A }
2N/A raidp->resync_flags = ri.ri_flags;
2N/A raidp->percent_dirty = ri.ri_percent_dirty;
2N/A raidp->percent_done = ri.ri_percent_done;
2N/A
2N/A /* cleanup, return success */
2N/A Free(mr);
2N/A dnp->unitp = (md_common_t *)raidp;
2N/A return (raidp);
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A Free(mr);
2N/A meta_free_raid(raidp);
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * get raid
2N/A */
2N/Amd_raid_t *
2N/Ameta_get_raid(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (meta_get_raid_common(sp, raidnp, 0, ep));
2N/A}
2N/A
2N/A/*
2N/A * check raid for dev
2N/A */
2N/Astatic int
2N/Ain_raid(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
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_raid_t *raidp;
2N/A uint_t col;
2N/A
2N/A /* should be in the same set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
2N/A
2N/A /* get unit */
2N/A if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* look in columns */
2N/A for (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A diskaddr_t col_sblk;
2N/A int err;
2N/A
2N/A /* check same drive since metagetstart() can fail */
2N/A if ((err = meta_check_samedrive(np, colnp, ep)) < 0)
2N/A return (-1);
2N/A else if (err == 0)
2N/A continue;
2N/A
2N/A /* check overlap */
2N/A if ((col_sblk = metagetstart(sp, colnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if (meta_check_overlap(raidnp->cname, np, slblk, nblks,
2N/A colnp, col_sblk, -1, 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 * check to see if we're in a raid
2N/A */
2N/Aint
2N/Ameta_check_inraid(
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 *raidnlp = 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 raid */
2N/A if (meta_get_raid_names(sp, &raidnlp, 0, ep) < 0)
2N/A return (-1);
2N/A for (p = raidnlp; (p != NULL); p = p->next) {
2N/A mdname_t *raidnp = p->namep;
2N/A
2N/A /* check raid */
2N/A if (in_raid(sp, raidnp, 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(raidnlp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * check column
2N/A */
2N/Aint
2N/Ameta_check_column(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdchkopts_t options = (MDCHK_ALLOW_MDDB);
2N/A
2N/A /* check for soft partitions */
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 }
2N/A
2N/A /* check to ensure that it is not already in use */
2N/A if (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 raid
2N/A */
2N/Astatic int
2N/Araid_print(
2N/A md_raid_t *raidp,
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 col;
2N/A int rval = -1;
2N/A
2N/A
2N/A if (options & PRINT_LARGEDEVICES) {
2N/A if ((raidp->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 ((raidp->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 -r */
2N/A if (fprintf(fp, "%s -r", raidp->common.namep->cname) == EOF)
2N/A goto out;
2N/A
2N/A /*
2N/A * Print columns. Always print the full path.
2N/A */
2N/A for (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *mdrcp = &raidp->cols.cols_val[col];
2N/A
2N/A if (fprintf(fp, " %s", mdrcp->colnamep->rname) == EOF)
2N/A goto out;
2N/A }
2N/A
2N/A if (fprintf(fp, " -k") == EOF)
2N/A goto out;
2N/A
2N/A /* print options */
2N/A if (fprintf(fp, " -i %lldb", raidp->interlace) == EOF)
2N/A goto out;
2N/A
2N/A if (raidp->pw_count != PWCNT_MIN)
2N/A if (fprintf(fp, " -w %d", raidp->pw_count) == EOF)
2N/A goto out;
2N/A
2N/A if (raidp->hspnamep != NULL) {
2N/A if (fprintf(fp, " -h %s", raidp->hspnamep->hspname) == EOF)
2N/A goto out;
2N/A }
2N/A if (raidp->orig_ncol != raidp->cols.cols_len) {
2N/A assert(raidp->orig_ncol < raidp->cols.cols_len);
2N/A if (fprintf(fp, " -o %u", raidp->orig_ncol) == EOF)
2N/A goto out;
2N/A }
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/Astatic int
2N/Afind_resyncing_column(
2N/A md_raid_t *raidp
2N/A)
2N/A{
2N/A int col;
2N/A
2N/A for (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A if (cp->state & RCS_RESYNC)
2N/A return (col);
2N/A }
2N/A
2N/A /* No resyncing columns */
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * convert raid state to name
2N/A */
2N/Achar *
2N/Araid_state_to_name(
2N/A md_raid_t *raidp,
2N/A md_timeval32_t *tvp,
2N/A uint_t tstate /* Errored tstate flags */
2N/A)
2N/A{
2N/A
2N/A /* grab time */
2N/A if (tvp != NULL)
2N/A *tvp = raidp->timestamp;
2N/A
2N/A /*
2N/A * If the device has a transient error state (due to it being DR'ed or
2N/A * failed) and there has been no I/O to it (the actual device is still
2N/A * marked as 'Okay') then we cannot know what the state is or what
2N/A * action to take on it. Therefore report the device as 'Unavailable'.
2N/A * A subsequent I/O to the device will cause the 'Okay' status to
2N/A * disappear if the device is actually gone and then we will print out
2N/A * the appropriate status. The MD_INACCESSIBLE state is only set
2N/A * on the raid when we open it or probe it. One the raid is open
2N/A * then we will just have regular error status on the device.
2N/A */
2N/A if (tstate & MD_INACCESSIBLE) {
2N/A return (dgettext(TEXT_DOMAIN, "Unavailable"));
2N/A }
2N/A
2N/A /* resyncing */
2N/A if (find_resyncing_column(raidp) >= 0)
2N/A return (dgettext(TEXT_DOMAIN, "Resyncing"));
2N/A
2N/A /* everything else */
2N/A switch (raidp->state) {
2N/A case RUS_INIT :
2N/A return (dgettext(TEXT_DOMAIN, "Initializing"));
2N/A case RUS_OKAY :
2N/A return (dgettext(TEXT_DOMAIN, "Okay"));
2N/A case RUS_ERRED :
2N/A /*FALLTHROUGH*/
2N/A case RUS_LAST_ERRED :
2N/A return (dgettext(TEXT_DOMAIN, "Needs Maintenance"));
2N/A case RUS_DOI :
2N/A return (dgettext(TEXT_DOMAIN, "Initialization Failed"));
2N/A case RUS_REGEN :
2N/A return (dgettext(TEXT_DOMAIN, "Regen"));
2N/A default :
2N/A return (dgettext(TEXT_DOMAIN, "invalid"));
2N/A } /* switch */
2N/A}
2N/A
2N/Astatic int
2N/Afind_erred_column(md_raid_t *raidp, rcs_state_t state)
2N/A{
2N/A int col;
2N/A
2N/A for (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A if (cp->state & state)
2N/A return (col);
2N/A }
2N/A
2N/A /* No erred columns */
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * convert raid state to repair action
2N/A */
2N/Achar *
2N/Araid_state_to_action(md_raid_t *raidp)
2N/A{
2N/A static char emsg[1024];
2N/A mdname_t *raidnp = raidp->common.namep;
2N/A int err_col;
2N/A
2N/A /* first check for full init failure */
2N/A if (raidp->state & RUS_DOI) {
2N/A (void) snprintf(emsg, sizeof (emsg),
2N/A "metaclear -f %s", raidnp->cname);
2N/A return (emsg);
2N/A }
2N/A
2N/A /* replace errored or init errored raid column */
2N/A if ((err_col = find_erred_column(raidp,
2N/A (RCS_ERRED | RCS_INIT_ERRED))) >= 0) {
2N/A mdname_t *colnp;
2N/A
2N/A /* get column with error */
2N/A assert(err_col < raidp->cols.cols_len);
2N/A colnp = raidp->cols.cols_val[err_col].colnamep;
2N/A (void) snprintf(emsg, sizeof (emsg),
2N/A "metareplace %s%s %s <%s>",
2N/A ((raidp->state == RUS_LAST_ERRED) ? "-f " : ""),
2N/A raidnp->cname, colnp->cname,
2N/A dgettext(TEXT_DOMAIN, "new device"));
2N/A return (emsg);
2N/A }
2N/A
2N/A
2N/A /* replace last errored raid column */
2N/A if ((err_col = find_erred_column(raidp, RCS_LAST_ERRED)) >= 0) {
2N/A mdname_t *colnp;
2N/A
2N/A assert(err_col < raidp->cols.cols_len);
2N/A colnp = raidp->cols.cols_val[err_col].colnamep;
2N/A (void) snprintf(emsg, sizeof (emsg),
2N/A "metareplace %s %s %s <%s>",
2N/A ((raidp->state == RUS_LAST_ERRED) ? "-f " : ""),
2N/A raidnp->cname, colnp->cname,
2N/A dgettext(TEXT_DOMAIN, "new device"));
2N/A return (emsg);
2N/A }
2N/A
2N/A /* OK */
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * get printable raid column state
2N/A */
2N/Achar *
2N/Araid_col_state_to_name(
2N/A md_raidcol_t *colp,
2N/A md_timeval32_t *tvp,
2N/A uint_t tstate
2N/A)
2N/A{
2N/A /* grab time */
2N/A if (tvp != NULL)
2N/A *tvp = colp->timestamp;
2N/A
2N/A if (tstate != 0) {
2N/A return (dgettext(TEXT_DOMAIN, "Unavailable"));
2N/A }
2N/A
2N/A /* everything else */
2N/A switch (colp->state) {
2N/A case RCS_INIT:
2N/A return (dgettext(TEXT_DOMAIN, "Initializing"));
2N/A
2N/A case RCS_OKAY:
2N/A return (dgettext(TEXT_DOMAIN, "Okay"));
2N/A
2N/A case RCS_INIT_ERRED:
2N/A /*FALLTHROUGH*/
2N/A case RCS_ERRED:
2N/A return (dgettext(TEXT_DOMAIN, "Maintenance"));
2N/A
2N/A case RCS_LAST_ERRED:
2N/A return (dgettext(TEXT_DOMAIN, "Last Erred"));
2N/A
2N/A case RCS_RESYNC:
2N/A return (dgettext(TEXT_DOMAIN, "Resyncing"));
2N/A
2N/A default:
2N/A return (dgettext(TEXT_DOMAIN, "Unknown"));
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * print raid column
2N/A */
2N/Astatic int
2N/Adisplay_raid_device_info(
2N/A mdsetname_t *sp,
2N/A md_raidcol_t *colp,
2N/A char *fname,
2N/A FILE *fp,
2N/A mdprtopts_t options,
2N/A int print_len,
2N/A uint_t top_tstate, /* Errored tstate flags */
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *namep = ((colp->hsnamep != NULL) ?
2N/A colp->hsnamep : colp->colnamep);
2N/A char *devid = "";
2N/A char *cname = colp->colnamep->cname;
2N/A diskaddr_t start_blk;
2N/A int has_mddb;
2N/A char *has_mddb_str;
2N/A char *col_state;
2N/A md_timeval32_t tv;
2N/A char *hsname = ((colp->hsnamep != NULL) ?
2N/A colp->hsnamep->cname : "");
2N/A int rval = -1;
2N/A mdname_t *didnp = NULL;
2N/A ddi_devid_t dtp;
2N/A uint_t tstate = 0;
2N/A
2N/A /* get info */
2N/A if ((start_blk = metagetstart(sp, namep, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((has_mddb = metahasmddb(sp, namep, ep)) < 0)
2N/A return (-1);
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 if (metaismeta(namep)) {
2N/A if (meta_get_tstate(namep->dev, &tstate, ep) != 0)
2N/A return (-1);
2N/A col_state = raid_col_state_to_name(colp, &tv,
2N/A tstate & 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 col_state = "-";
2N/A else
2N/A col_state = raid_col_state_to_name(colp, &tv, tstate);
2N/A }
2N/A
2N/A /* populate the key in the name_p structure */
2N/A if ((didnp = metadevname(&sp, namep->dev, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* determine if devid does NOT exist */
2N/A if (options & PRINT_DEVID) {
2N/A if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
2N/A 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 column */
2N/A /*
2N/A * Building a format string on the fly that will
2N/A * be used in (f)printf. This allows the length
2N/A * of the ctd to vary from small to large without
2N/A * looking horrible.
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 print_len, print_len, cname, start_blk, has_mddb_str,
2N/A col_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 print_len, cname, start_blk, has_mddb_str,
2N/A col_state, devid, hsname, timep) == 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
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * print raid options
2N/A */
2N/Aint
2N/Ameta_print_raid_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 raid
2N/A */
2N/Astatic int
2N/Araid_report(
2N/A mdsetname_t *sp,
2N/A md_raid_t *raidp,
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 char *p;
2N/A uint_t ncol = raidp->cols.cols_len;
2N/A uint_t orig_ncol = raidp->orig_ncol;
2N/A diskaddr_t column_size = raidp->column_size;
2N/A char *raid_state;
2N/A md_timeval32_t tv;
2N/A char *timep;
2N/A uint_t col;
2N/A int rval = -1;
2N/A int len = 0;
2N/A uint_t tstate = 0;
2N/A
2N/A if (options & PRINT_LARGEDEVICES) {
2N/A if ((raidp->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 ((raidp->common.revision & MD_FN_META_DEV) == 0) {
2N/A rval = 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: RAID\n"),
2N/A raidp->common.namep->cname) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A }
2N/A
2N/A /* print state */
2N/A if (metaismeta(raidp->common.namep)) {
2N/A if (meta_get_tstate(raidp->common.namep->dev, &tstate, ep) != 0)
2N/A return (-1);
2N/A }
2N/A tstate &= MD_DEV_ERRORED; /* extract the errored tstate bits */
2N/A raid_state = raid_state_to_name(raidp, &tv, tstate);
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 (fprintf(fp, dgettext(TEXT_DOMAIN, " State: %-12s %s\n"),
2N/A raid_state, timep) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Display recovery action if we're marked in the Unavailable state.
2N/A */
2N/A if ((tstate == 0) || (tstate & MD_INACCESSIBLE)) {
2N/A /* print what to do */
2N/A if (tstate & MD_INACCESSIBLE) {
2N/A char sname[MD_MAX_SETNAME + 3]; /* 3 = sizeof("-s ") */
2N/A
2N/A if (metaislocalset(sp)) {
2N/A sname[0] = '\0';
2N/A } else {
2N/A (void) snprintf(sname, MD_MAX_SETNAME + 3,
2N/A "-s %s", sp->setname);
2N/A }
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Invoke: metastat -i %s\n"), sname) == EOF) {
2N/A goto out;
2N/A }
2N/A } else if ((p = raid_state_to_action(raidp)) != NULL) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Invoke: %s\n"), p) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* resync status */
2N/A if (raidp->resync_flags & MD_RI_INPROGRESS) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Resync in progress: %2d.%1d%% done\n"),
2N/A raidp->percent_done/10,
2N/A raidp->percent_done % 10) == EOF) {
2N/A goto out;
2N/A }
2N/A } else if (raidp->resync_flags & MD_GROW_INPROGRESS) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Initialization in progress: %2d.%1d%% "
2N/A "done\n"),
2N/A raidp->percent_done/10,
2N/A raidp->percent_done % 10) == EOF) {
2N/A goto out;
2N/A }
2N/A } else if (raidp->state & RUS_REGEN) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Parity regeneration in progress: %2d.%1d%% "
2N/A "done\n"),
2N/A raidp->percent_done/10,
2N/A raidp->percent_done % 10) == EOF) {
2N/A goto out;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* print hotspare pool */
2N/A if (raidp->hspnamep != NULL) {
2N/A if (meta_print_raid_options(raidp->hspnamep,
2N/A fname, fp, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* print interlace */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Interlace: %lld blocks\n"),
2N/A raidp->interlace) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* print size */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %lld blocks (%s)\n"),
2N/A raidp->common.size,
2N/A meta_number_to_string(raidp->common.size, DEV_BSIZE)) == EOF) {
2N/A goto out;
2N/A }
2N/A
2N/A /* MD_DEBUG stuff */
2N/A if (options & PRINT_DEBUG) {
2N/A mdname_t *raidnp = raidp->common.namep;
2N/A mr_unit_t *mr;
2N/A
2N/A /* get additional info */
2N/A if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A assert(mr->c.un_type == MD_METARAID);
2N/A
2N/A /* print prewrite count and size */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Prewrite Count: %u slots\n"),
2N/A mr->un_pwcnt) == EOF) {
2N/A Free(mr);
2N/A goto out;
2N/A }
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Prewrite Slot Size: %u blocks\n"),
2N/A (mr->un_pwsize / mr->un_pwcnt)) == EOF) {
2N/A Free(mr);
2N/A goto out;
2N/A }
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Prewrite Total Size: %u blocks\n"),
2N/A mr->un_pwsize) == EOF) {
2N/A Free(mr);
2N/A goto out;
2N/A }
2N/A Free(mr);
2N/A }
2N/A
2N/A /* print original devices */
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, "Original device:\n")) == EOF)
2N/A goto out;
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %lld blocks (%s)\n"),
2N/A column_size * (orig_ncol - 1),
2N/A meta_number_to_string(column_size * (orig_ncol - 1), DEV_BSIZE))
2N/A == EOF) {
2N/A goto out;
2N/A }
2N/A /*
2N/A * Building a format string on the fly that will
2N/A * be used in (f)printf. This allows the length
2N/A * of the ctd to vary from small to large without
2N/A * looking horrible.
2N/A */
2N/A for (col = 0; (col < orig_ncol); ++col) {
2N/A len = max(len,
2N/A strlen(raidp->cols.cols_val[col].colnamep->cname));
2N/A }
2N/A
2N/A len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
2N/A len += 2;
2N/A
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 for (col = 0; (col < orig_ncol); ++col) {
2N/A md_raidcol_t *mdrcp = &raidp->cols.cols_val[col];
2N/A
2N/A if (display_raid_device_info(sp, mdrcp, fname, fp, options,
2N/A len, tstate, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* print concatenated devices */
2N/A if (col < ncol) {
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A "Concatenated Devices:\n")) == EOF) {
2N/A goto out;
2N/A }
2N/A if (fprintf(fp, dgettext(TEXT_DOMAIN,
2N/A " Size: %lld blocks (%s)\n"),
2N/A column_size * (ncol - orig_ncol),
2N/A meta_number_to_string(column_size * (ncol - orig_ncol),
2N/A DEV_BSIZE))
2N/A == EOF) {
2N/A goto out;
2N/A }
2N/A /*
2N/A * This allows the length
2N/A * of the ctd to vary from small to large without
2N/A * looking horrible.
2N/A */
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 %-9s %s\t%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 assert(col == orig_ncol);
2N/A for (/* void */; (col < ncol); col++) {
2N/A md_raidcol_t *mdrcp = &raidp->cols.cols_val[col];
2N/A
2N/A if (display_raid_device_info(sp, mdrcp, fname, fp,
2N/A options, len, tstate, 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 raid
2N/A */
2N/Aint
2N/Ameta_raid_print(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
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_raid_t *raidp;
2N/A int col;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert((raidnp == NULL) ||
2N/A (sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev))));
2N/A
2N/A /* print all raids */
2N/A if (raidnp == 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_raid_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_raid_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 ((raidp = meta_get_raid_common(sp, raidnp,
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(raidp->common.parent))) {
2N/A return (0);
2N/A }
2N/A
2N/A /* print appropriate detail */
2N/A if (options & PRINT_SHORT) {
2N/A if (raid_print(raidp, fname, fp, options, ep) != 0)
2N/A return (-1);
2N/A } else {
2N/A if (raid_report(sp, raidp, fname, fp, options, ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* Recurse on components that are metadevices */
2N/A for (col = 0; col < raidp->cols.cols_len; ++col) {
2N/A md_raidcol_t *colp = &raidp->cols.cols_val[col];
2N/A mdname_t *namep = colp->colnamep;
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 * adjust raid geometry
2N/A */
2N/Astatic int
2N/Aadjust_geom(
2N/A mdname_t *raidnp,
2N/A mdname_t *colnp,
2N/A mr_unit_t *mr,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t round_cyl = 1;
2N/A mdgeom_t *geomp;
2N/A
2N/A /* get reinstructs */
2N/A if ((geomp = metagetgeom(colnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* adjust geometry */
2N/A if (meta_adjust_geom((md_unit_t *)mr, raidnp, geomp->write_reinstruct,
2N/A geomp->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 * add another column to the raid unit structure
2N/A */
2N/Astatic int
2N/Aattach_raid_col(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mr_unit_t *mr,
2N/A mr_column_t *mdc,
2N/A mdname_t *colnp,
2N/A rcs_state_t state,
2N/A mdnamelist_t **keynlpp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A diskaddr_t column_size = mr->un_segsize * mr->un_segsincolumn;
2N/A diskaddr_t size;
2N/A uint_t maxio;
2N/A mdcinfo_t *cinfop;
2N/A md_timeval32_t tmp_time;
2N/A
2N/A /* setup state and timestamp */
2N/A mdc->un_devstate = state;
2N/A if (meta_gettimeofday(&tmp_time) == -1)
2N/A return (mdsyserror(ep, errno, NULL));
2N/A
2N/A mdc->un_devtimestamp = tmp_time;
2N/A /* get start, size, and maxio */
2N/A if ((mdc->un_orig_devstart = metagetstart(sp, colnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
2N/A return (-1);
2N/A if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
2N/A return (-1);
2N/A maxio = cinfop->maxtransfer;
2N/A
2N/A /* adjust start and size by prewrite */
2N/A mdc->un_orig_pwstart = mdc->un_orig_devstart;
2N/A mdc->un_orig_devstart += mr->un_pwsize;
2N/A
2N/A /* make sure we still have something left */
2N/A if ((mdc->un_orig_devstart >= size) ||
2N/A ((size - mdc->un_orig_devstart) < column_size)) {
2N/A return (mdsyserror(ep, ENOSPC, colnp->cname));
2N/A }
2N/A size -= mdc->un_orig_devstart;
2N/A if (maxio < mr->un_maxio) {
2N/A return (mdcomperror(ep, MDE_MAXIO,
2N/A meta_getminor(raidnp->dev), colnp->dev, colnp->cname));
2N/A }
2N/A
2N/A if (options & MDCMD_DOIT) {
2N/A /* store name in namespace */
2N/A if (add_key_name(sp, colnp, keynlpp, ep) != 0)
2N/A return (-1);
2N/A }
2N/A
2N/A /* setup column */
2N/A mdc->un_orig_dev = colnp->dev;
2N/A mdc->un_orig_key = colnp->key;
2N/A mdc->un_dev = colnp->dev;
2N/A mdc->un_pwstart = mdc->un_orig_pwstart;
2N/A mdc->un_devstart = mdc->un_orig_devstart;
2N/A mdc->un_alt_dev = NODEV64;
2N/A mdc->un_alt_pwstart = 0;
2N/A mdc->un_alt_devstart = 0;
2N/A mdc->un_hs_id = 0;
2N/A
2N/A /* add the size (we use) of the device to the total */
2N/A mr->c.un_actual_tb += column_size;
2N/A
2N/A /* adjust geometry */
2N/A if (adjust_geom(raidnp, colnp, mr, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* count column */
2N/A mr->un_totalcolumncnt++;
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * invalidate column names
2N/A */
2N/Astatic int
2N/Ainvalidate_columns(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_raid_t *raidp;
2N/A uint_t col;
2N/A
2N/A if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A for (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A
2N/A meta_invalidate_name(colnp);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * attach columns to raid
2N/A */
2N/Aint
2N/Ameta_raid_attach(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mdnamelist_t *colnlp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t concat_cnt = 0;
2N/A mdnamelist_t *p;
2N/A mr_unit_t *old_mr;
2N/A mr_unit_t *new_mr;
2N/A size_t old_rusize;
2N/A size_t new_rusize;
2N/A mdnamelist_t *keynlp = NULL;
2N/A md_grow_params_t mgp;
2N/A int rval = -1;
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(raidnp->dev)));
2N/A
2N/A /* check type */
2N/A if (metachkmeta(raidnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* check and count new columns */
2N/A for (p = colnlp; (p != NULL); p = p->next) {
2N/A mdname_t *np = p->namep;
2N/A mdnamelist_t *p2;
2N/A
2N/A /* check against existing devices */
2N/A if (meta_check_column(sp, np, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* check against ourselves */
2N/A for (p2 = p->next; (p2 != NULL); p2 = p2->next) {
2N/A if (meta_check_overlap(np->cname, np, 0, -1,
2N/A p2->namep, 0, -1, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* count */
2N/A ++concat_cnt;
2N/A }
2N/A
2N/A /* get old unit */
2N/A if ((old_mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /*
2N/A * calculate the size needed for the new raid unit and allocate
2N/A * the appropriate structure. allocate new unit.
2N/A */
2N/A old_rusize = sizeof (*old_mr) - sizeof (old_mr->un_column[0]);
2N/A old_rusize += old_mr->un_totalcolumncnt * sizeof (old_mr->un_column[0]);
2N/A new_rusize = sizeof (*new_mr) - sizeof (new_mr->un_column[0]);
2N/A new_rusize += (old_mr->un_totalcolumncnt + concat_cnt)
2N/A * sizeof (new_mr->un_column[0]);
2N/A new_mr = Zalloc(new_rusize);
2N/A (void) memcpy(new_mr, old_mr, old_rusize);
2N/A
2N/A /* We always want a do-it, this is for attach_raid_col below */
2N/A options |= MDCMD_DOIT;
2N/A
2N/A /* build new unit structure */
2N/A for (p = colnlp; (p != NULL); p = p->next) {
2N/A mdname_t *colnp = p->namep;
2N/A mr_column_t *mdc;
2N/A
2N/A /* attach column */
2N/A mdc = &new_mr->un_column[new_mr->un_totalcolumncnt];
2N/A if (attach_raid_col(sp, raidnp, new_mr, mdc, colnp,
2N/A RCS_INIT, &keynlp, options, ep) != 0) {
2N/A goto out;
2N/A }
2N/A }
2N/A assert(new_mr->un_totalcolumncnt
2N/A == (old_mr->un_totalcolumncnt + concat_cnt));
2N/A
2N/A
2N/A create_flag = meta_check_devicesize(new_mr->c.un_total_blocks);
2N/A
2N/A /* grow raid */
2N/A (void) memset(&mgp, 0, sizeof (mgp));
2N/A mgp.mnum = MD_SID(new_mr);
2N/A MD_SETDRIVERNAME(&mgp, MD_RAID, sp->setno);
2N/A mgp.size = new_rusize;
2N/A mgp.mdp = (uintptr_t)new_mr;
2N/A
2N/A if (create_flag == MD_CRO_32BIT) {
2N/A mgp.options = MD_CRO_32BIT;
2N/A new_mr->c.un_revision &= ~MD_64BIT_META_DEV;
2N/A } else {
2N/A mgp.options = MD_CRO_64BIT;
2N/A new_mr->c.un_revision |= MD_64BIT_META_DEV;
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_columns(sp, raidnp, ep) != 0)
2N/A goto out;
2N/A meta_invalidate_name(raidnp);
2N/A
2N/A /* let em know */
2N/A if (options & MDCMD_PRINT) {
2N/A if (concat_cnt == 1) {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: component is attached\n"),
2N/A raidnp->cname);
2N/A } else {
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "%s: components are attached\n"),
2N/A raidnp->cname);
2N/A }
2N/A (void) fflush(stdout);
2N/A }
2N/A
2N/A
2N/A /* grow any parents */
2N/A if (meta_concat_parent(sp, raidnp, ep) != 0)
2N/A goto out;
2N/A rval = 0; /* success */
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A Free(old_mr);
2N/A Free(new_mr);
2N/A if (rval != 0)
2N/A (void) del_key_names(sp, keynlp, NULL);
2N/A metafreenamelist(keynlp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * get raid parameters
2N/A */
2N/Aint
2N/Ameta_raid_get_params(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mr_params_t *paramsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_raid_t *raidp;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(raidnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get unit */
2N/A if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* return parameters */
2N/A (void) memset(paramsp, 0, sizeof (*paramsp));
2N/A if (raidp->hspnamep == NULL)
2N/A paramsp->hsp_id = MD_HSP_NONE;
2N/A else
2N/A paramsp->hsp_id = raidp->hspnamep->hsp;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * set raid parameters
2N/A */
2N/Aint
2N/Ameta_raid_set_params(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mr_params_t *paramsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_raid_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(raidnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(raidnp, 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_RAID, sp->setno);
2N/A msp.mnum = meta_getminor(raidnp->dev);
2N/A msp.params = *paramsp;
2N/A if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, raidnp->cname) != 0)
2N/A return (mdstealerror(ep, &msp.mde));
2N/A
2N/A /* clear cache */
2N/A meta_invalidate_name(raidnp);
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * validate raid replace column
2N/A */
2N/Astatic int
2N/Avalidate_new_raid(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mdname_t *colnp,
2N/A replace_params_t *paramsp,
2N/A int dup_ok,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mr_unit_t *mr;
2N/A diskaddr_t column_size;
2N/A diskaddr_t label;
2N/A mdcinfo_t *cinfop;
2N/A int rval = -1;
2N/A
2N/A /* get raid unit */
2N/A if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A column_size = mr->un_segsize * mr->un_segsincolumn;
2N/A
2N/A /* check it out */
2N/A if (meta_check_column(sp, colnp, ep) != 0) {
2N/A if ((! dup_ok) || (! mdisuseerror(ep, MDE_ALREADY)))
2N/A goto out;
2N/A mdclrerror(ep);
2N/A }
2N/A if ((paramsp->number_blks = metagetsize(colnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((label = metagetlabel(colnp, ep)) == MD_DISKADDR_ERROR)
2N/A goto out;
2N/A paramsp->has_label = ((label > 0) ? 1 : 0);
2N/A if ((paramsp->start_blk = metagetstart(sp, colnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((paramsp->number_blks - paramsp->start_blk) < column_size) {
2N/A (void) mdsyserror(ep, ENOSPC, colnp->cname);
2N/A goto out;
2N/A }
2N/A if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
2N/A goto out;
2N/A if (cinfop->maxtransfer < mr->un_maxio) {
2N/A (void) mdcomperror(ep, MDE_MAXIO, meta_getminor(raidnp->dev),
2N/A colnp->dev, colnp->cname);
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 Free(mr);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * replace raid column
2N/A */
2N/Aint
2N/Ameta_raid_replace(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
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 int force = ((options & MDCMD_FORCE) ? 1 : 0);
2N/A replace_params_t params;
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 char *new_devidp = NULL;
2N/A md_error_t xep = mdnullerror;
2N/A int ret;
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(raidnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(raidnp, 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 raid (fill in oldnp from metadb) */
2N/A meta_invalidate_name(raidnp);
2N/A if (meta_get_raid(sp, raidnp, ep) == NULL)
2N/A return (-1);
2N/A
2N/A /* can't replace a component if the raid inaccessible */
2N/A if (meta_get_tstate(raidnp->dev, &tstate, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A if (tstate & MD_INACCESSIBLE) {
2N/A return (mdmderror(ep, MDE_IN_UNAVAIL_STATE,
2N/A meta_getminor(raidnp->dev), raidnp->cname));
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 /* setup raid info */
2N/A (void) memset(&params, 0, sizeof (params));
2N/A params.mnum = meta_getminor(raidnp->dev);
2N/A MD_SETDRIVERNAME(&params, MD_RAID, sp->setno);
2N/A params.old_dev = old_dev;
2N/A params.cmd = force ? FORCE_REPLACE_COMP : REPLACE_COMP;
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
2N/A * reason is that the checks for the column (meta_check_column)
2N/A * via validate_new_raid(), could cause the disk's devid to be
2N/A * changed to that of the devid that is currently stored in the
2N/A * replica namespace for the disk in question. This devid could
2N/A * be stale if we are replacing the disk. The actual function
2N/A * that overwrites the devid is dr2drivedesc().
2N/A */
2N/A
2N/A /* don't setup new_devid if no devids */
2N/A if (newnp->drivenamep->devid != NULL)
2N/A new_devidp = Strdup(newnp->drivenamep->devid);
2N/A
2N/A /* check out new (sets up start_blk, has_label, number_blks) */
2N/A if (validate_new_raid(sp, raidnp, newnp, &params, rebind,
2N/A ep) != 0) {
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) {
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 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 the
2N/A * 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 column */
2N/A params.new_dev = new_dev;
2N/A params.new_key = newnp->key;
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 meta_invalidate_name(raidnp);
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 raidnp->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 raid column
2N/A */
2N/Aint
2N/Ameta_raid_enable(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mdname_t *colnp,
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 replace_params_t params;
2N/A md_dev64_t fs_dev, del_dev;
2N/A int err = 0;
2N/A char *devnm;
2N/A int ret;
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(raidnp->dev)));
2N/A
2N/A /* check name */
2N/A if (metachkmeta(raidnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get the file_system dev binding */
2N/A if (meta_getdev(sp, colnp, ep) != 0)
2N/A return (-1);
2N/A fs_dev = colnp->dev;
2N/A
2N/A /* get the raid unit (fill in colnp->dev with metadb version) */
2N/A meta_invalidate_name(raidnp);
2N/A if (meta_get_raid(sp, raidnp, ep) == NULL)
2N/A return (-1);
2N/A
2N/A /* enabling a component can't work if the raid inaccessible */
2N/A if (meta_get_tstate(raidnp->dev, &tstate, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A if (tstate & MD_INACCESSIBLE) {
2N/A return (mdmderror(ep, MDE_IN_UNAVAIL_STATE,
2N/A meta_getminor(raidnp->dev), raidnp->cname));
2N/A }
2N/A
2N/A /* the metadb device binding is now established */
2N/A if (colnp->dev == NODEV64)
2N/A return (mdsyserror(ep, ENODEV, colnp->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_raid_replace.
2N/A */
2N/A if (fs_dev != colnp->dev) {
2N/A /*
2N/A * Save the devt of mddb version
2N/A */
2N/A del_dev = colnp->dev;
2N/A
2N/A /* establish file system binding with invalid start/end */
2N/A colnp->dev = fs_dev;
2N/A colnp->start_blk = -1;
2N/A colnp->end_blk = -1;
2N/A err = meta_raid_replace(sp, raidnp, colnp, colnp, options, ep);
2N/A
2N/A /*
2N/A * Don't do it if meta_raid_replace returns an error
2N/A */
2N/A if (!err && (devnm = meta_getnmentbydev(sp->setno, MD_SIDEWILD,
2N/A del_dev, NULL, NULL, &colnp->key, ep)) != NULL) {
2N/A (void) del_key_name(sp, colnp, ep);
2N/A Free(devnm);
2N/A }
2N/A return (err);
2N/A }
2N/A
2N/A /* setup raid info */
2N/A (void) memset(&params, 0, sizeof (params));
2N/A params.mnum = meta_getminor(raidnp->dev);
2N/A MD_SETDRIVERNAME(&params, MD_RAID, sp->setno);
2N/A params.old_dev = params.new_dev = colnp->dev;
2N/A if (force)
2N/A params.cmd = FORCE_ENABLE_COMP;
2N/A else
2N/A params.cmd = ENABLE_COMP;
2N/A
2N/A /* check it out */
2N/A if (validate_new_raid(sp, raidnp, colnp, &params, 1, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* enable column */
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, colnp->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(colnp);
2N/A meta_invalidate_name(raidnp);
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 raidnp->cname, colnp->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 raid itself
2N/A */
2N/Astatic int
2N/Acheck_twice(
2N/A md_raid_t *raidp,
2N/A uint_t col,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *raidnp = raidp->common.namep;
2N/A mdname_t *thisnp;
2N/A uint_t c;
2N/A
2N/A thisnp = raidp->cols.cols_val[col].colnamep;
2N/A for (c = 0; (c < col); ++c) {
2N/A md_raidcol_t *mdcp = &raidp->cols.cols_val[c];
2N/A mdname_t *colnp = mdcp->colnamep;
2N/A
2N/A if (meta_check_overlap(raidnp->cname, thisnp, 0, -1,
2N/A colnp, 0, -1, ep) != 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * default raid interlace
2N/A */
2N/Adiskaddr_t
2N/Ameta_default_raid_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 < lbtodb(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_raid_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(RAID_MIN_INTERLACE)) ||
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 * check raid
2N/A */
2N/Aint
2N/Ameta_check_raid(
2N/A mdsetname_t *sp,
2N/A md_raid_t *raidp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *raidnp = raidp->common.namep;
2N/A int doit = ((options & MDCMD_DOIT) ? 1 : 0);
2N/A int updateit = ((options & MDCMD_UPDATE) ? 1 : 0);
2N/A uint_t ncol;
2N/A uint_t col;
2N/A minor_t mnum = meta_getminor(raidnp->dev);
2N/A
2N/A /* check number */
2N/A if (((ncol = raidp->cols.cols_len) < MD_RAID_MIN) ||
2N/A (raidp->orig_ncol > ncol)) {
2N/A return (mdmderror(ep, MDE_BAD_RAID, mnum, raidnp->cname));
2N/A }
2N/A
2N/A /* compute default interlace */
2N/A if (raidp->interlace == 0) {
2N/A raidp->interlace = meta_default_raid_interlace();
2N/A }
2N/A
2N/A /* check state */
2N/A switch (raidp->state) {
2N/A case RUS_INIT:
2N/A case RUS_OKAY:
2N/A break;
2N/A
2N/A default:
2N/A return (mdmderror(ep, MDE_BAD_RAID, mnum, raidnp->cname));
2N/A }
2N/A
2N/A /* check interlace */
2N/A if (meta_raid_check_interlace(raidp->interlace, raidnp->cname, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* check hotspare pool name */
2N/A if (doit) {
2N/A if ((raidp->hspnamep != NULL) &&
2N/A (metachkhsp(sp, raidp->hspnamep, ep) != 0)) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /* check columns */
2N/A for (col = 0; (col < ncol); ++col) {
2N/A md_raidcol_t *mdcp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = mdcp->colnamep;
2N/A diskaddr_t start_blk, size;
2N/A
2N/A /* setup column */
2N/A if (raidp->state == RUS_INIT)
2N/A mdcp->state = RCS_INIT;
2N/A else
2N/A mdcp->state = RCS_OKAY;
2N/A
2N/A /* check column */
2N/A if (!updateit) {
2N/A if (meta_check_column(sp, colnp, ep) != 0)
2N/A return (-1);
2N/A if (((start_blk = metagetstart(sp, colnp, ep)) ==
2N/A MD_DISKADDR_ERROR) || ((size = metagetsize(colnp,
2N/A ep)) == MD_DISKADDR_ERROR)) {
2N/A return (-1);
2N/A }
2N/A if (start_blk >= size)
2N/A return (mdsyserror(ep, ENOSPC, colnp->cname));
2N/A size -= start_blk;
2N/A size = rounddown(size, raidp->interlace);
2N/A if (size == 0)
2N/A return (mdsyserror(ep, ENOSPC, colnp->cname));
2N/A }
2N/A
2N/A /* check this raid too */
2N/A if (check_twice(raidp, col, 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 * setup raid geometry
2N/A */
2N/Astatic int
2N/Araid_geom(
2N/A md_raid_t *raidp,
2N/A mr_unit_t *mr,
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 uint_t col;
2N/A mdgeom_t *geomp;
2N/A
2N/A /* get worst reinstructs */
2N/A for (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *mdcp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = mdcp->colnamep;
2N/A
2N/A if ((geomp = metagetgeom(colnp, 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 /* setup geometry from first column */
2N/A assert(raidp->cols.cols_len > 0);
2N/A if ((geomp = metagetgeom(raidp->cols.cols_val[0].colnamep,
2N/A ep)) == NULL) {
2N/A return (-1);
2N/A }
2N/A if (meta_setup_geom((md_unit_t *)mr, raidp->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/Aint
2N/Ameta_raid_state_cnt(mr_unit_t *mr, rcs_state_t state)
2N/A{
2N/A int statecnt = 0;
2N/A int col;
2N/A
2N/A for (col = 0; col < mr->un_totalcolumncnt; col++)
2N/A if (mr->un_column[col].un_devstate & state)
2N/A statecnt++;
2N/A return (statecnt);
2N/A}
2N/A/*
2N/A * validate that a raid device being created with the -k flag is a real
2N/A * raid device
2N/A */
2N/Aint
2N/Ameta_raid_valid(md_raid_t *raidp, mr_unit_t *mr)
2N/A{
2N/A long long buf[DEV_BSIZE / sizeof (long long)];
2N/A raid_pwhdr_t pwhdr;
2N/A raid_pwhdr_t *rpw = &pwhdr;
2N/A minor_t mnum;
2N/A int col;
2N/A int fd;
2N/A
2N/A for (col = 0; col < mr->un_totalcolumncnt; col++) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A
2N/A if ((fd = open(colnp->rname, O_RDONLY)) < 0)
2N/A goto error_exit;
2N/A
2N/A if (lseek64(fd,
2N/A (mr->un_column[col].un_pwstart * DEV_BSIZE), SEEK_SET) < 0)
2N/A goto error_exit;
2N/A
2N/A if (read(fd, buf, DEV_BSIZE) < 0)
2N/A goto error_exit;
2N/A
2N/A /*
2N/A * If our raid device is a 64 bit device, we can accept the
2N/A * pw header we just read in.
2N/A * Otherwise it's of type raid_pwhdr32_od_t and has to
2N/A * be converted.
2N/A */
2N/A if (mr->c.un_revision & MD_64BIT_META_DEV) {
2N/A rpw = (raid_pwhdr_t *)buf;
2N/A } else {
2N/A RAID_CONVERT_RPW((raid_pwhdr32_od_t *)buf, rpw);
2N/A }
2N/A
2N/A if (rpw->rpw_column != col)
2N/A goto error_exit;
2N/A
2N/A if (col == 0)
2N/A mnum = rpw->rpw_unit;
2N/A
2N/A if (rpw->rpw_unit != mnum)
2N/A goto error_exit;
2N/A
2N/A if (rpw->rpw_magic_ext == RAID_PWMAGIC) {
2N/A /* 4.1 prewrite header */
2N/A if ((rpw->rpw_origcolumncnt != mr->un_origcolumncnt) ||
2N/A (rpw->rpw_totalcolumncnt !=
2N/A mr->un_totalcolumncnt) ||
2N/A (rpw->rpw_segsize != mr->un_segsize) ||
2N/A (rpw->rpw_segsincolumn != mr->un_segsincolumn) ||
2N/A (rpw->rpw_pwcnt != mr->un_pwcnt) ||
2N/A (rpw->rpw_pwstart !=
2N/A mr->un_column[col].un_pwstart) ||
2N/A (rpw->rpw_devstart !=
2N/A mr->un_column[col].un_devstart) ||
2N/A (rpw->rpw_pwsize != mr->un_pwsize))
2N/A goto error_exit;
2N/A }
2N/A /*
2N/A * this is an old prewrite header (4.0) the unit structure
2N/A * will have to be trusted.
2N/A */
2N/A (void) close(fd);
2N/A }
2N/A
2N/A return (0);
2N/A
2N/Aerror_exit:
2N/A (void) close(fd);
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * create raid
2N/A */
2N/Aint
2N/Ameta_create_raid(
2N/A mdsetname_t *sp,
2N/A md_raid_t *raidp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdname_t *raidnp = raidp->common.namep;
2N/A uint_t ncol = raidp->cols.cols_len;
2N/A uint_t orig_ncol = raidp->orig_ncol;
2N/A size_t rdsize;
2N/A mr_unit_t *mr;
2N/A uint_t col;
2N/A diskaddr_t disk_size = 0;
2N/A uint_t disk_maxio = 0;
2N/A uint_t pwes;
2N/A diskaddr_t non_pw_blks, column_size;
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 raid */
2N/A if (meta_check_raid(sp, raidp, options, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* allocate raid unit */
2N/A rdsize = sizeof (*mr) - sizeof (mr->un_column[0]);
2N/A rdsize += ncol * sizeof (mr->un_column[0]);
2N/A mr = Zalloc(rdsize);
2N/A
2N/A if (meta_gettimeofday(&creation_time) == -1)
2N/A return (mdsyserror(ep, errno, NULL));
2N/A /*
2N/A * initialize the top level mr_unit_t structure
2N/A * setup the unit state to indicate whether to retain
2N/A * any data currently on the metadevice or to clear it
2N/A */
2N/A mr->c.un_type = MD_METARAID;
2N/A MD_SID(mr) = meta_getminor(raidnp->dev);
2N/A mr->c.un_size = rdsize;
2N/A mr->un_magic = RAID_UNMAGIC;
2N/A mr->un_state = raidp->state;
2N/A mr->un_timestamp = creation_time;
2N/A mr->un_origcolumncnt = orig_ncol;
2N/A mr->un_segsize = (uint_t)raidp->interlace;
2N/A if (raidp->hspnamep != NULL) {
2N/A mr->un_hsp_id = raidp->hspnamep->hsp;
2N/A } else {
2N/A mr->un_hsp_id = MD_HSP_NONE;
2N/A }
2N/A /*
2N/A * setup original columns, saving start_block and
2N/A * finding smallest size and maxio
2N/A */
2N/A for (col = 0; (col < orig_ncol); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A mr_column_t *mdc = &mr->un_column[col];
2N/A diskaddr_t size;
2N/A uint_t maxio;
2N/A mdcinfo_t *cinfop;
2N/A
2N/A /* setup state */
2N/A mdc->un_devstate = cp->state;
2N/A
2N/A /* setup creation time */
2N/A mdc->un_devtimestamp = creation_time;
2N/A
2N/A /* get start, size, and maxio */
2N/A if ((mdc->un_orig_devstart = metagetstart(sp, colnp, ep)) ==
2N/A MD_DISKADDR_ERROR)
2N/A goto out;
2N/A if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
2N/A goto out;
2N/A size -= mdc->un_orig_devstart;
2N/A if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
2N/A goto out;
2N/A maxio = cinfop->maxtransfer;
2N/A
2N/A if (options & MDCMD_DOIT) {
2N/A /* store name in namespace */
2N/A if (add_key_name(sp, colnp, &keynlp, ep) != 0)
2N/A goto out;
2N/A }
2N/A
2N/A /* setup column */
2N/A mdc->un_orig_key = colnp->key;
2N/A mdc->un_orig_dev = colnp->dev;
2N/A mdc->un_dev = mdc->un_orig_dev;
2N/A mdc->un_pwstart = mdc->un_orig_pwstart;
2N/A mdc->un_devstart = mdc->un_orig_devstart;
2N/A mdc->un_alt_dev = NODEV64;
2N/A mdc->un_alt_pwstart = 0;
2N/A mdc->un_alt_devstart = 0;
2N/A mdc->un_hs_id = 0;
2N/A if (mr->un_state == RUS_INIT)
2N/A mdc->un_devstate = RCS_INIT;
2N/A else
2N/A mdc->un_devstate = RCS_OKAY;
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 if (disk_maxio == 0) {
2N/A disk_maxio = maxio;
2N/A } else if (maxio < disk_maxio) {
2N/A disk_maxio = maxio;
2N/A }
2N/A }
2N/A assert(col == mr->un_origcolumncnt);
2N/A
2N/A /*
2N/A * before processing any of the attached column(s)
2N/A * set up the composition of the metadevice for column
2N/A * sizes and pre-write information
2N/A */
2N/A mr->un_maxio = disk_maxio; /* smallest maxio */
2N/A mr->un_iosize = min(mr->un_maxio, (mr->un_segsize + 1));
2N/A pwes = mr->un_iosize;
2N/A if (raidp->pw_count)
2N/A mr->un_pwcnt = raidp->pw_count;
2N/A else
2N/A mr->un_pwcnt = PWCNT_MIN;
2N/A if ((mr->un_pwcnt < PWCNT_MIN) || (mr->un_pwcnt > PWCNT_MAX)) {
2N/A (void) mderror(ep, MDE_RAID_BAD_PW_CNT, raidnp->cname);
2N/A goto out;
2N/A }
2N/A mr->un_pwsize = roundup((mr->un_pwcnt * pwes), 2);
2N/A
2N/A /* now calculate the number of segments per column */
2N/A non_pw_blks = disk_size - mr->un_pwsize; /* smallest disk */
2N/A if ((mr->un_pwsize > disk_size) ||
2N/A (non_pw_blks < (diskaddr_t)mr->un_segsize)) {
2N/A (void) mdsyserror(ep, ENOSPC, raidnp->cname);
2N/A goto out;
2N/A }
2N/A mr->un_segsincolumn = non_pw_blks / mr->un_segsize;
2N/A column_size = mr->un_segsize * mr->un_segsincolumn;
2N/A
2N/A /*
2N/A * adjust the pw_cnt, pw_size, to fit into any fragmentation
2N/A * left over after column_size has been computed
2N/A */
2N/A mr->un_pwsize = rounddown(((uint_t)(disk_size - column_size)), 2);
2N/A mr->un_pwcnt = mr->un_pwsize / pwes;
2N/A assert(mr->un_pwcnt >= PWCNT_MIN);
2N/A mr->un_pwsize = roundup((mr->un_pwcnt * pwes), 2);
2N/A assert((mr->un_pwsize + column_size) <= disk_size);
2N/A
2N/A /*
2N/A * calculate the actual block count available based on the
2N/A * segment size and the number of segments per column ...
2N/A * ... and adjust for the number of parity segments
2N/A */
2N/A mr->c.un_actual_tb = column_size * (mr->un_origcolumncnt - 1);
2N/A
2N/A if (raid_geom(raidp, mr, ep) != 0)
2N/A goto out;
2N/A
2N/A create_flag = meta_check_devicesize(mr->c.un_total_blocks);
2N/A
2N/A /*
2N/A * now calculate the pre-write offset and update the column
2N/A * structures to include the address of the individual pre-write
2N/A * areas
2N/A */
2N/A for (col = 0; (col < orig_ncol); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A mr_column_t *mdc = &mr->un_column[col];
2N/A diskaddr_t size;
2N/A
2N/A /* get size */
2N/A if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
2N/A goto out;
2N/A
2N/A /* adjust start and size by prewrite */
2N/A mdc->un_orig_pwstart = mdc->un_orig_devstart;
2N/A mdc->un_orig_devstart += mr->un_pwsize;
2N/A mdc->un_pwstart = mdc->un_orig_pwstart;
2N/A mdc->un_devstart = mdc->un_orig_devstart;
2N/A
2N/A assert(size >= mdc->un_orig_devstart);
2N/A size -= mdc->un_orig_devstart;
2N/A
2N/A /* make sure we still have something left */
2N/A assert(size >= column_size);
2N/A }
2N/A
2N/A /* do concat cols */
2N/A mr->un_totalcolumncnt = mr->un_origcolumncnt;
2N/A assert(col == mr->un_origcolumncnt);
2N/A for (col = orig_ncol; (col < ncol); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A mr_column_t *mdc = &mr->un_column[col];
2N/A
2N/A /* attach column */
2N/A if (attach_raid_col(sp, raidnp, mr, mdc, colnp,
2N/A cp->state, &keynlp, options, ep) != 0) {
2N/A goto out;
2N/A }
2N/A }
2N/A assert(mr->un_totalcolumncnt == ncol);
2N/A
2N/A /* fill in the size of the raid */
2N/A if (options & MDCMD_UPDATE) {
2N/A raidp->common.size = mr->c.un_total_blocks;
2N/A raidp->column_size = mr->un_segsize * mr->un_segsincolumn;
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 if ((mr->un_state & RUS_OKAY) &&
2N/A (meta_raid_valid(raidp, mr) != 0)) {
2N/A (void) mderror(ep, MDE_RAID_INVALID, raidnp->cname);
2N/A goto out;
2N/A }
2N/A
2N/A /* create raid */
2N/A (void) memset(&set_params, 0, sizeof (set_params));
2N/A /* did the user tell us to generate a large device? */
2N/A if (create_flag == MD_CRO_64BIT) {
2N/A mr->c.un_revision |= MD_64BIT_META_DEV;
2N/A set_params.options = MD_CRO_64BIT;
2N/A } else {
2N/A mr->c.un_revision &= ~MD_64BIT_META_DEV;
2N/A set_params.options = MD_CRO_32BIT;
2N/A }
2N/A set_params.mnum = MD_SID(mr);
2N/A set_params.size = mr->c.un_size;
2N/A set_params.mdp = (uintptr_t)mr;
2N/A MD_SETDRIVERNAME(&set_params, MD_RAID, MD_MIN2SET(set_params.mnum));
2N/A if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
2N/A raidnp->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(mr);
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_columns(sp, raidnp, ep) != 0)
2N/A rval = -1;
2N/A meta_invalidate_name(raidnp);
2N/A }
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * initialize raid
2N/A * NOTE: this functions is metainit(1m)'s command line parser!
2N/A */
2N/Aint
2N/Ameta_init_raid(
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 *raidnp = NULL;
2N/A int old_optind;
2N/A int c;
2N/A md_raid_t *raidp = NULL;
2N/A uint_t ncol, col;
2N/A int rval = -1;
2N/A md_set_desc *sd;
2N/A
2N/A /* get raid name */
2N/A assert(argc > 0);
2N/A if (argc < 1)
2N/A goto syntax;
2N/A if ((raidnp = metaname(spp, uname, META_DEVICE, ep)) == NULL)
2N/A goto out;
2N/A assert(*spp != NULL);
2N/A
2N/A /*
2N/A * Raid metadevice not allowed on multi-node diskset.
2N/A */
2N/A if (! metaislocalset(*spp)) {
2N/A if ((sd = metaget_setdesc(*spp, ep)) == NULL)
2N/A goto out;
2N/A if (MD_MNSET_DESC(sd)) {
2N/A rval = meta_cook_syntax(ep, MDE_MNSET_NORAID, uname,
2N/A argc, argv);
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A uname = raidnp->cname;
2N/A if (metachkmeta(raidnp, 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(raidnp, ep) != NULL) {
2N/A (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
2N/A meta_getminor(raidnp->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 -r */
2N/A if ((argc < 1) || (strcmp(argv[0], "-r") != 0))
2N/A goto syntax;
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 raid */
2N/A raidp = Zalloc(sizeof (*raidp));
2N/A
2N/A /* setup common */
2N/A raidp->common.namep = raidnp;
2N/A raidp->common.type = MD_METARAID;
2N/A raidp->state = RUS_INIT;
2N/A
2N/A /* allocate and parse cols */
2N/A for (ncol = 0; ((ncol < argc) && (argv[ncol][0] != '-')); ++ncol)
2N/A ;
2N/A raidp->cols.cols_len = ncol;
2N/A if (ncol != 0) {
2N/A raidp->cols.cols_val =
2N/A Zalloc(ncol * sizeof (*raidp->cols.cols_val));
2N/A }
2N/A for (col = 0; ((argc > 0) && (col < ncol)); ++col) {
2N/A md_raidcol_t *mdc = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp;
2N/A
2N/A /* parse column name */
2N/A if ((colnp = metaname(spp, argv[0], UNKNOWN, ep)) == NULL)
2N/A goto out;
2N/A /* check for soft partitions */
2N/A if (meta_sp_issp(*spp, colnp, ep) != 0) {
2N/A /* check disks */
2N/A if (metachkcomp(colnp, ep) != 0)
2N/A goto out;
2N/A }
2N/A mdc->colnamep = colnp;
2N/A --argc, ++argv;
2N/A }
2N/A
2N/A /* parse raid options */
2N/A old_optind = optind = 0;
2N/A opterr = 0;
2N/A while ((c = getopt(argc, argv, "h:i:ko:w:")) != -1) {
2N/A switch (c) {
2N/A case 'h':
2N/A if ((raidp->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 (raidp->hspnamep->hsp == MD_HSP_NONE) {
2N/A (void) mdhsperror(ep, MDE_INVAL_HSP,
2N/A raidp->hspnamep->hsp, optarg);
2N/A goto out;
2N/A }
2N/A break;
2N/A
2N/A case 'i':
2N/A if (parse_interlace(uname, optarg, &raidp->interlace,
2N/A ep) != 0) {
2N/A goto out;
2N/A }
2N/A if (meta_raid_check_interlace(raidp->interlace,
2N/A uname, ep))
2N/A goto out;
2N/A break;
2N/A
2N/A case 'k':
2N/A raidp->state = RUS_OKAY;
2N/A break;
2N/A
2N/A case 'o':
2N/A if ((sscanf(optarg, "%u", &raidp->orig_ncol) != 1) ||
2N/A ((int)raidp->orig_ncol < 0)) {
2N/A goto syntax;
2N/A }
2N/A if ((raidp->orig_ncol < MD_RAID_MIN) ||
2N/A (raidp->orig_ncol > ncol)) {
2N/A rval = mderror(ep, MDE_BAD_ORIG_NCOL, uname);
2N/A goto out;
2N/A }
2N/A break;
2N/A case 'w':
2N/A if ((sscanf(optarg, "%d", &raidp->pw_count) != 1) ||
2N/A ((int)raidp->pw_count < 0))
2N/A goto syntax;
2N/A if (((int)raidp->pw_count < PWCNT_MIN) ||
2N/A ((int)raidp->pw_count > PWCNT_MAX)) {
2N/A rval = mderror(ep, MDE_RAID_BAD_PW_CNT, uname);
2N/A goto out;
2N/A }
2N/A break;
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 /* default to all original columns */
2N/A if (raidp->orig_ncol == 0)
2N/A raidp->orig_ncol = ncol;
2N/A
2N/A /* create raid */
2N/A if (meta_create_raid(*spp, raidp, 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, "%s: RAID 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 (raidp != NULL)
2N/A meta_free_raid(raidp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * reset RAIDs
2N/A */
2N/Aint
2N/Ameta_raid_reset(
2N/A mdsetname_t *sp,
2N/A mdname_t *raidnp,
2N/A mdcmdopts_t options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_raid_t *raidp;
2N/A int rval = -1;
2N/A int col;
2N/A
2N/A /* should have same set */
2N/A assert(sp != NULL);
2N/A assert((raidnp == NULL) ||
2N/A (sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev))));
2N/A
2N/A /* reset all raids */
2N/A if (raidnp == NULL) {
2N/A mdnamelist_t *raidnlp = NULL;
2N/A mdnamelist_t *p;
2N/A
2N/A /* for each raid */
2N/A rval = 0;
2N/A if (meta_get_raid_names(sp, &raidnlp, 0, ep) < 0)
2N/A return (-1);
2N/A for (p = raidnlp; (p != NULL); p = p->next) {
2N/A /* reset RAID */
2N/A raidnp = p->namep;
2N/A if (meta_raid_reset(sp, raidnp, options, ep) != 0) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/A metafreenamelist(raidnlp);
2N/A return (rval);
2N/A }
2N/A
2N/A /* check name */
2N/A if (metachkmeta(raidnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* get unit structure */
2N/A if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* make sure nobody owns us */
2N/A if (MD_HAS_PARENT(raidp->common.parent)) {
2N/A return (mdmderror(ep, MDE_IN_USE, meta_getminor(raidnp->dev),
2N/A raidnp->cname));
2N/A }
2N/A
2N/A /* clear subdevices cache */
2N/A if (invalidate_columns(sp, raidnp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* clear metadevice */
2N/A if (meta_reset(sp, raidnp, 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, "%s: RAID is cleared\n"),
2N/A raidnp->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 (col = 0; (col < raidp->cols.cols_len); ++col) {
2N/A md_raidcol_t *cp = &raidp->cols.cols_val[col];
2N/A mdname_t *colnp = cp->colnamep;
2N/A
2N/A /* only recurse on metadevices */
2N/A if (! metaismeta(colnp))
2N/A continue;
2N/A
2N/A if (meta_reset_by_name(sp, colnp, options, ep) != 0)
2N/A rval = -1;
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/Aout:
2N/A meta_invalidate_name(raidnp);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * reports TRUE if any RAID component is in error
2N/A */
2N/Aint
2N/Ameta_raid_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *raid_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 = raid_names; nlp; nlp = nlp->next) {
2N/A md_raid_t *raidp;
2N/A
2N/A if ((raidp = meta_get_raid(sp, nlp->namep, ep)) == NULL) {
2N/A any_errs |= TRUE;
2N/A goto out;
2N/A }
2N/A if (raidp->state != RUS_OKAY && raidp->state != RUS_INIT) {
2N/A any_errs |= TRUE;
2N/A goto out;
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/A * regen parity on a raid
2N/A */
2N/Aint
2N/Ameta_raid_regen_byname(mdsetname_t *sp, mdname_t *raidnp, diskaddr_t size,
2N/A md_error_t *ep)
2N/A{
2N/A char *miscname;
2N/A md_resync_ioctl_t ri;
2N/A
2N/A /* should have a set */
2N/A assert(sp != NULL);
2N/A assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
2N/A
2N/A /* make sure we have a raid */
2N/A if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
2N/A return (-1);
2N/A if (strcmp(miscname, MD_RAID) != 0) {
2N/A return (mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
2N/A raidnp->cname));
2N/A }
2N/A
2N/A /* start resync */
2N/A (void) memset(&ri, 0, sizeof (ri));
2N/A MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
2N/A ri.ri_mnum = meta_getminor(raidnp->dev);
2N/A ri.ri_copysize = size;
2N/A if (metaioctl(MD_IOCSETREGEN, &ri, &ri.mde, raidnp->cname) != 0)
2N/A return (mdstealerror(ep, &ri.mde));
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Ameta_raid_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_raid_t *raid;
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 i;
2N/A int rval = -1;
2N/A
2N/A (void) memset(&nm, '\0', sizeof (nm));
2N/A if ((raid = meta_get_raid_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 /* 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 (i = 0; i < raid->orig_ncol; i++) {
2N/A md_raidcol_t *colp = &raid->cols.cols_val[i];
2N/A mdname_t *compnp = colp->colnamep;
2N/A
2N/A if (mydevs == mydev[i]) {
2N/A /* Get the devname from the name space. */
2N/A if ((devname = meta_getnmentbydev(sp->setno, sideno,
2N/A compnp->dev, NULL, NULL, &key, ep)) == NULL) {
2N/A goto out;
2N/A }
2N/A
2N/A if (compnp->dev != meta_getminor(mydev[i])) {
2N/A /*
2N/A * The minor numbers are different. Update
2N/A * the namespace with the information from
2N/A * 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, sideno,
2N/A ctd_name, mydev[i], key, pname,
2N/A 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 } /* end of 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}