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