1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <errno.h> 31 #include <string.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 35 #include <meta.h> 36 #include <sdssc.h> 37 #include <mdiox.h> 38 #include <meta_repartition.h> 39 40 #include "volume_dlist.h" 41 #include "volume_error.h" 42 #include "volume_output.h" 43 44 #include "layout_device_util.h" 45 #include "layout_discovery.h" 46 #include "layout_dlist_util.h" 47 #include "layout_request.h" 48 #include "layout_svm_util.h" 49 50 static int _max_hsps = 1000; /* # of HSPs (arbitrary limit) */ 51 static int _max_devs = 8192; /* # of SVM volumes allowed */ 52 static int _max_devs_cfg = 128; /* # of SVM volumes configured */ 53 static int _max_sets = 4; /* # of SVM disk sets */ 54 55 /* volume name prefixes for generating new names */ 56 static const char *_hsp_prefix = "hsp"; 57 static const char *_dev_prefix = "d"; 58 59 /* 60 * dynamically allocated arrays to track used HSP (hspXXX) and volume 61 * names (dXXX) by number 62 */ 63 static boolean_t *hsps_by_number = NULL; 64 static boolean_t *devs_by_number = NULL; 65 66 /* 67 * This struct remembers a diskset and the names of 68 * the disks in the set 69 */ 70 typedef struct { 71 char *name; 72 dlist_t *disknames; 73 dlist_t *hsps; 74 } diskset_t; 75 76 /* 77 * list of diskset_t for known disksets 78 */ 79 static dlist_t *_disksets = NULL; 80 81 static int add_diskset( 82 char *diskset); 83 84 static int add_diskset_diskname( 85 char *diskset, 86 char *diskname); 87 88 static int add_diskset_hsp( 89 char *diskset, 90 char *hspname); 91 92 static int add_diskset_hsp_spare( 93 char *diskset, 94 char *hspname, 95 char *spare); 96 97 static int is_disk_in_local_diskset( 98 dm_descriptor_t disk, 99 boolean_t *bool); 100 101 static int is_disk_in_named_diskset( 102 dm_descriptor_t disk, 103 char *dsname, 104 boolean_t *bool); 105 106 /* SVM snapshot stuff */ 107 typedef enum { 108 SVM_DISKSET = 0, 109 SVM_MDB, 110 SVM_STRIPE, 111 SVM_MIRROR, 112 SVM_RAID, 113 SVM_TRANS, 114 SVM_SP, 115 SVM_HSP, 116 SVM_HS, 117 SVM_DRIVE 118 } svm_type_t; 119 120 typedef struct svm_snap_entry { 121 struct svm_snap_entry *next; 122 char *diskset; 123 svm_type_t type; 124 char *name; 125 char *slice; 126 } svm_snap_t; 127 128 static svm_snap_t *svm_snapshot(int *errp); 129 static void free_svm_snapshot(svm_snap_t *listp); 130 131 static char *type_name(svm_type_t type); 132 static int add_record( 133 svm_snap_t **listp, 134 char *setname, 135 svm_type_t type, 136 char *mname, 137 char *slice_name); 138 static int diskset_info(svm_snap_t **listp, mdsetname_t *sp); 139 static void free_names(mdnamelist_t *nlp); 140 static int load_svm(svm_snap_t **listp); 141 static int new_entry( 142 svm_snap_t **listp, 143 char *sname, 144 svm_type_t type, 145 char *mname, 146 mdsetname_t *sp); 147 148 /* 149 * FUNCTION: scan_svm_names(char *diskset) 150 * 151 * INPUT: diskset - a char * disk set name 152 * 153 * PURPOSE: Take a snapshot of the current SVM config. 154 * 155 * Scan it and remember: 156 * 1. all known disk sets 157 * s. the disks in the named disk set 158 * 3. the used device and HSP names in the named disk set 159 * 4. the HSPs in the disk set 160 * 5. the spares in the HSPs 161 */ 162 int 163 scan_svm_names( 164 char *diskset) 165 { 166 int ndisks = 0; 167 int nhsps = 0; 168 int ndevices = 0; 169 int nsets = 0; 170 171 int number = 0; 172 int error = 0; 173 svm_snap_t *headp = NULL; 174 svm_snap_t *listp = NULL; 175 char *tablefmt = " %-20s %-10s %-20s %-10s\n"; 176 177 oprintf(OUTPUT_TERSE, 178 gettext("\nScanning system SVM configuration...\n")); 179 180 headp = svm_snapshot(&error); 181 if (error != 0) { 182 oprintf(OUTPUT_TERSE, 183 gettext("failed to scan SVM devices\n")); 184 return (error); 185 } 186 187 if (error == 0) { 188 if ((error = get_max_number_of_devices(&_max_devs_cfg)) == 0) { 189 oprintf(OUTPUT_VERBOSE, 190 gettext(" configured maximum number of " 191 "volumes: %d\n"), 192 _max_devs_cfg); 193 } 194 } 195 196 if (error == 0) { 197 if ((error = get_max_number_of_disksets(&_max_sets)) == 0) { 198 oprintf(OUTPUT_VERBOSE, 199 gettext(" configured maximum number of " 200 "disk sets: %d\n"), 201 _max_sets); 202 } 203 } 204 205 if (error == 0) { 206 /* array is realloc'ed as necessary */ 207 if ((hsps_by_number = 208 (boolean_t *)calloc(_max_hsps, sizeof (boolean_t))) == NULL) { 209 oprintf(OUTPUT_TERSE, 210 gettext("failed to allocate HSP name array\n")); 211 error = ENOMEM; 212 } 213 } 214 215 if (error == 0) { 216 /* array is realloc'ed as necessary */ 217 if ((devs_by_number = 218 (boolean_t *)calloc(_max_devs, sizeof (boolean_t))) == NULL) { 219 oprintf(OUTPUT_TERSE, 220 gettext("failed to allocate volume name array\n")); 221 error = ENOMEM; 222 } 223 } 224 225 if ((error == 0) && (get_max_verbosity() >= OUTPUT_DEBUG)) { 226 (void) oprintf(OUTPUT_DEBUG, "\n"); 227 (void) oprintf(OUTPUT_DEBUG, 228 tablefmt, 229 gettext("disk set"), 230 gettext("dev type"), 231 gettext("name"), 232 gettext("slice")); 233 (void) oprintf(OUTPUT_DEBUG, 234 " -----------------------------------" 235 "-----------------------------------\n"); 236 } 237 238 for (listp = headp; listp != NULL && error == 0; listp = listp->next) { 239 240 oprintf(OUTPUT_DEBUG, 241 tablefmt, 242 listp->diskset, 243 type_name(listp->type), 244 listp->name, 245 listp->slice); 246 247 switch (listp->type) { 248 case SVM_DISKSET: 249 250 error = add_diskset(listp->name); 251 ++nsets; 252 break; 253 254 case SVM_DRIVE: 255 256 error = add_diskset_diskname(listp->diskset, listp->name); 257 258 /* is this drive in the requested diskset? */ 259 if (string_case_compare(diskset, listp->diskset) == 0) { 260 ++ndisks; 261 } 262 break; 263 264 case SVM_MIRROR: 265 case SVM_RAID: 266 case SVM_TRANS: 267 case SVM_SP: 268 case SVM_STRIPE: 269 270 /* is this SVM volume in the requested diskset? */ 271 if (string_case_compare(diskset, listp->diskset) == 0) { 272 273 /* isolate device name from "poolname/dXXXX" */ 274 char *cp = strrchr(listp->name, '/'); 275 if (cp != NULL) { 276 ++cp; 277 } else { 278 cp = listp->name; 279 } 280 281 /* BEGIN CSTYLED */ 282 /* 283 * names for requested devices and HSPs are remembered 284 * so that the default name generation scheme knows 285 * which names are already being used 286 */ 287 /* END CSTYLED */ 288 /* extract device number from name "dXXXX" */ 289 if (sscanf(cp, "d%d", &number) != EOF) { 290 oprintf(OUTPUT_DEBUG, 291 gettext(" device: %6s number: %3d\n"), 292 cp, number); 293 294 if (number > _max_devs) { 295 /* hit current limit, expand it */ 296 boolean_t *tmp = 297 (boolean_t *)realloc((void *)_max_devs, 298 (number * sizeof (boolean_t))); 299 300 if (tmp == NULL) { 301 error = ENOMEM; 302 } else { 303 _max_devs = number; 304 devs_by_number = tmp; 305 } 306 } 307 308 if ((error == 0) && 309 (devs_by_number[number] == B_FALSE)) { 310 devs_by_number[number] = B_TRUE; 311 ++ndevices; 312 } 313 } 314 } 315 break; 316 317 case SVM_HSP: 318 319 /* is this HSP in the requested diskset? */ 320 if (string_case_compare(diskset, listp->diskset) == 0) { 321 322 /* isolate HSP name from "poolname/hspXXX" */ 323 char *cp = strrchr(listp->name, '/'); 324 if (cp != NULL) { 325 ++cp; 326 } else { 327 cp = listp->name; 328 } 329 330 /* extract pool number from name "hspXXX" */ 331 if (sscanf(cp, "hsp%03d", &number) != EOF) { 332 oprintf(OUTPUT_DEBUG, 333 gettext(" HSP: %6s number: %3d\n"), 334 cp, number); 335 336 if (number > _max_hsps) { 337 /* hit our arbitrary limit, double it */ 338 boolean_t *tmp = 339 (boolean_t *)realloc((void *)hsps_by_number, 340 2 * _max_hsps * sizeof (boolean_t)); 341 342 if (tmp != NULL) { 343 _max_hsps *= 2; 344 hsps_by_number = tmp; 345 } else { 346 error = ENOMEM; 347 } 348 } 349 350 if ((error == 0) && 351 (hsps_by_number[number] == B_FALSE)) { 352 hsps_by_number[number] = B_TRUE; 353 error = add_diskset_hsp(diskset, cp); 354 ++nhsps; 355 } 356 } 357 } 358 359 break; 360 361 case SVM_HS: 362 363 /* is this hot spare in the requested disk set? */ 364 if (string_case_compare(diskset, listp->diskset) == 0) { 365 366 /* isolate HSP name from "poolname/hspXXXX" */ 367 char *cp = strrchr(listp->name, '/'); 368 if (cp != NULL) { 369 ++cp; 370 } else { 371 cp = listp->name; 372 } 373 374 error = add_diskset_hsp_spare(diskset, cp, listp->slice); 375 } 376 break; 377 378 case SVM_MDB: 379 default: 380 break; 381 } 382 } 383 384 free_svm_snapshot(headp); 385 386 if (error == 0) { 387 /* available diskset? subtract 1 for the local set */ 388 if ((diskset_exists(diskset) != B_TRUE) && 389 (nsets >= _max_sets)) { 390 volume_set_error( 391 gettext("Disk set \"%s\" cannot be created, the " 392 "maximum number of disk sets (%d) already " 393 "exists.\n"), 394 diskset, _max_sets); 395 error = -1; 396 } 397 } 398 399 if (error == 0) { 400 oprintf(OUTPUT_VERBOSE, 401 gettext("\n Disk set \"%s\" has:\n\n"), diskset); 402 oprintf(OUTPUT_VERBOSE, 403 gettext(" %d drives\n"), ndisks); 404 oprintf(OUTPUT_VERBOSE, 405 gettext(" %d volumes\n"), ndevices); 406 oprintf(OUTPUT_VERBOSE, 407 gettext(" %d HSPs\n"), nhsps); 408 } else { 409 free(hsps_by_number); 410 free(devs_by_number); 411 hsps_by_number = (boolean_t *)NULL; 412 devs_by_number = (boolean_t *)NULL; 413 } 414 415 return (error); 416 } 417 418 /* 419 * FUNCTION: release_svm_names() 420 * 421 * PURPOSE: Release snapshot of the current SVM config. 422 * 423 * Free memory allocated by scan_svm_names() 424 */ 425 void 426 release_svm_names() 427 { 428 dlist_t *iter; 429 430 for (iter = _disksets; iter != NULL; iter = iter->next) { 431 diskset_t *diskset = (diskset_t *)iter->obj; 432 dlist_free_items(diskset->disknames, free); 433 dlist_free_items(diskset->hsps, free_devconfig); 434 free(diskset->name); 435 } 436 dlist_free_items(_disksets, free); 437 _disksets = NULL; 438 439 if (hsps_by_number != NULL) 440 free(hsps_by_number); 441 if (devs_by_number != NULL) 442 free(devs_by_number); 443 444 hsps_by_number = (boolean_t *)NULL; 445 devs_by_number = (boolean_t *)NULL; 446 } 447 448 /* 449 * FUNCTION: diskset_exists(char *diskset) 450 * 451 * INPUT: dsname - a char * diskset name 452 * 453 * RETURNS: boolean_t - B_TRUE if the named diskset exists 454 * B_FALSE otherwise 455 * 456 * PURPOSE: Checks the list of known disk sets and determines 457 * if the input name is in that list. 458 */ 459 boolean_t 460 diskset_exists( 461 char *dsname) 462 { 463 dlist_t *iter; 464 465 for (iter = _disksets; iter != NULL; iter = iter->next) { 466 diskset_t *diskset = (diskset_t *)iter->obj; 467 if (string_case_compare(dsname, diskset->name) == 0) { 468 return (B_TRUE); 469 } 470 } 471 472 return (B_FALSE); 473 } 474 475 /* 476 * FUNCTION: add_diskset(char *dsname) 477 * 478 * INPUT: dsname - a char * disk set name 479 * 480 * RETURNS: int - 0 on success 481 * !0 otherwise 482 * 483 * PURPOSE: Add the named disk set to the list of known disk sets. 484 */ 485 static int 486 add_diskset( 487 char *dsname) 488 { 489 dlist_t *iter; 490 int error = 0; 491 492 for (iter = _disksets; iter != NULL; iter = iter->next) { 493 diskset_t *diskset = (diskset_t *)iter->obj; 494 if (string_case_compare(diskset->name, dsname) == 0) { 495 break; 496 } 497 } 498 499 if (iter == NULL) { 500 501 dlist_t *item = NULL; 502 diskset_t *diskset = (diskset_t *)calloc(1, sizeof (diskset_t)); 503 504 if (diskset == NULL) { 505 error = ENOMEM; 506 } else { 507 diskset->hsps = NULL; 508 diskset->name = strdup(dsname); 509 if (diskset->name == NULL) { 510 free(diskset); 511 error = ENOMEM; 512 } else { 513 if ((item = dlist_new_item(diskset)) == NULL) { 514 free(diskset->name); 515 free(diskset); 516 error = ENOMEM; 517 } else { 518 _disksets = dlist_append(item, _disksets, AT_HEAD); 519 oprintf(OUTPUT_DEBUG, 520 gettext(" added disk set %s \n"), dsname); 521 } 522 } 523 } 524 } 525 526 return (error); 527 } 528 529 /* 530 * FUNCTION: add_diskset_diskname(char *diskset, char *diskname) 531 * 532 * INPUT: dsname - a char * disk set name 533 * diskname - a char * disk name 534 * 535 * RETURNS: int - 0 on success 536 * !0 otherwise 537 * 538 * PURPOSE: Add the disk name to the named disk set's list of disks. 539 * 540 * The input diskname is fully qualified with the path 541 * to the raw disk device (/dev/rdsk/cXtXdXsX) which is 542 * not relevant, so it is removed. 543 */ 544 static int 545 add_diskset_diskname( 546 char *dsname, 547 char *diskname) 548 { 549 dlist_t *iter; 550 int error = 0; 551 552 for (iter = _disksets; iter != NULL; iter = iter->next) { 553 554 diskset_t *diskset = (diskset_t *)iter->obj; 555 if (string_case_compare(diskset->name, dsname) == 0) { 556 557 dlist_t *item = NULL; 558 char *name = NULL; 559 char *cp = NULL; 560 561 /* trim leading path */ 562 if ((cp = strrchr(diskname, '/')) != 0) { 563 if ((name = strdup(cp+1)) == NULL) { 564 error = ENOMEM; 565 } 566 } else if ((name = strdup(diskname)) == NULL) { 567 error = ENOMEM; 568 } 569 570 if ((item = dlist_new_item(name)) == NULL) { 571 free(name); 572 error = ENOMEM; 573 } else { 574 diskset->disknames = 575 dlist_append(item, diskset->disknames, AT_HEAD); 576 } 577 578 break; 579 } 580 } 581 582 if ((error == 0) && (iter == NULL)) { 583 /* new disk set */ 584 if ((error = add_diskset(dsname)) == 0) { 585 return (add_diskset_diskname(dsname, diskname)); 586 } 587 } 588 589 return (error); 590 } 591 592 /* 593 * FUNCTION: add_diskset_hsp(char *dsname, char *hspname) 594 * 595 * INPUT: dsname - a char * disk set name 596 * hspname - a char * HSP name 597 * 598 * RETURNS: int - 0 on success 599 * !0 otherwise 600 * 601 * PURPOSE: Model a new HSP for the named disk set. 602 * 603 * Metassist can use existing HSPs to service new volumes. 604 * 605 * It is necessary to have a model of what HSPs currently 606 * exist for each disk set. 607 * 608 * This function takes information found during discovery 609 * and turns it into a form usable by the HSP layout code. 610 */ 611 static int 612 add_diskset_hsp( 613 char *dsname, 614 char *hspname) 615 { 616 dlist_t *iter; 617 int error = 0; 618 619 for (iter = _disksets; iter != NULL; iter = iter->next) { 620 621 diskset_t *diskset = (diskset_t *)iter->obj; 622 623 if (string_case_compare(diskset->name, dsname) == 0) { 624 625 dlist_t *item = NULL; 626 devconfig_t *hsp = NULL; 627 628 if (((error = new_devconfig(&hsp, TYPE_HSP)) != 0) || 629 (error = devconfig_set_name(hsp, hspname))) { 630 free_devconfig(hsp); 631 } else { 632 if ((item = dlist_new_item(hsp)) == NULL) { 633 free_devconfig(hsp); 634 error = ENOMEM; 635 } else { 636 diskset->hsps = 637 dlist_append(item, diskset->hsps, AT_TAIL); 638 639 oprintf(OUTPUT_DEBUG, 640 gettext(" added %s to disk set %s\n"), 641 hspname, dsname); 642 } 643 } 644 break; 645 } 646 } 647 648 if ((error == 0) && (iter == NULL)) { 649 if ((error = add_diskset(dsname)) == 0) { 650 return (add_diskset_hsp(dsname, hspname)); 651 } 652 } 653 654 return (error); 655 } 656 657 /* 658 * FUNCTION: add_diskset_hsp_spare(char *dsname, char *hspname, 659 * char *sparename) 660 * 661 * INPUT: dsname - a char * diskset name 662 * hspname - a char * HSP name 663 * sparename - a char * hot spare (slice) name 664 * 665 * RETURNS: int - 0 on success 666 * !0 otherwise 667 * 668 * PURPOSE: Locate the named hot spare pool in the named disk set and 669 * add the named spare slice to its list of spares. 670 * 671 * Metassist can use existing HSPs to service new volumes. 672 * 673 * It is necessary to have a model of what HSPs currently 674 * exist for each disk set. 675 * 676 * This function takes information found during discovery 677 * and turns it into a form usable by the HSP layout code. 678 */ 679 static int 680 add_diskset_hsp_spare( 681 char *dsname, 682 char *hspname, 683 char *sparename) 684 { 685 dlist_t *iter; 686 int error = 0; 687 688 for (iter = _disksets; iter != NULL; iter = iter->next) { 689 690 diskset_t *diskset = (diskset_t *)iter->obj; 691 692 if (string_case_compare(diskset->name, dsname) == 0) { 693 694 dlist_t *item = 695 dlist_find( 696 diskset->hsps, hspname, 697 compare_string_to_devconfig_name); 698 699 if (item != NULL) { 700 701 /* add spare to HSP */ 702 devconfig_t *hsp = (devconfig_t *)item->obj; 703 dm_descriptor_t slice = (dm_descriptor_t)0; 704 705 (void) slice_get_by_name(sparename, &slice); 706 if (slice == (dm_descriptor_t)0) { 707 oprintf(OUTPUT_TERSE, 708 gettext("warning: ignoring nonexistent " 709 "slice %s defined in %s\n"), 710 sparename, hspname); 711 } else { 712 713 uint64_t nbytes = 0; 714 uint32_t index = 0; 715 devconfig_t *spare = NULL; 716 717 /* build a devconfig_t model of the slice */ 718 if (((error = slice_get_size(slice, &nbytes)) != 0) || 719 (error = slice_get_index(slice, &index)) || 720 (error = new_devconfig(&spare, TYPE_SLICE)) || 721 (error = devconfig_set_name(spare, sparename)) || 722 (error = devconfig_set_size(spare, nbytes)) || 723 (error = devconfig_set_slice_index(spare, index))) { 724 free_devconfig(spare); 725 } else { 726 727 if ((item = dlist_new_item(spare)) == NULL) { 728 error = ENOMEM; 729 free_devconfig(spare); 730 } else { 731 dlist_t *spares; 732 spares = devconfig_get_components(hsp); 733 spares = dlist_append(item, spares, AT_TAIL); 734 devconfig_set_components(hsp, spares); 735 736 oprintf(OUTPUT_DEBUG, 737 gettext(" added %s to %s in " 738 "disk set %s\n"), 739 sparename, hspname, dsname); 740 } 741 } 742 } 743 744 break; 745 746 } else { 747 if ((error = add_diskset_hsp(dsname, hspname)) == 0) { 748 return (add_diskset_hsp_spare( 749 dsname, hspname, sparename)); 750 } 751 } 752 } 753 } 754 755 return (error); 756 } 757 758 /* 759 * Return a list of disks in the given diskset. 760 * 761 * @param dsname 762 * The name of the named disk set, or "" for the local 763 * set. 764 * 765 * @param disks 766 * RETURN: pointer to the list of disks in the given disk 767 * set 768 * 769 * @return 0 if succesful, non-zero otherwise 770 */ 771 int 772 get_disks_in_diskset( 773 char *dsname, 774 dlist_t **disks) 775 { 776 dlist_t *known_disks; 777 int error = 0; 778 779 *disks = NULL; 780 781 if ((error = get_known_disks(&known_disks)) == 0) { 782 dlist_t *iter; 783 784 /* For each known disk... */ 785 for (iter = known_disks; 786 iter != NULL && error == 0; 787 iter = iter->next) { 788 dm_descriptor_t disk = (uintptr_t)iter->obj; 789 boolean_t in_diskset = B_FALSE; 790 791 /* If this disk is in the given set... */ 792 error = is_disk_in_diskset(disk, dsname, &in_diskset); 793 if (error == 0 && in_diskset == B_TRUE) { 794 dlist_t *item = dlist_new_item((void *)(uintptr_t)disk); 795 *disks = dlist_append(item, *disks, AT_TAIL); 796 } 797 } 798 } 799 800 return (error); 801 } 802 803 /* 804 * FUNCTION: is_disk_in_diskset(dm_descriptor_t disk, char *dsname, 805 * boolean_t *bool) 806 * 807 * INPUT: disk - dm_descriptor_t disk handle 808 * dsname - char * diskset name, or MD_LOCAL_NAME for 809 * the local set. 810 * 811 * OUTPUT: bool - pointer to a boolean_t to hold the result 812 * 813 * RETURNS: int - 0 on success 814 * !0 otherwise 815 * 816 * PURPOSE: Determine if the input disk is known to be in the 817 * given diskset. 818 */ 819 int 820 is_disk_in_diskset( 821 dm_descriptor_t disk, 822 char *dsname, 823 boolean_t *bool) 824 { 825 if (string_case_compare(dsname, MD_LOCAL_NAME) == 0) { 826 return (is_disk_in_local_diskset(disk, bool)); 827 } 828 829 return (is_disk_in_named_diskset(disk, dsname, bool)); 830 } 831 832 static int 833 is_disk_in_local_diskset( 834 dm_descriptor_t disk, 835 boolean_t *bool) 836 { 837 dlist_t *iter; 838 dlist_t *aliases = NULL; 839 boolean_t in_named_diskset = B_FALSE; 840 char *name = NULL; 841 int error = 0; 842 843 *bool = B_FALSE; 844 845 error = get_display_name(disk, &name); 846 if (error == 0) { 847 848 error = get_aliases(disk, &aliases); 849 if (error == 0) { 850 851 /* For each known disk set... */ 852 for (iter = _disksets; 853 iter != NULL && in_named_diskset == B_FALSE; 854 iter = iter->next) { 855 856 diskset_t *diskset = (diskset_t *)iter->obj; 857 dlist_t *names = diskset->disknames; 858 859 /* Check disk name */ 860 in_named_diskset = dlist_contains( 861 names, name, compare_device_names); 862 863 /* Check disk aliases */ 864 if (in_named_diskset == B_FALSE) { 865 dlist_t *iter2; 866 for (iter2 = aliases; 867 iter2 != NULL && in_named_diskset == B_FALSE; 868 iter2 = iter2->next) { 869 in_named_diskset = dlist_contains(names, 870 (char *)iter2->obj, compare_device_names); 871 } 872 } 873 } 874 } 875 } 876 877 if (error == 0) { 878 *bool = (in_named_diskset == B_TRUE ? B_FALSE : B_TRUE); 879 } 880 881 return (error); 882 } 883 884 static int 885 is_disk_in_named_diskset( 886 dm_descriptor_t disk, 887 char *dsname, 888 boolean_t *bool) 889 { 890 dlist_t *iter; 891 int error = 0; 892 boolean_t in_diskset = B_FALSE; 893 894 *bool = B_FALSE; 895 896 for (iter = _disksets; 897 (iter != NULL) && (in_diskset == B_FALSE); 898 iter = iter->next) { 899 900 diskset_t *diskset = (diskset_t *)iter->obj; 901 902 if (string_case_compare(diskset->name, dsname) == 0) { 903 904 dlist_t *names = diskset->disknames; 905 dlist_t *aliases = NULL; 906 char *name = NULL; 907 908 ((error = get_display_name(disk, &name)) != 0) || 909 (error = get_aliases(disk, &aliases)); 910 if (error != 0) { 911 break; 912 } 913 914 /* check disk name */ 915 in_diskset = dlist_contains(names, name, compare_device_names); 916 917 /* check disk aliases */ 918 if (in_diskset == B_FALSE) { 919 dlist_t *iter2; 920 for (iter2 = aliases; 921 (iter2 != NULL) && (in_diskset == B_FALSE); 922 iter2 = iter2->next) { 923 in_diskset = dlist_contains(names, 924 (char *)iter2->obj, compare_device_names); 925 } 926 } 927 } 928 } 929 930 *bool = in_diskset; 931 932 return (error); 933 } 934 935 /* 936 * FUNCTION: is_disk_in_other_diskset(dm_descriptor_t disk, char *dsname, 937 * boolean_t *bool) 938 * 939 * INPUT: disk - dm_descriptor_t disk handle 940 * dsname - char * disk set name 941 * 942 * OUTPUT: bool - pointer to a boolean_t to hold the result. 943 * 944 * RETURNS: int - 0 on success 945 * !0 otherwise 946 * 947 * PURPOSE: Determine if the named disk is known to be in a disk set 948 * other than the named disk set. 949 */ 950 int 951 is_disk_in_other_diskset( 952 dm_descriptor_t disk, 953 char *dsname, 954 boolean_t *bool) 955 { 956 boolean_t in_other = B_FALSE; 957 dlist_t *iter; 958 dlist_t *aliases = NULL; 959 char *name = NULL; 960 char *cp = NULL; 961 int error = 0; 962 963 ((error = get_display_name(disk, &name)) != 0) || 964 (error = get_aliases(disk, &aliases)); 965 if (error != 0) { 966 return (error); 967 } 968 969 /* 970 * discard the leading path, it is probably /dev/dsk 971 * and the disk set disk names are all /dev/rdsk/... 972 * 973 * aliases do not have leading paths 974 */ 975 cp = strrchr(name, '/'); 976 if (cp != NULL) { 977 ++cp; 978 } else { 979 cp = name; 980 } 981 name = cp; 982 983 for (iter = _disksets; 984 (iter != NULL) && (in_other == B_FALSE); 985 iter = iter->next) { 986 987 diskset_t *diskset = (diskset_t *)iter->obj; 988 dlist_t *names = diskset->disknames; 989 990 if (string_case_compare(diskset->name, dsname) == 0) { 991 /* skip named disk set */ 992 continue; 993 } 994 995 /* see if disk's name is in disk set's name list */ 996 in_other = dlist_contains(names, name, compare_device_names); 997 998 /* see if any of the disk's aliases is in name list */ 999 if (in_other == B_FALSE) { 1000 dlist_t *iter2; 1001 for (iter2 = aliases; 1002 (iter2 != NULL) && (in_other == B_FALSE); 1003 iter2 = iter2->next) { 1004 1005 in_other = dlist_contains(names, 1006 (char *)iter2->obj, compare_device_names); 1007 } 1008 } 1009 } 1010 1011 *bool = in_other; 1012 1013 return (error); 1014 } 1015 1016 /* 1017 * FUNCTION: hsp_get_default_for_diskset(char *diskset, 1018 * devconfig_t **hsp) 1019 * 1020 * INPUT: diskset - char * disk set name 1021 * 1022 * RETURNS: devconfig_t * - pointer to the first HSP in the disk set 1023 * NULL if none found 1024 * 1025 * PURPOSE: Locate the first HSP in the named disk set. 1026 */ 1027 int 1028 hsp_get_default_for_diskset( 1029 char *diskset, 1030 devconfig_t **hsp) 1031 { 1032 dlist_t *iter = _disksets; 1033 1034 *hsp = NULL; 1035 1036 for (; (iter != NULL) && (*hsp == NULL); iter = iter->next) { 1037 diskset_t *set = (diskset_t *)iter->obj; 1038 if (string_case_compare(set->name, diskset) == 0) { 1039 dlist_t *item = set->hsps; 1040 if (item != NULL) { 1041 *hsp = item->obj; 1042 } 1043 } 1044 } 1045 1046 return (0); 1047 } 1048 1049 /* 1050 * FUNCTION: get_n_metadb_replicas(int *nreplicas) 1051 * 1052 * OUTPUT: nreplicas - pointer to int to hold the result 1053 * 1054 * RETURNS: int - 0 on success 1055 * !0 on failure 1056 * 1057 * PURPOSE: Check the number of replicas configured for the local set. 1058 */ 1059 int 1060 get_n_metadb_replicas( 1061 int *nreplicas) 1062 { 1063 mdsetname_t *sp; 1064 md_replicalist_t *rlp = NULL; 1065 md_error_t mderror = mdnullerror; 1066 int error = 0; 1067 1068 *nreplicas = 0; 1069 1070 sp = metasetname(MD_LOCAL_NAME, &mderror); 1071 if (!mdisok(&mderror)) { 1072 volume_set_error(mde_sperror(&mderror, NULL)); 1073 mdclrerror(&mderror); 1074 error = -1; 1075 } else { 1076 *nreplicas = metareplicalist(sp, MD_BASICNAME_OK, &rlp, &mderror); 1077 if (!mdisok(&mderror)) { 1078 volume_set_error(mde_sperror(&mderror, NULL)); 1079 mdclrerror(&mderror); 1080 error = -1; 1081 } else if (rlp != NULL) { 1082 metafreereplicalist(rlp); 1083 rlp = NULL; 1084 } 1085 1086 if (*nreplicas < 0) { 1087 *nreplicas = 0; 1088 } 1089 } 1090 1091 return (error); 1092 } 1093 1094 /* 1095 * FUNCTION: hsp_get_by_name(char *diskset, char *name, 1096 * devconfig_t **hsp) 1097 * 1098 * INPUT: diskset - char * disk set name 1099 * name - char * HSP name 1100 * 1101 * OUTPUT: hsp - a devconfig_t * - pointer to hold 1102 * the named HSP if none found 1103 * 1104 * PURPOSE: Locate the named HSP in the named disk set. 1105 */ 1106 int 1107 hsp_get_by_name( 1108 char *diskset, 1109 char *name, 1110 devconfig_t **hsp) 1111 { 1112 dlist_t *iter = _disksets; 1113 1114 *hsp = NULL; 1115 1116 for (; (iter != NULL) && (*hsp == NULL); iter = iter->next) { 1117 diskset_t *set = (diskset_t *)iter->obj; 1118 if (string_case_compare(set->name, diskset) == 0) { 1119 dlist_t *item = dlist_find( 1120 set->hsps, name, compare_string_to_devconfig_name); 1121 if (item != NULL) { 1122 *hsp = item->obj; 1123 } 1124 } 1125 } 1126 1127 return (0); 1128 } 1129 1130 /* 1131 * FUNCTION: is_volume_name_valid(char *name) 1132 * 1133 * OUTPUT: name - pointer to a char * volume name 1134 * 1135 * RETURNS: boolean_t - B_TRUE if the input name is valid 1136 * B_FALSE otherwise 1137 * 1138 * PURPOSE: Wrapper around libmeta volume name validation method. 1139 */ 1140 boolean_t 1141 is_volume_name_valid( 1142 char *name) 1143 { 1144 return (is_metaname(name)); 1145 } 1146 1147 /* 1148 * FUNCTION: is_hsp_name_valid(char *name) 1149 * 1150 * INPUT: name - char * HSP name 1151 * 1152 * RETURNS: boolean_t - B_TRUE if the input name is valid 1153 * B_FALSE otherwise 1154 * 1155 * PURPOSE: Wrapper around libmeta HSP name validation method. 1156 */ 1157 boolean_t 1158 is_hsp_name_valid( 1159 char *name) 1160 { 1161 return (is_hspname(name)); 1162 } 1163 1164 /* 1165 * FUNCTION: extract_index(char *name, char *prefix, char *num_fmt, 1166 * int *index) 1167 * 1168 * INPUT: name - const char * volume name 1169 * prefix - const char * fixed part of format string 1170 * num_fmt - const char * format of number to extract (e.g. %d) 1171 * 1172 * OUTPUT: index - pointer to int to hold numeric part of name 1173 * 1174 * RETURNS: boolean_t - B_TRUE if the input name is parsed correctly 1175 * B_FALSE otherwise 1176 * 1177 * PURPOSE: Extract the numeric portion of a device name for use 1178 * by higher-level functions. 1179 */ 1180 static boolean_t 1181 extract_index( 1182 const char *name, 1183 const char *prefix, 1184 const char *num_fmt, 1185 int *index) 1186 { 1187 char buf[MAXNAMELEN]; 1188 const char *cp; 1189 const char *fmt = buf; 1190 1191 if ((cp = strrchr(name, '/')) != NULL) { 1192 ++cp; 1193 } else { 1194 cp = name; 1195 } 1196 1197 (void) snprintf(buf, sizeof (buf), "%s%s", prefix, num_fmt); 1198 if (sscanf(cp, fmt, index) == 1) 1199 return (B_TRUE); 1200 else 1201 return (B_FALSE); 1202 } 1203 1204 /* 1205 * FUNCTION: is_volume_name_in_range(char *name) 1206 * 1207 * INPUT: name - char * volume name 1208 * 1209 * RETURNS: boolean_t - B_TRUE if the input name is in the allowed 1210 * range of names 1211 * B_FALSE otherwise 1212 * 1213 * PURPOSE: Determine if the input volume name is within the allowed 1214 * range of device names (0 <= n < max # of devices configured). 1215 */ 1216 boolean_t 1217 is_volume_name_in_range( 1218 char *name) 1219 { 1220 int index = -1; 1221 1222 if (extract_index(name, _dev_prefix, "%d", &index)) { 1223 if (index >= 0 && index < _max_devs_cfg) { 1224 return (B_TRUE); 1225 } 1226 } 1227 1228 return (B_FALSE); 1229 } 1230 1231 /* 1232 * FUNCTION: reserve_volume_name(char *name) 1233 * 1234 * INPUT: name - a char * volume name 1235 * 1236 * RETURNS: int - 0 on success 1237 * !0 otherwise 1238 * 1239 * PURPOSE: Mark a volume name/number as used. 1240 * 1241 * Assumes that the input name has been validated. 1242 * 1243 * if the name is not currently available, return -1 1244 */ 1245 int 1246 reserve_volume_name( 1247 char *name) 1248 { 1249 int index = -1; 1250 1251 if (extract_index(name, _dev_prefix, "%d", &index)) { 1252 if (devs_by_number[index] != B_TRUE) { 1253 devs_by_number[index] = B_TRUE; 1254 return (0); 1255 } 1256 } 1257 1258 return (-1); 1259 } 1260 1261 /* 1262 * FUNCTION: reserve_hsp_name(char *name) 1263 * 1264 * INPUT: name - a char * hsp name 1265 * 1266 * RETURNS: int - 0 on success 1267 * !0 otherwise 1268 * 1269 * PURPOSE: Mark a HSP name/number as used. 1270 * 1271 * Assumes that the input name has been validated. 1272 * 1273 * if the name is not currently available, return -1 1274 */ 1275 int 1276 reserve_hsp_name( 1277 char *name) 1278 { 1279 int index = -1; 1280 1281 if (extract_index(name, _hsp_prefix, "%03d", &index)) { 1282 if (hsps_by_number[index] != B_TRUE) { 1283 hsps_by_number[index] = B_TRUE; 1284 return (0); 1285 } 1286 } 1287 1288 return (-1); 1289 } 1290 1291 /* 1292 * FUNCTION: release_volume_name(char *name) 1293 * 1294 * INPUT: name - a char * volume name 1295 * 1296 * PURPOSE: release the input volume name. 1297 * 1298 * Extract volume number from the input name 1299 * and use it to index into the array of used 1300 * volume numbers. Make that volume number 1301 * available for use again. 1302 */ 1303 void 1304 release_volume_name( 1305 char *name) 1306 { 1307 int index = -1; 1308 1309 if (name != NULL && extract_index(name, _dev_prefix, "%d", &index)) { 1310 oprintf(OUTPUT_DEBUG, 1311 gettext("released volume name %s%d\n"), 1312 _dev_prefix, index); 1313 devs_by_number[index] = B_FALSE; 1314 } 1315 } 1316 1317 /* 1318 * FUNCTION: release_hsp_name(char *name) 1319 * 1320 * INPUT: name - a char * HSP name 1321 * 1322 * PURPOSE: release the input HSP name. 1323 * 1324 * Extract volume number from the input name 1325 * and use it to index into the array of used 1326 * hsp numbers. Make that hsp number available 1327 * for use again. 1328 */ 1329 void 1330 release_hsp_name( 1331 char *name) 1332 { 1333 int index = -1; 1334 1335 if (name != NULL && extract_index(name, _hsp_prefix, "%d", &index)) { 1336 oprintf(OUTPUT_DEBUG, 1337 gettext("released hsp name %s%d\n"), 1338 _hsp_prefix, index); 1339 hsps_by_number[index] = B_FALSE; 1340 } 1341 } 1342 1343 /* 1344 * FUNCTION: get_next_volume_name(char **name) 1345 * 1346 * OUTPUT: name - pointer to a char * to hold volume name 1347 * 1348 * RETURNS: int - 0 on success 1349 * !0 otherwise 1350 * 1351 * PURPOSE: generate a new volume name using the standard device 1352 * name prefix and the lowest available device number. 1353 * 1354 * if type == MIRROR, determine the next available mirror 1355 * name according to the convention that a mirror name is 1356 * a multiple of 10. 1357 * 1358 * If such a name is unavailable, use the next available name. 1359 */ 1360 int 1361 get_next_volume_name( 1362 char **name, 1363 component_type_t type) 1364 { 1365 int next = 0; 1366 1367 for (next = 0; next < _max_devs_cfg; ++next) { 1368 if ((type == TYPE_MIRROR && ((next % 10) != 0)) || 1369 (type != TYPE_MIRROR && ((next % 10) == 0))) { 1370 /* use/save multiples of 10 for mirrors */ 1371 continue; 1372 } 1373 if (devs_by_number[next] != B_TRUE) { 1374 break; 1375 } 1376 } 1377 1378 if ((next == _max_devs_cfg) && (type == TYPE_MIRROR)) { 1379 /* try next sequentially available name */ 1380 for (next = 0; next < _max_devs_cfg; ++next) { 1381 if (devs_by_number[next] != B_TRUE) { 1382 break; 1383 } 1384 } 1385 } 1386 1387 if (next == _max_devs_cfg) { 1388 volume_set_error( 1389 gettext("ran out of logical volume names.\n")); 1390 return (-1); 1391 } 1392 1393 *name = (char *)calloc(MAXNAMELEN, sizeof (char)); 1394 if (*name == NULL) { 1395 return (ENOMEM); 1396 } 1397 1398 (void) snprintf(*name, MAXNAMELEN-1, "%s%d", _dev_prefix, next); 1399 1400 devs_by_number[next] = B_TRUE; 1401 return (0); 1402 } 1403 1404 /* 1405 * FUNCTION: get_next_submirror_name(char *mname, char **subname) 1406 * 1407 * INPUT: mname - pointer to a char * mirror name 1408 * OUTPUT: subname - pointer to a char * to hold submirror name 1409 * 1410 * RETURNS: int - 0 on success 1411 * !0 otherwise 1412 * 1413 * PURPOSE: Determine the next available submirror name according 1414 * to the convention that each submirror name is a sequential 1415 * increment of its mirror's name. 1416 * 1417 * If such a name is unavailable, return the next sequentially 1418 * available volume name. 1419 */ 1420 int 1421 get_next_submirror_name( 1422 char *mname, 1423 char **subname) 1424 { 1425 char buf[MAXNAMELEN]; 1426 int error = 0; 1427 int next = 0; 1428 int i = 0; 1429 1430 *subname = NULL; 1431 1432 /* try next sequential name: mirror + 1... */ 1433 if (extract_index(mname, _dev_prefix, "%d", &next)) { 1434 for (i = next + 1; i < _max_devs_cfg; i++) { 1435 if ((i % 10) == 0) { 1436 /* save for mirrors */ 1437 continue; 1438 } 1439 if (devs_by_number[i] == B_FALSE) { 1440 (void) snprintf(buf, MAXNAMELEN-1, "%s%d", _dev_prefix, i); 1441 if ((*subname = strdup(buf)) != NULL) { 1442 devs_by_number[i] = B_TRUE; 1443 } else { 1444 error = ENOMEM; 1445 } 1446 break; 1447 } 1448 } 1449 } 1450 1451 if ((error == 0) && (*subname == NULL)) { 1452 /* name adhering to convention isn't available, */ 1453 /* use next sequentially available name */ 1454 error = get_next_volume_name(subname, TYPE_STRIPE); 1455 } 1456 1457 return (error); 1458 } 1459 1460 /* 1461 * FUNCTION: get_next_hsp_name(char **name) 1462 * 1463 * OUTPUT: name - pointer to a char * to hold name 1464 * 1465 * RETURNS: int - 0 on success 1466 * !0 otherwise 1467 * 1468 * PURPOSE: Helper which generates a new hotsparepool name 1469 * using the standard name prefix and the lowest 1470 * available hsp number. 1471 */ 1472 int 1473 get_next_hsp_name( 1474 char **name) 1475 { 1476 int next = 0; 1477 1478 for (next = 0; next < _max_hsps; ++next) { 1479 if (hsps_by_number[next] != B_TRUE) { 1480 break; 1481 } 1482 } 1483 1484 if (next == _max_hsps) { 1485 volume_set_error(gettext("ran out of HSP names")); 1486 return (-1); 1487 } 1488 1489 *name = (char *)calloc(MAXNAMELEN, sizeof (char)); 1490 if (*name == NULL) { 1491 oprintf(OUTPUT_TERSE, 1492 gettext("failed to allocate volume name string, " 1493 "out of memory")); 1494 return (ENOMEM); 1495 } 1496 1497 (void) snprintf(*name, MAXNAMELEN-1, "%s%03d", _hsp_prefix, next); 1498 1499 hsps_by_number[next] = B_TRUE; 1500 1501 return (0); 1502 } 1503 1504 static char * 1505 type_name( 1506 svm_type_t type) 1507 { 1508 switch (type) { 1509 case SVM_DISKSET: return (gettext("disk set")); 1510 case SVM_MDB: return (gettext("metadb")); 1511 case SVM_STRIPE: return (gettext("stripe")); 1512 case SVM_MIRROR: return (gettext("mirror")); 1513 case SVM_RAID: return (gettext("raid")); 1514 case SVM_TRANS: return (gettext("trans")); 1515 case SVM_SP: return (gettext("soft partition")); 1516 case SVM_HSP: return (gettext("hot spare pool")); 1517 case SVM_HS: return (gettext("hot spare")); 1518 case SVM_DRIVE: return (gettext("drive")); 1519 default: return (gettext("unknown")); 1520 } 1521 } 1522 1523 static svm_snap_t * 1524 svm_snapshot(int *errp) 1525 { 1526 svm_snap_t *svm_listp = NULL; 1527 1528 *errp = 0; 1529 1530 /* initialize the cluster library entry points */ 1531 if (sdssc_bind_library() == SDSSC_ERROR) { 1532 1533 volume_set_error(gettext("sdssc_bin_library() failed\n")); 1534 *errp = -1; 1535 1536 } else { 1537 1538 /* load the SVM cache */ 1539 *errp = load_svm(&svm_listp); 1540 1541 if (*errp != 0) { 1542 free_svm_snapshot(svm_listp); 1543 svm_listp = NULL; 1544 } 1545 1546 } 1547 1548 return (svm_listp); 1549 } 1550 1551 static void 1552 free_svm_snapshot(svm_snap_t *listp) { 1553 1554 svm_snap_t *nextp; 1555 1556 while (listp != NULL) { 1557 nextp = listp->next; 1558 free((void *)listp->diskset); 1559 free((void *)listp->name); 1560 free((void *)listp->slice); 1561 free((void *)listp); 1562 listp = nextp; 1563 } 1564 } 1565 1566 static int 1567 add_record( 1568 svm_snap_t **listp, 1569 char *setname, 1570 svm_type_t type, 1571 char *mname, 1572 char *slice_name) 1573 { 1574 svm_snap_t *sp; 1575 1576 sp = (svm_snap_t *)malloc(sizeof (svm_snap_t)); 1577 if (sp == NULL) { 1578 return (ENOMEM); 1579 } 1580 1581 if ((sp->diskset = strdup(setname)) == NULL) { 1582 free(sp); 1583 return (ENOMEM); 1584 } 1585 1586 if ((sp->name = strdup(mname)) == NULL) { 1587 free(sp->diskset); 1588 free(sp); 1589 return (ENOMEM); 1590 } 1591 1592 sp->type = type; 1593 1594 if ((sp->slice = strdup(slice_name)) == NULL) { 1595 free(sp->diskset); 1596 free(sp->name); 1597 free(sp); 1598 return (ENOMEM); 1599 } 1600 1601 sp->next = *listp; 1602 *listp = sp; 1603 1604 return (0); 1605 } 1606 1607 static int 1608 diskset_info( 1609 svm_snap_t **listp, 1610 mdsetname_t *sp) 1611 { 1612 md_error_t error = mdnullerror; 1613 md_replicalist_t *replica_list = NULL; 1614 md_replicalist_t *mdbp; 1615 mdnamelist_t *nlp; 1616 mdnamelist_t *trans_list = NULL; 1617 mdnamelist_t *mirror_list = NULL; 1618 mdnamelist_t *raid_list = NULL; 1619 mdnamelist_t *stripe_list = NULL; 1620 mdnamelist_t *sp_list = NULL; 1621 mdhspnamelist_t *hsp_list = NULL; 1622 1623 if (metareplicalist(sp, MD_BASICNAME_OK, &replica_list, &error) < 0) { 1624 /* there are no metadb's; that is ok, no need to check the rest */ 1625 mdclrerror(&error); 1626 return (0); 1627 } 1628 mdclrerror(&error); 1629 1630 for (mdbp = replica_list; mdbp != NULL; mdbp = mdbp->rl_next) { 1631 char size[MAXPATHLEN]; 1632 1633 (void) snprintf(size, sizeof (size), "%d", 1634 (int)mdbp->rl_repp->r_nblk); 1635 1636 if (new_entry(listp, mdbp->rl_repp->r_namep->cname, SVM_MDB, size, 1637 sp)) { 1638 metafreereplicalist(replica_list); 1639 return (ENOMEM); 1640 } 1641 } 1642 metafreereplicalist(replica_list); 1643 1644 if (meta_get_trans_names(sp, &trans_list, 0, &error) >= 0) { 1645 for (nlp = trans_list; nlp != NULL; nlp = nlp->next) { 1646 if (new_entry(listp, nlp->namep->cname, SVM_TRANS, 1647 nlp->namep->cname, sp)) { 1648 free_names(trans_list); 1649 return (ENOMEM); 1650 } 1651 } 1652 1653 free_names(trans_list); 1654 } 1655 mdclrerror(&error); 1656 1657 if (meta_get_mirror_names(sp, &mirror_list, 0, &error) >= 0) { 1658 for (nlp = mirror_list; nlp != NULL; nlp = nlp->next) { 1659 if (add_record(listp, sp->setname, SVM_MIRROR, 1660 nlp->namep->cname, "")) { 1661 free_names(mirror_list); 1662 return (ENOMEM); 1663 } 1664 } 1665 1666 free_names(mirror_list); 1667 } 1668 mdclrerror(&error); 1669 1670 if (meta_get_raid_names(sp, &raid_list, 0, &error) >= 0) { 1671 for (nlp = raid_list; nlp != NULL; nlp = nlp->next) { 1672 mdname_t *mdn; 1673 md_raid_t *raid; 1674 1675 mdn = metaname(&sp, nlp->namep->cname, &error); 1676 mdclrerror(&error); 1677 if (mdn == NULL) { 1678 continue; 1679 } 1680 1681 raid = meta_get_raid(sp, mdn, &error); 1682 mdclrerror(&error); 1683 1684 if (raid != NULL) { 1685 int i; 1686 1687 for (i = 0; i < raid->cols.cols_len; i++) { 1688 if (new_entry(listp, 1689 raid->cols.cols_val[i].colnamep->cname, SVM_RAID, 1690 nlp->namep->cname, sp)) { 1691 free_names(raid_list); 1692 return (ENOMEM); 1693 } 1694 } 1695 } 1696 } 1697 1698 free_names(raid_list); 1699 } 1700 mdclrerror(&error); 1701 1702 if (meta_get_stripe_names(sp, &stripe_list, 0, &error) >= 0) { 1703 for (nlp = stripe_list; nlp != NULL; nlp = nlp->next) { 1704 mdname_t *mdn; 1705 md_stripe_t *stripe; 1706 1707 mdn = metaname(&sp, nlp->namep->cname, &error); 1708 mdclrerror(&error); 1709 if (mdn == NULL) { 1710 continue; 1711 } 1712 1713 stripe = meta_get_stripe(sp, mdn, &error); 1714 mdclrerror(&error); 1715 1716 if (stripe != NULL) { 1717 int i; 1718 1719 for (i = 0; i < stripe->rows.rows_len; i++) { 1720 md_row_t *rowp; 1721 int j; 1722 1723 rowp = &stripe->rows.rows_val[i]; 1724 1725 for (j = 0; j < rowp->comps.comps_len; j++) { 1726 md_comp_t *component; 1727 1728 component = &rowp->comps.comps_val[j]; 1729 if (new_entry(listp, component->compnamep->cname, 1730 SVM_STRIPE, nlp->namep->cname, sp)) { 1731 free_names(stripe_list); 1732 return (ENOMEM); 1733 } 1734 } 1735 } 1736 } 1737 } 1738 1739 free_names(stripe_list); 1740 } 1741 mdclrerror(&error); 1742 1743 if (meta_get_sp_names(sp, &sp_list, 0, &error) >= 0) { 1744 for (nlp = sp_list; nlp != NULL; nlp = nlp->next) { 1745 mdname_t *mdn; 1746 md_sp_t *soft_part; 1747 1748 mdn = metaname(&sp, nlp->namep->cname, &error); 1749 mdclrerror(&error); 1750 if (mdn == NULL) { 1751 continue; 1752 } 1753 1754 soft_part = meta_get_sp(sp, mdn, &error); 1755 mdclrerror(&error); 1756 1757 if (soft_part != NULL) { 1758 if (new_entry(listp, soft_part->compnamep->cname, SVM_SP, 1759 nlp->namep->cname, sp)) { 1760 free_names(sp_list); 1761 return (ENOMEM); 1762 } 1763 } 1764 } 1765 1766 free_names(sp_list); 1767 } 1768 mdclrerror(&error); 1769 1770 if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) { 1771 mdhspnamelist_t *nlp; 1772 1773 for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) { 1774 md_hsp_t *hsp; 1775 1776 hsp = meta_get_hsp(sp, nlp->hspnamep, &error); 1777 mdclrerror(&error); 1778 if (hsp != NULL) { 1779 int i; 1780 1781 for (i = 0; i < hsp->hotspares.hotspares_len; i++) { 1782 md_hs_t *hs; 1783 1784 hs = &hsp->hotspares.hotspares_val[i]; 1785 1786 if (add_record(listp, sp->setname, SVM_HS, 1787 nlp->hspnamep->hspname, hs->hsnamep->bname)) { 1788 metafreehspnamelist(hsp_list); 1789 return (ENOMEM); 1790 } 1791 } 1792 } 1793 1794 if (add_record(listp, sp->setname, SVM_HSP, 1795 nlp->hspnamep->hspname, "")) { 1796 metafreehspnamelist(hsp_list); 1797 return (ENOMEM); 1798 } 1799 } 1800 1801 metafreehspnamelist(hsp_list); 1802 } 1803 1804 mdclrerror(&error); 1805 1806 return (0); 1807 } 1808 1809 static void 1810 free_names( 1811 mdnamelist_t *nlp) 1812 { 1813 mdnamelist_t *p; 1814 1815 for (p = nlp; p != NULL; p = p->next) { 1816 meta_invalidate_name(p->namep); 1817 } 1818 metafreenamelist(nlp); 1819 } 1820 1821 /* 1822 * Create a list of SVM devices 1823 */ 1824 static int 1825 load_svm( 1826 svm_snap_t **listp) 1827 { 1828 int max_sets; 1829 md_error_t error = mdnullerror; 1830 int i; 1831 1832 if ((max_sets = get_max_sets(&error)) == 0) { 1833 return (0); 1834 } 1835 1836 if (!mdisok(&error)) { 1837 volume_set_error( 1838 gettext("failed to get maximum number of disk sets.\n")); 1839 mdclrerror(&error); 1840 return (-1); 1841 } 1842 1843 /* for each possible set number, see if we really have a disk set */ 1844 for (i = 0; i < max_sets; i++) { 1845 mdsetname_t *sp; 1846 1847 if ((sp = metasetnosetname(i, &error)) == NULL) { 1848 if (!mdisok(&error) && error.info.errclass == MDEC_RPC) { 1849 /* rpc error - no metasets */ 1850 break; 1851 } 1852 1853 mdclrerror(&error); 1854 continue; 1855 } 1856 1857 mdclrerror(&error); 1858 1859 if (add_record(listp, sp->setname, SVM_DISKSET, sp->setname, "")) { 1860 metaflushsetname(sp); 1861 return (ENOMEM); 1862 } 1863 1864 /* check for drives in disk sets */ 1865 if (sp->setno != 0) { 1866 md_drive_desc *dd; 1867 1868 dd = metaget_drivedesc(sp, MD_BASICNAME_OK | PRINT_FAST, 1869 &error); 1870 mdclrerror(&error); 1871 for (; dd != NULL; dd = dd->dd_next) { 1872 if (add_record(listp, sp->setname, SVM_DRIVE, 1873 dd->dd_dnp->rname, "")) { 1874 metaflushsetname(sp); 1875 return (ENOMEM); 1876 } 1877 } 1878 } 1879 1880 if (diskset_info(listp, sp)) { 1881 metaflushsetname(sp); 1882 return (ENOMEM); 1883 } 1884 1885 metaflushsetname(sp); 1886 } 1887 1888 mdclrerror(&error); 1889 1890 return (0); 1891 } 1892 1893 /* determine if 'sp' is built on a slice */ 1894 static int 1895 new_entry( 1896 svm_snap_t **listp, 1897 char *slice_name, 1898 svm_type_t type, 1899 char *mname, 1900 mdsetname_t *sp) 1901 { 1902 mdname_t *mdn; 1903 md_error_t error = mdnullerror; 1904 1905 mdn = metaname(&sp, slice_name, &error); 1906 if (!mdisok(&error)) { 1907 mdn = NULL; 1908 } 1909 mdclrerror(&error); 1910 1911 if (mdn != NULL && ( 1912 mdn->drivenamep->type == MDT_ACCES || 1913 mdn->drivenamep->type == MDT_COMP || 1914 mdn->drivenamep->type == MDT_FAST_COMP)) { 1915 1916 return (add_record(listp, sp->setname, type, mname, mdn->bname)); 1917 } else { 1918 return (add_record(listp, sp->setname, type, mname, "")); 1919 } 1920 } 1921 1922 /* 1923 * FUNCTION: get_default_stripe_interlace() 1924 * 1925 * RETURNS: uint64_t - default stripe interlace value 1926 * 1927 * PURPOSE: Helper which retrieves the default stripe interlace 1928 * from libmeta. 1929 */ 1930 uint64_t 1931 get_default_stripe_interlace() 1932 { 1933 /* convert back to bytes */ 1934 return ((uint64_t)meta_default_stripe_interlace() * DEV_BSIZE); 1935 } 1936 1937 /* 1938 * FUNCTION: get_max_number_of_devices(int *max) 1939 * 1940 * OUTPUT: max - pointer to int to hold the configured maximum number 1941 * of SVM devices 1942 * 1943 * RETURNS: int - 0 on success 1944 * !0 otherwise 1945 * 1946 * PURPOSE: Helper which determines the maximum number of allowed 1947 * SVM devices configured for the system. 1948 * 1949 * Wrapper around libmeta function meta_get_max_nunits(). 1950 */ 1951 int 1952 get_max_number_of_devices( 1953 int *max) 1954 { 1955 md_error_t mderror = mdnullerror; 1956 1957 *max = meta_get_nunits(&mderror); 1958 if (!mdisok(&mderror)) { 1959 volume_set_error(mde_sperror(&mderror, NULL)); 1960 mdclrerror(&mderror); 1961 return (-1); 1962 } 1963 1964 return (0); 1965 } 1966 1967 /* 1968 * FUNCTION: get_max_number_of_disksets(int *max) 1969 * 1970 * OUTPUT: max - pointer to in to hold the configured maximum number 1971 * of disk sets 1972 * 1973 * RETURNS: int - 0 on success 1974 * !0 otherwise 1975 * 1976 * PURPOSE: Helper which determines the maximum number of allowed 1977 * disk sets which has been configured for the system. 1978 * 1979 * Wrapper around libmeta function get_max_sets(). 1980 */ 1981 int 1982 get_max_number_of_disksets( 1983 int *max) 1984 { 1985 md_error_t mderror = mdnullerror; 1986 1987 *max = get_max_sets(&mderror); 1988 if (!mdisok(&mderror)) { 1989 volume_set_error(mde_sperror(&mderror, NULL)); 1990 mdclrerror(&mderror); 1991 return (-1); 1992 } 1993 1994 return (0); 1995 } 1996 1997 /* 1998 * FUNCTION: is_reserved_replica_slice_index(char *diskset, char *dname, 1999 * uint32_t index, boolean_t *bool) 2000 * 2001 * INPUT: diskset - char * disk set name 2002 * dname - char * disk name 2003 * index - integer index of interest 2004 * 2005 * OUTPUT: bool - pointer to a boolean_t to hold the result 2006 * 2007 * RETURNS: int - 0 - success 2008 * !0 - failure 2009 * 2010 * PURPOSE: Helper which determines if the input slice index on 2011 * the named disk in the named disk set is the replica 2012 * slice that is reserved on disks in disk sets. 2013 * 2014 * The named disk is assumed to be in the named disk set. 2015 * 2016 * Determines if metassist is being run in a simulated 2017 * hardware enironment, if not the libmeta function to 2018 * determine the replica slice index is called. 2019 * 2020 * If simulation is active, then a local implementation 2021 * is used to determine the replica slice index. 2022 */ 2023 int 2024 is_reserved_replica_slice_index( 2025 char *diskset, 2026 char *dname, 2027 uint32_t index, 2028 boolean_t *bool) 2029 { 2030 int error = 0; 2031 boolean_t sim = B_FALSE; 2032 static char *simfile = "METASSISTSIMFILE"; 2033 2034 sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0)); 2035 2036 if (sim != B_TRUE) { 2037 2038 /* sim disabled: use meta_replicaslice() */ 2039 2040 md_error_t mderror = mdnullerror; 2041 mdsetname_t *sp; 2042 mddrivename_t *dnp; 2043 uint_t replicaslice; 2044 2045 /* slice assumed to be on disk in the named disk set */ 2046 sp = metasetname(diskset, &mderror); 2047 if (!mdisok(&mderror)) { 2048 volume_set_error(mde_sperror(&mderror, NULL)); 2049 mdclrerror(&mderror); 2050 return (-1); 2051 } 2052 2053 dnp = metadrivename(&sp, dname, &mderror); 2054 if (!mdisok(&mderror)) { 2055 volume_set_error(mde_sperror(&mderror, NULL)); 2056 mdclrerror(&mderror); 2057 return (-1); 2058 } 2059 2060 if (meta_replicaslice(dnp, &replicaslice, &mderror) != 0) { 2061 volume_set_error(mde_sperror(&mderror, NULL)); 2062 mdclrerror(&mderror); 2063 return (-1); 2064 } 2065 2066 *bool = (replicaslice == (uint_t)index); 2067 2068 } else { 2069 2070 dm_descriptor_t disk; 2071 boolean_t efi = B_FALSE; 2072 2073 /* sim enabled: use same logic as meta_replicaslice() */ 2074 ((error = disk_get_by_name(dname, &disk)) != 0) || 2075 (error = disk_get_is_efi(disk, &efi)); 2076 if (error == 0) { 2077 2078 if (efi == B_FALSE) { 2079 *bool = (index == MD_SLICE7); 2080 } else { 2081 *bool = (index == MD_SLICE6); 2082 } 2083 } 2084 } 2085 2086 return (error); 2087 } 2088