1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * attach submirrors 30 */ 31 32 #include <meta.h> 33 34 #include <sdssc.h> 35 36 /* 37 * print usage message 38 */ 39 static void 40 usage( 41 mdsetname_t *sp, 42 int eval 43 ) 44 { 45 (void) fprintf(stderr, gettext("\ 46 usage: %s [-s setname] mirror [metadevice]\n\ 47 %s [-s setname] [-i interlace] concat/stripe component...\n\ 48 %s [-s setname] RAID component...\n\ 49 %s [-s setname] [-A alignment] softpart size|all\n"), 50 myname, myname, myname, myname); 51 md_exit(sp, eval); 52 } 53 54 /* 55 * attach more space to a soft partition 56 */ 57 static int 58 sp_attach( 59 mdsetname_t **spp, 60 mdname_t *spnp, 61 int argc, 62 char *argv[], 63 mdcmdopts_t options, 64 md_error_t *ep 65 ) 66 { 67 int c; 68 sp_ext_offset_t alignment = 0; 69 70 /* reset and parse args */ 71 optind = 1; 72 opterr = 1; 73 while ((c = getopt(argc, argv, "ns:A:")) != -1) { 74 switch (c) { 75 case 'n': 76 case 's': 77 break; 78 case 'A': 79 if (meta_sp_parsesize(optarg, &alignment) == -1) { 80 usage(*spp, 1); 81 /* NOTREACHED */ 82 } 83 break; 84 default: 85 usage(*spp, 1); 86 /* NOTREACHED */ 87 break; 88 } 89 } 90 argc -= optind + 1; 91 argv += optind + 1; 92 93 if (argc != 1) 94 usage(*spp, 1); 95 96 if (meta_sp_attach(*spp, spnp, argv[0], options, alignment, ep) != 0) { 97 return (-1); 98 } 99 100 /* update md.cf file */ 101 if (meta_update_md_cf(*spp, ep) != 0) 102 return (-1); 103 104 return (0); 105 } 106 /* 107 * attach components to stripe 108 */ 109 static int 110 stripe_attach( 111 mdsetname_t **spp, 112 mdname_t *stripenp, 113 int argc, 114 char *argv[], 115 mdcmdopts_t options, 116 md_error_t *ep 117 ) 118 { 119 diskaddr_t interlace = 0; 120 int c; 121 mdnamelist_t *compnlp = NULL; 122 mdnamelist_t *p; 123 mdname_t *currootnp; 124 md_stripe_t *stripep; 125 md_row_t *rp; 126 md_comp_t *cp; 127 128 129 /* reset and parse args */ 130 optind = 1; 131 opterr = 1; 132 while ((c = getopt(argc, argv, "s:ani:")) != -1) { 133 switch (c) { 134 case 'n': 135 case 's': 136 break; 137 138 case 'a': 139 break; /* obsolete */ 140 141 case 'i': 142 if (parse_interlace(stripenp->cname, optarg, 143 &interlace, ep) != 0) { 144 return (-1); 145 } 146 if (meta_stripe_check_interlace(interlace, 147 stripenp->cname, ep)) 148 return (-1); 149 break; 150 151 default: 152 usage(*spp, 1); 153 /*NOTREACHED*/ 154 break; 155 } 156 } 157 158 argc -= optind + 1; 159 argv += optind + 1; 160 161 if (argc <= 0) 162 usage(*spp, 1); 163 164 /* get list of components */ 165 if (metanamelist(spp, &compnlp, argc, argv, 166 UNKNOWN, ep) < 0) 167 return (-1); 168 assert(compnlp != NULL); 169 for (p = compnlp; (p != NULL); p = p->next) { 170 mdname_t *compnp = p->namep; 171 172 /* see if we are a soft partition */ 173 if (meta_sp_issp(*spp, compnp, ep) != 0) { 174 /* nope, check component */ 175 if (metachkcomp(compnp, ep) != 0) 176 return (-1); 177 } 178 } 179 180 /* get root device */ 181 if ((currootnp = meta_get_current_root_dev(*spp, ep)) != NULL) { 182 /* 183 * Root is either a stripe or a slice 184 * If root device is the 1st component of the stripe 185 * Then fail as root cannot be expanded 186 */ 187 if ((stripep = meta_get_stripe(*spp, stripenp, ep)) == NULL) 188 return (-1); 189 190 rp = &stripep->rows.rows_val[0]; 191 cp = &rp->comps.comps_val[0]; 192 if (metachkcomp(cp->compnamep, ep) == 0) { 193 /* Component is a disk */ 194 if (strcmp(currootnp->cname, 195 cp->compnamep->cname) == 0) { 196 md_eprintf(gettext( 197 "%s: volume mounted as root cannot be " 198 "expanded\n"), stripenp->cname); 199 md_exit(*spp, 1); 200 } 201 } 202 } 203 204 /* attach components */ 205 if (meta_stripe_attach(*spp, stripenp, compnlp, interlace, options, 206 ep) != 0) { 207 return (-1); 208 } 209 210 /* update md.cf file */ 211 if (meta_update_md_cf(*spp, ep) != 0) 212 return (-1); 213 214 /* return success */ 215 return (0); 216 } 217 218 /* 219 * attach components to raid 220 */ 221 static int 222 raid_attach( 223 mdsetname_t **spp, 224 mdname_t *raidnp, 225 int argc, 226 char *argv[], 227 mdcmdopts_t options, 228 md_error_t *ep 229 ) 230 { 231 int c; 232 mdnamelist_t *compnlp = NULL; 233 mdnamelist_t *p; 234 235 /* reset and parse args */ 236 optind = 1; 237 opterr = 1; 238 while ((c = getopt(argc, argv, "s:ai:")) != -1) { 239 switch (c) { 240 case 'n': 241 case 's': 242 break; 243 244 case 'a': 245 break; /* obsolete */ 246 247 default: 248 usage(*spp, 1); 249 /*NOTREACHED*/ 250 break; 251 } 252 } 253 argc -= optind + 1; 254 argv += optind + 1; 255 if (argc <= 0) 256 usage(*spp, 1); 257 258 /* get list of components */ 259 if (metanamelist(spp, &compnlp, argc, argv, 260 UNKNOWN, ep) < 0) 261 return (-1); 262 assert(compnlp != NULL); 263 for (p = compnlp; (p != NULL); p = p->next) { 264 mdname_t *compnp = p->namep; 265 266 /* check for soft partitions */ 267 if (meta_sp_issp(*spp, compnp, ep) != 0) { 268 /* check disk */ 269 if (metachkcomp(compnp, ep) != 0) 270 return (-1); 271 } 272 } 273 274 /* attach components */ 275 if (meta_raid_attach(*spp, raidnp, compnlp, options, ep) != 0) 276 return (-1); 277 278 /* update md.cf file */ 279 if (meta_update_md_cf(*spp, ep) != 0) 280 return (-1); 281 282 /* return success */ 283 return (0); 284 } 285 286 /* 287 * attach submirror to mirror 288 */ 289 static int 290 mirror_attach( 291 mdsetname_t **spp, 292 mdname_t *mirnp, 293 int argc, 294 char *argv[], 295 mdcmdopts_t options, 296 md_error_t *ep 297 ) 298 { 299 int c; 300 mdname_t *submirnp; 301 302 /* reset and parse args */ 303 optind = 1; 304 opterr = 1; 305 while ((c = getopt(argc, argv, "ns:")) != -1) { 306 switch (c) { 307 case 'n': 308 case 's': 309 break; 310 311 default: 312 usage(*spp, 1); 313 /*NOTREACHED*/ 314 break; 315 } 316 } 317 argc -= optind + 1; 318 argv += optind + 1; 319 320 /* get submirror */ 321 if (argc == 1) { 322 if (((submirnp = metaname(spp, argv[0], META_DEVICE, 323 ep)) == NULL) || 324 (metachkmeta(submirnp, ep) != 0)) { 325 return (-1); 326 } 327 } else if (argc == 0) { 328 submirnp = NULL; 329 } else { 330 usage(*spp, 1); 331 } 332 333 /* attach submirror */ 334 if (meta_mirror_attach(*spp, mirnp, submirnp, options, ep) != 0) 335 return (-1); 336 337 /* update md.cf file */ 338 if (meta_update_md_cf(*spp, ep) != 0) 339 return (-1); 340 341 /* return success */ 342 return (0); 343 } 344 345 /* 346 * attach devices 347 */ 348 int 349 main( 350 int argc, 351 char *argv[] 352 ) 353 { 354 char *sname = NULL; 355 mdsetname_t *sp = NULL; 356 mdcmdopts_t options = (MDCMD_PRINT|MDCMD_DOIT); 357 mdname_t *np; 358 char *miscname; 359 int c; 360 md_error_t status = mdnullerror; 361 md_error_t *ep = &status; 362 int error; 363 bool_t called_thru_rpc = FALSE; 364 char *cp; 365 366 /* 367 * Get the locale set up before calling any other routines 368 * with messages to ouput. Just in case we're not in a build 369 * environment, make sure that TEXT_DOMAIN gets set to 370 * something. 371 */ 372 #if !defined(TEXT_DOMAIN) 373 #define TEXT_DOMAIN "SYS_TEST" 374 #endif 375 (void) setlocale(LC_ALL, ""); 376 (void) textdomain(TEXT_DOMAIN); 377 378 /* initialize */ 379 if ((cp = strstr(argv[0], ".rpc_call")) == NULL) { 380 if (sdssc_bind_library() == SDSSC_OKAY) 381 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 382 &error) == SDSSC_PROXY_DONE) 383 exit(error); 384 } else { 385 *cp = '\0'; /* cut off ".rpc_call" */ 386 called_thru_rpc = TRUE; 387 } 388 389 if (md_init(argc, argv, 0, 1, ep) != 0 || 390 meta_check_root(ep) != 0) { 391 mde_perror(ep, ""); 392 md_exit(sp, 1); 393 } 394 395 /* find set and metadevice first */ 396 optind = 1; 397 opterr = 1; 398 while ((c = getopt(argc, argv, "hns:A:ai:?")) != -1) { 399 switch (c) { 400 case 'h': 401 usage(sp, 0); 402 break; 403 404 case 'n': 405 if (called_thru_rpc == TRUE) { 406 options &= ~MDCMD_DOIT; 407 } else { 408 usage(sp, 1); 409 } 410 break; 411 412 case 's': 413 sname = optarg; 414 break; 415 416 case '?': 417 if (optopt == '?') 418 usage(sp, 0); 419 break; 420 } 421 } 422 if ((argc - optind) <= 0) 423 usage(sp, 1); 424 425 if (sname != NULL) { 426 if ((sp = metasetname(sname, ep)) == NULL) { 427 mde_perror(ep, ""); 428 md_exit(sp, 1); 429 } 430 } 431 432 if (((np = metaname(&sp, argv[optind], META_DEVICE, ep)) == NULL) || 433 (metachkmeta(np, ep) != 0)) { 434 mde_perror(ep, ""); 435 md_exit(sp, 1); 436 } 437 assert(sp != NULL); 438 439 if ((called_thru_rpc == FALSE) && 440 meta_is_mn_name(&sp, argv[optind], ep)) { 441 /* 442 * If we are dealing with a MN set and we were not 443 * called thru an rpc call, we are just to send this 444 * command string to the master of the set and let it 445 * deal with it. 446 * Note that if sp is NULL, meta_is_mn_name() derives sp 447 * from argv[optind] which is the metadevice arg 448 */ 449 int i; 450 int newargc; 451 int result; 452 char **newargv; 453 454 if ((miscname = metagetmiscname(np, ep)) == NULL) { 455 mde_perror(ep, ""); 456 md_exit(sp, 1); 457 } 458 459 newargv = calloc(argc+1, sizeof (char *)); 460 newargv[0] = "metattach"; 461 newargv[1] = "-n"; /* always do "-n" first */ 462 newargc = 2; 463 for (i = 1; i < argc; i++, newargc++) 464 newargv[newargc] = argv[i]; 465 466 result = meta_mn_send_command(sp, newargc, newargv, 467 MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep); 468 469 /* If we found a problem don't do it for real */ 470 if (result != 0) { 471 md_exit(sp, result); 472 } 473 474 /* 475 * Do it for real now. Remove "-n" from the arguments and 476 * MD_DRYRUN from the flags. If we fail now, the master must 477 * panic as the mddbs may be inconsistent. 478 */ 479 newargv[1] = ""; /* this was "-n" before */ 480 result = meta_mn_send_command(sp, newargc, newargv, 481 MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT, 482 NO_CONTEXT_STRING, ep); 483 484 free(newargv); 485 486 /* 487 * If the metattach command succeeds, for a mirror, send a 488 * resync starting message for the metadevice 489 */ 490 if ((result == 0) && (strcmp(miscname, MD_MIRROR) == 0)) 491 if ((result = meta_mn_send_resync_starting(np, ep)) 492 != 0) 493 mde_perror(ep, "Unable to start resync"); 494 md_exit(sp, result); 495 } 496 497 if (meta_lock(sp, TRUE, ep)) { 498 mde_perror(ep, ""); 499 md_exit(sp, 1); 500 } 501 502 if (meta_check_ownership(sp, ep) != 0) { 503 mde_perror(ep, ""); 504 md_exit(sp, 1); 505 } 506 if ((miscname = metagetmiscname(np, ep)) == NULL) { 507 mde_perror(ep, ""); 508 md_exit(sp, 1); 509 } 510 511 /* dispatch based on device type */ 512 if (strcmp(miscname, MD_STRIPE) == 0) { 513 if (stripe_attach(&sp, np, argc, argv, options, ep) != 0) { 514 mde_perror(ep, ""); 515 md_exit(sp, 1); 516 } 517 } else if (strcmp(miscname, MD_RAID) == 0) { 518 if (raid_attach(&sp, np, argc, argv, options, ep) != 0) { 519 mde_perror(ep, ""); 520 md_exit(sp, 1); 521 } 522 } else if (strcmp(miscname, MD_MIRROR) == 0) { 523 if (mirror_attach(&sp, np, argc, argv, options, ep) != 0) { 524 mde_perror(ep, ""); 525 md_exit(sp, 1); 526 } 527 } else if (strcmp(miscname, MD_TRANS) == 0) { 528 md_eprintf(gettext(MD_EOF_TRANS_MSG)); 529 md_exit(sp, 1); 530 } else if (strcmp(miscname, MD_SP) == 0) { 531 if (sp_attach(&sp, np, argc, argv, options, ep) != 0) { 532 mde_perror(ep, ""); 533 md_exit(sp, 1); 534 } 535 } else { 536 md_eprintf(gettext( 537 "%s: invalid metadevice type %s\n"), 538 np->cname, miscname); 539 md_exit(sp, 1); 540 } 541 542 /* return success */ 543 md_exit(sp, 0); 544 /*NOTREACHED*/ 545 return (0); 546 } 547