meta_mirror.c revision 32e0da9f9721fdfe44802ab869bc447dc4357bc6
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Just in case we're not in a build environment, make sure that
* TEXT_DOMAIN gets set to something.
*/
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
/*
* mirror operations
*/
#include <meta.h>
#include <ctype.h>
#include <stddef.h>
/*
* FUNCTION: meta_get_mirror_names()
* INPUT: sp - the set name to get mirrors from
* options - options from the command line
* OUTPUT: nlpp - list of all mirror names
* ep - return error pointer
* RETURNS: int - -1 if error, 0 success
* PURPOSE: returns a list of all mirrors in the metadb
* for all devices in the specified set
*/
int
mdnamelist_t **nlpp,
int options,
)
{
}
/*
* free mirror unit
*/
void
)
{
}
/*
* get mirror unit
*/
static md_mirror_t *
int fast,
)
{
char *miscname;
/* must have set */
/* short circuit */
}
/* get miscname and unit */
return (NULL);
return (NULL);
}
return (NULL);
/* allocate mirror */
/* get common info */
/* get options */
/* get submirrors */
/* get submirror state */
continue;
++nsm;
/* get submirror time of last state change */
/* get submirror flags */
/* get submirror name */
goto out;
}
/* get resync info */
goto out;
}
/* cleanup, return success */
return (mirrorp);
/* cleanup, return error */
out:
return (NULL);
}
/*
* get mirror unit
*/
)
{
}
/*
* check mirror for dev
*/
static int
)
{
/* should be in the same set */
/* get unit */
return (-1);
/* look in submirrors */
/* skip unused submirrors */
continue;
}
/* check overlap */
if (metaismeta(submirnp))
continue;
return (-1);
}
/* return success */
return (0);
}
/*
* check to see if we're in a mirror
*/
int
)
{
mdnamelist_t *p;
int rval = 0;
/* should have a set */
/* for each mirror */
return (-1);
/* check mirror */
rval = -1;
break;
}
}
/* cleanup, return success */
return (rval);
}
/*
* Check to see if the primary mirror is built on top of a
* root slice which is mounted. This check is primarily to
* account for this case -
*
* # metainit -f d1 1 1 <root slice>
* # metainit d0 -m d1
* # metainit d2 1 1 ctds
* # metattach d0 d2
*
* The metattach here needs to fail if the root slice is
* being mirrored; otherwise there is a potential for
* data corruption.
*/
static int
)
{
int smi;
char *curroot;
char *temproot;
return (-1);
/*
* We need to take the canonical name here otherwise the call to
* metaname will add a bad entry to the drivelistp cache and
* things will get nasty later on.
* However we also need to trap the case where we have a logical
* device name and meta_canonicalize returns NULL.
*/
}
/*
* Get device name of current root metadevice. If root
* is net mounted as happens if we're part of the
* install process, rootnp will be set to NULL and we
* return success.
*
* Since curroot should be a complete path, we only
* need to check whether the device is a logical device.
* The metaname below returns NULL if curroot is not a logical
* device.
*/
return (0);
/*
* If we're here, the curroot is a mounted on a logical device.
* Make sure this mirror is not on the root logical device.
*/
if (metaismeta(mirnp)) {
return (-1);
/* Check all submirrors */
/* skip unused submirrors */
if (submirnamep == NULL) {
continue;
}
/* check if submirror is a stripe or not */
!= 0)
return (-1);
== NULL)
return (-1);
/*
* Examine the first component of the first row and
* check to see if it has a mounted root slice
*/
/*
* we just care about the component built on
* top of a raw device
*/
/*
* If root device is the 1st component of
* the stripe, then fail.
*/
== 0) {
return (-1);
}
}
}
}
/* return success */
return (0);
}
/*
* check submirror
*/
int
int force,
)
{
mdchkopts_t options = 0;
/* make sure we have a metadevice disk */
return (-1);
/*
* Check to see if the primary mirror consists of a root
* mounted device
*/
!= 0)))
return (-1);
/* check to ensure that it is not already in use */
if ((! force) &&
return (-1);
}
/* make sure it is in the set */
return (-1);
/* make sure its not in a metadevice */
return (-1);
} else { /* Metadevices only! */
/* make sure it can be parented */
return (-1);
}
}
/* return success */
return (0);
}
/*
* convert read options
*/
char *
)
{
switch (opt) {
case RD_LOAD_BAL:
return ("roundrobin");
case RD_GEOMETRY:
return ("geometric");
case RD_FIRST:
return ("first");
default:
assert(0);
}
}
static char *
)
{
switch (opt) {
case RD_LOAD_BAL:
return (NULL); /* default */
case RD_GEOMETRY:
return ("-g");
case RD_FIRST:
return ("-r");
default:
assert(0);
}
}
int
char *uname,
char *name,
)
{
*optp = RD_LOAD_BAL;
return (0);
}
*optp = RD_GEOMETRY;
return (0);
}
return (0);
}
}
/*
* convert write options
*/
char *
)
{
switch (opt) {
case WR_PARALLEL:
return ("parallel");
case WR_SERIAL:
return ("serial");
default:
assert(0);
}
}
static char *
)
{
switch (opt) {
case WR_PARALLEL:
return (NULL); /* default */
case WR_SERIAL:
return ("-S");
default:
assert(0);
}
}
int
char *uname,
char *name,
)
{
*optp = WR_PARALLEL;
return (0);
}
return (0);
}
}
/*
* convert pass numbers
*/
int
char *uname,
char *name,
)
{
}
return (0);
}
/*
* convert resync option
*/
static char *
)
{
if (tstate & MD_ABR_CAP)
else
}
/*
* print mirror
*/
static int
char *fname,
)
{
char *p;
int rval = -1;
if (options & PRINT_LARGEDEVICES) {
rval = 0;
goto out;
}
}
rval = 0;
goto out;
}
}
/* print name and -m */
goto out;
/* print submirrors */
/* skip unused submirrors */
if (submirnamep == NULL) {
continue;
}
/* print submirror */
goto out;
}
/* print options */
goto out;
}
goto out;
}
goto out;
/* success */
rval = 0;
/* cleanup, return error */
out:
if (rval != 0)
return (rval);
}
/*
* convert submirror state to name
*/
char *
)
{
static char state_to_str[100];
/* grab time */
/*
* Only return Unavailable if there is no flagged error on the
* submirror. If the mirror has received any writes since the submirror
* went into Unavailable state a resync is required. To alert the
* administrator to this we return a 'Needs maintenance' message.
*/
}
/* all is well */
if (state & SMS_RUNNING) {
if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
}
}
/* resyncing, needs repair */
SMS_OFFLINE_RESYNC)) ||
(mirror_status & MD_UN_OPT_NOT_DONE)) {
if (mirror_status & MD_UN_RESYNC_ACTIVE) {
}
if (mirror_status & MD_UN_RESYNC_CANCEL) {
}
}
/* needs repair */
if (mirror_status & MD_UN_RESYNC_CANCEL) {
}
}
/* unknown */
assert(0);
return (state_to_str);
}
/*
* convert submirror state to repair action
*/
int
char **actionp,
)
{
static char buf[1024];
char *miscname;
/* all is well */
if (mirror_status & MD_UN_RESYNC_ACTIVE)
return (0);
return (0);
/* complete cancelled resync */
if (mirror_status & MD_UN_RESYNC_CANCEL) {
return (0);
}
/* replace stripe component */
return (-1);
return (-1);
}
if (compstate != CS_LAST_ERRED)
"metareplace %s %s <%s>",
else
"after replacing \"Maintenance\" "
"components:\n"
"\t\tmetareplace %s %s <new device>"),
return (0);
}
}
/* resync mirror */
SMS_COMP_RESYNC | SMS_ATTACHED)) ||
(mirror_status & MD_UN_OPT_NOT_DONE)) {
return (0);
}
/* online submirror */
if (state & SMS_OFFLINE) {
return (0);
}
/* unknown action */
return (0);
}
/*
* print mirror options
*/
int
char *fname,
)
{
char *p;
int rval = -1;
/* print options */
goto out;
}
goto out;
}
goto out;
}
/* Display resync option for mirror, if MultiNode set */
" Resync option: %s\n"),
goto out;
}
}
/* success */
rval = 0;
/* cleanup, return error */
out:
if (rval != 0)
return (rval);
}
static char *
{
mndiskset_membershiplist_t *nl, *p;
int n;
char *node_nm;
/* get the known membership list */
return (NULL);
}
/* find the matching node and return the name */
if (nid == p->msl_node_id) {
/* match found */
goto out;
}
}
/* match not found */
out:
return (node_nm);
}
/*
* report mirror
*/
static int
mdnamelist_t **nlpp,
char *fname,
)
{
char *p;
int rval = -1;
/*
* check for the -B option. If -B and the metadevice is
* a 64 bit device, get the dev for relocation information
* printout. If not a 64 bit device, just don't print this
* information out but you need to go down to the subdevice
* level and print there if appropriate.
*/
if (options & PRINT_LARGEDEVICES) {
if (submirnamep == NULL) {
continue;
}
if ((metaismeta(submirnamep)) &&
ep) != 0)) {
return (-1);
}
}
rval = 0;
goto out;
} else {
goto out;
}
}
/*
* check for the -D option. If -D and the name is
* a descriptive name, get the dev for relocation information
* printout. If not a descriptive name, don't print this
* information out but you need to go down to the subdevice
* level and print there if appropriate.
*/
if (submirnamep == NULL) {
continue;
}
if ((metaismeta(submirnamep)) &&
ep) != 0)) {
return (-1);
}
}
rval = 0;
goto out;
} else {
goto out;
}
}
/* print header */
if (options & PRINT_HEADER) {
goto out;
}
}
/* print submirrors, adjust status */
char *sm_state;
char *timep;
/* skip unused submirrors */
if (submirnamep == NULL) {
continue;
}
status &= ~MD_UN_OPT_NOT_DONE;
/* print submirror */
goto out;
}
/* print state */
ep) != 0)
return (-1);
}
tstate & MD_DEV_ERRORED);
if (options & PRINT_TIMES) {
} else {
timep = "";
}
" State: %-12s %s\n"),
goto out;
}
}
/* print resync status */
if (status & MD_UN_RESYNC_CANCEL) {
/* Resync was cancelled but is restartable */
" Resync cancelled: %2d.%1d %% done\n"),
goto out;
}
} else {
" Resync cancelled: %d %% done\n"),
goto out;
}
}
} else if (status & MD_UN_RESYNC_ACTIVE) {
" Resync in progress: %2d.%1d %% done\n"),
goto out;
}
} else {
" Resync in progress: %d %% done\n"),
goto out;
}
}
}
/* print options */
return (-1);
return (-1);
/* print mirror owner for multi-node metadevice */
char *node_name;
"MD_MN_GET_MM_OWNER") != 0) {
return (-1);
}
return (-1);
goto out;
}
}
/* print size */
== EOF) {
goto out;
}
/* MD_DEBUG stuff */
if (options & PRINT_DEBUG) {
uint_t i;
/* get real mirror unit */
== NULL) {
return (-1);
}
/* print dirty regions */
" Regions which are dirty: %d%% (blksize %d num %d)\n"),
goto out;
}
/* print optimized resync record locations */
"MD_DB_GETOPTLOC") != 0) {
return (-1);
}
++i) {
char *devname;
/* Don't need device id information from this ioctl */
"MD_DB_ENDDEV") != 0) {
}
== NULL) {
"unknown"));
}
" Resync record[%u]: %d (%s %d %d)\n"), i,
== EOF) {
goto out;
}
}
}
/* print submirror details */
char *sm_state;
char *timep;
/* skip unused submirrors */
if (submirnamep == NULL) {
continue;
}
/* get unit structure */
goto out;
== 0)
continue;
}
/* add extra line */
goto out;
/* print submirror */
"%s: Submirror of %s\n"),
goto out;
}
/* print state */
!= 0)
return (-1);
}
if (options & PRINT_TIMES) {
} else {
timep = "";
}
if ((tstate & MD_DEV_ERRORED) == 0) {
" State: %-12s %s\n"),
goto out;
}
/* print what to do */
return (-1);
if ((p != NULL) &&
" Invoke: %s\n"), p) == EOF)) {
goto out;
}
}
/* print underlying metadevice */
if ((metaismeta(submirnamep)) &&
return (-1);
}
}
/* add extra line */
goto out;
/* success */
rval = 0;
/* cleanup, return error */
out:
if (rval != 0)
return (rval);
}
/*
*/
int
mdnamelist_t **nlpp,
char *fname,
)
{
/* should have same set */
/* print all mirrors */
mdnamelist_t *p;
int cnt;
int rval = 0;
/* get list */
return (-1);
else if (cnt == 0)
return (0);
/* recurse */
rval = -1;
}
/* cleanup, return success */
return (rval);
}
/* get unit structure */
return (-1);
/* check for parented */
if ((! (options & PRINT_SUBDEVS)) &&
return (0);
}
/* print appropriate detail */
if (options & PRINT_SHORT) {
/* print mirror */
return (-1);
/* print underlying metadevices */
/* skip unused submirrors */
if (submirnamep == NULL) {
continue;
}
/* print submirror */
if (metaismeta(submirnamep)) {
ep) != 0) {
return (-1);
}
}
}
/* return success */
return (0);
} else {
}
}
/*
* online submirror
*/
int
)
{
/* should have same set */
/* check name */
return (-1);
return (-1);
/* Only valid for mirror without ABR set */
return (-1);
if (tstate & MD_ABR_CAP) {
return (-1);
}
/*
* In a MN set, the master always executes the online command first.
* Before the master executes the IOC_ONLINE ioctl,
* the master sends a message to all nodes to suspend writes to
* this mirror. Then the master executes the IOC_ONLINE ioctl
* which resumes writes to this mirror from the master node.
* As each slave executes the online command, each slave will
* call the IOC_ONLINE ioctl which will resume writes to this mirror
* from that slave node.
*/
if (! metaislocalset(sp)) {
return (-1);
return (-1);
}
/* online submirror */
/* clear cache */
/* let em know */
if (options & MDCMD_PRINT) {
"%s: submirror %s is onlined\n"),
}
/* return success */
return (0);
}
/*
* offline submirror
*/
int
)
{
/* should have same set */
/* check name */
return (-1);
return (-1);
/* Only valid for mirror without ABR set */
return (-1);
if (tstate & MD_ABR_CAP) {
return (-1);
}
/*
* In a MN set, the master always executes the offline command first.
* Before the master executes the IOC_OFFLINE ioctl,
* the master sends a message to all nodes to suspend writes to
* this mirror. Then the master executes the IOC_OFFLINE ioctl
* which resumes writes to this mirror from the master node.
* As each slave executes the offline command, each slave will
* call the IOC_OFFLINE ioctl which will resume writes to this mirror
* from that slave node.
*/
if (! metaislocalset(sp)) {
return (-1);
return (-1);
}
/* offline submirror */
/* clear cache */
/* let em know */
if (options & MDCMD_PRINT) {
"%s: submirror %s is offlined\n"),
}
/* return success */
return (0);
}
/*
* attach submirror to mirror
* we actually never have to worry about crossing a thresh hold here.
* 2 cases 1) attach and the only way the mirror can be 64 bit is if
* one of the submirrors already is. 2) grow and the only way the mirror
* is 64 bit is if one of the submirror's already is.
*/
int
)
{
/* should have same set */
/* check name */
return (-1);
/* just grow */
}
/* check submirror */
return (-1);
/* In dryrun mode (DOIT not set) we must not alter the mddb */
if (options & MDCMD_DOIT) {
/* store name in namespace */
return (-1);
}
/*
* In a MN set, the master always executes the attach command first.
* Before the master executes the IOC_ATTACH ioctl, in non-DRYRUN mode
* the master sends a message to all nodes to suspend writes to
* this mirror. Then the master executes the IOC_ATTACH ioctl
* which resumes writes to this mirror from the master node.
* As each slave executes the attach command, each slave will
* call the IOC_ATTACH ioctl which will resume writes to this mirror
* from that slave node.
*/
if (! metaislocalset(sp)) {
return (-1);
return (-1);
}
/* attach submirror */
/* if the comamnd was issued with -n option, use dryrun mode */
if ((options & MDCMD_DOIT) == 0) {
}
/* In dryrun mode (DOIT not set) we must not alter the mddb */
if (options & MDCMD_DOIT) {
}
}
/* In dryrun mode (DOIT not set) we must not alter the mddb */
if (options & MDCMD_DOIT) {
/* clear cache */
}
/* let em know */
if (options & MDCMD_PRINT) {
}
/* return success */
return (0);
}
/*
* detach submirror
*/
int
)
{
/* should have same set */
/* check name */
return (-1);
/*
* In a MN set, the master always executes the detach command first.
* Before the master executes the IOC_DETACH ioctl,
* the master sends a message to all nodes to suspend writes to
* this mirror. Then the master executes the IOC_DETACH ioctl
* which resumes writes to this mirror from the master node.
* As each slave executes the detach command, each slave will
* call the IOC_DETACH ioctl which will resume writes to this mirror
* from that slave node.
*/
if (! metaislocalset(sp)) {
return (-1);
return (-1);
}
/* detach submirror */
/* clear cache */
/* let em know */
if (options & MDCMD_PRINT) {
"%s: submirror %s is detached\n"),
}
/* return success */
return (0);
}
/*
* get mirror parameters
*/
int
)
{
/* should have a set */
/* check name */
return (-1);
/* get unit */
return (-1);
/* return parameters */
return (0);
}
/*
* set mirror parameters
*/
int
)
{
/* should have a set */
/* check name */
return (-1);
/* set parameters */
/* clear cache */
/* return success */
return (0);
}
/*
* invalidate submirror names
*/
static int
)
{
return (-1);
continue;
}
}
return (0);
}
/*
* replace mirror component
*/
int
)
{
int rebind;
char *new_devidp = NULL;
int ret;
/* should have same set */
/* check name */
return (-1);
/* save new binding incase this is a rebind where oldnp==newnp */
/* invalidate, then get the mirror (fill in oldnp from metadb) */
return (-1);
continue;
}
if (! metaismeta(submirnp))
continue;
return (-1);
}
/* the old device binding is now established */
/*
* check for the case where oldnp and newnp indicate the same
* device, but the dev_t of the device has changed between old
* and new. This is called a rebind. On entry the dev_t
* represents the new device binding determined from the
* filesystem (meta_getdev). After calling meta_get_unit
* oldnp (and maybe newnp if this is a rebind) is updated based
* to the old binding from the metadb (done by metakeyname).
*/
rebind = 1;
} else {
rebind = 0;
}
if (rebind) {
}
/*
* Save a copy of the devid associated with the new disk, the reason
* is that if we are rebinding then the call to meta_check_component()
* will cause the devid of the disk to be overwritten with what is in
* the replica namespace. The function that actually overwrites the
* devid is dr2drivedesc().
*/
/* if it's a multi-node diskset clear new_devidp */
if (!metaislocalset(sp)) {
return (-1);
if (MD_MNSET_DESC(sd))
new_devidp = NULL;
}
/* check it out (dup on rebind is ok) */
return (-1);
}
mdclrerror(ep);
}
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
/*
* Copy back the saved devid.
*/
if (new_devidp != NULL) {
}
/* store name in namespace, allocate new key */
return (-1);
/*
* In a MN set, the master always executes the replace command first.
* Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
* the master sends a message to all nodes to suspend writes to
* this mirror. Then the master executes the IOC_REPLACE ioctl
* which resumes writes to this mirror from the master node.
* As each slave executes the replace command, each slave will
* call the IOC_REPLACE ioctl which will resume writes to this mirror
* from that slave node.
*/
if (! metaislocalset(sp)) {
return (-1);
}
/*
* We are 'rebind'ing a disk that is in a diskset so as well
* as updating the diskset's namespace the local set needs
* to be updated because it also contains a reference to
* the disk in question.
*/
if (ret != METADEVADM_SUCCESS) {
return (-1);
}
}
/* replace component */
/* Is this just a dryrun ? */
if ((options & MDCMD_DOIT) == 0) {
}
}
/* clear cache */
return (-1);
}
/* let em know */
if (options & MDCMD_PRINT) {
"%s: device %s is replaced with %s\n"),
}
/* return success */
return (0);
}
/*
* enable mirror component
*/
int
)
{
int ret;
/* should have same set */
/* check name */
return (-1);
/* get the file_system dev binding */
return (-1);
/* get the mirror unit (fill in compnp->dev with metadb version) */
return (-1);
continue;
}
if (! metaismeta(submirnp))
continue;
return (-1);
}
/* the metadb device binding is now established */
/*
* check for the case where the dev_t has changed between the
* filesystem and the metadb. This is called a rebind, and
* is handled by meta_mirror_replace.
*/
}
/* setup mirror info */
/* check it out */
return (-1);
mdclrerror(ep);
}
return (-1);
return (-1);
return (-1);
return (-1);
}
/*
* In a MN set, the master always executes the replace command first.
* Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
* the master sends a message to all nodes to suspend writes to
* this mirror. Then the master executes the IOC_REPLACE ioctl
* which resumes writes to this mirror from the master node.
* As each slave executes the replace command, each slave will
* call the IOC_REPLACE ioctl which will resume writes to this mirror
* from that slave node.
*/
if (! metaislocalset(sp)) {
return (-1);
return (-1);
}
/* enable component */
/* Is this just a dryrun ? */
if ((options & MDCMD_DOIT) == 0) {
}
/*
* Are we dealing with a non-local set? If so need to update the
* local namespace so that the disk record has the correct devid.
*/
if (!metaislocalset(sp)) {
ep);
if (ret != METADEVADM_SUCCESS) {
/*
* Failed to update the local set. Nothing to do here
* apart from report the error. The namespace is
* most likely broken and some form of remedial
* recovery is going to be required.
*/
mdclrerror(ep);
}
}
/* clear cache */
return (-1);
}
/* let em know */
if (options & MDCMD_PRINT) {
"%s: device %s is enabled\n"),
}
/* return success */
return (0);
}
/*
* check for dups in the mirror itself
*/
static int
)
{
uint_t s;
for (s = 0; (s < smi); ++s) {
continue;
return (-1);
}
}
return (0);
}
/*
* check mirror
*/
int
)
{
/* check submirrors */
continue;
++nsm;
}
if (nsm < 1) {
}
/* skip unused submirrors */
}
continue;
}
/* check submirror */
if (doit) {
ep) != 0)
return (-1);
return (-1);
} else if (size == 0) {
}
}
/* check this mirror too */
return (-1);
}
/* check read option */
switch (mirrorp->read_option) {
case RD_LOAD_BAL:
case RD_GEOMETRY:
case RD_FIRST:
break;
default:
}
/* check write option */
switch (mirrorp->write_option) {
case WR_PARALLEL:
case WR_SERIAL:
break;
default:
}
/* check pass number */
/* return success */
return (0);
}
/*
* setup mirror geometry
*/
static int
)
{
uint_t write_reinstruct = 0;
uint_t read_reinstruct = 0;
/* get worst reinstructs */
continue;
return (-1);
}
/* setup geometry from first submirror */
return (-1);
return (-1);
/* return success */
return (0);
}
/*
* create mirror
*/
int
)
{
int rval = -1;
int create_flag = MD_CRO_32BIT;
/* validate mirror */
return (-1);
/* allocate mirror unit */
/* do submirrors */
/* skip unused submirrors */
continue;
}
++nsm;
/* get size */
goto out;
/* adjust for smallest submirror */
if (submir_size == MD_DISKADDR_ERROR) {
submir_size = size;
} else if (size < submir_size) {
submir_size = size;
}
if (options & MDCMD_DOIT) {
/* store name in namespace */
goto out;
}
/* setup submirror */
}
/* setup unit */
goto out;
/* fill in the size of the mirror */
if (options & MDCMD_UPDATE) {
}
/* if we're not doing anything, return success */
if (! (options & MDCMD_DOIT)) {
rval = 0; /* success */
goto out;
}
/* create mirror */
/* did the user tell us to generate a large device? */
if (create_flag == MD_CRO_64BIT) {
} else {
}
goto out;
}
rval = 0; /* success */
/* cleanup, return success */
out:
if (rval != 0) {
}
rval = -1;
}
return (rval);
}
/*
* initialize mirror
* NOTE: this functions is metainit(1m)'s command line parser!
*/
int
mdsetname_t **spp,
int argc,
char *argv[],
)
{
int old_optind;
int c;
int rval = -1;
/* get mirror name */
if (argc < 1)
goto syntax;
goto out;
goto out;
if (!(options & MDCMD_NOLOCK)) {
/* grab set lock */
goto out;
goto out;
}
/* see if it exists already */
goto out;
goto out;
} else {
mdclrerror(ep);
}
/* grab -m */
goto syntax;
if (argc == 0)
goto syntax;
/* parse general options */
optind = 0;
opterr = 0;
goto options;
/* allocate mirror */
/* setup common */
/* parse submirrors */
/* check for room */
goto out;
}
/* parse submirror name */
goto out;
}
if (smi == 0) {
uname);
goto out;
}
/* dangerous n-way mirror creation */
"%s: WARNING: This form of metainit is not recommended.\n"
"The submirrors may not have the same data.\n"
"Please see ERRORS in metainit(1M) for additional information.\n"),
uname);
}
/* parse mirror options */
old_optind = optind = 0;
opterr = 0;
switch (c) {
case 'g':
goto out;
}
break;
case 'r':
goto out;
}
break;
case 'S':
goto out;
}
break;
default:
argc -= old_optind;
argv += old_optind;
goto options;
}
old_optind = optind;
}
/* parse pass number */
goto out;
}
}
/* we should be at the end */
if (argc != 0)
goto syntax;
/* create mirror */
goto out;
rval = 0; /* success */
/* let em know */
if (options & MDCMD_PRINT) {
"%s: Mirror is setup\n"),
uname);
}
goto out;
/* syntax error */
goto out;
/* options error */
goto out;
/* cleanup, return error */
out:
return (rval);
}
/*
* reset mirrors
*/
int
)
{
int rval = -1;
/* should have same set */
/* reset all mirrors */
mdnamelist_t *p;
/* for each mirror */
rval = 0;
return (-1);
/* reset mirror */
/*
* If this is a multi-node set, we send a series
* of individual metaclear commands.
*/
rval = -1;
break;
}
} else {
ep) != 0) {
rval = -1;
break;
}
}
}
/* cleanup return success */
return (rval);
}
/* check name */
return (-1);
/* get unit structure */
return (-1);
/* make sure nobody owns us */
}
/* clear subdevices cache */
return (-1);
/* clear metadevice */
goto out;
rval = 0; /* success */
/* let em know */
if (options & MDCMD_PRINT) {
}
/* clear subdevices */
if (! (options & MDCMD_RECURSE))
goto out;
/* skip unused submirrors */
continue;
}
/* make sure we have a metadevice */
if (! metaismeta(submirnp))
continue;
/* clear submirror */
rval = -1;
}
/* cleanup, return success */
out:
return (rval);
}
/*
* reports TRUE if any mirror component is in error
*/
int
{
int smi;
goto out;
}
goto out;
}
}
}
out:
mdclrerror(ep);
return (any_errs);
}