10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1623Stw21770 * Common Development and Distribution License (the "License"). 6*1623Stw21770 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1623Stw21770 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * initialize metadevices 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <meta.h> 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include <sdssc.h> 350Sstevel@tonic-gate #include <sys/lvm/md_mirror.h> 360Sstevel@tonic-gate #include <syslog.h> 370Sstevel@tonic-gate #include "meta_set_prv.h" 380Sstevel@tonic-gate 390Sstevel@tonic-gate /* 400Sstevel@tonic-gate * try to initialize devices 410Sstevel@tonic-gate */ 420Sstevel@tonic-gate #define DO_AGAIN 0 430Sstevel@tonic-gate #define DONT_DO 1 440Sstevel@tonic-gate #define IS_DONE 2 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * mn_send_command 480Sstevel@tonic-gate * 490Sstevel@tonic-gate * generate a command of the form "metainit -s setname [-n] [-f] ....." 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * If -n option is *not* set, send the metainit command *with -n set* to 520Sstevel@tonic-gate * all nodes first. Do this with MD_MSGF_STOP_ON_ERROR set. 530Sstevel@tonic-gate * That means if it fails on one node, it'll return immediately, 540Sstevel@tonic-gate * reporting the error. 550Sstevel@tonic-gate * By doing so, we have a dryrun first that has to succeed on every node 560Sstevel@tonic-gate * before we start the command for real. 570Sstevel@tonic-gate * This saves us from backing out a metainit command that succeeded on 580Sstevel@tonic-gate * some nodes but failed on one. 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate static int 610Sstevel@tonic-gate mn_send_command( 620Sstevel@tonic-gate mdsetname_t **spp, 630Sstevel@tonic-gate int argc, 640Sstevel@tonic-gate char **argv, 650Sstevel@tonic-gate mdcmdopts_t options, 660Sstevel@tonic-gate int flags, 670Sstevel@tonic-gate char *context, 680Sstevel@tonic-gate md_error_t *ep 690Sstevel@tonic-gate ) 700Sstevel@tonic-gate { 710Sstevel@tonic-gate int newargc; 720Sstevel@tonic-gate char **newargv; 730Sstevel@tonic-gate int i; 740Sstevel@tonic-gate int ret; 750Sstevel@tonic-gate int dryrun_only = 0; 760Sstevel@tonic-gate 770Sstevel@tonic-gate 780Sstevel@tonic-gate newargv = calloc(argc+5, sizeof (char *)); 790Sstevel@tonic-gate newargv[0] = "metainit"; 800Sstevel@tonic-gate newargv[1] = "-s"; 810Sstevel@tonic-gate newargv[2] = (*spp)->setname; 820Sstevel@tonic-gate newargv[3] = "-n"; /* always do "-n" first */ 830Sstevel@tonic-gate newargc = 4; 840Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) { 850Sstevel@tonic-gate dryrun_only = 1; 860Sstevel@tonic-gate } 870Sstevel@tonic-gate if ((options & MDCMD_FORCE) != 0) { 880Sstevel@tonic-gate newargv[newargc] = "-f"; 890Sstevel@tonic-gate newargc++; 900Sstevel@tonic-gate } 910Sstevel@tonic-gate for (i = 0; i < argc; i++, newargc++) 920Sstevel@tonic-gate newargv[newargc] = argv[i]; 930Sstevel@tonic-gate ret = meta_mn_send_command(*spp, newargc, newargv, 940Sstevel@tonic-gate flags | MD_DRYRUN | MD_NOLOG, context, ep); 950Sstevel@tonic-gate 960Sstevel@tonic-gate if ((dryrun_only == 0) && (ret == 0)) { 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * Do it for real now. Remove "-n" from the arguments and 990Sstevel@tonic-gate * MD_DRYRUN from the flags. If we fail this time the master 1000Sstevel@tonic-gate * must panic as the mddbs may be inconsistent. 1010Sstevel@tonic-gate */ 1020Sstevel@tonic-gate newargv[3] = ""; /* this was "-n" before */ 1030Sstevel@tonic-gate ret = meta_mn_send_command(*spp, newargc, newargv, 1040Sstevel@tonic-gate flags | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT, 1050Sstevel@tonic-gate context, ep); 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate free(newargv); 1090Sstevel@tonic-gate return (ret); 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate static int 1130Sstevel@tonic-gate init_entries( 1140Sstevel@tonic-gate mdsetname_t **spp, 1150Sstevel@tonic-gate md_tab_t *tabp, 1160Sstevel@tonic-gate mdcmdopts_t options, 1170Sstevel@tonic-gate uint_t flags, 1180Sstevel@tonic-gate bool_t called_thru_rpc, 1190Sstevel@tonic-gate md_error_t *ep 1200Sstevel@tonic-gate ) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate uint_t cnt = 0; 1230Sstevel@tonic-gate uint_t line; 1240Sstevel@tonic-gate int rval = 0; 1250Sstevel@tonic-gate int ret; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* for all matching entries, which haven't already been done */ 1280Sstevel@tonic-gate for (line = 0; (line < tabp->nlines); ++line) { 1290Sstevel@tonic-gate md_tab_line_t *linep = &tabp->lines[line]; 130*1623Stw21770 char *uname = linep->argv[0]; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* see if already done */ 1330Sstevel@tonic-gate if (linep->flags != DO_AGAIN) 1340Sstevel@tonic-gate continue; 1350Sstevel@tonic-gate 136*1623Stw21770 /* clear the metadev/hsp caches between inits */ 137*1623Stw21770 metaflushmetanames(); 138*1623Stw21770 1390Sstevel@tonic-gate /* try it */ 1400Sstevel@tonic-gate if ((called_thru_rpc == FALSE) && 141*1623Stw21770 meta_is_mn_name(spp, uname, ep)) { 1420Sstevel@tonic-gate /* 1430Sstevel@tonic-gate * MN set, send command to all nodes 1440Sstevel@tonic-gate * Note that is sp is NULL, meta_is_mn_name() derives 1450Sstevel@tonic-gate * sp from linep->argv which is the metadevice arg 1460Sstevel@tonic-gate */ 1470Sstevel@tonic-gate ret = mn_send_command(spp, linep->argc, linep->argv, 1480Sstevel@tonic-gate options, flags, linep->context, ep); 1490Sstevel@tonic-gate } else { 150*1623Stw21770 char *cname = NULL; 151*1623Stw21770 152*1623Stw21770 cname = meta_name_getname(spp, uname, META_DEVICE, ep); 153*1623Stw21770 if (cname == NULL) { 154*1623Stw21770 mde_perror(ep, ""); 155*1623Stw21770 mdclrerror(ep); 156*1623Stw21770 } else { 157*1623Stw21770 158*1623Stw21770 ret = meta_init_name(spp, linep->argc, 159*1623Stw21770 linep->argv, cname, options, ep); 160*1623Stw21770 Free(cname); 161*1623Stw21770 162*1623Stw21770 if (ret != 0) { 163*1623Stw21770 if (!(flags & MD_IGNORE_STDERR)) { 164*1623Stw21770 mderrorextra(ep, linep->context); 165*1623Stw21770 mde_perror(ep, ""); 166*1623Stw21770 rval = -1; 167*1623Stw21770 } 168*1623Stw21770 mdclrerror(ep); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate if (ret == 0) { 1730Sstevel@tonic-gate linep->flags = IS_DONE; 1740Sstevel@tonic-gate ++cnt; 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* return success */ 1790Sstevel@tonic-gate if (rval != 0) 1800Sstevel@tonic-gate return (rval); 1810Sstevel@tonic-gate return (cnt); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate /* 1850Sstevel@tonic-gate * initialize all devices in set 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate static int 1880Sstevel@tonic-gate init_all( 1890Sstevel@tonic-gate mdsetname_t **spp, 1900Sstevel@tonic-gate mdcmdopts_t options, 1910Sstevel@tonic-gate bool_t called_thru_rpc, 1920Sstevel@tonic-gate md_error_t *ep 1930Sstevel@tonic-gate ) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate md_tab_t *tabp = NULL; 1960Sstevel@tonic-gate size_t setlen; 1970Sstevel@tonic-gate uint_t more; 1980Sstevel@tonic-gate int done; 1990Sstevel@tonic-gate int eval = -1; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Only take the lock if this is not a MN set 2030Sstevel@tonic-gate * We can only enter this code for a MN set if we are the initiator 2040Sstevel@tonic-gate * and in this case, we don't want to take locks. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate if (meta_is_mn_set((*spp), ep) == 0) { 2070Sstevel@tonic-gate /* grab set lock */ 2080Sstevel@tonic-gate if (meta_lock(*spp, TRUE, ep)) { 2090Sstevel@tonic-gate mde_perror(ep, ""); 2100Sstevel@tonic-gate mdclrerror(ep); 2110Sstevel@tonic-gate return (eval); 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate /* check for ownership */ 2150Sstevel@tonic-gate if (meta_check_ownership(*spp, ep) != 0) { 2160Sstevel@tonic-gate mde_perror(ep, ""); 2170Sstevel@tonic-gate mdclrerror(ep); 2180Sstevel@tonic-gate return (eval); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* lock is held across init_entries */ 2220Sstevel@tonic-gate options |= MDCMD_NOLOCK; 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* get md.tab, preen entries */ 2260Sstevel@tonic-gate if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { 2270Sstevel@tonic-gate mde_perror(ep, ""); 2280Sstevel@tonic-gate mdclrerror(ep); 2290Sstevel@tonic-gate return (eval); 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 232*1623Stw21770 setlen = strlen((*spp)->setname); 2330Sstevel@tonic-gate for (more = 0; (more < tabp->nlines); ++more) { 2340Sstevel@tonic-gate md_tab_line_t *linep = &tabp->lines[more]; 2350Sstevel@tonic-gate char *cname = linep->cname; 2360Sstevel@tonic-gate char *p; 2370Sstevel@tonic-gate size_t len; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* better have args */ 2400Sstevel@tonic-gate assert((linep->argc > 0) && (linep->argv[0] != NULL)); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* only do metadevices and hotspare pools in set */ 2430Sstevel@tonic-gate if (linep->type & TAB_MD_HSP) { 2440Sstevel@tonic-gate if ((p = strrchr(cname, '/')) == NULL) { 2450Sstevel@tonic-gate len = 0; 2460Sstevel@tonic-gate } else { 2470Sstevel@tonic-gate len = p - cname; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate if ((len == setlen) && 2500Sstevel@tonic-gate (strncmp(cname, (*spp)->setname, len) == 0)) { 2510Sstevel@tonic-gate linep->flags = DO_AGAIN; 2520Sstevel@tonic-gate } else { 2530Sstevel@tonic-gate linep->flags = DONT_DO; 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate } else { 2570Sstevel@tonic-gate linep->flags = DONT_DO; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate eval = 1; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate /* while more devices get made */ 2640Sstevel@tonic-gate do { 2650Sstevel@tonic-gate done = init_entries(spp, tabp, options, 2660Sstevel@tonic-gate MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep); 2670Sstevel@tonic-gate } while (done > 0); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* now do it and report errors */ 2700Sstevel@tonic-gate if (init_entries(spp, tabp, options, MD_RETRY_BUSY, 2710Sstevel@tonic-gate called_thru_rpc, ep) >= 0) 2720Sstevel@tonic-gate eval = 0; /* success */ 2730Sstevel@tonic-gate mdclrerror(ep); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* cleanup, return success */ 2760Sstevel@tonic-gate out: 2770Sstevel@tonic-gate meta_tab_free(tabp); 2780Sstevel@tonic-gate return (eval); 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * initialize named device or hotspare pool 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate static int 2850Sstevel@tonic-gate init_name( 2860Sstevel@tonic-gate mdsetname_t **spp, 2870Sstevel@tonic-gate int argc, 2880Sstevel@tonic-gate char *argv[], 2890Sstevel@tonic-gate mdcmdopts_t options, 2900Sstevel@tonic-gate int called_thru_rpc, 2910Sstevel@tonic-gate md_error_t *ep 2920Sstevel@tonic-gate ) 2930Sstevel@tonic-gate { 2940Sstevel@tonic-gate md_tab_t *tabp = NULL; 2950Sstevel@tonic-gate md_tab_line_t *linep = NULL; 2960Sstevel@tonic-gate int rval = -1; 2970Sstevel@tonic-gate int ret; 298*1623Stw21770 char *uname = argv[0]; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* look in md.tab */ 3010Sstevel@tonic-gate if (argc == 1) { 3020Sstevel@tonic-gate /* get md.tab entries */ 3030Sstevel@tonic-gate if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { 3040Sstevel@tonic-gate if (! mdissyserror(ep, ENOENT)) 3050Sstevel@tonic-gate return (-1); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* look in md.tab */ 309*1623Stw21770 if ((linep = meta_tab_find(*spp, tabp, uname, TAB_MD_HSP)) 3100Sstevel@tonic-gate != NULL) { 3110Sstevel@tonic-gate argc = linep->argc; 3120Sstevel@tonic-gate argv = linep->argv; 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate if ((called_thru_rpc == FALSE) && 317*1623Stw21770 meta_is_mn_name(spp, uname, ep)) { 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * MN set, send command to all nodes 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate ret = mn_send_command(spp, argc, argv, options, 3220Sstevel@tonic-gate MD_DISP_STDERR, NO_CONTEXT_STRING, ep); 323*1623Stw21770 } else { 324*1623Stw21770 char *cname = NULL; 325*1623Stw21770 326*1623Stw21770 cname = meta_name_getname(spp, uname, META_DEVICE, ep); 327*1623Stw21770 if (cname == NULL) { 328*1623Stw21770 goto out; 329*1623Stw21770 } 330*1623Stw21770 331*1623Stw21770 /* check for ownership */ 332*1623Stw21770 if (meta_check_ownership(*spp, ep) != 0) { 333*1623Stw21770 Free(cname); 334*1623Stw21770 goto out; 335*1623Stw21770 } 336*1623Stw21770 337*1623Stw21770 ret = meta_init_name(spp, argc, argv, cname, options, ep); 338*1623Stw21770 Free(cname); 339*1623Stw21770 } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate if (ret != 0) { 3420Sstevel@tonic-gate if (linep != NULL) 3430Sstevel@tonic-gate mderrorextra(ep, linep->context); 3440Sstevel@tonic-gate goto out; 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate rval = 0; /* success */ 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate /* cleanup, return error */ 3490Sstevel@tonic-gate out: 3500Sstevel@tonic-gate if (tabp != NULL) 3510Sstevel@tonic-gate meta_tab_free(tabp); 3520Sstevel@tonic-gate return (rval); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * print usage message 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate static void 3590Sstevel@tonic-gate usage( 3600Sstevel@tonic-gate mdsetname_t *sp, 3610Sstevel@tonic-gate int eval 3620Sstevel@tonic-gate ) 3630Sstevel@tonic-gate { 3640Sstevel@tonic-gate #ifndef lint 3650Sstevel@tonic-gate (void) fprintf(stderr, gettext("\ 3660Sstevel@tonic-gate usage: %s [-s setname] [-n] [-f] concat/stripe numstripes\n\ 3670Sstevel@tonic-gate width component... [-i interlace]\n\ 3680Sstevel@tonic-gate [width component... [-i interlace]] [-h hotspare_pool]\n\ 3690Sstevel@tonic-gate %s [-s setname] [-n] [-f] mirror -m submirror...\n\ 3700Sstevel@tonic-gate [read_options] [write_options] [pass_num]\n\ 3710Sstevel@tonic-gate %s [-s setname] [-n] [-f] RAID -r component...\n\ 3720Sstevel@tonic-gate [-i interlace] [-h hotspare_pool]\n\ 3730Sstevel@tonic-gate [-k] [-o original_column_count]\n\ 3740Sstevel@tonic-gate %s [-s setname] [-n] [-f] hotspare_pool [hotspare...]\n\ 3750Sstevel@tonic-gate %s [-s setname] [-n] [-f] softpart -p [-A alignment]\n\ 3760Sstevel@tonic-gate [-e] device size|all\n\ 3770Sstevel@tonic-gate %s [-s setname] [-n] [-f] md.tab_entry\n\ 3780Sstevel@tonic-gate %s [-s setname] [-n] [-f] -a\n\ 3790Sstevel@tonic-gate %s -r\n"), myname, myname, myname, myname, myname, myname, myname, 3800Sstevel@tonic-gate myname); 3810Sstevel@tonic-gate #endif /* ! lint */ 3820Sstevel@tonic-gate md_exit(sp, eval); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate /* 3860Sstevel@tonic-gate * If we fail during the attempt to take the auto-take disksets 3870Sstevel@tonic-gate * we need to tell the kernel to cleanup the in-core set struct 3880Sstevel@tonic-gate * so that we have a chance to take the set again later. 3890Sstevel@tonic-gate */ 3900Sstevel@tonic-gate static void 3910Sstevel@tonic-gate auto_take_cleanup(mdsetname_t *sp, side_t sideno) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate mddb_config_t c; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate (void) memset(&c, 0, sizeof (c)); 3960Sstevel@tonic-gate c.c_setno = sp->setno; 3970Sstevel@tonic-gate c.c_sideno = sideno; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0) { 4000Sstevel@tonic-gate mde_perror(&c.c_mde, "auto_take_cleanup"); 4010Sstevel@tonic-gate return; 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* 4060Sstevel@tonic-gate * Take the diskset. 4070Sstevel@tonic-gate * 4080Sstevel@tonic-gate * This is a clean auto-take set, so do the work to take it. 4090Sstevel@tonic-gate * This is a streamlined version of the code in meta_set_take. We avoid the 4100Sstevel@tonic-gate * need for talking to the rpc.metad since that can't run this early during the 4110Sstevel@tonic-gate * boot. We don't need to talk to the metad for this diskset since we're the 4120Sstevel@tonic-gate * only host in the set. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate static void 4150Sstevel@tonic-gate take_set(md_set_record *sr) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate mdsetname_t sn; 4180Sstevel@tonic-gate md_drive_desc *dd; 4190Sstevel@tonic-gate md_error_t error = mdnullerror; 4200Sstevel@tonic-gate md_replicalist_t *rlp = NULL; 4210Sstevel@tonic-gate md_replicalist_t *rl; 4220Sstevel@tonic-gate daddr_t nblks = 0; 4230Sstevel@tonic-gate md_drive_record *dr; 4240Sstevel@tonic-gate side_t sideno; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * Several of the functions we call take a sp param so 4280Sstevel@tonic-gate * construct one from the set record. 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate sn.setname = sr->sr_setname; 4310Sstevel@tonic-gate sn.setno = sr->sr_setno; 4320Sstevel@tonic-gate sn.setdesc = sr2setdesc(sr); 4330Sstevel@tonic-gate sn.lockfd = MD_NO_LOCK; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (sr->sr_flags & MD_SR_MB_DEVID) 4360Sstevel@tonic-gate dd = metaget_drivedesc(&sn, MD_BASICNAME_OK | PRINT_FAST, 4370Sstevel@tonic-gate &error); 4380Sstevel@tonic-gate else 4390Sstevel@tonic-gate dd = metaget_drivedesc(&sn, MD_BASICNAME_OK, &error); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate if (dd == NULL) { 4420Sstevel@tonic-gate mde_perror(&error, ""); 4430Sstevel@tonic-gate mdclrerror(&error); 4440Sstevel@tonic-gate return; 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * Skip call to tk_own_bydd. This talks to rpc.metamhd (which we can't 4490Sstevel@tonic-gate * do yet) and is not needed for auto-take disksets since we are not 4500Sstevel@tonic-gate * doing SCSI reservations on these drives. 4510Sstevel@tonic-gate */ 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate if (setup_db_bydd(&sn, dd, 0, &error) != 0) { 4540Sstevel@tonic-gate if (! mdismddberror(&error, MDE_DB_ACCOK) && 4550Sstevel@tonic-gate ! mdismddberror(&error, MDE_DB_TAGDATA)) { 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * Skip call to rel_own_bydd since that really just 4580Sstevel@tonic-gate * calls rpc.metamhd which we don't need to do, 4590Sstevel@tonic-gate * so there really isn't anything to rollback here. 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate mde_perror(&error, ""); 4620Sstevel@tonic-gate mdclrerror(&error); 4630Sstevel@tonic-gate return; 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate mdclrerror(&error); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate if ((sideno = getmyside(&sn, &error)) == MD_SIDEWILD) { 4690Sstevel@tonic-gate mde_perror(&error, ""); 4700Sstevel@tonic-gate return; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate if (snarf_set(&sn, FALSE, &error) != 0) { 4740Sstevel@tonic-gate if (mdismddberror(&error, MDE_DB_STALE) || 4750Sstevel@tonic-gate mdismddberror(&error, MDE_DB_TAGDATA) || 4760Sstevel@tonic-gate ! mdismddberror(&error, MDE_DB_NODB) && 4770Sstevel@tonic-gate ! mdismddberror(&error, MDE_DB_NOTOWNER)) { 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * rollback 4800Sstevel@tonic-gate * Normally MDE_DB_STALE or MDE_DB_TAGDATA 4810Sstevel@tonic-gate * would still keep the set but in this case we don't 4820Sstevel@tonic-gate * want to do that. This will probably result in the 4830Sstevel@tonic-gate * boot going in to single-user since we won't have the 4840Sstevel@tonic-gate * set so any attempted mounts using the set's metadevices 4850Sstevel@tonic-gate * will fail. However, that is a "good thing" so the 4860Sstevel@tonic-gate * sysadmin can fix the set. Normally they would see 4870Sstevel@tonic-gate * all of these problems when they ran the take and be 4880Sstevel@tonic-gate * able to immediately fix the problem. 4890Sstevel@tonic-gate */ 4900Sstevel@tonic-gate mde_perror(&error, ""); 4910Sstevel@tonic-gate auto_take_cleanup(&sn, sideno); 4920Sstevel@tonic-gate return; 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* 4970Sstevel@tonic-gate * Call metareplicalist and upd_dr_dbinfo. 4980Sstevel@tonic-gate * Most of that code is only needed to synchronize amongst the multiple 4990Sstevel@tonic-gate * hosts in a set, which is not applicable in our case. But we do a 5000Sstevel@tonic-gate * subset here to handle the case when the user had been 5010Sstevel@tonic-gate * adding/deleting/balancing mddbs when this node panic'd. We are 5020Sstevel@tonic-gate * synchronizing the ondisk mddbs to the list of drive records stored 5030Sstevel@tonic-gate * in the local mddb. 5040Sstevel@tonic-gate */ 5050Sstevel@tonic-gate if (metareplicalist(&sn, (MD_BASICNAME_OK | PRINT_FAST), &rlp, &error) 5060Sstevel@tonic-gate < 0) { 5070Sstevel@tonic-gate /* rollback */ 5080Sstevel@tonic-gate mde_perror(&error, ""); 5090Sstevel@tonic-gate auto_take_cleanup(&sn, sideno); 5100Sstevel@tonic-gate return; 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * The following code is equivalent to upd_dr_dbinfo for syncronizing 5150Sstevel@tonic-gate * the local host only. That function is normally run through the 5160Sstevel@tonic-gate * metad with a local and daemon side but we'll do all of the work 5170Sstevel@tonic-gate * here. 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate /* find the smallest existing replica */ 5210Sstevel@tonic-gate for (rl = rlp; rl != NULL; rl = rl->rl_next) { 5220Sstevel@tonic-gate md_replica_t *r; 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate r = rl->rl_repp; 5250Sstevel@tonic-gate nblks = ((nblks == 0) ? r->r_nblk : min(r->r_nblk, nblks)); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate if (nblks <= 0) 5290Sstevel@tonic-gate nblks = MD_DBSIZE; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate for (dr = sr->sr_drivechain; dr; dr = dr->dr_next) { 5320Sstevel@tonic-gate int dbcnt; 5330Sstevel@tonic-gate mddrivename_t *dnp; 5340Sstevel@tonic-gate md_replicalist_t *rl; 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * The cname style for dnp and replica list will be same since 5380Sstevel@tonic-gate * both use the the same flags MD_BASICNAME_OK|PRINT_FAST which 5390Sstevel@tonic-gate * will always provide the cached value. 5400Sstevel@tonic-gate */ 5410Sstevel@tonic-gate if ((dnp = metadrivename_withdrkey(&sn, sideno, dr->dr_key, 5420Sstevel@tonic-gate MD_BASICNAME_OK | PRINT_FAST, &error)) == NULL) { 5430Sstevel@tonic-gate mde_perror(&error, ""); 5440Sstevel@tonic-gate metafreereplicalist(rlp); 5450Sstevel@tonic-gate auto_take_cleanup(&sn, sideno); 5460Sstevel@tonic-gate return; 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate dbcnt = 0; 5500Sstevel@tonic-gate /* see how many replicas are on this drive */ 5510Sstevel@tonic-gate for (rl = rlp; rl != NULL; rl = rl->rl_next) { 5520Sstevel@tonic-gate if (strcmp(rl->rl_repp->r_namep->drivenamep->cname, dnp->cname) 5530Sstevel@tonic-gate == 0) 5540Sstevel@tonic-gate dbcnt++; 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate /* Adjust the fields in the copy */ 5580Sstevel@tonic-gate dr->dr_dbcnt = dbcnt; 5590Sstevel@tonic-gate dr->dr_dbsize = dbcnt > 0 ? nblks : 0; 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate /* 5630Sstevel@tonic-gate * If the set doesn't have the MD_SR_MB_DEVID bit set, i.e 5640Sstevel@tonic-gate * the drives in the set don't have the device id information, 5650Sstevel@tonic-gate * then stick it in if possible. 5660Sstevel@tonic-gate * 5670Sstevel@tonic-gate * If updating the master block fails for whatever reason, it's 5680Sstevel@tonic-gate * okay. It just means the disk(s) in the diskset won't be self 5690Sstevel@tonic-gate * identifying. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate if (!(sr->sr_flags & MD_SR_MB_DEVID)) { 5720Sstevel@tonic-gate if (meta_update_mb(&sn, dd, &error) == 0) { 5730Sstevel@tonic-gate sr->sr_flags |= MD_SR_MB_DEVID; 5740Sstevel@tonic-gate mdclrerror(&error); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate commitset(sr, FALSE, &error); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate metafreereplicalist(rlp); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate /* 5830Sstevel@tonic-gate * This finishes up the logical equivalent of meta_set_take. 5840Sstevel@tonic-gate */ 5850Sstevel@tonic-gate if (meta_resync_all(&sn, MD_DEF_RESYNC_BUF_SIZE, &error) != 0) { 5860Sstevel@tonic-gate mde_perror(&error, ""); 5870Sstevel@tonic-gate mdclrerror(&error); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate /* 5920Sstevel@tonic-gate * Take the disksets that are marked to be taken at boot time. 5930Sstevel@tonic-gate */ 5940Sstevel@tonic-gate static void 5950Sstevel@tonic-gate auto_take_sets() 5960Sstevel@tonic-gate { 5970Sstevel@tonic-gate int max_sets; 5980Sstevel@tonic-gate int i; 5990Sstevel@tonic-gate md_error_t error = mdnullerror; 6000Sstevel@tonic-gate char *hostname; 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate if ((max_sets = get_max_sets(&error)) == 0) 6030Sstevel@tonic-gate return; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate if (!mdisok(&error)) { 6060Sstevel@tonic-gate mde_perror(&error, ""); 6070Sstevel@tonic-gate return; 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* set up so auto-take errors also go to syslog */ 6110Sstevel@tonic-gate openlog("metainit", LOG_ODELAY, LOG_USER); 6120Sstevel@tonic-gate metasyslog = 1; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate hostname = mynode(); 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate /* 6170Sstevel@tonic-gate * For each possible set number (skip set 0 which is the unnamed local 6180Sstevel@tonic-gate * set), see if we really have a diskset. If so, check if auto-take 6190Sstevel@tonic-gate * is enabled. 6200Sstevel@tonic-gate * 6210Sstevel@tonic-gate * In order to take the set it must have drives and it must not be 6220Sstevel@tonic-gate * stuck in mid-add. The sr_validate routine within rpc.metad will 6230Sstevel@tonic-gate * delete sets that are in mid-add when it runs. 6240Sstevel@tonic-gate */ 6250Sstevel@tonic-gate for (i = 1; i < max_sets; i++) { 6260Sstevel@tonic-gate md_set_record *sr; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate if ((sr = metad_getsetbynum(i, &error)) == NULL) { 6290Sstevel@tonic-gate mdclrerror(&error); 6300Sstevel@tonic-gate continue; 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if (sr->sr_flags & MD_SR_AUTO_TAKE && !(sr->sr_flags & MD_SR_ADD)) { 6340Sstevel@tonic-gate int j; 6350Sstevel@tonic-gate int cnt = 0; 6360Sstevel@tonic-gate int host_mismatch = 0; 6370Sstevel@tonic-gate int take = 0; 6380Sstevel@tonic-gate md_drive_record *dr; 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /* check for host renames or multiple hosts in set */ 6410Sstevel@tonic-gate for (j = 0; j < MD_MAXSIDES; j++) { 6420Sstevel@tonic-gate /* Skip empty slots */ 6430Sstevel@tonic-gate if (sr->sr_nodes[j][0] == '\0') 6440Sstevel@tonic-gate continue; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate cnt++; 6470Sstevel@tonic-gate if (strcmp(sr->sr_nodes[j], hostname) != 0) 6480Sstevel@tonic-gate host_mismatch = 1; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* paranoid check that we're the only host in the set */ 6520Sstevel@tonic-gate if (cnt > 1) { 6530Sstevel@tonic-gate md_eprintf(gettext( 6540Sstevel@tonic-gate "diskset %s: auto-take enabled and multiple hosts in set\n"), 6550Sstevel@tonic-gate sr->sr_setname); 6560Sstevel@tonic-gate continue; 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate if (host_mismatch) { 6600Sstevel@tonic-gate /* The host was renamed, repair the set. */ 6610Sstevel@tonic-gate for (j = 0; j < MD_MAXSIDES; j++) { 6620Sstevel@tonic-gate /* Skip empty slots */ 6630Sstevel@tonic-gate if (sr->sr_nodes[j][0] == '\0') 6640Sstevel@tonic-gate continue; 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate (void) strncpy(sr->sr_nodes[j], hostname, 6670Sstevel@tonic-gate sizeof (sr->sr_nodes[j])); 6680Sstevel@tonic-gate commitset(sr, FALSE, &error); 6690Sstevel@tonic-gate if (!mdisok(&error)) { 6700Sstevel@tonic-gate mde_perror(&error, ""); 6710Sstevel@tonic-gate mdclrerror(&error); 6720Sstevel@tonic-gate } else { 6730Sstevel@tonic-gate md_eprintf(gettext( 6740Sstevel@tonic-gate "new hostname %s, update auto-take diskset %s\n"), 6750Sstevel@tonic-gate hostname, sr->sr_setname); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate break; 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate /* set must have at least one drive to be taken */ 6820Sstevel@tonic-gate for (dr = sr->sr_drivechain; dr != NULL; dr = dr->dr_next) { 6830Sstevel@tonic-gate /* ignore drives in mid-add */ 6840Sstevel@tonic-gate if (!(dr->dr_flags & MD_DR_ADD)) { 6850Sstevel@tonic-gate take = 1; 6860Sstevel@tonic-gate break; 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate if (take) 6910Sstevel@tonic-gate take_set(sr); 6920Sstevel@tonic-gate else 6930Sstevel@tonic-gate md_eprintf(gettext( 6940Sstevel@tonic-gate "diskset %s: auto-take enabled but set has no drives\n"), 6950Sstevel@tonic-gate sr->sr_setname); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * mainline. crack command line arguments. 7020Sstevel@tonic-gate */ 7030Sstevel@tonic-gate int 7040Sstevel@tonic-gate main( 7050Sstevel@tonic-gate int argc, 7060Sstevel@tonic-gate char *argv[] 7070Sstevel@tonic-gate ) 7080Sstevel@tonic-gate { 709*1623Stw21770 char *sname = MD_LOCAL_NAME; 7100Sstevel@tonic-gate mdsetname_t *sp = NULL; 7110Sstevel@tonic-gate enum action { 7120Sstevel@tonic-gate NONE, 7130Sstevel@tonic-gate INIT, 7140Sstevel@tonic-gate ALL 7150Sstevel@tonic-gate } todo = NONE; 7160Sstevel@tonic-gate mdcmdopts_t options = (MDCMD_DOIT | MDCMD_PRINT); 7170Sstevel@tonic-gate int c; 7180Sstevel@tonic-gate md_error_t status = mdnullerror; 7190Sstevel@tonic-gate md_error_t *ep = &status; 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate md_error_t dummystatus = mdnullerror; 7220Sstevel@tonic-gate md_error_t *dummyep = &dummystatus; 7230Sstevel@tonic-gate int eval = 1; 7240Sstevel@tonic-gate int error; 7250Sstevel@tonic-gate bool_t called_thru_rpc = FALSE; 7260Sstevel@tonic-gate char *cp; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate /* 7290Sstevel@tonic-gate * Get the locale set up before calling any other routines 7300Sstevel@tonic-gate * with messages to ouput. Just in case we're not in a build 7310Sstevel@tonic-gate * environment, make sure that TEXT_DOMAIN gets set to 7320Sstevel@tonic-gate * something. 7330Sstevel@tonic-gate */ 7340Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 7350Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 7360Sstevel@tonic-gate #endif 7370Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 7380Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 7390Sstevel@tonic-gate if ((cp = strstr(argv[0], ".rpc_call")) != NULL) { 7400Sstevel@tonic-gate *cp = '\0'; /* cut off ".rpc_call" */ 7410Sstevel@tonic-gate called_thru_rpc = TRUE; 7420Sstevel@tonic-gate } else { 7430Sstevel@tonic-gate if (sdssc_bind_library() == SDSSC_OKAY) 7440Sstevel@tonic-gate if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 7450Sstevel@tonic-gate &error) == SDSSC_PROXY_DONE) 7460Sstevel@tonic-gate exit(error); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate /* initialize */ 7500Sstevel@tonic-gate if (md_init(argc, argv, 0, 1, ep) != 0 || 7510Sstevel@tonic-gate meta_check_root(ep) != 0) { 7520Sstevel@tonic-gate mde_perror(ep, ""); 7530Sstevel@tonic-gate md_exit(sp, 1); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* parse args */ 7570Sstevel@tonic-gate optind = 1; 7580Sstevel@tonic-gate opterr = 1; 7590Sstevel@tonic-gate while ((c = getopt(argc, argv, "afhnrs:?")) != -1) { 7600Sstevel@tonic-gate switch (c) { 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate /* help */ 7630Sstevel@tonic-gate case 'h': 7640Sstevel@tonic-gate usage(sp, 0); 7650Sstevel@tonic-gate break; 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate /* set name */ 7680Sstevel@tonic-gate case 's': 7690Sstevel@tonic-gate sname = optarg; 7700Sstevel@tonic-gate break; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* all devices in md.tab */ 7730Sstevel@tonic-gate case 'a': 7740Sstevel@tonic-gate if (todo != NONE) 7750Sstevel@tonic-gate usage(sp, 1); 7760Sstevel@tonic-gate todo = ALL; 7770Sstevel@tonic-gate options |= MDCMD_ALLOPTION; 7780Sstevel@tonic-gate break; 7790Sstevel@tonic-gate /* check for validity, but don't really init */ 7800Sstevel@tonic-gate case 'n': 7810Sstevel@tonic-gate options &= ~MDCMD_DOIT; 7820Sstevel@tonic-gate break; 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate /* for recovery */ 7850Sstevel@tonic-gate case 'r': 7860Sstevel@tonic-gate if (todo != NONE) 7870Sstevel@tonic-gate usage(sp, 1); 7880Sstevel@tonic-gate todo = INIT; 7890Sstevel@tonic-gate break; 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate /* mounted and swapped components are OK */ 7920Sstevel@tonic-gate case 'f': 7930Sstevel@tonic-gate options |= MDCMD_FORCE; 7940Sstevel@tonic-gate break; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate case '?': 7970Sstevel@tonic-gate if (optopt == '?') 7980Sstevel@tonic-gate usage(sp, 0); 7990Sstevel@tonic-gate /*FALLTHROUGH*/ 8000Sstevel@tonic-gate default: 8010Sstevel@tonic-gate usage(sp, 1); 8020Sstevel@tonic-gate break; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 806*1623Stw21770 /* sname is MD_LOCAL_NAME if not specified on the command line */ 807*1623Stw21770 if ((sp = metasetname(sname, ep)) == NULL) { 808*1623Stw21770 mde_perror(ep, ""); 809*1623Stw21770 md_exit(sp, 1); 8100Sstevel@tonic-gate } 811*1623Stw21770 8120Sstevel@tonic-gate argc -= optind; 8130Sstevel@tonic-gate argv += optind; 8140Sstevel@tonic-gate if (todo == NONE) { 8150Sstevel@tonic-gate if (argc <= 0) { 8160Sstevel@tonic-gate usage(sp, 1); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate } else if (argc > 0) { 8190Sstevel@tonic-gate usage(sp, 1); 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* setup database locations */ 8240Sstevel@tonic-gate if (meta_setup_db_locations(ep) != 0) { 8250Sstevel@tonic-gate mde_perror(ep, ""); 8260Sstevel@tonic-gate if (mdismddberror(ep, MDE_DB_STALE)) 8270Sstevel@tonic-gate md_exit(sp, 66); 8280Sstevel@tonic-gate if (! mdiserror(ep, MDE_MDDB_CKSUM)) /* relatively benign */ 8290Sstevel@tonic-gate md_exit(sp, 1); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate if (todo == INIT) { /* load and take auto-take sets */ 8320Sstevel@tonic-gate auto_take_sets(); 8330Sstevel@tonic-gate md_exit(sp, 0); 8340Sstevel@tonic-gate } else if (todo == ALL) { /* initialize all devices in md.tab */ 8350Sstevel@tonic-gate eval = init_all(&sp, options, called_thru_rpc, ep); 8360Sstevel@tonic-gate } else { /* initialize the named device */ 8370Sstevel@tonic-gate eval = 0; 8380Sstevel@tonic-gate if (init_name(&sp, argc, argv, options, called_thru_rpc, 8390Sstevel@tonic-gate ep) != 0) { 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * If we're dealing with MN metadevices and we are 8420Sstevel@tonic-gate * directly called, then the appropriate error message 8430Sstevel@tonic-gate * has already been displayed. So just exit. 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate if (meta_is_mn_set(sp, dummyep) && (!called_thru_rpc)) { 8460Sstevel@tonic-gate md_exit(sp, 1); 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate mde_perror(ep, ""); 8490Sstevel@tonic-gate mdclrerror(ep); 8500Sstevel@tonic-gate eval = 1; 8510Sstevel@tonic-gate goto nomdcf; 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate domdcf: 8560Sstevel@tonic-gate /* update md.cf, return success */ 8570Sstevel@tonic-gate if (meta_update_md_cf(sp, ep) != 0) { 8580Sstevel@tonic-gate mde_perror(ep, ""); 8590Sstevel@tonic-gate eval = 1; 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate nomdcf: 8630Sstevel@tonic-gate md_exit(sp, eval); 8640Sstevel@tonic-gate /*NOTREACHED*/ 8650Sstevel@tonic-gate return (eval); 8660Sstevel@tonic-gate } 867