7712 mandoc -Tlint does always exit with error code 0
[unleashed.git] / usr / src / cmd / lvm / metassist / layout / layout_slice.c
blobae36f967458d441c559559ae89314fbec3ccd119
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
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>
30 #include <meta.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(
50 dlist_t *list,
51 dlist_t *used,
52 dm_descriptor_t *chosen);
54 static int slice_has_same_disk_geom(
55 dm_descriptor_t slice,
56 dlist_t *used,
57 boolean_t *bool);
59 static int slice_on_unique_disk(
60 dm_descriptor_t slice,
61 dlist_t *used,
62 dlist_t *othervols,
63 boolean_t *bool);
65 static int slice_on_unique_hba(
66 dm_descriptor_t slice,
67 dlist_t *used,
68 dlist_t *othervols,
69 boolean_t *bool);
71 static int slice_on_similar_bus(
72 dm_descriptor_t slice,
73 dlist_t *used,
74 boolean_t *bool);
76 static int slice_has_n_paths(
77 dm_descriptor_t slice,
78 uint16_t npaths,
79 boolean_t *bool);
81 static int compare_modslice_names(
82 void *obj1,
83 void *obj2);
85 static int compare_string_to_modslice_name(
86 void *str,
87 void *modslice);
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);
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);
108 * list to track resized slices
110 static dlist_t *_modified_slices = NULL;
113 * struct to track used slices and their disks...
115 typedef struct {
116 char *slicename;
117 dm_descriptor_t disk;
118 } usedslice_t;
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
132 * volume requests
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(
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)
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
170 * RETURNS: int - 0 on success
171 * !0 otherwise
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
194 * and/or disk.
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.
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)
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);
221 int error = 0;
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
231 int i, j, k, l, m;
232 dlist_t *list[2][2][2][2][3];
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];
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 */
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");
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");
296 /* END CSTYLED */
299 /* init list array pointers */
300 (void) memset(list, 0, 2*2*2*2*3 * sizeof (dlist_t *));
302 for (iter = slices;
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,
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;
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);
336 if (npaths > 1) {
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 */
343 paths = B_TRUE;
346 if (verbose == B_TRUE) {
347 if (uniqhba) {
348 oprintf(OUTPUT_VERBOSE, uniqhba_msg);
350 if (uniqdisk) {
351 oprintf(OUTPUT_VERBOSE, uniqdisk_msg);
354 if (used != NULL) {
355 if (samebus) {
356 oprintf(OUTPUT_VERBOSE, samebus_msg);
358 if (samegeom) {
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);
367 } else {
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);
378 continue;
381 if (paths == B_FALSE) {
382 /* not connected thru enough paths */
383 if (verbose == B_TRUE) {
384 oprintf(OUTPUT_VERBOSE, insuff_paths, npaths);
386 continue;
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);
394 continue;
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) {
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);
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
439 slice = NULL;
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(
450 list[i][j][k][l][m],
451 used, &slice);
453 resize = (m == 1);
455 /* terminate all loops */
456 goto stop;
463 stop:
466 * Slice chosen, is a resize necessary?
468 if ((error == 0) && (slice != NULL)) {
470 if (error == 0) {
471 if (verbose == B_TRUE) {
472 uint64_t snbytes = 0;
473 char *sname = NULL;
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"
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);
494 if (resize) {
495 if (verbose == B_TRUE) {
496 oprintf(OUTPUT_VERBOSE,
497 gettext(" it has excess space, "
498 "resizing...\n"));
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"));
509 if (error == 0) {
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);
539 return (error);
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
550 * !0 otherwise
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)
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;
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);
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);
586 return (error);
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
599 * !0 otherwise
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.
606 static int
607 make_slicename_for_disk_and_index(
608 dm_descriptor_t disk,
609 uint16_t index,
610 char **slicename)
612 char *dname;
613 int error = 0;
615 if ((error = get_display_name(disk, &dname)) == 0) {
616 error = make_slicename_for_diskname_and_index(dname,
617 index, slicename);
620 return (error);
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
633 * !0 otherwise
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(
642 char *diskname,
643 uint16_t index,
644 char **slicename)
646 int error = 0;
647 char buf[MAXNAMELEN+1];
649 (void) snprintf(buf, sizeof (buf), "%ss%u", diskname, index);
650 if ((*slicename = strdup(buf)) == NULL) {
651 *slicename = NULL;
652 error = ENOMEM;
655 return (error);
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
670 * !0 otherwise
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
685 * boundary.
687 * For VTOC labeled disks, nbytes is rounded up to the next
688 * cylinder boundary.
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
706 * be NULL.
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)
715 dm_descriptor_t odisk = NULL;
716 boolean_t efi = B_FALSE;
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;
725 uint32_t oindex = 0;
726 uint32_t nindex = oindex;
728 int error = 0;
730 *nslice = NULL;
732 ((error = slice_get_disk(oslice, &odisk)) != 0) ||
733 (error = slice_get_index(oslice, &oindex));
734 if (error != 0) {
735 return (error);
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);
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);
754 if (efi) {
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,
761 gettext(" "
762 "rounded up to %10.2f blocks\n"),
763 (double)(nsize/bytes_per_sect));
765 } else {
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;
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);
780 if (add_extra_cyl == TRUE) {
781 nsize += bytes_per_cyl;
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);
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) {
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));
809 } else {
810 /* make a new slice */
811 char *nname = NULL;
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));
821 if ((error != 0) && (*nslice == NULL)) {
822 free(nname);
828 return (error);
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
852 * existing slice.
854 * The input size for the new slice is expected to be
855 * cylinder aligned.
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)
870 int error = 0;
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);
886 if (error != 0) {
887 free(nname);
888 return (error);
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),
899 osize, NULL);
901 return (error);
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
926 * !0 otherwise
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
936 * the input values.
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,
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)
951 devconfig_t *slice = NULL;
952 modslice_t *mstp = NULL;
953 dlist_t *item = NULL;
954 int error = 0;
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,
968 mod_stblk)) != 0) ||
969 (error = devconfig_set_size(slice, mod_size)) ||
970 (error = devconfig_set_size_in_blocks(slice, mod_nblks));
972 } else {
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) {
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;
993 mstp->src_slice_desc = src_slice;
994 mstp->slice_devcfg = slice;
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;
1006 } else {
1007 error = ENOMEM;
1011 if (error != 0) {
1012 free_devconfig(mstp);
1013 free_devconfig(slice);
1017 if (error == 0) {
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) {
1025 *mod_slice = slice;
1026 mstp->volume_component = B_TRUE;
1030 return (error);
1034 * FUNCTION: dlist_t *get_modified_slices()
1036 * RETURNS: pointer to the list of modslice_t structs representing
1037 * modified slices
1039 * PURPOSE: public accessor to the list of slices modified while
1040 * processing a request.
1042 dlist_t *
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.
1055 static void
1056 free_modslice_object(
1057 void *obj)
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);
1067 free(obj);
1071 * FUNCTION: void release_modified_slices()
1073 * INPUT: none -
1074 * OUTPUT: none -
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;
1085 return (0);
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
1094 * !0 otherwise
1096 * PURPOSE: Undoes slice creation done by create_new_slice():
1098 * release index
1099 * remove from used_slices
1100 * remove from modified_slices
1101 * return space to source slice
1102 * free memory
1105 destroy_new_slice(
1106 devconfig_t *dev)
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;
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);
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);
1132 if (item != NULL) {
1133 modified = (modslice_t *)item->obj;
1134 free((void*) item);
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) {
1146 srcitem =
1147 dlist_find(
1148 _modified_slices,
1149 srcname,
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));
1172 if (error == 0) {
1174 /* was only modification undone? */
1175 if (source->times_modified == 0) {
1177 _modified_slices =
1178 dlist_remove_equivalent_item(
1179 _modified_slices, srcname,
1180 compare_string_to_modslice_name,
1181 &srcitem);
1183 free_modslice_object((modslice_t *)srcitem->obj);
1184 free((void *)srcitem);
1189 free_modslice_object(modified);
1192 return (error);
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
1204 * !0 otherwise
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
1215 * is selected.
1217 * The largest slice from that disk is then returned.
1219 static int
1220 pick_from_best_hba_and_disk(
1221 dlist_t *slices,
1222 dlist_t *used,
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;
1232 int maxuses = 128;
1233 int maxslices = VTOC_SIZE; /* meta.h */
1235 int i = 0;
1236 int error = 0;
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) {
1255 free(prefhbas);
1256 free(prefdisks);
1257 return (ENOMEM);
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.
1265 for (iter = used;
1266 (iter != NULL) && (error == 0);
1267 iter = iter->next) {
1269 devconfig_t *uslice = (devconfig_t *)iter->obj;
1270 dm_descriptor_t udisk = NULL;
1271 char *uname = 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));
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);
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.
1302 for (iter = slices;
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) {
1311 continue;
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) {
1321 n++;
1326 dlist_free_items(hbas, NULL);
1328 /* group slices from HBAs contributing more than maxuses */
1329 if (n >= maxuses) {
1330 n = maxuses - 1;
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);
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;
1365 int n = 0;
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) {
1377 n++;
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);
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;
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);
1414 return (error);
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
1428 * !0 otherwise
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.
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)
1446 dlist_t *iter = NULL;
1447 dlist_t *iter1 = NULL;
1449 dlist_t *hbas = NULL;
1451 int error = 0;
1453 *unique = B_TRUE;
1455 if ((error = slice_get_hbas(slice, &hbas)) != 0) {
1456 return (error);
1460 * check to see if any of slice's HBAs is the same
1461 * as the HBA for any of the used
1463 for (iter = 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;
1471 char *oname = 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? */
1481 for (iter1 = hbas;
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) {
1487 *unique = B_FALSE;
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
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;
1507 dlist_free_items(hbas, NULL);
1509 return (error);
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
1523 * !0 otherwise
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.
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)
1539 dm_descriptor_t disk = NULL;
1540 dlist_t *iter = NULL;
1541 int error = 0;
1543 *unique = B_TRUE;
1545 if ((error = slice_get_disk(slice, &disk)) != 0) {
1546 return (error);
1550 * check to see if this disk is the same as the
1551 * disk for any of the used
1553 for (iter = 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;
1563 char *oname = NULL;
1565 ((error = devconfig_get_name(dev, &oname)) != 0) ||
1566 (error = get_disk_for_named_slice(oname, &odisk));
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;
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;
1584 return (error);
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
1596 * !0 otherwise
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
1607 * checked as well.
1609 static int
1610 slice_has_same_disk_geom(
1611 dm_descriptor_t slice,
1612 dlist_t *used,
1613 boolean_t *has_same_geom)
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;
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));
1636 if (error != 0) {
1637 return (error);
1641 * check to see if slice's disk has the same geometry
1642 * as the disks for the slices in the used list
1644 for (iter = used;
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;
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;
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));
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;
1682 return (error);
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
1694 * !0 otherwise
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.
1708 static int
1709 slice_on_similar_bus(
1710 dm_descriptor_t slice,
1711 dlist_t *used,
1712 boolean_t *on_smlr_bus)
1714 dlist_t *iter = NULL;
1715 dlist_t *iter1 = NULL;
1716 dlist_t *hbas = NULL;
1717 int error = 0;
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);
1725 (error = slice_get_hbas(slice, &hbas));
1726 if (error != 0) {
1727 return (error);
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) {
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;
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;
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) {
1757 devconfig_t *used = (devconfig_t *)iter1->obj;
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;
1765 ((error = devconfig_get_name(used, &uname)) != 0) ||
1766 (error = get_disk_for_named_slice(uname, &udisk)) ||
1767 (error = disk_get_hbas(udisk, &uhbas));
1769 for (iter2 = uhbas;
1770 (iter2 != NULL) && (*on_smlr_bus == B_FALSE) &&
1771 (error == 0);
1772 iter2 = iter2 ->next) {
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;
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));
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;
1796 dlist_free_items(uhbas, NULL);
1800 dlist_free_items(hbas, NULL);
1802 return (error);
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
1813 * !0 otherwise
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.
1831 static int
1832 slice_has_n_paths(
1833 dm_descriptor_t slice,
1834 uint16_t npaths,
1835 boolean_t *has_n_paths)
1837 int error = 0;
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);
1855 return (error);
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.
1873 static int
1874 compare_string_to_modslice_name(
1875 void *str,
1876 void *modslice)
1878 char *name = NULL;
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
1904 static int
1905 compare_modslice_names(
1906 void *obj1,
1907 void *obj2)
1909 char *name1 = NULL;
1910 char *name2 = NULL;
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
1927 * slices.
1929 void
1930 release_used_slices()
1932 dlist_free_items(_used_slices, free_used_slice);
1933 _used_slices = NULL;
1936 static void
1937 free_used_slice(
1938 void *obj)
1940 if (obj != NULL) {
1941 usedslice_t *used = (usedslice_t *)obj;
1942 free(used->slicename);
1943 free(used);
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
1953 * return result.
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.
1963 is_used_slice(
1964 dm_descriptor_t slice,
1965 boolean_t *is_used)
1967 char *name;
1968 int error = 0;
1970 if ((error = get_display_name(slice, &name)) == 0) {
1971 *is_used = dlist_contains(_used_slices, (void *)name,
1972 compare_usedslice_name_to_string);
1975 return (error);
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
1988 * !0 otherwise
1990 * PURPOSE: Access or maintain the list of used slices.
1993 add_used_slice(
1994 dm_descriptor_t slice)
1996 dm_descriptor_t disk;
1997 char *name;
1998 int error = 0;
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));
2006 return (error);
2010 add_used_slice_by_name(
2011 char *slicename)
2013 dm_descriptor_t disk = (dm_descriptor_t)0;
2014 int error = 0;
2016 assert(slicename != NULL);
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);
2024 return (error);
2027 static int
2028 add_used_slice_list_entry(
2029 char *slicename,
2030 dm_descriptor_t disk)
2032 usedslice_t *used = NULL;
2033 int error = 0;
2035 assert(slicename != NULL);
2036 assert(disk != (dm_descriptor_t)0);
2038 used = (usedslice_t *)calloc(1, sizeof (usedslice_t));
2039 if (used == NULL) {
2040 error = ENOMEM;
2041 } else {
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);
2059 return (error);
2063 remove_used_slice_by_name(
2064 char *slice)
2066 dlist_t *removed = NULL;
2068 _used_slices =
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;
2075 free(removed);
2078 return (0);
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.
2098 static int
2099 compare_usedslice_name_to_string(
2100 void *obj1,
2101 void *obj2)
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
2117 * !0 othersize.
2119 * PURPOSE: Determines if any of the known used slices is on the
2120 * input disk.
2123 disk_has_used_slice(
2124 dm_descriptor_t disk,
2125 boolean_t *hasused)
2127 dlist_t *iter;
2128 int error = 0;
2130 *hasused = B_FALSE;
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) {
2140 *hasused = B_TRUE;
2144 return (error);
2148 * FUNCTION: add_reserved_slice(dm_descriptor_t slice)
2150 * INPUT: slice - a dm_descriptor_t slice handle
2152 * RETURNS: int - 0 on success
2153 * !0 otherwise.
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.
2178 add_reserved_slice(
2179 dm_descriptor_t slice)
2181 dlist_t *item = NULL;
2183 if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) {
2184 return (ENOMEM);
2187 _rsvd_slices = dlist_append(item, _rsvd_slices, AT_HEAD);
2189 return (0);
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
2199 * return result.
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.
2209 is_reserved_slice(
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);
2216 return (0);
2220 * FUNCTION: release_reserved_slice()
2222 * PURPOSE: Helper which cleans up the module private list of reserved
2223 * slices.
2225 void
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
2236 * reserverd slices.
2238 * RETURNS: int - 0 on success
2239 * !0 otherwise
2241 * PURPOSE: Accessor to retrieve the current list of reserved slice
2242 * dm_descriptor_t handles.
2245 get_reserved_slices(
2246 dlist_t **list)
2248 *list = _rsvd_slices;
2250 return (0);
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
2260 * !0 otherwise
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.
2267 add_slice_to_remove(
2268 char *name,
2269 uint32_t index)
2271 rmvdslice_t *rmvd = NULL;
2272 int error = 0;
2274 assert(name != NULL);
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);
2296 return (error);
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
2305 * to be removed.
2307 dlist_t *
2308 get_slices_to_remove(
2309 dlist_t **list)
2311 return (_rmvd_slices);
2314 static void
2315 free_rmvd_slice(
2316 void *obj)
2318 if (obj != NULL) {
2319 rmvdslice_t *rmvd = (rmvdslice_t *)obj;
2320 free(rmvd->slice_name);
2321 free(rmvd);
2326 * FUNCTION: release_removed_slices()
2328 * PURPOSE: Helper which cleans up the module private list of removed
2329 * slices.
2331 void
2332 release_slices_to_remove()
2334 dlist_free_items(_rmvd_slices, free_rmvd_slice);
2335 _rmvd_slices = NULL;