1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * initialize metadevices 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <meta.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <sdssc.h> 36*0Sstevel@tonic-gate #include <sys/lvm/md_mirror.h> 37*0Sstevel@tonic-gate #include <syslog.h> 38*0Sstevel@tonic-gate #include "meta_set_prv.h" 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate /* 41*0Sstevel@tonic-gate * try to initialize devices 42*0Sstevel@tonic-gate */ 43*0Sstevel@tonic-gate #define DO_AGAIN 0 44*0Sstevel@tonic-gate #define DONT_DO 1 45*0Sstevel@tonic-gate #define IS_DONE 2 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate /* 48*0Sstevel@tonic-gate * mn_send_command 49*0Sstevel@tonic-gate * 50*0Sstevel@tonic-gate * generate a command of the form "metainit -s setname [-n] [-f] ....." 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * If -n option is *not* set, send the metainit command *with -n set* to 53*0Sstevel@tonic-gate * all nodes first. Do this with MD_MSGF_STOP_ON_ERROR set. 54*0Sstevel@tonic-gate * That means if it fails on one node, it'll return immediately, 55*0Sstevel@tonic-gate * reporting the error. 56*0Sstevel@tonic-gate * By doing so, we have a dryrun first that has to succeed on every node 57*0Sstevel@tonic-gate * before we start the command for real. 58*0Sstevel@tonic-gate * This saves us from backing out a metainit command that succeeded on 59*0Sstevel@tonic-gate * some nodes but failed on one. 60*0Sstevel@tonic-gate */ 61*0Sstevel@tonic-gate static int 62*0Sstevel@tonic-gate mn_send_command( 63*0Sstevel@tonic-gate mdsetname_t **spp, 64*0Sstevel@tonic-gate int argc, 65*0Sstevel@tonic-gate char **argv, 66*0Sstevel@tonic-gate mdcmdopts_t options, 67*0Sstevel@tonic-gate int flags, 68*0Sstevel@tonic-gate char *context, 69*0Sstevel@tonic-gate md_error_t *ep 70*0Sstevel@tonic-gate ) 71*0Sstevel@tonic-gate { 72*0Sstevel@tonic-gate int newargc; 73*0Sstevel@tonic-gate char **newargv; 74*0Sstevel@tonic-gate int i; 75*0Sstevel@tonic-gate int ret; 76*0Sstevel@tonic-gate int dryrun_only = 0; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate newargv = calloc(argc+5, sizeof (char *)); 80*0Sstevel@tonic-gate newargv[0] = "metainit"; 81*0Sstevel@tonic-gate newargv[1] = "-s"; 82*0Sstevel@tonic-gate newargv[2] = (*spp)->setname; 83*0Sstevel@tonic-gate newargv[3] = "-n"; /* always do "-n" first */ 84*0Sstevel@tonic-gate newargc = 4; 85*0Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) { 86*0Sstevel@tonic-gate dryrun_only = 1; 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate if ((options & MDCMD_FORCE) != 0) { 89*0Sstevel@tonic-gate newargv[newargc] = "-f"; 90*0Sstevel@tonic-gate newargc++; 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate for (i = 0; i < argc; i++, newargc++) 93*0Sstevel@tonic-gate newargv[newargc] = argv[i]; 94*0Sstevel@tonic-gate ret = meta_mn_send_command(*spp, newargc, newargv, 95*0Sstevel@tonic-gate flags | MD_DRYRUN | MD_NOLOG, context, ep); 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate if ((dryrun_only == 0) && (ret == 0)) { 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * Do it for real now. Remove "-n" from the arguments and 100*0Sstevel@tonic-gate * MD_DRYRUN from the flags. If we fail this time the master 101*0Sstevel@tonic-gate * must panic as the mddbs may be inconsistent. 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate newargv[3] = ""; /* this was "-n" before */ 104*0Sstevel@tonic-gate ret = meta_mn_send_command(*spp, newargc, newargv, 105*0Sstevel@tonic-gate flags | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT, 106*0Sstevel@tonic-gate context, ep); 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate free(newargv); 110*0Sstevel@tonic-gate return (ret); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate static int 114*0Sstevel@tonic-gate init_entries( 115*0Sstevel@tonic-gate mdsetname_t **spp, 116*0Sstevel@tonic-gate md_tab_t *tabp, 117*0Sstevel@tonic-gate mdcmdopts_t options, 118*0Sstevel@tonic-gate uint_t flags, 119*0Sstevel@tonic-gate bool_t called_thru_rpc, 120*0Sstevel@tonic-gate md_error_t *ep 121*0Sstevel@tonic-gate ) 122*0Sstevel@tonic-gate { 123*0Sstevel@tonic-gate uint_t cnt = 0; 124*0Sstevel@tonic-gate uint_t line; 125*0Sstevel@tonic-gate int rval = 0; 126*0Sstevel@tonic-gate int ret; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* for all matching entries, which haven't already been done */ 129*0Sstevel@tonic-gate for (line = 0; (line < tabp->nlines); ++line) { 130*0Sstevel@tonic-gate md_tab_line_t *linep = &tabp->lines[line]; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate /* see if already done */ 133*0Sstevel@tonic-gate if (linep->flags != DO_AGAIN) 134*0Sstevel@tonic-gate continue; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* try it */ 137*0Sstevel@tonic-gate if ((called_thru_rpc == FALSE) && 138*0Sstevel@tonic-gate meta_is_mn_name(spp, linep->argv[0], ep)) { 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * MN set, send command to all nodes 141*0Sstevel@tonic-gate * Note that is sp is NULL, meta_is_mn_name() derives 142*0Sstevel@tonic-gate * sp from linep->argv which is the metadevice arg 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate ret = mn_send_command(spp, linep->argc, linep->argv, 145*0Sstevel@tonic-gate options, flags, linep->context, ep); 146*0Sstevel@tonic-gate } else { 147*0Sstevel@tonic-gate ret = meta_init_name(spp, linep->argc, linep->argv, 148*0Sstevel@tonic-gate options, ep); 149*0Sstevel@tonic-gate if (ret != 0) { 150*0Sstevel@tonic-gate if (!(flags & MD_IGNORE_STDERR)) { 151*0Sstevel@tonic-gate mderrorextra(ep, linep->context); 152*0Sstevel@tonic-gate mde_perror(ep, ""); 153*0Sstevel@tonic-gate rval = -1; 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate mdclrerror(ep); 156*0Sstevel@tonic-gate } 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate if (ret == 0) { 159*0Sstevel@tonic-gate linep->flags = IS_DONE; 160*0Sstevel@tonic-gate ++cnt; 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* return success */ 165*0Sstevel@tonic-gate if (rval != 0) 166*0Sstevel@tonic-gate return (rval); 167*0Sstevel@tonic-gate return (cnt); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* 171*0Sstevel@tonic-gate * initialize all devices in set 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate static int 174*0Sstevel@tonic-gate init_all( 175*0Sstevel@tonic-gate mdsetname_t **spp, 176*0Sstevel@tonic-gate mdcmdopts_t options, 177*0Sstevel@tonic-gate bool_t called_thru_rpc, 178*0Sstevel@tonic-gate md_error_t *ep 179*0Sstevel@tonic-gate ) 180*0Sstevel@tonic-gate { 181*0Sstevel@tonic-gate md_tab_t *tabp = NULL; 182*0Sstevel@tonic-gate size_t setlen; 183*0Sstevel@tonic-gate uint_t more; 184*0Sstevel@tonic-gate int done; 185*0Sstevel@tonic-gate int eval = -1; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* create local set, if necessary */ 188*0Sstevel@tonic-gate if (*spp == NULL) { 189*0Sstevel@tonic-gate if ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 190*0Sstevel@tonic-gate mde_perror(ep, ""); 191*0Sstevel@tonic-gate mdclrerror(ep); 192*0Sstevel@tonic-gate return (eval); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate setlen = strlen((*spp)->setname); 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * Only take the lock if this is not a MN set 199*0Sstevel@tonic-gate * We can only enter this code for a MN set if we are the initiator 200*0Sstevel@tonic-gate * and in this case, we don't want to take locks. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate if (meta_is_mn_set((*spp), ep) == 0) { 203*0Sstevel@tonic-gate /* grab set lock */ 204*0Sstevel@tonic-gate if (meta_lock(*spp, TRUE, ep)) { 205*0Sstevel@tonic-gate mde_perror(ep, ""); 206*0Sstevel@tonic-gate mdclrerror(ep); 207*0Sstevel@tonic-gate return (eval); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* check for ownership */ 211*0Sstevel@tonic-gate if (meta_check_ownership(*spp, ep) != 0) { 212*0Sstevel@tonic-gate mde_perror(ep, ""); 213*0Sstevel@tonic-gate mdclrerror(ep); 214*0Sstevel@tonic-gate return (eval); 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate /* lock is held across init_entries */ 218*0Sstevel@tonic-gate options |= MDCMD_NOLOCK; 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* get md.tab, preen entries */ 222*0Sstevel@tonic-gate if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { 223*0Sstevel@tonic-gate mde_perror(ep, ""); 224*0Sstevel@tonic-gate mdclrerror(ep); 225*0Sstevel@tonic-gate return (eval); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate for (more = 0; (more < tabp->nlines); ++more) { 229*0Sstevel@tonic-gate md_tab_line_t *linep = &tabp->lines[more]; 230*0Sstevel@tonic-gate char *cname = linep->cname; 231*0Sstevel@tonic-gate char *p; 232*0Sstevel@tonic-gate size_t len; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* better have args */ 235*0Sstevel@tonic-gate assert((linep->argc > 0) && (linep->argv[0] != NULL)); 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* only do metadevices and hotspare pools in set */ 238*0Sstevel@tonic-gate if (linep->type & TAB_MD_HSP) { 239*0Sstevel@tonic-gate if ((p = strrchr(cname, '/')) == NULL) { 240*0Sstevel@tonic-gate len = 0; 241*0Sstevel@tonic-gate } else { 242*0Sstevel@tonic-gate len = p - cname; 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate if ((len == setlen) && 245*0Sstevel@tonic-gate (strncmp(cname, (*spp)->setname, len) == 0)) { 246*0Sstevel@tonic-gate linep->flags = DO_AGAIN; 247*0Sstevel@tonic-gate } else { 248*0Sstevel@tonic-gate linep->flags = DONT_DO; 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate } else { 252*0Sstevel@tonic-gate linep->flags = DONT_DO; 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate eval = 1; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* while more devices get made */ 259*0Sstevel@tonic-gate do { 260*0Sstevel@tonic-gate done = init_entries(spp, tabp, options, 261*0Sstevel@tonic-gate MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep); 262*0Sstevel@tonic-gate } while (done > 0); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate /* now do it and report errors */ 265*0Sstevel@tonic-gate if (init_entries(spp, tabp, options, MD_RETRY_BUSY, 266*0Sstevel@tonic-gate called_thru_rpc, ep) >= 0) 267*0Sstevel@tonic-gate eval = 0; /* success */ 268*0Sstevel@tonic-gate mdclrerror(ep); 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* cleanup, return success */ 271*0Sstevel@tonic-gate out: 272*0Sstevel@tonic-gate meta_tab_free(tabp); 273*0Sstevel@tonic-gate return (eval); 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * initialize named device or hotspare pool 278*0Sstevel@tonic-gate */ 279*0Sstevel@tonic-gate static int 280*0Sstevel@tonic-gate init_name( 281*0Sstevel@tonic-gate mdsetname_t **spp, 282*0Sstevel@tonic-gate int argc, 283*0Sstevel@tonic-gate char *argv[], 284*0Sstevel@tonic-gate mdcmdopts_t options, 285*0Sstevel@tonic-gate int called_thru_rpc, 286*0Sstevel@tonic-gate md_error_t *ep 287*0Sstevel@tonic-gate ) 288*0Sstevel@tonic-gate { 289*0Sstevel@tonic-gate md_tab_t *tabp = NULL; 290*0Sstevel@tonic-gate md_tab_line_t *linep = NULL; 291*0Sstevel@tonic-gate int rval = -1; 292*0Sstevel@tonic-gate int ret; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate /* look in md.tab */ 295*0Sstevel@tonic-gate if (argc == 1) { 296*0Sstevel@tonic-gate char *name = argv[0]; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* get md.tab entries */ 299*0Sstevel@tonic-gate if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { 300*0Sstevel@tonic-gate if (! mdissyserror(ep, ENOENT)) 301*0Sstevel@tonic-gate return (-1); 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* look in md.tab */ 305*0Sstevel@tonic-gate if ((linep = meta_tab_find(*spp, tabp, name, TAB_MD_HSP)) 306*0Sstevel@tonic-gate != NULL) { 307*0Sstevel@tonic-gate argc = linep->argc; 308*0Sstevel@tonic-gate argv = linep->argv; 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if ((called_thru_rpc == FALSE) && 313*0Sstevel@tonic-gate meta_is_mn_name(spp, argv[0], ep)) { 314*0Sstevel@tonic-gate /* 315*0Sstevel@tonic-gate * MN set, send command to all nodes 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate ret = mn_send_command(spp, argc, argv, options, 318*0Sstevel@tonic-gate MD_DISP_STDERR, NO_CONTEXT_STRING, ep); 319*0Sstevel@tonic-gate } else 320*0Sstevel@tonic-gate ret = meta_init_name(spp, argc, argv, options, ep); 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate if (ret != 0) { 323*0Sstevel@tonic-gate if (linep != NULL) 324*0Sstevel@tonic-gate mderrorextra(ep, linep->context); 325*0Sstevel@tonic-gate goto out; 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate rval = 0; /* success */ 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate /* cleanup, return error */ 330*0Sstevel@tonic-gate out: 331*0Sstevel@tonic-gate if (tabp != NULL) 332*0Sstevel@tonic-gate meta_tab_free(tabp); 333*0Sstevel@tonic-gate return (rval); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * print usage message 338*0Sstevel@tonic-gate */ 339*0Sstevel@tonic-gate static void 340*0Sstevel@tonic-gate usage( 341*0Sstevel@tonic-gate mdsetname_t *sp, 342*0Sstevel@tonic-gate int eval 343*0Sstevel@tonic-gate ) 344*0Sstevel@tonic-gate { 345*0Sstevel@tonic-gate #ifndef lint 346*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("\ 347*0Sstevel@tonic-gate usage: %s [-s setname] [-n] [-f] concat/stripe numstripes\n\ 348*0Sstevel@tonic-gate width component... [-i interlace]\n\ 349*0Sstevel@tonic-gate [width component... [-i interlace]] [-h hotspare_pool]\n\ 350*0Sstevel@tonic-gate %s [-s setname] [-n] [-f] mirror -m submirror...\n\ 351*0Sstevel@tonic-gate [read_options] [write_options] [pass_num]\n\ 352*0Sstevel@tonic-gate %s [-s setname] [-n] [-f] RAID -r component...\n\ 353*0Sstevel@tonic-gate [-i interlace] [-h hotspare_pool]\n\ 354*0Sstevel@tonic-gate [-k] [-o original_column_count]\n\ 355*0Sstevel@tonic-gate %s [-s setname] [-n] [-f] hotspare_pool [hotspare...]\n\ 356*0Sstevel@tonic-gate %s [-s setname] [-n] [-f] softpart -p [-A alignment]\n\ 357*0Sstevel@tonic-gate [-e] device size|all\n\ 358*0Sstevel@tonic-gate %s [-s setname] [-n] [-f] md.tab_entry\n\ 359*0Sstevel@tonic-gate %s [-s setname] [-n] [-f] -a\n\ 360*0Sstevel@tonic-gate %s -r\n"), myname, myname, myname, myname, myname, myname, myname, 361*0Sstevel@tonic-gate myname); 362*0Sstevel@tonic-gate #endif /* ! lint */ 363*0Sstevel@tonic-gate md_exit(sp, eval); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * If we fail during the attempt to take the auto-take disksets 368*0Sstevel@tonic-gate * we need to tell the kernel to cleanup the in-core set struct 369*0Sstevel@tonic-gate * so that we have a chance to take the set again later. 370*0Sstevel@tonic-gate */ 371*0Sstevel@tonic-gate static void 372*0Sstevel@tonic-gate auto_take_cleanup(mdsetname_t *sp, side_t sideno) 373*0Sstevel@tonic-gate { 374*0Sstevel@tonic-gate mddb_config_t c; 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate (void) memset(&c, 0, sizeof (c)); 377*0Sstevel@tonic-gate c.c_setno = sp->setno; 378*0Sstevel@tonic-gate c.c_sideno = sideno; 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0) { 381*0Sstevel@tonic-gate mde_perror(&c.c_mde, "auto_take_cleanup"); 382*0Sstevel@tonic-gate return; 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * Take the diskset. 388*0Sstevel@tonic-gate * 389*0Sstevel@tonic-gate * This is a clean auto-take set, so do the work to take it. 390*0Sstevel@tonic-gate * This is a streamlined version of the code in meta_set_take. We avoid the 391*0Sstevel@tonic-gate * need for talking to the rpc.metad since that can't run this early during the 392*0Sstevel@tonic-gate * boot. We don't need to talk to the metad for this diskset since we're the 393*0Sstevel@tonic-gate * only host in the set. 394*0Sstevel@tonic-gate */ 395*0Sstevel@tonic-gate static void 396*0Sstevel@tonic-gate take_set(md_set_record *sr) 397*0Sstevel@tonic-gate { 398*0Sstevel@tonic-gate mdsetname_t sn; 399*0Sstevel@tonic-gate md_drive_desc *dd; 400*0Sstevel@tonic-gate md_error_t error = mdnullerror; 401*0Sstevel@tonic-gate md_replicalist_t *rlp = NULL; 402*0Sstevel@tonic-gate md_replicalist_t *rl; 403*0Sstevel@tonic-gate daddr_t nblks = 0; 404*0Sstevel@tonic-gate md_drive_record *dr; 405*0Sstevel@tonic-gate side_t sideno; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * Several of the functions we call take a sp param so 409*0Sstevel@tonic-gate * construct one from the set record. 410*0Sstevel@tonic-gate */ 411*0Sstevel@tonic-gate sn.setname = sr->sr_setname; 412*0Sstevel@tonic-gate sn.setno = sr->sr_setno; 413*0Sstevel@tonic-gate sn.setdesc = sr2setdesc(sr); 414*0Sstevel@tonic-gate sn.lockfd = MD_NO_LOCK; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate if (sr->sr_flags & MD_SR_MB_DEVID) 417*0Sstevel@tonic-gate dd = metaget_drivedesc(&sn, MD_BASICNAME_OK | PRINT_FAST, 418*0Sstevel@tonic-gate &error); 419*0Sstevel@tonic-gate else 420*0Sstevel@tonic-gate dd = metaget_drivedesc(&sn, MD_BASICNAME_OK, &error); 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if (dd == NULL) { 423*0Sstevel@tonic-gate mde_perror(&error, ""); 424*0Sstevel@tonic-gate mdclrerror(&error); 425*0Sstevel@tonic-gate return; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Skip call to tk_own_bydd. This talks to rpc.metamhd (which we can't 430*0Sstevel@tonic-gate * do yet) and is not needed for auto-take disksets since we are not 431*0Sstevel@tonic-gate * doing SCSI reservations on these drives. 432*0Sstevel@tonic-gate */ 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate if (setup_db_bydd(&sn, dd, 0, &error) != 0) { 435*0Sstevel@tonic-gate if (! mdismddberror(&error, MDE_DB_ACCOK) && 436*0Sstevel@tonic-gate ! mdismddberror(&error, MDE_DB_TAGDATA)) { 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * Skip call to rel_own_bydd since that really just 439*0Sstevel@tonic-gate * calls rpc.metamhd which we don't need to do, 440*0Sstevel@tonic-gate * so there really isn't anything to rollback here. 441*0Sstevel@tonic-gate */ 442*0Sstevel@tonic-gate mde_perror(&error, ""); 443*0Sstevel@tonic-gate mdclrerror(&error); 444*0Sstevel@tonic-gate return; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate mdclrerror(&error); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate if ((sideno = getmyside(&sn, &error)) == MD_SIDEWILD) { 450*0Sstevel@tonic-gate mde_perror(&error, ""); 451*0Sstevel@tonic-gate return; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate if (snarf_set(&sn, FALSE, &error) != 0) { 455*0Sstevel@tonic-gate if (mdismddberror(&error, MDE_DB_STALE) || 456*0Sstevel@tonic-gate mdismddberror(&error, MDE_DB_TAGDATA) || 457*0Sstevel@tonic-gate ! mdismddberror(&error, MDE_DB_NODB) && 458*0Sstevel@tonic-gate ! mdismddberror(&error, MDE_DB_NOTOWNER)) { 459*0Sstevel@tonic-gate /* 460*0Sstevel@tonic-gate * rollback 461*0Sstevel@tonic-gate * Normally MDE_DB_STALE or MDE_DB_TAGDATA 462*0Sstevel@tonic-gate * would still keep the set but in this case we don't 463*0Sstevel@tonic-gate * want to do that. This will probably result in the 464*0Sstevel@tonic-gate * boot going in to single-user since we won't have the 465*0Sstevel@tonic-gate * set so any attempted mounts using the set's metadevices 466*0Sstevel@tonic-gate * will fail. However, that is a "good thing" so the 467*0Sstevel@tonic-gate * sysadmin can fix the set. Normally they would see 468*0Sstevel@tonic-gate * all of these problems when they ran the take and be 469*0Sstevel@tonic-gate * able to immediately fix the problem. 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate mde_perror(&error, ""); 472*0Sstevel@tonic-gate auto_take_cleanup(&sn, sideno); 473*0Sstevel@tonic-gate return; 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate /* 478*0Sstevel@tonic-gate * Call metareplicalist and upd_dr_dbinfo. 479*0Sstevel@tonic-gate * Most of that code is only needed to synchronize amongst the multiple 480*0Sstevel@tonic-gate * hosts in a set, which is not applicable in our case. But we do a 481*0Sstevel@tonic-gate * subset here to handle the case when the user had been 482*0Sstevel@tonic-gate * adding/deleting/balancing mddbs when this node panic'd. We are 483*0Sstevel@tonic-gate * synchronizing the ondisk mddbs to the list of drive records stored 484*0Sstevel@tonic-gate * in the local mddb. 485*0Sstevel@tonic-gate */ 486*0Sstevel@tonic-gate if (metareplicalist(&sn, (MD_BASICNAME_OK | PRINT_FAST), &rlp, &error) 487*0Sstevel@tonic-gate < 0) { 488*0Sstevel@tonic-gate /* rollback */ 489*0Sstevel@tonic-gate mde_perror(&error, ""); 490*0Sstevel@tonic-gate auto_take_cleanup(&sn, sideno); 491*0Sstevel@tonic-gate return; 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* 495*0Sstevel@tonic-gate * The following code is equivalent to upd_dr_dbinfo for syncronizing 496*0Sstevel@tonic-gate * the local host only. That function is normally run through the 497*0Sstevel@tonic-gate * metad with a local and daemon side but we'll do all of the work 498*0Sstevel@tonic-gate * here. 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate /* find the smallest existing replica */ 502*0Sstevel@tonic-gate for (rl = rlp; rl != NULL; rl = rl->rl_next) { 503*0Sstevel@tonic-gate md_replica_t *r; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate r = rl->rl_repp; 506*0Sstevel@tonic-gate nblks = ((nblks == 0) ? r->r_nblk : min(r->r_nblk, nblks)); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate if (nblks <= 0) 510*0Sstevel@tonic-gate nblks = MD_DBSIZE; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate for (dr = sr->sr_drivechain; dr; dr = dr->dr_next) { 513*0Sstevel@tonic-gate int dbcnt; 514*0Sstevel@tonic-gate mddrivename_t *dnp; 515*0Sstevel@tonic-gate md_replicalist_t *rl; 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate /* 518*0Sstevel@tonic-gate * The cname style for dnp and replica list will be same since 519*0Sstevel@tonic-gate * both use the the same flags MD_BASICNAME_OK|PRINT_FAST which 520*0Sstevel@tonic-gate * will always provide the cached value. 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate if ((dnp = metadrivename_withdrkey(&sn, sideno, dr->dr_key, 523*0Sstevel@tonic-gate MD_BASICNAME_OK | PRINT_FAST, &error)) == NULL) { 524*0Sstevel@tonic-gate mde_perror(&error, ""); 525*0Sstevel@tonic-gate metafreereplicalist(rlp); 526*0Sstevel@tonic-gate auto_take_cleanup(&sn, sideno); 527*0Sstevel@tonic-gate return; 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate dbcnt = 0; 531*0Sstevel@tonic-gate /* see how many replicas are on this drive */ 532*0Sstevel@tonic-gate for (rl = rlp; rl != NULL; rl = rl->rl_next) { 533*0Sstevel@tonic-gate if (strcmp(rl->rl_repp->r_namep->drivenamep->cname, dnp->cname) 534*0Sstevel@tonic-gate == 0) 535*0Sstevel@tonic-gate dbcnt++; 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate /* Adjust the fields in the copy */ 539*0Sstevel@tonic-gate dr->dr_dbcnt = dbcnt; 540*0Sstevel@tonic-gate dr->dr_dbsize = dbcnt > 0 ? nblks : 0; 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * If the set doesn't have the MD_SR_MB_DEVID bit set, i.e 545*0Sstevel@tonic-gate * the drives in the set don't have the device id information, 546*0Sstevel@tonic-gate * then stick it in if possible. 547*0Sstevel@tonic-gate * 548*0Sstevel@tonic-gate * If updating the master block fails for whatever reason, it's 549*0Sstevel@tonic-gate * okay. It just means the disk(s) in the diskset won't be self 550*0Sstevel@tonic-gate * identifying. 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate if (!(sr->sr_flags & MD_SR_MB_DEVID)) { 553*0Sstevel@tonic-gate if (meta_update_mb(&sn, dd, &error) == 0) { 554*0Sstevel@tonic-gate sr->sr_flags |= MD_SR_MB_DEVID; 555*0Sstevel@tonic-gate mdclrerror(&error); 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate commitset(sr, FALSE, &error); 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate metafreereplicalist(rlp); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate /* 564*0Sstevel@tonic-gate * This finishes up the logical equivalent of meta_set_take. 565*0Sstevel@tonic-gate */ 566*0Sstevel@tonic-gate if (meta_resync_all(&sn, MD_DEF_RESYNC_BUF_SIZE, &error) != 0) { 567*0Sstevel@tonic-gate mde_perror(&error, ""); 568*0Sstevel@tonic-gate mdclrerror(&error); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate /* 573*0Sstevel@tonic-gate * Take the disksets that are marked to be taken at boot time. 574*0Sstevel@tonic-gate */ 575*0Sstevel@tonic-gate static void 576*0Sstevel@tonic-gate auto_take_sets() 577*0Sstevel@tonic-gate { 578*0Sstevel@tonic-gate int max_sets; 579*0Sstevel@tonic-gate int i; 580*0Sstevel@tonic-gate md_error_t error = mdnullerror; 581*0Sstevel@tonic-gate char *hostname; 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate if ((max_sets = get_max_sets(&error)) == 0) 584*0Sstevel@tonic-gate return; 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate if (!mdisok(&error)) { 587*0Sstevel@tonic-gate mde_perror(&error, ""); 588*0Sstevel@tonic-gate return; 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate /* set up so auto-take errors also go to syslog */ 592*0Sstevel@tonic-gate openlog("metainit", LOG_ODELAY, LOG_USER); 593*0Sstevel@tonic-gate metasyslog = 1; 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate hostname = mynode(); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate /* 598*0Sstevel@tonic-gate * For each possible set number (skip set 0 which is the unnamed local 599*0Sstevel@tonic-gate * set), see if we really have a diskset. If so, check if auto-take 600*0Sstevel@tonic-gate * is enabled. 601*0Sstevel@tonic-gate * 602*0Sstevel@tonic-gate * In order to take the set it must have drives and it must not be 603*0Sstevel@tonic-gate * stuck in mid-add. The sr_validate routine within rpc.metad will 604*0Sstevel@tonic-gate * delete sets that are in mid-add when it runs. 605*0Sstevel@tonic-gate */ 606*0Sstevel@tonic-gate for (i = 1; i < max_sets; i++) { 607*0Sstevel@tonic-gate md_set_record *sr; 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate if ((sr = metad_getsetbynum(i, &error)) == NULL) { 610*0Sstevel@tonic-gate mdclrerror(&error); 611*0Sstevel@tonic-gate continue; 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate if (sr->sr_flags & MD_SR_AUTO_TAKE && !(sr->sr_flags & MD_SR_ADD)) { 615*0Sstevel@tonic-gate int j; 616*0Sstevel@tonic-gate int cnt = 0; 617*0Sstevel@tonic-gate int host_mismatch = 0; 618*0Sstevel@tonic-gate int take = 0; 619*0Sstevel@tonic-gate md_drive_record *dr; 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate /* check for host renames or multiple hosts in set */ 622*0Sstevel@tonic-gate for (j = 0; j < MD_MAXSIDES; j++) { 623*0Sstevel@tonic-gate /* Skip empty slots */ 624*0Sstevel@tonic-gate if (sr->sr_nodes[j][0] == '\0') 625*0Sstevel@tonic-gate continue; 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate cnt++; 628*0Sstevel@tonic-gate if (strcmp(sr->sr_nodes[j], hostname) != 0) 629*0Sstevel@tonic-gate host_mismatch = 1; 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* paranoid check that we're the only host in the set */ 633*0Sstevel@tonic-gate if (cnt > 1) { 634*0Sstevel@tonic-gate md_eprintf(gettext( 635*0Sstevel@tonic-gate "diskset %s: auto-take enabled and multiple hosts in set\n"), 636*0Sstevel@tonic-gate sr->sr_setname); 637*0Sstevel@tonic-gate continue; 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate if (host_mismatch) { 641*0Sstevel@tonic-gate /* The host was renamed, repair the set. */ 642*0Sstevel@tonic-gate for (j = 0; j < MD_MAXSIDES; j++) { 643*0Sstevel@tonic-gate /* Skip empty slots */ 644*0Sstevel@tonic-gate if (sr->sr_nodes[j][0] == '\0') 645*0Sstevel@tonic-gate continue; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate (void) strncpy(sr->sr_nodes[j], hostname, 648*0Sstevel@tonic-gate sizeof (sr->sr_nodes[j])); 649*0Sstevel@tonic-gate commitset(sr, FALSE, &error); 650*0Sstevel@tonic-gate if (!mdisok(&error)) { 651*0Sstevel@tonic-gate mde_perror(&error, ""); 652*0Sstevel@tonic-gate mdclrerror(&error); 653*0Sstevel@tonic-gate } else { 654*0Sstevel@tonic-gate md_eprintf(gettext( 655*0Sstevel@tonic-gate "new hostname %s, update auto-take diskset %s\n"), 656*0Sstevel@tonic-gate hostname, sr->sr_setname); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate break; 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate /* set must have at least one drive to be taken */ 663*0Sstevel@tonic-gate for (dr = sr->sr_drivechain; dr != NULL; dr = dr->dr_next) { 664*0Sstevel@tonic-gate /* ignore drives in mid-add */ 665*0Sstevel@tonic-gate if (!(dr->dr_flags & MD_DR_ADD)) { 666*0Sstevel@tonic-gate take = 1; 667*0Sstevel@tonic-gate break; 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate if (take) 672*0Sstevel@tonic-gate take_set(sr); 673*0Sstevel@tonic-gate else 674*0Sstevel@tonic-gate md_eprintf(gettext( 675*0Sstevel@tonic-gate "diskset %s: auto-take enabled but set has no drives\n"), 676*0Sstevel@tonic-gate sr->sr_setname); 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate /* 682*0Sstevel@tonic-gate * mainline. crack command line arguments. 683*0Sstevel@tonic-gate */ 684*0Sstevel@tonic-gate int 685*0Sstevel@tonic-gate main( 686*0Sstevel@tonic-gate int argc, 687*0Sstevel@tonic-gate char *argv[] 688*0Sstevel@tonic-gate ) 689*0Sstevel@tonic-gate { 690*0Sstevel@tonic-gate char *sname = NULL; 691*0Sstevel@tonic-gate mdsetname_t *sp = NULL; 692*0Sstevel@tonic-gate enum action { 693*0Sstevel@tonic-gate NONE, 694*0Sstevel@tonic-gate INIT, 695*0Sstevel@tonic-gate ALL 696*0Sstevel@tonic-gate } todo = NONE; 697*0Sstevel@tonic-gate mdcmdopts_t options = (MDCMD_DOIT | MDCMD_PRINT); 698*0Sstevel@tonic-gate int c; 699*0Sstevel@tonic-gate md_error_t status = mdnullerror; 700*0Sstevel@tonic-gate md_error_t *ep = &status; 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate md_error_t dummystatus = mdnullerror; 703*0Sstevel@tonic-gate md_error_t *dummyep = &dummystatus; 704*0Sstevel@tonic-gate int eval = 1; 705*0Sstevel@tonic-gate int error; 706*0Sstevel@tonic-gate bool_t called_thru_rpc = FALSE; 707*0Sstevel@tonic-gate char *cp; 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate /* 710*0Sstevel@tonic-gate * Get the locale set up before calling any other routines 711*0Sstevel@tonic-gate * with messages to ouput. Just in case we're not in a build 712*0Sstevel@tonic-gate * environment, make sure that TEXT_DOMAIN gets set to 713*0Sstevel@tonic-gate * something. 714*0Sstevel@tonic-gate */ 715*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 716*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 717*0Sstevel@tonic-gate #endif 718*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 719*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 720*0Sstevel@tonic-gate if ((cp = strstr(argv[0], ".rpc_call")) != NULL) { 721*0Sstevel@tonic-gate *cp = '\0'; /* cut off ".rpc_call" */ 722*0Sstevel@tonic-gate called_thru_rpc = TRUE; 723*0Sstevel@tonic-gate } else { 724*0Sstevel@tonic-gate if (sdssc_bind_library() == SDSSC_OKAY) 725*0Sstevel@tonic-gate if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 726*0Sstevel@tonic-gate &error) == SDSSC_PROXY_DONE) 727*0Sstevel@tonic-gate exit(error); 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate /* initialize */ 731*0Sstevel@tonic-gate if (md_init(argc, argv, 0, 1, ep) != 0 || 732*0Sstevel@tonic-gate meta_check_root(ep) != 0) { 733*0Sstevel@tonic-gate mde_perror(ep, ""); 734*0Sstevel@tonic-gate md_exit(sp, 1); 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate /* parse args */ 738*0Sstevel@tonic-gate optind = 1; 739*0Sstevel@tonic-gate opterr = 1; 740*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "afhnrs:?")) != -1) { 741*0Sstevel@tonic-gate switch (c) { 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate /* help */ 744*0Sstevel@tonic-gate case 'h': 745*0Sstevel@tonic-gate usage(sp, 0); 746*0Sstevel@tonic-gate break; 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate /* set name */ 749*0Sstevel@tonic-gate case 's': 750*0Sstevel@tonic-gate sname = optarg; 751*0Sstevel@tonic-gate break; 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate /* all devices in md.tab */ 754*0Sstevel@tonic-gate case 'a': 755*0Sstevel@tonic-gate if (todo != NONE) 756*0Sstevel@tonic-gate usage(sp, 1); 757*0Sstevel@tonic-gate todo = ALL; 758*0Sstevel@tonic-gate options |= MDCMD_ALLOPTION; 759*0Sstevel@tonic-gate break; 760*0Sstevel@tonic-gate /* check for validity, but don't really init */ 761*0Sstevel@tonic-gate case 'n': 762*0Sstevel@tonic-gate options &= ~MDCMD_DOIT; 763*0Sstevel@tonic-gate break; 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate /* for recovery */ 766*0Sstevel@tonic-gate case 'r': 767*0Sstevel@tonic-gate if (todo != NONE) 768*0Sstevel@tonic-gate usage(sp, 1); 769*0Sstevel@tonic-gate todo = INIT; 770*0Sstevel@tonic-gate break; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* mounted and swapped components are OK */ 773*0Sstevel@tonic-gate case 'f': 774*0Sstevel@tonic-gate options |= MDCMD_FORCE; 775*0Sstevel@tonic-gate break; 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate case '?': 778*0Sstevel@tonic-gate if (optopt == '?') 779*0Sstevel@tonic-gate usage(sp, 0); 780*0Sstevel@tonic-gate /*FALLTHROUGH*/ 781*0Sstevel@tonic-gate default: 782*0Sstevel@tonic-gate usage(sp, 1); 783*0Sstevel@tonic-gate break; 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate } 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate if (sname != NULL) { 788*0Sstevel@tonic-gate if ((sp = metasetname(sname, ep)) == NULL) { 789*0Sstevel@tonic-gate mde_perror(ep, ""); 790*0Sstevel@tonic-gate md_exit(sp, 1); 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate argc -= optind; 794*0Sstevel@tonic-gate argv += optind; 795*0Sstevel@tonic-gate if (todo == NONE) { 796*0Sstevel@tonic-gate if (argc <= 0) { 797*0Sstevel@tonic-gate usage(sp, 1); 798*0Sstevel@tonic-gate } 799*0Sstevel@tonic-gate } else if (argc > 0) { 800*0Sstevel@tonic-gate usage(sp, 1); 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate /* setup database locations */ 805*0Sstevel@tonic-gate if (meta_setup_db_locations(ep) != 0) { 806*0Sstevel@tonic-gate mde_perror(ep, ""); 807*0Sstevel@tonic-gate if (mdismddberror(ep, MDE_DB_STALE)) 808*0Sstevel@tonic-gate md_exit(sp, 66); 809*0Sstevel@tonic-gate if (! mdiserror(ep, MDE_MDDB_CKSUM)) /* relatively benign */ 810*0Sstevel@tonic-gate md_exit(sp, 1); 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate if (todo == INIT) { /* load and take auto-take sets */ 813*0Sstevel@tonic-gate auto_take_sets(); 814*0Sstevel@tonic-gate md_exit(sp, 0); 815*0Sstevel@tonic-gate } else if (todo == ALL) { /* initialize all devices in md.tab */ 816*0Sstevel@tonic-gate eval = init_all(&sp, options, called_thru_rpc, ep); 817*0Sstevel@tonic-gate } else { /* initialize the named device */ 818*0Sstevel@tonic-gate eval = 0; 819*0Sstevel@tonic-gate if (init_name(&sp, argc, argv, options, called_thru_rpc, 820*0Sstevel@tonic-gate ep) != 0) { 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * If we're dealing with MN metadevices and we are 823*0Sstevel@tonic-gate * directly called, then the appropriate error message 824*0Sstevel@tonic-gate * has already been displayed. So just exit. 825*0Sstevel@tonic-gate */ 826*0Sstevel@tonic-gate if (meta_is_mn_set(sp, dummyep) && (!called_thru_rpc)) { 827*0Sstevel@tonic-gate md_exit(sp, 1); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate mde_perror(ep, ""); 830*0Sstevel@tonic-gate mdclrerror(ep); 831*0Sstevel@tonic-gate eval = 1; 832*0Sstevel@tonic-gate goto nomdcf; 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate domdcf: 837*0Sstevel@tonic-gate /* update md.cf, return success */ 838*0Sstevel@tonic-gate if (meta_update_md_cf(sp, ep) != 0) { 839*0Sstevel@tonic-gate mde_perror(ep, ""); 840*0Sstevel@tonic-gate eval = 1; 841*0Sstevel@tonic-gate } 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate nomdcf: 844*0Sstevel@tonic-gate md_exit(sp, eval); 845*0Sstevel@tonic-gate /*NOTREACHED*/ 846*0Sstevel@tonic-gate return (eval); 847*0Sstevel@tonic-gate } 848