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