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