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 <string.h> 30 31 #include <libintl.h> 32 33 #include "volume_error.h" 34 #include "volume_dlist.h" 35 #include "volume_output.h" 36 37 #include "layout_device_cache.h" 38 #include "layout_device_util.h" 39 #include "layout_discovery.h" 40 #include "layout_dlist_util.h" 41 #include "layout_messages.h" 42 #include "layout_request.h" 43 #include "layout_slice.h" 44 #include "layout_svm_util.h" 45 46 #define _LAYOUT_HSP_C 47 48 static int layout_explicit_hsp( 49 devconfig_t *hsprequest, 50 dlist_t *devices, 51 devconfig_t **hsp); 52 53 static int layout_default_hsp( 54 devconfig_t *request, 55 dlist_t *devices, 56 devconfig_t **hsp); 57 58 static int populate_hsp( 59 devconfig_t *request, 60 devconfig_t *hsp, 61 dlist_t *devices); 62 63 static int assemble_hsp( 64 devconfig_t *hsp, 65 dlist_t *newspares, 66 dlist_t *devices); 67 68 static int get_uniquely_sized_slices( 69 dlist_t *devices, 70 dlist_t **unique); 71 72 static int remove_undersized_slices( 73 dlist_t *unique, 74 dlist_t **avail); 75 76 static int find_spare_for_component( 77 devconfig_t *component, 78 dlist_t *all_spares, 79 dlist_t *hbas, 80 dlist_t *disks, 81 boolean_t *found); 82 83 static int choose_spare_for_component( 84 devconfig_t *comp, 85 dlist_t **all_spares, 86 dlist_t **new_spares, 87 dlist_t **avail, 88 dlist_t *used_hbas, 89 dlist_t *used_disks, 90 uint16_t npaths); 91 92 /* 93 * FUNCTION: layout_hsp(devconfig_t *request, devconfig_t hsprequest, 94 * dlist_t *devices, dlist_t **results) 95 * 96 * INPUT: request - pointer to the toplevel request devconfig_t 97 * hsp - pointer to the optional HSP request devconfig_t 98 * devices - pointer to a list of devices to be served by the HSP 99 * 100 * OUTPUT: results - pointer to a list result devconfig_t, if the HSP 101 * to service the input list of devices needs to be 102 * created or modified, it will be appended to the list. 103 * 104 * RETURNS: int - 0 on success 105 * !0 otherwise. 106 * 107 * PURPOSE: Main layout driver for HSP, attempts to build/populate a 108 * single HSP to service the list of devices. 109 * 110 * If the input hsprequest is NULL, use the default HSP scheme: 111 * a. use the first HSP in the diskset 112 * b. create an HSP if the diskset has none 113 * 114 * If the hsprequest is not NULL: 115 * a. if the request names an HSP and it already exists, use it 116 * b. if the request names an HSP and it does not exist, create it 117 * c. if the request specifies components, use them 118 */ 119 int 120 layout_hsp( 121 devconfig_t *request, 122 devconfig_t *hsprequest, 123 dlist_t *devices, 124 dlist_t **results) 125 { 126 int error = 0; 127 devconfig_t *hsp = NULL; 128 129 oprintf(OUTPUT_TERSE, 130 gettext(" ->Layout a %s\n"), 131 devconfig_type_to_str(TYPE_HSP)); 132 133 if (hsprequest == NULL) { 134 error = layout_default_hsp(request, devices, &hsp); 135 } else { 136 error = layout_explicit_hsp(hsprequest, devices, &hsp); 137 } 138 139 if (error != 0) { 140 print_debug_failure_msg(devconfig_type_to_str(TYPE_HSP), 141 get_error_string(error)); 142 } else if (hsp != NULL) { 143 144 if (devconfig_get_components(hsp) == NULL) { 145 /* HSP is usable as it is */ 146 free_devconfig(hsp); 147 hsp = NULL; 148 } else { 149 dlist_t *item = NULL; 150 if ((item = dlist_new_item(hsp)) == NULL) { 151 error = ENOMEM; 152 } else { 153 *results = dlist_append(item, *results, AT_TAIL); 154 print_layout_success_msg(); 155 } 156 } 157 } 158 159 return (error); 160 } 161 162 /* 163 * FUNCTION: layout_default_hsp(devconfig_t *request, 164 * dlist_t *devices, devconfig_t **hsp) 165 * 166 * INPUT: request - pointer to the toplevel request devconfig_t 167 * devices - pointer to a list of devices to be served by the HSP 168 * 169 * OUTPUT: hsp - pointer to a devconfig_t to hold the resulting HSP 170 * 171 * RETURNS: int - 0 on success 172 * !0 otherwise. 173 * 174 * PURPOSE: Layout driver for default HSP construction. 175 * 176 * a. use the first HSP in the diskset 177 * b. create an HSP if the diskset has none 178 * c. add spares to the HSP to service the list of input devices. 179 */ 180 static int 181 layout_default_hsp( 182 devconfig_t *request, 183 dlist_t *devices, 184 devconfig_t **hsp) 185 { 186 char *dsname = get_request_diskset(); 187 char *hspname = NULL; 188 boolean_t free_hspname = B_FALSE; 189 devconfig_t *default_hsp = NULL; 190 int error = 0; 191 192 oprintf(OUTPUT_TERSE, 193 gettext(" -->Using default HSP scheme...\n")); 194 195 if ((error = get_default_hsp_name(request, &hspname)) != 0) { 196 volume_set_error( 197 gettext("error getting HSP name from defaults\n")); 198 return (error); 199 } 200 201 if (hspname != NULL) { 202 if ((error = hsp_get_by_name(dsname, hspname, &default_hsp)) != 0) { 203 volume_set_error( 204 gettext("error getting default HSP by name\n")); 205 return (error); 206 } 207 } else { 208 /* no default HSP name, get diskset's default HSP */ 209 if ((error = hsp_get_default_for_diskset(dsname, 210 &default_hsp)) != 0) { 211 volume_set_error( 212 gettext("error getting default HSP\n")); 213 return (error); 214 } 215 216 if (default_hsp == NULL) { 217 /* no default HSP name, no default HSP, make one */ 218 if ((error = get_next_hsp_name(&hspname)) != 0) { 219 volume_set_error( 220 gettext("error making default HSP name\n")); 221 return (error); 222 } 223 free_hspname = B_TRUE; 224 } 225 } 226 227 if (default_hsp != NULL) { 228 229 /* Found existing default HSP, copy it */ 230 dlist_t *spares = devconfig_get_components(default_hsp); 231 232 ((error = devconfig_get_name(default_hsp, &hspname)) != 0) || 233 (error = new_devconfig(hsp, TYPE_HSP)) || 234 (error = devconfig_set_name(*hsp, hspname)); 235 236 if (error == 0) { 237 devconfig_set_components(*hsp, spares); 238 devconfig_set_components(default_hsp, NULL); 239 240 oprintf(OUTPUT_TERSE, 241 gettext(" --->Using %s from disk set %s...\n"), 242 hspname, dsname); 243 } else { 244 free_devconfig(*hsp); 245 *hsp = NULL; 246 } 247 248 } else { 249 250 /* no existing default HSP, make it */ 251 ((error = new_devconfig(hsp, TYPE_HSP)) != 0) || 252 (error = devconfig_set_name(*hsp, hspname)); 253 if (error == 0) { 254 oprintf(OUTPUT_VERBOSE, 255 gettext(" --->Created %s for disk set %s...\n "), 256 hspname, dsname); 257 } else { 258 free_devconfig(*hsp); 259 *hsp = NULL; 260 } 261 262 if (free_hspname == B_TRUE) { 263 free(hspname); 264 } 265 } 266 267 if (error == 0) { 268 error = populate_hsp(request, *hsp, devices); 269 } 270 271 return (error); 272 } 273 274 /* 275 * FUNCTION: layout_explicit_hsp(devconfig_t *hsprequest, 276 * dlist_t *devices, devconfig_t **hsp) 277 * 278 * INPUT: hsprequest - pointer to the explicit HSP request devconfig_t 279 * devices - pointer to a list of devices to be served by the HSP 280 * 281 * OUTPUT: hsp - pointer to a HSP devconfig_t to hold resulting HSP 282 * 283 * RETURNS: int - 0 on success 284 * !0 otherwise. 285 * 286 * PURPOSE: Layout driver for an explicit HSP request. 287 * 288 * a. if the request names an HSP and it already exists, use it 289 * b. if the request names an HSP and it does not exist, create it 290 * c. if the request specifies components, use them 291 * otherwise, add new spares to handle the input list 292 * of devices. 293 */ 294 static int 295 layout_explicit_hsp( 296 devconfig_t *hsprequest, 297 dlist_t *devices, 298 devconfig_t **hsp) 299 { 300 char *dsname = get_request_diskset(); 301 char *hspname = NULL; 302 dlist_t *rspares = NULL; 303 int error = 0; 304 305 oprintf(OUTPUT_VERBOSE, 306 gettext(" --->Explicit HSP request...\n")); 307 308 (void) devconfig_get_name(hsprequest, &hspname); 309 if (hspname != NULL) { 310 311 (void) hsp_get_by_name(dsname, hspname, hsp); 312 if (*hsp != NULL) { 313 314 oprintf(OUTPUT_VERBOSE, 315 gettext(" --->Using %s...\n"), 316 hspname); 317 } else { 318 319 /* named HSP doesn't exist, create it */ 320 ((error = new_devconfig(hsp, TYPE_HSP)) != 0) || 321 (error = devconfig_set_name(*hsp, hspname)); 322 if (error == 0) { 323 oprintf(OUTPUT_VERBOSE, 324 gettext(" --->%s does not exist, " 325 "created...\n"), hspname); 326 } else { 327 free_devconfig(*hsp); 328 *hsp = NULL; 329 } 330 free(hspname); 331 } 332 } 333 334 if (error == 0) { 335 336 /* does the hsprequest specify spares? */ 337 rspares = devconfig_get_components(hsprequest); 338 if (rspares != NULL) { 339 340 /* put requested spares into HSP */ 341 dlist_t *list = NULL; 342 dlist_t *iter = NULL; 343 344 for (iter = rspares; 345 (iter != NULL) && (error == 0); 346 iter = iter->next) { 347 348 dlist_t *item = NULL; 349 if ((dlist_new_item(iter->obj)) == NULL) { 350 error = ENOMEM; 351 } else { 352 list = dlist_append(item, list, AT_TAIL); 353 } 354 } 355 356 if (error == 0) { 357 error = assemble_hsp(*hsp, rspares, devices); 358 } 359 360 } else { 361 362 /* select new spares */ 363 error = populate_hsp(hsprequest, *hsp, devices); 364 } 365 } 366 367 return (error); 368 } 369 370 /* 371 * FUNCTION: populate_hsp(devconfig_t *request, devconfig_t *hsp, 372 * dlist_t *devices) 373 * 374 * INPUT: request - pointer to a request devconfig_t 375 * hsp - pointer to a HSP devconfig_t 376 * devices - pointer to a list of devices to be served by the HSP 377 * 378 * RETURNS: int - 0 on success 379 * !0 otherwise. 380 * 381 * PURPOSE: Processes the input HSP request and add spares sufficient 382 * to service the input list of devices. 383 * 384 * Determine the available HBAs, disks, and slices. 385 * Sort thru the input list of devices and determine 386 * the unique component sizes which need to be spared. 387 * Filter the available slices and remove those that are 388 * too small to serve as spares. 389 * 390 * Iterate each device and its components and see if the 391 * HSP currently has a sufficient spare, if not, try 392 * to select one from the available slices. 393 * 394 * If a spare cannot be found for any device component, 395 * the HSP layout process stops. 396 * 397 * If spares are found for all device components, add 398 * any required new ones to the HSP. 399 */ 400 static int 401 populate_hsp( 402 devconfig_t *request, 403 devconfig_t *hsp, 404 dlist_t *devices) 405 { 406 int error = 0; 407 uint16_t npaths = 0; 408 409 dlist_t *usable_hbas = NULL; 410 dlist_t *sel_hbas = NULL; 411 dlist_t *disks = NULL; 412 dlist_t *iter = NULL; 413 414 dlist_t *avail = NULL; /* available slices */ 415 dlist_t *slices = NULL; /* avail slices of sufficient size */ 416 dlist_t *unique = NULL; /* volume slices that need spares */ 417 dlist_t *curspares = NULL; /* current spares in the HSP */ 418 dlist_t *newspares = NULL; /* slices to add to HSP */ 419 dlist_t *allspares = NULL; /* current and new spares */ 420 421 ((error = get_usable_hbas(&usable_hbas)) != 0) || 422 (error = select_hbas_with_n_disks(request, usable_hbas, 1, &sel_hbas, 423 &disks)) || 424 (error = disks_get_avail_slices(request, disks, &avail)) || 425 (error = get_volume_npaths(request, &npaths)); 426 if (error != 0) { 427 dlist_free_items(sel_hbas, NULL); 428 dlist_free_items(disks, NULL); 429 dlist_free_items(avail, NULL); 430 return (error); 431 } 432 433 if (disks == NULL || dlist_length(disks) == 0) { 434 /* all disks have been consumed by the devices */ 435 volume_set_error( 436 gettext(" no available disks to populate HSP\n")); 437 dlist_free_items(sel_hbas, NULL); 438 dlist_free_items(avail, NULL); 439 return (-1); 440 } 441 442 if (avail == NULL || dlist_length(avail) == 0) { 443 /* all slices have been consumed by the devices */ 444 volume_set_error( 445 gettext(" no available slices to populate HSP\n")); 446 dlist_free_items(sel_hbas, NULL); 447 dlist_free_items(disks, NULL); 448 return (-1); 449 } 450 451 dlist_free_items(sel_hbas, NULL); 452 dlist_free_items(disks, NULL); 453 454 /* build list of slices needing to be spared */ 455 ((error = get_uniquely_sized_slices(devices, &unique)) != 0) || 456 457 /* and list of slices of sufficient size to spare for them */ 458 (error = remove_undersized_slices(unique, &avail)); 459 460 if (error != 0) { 461 dlist_free_items(avail, NULL); 462 dlist_free_items(unique, NULL); 463 dlist_free_items(slices, NULL); 464 return (error); 465 } 466 467 /* get spares currently in the HSP */ 468 curspares = devconfig_get_components(hsp); 469 470 /* clone current spares list */ 471 for (iter = curspares; 472 (iter != NULL) && (error == 0); 473 iter = iter->next) { 474 dlist_t *item = dlist_new_item(iter->obj); 475 if (item == NULL) { 476 error = ENOMEM; 477 } else { 478 allspares = dlist_append(item, allspares, AT_TAIL); 479 } 480 } 481 482 if (error != 0) { 483 dlist_free_items(avail, NULL); 484 dlist_free_items(unique, NULL); 485 dlist_free_items(slices, NULL); 486 dlist_free_items(allspares, NULL); 487 return (error); 488 } 489 490 /* 491 * examine device component slices and see if the HSP already 492 * has a suitable spare. If not, select the best available 493 * of the same (or larger) size 494 */ 495 for (iter = devices; 496 (iter != NULL) && (error == 0); 497 iter = iter->next) { 498 499 devconfig_t *device = (devconfig_t *)iter->obj; 500 dlist_t *components = devconfig_get_components(device); 501 dlist_t *hbas = NULL; 502 dlist_t *disks = NULL; 503 dlist_t *iter1; 504 505 error = get_hbas_and_disks_used_by_volume(device, &hbas, &disks); 506 for (iter1 = components; (iter1 != NULL) && (error == 0); 507 iter1 = iter1->next) { 508 509 devconfig_t *comp = (devconfig_t *)iter1->obj; 510 boolean_t found = B_FALSE; 511 512 if ((error = find_spare_for_component( 513 comp, allspares, hbas, disks, &found)) == 0) { 514 if (found != B_TRUE) { 515 error = choose_spare_for_component( 516 comp, &allspares, &newspares, 517 &avail, hbas, disks, npaths); 518 } 519 } 520 } 521 dlist_free_items(disks, NULL); 522 dlist_free_items(hbas, NULL); 523 } 524 525 if (error == 0) { 526 /* existing spares are no longer needed */ 527 dlist_free_items(curspares, free_devconfig_object); 528 curspares = NULL; 529 530 error = assemble_hsp(hsp, newspares, devices); 531 } else { 532 dlist_free_items(newspares, free_devconfig_object); 533 newspares = NULL; 534 } 535 536 dlist_free_items(avail, NULL); 537 dlist_free_items(slices, NULL); 538 dlist_free_items(unique, NULL); 539 dlist_free_items(allspares, NULL); 540 541 return (error); 542 } 543 544 /* 545 * FUNCTION: assemble_hsp(devconfig_t *hsp, dlist_t *newspares, 546 * dlist_t *devices) 547 * 548 * INPUT: request - pointer to a HSP devconfig_t 549 * newspare - pointer to a list of new spares for the HSP 550 * devices - pointer to a list of devices to be served by the HSP 551 * 552 * RETURNS: int - 0 on success 553 * !0 otherwise. 554 * 555 * PURPOSE: Final assembly of an HSP. Attach new spare components 556 * and associate the HSP with each device in the input list. 557 */ 558 static int 559 assemble_hsp( 560 devconfig_t *hsp, 561 dlist_t *newspares, 562 dlist_t *devices) 563 { 564 dlist_t *iter; 565 char *hspname = NULL; 566 int error = 0; 567 568 /* add new spares to HSP */ 569 (void) devconfig_set_components(hsp, newspares); 570 (void) devconfig_get_name(hsp, &hspname); 571 572 /* associate HSP with each of the devices */ 573 for (iter = devices; 574 (iter != NULL) && (error == 0); 575 iter = iter->next) { 576 577 devconfig_t *dev = iter->obj; 578 devconfig_t *hspcomp = NULL; 579 dlist_t *item = NULL; 580 char *devname = NULL; 581 582 ((error = devconfig_get_name(dev, &devname)) != 0) || 583 (error = new_devconfig(&hspcomp, TYPE_HSP)) || 584 (error = devconfig_set_name(hspcomp, hspname)); 585 586 if (error != 0) { 587 588 free_devconfig(hspcomp); 589 590 } else if ((item = dlist_new_item(hspcomp)) == NULL) { 591 592 free_devconfig(hspcomp); 593 error = ENOMEM; 594 595 } else { 596 597 dlist_t *comps = devconfig_get_components(dev); 598 comps = dlist_append(comps, item, AT_TAIL); 599 (void) devconfig_set_components(dev, comps); 600 601 oprintf(OUTPUT_VERBOSE, 602 gettext(" --->volume %s will use HSP %s\n"), 603 devname, hspname); 604 } 605 } 606 607 return (error); 608 } 609 610 /* 611 * FUNCTION: get_uniquely_sized_slices(dlist_t *devices, 612 * dlist_t **unique) 613 * 614 * INPUT: devices - pointer to a list of devconfig_t devices 615 * 616 * OUTPUT: unique - pointer to a list of uniquely size slices 617 * from the input list of devices. 618 * 619 * RETURNS: int - 0 on success 620 * !0 otherwise. 621 * 622 * PURPOSE: Examine each device's slice components and build a list 623 * of uniquely sized slices. 624 */ 625 static int 626 get_uniquely_sized_slices( 627 dlist_t *devices, 628 dlist_t **unique) 629 { 630 int error = 0; 631 dlist_t *iter = NULL; 632 633 for (iter = devices; 634 (iter != NULL) && (error == 0); 635 iter = iter->next) { 636 637 dlist_t *iter1; 638 for (iter1 = devconfig_get_components((devconfig_t *)iter->obj); 639 (iter1 != NULL) && (error == 0); 640 iter1 = iter1->next) { 641 642 devconfig_t *comp = (devconfig_t *)iter1->obj; 643 if (dlist_contains(*unique, comp, 644 compare_devconfig_sizes) != B_TRUE) { 645 646 dlist_t *item = NULL; 647 if ((item = dlist_new_item(comp)) == NULL) { 648 error = ENOMEM; 649 } else { 650 *unique = dlist_insert_ordered(item, *unique, 651 ASCENDING, compare_devconfig_sizes); 652 } 653 } 654 } 655 } 656 657 return (error); 658 } 659 660 /* 661 * FUNCTION: remove_undersized_slices(dlist_t *unique, 662 * dlist_t **avail) 663 * 664 * INPUT: avail - pointer to a list of available slices 665 * unique - pointer to a list of uniquely size slices 666 * 667 * OUTPUT: avail - pointer to an updated list of available slices 668 * that are at least as large as slices in the 669 * unique list. 670 * 671 * RETURNS: int - 0 on success 672 * !0 otherwise. 673 * 674 * PURPOSE: filter available slices and remove those that aren't 675 * large enough for the device components which need spares. 676 * 677 * For each uniquely sized slice, find all available slices 678 * that are larger and add them to the filtered list. 679 */ 680 static int 681 remove_undersized_slices( 682 dlist_t *unique, 683 dlist_t **avail) 684 { 685 dlist_t *filtered = NULL; 686 dlist_t *iter = NULL; 687 int error = 0; 688 689 for (iter = unique; 690 (iter != NULL) && (error == 0); 691 iter = iter->next) { 692 693 devconfig_t *uslice = (devconfig_t *)iter->obj; 694 uint64_t usize = 0; 695 dlist_t *iter2 = NULL; 696 697 error = devconfig_get_size(uslice, &usize); 698 699 for (iter2 = *avail; 700 (iter2 != NULL) && (error == 0); 701 iter2 = iter2->next) { 702 703 dm_descriptor_t aslice = (uintptr_t)iter2->obj; 704 uint64_t asize = 0; 705 706 error = slice_get_size(aslice, &asize); 707 if (asize >= usize) { 708 709 /* this slice is large enough */ 710 dlist_t *item = NULL; 711 if ((item = dlist_new_item((void *)(uintptr_t)aslice)) == 712 NULL) { 713 error = ENOMEM; 714 } else { 715 filtered = dlist_insert_ordered(item, filtered, 716 ASCENDING, compare_slice_sizes); 717 } 718 719 } 720 } 721 } 722 723 if (error == 0) { 724 dlist_free_items(*avail, NULL); 725 *avail = filtered; 726 } else { 727 dlist_free_items(filtered, NULL); 728 } 729 730 return (error); 731 } 732 733 /* 734 * FUNCTION: find_spare_for_component(devconfig_t *component, 735 * dlist_t *all_spares, dlist_t *hbas, dlist_t *disks, 736 * boolean_t *found) 737 * 738 * INPUT: comp - pointer to a devconfig_t slice compenent that 739 * needs to be spared 740 * all_spares - pointer to a list of spares currently 741 * in the pool or that will be added 742 * hbas - pointer to a list of HBAs the component's 743 * parent device utilizes 744 * disks - pointer to a list of disks the component's 745 * parent device utilizes 746 * 747 * OUTPUT: found - pointer to a boolean_t to hold the result. 748 * 749 * RETURNS: int - 0 on success 750 * !0 otherwise. 751 * 752 * PURPOSE: Find a spare for the input component. 753 * 754 * Searches the input list of spares to see if one is 755 * sufficient. 756 * 757 * A suffcient spare is one that is large enough to spare 758 * for the input component and not on the same disk as any 759 * of the components in the parent device. 760 * 761 * The optimal spare would be on a different controller/HBA 762 * as the component and any of the components in the parent 763 * device. We settle for sufficient. 764 */ 765 static int 766 find_spare_for_component( 767 devconfig_t *component, 768 dlist_t *all_spares, 769 dlist_t *hbas, 770 dlist_t *disks, 771 boolean_t *found) 772 { 773 dlist_t *iter = NULL; 774 uint64_t csize = 0; 775 int error = 0; 776 777 *found = B_FALSE; 778 779 (void) devconfig_get_size(component, &csize); 780 781 for (iter = all_spares; 782 (iter != NULL) && (*found == B_FALSE) && (error == 0); 783 iter = iter->next) { 784 785 devconfig_t *spare = (devconfig_t *)iter->obj; 786 char *spname = NULL; 787 uint64_t spsize = 0; 788 789 if (((error = devconfig_get_name(spare, &spname)) != 0) || 790 ((error = devconfig_get_size(spare, &spsize)) != 0)) { 791 continue; 792 } 793 794 if (spsize >= csize) { 795 796 dm_descriptor_t disk = NULL; 797 798 /* see if spare's disk is independent of the volume */ 799 error = get_disk_for_named_slice(spname, &disk); 800 if ((error == 0) && (dlist_contains(disks, 801 (void *)(uintptr_t)disk, compare_descriptor_names) == 802 B_FALSE)) { 803 *found = B_TRUE; 804 } 805 } 806 } 807 808 if ((*found == B_TRUE) && (get_max_verbosity() >= OUTPUT_DEBUG)) { 809 char *cname = NULL; 810 (void) devconfig_get_name(component, &cname); 811 oprintf(OUTPUT_DEBUG, 812 gettext(" found existing spare for: %s (%llu)\n"), 813 cname, csize); 814 } 815 816 return (error); 817 } 818 819 /* 820 * FUNCTION: choose_spare_for_component(devconfig_t *component, 821 * dlist_t *all_spares, dlist_t **new_spares, 822 * dlist_t avail, uint16_t npaths, dlist_t *used_hbas, 823 * dlist_t *used_disks) 824 * 825 * INPUT: comp - pointer to a devconfig_t slice compenent that 826 * needs to be spared 827 * all_spares - pointer to a list of spares currently 828 * in the pool and those to be added 829 * new_spares - pointer to a list of spares that need to 830 * be added to the pool 831 * avail - list of available slices 832 * npaths - required number of paths for the spare 833 * used_hbas - list of HBAs used by the component's parent 834 * used_disks - list of disks used by the component's parent 835 * 836 * OUTPUT: all_spares - the possibly updated list of all spares 837 * new_spares - the possibly updated list of spares which 838 * need to be added to the pool. 839 * 840 * RETURNS: int - 0 on success 841 * !0 otherwise. 842 * 843 * PURPOSE: Find a new spare for the input component. 844 * 845 * Select a spare from the available slice list and add 846 * it to the new_spares list. 847 * 848 * The spare slice chosen should be on a unique HBA and 849 * disk relative to the input lists of used HBAs and disks 850 * and any spares in the pool. 851 */ 852 static int 853 choose_spare_for_component( 854 devconfig_t *component, 855 dlist_t **all_spares, 856 dlist_t **new_spares, 857 dlist_t **avail, 858 dlist_t *used_hbas, 859 dlist_t *used_disks, 860 uint16_t npaths) 861 { 862 devconfig_t *spare = NULL; 863 uint64_t csize = 0; 864 int error = 0; 865 866 (void) devconfig_get_size(component, &csize); 867 868 if (get_max_verbosity() >= OUTPUT_DEBUG) { 869 char *cname = NULL; 870 (void) devconfig_get_name(component, &cname); 871 oprintf(OUTPUT_DEBUG, 872 gettext(" select new spare for: %s (%llu)\n"), 873 cname, csize); 874 } 875 876 /* 877 * find a spare for the input component. 878 * select the best one from the available list that 879 * is on a unique disk. 880 */ 881 882 /* 883 * 1st B_TRUE: require a different disk than those used by 884 * all spares and devices 885 * 2nd B_TRUE: requested size is the minimum acceptable 886 * 1st B_FALSE: do not add an extra cylinder when resizing slice, 887 * this is only necessary for Stripe components whose 888 * sizes get rounded down to an interlace multiple and 889 * then down to a cylinder boundary. 890 */ 891 error = choose_slice(csize, npaths, *avail, *all_spares, 892 used_hbas, used_disks, B_TRUE, B_TRUE, B_FALSE, &spare); 893 894 if ((error == 0) && (spare == NULL)) { 895 /* can't find one on a unique disk, try again on any disk */ 896 897 /* BEGIN CSTYLED */ 898 /* 899 * 1st B_FALSE: don't require a different disk than those used 900 * by all spares and devices 901 * 2nd B_TRUE: requested size is still the minimum acceptable 902 * 2nd B_FALSE: do not add an extra cylinder when resizing slice 903 * this is only necessary for Stripe components whose 904 * sizes get rounded down to an interlace multiple and 905 * then down to a cylinder boundary. 906 */ 907 /* END CSTYLED */ 908 error = choose_slice( 909 csize, npaths, *avail, *all_spares, used_hbas, 910 used_disks, B_FALSE, B_TRUE, B_FALSE, &spare); 911 } 912 913 if ((error == 0) && (spare != NULL)) { 914 915 dlist_t *rmvd = NULL; 916 dlist_t *item = NULL; 917 char *spname = NULL; 918 919 if ((item = dlist_new_item(spare)) == NULL) { 920 error = ENOMEM; 921 } else { 922 923 /* add spare to the all spares list */ 924 *all_spares = dlist_append(item, *all_spares, AT_HEAD); 925 926 if ((item = dlist_new_item(spare)) == NULL) { 927 error = ENOMEM; 928 } else { 929 930 /* add spare to the new spares list */ 931 *new_spares = dlist_insert_ordered( 932 item, *new_spares, ASCENDING, 933 compare_devconfig_sizes); 934 935 /* remove it from the available list */ 936 *avail = dlist_remove_equivalent_item(*avail, spare, 937 compare_devconfig_and_descriptor_names, 938 &rmvd); 939 940 if (rmvd != NULL) { 941 free(rmvd); 942 } 943 944 /* add the spare to the used slice list */ 945 error = devconfig_get_name(spare, &spname); 946 if (error == 0) { 947 error = add_used_slice_by_name(spname); 948 } 949 } 950 } 951 952 } else { 953 954 /* no spare, give up on layout */ 955 oprintf(OUTPUT_TERSE, 956 gettext(" <---Failed: insufficient suitable spares\n")); 957 958 volume_set_error( 959 gettext("failed to find sufficient spares for HSP\n")); 960 961 error = -1; 962 } 963 964 return (error); 965 } 966