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