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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/param.h>
32 #include "volume_string.h"
34 #include "volume_devconfig.h"
35 #include "volume_error.h"
36 #include "volume_dlist.h"
37 #include "volume_output.h"
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"
47 #define _LAYOUT_SLICE_C
49 static int pick_from_best_hba_and_disk(
52 dm_descriptor_t
*chosen
);
54 static int slice_has_same_disk_geom(
55 dm_descriptor_t slice
,
59 static int slice_on_unique_disk(
60 dm_descriptor_t slice
,
65 static int slice_on_unique_hba(
66 dm_descriptor_t slice
,
71 static int slice_on_similar_bus(
72 dm_descriptor_t slice
,
76 static int slice_has_n_paths(
77 dm_descriptor_t slice
,
81 static int compare_modslice_names(
85 static int compare_string_to_modslice_name(
89 static int create_new_slice(
90 dm_descriptor_t oslice
,
92 boolean_t add_extra_cyl
,
93 devconfig_t
**nslice
);
95 static int create_modified_slice(
96 dm_descriptor_t oslice
,
105 devconfig_t
**nslice
);
108 * list to track resized slices
110 static dlist_t
*_modified_slices
= NULL
;
113 * struct to track used slices and their disks...
117 dm_descriptor_t disk
;
121 * list to of usedslice_t to track slices that have been
122 * used for any reason.
124 static dlist_t
*_used_slices
= NULL
;
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
);
131 * list of slices reserved to be used for explicit
134 static dlist_t
*_rsvd_slices
= NULL
;
137 * list of slices needing to be removed (zeroed out) prior to
138 * applying any metassist modifications to the system.
140 static dlist_t
*_rmvd_slices
= NULL
;
143 * FUNCTION: choose_slice(
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)
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
165 * nbytes_is_min - if true, the chosen slice may be larger than
167 * add_extra_cyl - passed to create_new_slice, see comment there.
168 * **chosen - pointer to hold the chosen slice
170 * RETURNS: int - 0 on success
173 * PURPOSE: Choosen a slice from the list of those available.
175 * Of those available, choose in order of preference:
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
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
196 * If nbytes_is_min is true, the returned slice will be
197 * at least nbytes in capacity.
199 * If unused_disk is true, the returned slice will be from
200 * a disk with no other known uses.
210 boolean_t unused_disk
,
211 boolean_t nbytes_is_min
,
212 boolean_t add_extra_cyl
,
213 devconfig_t
**chosen
)
215 dlist_t
*iter
= NULL
;
217 dm_descriptor_t slice
= NULL
;
218 boolean_t resize
= B_FALSE
;
219 boolean_t verbose
= (get_max_verbosity() == OUTPUT_VERBOSE
);
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
232 dlist_t
*list
[2][2][2][2][3];
234 /* output string arrays for each array dimension and index */
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
;
255 if (verbose
== B_TRUE
) {
256 /* only initialize the output strings if needed */
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");
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");
280 "\t rejected: too small\n");
281 useddisk_msg
= gettext(
282 "\t rejected: on a disk with other volume component(s)\n");
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");
299 /* init list array pointers */
300 (void) memset(list
, 0, 2*2*2*2*3 * sizeof (dlist_t
*));
303 (iter
!= NULL
) && (error
== 0); iter
= iter
->next
) {
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
;
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
,
319 (error
= slice_on_similar_bus(slice
, used
, &samebus
)) ||
320 (error
= slice_has_same_disk_geom(slice
, used
, &samegeom
));
325 if (verbose
== B_TRUE
) {
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
);
337 if (paths
&& verbose
) {
338 /* specifically asked for more paths, ... */
339 oprintf(OUTPUT_VERBOSE
, npaths_msg
);
341 } else if (npaths
== 1) {
342 /* every disk has at least 1 path */
346 if (verbose
== B_TRUE
) {
348 oprintf(OUTPUT_VERBOSE
, uniqhba_msg
);
351 oprintf(OUTPUT_VERBOSE
, uniqdisk_msg
);
356 oprintf(OUTPUT_VERBOSE
, samebus_msg
);
359 oprintf(OUTPUT_VERBOSE
, samegeom_msg
);
363 if (snbytes
> nbytes
) {
364 oprintf(OUTPUT_VERBOSE
, larger_msg
);
365 } else if (snbytes
== nbytes
) {
366 oprintf(OUTPUT_VERBOSE
, exact_msg
);
368 oprintf(OUTPUT_VERBOSE
, smaller_msg
);
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
);
381 if (paths
== B_FALSE
) {
382 /* not connected thru enough paths */
383 if (verbose
== B_TRUE
) {
384 oprintf(OUTPUT_VERBOSE
, insuff_paths
, npaths
);
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
);
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));
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)
409 if ((item
= dlist_new_item((void*)(uintptr_t)slice
)) == NULL
) {
412 list
[i
][j
][k
][l
][m
] =
413 dlist_insert_ordered(
416 (m
== 1 ? ASCENDING
: DESCENDING
),
417 compare_slice_sizes
);
422 * Select a slice from one of the lists.
424 * The list with the combination of lowest indices
425 * is the most preferred list... in rough order:
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
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
) {
448 /* pick least used slice from this list */
449 error
= pick_from_best_hba_and_disk(
455 /* terminate all loops */
466 * Slice chosen, is a resize necessary?
468 if ((error
== 0) && (slice
!= NULL
)) {
471 if (verbose
== B_TRUE
) {
472 uint64_t snbytes
= 0;
474 char *sizestr
= NULL
;
476 (void) get_display_name(slice
, &sname
);
477 (void) slice_get_size(slice
, &snbytes
);
479 if (bytes_to_sizestr(snbytes
, &sizestr
,
480 universal_units
, B_FALSE
) == 0) {
481 oprintf(OUTPUT_VERBOSE
,
482 gettext(" selected %s (%s)\n"
488 uniqhba
[i
], samebus
[j
],
489 uniqdisk
[k
], samegeom
[l
]);
495 if (verbose
== B_TRUE
) {
496 oprintf(OUTPUT_VERBOSE
,
497 gettext(" it has excess space, "
501 error
= create_new_slice(slice
, nbytes
, add_extra_cyl
,
503 if ((error
== 0) && (*chosen
!= NULL
) && verbose
) {
504 oprintf(OUTPUT_VERBOSE
,
505 gettext(" exactly resized\n"));
510 /* either no resize was necessary or the resize failed */
511 if (*chosen
== NULL
) {
513 * use the original slice as it is.
514 * Make a devconfig_t for it.
516 error
= create_devconfig_for_slice(slice
, chosen
);
520 } else if (slice
== NULL
) {
521 oprintf(OUTPUT_DEBUG
,
522 gettext(" no possible slice\n"));
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
);
543 * FUNCTION: create_devconfig_for_slice(dm_descriptor_t slice,
544 * devconfig_t **nslice)
546 * INPUT: slice - dm_descriptor_t handle to an existing slice
547 * nslice - devconfig_t pointer to hold the new slice
549 * RETURNS: int - 0 on success
552 * PURPOSE: Creates a devconfig_t struct representation of the input
553 * slice dm_descriptor.
556 create_devconfig_for_slice(
557 dm_descriptor_t slice
,
558 devconfig_t
**nslice
)
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
));
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
));
583 free_devconfig(*nslice
);
590 * FUNCTION: make_slicename_for_disk_and_index(dm_descriptor_t disk,
591 * uint32_t index, char **slicename)
593 * INPUT: disk - a dm_descriptor_t disk handle
594 * index - a slice index
596 * OUTPUT slicename - a char * pointer to hold the resulting slicename
598 * RETURNS: int - 0 on success
601 * PURPOSE: Utility function to manufacture a new slice name given the
602 * "parent" disk and an available slice index.
604 * The caller should free the returned name when done with it.
607 make_slicename_for_disk_and_index(
608 dm_descriptor_t disk
,
615 if ((error
= get_display_name(disk
, &dname
)) == 0) {
616 error
= make_slicename_for_diskname_and_index(dname
,
624 * FUNCTION: make_slicename_for_diskname_and_index(char *diskname,
625 * uint32_t index, char **slicename)
627 * INPUT: diskname - a char * disk name
628 * index - a slice index
630 * OUTPUT slicename - a char * pointer to hold the resulting slicename
632 * RETURNS: int - 0 on success
635 * PURPOSE: Utility function to manufacture a new slice name given the
636 * name of a disk and an available slice index.
638 * The caller should free the returned name when done with it.
641 make_slicename_for_diskname_and_index(
647 char buf
[MAXNAMELEN
+1];
649 (void) snprintf(buf
, sizeof (buf
), "%ss%u", diskname
, index
);
650 if ((*slicename
= strdup(buf
)) == NULL
) {
659 * FUNCTION: create_new_slice(dm_descriptor_t oslice, uint64_t nbytes,
660 * boolean_t add_extra_cyl, devconfig_t **nslice)
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
669 * RETURNS: int - 0 on success
672 * PURPOSE: Creates a new slice object using space from the input slice.
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.
678 * If there is no open slice slot, the original slice will be
679 * returned as the usable new slice.
681 * The new slice will be of at least 'nbytes' bytes and possibly
682 * larger due to sector and cylinder boundary alignment.
684 * For EFI labeled disks, nbytes is rounded up to the next block
687 * For VTOC labeled disks, nbytes is rounded up to the next
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.
702 * If the resize is successful a pointer to the devconfig_t
703 * representing the new slice will be returned in "newslice".
705 * If the resize cannot be done, the newslice pointer will
710 dm_descriptor_t oslice
,
712 boolean_t add_extra_cyl
,
713 devconfig_t
**nslice
)
715 dm_descriptor_t odisk
= NULL
;
716 boolean_t efi
= B_FALSE
;
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;
726 uint32_t nindex
= oindex
;
732 ((error
= slice_get_disk(oslice
, &odisk
)) != 0) ||
733 (error
= slice_get_index(oslice
, &oindex
));
738 /* find an unused slice number, default to oindex */
740 if ((error
= disk_get_available_slice_index(odisk
, &nindex
)) != 0) {
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
));
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
);
760 oprintf(OUTPUT_DEBUG
,
762 "rounded up to %10.2f blocks\n"),
763 (double)(nsize
/bytes_per_sect
));
767 /* VTOC: round size to an integral number of cylinders */
772 ((error
= disk_get_ncylinders(odisk
, &ncyls
)) != 0) ||
773 (error
= disk_get_nheads(odisk
, &nhead
)) ||
774 (error
= disk_get_nsectors(odisk
, &nsect
));
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
);
780 if (add_extra_cyl
== TRUE
) {
781 nsize
+= bytes_per_cyl
;
784 oprintf(OUTPUT_DEBUG
,
786 "rounded VTOC slice to %10.2f cylinders "
788 (double)(nsize
/bytes_per_cyl
), ncyls
);
792 /* is sufficient space still available? */
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
) {
800 if (nindex
== oindex
) {
801 /* no more slices, resize existing slice */
802 ((error
= create_devconfig_for_slice(oslice
,
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
));
810 /* make a new slice */
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
,
818 /* mark the new slice's index as used */
819 (error
= disk_reserve_index(odisk
, (uint16_t)nindex
));
821 if ((error
!= 0) && (*nslice
== NULL
)) {
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)
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)
847 * SIDEEFFECTS: updates the module private list of modified slices
849 * OUTPUT: nslice - pointer to a devconfig_t to hold the new slice
851 * PURPOSE: create a new VTOC slice by taking space from an
854 * The input size for the new slice is expected to be
858 create_modified_slice(
859 dm_descriptor_t oslice
,
864 uint64_t bytes_per_sect
,
868 devconfig_t
**nslice
)
872 /* compute start sector and size in sectors for the new slice */
874 /* subtract nsize from original slice to get starting byte */
875 uint64_t nstart
= (ostart
+ osize
) - nsize
;
877 /* convert starting byte to a sector */
878 uint64_t nstblk
= (uint64_t)(nstart
/ bytes_per_sect
);
880 /* convert nsize to an integral number of blocks (sectors) */
881 uint64_t nblks
= (uint64_t)(nsize
/ bytes_per_sect
);
883 /* create a modified slice record for the new slice */
884 error
= assemble_modified_slice(oslice
, nname
, nindex
,
885 nstblk
, nblks
, nsize
, nslice
);
891 /* update the existing source slice's new size */
892 osize
= osize
- nsize
;
893 (void) slice_set_size(oslice
, osize
);
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
),
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)
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
918 * OUTPUT: mod_slice - if non-NULL, will be populated with a
919 * devconfig_t representing the modified slice.
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.
925 * RETURNS: int - 0 on success
928 * PURPOSE: Utility function to which updates or creates a devconfig_t
929 * representing a slice that needs to be modified.
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.
935 * The existing or created devconfig_t struct is updated with
938 * The information about the slices in the modified slice list
939 * will eventually be handed to fmthard.
942 assemble_modified_slice(
943 dm_descriptor_t src_slice
,
949 devconfig_t
**mod_slice
)
951 devconfig_t
*slice
= NULL
;
952 modslice_t
*mstp
= NULL
;
953 dlist_t
*item
= NULL
;
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
) {
960 /* yes, update the resize count and attributes */
961 mstp
= (modslice_t
*)item
->obj
;
962 slice
= mstp
->slice_devcfg
;
964 mstp
->times_modified
+= 1;
965 mstp
->src_slice_desc
= src_slice
;
967 ((error
= devconfig_set_slice_start_block(slice
,
969 (error
= devconfig_set_size(slice
, mod_size
)) ||
970 (error
= devconfig_set_size_in_blocks(slice
, mod_nblks
));
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
));
983 /* add to list of modified slices */
984 if ((mstp
= (modslice_t
*)
985 calloc(1, sizeof (modslice_t
))) != NULL
) {
987 /* count # of times source slice has been modified */
988 if (src_slice
!= (dm_descriptor_t
)0) {
989 mstp
->times_modified
= 0;
991 mstp
->times_modified
= 1;
993 mstp
->src_slice_desc
= src_slice
;
994 mstp
->slice_devcfg
= slice
;
996 if ((item
= dlist_new_item(mstp
)) != NULL
) {
998 dlist_insert_ordered(
1002 compare_modslice_names
);
1012 free_devconfig(mstp
);
1013 free_devconfig(slice
);
1018 oprintf(OUTPUT_DEBUG
,
1020 "modified %s (start blk: %9llu, nblks: %9llu)\n",
1021 mod_name
, mod_stblk
, mod_nblks
);
1023 /* return devconfig_t for modified slice */
1024 if (mod_slice
!= NULL
) {
1026 mstp
->volume_component
= B_TRUE
;
1034 * FUNCTION: dlist_t *get_modified_slices()
1036 * RETURNS: pointer to the list of modslice_t structs representing
1039 * PURPOSE: public accessor to the list of slices modified while
1040 * processing a request.
1043 get_modified_slices()
1045 return (_modified_slices
);
1049 * FUNCTION: free_modslice_object(void *obj)
1051 * INPUT: obj - opaque pointer
1053 * PURPOSE: Frees memory associated with a modslice_t struct.
1056 free_modslice_object(
1059 assert(obj
!= (modslice_t
*)NULL
);
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
);
1071 * FUNCTION: void release_modified_slices()
1076 * PURPOSE: cleanup the module global list of slices modified
1077 * while processing a request.
1080 release_modified_slices()
1082 dlist_free_items(_modified_slices
, free_modslice_object
);
1083 _modified_slices
= NULL
;
1089 * FUNCTION: destroy_new_slice(devconfig_t *dev)
1091 * INPUT: dev - a devconfig_t pointer to a slice object
1093 * RETURNS: int - 0 on success
1096 * PURPOSE: Undoes slice creation done by create_new_slice():
1099 * remove from used_slices
1100 * remove from modified_slices
1101 * return space to source slice
1108 dm_descriptor_t disk
= NULL
;
1111 modslice_t
*modified
= NULL
;
1112 dlist_t
*item
= NULL
;
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
));
1126 /* remove from the modified_slices list */
1128 dlist_remove_equivalent_item(
1129 _modified_slices
, name
,
1130 compare_string_to_modslice_name
, &item
);
1133 modified
= (modslice_t
*)item
->obj
;
1137 /* space from an existing slice? if so reclaim it. */
1138 if (modified
!= NULL
) {
1140 dm_descriptor_t src
= modified
->src_slice_desc
;
1141 char *srcname
= NULL
;
1142 dlist_t
*srcitem
= NULL
;
1144 if (src
!= (dm_descriptor_t
)0) {
1145 if ((error
= get_display_name(src
, &srcname
)) == 0) {
1150 compare_string_to_modslice_name
);
1154 if ((error
== 0) && (srcitem
!= NULL
)) {
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
;
1162 srcdevcfg
= source
->slice_devcfg
;
1163 source
->times_modified
-= 1;
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
));
1174 /* was only modification undone? */
1175 if (source
->times_modified
== 0) {
1178 dlist_remove_equivalent_item(
1179 _modified_slices
, srcname
,
1180 compare_string_to_modslice_name
,
1183 free_modslice_object((modslice_t
*)srcitem
->obj
);
1184 free((void *)srcitem
);
1189 free_modslice_object(modified
);
1196 * FUNCTION: pick_from_best_hba_and_disk(dlist_t *slices,
1197 * dlist_t *used, dm_descriptor_t *chosen)
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
1203 * RETURNS: int - 0 on success
1206 * PURPOSE: Examines the input list of slices and chooses the one
1207 * that is on the least used HBA and disk.
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.
1213 * The HBA which contributes the fewest is selected, and
1214 * then the disk on that HBA which contributes the fewest
1217 * The largest slice from that disk is then returned.
1220 pick_from_best_hba_and_disk(
1223 dm_descriptor_t
*chosen
)
1225 dlist_t
*iter
= NULL
;
1226 dlist_t
*iter1
= NULL
;
1227 dlist_t
*iter2
= NULL
;
1228 dlist_t
*item
= NULL
;
1230 dlist_t
*used_slice_hbas
= NULL
;
1233 int maxslices
= VTOC_SIZE
; /* meta.h */
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
1243 dlist_t
**prefhbas
= (dlist_t
**)calloc(maxuses
, sizeof (dlist_t
*));
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
1250 dlist_t
**prefdisks
= (dlist_t
**)calloc(maxslices
, sizeof (dlist_t
*));
1252 *chosen
= (dm_descriptor_t
)0;
1254 if (prefhbas
== NULL
|| prefdisks
== NULL
) {
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.
1266 (iter
!= NULL
) && (error
== 0);
1267 iter
= iter
->next
) {
1269 devconfig_t
*uslice
= (devconfig_t
*)iter
->obj
;
1270 dm_descriptor_t udisk
= NULL
;
1272 dlist_t
*uhbas
= NULL
;
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
));
1280 if ((item
= dlist_new_item((void *)uhbas
)) == NULL
) {
1283 used_slice_hbas
= dlist_append(
1284 item
, used_slice_hbas
, AT_HEAD
);
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...
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
1300 * If it does, increment the count for that HBA.
1303 (iter
!= NULL
) && (error
== 0);
1304 iter
= iter
->next
) {
1306 dm_descriptor_t slice
= (uintptr_t)iter
->obj
;
1307 dlist_t
*hbas
= NULL
;
1308 int n
= 0; /* # slices each HBA contributes */
1310 if ((error
= slice_get_hbas(slice
, &hbas
)) != 0) {
1314 for (iter1
= hbas
; iter1
!= NULL
; iter1
= iter1
->next
) {
1315 for (iter2
= used_slice_hbas
; iter2
!= NULL
;
1316 iter2
= iter2
->next
) {
1318 dlist_t
*uhbas
= (dlist_t
*)iter2
->obj
;
1319 if (dlist_contains(uhbas
, iter1
->obj
,
1320 compare_descriptor_names
) == B_TRUE
) {
1326 dlist_free_items(hbas
, NULL
);
1328 /* group slices from HBAs contributing more than maxuses */
1333 /* add slice to list in descending size order */
1334 if ((item
= dlist_new_item((void*)(uintptr_t)slice
)) == NULL
) {
1338 dlist_insert_ordered(
1342 compare_slice_sizes
);
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
);
1350 dlist_free_items(used_slice_hbas
, NULL
);
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...
1357 for (i
= 0; (i
< maxuses
) && (error
== 0); i
++) {
1359 for (iter
= (dlist_t
*)prefhbas
[i
];
1360 (iter
!= NULL
) && (error
== 0);
1361 iter
= iter
->next
) {
1363 dm_descriptor_t slice
= (uintptr_t)iter
->obj
;
1364 dm_descriptor_t disk
;
1367 (void) slice_get_disk(slice
, &disk
);
1370 * count how many slices this slice's disk is contributing
1371 * by comparing it to the list of used slices
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) {
1381 /* add slice to list in descending size order */
1382 if ((item
= dlist_new_item((void *)(uintptr_t)slice
)) == NULL
) {
1386 dlist_insert_ordered(
1390 compare_slice_sizes
);
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
;
1404 for (i
= 0; i
< maxuses
; i
++) {
1405 dlist_free_items(prefhbas
[i
], NULL
);
1407 for (i
= 0; i
< maxslices
; i
++) {
1408 dlist_free_items(prefdisks
[i
], NULL
);
1411 free((void*)prefhbas
);
1412 free((void*)prefdisks
);
1418 * FUNCTION: slice_on_unique_hba(dm_descriptor_t slice,
1419 * dlist_t *used, dlist_t *used_hbas,
1420 * boolean_t *unique)
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
1427 * RETURNS: int - 0 on success
1430 * PURPOSE: Determines if the input slice is connected thru the same HBA
1431 * as a slice in the used list.
1433 * Also checks to see if the input slice is connected thru any
1434 * HBA in the used_hbas list.
1436 * If the slice is found to be on a unique HBA, bool is set
1437 * to B_TRUE, B_FALSE otherwise.
1440 slice_on_unique_hba(
1441 dm_descriptor_t slice
,
1446 dlist_t
*iter
= NULL
;
1447 dlist_t
*iter1
= NULL
;
1449 dlist_t
*hbas
= NULL
;
1455 if ((error
= slice_get_hbas(slice
, &hbas
)) != 0) {
1460 * check to see if any of slice's HBAs is the same
1461 * as the HBA for any of the used
1464 (iter
!= NULL
) && (*unique
== B_TRUE
) && (error
== 0);
1465 iter
= iter
->next
) {
1467 devconfig_t
*dev
= (devconfig_t
*)iter
->obj
;
1468 if (devconfig_isA(dev
, TYPE_SLICE
)) {
1470 dm_descriptor_t odisk
= NULL
;
1472 dlist_t
*ohbas
= NULL
;
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
));
1480 /* any HBA overlap? */
1482 (iter1
!= NULL
) && (*unique
== B_TRUE
) && (error
== 0);
1483 iter1
= iter1
->next
) {
1485 if (dlist_contains(ohbas
, iter1
->obj
,
1486 compare_descriptor_names
) == B_TRUE
) {
1490 dlist_free_items(ohbas
, NULL
);
1495 * check to see if any of slice's HBAs is the contained
1496 * in the list of used 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
) {
1507 dlist_free_items(hbas
, NULL
);
1513 * FUNCTION: slice_on_unique_disk(dm_descriptor_t slice,
1514 * dlist_t *used, dlist_t *used_disks,
1515 * boolean_t *unique)
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
1522 * RETURNS: int - 0 on success
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.
1529 * If the slice is found to be on a unique disk, bool is set
1530 * to B_TRUE, B_FALSE otherwise.
1533 slice_on_unique_disk(
1534 dm_descriptor_t slice
,
1536 dlist_t
*used_disks
,
1539 dm_descriptor_t disk
= NULL
;
1540 dlist_t
*iter
= NULL
;
1545 if ((error
= slice_get_disk(slice
, &disk
)) != 0) {
1550 * check to see if this disk is the same as the
1551 * disk for any of the used
1554 (iter
!= NULL
) && (*unique
== B_TRUE
) && (error
== 0);
1555 iter
= iter
->next
) {
1557 devconfig_t
*dev
= (devconfig_t
*)iter
->obj
;
1559 if (devconfig_isA(dev
, TYPE_SLICE
)) {
1561 /* get disk for otherslice */
1562 dm_descriptor_t odisk
= NULL
;
1565 ((error
= devconfig_get_name(dev
, &oname
)) != 0) ||
1566 (error
= get_disk_for_named_slice(oname
, &odisk
));
1569 (compare_descriptor_names((void*)(uintptr_t)disk
,
1570 (void*)(uintptr_t)odisk
) == 0)) {
1571 /* origslice is on same disk, stop */
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
) {
1588 * FUNCTION: slice_has_same_disk_geom(dm_descriptor_t slice,
1589 * dlist_t *used, boolean_t *has_same_geom)
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
1595 * RETURNS: int - 0 on success
1598 * PURPOSE: Determines if the input slice is on a drive with similar
1599 * hardware geometry as the slices in the used list.
1601 * If the slice is found to be on a disk with similar geometry,
1602 * bool is set to B_TRUE, B_FALSE otherwise.
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
1610 slice_has_same_disk_geom(
1611 dm_descriptor_t slice
,
1613 boolean_t
*has_same_geom
)
1615 dm_descriptor_t disk
= NULL
;
1616 boolean_t efi
= B_FALSE
;
1619 uint64_t nsects
= 0;
1620 uint64_t nheads
= 0;
1621 dlist_t
*iter
= NULL
;
1624 *has_same_geom
= B_TRUE
;
1626 ((error
= slice_get_disk(slice
, &disk
)) != 0) ||
1627 (error
= disk_get_is_efi(disk
, &efi
)) ||
1628 (error
= disk_get_blocksize(disk
, &bsize
));
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
));
1641 * check to see if slice's disk has the same geometry
1642 * as the disks for the slices in the used list
1645 (iter
!= NULL
) && (*has_same_geom
== B_TRUE
) && (error
= 0);
1646 iter
= iter
->next
) {
1648 devconfig_t
*dev
= (devconfig_t
*)iter
->obj
;
1650 if (devconfig_isA(dev
, TYPE_SLICE
)) {
1652 /* get disk info for otherslice */
1653 dm_descriptor_t odisk
= 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;
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
));
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
));
1673 if ((bsize
!= obsize
) || (ncyls
!= oncyls
) ||
1674 (nsects
!= onsects
) || (nheads
!= onheads
)) {
1675 /* this disk has a different geometry */
1676 *has_same_geom
= B_FALSE
;
1686 * FUNCTION: slice_on_similar_bus(dm_descriptor_t slice,
1687 * dlist_t *used, boolean_t *on_smlr_bus)
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
1693 * RETURNS: int - 0 on success
1696 * PURPOSE: Determines if the input slice is connected thru a bus with
1697 * characteristics similar to the slices in the used list.
1699 * If the slice is found to be on a similar bus, bool is set
1700 * to B_TRUE, B_FALSE otherwise.
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.
1709 slice_on_similar_bus(
1710 dm_descriptor_t slice
,
1712 boolean_t
*on_smlr_bus
)
1714 dlist_t
*iter
= NULL
;
1715 dlist_t
*iter1
= NULL
;
1716 dlist_t
*hbas
= NULL
;
1719 /* if there are no used slices, then the bus is similar */
1720 *on_smlr_bus
= B_TRUE
;
1721 if (dlist_length(used
) == 0) {
1725 (error
= slice_get_hbas(slice
, &hbas
));
1730 /* if there are used slices, then make sure the bus is similar */
1731 *on_smlr_bus
= B_FALSE
;
1733 (iter
!= NULL
) && (*on_smlr_bus
== B_FALSE
) && (error
== 0);
1734 iter
= iter
->next
) {
1736 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
1738 boolean_t fast80
= B_FALSE
;
1739 boolean_t fast40
= B_FALSE
;
1740 boolean_t fast20
= B_FALSE
;
1741 boolean_t wide
= B_FALSE
;
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
));
1752 /* check against the HBAs for the used slices */
1754 (iter1
!= NULL
) && (*on_smlr_bus
== B_FALSE
) && (error
== 0);
1755 iter1
= iter1
->next
) {
1757 devconfig_t
*used
= (devconfig_t
*)iter1
->obj
;
1759 /* get HBAs for otherslice */
1760 dm_descriptor_t udisk
= NULL
;
1762 dlist_t
*uhbas
= NULL
;
1763 dlist_t
*iter2
= NULL
;
1765 ((error
= devconfig_get_name(used
, &uname
)) != 0) ||
1766 (error
= get_disk_for_named_slice(uname
, &udisk
)) ||
1767 (error
= disk_get_hbas(udisk
, &uhbas
));
1770 (iter2
!= NULL
) && (*on_smlr_bus
== B_FALSE
) &&
1772 iter2
= iter2
->next
) {
1774 dm_descriptor_t uhba
= (uintptr_t)iter2
->obj
;
1776 boolean_t ufast80
= B_FALSE
;
1777 boolean_t ufast40
= B_FALSE
;
1778 boolean_t ufast20
= B_FALSE
;
1779 boolean_t uwide
= B_FALSE
;
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
));
1788 /* check sync speed ? */
1789 if ((fast80
== ufast80
) && (fast40
== ufast40
) &&
1790 (fast20
== ufast20
) && (wide
== uwide
) &&
1792 *on_smlr_bus
= B_TRUE
;
1796 dlist_free_items(uhbas
, NULL
);
1800 dlist_free_items(hbas
, NULL
);
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
1812 * RETURNS: int - 0 on success
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.
1818 * In order for a disk to have multiple paths, MPXIO must
1819 * be enabled and these conditions should hold:
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.
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.
1833 dm_descriptor_t slice
,
1835 boolean_t
*has_n_paths
)
1839 *has_n_paths
= B_FALSE
;
1841 if ((npaths
> 1) && (is_mpxio_enabled() == B_TRUE
)) {
1843 dm_descriptor_t disk
= NULL
;
1844 dlist_t
*paths
= NULL
;
1846 ((error
= slice_get_disk(slice
, &disk
)) != 0) ||
1847 (error
= disk_get_paths(disk
, &paths
));
1849 if ((error
== 0) && (dlist_length(paths
) == npaths
)) {
1850 *has_n_paths
= B_TRUE
;
1852 dlist_free_items(paths
, NULL
);
1859 * FUNCTION: compare_string_to_modslice_name(void *str, void *modslice)
1861 * INPUT: str - opaque char * pointer
1862 * modslice - opaque modslice_t pointer
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
1868 * PURPOSE: dlist_t helper which compares the input string to
1869 * the name of a slice represented as modslice_t struct.
1871 * Comparison is done via string_case_compare.
1874 compare_string_to_modslice_name(
1880 assert(str
!= NULL
);
1881 assert(modslice
!= NULL
);
1883 (void) devconfig_get_name(
1884 ((modslice_t
*)modslice
)->slice_devcfg
, &name
);
1886 return (string_case_compare((char *)str
, name
));
1890 * FUNCTION: compare_modslice_names(void *obj1, void *obj2)
1892 * INPUT: obj1 - opaque pointer
1893 * obj2 - opaque pointer
1895 * RETURNS: int - <0 - if obj1 name < obj2 name
1896 * 0 - if obj1 name == obj2 name
1897 * >0 - if obj1 name > obj2 name
1899 * PURPOSE: dlist_t helper which compares the names of two slices
1900 * represented as modslice_t structs.
1902 * Comparison is done by string_case_compare
1905 compare_modslice_names(
1912 assert(obj1
!= NULL
);
1913 assert(obj2
!= NULL
);
1915 (void) devconfig_get_name(
1916 ((modslice_t
*)obj1
)->slice_devcfg
, &name1
);
1917 (void) devconfig_get_name(
1918 ((modslice_t
*)obj2
)->slice_devcfg
, &name2
);
1920 return (string_case_compare(name1
, name2
));
1924 * FUNCTION: release_used_slices()
1926 * PURPOSE: Helper which cleans up the module private list of used
1930 release_used_slices()
1932 dlist_free_items(_used_slices
, free_used_slice
);
1933 _used_slices
= NULL
;
1941 usedslice_t
*used
= (usedslice_t
*)obj
;
1942 free(used
->slicename
);
1948 * FUNCTION: is_used_slice(dm_descriptor_t slice, boolean_t *is_used)
1950 * INPUT: slice - a dm_descriptor_t slice handle
1952 * OUTPUT: is_reserved - pointer to a boolean_t to hold the
1955 * PURPOSE: Helper which checks to see if the input slice
1956 * is in the used_slice list.
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.
1964 dm_descriptor_t slice
,
1970 if ((error
= get_display_name(slice
, &name
)) == 0) {
1971 *is_used
= dlist_contains(_used_slices
, (void *)name
,
1972 compare_usedslice_name_to_string
);
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)
1984 * INPUT: diskset - a char * diskset name.
1985 * slice - a dm_descriptor_t slice handle
1987 * RETURNS: int - 0 on success
1990 * PURPOSE: Access or maintain the list of used slices.
1994 dm_descriptor_t slice
)
1996 dm_descriptor_t disk
;
2000 assert(slice
!= (dm_descriptor_t
)0);
2002 ((error
= get_display_name(slice
, &name
)) != 0) ||
2003 (error
= slice_get_disk(slice
, &disk
)) ||
2004 (error
= add_used_slice_list_entry(name
, disk
));
2010 add_used_slice_by_name(
2013 dm_descriptor_t disk
= (dm_descriptor_t
)0;
2016 assert(slicename
!= NULL
);
2018 /* find disk for slice */
2019 error
= get_disk_for_named_slice(slicename
, &disk
);
2021 error
= add_used_slice_list_entry(slicename
, disk
);
2028 add_used_slice_list_entry(
2030 dm_descriptor_t disk
)
2032 usedslice_t
*used
= NULL
;
2035 assert(slicename
!= NULL
);
2036 assert(disk
!= (dm_descriptor_t
)0);
2038 used
= (usedslice_t
*)calloc(1, sizeof (usedslice_t
));
2044 if ((used
->slicename
= strdup(slicename
)) == NULL
) {
2048 dlist_t
*item
= dlist_new_item((void *) used
);
2050 free(used
->slicename
);
2055 dlist_append(item
, _used_slices
, AT_HEAD
);
2063 remove_used_slice_by_name(
2066 dlist_t
*removed
= NULL
;
2069 dlist_remove_equivalent_item(_used_slices
, (void *)slice
,
2070 compare_usedslice_name_to_string
, &removed
);
2072 if (removed
!= NULL
) {
2073 free_used_slice(removed
->obj
);
2074 removed
->obj
= NULL
;
2082 * FUNCTION: compare_usedslice_name_to_string(void *obj1, void *obj2)
2083 * INPUT: obj1 - opaque pointer
2084 * obj2 - opaque pointer
2086 * RETURNS: int - <0 - if obj1 name < obj2 name
2087 * 0 - if obj1 name == obj2 name
2088 * >0 - if obj1 name > obj2 name
2090 * PURPOSE: dlist_t helper which compares the names of a slice
2091 * represented as modslice_t struct to a string.
2093 * obj1 is assumed to be a char *
2094 * obj2 is assumed to be a usedslice_t *
2096 * Comparison is done via string_case_compare.
2099 compare_usedslice_name_to_string(
2103 assert(obj1
!= NULL
);
2104 assert(obj2
!= NULL
);
2106 return (string_case_compare((char *)obj1
,
2107 ((usedslice_t
*)obj2
)->slicename
));
2111 * FUNCTION: disk_has_used_slice(dm_descriptor_t disk, boolean_t *hasused)
2113 * INPUT: disk - a dm_descriptor_t disk handle.
2114 * inuse - a boolean_t pointer to hold the result
2116 * RETURNS: int - 0 on success
2119 * PURPOSE: Determines if any of the known used slices is on the
2123 disk_has_used_slice(
2124 dm_descriptor_t disk
,
2131 for (iter
= _used_slices
;
2132 (iter
!= NULL
) && (*hasused
== B_FALSE
);
2133 iter
= iter
->next
) {
2135 usedslice_t
*used
= (usedslice_t
*)iter
->obj
;
2137 /* compare used slice's disk to disk */
2138 if (compare_descriptors((void *)(uintptr_t)disk
,
2139 (void *)(uintptr_t)used
->disk
) == 0) {
2148 * FUNCTION: add_reserved_slice(dm_descriptor_t slice)
2150 * INPUT: slice - a dm_descriptor_t slice handle
2152 * RETURNS: int - 0 on success
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.
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().
2163 * The reserved slice list is used by several functions:
2165 * 1. layout_validate.validate_slice_components() adds user
2166 * requested slices to the list.
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.
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.
2179 dm_descriptor_t slice
)
2181 dlist_t
*item
= NULL
;
2183 if ((item
= dlist_new_item((void *)(uintptr_t)slice
)) == NULL
) {
2187 _rsvd_slices
= dlist_append(item
, _rsvd_slices
, AT_HEAD
);
2193 * FUNCTION: is_reserved_slice(dm_descriptor_t slice,
2194 * boolean_t *is_reserved)
2196 * INPUT: slice - a dm_descriptor_t slice handle
2198 * OUTPUT: is_reserved - pointer to a boolean_t to hold the
2201 * PURPOSE: Helper which checks to see if the input slice
2202 * was previously reserved.
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.
2210 dm_descriptor_t slice
,
2211 boolean_t
*is_reserved
)
2213 *is_reserved
= dlist_contains(_rsvd_slices
,
2214 (void *)(uintptr_t)slice
, compare_descriptor_names
);
2220 * FUNCTION: release_reserved_slice()
2222 * PURPOSE: Helper which cleans up the module private list of reserved
2226 release_reserved_slices()
2228 dlist_free_items(_rsvd_slices
, free
);
2229 _rsvd_slices
= NULL
;
2233 * FUNCTION: get_reserved_slices(dlist_t **list)
2235 * OUTPUT: list - a dlist_t pointer to hold the returned list of
2238 * RETURNS: int - 0 on success
2241 * PURPOSE: Accessor to retrieve the current list of reserved slice
2242 * dm_descriptor_t handles.
2245 get_reserved_slices(
2248 *list
= _rsvd_slices
;
2254 * FUNCTION: add_slice_to_remove(char *name, uint32_t index)
2256 * INPUT: name - name of a slice
2257 * index - index for the slice
2259 * RETURNS: int - 0 on success
2262 * PURPOSE: Utility function to add the named slice to the list of
2263 * those that need to be "removed" by having their sizes
2267 add_slice_to_remove(
2271 rmvdslice_t
*rmvd
= NULL
;
2274 assert(name
!= NULL
);
2276 rmvd
= (rmvdslice_t
*)calloc(1, sizeof (rmvdslice_t
));
2280 rmvd
->slice_index
= index
;
2281 if ((rmvd
->slice_name
= strdup(name
)) == NULL
) {
2285 dlist_t
*item
= dlist_new_item((void *) rmvd
);
2287 free(rmvd
->slice_name
);
2292 dlist_append(item
, _rmvd_slices
, AT_HEAD
);
2300 * FUNCTION: get_removed_slices()
2302 * RETURNS: dlist_t * - pointer to a list of rmvdslice_t structs
2304 * PURPOSE: Accessor to retrieve the current list of names of slices
2308 get_slices_to_remove(
2311 return (_rmvd_slices
);
2319 rmvdslice_t
*rmvd
= (rmvdslice_t
*)obj
;
2320 free(rmvd
->slice_name
);
2326 * FUNCTION: release_removed_slices()
2328 * PURPOSE: Helper which cleans up the module private list of removed
2332 release_slices_to_remove()
2334 dlist_free_items(_rmvd_slices
, free_rmvd_slice
);
2335 _rmvd_slices
= NULL
;