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