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 * hotspares utilities 38 */ 39 40 #include <meta.h> 41 #include <sys/lvm/md_hotspares.h> 42 #include <sys/lvm/md_convert.h> 43 44 /* 45 * FUNCTION: meta_get_hsp_names() 46 * INPUT: sp - the set name to get hotspares from 47 * options - options from the command line 48 * OUTPUT: hspnlpp - list of all hotspare names 49 * ep - return error pointer 50 * RETURNS: int - -1 if error, 0 success 51 * PURPOSE: returns a list of all hotspares in the metadb 52 * for all devices in the specified set 53 */ 54 /*ARGSUSED*/ 55 int 56 meta_get_hsp_names( 57 mdsetname_t *sp, 58 mdhspnamelist_t **hspnlpp, 59 int options, 60 md_error_t *ep 61 ) 62 { 63 md_i_getnum_t gn; /* MD_IOCGET_NUM params */ 64 minor_t *minors = NULL; 65 minor_t *m_ptr; 66 int i; 67 68 /* we must have a set */ 69 assert(sp != NULL); 70 71 (void) memset(&gn, 0, sizeof (gn)); 72 MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno); 73 74 /* get number of devices */ 75 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) { 76 if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) { 77 mdclrerror(&gn.mde); 78 } else { 79 (void) mdstealerror(ep, &gn.mde); 80 return (-1); 81 } 82 } 83 84 if (gn.size > 0) { 85 /* malloc minor number buffer to be filled by ioctl */ 86 if ((minors = (minor_t *)malloc( 87 gn.size * sizeof (minor_t))) == 0) { 88 return (ENOMEM); 89 } 90 gn.minors = (uintptr_t)minors; 91 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) { 92 (void) mdstealerror(ep, &gn.mde); 93 free(minors); 94 return (-1); 95 } 96 m_ptr = minors; 97 for (i = 0; i < gn.size; i++) { 98 mdhspname_t *hspnp; 99 100 101 /* get name */ 102 if ((hspnp = metahsphspname(&sp, *m_ptr, ep)) 103 == NULL) 104 goto out; 105 106 /* append to list */ 107 (void) metahspnamelist_append(hspnlpp, hspnp); 108 109 /* next device */ 110 m_ptr++; 111 } 112 free(minors); 113 } 114 return (gn.size); 115 116 out: 117 if (minors != NULL) 118 free(minors); 119 metafreehspnamelist(*hspnlpp); 120 *hspnlpp = NULL; 121 return (-1); 122 } 123 124 /* 125 * get information of a specific hotspare pool from driver 126 */ 127 static get_hsp_t * 128 get_hspinfo( 129 mdsetname_t *sp, 130 mdhspname_t *hspnp, 131 md_error_t *ep 132 ) 133 { 134 md_i_get_t mig; 135 136 /* should have a set */ 137 assert(sp != NULL); 138 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp)); 139 140 /* get size of unit structure */ 141 (void) memset(&mig, 0, sizeof (mig)); 142 MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno); 143 mig.id = hspnp->hsp; 144 if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) { 145 (void) mdstealerror(ep, &mig.mde); 146 return (NULL); 147 } 148 149 /* get actual unit structure */ 150 assert(mig.size > 0); 151 mig.mdp = (uintptr_t)Zalloc(mig.size); 152 if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) { 153 (void) mdstealerror(ep, &mig.mde); 154 Free((void *)(uintptr_t)mig.mdp); 155 return (NULL); 156 } 157 return ((get_hsp_t *)(uintptr_t)mig.mdp); 158 } 159 160 /* 161 * free hotspare pool unit 162 */ 163 void 164 meta_free_hsp( 165 md_hsp_t *hspp 166 ) 167 { 168 if (hspp->hotspares.hotspares_val != NULL) { 169 assert(hspp->hotspares.hotspares_len > 0); 170 Free(hspp->hotspares.hotspares_val); 171 } 172 Free(hspp); 173 } 174 175 /* 176 * get hotspare pool unit (common) 177 */ 178 md_hsp_t * 179 meta_get_hsp_common( 180 mdsetname_t *sp, 181 mdhspname_t *hspnp, 182 int fast, 183 md_error_t *ep 184 ) 185 { 186 get_hsp_t *ghsp; 187 md_hsp_t *hspp; 188 uint_t hsi; 189 190 /* must have set */ 191 assert(sp != NULL); 192 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp)); 193 194 /* short circuit */ 195 if (hspnp->unitp != NULL) 196 return (hspnp->unitp); 197 198 /* get unit */ 199 if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL) 200 return (NULL); 201 202 /* allocate hsp */ 203 hspp = Zalloc(sizeof (*hspp)); 204 205 /* allocate hotspares */ 206 hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares; 207 208 /* if empty hotspare pool, we are done */ 209 if (hspp->hotspares.hotspares_len != 0) 210 hspp->hotspares.hotspares_val = 211 Zalloc(hspp->hotspares.hotspares_len * 212 sizeof (*hspp->hotspares.hotspares_val)); 213 214 /* get name, refcount */ 215 hspp->hspnamep = hspnp; 216 hspp->refcount = ghsp->ghsp_refcount; 217 218 /* get hotspares */ 219 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 220 mdkey_t hs_key = ghsp->ghsp_hs_keys[hsi]; 221 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 222 get_hs_params_t ghs; 223 224 /* get hotspare name */ 225 hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep); 226 if (hsp->hsnamep == NULL) 227 goto out; 228 229 /* get hotspare state */ 230 (void) memset(&ghs, 0, sizeof (ghs)); 231 MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno); 232 ghs.ghs_key = hs_key; 233 if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) { 234 (void) mdstealerror(ep, &ghs.mde); 235 goto out; 236 } 237 hsp->state = ghs.ghs_state; 238 hsp->size = ghs.ghs_number_blks; 239 hsp->timestamp = ghs.ghs_timestamp; 240 hsp->revision = ghs.ghs_revision; 241 } 242 243 /* cleanup, return success */ 244 Free(ghsp); 245 hspnp->unitp = hspp; 246 return (hspp); 247 248 /* cleanup, return error */ 249 out: 250 Free(ghsp); 251 meta_free_hsp(hspp); 252 return (NULL); 253 } 254 255 /* 256 * get hotspare pool unit 257 */ 258 md_hsp_t * 259 meta_get_hsp( 260 mdsetname_t *sp, 261 mdhspname_t *hspnp, 262 md_error_t *ep 263 ) 264 { 265 return (meta_get_hsp_common(sp, hspnp, 0, ep)); 266 } 267 268 /* 269 * check hotspare pool for dev 270 */ 271 static int 272 in_hsp( 273 mdsetname_t *sp, 274 mdhspname_t *hspnp, 275 mdname_t *np, 276 diskaddr_t slblk, 277 diskaddr_t nblks, 278 md_error_t *ep 279 ) 280 { 281 md_hsp_t *hspp; 282 uint_t i; 283 284 /* should be in the same set */ 285 assert(sp != NULL); 286 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp)); 287 288 /* get unit */ 289 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL) 290 return (-1); 291 292 /* look in hotspares */ 293 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) { 294 md_hs_t *hs = &hspp->hotspares.hotspares_val[i]; 295 mdname_t *hsnp = hs->hsnamep; 296 297 /* check overlap */ 298 if (metaismeta(hsnp)) 299 continue; 300 if (meta_check_overlap(hspnp->hspname, np, slblk, nblks, 301 hsnp, 0, -1, ep) != 0) 302 return (-1); 303 } 304 305 /* return success */ 306 return (0); 307 } 308 309 /* 310 * check to see if we're in a hotspare pool 311 */ 312 int 313 meta_check_inhsp( 314 mdsetname_t *sp, 315 mdname_t *np, 316 diskaddr_t slblk, 317 diskaddr_t nblks, 318 md_error_t *ep 319 ) 320 { 321 mdhspnamelist_t *hspnlp = NULL; 322 mdhspnamelist_t *p; 323 int rval = 0; 324 325 /* should have a set */ 326 assert(sp != NULL); 327 328 /* for each hotspare pool */ 329 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 330 return (-1); 331 for (p = hspnlp; (p != NULL); p = p->next) { 332 mdhspname_t *hspnp = p->hspnamep; 333 334 /* check hotspare pool */ 335 if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) { 336 rval = -1; 337 break; 338 } 339 } 340 341 /* cleanup, return success */ 342 metafreehspnamelist(hspnlp); 343 return (rval); 344 } 345 346 /* 347 * check hotspare 348 */ 349 int 350 meta_check_hotspare( 351 mdsetname_t *sp, 352 mdname_t *np, 353 md_error_t *ep 354 ) 355 { 356 mdchkopts_t options = (MDCHK_ALLOW_HS); 357 358 /* make sure we have a disk */ 359 if (metachkcomp(np, ep) != 0) 360 return (-1); 361 362 /* check to ensure that it is not already in use */ 363 if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) { 364 return (-1); 365 } 366 367 /* make sure it is in the set */ 368 if (meta_check_inset(sp, np, ep) != 0) 369 return (-1); 370 371 /* make sure its not in a metadevice */ 372 if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0) 373 return (-1); 374 375 /* return success */ 376 return (0); 377 } 378 379 /* 380 * print hsp 381 */ 382 static int 383 hsp_print( 384 md_hsp_t *hspp, 385 char *fname, 386 FILE *fp, 387 md_error_t *ep 388 ) 389 { 390 uint_t hsi; 391 int rval = -1; 392 393 /* print name */ 394 if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF) 395 goto out; 396 397 /* print hotspares */ 398 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 399 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 400 401 /* print hotspare */ 402 /* 403 * If the path is our standard /dev/rdsk or /dev/md/rdsk 404 * then just print out the cxtxdxsx or the dx, metainit 405 * will assume the default, otherwise we need the full 406 * pathname to make sure this works as we intend. 407 */ 408 if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) && 409 (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) && 410 (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) { 411 /* not standard path, print full pathname */ 412 if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF) 413 goto out; 414 } else { 415 /* standard path, just print ctd or d value */ 416 if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF) 417 goto out; 418 } 419 } 420 421 /* terminate last line */ 422 if (fprintf(fp, "\n") == EOF) 423 goto out; 424 425 /* success */ 426 rval = 0; 427 428 /* cleanup, return error */ 429 out: 430 if (rval != 0) 431 (void) mdsyserror(ep, errno, fname); 432 return (rval); 433 } 434 435 /* 436 * hotspare state name 437 */ 438 char * 439 hs_state_to_name( 440 md_hs_t *hsp, 441 md_timeval32_t *tvp 442 ) 443 { 444 hotspare_states_t state = hsp->state; 445 446 /* grab time */ 447 if (tvp != NULL) 448 *tvp = hsp->timestamp; 449 450 switch (state) { 451 case HSS_AVAILABLE: 452 return (dgettext(TEXT_DOMAIN, "Available")); 453 case HSS_RESERVED: 454 return (dgettext(TEXT_DOMAIN, "In use")); 455 case HSS_BROKEN: 456 return (dgettext(TEXT_DOMAIN, "Broken")); 457 case HSS_UNUSED: 458 default: 459 return (dgettext(TEXT_DOMAIN, "invalid")); 460 } 461 } 462 463 /* 464 * report hsp 465 */ 466 static int 467 hsp_report( 468 md_hsp_t *hspp, 469 mdnamelist_t **nlpp, 470 char *fname, 471 FILE *fp, 472 mdprtopts_t options, 473 md_error_t *ep, 474 mdsetname_t *sp 475 ) 476 { 477 uint_t hsi; 478 int rval = -1; 479 char *devid = ""; 480 mdname_t *didnp = NULL; 481 uint_t len; 482 int large_hs_dev_cnt = 0; 483 int fn_hs_dev_cnt = 0; 484 485 if (options & PRINT_LARGEDEVICES) { 486 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 487 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 488 if (hsp->revision & MD_64BIT_META_DEV) { 489 large_hs_dev_cnt += 1; 490 if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep) 491 != 0) 492 goto out; 493 } 494 } 495 496 if (large_hs_dev_cnt == 0) { 497 rval = 0; 498 goto out; 499 } 500 } 501 502 if (options & PRINT_FN) { 503 if (!HSP_ID_IS_FN(hspp->hspnamep->hsp)) { 504 rval = 0; 505 goto out; 506 } 507 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 508 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 509 fn_hs_dev_cnt += 1; 510 if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep) 511 != 0) 512 goto out; 513 } 514 } 515 516 /* print header */ 517 if (hspp->hotspares.hotspares_len == 0) { 518 if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"), 519 hspp->hspnamep->hspname) == EOF) { 520 goto out; 521 } 522 } else if (hspp->hotspares.hotspares_len == 1) { 523 524 /* 525 * This allows the length 526 * of the ctd to vary from small to large without 527 * looking horrible. 528 */ 529 530 len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname); 531 /* 532 * if the length is to short to print out all of the header 533 * force the matter 534 */ 535 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device"))); 536 len += 2; 537 if (options & PRINT_LARGEDEVICES) { 538 if (fprintf(fp, 539 "%s: 1 hot spare (1 big device)\n\t%-*.*s " 540 "%-12.12s%-8.6s\t\t%s\n", 541 hspp->hspnamep->hspname, len, len, 542 dgettext(TEXT_DOMAIN, "Device"), 543 dgettext(TEXT_DOMAIN, "Status"), 544 dgettext(TEXT_DOMAIN, "Length"), 545 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 546 goto out; 547 } 548 } else { 549 if (fprintf(fp, 550 "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n", 551 hspp->hspnamep->hspname, len, len, 552 dgettext(TEXT_DOMAIN, "Device"), 553 dgettext(TEXT_DOMAIN, "Status"), 554 dgettext(TEXT_DOMAIN, "Length"), 555 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 556 goto out; 557 } 558 } 559 } else { 560 /* 561 * This allows the length 562 * of the ctd to vary from small to large without 563 * looking horrible. 564 */ 565 len = 0; 566 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 567 len = max(len, strlen(hspp-> 568 hotspares.hotspares_val[hsi].hsnamep->cname)); 569 } 570 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device"))); 571 len += 2; 572 if (options & PRINT_LARGEDEVICES) { 573 if (fprintf(fp, 574 "%s: %u hot spares (%d big device(s))\n\t%-*.*s " 575 "%-12.12s%-8.6s\t\t%s\n", 576 hspp->hspnamep->hspname, 577 hspp->hotspares.hotspares_len, 578 large_hs_dev_cnt, len, len, 579 dgettext(TEXT_DOMAIN, "Device"), 580 dgettext(TEXT_DOMAIN, "Status"), 581 dgettext(TEXT_DOMAIN, "Length"), 582 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 583 goto out; 584 } 585 } else { 586 if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s " 587 "%-12.12s%-8.6s\t\t%s\n", 588 hspp->hspnamep->hspname, 589 hspp->hotspares.hotspares_len, len, len, 590 dgettext(TEXT_DOMAIN, "Device"), 591 dgettext(TEXT_DOMAIN, "Status"), 592 dgettext(TEXT_DOMAIN, "Length"), 593 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 594 goto out; 595 } 596 } 597 } 598 599 /* print hotspares */ 600 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 601 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 602 char *cname = hsp->hsnamep->cname; 603 char *hs_state; 604 md_timeval32_t tv; 605 char *timep; 606 ddi_devid_t dtp; 607 608 /* populate the key in the name_p structure */ 609 if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) { 610 return (-1); 611 } 612 613 if (options & PRINT_LARGEDEVICES) { 614 if ((hsp->revision & MD_64BIT_META_DEV) == 0) 615 continue; 616 } 617 /* determine if devid does NOT exist */ 618 if (options & PRINT_DEVID) { 619 if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep), 620 didnp->key, ep)) == NULL) 621 devid = dgettext(TEXT_DOMAIN, "No "); 622 else { 623 devid = dgettext(TEXT_DOMAIN, "Yes"); 624 free(dtp); 625 } 626 } 627 /* print hotspare */ 628 hs_state = hs_state_to_name(hsp, &tv); 629 /* 630 * This allows the length 631 * of the ctd to vary from small to large without 632 * looking horrible. 633 */ 634 if (! (options & PRINT_TIMES)) { 635 if (fprintf(fp, 636 " %-*s %-12s %lld blocks\t%s\n", 637 len, cname, hs_state, 638 hsp->size, devid) == EOF) { 639 goto out; 640 } 641 } else { 642 timep = meta_print_time(&tv); 643 644 if (fprintf(fp, 645 " %-*s\t %-11s %8lld blocks%s\t%s\n", 646 len, cname, hs_state, 647 hsp->size, devid, timep) == EOF) { 648 goto out; 649 } 650 } 651 } 652 653 /* add extra line */ 654 if (fprintf(fp, "\n") == EOF) 655 goto out; 656 657 /* success */ 658 rval = 0; 659 660 /* cleanup, return error */ 661 out: 662 if (rval != 0) 663 (void) mdsyserror(ep, errno, fname); 664 return (rval); 665 } 666 667 /* 668 * print/report hsp 669 */ 670 int 671 meta_hsp_print( 672 mdsetname_t *sp, 673 mdhspname_t *hspnp, 674 mdnamelist_t **nlpp, 675 char *fname, 676 FILE *fp, 677 mdprtopts_t options, 678 md_error_t *ep 679 ) 680 { 681 md_hsp_t *hspp; 682 683 /* should have same set */ 684 assert(sp != NULL); 685 assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE || 686 sp->setno == HSP_SET(hspnp->hsp)); 687 688 /* print all hsps */ 689 if (hspnp == NULL) { 690 mdhspnamelist_t *hspnlp = NULL; 691 mdhspnamelist_t *p; 692 int cnt; 693 int rval = 0; 694 695 if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0) 696 return (-1); 697 else if (cnt == 0) 698 return (0); 699 700 /* recurse */ 701 for (p = hspnlp; (p != NULL); p = p->next) { 702 mdhspname_t *hspnp = p->hspnamep; 703 704 if (meta_hsp_print(sp, hspnp, nlpp, fname, fp, 705 options, ep) != 0) 706 rval = -1; 707 } 708 709 /* cleanup, return success */ 710 metafreehspnamelist(hspnlp); 711 return (rval); 712 } 713 714 /* get unit structure */ 715 if ((hspp = meta_get_hsp_common(sp, hspnp, 716 ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL) 717 return (-1); 718 719 /* print appropriate detail */ 720 if (options & PRINT_SHORT) 721 return (hsp_print(hspp, fname, fp, ep)); 722 else 723 return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp)); 724 } 725 726 /* 727 * check for valid hotspare pool 728 */ 729 int 730 metachkhsp( 731 mdsetname_t *sp, 732 mdhspname_t *hspnp, 733 md_error_t *ep 734 ) 735 { 736 if (meta_get_hsp(sp, hspnp, ep) == NULL) 737 return (-1); 738 return (0); 739 } 740 741 /* 742 * invalidate hotspare pool info 743 */ 744 void 745 meta_invalidate_hsp( 746 mdhspname_t *hspnp 747 ) 748 { 749 md_hsp_t *hspp = hspnp->unitp; 750 751 /* free it up */ 752 if (hspp == NULL) 753 return; 754 meta_free_hsp(hspp); 755 756 /* clear cache */ 757 hspnp->unitp = NULL; 758 } 759 760 /* 761 * FUNCTION: del_hsp_name_mn_sides() 762 * INPUT: sp - set name 763 * curside - side of this node 764 * key - key of records to delete 765 * OUTPUT: ep - error information 766 * RETURNS: none. 767 * PURPOSE: There are name records for each side in a set. This 768 * function deletes the records associated with the specified 769 * key for all sides except curside. This function is used 770 * when the set is a multinode set. 771 */ 772 static void 773 del_hsp_name_mn_sides( 774 mdsetname_t *sp, 775 md_set_desc *sd, 776 side_t curside, 777 mdkey_t key, 778 md_error_t *ep 779 ) 780 { 781 md_error_t first_error = MDNULLERROR; 782 int error_seen = FALSE; 783 md_mnnode_desc *nd; 784 785 for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) { 786 if (nd->nd_nodeid == curside) 787 continue; 788 if (del_name(sp, nd->nd_nodeid, key, &first_error) == -1) { 789 if (error_seen == FALSE) { 790 error_seen = TRUE; 791 (void) mdstealerror(ep, &first_error); 792 } 793 } 794 } 795 } 796 797 /* 798 * FUNCTION: del_hsp_name_trad_sides() 799 * INPUT: sp - set name 800 * curside - side of this node 801 * key - key of records to delete 802 * OUTPUT: ep - error information 803 * RETURNS: none. 804 * PURPOSE: There are name records for each side in a set. This 805 * function deletes the records associated with the specified 806 * key for all sides except curside. This function is used 807 * when the set is a traditional set. 808 */ 809 static void 810 del_hsp_name_trad_sides( 811 mdsetname_t *sp, 812 md_set_desc *sd, 813 side_t curside, 814 mdkey_t key, 815 md_error_t *ep 816 ) 817 { 818 int error_seen = FALSE; 819 md_error_t first_error = MDNULLERROR; 820 int i; 821 822 for (i = 0; i < MD_MAXSIDES; i++) { 823 if (i == curside) 824 continue; 825 if (sd->sd_nodes[i][0] != '\0') { 826 if (del_name(sp, i, key, &first_error) == -1) { 827 if (error_seen == FALSE) { 828 error_seen = TRUE; 829 (void) mdstealerror(ep, &first_error); 830 } 831 } 832 } 833 } 834 } 835 836 /* 837 * FUNCTION: del_hsp_keys() 838 * INPUT: sp - set name 839 * hspid - ID of records to delete 840 * OUTPUT: ep - error information 841 * RETURNS: 0 - success 842 * -1 - error 843 * PURPOSE: Remove the NM records associated with hspid from all sides 844 * of the set. Missing records are not considered to be an 845 * error. The key associated with the current side is removed 846 * last. 847 * 848 * This function is very similar to del_key_name(), except it 849 * does not require any device look up. This is because the 850 * hot spare pool is not a device. 851 */ 852 static int 853 del_hsp_keys(mdsetname_t *sp, hsp_t hspid, md_error_t *ep) 854 { 855 md_error_t first_error = MDNULLERROR; 856 mdkey_t key = HSP_ID_TO_KEY(hspid); 857 md_set_desc *sd; 858 side_t thisside; /* Side # of this node. */ 859 860 /* 861 * If there is no key, this means that the hot spare was created 862 * before the introduction of friendly names. Thus, the is no NM 863 * record and nothing for us to do in this function. 864 */ 865 if (key == MD_KEYBAD) 866 return (0); 867 868 /* Find our current side */ 869 mdclrerror(ep); 870 thisside = getmyside(sp, ep); 871 if (! mdisok(ep)) 872 return (-1); 873 874 /* 875 * If not the local set, we need to process the non-local sides 876 * first. 877 */ 878 if (!metaislocalset(sp)) { 879 if ((sd = metaget_setdesc(sp, ep)) == NULL) 880 return (-1); 881 if (MD_MNSET_DESC(sd)) { 882 /* Multinode set. Sides are in a linked list. */ 883 del_hsp_name_mn_sides(sp, sd, thisside, key, 884 &first_error); 885 } else { 886 /* Sides are in an array. */ 887 del_hsp_name_trad_sides(sp, sd, thisside, key, 888 &first_error); 889 } 890 } 891 892 /* Now delete the name for the current side. */ 893 (void) del_name(sp, thisside, key, ep); 894 if (! mdisok(&first_error)) 895 (void) mdstealerror(ep, &first_error); 896 return (mdisok(ep) ? 0 : -1); 897 } 898 899 /* 900 * FUNCTION: add_hsp_name_mn_sides() 901 * INPUT: sp - set name 902 * curside - side number for this node 903 * key - key to use for the name record 904 * hsp_name - name of the hot spare 905 * OUTPUT: ep - error information 906 * RETURNS: 0 indicates success, and -1 indicates failure. 907 * PURPOSE: Once the name record has been added for the current side, 908 * this function adds the record to the remaining sides. This 909 * function is to be used when the set is a multinode set. 910 * The side designated by curside will be ignored when adding 911 * records. 912 */ 913 static int 914 add_hsp_name_mn_sides( 915 mdsetname_t *sp, 916 md_set_desc *sd, 917 side_t curside, 918 mdkey_t key, 919 char *hsp_name, 920 md_error_t *ep 921 ) 922 { 923 md_mnnode_desc *nd; 924 925 for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) { 926 if (nd->nd_nodeid == curside) 927 continue; 928 if (add_name(sp, nd->nd_nodeid, key, MD_HOTSPARES, 929 minor(NODEV), hsp_name, NULL, NULL, ep) == -1) { 930 return (-1); 931 } 932 } 933 return (0); 934 } 935 936 /* 937 * FUNCTION: add_hsp_name_trad_sides() 938 * INPUT: sp - set name 939 * curside - side number for this node 940 * key - key to use for the name record 941 * hsp_name - name of the hot spare 942 * OUTPUT: ep - error information 943 * RETURNS: 0 indicates success, and -1 indicates failure. 944 * PURPOSE: Once the name record has been added for the current side, 945 * this function adds the record to the remaining sides. This 946 * function is to be used when the set is a traditional set. 947 * The side designated by curside will be ignored when adding 948 * records. 949 */ 950 static int 951 add_hsp_name_trad_sides( 952 mdsetname_t *sp, 953 md_set_desc *sd, 954 side_t curside, 955 mdkey_t key, 956 char *hsp_name, 957 md_error_t *ep 958 ) 959 { 960 int i; 961 962 for (i = 0; i < MD_MAXSIDES; i++) { 963 if (i == curside) 964 continue; 965 if (sd->sd_nodes[i][0] != '\0') { 966 if (add_name(sp, i, key, MD_HOTSPARES, minor(NODEV), 967 hsp_name, NULL, NULL, ep) == -1) { 968 return (-1); 969 } 970 } 971 } 972 return (0); 973 } 974 975 /* 976 * FUNCTION: add_hsp_name() 977 * INPUT: sp - Name of the set containing the hsp 978 * hsp_name - Hot spare pool name to be added 979 * OUTPUT: ep - Error information 980 * RETURNS: If successful the key of the newly added record is 981 * returned. MD_KEYBAD is returned to indicate a failure. 982 * PURPOSE: This function creates a new NM record containing the name 983 * of the hotspare pool. A record containing the name is 984 * added to each active side, but the record is added first to 985 * the current side. This function is modeled on 986 * add_key_name() in meta_namespace. The difference is that 987 * there is no device associated with a hot spare pool 988 */ 989 static hsp_t 990 add_hsp_name( 991 mdsetname_t *sp, 992 char *hsp_name, 993 md_error_t *ep 994 ) 995 { 996 md_error_t ignore_error = MDNULLERROR; 997 mdkey_t key; 998 md_set_desc *sd; 999 side_t thisside; /* Side # of this node. */ 1000 1001 if (sp == NULL) { 1002 (void) mderror(ep, MDE_NO_SET, NULL); 1003 return (MD_KEYBAD); 1004 } 1005 if (hsp_name == NULL) { 1006 (void) mderror(ep, MDE_INVAL_HSOP, NULL); 1007 return (MD_KEYBAD); 1008 } 1009 1010 mdclrerror(ep); 1011 thisside = getmyside(sp, ep); 1012 if (! mdisok(ep)) 1013 return (MD_HSPID_WILD); 1014 1015 /* First add the record for the side of the current node. */ 1016 key = add_name(sp, thisside, MD_KEYWILD, MD_HOTSPARES, minor(NODEV), 1017 hsp_name, NULL, NULL, ep); 1018 if (key == -1) { 1019 goto cleanup; 1020 } 1021 1022 /* Make sure that we can use the key */ 1023 if (!HSP_KEY_OK(key)) { 1024 (void) mdhsperror(ep, MDE_HSP_CREATE_FAILURE, MD_HSPID_WILD, 1025 hsp_name); 1026 goto cleanup; 1027 } 1028 1029 /* 1030 * Now that we have a key, we will use it to add a record to the 1031 * rest of the sides in the set. For multinode sets, the sides are 1032 * in a linked list that is anchored on the set descriptor. For 1033 * traditional sets the side information is in an array in the set 1034 * descriptor. 1035 */ 1036 if (!metaislocalset(sp)) { 1037 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1038 goto cleanup; 1039 } 1040 if (MD_MNSET_DESC(sd)) { 1041 /* Multinode set. Sides are in linked list. */ 1042 if (add_hsp_name_mn_sides(sp, sd, thisside, key, 1043 hsp_name, ep) == -1) { 1044 goto cleanup; 1045 } 1046 } else { 1047 /* Traditional set. Sides are in an array. */ 1048 if (add_hsp_name_trad_sides(sp, sd, thisside, key, 1049 hsp_name, ep) == -1) { 1050 goto cleanup; 1051 } 1052 } 1053 } 1054 1055 return (KEY_TO_HSP_ID(sp->setno, key)); 1056 1057 cleanup: 1058 /* Get rid records that we added. */ 1059 (void) del_hsp_keys(sp, KEY_TO_HSP_ID(sp->setno, key), &ignore_error); 1060 return (MD_HSPID_WILD); 1061 } 1062 1063 /* 1064 * add hotspares and/or hotspare pool 1065 */ 1066 int 1067 meta_hs_add( 1068 mdsetname_t *sp, 1069 mdhspname_t *hspnp, 1070 mdnamelist_t *hsnlp, 1071 mdcmdopts_t options, 1072 md_error_t *ep 1073 ) 1074 { 1075 md_error_t ignore_error = MDNULLERROR; 1076 mdnamelist_t *p; 1077 set_hs_params_t shs; 1078 side_t thisside; 1079 1080 /* should have a set */ 1081 assert(sp != NULL); 1082 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp)); 1083 1084 /* clear cache */ 1085 meta_invalidate_hsp(hspnp); 1086 1087 /* setup hotspare pool info */ 1088 (void) memset(&shs, 0, sizeof (shs)); 1089 shs.shs_cmd = ADD_HOT_SPARE; 1090 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1091 1092 /* Get key for hot spare pool name record. */ 1093 if (options & MDCMD_DOIT) { 1094 /* First see if the name record already exists. */ 1095 mdclrerror(ep); 1096 thisside = getmyside(sp, ep); 1097 if (! mdisok(ep)) 1098 return (-1); 1099 shs.shs_hot_spare_pool = 1100 meta_gethspnmentbyname(sp->setno, thisside, 1101 hspnp->hspname, ep); 1102 if (! mdisok(ep)) { 1103 /* 1104 * If the error is ENOENT, then we will create a 1105 * hot spare pool name records. For other types of 1106 * errors, however, we'll bail out. 1107 */ 1108 if (! mdissyserror(ep, ENOENT)) 1109 return (-1); 1110 mdclrerror(ep); 1111 /* make sure that the name isn't already in use */ 1112 if (is_existing_metadevice(sp, hspnp->hspname)) 1113 return (mderror(ep, MDE_NAME_IN_USE, 1114 hspnp->hspname)); 1115 if ((shs.shs_hot_spare_pool = 1116 add_hsp_name(sp, hspnp->hspname, ep)) == 1117 MD_HSPID_WILD) { 1118 return (-1); 1119 } 1120 } 1121 } 1122 1123 /* add empty hotspare pool */ 1124 if (hsnlp == NULL) { 1125 shs.shs_options = HS_OPT_POOL; 1126 /* If DOIT is not set, it's a dryrun */ 1127 if ((options & MDCMD_DOIT) == 0) { 1128 shs.shs_options |= HS_OPT_DRYRUN; 1129 } 1130 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, 1131 hspnp->hspname) != 0) { 1132 if (options & MDCMD_DOIT) { 1133 (void) del_hsp_keys(sp, 1134 shs.shs_hot_spare_pool, 1135 &ignore_error); 1136 } 1137 return (mdstealerror(ep, &shs.mde)); 1138 } 1139 goto success; 1140 } 1141 1142 /* add hotspares */ 1143 shs.shs_options = HS_OPT_NONE; 1144 /* If DOIT is not set, it's a dryrun */ 1145 if ((options & MDCMD_DOIT) == 0) { 1146 shs.shs_options |= HS_OPT_DRYRUN; 1147 } 1148 for (p = hsnlp; (p != NULL); p = p->next) { 1149 mdname_t *hsnp = p->namep; 1150 diskaddr_t size, label, start_blk; 1151 1152 /* should be in same set */ 1153 assert(hspnp->hsp == MD_HSP_NONE || 1154 sp->setno == HSP_SET(hspnp->hsp)); 1155 1156 /* check it out */ 1157 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1158 return (-1); 1159 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) 1160 return (-1); 1161 else if (size == 0) 1162 return (mdsyserror(ep, ENOSPC, hsnp->cname)); 1163 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR) 1164 return (-1); 1165 if ((start_blk = metagetstart(sp, hsnp, ep)) 1166 == MD_DISKADDR_ERROR) 1167 return (-1); 1168 1169 shs.shs_size_option = meta_check_devicesize(size); 1170 1171 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 1172 if (options & MDCMD_DOIT) { 1173 /* store name in namespace */ 1174 if (add_key_name(sp, hsnp, NULL, ep) != 0) 1175 return (-1); 1176 } 1177 1178 /* add hotspare and/or hotspare pool */ 1179 shs.shs_component_old = hsnp->dev; 1180 shs.shs_start_blk = start_blk; 1181 shs.shs_has_label = ((label > 0) ? 1 : 0); 1182 shs.shs_number_blks = size; 1183 shs.shs_key_old = hsnp->key; 1184 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1185 if ((options & MDCMD_DOIT) && 1186 (shs.shs_options != HS_OPT_POOL)) { 1187 (void) del_key_name(sp, hsnp, ep); 1188 } 1189 return (mdstealerror(ep, &shs.mde)); 1190 } 1191 } 1192 1193 /* print success message */ 1194 success: 1195 if (options & MDCMD_PRINT) { 1196 if ((options & MDCMD_INIT) || (hsnlp == NULL)) { 1197 (void) printf(dgettext(TEXT_DOMAIN, 1198 "%s: Hotspare pool is setup\n"), 1199 hspnp->hspname); 1200 } else if (hsnlp->next == NULL) { 1201 (void) printf(dgettext(TEXT_DOMAIN, 1202 "%s: Hotspare is added\n"), 1203 hspnp->hspname); 1204 } else { 1205 (void) printf(dgettext(TEXT_DOMAIN, 1206 "%s: Hotspares are added\n"), 1207 hspnp->hspname); 1208 } 1209 (void) fflush(stdout); 1210 } 1211 1212 /* return success */ 1213 return (0); 1214 } 1215 1216 /* 1217 * FUNCTION: meta_hsp_delete() 1218 * INPUT: sp - Name of the set containing the hsp 1219 * hspnp - Hot spare pool name information 1220 * options - Options from command line 1221 * OUTPUT: ep - Error information 1222 * RETURNS: 0 on success and -1 on failure. 1223 * PURPOSE: Common code to delete an empty hot spare pool. 1224 */ 1225 static int 1226 meta_hsp_delete( 1227 mdsetname_t *sp, 1228 mdhspname_t *hspnp, 1229 mdcmdopts_t options, 1230 md_error_t *ep 1231 ) 1232 { 1233 set_hs_params_t shs; 1234 1235 /* setup hotspare pool info */ 1236 (void) memset(&shs, 0, sizeof (shs)); 1237 shs.shs_hot_spare_pool = hspnp->hsp; 1238 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1239 shs.shs_cmd = DELETE_HOT_SPARE; 1240 shs.shs_options = HS_OPT_POOL; 1241 /* If DOIT is not set, it's a dryrun */ 1242 if ((options & MDCMD_DOIT) == 0) { 1243 shs.shs_options |= HS_OPT_DRYRUN; 1244 } 1245 1246 /* Remove hsp record. */ 1247 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, 1248 hspnp->hspname) != 0) 1249 return (mdstealerror(ep, &shs.mde)); 1250 1251 /* Get rid of hsp NM records */ 1252 if ((options & MDCMD_DOIT) && 1253 (del_hsp_keys(sp, hspnp->hsp, ep) == -1)) { 1254 return (-1); 1255 } 1256 return (0); 1257 } 1258 1259 /* 1260 * delete hotspares from pool 1261 */ 1262 int 1263 meta_hs_delete( 1264 mdsetname_t *sp, 1265 mdhspname_t *hspnp, 1266 mdnamelist_t *hsnlp, 1267 mdcmdopts_t options, 1268 md_error_t *ep 1269 ) 1270 { 1271 mdnamelist_t *p; 1272 set_hs_params_t shs; 1273 1274 /* should have a set */ 1275 assert(sp != NULL); 1276 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp)); 1277 1278 /* clear cache */ 1279 meta_invalidate_hsp(hspnp); 1280 1281 /* setup hotspare pool info */ 1282 (void) memset(&shs, 0, sizeof (shs)); 1283 shs.shs_hot_spare_pool = hspnp->hsp; 1284 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1285 shs.shs_cmd = DELETE_HOT_SPARE; 1286 1287 /* delete empty hotspare pool */ 1288 if (hsnlp == NULL) { 1289 if (meta_hsp_delete(sp, hspnp, options, ep) != 0) 1290 return (-1); 1291 goto success; 1292 } 1293 1294 /* delete hotspares */ 1295 shs.shs_options = HS_OPT_NONE; 1296 /* If DOIT is not set, it's a dryrun */ 1297 if ((options & MDCMD_DOIT) == 0) { 1298 shs.shs_options |= HS_OPT_DRYRUN; 1299 } 1300 for (p = hsnlp; (p != NULL); p = p->next) { 1301 mdname_t *hsnp = p->namep; 1302 1303 /* should be in same set */ 1304 assert(hspnp->hsp == MD_HSP_NONE || 1305 sp->setno == HSP_SET(hspnp->hsp)); 1306 1307 /* delete hotspare */ 1308 shs.shs_component_old = hsnp->dev; 1309 meta_invalidate_name(hsnp); 1310 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) 1311 return (mdstealerror(ep, &shs.mde)); 1312 } 1313 1314 /* print success message */ 1315 success: 1316 if (options & MDCMD_PRINT) { 1317 if (hsnlp == NULL) { 1318 (void) printf(dgettext(TEXT_DOMAIN, 1319 "%s: Hotspare pool is cleared\n"), 1320 hspnp->hspname); 1321 } else if (hsnlp->next == NULL) { 1322 (void) printf(dgettext(TEXT_DOMAIN, 1323 "%s: Hotspare is deleted\n"), 1324 hspnp->hspname); 1325 } else { 1326 (void) printf(dgettext(TEXT_DOMAIN, 1327 "%s: Hotspares are deleted\n"), 1328 hspnp->hspname); 1329 } 1330 (void) fflush(stdout); 1331 } 1332 1333 /* return success */ 1334 return (0); 1335 } 1336 1337 /* 1338 * replace hotspare in pool 1339 */ 1340 int 1341 meta_hs_replace( 1342 mdsetname_t *sp, 1343 mdhspname_t *hspnp, 1344 mdname_t *oldnp, 1345 mdname_t *newnp, 1346 mdcmdopts_t options, 1347 md_error_t *ep 1348 ) 1349 { 1350 set_hs_params_t shs; 1351 diskaddr_t size, label, start_blk; 1352 md_dev64_t old_dev, new_dev; 1353 diskaddr_t new_start_blk, new_end_blk; 1354 int rebind; 1355 char *new_devidp = NULL; 1356 int ret; 1357 md_set_desc *sd; 1358 1359 /* should be in same set */ 1360 assert(sp != NULL); 1361 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp)); 1362 1363 /* save new binding incase this is a rebind where oldnp==newnp */ 1364 new_dev = newnp->dev; 1365 new_start_blk = newnp->start_blk; 1366 new_end_blk = newnp->end_blk; 1367 1368 /* invalidate, then get the hotspare (fill in oldnp from metadb) */ 1369 meta_invalidate_hsp(hspnp); 1370 if (meta_get_hsp(sp, hspnp, ep) == NULL) 1371 return (-1); 1372 1373 /* the old device binding is now established */ 1374 if ((old_dev = oldnp->dev) == NODEV64) 1375 return (mdsyserror(ep, ENODEV, oldnp->cname)); 1376 1377 /* 1378 * check for the case where oldnp and newnp indicate the same 1379 * device, but the dev_t of the device has changed between old 1380 * and new. This is called a rebind. On entry the dev_t 1381 * represents the new device binding determined from the 1382 * filesystem (meta_getdev). After calling meta_get_hsp 1383 * oldnp (and maybe newnp if this is a rebind) is updated based 1384 * to the old binding from the metadb (done by metakeyname). 1385 */ 1386 if ((strcmp(oldnp->rname, newnp->rname) == 0) && 1387 (old_dev != new_dev)) { 1388 rebind = 1; 1389 } else { 1390 rebind = 0; 1391 } 1392 if (rebind) { 1393 newnp->dev = new_dev; 1394 newnp->start_blk = new_start_blk; 1395 newnp->end_blk = new_end_blk; 1396 } 1397 1398 /* 1399 * Save a copy of the devid associated with the new disk, the reason 1400 * is that the meta_check_hotspare() call could cause the devid to 1401 * be changed to that of the devid that is currently stored in the 1402 * replica namespace for the disk in question. This devid could be 1403 * stale if we are replacing the disk. The function that overwrites 1404 * the devid is dr2drivedesc(). 1405 */ 1406 if (newnp->drivenamep->devid != NULL) 1407 new_devidp = Strdup(newnp->drivenamep->devid); 1408 1409 /* if it's a multi-node diskset clear new_devidp */ 1410 if (!metaislocalset(sp)) { 1411 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1412 Free(new_devidp); 1413 return (-1); 1414 } 1415 if (MD_MNSET_DESC(sd)) { 1416 Free(new_devidp); 1417 new_devidp = NULL; 1418 } 1419 } 1420 1421 /* check it out */ 1422 if (meta_check_hotspare(sp, newnp, ep) != 0) { 1423 if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) { 1424 Free(new_devidp); 1425 return (-1); 1426 } 1427 mdclrerror(ep); 1428 } 1429 if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) { 1430 Free(new_devidp); 1431 return (-1); 1432 } 1433 if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) { 1434 Free(new_devidp); 1435 return (-1); 1436 } 1437 if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) { 1438 Free(new_devidp); 1439 return (-1); 1440 } 1441 if (start_blk >= size) { 1442 (void) mdsyserror(ep, ENOSPC, newnp->cname); 1443 Free(new_devidp); 1444 return (-1); 1445 } 1446 1447 /* 1448 * Copy back the saved devid. 1449 */ 1450 Free(newnp->drivenamep->devid); 1451 if (new_devidp != NULL) { 1452 newnp->drivenamep->devid = new_devidp; 1453 new_devidp = NULL; 1454 } 1455 1456 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 1457 if (options & MDCMD_DOIT) { 1458 /* store name in namespace */ 1459 if (add_key_name(sp, newnp, NULL, ep) != 0) 1460 return (-1); 1461 } 1462 1463 if (rebind && !metaislocalset(sp)) { 1464 /* 1465 * We are 'rebind'ing a disk that is in a diskset so as well 1466 * as updating the diskset's namespace the local set needs 1467 * to be updated because it also contains a reference to the 1468 * disk in question. 1469 */ 1470 ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname, 1471 ep); 1472 1473 if (ret != METADEVADM_SUCCESS) { 1474 md_error_t xep = mdnullerror; 1475 1476 /* 1477 * In dryrun mode (DOIT not set) we must not alter 1478 * the mddb 1479 */ 1480 if (options & MDCMD_DOIT) { 1481 (void) del_key_name(sp, newnp, &xep); 1482 mdclrerror(&xep); 1483 return (-1); 1484 } 1485 } 1486 } 1487 1488 /* replace hotspare */ 1489 (void) memset(&shs, 0, sizeof (shs)); 1490 1491 shs.shs_size_option = meta_check_devicesize(size); 1492 1493 shs.shs_cmd = REPLACE_HOT_SPARE; 1494 shs.shs_hot_spare_pool = hspnp->hsp; 1495 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1496 shs.shs_component_old = old_dev; 1497 shs.shs_options = HS_OPT_NONE; 1498 /* If DOIT is not set, it's a dryrun */ 1499 if ((options & MDCMD_DOIT) == 0) { 1500 shs.shs_options |= HS_OPT_DRYRUN; 1501 } 1502 shs.shs_component_new = new_dev; 1503 shs.shs_start_blk = start_blk; 1504 shs.shs_has_label = ((label > 0) ? 1 : 0); 1505 shs.shs_number_blks = size; 1506 shs.shs_key_new = newnp->key; 1507 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1508 if (options & MDCMD_DOIT) { 1509 (void) del_key_name(sp, newnp, ep); 1510 } 1511 return (mdstealerror(ep, &shs.mde)); 1512 } 1513 1514 /* clear cache */ 1515 meta_invalidate_name(oldnp); 1516 meta_invalidate_name(newnp); 1517 meta_invalidate_hsp(hspnp); 1518 1519 /* let em know */ 1520 if (options & MDCMD_PRINT) { 1521 (void) printf(dgettext(TEXT_DOMAIN, 1522 "%s: Hotspare %s is replaced with %s\n"), 1523 hspnp->hspname, oldnp->cname, newnp->cname); 1524 (void) fflush(stdout); 1525 } 1526 1527 /* return success */ 1528 return (0); 1529 } 1530 1531 /* 1532 * enable hotspares 1533 */ 1534 int 1535 meta_hs_enable( 1536 mdsetname_t *sp, 1537 mdnamelist_t *hsnlp, 1538 mdcmdopts_t options, 1539 md_error_t *ep 1540 ) 1541 { 1542 mdhspnamelist_t *hspnlp = NULL; 1543 mdhspnamelist_t *hspnp; 1544 set_hs_params_t shs; 1545 int rval = -1; 1546 1547 /* should have a set */ 1548 assert(sp != NULL); 1549 1550 /* setup device info */ 1551 (void) memset(&shs, 0, sizeof (shs)); 1552 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1553 shs.shs_cmd = FIX_HOT_SPARE; 1554 shs.shs_options = HS_OPT_NONE; 1555 /* If DOIT is not set, it's a dryrun */ 1556 if ((options & MDCMD_DOIT) == 0) { 1557 shs.shs_options |= HS_OPT_DRYRUN; 1558 } 1559 1560 /* get the list of hotspare names */ 1561 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 1562 goto out; 1563 1564 /* enable hotspares for each components */ 1565 for (; (hsnlp != NULL); hsnlp = hsnlp->next) { 1566 mdname_t *hsnp = hsnlp->namep; 1567 md_dev64_t fs_dev; 1568 int rebind = 0; 1569 diskaddr_t size, label, start_blk; 1570 1571 /* get the file_system dev binding */ 1572 if (meta_getdev(sp, hsnp, ep) != 0) 1573 return (-1); 1574 fs_dev = hsnp->dev; 1575 1576 /* 1577 * search for the component in each hotspare pool 1578 * and replace it (instead of enable) if the binding 1579 * has changed. 1580 */ 1581 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) { 1582 /* 1583 * in_hsp will call meta_get_hsp which will fill 1584 * in hspnp with metadb version of component 1585 */ 1586 meta_invalidate_hsp(hspnp->hspnamep); 1587 if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) { 1588 /* 1589 * check for the case where the dev_t has 1590 * changed between the filesystem and the 1591 * metadb. This is called a rebind, and 1592 * is handled by meta_hs_replace. 1593 */ 1594 if (fs_dev != hsnp->dev) { 1595 /* 1596 * establish file system binding 1597 * with invalid start/end 1598 */ 1599 rebind++; 1600 hsnp->dev = fs_dev; 1601 hsnp->start_blk = -1; 1602 hsnp->end_blk = -1; 1603 rval = meta_hs_replace(sp, 1604 hspnp->hspnamep, 1605 hsnp, hsnp, options, ep); 1606 if (rval != 0) 1607 goto out; 1608 } 1609 } 1610 } 1611 if (rebind) 1612 continue; 1613 1614 /* enable the component in all hotspares that use it */ 1615 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1616 goto out; 1617 1618 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) 1619 goto out; 1620 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR) 1621 goto out; 1622 if ((start_blk = metagetstart(sp, hsnp, ep)) 1623 == MD_DISKADDR_ERROR) 1624 goto out; 1625 if (start_blk >= size) { 1626 (void) mdsyserror(ep, ENOSPC, hsnp->cname); 1627 goto out; 1628 } 1629 1630 /* enable hotspare */ 1631 shs.shs_component_old = hsnp->dev; 1632 shs.shs_component_new = hsnp->dev; 1633 shs.shs_start_blk = start_blk; 1634 shs.shs_has_label = ((label > 0) ? 1 : 0); 1635 shs.shs_number_blks = size; 1636 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) { 1637 rval = mdstealerror(ep, &shs.mde); 1638 goto out; 1639 } 1640 1641 /* 1642 * Are we dealing with a non-local set? If so need to update 1643 * the local namespace so that the disk record has the correct 1644 * devid. 1645 */ 1646 if (!metaislocalset(sp)) { 1647 rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, 1648 hsnp->cname, ep); 1649 1650 if (rval != METADEVADM_SUCCESS) { 1651 /* 1652 * Failed to update the local set. Nothing to 1653 * do here apart from report the error. The 1654 * namespace is most likely broken and some 1655 * form of remedial recovery is going to 1656 * be required. 1657 */ 1658 mde_perror(ep, ""); 1659 mdclrerror(ep); 1660 } 1661 } 1662 1663 /* clear cache */ 1664 meta_invalidate_name(hsnp); 1665 1666 /* let em know */ 1667 if (options & MDCMD_PRINT) { 1668 (void) printf(dgettext(TEXT_DOMAIN, 1669 "hotspare %s is enabled\n"), 1670 hsnp->cname); 1671 (void) fflush(stdout); 1672 } 1673 } 1674 1675 /* clear whole cache */ 1676 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) { 1677 meta_invalidate_hsp(hspnp->hspnamep); 1678 } 1679 1680 1681 /* return success */ 1682 rval = 0; 1683 1684 out: 1685 if (hspnlp) 1686 metafreehspnamelist(hspnlp); 1687 return (rval); 1688 } 1689 1690 /* 1691 * check for dups in the hsp itself 1692 */ 1693 static int 1694 check_twice( 1695 md_hsp_t *hspp, 1696 uint_t hsi, 1697 md_error_t *ep 1698 ) 1699 { 1700 mdhspname_t *hspnp = hspp->hspnamep; 1701 mdname_t *thisnp; 1702 uint_t h; 1703 1704 thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep; 1705 for (h = 0; (h < hsi); ++h) { 1706 md_hs_t *hsp = &hspp->hotspares.hotspares_val[h]; 1707 mdname_t *hsnp = hsp->hsnamep; 1708 1709 if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1, 1710 hsnp, 0, -1, ep) != 0) 1711 return (-1); 1712 } 1713 return (0); 1714 } 1715 1716 /* 1717 * check hsp 1718 */ 1719 /*ARGSUSED2*/ 1720 int 1721 meta_check_hsp( 1722 mdsetname_t *sp, 1723 md_hsp_t *hspp, 1724 mdcmdopts_t options, 1725 md_error_t *ep 1726 ) 1727 { 1728 mdhspname_t *hspnp = hspp->hspnamep; 1729 uint_t hsi; 1730 1731 /* check hotspares */ 1732 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 1733 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1734 mdname_t *hsnp = hsp->hsnamep; 1735 diskaddr_t size; 1736 1737 /* check hotspare */ 1738 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1739 return (-1); 1740 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) { 1741 return (-1); 1742 } else if (size == 0) { 1743 return (mdsyserror(ep, ENOSPC, hspnp->hspname)); 1744 } 1745 1746 /* check this hsp too */ 1747 if (check_twice(hspp, hsi, ep) != 0) 1748 return (-1); 1749 } 1750 1751 /* return success */ 1752 return (0); 1753 } 1754 1755 /* 1756 * create hsp 1757 */ 1758 int 1759 meta_create_hsp( 1760 mdsetname_t *sp, 1761 md_hsp_t *hspp, 1762 mdcmdopts_t options, 1763 md_error_t *ep 1764 ) 1765 { 1766 mdhspname_t *hspnp = hspp->hspnamep; 1767 mdnamelist_t *hsnlp = NULL; 1768 uint_t hsi; 1769 int rval = -1; 1770 1771 /* validate hsp */ 1772 if (meta_check_hsp(sp, hspp, options, ep) != 0) 1773 return (-1); 1774 1775 /* if we're not doing anything, return success */ 1776 if (! (options & MDCMD_DOIT)) 1777 return (0); 1778 1779 /* create hsp */ 1780 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 1781 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1782 mdname_t *hsnp = hsp->hsnamep; 1783 1784 (void) metanamelist_append(&hsnlp, hsnp); 1785 } 1786 options |= MDCMD_INIT; 1787 rval = meta_hs_add(sp, hspnp, hsnlp, options, ep); 1788 1789 /* cleanup, return success */ 1790 metafreenamelist(hsnlp); 1791 return (rval); 1792 } 1793 1794 /* 1795 * initialize hsp 1796 * NOTE: this functions is metainit(1m)'s command line parser! 1797 */ 1798 int 1799 meta_init_hsp( 1800 mdsetname_t **spp, 1801 int argc, 1802 char *argv[], 1803 mdcmdopts_t options, 1804 md_error_t *ep 1805 ) 1806 { 1807 char *uname = argv[0]; 1808 mdhspname_t *hspnp = NULL; 1809 md_hsp_t *hspp = NULL; 1810 uint_t hsi; 1811 int rval = -1; 1812 1813 1814 /* get hsp name */ 1815 assert(argc > 0); 1816 if (argc < 1) 1817 goto syntax; 1818 if ((hspnp = metahspname(spp, uname, ep)) == NULL) 1819 goto out; 1820 assert(*spp != NULL); 1821 uname = hspnp->hspname; 1822 1823 if (!(options & MDCMD_NOLOCK)) { 1824 /* grab set lock */ 1825 if (meta_lock(*spp, TRUE, ep)) 1826 goto out; 1827 1828 if (meta_check_ownership(*spp, ep) != 0) 1829 goto out; 1830 } 1831 1832 /* see if it exists already */ 1833 if (is_existing_metadevice(*spp, uname)) { 1834 mdname_t *np; 1835 if ((np = metaname(spp, uname, META_DEVICE, ep)) != NULL) 1836 if ((meta_get_unit(*spp, np, ep)) != NULL) 1837 return (mderror(ep, MDE_NAME_IN_USE, uname)); 1838 } 1839 1840 if (meta_get_hsp(*spp, hspnp, ep) != NULL) { 1841 (void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, 1842 hspnp->hsp, uname); 1843 goto out; 1844 } else if (! mdishsperror(ep, MDE_INVAL_HSP)) { 1845 goto out; 1846 } else { 1847 mdclrerror(ep); 1848 } 1849 --argc, ++argv; 1850 1851 /* parse general options */ 1852 optind = 0; 1853 opterr = 0; 1854 if (getopt(argc, argv, "") != -1) 1855 goto options; 1856 1857 /* allocate hsp */ 1858 hspp = Zalloc(sizeof (*hspp)); 1859 hspp->hotspares.hotspares_len = argc; 1860 if (argc > 0) { 1861 hspp->hotspares.hotspares_val = 1862 Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val)); 1863 } 1864 1865 /* setup pool */ 1866 hspp->hspnamep = hspnp; 1867 1868 /* parse hotspares */ 1869 for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len)); 1870 ++hsi) { 1871 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1872 mdname_t *hsnamep; 1873 1874 /* parse hotspare name */ 1875 if ((hsnamep = metaname(spp, argv[0], 1876 LOGICAL_DEVICE, ep)) == NULL) 1877 goto out; 1878 hsp->hsnamep = hsnamep; 1879 --argc, ++argv; 1880 } 1881 1882 /* we should be at the end */ 1883 if (argc != 0) 1884 goto syntax; 1885 1886 /* create hotspare pool */ 1887 if (meta_create_hsp(*spp, hspp, options, ep) != 0) 1888 goto out; 1889 rval = 0; /* success */ 1890 goto out; 1891 1892 /* syntax error */ 1893 syntax: 1894 rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv); 1895 goto out; 1896 1897 /* options error */ 1898 options: 1899 rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv); 1900 goto out; 1901 1902 /* cleanup, return error */ 1903 out: 1904 if (hspp != NULL) 1905 meta_free_hsp(hspp); 1906 return (rval); 1907 } 1908 1909 /* 1910 * reset hotspare pool 1911 */ 1912 int 1913 meta_hsp_reset( 1914 mdsetname_t *sp, 1915 mdhspname_t *hspnp, 1916 mdcmdopts_t options, 1917 md_error_t *ep 1918 ) 1919 { 1920 md_hsp_t *hspp; 1921 set_hs_params_t shs; 1922 uint_t i; 1923 int rval = -1; 1924 1925 /* should have the same set */ 1926 assert(sp != NULL); 1927 assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE || 1928 sp->setno == HSP_SET(hspnp->hsp)); 1929 1930 /* reset all hotspares */ 1931 if (hspnp == NULL) { 1932 mdhspnamelist_t *hspnlp = NULL; 1933 mdhspnamelist_t *p; 1934 1935 /* for each hotspare pool */ 1936 rval = 0; 1937 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 1938 return (-1); 1939 for (p = hspnlp; (p != NULL); p = p->next) { 1940 /* reset hotspare pool */ 1941 hspnp = p->hspnamep; 1942 1943 /* 1944 * If this is a multi-node set, we send a series 1945 * of individual metaclear commands. 1946 */ 1947 if (meta_is_mn_set(sp, ep)) { 1948 if (meta_mn_send_metaclear_command(sp, 1949 hspnp->hspname, options, 0, ep) != 0) { 1950 rval = -1; 1951 break; 1952 } 1953 } else { 1954 if (meta_hsp_reset(sp, hspnp, options, 1955 ep) != 0) { 1956 rval = -1; 1957 break; 1958 } 1959 } 1960 } 1961 1962 /* cleanup, return success */ 1963 metafreehspnamelist(hspnlp); 1964 return (rval); 1965 } 1966 1967 /* get unit structure */ 1968 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL) 1969 return (-1); 1970 1971 /* make sure nobody owns us */ 1972 if (hspp->refcount > 0) { 1973 return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp, 1974 hspnp->hspname)); 1975 } 1976 1977 /* clear hotspare pool members */ 1978 (void) memset(&shs, 0, sizeof (shs)); 1979 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1980 shs.shs_cmd = DELETE_HOT_SPARE; 1981 shs.shs_hot_spare_pool = hspnp->hsp; 1982 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) { 1983 md_hs_t *hs = &hspp->hotspares.hotspares_val[i]; 1984 mdname_t *hsnamep = hs->hsnamep; 1985 1986 /* clear cache */ 1987 meta_invalidate_name(hsnamep); 1988 1989 /* clear hotspare */ 1990 shs.shs_component_old = hsnamep->dev; 1991 shs.shs_options = HS_OPT_FORCE; 1992 /* If DOIT is not set, it's a dryrun */ 1993 if ((options & MDCMD_DOIT) == 0) { 1994 shs.shs_options |= HS_OPT_DRYRUN; 1995 } 1996 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1997 (void) mdstealerror(ep, &shs.mde); 1998 goto out; 1999 } 2000 } 2001 2002 /* clear hotspare pool */ 2003 if (meta_hsp_delete(sp, hspnp, options, ep) != 0) 2004 goto out; 2005 rval = 0; /* success */ 2006 2007 /* let em know */ 2008 if (options & MDCMD_PRINT) { 2009 (void) printf(dgettext(TEXT_DOMAIN, 2010 "%s: Hotspare pool is cleared\n"), 2011 hspnp->hspname); 2012 (void) fflush(stdout); 2013 } 2014 2015 /* clear subdevices (nothing to do) */ 2016 2017 /* cleanup, return success */ 2018 out: 2019 meta_invalidate_hsp(hspnp); 2020 return (rval); 2021 } 2022