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"
31 #include "volume_error.h"
32 #include "volume_dlist.h"
33 #include "volume_output.h"
35 #include "layout_concat.h"
36 #include "layout_device_cache.h"
37 #include "layout_device_util.h"
38 #include "layout_discovery.h"
39 #include "layout_dlist_util.h"
40 #include "layout_messages.h"
41 #include "layout_request.h"
42 #include "layout_slice.h"
43 #include "layout_stripe.h"
44 #include "layout_svm_util.h"
46 #define _LAYOUT_MIRROR_C
48 static int layout_stripe_submirrors(
55 static int layout_concat_submirrors(
62 static int compose_stripe_per_hba(
72 static int compose_stripes_across_hbas(
83 static int compose_stripes_within_hba(
93 static int compose_concat_per_hba(
101 static int compose_concats_across_hbas(
102 devconfig_t
*request
,
110 static int compose_concats_within_hba(
111 devconfig_t
*request
,
118 static int assemble_mirror(
119 devconfig_t
*request
,
121 devconfig_t
**mirror
);
123 static int remove_used_disks(
125 devconfig_t
*volume
);
127 static int volume_shares_disk(
128 dm_descriptor_t disk
,
132 static int select_mpxio_hbas(
134 dlist_t
**mpxio_hbas
);
136 static int set_explicit_submirror_names(
140 static int set_explicit_submirror_name(
145 * FUNCTION: layout_mirror(devconfig_t *request, nbytes, dlist_t **results)
147 * INPUT: request - pointer to a request devconfig_t
148 * nsubs - number of submirrors
149 * nbytes - desired mirror size
151 * OUTPUT: results - pointer to a list of volume devconfig_t results
153 * RETURNS: int - 0 on success
156 * PURPOSE: Main driver to handle a mirror request that does not specify
159 * Striped submirrors are tried first, then concats.
163 devconfig_t
*request
,
168 dlist_t
*subs
= NULL
;
169 dlist_t
*item
= NULL
;
170 boolean_t usehsp
= B_FALSE
;
173 if ((error
= get_volume_faultrecov(request
, &usehsp
)) != 0) {
174 if (error
!= ERR_ATTR_UNSET
) {
180 print_layout_volume_msg(devconfig_type_to_str(TYPE_MIRROR
), nbytes
);
182 /* prefer stripe submirrors */
183 if ((error
= layout_stripe_submirrors(
184 request
, NULL
, nbytes
, nsubs
, &subs
)) != 0) {
189 /* second chance: mirrored concats */
190 if ((error
= layout_concat_submirrors(
191 request
, NULL
, nbytes
, nsubs
, &subs
)) != 0) {
198 devconfig_t
*mirror
= NULL
;
199 dlist_t
*iter
= NULL
;
201 /* unset submirror names prior to final assembly */
202 for (iter
= subs
; iter
!= NULL
; iter
= iter
->next
) {
203 devconfig_t
*sub
= (devconfig_t
*)iter
->obj
;
206 (void) devconfig_get_name(sub
, &name
);
207 release_volume_name(name
);
208 (void) devconfig_set_name(sub
, "");
211 error
= assemble_mirror(request
, subs
, &mirror
);
214 if ((item
= dlist_new_item(mirror
)) == NULL
) {
217 *results
= dlist_append(item
, *results
, AT_TAIL
);
219 /* remember submirrors that need HSPs */
220 if (usehsp
== B_TRUE
) {
221 error
= add_to_hsp_list(
222 devconfig_get_components(mirror
));
225 print_layout_success_msg();
228 /* cleanup submirrors */
229 dlist_free_items(subs
, free_devconfig_object
);
233 } else if (error
!= 0) {
235 print_debug_failure_msg(devconfig_type_to_str(TYPE_MIRROR
),
236 get_error_string(error
));
240 print_insufficient_resources_msg(
241 devconfig_type_to_str(TYPE_MIRROR
));
249 * FUNCTION: populate_explicit_mirror(devconfig_t *request,
252 * INPUT: request - pointer to a request devconfig_t
254 * OUTPUT: results - pointer to a list of volume devconfig_t results
256 * RETURNS: int - 0 on success
259 * PURPOSE: Processes the input mirror request specifying explicit layout
260 * constraints on the submirrors.
262 * Primary submirror constraint is explicit type, either
263 * stripe or concat. Submirror types may be mixed.
265 * Submirror sizes or components may be specified explicitly.
267 * If the mirror does not specify a size, assume the first explicit
268 * submirror size is the desired size. If a submirror does not
269 * specify a size or components, use the mirror size.
271 * Scan the submirror requests: those with specific components
272 * get assembled as encountered. The remainder are grouped by
273 * type and handled by layout_stripe_submirrors() or
274 * layout_concat_submirrors().
276 * If all specified submirrors can be assembled, the final mirror
277 * is assembled and appended to the results list.
280 populate_explicit_mirror(
281 devconfig_t
*request
,
284 dlist_t
*composed
= NULL
;
285 dlist_t
*list
= NULL
;
286 dlist_t
*iter
= NULL
;
287 dlist_t
*concats_by_size
= NULL
;
288 dlist_t
*stripes_by_size
= NULL
;
292 boolean_t usehsp
= B_FALSE
;
294 list
= devconfig_get_components(request
);
295 nsubs
= dlist_length(list
);
297 if ((error
= get_volume_faultrecov(request
, &usehsp
)) != 0) {
298 if (error
!= ERR_ATTR_UNSET
) {
304 if ((error
= devconfig_get_size(request
, &msize
)) != 0) {
305 if (error
== ERR_ATTR_UNSET
) {
313 print_layout_explicit_msg(devconfig_type_to_str(TYPE_MIRROR
));
316 * Scan the list of specified submirrors, collect those that only
317 * specify size (or no size). Process those with explicit components
321 for (iter
= list
; (iter
!= NULL
) && (error
== 0); iter
= iter
->next
) {
323 devconfig_t
*comp
= (devconfig_t
*)iter
->obj
;
324 component_type_t ctype
= TYPE_UNKNOWN
;
325 dlist_t
*clist
= NULL
;
327 dlist_t
*item
= NULL
;
329 (void) devconfig_get_type(comp
, &ctype
);
330 (void) devconfig_get_size(comp
, &csize
);
331 clist
= devconfig_get_components(comp
);
335 /* components specified */
337 if (ctype
== TYPE_STRIPE
) {
338 error
= populate_explicit_stripe(comp
, &item
);
340 error
= populate_explicit_concat(comp
, &item
);
344 set_explicit_submirror_name(
345 comp
, (devconfig_t
*)item
->obj
);
346 composed
= dlist_append(item
, composed
, AT_TAIL
);
351 /* no components specified */
353 /* if no size is specified, it needs to be inferred */
356 /* mirror specified no size, first explicit submirror */
357 /* size is assumed to be the desired mirror size */
361 /* this submirror specified no size, use mirror size */
362 devconfig_set_size(comp
, msize
);
365 if ((item
= dlist_new_item(comp
)) == NULL
) {
370 if (ctype
== TYPE_STRIPE
) {
371 stripes_by_size
= dlist_append(
372 item
, stripes_by_size
, AT_TAIL
);
374 concats_by_size
= dlist_append(
375 item
, concats_by_size
, AT_TAIL
);
381 /* compose stripes specified by size */
382 if ((error
== 0) && (stripes_by_size
!= NULL
)) {
383 uint16_t n
= dlist_length(stripes_by_size
);
384 dlist_t
*stripes
= NULL
;
385 if ((error
= layout_stripe_submirrors(
386 request
, composed
, msize
, n
, &stripes
)) == 0) {
388 /* adjust stripe names */
389 set_explicit_submirror_names(stripes_by_size
, stripes
);
390 composed
= dlist_append(stripes
, composed
, AT_TAIL
);
393 /* these stripes failed, skip concats_by_size */
394 dlist_free_items(stripes
, free_devconfig_object
);
395 dlist_free_items(concats_by_size
, NULL
);
396 concats_by_size
= NULL
;
398 dlist_free_items(stripes_by_size
, NULL
);
401 /* compose concats specified by size */
402 if ((error
== 0) && (concats_by_size
!= NULL
)) {
403 uint16_t n
= dlist_length(concats_by_size
);
404 dlist_t
*concats
= NULL
;
405 if ((error
= layout_concat_submirrors(
406 request
, composed
, msize
, n
, &concats
)) == 0) {
408 /* adjust concat names */
409 set_explicit_submirror_names(concats_by_size
, concats
);
410 composed
= dlist_append(concats
, composed
, AT_TAIL
);
414 /* these concats failed */
415 dlist_free_items(concats
, free_devconfig_object
);
418 dlist_free_items(concats_by_size
, NULL
);
421 if ((composed
!= NULL
) && ((dlist_length(composed
) == nsubs
))) {
423 /* assemble final mirror */
425 devconfig_t
*mirror
= NULL
;
426 dlist_t
*item
= NULL
;
428 if ((error
= assemble_mirror(request
, composed
, &mirror
)) == 0) {
430 if ((item
= dlist_new_item(mirror
)) == NULL
) {
433 *results
= dlist_append(item
, *results
, AT_TAIL
);
434 if (usehsp
== B_TRUE
) {
435 error
= add_to_hsp_list(
436 devconfig_get_components(mirror
));
438 print_layout_success_msg();
442 } else if (error
!= 0) {
444 print_debug_failure_msg(
445 devconfig_type_to_str(TYPE_MIRROR
),
446 get_error_string(error
));
450 dlist_free_items(composed
, free_devconfig_object
);
451 print_insufficient_resources_msg(
452 devconfig_type_to_str(TYPE_MIRROR
));
460 * FUNCTION: assemble_mirror(devconfig_t *request, dlist_t *subs,
461 * devconfig_t **mirror)
463 * INPUT: request - pointer to a devconfig_t of the current request
464 * subs - pointer to a list of composed submirrors
466 * OUPUT: mirror - pointer to a devconfig_t to hold final mirror
468 * RETURNS: int - 0 on success
471 * PURPOSE: Helper which creates and populates a mirror devconfig_t
472 * struct using information from the input request and the
473 * list of submirror components.
475 * Determines the name of the mirror either from the request
476 * or from the default naming scheme and assigns names to
477 * unnamed submirrors according to the default naming scheme.
479 * Sets the read and write strategies, and the resync pass
480 * number for the mirror if values are specified in the request.
482 * Attaches the input list of submirrors to the devconfig.
486 devconfig_t
*request
,
488 devconfig_t
**mirror
)
490 dlist_t
*iter
= NULL
;
494 if ((error
= new_devconfig(mirror
, TYPE_MIRROR
)) == 0) {
495 /* set stripe name, use requested name if specified */
496 if ((error
= devconfig_get_name(request
, &name
)) != 0) {
497 if (error
!= ERR_ATTR_UNSET
) {
498 volume_set_error(gettext("error getting requested name\n"));
506 if ((error
= get_next_volume_name(&name
,
507 TYPE_MIRROR
)) == 0) {
508 error
= devconfig_set_name(*mirror
, name
);
510 /* get name for generating submirror names below */
511 error
= devconfig_get_name(*mirror
, &name
);
514 error
= devconfig_set_name(*mirror
, name
);
519 /* assign name to any unnamed submirror */
521 (error
== 0) && (iter
!= NULL
);
524 devconfig_t
*sub
= (devconfig_t
*)iter
->obj
;
525 char *subname
= NULL
;
527 error
= devconfig_get_name(sub
, &subname
);
528 if ((error
== ERR_ATTR_UNSET
) || (subname
== NULL
) ||
529 (*subname
== '\0')) {
530 ((error
= get_next_submirror_name(name
, &subname
)) != 0) ||
531 (error
= devconfig_set_name(sub
, subname
));
537 mirror_read_strategy_t read
= 0;
538 if ((error
= get_mirror_read_strategy(request
, &read
)) == 0) {
539 error
= devconfig_set_mirror_read(*mirror
, read
);
540 } else if (error
== ERR_ATTR_UNSET
) {
546 mirror_write_strategy_t write
= 0;
547 if ((error
= get_mirror_write_strategy(request
, &write
)) == 0) {
548 error
= devconfig_set_mirror_write(*mirror
, write
);
549 } else if (error
== ERR_ATTR_UNSET
) {
556 if ((error
= get_mirror_pass(request
, &pass
)) == 0) {
557 error
= devconfig_set_mirror_pass(*mirror
, pass
);
558 } else if (error
== ERR_ATTR_UNSET
) {
563 /* arrange submirrors in ascending size order */
565 dlist_t
*sorted
= NULL
;
566 dlist_t
*next
= NULL
;
569 while (iter
!= NULL
) {
575 sorted
= dlist_insert_ordered(iter
,
576 sorted
, ASCENDING
, compare_devconfig_sizes
);
584 devconfig_set_components(*mirror
, subs
);
586 free_devconfig(*mirror
);
594 * FUNCTION: layout_stripe_submirrors(devconfig_t *request, dlist_t *cursubs,
595 * uint64_t nbytes, uint16_t nsubs, dlist_t **results)
597 * INPUT: request - pointer to a devconfig_t of the current request
598 * cursubs - pointer to a list of already composed submirrors
599 * these may affect disk and HBA choices for new
600 * submirrors being composed and are passed along
601 * into the component selection functions.
602 * nbytes - the desired capacity for the stripes
604 * OUPUT: results - pointer to a list of composed volumes
606 * RETURNS: int - 0 on success
609 * PURPOSE: Main layout driver for composing stripe submirrors.
611 * Attempts to construct nsub submirrors of size nbytes.
613 * Several different layout strategies are tried in order
614 * of preference until one succeeds or there are none left.
616 * 1 - mirror with all stripes on the MPXIO "controller"
617 * . requires MPXIO to be enabled
618 * . requires nsubs * mincomp available disks on the
621 * 2 - mirror with stripes within separate HBAs of same type
622 * . requires nsubs HBAs with mincomp disks
623 * . stripe width is driven by number of disks on HBA
625 * 3 - mirror with stripes across HBAs of same type
626 * . requires mincomp HBAs with nsubs disks
627 * (each stripe has a disk per HBA)
628 * . stripe width is driven by number of HBAs
630 * 4 - mirror with stripes within separate HBAs of mixed type
631 * . requires nsubs HBAs with mincomp disks
632 * . stripe width is driven by number of disks on HBA
634 * 5 - mirror with stripes across HBAs of mixed type
635 * . requires mincomp HBAs with nsubs disks
636 * (each stripe has a disk per HBA)
637 * . stripe width is driven by number of HBAs
639 * 6 - mirror with all stripes within the same HBA
640 * . requires an HBA with mincomp * nsubs disks
644 * group HBAs by characteristics
645 * for (each HBA grouping) and (nsub stripes not composed) {
646 * select next HBA group
647 * for (strategy[1,2,3]) and (nsub stripes not composed) {
648 * compose nsub stripes using HBAs in group
652 * if (nsub stripes not composed) {
653 * for (strategy[4,5,6]) and (nsub stripes not composed) {
654 * compose nsub stripes using all HBAs
658 * if (all stripes composed) {
659 * append composed stripes to results
664 layout_stripe_submirrors(
665 devconfig_t
*request
,
672 * these enums define the # of strategies and the preference order
673 * in which they are tried
676 ALL_STRIPES_ON_MPXIO
= 0,
677 STRIPE_PER_SIMILAR_HBA
,
678 STRIPE_ACROSS_SIMILAR_HBAS
,
679 N_SIMILAR_HBA_STRATEGIES
680 } similar_hba_strategy_order_t
;
683 STRIPE_PER_ANY_HBA
= 0,
684 STRIPE_ACROSS_ANY_HBAS
,
685 STRIPE_WITHIN_ANY_HBA
,
687 } any_hba_strategy_order_t
;
689 dlist_t
*usable_hbas
= NULL
;
690 dlist_t
*similar_hba_groups
= NULL
;
691 dlist_t
*iter
= NULL
;
692 dlist_t
*subs
= NULL
;
694 boolean_t usehsp
= B_FALSE
;
695 uint16_t mincomp
= 0;
696 uint16_t maxcomp
= 0;
700 (error
= get_usable_hbas(&usable_hbas
));
705 print_layout_submirrors_msg(devconfig_type_to_str(TYPE_STRIPE
),
708 if (dlist_length(usable_hbas
) == 0) {
710 volume_set_error(gettext("There are no usable HBAs."));
714 similar_hba_groups
= NULL
;
715 ((error
= group_similar_hbas(usable_hbas
, &similar_hba_groups
)) != 0) ||
718 * determine the min/max number of stripe components
719 * based on the request, the diskset defaults or the
720 * global defaults. These are absolute limits, the
721 * actual values are determined by the number of HBAs
722 * and/or disks available.
724 (error
= get_stripe_min_comp(request
, &mincomp
)) ||
725 (error
= get_stripe_max_comp(request
, &maxcomp
)) ||
726 (error
= get_volume_faultrecov(request
, &usehsp
));
731 for (iter
= similar_hba_groups
;
732 (error
== 0) && (subs
== NULL
) && (iter
!= NULL
);
735 dlist_t
*hbas
= (dlist_t
*)iter
->obj
;
737 similar_hba_strategy_order_t order
;
739 for (order
= ALL_STRIPES_ON_MPXIO
;
740 (order
< N_SIMILAR_HBA_STRATEGIES
) &&
741 (subs
== NULL
) && (error
== 0);
744 dlist_t
*selhbas
= NULL
;
745 dlist_t
*disks
= NULL
;
750 case ALL_STRIPES_ON_MPXIO
:
752 if (is_mpxio_enabled() == B_TRUE
) {
753 dlist_t
*mpxio_hbas
= NULL
;
755 /* see if any HBA supports MPXIO */
756 error
= select_mpxio_hbas(hbas
, &mpxio_hbas
);
757 if ((error
== 0) && (mpxio_hbas
!= NULL
)) {
760 oprintf(OUTPUT_TERSE
,
761 gettext(" -->Strategy 1: use %d-%d MPXIO disks\n"),
762 mincomp
* nsubs
, maxcomp
* nsubs
);
765 /* see if MPXIO HBA has enough disks */
766 error
= select_hbas_with_n_disks(
767 request
, mpxio_hbas
, (mincomp
* nsubs
),
770 if ((error
== 0) && (dlist_length(selhbas
) > 0)) {
771 error
= compose_stripes_within_hba(
772 request
, cursubs
, mpxio_hbas
, nbytes
,
773 nsubs
, maxcomp
, mincomp
, &subs
);
775 print_insufficient_hbas_msg(n
);
779 dlist_free_items(mpxio_hbas
, NULL
);
784 case STRIPE_PER_SIMILAR_HBA
:
786 error
= select_hbas_with_n_disks(
787 request
, hbas
, mincomp
, &selhbas
, &disks
);
792 oprintf(OUTPUT_TERSE
,
793 gettext(" -->Strategy 2: use %d-%d disks from %d similar HBAs - stripe per HBA\n"),
794 mincomp
, maxcomp
, nsubs
);
797 if ((n
= dlist_length(selhbas
)) >= nsubs
) {
798 error
= compose_stripe_per_hba(
799 request
, cursubs
, selhbas
, nbytes
,
800 nsubs
, maxcomp
, mincomp
, &subs
);
802 print_insufficient_hbas_msg(n
);
808 case STRIPE_ACROSS_SIMILAR_HBAS
:
810 error
= select_hbas_with_n_disks(
811 request
, hbas
, nsubs
, &selhbas
, &disks
);
816 oprintf(OUTPUT_TERSE
,
817 gettext(" -->Strategy 3: use %d disks from %d-%d similar HBAs - stripe across HBAs \n"),
818 nsubs
, mincomp
, maxcomp
);
821 if ((n
= dlist_length(selhbas
)) >= mincomp
) {
822 error
= compose_stripes_across_hbas(
823 request
, cursubs
, selhbas
, disks
,
824 nbytes
, nsubs
, maxcomp
, mincomp
, &subs
);
826 print_insufficient_hbas_msg(n
);
836 dlist_free_items(selhbas
, NULL
);
837 dlist_free_items(disks
, NULL
);
841 for (iter
= similar_hba_groups
; iter
!= NULL
; iter
= iter
->next
) {
842 dlist_free_items((dlist_t
*)iter
->obj
, NULL
);
844 dlist_free_items(similar_hba_groups
, NULL
);
846 /* retry using all available HBAs */
849 any_hba_strategy_order_t order
;
851 for (order
= STRIPE_PER_ANY_HBA
;
852 (order
< N_ANY_HBA_STRATEGIES
) &&
853 (subs
== NULL
) && (error
== 0);
856 dlist_t
*selhbas
= NULL
;
857 dlist_t
*disks
= NULL
;
862 case STRIPE_PER_ANY_HBA
:
864 error
= select_hbas_with_n_disks(
865 request
, usable_hbas
, nsubs
, &selhbas
, &disks
);
870 oprintf(OUTPUT_TERSE
,
871 gettext(" -->Strategy 4: use %d-%d disks from any %d HBAs - stripe per HBA\n"),
872 mincomp
, maxcomp
, nsubs
);
875 if ((n
= dlist_length(selhbas
)) >= nsubs
) {
876 error
= compose_stripe_per_hba(
877 request
, cursubs
, selhbas
, nbytes
,
878 nsubs
, maxcomp
, mincomp
, &subs
);
880 print_insufficient_hbas_msg(n
);
886 case STRIPE_ACROSS_ANY_HBAS
:
888 error
= select_hbas_with_n_disks(
889 request
, usable_hbas
, nsubs
, &selhbas
, &disks
);
894 oprintf(OUTPUT_TERSE
,
895 gettext(" -->Strategy 5: use %d disks from %d-%d HBAs - stripe across HBAs \n"),
896 nsubs
, mincomp
, maxcomp
);
899 if ((n
= dlist_length(selhbas
)) >= mincomp
) {
900 error
= compose_stripes_across_hbas(
901 request
, cursubs
, selhbas
, disks
,
902 nbytes
, nsubs
, maxcomp
, mincomp
, &subs
);
904 print_insufficient_hbas_msg(n
);
910 case STRIPE_WITHIN_ANY_HBA
:
912 error
= select_hbas_with_n_disks(
913 request
, usable_hbas
, (mincomp
* nsubs
),
919 oprintf(OUTPUT_TERSE
,
920 gettext(" -->Strategy 6: use %d-%d disks from any single HBA - %d stripes within HBA\n"),
921 mincomp
* nsubs
, maxcomp
* nsubs
, nsubs
);
923 if ((n
= dlist_length(selhbas
)) > 0) {
924 error
= compose_stripes_within_hba(
925 request
, cursubs
, selhbas
, nbytes
,
926 nsubs
, maxcomp
, mincomp
, &subs
);
928 print_insufficient_hbas_msg(n
);
938 dlist_free_items(selhbas
, NULL
);
939 dlist_free_items(disks
, NULL
);
944 *results
= dlist_append(subs
, *results
, AT_TAIL
);
950 * FUNCTION: layout_concat_submirrors(devconfig_t *request, dlist_t *cursubs,
951 * uint64_t nbytes, uint16_t nsubs, dlist_t **results)
953 * INPUT: request - pointer to a devconfig_t of the current request
954 * cursubs - pointer to a list of already composed submirrors
955 * nbytes - the desired capacity for the concats
957 * OUPUT: results - pointer to a list of composed volumes
959 * RETURNS: int - 0 on success
962 * PURPOSE: Main layout driver for composing concat submirrors.
964 * Attempts to construct nsub submirrors of size nbytes.
966 * Several different layout strategies are tried in order
967 * of preference until one succeeds or there are none left.
969 * 1 - mirror with all concats on the MPXIO "controller"
970 * . requires MPXIO to be enabled
971 * . requires nsubs available disks on the MPXIO HBA
973 * 2 - mirror with concats on separate HBAs of same type
974 * . requires nsubs HBAs with available disks
976 * 3 - mirror with concats across HBAs of same type
977 * . requires an HBA with at least 1 available disk
979 * 4 - mirror with concats on separate HBAs of mixed type
980 * . requires nsubs HBAs with available disks
982 * 5 - mirror with concats across HBAs of mixed type
983 * . requires an HBA with at least 1 available disk
985 * 6 - mirror with all concats on the same HBA
986 * . requires an HBA with at least nsubs available disks
990 * group HBAs by characteristics
991 * for (each HBA grouping) and (nsub concats not composed) {
992 * select next HBA group
993 * for (strategy[1,2,3]) and (nsub concats not composed) {
994 * compose nsub concats, nbytes in size
998 * if (nsub concats not composed) {
999 * for (strategy[4,5,6]) and (nsub concats not composed) {
1000 * compose nsub concats, nbytes in size
1004 * if (all concats composed) {
1005 * append composed concats to results
1010 layout_concat_submirrors(
1011 devconfig_t
*request
,
1018 * these enums define the # of strategies and the preference order
1019 * in which they are tried
1022 ALL_CONCATS_ON_MPXIO
= 0,
1023 CONCAT_PER_SIMILAR_HBA
,
1024 CONCAT_ACROSS_SIMILAR_HBAS
,
1025 N_SIMILAR_HBA_STRATEGIES
1026 } similar_hba_strategy_order_t
;
1029 CONCAT_PER_ANY_HBA
= 0,
1030 CONCAT_ACROSS_ANY_HBAS
,
1031 CONCAT_WITHIN_ANY_HBA
,
1032 N_ANY_HBA_STRATEGIES
1033 } any_hba_strategy_order_t
;
1035 dlist_t
*usable_hbas
= NULL
;
1036 dlist_t
*similar_hba_groups
= NULL
;
1037 dlist_t
*iter
= NULL
;
1038 dlist_t
*subs
= NULL
;
1040 boolean_t usehsp
= B_FALSE
;
1044 (error
= get_usable_hbas(&usable_hbas
));
1049 print_layout_submirrors_msg(devconfig_type_to_str(TYPE_CONCAT
),
1052 if (dlist_length(usable_hbas
) == 0) {
1053 print_no_hbas_msg();
1054 volume_set_error(gettext("There are no usable HBAs."));
1058 similar_hba_groups
= NULL
;
1059 ((error
= group_similar_hbas(usable_hbas
, &similar_hba_groups
)) != 0) ||
1060 (error
= get_volume_faultrecov(request
, &usehsp
));
1065 for (iter
= similar_hba_groups
;
1066 (error
== 0) && (subs
== NULL
) && (iter
!= NULL
);
1067 iter
= iter
->next
) {
1069 dlist_t
*hbas
= (dlist_t
*)iter
->obj
;
1071 similar_hba_strategy_order_t order
;
1073 for (order
= ALL_CONCATS_ON_MPXIO
;
1074 (order
< N_SIMILAR_HBA_STRATEGIES
) &&
1075 (subs
== NULL
) && (error
== 0);
1078 dlist_t
*selhbas
= NULL
;
1079 dlist_t
*disks
= NULL
;
1084 case ALL_CONCATS_ON_MPXIO
:
1086 if (is_mpxio_enabled() == B_TRUE
) {
1087 dlist_t
*mpxio_hbas
= NULL
;
1089 /* see if any HBA supports MPXIO */
1090 error
= select_mpxio_hbas(hbas
, &mpxio_hbas
);
1091 if ((error
== 0) && (mpxio_hbas
!= NULL
)) {
1094 oprintf(OUTPUT_TERSE
,
1095 gettext(" -->Strategy 1: use at least %d MPXIO disks\n"),
1099 /* see if MPXIO HBA has enough disks */
1100 error
= select_hbas_with_n_disks(
1101 request
, hbas
, nsubs
, &selhbas
, &disks
);
1104 ((n
= dlist_length(selhbas
)) > 0)) {
1105 error
= compose_concats_within_hba(
1106 request
, cursubs
, mpxio_hbas
, nbytes
,
1109 print_insufficient_hbas_msg(n
);
1113 dlist_free_items(mpxio_hbas
, NULL
);
1118 case CONCAT_PER_SIMILAR_HBA
:
1120 error
= select_hbas_with_n_disks(
1121 request
, hbas
, 1, &selhbas
, &disks
);
1126 oprintf(OUTPUT_TERSE
,
1127 gettext(" -->Strategy 2: use any disks from %d similar HBAs - concat per HBA\n"),
1131 if ((n
= dlist_length(selhbas
)) >= nsubs
) {
1132 error
= compose_concat_per_hba(
1133 request
, cursubs
, selhbas
,
1134 nbytes
, nsubs
, &subs
);
1136 print_insufficient_hbas_msg(n
);
1142 case CONCAT_ACROSS_SIMILAR_HBAS
:
1144 error
= select_hbas_with_n_disks(
1145 request
, hbas
, 1, &selhbas
, &disks
);
1150 oprintf(OUTPUT_TERSE
,
1151 gettext(" -->Strategy 3: use any disks from any similar HBAs - "
1152 "%d concats across HBAs\n"),
1155 error
= compose_concats_across_hbas(
1156 request
, cursubs
, selhbas
, disks
,
1157 nbytes
, nsubs
, &subs
);
1166 dlist_free_items(selhbas
, NULL
);
1167 dlist_free_items(disks
, NULL
);
1171 for (iter
= similar_hba_groups
; iter
!= NULL
; iter
= iter
->next
) {
1172 dlist_free_items((dlist_t
*)iter
->obj
, NULL
);
1174 dlist_free_items(similar_hba_groups
, NULL
);
1176 /* retry using all available HBAs */
1179 any_hba_strategy_order_t order
;
1181 for (order
= CONCAT_PER_ANY_HBA
;
1182 (order
< N_ANY_HBA_STRATEGIES
) &&
1183 (subs
== NULL
) && (error
== 0);
1186 dlist_t
*selhbas
= NULL
;
1187 dlist_t
*disks
= NULL
;
1192 case CONCAT_PER_ANY_HBA
:
1194 error
= select_hbas_with_n_disks(
1195 request
, usable_hbas
, 1, &selhbas
, &disks
);
1200 oprintf(OUTPUT_TERSE
,
1201 gettext(" -->Strategy 4: use any disks from %d HBAs - concat per HBA\n"),
1204 if ((n
= dlist_length(selhbas
)) >= nsubs
) {
1205 error
= compose_concat_per_hba(
1206 request
, cursubs
, selhbas
,
1207 nbytes
, nsubs
, &subs
);
1209 print_insufficient_hbas_msg(n
);
1214 case CONCAT_ACROSS_ANY_HBAS
:
1216 error
= select_hbas_with_n_disks(
1217 request
, usable_hbas
, 1, &selhbas
, &disks
);
1222 oprintf(OUTPUT_TERSE
,
1223 gettext(" -->Strategy 5: use any disks from any HBA - %d concats across HBAs\n"),
1226 error
= compose_concats_across_hbas(
1227 request
, cursubs
, selhbas
, disks
,
1228 nbytes
, nsubs
, &subs
);
1233 case CONCAT_WITHIN_ANY_HBA
:
1235 error
= select_hbas_with_n_disks(
1236 request
, usable_hbas
, 1, &selhbas
, &disks
);
1241 oprintf(OUTPUT_TERSE
,
1242 gettext(" -->Strategy 6: use any disks from any single HBA - %d concats within an HBA\n"),
1246 if ((n
= dlist_length(selhbas
)) > 0) {
1247 error
= compose_concats_within_hba(
1248 request
, cursubs
, selhbas
,
1249 nbytes
, nsubs
, &subs
);
1251 print_insufficient_hbas_msg(n
);
1261 dlist_free_items(selhbas
, NULL
);
1262 dlist_free_items(disks
, NULL
);
1267 *results
= dlist_append(subs
, *results
, AT_TAIL
);
1274 * FUNCTION: compose_stripe_per_hba(devconfig_t *request,
1275 * dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
1276 * uint16_t nsubs, int maxcomp, int mincomp,
1277 * dlist_t **results)
1279 * INPUT: request - pointer to a devconfig_t of the current request
1280 * cursubs - pointer to a list of already composed submirrors
1281 * hbas - pointer to a list of available HBAs
1282 * nbytes - the desired capacity for the stripes
1283 * nsubs - the desired number of stripes
1284 * maxcomp - the maximum number of stripe components
1285 * mincomp - the minimum number of stripe components
1287 * OUPUT: results - pointer to a list of composed volumes
1289 * RETURNS: int - 0 on success
1292 * PURPOSE: Layout function which composes the requested number of stripes
1293 * of the desired size using available disks on any of the HBAs
1294 * from the input list.
1296 * The number of components within the composed stripes will be
1297 * in the range of mincomp to ncomp, preferring more components
1298 * over fewer. All stripes composed by a single call to this
1299 * function will have the same number of components.
1301 * Each stripe will use disks from a single HBA.
1303 * All input HBAs are expected to have at least mincomp available
1306 * If the stripes can be composed, they are appended to the list
1307 * of result volumes.
1309 * while (more HBAs and more stripes to compose) {
1311 * get available space for this HBA
1312 * get available disks for this HBA
1313 * if (not enough space or disks) {
1317 * use # disks as # of stripe components - limit to maxcomp
1318 * for ((ncomps downto mincomp) && (more stripes to compose)) {
1319 * while (more stripes to compose) {
1320 * if a stripe can be composed using disks {
1322 * increment stripe count
1324 * while (more HBAs and more stripes to compose) {
1326 * get available space for this HBA
1327 * get available disks for this HBA
1328 * if (not enough space or disks) {
1331 * if a stripe can be composed using disks {
1333 * increment stripe count
1337 * if (not all stripes composed) {
1338 * delete any compose stripes
1343 * if (not all stripes composed) {
1344 * delete any stripes composed
1348 * if (not all stripes composed) {
1349 * delete any stripes composed
1352 * append composed stripes to results
1355 compose_stripe_per_hba(
1356 devconfig_t
*request
,
1366 dlist_t
*list
= NULL
;
1367 dlist_t
*iter
= NULL
;
1369 oprintf(OUTPUT_VERBOSE
,
1370 gettext(" --->Trying to compose %d Stripes with "
1371 "%d-%d components on separate HBAs.\n"),
1372 nsubs
, mincomp
, maxcomp
);
1375 (list
== NULL
) && (iter
!= NULL
) && (error
== 0);
1376 iter
= iter
->next
) {
1378 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
1379 dlist_t
*disks
= NULL
;
1384 ((error
= get_display_name(hba
, &name
)) != 0) ||
1385 (error
= hba_get_avail_disks_and_space(request
,
1386 hba
, &disks
, &space
));
1391 /* check for sufficient space and minimum # of disks */
1392 if (space
< nbytes
) {
1393 (void) print_hba_insufficient_space_msg(name
, space
);
1394 dlist_free_items(disks
, NULL
);
1398 if ((ncomp
= dlist_length(disks
)) < mincomp
) {
1399 print_insufficient_disks_msg(ncomp
);
1400 dlist_free_items(disks
, NULL
);
1404 /* make the stripe as wide as possible, up to maxcomp */
1405 for (ncomp
= ((ncomp
> maxcomp
) ? maxcomp
: ncomp
);
1406 (list
== NULL
) && (ncomp
>= mincomp
) && (error
== 0);
1411 /* try composing nsubs stripes with ncomp components */
1412 while (count
< nsubs
) {
1414 devconfig_t
*stripe
= NULL
;
1415 dlist_t
*item
= NULL
;
1416 dlist_t
*iter1
= NULL
;
1418 /* build first stripe using disks on this HBA */
1419 if (((error
= populate_stripe(request
, nbytes
,
1420 disks
, ncomp
, cursubs
, &stripe
)) != 0) ||
1422 /* first stripe failed at the current width */
1423 /* break while loop and try a different width */
1427 /* composed a stripe */
1428 if ((item
= dlist_new_item((void*)stripe
)) == NULL
) {
1433 list
= dlist_append(item
, list
, AT_TAIL
);
1435 /* compose stripes on remaining HBAs */
1436 for (iter1
= iter
->next
;
1437 (count
< nsubs
) && (iter1
!= NULL
) && (error
== 0);
1438 iter1
= iter1
->next
) {
1440 dm_descriptor_t hba1
= (uintptr_t)iter1
->obj
;
1441 uint64_t space1
= 0;
1442 dlist_t
*disks1
= NULL
;
1444 error
= hba_get_avail_disks_and_space(request
,
1445 hba1
, &disks1
, &space1
);
1450 /* enough space/disks on this HBA? */
1451 if ((dlist_length(disks1
) < ncomp
) ||
1452 (space1
< nbytes
)) {
1453 dlist_free_items(disks1
, NULL
);
1458 error
= populate_stripe(
1459 request
, nbytes
, disks1
,
1460 ncomp
, cursubs
, &stripe
);
1462 if (stripe
!= NULL
) {
1463 /* prepare to compose another */
1464 if ((item
= dlist_new_item(
1465 (void *)stripe
)) == NULL
) {
1469 list
= dlist_append(item
, list
, AT_TAIL
);
1473 dlist_free_items(disks1
, NULL
);
1477 if ((iter1
== NULL
) && (count
< nsubs
)) {
1479 * no HBAs remain and haven't composed
1480 * enough stripes at the current width.
1481 * break while loop and try another width.
1487 if (count
< nsubs
) {
1489 * stripe composition at current width failed...
1490 * prepare to try a narrower width.
1491 * NB: narrower widths may work since some HBA(s)
1492 * may have fewer available disks
1494 print_layout_submirrors_failed_msg(
1495 devconfig_type_to_str(TYPE_STRIPE
),
1498 dlist_free_items(list
, free_devconfig_object
);
1503 dlist_free_items(disks
, NULL
);
1508 *results
= dlist_append(list
, *results
, AT_TAIL
);
1510 dlist_free_items(list
, free_devconfig_object
);
1517 * FUNCTION: compose_stripes_across_hbas(devconfig_t *request,
1518 * dlist_t *cursubs, dlist_t *hbas, dlist_t *disks,
1519 * uint64_t nbytes, uint16_t nsubs, int maxcomp,
1520 * int mincomp, dlist_t **results)
1522 * INPUT: request - pointer to a devconfig_t of the current request
1523 * cursubs - pointer to a list of already composed submirrors
1524 * hbas - pointer to a list of available HBAs
1525 * disks - pointer to a list of available disks on the HBAs
1526 * nbytes - the desired capacity for the stripes
1527 * nsubs - the desired number of stripes
1528 * ncomp - the maximum number of stripe components
1529 * mincomp - the minimum number of stripe components
1531 * OUPUT: results - pointer to a list of composed volumes
1533 * RETURNS: int - 0 on success
1536 * PURPOSE: Layout function which composes the requested number of stripes
1537 * of the desired size using available disks on any of the HBAs
1538 * from the input list.
1540 * The number of components within the composed stripes will be
1541 * in the range of mincomp to ncomp, preferring more components
1542 * over fewer. All stripes composed by a single call to this
1543 * function will have the same number of components.
1545 * Each stripe will use a disk from several different HBAs.
1547 * All input HBAs are expected to have at least nsubs available
1550 * If the stripes can be composed, they are appended to the list
1551 * of result volumes.
1553 * for (ncomps downto mincomp) {
1555 * copy the input disk list
1556 * while (more stripes to compose) {
1557 * if a stripe can be composed using disks {
1559 * remove used disks from disk list
1560 * increment stripe count
1565 * free copied disk list
1566 * if (not all stripes composed) {
1567 * delete any stripes composed
1572 * if (not all stripes composed) {
1573 * delete any stripes composed
1576 * append composed stripes to results
1579 compose_stripes_across_hbas(
1580 devconfig_t
*request
,
1593 dlist_t
*list
= NULL
;
1595 while ((ncomp
>= mincomp
) && (count
< nsubs
) && (error
== 0)) {
1599 dlist_t
*disks_copy
= NULL
;
1601 oprintf(OUTPUT_VERBOSE
,
1602 gettext(" --->Trying to compose %d Stripes with "
1603 "%d components across %d HBAs.\n"),
1604 nsubs
, ncomp
, dlist_length(hbas
));
1606 /* copy disk list, it is modified by the while loop */
1607 for (iter
= disks
; iter
!= NULL
; iter
= iter
->next
) {
1608 if ((item
= dlist_new_item(iter
->obj
)) == NULL
) {
1611 disks_copy
= dlist_append(item
, disks_copy
, AT_HEAD
);
1615 /* compose nsubs stripe submirrors of ncomp components */
1616 while ((count
< nsubs
) && (error
== 0)) {
1618 devconfig_t
*stripe
= NULL
;
1619 dlist_t
*item
= NULL
;
1621 error
= populate_stripe(
1622 request
, nbytes
, disks_copy
, ncomp
, cursubs
, &stripe
);
1624 if ((error
== 0) && (stripe
!= NULL
)) {
1625 if ((item
= dlist_new_item((void *)stripe
)) == NULL
) {
1629 list
= dlist_append(item
, list
, AT_TAIL
);
1630 error
= remove_used_disks(&disks_copy
, stripe
);
1632 } else if (stripe
== NULL
) {
1637 /* free copy of disk list */
1638 dlist_free_items(disks_copy
, NULL
);
1641 if ((error
== 0) && (count
< nsubs
)) {
1642 /* failed to compose enough stripes at this width, */
1643 /* prepare to try again with the next narrower width. */
1644 print_layout_submirrors_failed_msg(
1645 devconfig_type_to_str(TYPE_STRIPE
),
1648 dlist_free_items(list
, free_devconfig_object
);
1655 if (count
< nsubs
) {
1656 dlist_free_items(list
, free_devconfig_object
);
1659 *results
= dlist_append(list
, *results
, AT_TAIL
);
1666 * FUNCTION: compose_stripes_within_hba(devconfig_t *request,
1667 * dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
1668 * uint16_t nsubs, int maxcomp, int mincomp,
1669 * dlist_t **results)
1671 * INPUT: request - pointer to a devconfig_t of the current request
1672 * cursubs - pointer to a list of already composed submirrors
1673 * hbas - pointer to a list of available HBAs
1674 * nbytes - the desired capacity for the stripes
1675 * nsubs - the desired number of stripes
1676 * maxcomp - the maximum number of stripe components
1677 * mincomp - the minimum number of stripe components
1678 * nsubs - the number of stripes to be composed
1680 * OUPUT: results - pointer to a list of composed volumes
1682 * RETURNS: int - 0 on success
1685 * PURPOSE: Layout function which composes the requested number of stripes
1686 * of the desired size using available disks within any single
1687 * HBA from the input list.
1689 * The number of components within the composed stripes will be
1690 * in the range of mincomp to maxcomp, preferring more components
1691 * over fewer. All stripes composed by a single call to this
1692 * function will have the same number of components.
1694 * All stripes will use disks from a single HBA.
1696 * All input HBAs are expected to have at least nsubs * mincomp
1697 * available disks and total space sufficient for subs stripes.
1699 * If the stripes can be composed, they are appended to the list
1700 * of result volumes.
1702 * while (more HBAs and more stripes need to be composed) {
1704 * if (not enough available space on this HBA) {
1707 * get available disks for HBA
1708 * use # disks as # of stripe components - limit to maxcomp
1709 * for (ncomps downto mincomp) {
1710 * if ((ncomps * nsubs) > ndisks) {
1713 * while (more stripes need to be composed) {
1714 * if a stripe can be composed using disks {
1716 * remove used disks from disk list
1720 * if (not all stripes composed) {
1721 * delete any stripes composed
1726 * if (not all stripes composed) {
1727 * delete any stripes composed
1730 * append composed stripes to results
1733 compose_stripes_within_hba(
1734 devconfig_t
*request
,
1746 dlist_t
*list
= NULL
;
1747 dlist_t
*iter
= NULL
;
1750 (count
< nsubs
) && (iter
!= NULL
) && (error
== 0);
1751 iter
= iter
->next
) {
1753 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
1755 dlist_t
*disks
= NULL
;
1760 ((error
= get_display_name(hba
, &name
)) != 0) ||
1761 (error
= hba_get_avail_disks_and_space(request
,
1762 hba
, &disks
, &space
));
1764 dlist_free_items(disks
, NULL
);
1768 if (space
< (nsubs
* nbytes
)) {
1769 (void) print_hba_insufficient_space_msg(name
, space
);
1770 dlist_free_items(disks
, NULL
);
1774 ndisks
= dlist_length(disks
);
1777 * try composing stripes from ncomp down to mincomp.
1778 * stop when nsubs stripes have been composed, or when the
1779 * minimum stripe width has been tried
1781 for (ncomp
= maxcomp
;
1782 (ncomp
>= mincomp
) && (count
!= nsubs
) && (error
== 0);
1785 oprintf(OUTPUT_VERBOSE
,
1786 gettext(" --->Trying to compose %d Stripes with "
1787 "%d components on a single HBA.\n"),
1790 if (ndisks
< (ncomp
* nsubs
)) {
1791 print_insufficient_disks_msg(ndisks
);
1795 /* try composing nsubs stripes, each ncomp wide */
1796 for (count
= 0; (count
< nsubs
) && (error
== 0); count
++) {
1798 devconfig_t
*stripe
= NULL
;
1800 error
= populate_stripe(
1801 request
, nbytes
, disks
, ncomp
, cursubs
, &stripe
);
1803 if ((error
== 0) && (stripe
!= NULL
)) {
1805 dlist_t
*item
= dlist_new_item((void *)stripe
);
1809 list
= dlist_append(item
, list
, AT_TAIL
);
1810 error
= remove_used_disks(&disks
, stripe
);
1812 } else if (stripe
== NULL
) {
1817 if (count
< nsubs
) {
1818 /* failed to compose enough stripes at this width, */
1819 /* prepare to try again with fewer components */
1820 print_layout_submirrors_failed_msg(
1821 devconfig_type_to_str(TYPE_STRIPE
),
1824 dlist_free_items(list
, free_devconfig_object
);
1829 dlist_free_items(disks
, NULL
);
1832 if (count
< nsubs
) {
1833 dlist_free_items(list
, free_devconfig_object
);
1843 * FUNCTION: compose_concats_per_hba(devconfig_t *request,
1844 * dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
1845 * uint16_t nsubs, dlist_t **results)
1847 * INPUT: request - pointer to a devconfig_t of the current request
1848 * cursubs - pointer to a list of already composed submirrors
1849 * hbas - pointer to a list of available HBAs
1850 * nbytes - the desired capacity for the concats
1851 * nsubs - the number of concats to be composed
1853 * OUPUT: results - pointer to a list of composed volumes
1855 * RETURNS: int - 0 on success
1858 * PURPOSE: Layout function which composes the requested number of concats
1859 * of the desired size using available disks within HBAs from the
1860 * input list. Each concat will be composed using disks from a
1863 * If the concats can be composed, they are appended to the list
1864 * of result volumes.
1866 * while (more HBAs AND more concats need to be composed) {
1867 * if (not enough available space on this HBA) {
1871 * get available disks for HBA
1872 * if (concat can be composed) {
1878 * if (not all stripes composed) {
1879 * delete any concats composed
1882 * append composed concats to results
1885 compose_concat_per_hba(
1886 devconfig_t
*request
,
1896 dlist_t
*list
= NULL
;
1897 dlist_t
*iter
= NULL
;
1899 oprintf(OUTPUT_VERBOSE
,
1900 gettext(" --->Trying to compose %d Concats on "
1901 "separate HBAs.\n"), nsubs
);
1904 (iter
!= NULL
) && (error
== 0) && (count
< nsubs
);
1905 iter
= iter
->next
) {
1907 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
1909 devconfig_t
*concat
= NULL
;
1910 dlist_t
*disks
= NULL
;
1912 error
= hba_get_avail_disks_and_space(request
, hba
, &disks
, &space
);
1913 if ((error
== 0) && (space
>= nbytes
)) {
1914 error
= populate_concat(
1915 request
, nbytes
, disks
, cursubs
, &concat
);
1918 if ((error
== 0) && (concat
!= NULL
)) {
1919 dlist_t
*item
= dlist_new_item((void *)concat
);
1924 list
= dlist_append(item
, list
, AT_TAIL
);
1928 dlist_free_items(disks
, NULL
);
1931 if (count
!= nsubs
) {
1932 print_layout_submirrors_failed_msg(
1933 devconfig_type_to_str(TYPE_CONCAT
),
1936 dlist_free_items(list
, free_devconfig_object
);
1939 *results
= dlist_append(list
, *results
, AT_TAIL
);
1946 * FUNCTION: compose_concats_across_hbas(devconfig_t *request,
1947 * dlist_t *cursubs, dlist_t *hbas, dlist_t *disks,
1948 * uint64_t nbytes, uint16_t nsubs, dlist_t **results)
1950 * INPUT: request - pointer to a devconfig_t of the current request
1951 * cursubs - pointer to a list of already composed submirrors
1952 * hbas - pointer to a list of available HBAs
1953 * disks - pointer to a list of available disks on the HBAs
1954 * nbytes - the desired capacity for the concats
1955 * nsubs - the number of concats to be composed
1957 * OUPUT: results - pointer to a list of composed volumes
1959 * RETURNS: int - 0 on success
1962 * PURPOSE: Layout function which composes the requested number of concats
1963 * of the desired size using any available disks from the input
1964 * list of available HBAs.
1966 * If the concats can be composed, they are appended to the list
1967 * of result volumes.
1969 * copy the input disk list
1970 * while (more concats need to be composed) {
1971 * if (a concat can be composed using remaining disks) {
1973 * remove used disks from disk list
1980 * if (not all concats composed) {
1981 * delete any concats composed
1984 * append composed concats to results
1987 compose_concats_across_hbas(
1988 devconfig_t
*request
,
1999 dlist_t
*list
= NULL
;
2000 dlist_t
*item
= NULL
;
2001 dlist_t
*iter
= NULL
;
2002 dlist_t
*disks_copy
= NULL
;
2004 /* copy disk list, it is modified by the while loop */
2005 for (iter
= disks
; iter
!= NULL
; iter
= iter
->next
) {
2006 if ((item
= dlist_new_item(iter
->obj
)) == NULL
) {
2009 disks_copy
= dlist_append(item
, disks_copy
, AT_HEAD
);
2013 while ((count
< nsubs
) && (error
== 0)) {
2015 devconfig_t
*concat
= NULL
;
2017 error
= populate_concat(
2018 request
, nbytes
, disks_copy
, cursubs
, &concat
);
2020 if ((error
== 0) && (concat
!= NULL
)) {
2022 item
= dlist_new_item((void *)concat
);
2027 list
= dlist_append(item
, list
, AT_TAIL
);
2028 error
= remove_used_disks(&disks_copy
, concat
);
2030 } else if (concat
== NULL
) {
2035 /* free copy of disk list */
2036 dlist_free_items(disks_copy
, NULL
);
2039 if (count
!= nsubs
) {
2040 print_layout_submirrors_failed_msg(
2041 devconfig_type_to_str(TYPE_CONCAT
),
2044 dlist_free_items(list
, free_devconfig_object
);
2047 *results
= dlist_append(list
, *results
, AT_TAIL
);
2054 * FUNCTION: compose_concats_within_hba(devconfig_t *request,
2055 * dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
2056 * uint16_t nsubs, dlist_t **results)
2058 * INPUT: request - pointer to a devconfig_t of the current request
2059 * cursubs - pointer to a list of already composed submirrors
2060 * hbas - pointer to a list of available HBAs
2061 * nbytes - the desired capacity for the concats
2062 * nsubs - the number of concats to be composed
2064 * OUPUT: results - pointer to a list of composed volumes
2066 * RETURNS: int - 0 on success
2069 * PURPOSE: Layout function which composes the requested number of concats
2070 * of the desired size using available disks within any single
2071 * HBA from the input list.
2074 * HBAs in the list are expected to have at least 2 available
2075 * disks and total space sufficient for the submirrors.
2077 * If the concats can be composed, they are appended to the list
2078 * of result volumes.
2080 * while (more HBAs) {
2081 * if (not enough available space on this HBA) {
2085 * get available disks for HBA
2086 * while (more concats need to be composed) {
2087 * if a concat can be composed using disks {
2089 * remove used disks from disk list
2092 * delete any concats composed
2098 * if (not all concats composed) {
2099 * delete any concats composed
2102 * append composed concats to results
2105 compose_concats_within_hba(
2106 devconfig_t
*request
,
2115 dlist_t
*iter
= NULL
;
2116 dlist_t
*list
= NULL
;
2119 oprintf(OUTPUT_VERBOSE
,
2120 gettext(" --->Trying to compose %d Concats within "
2121 "a single HBA.\n"), nsubs
);
2124 (count
< nsubs
) && (error
== 0) && (iter
!= NULL
);
2125 iter
= iter
->next
) {
2127 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
2128 dlist_t
*disks
= NULL
;
2131 error
= hba_get_avail_disks_and_space(request
, hba
, &disks
, &space
);
2132 if ((error
== 0) && (space
>= (nsubs
* nbytes
))) {
2134 /* try composing nsubs concats all on this HBA */
2136 while ((count
< nsubs
) && (error
== 0)) {
2137 devconfig_t
*concat
= NULL
;
2138 dlist_t
*item
= NULL
;
2140 error
= populate_concat(
2141 request
, nbytes
, disks
, cursubs
, &concat
);
2143 if ((error
== 0) && (concat
!= NULL
)) {
2144 item
= dlist_new_item((void*)concat
);
2149 list
= dlist_append(item
, list
, AT_TAIL
);
2150 error
= remove_used_disks(&disks
, concat
);
2152 } else if (concat
== NULL
) {
2153 dlist_free_items(list
, free_devconfig_object
);
2160 dlist_free_items(disks
, NULL
);
2163 if (count
< nsubs
) {
2164 print_layout_submirrors_failed_msg(
2165 devconfig_type_to_str(TYPE_CONCAT
),
2168 dlist_free_items(list
, free_devconfig_object
);
2171 *results
= dlist_append(list
, *results
, AT_TAIL
);
2178 * FUNCTION: remove_used_disks(dlist_t **disks, devconfig_t *volume)
2180 * INPUT: disks - pointer to a list of disks
2181 * volume - pointer to a devconfig_t volume
2183 * OUPUT: disks - pointer to new list of disks
2185 * RETURNS: int - 0 on success
2188 * PURPOSE: Helper which updates the input list of disks by removing
2189 * those which have slices used by the input volume.
2191 * Constructs a new list containing only disks not used by
2194 * The original list is freed.
2199 devconfig_t
*volume
)
2201 dlist_t
*list
= NULL
;
2202 dlist_t
*iter
= NULL
;
2203 dlist_t
*item
= NULL
;
2206 for (iter
= *disks
; (iter
!= NULL
) && (error
== 0); iter
= iter
->next
) {
2208 dm_descriptor_t diskp
= (uintptr_t)iter
->obj
;
2209 boolean_t shares
= B_FALSE
;
2211 error
= volume_shares_disk(diskp
, volume
, &shares
);
2212 if ((error
== 0) && (shares
!= B_TRUE
)) {
2213 /* disk is unused */
2214 if ((item
= dlist_new_item((void*)(uintptr_t)diskp
)) == NULL
) {
2217 list
= dlist_append(item
, list
, AT_TAIL
);
2223 dlist_free_items(list
, NULL
);
2226 /* free original disk list, return new list */
2227 dlist_free_items(*disks
, NULL
);
2236 * FUNCTION: volume_shares_disk(dm_descriptor_t disk,
2237 * devconfig_t *volume, boolean_t *shares)
2239 * INPUT: disk - a dm_descriptor_t handle for the disk of interest
2240 * volume - a devconfig_t pointer to a volume
2241 * bool - a boolean_t pointer to hold the result
2243 * RETURNS: int - 0 on success
2246 * PURPOSE: Determines if the input disk has a slice that is used
2247 * as a component by the input volume.
2249 * If the disk contributes a slice component, bool is set
2250 * to B_TRUE, B_FALSE otherwise.
2254 dm_descriptor_t disk
,
2255 devconfig_t
*volume
,
2258 dlist_t
*iter
= NULL
;
2263 /* look at all slices in the volume */
2264 for (iter
= devconfig_get_components(volume
);
2265 (iter
!= NULL
) && (*shares
== B_FALSE
) && (error
== 0);
2266 iter
= iter
->next
) {
2268 devconfig_t
*dev
= (devconfig_t
*)iter
->obj
;
2270 if (devconfig_isA(dev
, TYPE_SLICE
)) {
2272 /* get disk for volume's slice */
2273 dm_descriptor_t odisk
= NULL
;
2276 ((error
= devconfig_get_name(dev
, &oname
)) != 0) ||
2277 (error
= get_disk_for_named_slice(oname
, &odisk
));
2280 if (compare_descriptor_names(
2281 (void*)(uintptr_t)disk
, (void*)(uintptr_t)odisk
) == 0) {
2282 /* otherslice is on same disk, stop */
2293 * FUNCTION: select_mpxio_hbas(dlist_t *hbas, dlist_t **mpxio_hbas)
2295 * INPUT: hbas - pointer to a list of dm_descriptor_t HBA handles
2297 * OUTPUT: mpxio_hbas - pointer to a new list of containing HBAs that
2298 * are multiplex enabled.
2300 * RETURNS: int - 0 on success
2303 * PURPOSE: Iterates the input list of HBAs and builds a new list
2304 * containing those that are multiplex enabled.
2306 * The output list should be passed to dlist_free_items()
2307 * when no longer needed.
2312 dlist_t
**mpxio_hbas
)
2317 for (iter
= hbas
; (iter
!= NULL
) && (error
== 0); iter
= iter
->next
) {
2318 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
2319 boolean_t ismpxio
= B_FALSE
;
2320 if ((error
= hba_is_multiplex(hba
, &ismpxio
)) == 0) {
2321 if (ismpxio
== B_TRUE
) {
2322 dlist_t
*item
= dlist_new_item((void *)(uintptr_t)hba
);
2325 dlist_append(item
, *mpxio_hbas
, AT_TAIL
);
2334 dlist_free_items(*mpxio_hbas
, NULL
);
2342 * FUNCTION: set_explicit_submirror_names(dlist_t *reqs, dlist_t *subs)
2344 * INPUT: reqs - pointer to a list of request devconfig_ts
2345 * subs - pointer to a list of volume devconfig_ts
2347 * SIDEEFFECT: Modifies the volume names.
2349 * RETURNS: int - 0 on success
2352 * PURPOSE: Iterates the lists of volumes and requests and calls
2353 * set_explicit_mirror_name for each pair.
2356 set_explicit_submirror_names(
2362 while ((reqs
!= NULL
) && (subs
!= NULL
) && (error
== 0)) {
2364 error
= set_explicit_submirror_name(
2365 (devconfig_t
*)reqs
->obj
,
2366 (devconfig_t
*)subs
->obj
);
2376 * FUNCTION: set_explicit_submirror_name(dlist_t *req, dlist_t *sub)
2378 * INPUT: req - pointer to a request devconfig_t
2379 * sub - pointer to a volume devconfig_t
2381 * SIDEEFFECT: Modifies the volume name.
2383 * RETURNS: int - 0 on success
2386 * PURPOSE: Clears the volume's current name and returns the name
2387 * to the available pool.
2389 * If a name is specified in the request, the name is used
2390 * as the volume's name.
2392 * (Unnamed submirrors will have default names assigned
2393 * during final mirror assembly.)
2396 set_explicit_submirror_name(
2403 /* unset current submirror name */
2404 (void) devconfig_get_name(sub
, &name
);
2405 release_volume_name(name
);
2406 (void) devconfig_set_name(sub
, "");
2408 if (devconfig_get_name(req
, &name
) != ERR_ATTR_UNSET
) {
2409 (void) devconfig_set_name(sub
, name
);