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 (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Metadevice diskset utility. 27 */ 28 29 #include <meta.h> 30 #include <sys/lvm/md_mddb.h> 31 #include <sdssc.h> 32 33 enum metaset_cmd { 34 notspecified, 35 add, 36 balance, 37 delete, 38 cluster, 39 isowner, 40 purge, 41 query, 42 release, 43 take, 44 join, /* Join a multinode diskset */ 45 withdraw /* Withdraw from a multinode diskset */ 46 }; 47 48 enum cluster_cmd { 49 ccnotspecified, 50 clusterversion, /* Return the version of the cluster I/F */ 51 clusterdisksin, /* List disks in a given diskset */ 52 clustertake, /* back door for Cluster take */ 53 clusterrelease, /* ditto */ 54 clusterpurge, /* back door for Cluster purge */ 55 clusterproxy /* proxy the args after '--' to primary */ 56 }; 57 58 static void 59 usage( 60 mdsetname_t *sp, 61 char *string) 62 { 63 if ((string != NULL) && (*string != '\0')) 64 md_eprintf("%s\n", string); 65 (void) fprintf(stderr, gettext( 66 "usage:\t%s -s setname -a [-A enable | disable] -h hostname ...\n" 67 " %s -s setname -a [-M] -h hostname ...\n" 68 " %s -s setname -a [-M] [-l length] [-L] drivename ...\n" 69 " %s -s setname -d [-M] -h hostname ...\n" 70 " %s -s setname -d [-M] -f -h all-hostnames\n" 71 " %s -s setname -d [-M] [-f] drivename ...\n" 72 " %s -s setname -d [-M] [-f] hostname ...\n" 73 " %s -s setname -A enable | disable\n" 74 " %s -s setname -t [-f]\n" 75 " %s -s setname -r\n" 76 " %s [-s setname] -j [-M]\n" 77 " %s [-s setname] -w [-M]\n" 78 " %s -s setname -P [-M]\n" 79 " %s -s setname -b [-M]\n" 80 " %s -s setname -o [-M] [-h hostname]\n" 81 " %s [-s setname]\n" 82 "\n" 83 " hostname = contents of /etc/nodename\n" 84 " drivename = cNtNdN no slice\n" 85 " [-M] for multi-owner set is optional except" 86 " on set creation\n"), 87 myname, myname, myname, myname, myname, myname, myname, myname, 88 myname, myname, myname, myname, myname, myname, myname, myname); 89 md_exit(sp, (string == NULL) ? 0 : 1); 90 } 91 92 /* 93 * The svm.sync rc script relies heavily on the metaset output. 94 * Any changes to the metaset output MUST verify that the rc script 95 * does not break. Not doing so may potentially leave the system 96 * unusable. You have been WARNED. 97 */ 98 static int 99 printset(mdsetname_t *sp, md_error_t *ep) 100 { 101 int i, j; 102 md_set_desc *sd; 103 md_drive_desc *dd, *p; 104 int max_meds; 105 md_mnnode_desc *nd; 106 107 if ((sd = metaget_setdesc(sp, ep)) == NULL) 108 return (-1); 109 110 /* 111 * Only get set owner information for traditional diskset. 112 * This set owner information is stored in the node records 113 * for a MN diskset. 114 */ 115 if (!(MD_MNSET_DESC(sd))) { 116 if (metaget_setownership(sp, ep) == -1) 117 return (-1); 118 } 119 120 if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST), 121 ep)) == NULL) && !mdisok(ep)) 122 return (-1); 123 124 if (MD_MNSET_DESC(sd)) { 125 (void) printf(gettext( 126 "\nMulti-owner Set name = %s, Set number = %d, Master = %s\n"), 127 sp->setname, sp->setno, sd->sd_mn_master_nodenm); 128 if ((sd->sd_mn_master_nodeid == MD_MN_INVALID_NID) && 129 (dd != NULL)) { 130 (void) printf(gettext( 131 "Master and owner information unavailable " 132 "until joined (metaset -j)\n")); 133 } 134 } else { 135 (void) printf(gettext( 136 "\nSet name = %s, Set number = %d\n"), 137 sp->setname, sp->setno); 138 } 139 140 if (MD_MNSET_DESC(sd)) { 141 (void) printf(gettext("\n%-19.19s %-14.14s %-6.6s\n"), 142 gettext("Host"), gettext("Owner"), gettext("Member")); 143 nd = sd->sd_nodelist; 144 while (nd) { 145 /* 146 * Don't print nodes that aren't ok since they may be 147 * removed from config during a reconfig cycle. If a 148 * node was being added to a diskset and the entire 149 * cluster went down but the node being added was unable 150 * to reboot, there's no way to know if that node had 151 * its own node record set to OK or not. So, node 152 * record is left in ADD state during reconfig cycle. 153 * When that node reboots and returns to the cluster, 154 * the reconfig cycle will either remove the node 155 * record (if not marked OK on that node) or will mark 156 * it OK on all nodes. 157 * It is very important to only remove a node record 158 * from the other nodes when that node record is not 159 * marked OK on its own node - otherwise, different 160 * nodes would have different nodelists possibly 161 * causing different nodes to to choose different 162 * masters. 163 * 164 * Standard hostname field is 17 bytes but metaset 165 * will display up to MD_MAX_NODENAME, defined in 166 * meta_basic.h 167 */ 168 if (!(nd->nd_flags & MD_MN_NODE_OK)) { 169 nd = nd->nd_next; 170 continue; 171 } 172 if ((nd->nd_flags & MD_MN_NODE_ALIVE) && 173 (nd->nd_flags & MD_MN_NODE_OWN)) { 174 (void) printf( 175 gettext(" %-17.*s %-12.12s %-4.4s\n"), 176 MD_MAX_NODENAME, 177 nd->nd_nodename, gettext("multi-owner"), 178 gettext("Yes")); 179 } else if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) && 180 (nd->nd_flags & MD_MN_NODE_OWN)) { 181 /* Should never be able to happen */ 182 (void) printf( 183 gettext(" %-17.*s %-12.12s %-4.4s\n"), 184 MD_MAX_NODENAME, 185 nd->nd_nodename, gettext("multi-owner"), 186 gettext("No")); 187 } else if ((nd->nd_flags & MD_MN_NODE_ALIVE) && 188 (!(nd->nd_flags & MD_MN_NODE_OWN))) { 189 (void) printf( 190 gettext(" %-17.*s %-12.12s %-4.4s\n"), 191 MD_MAX_NODENAME, 192 nd->nd_nodename, gettext(""), 193 gettext("Yes")); 194 } else if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) && 195 (!(nd->nd_flags & MD_MN_NODE_OWN))) { 196 (void) printf( 197 gettext(" %-17.*s %-12.12s %-4.4s\n"), 198 MD_MAX_NODENAME, 199 nd->nd_nodename, gettext(""), 200 gettext("No")); 201 } 202 nd = nd->nd_next; 203 } 204 } else { 205 (void) printf("\n%-19.19s %-5.5s\n", 206 gettext("Host"), gettext("Owner")); 207 for (i = 0; i < MD_MAXSIDES; i++) { 208 /* Skip empty slots */ 209 if (sd->sd_nodes[i][0] == '\0') 210 continue; 211 212 /* 213 * Standard hostname field is 17 bytes but metaset will 214 * display up to MD_MAX_NODENAME, def in meta_basic.h 215 */ 216 (void) printf(" %-17.*s %s\n", MD_MAX_NODENAME, 217 sd->sd_nodes[i], (sd->sd_flags & MD_SR_AUTO_TAKE ? 218 (sd->sd_isown[i] ? gettext("Yes (auto)") : 219 gettext("No (auto)")) 220 : (sd->sd_isown[i] ? gettext("Yes") : ""))); 221 } 222 } 223 224 if (sd->sd_med.n_cnt > 0) 225 (void) printf("\n%-19.19s %-7.7s\n", 226 gettext("Mediator Host(s)"), gettext("Aliases")); 227 228 if ((max_meds = get_max_meds(ep)) == 0) 229 return (-1); 230 231 for (i = 0; i < max_meds; i++) { 232 if (sd->sd_med.n_lst[i].a_cnt == 0) 233 continue; 234 /* 235 * Standard hostname field is 17 bytes but metaset will 236 * display up to MD_MAX_NODENAME, def in meta_basic.h 237 */ 238 (void) printf(" %-17.*s ", MD_MAX_NODENAME, 239 sd->sd_med.n_lst[i].a_nm[0]); 240 for (j = 1; j < sd->sd_med.n_lst[i].a_cnt; j++) { 241 (void) printf("%s", sd->sd_med.n_lst[i].a_nm[j]); 242 if (sd->sd_med.n_lst[i].a_cnt - j > 1) 243 (void) printf(gettext(", ")); 244 } 245 (void) printf("\n"); 246 } 247 248 if (dd) { 249 int len = 0; 250 251 252 /* 253 * Building a format string on the fly that will 254 * be used in (f)printf. This allows the length 255 * of the ctd to vary from small to large without 256 * looking horrible. 257 */ 258 for (p = dd; p != NULL; p = p->dd_next) 259 len = max(len, strlen(p->dd_dnp->cname)); 260 261 len += 2; 262 (void) printf("\n%-*.*s %-5.5s\n", len, len, 263 gettext("Drive"), 264 gettext("Dbase")); 265 for (p = dd; p != NULL; p = p->dd_next) { 266 (void) printf("\n%-*.*s %-5.5s\n", len, len, 267 p->dd_dnp->cname, 268 (p->dd_dbcnt ? gettext("Yes") : 269 gettext("No"))); 270 } 271 } 272 273 return (0); 274 } 275 276 static int 277 printsets(mdsetname_t *sp, md_error_t *ep) 278 { 279 int i; 280 mdsetname_t *sp1; 281 set_t max_sets; 282 283 /* 284 * print setname given. 285 */ 286 if (! metaislocalset(sp)) { 287 if (printset(sp, ep)) 288 return (-1); 289 return (0); 290 } 291 292 if ((max_sets = get_max_sets(ep)) == 0) 293 return (-1); 294 295 /* 296 * Print all known sets 297 */ 298 for (i = 1; i < max_sets; i++) { 299 if ((sp1 = metasetnosetname(i, ep)) == NULL) { 300 if (! mdiserror(ep, MDE_NO_SET)) 301 break; 302 mdclrerror(ep); 303 continue; 304 } 305 306 if (printset(sp1, ep)) 307 break; 308 } 309 if (! mdisok(ep)) 310 return (-1); 311 312 return (0); 313 } 314 315 /* 316 * Print the current versionn of the cluster contract private interface. 317 */ 318 static void 319 printclusterversion() 320 { 321 (void) printf("%s\n", METASETIFVERSION); 322 } 323 324 /* 325 * Print the disks that make up the given disk set. This is used 326 * exclusively by Sun Cluster and is contract private. 327 * Should never be called with sname of a Multinode diskset. 328 */ 329 static int 330 printdisksin(char *sname, md_error_t *ep) 331 { 332 mdsetname_t *sp; 333 md_drive_desc *dd, *p; 334 335 if ((sp = metasetname(sname, ep)) == NULL) { 336 337 /* 338 * During a deletion of a set the associated service is 339 * put offline. The SC3.0 reservation code calls disksuite 340 * to find a list of disks associated with the set so that 341 * it can release the reservation on those disks. In this 342 * case there won't be any disks or even a set left. So just 343 * return. 344 */ 345 return (0); 346 } 347 348 if (metaget_setownership(sp, ep) == -1) 349 return (-1); 350 351 if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST), 352 ep)) == NULL) && !mdisok(ep)) 353 return (-1); 354 355 for (p = dd; p != NULL; p = p->dd_next) 356 (void) printf("%s\n", p->dd_dnp->rname); 357 358 return (0); 359 } 360 361 static void 362 parse_printset(int argc, char **argv) 363 { 364 int c; 365 mdsetname_t *sp = NULL; 366 char *sname = MD_LOCAL_NAME; 367 md_error_t status = mdnullerror; 368 md_error_t *ep = &status; 369 370 /* reset and parse args */ 371 optind = 1; 372 opterr = 1; 373 while ((c = getopt(argc, argv, "s:")) != -1) { 374 switch (c) { 375 case 's': 376 sname = optarg; 377 break; 378 default: 379 usage(sp, gettext("unknown options")); 380 } 381 } 382 383 argc -= optind; 384 argv += optind; 385 386 if (argc != 0) 387 usage(sp, gettext("too many args")); 388 389 if ((sp = metasetname(sname, ep)) == NULL) { 390 mde_perror(ep, ""); 391 md_exit(sp, 1); 392 } 393 394 if (printsets(sp, ep) && !mdiserror(ep, MDE_SMF_NO_SERVICE)) { 395 mde_perror(ep, ""); 396 md_exit(sp, 1); 397 } 398 399 if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) { 400 mde_perror(ep, ""); 401 md_exit(sp, 1); 402 } 403 404 md_exit(sp, 0); 405 } 406 407 static void 408 parse_add(int argc, char **argv) 409 { 410 int c, created_set; 411 int hosts = FALSE; 412 int meds = FALSE; 413 int auto_take = FALSE; 414 int force_label = FALSE; 415 int default_size = TRUE; 416 mdsetname_t *sp = NULL; 417 char *sname = MD_LOCAL_NAME; 418 md_error_t status = mdnullerror; 419 md_error_t *ep = &status; 420 mddrivenamelist_t *dnlp = NULL; 421 mddrivenamelist_t *p; 422 daddr_t dbsize, nblks; 423 mdsetname_t *local_sp = NULL; 424 int multi_node = 0; 425 md_set_desc *sd; 426 rval_e sdssc_rval; 427 428 /* reset and parse args */ 429 optind = 1; 430 opterr = 1; 431 while ((c = getopt(argc, argv, "MaA:hl:Lms:")) != -1) { 432 switch (c) { 433 case 'M': 434 multi_node = 1; 435 break; 436 case 'A': 437 /* verified sub-option in main */ 438 if (strcmp(optarg, "enable") == 0) 439 auto_take = TRUE; 440 break; 441 case 'a': 442 break; 443 case 'h': 444 case 'm': 445 if (meds == TRUE || hosts == TRUE) 446 usage(sp, gettext( 447 "only one -m or -h option allowed")); 448 449 if (default_size == FALSE || force_label == TRUE) 450 usage(sp, gettext( 451 "conflicting options")); 452 453 if (c == 'h') 454 hosts = TRUE; 455 else 456 meds = TRUE; 457 break; 458 case 'l': 459 if (hosts == TRUE || meds == TRUE) 460 usage(sp, gettext( 461 "conflicting options")); 462 if (sscanf(optarg, "%ld", &dbsize) != 1) { 463 md_eprintf(gettext( 464 "%s: bad format\n"), optarg); 465 usage(sp, ""); 466 } 467 468 default_size = FALSE; 469 break; 470 case 'L': 471 /* Same criteria as -l */ 472 if (hosts == TRUE || meds == TRUE) 473 usage(sp, gettext( 474 "conflicting options")); 475 force_label = TRUE; 476 break; 477 case 's': 478 sname = optarg; 479 break; 480 default: 481 usage(sp, gettext( 482 "unknown options")); 483 } 484 } 485 486 /* Can only use -A enable when creating the single-node set */ 487 if (auto_take && hosts != TRUE) 488 usage(sp, gettext("conflicting options")); 489 490 argc -= optind; 491 argv += optind; 492 493 /* 494 * Add hosts 495 */ 496 if (hosts == TRUE) { 497 498 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 499 mde_perror(ep, ""); 500 md_exit(local_sp, 1); 501 } 502 503 if (meta_lock(local_sp, TRUE, ep) != 0) { 504 mde_perror(ep, ""); 505 md_exit(local_sp, 1); 506 } 507 508 /* 509 * Keep track of Cluster set creation. Need to complete 510 * the transaction no matter if the set was created or not. 511 */ 512 created_set = 0; 513 514 /* 515 * Have no set, cannot take the lock, so only take the 516 * local lock. 517 */ 518 if ((sp = metasetname(sname, ep)) == NULL) { 519 sdssc_rval = 0; 520 if (multi_node) { 521 /* 522 * When running on a cluster system that 523 * does not support MN disksets, the routine 524 * sdssc_mo_create_begin will be bound 525 * to the SVM routine not_bound_error 526 * which returns SDSSC_NOT_BOUND_ERROR. 527 * 528 * When running on a cluster system that 529 * does support MN disksets, the routine 530 * sdssc_mo_create_begin will be bound to 531 * the sdssc_mo_create_begin routine in 532 * library libsdssc_so. A call to 533 * sdssc_mo_create_begin will return with 534 * either SDSSC_ERROR or SDSSC_OKAY. If 535 * an SDSSC_OKAY is returned, then the 536 * cluster framework has allocated a 537 * set number for this new set that is unique 538 * across traditional and MN disksets. 539 * Libmeta will get this unique set number 540 * by calling sdssc_get_index. 541 * 542 * When running on a non-cluster system, 543 * the routine sdssc_mo_create_begin 544 * will be bound to the SVM routine 545 * not_bound which returns SDSSC_NOT_BOUND. 546 * In this case, all sdssc routines will 547 * return SDSSC_NOT_BOUND. No need to check 548 * for return value of SDSSC_NOT_BOUND since 549 * the libmeta call to get the set number 550 * (sdssc_get_index) will also fail with 551 * SDSSC_NOT_BOUND causing libmeta to 552 * determine its own set number. 553 */ 554 sdssc_rval = sdssc_mo_create_begin(sname, argc, 555 argv, SDSSC_PICK_SETNO); 556 if (sdssc_rval == SDSSC_NOT_BOUND_ERROR) { 557 (void) mderror(ep, MDE_NOT_MN, NULL); 558 mde_perror(ep, 559 "Cluster node does not support " 560 "multi-owner diskset operations"); 561 md_exit(local_sp, 1); 562 } else if (sdssc_rval == SDSSC_ERROR) { 563 mde_perror(ep, ""); 564 md_exit(local_sp, 1); 565 } 566 } else { 567 sdssc_rval = sdssc_create_begin(sname, argc, 568 argv, SDSSC_PICK_SETNO); 569 if (sdssc_rval == SDSSC_ERROR) { 570 mde_perror(ep, ""); 571 md_exit(local_sp, 1); 572 } 573 } 574 /* 575 * Created diskset (as opposed to adding a 576 * host to an existing diskset). 577 */ 578 created_set = 1; 579 580 sp = Zalloc(sizeof (*sp)); 581 sp->setname = Strdup(sname); 582 sp->lockfd = MD_NO_LOCK; 583 mdclrerror(ep); 584 } else { 585 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 586 mde_perror(ep, ""); 587 md_exit(local_sp, 1); 588 } 589 if (MD_MNSET_DESC(sd)) { 590 multi_node = 1; 591 } 592 593 /* 594 * can't add hosts to an existing set & enable 595 * auto-take 596 */ 597 if (auto_take) 598 usage(sp, gettext("conflicting options")); 599 600 /* 601 * Have a valid set, take the set lock also. 602 * 603 * A MN diskset does not use the set meta_lock but 604 * instead uses the clnt_lock of rpc.metad and the 605 * suspend/resume feature of the rpc.mdcommd. Can't 606 * use set meta_lock since class 1 messages are 607 * grabbing this lock and if this thread is holding 608 * the set meta_lock then no rpc.mdcommd suspend 609 * can occur. 610 */ 611 if (!multi_node) { 612 if (meta_lock(sp, TRUE, ep) != 0) { 613 mde_perror(ep, ""); 614 md_exit(local_sp, 1); 615 } 616 } 617 } 618 619 if (meta_set_addhosts(sp, multi_node, argc, argv, auto_take, 620 ep)) { 621 if (created_set) 622 sdssc_create_end(sname, SDSSC_CLEANUP); 623 mde_perror(&status, ""); 624 if (!multi_node) 625 (void) meta_unlock(sp, ep); 626 md_exit(local_sp, 1); 627 } 628 629 if (created_set) 630 sdssc_create_end(sname, SDSSC_COMMIT); 631 632 else { 633 /* 634 * If adding hosts to existing diskset, 635 * call DCS svcs 636 */ 637 sdssc_add_hosts(sname, argc, argv); 638 } 639 if (!multi_node) 640 (void) meta_unlock(sp, ep); 641 md_exit(local_sp, 0); 642 } 643 644 /* 645 * Add mediators 646 */ 647 if (meds == TRUE) { 648 649 if ((sp = metasetname(sname, ep)) == NULL) { 650 mde_perror(ep, ""); 651 md_exit(local_sp, 1); 652 } 653 654 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 655 mde_perror(ep, ""); 656 md_exit(local_sp, 1); 657 } 658 659 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 660 mde_perror(ep, ""); 661 md_exit(local_sp, 1); 662 } 663 if (MD_MNSET_DESC(sd)) { 664 multi_node = 1; 665 } 666 667 if (meta_lock(local_sp, TRUE, ep) != 0) { 668 mde_perror(ep, ""); 669 md_exit(local_sp, 1); 670 } 671 /* 672 * A MN diskset does not use the set meta_lock but 673 * instead uses the clnt_lock of rpc.metad and the 674 * suspend/resume feature of the rpc.mdcommd. Can't 675 * use set meta_lock since class 1 messages are 676 * grabbing this lock and if this thread is holding 677 * the set meta_lock then no rpc.mdcommd suspend 678 * can occur. 679 */ 680 if (!multi_node) { 681 if (meta_lock(sp, TRUE, ep) != 0) { 682 mde_perror(ep, ""); 683 md_exit(local_sp, 1); 684 } 685 } 686 687 if (meta_set_addmeds(sp, argc, argv, ep)) { 688 mde_perror(&status, ""); 689 if (!multi_node) 690 (void) meta_unlock(sp, ep); 691 md_exit(local_sp, 1); 692 } 693 694 if (!multi_node) 695 (void) meta_unlock(sp, ep); 696 md_exit(local_sp, 0); 697 } 698 699 /* 700 * Add drives 701 */ 702 if ((sp = metasetname(sname, ep)) == NULL) { 703 mde_perror(ep, ""); 704 md_exit(local_sp, 1); 705 } 706 707 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 708 mde_perror(ep, ""); 709 md_exit(local_sp, 1); 710 } 711 712 /* Determine if diskset is a MN diskset or not */ 713 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 714 mde_perror(ep, ""); 715 md_exit(local_sp, 1); 716 } 717 if (MD_MNSET_DESC(sd)) { 718 multi_node = 1; 719 } 720 721 if (meta_lock(local_sp, TRUE, ep) != 0) { 722 mde_perror(ep, ""); 723 md_exit(local_sp, 1); 724 } 725 726 /* Make sure database size is within limits */ 727 if (default_size == FALSE) { 728 if ((multi_node && dbsize < MDDB_MN_MINBLKS) || 729 (!multi_node && dbsize < MDDB_MINBLKS)) 730 usage(sp, gettext( 731 "size (-l) is too small")); 732 733 if ((multi_node && dbsize > MDDB_MN_MAXBLKS) || 734 (!multi_node && dbsize > MDDB_MAXBLKS)) 735 usage(sp, gettext( 736 "size (-l) is too big")); 737 } 738 739 /* 740 * Have a valid set, take the set lock also. 741 * 742 * A MN diskset does not use the set meta_lock but 743 * instead uses the clnt_lock of rpc.metad and the 744 * suspend/resume feature of the rpc.mdcommd. Can't 745 * use set meta_lock since class 1 messages are 746 * grabbing this lock and if this thread is holding 747 * the set meta_lock then no rpc.mdcommd suspend 748 * can occur. 749 */ 750 if (!multi_node) { 751 if (meta_lock(sp, TRUE, ep) != 0) { 752 mde_perror(ep, ""); 753 md_exit(local_sp, 1); 754 } 755 } 756 757 758 /* 759 * If using the default size, 760 * then let's adjust the default to the minimum 761 * size currently in use. 762 */ 763 if (default_size) { 764 dbsize = multi_node ? MD_MN_DBSIZE : MD_DBSIZE; 765 if ((nblks = meta_db_minreplica(sp, ep)) < 0) 766 mdclrerror(ep); 767 else 768 dbsize = nblks; /* adjust replica size */ 769 } 770 771 if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) { 772 mde_perror(ep, ""); 773 if (!multi_node) 774 (void) meta_unlock(sp, ep); 775 md_exit(local_sp, 1); 776 } 777 778 if (c == 0) { 779 md_perror(gettext( 780 "No drives specified to add.\n")); 781 if (!multi_node) 782 (void) meta_unlock(sp, ep); 783 md_exit(local_sp, 1); 784 } 785 786 if (meta_set_adddrives(sp, dnlp, dbsize, force_label, ep)) { 787 metafreedrivenamelist(dnlp); 788 mde_perror(ep, ""); 789 if (!multi_node) 790 (void) meta_unlock(sp, ep); 791 md_exit(local_sp, 1); 792 } 793 794 /* 795 * MN disksets don't have a device id in the master block 796 * For traditional disksets, check for the drive device 797 * id not fitting in the master block 798 */ 799 if (!multi_node) { 800 for (p = dnlp; p != NULL; p = p->next) { 801 int fd; 802 ddi_devid_t devid; 803 mdname_t *np; 804 805 np = metaslicename(p->drivenamep, 0, ep); 806 if (np == NULL) 807 continue; 808 809 if ((fd = open(np->rname, O_RDONLY | O_NDELAY)) < 0) 810 continue; 811 812 if (devid_get(fd, &devid) == 0) { 813 size_t len; 814 815 len = devid_sizeof(devid); 816 if (len > (DEV_BSIZE - sizeof (mddb_mb_t))) 817 (void) mddserror(ep, 818 MDE_DS_NOTSELFIDENTIFY, NULL, NULL, 819 np->rname, NULL); 820 devid_free(devid); 821 } else { 822 (void) mddserror(ep, MDE_DS_NOTSELFIDENTIFY, 823 NULL, NULL, np->rname, NULL); 824 } 825 (void) close(fd); 826 } 827 } 828 829 /* 830 * MN disksets don't use DCS clustering services. 831 * For traditional disksets: 832 * There's not really much we can do here if this call fails. 833 * The drives have been added to the set and DiskSuite believes 834 * it owns the drives. 835 * Relase the set and hope for the best. 836 */ 837 if ((!multi_node) && 838 (sdssc_notify_service(sname, Make_Primary) == SDSSC_ERROR)) { 839 (void) meta_set_release(sp, ep); 840 (void) printf(gettext( 841 "Sun Clustering failed to make set primary\n")); 842 } 843 844 metafreedrivenamelist(dnlp); 845 if (!multi_node) 846 (void) meta_unlock(sp, ep); 847 md_exit(local_sp, 0); 848 } 849 850 static void 851 parse_balance(int argc, char **argv) 852 { 853 int c; 854 mdsetname_t *sp = NULL; 855 char *sname = MD_LOCAL_NAME; 856 md_error_t status = mdnullerror; 857 md_set_desc *sd; 858 int multi_node = 0; 859 860 /* reset and parse args */ 861 optind = 1; 862 opterr = 1; 863 while ((c = getopt(argc, argv, "Mbs:")) != -1) { 864 switch (c) { 865 case 'M': 866 break; 867 case 'b': 868 break; 869 case 's': 870 sname = optarg; 871 break; 872 default: 873 usage(sp, gettext("unknown options")); 874 } 875 } 876 877 argc -= optind; 878 argv += optind; 879 880 if (argc != 0) 881 usage(sp, gettext("too many args")); 882 883 if ((sp = metasetname(sname, &status)) == NULL) { 884 mde_perror(&status, ""); 885 md_exit(sp, 1); 886 } 887 if ((sd = metaget_setdesc(sp, &status)) == NULL) { 888 mde_perror(&status, ""); 889 md_exit(sp, 1); 890 } 891 if (MD_MNSET_DESC(sd)) { 892 multi_node = 1; 893 } 894 /* 895 * Have a valid set, take the set lock also. 896 * 897 * A MN diskset does not use the set meta_lock but 898 * instead uses the clnt_lock of rpc.metad and the 899 * suspend/resume feature of the rpc.mdcommd. Can't 900 * use set meta_lock since class 1 messages are 901 * grabbing this lock and if this thread is holding 902 * the set meta_lock then no rpc.mdcommd suspend 903 * can occur. 904 */ 905 if (!multi_node) { 906 if (meta_lock(sp, TRUE, &status) != 0) { 907 mde_perror(&status, ""); 908 md_exit(sp, 1); 909 } 910 } 911 912 if (meta_set_balance(sp, &status) != 0) { 913 mde_perror(&status, ""); 914 md_exit(sp, 1); 915 } 916 md_exit(sp, 0); 917 } 918 919 static void 920 parse_autotake(int argc, char **argv) 921 { 922 int c; 923 int enable = 0; 924 mdsetname_t *sp = NULL; 925 char *sname = MD_LOCAL_NAME; 926 md_error_t status = mdnullerror; 927 md_error_t *ep = &status; 928 929 /* reset and parse args */ 930 optind = 1; 931 opterr = 1; 932 while ((c = getopt(argc, argv, "A:s:")) != -1) { 933 switch (c) { 934 case 'A': 935 /* verified sub-option in main */ 936 if (strcmp(optarg, "enable") == 0) 937 enable = 1; 938 break; 939 case 's': 940 /* verified presence of setname in main */ 941 sname = optarg; 942 break; 943 default: 944 usage(sp, gettext("unknown options")); 945 } 946 } 947 948 if ((sp = metasetname(sname, ep)) == NULL) { 949 mde_perror(ep, ""); 950 md_exit(sp, 1); 951 } 952 953 if (meta_lock(sp, TRUE, ep) != 0) { 954 mde_perror(ep, ""); 955 md_exit(sp, 1); 956 } 957 958 if (meta_check_ownership(sp, ep) != 0) { 959 mde_perror(ep, ""); 960 md_exit(sp, 1); 961 } 962 963 if (meta_set_auto_take(sp, enable, ep) != 0) { 964 mde_perror(ep, ""); 965 md_exit(sp, 1); 966 } 967 968 md_exit(sp, 0); 969 } 970 971 static void 972 parse_del(int argc, char **argv) 973 { 974 int c; 975 mdsetname_t *sp = NULL; 976 char *sname = MD_LOCAL_NAME; 977 int hosts = FALSE; 978 int meds = FALSE; 979 int forceflg = FALSE; 980 md_error_t status = mdnullerror; 981 md_error_t *ep = &status; 982 mddrivenamelist_t *dnlp = NULL; 983 mdsetname_t *local_sp = NULL; 984 md_set_desc *sd; 985 int multi_node = 0; 986 987 /* reset and parse args */ 988 optind = 1; 989 opterr = 1; 990 while ((c = getopt(argc, argv, "Mdfhms:")) != -1) { 991 switch (c) { 992 case 'M': 993 break; 994 case 'd': 995 break; 996 case 'f': 997 forceflg = TRUE; 998 break; 999 case 'h': 1000 case 'm': 1001 if (meds == TRUE || hosts == TRUE) 1002 usage(sp, gettext( 1003 "only one -m or -h option allowed")); 1004 1005 if (c == 'h') 1006 hosts = TRUE; 1007 else 1008 meds = TRUE; 1009 break; 1010 case 's': 1011 sname = optarg; 1012 break; 1013 default: 1014 usage(sp, gettext("unknown options")); 1015 } 1016 } 1017 1018 argc -= optind; 1019 argv += optind; 1020 1021 if ((sp = metasetname(sname, ep)) == NULL) { 1022 mde_perror(ep, ""); 1023 md_exit(local_sp, 1); 1024 } 1025 1026 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 1027 mde_perror(ep, ""); 1028 md_exit(local_sp, 1); 1029 } 1030 1031 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1032 mde_perror(ep, ""); 1033 md_exit(local_sp, 1); 1034 } 1035 if (MD_MNSET_DESC(sd)) 1036 multi_node = 1; 1037 1038 if (meta_lock(local_sp, TRUE, ep) != 0) { 1039 mde_perror(ep, ""); 1040 md_exit(local_sp, 1); 1041 } 1042 1043 /* 1044 * Have a valid set, take the set lock also. 1045 * 1046 * A MN diskset does not use the set meta_lock but 1047 * instead uses the clnt_lock of rpc.metad and the 1048 * suspend/resume feature of the rpc.mdcommd. Can't 1049 * use set meta_lock since class 1 messages are 1050 * grabbing this lock and if this thread is holding 1051 * the set meta_lock then no rpc.mdcommd suspend 1052 * can occur. 1053 */ 1054 if (!multi_node) { 1055 if (meta_lock(sp, TRUE, ep) != 0) { 1056 mde_perror(ep, ""); 1057 md_exit(local_sp, 1); 1058 } 1059 } 1060 1061 /* 1062 * Delete hosts 1063 */ 1064 if (hosts == TRUE) { 1065 if (meta_check_ownership(sp, ep) != 0) { 1066 /* 1067 * If we don't own the set bail out here otherwise 1068 * we could delete the node from the DCS service 1069 * yet not delete the host from the set. 1070 */ 1071 mde_perror(ep, ""); 1072 if (!multi_node) 1073 (void) meta_unlock(sp, ep); 1074 md_exit(local_sp, 1); 1075 } 1076 if (sdssc_delete_hosts(sname, argc, argv) == SDSSC_ERROR) { 1077 if (!metad_isautotakebyname(sname)) { 1078 /* 1079 * SC could have been installed after the set 1080 * was created. We still want to be able to 1081 * delete these sets. 1082 */ 1083 md_perror(gettext( 1084 "Failed to delete hosts from DCS service")); 1085 if (!multi_node) 1086 (void) meta_unlock(sp, ep); 1087 md_exit(local_sp, 1); 1088 } 1089 } 1090 if (meta_set_deletehosts(sp, argc, argv, forceflg, ep)) { 1091 if (sdssc_add_hosts(sname, argc, argv) == SDSSC_ERROR) { 1092 (void) printf(gettext( 1093 "Failed to restore host(s) in DCS " 1094 "database\n")); 1095 } 1096 mde_perror(ep, ""); 1097 if (!multi_node) 1098 (void) meta_unlock(sp, ep); 1099 md_exit(local_sp, 1); 1100 } 1101 if (!multi_node) 1102 (void) meta_unlock(sp, ep); 1103 md_exit(local_sp, 0); 1104 } 1105 1106 /* 1107 * Delete mediators 1108 */ 1109 if (meds == TRUE) { 1110 if (meta_set_deletemeds(sp, argc, argv, forceflg, ep)) { 1111 mde_perror(ep, ""); 1112 if (!multi_node) 1113 (void) meta_unlock(sp, ep); 1114 md_exit(local_sp, 1); 1115 } 1116 if (!multi_node) 1117 (void) meta_unlock(sp, ep); 1118 md_exit(local_sp, 0); 1119 } 1120 1121 /* 1122 * Delete drives 1123 */ 1124 1125 if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) { 1126 mde_perror(ep, ""); 1127 if (!multi_node) 1128 (void) meta_unlock(sp, ep); 1129 md_exit(local_sp, 1); 1130 } 1131 1132 if (c == 0) { 1133 md_perror(gettext( 1134 "No drives specified to delete.\n")); 1135 if (!multi_node) 1136 (void) meta_unlock(sp, ep); 1137 md_exit(local_sp, 1); 1138 } 1139 1140 if (meta_set_deletedrives(sp, dnlp, forceflg, ep)) { 1141 metafreedrivenamelist(dnlp); 1142 mde_perror(ep, ""); 1143 if (!multi_node) 1144 (void) meta_unlock(sp, ep); 1145 md_exit(local_sp, 1); 1146 } 1147 1148 metafreedrivenamelist(dnlp); 1149 if (!multi_node) 1150 (void) meta_unlock(sp, ep); 1151 md_exit(local_sp, 0); 1152 } 1153 1154 static void 1155 parse_isowner(int argc, char **argv) 1156 { 1157 int c; 1158 mdsetname_t *sp = NULL; 1159 char *sname = MD_LOCAL_NAME; 1160 md_error_t status = mdnullerror; 1161 md_error_t *ep = &status; 1162 char *host = NULL; 1163 1164 /* reset and parse args */ 1165 optind = 1; 1166 opterr = 1; 1167 while ((c = getopt(argc, argv, "Moh:s:")) != -1) { 1168 switch (c) { 1169 case 'M': 1170 break; 1171 case 'o': 1172 break; 1173 case 'h': 1174 if (host != NULL) { 1175 usage(sp, gettext( 1176 "only one -h option allowed")); 1177 } 1178 host = optarg; 1179 break; 1180 case 's': 1181 sname = optarg; 1182 break; 1183 default: 1184 usage(sp, gettext("unknown options")); 1185 } 1186 } 1187 1188 argc -= optind; 1189 argv += optind; 1190 1191 if (argc != 0) 1192 usage(sp, gettext("too many args")); 1193 1194 if ((sp = metasetname(sname, ep)) == NULL) { 1195 mde_perror(ep, ""); 1196 md_exit(sp, 1); 1197 } 1198 1199 if (host == NULL) { 1200 if (meta_check_ownership(sp, ep) != 0) { 1201 mde_perror(ep, ""); 1202 md_exit(sp, 1); 1203 } 1204 } else { 1205 if (meta_check_ownership_on_host(sp, host, ep) != 0) { 1206 mde_perror(ep, ""); 1207 md_exit(sp, 1); 1208 } 1209 } 1210 md_exit(sp, 0); 1211 } 1212 1213 static void 1214 parse_purge(int argc, char **argv) 1215 { 1216 int c; 1217 mdsetname_t *sp = NULL; 1218 mdsetname_t *local_sp = NULL; 1219 md_drive_desc *dd; 1220 char *sname = MD_LOCAL_NAME; 1221 char *thishost = mynode(); 1222 md_error_t status = mdnullerror; 1223 md_error_t *ep = &status; 1224 int bypass_cluster_purge = 0; 1225 int forceflg = FALSE; 1226 int ret = 0; 1227 int multi_node = 0; 1228 md_set_desc *sd; 1229 1230 optind = 1; 1231 opterr = 1; 1232 while ((c = getopt(argc, argv, "C:fPs:")) != -1) { 1233 switch (c) { 1234 case 'M': 1235 break; 1236 case 'C': 1237 bypass_cluster_purge = 1; 1238 break; 1239 case 'f': 1240 forceflg = TRUE; 1241 break; 1242 case 'P': 1243 break; 1244 case 's': 1245 sname = optarg; 1246 break; 1247 default: 1248 usage(sp, gettext("unknown options")); 1249 } 1250 } 1251 1252 argc -= optind; 1253 argv += optind; 1254 1255 if (argc != 0) 1256 usage(sp, gettext("too many arguments")); 1257 1258 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 1259 mde_perror(ep, ""); 1260 md_exit(local_sp, 1); 1261 } 1262 1263 if (meta_lock(local_sp, TRUE, ep) != 0) { 1264 mde_perror(ep, ""); 1265 md_exit(local_sp, 1); 1266 } 1267 1268 if ((sp = metasetname(sname, ep)) == NULL) { 1269 mde_perror(ep, ""); 1270 md_exit(sp, 1); 1271 } 1272 1273 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1274 mde_perror(ep, ""); 1275 md_exit(local_sp, 1); 1276 } 1277 if (MD_MNSET_DESC(sd)) 1278 multi_node = 1; 1279 1280 if (!multi_node) { 1281 if (meta_lock(sp, TRUE, ep) != 0) { 1282 mde_perror(ep, ""); 1283 md_exit(local_sp, 1); 1284 } 1285 } 1286 1287 /* Must not own the set if purging it from this host */ 1288 if (meta_check_ownership(sp, ep) == 0) { 1289 /* 1290 * Need to see if there are disks in the set, if not then 1291 * there is no ownership but meta_check_ownership returns 0 1292 */ 1293 dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST), ep); 1294 if (!mdisok(ep)) { 1295 mde_perror(ep, ""); 1296 if (!multi_node) 1297 (void) meta_unlock(sp, ep); 1298 md_exit(local_sp, 1); 1299 } 1300 if (dd != NULL) { 1301 (void) printf(gettext 1302 ("Must not be owner of the set when purging it\n")); 1303 if (!multi_node) 1304 (void) meta_unlock(sp, ep); 1305 md_exit(local_sp, 1); 1306 } 1307 } 1308 /* 1309 * Remove the node from the DCS service 1310 */ 1311 if (!bypass_cluster_purge) { 1312 if (sdssc_delete_hosts(sname, 1, &thishost) == SDSSC_ERROR) { 1313 md_perror(gettext 1314 ("Failed to purge hosts from DCS service")); 1315 if (!multi_node) 1316 (void) meta_unlock(sp, ep); 1317 md_exit(local_sp, 1); 1318 } 1319 } 1320 1321 if ((ret = meta_set_purge(sp, bypass_cluster_purge, forceflg, 1322 ep)) != 0) { 1323 if (!bypass_cluster_purge) { 1324 if (sdssc_add_hosts(sname, 1, &thishost) == 1325 SDSSC_ERROR) { 1326 (void) printf(gettext( 1327 "Failed to restore host in DCS " 1328 "database\n")); 1329 } 1330 } 1331 mde_perror(ep, ""); 1332 if (!multi_node) 1333 (void) meta_unlock(sp, ep); 1334 md_exit(local_sp, ret); 1335 } 1336 1337 if (!multi_node) 1338 (void) meta_unlock(sp, ep); 1339 md_exit(local_sp, 0); 1340 } 1341 1342 static void 1343 parse_query(int argc, char **argv) 1344 { 1345 int c; 1346 mdsetname_t *sp = NULL; 1347 mddb_dtag_lst_t *dtlp = NULL; 1348 mddb_dtag_lst_t *tdtlp; 1349 char *sname = MD_LOCAL_NAME; 1350 md_error_t status = mdnullerror; 1351 1352 /* reset and parse args */ 1353 optind = 1; 1354 opterr = 1; 1355 while ((c = getopt(argc, argv, "Mqs:")) != -1) { 1356 switch (c) { 1357 case 'M': 1358 break; 1359 case 'q': 1360 break; 1361 case 's': 1362 sname = optarg; 1363 break; 1364 default: 1365 usage(sp, gettext("unknown options")); 1366 } 1367 } 1368 1369 argc -= optind; 1370 argv += optind; 1371 1372 if (argc != 0) 1373 usage(sp, gettext("too many args")); 1374 1375 if ((sp = metasetname(sname, &status)) == NULL) { 1376 mde_perror(&status, ""); 1377 md_exit(sp, 1); 1378 } 1379 1380 if (meta_lock(sp, TRUE, &status) != 0) { 1381 mde_perror(&status, ""); 1382 md_exit(sp, 1); 1383 } 1384 1385 if (meta_set_query(sp, &dtlp, &status) != 0) { 1386 mde_perror(&status, ""); 1387 md_exit(sp, 1); 1388 } 1389 1390 if (dtlp != NULL) 1391 (void) printf("The following tag(s) were found:\n"); 1392 1393 for (tdtlp = dtlp; tdtlp != NULL; tdtlp = dtlp) { 1394 dtlp = tdtlp->dtl_nx; 1395 (void) printf("%2d - %s - %s", tdtlp->dtl_dt.dt_id, 1396 tdtlp->dtl_dt.dt_hn, 1397 ctime((long *)&tdtlp->dtl_dt.dt_tv.tv_sec)); 1398 Free(tdtlp); 1399 } 1400 1401 md_exit(sp, 0); 1402 } 1403 1404 /* Should never be called with sname of a Multinode diskset. */ 1405 static void 1406 parse_releaseset(int argc, char **argv) 1407 { 1408 int c; 1409 mdsetname_t *sp = NULL; 1410 md_error_t status = mdnullerror; 1411 md_error_t *ep = &status; 1412 char *sname = MD_LOCAL_NAME; 1413 sdssc_boolean_e cluster_release = SDSSC_False; 1414 sdssc_version_t vers; 1415 rval_e rval; 1416 md_set_desc *sd; 1417 1418 /* reset and parse args */ 1419 optind = 1; 1420 opterr = 1; 1421 while ((c = getopt(argc, argv, "C:s:r")) != -1) { 1422 switch (c) { 1423 case 'C': 1424 cluster_release = SDSSC_True; 1425 break; 1426 case 's': 1427 sname = optarg; 1428 break; 1429 case 'r': 1430 break; 1431 default: 1432 usage(sp, gettext("unknown options")); 1433 } 1434 } 1435 1436 argc -= optind; 1437 argv += optind; 1438 1439 if (argc > 0) 1440 usage(sp, gettext("too many args")); 1441 1442 (void) memset(&vers, 0, sizeof (vers)); 1443 1444 if ((sdssc_version(&vers) == SDSSC_OKAY) && 1445 (vers.major == 3) && 1446 (cluster_release == SDSSC_False)) { 1447 1448 /* 1449 * If the release is being done by the user via the CLI 1450 * we need to notify the DCS to release this node as being 1451 * the primary. The reason nothing else needs to be done 1452 * is due to the fact that the reservation code will exec 1453 * metaset -C release to complete the operation. 1454 */ 1455 rval = sdssc_notify_service(sname, Release_Primary); 1456 if (rval == SDSSC_ERROR) { 1457 (void) printf(gettext( 1458 "metaset: failed to notify DCS of release\n")); 1459 } 1460 md_exit(NULL, rval == SDSSC_ERROR); 1461 } 1462 1463 if ((sp = metasetname(sname, ep)) == NULL) { 1464 1465 /* 1466 * It's entirely possible for the SC3.0 reservation code 1467 * to call for DiskSet to release a diskset and have that 1468 * diskset not exist. During a diskset removal DiskSuite 1469 * maybe able to remove all traces of the diskset before 1470 * the reservation code execs metaset -C release in which 1471 * case the metasetname will fail, but the overall command 1472 * shouldn't. 1473 */ 1474 if (vers.major == 3) 1475 md_exit(sp, 0); 1476 else { 1477 mde_perror(ep, ""); 1478 md_exit(sp, 1); 1479 } 1480 } 1481 1482 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1483 mde_perror(ep, ""); 1484 md_exit(sp, 1); 1485 } 1486 1487 if (sd->sd_flags & MD_SR_AUTO_TAKE) { 1488 md_eprintf(gettext("cannot release auto-take diskset\n")); 1489 md_exit(sp, 1); 1490 } 1491 1492 if (meta_lock_nowait(sp, ep) != 0) { 1493 mde_perror(ep, ""); 1494 md_exit(sp, 10); /* special errcode */ 1495 } 1496 1497 if (meta_set_release(sp, ep)) { 1498 mde_perror(ep, ""); 1499 md_exit(sp, 1); 1500 } 1501 md_exit(sp, 0); 1502 } 1503 1504 /* Should never be called with sname of a Multinode diskset. */ 1505 static void 1506 parse_takeset(int argc, char **argv) 1507 { 1508 int c; 1509 mdsetname_t *sp = NULL; 1510 int flags = 0; 1511 char *sname = MD_LOCAL_NAME; 1512 mhd_mhiargs_t mhiargs; 1513 char *cp = NULL; 1514 int pos = -1; /* position of timeout value */ 1515 int usetag = 0; 1516 static char *nullopts[] = { NULL }; 1517 md_error_t status = mdnullerror; 1518 md_error_t *ep = &status; 1519 sdssc_boolean_e cluster_take = SDSSC_False; 1520 sdssc_version_t vers; 1521 rval_e rval; 1522 int set_take_rval; 1523 1524 /* reset and parse args */ 1525 optind = 1; 1526 opterr = 1; 1527 while ((c = getopt(argc, argv, "C:fs:tu:y")) != -1) { 1528 switch (c) { 1529 case 'C': 1530 cluster_take = SDSSC_True; 1531 break; 1532 case 'f': 1533 flags |= TAKE_FORCE; 1534 break; 1535 case 's': 1536 sname = optarg; 1537 break; 1538 case 't': 1539 break; 1540 case 'u': 1541 usetag = atoi(optarg); 1542 flags |= TAKE_USETAG; 1543 break; 1544 case 'y': 1545 flags |= TAKE_USEIT; 1546 break; 1547 default: 1548 usage(sp, gettext("unknown options")); 1549 } 1550 } 1551 1552 mhiargs = defmhiargs; 1553 1554 argc -= optind; 1555 argv += optind; 1556 1557 if (argc > 1) 1558 usage(sp, gettext("too many args")); 1559 1560 /* 1561 * If we have a list of timeout value overrides, handle it here 1562 */ 1563 while (argv[0] != NULL && *argv[0] != '\0') { 1564 /* 1565 * The use of the nullopts[] "token list" here is to make 1566 * getsubopts() simply parse a comma separated list 1567 * returning either "" or the contents of the field, the 1568 * end condition is exaustion of the initial string, which 1569 * is modified in the process. 1570 */ 1571 (void) getsubopt(&argv[0], nullopts, &cp); 1572 1573 c = 0; /* re-use c as temp value of timeout */ 1574 1575 if (*cp != '-') /* '-' uses default */ 1576 c = atoi(cp); 1577 1578 if (c < 0) { 1579 usage(sp, gettext( 1580 "time out values must be > 0")); 1581 } 1582 1583 if (++pos > 3) { 1584 usage(sp, gettext( 1585 "too many timeout values specified.")); 1586 } 1587 1588 if (c == 0) /* 0 or "" field uses default */ 1589 continue; 1590 1591 /* 1592 * Assign temp value to appropriate structure member based on 1593 * its position in the comma separated list. 1594 */ 1595 switch (pos) { 1596 case 0: 1597 mhiargs.mh_ff = c; 1598 break; 1599 1600 case 1: 1601 mhiargs.mh_tk.reinstate_resv_delay = c; 1602 break; 1603 1604 case 2: 1605 mhiargs.mh_tk.min_ownership_delay = c; 1606 break; 1607 1608 case 3: 1609 mhiargs.mh_tk.max_ownership_delay = c; 1610 break; 1611 } 1612 } 1613 1614 (void) memset(&vers, 0, sizeof (vers)); 1615 1616 if ((sdssc_version(&vers) == SDSSC_OKAY) && 1617 (vers.major == 3) && 1618 (cluster_take == SDSSC_False)) { 1619 1620 /* 1621 * If the take is beging done by the user via the CLI we need 1622 * to notify the DCS to make this current node the primary. 1623 * The SC3.0 reservation code will in turn exec metaset with 1624 * the -C take arg to complete this operation. 1625 */ 1626 if ((rval = sdssc_notify_service(sname, Make_Primary)) == 1627 SDSSC_ERROR) { 1628 (void) printf(gettext( 1629 "metaset: failed to notify DCS of take\n")); 1630 } 1631 md_exit(NULL, rval == SDSSC_ERROR); 1632 } 1633 1634 if ((sp = metasetname(sname, ep)) == NULL) { 1635 mde_perror(ep, ""); 1636 md_exit(sp, 1); 1637 } 1638 1639 if ((vers.major == 3) && (meta_check_ownership(sp, ep) == 0)) { 1640 1641 /* 1642 * If we're running in a cluster environment and this 1643 * node already owns the set. Don't bother trying to 1644 * take the set again. There's one case where an adminstrator 1645 * is adding disks to a set for the first time. metaset 1646 * will take the ownership of the set at that point. During 1647 * that add operation SC3.0 notices activity on the device 1648 * and also tries to perform a take operation. The SC3.0 take 1649 * will fail because the adminstrative add has the set locked 1650 */ 1651 md_exit(sp, 0); 1652 } 1653 1654 if (meta_lock_nowait(sp, ep) != 0) { 1655 mde_perror(ep, ""); 1656 md_exit(sp, 10); /* special errcode */ 1657 } 1658 1659 /* 1660 * If a 2 is returned from meta_set_take, this take was able to resolve 1661 * an unresolved replicated disk (i.e. a disk is now available that 1662 * had been missing during the import of the replicated diskset). 1663 * Need to release the diskset and re-take in order to have 1664 * the subdrivers re-snarf using the newly resolved (or newly mapped) 1665 * devids. This also allows the namespace to be updated with the 1666 * correct major names in the case where the disk being replicated 1667 * was handled by a different driver than the replicated disk. 1668 */ 1669 set_take_rval = meta_set_take(sp, &mhiargs, flags, usetag, &status); 1670 if (set_take_rval == 2) { 1671 if (meta_set_release(sp, &status)) { 1672 mde_perror(&status, 1673 "Need to release and take set to resolve names."); 1674 md_exit(sp, 1); 1675 } 1676 metaflushdrivenames(); 1677 metaflushsetname(sp); 1678 set_take_rval = meta_set_take(sp, &mhiargs, 1679 (flags | TAKE_RETAKE), usetag, &status); 1680 } 1681 1682 if (set_take_rval == -1) { 1683 mde_perror(&status, ""); 1684 if (mdismddberror(&status, MDE_DB_TAGDATA)) 1685 md_exit(sp, 2); 1686 if (mdismddberror(&status, MDE_DB_ACCOK)) 1687 md_exit(sp, 3); 1688 if (mdismddberror(&status, MDE_DB_STALE)) 1689 md_exit(sp, 66); 1690 md_exit(sp, 1); 1691 } 1692 md_exit(sp, 0); 1693 } 1694 1695 /* 1696 * Joins a node to a specific set or to all multinode disksets known 1697 * by this node. If set is specified then caller should have verified 1698 * that the set is a multinode diskset. 1699 * 1700 * If an error occurs, metaset exits with a 1. 1701 * If there is no error, metaset exits with a 0. 1702 */ 1703 static void 1704 parse_joinset(int argc, char **argv) 1705 { 1706 int c; 1707 mdsetname_t *sp = NULL, *local_sp = NULL; 1708 char *sname = MD_LOCAL_NAME; 1709 md_error_t status = mdnullerror; 1710 md_error_t *ep = &status; 1711 md_set_desc *sd; 1712 char buf[BUFSIZ]; 1713 char *p = buf; 1714 set_t max_sets, setno; 1715 int err, cumm_err = 0; 1716 size_t bufsz; 1717 1718 bufsz = sizeof (buf); 1719 /* reset and parse args */ 1720 optind = 1; 1721 opterr = 1; 1722 while ((c = getopt(argc, argv, "Ms:j")) != -1) { 1723 switch (c) { 1724 case 'M': 1725 break; 1726 case 'j': 1727 break; 1728 case 's': 1729 sname = optarg; 1730 break; 1731 default: 1732 usage(sp, gettext("unknown options")); 1733 } 1734 } 1735 1736 argc -= optind; 1737 argv += optind; 1738 1739 if (argc > 1) 1740 usage(sp, gettext("too many args")); 1741 1742 /* 1743 * If no setname option was used, then join all disksets 1744 * that this node knows about. Attempt to join all 1745 * disksets that this node knows about. 1746 * 1747 * Additional text is added to the error messages during 1748 * this section of code in order to help the user understand 1749 * why the 'join of all sets' failed and which set caused 1750 * the failure. 1751 */ 1752 1753 /* 1754 * Hold local set lock throughout this call to keep 1755 * other actions from interfering (such as creating a new 1756 * set, etc.). 1757 */ 1758 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 1759 mde_perror(ep, ""); 1760 md_exit(sp, 1); 1761 } 1762 1763 if (meta_lock(local_sp, TRUE, ep) != 0) { 1764 mde_perror(ep, ""); 1765 md_exit(local_sp, 1); 1766 } 1767 1768 if (strcmp(sname, MD_LOCAL_NAME) == 0) { 1769 /* 1770 * If no set name is given, then walk through all sets 1771 * on this node which could include: 1772 * - MN disksets 1773 * - traditional disksets 1774 * - non-existent disksets 1775 * Attempt to join the MN disksets. 1776 * If the join of one set fails, print out an error message 1777 * about that set and continue the walk. 1778 */ 1779 if ((max_sets = get_max_sets(ep)) == 0) { 1780 mde_perror(ep, ""); 1781 md_exit(local_sp, 1); 1782 } 1783 1784 /* Start walking through all possible disksets */ 1785 for (setno = 1; setno < max_sets; setno++) { 1786 if ((sp = metasetnosetname(setno, ep)) == NULL) { 1787 if (mdiserror(ep, MDE_NO_SET)) { 1788 /* No set for this setno - continue */ 1789 mdclrerror(ep); 1790 continue; 1791 } else { 1792 (void) sprintf(p, gettext( 1793 "Unable to get set %d information"), 1794 setno); 1795 mde_perror(ep, p); 1796 cumm_err = 1; 1797 mdclrerror(ep); 1798 continue; 1799 } 1800 } 1801 1802 /* If setname is there, set desc should exist. */ 1803 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1804 (void) snprintf(p, bufsz, gettext( 1805 "Unable to get set %s desc information"), 1806 sp->setname); 1807 mde_perror(ep, p); 1808 cumm_err = 1; 1809 mdclrerror(ep); 1810 continue; 1811 } 1812 1813 /* Only check MN disksets */ 1814 if (!MD_MNSET_DESC(sd)) { 1815 continue; 1816 } 1817 1818 /* 1819 * Return value of 0 is success. 1820 * Return value of -1 means a failure. 1821 * Return value of -2 means set could not be 1822 * joined, but shouldn't cause an error. 1823 * Reasons would be: 1824 * - no drives in set 1825 * - node already joined to set 1826 * Return value of -3 means joined stale set. 1827 * Can't check for all reasons here 1828 * since set isn't locked yet across all 1829 * nodes in the cluster. The call 1830 * to libmeta routine, meta_set_join, will 1831 * lock across the cluster and perform 1832 * the checks. 1833 */ 1834 if ((err = meta_set_join(sp, ep)) == -1) { 1835 /* Print error of diskset join failure */ 1836 (void) snprintf(p, bufsz, 1837 gettext("Join to diskset %s failed"), 1838 sp->setname); 1839 mde_perror(ep, p); 1840 cumm_err = 1; 1841 mdclrerror(ep); 1842 continue; 1843 } 1844 1845 if (err == -3) { 1846 /* Print error of diskset join failure */ 1847 (void) snprintf(p, bufsz, 1848 gettext("Joined to stale diskset %s"), 1849 sp->setname); 1850 mde_perror(ep, p); 1851 mdclrerror(ep); 1852 } 1853 1854 mdclrerror(ep); 1855 } 1856 1857 md_exit(local_sp, cumm_err); 1858 } 1859 1860 /* 1861 * Code for a specific set is much simpler. 1862 * Error messages don't need extra text since specific setname 1863 * was used. 1864 * Don't need to lock the local set, just the specific set given. 1865 */ 1866 if ((sp = metasetname(sname, ep)) == NULL) { 1867 mde_perror(ep, ""); 1868 md_exit(local_sp, 1); 1869 } 1870 1871 /* 1872 * Fail command if meta_set_join returns -1. 1873 * 1874 * Return of 0 means that node joined set. 1875 * 1876 * Return of -2 means that node was unable to 1877 * join a set since that set had no drives 1878 * or that had already joined the set. No 1879 * need to fail the command for these reasons. 1880 * 1881 * Return of -3 means that set is stale. 1882 * Return a value of 66 to historically match traditional disksets. 1883 */ 1884 if ((err = meta_set_join(sp, ep)) == -1) { 1885 mde_perror(&status, ""); 1886 md_exit(local_sp, 1); 1887 } 1888 1889 if (err == -3) { 1890 /* Print error of diskset join failure */ 1891 (void) snprintf(p, bufsz, 1892 gettext("Joined to stale diskset %s"), 1893 sp->setname); 1894 mde_perror(&status, ""); 1895 md_exit(local_sp, 66); 1896 } 1897 1898 md_exit(local_sp, 0); 1899 } 1900 1901 /* 1902 * Withdraws a node from a specific set or from all multinode disksets known 1903 * by this node. If set is specified then caller should have verified 1904 * that the set is a multinode diskset. 1905 * 1906 * If an error occurs, metaset exits with a 1. 1907 * If there is no error, metaset exits with a 0. 1908 */ 1909 static void 1910 parse_withdrawset(int argc, char **argv) 1911 { 1912 int c; 1913 mdsetname_t *sp = NULL, *local_sp = NULL; 1914 char *sname = MD_LOCAL_NAME; 1915 md_error_t status = mdnullerror; 1916 md_error_t *ep = &status; 1917 char buf[BUFSIZ]; 1918 char *p = buf; 1919 md_set_desc *sd; 1920 set_t max_sets, setno; 1921 int err, cumm_err = 0; 1922 size_t bufsz; 1923 1924 bufsz = sizeof (buf); 1925 /* reset and parse args */ 1926 optind = 1; 1927 opterr = 1; 1928 while ((c = getopt(argc, argv, "Ms:w")) != -1) { 1929 switch (c) { 1930 case 'M': 1931 break; 1932 case 'w': 1933 break; 1934 case 's': 1935 sname = optarg; 1936 break; 1937 default: 1938 usage(sp, gettext("unknown options")); 1939 } 1940 } 1941 1942 argc -= optind; 1943 argv += optind; 1944 1945 if (argc > 1) 1946 usage(sp, gettext("too many args")); 1947 1948 /* 1949 * If no setname option was used, then withdraw from all disksets 1950 * that this node knows about. 1951 * 1952 * Additional text is added to the error messages during 1953 * this section of code in order to help the user understand 1954 * why the 'withdraw from all sets' failed and which set caused 1955 * the failure. 1956 */ 1957 1958 /* 1959 * Hold local set lock throughout this call to keep 1960 * other actions from interfering (such as creating a new 1961 * set, etc.). 1962 */ 1963 if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 1964 mde_perror(ep, ""); 1965 md_exit(sp, 1); 1966 } 1967 1968 if (meta_lock(local_sp, TRUE, ep) != 0) { 1969 mde_perror(ep, ""); 1970 md_exit(local_sp, 1); 1971 } 1972 1973 if (strcmp(sname, MD_LOCAL_NAME) == 0) { 1974 /* 1975 * If no set name is given, then walk through all sets 1976 * on this node which could include: 1977 * - MN disksets 1978 * - traditional disksets 1979 * - non-existent disksets 1980 * Attempt to withdraw from the MN disksets. 1981 * If the withdraw of one set fails, print out an error 1982 * message about that set and continue the walk. 1983 */ 1984 if ((max_sets = get_max_sets(ep)) == 0) { 1985 mde_perror(ep, ""); 1986 md_exit(local_sp, 1); 1987 } 1988 1989 /* Start walking through all possible disksets */ 1990 for (setno = 1; setno < max_sets; setno++) { 1991 if ((sp = metasetnosetname(setno, ep)) == NULL) { 1992 if (mdiserror(ep, MDE_NO_SET)) { 1993 /* No set for this setno - continue */ 1994 mdclrerror(ep); 1995 continue; 1996 } else { 1997 (void) sprintf(p, gettext( 1998 "Unable to get set %d information"), 1999 setno); 2000 mde_perror(ep, p); 2001 cumm_err = 1; 2002 mdclrerror(ep); 2003 continue; 2004 } 2005 } 2006 2007 /* If setname is there, set desc should exist. */ 2008 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 2009 (void) snprintf(p, bufsz, gettext( 2010 "Unable to get set %s desc information"), 2011 sp->setname); 2012 mde_perror(ep, p); 2013 cumm_err = 1; 2014 mdclrerror(ep); 2015 continue; 2016 } 2017 2018 /* Only check MN disksets */ 2019 if (!MD_MNSET_DESC(sd)) { 2020 continue; 2021 } 2022 2023 /* 2024 * Return value of 0 is success. 2025 * Return value of -1 means a failure. 2026 * Return value of -2 means set could not be 2027 * withdrawn from, but this shouldn't cause 2028 * an error. Reasons would be: 2029 * - no drives in set 2030 * - node already withdrawn from set 2031 * Can't check for all reasons here 2032 * since set isn't locked yet across all 2033 * nodes in the cluster. The call 2034 * to libmeta routine, meta_set_withdraw, will 2035 * lock across the cluster and perform 2036 * the checks. 2037 */ 2038 if ((err = meta_set_withdraw(sp, ep)) == -1) { 2039 /* Print error of diskset withdraw failure */ 2040 (void) snprintf(p, bufsz, 2041 gettext("Withdraw from diskset %s failed"), 2042 sp->setname); 2043 mde_perror(ep, p); 2044 mdclrerror(ep); 2045 cumm_err = 1; 2046 continue; 2047 } 2048 2049 if (err == -2) { 2050 mdclrerror(ep); 2051 continue; 2052 } 2053 2054 mdclrerror(ep); 2055 } 2056 md_exit(local_sp, cumm_err); 2057 } 2058 2059 2060 /* 2061 * Code for a specific set is much simpler. 2062 * Error messages don't need extra text since specific setname 2063 * was used. 2064 * Don't need to lock the local set, just the specific set given. 2065 */ 2066 if ((sp = metasetname(sname, ep)) == NULL) { 2067 mde_perror(ep, ""); 2068 md_exit(local_sp, 1); 2069 } 2070 2071 /* 2072 * Fail command if meta_set_withdraw returns -1. 2073 * 2074 * Return of 0 means that node withdrew from set. 2075 * 2076 * Return of -2 means that node was unable to 2077 * withdraw from a set since that set had no drives 2078 * or node was not joined to set. No 2079 * need to fail the command for these reasons. 2080 */ 2081 if (meta_set_withdraw(sp, ep) == -1) { 2082 mde_perror(&status, ""); 2083 md_exit(local_sp, 1); 2084 } 2085 2086 md_exit(local_sp, 0); 2087 } 2088 2089 static void 2090 parse_cluster(int argc, char **argv, int multi_node) 2091 { 2092 int c, error, new_argc, x; 2093 enum cluster_cmd cmd = ccnotspecified; 2094 char *hostname = SDSSC_PROXY_PRIMARY; 2095 char *argument = NULL; 2096 char *sname = MD_LOCAL_NAME; 2097 char primary_node[SDSSC_NODE_NAME_LEN]; 2098 char **new_argv = NULL; 2099 char **np = NULL; 2100 mdsetname_t *sp = NULL; 2101 md_error_t status = mdnullerror; 2102 md_error_t *ep = &status; 2103 2104 /* reset and parse args */ 2105 optind = 1; 2106 opterr = 1; 2107 while ((c = getopt(argc, argv, "C:s:h:ftu:yr")) != -1) { 2108 switch (c) { 2109 case 'C': 2110 if (cmd != ccnotspecified) { 2111 md_exit(sp, -1); 2112 } 2113 argument = optarg; 2114 2115 if (strcmp(argument, "disksin") == 0) { 2116 cmd = clusterdisksin; 2117 } else if (strcmp(argument, "version") == 0) { 2118 cmd = clusterversion; 2119 } else if (strcmp(argument, "release") == 0) { 2120 cmd = clusterrelease; 2121 } else if (strcmp(argument, "take") == 0) { 2122 cmd = clustertake; 2123 } else if (strcmp(argument, "proxy") == 0) { 2124 cmd = clusterproxy; 2125 } else if (strcmp(argument, "purge") == 0) { 2126 cmd = clusterpurge; 2127 } else { 2128 md_exit(sp, -1); 2129 } 2130 2131 break; 2132 2133 case 'h': 2134 hostname = optarg; 2135 break; 2136 2137 case 's': 2138 sname = optarg; 2139 break; 2140 2141 case 'f': 2142 case 't': 2143 case 'u': 2144 case 'y': 2145 case 'r': 2146 break; 2147 2148 default: 2149 md_exit(sp, -1); 2150 } 2151 } 2152 2153 /* Now call the appropriate command function. */ 2154 switch (cmd) { 2155 case clusterversion: 2156 printclusterversion(); 2157 break; 2158 2159 case clusterdisksin: 2160 if (printdisksin(sname, ep)) { 2161 md_exit(sp, -1); 2162 } 2163 break; 2164 2165 case clusterrelease: 2166 if (multi_node) { 2167 usage(sp, gettext( 2168 "-C release is not allowed on multi-owner" 2169 " disksets")); 2170 } 2171 parse_releaseset(argc, argv); 2172 break; 2173 2174 case clustertake: 2175 if (multi_node) { 2176 usage(sp, gettext( 2177 "-C take is not allowed on multi-owner disksets")); 2178 } 2179 parse_takeset(argc, argv); 2180 break; 2181 2182 case clusterproxy: 2183 if (multi_node) { 2184 usage(sp, gettext( 2185 "-C proxy is not allowed on multi-owner disksets")); 2186 } 2187 2188 if ((new_argv = calloc(argc, sizeof (char *))) == NULL) { 2189 (void) printf(gettext("Out of memory\n")); 2190 md_exit(sp, 1); 2191 } 2192 2193 np = new_argv; 2194 new_argc = 0; 2195 (void) memset(primary_node, '\0', SDSSC_NODE_NAME_LEN); 2196 2197 for (x = 0; x < argc; x++) { 2198 if (strcmp(argv[x], "-C") == 0) { 2199 2200 /* 2201 * Need to skip the '-C proxy' args so 2202 * just increase x by one and the work is 2203 * done. 2204 */ 2205 x++; 2206 } else { 2207 *np++ = strdup(argv[x]); 2208 new_argc++; 2209 } 2210 } 2211 2212 switch (sdssc_get_primary_host(sname, primary_node, 2213 SDSSC_NODE_NAME_LEN)) { 2214 case SDSSC_ERROR: 2215 md_exit(sp, 1); 2216 break; 2217 2218 case SDSSC_NO_SERVICE: 2219 if (hostname != SDSSC_PROXY_PRIMARY) { 2220 (void) strlcpy(primary_node, hostname, 2221 SDSSC_NODE_NAME_LEN); 2222 } 2223 break; 2224 } 2225 2226 if (sdssc_cmd_proxy(new_argc, new_argv, 2227 primary_node[0] == '\0' ? SDSSC_PROXY_PRIMARY : 2228 primary_node, &error) == SDSSC_PROXY_DONE) { 2229 md_exit(sp, error); 2230 } else { 2231 (void) printf(gettext( 2232 "Couldn't proxy command\n")); 2233 md_exit(sp, 1); 2234 } 2235 break; 2236 2237 case clusterpurge: 2238 parse_purge(argc, argv); 2239 break; 2240 2241 default: 2242 break; 2243 } 2244 2245 md_exit(sp, 0); 2246 } 2247 2248 /* 2249 * parse args and do it 2250 */ 2251 int 2252 main(int argc, char *argv[]) 2253 { 2254 enum metaset_cmd cmd = notspecified; 2255 md_error_t status = mdnullerror; 2256 md_error_t *ep = &status; 2257 mdsetname_t *sp = NULL; 2258 char *hostname = SDSSC_PROXY_PRIMARY; 2259 char *sname = MD_LOCAL_NAME; 2260 char *auto_take_option = NULL; 2261 char primary_node[SDSSC_NODE_NAME_LEN]; 2262 int error, c, stat; 2263 int auto_take = FALSE; 2264 md_set_desc *sd; 2265 int mflag = 0; 2266 int multi_node = 0; 2267 rval_e sdssc_res; 2268 2269 /* 2270 * Get the locale set up before calling any other routines 2271 * with messages to ouput. Just in case we're not in a build 2272 * environment, make sure that TEXT_DOMAIN gets set to 2273 * something. 2274 */ 2275 #if !defined(TEXT_DOMAIN) 2276 #define TEXT_DOMAIN "SYS_TEST" 2277 #endif 2278 (void) setlocale(LC_ALL, ""); 2279 (void) textdomain(TEXT_DOMAIN); 2280 2281 sdssc_res = sdssc_bind_library(); 2282 if (sdssc_res == SDSSC_ERROR) { 2283 (void) printf(gettext( 2284 "%s: Interface error with libsds_sc.so\n"), argv[0]); 2285 exit(1); 2286 } 2287 2288 /* initialize */ 2289 if (md_init(argc, argv, 0, 1, ep) != 0) { 2290 mde_perror(ep, ""); 2291 md_exit(sp, 1); 2292 } 2293 2294 optind = 1; 2295 opterr = 1; 2296 2297 /* 2298 * NOTE: The "C" option is strictly for cluster use. it is not 2299 * and should not be documented for the customer. - JST 2300 */ 2301 while ((c = getopt(argc, argv, "C:MaA:bdfh:jl:Lm:oPqrs:tu:wy?")) 2302 != -1) { 2303 switch (c) { 2304 case 'M': 2305 mflag = 1; 2306 break; 2307 case 'A': 2308 auto_take = TRUE; 2309 if (optarg == NULL || !(strcmp(optarg, "enable") == 0 || 2310 strcmp(optarg, "disable") == 0)) 2311 usage(sp, gettext( 2312 "-A: enable or disable must be specified")); 2313 auto_take_option = optarg; 2314 break; 2315 case 'a': 2316 if (cmd != notspecified) { 2317 usage(sp, gettext( 2318 "conflicting options")); 2319 } 2320 cmd = add; 2321 break; 2322 case 'b': 2323 if (cmd != notspecified) { 2324 usage(sp, gettext( 2325 "conflicting options")); 2326 } 2327 cmd = balance; 2328 break; 2329 case 'd': 2330 if (cmd != notspecified) { 2331 usage(sp, gettext( 2332 "conflicting options")); 2333 } 2334 cmd = delete; 2335 break; 2336 case 'C': /* cluster commands */ 2337 if (cmd != notspecified) { 2338 md_exit(sp, -1); /* conflicting options */ 2339 } 2340 cmd = cluster; 2341 break; 2342 case 'f': 2343 break; 2344 case 'h': 2345 hostname = optarg; 2346 break; 2347 case 'j': 2348 if (cmd != notspecified) { 2349 usage(sp, gettext( 2350 "conflicting options")); 2351 } 2352 cmd = join; 2353 break; 2354 case 'l': 2355 break; 2356 case 'L': 2357 break; 2358 case 'm': 2359 break; 2360 case 'o': 2361 if (cmd != notspecified) { 2362 usage(sp, gettext( 2363 "conflicting options")); 2364 } 2365 cmd = isowner; 2366 break; 2367 case 'P': 2368 if (cmd != notspecified) { 2369 usage(sp, gettext( 2370 "conflicting options")); 2371 } 2372 cmd = purge; 2373 break; 2374 case 'q': 2375 if (cmd != notspecified) { 2376 usage(sp, gettext( 2377 "conflicting options")); 2378 } 2379 cmd = query; 2380 break; 2381 case 'r': 2382 if (cmd != notspecified) { 2383 usage(sp, gettext( 2384 "conflicting options")); 2385 } 2386 cmd = release; 2387 break; 2388 case 's': 2389 sname = optarg; 2390 break; 2391 case 't': 2392 if (cmd != notspecified) { 2393 usage(sp, gettext( 2394 "conflicting options")); 2395 } 2396 cmd = take; 2397 break; 2398 case 'u': 2399 break; 2400 case 'w': 2401 if (cmd != notspecified) { 2402 usage(sp, gettext( 2403 "conflicting options")); 2404 } 2405 cmd = withdraw; 2406 break; 2407 case 'y': 2408 break; 2409 case '?': 2410 if (optopt == '?') 2411 usage(sp, NULL); 2412 /*FALLTHROUGH*/ 2413 default: 2414 if (cmd == cluster) { /* cluster is silent */ 2415 md_exit(sp, -1); 2416 } else { 2417 usage(sp, gettext( 2418 "unknown command")); 2419 } 2420 } 2421 } 2422 2423 /* check if suncluster is installed and -A enable specified */ 2424 if (auto_take && sdssc_res != SDSSC_NOT_BOUND && 2425 strcmp(auto_take_option, "enable") == 0) { 2426 md_eprintf(gettext( 2427 "cannot enable auto-take when SunCluster is installed\n")); 2428 md_exit(sp, 1); 2429 } 2430 2431 /* 2432 * At this point we know that if the -A enable option is specified 2433 * for an auto-take diskset that SC is not installed on the machine, so 2434 * all of the sdssc calls will just be no-ops. 2435 */ 2436 2437 /* list sets */ 2438 if (cmd == notspecified && auto_take == FALSE) { 2439 parse_printset(argc, argv); 2440 /*NOTREACHED*/ 2441 } 2442 2443 if (meta_check_root(ep) != 0) { 2444 mde_perror(ep, ""); 2445 md_exit(sp, 1); 2446 } 2447 2448 /* snarf MDDB */ 2449 if (meta_setup_db_locations(ep) != 0) { 2450 mde_perror(ep, ""); 2451 md_exit(sp, 1); 2452 } 2453 2454 /* 2455 * If sname is a diskset - check for multi_node. 2456 * It is possible for sname to not exist. 2457 */ 2458 if (strcmp(sname, MD_LOCAL_NAME)) { 2459 if ((sp = metasetname(sname, ep)) != NULL) { 2460 /* Set exists - check for MN diskset */ 2461 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 2462 mde_perror(ep, ""); 2463 md_exit(sp, 1); 2464 } 2465 if (MD_MNSET_DESC(sd)) { 2466 /* 2467 * If a MN diskset always set multi_node 2468 * regardless of whether the -M option was 2469 * used or not (mflag). 2470 */ 2471 multi_node = 1; 2472 } else { 2473 /* 2474 * If a traditional diskset, mflag must 2475 * not be set. 2476 */ 2477 if (mflag) { 2478 usage(sp, gettext( 2479 "-M option only allowed " 2480 "on multi-owner diskset")); 2481 } 2482 } 2483 } else { 2484 /* 2485 * Set name does not exist, set multi_node 2486 * based on -M option. 2487 */ 2488 if (mflag) { 2489 multi_node = 1; 2490 } 2491 } 2492 } 2493 2494 if (auto_take && multi_node) { 2495 /* Can't mix multinode and auto-take on a diskset */ 2496 usage(sp, 2497 gettext("-A option not allowed on multi-owner diskset")); 2498 } 2499 2500 /* 2501 * MN disksets don't use DCS clustering services, so 2502 * do not get primary_node for MN diskset since no command 2503 * proxying is done to Primary cluster node. Do not proxy 2504 * MN diskset commands of join and withdraw when issued without 2505 * a valid setname. 2506 * For traditional disksets: proxy all commands except a take 2507 * and release. Use first host listed as the host to send the 2508 * command to if there isn't already a primary 2509 */ 2510 if (strcmp(sname, MD_LOCAL_NAME) && (multi_node == 0) && 2511 (cmd != take) && (cmd != release) && 2512 (cmd != cluster) && (cmd != join) && 2513 (cmd != withdraw) && (cmd != purge)) { 2514 stat = sdssc_get_primary_host(sname, primary_node, 2515 SDSSC_NODE_NAME_LEN); 2516 switch (stat) { 2517 case SDSSC_ERROR: 2518 return (0); 2519 2520 case SDSSC_NO_SERVICE: 2521 if (hostname != SDSSC_PROXY_PRIMARY) { 2522 (void) strlcpy(primary_node, hostname, 2523 SDSSC_NODE_NAME_LEN); 2524 } else { 2525 (void) memset(primary_node, '\0', 2526 SDSSC_NODE_NAME_LEN); 2527 } 2528 break; 2529 } 2530 2531 /* 2532 * We've got a complicated decision here regarding 2533 * the hostname. If we didn't get a primary host 2534 * and a host name wasn't supplied on the command line 2535 * then we need to revert to SDSSC_PROXY_PRIMARY. Otherwise 2536 * use what's been found. 2537 */ 2538 if (sdssc_cmd_proxy(argc, argv, 2539 primary_node[0] == '\0' ? 2540 SDSSC_PROXY_PRIMARY : primary_node, 2541 &error) == SDSSC_PROXY_DONE) { 2542 exit(error); 2543 } 2544 } 2545 2546 /* cluster-specific commands */ 2547 if (cmd == cluster) { 2548 parse_cluster(argc, argv, multi_node); 2549 /*NOTREACHED*/ 2550 } 2551 2552 /* join MultiNode diskset */ 2553 if (cmd == join) { 2554 /* 2555 * If diskset specified, verify that it exists 2556 * and is a multinode diskset. 2557 */ 2558 if (strcmp(sname, MD_LOCAL_NAME)) { 2559 if ((sp = metasetname(sname, ep)) == NULL) { 2560 mde_perror(ep, ""); 2561 md_exit(sp, 1); 2562 } 2563 2564 if (!multi_node) { 2565 usage(sp, gettext( 2566 "-j option only allowed on " 2567 "multi-owner diskset")); 2568 } 2569 } 2570 /* 2571 * Start mddoors daemon here. 2572 * mddoors itself takes care there will be only one 2573 * instance running, so starting it twice won't hurt 2574 */ 2575 (void) pclose(popen("/usr/lib/lvm/mddoors", "w")); 2576 parse_joinset(argc, argv); 2577 /*NOTREACHED*/ 2578 } 2579 2580 /* withdraw from MultiNode diskset */ 2581 if (cmd == withdraw) { 2582 /* 2583 * If diskset specified, verify that it exists 2584 * and is a multinode diskset. 2585 */ 2586 if (strcmp(sname, MD_LOCAL_NAME)) { 2587 if ((sp = metasetname(sname, ep)) == NULL) { 2588 mde_perror(ep, ""); 2589 md_exit(sp, 1); 2590 } 2591 2592 if (!multi_node) { 2593 usage(sp, gettext( 2594 "-w option only allowed on " 2595 "multi-owner diskset")); 2596 } 2597 } 2598 parse_withdrawset(argc, argv); 2599 /*NOTREACHED*/ 2600 } 2601 2602 /* must have set for everything else */ 2603 if (strcmp(sname, MD_LOCAL_NAME) == 0) 2604 usage(sp, gettext("setname must be specified")); 2605 2606 /* add hosts or drives */ 2607 if (cmd == add) { 2608 /* 2609 * In the multi node case start mddoors daemon. 2610 * mddoors itself takes care there will be 2611 * only one instance running, so starting it twice won't hurt 2612 */ 2613 if (multi_node) { 2614 (void) pclose(popen("/usr/lib/lvm/mddoors", "w")); 2615 } 2616 2617 parse_add(argc, argv); 2618 /*NOTREACHED*/ 2619 } 2620 2621 /* re-balance the replicas */ 2622 if (cmd == balance) { 2623 parse_balance(argc, argv); 2624 /*NOTREACHED*/ 2625 } 2626 2627 /* delete hosts or drives */ 2628 if (cmd == delete) { 2629 parse_del(argc, argv); 2630 /*NOTREACHED*/ 2631 } 2632 2633 /* check ownership */ 2634 if (cmd == isowner) { 2635 parse_isowner(argc, argv); 2636 /*NOTREACHED*/ 2637 } 2638 2639 /* purge the diskset */ 2640 if (cmd == purge) { 2641 parse_purge(argc, argv); 2642 /*NOTREACHED*/ 2643 } 2644 2645 /* query for data marks */ 2646 if (cmd == query) { 2647 parse_query(argc, argv); 2648 /*NOTREACHED*/ 2649 } 2650 2651 /* release ownership */ 2652 if (cmd == release) { 2653 if (multi_node) { 2654 /* Can't release multinode diskset */ 2655 usage(sp, gettext( 2656 "-r option not allowed on multi-owner diskset")); 2657 } else { 2658 parse_releaseset(argc, argv); 2659 /*NOTREACHED*/ 2660 } 2661 } 2662 2663 /* take ownership */ 2664 if (cmd == take) { 2665 if (multi_node) { 2666 /* Can't take multinode diskset */ 2667 usage(sp, gettext( 2668 "-t option not allowed on multi-owner diskset")); 2669 } else { 2670 parse_takeset(argc, argv); 2671 /*NOTREACHED*/ 2672 } 2673 } 2674 2675 /* take ownership of auto-take sets */ 2676 if (auto_take) { 2677 parse_autotake(argc, argv); 2678 /*NOTREACHED*/ 2679 } 2680 2681 /*NOTREACHED*/ 2682 return (0); 2683 } 2684