1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <string.h>
30
31 #include <libintl.h>
32
33 #include "volume_error.h"
34 #include "volume_devconfig.h"
35 #include "volume_dlist.h"
36 #include "volume_output.h"
37
38 #include "layout_device_cache.h"
39 #include "layout_device_util.h"
40 #include "layout_discovery.h"
41 #include "layout_dlist_util.h"
42 #include "layout_messages.h"
43 #include "layout_request.h"
44 #include "layout_slice.h"
45 #include "layout_svm_util.h"
46
47 #define _LAYOUT_STRIPE_C
48
49 static int compose_stripe(
50 devconfig_t *request,
51 uint64_t nbytes,
52 dlist_t *disks,
53 int max,
54 int min,
55 dlist_t *othervols,
56 devconfig_t **stripe);
57
58 static int compose_stripe_within_hba(
59 devconfig_t *request,
60 dlist_t *hbas,
61 uint64_t nbytes,
62 uint16_t min,
63 uint16_t max,
64 devconfig_t **stripe);
65
66 static int assemble_stripe(
67 devconfig_t *request,
68 dlist_t *comps,
69 devconfig_t **stripe);
70
71 static dlist_t *
72 order_stripe_components_alternate_hbas(
73 dlist_t *comps);
74
75 static int compute_usable_stripe_capacity(
76 dlist_t *comps,
77 uint64_t ilace,
78 uint64_t *nbytes);
79
80 /*
81 * FUNCTION: layout_stripe(devconfig_t *request, uint64_t nbytes,
82 * dlist_t **results)
83 *
84 * INPUT: request - pointer to a devconfig_t of the current request
85 * nbytes - the desired capacity of the stripe
86 *
87 * OUPUT: results - pointer to a list of composed volumes
88 *
89 * RETURNS: int - 0 on success
90 * !0 otherwise.
91 *
92 * PURPOSE: Main layout driver for composing stripe volumes.
93 *
94 * Attempts to construct a stripe of size nbytes.
95 *
96 * Basic goal of all strategies is to build wide-thin stripes:
97 * build widest stripe possible across as many HBAs as possible.
98 *
99 * Several different layout strategies are tried in order
100 * of preference until one succeeds or there are none left.
101 *
102 * 1 - stripe across similar HBAs
103 * . number of components is driven by # of HBAs
104 * . requires mincomp available HBAs
105 *
106 * 2 - stripe within a single HBA
107 * . number of components is driven by # of disks
108 * . requires at least 1 HBA with mincomp disks
109 *
110 * 3 - stripe across all available disks on similar HBAs
111 * . number of components is driven by # of disk
112 * . requires at least mincomp disks
113 *
114 * 4 - stripe across all available HBAs
115 * . number of components is driven by # of HBAs
116 * . requires at least mincomp HBAs
117 *
118 * 5 - stripe across all available disks on all HBAs
119 * . number of components is driven by # of disks
120 * . requires at least mincomp disks
121 *
122 * Each strategy tries to compose a stripe with the
123 * maximum number of components first then reduces the
124 * number of components down to mincomp.
125 *
126 * get allowed minimum number of stripe components
127 * get allowed maximum number of stripe components
128 * get available HBAs
129 *
130 * group HBAs by characteristics
131 * for (each HBA grouping) and (stripe not composed) {
132 * select next HBA group
133 * for (strategy[1,2,3]) and (stripe not composed) {
134 * compose stripe using HBAs in group
135 * }
136 * }
137 *
138 * if (stripe not composed) {
139 * for (strategy[4,5]) and (stripe not composed) {
140 * compose stripe using all HBAs
141 * }
142 * }
143 *
144 * if (stripe composed) {
145 * append composed stripe to results
146 * }
147 *
148 */
149 int
layout_stripe(devconfig_t * request,uint64_t nbytes,dlist_t ** results)150 layout_stripe(
151 devconfig_t *request,
152 uint64_t nbytes,
153 dlist_t **results)
154 {
155 /*
156 * these enums define the # of strategies and the preference order
157 * in which they are tried
158 */
159 typedef enum {
160 STRIPE_ACROSS_SIMILAR_HBAS_DISK_PER = 0,
161 STRIPE_WITHIN_SIMILAR_HBA,
162 STRIPE_ACROSS_SIMILAR_HBAS,
163 N_SIMILAR_HBA_STRATEGIES
164 } similar_hba_strategy_order_t;
165
166 typedef enum {
167 STRIPE_ACROSS_ANY_HBAS_DISK_PER = 0,
168 STRIPE_ACROSS_ANY_HBAS,
169 N_ANY_HBA_STRATEGIES
170 } any_hba_strategy_order_t;
171
172
173 dlist_t *usable_hbas = NULL;
174 dlist_t *similar_hba_groups = NULL;
175 dlist_t *iter = NULL;
176 devconfig_t *stripe = NULL;
177
178 uint16_t mincomp = 0;
179 uint16_t maxcomp = 0;
180
181 int error = 0;
182
183 (error = get_usable_hbas(&usable_hbas));
184 if (error != 0) {
185 return (error);
186 }
187
188 print_layout_volume_msg(devconfig_type_to_str(TYPE_STRIPE), nbytes);
189
190 if (dlist_length(usable_hbas) == 0) {
191 print_no_hbas_msg();
192 volume_set_error(gettext("There are no usable HBAs."));
193 return (-1);
194 }
195
196 ((error = group_similar_hbas(usable_hbas, &similar_hba_groups)) != 0) ||
197
198 /*
199 * determine the min/max number of stripe components
200 * based on the request, the diskset defaults or the
201 * global defaults. These are absolute limits, the
202 * actual values are determined by the number of HBAs
203 * and/or disks available.
204 */
205 (error = get_stripe_min_comp(request, &mincomp)) ||
206 (error = get_stripe_max_comp(request, &maxcomp));
207 if (error != 0) {
208 return (error);
209 }
210
211 for (iter = similar_hba_groups;
212 (error == 0) && (stripe == NULL) && (iter != NULL);
213 iter = iter->next) {
214
215 dlist_t *hbas = (dlist_t *)iter->obj;
216
217 similar_hba_strategy_order_t order;
218
219 for (order = STRIPE_ACROSS_SIMILAR_HBAS_DISK_PER;
220 (order < N_SIMILAR_HBA_STRATEGIES) &&
221 (stripe == NULL) && (error == 0);
222 order++) {
223
224 dlist_t *selhbas = NULL;
225 dlist_t *disks = NULL;
226 int n = 0;
227
228 switch (order) {
229
230 case STRIPE_ACROSS_SIMILAR_HBAS_DISK_PER:
231
232 error = select_hbas_with_n_disks(
233 request, hbas, 1, &selhbas, &disks);
234
235 if (error == 0) {
236
237 /* BEGIN CSTYLED */
238 oprintf(OUTPUT_TERSE,
239 gettext(" -->Strategy 1: use 1 disk from %d-%d similar HBAs - stripe across HBAs\n"),
240 mincomp, maxcomp);
241 /* END CSTYLED */
242
243 if ((n = dlist_length(selhbas)) >= mincomp) {
244 n = ((n > maxcomp) ? maxcomp : n);
245 error = compose_stripe(
246 request, nbytes, disks, n,
247 mincomp, NULL, &stripe);
248 } else {
249 print_insufficient_hbas_msg(n);
250 }
251 }
252
253 break;
254
255 case STRIPE_WITHIN_SIMILAR_HBA:
256
257 error = select_hbas_with_n_disks(
258 request, hbas, mincomp, &selhbas, &disks);
259
260 if (error == 0) {
261
262 /* BEGIN CSTYLED */
263 oprintf(OUTPUT_TERSE,
264 gettext(" -->Strategy 2: use %d-%d disks from any single HBA - stripe within HBA\n"),
265 mincomp, maxcomp);
266 /* END CSTYLED */
267
268 if ((n = dlist_length(selhbas)) > 0) {
269 error = compose_stripe_within_hba(
270 request, selhbas, nbytes,
271 mincomp, maxcomp, &stripe);
272 } else {
273 print_insufficient_disks_msg(n);
274 }
275 }
276
277 break;
278
279 case STRIPE_ACROSS_SIMILAR_HBAS:
280
281 error = select_hbas_with_n_disks(
282 request, hbas, 1, &selhbas, &disks);
283
284 if (error == 0) {
285
286 /* BEGIN CSTYLED */
287 oprintf(OUTPUT_TERSE,
288 gettext(" -->Strategy 3: use %d-%d disks from %d similar HBAs - stripe across HBAs\n"),
289 mincomp, maxcomp, dlist_length(hbas));
290 /* END CSTYLED */
291
292 if ((n = dlist_length(selhbas)) > 0) {
293 if ((n = dlist_length(disks)) >= mincomp) {
294 n = ((n > maxcomp) ? maxcomp : n);
295 error = compose_stripe(
296 request, nbytes, disks, n,
297 mincomp, NULL, &stripe);
298 } else {
299 print_insufficient_disks_msg(n);
300 }
301 } else {
302 print_insufficient_hbas_msg(n);
303 }
304 }
305
306 break;
307
308 default:
309 break;
310 }
311
312 dlist_free_items(disks, NULL);
313 dlist_free_items(selhbas, NULL);
314 }
315 }
316
317 for (iter = similar_hba_groups; iter != NULL; iter = iter->next) {
318 dlist_free_items((dlist_t *)iter->obj, NULL);
319 }
320 dlist_free_items(similar_hba_groups, NULL);
321
322 /*
323 * if striping within similar HBA groups failed,
324 * try across all available HBAs
325 */
326 if ((stripe == NULL) && (error == 0)) {
327
328 any_hba_strategy_order_t order;
329
330 for (order = STRIPE_ACROSS_ANY_HBAS_DISK_PER;
331 (order < N_ANY_HBA_STRATEGIES) &&
332 (stripe == NULL) && (error == 0);
333 order++) {
334
335 dlist_t *selhbas = NULL;
336 dlist_t *disks = NULL;
337 int n = 0;
338
339 switch (order) {
340
341 case STRIPE_ACROSS_ANY_HBAS_DISK_PER:
342
343 error = select_hbas_with_n_disks(
344 request, usable_hbas, 1, &selhbas, &disks);
345
346 if (error == 0) {
347
348 /* BEGIN CSTYLED */
349 oprintf(OUTPUT_TERSE,
350 gettext(" -->Strategy 4: use 1 disk from %d-%d available HBAs - stripe across any HBAs\n"),
351 mincomp, maxcomp);
352 /* END CSTYLED */
353
354 if ((n = dlist_length(selhbas)) >= mincomp) {
355
356 n = ((n > maxcomp) ? maxcomp : n);
357 error = compose_stripe(
358 request, nbytes, disks, n,
359 mincomp, NULL, &stripe);
360
361 } else {
362 print_insufficient_hbas_msg(n);
363 }
364 }
365
366 break;
367
368 case STRIPE_ACROSS_ANY_HBAS:
369
370 error = select_hbas_with_n_disks(
371 request, usable_hbas, 1, &selhbas, &disks);
372
373 if (error == 0) {
374
375 /* BEGIN CSTYLED */
376 oprintf(OUTPUT_TERSE,
377 gettext(" -->Strategy 5: use %d-%d disks from %d available HBA - stripe across any HBAs\n"),
378 mincomp, maxcomp, dlist_length(selhbas));
379 /* END CSTYLED */
380
381 if ((n = dlist_length(disks)) >= mincomp) {
382
383 n = ((n > maxcomp) ? maxcomp : n);
384 error = compose_stripe(
385 request, nbytes, disks, n,
386 mincomp, NULL, &stripe);
387
388 } else {
389 print_insufficient_disks_msg(n);
390 }
391 }
392
393 break;
394 }
395
396 dlist_free_items(disks, NULL);
397 dlist_free_items(selhbas, NULL);
398 }
399 }
400
401 if (stripe != NULL) {
402
403 dlist_t *item = NULL;
404 if ((item = dlist_new_item(stripe)) == NULL) {
405 error = ENOMEM;
406 } else {
407 *results = dlist_append(item, *results, AT_TAIL);
408 print_layout_success_msg();
409 }
410
411 } else if (error != 0) {
412
413 print_debug_failure_msg(
414 devconfig_type_to_str(TYPE_STRIPE),
415 get_error_string(error));
416
417 } else {
418
419 print_insufficient_resources_msg(
420 devconfig_type_to_str(TYPE_STRIPE));
421 error = -1;
422 }
423
424 return (error);
425 }
426
427 /*
428 * FUNCTION: populate_stripe(devconfig_t *request, uint64_t nbytes,
429 * dlist_t *disks, uint16_t ncomp, dlist_t *othervols,
430 * devconfig_t **stripe)
431 *
432 * INPUT: request - pointer to a request devconfig_t
433 * nbytes - desired stripe size
434 * disks - pointer to a list of availalb disks
435 * ncomp - number of components desired
436 * othervols - pointer to a list of other volumes whose
437 * composition may affect this stripe
438 * (e.g., submirrors of the same mirror)
439 *
440 * OUTPUT: stripe - pointer to a devconfig_t to hold resulting stripe
441 *
442 * RETURNS: int - 0 on success
443 * !0 otherwise.
444 *
445 * PURPOSE: Helper to populate a stripe with the specified number of
446 * components and aggregate capacity using slices on disks
447 * in the input list.
448 *
449 * If the othervols list is not empty, the slice components
450 * chosen for the stripe must not on the same disks as any
451 * of the other volumes.
452 *
453 * If sufficient slice components can be found, the stripe
454 * is assembled and returned.
455 */
456 int
populate_stripe(devconfig_t * request,uint64_t nbytes,dlist_t * disks,uint16_t ncomp,dlist_t * othervols,devconfig_t ** stripe)457 populate_stripe(
458 devconfig_t *request,
459 uint64_t nbytes,
460 dlist_t *disks,
461 uint16_t ncomp,
462 dlist_t *othervols,
463 devconfig_t **stripe)
464 {
465 uint16_t npaths = 0;
466 uint16_t ncomps = 0; /* number of components found */
467 uint64_t rsize = 0; /* reqd component size */
468
469 dlist_t *other_hbas = NULL;
470 dlist_t *other_disks = NULL;
471
472 dlist_t *slices = NULL;
473 dlist_t *comps = NULL;
474
475 int error = 0;
476
477 *stripe = NULL;
478
479 ((error = disks_get_avail_slices(request, disks, &slices)) != 0) ||
480 (error = get_volume_npaths(request, &npaths));
481 if (error != 0) {
482 return (error);
483 }
484
485 print_populate_volume_ncomps_msg(
486 devconfig_type_to_str(TYPE_STRIPE), nbytes, ncomp);
487
488 if (slices == NULL) {
489 print_populate_no_slices_msg();
490 return (0);
491 }
492
493 /* determine HBAs and disks used by othervols */
494 error = get_hbas_and_disks_used_by_volumes(othervols,
495 &other_hbas, &other_disks);
496 if (error != 0) {
497 dlist_free_items(other_hbas, NULL);
498 dlist_free_items(other_disks, NULL);
499 return (error);
500 }
501
502 print_populate_choose_slices_msg();
503
504 /*
505 * each stripe component needs to be this size.
506 * Note that the stripe interlace doesn't need to be
507 * taken into account in this computation because any
508 * slice selected as a stripe component will be oversized
509 * to account for interlace and cylinder rounding done
510 * by libmeta.
511 */
512 rsize = nbytes / ncomp;
513
514 /*
515 * need to select 'ncomp' slices that are at least 'rsize'
516 * large in order to reach the desired capacity.
517 */
518 ncomps = 0;
519 while ((ncomps < ncomp) && (error == 0)) {
520
521 devconfig_t *comp = NULL;
522 dlist_t *item = NULL;
523 dlist_t *rmvd = NULL;
524 char *cname = NULL;
525
526 /* BEGIN CSTYLED */
527 /*
528 * 1st B_TRUE: require a different disk than those used by
529 * comps and othervols
530 * 2nd B_TRUE: requested size is minimum acceptable
531 * 3rd B_TRUE: add an extra cylinder to the resulting slice, this is
532 * necessary for Stripe components whose sizes get rounded
533 * down to an interlace multiple and then down to a cylinder
534 * boundary.
535 */
536 /* END CSTYLED */
537 error = choose_slice(rsize, npaths, slices, comps,
538 other_hbas, other_disks, B_TRUE, B_TRUE, B_TRUE, &comp);
539
540 if ((error == 0) && (comp != NULL)) {
541
542 ++ncomps;
543
544 item = dlist_new_item(comp);
545 if (item == NULL) {
546 error = ENOMEM;
547 } else {
548
549 /* add selected component to comp list */
550 comps = dlist_insert_ordered(
551 item,
552 comps,
553 ASCENDING,
554 compare_devconfig_sizes);
555
556 /* remove it from the available list */
557 slices = dlist_remove_equivalent_item(slices, (void *) comp,
558 compare_devconfig_and_descriptor_names, &rmvd);
559
560 if (rmvd != NULL) {
561 free(rmvd);
562 }
563
564 /* add the component slice to the used list */
565 if ((error = devconfig_get_name(comp, &cname)) == 0) {
566 error = add_used_slice_by_name(cname);
567 }
568 }
569 } else if (comp == NULL) {
570 /* no possible slice */
571 break;
572 }
573 }
574
575 dlist_free_items(slices, NULL);
576 dlist_free_items(other_hbas, NULL);
577 dlist_free_items(other_disks, NULL);
578
579 if (ncomps == ncomp) {
580
581 if ((error = assemble_stripe(request, comps, stripe)) == 0) {
582 print_populate_success_msg();
583 } else {
584 dlist_free_items(comps, free_devconfig_object);
585 }
586
587 } else if (error == 0) {
588
589 if (ncomps > 0) {
590 print_insufficient_components_msg(ncomps);
591 dlist_free_items(comps, free_devconfig_object);
592 } else {
593 print_populate_no_slices_msg();
594 }
595
596 }
597 return (error);
598 }
599
600 /*
601 * FUNCTION: populate_explicit_stripe(devconfig_t *request,
602 * dlist_t **results)
603 *
604 * INPUT: request - pointer to a request devconfig_t
605 *
606 * OUTPUT: results - pointer to a list of volume devconfig_t results
607 *
608 * RETURNS: int - 0 on success
609 * !0 otherwise.
610 *
611 * PURPOSE: Processes the input stripe request that specifies explicit
612 * slice components.
613 *
614 * The components have already been validated and reserved,
615 * all that is required is to create devconfig_t structs
616 * for each requested slice.
617 *
618 * The net size of the stripe is determined by the slice
619 * components.
620 *
621 * The stripe devconfig_t is assembled and appended to the
622 * results list.
623 *
624 * This function is also called from
625 * layout_mirror.populate_explicit_mirror()
626 */
627 int
populate_explicit_stripe(devconfig_t * request,dlist_t ** results)628 populate_explicit_stripe(
629 devconfig_t *request,
630 dlist_t **results)
631 {
632 devconfig_t *stripe = NULL;
633 int error = 0;
634
635 dlist_t *comps = NULL;
636 dlist_t *iter = NULL;
637 dlist_t *item = NULL;
638
639 print_layout_explicit_msg(devconfig_type_to_str(TYPE_STRIPE));
640
641 /* assemble components */
642 iter = devconfig_get_components(request);
643 for (; (iter != NULL) && (error == 0); iter = iter->next) {
644 devconfig_t *rqst = (devconfig_t *)iter->obj;
645 dm_descriptor_t rqst_slice = NULL;
646 char *rqst_name = NULL;
647 devconfig_t *comp = NULL;
648
649 /* slice components have been validated */
650 /* turn each into a devconfig_t */
651 ((error = devconfig_get_name(rqst, &rqst_name)) != 0) ||
652 (error = slice_get_by_name(rqst_name, &rqst_slice)) ||
653 (error = create_devconfig_for_slice(rqst_slice, &comp));
654
655 if (error == 0) {
656
657 print_layout_explicit_added_msg(rqst_name);
658
659 item = dlist_new_item((void *)comp);
660 if (item == NULL) {
661 error = ENOMEM;
662 } else {
663 comps = dlist_append(item, comps, AT_TAIL);
664 }
665 }
666 }
667
668 if (error == 0) {
669 error = assemble_stripe(request, comps, &stripe);
670 }
671
672 if (error == 0) {
673 if ((item = dlist_new_item(stripe)) == NULL) {
674 error = ENOMEM;
675 } else {
676 *results = dlist_append(item, *results, AT_TAIL);
677 print_populate_success_msg();
678 }
679 } else {
680 dlist_free_items(comps, free_devconfig);
681 }
682
683 return (error);
684 }
685
686 /*
687 * FUNCTION: compose_stripe(devconfig_t *request, uint64_t nbytes,
688 * dlist_t *disks, uint16_t max, uint16_t min,
689 * dlist_t *othervols, devconfig_t **stripe)
690 *
691 * INPUT: request - pointer to a request devconfig_t
692 * nbytes - desired stripe size
693 * disks - pointer to a list of availalb disks
694 * max - maximum number of components allowed
695 * min - minimum number of components allowed
696 * othervols - pointer to a list of other volumes whose
697 * composition may affect this stripe
698 * (e.g., submirrors of the same mirror)
699 *
700 * OUTPUT: stripe - pointer to a devconfig_t to hold resulting stripe
701 *
702 * RETURNS: int - 0 on success
703 * !0 otherwise.
704 *
705 * PURPOSE: Attempt to compose a stripe of capacity nbytes, with
706 * component slices chosen from the input list of disks.
707 * The number of components in the stripe should be in the
708 * range min <= N <= max, more components are preferred.
709 *
710 * If a stripe can be composed, a pointer to it will be
711 * returned in the stripe devconfig_t.
712 *
713 * This is a loop wrapped around populate_stripe which
714 * varies the number of components between 'max' and 'min'.
715 */
716 static int
compose_stripe(devconfig_t * request,uint64_t nbytes,dlist_t * disks,int max,int min,dlist_t * othervols,devconfig_t ** stripe)717 compose_stripe(
718 devconfig_t *request,
719 uint64_t nbytes,
720 dlist_t *disks,
721 int max,
722 int min,
723 dlist_t *othervols,
724 devconfig_t **stripe)
725 {
726 int error = 0;
727
728 *stripe = NULL;
729
730 for (; (error == 0) && (*stripe == NULL) && (max >= min); max--) {
731 error = populate_stripe(
732 request, nbytes, disks, max, othervols, stripe);
733 }
734
735 return (error);
736 }
737
738 /*
739 * FUNCTION: compose_stripe_within_hba(devconfig_t *request,
740 * dlist_t *hbas, uint64_t nbytes,
741 * int maxcomp, int mincomp, dlist_t **stripe)
742 *
743 * INPUT: request - pointer to a devconfig_t of the current request
744 * hbas - pointer to a list of available HBAs
745 * nbytes - the desired capacity for the stripe
746 * maxcomp - the maximum number of stripe components
747 * mincomp - the minimum number of stripe components
748 *
749 * OUTPUT: stripe - pointer to a stripe devconfig_t result
750 *
751 * RETURNS: int - 0 on success
752 * !0 otherwise.
753 *
754 * PURPOSE: Layout function which compose a stripe of the desired size
755 * using available disks within any single HBA from the input list.
756 *
757 * The number of components within the composed stripe will be
758 * in the range of min to max, preferring more components
759 * over fewer.
760 *
761 * All input HBAs are expected to have at least mincomp
762 * available disks and total space sufficient for the stripe.
763 *
764 * If the stripe can be composed, a pointer to it is returned in
765 * the stripe devconfig_t *.
766 *
767 *
768 * while (more hbas and stripe not composed) {
769 * select HBA
770 * if (not enough available space on this HBA) {
771 * continue;
772 * }
773 * get available disks for HBA
774 * use # disks as max # of stripe components
775 * try to compose stripe
776 * }
777 *
778 */
779 static int
compose_stripe_within_hba(devconfig_t * request,dlist_t * hbas,uint64_t nbytes,uint16_t min,uint16_t max,devconfig_t ** stripe)780 compose_stripe_within_hba(
781 devconfig_t *request,
782 dlist_t *hbas,
783 uint64_t nbytes,
784 uint16_t min,
785 uint16_t max,
786 devconfig_t **stripe)
787 {
788 int error = 0;
789
790 dlist_t *iter = NULL;
791
792 *stripe = NULL;
793
794 for (iter = hbas;
795 (iter != NULL) && (error == 0) && (*stripe == NULL);
796 iter = iter->next) {
797
798 dm_descriptor_t hba = (uintptr_t)iter->obj;
799 dlist_t *disks = NULL;
800 uint64_t space = 0;
801 uint16_t ncomp = 0;
802 char *name;
803
804 ((error = get_display_name(hba, &name)) != 0) ||
805 (error = hba_get_avail_disks_and_space(request,
806 hba, &disks, &space));
807
808 if (error == 0) {
809 if (space >= nbytes) {
810 ncomp = dlist_length(disks);
811 ncomp = ((ncomp > max) ? max : ncomp);
812 error = compose_stripe(
813 request, nbytes, disks, ncomp,
814 min, NULL, stripe);
815 } else {
816 print_hba_insufficient_space_msg(name, space);
817 }
818 }
819
820 dlist_free_items(disks, NULL);
821 }
822
823 return (error);
824 }
825
826 /*
827 * FUNCTION: assemble_stripe(devconfig_t *request, dlist_t *comps,
828 * devconfig_t **stripe)
829 *
830 * INPUT: request - pointer to a devconfig_t of the current request
831 * comps - pointer to a list of slice components
832 *
833 * OUPUT: stripe - pointer to a devconfig_t to hold final stripe
834 *
835 * RETURNS: int - 0 on success
836 * !0 otherwise.
837 *
838 * PURPOSE: Helper which creates and populates a stripe devconfig_t
839 * struct using information from the input request and the
840 * list of slice components.
841 *
842 * Determines the name of the stripe either from the request
843 * or from the default naming scheme.
844 *
845 * Sets the interlace for the stripe if a value is specified
846 * in the request.
847 *
848 * Attaches the input list of components to the devconfig.
849 */
850 static int
assemble_stripe(devconfig_t * request,dlist_t * comps,devconfig_t ** stripe)851 assemble_stripe(
852 devconfig_t *request,
853 dlist_t *comps,
854 devconfig_t **stripe)
855 {
856 uint64_t ilace = 0;
857 char *name = NULL;
858 int error = 0;
859
860 if ((error = new_devconfig(stripe, TYPE_STRIPE)) == 0) {
861 /* set stripe name, use requested name if specified */
862 if ((error = devconfig_get_name(request, &name)) != 0) {
863 if (error != ERR_ATTR_UNSET) {
864 volume_set_error(gettext("error getting requested name\n"));
865 } else {
866 error = 0;
867 }
868 }
869
870 if (error == 0) {
871 if (name == NULL) {
872 if ((error = get_next_volume_name(&name,
873 TYPE_STRIPE)) == 0) {
874 error = devconfig_set_name(*stripe, name);
875 free(name);
876 }
877 } else {
878 error = devconfig_set_name(*stripe, name);
879 }
880 }
881 }
882
883 if (error == 0) {
884 if ((error = get_stripe_interlace(request, &ilace)) == 0) {
885 error = devconfig_set_stripe_interlace(*stripe, ilace);
886 } else if (error == ENOENT) {
887 ilace = get_default_stripe_interlace();
888 error = 0;
889 }
890 }
891
892 if (error == 0) {
893 uint64_t nbytes = 0;
894 if ((error = compute_usable_stripe_capacity(comps,
895 ilace, &nbytes)) == 0) {
896 error = devconfig_set_size_in_blocks(*stripe, nbytes/DEV_BSIZE);
897 }
898 }
899
900 if (error == 0) {
901 comps = order_stripe_components_alternate_hbas(comps);
902 devconfig_set_components(*stripe, comps);
903 } else {
904 free_devconfig(*stripe);
905 *stripe = NULL;
906 }
907
908 return (error);
909 }
910
911 /*
912 * Order the given stripe component list such that the number of
913 * slices on the same hba adjacent to each other in the list are
914 * minimized.
915 *
916 * @param comps
917 * the slice component list to order
918 *
919 * @return the first element of the resulting list
920 */
921 static dlist_t *
order_stripe_components_alternate_hbas(dlist_t * comps)922 order_stripe_components_alternate_hbas(
923 dlist_t *comps)
924 {
925 dlist_t *iter;
926
927 oprintf(OUTPUT_DEBUG,
928 gettext("Stripe components before ordering to alternate HBAs:\n"));
929
930 for (iter = comps; iter != NULL; iter = iter->next) {
931 devconfig_t *slice = (devconfig_t *)(iter->obj);
932 char *name;
933 devconfig_get_name(slice, &name);
934 oprintf(OUTPUT_DEBUG, " %s\n", name);
935 }
936
937 return (dlist_separate_similar_elements(
938 comps, compare_slices_on_same_hba));
939 }
940
941 /*
942 * FUNCTION: compute_usable_stripe_capacity(dlist_t *comps, uint64_t ilace,
943 * uint64_t *nbytes)
944 *
945 * INPUT: comps - pointer to a list of stripe components
946 * ilace - the expected stripe interlace in bytes
947 *
948 * OUPUT: nbytes - pointer to hold the computed capacity
949 *
950 * RETURNS: int - 0 on success
951 * !0 otherwise.
952 *
953 * PURPOSE: Helper which computes the usable size of a stripe taking
954 * into account the interlace and cylinder rounding that
955 * libmeta uses: a stripe component's size is rounded down to
956 * an integral multiple of the interlace and then rounded down
957 * to a cylinder boundary on VTOC labeled disks.
958 *
959 * (These libmeta computations are in the meta_stripe_attach()
960 * function of .../lib/lvm/libmeta/common/meta_stripe.c and
961 * meta_adjust_geom() in .../lib/lvm/libmeta/common/meta_init.c)
962 *
963 * This function's implementation iterates the input list of
964 * stripe component slices and determines the smallest usable
965 * component capacity.
966 *
967 * The usable stripe capacity is then that component capacity
968 * times the number of components.
969 */
970 static int
compute_usable_stripe_capacity(dlist_t * comps,uint64_t ilace,uint64_t * nbytes)971 compute_usable_stripe_capacity(
972 dlist_t *comps,
973 uint64_t ilace,
974 uint64_t *nbytes)
975 {
976 uint64_t bytes_per_component = 0;
977 dlist_t *iter;
978 int ncomps = 0;
979 int error = 0;
980
981 for (iter = comps; (iter != NULL) && (error == 0); iter = iter->next) {
982
983 devconfig_t *comp = (devconfig_t *)iter->obj;
984 char *comp_name = NULL;
985 uint64_t comp_nbytes = 0;
986 dm_descriptor_t comp_disk;
987 boolean_t comp_disk_efi = B_FALSE;
988 uint64_t comp_disk_bps = 0; /* disk bytes per sector */
989
990 ((error = devconfig_get_size(comp, &comp_nbytes)) != 0) ||
991 (error = devconfig_get_name(comp, &comp_name)) ||
992 (error = get_disk_for_named_slice(comp_name, &comp_disk)) ||
993 (error = disk_get_blocksize(comp_disk, &comp_disk_bps)) ||
994 (error = disk_get_is_efi(comp_disk, &comp_disk_efi));
995 if (error == 0) {
996
997 if (comp_disk_efi == B_FALSE) {
998 uint64_t nhead = 0;
999 uint64_t nsect = 0;
1000 uint64_t ncyls = 0;
1001
1002 /* do cylinder and interlace rounding for non-EFI disks */
1003 ((error = disk_get_ncylinders(comp_disk, &ncyls)) != 0) ||
1004 (error = disk_get_nheads(comp_disk, &nhead)) ||
1005 (error = disk_get_nsectors(comp_disk, &nsect));
1006 if (error == 0) {
1007 /* compute bytes per cyl */
1008 uint64_t bpc = nhead * nsect * comp_disk_bps;
1009
1010 /* round nbytes down to a multiple of interlace */
1011 comp_nbytes = (comp_nbytes / ilace) * ilace;
1012
1013 /* round nbytes down to a cylinder boundary */
1014 comp_nbytes = (comp_nbytes / bpc) * bpc;
1015 }
1016 }
1017
1018 /* save smallest component size */
1019 if ((bytes_per_component == 0) ||
1020 (comp_nbytes < bytes_per_component)) {
1021 bytes_per_component = comp_nbytes;
1022 }
1023
1024 ++ncomps;
1025 }
1026 }
1027
1028 if (error == 0) {
1029 /* size of stripe = smallest component size * n components */
1030 *nbytes = (bytes_per_component * ncomps);
1031 }
1032
1033 return (error);
1034 }
1035