xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_stripe.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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