metainit.c revision f3e56050555d3d1ae673b32c5815b57e97db899a
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* initialize metadevices
*/
#include <meta.h>
#include <sdssc.h>
#include <syslog.h>
#include "meta_set_prv.h"
/*
* try to initialize devices
*/
#define DO_AGAIN 0
#define DONT_DO 1
#define IS_DONE 2
/*
* mn_send_command
*
* generate a command of the form "metainit -s setname [-n] [-f] ....."
*
* If -n option is *not* set, send the metainit command *with -n set* to
* all nodes first. Do this with MD_MSGF_STOP_ON_ERROR set.
* That means if it fails on one node, it'll return immediately,
* reporting the error.
* By doing so, we have a dryrun first that has to succeed on every node
* before we start the command for real.
* This saves us from backing out a metainit command that succeeded on
* some nodes but failed on one.
*/
static int
mdsetname_t **spp,
int argc,
char **argv,
int flags,
char *context,
)
{
int newargc;
char **newargv;
int i;
int ret;
int dryrun_only = 0;
newargv[0] = "metainit";
newargc = 4;
if ((options & MDCMD_DOIT) == 0) {
dryrun_only = 1;
}
if ((options & MDCMD_FORCE) != 0) {
newargc++;
}
if ((dryrun_only == 0) && (ret == 0)) {
/*
* Do it for real now. Remove "-n" from the arguments and
* MD_DRYRUN from the flags. If we fail this time the master
* must panic as the mddbs may be inconsistent.
*/
}
return (ret);
}
static int
mdsetname_t **spp,
)
{
int rval = 0;
int ret;
/* for all matching entries, which haven't already been done */
/* see if already done */
continue;
/* try it */
if ((called_thru_rpc == FALSE) &&
/*
* MN set, send command to all nodes
* Note that is sp is NULL, meta_is_mn_name() derives
* sp from linep->argv which is the metadevice arg
*/
} else {
mdclrerror(ep);
} else {
if (ret != 0) {
if (!(flags & MD_IGNORE_STDERR)) {
rval = -1;
}
mdclrerror(ep);
}
}
}
if (ret == 0) {
++cnt;
}
}
/* return success */
if (rval != 0)
return (rval);
return (cnt);
}
/*
* initialize all devices in set
*/
static int
mdsetname_t **spp,
)
{
int done;
int eval = -1;
/*
* Only take the lock if this is not a MN set
* We can only enter this code for a MN set if we are the initiator
* and in this case, we don't want to take locks.
*/
/* grab set lock */
mdclrerror(ep);
return (eval);
}
/* check for ownership */
mdclrerror(ep);
return (eval);
}
/* lock is held across init_entries */
options |= MDCMD_NOLOCK;
}
/* get md.tab, preen entries */
mdclrerror(ep);
return (eval);
}
char *p;
/* better have args */
/* only do metadevices and hotspare pools in set */
len = 0;
} else {
}
} else {
}
} else {
}
}
eval = 1;
/* while more devices get made */
do {
} while (done > 0);
/* now do it and report errors */
called_thru_rpc, ep) >= 0)
eval = 0; /* success */
mdclrerror(ep);
/* cleanup, return success */
out:
return (eval);
}
/*
* initialize named device or hotspare pool
*/
static int
mdsetname_t **spp,
int argc,
char *argv[],
int called_thru_rpc,
)
{
int rval = -1;
int ret;
/* look in md.tab */
if (argc == 1) {
/* get md.tab entries */
return (-1);
}
/* look in md.tab */
!= NULL) {
}
}
if ((called_thru_rpc == FALSE) &&
/*
* MN set, send command to all nodes
*/
} else {
goto out;
}
/* check for ownership */
goto out;
}
}
if (ret != 0) {
goto out;
}
rval = 0; /* success */
/* cleanup, return error */
out:
return (rval);
}
/*
* print usage message
*/
static void
int eval
)
{
#ifndef lint
width component... [-i interlace]\n\
[width component... [-i interlace]] [-h hotspare_pool]\n\
%s [-s setname] [-n] [-f] mirror -m submirror...\n\
[read_options] [write_options] [pass_num]\n\
%s [-s setname] [-n] [-f] RAID -r component...\n\
[-i interlace] [-h hotspare_pool]\n\
[-k] [-o original_column_count]\n\
%s [-s setname] [-n] [-f] hotspare_pool [hotspare...]\n\
%s [-s setname] [-n] [-f] softpart -p [-A alignment]\n\
[-e] device size|all\n\
%s [-s setname] [-n] [-f] md.tab_entry\n\
%s [-s setname] [-n] [-f] -a\n\
myname);
#endif /* ! lint */
}
/*
* If we fail during the attempt to take the auto-take disksets
* we need to tell the kernel to cleanup the in-core set struct
* so that we have a chance to take the set again later.
*/
static void
{
(void) memset(&c, 0, sizeof (c));
return;
}
}
/*
* Take the diskset.
*
* This is a clean auto-take set, so do the work to take it.
* This is a streamlined version of the code in meta_set_take. We avoid the
* need for talking to the rpc.metad since that can't run this early during the
* boot. We don't need to talk to the metad for this diskset since we're the
* only host in the set.
*/
static void
{
/*
* Several of the functions we call take a sp param so
* construct one from the set record.
*/
&error);
else
mdclrerror(&error);
return;
}
/*
* Skip call to tk_own_bydd. This talks to rpc.metamhd (which we can't
* do yet) and is not needed for auto-take disksets since we are not
* doing SCSI reservations on these drives.
*/
/*
* Skip call to rel_own_bydd since that really just
* calls rpc.metamhd which we don't need to do,
* so there really isn't anything to rollback here.
*/
mdclrerror(&error);
return;
}
mdclrerror(&error);
}
return;
}
/*
* rollback
* Normally MDE_DB_STALE or MDE_DB_TAGDATA
* would still keep the set but in this case we don't
* want to do that. This will probably result in the
* boot going in to single-user since we won't have the
* set so any attempted mounts using the set's metadevices
* will fail. However, that is a "good thing" so the
* sysadmin can fix the set. Normally they would see
* all of these problems when they ran the take and be
* able to immediately fix the problem.
*/
return;
}
}
/*
* Call metareplicalist and upd_dr_dbinfo.
* Most of that code is only needed to synchronize amongst the multiple
* hosts in a set, which is not applicable in our case. But we do a
* subset here to handle the case when the user had been
* synchronizing the ondisk mddbs to the list of drive records stored
* in the local mddb.
*/
< 0) {
/* rollback */
return;
}
/*
* The following code is equivalent to upd_dr_dbinfo for syncronizing
* the local host only. That function is normally run through the
* metad with a local and daemon side but we'll do all of the work
* here.
*/
/* find the smallest existing replica */
md_replica_t *r;
}
if (nblks <= 0)
int dbcnt;
/*
* The cname style for dnp and replica list will be same since
* both use the the same flags MD_BASICNAME_OK|PRINT_FAST which
* will always provide the cached value.
*/
return;
}
dbcnt = 0;
/* see how many replicas are on this drive */
== 0)
dbcnt++;
}
/* Adjust the fields in the copy */
}
/*
* If the set doesn't have the MD_SR_MB_DEVID bit set, i.e
* the drives in the set don't have the device id information,
* then stick it in if possible.
*
* If updating the master block fails for whatever reason, it's
* okay. It just means the disk(s) in the diskset won't be self
* identifying.
*/
mdclrerror(&error);
}
}
/*
* This finishes up the logical equivalent of meta_set_take.
*/
mdclrerror(&error);
}
}
/*
* Take the disksets that are marked to be taken at boot time.
*/
static void
{
int max_sets;
int i;
char *hostname;
return;
return;
}
/* set up so auto-take errors also go to syslog */
metasyslog = 1;
/*
* For each possible set number (skip set 0 which is the unnamed local
* set), see if we really have a diskset. If so, check if auto-take
* is enabled.
*
* In order to take the set it must have drives and it must not be
* stuck in mid-add. The sr_validate routine within rpc.metad will
* delete sets that are in mid-add when it runs.
*/
for (i = 1; i < max_sets; i++) {
mdclrerror(&error);
continue;
}
int j;
int cnt = 0;
int host_mismatch = 0;
int take = 0;
/* check for host renames or multiple hosts in set */
for (j = 0; j < MD_MAXSIDES; j++) {
/* Skip empty slots */
continue;
cnt++;
host_mismatch = 1;
}
/* paranoid check that we're the only host in the set */
if (cnt > 1) {
"diskset %s: auto-take enabled and multiple hosts in set\n"),
sr->sr_setname);
continue;
}
if (host_mismatch) {
/* The host was renamed, repair the set. */
for (j = 0; j < MD_MAXSIDES; j++) {
/* Skip empty slots */
continue;
mdclrerror(&error);
} else {
"new hostname %s, update auto-take diskset %s\n"),
}
break;
}
}
/* set must have at least one drive to be taken */
/* ignore drives in mid-add */
take = 1;
break;
}
}
if (take)
else
"diskset %s: auto-take enabled but set has no drives\n"),
sr->sr_setname);
}
}
}
/*
* mainline. crack command line arguments.
*/
int
main(
int argc,
char *argv[]
)
{
char *sname = MD_LOCAL_NAME;
enum action {
NONE,
INIT,
int c;
int eval = 1;
int error;
char *cp;
/*
* Get the locale set up before calling any other routines
* with messages to ouput. 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
(void) textdomain(TEXT_DOMAIN);
} else {
if (sdssc_bind_library() == SDSSC_OKAY)
&error) == SDSSC_PROXY_DONE)
}
/* initialize */
meta_check_root(ep) != 0) {
}
/* parse args */
optind = 1;
opterr = 1;
switch (c) {
/* help */
case 'h':
break;
/* set name */
case 's':
break;
/* all devices in md.tab */
case 'a':
break;
/* check for validity, but don't really init */
case 'n':
options &= ~MDCMD_DOIT;
break;
/* for recovery */
case 'r':
break;
/* mounted and swapped components are OK */
case 'f':
options |= MDCMD_FORCE;
break;
case '?':
if (optopt == '?')
/*FALLTHROUGH*/
default:
break;
}
}
/* sname is MD_LOCAL_NAME if not specified on the command line */
}
if (argc <= 0) {
}
} else if (argc > 0) {
}
/* setup database locations */
if (meta_setup_db_locations(ep) != 0) {
}
/*
* During the boot sequence we need to update the mediator
* records, however this depends upon the rpc.metamedd
* running. So, in order to not introduce a delay in the
* boot time, fork a new process to do this work in the
* background.
*/
/*
* We could not fork a child process to udpate mediator
* information on this node. There is no need to panic.
* We shall simply return 1.
*/
" update mediator record");
/* child */
/*
* No need to print any error messages.
* All the errors messages are printed in the
* library routine itself.
*/
} else {
}
} else {
/* Parent process */
}
} else { /* initialize the named device */
eval = 0;
ep) != 0) {
/*
* If we're dealing with MN metadevices and we are
* directly called, then the appropriate error message
* has already been displayed. So just exit.
*/
}
mdclrerror(ep);
eval = 1;
goto nomdcf;
}
}
/* update md.cf, return success */
eval = 1;
}
/*NOTREACHED*/
return (eval);
}