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 <sys/param.h> 30 #include <meta.h> 31 32 #include "volume_string.h" 33 34 #include "volume_devconfig.h" 35 #include "volume_error.h" 36 #include "volume_dlist.h" 37 #include "volume_output.h" 38 39 #include "layout_device_cache.h" 40 #include "layout_device_util.h" 41 #include "layout_discovery.h" 42 #include "layout_dlist_util.h" 43 #include "layout_messages.h" 44 #include "layout_request.h" 45 #include "layout_slice.h" 46 47 #define _LAYOUT_SLICE_C 48 49 static int pick_from_best_hba_and_disk( 50 dlist_t *list, 51 dlist_t *used, 52 dm_descriptor_t *chosen); 53 54 static int slice_has_same_disk_geom( 55 dm_descriptor_t slice, 56 dlist_t *used, 57 boolean_t *bool); 58 59 static int slice_on_unique_disk( 60 dm_descriptor_t slice, 61 dlist_t *used, 62 dlist_t *othervols, 63 boolean_t *bool); 64 65 static int slice_on_unique_hba( 66 dm_descriptor_t slice, 67 dlist_t *used, 68 dlist_t *othervols, 69 boolean_t *bool); 70 71 static int slice_on_similar_bus( 72 dm_descriptor_t slice, 73 dlist_t *used, 74 boolean_t *bool); 75 76 static int slice_has_n_paths( 77 dm_descriptor_t slice, 78 uint16_t npaths, 79 boolean_t *bool); 80 81 static int compare_modslice_names( 82 void *obj1, 83 void *obj2); 84 85 static int compare_string_to_modslice_name( 86 void *str, 87 void *modslice); 88 89 static int create_new_slice( 90 dm_descriptor_t oslice, 91 uint64_t nbytes, 92 boolean_t add_extra_cyl, 93 devconfig_t **nslice); 94 95 static int create_modified_slice( 96 dm_descriptor_t oslice, 97 char *oname, 98 uint32_t oindex, 99 uint64_t ostart, 100 uint64_t osize, 101 uint64_t bps, 102 char *nname, 103 uint32_t nindex, 104 uint64_t nsize, 105 devconfig_t **nslice); 106 107 /* 108 * list to track resized slices 109 */ 110 static dlist_t *_modified_slices = NULL; 111 112 /* 113 * struct to track used slices and their disks... 114 */ 115 typedef struct { 116 char *slicename; 117 dm_descriptor_t disk; 118 } usedslice_t; 119 120 /* 121 * list to of usedslice_t to track slices that have been 122 * used for any reason. 123 */ 124 static dlist_t *_used_slices = NULL; 125 126 static int add_used_slice_list_entry(char *slicename, dm_descriptor_t disk); 127 static int compare_usedslice_name_to_string(void *obj1, void *obj2); 128 static void free_used_slice(void *obj); 129 130 /* 131 * list of slices reserved to be used for explicit 132 * volume requests 133 */ 134 static dlist_t *_rsvd_slices = NULL; 135 136 /* 137 * list of slices needing to be removed (zeroed out) prior to 138 * applying any metassist modifications to the system. 139 */ 140 static dlist_t *_rmvd_slices = NULL; 141 142 /* 143 * FUNCTION: choose_slice( 144 * uint64_t nbytes, 145 * uint16_t npaths, 146 * dlist_t *slices, 147 * dlist_t *used, 148 * dlist_t *used_hbas, 149 * dlist_t *used_disks, 150 * boolean_t unused_disk, 151 * boolean_t nbytes_is_min, 152 * boolean_t add_extra_cyl, 153 * devconfig_t **chosen) 154 * 155 * INPUT: nbytes - required size 156 * npaths - minimum required data paths 157 * *slices - slices from which to choose 158 * *used - slices used by the volume under construction 159 * *used_hbas - hbas used by other volumes relevant to 160 * the volume under construction 161 * *used_disks - disks used by other volumes relevant to 162 * the volume under construction 163 * unused_disk - if true, the chosen slice must be from an 164 * unused disk 165 * nbytes_is_min - if true, the chosen slice may be larger than 166 * nbytes. 167 * add_extra_cyl - passed to create_new_slice, see comment there. 168 * **chosen - pointer to hold the chosen slice 169 * 170 * RETURNS: int - 0 on success 171 * !0 otherwise 172 * 173 * PURPOSE: Choosen a slice from the list of those available. 174 * 175 * Of those available, choose in order of preference: 176 * 177 * - one on a unique HBA and disk that is of the exact size 178 * - one on a unique HBA and disk that is of sufficient size 179 * - one on unique HBA that is of the exact size 180 * - one on unique HBA that is of sufficient size 181 * - one on unique disk that is of the exact size 182 * - one on unique disk that is of sufficient size 183 * - one on any HBA that is of exact size 184 * - one on any HBA that is of sufficient size 185 * - one on a unique HBA that is the largest size 186 * - one on a unique disk that is the largest size 187 * - one on any HBA that is the largest size 188 * 189 * The function scans the available slices and builds lists of 190 * those meeting the criteria above. After the scan is complete, 191 * the lists are examined in order, the first non-empty list is 192 * chosen. If there are several possibilities in the chosen list, 193 * see if it is possible select the slice from the least used HBA 194 * and/or disk. 195 * 196 * If nbytes_is_min is true, the returned slice will be 197 * at least nbytes in capacity. 198 * 199 * If unused_disk is true, the returned slice will be from 200 * a disk with no other known uses. 201 */ 202 int 203 choose_slice( 204 uint64_t nbytes, 205 uint16_t npaths, 206 dlist_t *slices, 207 dlist_t *used, 208 dlist_t *used_hbas, 209 dlist_t *used_disks, 210 boolean_t unused_disk, 211 boolean_t nbytes_is_min, 212 boolean_t add_extra_cyl, 213 devconfig_t **chosen) 214 { 215 dlist_t *iter = NULL; 216 217 dm_descriptor_t slice = NULL; 218 boolean_t resize = B_FALSE; 219 boolean_t verbose = (get_max_verbosity() == OUTPUT_VERBOSE); 220 221 int error = 0; 222 223 /* 224 * indexes into the list array: 225 * i -> unique controller 0 = yes, 1 = no 226 * j -> same bus type 0 = yes, 1 = no 227 * k -> unique disk 0 = yes, 1 = no 228 * l -> same disk geom 0 = yes, 1 = no 229 * m -> size 0 == exact, 1 = larger, 2 = any 230 */ 231 int i, j, k, l, m; 232 dlist_t *list[2][2][2][2][3]; 233 234 /* output string arrays for each array dimension and index */ 235 char *uniqhba[2]; 236 char *samebus[2]; 237 char *uniqdisk[2]; 238 char *samegeom[2]; 239 char *sizes[3]; 240 241 /* other output strings */ 242 char *look_msg = NULL; 243 char *npaths_msg = NULL; 244 char *samegeom_msg = NULL; 245 char *samebus_msg = NULL; 246 char *uniqhba_msg = NULL; 247 char *uniqdisk_msg = NULL; 248 char *exact_msg = NULL; 249 char *larger_msg = NULL; 250 char *smaller_msg = NULL; 251 char *insuff_paths = NULL; 252 char *too_small = NULL; 253 char *useddisk_msg = NULL; 254 255 if (verbose == B_TRUE) { 256 /* only initialize the output strings if needed */ 257 258 /* BEGIN CSTYLED */ 259 look_msg = gettext( 260 "\tlooking at slice: %s (%s)\n"); 261 npaths_msg = gettext( 262 "\t has the requested number of data paths (%d)\n"); 263 samegeom_msg = gettext( 264 "\t has the same disk geometry relative to used slices\n"); 265 samebus_msg = gettext( 266 "\t on a similar I/O bus/HBA relative to used slices\n"); 267 uniqhba_msg = gettext( 268 "\t on a unique HBA relative to used slices\n"); 269 uniqdisk_msg = gettext( 270 "\t on a unique disk relative to used slices\n"); 271 exact_msg = gettext( 272 "\t the exact size necessary\n"); 273 larger_msg = gettext( 274 "\t larger than necessary\n"); 275 smaller_msg = gettext( 276 "\t smaller than necessary\n"); 277 insuff_paths = gettext( 278 "\t rejected: not enough paths (%d requested)\n"); 279 too_small = gettext( 280 "\t rejected: too small\n"); 281 useddisk_msg = gettext( 282 "\t rejected: on a disk with other volume component(s)\n"); 283 284 uniqhba[0] = gettext("unique HBA"); 285 uniqhba[1] = gettext("non unique HBA"); 286 samebus[0] = gettext("same bus type"); 287 samebus[1] = gettext("different bus type"); 288 uniqdisk[0] = gettext("unique disk"); 289 uniqdisk[1] = gettext("non unique disk"); 290 samegeom[0] = gettext("same geometry"); 291 samegeom[1] = gettext("different geometry"); 292 sizes[0] = gettext("an exact size slice"); 293 sizes[1] = gettext("a larger slice"); 294 sizes[2] = gettext("a smaller slice"); 295 296 /* END CSTYLED */ 297 } 298 299 /* init list array pointers */ 300 (void) memset(list, 0, 2*2*2*2*3 * sizeof (dlist_t *)); 301 302 for (iter = slices; 303 (iter != NULL) && (error == 0); iter = iter->next) { 304 305 dm_descriptor_t slice = (uintptr_t)iter->obj; 306 uint64_t snbytes = 0; 307 boolean_t uniqdisk = B_FALSE; 308 boolean_t uniqhba = B_FALSE; 309 boolean_t samegeom = B_FALSE; 310 boolean_t samebus = B_FALSE; 311 boolean_t paths = B_FALSE; 312 dlist_t *item = NULL; 313 314 ((error = slice_get_size(slice, &snbytes)) != 0) || 315 (error = slice_has_n_paths(slice, npaths, &paths)) || 316 (error = slice_on_unique_hba(slice, used, used_hbas, &uniqhba)) || 317 (error = slice_on_unique_disk(slice, used, used_disks, 318 &uniqdisk)) || 319 (error = slice_on_similar_bus(slice, used, &samebus)) || 320 (error = slice_has_same_disk_geom(slice, used, &samegeom)); 321 if (error != 0) { 322 continue; 323 } 324 325 if (verbose == B_TRUE) { 326 char *sname = NULL; 327 char *sizestr = NULL; 328 (void) get_display_name(slice, &sname); 329 if (bytes_to_sizestr(snbytes, &sizestr, 330 universal_units, B_FALSE) == 0) { 331 oprintf(OUTPUT_VERBOSE, look_msg, sname, sizestr); 332 free(sizestr); 333 } 334 } 335 336 if (npaths > 1) { 337 if (paths && verbose) { 338 /* specifically asked for more paths, ... */ 339 oprintf(OUTPUT_VERBOSE, npaths_msg); 340 } 341 } else if (npaths == 1) { 342 /* every disk has at least 1 path */ 343 paths = B_TRUE; 344 } 345 346 if (verbose == B_TRUE) { 347 if (uniqhba) { 348 oprintf(OUTPUT_VERBOSE, uniqhba_msg); 349 } 350 if (uniqdisk) { 351 oprintf(OUTPUT_VERBOSE, uniqdisk_msg); 352 } 353 354 if (used != NULL) { 355 if (samebus) { 356 oprintf(OUTPUT_VERBOSE, samebus_msg); 357 } 358 if (samegeom) { 359 oprintf(OUTPUT_VERBOSE, samegeom_msg); 360 } 361 } 362 363 if (snbytes > nbytes) { 364 oprintf(OUTPUT_VERBOSE, larger_msg); 365 } else if (snbytes == nbytes) { 366 oprintf(OUTPUT_VERBOSE, exact_msg); 367 } else { 368 oprintf(OUTPUT_VERBOSE, smaller_msg); 369 } 370 } 371 372 /* filter slices not meeting minimum criteria */ 373 if (nbytes_is_min && (snbytes < nbytes)) { 374 /* not large enough */ 375 if (verbose == B_TRUE) { 376 oprintf(OUTPUT_VERBOSE, too_small); 377 } 378 continue; 379 } 380 381 if (paths == B_FALSE) { 382 /* not connected thru enough paths */ 383 if (verbose == B_TRUE) { 384 oprintf(OUTPUT_VERBOSE, insuff_paths, npaths); 385 } 386 continue; 387 } 388 389 if (uniqdisk != B_TRUE && unused_disk == TRUE) { 390 /* not on a unique disk */ 391 if (verbose == B_TRUE) { 392 oprintf(OUTPUT_VERBOSE, useddisk_msg); 393 } 394 continue; 395 } 396 397 /* map slice properties into array indices */ 398 i = (uniqhba ? 0 : 1); 399 j = (samebus ? 0 : 1); 400 k = (uniqdisk ? 0 : 1); 401 l = (samegeom ? 0 : 1); 402 m = (snbytes == nbytes ? 0 : (snbytes > nbytes ? 1 : 2)); 403 404 /* 405 * insert slice into the list array using derived indices. 406 * NB: lists of slices larger than necessary are kept in 407 * ascending order (results in best fit, not worst fit) 408 */ 409 if ((item = dlist_new_item((void*)(uintptr_t)slice)) == NULL) { 410 error = ENOMEM; 411 } else { 412 list[i][j][k][l][m] = 413 dlist_insert_ordered( 414 item, 415 list[i][j][k][l][m], 416 (m == 1 ? ASCENDING : DESCENDING), 417 compare_slice_sizes); 418 } 419 } 420 421 /* 422 * Select a slice from one of the lists. 423 * 424 * The list with the combination of lowest indices 425 * is the most preferred list... in rough order: 426 * 427 * one on a unique HBA and disk that is of the exact size 428 * one on a unique HBA and disk that is of sufficient size (resize) 429 * one on unique HBA that is of the exact size 430 * one on unique HBA that is of sufficient size (resize) 431 * one on unique disk that is of the exact size 432 * one on unique disk that is of sufficient size (resize) 433 * one on any HBA that is of exact size 434 * one on any HBA that is of sufficient size (resize) 435 * one on a unique HBA that is the largest size 436 * one on a unique disk that is the largest size 437 * one on any HBA that is the largest size 438 */ 439 slice = NULL; 440 441 for (i = 0; i < 2; i++) { 442 for (j = 0; j < 2; j++) { 443 for (k = 0; k < 2; k++) { 444 for (l = 0; l < 2; l++) { 445 for (m = 0; m < 3; m++) { 446 if (list[i][j][k][l][m] != NULL) { 447 448 /* pick least used slice from this list */ 449 error = pick_from_best_hba_and_disk( 450 list[i][j][k][l][m], 451 used, &slice); 452 453 resize = (m == 1); 454 455 /* terminate all loops */ 456 goto stop; 457 } 458 } 459 } 460 } 461 } 462 } 463 stop: 464 465 /* 466 * Slice chosen, is a resize necessary? 467 */ 468 if ((error == 0) && (slice != NULL)) { 469 470 if (error == 0) { 471 if (verbose == B_TRUE) { 472 uint64_t snbytes = 0; 473 char *sname = NULL; 474 char *sizestr = NULL; 475 476 (void) get_display_name(slice, &sname); 477 (void) slice_get_size(slice, &snbytes); 478 479 if (bytes_to_sizestr(snbytes, &sizestr, 480 universal_units, B_FALSE) == 0) { 481 oprintf(OUTPUT_VERBOSE, 482 gettext(" selected %s (%s)\n" 483 " it is %s on a\n" 484 " %s (%s) and a\n" 485 " %s (%s)\n"), 486 sname, sizestr, 487 sizes[m], 488 uniqhba[i], samebus[j], 489 uniqdisk[k], samegeom[l]); 490 free(sizestr); 491 } 492 } 493 494 if (resize) { 495 if (verbose == B_TRUE) { 496 oprintf(OUTPUT_VERBOSE, 497 gettext(" it has excess space, " 498 "resizing...\n")); 499 } 500 501 error = create_new_slice(slice, nbytes, add_extra_cyl, 502 chosen); 503 if ((error == 0) && (*chosen != NULL) && verbose) { 504 oprintf(OUTPUT_VERBOSE, 505 gettext(" exactly resized\n")); 506 } 507 } 508 509 if (error == 0) { 510 /* either no resize was necessary or the resize failed */ 511 if (*chosen == NULL) { 512 /* 513 * use the original slice as it is. 514 * Make a devconfig_t for it. 515 */ 516 error = create_devconfig_for_slice(slice, chosen); 517 } 518 } 519 } 520 } else if (slice == NULL) { 521 oprintf(OUTPUT_DEBUG, 522 gettext(" no possible slice\n")); 523 } 524 525 for (i = 0; i < 2; i++) { 526 for (j = 0; j < 2; j++) { 527 for (k = 0; k < 2; k++) { 528 for (l = 0; l < 2; l++) { 529 for (m = 0; m < 3; m++) { 530 if (list[i][j][k][l][m] != NULL) { 531 dlist_free_items(list[i][j][k][l][m], NULL); 532 } 533 } 534 } 535 } 536 } 537 } 538 539 return (error); 540 } 541 542 /* 543 * FUNCTION: create_devconfig_for_slice(dm_descriptor_t slice, 544 * devconfig_t **nslice) 545 * 546 * INPUT: slice - dm_descriptor_t handle to an existing slice 547 * nslice - devconfig_t pointer to hold the new slice 548 * 549 * RETURNS: int - 0 on success 550 * !0 otherwise 551 * 552 * PURPOSE: Creates a devconfig_t struct representation of the input 553 * slice dm_descriptor. 554 */ 555 int 556 create_devconfig_for_slice( 557 dm_descriptor_t slice, 558 devconfig_t **nslice) 559 { 560 uint64_t nbytes = 0; 561 uint64_t nblks = 0; 562 uint64_t stblk = 0; 563 uint32_t index = 0; 564 char *name = NULL; 565 int error = 0; 566 567 ((error = get_display_name(slice, &name)) != 0) || 568 (error = slice_get_size(slice, &nbytes)) || 569 (error = slice_get_size_in_blocks(slice, &nblks)) || 570 (error = slice_get_start_block(slice, &stblk)) || 571 (error = slice_get_index(slice, &index)); 572 if (error != 0) { 573 return (error); 574 } 575 576 ((error = new_devconfig(nslice, TYPE_SLICE)) != 0) || 577 (error = devconfig_set_name(*nslice, name)) || 578 (error = devconfig_set_slice_index(*nslice, index)) || 579 (error = devconfig_set_slice_start_block(*nslice, stblk)) || 580 (error = devconfig_set_size_in_blocks(*nslice, nblks)) || 581 (error = devconfig_set_size(*nslice, nbytes)); 582 if (error != 0) { 583 free_devconfig(*nslice); 584 } 585 586 return (error); 587 } 588 589 /* 590 * FUNCTION: make_slicename_for_disk_and_index(dm_descriptor_t disk, 591 * uint32_t index, char **slicename) 592 * 593 * INPUT: disk - a dm_descriptor_t disk handle 594 * index - a slice index 595 * 596 * OUTPUT slicename - a char * pointer to hold the resulting slicename 597 * 598 * RETURNS: int - 0 on success 599 * !0 otherwise 600 * 601 * PURPOSE: Utility function to manufacture a new slice name given the 602 * "parent" disk and an available slice index. 603 * 604 * The caller should free the returned name when done with it. 605 */ 606 static int 607 make_slicename_for_disk_and_index( 608 dm_descriptor_t disk, 609 uint16_t index, 610 char **slicename) 611 { 612 char *dname; 613 int error = 0; 614 615 if ((error = get_display_name(disk, &dname)) == 0) { 616 error = make_slicename_for_diskname_and_index(dname, 617 index, slicename); 618 } 619 620 return (error); 621 } 622 623 /* 624 * FUNCTION: make_slicename_for_diskname_and_index(char *diskname, 625 * uint32_t index, char **slicename) 626 * 627 * INPUT: diskname - a char * disk name 628 * index - a slice index 629 * 630 * OUTPUT slicename - a char * pointer to hold the resulting slicename 631 * 632 * RETURNS: int - 0 on success 633 * !0 otherwise 634 * 635 * PURPOSE: Utility function to manufacture a new slice name given the 636 * name of a disk and an available slice index. 637 * 638 * The caller should free the returned name when done with it. 639 */ 640 int 641 make_slicename_for_diskname_and_index( 642 char *diskname, 643 uint16_t index, 644 char **slicename) 645 { 646 int error = 0; 647 char buf[MAXNAMELEN+1]; 648 649 (void) snprintf(buf, sizeof (buf), "%ss%u", diskname, index); 650 if ((*slicename = strdup(buf)) == NULL) { 651 *slicename = NULL; 652 error = ENOMEM; 653 } 654 655 return (error); 656 } 657 658 /* 659 * FUNCTION: create_new_slice(dm_descriptor_t oslice, uint64_t nbytes, 660 * boolean_t add_extra_cyl, devconfig_t **nslice) 661 * 662 * INPUT: oslice - dm_descriptor_t handle to an existing slice 663 * nbytes - desired minimum size of the new slice 664 * add_extra_cyl - boolean indicating whether the resized slice 665 * needs to be oversized by 1 cylinder to account for 666 * interlace rounding done for stripe components. 667 * nslice - devconfig_t pointer to hold the new slice 668 * 669 * RETURNS: int - 0 on success 670 * !0 otherwise 671 * 672 * PURPOSE: Creates a new slice object using space from the input slice. 673 * 674 * If there is an open slice slot in the disk VTOC, it will be 675 * reserved for the new slice. Space for the new slice will be 676 * taken from the original slice. 677 * 678 * If there is no open slice slot, the original slice will be 679 * returned as the usable new slice. 680 * 681 * The new slice will be of at least 'nbytes' bytes and possibly 682 * larger due to sector and cylinder boundary alignment. 683 * 684 * For EFI labeled disks, nbytes is rounded up to the next block 685 * boundary. 686 * 687 * For VTOC labeled disks, nbytes is rounded up to the next 688 * cylinder boundary. 689 * 690 * Additionally, if add_extra_cyl is true, the new slice will be 691 * made 1 cylinder larger than necessary. This accounts for the 692 * interlace rounding done within libmeta when computing the 693 * usable size of stripe components on disks with VTOC labels. 694 * Rounding the size up to the next cylinder boundary is not 695 * sufficient because libmeta will round this size down to an 696 * integral multiple of the stripe interlace and then round that 697 * result down to a cylinder boundary. This makes the usable 698 * size of the slice one cylinder smaller and possibly less than 699 * nbytes. Adding an extra cylinder ensures the usable size is 700 * greater than nbytes despite the rounding. 701 * 702 * If the resize is successful a pointer to the devconfig_t 703 * representing the new slice will be returned in "newslice". 704 * 705 * If the resize cannot be done, the newslice pointer will 706 * be NULL. 707 */ 708 static int 709 create_new_slice( 710 dm_descriptor_t oslice, 711 uint64_t nbytes, 712 boolean_t add_extra_cyl, 713 devconfig_t **nslice) 714 { 715 dm_descriptor_t odisk = NULL; 716 boolean_t efi = B_FALSE; 717 718 char *oname = NULL; 719 uint64_t osize = 0; /* orig size (bytes) */ 720 uint64_t ostart = 0; /* orig start (byte) */ 721 uint64_t ostblk = 0; /* orig start (blk) */ 722 uint64_t nsize = 0; /* new size (bytes) */ 723 uint64_t bytes_per_sect = 0; 724 725 uint32_t oindex = 0; 726 uint32_t nindex = oindex; 727 728 int error = 0; 729 730 *nslice = NULL; 731 732 ((error = slice_get_disk(oslice, &odisk)) != 0) || 733 (error = slice_get_index(oslice, &oindex)); 734 if (error != 0) { 735 return (error); 736 } 737 738 /* find an unused slice number, default to oindex */ 739 nindex = oindex; 740 if ((error = disk_get_available_slice_index(odisk, &nindex)) != 0) { 741 return (error); 742 } 743 744 ((error = get_display_name(oslice, &oname)) != 0) || 745 (error = slice_get_size(oslice, &osize)) || 746 (error = slice_get_start(oslice, &ostart)) || 747 (error = slice_get_start_block(oslice, &ostblk)) || 748 (error = disk_get_is_efi(odisk, &efi)) || 749 (error = disk_get_blocksize(odisk, &bytes_per_sect)); 750 if (error != 0) { 751 return (error); 752 } 753 754 if (efi) { 755 756 /* EFI: round size to an integral number of blocks (sectors) */ 757 nsize = bytes_per_sect * 758 ((nbytes + (bytes_per_sect - 1)) / bytes_per_sect); 759 760 oprintf(OUTPUT_DEBUG, 761 gettext(" " 762 "rounded up to %10.2f blocks\n"), 763 (double)(nsize/bytes_per_sect)); 764 765 } else { 766 767 /* VTOC: round size to an integral number of cylinders */ 768 uint64_t nhead = 0; 769 uint64_t nsect = 0; 770 uint64_t ncyls = 0; 771 772 ((error = disk_get_ncylinders(odisk, &ncyls)) != 0) || 773 (error = disk_get_nheads(odisk, &nhead)) || 774 (error = disk_get_nsectors(odisk, &nsect)); 775 if (error == 0) { 776 uint64_t bytes_per_cyl = nhead * nsect * bytes_per_sect; 777 nsize = bytes_per_cyl * 778 ((nbytes + (bytes_per_cyl - 1)) / bytes_per_cyl); 779 780 if (add_extra_cyl == TRUE) { 781 nsize += bytes_per_cyl; 782 } 783 784 oprintf(OUTPUT_DEBUG, 785 gettext(" " 786 "rounded VTOC slice to %10.2f cylinders " 787 "(out of %llu)\n"), 788 (double)(nsize/bytes_per_cyl), ncyls); 789 } 790 } 791 792 /* is sufficient space still available? */ 793 if (error == 0) { 794 if (osize == nsize) { 795 /* use existing slice as is */ 796 ((error = create_devconfig_for_slice(oslice, nslice)) != 0) || 797 (error = disk_reserve_index(odisk, (uint16_t)nindex)); 798 } else if (osize > nsize) { 799 800 if (nindex == oindex) { 801 /* no more slices, resize existing slice */ 802 ((error = create_devconfig_for_slice(oslice, 803 nslice)) != 0) || 804 (error = devconfig_set_size(*nslice, nsize)) || 805 (error = devconfig_set_size_in_blocks(*nslice, 806 nsize/bytes_per_sect)); 807 (error = disk_reserve_index(odisk, (uint16_t)nindex)); 808 809 } else { 810 /* make a new slice */ 811 char *nname = NULL; 812 813 ((error = make_slicename_for_disk_and_index(odisk, 814 nindex, &nname)) != 0) || 815 (error = create_modified_slice(oslice, oname, oindex, 816 ostart, osize, bytes_per_sect, nname, nindex, nsize, 817 nslice)) || 818 /* mark the new slice's index as used */ 819 (error = disk_reserve_index(odisk, (uint16_t)nindex)); 820 821 if ((error != 0) && (*nslice == NULL)) { 822 free(nname); 823 } 824 } 825 } 826 } 827 828 return (error); 829 } 830 831 /* 832 * FUNCTION: create_modified_slice(dm_descriptor_t oslice, char *oname, 833 * uint32_t oindex, uint64_t ostart, uint64_t osize, 834 * uint64_t bytes_per_sect, uint64_t nsize, 835 * char *nname, uint32_t nindex, devconfig_t **nslice) 836 * 837 * INPUT: oslice - dm_descriptor_t handle for the original slice 838 * oname - existing source slice name 839 * oindex - existing source slice VTOC index 840 * ostart - existing source slice start byte 841 * osize - existing source slice size in bytes 842 * bytes_per_sect - bytes per block (sector) for the disk 843 * nname - new slice name 844 * nindex - new slice VTOC index 845 * nsize - new slice size in bytes (cylinder and block aligned) 846 * 847 * SIDEEFFECTS: updates the module private list of modified slices 848 * 849 * OUTPUT: nslice - pointer to a devconfig_t to hold the new slice 850 * 851 * PURPOSE: create a new VTOC slice by taking space from an 852 * existing slice. 853 * 854 * The input size for the new slice is expected to be 855 * cylinder aligned. 856 */ 857 static int 858 create_modified_slice( 859 dm_descriptor_t oslice, 860 char *oname, 861 uint32_t oindex, 862 uint64_t ostart, 863 uint64_t osize, 864 uint64_t bytes_per_sect, 865 char *nname, 866 uint32_t nindex, 867 uint64_t nsize, 868 devconfig_t **nslice) 869 { 870 int error = 0; 871 872 /* compute start sector and size in sectors for the new slice */ 873 874 /* subtract nsize from original slice to get starting byte */ 875 uint64_t nstart = (ostart + osize) - nsize; 876 877 /* convert starting byte to a sector */ 878 uint64_t nstblk = (uint64_t)(nstart / bytes_per_sect); 879 880 /* convert nsize to an integral number of blocks (sectors) */ 881 uint64_t nblks = (uint64_t)(nsize / bytes_per_sect); 882 883 /* create a modified slice record for the new slice */ 884 error = assemble_modified_slice(oslice, nname, nindex, 885 nstblk, nblks, nsize, nslice); 886 if (error != 0) { 887 free(nname); 888 return (error); 889 } 890 891 /* update the existing source slice's new size */ 892 osize = osize - nsize; 893 (void) slice_set_size(oslice, osize); 894 895 /* update/create the modified slice record gfor the source slice */ 896 error = assemble_modified_slice((dm_descriptor_t)0, 897 oname, oindex, (uint64_t)(ostart / bytes_per_sect), 898 (uint64_t)(osize / bytes_per_sect), 899 osize, NULL); 900 901 return (error); 902 } 903 904 /* 905 * FUNCTION: assemble_modified_slice(dm_descriptor_t src_slice, 906 * char *mod_name, uint32_t mod_index, 907 * uint64_t mod_stblk, uint64_t mod_nblks, 908 * uint64_t mod_size, devconfig_t **modslice) 909 * 910 * INPUT: src_slice - dm_descriptor_t handle of the slice space 911 * was taken from to create the modified slice 912 * mod_name - name of the modified slice 913 * mod_index - name of the modified slice 914 * mod_stblk - start block of the modified slice 915 * mod_nblks - size in blocks of the modified slice 916 * mod_size - size in bytes of the modified slice 917 * 918 * OUTPUT: mod_slice - if non-NULL, will be populated with a 919 * devconfig_t representing the modified slice. 920 * 921 * SIDEEFFECTS: adds or updates an entry in the modified slice list 922 * tracking the slices that have been explicitly modified 923 * by the layout code. 924 * 925 * RETURNS: int - 0 on success 926 * !0 otherwise 927 * 928 * PURPOSE: Utility function to which updates or creates a devconfig_t 929 * representing a slice that needs to be modified. 930 * 931 * If a modified slice record does not exist for the named 932 * slice, a new devconfig_t struct is allocated and added 933 * to the modified slice list. 934 * 935 * The existing or created devconfig_t struct is updated with 936 * the input values. 937 * 938 * The information about the slices in the modified slice list 939 * will eventually be handed to fmthard. 940 */ 941 int 942 assemble_modified_slice( 943 dm_descriptor_t src_slice, 944 char *mod_name, 945 uint32_t mod_index, 946 uint64_t mod_stblk, 947 uint64_t mod_nblks, 948 uint64_t mod_size, 949 devconfig_t **mod_slice) 950 { 951 devconfig_t *slice = NULL; 952 modslice_t *mstp = NULL; 953 dlist_t *item = NULL; 954 int error = 0; 955 956 /* see if the slice has been modified before */ 957 if ((item = dlist_find(_modified_slices, mod_name, 958 compare_string_to_modslice_name)) != NULL) { 959 960 /* yes, update the resize count and attributes */ 961 mstp = (modslice_t *)item->obj; 962 slice = mstp->slice_devcfg; 963 964 mstp->times_modified += 1; 965 mstp->src_slice_desc = src_slice; 966 967 ((error = devconfig_set_slice_start_block(slice, 968 mod_stblk)) != 0) || 969 (error = devconfig_set_size(slice, mod_size)) || 970 (error = devconfig_set_size_in_blocks(slice, mod_nblks)); 971 972 } else { 973 974 /* no, first modification... */ 975 /* create a devconfig_t representing the new slice */ 976 ((error = new_devconfig(&slice, TYPE_SLICE)) != 0) || 977 (error = devconfig_set_name(slice, mod_name)) || 978 (error = devconfig_set_slice_index(slice, mod_index)) || 979 (error = devconfig_set_slice_start_block(slice, mod_stblk)) || 980 (error = devconfig_set_size_in_blocks(slice, mod_nblks)) || 981 (error = devconfig_set_size(slice, mod_size)); 982 if (error == 0) { 983 /* add to list of modified slices */ 984 if ((mstp = (modslice_t *) 985 calloc(1, sizeof (modslice_t))) != NULL) { 986 987 /* count # of times source slice has been modified */ 988 if (src_slice != (dm_descriptor_t)0) { 989 mstp->times_modified = 0; 990 } else { 991 mstp->times_modified = 1; 992 } 993 mstp->src_slice_desc = src_slice; 994 mstp->slice_devcfg = slice; 995 996 if ((item = dlist_new_item(mstp)) != NULL) { 997 _modified_slices = 998 dlist_insert_ordered( 999 item, 1000 _modified_slices, 1001 ASCENDING, 1002 compare_modslice_names); 1003 } else { 1004 error = ENOMEM; 1005 } 1006 } else { 1007 error = ENOMEM; 1008 } 1009 } 1010 1011 if (error != 0) { 1012 free_devconfig(mstp); 1013 free_devconfig(slice); 1014 } 1015 } 1016 1017 if (error == 0) { 1018 oprintf(OUTPUT_DEBUG, 1019 " " 1020 "modified %s (start blk: %9llu, nblks: %9llu)\n", 1021 mod_name, mod_stblk, mod_nblks); 1022 1023 /* return devconfig_t for modified slice */ 1024 if (mod_slice != NULL) { 1025 *mod_slice = slice; 1026 mstp->volume_component = B_TRUE; 1027 } 1028 } 1029 1030 return (error); 1031 } 1032 1033 /* 1034 * FUNCTION: dlist_t *get_modified_slices() 1035 * 1036 * RETURNS: pointer to the list of modslice_t structs representing 1037 * modified slices 1038 * 1039 * PURPOSE: public accessor to the list of slices modified while 1040 * processing a request. 1041 */ 1042 dlist_t * 1043 get_modified_slices() 1044 { 1045 return (_modified_slices); 1046 } 1047 1048 /* 1049 * FUNCTION: free_modslice_object(void *obj) 1050 * 1051 * INPUT: obj - opaque pointer 1052 * 1053 * PURPOSE: Frees memory associated with a modslice_t struct. 1054 */ 1055 static void 1056 free_modslice_object( 1057 void *obj) 1058 { 1059 assert(obj != (modslice_t *)NULL); 1060 1061 if (((modslice_t *)obj)->slice_devcfg != NULL) { 1062 if (((modslice_t *)obj)->volume_component != B_TRUE) { 1063 free_devconfig(((modslice_t *)obj)->slice_devcfg); 1064 } 1065 } 1066 1067 free(obj); 1068 } 1069 1070 /* 1071 * FUNCTION: void release_modified_slices() 1072 * 1073 * INPUT: none - 1074 * OUTPUT: none - 1075 * 1076 * PURPOSE: cleanup the module global list of slices modified 1077 * while processing a request. 1078 */ 1079 int 1080 release_modified_slices() 1081 { 1082 dlist_free_items(_modified_slices, free_modslice_object); 1083 _modified_slices = NULL; 1084 1085 return (0); 1086 } 1087 1088 /* 1089 * FUNCTION: destroy_new_slice(devconfig_t *dev) 1090 * 1091 * INPUT: dev - a devconfig_t pointer to a slice object 1092 * 1093 * RETURNS: int - 0 on success 1094 * !0 otherwise 1095 * 1096 * PURPOSE: Undoes slice creation done by create_new_slice(): 1097 * 1098 * release index 1099 * remove from used_slices 1100 * remove from modified_slices 1101 * return space to source slice 1102 * free memory 1103 */ 1104 int 1105 destroy_new_slice( 1106 devconfig_t *dev) 1107 { 1108 dm_descriptor_t disk = NULL; 1109 uint64_t size = 0; 1110 uint16_t index = 0; 1111 modslice_t *modified = NULL; 1112 dlist_t *item = NULL; 1113 char *name = NULL; 1114 int error = 0; 1115 1116 ((error = devconfig_get_name(dev, &name)) != 0) || 1117 (error = devconfig_get_slice_index(dev, &index)) || 1118 (error = devconfig_get_size(dev, &size)) || 1119 (error = get_disk_for_named_slice(name, &disk)) || 1120 (error = disk_release_index(disk, index)) || 1121 (error = remove_used_slice_by_name(name)); 1122 if (error != 0) { 1123 return (error); 1124 } 1125 1126 /* remove from the modified_slices list */ 1127 _modified_slices = 1128 dlist_remove_equivalent_item( 1129 _modified_slices, name, 1130 compare_string_to_modslice_name, &item); 1131 1132 if (item != NULL) { 1133 modified = (modslice_t *)item->obj; 1134 free((void*) item); 1135 } 1136 1137 /* space from an existing slice? if so reclaim it. */ 1138 if (modified != NULL) { 1139 1140 dm_descriptor_t src = modified->src_slice_desc; 1141 char *srcname = NULL; 1142 dlist_t *srcitem = NULL; 1143 1144 if (src != (dm_descriptor_t)0) { 1145 if ((error = get_display_name(src, &srcname)) == 0) { 1146 srcitem = 1147 dlist_find( 1148 _modified_slices, 1149 srcname, 1150 compare_string_to_modslice_name); 1151 } 1152 } 1153 1154 if ((error == 0) && (srcitem != NULL)) { 1155 1156 modslice_t *source = (modslice_t *)srcitem->obj; 1157 devconfig_t *srcdevcfg = NULL; 1158 uint64_t srcsize = NULL; 1159 uint64_t srcsizeblks = NULL; 1160 uint64_t inblks = NULL; 1161 1162 srcdevcfg = source->slice_devcfg; 1163 source->times_modified -= 1; 1164 1165 ((error = devconfig_get_size(srcdevcfg, &srcsize)) != 0) || 1166 (error = devconfig_set_size(srcdevcfg, srcsize + size)) || 1167 (error = slice_set_size(src, srcsize + size)) || 1168 (error = slice_get_size_in_blocks(src, &srcsizeblks)) || 1169 (error = devconfig_get_size_in_blocks(srcdevcfg, &inblks)); 1170 (error = devconfig_set_size_in_blocks(srcdevcfg, srcsizeblks)); 1171 1172 if (error == 0) { 1173 1174 /* was only modification undone? */ 1175 if (source->times_modified == 0) { 1176 1177 _modified_slices = 1178 dlist_remove_equivalent_item( 1179 _modified_slices, srcname, 1180 compare_string_to_modslice_name, 1181 &srcitem); 1182 1183 free_modslice_object((modslice_t *)srcitem->obj); 1184 free((void *)srcitem); 1185 } 1186 } 1187 } 1188 1189 free_modslice_object(modified); 1190 } 1191 1192 return (error); 1193 } 1194 1195 /* 1196 * FUNCTION: pick_from_best_hba_and_disk(dlist_t *slices, 1197 * dlist_t *used, dm_descriptor_t *chosen) 1198 * 1199 * INPUT: slices - a dlist_t poitner to a list of slices 1200 * used - a dlist_t pointer to a list of used slices 1201 * chosen - a dm_descriptor_t pointer to hold the result 1202 * 1203 * RETURNS: int - 0 on success 1204 * !0 otherwise 1205 * 1206 * PURPOSE: Examines the input list of slices and chooses the one 1207 * that is on the least used HBA and disk. 1208 * 1209 * HBA and disk usage is determined by examining the input 1210 * list of used slices and counting the number of slices 1211 * each HBA and disk contributes. 1212 * 1213 * The HBA which contributes the fewest is selected, and 1214 * then the disk on that HBA which contributes the fewest 1215 * is selected. 1216 * 1217 * The largest slice from that disk is then returned. 1218 */ 1219 static int 1220 pick_from_best_hba_and_disk( 1221 dlist_t *slices, 1222 dlist_t *used, 1223 dm_descriptor_t *chosen) 1224 { 1225 dlist_t *iter = NULL; 1226 dlist_t *iter1 = NULL; 1227 dlist_t *iter2 = NULL; 1228 dlist_t *item = NULL; 1229 1230 dlist_t *used_slice_hbas = NULL; 1231 1232 int maxuses = 128; 1233 int maxslices = VTOC_SIZE; /* meta.h */ 1234 1235 int i = 0; 1236 int error = 0; 1237 1238 /* 1239 * allocate an array to hold lists of slices grouped by 1240 * HBA contribution... the list indexed by N is the list 1241 * of slices that are on HBAs contributing N slices 1242 */ 1243 dlist_t **prefhbas = (dlist_t **)calloc(maxuses, sizeof (dlist_t *)); 1244 1245 /* 1246 * allocate an array to hold lists of slices grouped by 1247 * disk contribution... the list indexed by N is the list 1248 * of slices that are on disks contributing N slices 1249 */ 1250 dlist_t **prefdisks = (dlist_t **)calloc(maxslices, sizeof (dlist_t *)); 1251 1252 *chosen = (dm_descriptor_t)0; 1253 1254 if (prefhbas == NULL || prefdisks == NULL) { 1255 free(prefhbas); 1256 free(prefdisks); 1257 return (ENOMEM); 1258 } 1259 1260 /* 1261 * precompute the used slices' lists of HBAS: iterate the list 1262 * of used slices and determine the HBA(s) each is connected thru. 1263 * construct a list of lists containing the HBAs. 1264 */ 1265 for (iter = used; 1266 (iter != NULL) && (error == 0); 1267 iter = iter->next) { 1268 1269 devconfig_t *uslice = (devconfig_t *)iter->obj; 1270 dm_descriptor_t udisk = NULL; 1271 char *uname = NULL; 1272 dlist_t *uhbas = NULL; 1273 1274 /* need to use disk to get to HBAs because */ 1275 /* the slice doesn't exist yet */ 1276 ((error = devconfig_get_name(uslice, &uname)) != 0) || 1277 (error = get_disk_for_named_slice(uname, &udisk)) || 1278 (error = disk_get_hbas(udisk, &uhbas)); 1279 if (error == 0) { 1280 if ((item = dlist_new_item((void *)uhbas)) == NULL) { 1281 error = ENOMEM; 1282 } else { 1283 used_slice_hbas = dlist_append( 1284 item, used_slice_hbas, AT_HEAD); 1285 } 1286 } 1287 } 1288 1289 /* 1290 * iterate the list of chosen slices and for each, 1291 * determine how many other slices from its HBA(s) 1292 * are already being used... 1293 * 1294 * iter steps thru the list of slices 1295 * iter1 steps thru each of the slice's HBAs 1296 * iter2 steps thru the precomputed list of used slice's HBAs 1297 * dlist_contains then searches each used slice's HBAs 1298 * to see if it contains iter1's HBA 1299 * 1300 * If it does, increment the count for that HBA. 1301 */ 1302 for (iter = slices; 1303 (iter != NULL) && (error == 0); 1304 iter = iter->next) { 1305 1306 dm_descriptor_t slice = (uintptr_t)iter->obj; 1307 dlist_t *hbas = NULL; 1308 int n = 0; /* # slices each HBA contributes */ 1309 1310 if ((error = slice_get_hbas(slice, &hbas)) != 0) { 1311 continue; 1312 } 1313 1314 for (iter1 = hbas; iter1 != NULL; iter1 = iter1->next) { 1315 for (iter2 = used_slice_hbas; iter2 != NULL; 1316 iter2 = iter2->next) { 1317 1318 dlist_t *uhbas = (dlist_t *)iter2->obj; 1319 if (dlist_contains(uhbas, iter1->obj, 1320 compare_descriptor_names) == B_TRUE) { 1321 n++; 1322 } 1323 } 1324 } 1325 1326 dlist_free_items(hbas, NULL); 1327 1328 /* group slices from HBAs contributing more than maxuses */ 1329 if (n >= maxuses) { 1330 n = maxuses - 1; 1331 } 1332 1333 /* add slice to list in descending size order */ 1334 if ((item = dlist_new_item((void*)(uintptr_t)slice)) == NULL) { 1335 error = ENOMEM; 1336 } else { 1337 prefhbas[n] = 1338 dlist_insert_ordered( 1339 item, 1340 prefhbas[n], 1341 DESCENDING, 1342 compare_slice_sizes); 1343 } 1344 } 1345 1346 /* free list of lists of used slices HBAs */ 1347 for (iter = used_slice_hbas; iter != NULL; iter = iter->next) { 1348 dlist_free_items((dlist_t *)iter->obj, NULL); 1349 } 1350 dlist_free_items(used_slice_hbas, NULL); 1351 1352 /* 1353 * Select the list of slices that are on the HBA(s) contributing 1354 * the fewest slices... iterate these slices and for each, detemmine 1355 * how many other slices from its disk are already being used... 1356 */ 1357 for (i = 0; (i < maxuses) && (error == 0); i++) { 1358 1359 for (iter = (dlist_t *)prefhbas[i]; 1360 (iter != NULL) && (error == 0); 1361 iter = iter->next) { 1362 1363 dm_descriptor_t slice = (uintptr_t)iter->obj; 1364 dm_descriptor_t disk; 1365 int n = 0; 1366 1367 (void) slice_get_disk(slice, &disk); 1368 1369 /* 1370 * count how many slices this slice's disk is contributing 1371 * by comparing it to the list of used slices 1372 */ 1373 for (iter1 = _used_slices; iter1 != NULL; iter1 = iter1->next) { 1374 usedslice_t *used = (usedslice_t *)iter1->obj; 1375 if (compare_descriptors((void *)(uintptr_t)disk, 1376 (void *)(uintptr_t)used->disk) == 0) { 1377 n++; 1378 } 1379 } 1380 1381 /* add slice to list in descending size order */ 1382 if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) { 1383 error = ENOMEM; 1384 } else { 1385 prefdisks[n] = 1386 dlist_insert_ordered( 1387 item, 1388 prefdisks[n], 1389 DESCENDING, 1390 compare_slice_sizes); 1391 } 1392 } 1393 } 1394 1395 if (error == 0) { 1396 /* select largest slice from least used disk */ 1397 for (i = 0; (i < maxslices) && (*chosen == NULL); i++) { 1398 if (prefdisks[i] != NULL) { 1399 *chosen = (uintptr_t)prefdisks[i]->obj; 1400 } 1401 } 1402 } 1403 1404 for (i = 0; i < maxuses; i++) { 1405 dlist_free_items(prefhbas[i], NULL); 1406 } 1407 for (i = 0; i < maxslices; i++) { 1408 dlist_free_items(prefdisks[i], NULL); 1409 } 1410 1411 free((void*)prefhbas); 1412 free((void*)prefdisks); 1413 1414 return (error); 1415 } 1416 1417 /* 1418 * FUNCTION: slice_on_unique_hba(dm_descriptor_t slice, 1419 * dlist_t *used, dlist_t *used_hbas, 1420 * boolean_t *unique) 1421 * 1422 * INPUT: slice - a dm_descriptor_t handle for the slice of interest 1423 * used - a dlist_t pointer to a list of used slices 1424 * used_hbas - a dlist_t pointer to a list of used_hbas 1425 * unique - a boolean_t pointer to hold the result 1426 * 1427 * RETURNS: int - 0 on success 1428 * !0 otherwise 1429 * 1430 * PURPOSE: Determines if the input slice is connected thru the same HBA 1431 * as a slice in the used list. 1432 * 1433 * Also checks to see if the input slice is connected thru any 1434 * HBA in the used_hbas list. 1435 * 1436 * If the slice is found to be on a unique HBA, bool is set 1437 * to B_TRUE, B_FALSE otherwise. 1438 */ 1439 static int 1440 slice_on_unique_hba( 1441 dm_descriptor_t slice, 1442 dlist_t *used, 1443 dlist_t *used_hbas, 1444 boolean_t *unique) 1445 { 1446 dlist_t *iter = NULL; 1447 dlist_t *iter1 = NULL; 1448 1449 dlist_t *hbas = NULL; 1450 1451 int error = 0; 1452 1453 *unique = B_TRUE; 1454 1455 if ((error = slice_get_hbas(slice, &hbas)) != 0) { 1456 return (error); 1457 } 1458 1459 /* 1460 * check to see if any of slice's HBAs is the same 1461 * as the HBA for any of the used 1462 */ 1463 for (iter = used; 1464 (iter != NULL) && (*unique == B_TRUE) && (error == 0); 1465 iter = iter->next) { 1466 1467 devconfig_t *dev = (devconfig_t *)iter->obj; 1468 if (devconfig_isA(dev, TYPE_SLICE)) { 1469 1470 dm_descriptor_t odisk = NULL; 1471 char *oname = NULL; 1472 dlist_t *ohbas = NULL; 1473 1474 /* get HBAs for other slice using its disk */ 1475 /* because the slice doesn't exist yet. */ 1476 ((error = devconfig_get_name(dev, &oname)) != 0) || 1477 (error = get_disk_for_named_slice(oname, &odisk)) || 1478 (error = disk_get_hbas(odisk, &ohbas)); 1479 1480 /* any HBA overlap? */ 1481 for (iter1 = hbas; 1482 (iter1 != NULL) && (*unique == B_TRUE) && (error == 0); 1483 iter1 = iter1->next) { 1484 1485 if (dlist_contains(ohbas, iter1->obj, 1486 compare_descriptor_names) == B_TRUE) { 1487 *unique = B_FALSE; 1488 } 1489 } 1490 dlist_free_items(ohbas, NULL); 1491 } 1492 } 1493 1494 /* 1495 * check to see if any of slice's HBAs is the contained 1496 * in the list of used hbas 1497 */ 1498 for (iter = hbas; 1499 (iter != NULL) && (*unique == B_TRUE) && (error == 0); 1500 iter = iter->next) { 1501 if (dlist_contains(used_hbas, 1502 iter->obj, compare_descriptor_names) == B_TRUE) { 1503 *unique = B_FALSE; 1504 } 1505 } 1506 1507 dlist_free_items(hbas, NULL); 1508 1509 return (error); 1510 } 1511 1512 /* 1513 * FUNCTION: slice_on_unique_disk(dm_descriptor_t slice, 1514 * dlist_t *used, dlist_t *used_disks, 1515 * boolean_t *unique) 1516 * 1517 * INPUT: slice - a dm_descriptor_t handle for the slice of interest 1518 * used - a dlist_t pointer to a list of used slices 1519 * othervols - a dlist_t pointer to a list of other volumes 1520 * bool - a boolean_t pointer to hold the result 1521 * 1522 * RETURNS: int - 0 on success 1523 * !0 otherwise 1524 * 1525 * PURPOSE: Determines if the input slice is on a drive that is not 1526 * part of any volume in the othervols list, or on the same 1527 * drive as any slice in the used list. 1528 * 1529 * If the slice is found to be on a unique disk, bool is set 1530 * to B_TRUE, B_FALSE otherwise. 1531 */ 1532 static int 1533 slice_on_unique_disk( 1534 dm_descriptor_t slice, 1535 dlist_t *used, 1536 dlist_t *used_disks, 1537 boolean_t *unique) 1538 { 1539 dm_descriptor_t disk = NULL; 1540 dlist_t *iter = NULL; 1541 int error = 0; 1542 1543 *unique = B_TRUE; 1544 1545 if ((error = slice_get_disk(slice, &disk)) != 0) { 1546 return (error); 1547 } 1548 1549 /* 1550 * check to see if this disk is the same as the 1551 * disk for any of the used 1552 */ 1553 for (iter = used; 1554 (iter != NULL) && (*unique == B_TRUE) && (error == 0); 1555 iter = iter->next) { 1556 1557 devconfig_t *dev = (devconfig_t *)iter->obj; 1558 1559 if (devconfig_isA(dev, TYPE_SLICE)) { 1560 1561 /* get disk for otherslice */ 1562 dm_descriptor_t odisk = NULL; 1563 char *oname = NULL; 1564 1565 ((error = devconfig_get_name(dev, &oname)) != 0) || 1566 (error = get_disk_for_named_slice(oname, &odisk)); 1567 1568 if ((error == 0) && 1569 (compare_descriptor_names((void*)(uintptr_t)disk, 1570 (void*)(uintptr_t)odisk) == 0)) { 1571 /* origslice is on same disk, stop */ 1572 *unique = B_FALSE; 1573 } 1574 } 1575 } 1576 1577 /* check disk against the used disks */ 1578 if ((error == 0) && (*unique == B_TRUE) && 1579 dlist_contains(used_disks, (void *)(uintptr_t)disk, 1580 compare_descriptor_names) == B_TRUE) { 1581 *unique = B_FALSE; 1582 } 1583 1584 return (error); 1585 } 1586 1587 /* 1588 * FUNCTION: slice_has_same_disk_geom(dm_descriptor_t slice, 1589 * dlist_t *used, boolean_t *has_same_geom) 1590 * 1591 * INPUT: slice - a dm_descriptor_t handle for the slice of interest 1592 * used - a dlist_t pointer to a list of used slices 1593 * bool - a boolean_t pointer to hold the result 1594 * 1595 * RETURNS: int - 0 on success 1596 * !0 otherwise 1597 * 1598 * PURPOSE: Determines if the input slice is on a drive with similar 1599 * hardware geometry as the slices in the used list. 1600 * 1601 * If the slice is found to be on a disk with similar geometry, 1602 * bool is set to B_TRUE, B_FALSE otherwise. 1603 * 1604 * The comparison is based on the available disk geometry 1605 * information which may not be relevant or accurate for 1606 * EFI labeled disks, so the disk drive type needs to be 1607 * checked as well. 1608 */ 1609 static int 1610 slice_has_same_disk_geom( 1611 dm_descriptor_t slice, 1612 dlist_t *used, 1613 boolean_t *has_same_geom) 1614 { 1615 dm_descriptor_t disk = NULL; 1616 boolean_t efi = B_FALSE; 1617 uint64_t bsize = 0; 1618 uint64_t ncyls = 0; 1619 uint64_t nsects = 0; 1620 uint64_t nheads = 0; 1621 dlist_t *iter = NULL; 1622 int error = 0; 1623 1624 *has_same_geom = B_TRUE; 1625 1626 ((error = slice_get_disk(slice, &disk)) != 0) || 1627 (error = disk_get_is_efi(disk, &efi)) || 1628 (error = disk_get_blocksize(disk, &bsize)); 1629 1630 if ((error == 0) && (efi == B_FALSE)) { 1631 ((error = disk_get_ncylinders(disk, &ncyls)) != 0) || 1632 (error = disk_get_nheads(disk, &nheads)) || 1633 (error = disk_get_nsectors(disk, &nsects)); 1634 } 1635 1636 if (error != 0) { 1637 return (error); 1638 } 1639 1640 /* 1641 * check to see if slice's disk has the same geometry 1642 * as the disks for the slices in the used list 1643 */ 1644 for (iter = used; 1645 (iter != NULL) && (*has_same_geom == B_TRUE) && (error = 0); 1646 iter = iter->next) { 1647 1648 devconfig_t *dev = (devconfig_t *)iter->obj; 1649 1650 if (devconfig_isA(dev, TYPE_SLICE)) { 1651 1652 /* get disk info for otherslice */ 1653 dm_descriptor_t odisk = NULL; 1654 char *oname = NULL; 1655 boolean_t oefi = B_FALSE; 1656 uint64_t obsize = 0; 1657 uint64_t oncyls = 0; 1658 uint64_t onsects = 0; 1659 uint64_t onheads = 0; 1660 1661 ((error = devconfig_get_name(dev, &oname)) != 0) || 1662 (error = get_disk_for_named_slice(oname, &odisk)) || 1663 (error = disk_get_is_efi(odisk, &oefi)) || 1664 (error = disk_get_blocksize(odisk, &obsize)); 1665 1666 if ((error == 0) && (oefi == B_FALSE)) { 1667 ((error = disk_get_ncylinders(odisk, &oncyls)) != 0) || 1668 (error = disk_get_nheads(odisk, &onheads)) || 1669 (error = disk_get_nsectors(odisk, &onsects)); 1670 } 1671 1672 if (error == 0) { 1673 if ((bsize != obsize) || (ncyls != oncyls) || 1674 (nsects != onsects) || (nheads != onheads)) { 1675 /* this disk has a different geometry */ 1676 *has_same_geom = B_FALSE; 1677 } 1678 } 1679 } 1680 } 1681 1682 return (error); 1683 } 1684 1685 /* 1686 * FUNCTION: slice_on_similar_bus(dm_descriptor_t slice, 1687 * dlist_t *used, boolean_t *on_smlr_bus) 1688 * 1689 * INPUT: slice - a dm_descriptor_t handle for the slice of interest 1690 * used - a dlist_t pointer to a list of used slices 1691 * bool - a boolean_t pointer to hold the result 1692 * 1693 * RETURNS: int - 0 on success 1694 * !0 otherwise 1695 * 1696 * PURPOSE: Determines if the input slice is connected thru a bus with 1697 * characteristics similar to the slices in the used list. 1698 * 1699 * If the slice is found to be on a similar bus, bool is set 1700 * to B_TRUE, B_FALSE otherwise. 1701 * 1702 * The comparison is actually between any of the HBA/controllers 1703 * thru which the slices are connected to the system. 1704 * If any are of similar type (e.g., fibre, SCSI) and 1705 * protocol (SCSI-2, -3, fast/wide), then the slices are 1706 * considered to be on similar busses. 1707 */ 1708 static int 1709 slice_on_similar_bus( 1710 dm_descriptor_t slice, 1711 dlist_t *used, 1712 boolean_t *on_smlr_bus) 1713 { 1714 dlist_t *iter = NULL; 1715 dlist_t *iter1 = NULL; 1716 dlist_t *hbas = NULL; 1717 int error = 0; 1718 1719 /* if there are no used slices, then the bus is similar */ 1720 *on_smlr_bus = B_TRUE; 1721 if (dlist_length(used) == 0) { 1722 return (0); 1723 } 1724 1725 (error = slice_get_hbas(slice, &hbas)); 1726 if (error != 0) { 1727 return (error); 1728 } 1729 1730 /* if there are used slices, then make sure the bus is similar */ 1731 *on_smlr_bus = B_FALSE; 1732 for (iter = hbas; 1733 (iter != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0); 1734 iter = iter->next) { 1735 1736 dm_descriptor_t hba = (uintptr_t)iter->obj; 1737 char *type = NULL; 1738 boolean_t fast80 = B_FALSE; 1739 boolean_t fast40 = B_FALSE; 1740 boolean_t fast20 = B_FALSE; 1741 boolean_t wide = B_FALSE; 1742 1743 ((error = hba_get_type(hba, &type)) != 0) || 1744 (error = hba_is_fast_80(hba, &fast80)) || 1745 (error = hba_is_fast_40(hba, &fast40)) || 1746 (error = hba_is_fast_20(hba, &fast20)) || 1747 (error = hba_supports_wide(hba, &wide)); 1748 if (error != 0) { 1749 continue; 1750 } 1751 1752 /* check against the HBAs for the used slices */ 1753 for (iter1 = used; 1754 (iter1 != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0); 1755 iter1 = iter1->next) { 1756 1757 devconfig_t *used = (devconfig_t *)iter1->obj; 1758 1759 /* get HBAs for otherslice */ 1760 dm_descriptor_t udisk = NULL; 1761 char *uname = NULL; 1762 dlist_t *uhbas = NULL; 1763 dlist_t *iter2 = NULL; 1764 1765 ((error = devconfig_get_name(used, &uname)) != 0) || 1766 (error = get_disk_for_named_slice(uname, &udisk)) || 1767 (error = disk_get_hbas(udisk, &uhbas)); 1768 1769 for (iter2 = uhbas; 1770 (iter2 != NULL) && (*on_smlr_bus == B_FALSE) && 1771 (error == 0); 1772 iter2 = iter2 ->next) { 1773 1774 dm_descriptor_t uhba = (uintptr_t)iter2->obj; 1775 char *utype = NULL; 1776 boolean_t ufast80 = B_FALSE; 1777 boolean_t ufast40 = B_FALSE; 1778 boolean_t ufast20 = B_FALSE; 1779 boolean_t uwide = B_FALSE; 1780 1781 ((error = hba_get_type(uhba, &utype)) != 0) || 1782 (error = hba_is_fast_80(uhba, &ufast80)) || 1783 (error = hba_is_fast_40(uhba, &ufast40)) || 1784 (error = hba_is_fast_20(uhba, &ufast20)) || 1785 (error = hba_supports_wide(uhba, &uwide)); 1786 1787 if (error == 0) { 1788 /* check sync speed ? */ 1789 if ((fast80 == ufast80) && (fast40 == ufast40) && 1790 (fast20 == ufast20) && (wide == uwide) && 1791 (type == utype)) { 1792 *on_smlr_bus = B_TRUE; 1793 } 1794 } 1795 } 1796 dlist_free_items(uhbas, NULL); 1797 } 1798 } 1799 1800 dlist_free_items(hbas, NULL); 1801 1802 return (error); 1803 } 1804 1805 /* 1806 * FUNCTION: slice_has_n_paths(dm_descriptor_t slice, 1807 * uint16_t npaths, boolean_t *has_n_paths) 1808 * INPUT: slice - a dm_descriptor_t handle for the slice of interest 1809 * npaths - the number of paths desired 1810 * has_n_paths - a boolean_t pointer to hold the result 1811 * 1812 * RETURNS: int - 0 on success 1813 * !0 otherwise 1814 * 1815 * PURPOSE: Determines if the input slice is connected via npaths. 1816 * has_n_paths is set to B_TRUE if so, B_FALSE otherwise. 1817 * 1818 * In order for a disk to have multiple paths, MPXIO must 1819 * be enabled and these conditions should hold: 1820 * 1821 * Slice will have one drive object. 1822 * Drive will have one HBA (scsi_vhci) 1823 * Drive will have one alias. 1824 * Drive will have possibly > 1 paths. 1825 * 1826 * Getting the HBAs and aliases for the disk is relatively 1827 * expensive, so they aren't checked. The actual number of 1828 * paths is only checked if MPXIO is known to be enabled on 1829 * the system and the input npaths is > 1. 1830 */ 1831 static int 1832 slice_has_n_paths( 1833 dm_descriptor_t slice, 1834 uint16_t npaths, 1835 boolean_t *has_n_paths) 1836 { 1837 int error = 0; 1838 1839 *has_n_paths = B_FALSE; 1840 1841 if ((npaths > 1) && (is_mpxio_enabled() == B_TRUE)) { 1842 1843 dm_descriptor_t disk = NULL; 1844 dlist_t *paths = NULL; 1845 1846 ((error = slice_get_disk(slice, &disk)) != 0) || 1847 (error = disk_get_paths(disk, &paths)); 1848 1849 if ((error == 0) && (dlist_length(paths) == npaths)) { 1850 *has_n_paths = B_TRUE; 1851 } 1852 dlist_free_items(paths, NULL); 1853 } 1854 1855 return (error); 1856 } 1857 1858 /* 1859 * FUNCTION: compare_string_to_modslice_name(void *str, void *modslice) 1860 * 1861 * INPUT: str - opaque char * pointer 1862 * modslice - opaque modslice_t pointer 1863 * 1864 * RETURNS: int - <0 - if str < modslice->slice_devcfg.name 1865 * 0 - if str == modslice->slice_devcfg.name 1866 * >0 - if str > modslice->slice_devcfg.name 1867 * 1868 * PURPOSE: dlist_t helper which compares the input string to 1869 * the name of a slice represented as modslice_t struct. 1870 * 1871 * Comparison is done via string_case_compare. 1872 */ 1873 static int 1874 compare_string_to_modslice_name( 1875 void *str, 1876 void *modslice) 1877 { 1878 char *name = NULL; 1879 1880 assert(str != NULL); 1881 assert(modslice != NULL); 1882 1883 (void) devconfig_get_name( 1884 ((modslice_t *)modslice)->slice_devcfg, &name); 1885 1886 return (string_case_compare((char *)str, name)); 1887 } 1888 1889 /* 1890 * FUNCTION: compare_modslice_names(void *obj1, void *obj2) 1891 * 1892 * INPUT: obj1 - opaque pointer 1893 * obj2 - opaque pointer 1894 * 1895 * RETURNS: int - <0 - if obj1 name < obj2 name 1896 * 0 - if obj1 name == obj2 name 1897 * >0 - if obj1 name > obj2 name 1898 * 1899 * PURPOSE: dlist_t helper which compares the names of two slices 1900 * represented as modslice_t structs. 1901 * 1902 * Comparison is done by string_case_compare 1903 */ 1904 static int 1905 compare_modslice_names( 1906 void *obj1, 1907 void *obj2) 1908 { 1909 char *name1 = NULL; 1910 char *name2 = NULL; 1911 1912 assert(obj1 != NULL); 1913 assert(obj2 != NULL); 1914 1915 (void) devconfig_get_name( 1916 ((modslice_t *)obj1)->slice_devcfg, &name1); 1917 (void) devconfig_get_name( 1918 ((modslice_t *)obj2)->slice_devcfg, &name2); 1919 1920 return (string_case_compare(name1, name2)); 1921 } 1922 1923 /* 1924 * FUNCTION: release_used_slices() 1925 * 1926 * PURPOSE: Helper which cleans up the module private list of used 1927 * slices. 1928 */ 1929 void 1930 release_used_slices() 1931 { 1932 dlist_free_items(_used_slices, free_used_slice); 1933 _used_slices = NULL; 1934 } 1935 1936 static void 1937 free_used_slice( 1938 void *obj) 1939 { 1940 if (obj != NULL) { 1941 usedslice_t *used = (usedslice_t *)obj; 1942 free(used->slicename); 1943 free(used); 1944 } 1945 } 1946 1947 /* 1948 * FUNCTION: is_used_slice(dm_descriptor_t slice, boolean_t *is_used) 1949 * 1950 * INPUT: slice - a dm_descriptor_t slice handle 1951 * 1952 * OUTPUT: is_reserved - pointer to a boolean_t to hold the 1953 * return result. 1954 * 1955 * PURPOSE: Helper which checks to see if the input slice 1956 * is in the used_slice list. 1957 * 1958 * Check the input name against any used slice name or alias. 1959 * is_used is set to B_TRUE if the input slice is already used, 1960 * B_FALSE otherwise. 1961 */ 1962 int 1963 is_used_slice( 1964 dm_descriptor_t slice, 1965 boolean_t *is_used) 1966 { 1967 char *name; 1968 int error = 0; 1969 1970 if ((error = get_display_name(slice, &name)) == 0) { 1971 *is_used = dlist_contains(_used_slices, (void *)name, 1972 compare_usedslice_name_to_string); 1973 } 1974 1975 return (error); 1976 } 1977 1978 /* 1979 * FUNCTIONS: add_used_slice(dm_descriptor_t slice) 1980 * add_used_slice_by_name(char *slicename) 1981 * add_used_slice_list_entry(char *slice) 1982 * remove_used_slice_by_name(char *slicename) 1983 * 1984 * INPUT: diskset - a char * diskset name. 1985 * slice - a dm_descriptor_t slice handle 1986 * 1987 * RETURNS: int - 0 on success 1988 * !0 otherwise 1989 * 1990 * PURPOSE: Access or maintain the list of used slices. 1991 */ 1992 int 1993 add_used_slice( 1994 dm_descriptor_t slice) 1995 { 1996 dm_descriptor_t disk; 1997 char *name; 1998 int error = 0; 1999 2000 assert(slice != (dm_descriptor_t)0); 2001 2002 ((error = get_display_name(slice, &name)) != 0) || 2003 (error = slice_get_disk(slice, &disk)) || 2004 (error = add_used_slice_list_entry(name, disk)); 2005 2006 return (error); 2007 } 2008 2009 int 2010 add_used_slice_by_name( 2011 char *slicename) 2012 { 2013 dm_descriptor_t disk = (dm_descriptor_t)0; 2014 int error = 0; 2015 2016 assert(slicename != NULL); 2017 2018 /* find disk for slice */ 2019 error = get_disk_for_named_slice(slicename, &disk); 2020 if (error == 0) { 2021 error = add_used_slice_list_entry(slicename, disk); 2022 } 2023 2024 return (error); 2025 } 2026 2027 static int 2028 add_used_slice_list_entry( 2029 char *slicename, 2030 dm_descriptor_t disk) 2031 { 2032 usedslice_t *used = NULL; 2033 int error = 0; 2034 2035 assert(slicename != NULL); 2036 assert(disk != (dm_descriptor_t)0); 2037 2038 used = (usedslice_t *)calloc(1, sizeof (usedslice_t)); 2039 if (used == NULL) { 2040 error = ENOMEM; 2041 } else { 2042 2043 used->disk = disk; 2044 if ((used->slicename = strdup(slicename)) == NULL) { 2045 free(used); 2046 error = ENOMEM; 2047 } else { 2048 dlist_t *item = dlist_new_item((void *) used); 2049 if (item == NULL) { 2050 free(used->slicename); 2051 free(used); 2052 error = ENOMEM; 2053 } else { 2054 _used_slices = 2055 dlist_append(item, _used_slices, AT_HEAD); 2056 } 2057 } 2058 } 2059 return (error); 2060 } 2061 2062 int 2063 remove_used_slice_by_name( 2064 char *slice) 2065 { 2066 dlist_t *removed = NULL; 2067 2068 _used_slices = 2069 dlist_remove_equivalent_item(_used_slices, (void *)slice, 2070 compare_usedslice_name_to_string, &removed); 2071 2072 if (removed != NULL) { 2073 free_used_slice(removed->obj); 2074 removed->obj = NULL; 2075 free(removed); 2076 } 2077 2078 return (0); 2079 } 2080 2081 /* 2082 * FUNCTION: compare_usedslice_name_to_string(void *obj1, void *obj2) 2083 * INPUT: obj1 - opaque pointer 2084 * obj2 - opaque pointer 2085 * 2086 * RETURNS: int - <0 - if obj1 name < obj2 name 2087 * 0 - if obj1 name == obj2 name 2088 * >0 - if obj1 name > obj2 name 2089 * 2090 * PURPOSE: dlist_t helper which compares the names of a slice 2091 * represented as modslice_t struct to a string. 2092 * 2093 * obj1 is assumed to be a char * 2094 * obj2 is assumed to be a usedslice_t * 2095 * 2096 * Comparison is done via string_case_compare. 2097 */ 2098 static int 2099 compare_usedslice_name_to_string( 2100 void *obj1, 2101 void *obj2) 2102 { 2103 assert(obj1 != NULL); 2104 assert(obj2 != NULL); 2105 2106 return (string_case_compare((char *)obj1, 2107 ((usedslice_t *)obj2)->slicename)); 2108 } 2109 2110 /* 2111 * FUNCTION: disk_has_used_slice(dm_descriptor_t disk, boolean_t *hasused) 2112 * 2113 * INPUT: disk - a dm_descriptor_t disk handle. 2114 * inuse - a boolean_t pointer to hold the result 2115 * 2116 * RETURNS: int - 0 on success 2117 * !0 othersize. 2118 * 2119 * PURPOSE: Determines if any of the known used slices is on the 2120 * input disk. 2121 */ 2122 int 2123 disk_has_used_slice( 2124 dm_descriptor_t disk, 2125 boolean_t *hasused) 2126 { 2127 dlist_t *iter; 2128 int error = 0; 2129 2130 *hasused = B_FALSE; 2131 for (iter = _used_slices; 2132 (iter != NULL) && (*hasused == B_FALSE); 2133 iter = iter->next) { 2134 2135 usedslice_t *used = (usedslice_t *)iter->obj; 2136 2137 /* compare used slice's disk to disk */ 2138 if (compare_descriptors((void *)(uintptr_t)disk, 2139 (void *)(uintptr_t)used->disk) == 0) { 2140 *hasused = B_TRUE; 2141 } 2142 } 2143 2144 return (error); 2145 } 2146 2147 /* 2148 * FUNCTION: add_reserved_slice(dm_descriptor_t slice) 2149 * 2150 * INPUT: slice - a dm_descriptor_t slice handle 2151 * 2152 * RETURNS: int - 0 on success 2153 * !0 otherwise. 2154 * 2155 * PURPOSE: Helper which remembers specfically requested slices 2156 * in a private list to ensure that the same slice isn't 2157 * requested more than once. 2158 * 2159 * Does not check to see if the slice already exists 2160 * in the list of reserved slices. Assumes that the 2161 * caller has checked using is_reserved_slice(). 2162 * 2163 * The reserved slice list is used by several functions: 2164 * 2165 * 1. layout_validate.validate_slice_components() adds user 2166 * requested slices to the list. 2167 * 2168 * 2. After all potentially usable slices have been scanned, 2169 * layout_validate.validate_reserved_slices() checks the 2170 * slices in the reserved and ensures that each slice is 2171 * actually usable as a volume component. 2172 * 2173 * 3. layout.disk_get_avail_space(), layout.disk_get_avail_slices() 2174 * exclude slices in the reserved list from being considered 2175 * available for general layout use. 2176 */ 2177 int 2178 add_reserved_slice( 2179 dm_descriptor_t slice) 2180 { 2181 dlist_t *item = NULL; 2182 2183 if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) { 2184 return (ENOMEM); 2185 } 2186 2187 _rsvd_slices = dlist_append(item, _rsvd_slices, AT_HEAD); 2188 2189 return (0); 2190 } 2191 2192 /* 2193 * FUNCTION: is_reserved_slice(dm_descriptor_t slice, 2194 * boolean_t *is_reserved) 2195 * 2196 * INPUT: slice - a dm_descriptor_t slice handle 2197 * 2198 * OUTPUT: is_reserved - pointer to a boolean_t to hold the 2199 * return result. 2200 * 2201 * PURPOSE: Helper which checks to see if the input slice 2202 * was previously reserved. 2203 * 2204 * Check the input name against any reserved slice 2205 * name or alias. is_reserved is set to B_TRUE if the 2206 * input slice is already reserved, B_FALSE otherwise. 2207 */ 2208 int 2209 is_reserved_slice( 2210 dm_descriptor_t slice, 2211 boolean_t *is_reserved) 2212 { 2213 *is_reserved = dlist_contains(_rsvd_slices, 2214 (void *)(uintptr_t)slice, compare_descriptor_names); 2215 2216 return (0); 2217 } 2218 2219 /* 2220 * FUNCTION: release_reserved_slice() 2221 * 2222 * PURPOSE: Helper which cleans up the module private list of reserved 2223 * slices. 2224 */ 2225 void 2226 release_reserved_slices() 2227 { 2228 dlist_free_items(_rsvd_slices, free); 2229 _rsvd_slices = NULL; 2230 } 2231 2232 /* 2233 * FUNCTION: get_reserved_slices(dlist_t **list) 2234 * 2235 * OUTPUT: list - a dlist_t pointer to hold the returned list of 2236 * reserverd slices. 2237 * 2238 * RETURNS: int - 0 on success 2239 * !0 otherwise 2240 * 2241 * PURPOSE: Accessor to retrieve the current list of reserved slice 2242 * dm_descriptor_t handles. 2243 */ 2244 int 2245 get_reserved_slices( 2246 dlist_t **list) 2247 { 2248 *list = _rsvd_slices; 2249 2250 return (0); 2251 } 2252 2253 /* 2254 * FUNCTION: add_slice_to_remove(char *name, uint32_t index) 2255 * 2256 * INPUT: name - name of a slice 2257 * index - index for the slice 2258 * 2259 * RETURNS: int - 0 on success 2260 * !0 otherwise 2261 * 2262 * PURPOSE: Utility function to add the named slice to the list of 2263 * those that need to be "removed" by having their sizes 2264 * set to 0. 2265 */ 2266 int 2267 add_slice_to_remove( 2268 char *name, 2269 uint32_t index) 2270 { 2271 rmvdslice_t *rmvd = NULL; 2272 int error = 0; 2273 2274 assert(name != NULL); 2275 2276 rmvd = (rmvdslice_t *)calloc(1, sizeof (rmvdslice_t)); 2277 if (rmvd == NULL) { 2278 error = ENOMEM; 2279 } else { 2280 rmvd->slice_index = index; 2281 if ((rmvd->slice_name = strdup(name)) == NULL) { 2282 free(rmvd); 2283 error = ENOMEM; 2284 } else { 2285 dlist_t *item = dlist_new_item((void *) rmvd); 2286 if (item == NULL) { 2287 free(rmvd->slice_name); 2288 free(rmvd); 2289 error = ENOMEM; 2290 } else { 2291 _rmvd_slices = 2292 dlist_append(item, _rmvd_slices, AT_HEAD); 2293 } 2294 } 2295 } 2296 return (error); 2297 } 2298 2299 /* 2300 * FUNCTION: get_removed_slices() 2301 * 2302 * RETURNS: dlist_t * - pointer to a list of rmvdslice_t structs 2303 * 2304 * PURPOSE: Accessor to retrieve the current list of names of slices 2305 * to be removed. 2306 */ 2307 dlist_t * 2308 get_slices_to_remove( 2309 dlist_t **list) 2310 { 2311 return (_rmvd_slices); 2312 } 2313 2314 static void 2315 free_rmvd_slice( 2316 void *obj) 2317 { 2318 if (obj != NULL) { 2319 rmvdslice_t *rmvd = (rmvdslice_t *)obj; 2320 free(rmvd->slice_name); 2321 free(rmvd); 2322 } 2323 } 2324 2325 /* 2326 * FUNCTION: release_removed_slices() 2327 * 2328 * PURPOSE: Helper which cleans up the module private list of removed 2329 * slices. 2330 */ 2331 void 2332 release_slices_to_remove() 2333 { 2334 dlist_free_items(_rmvd_slices, free_rmvd_slice); 2335 _rmvd_slices = NULL; 2336 } 2337