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 * Just in case we're not in a build environment, make sure that 30 * TEXT_DOMAIN gets set to something. 31 */ 32 #if !defined(TEXT_DOMAIN) 33 #define TEXT_DOMAIN "SYS_TEST" 34 #endif 35 36 /* 37 * stripe operations 38 */ 39 40 #include <limits.h> 41 #include <stdlib.h> 42 #include <meta.h> 43 #include <sys/lvm/md_stripe.h> 44 #include <sys/lvm/md_convert.h> 45 46 #define QUOTE(x) #x 47 #define VAL2STR(x) QUOTE(x) 48 49 /* 50 * replace stripe/concat 51 */ 52 int 53 meta_stripe_replace( 54 mdsetname_t *sp, 55 mdname_t *stripenp, 56 mdname_t *oldnp, 57 mdname_t *newnp, 58 mdcmdopts_t options, 59 md_error_t *ep 60 ) 61 { 62 replace_params_t params; 63 md_dev64_t old_dev, 64 new_dev; 65 diskaddr_t new_start_blk, 66 new_end_blk, 67 label, 68 size, 69 start_blk; 70 71 /* should have same set */ 72 assert(sp != NULL); 73 assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))); 74 75 new_dev = newnp->dev; 76 new_start_blk = newnp->start_blk; 77 new_end_blk = newnp->end_blk; 78 79 meta_invalidate_name(stripenp); 80 81 /* the old device binding is now established */ 82 if ((old_dev = oldnp->dev) == NODEV64) 83 return (mdsyserror(ep, ENODEV, oldnp->cname)); 84 85 if (((strcmp(oldnp->rname, newnp->rname) == 0) && 86 (old_dev != new_dev))) { 87 newnp->dev = new_dev; 88 newnp->start_blk = new_start_blk; 89 newnp->end_blk = new_end_blk; 90 } 91 92 if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) 93 return (-1); 94 if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) 95 return (-1); 96 if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) 97 return (-1); 98 if (start_blk >= size) { 99 (void) mdsyserror(ep, ENOSPC, newnp->cname); 100 return (-1); 101 } 102 103 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 104 if (options & MDCMD_DOIT) { 105 if (add_key_name(sp, newnp, NULL, ep) != 0) 106 return (-1); 107 } 108 109 /* 110 * There is no need to call meta_fixdevid() here as this function is 111 * only called by the metareplace -c command which actually does 112 * nothing (in terms of a resync) and thus does nothing with the devid. 113 */ 114 115 (void) memset(¶ms, 0, sizeof (params)); 116 params.mnum = meta_getminor(stripenp->dev); 117 MD_SETDRIVERNAME(¶ms, MD_STRIPE, sp->setno); 118 119 params.cmd = REPLACE_COMP; 120 params.old_dev = old_dev; 121 params.new_dev = new_dev; 122 params.new_key = newnp->key; 123 params.start_blk = newnp->start_blk; 124 params.number_blks = size; 125 /* Is this just a dryrun ? */ 126 if ((options & MDCMD_DOIT) == 0) { 127 params.options |= MDIOCTL_DRYRUN; 128 } 129 if (label == 0) 130 params.has_label = 0; 131 else 132 params.has_label = 1; 133 if (metaioctl(MD_IOCREPLACE, ¶ms, ¶ms.mde, NULL) != 0) { 134 if (options & MDCMD_DOIT) 135 (void) del_key_name(sp, newnp, ep); 136 return (mdstealerror(ep, ¶ms.mde)); 137 } 138 meta_invalidate_name(oldnp); 139 meta_invalidate_name(newnp); 140 meta_invalidate_name(stripenp); 141 142 if (options & MDCMD_PRINT) { 143 (void) printf(dgettext(TEXT_DOMAIN, 144 "%s: device %s is replaced with %s\n"), 145 stripenp->cname, oldnp->cname, newnp->cname); 146 147 } 148 return (0); 149 } 150 151 152 /* 153 * FUNCTION: meta_get_stripe_names() 154 * INPUT: sp - the set name to get stripes from 155 * options - options from the command line 156 * OUTPUT: nlpp - list of all stripe names 157 * ep - return error pointer 158 * RETURNS: int - -1 if error, 0 success 159 * PURPOSE: returns a list of all stripes in the metadb 160 * for all devices in the specified set 161 */ 162 int 163 meta_get_stripe_names( 164 mdsetname_t *sp, 165 mdnamelist_t **nlpp, 166 int options, 167 md_error_t *ep 168 ) 169 { 170 return (meta_get_names(MD_STRIPE, sp, nlpp, options, ep)); 171 } 172 173 /* 174 * free stripe 175 */ 176 void 177 meta_free_stripe( 178 md_stripe_t *stripep 179 ) 180 { 181 uint_t row; 182 183 for (row = 0; (row < stripep->rows.rows_len); ++row) { 184 md_row_t *rp = &stripep->rows.rows_val[row]; 185 186 if (rp->comps.comps_val != NULL) { 187 assert(rp->comps.comps_len > 0); 188 Free(rp->comps.comps_val); 189 } 190 } 191 if (stripep->rows.rows_val != NULL) { 192 assert(stripep->rows.rows_len > 0); 193 Free(stripep->rows.rows_val); 194 } 195 Free(stripep); 196 } 197 198 199 /* 200 * get stripe (common) 201 */ 202 md_stripe_t * 203 meta_get_stripe_common( 204 mdsetname_t *sp, 205 mdname_t *stripenp, 206 int fast, 207 md_error_t *ep 208 ) 209 { 210 mddrivename_t *dnp = stripenp->drivenamep; 211 char *miscname; 212 ms_unit_t *ms; 213 md_stripe_t *stripep; 214 uint_t row; 215 216 /* must have set */ 217 assert(sp != NULL); 218 assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))); 219 220 /* short circuit */ 221 if (dnp->unitp != NULL) { 222 assert(dnp->unitp->type == MD_DEVICE); 223 return ((md_stripe_t *)dnp->unitp); 224 } 225 226 /* get miscname and unit */ 227 if ((miscname = metagetmiscname(stripenp, ep)) == NULL) 228 return (NULL); 229 if (strcmp(miscname, MD_STRIPE) != 0) { 230 (void) mdmderror(ep, MDE_NOT_STRIPE, 231 meta_getminor(stripenp->dev), stripenp->cname); 232 return (NULL); 233 } 234 if ((ms = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL) 235 return (NULL); 236 assert(ms->c.un_type == MD_DEVICE); 237 238 /* allocate stripe */ 239 stripep = Zalloc(sizeof (*stripep)); 240 241 /* allocate rows */ 242 assert(ms->un_nrows > 0); 243 stripep->rows.rows_len = ms->un_nrows; 244 stripep->rows.rows_val = Zalloc(stripep->rows.rows_len * 245 sizeof (*stripep->rows.rows_val)); 246 247 /* get common info */ 248 stripep->common.namep = stripenp; 249 stripep->common.type = ms->c.un_type; 250 stripep->common.state = ms->c.un_status; 251 stripep->common.capabilities = ms->c.un_capabilities; 252 stripep->common.parent = ms->c.un_parent; 253 stripep->common.size = ms->c.un_total_blocks; 254 stripep->common.user_flags = ms->c.un_user_flags; 255 stripep->common.revision = ms->c.un_revision; 256 257 /* get options */ 258 if ((ms->un_hsp_id != MD_HSP_NONE) && 259 ((stripep->hspnamep = metahsphspname(&sp, ms->un_hsp_id, 260 ep)) == NULL)) { 261 goto out; 262 } 263 264 /* get rows */ 265 for (row = 0; (row < ms->un_nrows); ++row) { 266 struct ms_row *mdr = &ms->un_row[row]; 267 struct ms_comp *mdcomp = (void *)&((char *)ms)[ms->un_ocomp]; 268 md_row_t *rp = &stripep->rows.rows_val[row]; 269 uint_t comp, c; 270 271 /* get interlace */ 272 rp->interlace = mdr->un_interlace; 273 274 /* allocate comps */ 275 assert(mdr->un_ncomp > 0); 276 rp->comps.comps_len = mdr->un_ncomp; 277 rp->comps.comps_val = Zalloc(rp->comps.comps_len * 278 sizeof (*rp->comps.comps_val)); 279 280 /* get components */ 281 for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp); 282 ++comp, ++c) { 283 struct ms_comp *mdc = &mdcomp[c]; 284 diskaddr_t comp_start_blk = mdc->un_start_block; 285 md_comp_t *cp = &rp->comps.comps_val[comp]; 286 287 /* get the component name */ 288 cp->compnamep = metakeyname(&sp, mdc->un_key, fast, ep); 289 if (cp->compnamep == NULL) 290 goto out; 291 292 /* if hotspared */ 293 if (mdc->un_mirror.ms_hs_id != 0) { 294 diskaddr_t hs_start_blk = mdc->un_start_block; 295 296 /* get the hotspare name */ 297 cp->hsnamep = metakeyname(&sp, 298 mdc->un_mirror.ms_hs_key, fast, ep); 299 if (cp->hsnamep == NULL) 300 goto out; 301 302 if (getenv("META_DEBUG_START_BLK") != NULL) { 303 if (metagetstart(sp, cp->hsnamep, 304 ep) == MD_DISKADDR_ERROR) 305 mdclrerror(ep); 306 307 if ((cp->hsnamep->start_blk == 0) && 308 (hs_start_blk != 0)) 309 md_eprintf(dgettext(TEXT_DOMAIN, 310 "%s: suspected bad start block," 311 " seems labelled [stripe/hs]\n"), 312 cp->hsnamep->cname); 313 314 if ((cp->hsnamep->start_blk > 0) && 315 (hs_start_blk == 0) && 316 ! ((row == 0) && (comp == 0))) 317 md_eprintf(dgettext(TEXT_DOMAIN, 318 "%s: suspected bad start block, " 319 "seems unlabelled [stripe/hs]\n"), 320 cp->hsnamep->cname); 321 } 322 /* override any start_blk */ 323 cp->hsnamep->start_blk = hs_start_blk; 324 325 /* get the right component start_blk */ 326 comp_start_blk = mdc->un_mirror.ms_orig_blk; 327 } else { 328 if (getenv("META_DEBUG_START_BLK") != NULL) { 329 if (metagetstart(sp, cp->compnamep, 330 ep) == MD_DISKADDR_ERROR) 331 mdclrerror(ep); 332 333 if ((cp->compnamep->start_blk == 0) && 334 (comp_start_blk != 0)) 335 md_eprintf(dgettext(TEXT_DOMAIN, 336 "%s: suspected bad start block," 337 " seems labelled [stripe]"), 338 cp->compnamep->cname); 339 340 if ((cp->compnamep->start_blk > 0) && 341 (comp_start_blk == 0) && 342 ! ((row == 0) && (comp == 0))) 343 md_eprintf(dgettext(TEXT_DOMAIN, 344 "%s: suspected bad start block, " 345 "seems unlabelled [stripe]"), 346 cp->compnamep->cname); 347 } 348 } 349 350 /* override any start_blk */ 351 cp->compnamep->start_blk = comp_start_blk; 352 353 /* get state */ 354 cp->state = mdc->un_mirror.ms_state; 355 356 /* get time of last state change */ 357 cp->timestamp = mdc->un_mirror.ms_timestamp; 358 359 /* get lasterr count */ 360 cp->lasterrcnt = mdc->un_mirror.ms_lasterrcnt; 361 } 362 } 363 364 /* cleanup, return success */ 365 Free(ms); 366 dnp->unitp = (md_common_t *)stripep; 367 return (stripep); 368 369 /* cleanup, return error */ 370 out: 371 Free(ms); 372 meta_free_stripe(stripep); 373 return (NULL); 374 } 375 376 /* 377 * get stripe 378 */ 379 md_stripe_t * 380 meta_get_stripe( 381 mdsetname_t *sp, 382 mdname_t *stripenp, 383 md_error_t *ep 384 ) 385 { 386 return (meta_get_stripe_common(sp, stripenp, 0, ep)); 387 } 388 389 /* 390 * check stripe for dev 391 */ 392 static int 393 in_stripe( 394 mdsetname_t *sp, 395 mdname_t *stripenp, 396 mdname_t *np, 397 diskaddr_t slblk, 398 diskaddr_t nblks, 399 md_error_t *ep 400 ) 401 { 402 md_stripe_t *stripep; 403 uint_t row; 404 405 /* should be in the same set */ 406 assert(sp != NULL); 407 408 /* get unit */ 409 if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL) 410 return (-1); 411 412 /* look in rows */ 413 for (row = 0; (row < stripep->rows.rows_len); ++row) { 414 md_row_t *rp = &stripep->rows.rows_val[row]; 415 uint_t comp; 416 417 /* look in columns */ 418 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 419 md_comp_t *cp = &rp->comps.comps_val[comp]; 420 mdname_t *compnp = cp->compnamep; 421 diskaddr_t comp_sblk; 422 int err; 423 424 /* check same drive since metagetstart() can fail */ 425 if ((err = meta_check_samedrive(np, compnp, ep)) < 0) 426 return (-1); 427 else if (err == 0) 428 continue; 429 430 /* check overlap */ 431 if ((comp_sblk = metagetstart(sp, compnp, ep)) == 432 MD_DISKADDR_ERROR) 433 return (-1); 434 if (meta_check_overlap(stripenp->cname, np, 435 slblk, nblks, compnp, comp_sblk, -1, 436 ep) != 0) { 437 return (-1); 438 } 439 } 440 } 441 442 /* return success */ 443 return (0); 444 } 445 446 /* 447 * check to see if we're in a stripe 448 */ 449 int 450 meta_check_instripe( 451 mdsetname_t *sp, 452 mdname_t *np, 453 diskaddr_t slblk, 454 diskaddr_t nblks, 455 md_error_t *ep 456 ) 457 { 458 mdnamelist_t *stripenlp = NULL; 459 mdnamelist_t *p; 460 int rval = 0; 461 462 /* should have a set */ 463 assert(sp != NULL); 464 465 /* for each stripe */ 466 if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0) 467 return (-1); 468 for (p = stripenlp; (p != NULL); p = p->next) { 469 mdname_t *stripenp = p->namep; 470 471 /* check stripe */ 472 if (in_stripe(sp, stripenp, np, slblk, nblks, ep) != 0) { 473 rval = -1; 474 break; 475 } 476 } 477 478 /* cleanup, return success */ 479 metafreenamelist(stripenlp); 480 return (rval); 481 } 482 483 /* 484 * check component 485 */ 486 int 487 meta_check_component( 488 mdsetname_t *sp, 489 mdname_t *np, 490 int force, 491 md_error_t *ep 492 ) 493 { 494 mdchkopts_t options = (MDCHK_ALLOW_MDDB); 495 md_common_t *mdp; 496 497 /* 498 * See if we are a soft partition: meta_sp_issp() returns 0 if 499 * np points to a soft partition, so the if and else clauses 500 * here represent "not a soft partition" and "soft partition," 501 * respectively. 502 */ 503 if (meta_sp_issp(sp, np, ep) != 0) { 504 /* make sure we have a disk */ 505 if (metachkcomp(np, ep) != 0) 506 return (-1); 507 } else { 508 /* make sure soft partition can parent & doesn't have parent */ 509 if ((mdp = meta_get_unit(sp, np, ep)) == NULL) 510 return (mdmderror(ep, MDE_INVAL_UNIT, NULL, 511 np->cname)); 512 if (mdp->capabilities == MD_CANT_PARENT) 513 return (mdmderror(ep, MDE_INVAL_UNIT, NULL, 514 np->cname)); 515 if (MD_HAS_PARENT(mdp->parent)) { 516 mdname_t *pnp; 517 518 pnp = metamnumname(&sp, mdp->parent, 0, ep); 519 if (pnp == NULL) { 520 return (-1); 521 } 522 523 return (mduseerror(ep, MDE_ALREADY, np->dev, 524 pnp->cname, np->cname)); 525 } 526 } 527 528 /* check to ensure that it is not already in use */ 529 if ((! force) && 530 (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0)) { 531 return (-1); 532 } 533 534 /* make sure it is in the set */ 535 if (meta_check_inset(sp, np, ep) != 0) 536 return (-1); 537 538 /* make sure its not in a metadevice */ 539 if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0) 540 return (-1); 541 542 /* return success */ 543 return (0); 544 } 545 546 /* 547 * print stripe 548 */ 549 static int 550 stripe_print( 551 md_stripe_t *stripep, 552 char *fname, 553 FILE *fp, 554 mdprtopts_t options, 555 md_error_t *ep 556 ) 557 { 558 uint_t row; 559 int rval = -1; 560 561 if (options & PRINT_LARGEDEVICES) { 562 if (stripep->common.revision != MD_64BIT_META_DEV) { 563 rval = 0; 564 goto out; 565 } 566 } 567 568 if (options & PRINT_FN) { 569 if (stripep->common.revision != MD_FN_META_DEV) { 570 rval = 0; 571 goto out; 572 } 573 } 574 575 /* print name and num rows */ 576 if (fprintf(fp, "%s %u", 577 stripep->common.namep->cname, stripep->rows.rows_len) == EOF) 578 goto out; 579 580 /* print rows */ 581 for (row = 0; (row < stripep->rows.rows_len); ++row) { 582 md_row_t *rp = &stripep->rows.rows_val[row]; 583 uint_t comp; 584 585 /* print num components */ 586 if (fprintf(fp, " %u", rp->comps.comps_len) == EOF) 587 goto out; 588 589 /* 590 * Print components. Always print the full path name. 591 */ 592 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 593 md_comp_t *cp = &rp->comps.comps_val[comp]; 594 595 if (fprintf(fp, " %s", cp->compnamep->rname) == EOF) 596 goto out; 597 } 598 599 /* print interlace */ 600 if (rp->comps.comps_len > 1) 601 if (fprintf(fp, " -i %lldb", rp->interlace) == EOF) 602 goto out; 603 604 /* print continuation */ 605 if (row != (stripep->rows.rows_len - 1)) 606 if (fprintf(fp, " \\\n\t") == EOF) 607 goto out; 608 } 609 610 /* print hotspare name */ 611 if (stripep->hspnamep != NULL) 612 if (fprintf(fp, " -h %s", stripep->hspnamep->hspname) == EOF) 613 goto out; 614 615 /* terminate last line */ 616 if (fprintf(fp, "\n") == EOF) 617 goto out; 618 619 /* success */ 620 rval = 0; 621 622 /* cleanup, return error */ 623 out: 624 if (rval != 0) 625 (void) mdsyserror(ep, errno, fname); 626 return (rval); 627 } 628 629 /* 630 * convert component state to name 631 */ 632 char * 633 comp_state_to_name( 634 md_comp_t *mdcp, 635 md_timeval32_t *tvp, 636 uint_t tstate /* Errored tstate flags */ 637 ) 638 { 639 comp_state_t state = mdcp->state; 640 641 /* grab time */ 642 if (tvp != NULL) 643 *tvp = mdcp->timestamp; 644 645 if (tstate != 0) { 646 return (dgettext(TEXT_DOMAIN, "Unavailable")); 647 } 648 649 /* return state */ 650 switch (state) { 651 case CS_OKAY: 652 return (dgettext(TEXT_DOMAIN, "Okay")); 653 case CS_ERRED: 654 return (dgettext(TEXT_DOMAIN, "Maintenance")); 655 case CS_LAST_ERRED: 656 return (dgettext(TEXT_DOMAIN, "Last Erred")); 657 case CS_RESYNC: 658 return (dgettext(TEXT_DOMAIN, "Resyncing")); 659 default: 660 return (dgettext(TEXT_DOMAIN, "invalid")); 661 } 662 } 663 664 /* 665 * print subdevice stripe row 666 */ 667 static int 668 subdev_row_report( 669 mdsetname_t *sp, 670 md_row_t *rp, 671 char *fname, 672 FILE *fp, 673 mdprtopts_t options, 674 uint_t top_tstate, /* Errored tstate flags */ 675 md_error_t *ep 676 ) 677 { 678 uint_t comp; 679 int rval = -1; 680 ddi_devid_t dtp; 681 int len = 0; 682 683 684 /* 685 * building a format string on the fly that will be used 686 * in fprintf. This is to allow really really long ctd names 687 */ 688 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 689 md_comp_t *cp = &rp->comps.comps_val[comp]; 690 char *cname = cp->compnamep->cname; 691 692 len = max(len, strlen(cname)); 693 } 694 695 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device"))); 696 len += 2; 697 /* print header */ 698 if (! (options & PRINT_TIMES)) { 699 if (fprintf(fp, 700 "\t%-*.*s %-12.12s %5.5s %12.12s %5.5s %s\n", 701 len, len, 702 dgettext(TEXT_DOMAIN, "Device"), 703 dgettext(TEXT_DOMAIN, "Start Block"), 704 dgettext(TEXT_DOMAIN, "Dbase"), 705 dgettext(TEXT_DOMAIN, "State"), 706 dgettext(TEXT_DOMAIN, "Reloc"), 707 dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) { 708 goto out; 709 } 710 } else { 711 if (fprintf(fp, 712 "\t%-*s %5s %5s %-11s %-5s %-9s %s\n", 713 len, 714 dgettext(TEXT_DOMAIN, "Device"), 715 dgettext(TEXT_DOMAIN, "Start"), 716 dgettext(TEXT_DOMAIN, "Dbase"), 717 dgettext(TEXT_DOMAIN, "State"), 718 dgettext(TEXT_DOMAIN, "Reloc"), 719 dgettext(TEXT_DOMAIN, "Hot Spare"), 720 dgettext(TEXT_DOMAIN, "Time")) == EOF) { 721 goto out; 722 } 723 } 724 725 726 /* print components */ 727 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 728 md_comp_t *cp = &rp->comps.comps_val[comp]; 729 mdname_t *namep = cp->compnamep; 730 char *cname = namep->cname; 731 diskaddr_t start_blk; 732 int has_mddb; 733 char *has_mddb_str; 734 char *comp_state; 735 md_timeval32_t tv; 736 char *hsname = ((cp->hsnamep != NULL) ? 737 cp->hsnamep->cname : ""); 738 char *devid = " "; 739 mdname_t *didnp = NULL; 740 uint_t tstate = 0; 741 742 /* get info */ 743 if ((start_blk = metagetstart(sp, namep, ep)) == 744 MD_DISKADDR_ERROR) { 745 return (-1); 746 } 747 if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) { 748 return (-1); 749 } 750 if (has_mddb) 751 has_mddb_str = dgettext(TEXT_DOMAIN, "Yes"); 752 else 753 has_mddb_str = dgettext(TEXT_DOMAIN, "No"); 754 755 /* 756 * If the component is a metadevice, print out either 757 * unavailable or the state of the metadevice, if not 758 * a metadevice, print nothing if the state of the 759 * stripe is unavailable 760 */ 761 if (metaismeta(namep)) { 762 if (meta_get_tstate(namep->dev, &tstate, ep) != 0) 763 return (-1); 764 comp_state = comp_state_to_name(cp, &tv, tstate & 765 MD_DEV_ERRORED); 766 } else { 767 /* 768 * if top_tstate is set, that implies that you have 769 * a ctd type device with an unavailable metadevice 770 * on top of it. If so, print a - for it's state 771 */ 772 if (top_tstate != 0) 773 comp_state = "-"; 774 else 775 comp_state = comp_state_to_name(cp, &tv, 776 tstate & MD_DEV_ERRORED); 777 } 778 779 /* populate the key in the name_p structure */ 780 if ((didnp = metadevname(&sp, namep->dev, ep)) 781 == NULL) { 782 return (-1); 783 } 784 785 /* determine if devid does NOT exist */ 786 if (options & PRINT_DEVID) { 787 if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep), 788 didnp->key, ep)) == NULL) 789 devid = dgettext(TEXT_DOMAIN, "No "); 790 else { 791 devid = dgettext(TEXT_DOMAIN, "Yes"); 792 free(dtp); 793 } 794 } 795 /* print info */ 796 /* 797 * building a format string on the fly that will be used 798 * in fprintf. This is to allow really really long ctd names 799 */ 800 if (! (options & PRINT_TIMES)) { 801 if (fprintf(fp, 802 "\t%-*s %8lld %-5.5s %12.12s %5.5s %s\n", 803 len, cname, start_blk, 804 has_mddb_str, comp_state, devid, hsname) == EOF) { 805 goto out; 806 } 807 } else { 808 char *timep = meta_print_time(&tv); 809 810 if (fprintf(fp, 811 "\t%-*s %5lld %-5s %-11s %-5s %-9s %s\n", 812 len, cname, start_blk, 813 has_mddb_str, comp_state, devid, hsname, 814 timep) == EOF) { 815 goto out; 816 } 817 } 818 } 819 820 /* success */ 821 rval = 0; 822 823 /* cleanup, return error */ 824 out: 825 if (rval != 0) 826 (void) mdsyserror(ep, errno, fname); 827 return (rval); 828 } 829 830 /* 831 * print toplevel stripe row 832 */ 833 /*ARGSUSED4*/ 834 static int 835 toplev_row_report( 836 mdsetname_t *sp, 837 md_row_t *rp, 838 char *fname, 839 FILE *fp, 840 mdprtopts_t options, 841 md_error_t *ep 842 ) 843 { 844 uint_t comp; 845 int rval = -1; 846 char *devid = " "; 847 mdname_t *didnp = NULL; 848 int len = 0; 849 850 /* 851 * building a format string on the fly that will be used 852 * in fprintf. This is to allow really really long ctd names 853 */ 854 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 855 len = max(len, 856 strlen(rp->comps.comps_val[comp].compnamep->cname)); 857 } 858 859 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device"))); 860 len += 2; 861 /* print header */ 862 if (fprintf(fp, 863 "\t%-*.*s %-12.12s %-5.5s\t%s\n", 864 len, len, 865 dgettext(TEXT_DOMAIN, "Device"), 866 dgettext(TEXT_DOMAIN, "Start Block"), 867 dgettext(TEXT_DOMAIN, "Dbase"), 868 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 869 goto out; 870 } 871 872 /* print components */ 873 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 874 md_comp_t *cp = &rp->comps.comps_val[comp]; 875 mdname_t *namep = cp->compnamep; 876 char *cname = namep->cname; 877 diskaddr_t start_blk; 878 int has_mddb; 879 char *has_mddb_str; 880 ddi_devid_t dtp; 881 882 /* get info */ 883 if ((start_blk = metagetstart(sp, namep, ep)) == 884 MD_DISKADDR_ERROR) { 885 return (-1); 886 } 887 if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) { 888 return (-1); 889 } 890 if (has_mddb) 891 has_mddb_str = dgettext(TEXT_DOMAIN, "Yes"); 892 else 893 has_mddb_str = dgettext(TEXT_DOMAIN, "No"); 894 895 /* populate the key in the name_p structure */ 896 if ((didnp = metadevname(&sp, namep->dev, ep)) 897 == NULL) { 898 return (-1); 899 } 900 901 /* determine if devid does NOT exist */ 902 if (options & PRINT_DEVID) { 903 if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep), 904 didnp->key, ep)) == NULL) { 905 devid = dgettext(TEXT_DOMAIN, "No "); 906 } else { 907 devid = dgettext(TEXT_DOMAIN, "Yes"); 908 free(dtp); 909 } 910 } 911 /* print info */ 912 /* 913 * building a format string on the fly that will be used 914 * in fprintf. This is to allow really really long ctd names 915 */ 916 if (fprintf(fp, 917 "\t%-*s %8lld %-5.5s\t%s\n", len, 918 cname, start_blk, has_mddb_str, devid) == EOF) { 919 goto out; 920 } 921 } 922 923 /* success */ 924 rval = 0; 925 926 /* cleanup, return error */ 927 out: 928 if (rval != 0) 929 (void) mdsyserror(ep, errno, fname); 930 return (rval); 931 } 932 933 /* 934 * print stripe options 935 */ 936 int 937 meta_print_stripe_options( 938 mdhspname_t *hspnamep, 939 char *fname, 940 FILE *fp, 941 md_error_t *ep 942 ) 943 { 944 char *hspname = ((hspnamep != NULL) ? hspnamep->hspname : 945 dgettext(TEXT_DOMAIN, "none")); 946 int rval = -1; 947 948 /* print options */ 949 if (fprintf(fp, dgettext(TEXT_DOMAIN, 950 " Hot spare pool: %s\n"), hspname) == EOF) { 951 goto out; 952 } 953 954 /* success */ 955 rval = 0; 956 957 /* cleanup, return error */ 958 out: 959 if (rval != 0) 960 (void) mdsyserror(ep, errno, fname); 961 return (rval); 962 } 963 964 /* 965 * report stripe 966 */ 967 static int 968 stripe_report( 969 mdsetname_t *sp, 970 md_stripe_t *stripep, 971 mdnamelist_t **nlpp, 972 char *fname, 973 FILE *fp, 974 mdprtopts_t options, 975 md_error_t *ep 976 ) 977 { 978 uint_t row; 979 int rval = -1; 980 uint_t tstate = 0; 981 982 /* 983 * if the -B option has been specified check to see if the 984 * metadevice is s "big" one and print if so, also if a 985 * big device we need to store the ctd involved for use in 986 * printing out the relocation information. 987 */ 988 if (options & PRINT_LARGEDEVICES) { 989 if ((stripep->common.revision & MD_64BIT_META_DEV) == 0) { 990 rval = 0; 991 goto out; 992 } else { 993 if (meta_getdevs(sp, stripep->common.namep, 994 nlpp, ep) != 0) 995 goto out; 996 } 997 } 998 999 /* 1000 * if the -D option has been specified check to see if the 1001 * metadevice has a descriptive name and print if so, also if a 1002 * descriptive device name we need to store the ctd involved 1003 * for use in printing out the relocation information. 1004 */ 1005 if (options & PRINT_FN) { 1006 if ((stripep->common.revision & MD_FN_META_DEV) == 0) { 1007 rval = 0; 1008 goto out; 1009 } else { 1010 if (meta_getdevs(sp, stripep->common.namep, 1011 nlpp, ep) != 0) 1012 goto out; 1013 } 1014 } 1015 1016 /* print header */ 1017 if (options & PRINT_HEADER) { 1018 if (fprintf(fp, "%s: Concat/Stripe\n", 1019 stripep->common.namep->cname) == EOF) { 1020 goto out; 1021 } 1022 1023 } 1024 1025 /* print hotspare pool */ 1026 if (stripep->hspnamep != NULL) { 1027 if (meta_print_stripe_options(stripep->hspnamep, 1028 fname, fp, ep) != 0) { 1029 return (-1); 1030 } 1031 } 1032 1033 if (metaismeta(stripep->common.namep)) { 1034 if (meta_get_tstate(stripep->common.namep->dev, &tstate, ep) 1035 != 0) 1036 return (-1); 1037 } 1038 if ((tstate & MD_DEV_ERRORED) != 0) { 1039 if (fprintf(fp, dgettext(TEXT_DOMAIN, 1040 " State: Unavailable\n" 1041 " Reconnect disk and invoke: metastat -i\n")) == EOF) { 1042 goto out; 1043 } 1044 } 1045 1046 /* print size */ 1047 if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %lld blocks (%s)\n"), 1048 stripep->common.size, 1049 meta_number_to_string(stripep->common.size, DEV_BSIZE)) 1050 == EOF) { 1051 goto out; 1052 } 1053 1054 /* print rows */ 1055 for (row = 0; (row < stripep->rows.rows_len); ++row) { 1056 md_row_t *rp = &stripep->rows.rows_val[row]; 1057 1058 /* print stripe and interlace */ 1059 if (rp->comps.comps_len > 1) { 1060 if (fprintf(fp, dgettext(TEXT_DOMAIN, 1061 " Stripe %u: (interlace: %lld blocks)\n"), 1062 row, rp->interlace) == EOF) { 1063 goto out; 1064 } 1065 } else { 1066 if (fprintf(fp, dgettext(TEXT_DOMAIN, 1067 " Stripe %u:\n"), 1068 row) == EOF) { 1069 goto out; 1070 } 1071 } 1072 1073 /* print components appropriately */ 1074 if (MD_HAS_PARENT(stripep->common.parent)) { 1075 if (subdev_row_report(sp, rp, fname, fp, options, 1076 tstate & MD_DEV_ERRORED, ep) != 0) { 1077 return (-1); 1078 } 1079 } else { 1080 if (toplev_row_report(sp, rp, fname, fp, options, 1081 ep) != 0) { 1082 return (-1); 1083 } 1084 } 1085 } 1086 1087 /* add extra line */ 1088 if (fprintf(fp, "\n") == EOF) 1089 goto out; 1090 1091 /* success */ 1092 rval = 0; 1093 1094 /* cleanup, return error */ 1095 out: 1096 if (rval != 0) 1097 (void) mdsyserror(ep, errno, fname); 1098 return (rval); 1099 } 1100 1101 /* 1102 * print/report stripe 1103 */ 1104 int 1105 meta_stripe_print( 1106 mdsetname_t *sp, 1107 mdname_t *stripenp, 1108 mdnamelist_t **nlpp, 1109 char *fname, 1110 FILE *fp, 1111 mdprtopts_t options, 1112 md_error_t *ep 1113 ) 1114 { 1115 md_stripe_t *stripep; 1116 int row, comp; 1117 1118 /* should have same set */ 1119 assert(sp != NULL); 1120 assert((stripenp == NULL) || 1121 (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)))); 1122 1123 /* print all stripes */ 1124 if (stripenp == NULL) { 1125 mdnamelist_t *nlp = NULL; 1126 mdnamelist_t *p; 1127 int cnt; 1128 int rval = 0; 1129 1130 /* get list */ 1131 if ((cnt = meta_get_stripe_names(sp, &nlp, options, ep)) < 0) 1132 return (-1); 1133 else if (cnt == 0) 1134 return (0); 1135 1136 /* recurse */ 1137 for (p = nlp; (p != NULL); p = p->next) { 1138 mdname_t *np = p->namep; 1139 1140 if (meta_stripe_print(sp, np, nlpp, fname, fp, 1141 options, ep) != 0) 1142 rval = -1; 1143 } 1144 1145 /* cleanup, return success */ 1146 metafreenamelist(nlp); 1147 return (rval); 1148 } 1149 1150 /* get unit structure */ 1151 if ((stripep = meta_get_stripe_common(sp, stripenp, 1152 ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL) 1153 return (-1); 1154 1155 /* check for parented */ 1156 if ((! (options & PRINT_SUBDEVS)) && 1157 (MD_HAS_PARENT(stripep->common.parent))) { 1158 return (0); 1159 } 1160 1161 /* print appropriate detail */ 1162 if (options & PRINT_SHORT) { 1163 if (stripe_print(stripep, fname, fp, options, ep) != 0) 1164 return (-1); 1165 } else { 1166 if (stripe_report(sp, stripep, nlpp, fname, fp, options, 1167 ep) != 0) 1168 return (-1); 1169 } 1170 1171 /* Recurse on components that are metadevices */ 1172 for (row = 0; (row < stripep->rows.rows_len); ++row) { 1173 md_row_t *rp = &stripep->rows.rows_val[row]; 1174 1175 /* look for components that are metadevices */ 1176 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 1177 md_comp_t *cp = &rp->comps.comps_val[comp]; 1178 mdname_t *namep = cp->compnamep; 1179 1180 if ((metaismeta(namep)) && 1181 (meta_print_name(sp, namep, nlpp, fname, fp, 1182 (options | PRINT_HEADER | PRINT_SUBDEVS), 1183 NULL, ep) != 0)) { 1184 return (-1); 1185 } 1186 } 1187 } 1188 return (0); 1189 } 1190 1191 /* 1192 * find stripe component to replace 1193 */ 1194 int 1195 meta_find_erred_comp( 1196 mdsetname_t *sp, 1197 mdname_t *stripenp, 1198 mdname_t **compnpp, 1199 comp_state_t *compstate, 1200 md_error_t *ep 1201 ) 1202 { 1203 md_stripe_t *stripep; 1204 md_comp_t *compp = NULL; 1205 uint_t lasterrcnt = 0; 1206 uint_t row; 1207 1208 /* get stripe */ 1209 *compnpp = NULL; 1210 if ((stripep = meta_get_stripe_common(sp, stripenp, 1, ep)) == NULL) 1211 return (-1); 1212 1213 /* 1214 * Try to find the first erred component. 1215 * If there is not one, then look for the 1216 * first last_erred component. 1217 */ 1218 for (row = 0; (row < stripep->rows.rows_len); ++row) { 1219 md_row_t *rp = &stripep->rows.rows_val[row]; 1220 uint_t comp; 1221 1222 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 1223 md_comp_t *cp = &rp->comps.comps_val[comp]; 1224 1225 if ((cp->state == CS_ERRED) && ((compp == NULL) || 1226 (cp->lasterrcnt < lasterrcnt))) { 1227 compp = cp; 1228 lasterrcnt = cp->lasterrcnt; 1229 } 1230 } 1231 } 1232 for (row = 0; (row < stripep->rows.rows_len); ++row) { 1233 md_row_t *rp = &stripep->rows.rows_val[row]; 1234 uint_t comp; 1235 1236 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 1237 md_comp_t *cp = &rp->comps.comps_val[comp]; 1238 1239 if ((cp->state == CS_LAST_ERRED) && ((compp == NULL) || 1240 (cp->lasterrcnt < lasterrcnt))) { 1241 compp = cp; 1242 lasterrcnt = cp->lasterrcnt; 1243 } 1244 } 1245 } 1246 1247 /* return component */ 1248 if (compp != NULL) { 1249 *compnpp = compp->compnamep; 1250 *compstate = compp->state; 1251 } 1252 1253 /* return success */ 1254 return (0); 1255 } 1256 1257 /* 1258 * invalidate component names 1259 */ 1260 static int 1261 invalidate_components( 1262 mdsetname_t *sp, 1263 mdname_t *stripenp, 1264 md_error_t *ep 1265 ) 1266 { 1267 md_stripe_t *stripep; 1268 uint_t row; 1269 1270 if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL) 1271 return (-1); 1272 for (row = 0; (row < stripep->rows.rows_len); ++row) { 1273 md_row_t *rp = &stripep->rows.rows_val[row]; 1274 uint_t comp; 1275 1276 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 1277 md_comp_t *cp = &rp->comps.comps_val[comp]; 1278 mdname_t *compnp = cp->compnamep; 1279 1280 meta_invalidate_name(compnp); 1281 } 1282 } 1283 return (0); 1284 } 1285 1286 /* 1287 * attach components to stripe 1288 */ 1289 int 1290 meta_stripe_attach( 1291 mdsetname_t *sp, 1292 mdname_t *stripenp, 1293 mdnamelist_t *nlp, 1294 diskaddr_t interlace, 1295 mdcmdopts_t options, 1296 md_error_t *ep 1297 ) 1298 { 1299 mdnamelist_t *lp; 1300 ms_unit_t *old_un, *new_un; 1301 struct ms_row *mdr, *new_mdr; 1302 uint_t newcomps, ncomps, icomp; 1303 uint_t row; 1304 size_t mdsize, first_comp; 1305 diskaddr_t new_blks; 1306 diskaddr_t limit; 1307 diskaddr_t disk_size = 0; 1308 ms_comp_t *mdcomp, *new_comp; 1309 uint_t write_reinstruct = 0; 1310 uint_t read_reinstruct = 0; 1311 mdnamelist_t *keynlp = NULL; 1312 uint_t round_cyl = 1; 1313 minor_t parent; 1314 md_grow_params_t mgp; 1315 int rval = -1; 1316 md_timeval32_t creation_time; 1317 int create_flag = MD_CRO_32BIT; 1318 1319 /* should have a set */ 1320 assert(sp != NULL); 1321 assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))); 1322 1323 /* check type */ 1324 if (metachkmeta(stripenp, ep) != 0) 1325 return (-1); 1326 1327 /* check and count components */ 1328 assert(nlp != NULL); 1329 newcomps = 0; 1330 for (lp = nlp; (lp != NULL); lp = lp->next) { 1331 mdname_t *np = lp->namep; 1332 mdnamelist_t *p; 1333 1334 /* check against existing devices */ 1335 if (meta_check_component(sp, np, 0, ep) != 0) 1336 return (-1); 1337 1338 /* check against ourselves */ 1339 for (p = lp->next; (p != NULL); p = p->next) { 1340 if (meta_check_overlap(np->cname, np, 0, -1, 1341 p->namep, 0, -1, ep) != 0) { 1342 return (-1); 1343 } 1344 } 1345 1346 /* count */ 1347 ++newcomps; 1348 } 1349 1350 /* get old unit */ 1351 if ((old_un = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL) 1352 return (-1); 1353 1354 /* if zero, inherit the last rows interlace value */ 1355 if (interlace == 0) { 1356 mdr = &old_un->un_row[old_un->un_nrows - 1]; 1357 interlace = mdr->un_interlace; 1358 } 1359 1360 /* 1361 * calculate size of new unit structure 1362 */ 1363 1364 /* unit + rows */ 1365 mdsize = sizeof (ms_unit_t) - sizeof (struct ms_row); 1366 mdsize += sizeof (struct ms_row) * (old_un->un_nrows + 1); 1367 1368 /* number of new components being added */ 1369 ncomps = newcomps; 1370 1371 /* count the # of components in the old unit */ 1372 mdr = &old_un->un_row[0]; 1373 for (row = 0; (row < old_un->un_nrows); row++) 1374 ncomps += mdr[row].un_ncomp; 1375 first_comp = roundup(mdsize, sizeof (long long)); 1376 mdsize += sizeof (ms_comp_t) * ncomps + (first_comp - mdsize); 1377 1378 /* allocate new unit */ 1379 new_un = Zalloc(mdsize); 1380 new_un->un_ocomp = first_comp; 1381 1382 /* compute new data */ 1383 new_mdr = &new_un->un_row[old_un->un_nrows]; 1384 new_mdr->un_icomp = ncomps - newcomps; 1385 new_mdr->un_ncomp = newcomps; 1386 new_mdr->un_blocks = 0; 1387 new_mdr->un_cum_blocks = 1388 old_un->un_row[old_un->un_nrows - 1].un_cum_blocks; 1389 new_mdr->un_interlace = interlace; 1390 1391 /* for each new device */ 1392 mdcomp = (struct ms_comp *)(void *)&((char *)new_un)[new_un->un_ocomp]; 1393 icomp = new_mdr->un_icomp; 1394 if (meta_gettimeofday(&creation_time) == -1) 1395 return (mdsyserror(ep, errno, NULL)); 1396 for (lp = nlp; (lp != NULL); lp = lp->next) { 1397 mdname_t *np = lp->namep; 1398 diskaddr_t size, start_blk; 1399 mdgeom_t *geomp; 1400 1401 /* figure out how big */ 1402 if ((size = metagetsize(np, ep)) == MD_DISKADDR_ERROR) 1403 goto out; 1404 if ((start_blk = metagetstart(sp, np, ep)) == 1405 MD_DISKADDR_ERROR) 1406 goto out; 1407 if (start_blk >= size) { 1408 (void) mdsyserror(ep, ENOSPC, np->cname); 1409 goto out; 1410 } 1411 size -= start_blk; 1412 if (newcomps > 1) 1413 size = rounddown(size, interlace); 1414 1415 /* adjust for smallest disk */ 1416 if (disk_size == 0) { 1417 disk_size = size; 1418 } else if (size < disk_size) { 1419 disk_size = size; 1420 } 1421 1422 /* get worst reinstructs */ 1423 if ((geomp = metagetgeom(np, ep)) == NULL) 1424 goto out; 1425 if (geomp->write_reinstruct > write_reinstruct) 1426 write_reinstruct = geomp->write_reinstruct; 1427 if (geomp->read_reinstruct > read_reinstruct) 1428 read_reinstruct = geomp->read_reinstruct; 1429 1430 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 1431 if (options & MDCMD_DOIT) { 1432 /* store name in namespace */ 1433 if (add_key_name(sp, np, &keynlp, ep) != 0) 1434 goto out; 1435 } 1436 1437 /* build new component */ 1438 new_comp = &mdcomp[icomp++]; 1439 new_comp->un_key = np->key; 1440 new_comp->un_dev = np->dev; 1441 new_comp->un_start_block = start_blk; 1442 new_comp->un_mirror.ms_state = CS_OKAY; 1443 new_comp->un_mirror.ms_timestamp = creation_time; 1444 } 1445 1446 limit = LLONG_MAX; 1447 1448 /* compute new size */ 1449 new_mdr->un_blocks = new_mdr->un_ncomp * disk_size; 1450 new_blks = new_mdr->un_cum_blocks + new_mdr->un_blocks; 1451 if (new_blks > limit) { 1452 new_mdr->un_cum_blocks = limit; 1453 new_blks = limit; 1454 md_eprintf(dgettext(TEXT_DOMAIN, 1455 "unit size overflow, limit is %lld blocks\n"), 1456 limit); 1457 } else { 1458 new_mdr->un_cum_blocks += new_mdr->un_blocks; 1459 } 1460 new_un->c.un_actual_tb = new_mdr->un_cum_blocks; 1461 new_un->un_nrows = old_un->un_nrows + 1; 1462 1463 /* adjust geometry */ 1464 new_un->c.un_nhead = old_un->c.un_nhead; 1465 new_un->c.un_nsect = old_un->c.un_nsect; 1466 new_un->c.un_rpm = old_un->c.un_rpm; 1467 new_un->c.un_wr_reinstruct = old_un->c.un_wr_reinstruct; 1468 new_un->c.un_rd_reinstruct = old_un->c.un_rd_reinstruct; 1469 if (meta_adjust_geom((md_unit_t *)new_un, stripenp, 1470 write_reinstruct, read_reinstruct, round_cyl, ep) != 0) 1471 goto out; 1472 1473 /* if in dryrun mode, we are done here. */ 1474 if ((options & MDCMD_DOIT) == 0) { 1475 if (options & MDCMD_PRINT) { 1476 if (newcomps == 1) { 1477 (void) printf(dgettext(TEXT_DOMAIN, 1478 "%s: attaching component would suceed\n"), 1479 stripenp->cname); 1480 } else { 1481 (void) printf(dgettext(TEXT_DOMAIN, 1482 "%s: attaching components would suceed\n"), 1483 stripenp->cname); 1484 } 1485 } 1486 rval = 0; /* success */ 1487 goto out; 1488 } 1489 1490 create_flag = meta_check_devicesize(new_un->c.un_total_blocks); 1491 1492 /* grow stripe */ 1493 (void) memset(&mgp, 0, sizeof (mgp)); 1494 mgp.mnum = MD_SID(old_un); 1495 MD_SETDRIVERNAME(&mgp, MD_STRIPE, sp->setno); 1496 mgp.size = mdsize; 1497 mgp.mdp = (uintptr_t)new_un; 1498 mgp.nrows = old_un->un_nrows; 1499 if (create_flag == MD_CRO_32BIT) { 1500 mgp.options = MD_CRO_32BIT; 1501 new_un->c.un_revision &= ~MD_64BIT_META_DEV; 1502 } else { 1503 mgp.options = MD_CRO_64BIT; 1504 new_un->c.un_revision |= MD_64BIT_META_DEV; 1505 } 1506 1507 if ((MD_HAS_PARENT(old_un->c.un_parent)) && 1508 (old_un->c.un_parent != MD_MULTI_PARENT)) { 1509 mgp.npar = 1; 1510 parent = old_un->c.un_parent; 1511 mgp.par = (uintptr_t)(&parent); 1512 } 1513 1514 if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, NULL) != 0) { 1515 (void) mdstealerror(ep, &mgp.mde); 1516 goto out; 1517 } 1518 1519 /* clear cache */ 1520 if (invalidate_components(sp, stripenp, ep) != 0) 1521 goto out; 1522 meta_invalidate_name(stripenp); 1523 1524 /* let em know */ 1525 if (options & MDCMD_PRINT) { 1526 if (newcomps == 1) { 1527 (void) printf(dgettext(TEXT_DOMAIN, 1528 "%s: component is attached\n"), stripenp->cname); 1529 } else { 1530 (void) printf(dgettext(TEXT_DOMAIN, 1531 "%s: components are attached\n"), stripenp->cname); 1532 } 1533 (void) fflush(stdout); 1534 } 1535 1536 /* grow any parents */ 1537 if (meta_concat_parent(sp, stripenp, ep) != 0) 1538 return (-1); 1539 1540 rval = 0; /* success */ 1541 1542 /* cleanup, return error */ 1543 out: 1544 Free(old_un); 1545 Free(new_un); 1546 if (options & MDCMD_DOIT) { 1547 if (rval != 0) 1548 (void) del_key_names(sp, keynlp, NULL); 1549 metafreenamelist(keynlp); 1550 } 1551 return (rval); 1552 } 1553 1554 /* 1555 * get stripe parameters 1556 */ 1557 int 1558 meta_stripe_get_params( 1559 mdsetname_t *sp, 1560 mdname_t *stripenp, 1561 ms_params_t *paramsp, 1562 md_error_t *ep 1563 ) 1564 { 1565 md_stripe_t *stripep; 1566 1567 /* should have a set */ 1568 assert(sp != NULL); 1569 assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))); 1570 1571 /* check name */ 1572 if (metachkmeta(stripenp, ep) != 0) 1573 return (-1); 1574 1575 /* get unit */ 1576 if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL) 1577 return (-1); 1578 1579 /* return parameters */ 1580 (void) memset(paramsp, 0, sizeof (*paramsp)); 1581 if (stripep->hspnamep == NULL) 1582 paramsp->hsp_id = MD_HSP_NONE; 1583 else 1584 paramsp->hsp_id = stripep->hspnamep->hsp; 1585 return (0); 1586 } 1587 1588 /* 1589 * set stripe parameters 1590 */ 1591 int 1592 meta_stripe_set_params( 1593 mdsetname_t *sp, 1594 mdname_t *stripenp, 1595 ms_params_t *paramsp, 1596 md_error_t *ep 1597 ) 1598 { 1599 md_stripe_params_t msp; 1600 1601 /* should have a set */ 1602 assert(sp != NULL); 1603 assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))); 1604 1605 /* check name */ 1606 if (metachkmeta(stripenp, ep) != 0) 1607 return (-1); 1608 1609 /* set parameters */ 1610 (void) memset(&msp, 0, sizeof (msp)); 1611 MD_SETDRIVERNAME(&msp, MD_STRIPE, sp->setno); 1612 msp.mnum = meta_getminor(stripenp->dev); 1613 msp.params = *paramsp; 1614 if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, stripenp->cname) != 0) 1615 return (mdstealerror(ep, &msp.mde)); 1616 1617 /* clear cache */ 1618 meta_invalidate_name(stripenp); 1619 1620 /* return success */ 1621 return (0); 1622 } 1623 1624 /* 1625 * check for dups in the stripe itself 1626 */ 1627 static int 1628 check_twice( 1629 md_stripe_t *stripep, 1630 uint_t row, 1631 uint_t comp, 1632 md_error_t *ep 1633 ) 1634 { 1635 mdname_t *stripenp = stripep->common.namep; 1636 mdname_t *thisnp; 1637 uint_t r; 1638 1639 thisnp = stripep->rows.rows_val[row].comps.comps_val[comp].compnamep; 1640 for (r = 0; (r <= row); ++r) { 1641 md_row_t *rp = &stripep->rows.rows_val[r]; 1642 uint_t e = ((r == row) ? comp : rp->comps.comps_len); 1643 uint_t c; 1644 1645 for (c = 0; (c < e); ++c) { 1646 md_comp_t *cp = &rp->comps.comps_val[c]; 1647 mdname_t *compnp = cp->compnamep; 1648 1649 if (meta_check_overlap(stripenp->cname, thisnp, 0, -1, 1650 compnp, 0, -1, ep) != 0) { 1651 return (-1); 1652 } 1653 } 1654 } 1655 return (0); 1656 } 1657 1658 /* 1659 * default stripe interlace 1660 */ 1661 diskaddr_t 1662 meta_default_stripe_interlace(void) 1663 { 1664 diskaddr_t interlace; 1665 1666 /* default to 512k, round up if necessary */ 1667 interlace = btodb(512 * 1024); 1668 if (interlace < btodb(MININTERLACE)) 1669 interlace = roundup(MININTERLACE, interlace); 1670 return (interlace); 1671 } 1672 1673 /* 1674 * convert interlaces 1675 */ 1676 int 1677 meta_stripe_check_interlace( 1678 diskaddr_t interlace, 1679 char *uname, 1680 md_error_t *ep 1681 ) 1682 { 1683 if ((interlace < btodb(MININTERLACE)) || 1684 (interlace > btodb(MAXINTERLACE))) { 1685 return (mderror(ep, MDE_BAD_INTERLACE, uname)); 1686 } 1687 return (0); 1688 } 1689 1690 1691 /* 1692 * check stripe 1693 */ 1694 int 1695 meta_check_stripe( 1696 mdsetname_t *sp, 1697 md_stripe_t *stripep, 1698 mdcmdopts_t options, 1699 md_error_t *ep 1700 ) 1701 { 1702 mdname_t *stripenp = stripep->common.namep; 1703 int force = ((options & MDCMD_FORCE) ? 1 : 0); 1704 int doit = ((options & MDCMD_DOIT) ? 1 : 0); 1705 int updateit = ((options & MDCMD_UPDATE) ? 1 : 0); 1706 uint_t row; 1707 1708 /* check rows */ 1709 if (stripep->rows.rows_len < 1) { 1710 return (mdmderror(ep, MDE_BAD_STRIPE, 1711 meta_getminor(stripenp->dev), stripenp->cname)); 1712 } 1713 for (row = 0; (row < stripep->rows.rows_len); ++row) { 1714 md_row_t *rp = &stripep->rows.rows_val[row]; 1715 uint_t comp; 1716 1717 /* check number */ 1718 if (rp->comps.comps_len < 1) { 1719 return (mdmderror(ep, MDE_BAD_STRIPE, 1720 meta_getminor(stripenp->dev), stripenp->cname)); 1721 } 1722 1723 /* compute default interlace */ 1724 if (rp->interlace == 0) { 1725 rp->interlace = meta_default_stripe_interlace(); 1726 } 1727 1728 /* check interlace */ 1729 if (meta_stripe_check_interlace(rp->interlace, stripenp->cname, 1730 ep) != 0) { 1731 return (-1); 1732 } 1733 1734 /* check components */ 1735 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 1736 md_comp_t *cp = &rp->comps.comps_val[comp]; 1737 mdname_t *compnp = cp->compnamep; 1738 diskaddr_t start_blk, size; 1739 1740 /* check component */ 1741 if (!updateit) { 1742 if (meta_check_component(sp, compnp, 1743 force, ep) != 0) 1744 return (-1); 1745 if (((start_blk = metagetstart(sp, compnp, 1746 ep)) == MD_DISKADDR_ERROR) || 1747 ((size = metagetsize(compnp, ep)) == 1748 MD_DISKADDR_ERROR)) { 1749 return (-1); 1750 } 1751 if (start_blk >= size) 1752 return (mdsyserror(ep, ENOSPC, 1753 compnp->cname)); 1754 size -= start_blk; 1755 size = rounddown(size, rp->interlace); 1756 if (size == 0) 1757 return (mdsyserror(ep, ENOSPC, 1758 compnp->cname)); 1759 } 1760 1761 /* check this stripe too */ 1762 if (check_twice(stripep, row, comp, ep) != 0) 1763 return (-1); 1764 } 1765 } 1766 1767 /* check hotspare pool name */ 1768 if (doit) { 1769 if ((stripep->hspnamep != NULL) && 1770 (metachkhsp(sp, stripep->hspnamep, ep) != 0)) { 1771 return (-1); 1772 } 1773 } 1774 1775 /* return success */ 1776 return (0); 1777 } 1778 1779 /* 1780 * setup stripe geometry 1781 */ 1782 static int 1783 stripe_geom( 1784 md_stripe_t *stripep, 1785 ms_unit_t *ms, 1786 md_error_t *ep 1787 ) 1788 { 1789 uint_t nrow = stripep->rows.rows_len; 1790 uint_t write_reinstruct = 0; 1791 uint_t read_reinstruct = 0; 1792 uint_t round_cyl = 1; 1793 uint_t row; 1794 mdgeom_t *geomp; 1795 diskaddr_t first_row_size = 0; 1796 char *miscname; 1797 int is_sp = 0; 1798 1799 /* get worst reinstructs */ 1800 for (row = 0; (row < nrow); ++row) { 1801 md_row_t *rp = &stripep->rows.rows_val[row]; 1802 uint_t ncomp = rp->comps.comps_len; 1803 uint_t comp; 1804 1805 for (comp = 0; (comp < ncomp); ++comp) { 1806 md_comp_t *cp = &rp->comps.comps_val[comp]; 1807 mdname_t *compnp = cp->compnamep; 1808 1809 if ((geomp = metagetgeom(compnp, ep)) == NULL) 1810 return (-1); 1811 if (geomp->write_reinstruct > write_reinstruct) 1812 write_reinstruct = geomp->write_reinstruct; 1813 if (geomp->read_reinstruct > read_reinstruct) 1814 read_reinstruct = geomp->read_reinstruct; 1815 } 1816 } 1817 1818 if ((geomp = metagetgeom( 1819 stripep->rows.rows_val[0].comps.comps_val[0].compnamep, 1820 ep)) == NULL) { 1821 return (-1); 1822 } 1823 /* 1824 * Figure out if the first component is a softpartition as the 1825 * truncation check only occurs on them. 1826 */ 1827 if ((miscname = metagetmiscname( 1828 stripep->rows.rows_val[0].comps.comps_val[0].compnamep, 1829 ep)) == NULL) { 1830 if (!mdisdeverror(ep, MDE_NOT_META)) 1831 return (-1); 1832 } else if (strcmp(miscname, MD_SP) == 0) { 1833 is_sp = 1; 1834 } 1835 1836 1837 /* setup geometry from first device */ 1838 if (meta_setup_geom((md_unit_t *)ms, stripep->common.namep, geomp, 1839 write_reinstruct, read_reinstruct, round_cyl, ep) != 0) 1840 return (-1); 1841 1842 /* 1843 * Here we want to make sure that any truncation did not 1844 * result in lost data (or, more appropriately, inaccessible 1845 * data). 1846 * 1847 * This is mainly a danger for (1, 1) concats, but it is 1848 * mathematically possible for other somewhat contrived 1849 * arrangements where in the sum of the lengths of each row 1850 * beyond the first is smaller than the cylinder size of the 1851 * only component in the first row. 1852 * 1853 * It is tempting to simply test for truncation here, by 1854 * (md->c.un_total_blocks < md->c.un_actual_tb). That does 1855 * not tell us, however, if rounding resulted in data loss, 1856 * rather only that it occurred. The somewhat less obvious 1857 * test below covers both the obvious (1, 1) case and the 1858 * aforementioned corner case. 1859 */ 1860 first_row_size = ms->un_row[0].un_blocks; 1861 if (is_sp == 1) { 1862 md_unit_t *md = (md_unit_t *)ms; 1863 1864 if (md->c.un_total_blocks < first_row_size) { 1865 char buf[] = VAL2STR(ULLONG_MAX); 1866 1867 /* 1868 * The only difference here is the text of the error 1869 * message, since the remediation is slightly 1870 * different in the one-component versus 1871 * multiple-component cases. 1872 */ 1873 if (nrow == 1) { 1874 (void) mderror(ep, MDE_STRIPE_TRUNC_SINGLE, 1875 stripep->common.namep->cname); 1876 } else { 1877 (void) mderror(ep, MDE_STRIPE_TRUNC_MULTIPLE, 1878 stripep->common.namep->cname); 1879 } 1880 1881 /* 1882 * By the size comparison above and the initialization 1883 * of buf[] in terms of ULLONG_MAX, we guarantee that 1884 * the value arg is non-negative and that we won't 1885 * overflow the container. 1886 */ 1887 mderrorextra(ep, ulltostr((md->c.un_total_blocks + 1888 (geomp->nhead * geomp->nsect)) 1889 - first_row_size, &buf[sizeof (buf) - 1])); 1890 1891 return (-1); 1892 } 1893 } 1894 1895 /* return success */ 1896 return (0); 1897 } 1898 1899 /* 1900 * create stripe 1901 */ 1902 int 1903 meta_create_stripe( 1904 mdsetname_t *sp, 1905 md_stripe_t *stripep, 1906 mdcmdopts_t options, 1907 md_error_t *ep 1908 ) 1909 { 1910 mdname_t *stripenp = stripep->common.namep; 1911 int force = ((options & MDCMD_FORCE) ? 1 : 0); 1912 int doall = ((options & MDCMD_ALLOPTION) ? 1 : 0); 1913 uint_t nrow = stripep->rows.rows_len; 1914 uint_t ncomp = 0; 1915 uint_t icomp = 0; 1916 diskaddr_t cum_blocks = 0; 1917 diskaddr_t limit; 1918 size_t mdsize, first_comp; 1919 uint_t row; 1920 ms_unit_t *ms; 1921 ms_comp_t *mdcomp; 1922 mdnamelist_t *keynlp = NULL; 1923 md_set_params_t set_params; 1924 int rval = -1; 1925 md_timeval32_t creation_time; 1926 int create_flag = MD_CRO_32BIT; 1927 1928 /* validate stripe */ 1929 if (meta_check_stripe(sp, stripep, options, ep) != 0) 1930 return (-1); 1931 1932 /* allocate stripe unit */ 1933 mdsize = sizeof (*ms) - sizeof (ms->un_row[0]); 1934 mdsize += sizeof (ms->un_row) * nrow; 1935 for (row = 0; (row < nrow); ++row) { 1936 md_row_t *rp = &stripep->rows.rows_val[row]; 1937 1938 ncomp += rp->comps.comps_len; 1939 } 1940 first_comp = roundup(mdsize, sizeof (long long)); 1941 mdsize += (first_comp - mdsize) + (ncomp * sizeof (ms_comp_t)); 1942 ms = Zalloc(mdsize); 1943 ms->un_ocomp = first_comp; 1944 if (meta_gettimeofday(&creation_time) == -1) 1945 return (mdsyserror(ep, errno, NULL)); 1946 1947 /* do rows */ 1948 mdcomp = (ms_comp_t *)(void *)&((char *)ms)[ms->un_ocomp]; 1949 for (row = 0; (row < nrow); ++row) { 1950 md_row_t *rp = &stripep->rows.rows_val[row]; 1951 uint_t ncomp = rp->comps.comps_len; 1952 struct ms_row *mdr = &ms->un_row[row]; 1953 diskaddr_t disk_size = 0; 1954 uint_t comp; 1955 1956 /* setup component count and offfset */ 1957 mdr->un_icomp = icomp; 1958 mdr->un_ncomp = ncomp; 1959 1960 /* do components */ 1961 for (comp = 0; (comp < ncomp); ++comp) { 1962 md_comp_t *cp = &rp->comps.comps_val[comp]; 1963 mdname_t *compnp = cp->compnamep; 1964 ms_comp_t *mdc = &mdcomp[icomp++]; 1965 diskaddr_t size, start_blk; 1966 1967 /* 1968 * get start and size 1969 * if first component is labelled, include label 1970 */ 1971 if ((size = metagetsize(compnp, ep)) == 1972 MD_DISKADDR_ERROR) 1973 goto out; 1974 if ((start_blk = metagetstart(sp, compnp, ep)) == 1975 MD_DISKADDR_ERROR) 1976 goto out; 1977 if ((row == 0) && (comp == 0)) { 1978 diskaddr_t label; 1979 int has_db; 1980 1981 if ((has_db = metahasmddb(sp, compnp, ep)) < 0) 1982 goto out; 1983 if ((label = metagetlabel(compnp, ep)) == 1984 MD_DISKADDR_ERROR) 1985 goto out; 1986 if ((has_db == 0) && (label != 0)) { 1987 ms->c.un_flag |= MD_LABELED; 1988 start_blk = compnp->start_blk = 0; 1989 } 1990 } 1991 /* make sure we still have something left */ 1992 if (start_blk >= size) { 1993 (void) mdsyserror(ep, ENOSPC, compnp->cname); 1994 goto out; 1995 } 1996 size -= start_blk; 1997 1998 /* 1999 * round down by interlace: this only applies 2000 * if this row is a stripe, as indicated by 2001 * (ncomp > 1) 2002 */ 2003 if (ncomp > 1) 2004 size = rounddown(size, rp->interlace); 2005 2006 if (size == 0) { 2007 (void) mdsyserror(ep, ENOSPC, compnp->cname); 2008 goto out; 2009 } 2010 2011 /* 2012 * adjust for smallest disk: for a concat (any 2013 * row with only one component), this will 2014 * never hit the second conditional. 2015 */ 2016 if (disk_size == 0) { 2017 disk_size = size; 2018 } else if (size < disk_size) { 2019 disk_size = size; 2020 } 2021 2022 if (options & MDCMD_DOIT) { 2023 /* store name in namespace */ 2024 if (add_key_name(sp, compnp, &keynlp, ep) != 0) 2025 goto out; 2026 } 2027 2028 /* setup component */ 2029 mdc->un_key = compnp->key; 2030 mdc->un_dev = compnp->dev; 2031 mdc->un_start_block = start_blk; 2032 mdc->un_mirror.ms_state = CS_OKAY; 2033 mdc->un_mirror.ms_timestamp = creation_time; 2034 } 2035 limit = LLONG_MAX; 2036 2037 /* setup row */ 2038 mdr->un_blocks = mdr->un_ncomp * disk_size; 2039 cum_blocks += mdr->un_blocks; 2040 if (cum_blocks > limit) { 2041 cum_blocks = limit; 2042 md_eprintf(dgettext(TEXT_DOMAIN, 2043 "unit size overflow, limit is %lld blocks\n"), 2044 limit); 2045 } 2046 mdr->un_cum_blocks = cum_blocks; 2047 mdr->un_interlace = rp->interlace; 2048 } 2049 2050 /* setup unit */ 2051 ms->c.un_type = MD_DEVICE; 2052 MD_SID(ms) = meta_getminor(stripenp->dev); 2053 ms->c.un_actual_tb = cum_blocks; 2054 ms->c.un_size = mdsize; 2055 if (stripep->hspnamep != NULL) 2056 ms->un_hsp_id = stripep->hspnamep->hsp; 2057 else 2058 ms->un_hsp_id = MD_HSP_NONE; 2059 ms->un_nrows = nrow; 2060 2061 /* fill in the size of the stripe */ 2062 if (options & MDCMD_UPDATE) { 2063 stripep->common.size = ms->c.un_total_blocks; 2064 for (row = 0; (row < nrow); ++row) { 2065 stripep->rows.rows_val[row].row_size = 2066 ms->un_row[row].un_blocks; 2067 } 2068 } 2069 2070 if (stripe_geom(stripep, ms, ep) != 0) { 2071 /* 2072 * If the device is being truncated then only allow this 2073 * if the user is aware (using the -f option) or they 2074 * are in a recovery/complete build situation (using the -a 2075 * option). 2076 */ 2077 if ((mdiserror(ep, MDE_STRIPE_TRUNC_SINGLE) || 2078 mdiserror(ep, MDE_STRIPE_TRUNC_MULTIPLE)) && 2079 (force || doall)) { 2080 md_eprintf(dgettext(TEXT_DOMAIN, 2081 "%s: WARNING: This form of metainit is not recommended.\n" 2082 "The stripe is truncating the size of the underlying device.\n" 2083 "Please see ERRORS in metainit(1M) for additional information.\n"), 2084 stripenp->cname); 2085 mdclrerror(ep); 2086 } else { 2087 goto out; 2088 } 2089 } 2090 2091 create_flag = meta_check_devicesize(ms->c.un_total_blocks); 2092 2093 /* if we're not doing anything, return success */ 2094 if (! (options & MDCMD_DOIT)) { 2095 rval = 0; /* success */ 2096 goto out; 2097 } 2098 2099 /* create stripe */ 2100 (void) memset(&set_params, 0, sizeof (set_params)); 2101 2102 /* did the user tell us to generate a large device? */ 2103 if (create_flag == MD_CRO_64BIT) { 2104 ms->c.un_revision |= MD_64BIT_META_DEV; 2105 set_params.options = MD_CRO_64BIT; 2106 } else { 2107 ms->c.un_revision &= ~MD_64BIT_META_DEV; 2108 set_params.options = MD_CRO_32BIT; 2109 } 2110 2111 set_params.mnum = MD_SID(ms); 2112 set_params.size = ms->c.un_size; 2113 set_params.mdp = (uintptr_t)ms; 2114 MD_SETDRIVERNAME(&set_params, MD_STRIPE, MD_MIN2SET(set_params.mnum)); 2115 if (metaioctl(MD_IOCSET, &set_params, &set_params.mde, 2116 stripenp->cname) != 0) { 2117 (void) mdstealerror(ep, &set_params.mde); 2118 goto out; 2119 } 2120 rval = 0; /* success */ 2121 2122 /* cleanup, return success */ 2123 out: 2124 Free(ms); 2125 if (rval != 0) { 2126 (void) del_key_names(sp, keynlp, NULL); 2127 } 2128 2129 metafreenamelist(keynlp); 2130 if ((rval == 0) && (options & MDCMD_DOIT)) { 2131 if (invalidate_components(sp, stripenp, ep) != 0) 2132 rval = -1; 2133 meta_invalidate_name(stripenp); 2134 } 2135 return (rval); 2136 } 2137 2138 /* 2139 * initialize stripe 2140 * NOTE: this functions is metainit(1m)'s command line parser! 2141 */ 2142 int 2143 meta_init_stripe( 2144 mdsetname_t **spp, 2145 int argc, 2146 char *argv[], 2147 mdcmdopts_t options, 2148 md_error_t *ep 2149 ) 2150 { 2151 char *uname = argv[0]; 2152 mdname_t *stripenp = NULL; 2153 int old_optind; 2154 int c; 2155 md_stripe_t *stripep = NULL; 2156 uint_t nrow, row; 2157 int rval = -1; 2158 2159 /* get stripe name */ 2160 assert(argc > 0); 2161 if (argc < 1) 2162 goto syntax; 2163 2164 if ((stripenp = metaname(spp, uname, META_DEVICE, ep)) == NULL) 2165 goto out; 2166 assert(*spp != NULL); 2167 uname = stripenp->cname; 2168 if (metachkmeta(stripenp, ep) != 0) 2169 goto out; 2170 2171 if (!(options & MDCMD_NOLOCK)) { 2172 /* grab set lock */ 2173 if (meta_lock(*spp, TRUE, ep)) 2174 goto out; 2175 2176 if (meta_check_ownership(*spp, ep) != 0) 2177 goto out; 2178 } 2179 2180 /* see if it exists already */ 2181 if (metagetmiscname(stripenp, ep) != NULL) { 2182 (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP, 2183 meta_getminor(stripenp->dev), uname); 2184 goto out; 2185 } else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) { 2186 goto out; 2187 } else { 2188 mdclrerror(ep); 2189 } 2190 --argc, ++argv; 2191 2192 /* parse general options */ 2193 optind = 0; 2194 opterr = 0; 2195 if (getopt(argc, argv, "") != -1) 2196 goto options; 2197 2198 /* allocate stripe */ 2199 stripep = Zalloc(sizeof (*stripep)); 2200 2201 /* setup common */ 2202 stripep->common.namep = stripenp; 2203 stripep->common.type = MD_DEVICE; 2204 2205 /* allocate and parse rows */ 2206 if (argc < 1) { 2207 (void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev), 2208 uname); 2209 goto out; 2210 } else if ((sscanf(argv[0], "%u", &nrow) != 1) || ((int)nrow < 0)) { 2211 goto syntax; 2212 } else if (nrow < 1) { 2213 (void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev), 2214 uname); 2215 goto out; 2216 } 2217 --argc, ++argv; 2218 stripep->rows.rows_len = nrow; 2219 stripep->rows.rows_val = 2220 Zalloc(nrow * sizeof (*stripep->rows.rows_val)); 2221 for (row = 0; (row < nrow); ++row) { 2222 md_row_t *mdr = &stripep->rows.rows_val[row]; 2223 uint_t ncomp, comp; 2224 2225 /* allocate and parse components */ 2226 if (argc < 1) { 2227 (void) mdmderror(ep, MDE_NROWS, 2228 meta_getminor(stripenp->dev), uname); 2229 goto out; 2230 } else if ((sscanf(argv[0], "%u", &ncomp) != 1) || 2231 ((int)ncomp < 0)) { 2232 goto syntax; 2233 } else if (ncomp < 1) { 2234 (void) mdmderror(ep, MDE_NCOMPS, 2235 meta_getminor(stripenp->dev), uname); 2236 goto out; 2237 } 2238 --argc, ++argv; 2239 mdr->comps.comps_len = ncomp; 2240 mdr->comps.comps_val = 2241 Zalloc(ncomp * sizeof (*mdr->comps.comps_val)); 2242 for (comp = 0; (comp < ncomp); ++comp) { 2243 md_comp_t *mdc = &mdr->comps.comps_val[comp]; 2244 mdname_t *compnp; 2245 2246 /* parse component name */ 2247 if (argc < 1) { 2248 (void) mdmderror(ep, MDE_NCOMPS, 2249 meta_getminor(stripenp->dev), uname); 2250 goto out; 2251 } 2252 if ((compnp = metaname(spp, argv[0], UNKNOWN, 2253 ep)) == NULL) { 2254 goto out; 2255 } 2256 /* check for soft partition */ 2257 if (meta_sp_issp(*spp, compnp, ep) != 0) { 2258 /* check disk */ 2259 if (metachkcomp(compnp, ep) != 0) { 2260 goto out; 2261 } 2262 } 2263 mdc->compnamep = compnp; 2264 --argc, ++argv; 2265 } 2266 2267 /* parse row options */ 2268 old_optind = optind = 0; 2269 opterr = 0; 2270 while ((c = getopt(argc, argv, "i:")) != -1) { 2271 switch (c) { 2272 case 'i': 2273 if (parse_interlace(uname, optarg, 2274 &mdr->interlace, ep) != 0) { 2275 goto out; 2276 } 2277 if (meta_stripe_check_interlace(mdr->interlace, 2278 uname, ep)) 2279 goto out; 2280 break; 2281 2282 default: 2283 optind = old_optind; /* bomb out later */ 2284 goto done_row_opts; 2285 } 2286 old_optind = optind; 2287 } 2288 done_row_opts: 2289 argc -= optind; 2290 argv += optind; 2291 } 2292 2293 /* parse stripe options */ 2294 old_optind = optind = 0; 2295 opterr = 0; 2296 while ((c = getopt(argc, argv, "h:")) != -1) { 2297 switch (c) { 2298 case 'h': 2299 if ((stripep->hspnamep = metahspname(spp, optarg, 2300 ep)) == NULL) { 2301 goto out; 2302 } 2303 break; 2304 2305 default: 2306 argc += old_optind; 2307 argv += old_optind; 2308 goto options; 2309 } 2310 old_optind = optind; 2311 } 2312 argc -= optind; 2313 argv += optind; 2314 2315 /* we should be at the end */ 2316 if (argc != 0) 2317 goto syntax; 2318 2319 /* create stripe */ 2320 if (meta_create_stripe(*spp, stripep, options, ep) != 0) 2321 goto out; 2322 rval = 0; /* success */ 2323 2324 /* let em know */ 2325 if (options & MDCMD_PRINT) { 2326 (void) printf(dgettext(TEXT_DOMAIN, 2327 "%s: Concat/Stripe is setup\n"), 2328 uname); 2329 (void) fflush(stdout); 2330 } 2331 goto out; 2332 2333 /* syntax error */ 2334 syntax: 2335 rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv); 2336 goto out; 2337 2338 /* options error */ 2339 options: 2340 rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv); 2341 goto out; 2342 2343 /* cleanup, return error */ 2344 out: 2345 if (stripep != NULL) 2346 meta_free_stripe(stripep); 2347 return (rval); 2348 } 2349 2350 /* 2351 * reset stripes 2352 */ 2353 int 2354 meta_stripe_reset( 2355 mdsetname_t *sp, 2356 mdname_t *stripenp, 2357 mdcmdopts_t options, 2358 md_error_t *ep 2359 ) 2360 { 2361 md_stripe_t *stripep; 2362 int rval = -1; 2363 int row, comp; 2364 2365 /* should have same set */ 2366 assert(sp != NULL); 2367 assert((stripenp == NULL) || 2368 (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)))); 2369 2370 /* reset all stripes */ 2371 if (stripenp == NULL) { 2372 mdnamelist_t *stripenlp = NULL; 2373 mdnamelist_t *p; 2374 2375 /* for each stripe */ 2376 rval = 0; 2377 if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0) 2378 return (-1); 2379 for (p = stripenlp; (p != NULL); p = p->next) { 2380 /* reset stripe */ 2381 stripenp = p->namep; 2382 2383 /* 2384 * If this is a multi-node set, we send a series 2385 * of individual metaclear commands. 2386 */ 2387 if (meta_is_mn_set(sp, ep)) { 2388 if (meta_mn_send_metaclear_command(sp, 2389 stripenp->cname, options, 0, ep) != 0) { 2390 rval = -1; 2391 break; 2392 } 2393 } else { 2394 if (meta_stripe_reset(sp, stripenp, 2395 options, ep) != 0) { 2396 rval = -1; 2397 break; 2398 } 2399 } 2400 } 2401 2402 /* cleanup, return success */ 2403 metafreenamelist(stripenlp); 2404 return (rval); 2405 } 2406 2407 /* check name */ 2408 if (metachkmeta(stripenp, ep) != 0) 2409 return (-1); 2410 2411 /* get unit structure */ 2412 if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL) 2413 return (-1); 2414 2415 /* make sure nobody owns us */ 2416 if (MD_HAS_PARENT(stripep->common.parent)) { 2417 return (mdmderror(ep, MDE_IN_USE, meta_getminor(stripenp->dev), 2418 stripenp->cname)); 2419 } 2420 2421 /* clear subdevices cache */ 2422 if (invalidate_components(sp, stripenp, ep) != 0) 2423 return (-1); 2424 2425 /* clear metadevice */ 2426 if (meta_reset(sp, stripenp, options, ep) != 0) 2427 goto out; 2428 rval = 0; /* success */ 2429 2430 /* let em know */ 2431 if (options & MDCMD_PRINT) { 2432 (void) printf(dgettext(TEXT_DOMAIN, 2433 "%s: Concat/Stripe is cleared\n"), 2434 stripenp->cname); 2435 (void) fflush(stdout); 2436 } 2437 2438 /* clear subdevices */ 2439 if (! (options & MDCMD_RECURSE)) 2440 goto out; 2441 2442 for (row = 0; (row < stripep->rows.rows_len); ++row) { 2443 md_row_t *rp = &stripep->rows.rows_val[row]; 2444 for (comp = 0; (comp < rp->comps.comps_len); ++comp) { 2445 md_comp_t *cp = &rp->comps.comps_val[comp]; 2446 mdname_t *compnp = cp->compnamep; 2447 2448 /* only recurse on metadevices */ 2449 if (! metaismeta(compnp)) 2450 continue; 2451 2452 if (meta_reset_by_name(sp, compnp, options, ep) != 0) 2453 rval = -1; 2454 } 2455 } 2456 2457 /* cleanup, return success */ 2458 out: 2459 meta_invalidate_name(stripenp); 2460 return (rval); 2461 } 2462 2463 /* 2464 * reports TRUE if any stripe component is in error 2465 */ 2466 int 2467 meta_stripe_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *stripe_names) 2468 { 2469 mdnamelist_t *nlp; 2470 md_error_t status = mdnullerror; 2471 md_error_t *ep = &status; 2472 int any_errs = FALSE; 2473 2474 for (nlp = stripe_names; nlp; nlp = nlp->next) { 2475 md_stripe_t *stripep; 2476 int row; 2477 2478 if ((stripep = meta_get_stripe(sp, nlp->namep, ep)) == NULL) { 2479 any_errs |= TRUE; 2480 goto out; 2481 } 2482 2483 for (row = 0; row < stripep->rows.rows_len; ++row) { 2484 md_row_t *rp = &stripep->rows.rows_val[row]; 2485 uint_t comp; 2486 2487 for (comp = 0; comp < rp->comps.comps_len; ++comp) { 2488 md_comp_t *cp = &rp->comps.comps_val[comp]; 2489 2490 if (cp->state != CS_OKAY) { 2491 any_errs |= TRUE; 2492 goto out; 2493 } 2494 } 2495 } 2496 } 2497 out: 2498 if (!mdisok(ep)) 2499 mdclrerror(ep); 2500 2501 return (any_errs); 2502 } 2503