xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_hsp.c (revision b6c8bd52ccb0f3491c2bd1f5867985cef630564a)
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 2005 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_dlist.h"
35 #include "volume_output.h"
36 
37 #include "layout_device_cache.h"
38 #include "layout_device_util.h"
39 #include "layout_discovery.h"
40 #include "layout_dlist_util.h"
41 #include "layout_messages.h"
42 #include "layout_request.h"
43 #include "layout_slice.h"
44 #include "layout_svm_util.h"
45 
46 #define	_LAYOUT_HSP_C
47 
48 static int layout_explicit_hsp(
49 	devconfig_t 	*hsprequest,
50 	dlist_t		*devices,
51 	devconfig_t 	**hsp);
52 
53 static int layout_default_hsp(
54 	devconfig_t 	*request,
55 	dlist_t		*devices,
56 	devconfig_t 	**hsp);
57 
58 static int populate_hsp(
59 	devconfig_t	*request,
60 	devconfig_t	*hsp,
61 	dlist_t		*devices);
62 
63 static int assemble_hsp(
64 	devconfig_t 	*hsp,
65 	dlist_t		*newspares,
66 	dlist_t		*devices);
67 
68 static int get_uniquely_sized_slices(
69 	dlist_t 	*devices,
70 	dlist_t 	**unique);
71 
72 static int remove_undersized_slices(
73 	dlist_t 	*unique,
74 	dlist_t 	**avail);
75 
76 static int find_spare_for_component(
77 	devconfig_t 	*component,
78 	dlist_t		*all_spares,
79 	dlist_t		*hbas,
80 	dlist_t		*disks,
81 	boolean_t 	*found);
82 
83 static int choose_spare_for_component(
84 	devconfig_t 	*comp,
85 	dlist_t 	**all_spares,
86 	dlist_t 	**new_spares,
87 	dlist_t 	**avail,
88 	dlist_t 	*used_hbas,
89 	dlist_t 	*used_disks,
90 	uint16_t	npaths);
91 
92 /*
93  * FUNCTION:	layout_hsp(devconfig_t *request, devconfig_t hsprequest,
94  *			dlist_t *devices, dlist_t **results)
95  *
96  * INPUT:	request	- pointer to the toplevel request devconfig_t
97  *		hsp	- pointer to the optional HSP request devconfig_t
98  *		devices - pointer to a list of devices to be served by the HSP
99  *
100  * OUTPUT:	results - pointer to a list result devconfig_t, if the HSP
101  *			to service the input list of devices needs to be
102  *			created or modified, it will be appended to the list.
103  *
104  * RETURNS:	int	- 0 on success
105  *			 !0 otherwise.
106  *
107  * PURPOSE:	Main layout driver for HSP, attempts to build/populate a
108  *		single HSP to service the list of devices.
109  *
110  *		If the input hsprequest is NULL, use the default HSP scheme:
111  *		a. use the first HSP in the diskset
112  *		b. create an HSP if the diskset has none
113  *
114  *		If the hsprequest is not NULL:
115  *		a. if the request names an HSP and it already exists, use it
116  *		b. if the request names an HSP and it does not exist, create it
117  *		c. if the request specifies components, use them
118  */
119 int
layout_hsp(devconfig_t * request,devconfig_t * hsprequest,dlist_t * devices,dlist_t ** results)120 layout_hsp(
121 	devconfig_t	*request,
122 	devconfig_t	*hsprequest,
123 	dlist_t		*devices,
124 	dlist_t		**results)
125 {
126 	int		error = 0;
127 	devconfig_t  	*hsp = NULL;
128 
129 	oprintf(OUTPUT_TERSE,
130 		gettext("  ->Layout a %s\n"),
131 		devconfig_type_to_str(TYPE_HSP));
132 
133 	if (hsprequest == NULL) {
134 	    error = layout_default_hsp(request, devices, &hsp);
135 	} else {
136 	    error = layout_explicit_hsp(hsprequest, devices, &hsp);
137 	}
138 
139 	if (error != 0) {
140 	    print_debug_failure_msg(devconfig_type_to_str(TYPE_HSP),
141 		    get_error_string(error));
142 	} else if (hsp != NULL) {
143 
144 	    if (devconfig_get_components(hsp) == NULL) {
145 		/* HSP is usable as it is */
146 		free_devconfig(hsp);
147 		hsp = NULL;
148 	    } else {
149 		dlist_t *item = NULL;
150 		if ((item = dlist_new_item(hsp)) == NULL) {
151 		    error = ENOMEM;
152 		} else {
153 		    *results = dlist_append(item, *results, AT_TAIL);
154 		    print_layout_success_msg();
155 		}
156 	    }
157 	}
158 
159 	return (error);
160 }
161 
162 /*
163  * FUNCTION:	layout_default_hsp(devconfig_t *request,
164  *			dlist_t *devices, devconfig_t **hsp)
165  *
166  * INPUT:	request	- pointer to the toplevel request devconfig_t
167  *		devices - pointer to a list of devices to be served by the HSP
168  *
169  * OUTPUT:	hsp	- pointer to a devconfig_t to hold the resulting HSP
170  *
171  * RETURNS:	int	- 0 on success
172  *			 !0 otherwise.
173  *
174  * PURPOSE:	Layout driver for default HSP construction.
175  *
176  *		a. use the first HSP in the diskset
177  *		b. create an HSP if the diskset has none
178  *		c. add spares to the HSP to service the list of input devices.
179  */
180 static int
layout_default_hsp(devconfig_t * request,dlist_t * devices,devconfig_t ** hsp)181 layout_default_hsp(
182 	devconfig_t 	*request,
183 	dlist_t		*devices,
184 	devconfig_t 	**hsp)
185 {
186 	char		*dsname = get_request_diskset();
187 	char		*hspname = NULL;
188 	boolean_t	free_hspname = B_FALSE;
189 	devconfig_t	*default_hsp = NULL;
190 	int		error = 0;
191 
192 	oprintf(OUTPUT_TERSE,
193 		gettext("  -->Using default HSP scheme...\n"));
194 
195 	if ((error = get_default_hsp_name(request, &hspname)) != 0) {
196 	    volume_set_error(
197 		    gettext("error getting HSP name from defaults\n"));
198 	    return (error);
199 	}
200 
201 	if (hspname != NULL) {
202 	    if ((error = hsp_get_by_name(dsname, hspname, &default_hsp)) != 0) {
203 		volume_set_error(
204 			gettext("error getting default HSP by name\n"));
205 		return (error);
206 	    }
207 	} else {
208 	    /* no default HSP name, get diskset's default HSP */
209 	    if ((error = hsp_get_default_for_diskset(dsname,
210 		&default_hsp)) != 0) {
211 		volume_set_error(
212 			gettext("error getting default HSP\n"));
213 		return (error);
214 	    }
215 
216 	    if (default_hsp == NULL) {
217 		/* no default HSP name, no default HSP, make one */
218 		if ((error = get_next_hsp_name(&hspname)) != 0) {
219 		    volume_set_error(
220 			    gettext("error making default HSP name\n"));
221 		    return (error);
222 		}
223 		free_hspname = B_TRUE;
224 	    }
225 	}
226 
227 	if (default_hsp != NULL) {
228 
229 	    /* Found existing default HSP, copy it */
230 	    dlist_t *spares = devconfig_get_components(default_hsp);
231 
232 	    ((error = devconfig_get_name(default_hsp, &hspname)) != 0) ||
233 	    (error = new_devconfig(hsp, TYPE_HSP)) ||
234 	    (error = devconfig_set_name(*hsp, hspname));
235 
236 	    if (error == 0) {
237 		devconfig_set_components(*hsp, spares);
238 		devconfig_set_components(default_hsp, NULL);
239 
240 		oprintf(OUTPUT_TERSE,
241 			gettext("  --->Using %s from disk set %s...\n"),
242 			hspname, dsname);
243 	    } else {
244 		free_devconfig(*hsp);
245 		*hsp = NULL;
246 	    }
247 
248 	} else {
249 
250 	    /* no existing default HSP, make it */
251 	    ((error = new_devconfig(hsp, TYPE_HSP)) != 0) ||
252 	    (error = devconfig_set_name(*hsp, hspname));
253 	    if (error == 0) {
254 		oprintf(OUTPUT_VERBOSE,
255 			gettext("  --->Created %s for disk set %s...\n "),
256 			hspname, dsname);
257 	    } else {
258 		free_devconfig(*hsp);
259 		*hsp = NULL;
260 	    }
261 
262 	    if (free_hspname == B_TRUE) {
263 		free(hspname);
264 	    }
265 	}
266 
267 	if (error == 0) {
268 	    error = populate_hsp(request, *hsp, devices);
269 	}
270 
271 	return (error);
272 }
273 
274 /*
275  * FUNCTION:	layout_explicit_hsp(devconfig_t *hsprequest,
276  *			dlist_t *devices, devconfig_t **hsp)
277  *
278  * INPUT:	hsprequest - pointer to the explicit HSP request devconfig_t
279  *		devices - pointer to a list of devices to be served by the HSP
280  *
281  * OUTPUT:	hsp	- pointer to a HSP devconfig_t to hold resulting HSP
282  *
283  * RETURNS:	int	- 0 on success
284  *			 !0 otherwise.
285  *
286  * PURPOSE:	Layout driver for an explicit HSP request.
287  *
288  *		a. if the request names an HSP and it already exists, use it
289  *		b. if the request names an HSP and it does not exist, create it
290  *		c. if the request specifies components, use them
291  *		   otherwise, add new spares to handle the input list
292  *		   of devices.
293  */
294 static int
layout_explicit_hsp(devconfig_t * hsprequest,dlist_t * devices,devconfig_t ** hsp)295 layout_explicit_hsp(
296 	devconfig_t	*hsprequest,
297 	dlist_t		*devices,
298 	devconfig_t 	**hsp)
299 {
300 	char		*dsname = get_request_diskset();
301 	char		*hspname = NULL;
302 	dlist_t		*rspares = NULL;
303 	int		error = 0;
304 
305 	oprintf(OUTPUT_VERBOSE,
306 		gettext("  --->Explicit HSP request...\n"));
307 
308 	(void) devconfig_get_name(hsprequest, &hspname);
309 	if (hspname != NULL) {
310 
311 	    (void) hsp_get_by_name(dsname, hspname, hsp);
312 	    if (*hsp != NULL) {
313 
314 		oprintf(OUTPUT_VERBOSE,
315 			gettext("  --->Using %s...\n"),
316 			hspname);
317 	    } else {
318 
319 		/* named HSP doesn't exist, create it */
320 		((error = new_devconfig(hsp, TYPE_HSP)) != 0) ||
321 		(error = devconfig_set_name(*hsp, hspname));
322 		if (error == 0) {
323 		    oprintf(OUTPUT_VERBOSE,
324 			    gettext("  --->%s does not exist, "
325 				    "created...\n"), hspname);
326 		} else {
327 		    free_devconfig(*hsp);
328 		    *hsp = NULL;
329 		}
330 		free(hspname);
331 	    }
332 	}
333 
334 	if (error == 0) {
335 
336 	    /* does the hsprequest specify spares? */
337 	    rspares = devconfig_get_components(hsprequest);
338 	    if (rspares != NULL) {
339 
340 		/* put requested spares into HSP */
341 		dlist_t	*list = NULL;
342 		dlist_t *iter = NULL;
343 
344 		for (iter = rspares;
345 		    (iter != NULL) && (error == 0);
346 		    iter = iter->next) {
347 
348 		    dlist_t *item = NULL;
349 		    if ((dlist_new_item(iter->obj)) == NULL) {
350 			error = ENOMEM;
351 		    } else {
352 			list = dlist_append(item, list, AT_TAIL);
353 		    }
354 		}
355 
356 		if (error == 0) {
357 		    error = assemble_hsp(*hsp, rspares, devices);
358 		}
359 
360 	    } else {
361 
362 		/* select new spares */
363 		error = populate_hsp(hsprequest, *hsp, devices);
364 	    }
365 	}
366 
367 	return (error);
368 }
369 
370 /*
371  * FUNCTION:	populate_hsp(devconfig_t *request, devconfig_t *hsp,
372  *			dlist_t *devices)
373  *
374  * INPUT:	request	- pointer to a request devconfig_t
375  *		hsp	- pointer to a HSP devconfig_t
376  *		devices - pointer to a list of devices to be served by the HSP
377  *
378  * RETURNS:	int	- 0 on success
379  *			 !0 otherwise.
380  *
381  * PURPOSE:	Processes the input HSP request and add spares sufficient
382  *		to service the input list of devices.
383  *
384  *		Determine the available HBAs, disks, and slices.
385  *		Sort thru the input list of devices and determine
386  *		    the unique component sizes which need to be spared.
387  *		Filter the available slices and remove those that are
388  *		    too small to serve as spares.
389  *
390  *		Iterate each device and its components and see if the
391  *		    HSP currently has a sufficient spare, if not, try
392  *		    to select one from the available slices.
393  *
394  *		If a spare cannot be found for any device component,
395  *		    the HSP layout process stops.
396  *
397  *              If spares are found for all device components, add
398  *		    any required new ones to the HSP.
399  */
400 static int
populate_hsp(devconfig_t * request,devconfig_t * hsp,dlist_t * devices)401 populate_hsp(
402 	devconfig_t	*request,
403 	devconfig_t	*hsp,
404 	dlist_t		*devices)
405 {
406 	int		error = 0;
407 	uint16_t	npaths	= 0;
408 
409 	dlist_t		*usable_hbas = NULL;
410 	dlist_t		*sel_hbas = NULL;
411 	dlist_t		*disks = NULL;
412 	dlist_t		*iter = NULL;
413 
414 	dlist_t		*avail = NULL;	/* available slices */
415 	dlist_t		*slices = NULL;	/* avail slices of sufficient size */
416 	dlist_t		*unique = NULL;	/* volume slices that need spares */
417 	dlist_t		*curspares = NULL; /* current spares in the HSP */
418 	dlist_t		*newspares = NULL; /* slices to add to HSP */
419 	dlist_t		*allspares = NULL; /* current and new spares */
420 
421 	((error = get_usable_hbas(&usable_hbas)) != 0) ||
422 	(error = select_hbas_with_n_disks(request, usable_hbas, 1, &sel_hbas,
423 		&disks)) ||
424 	(error = disks_get_avail_slices(request, disks, &avail)) ||
425 	(error = get_volume_npaths(request, &npaths));
426 	if (error != 0) {
427 	    dlist_free_items(sel_hbas, NULL);
428 	    dlist_free_items(disks, NULL);
429 	    dlist_free_items(avail, NULL);
430 	    return (error);
431 	}
432 
433 	if (disks == NULL || dlist_length(disks) == 0) {
434 	    /* all disks have been consumed by the devices */
435 	    volume_set_error(
436 		    gettext("  no available disks to populate HSP\n"));
437 	    dlist_free_items(sel_hbas, NULL);
438 	    dlist_free_items(avail, NULL);
439 	    return (-1);
440 	}
441 
442 	if (avail == NULL || dlist_length(avail) == 0) {
443 	    /* all slices have been consumed by the devices */
444 	    volume_set_error(
445 		    gettext("  no available slices to populate HSP\n"));
446 	    dlist_free_items(sel_hbas, NULL);
447 	    dlist_free_items(disks, NULL);
448 	    return (-1);
449 	}
450 
451 	dlist_free_items(sel_hbas, NULL);
452 	dlist_free_items(disks, NULL);
453 
454 	/* build list of slices needing to be spared */
455 	((error = get_uniquely_sized_slices(devices, &unique)) != 0) ||
456 
457 	/* and list of slices of sufficient size to spare for them */
458 	(error = remove_undersized_slices(unique, &avail));
459 
460 	if (error != 0) {
461 	    dlist_free_items(avail, NULL);
462 	    dlist_free_items(unique, NULL);
463 	    dlist_free_items(slices, NULL);
464 	    return (error);
465 	}
466 
467 	/* get spares currently in the HSP */
468 	curspares = devconfig_get_components(hsp);
469 
470 	/* clone current spares list */
471 	for (iter = curspares;
472 	    (iter != NULL) && (error == 0);
473 	    iter = iter->next) {
474 	    dlist_t *item = dlist_new_item(iter->obj);
475 	    if (item == NULL) {
476 		error = ENOMEM;
477 	    } else {
478 		allspares = dlist_append(item, allspares, AT_TAIL);
479 	    }
480 	}
481 
482 	if (error != 0) {
483 	    dlist_free_items(avail, NULL);
484 	    dlist_free_items(unique, NULL);
485 	    dlist_free_items(slices, NULL);
486 	    dlist_free_items(allspares, NULL);
487 	    return (error);
488 	}
489 
490 	/*
491 	 * examine device component slices and see if the HSP already
492 	 * has a suitable spare. If not, select the best available
493 	 * of the same (or larger) size
494 	 */
495 	for (iter = devices;
496 	    (iter != NULL) && (error == 0);
497 	    iter = iter->next) {
498 
499 	    devconfig_t *device = (devconfig_t *)iter->obj;
500 	    dlist_t *components = devconfig_get_components(device);
501 	    dlist_t *hbas = NULL;
502 	    dlist_t *disks = NULL;
503 	    dlist_t *iter1;
504 
505 	    error = get_hbas_and_disks_used_by_volume(device, &hbas, &disks);
506 	    for (iter1 = components; (iter1 != NULL) && (error == 0);
507 		iter1 = iter1->next) {
508 
509 		devconfig_t	*comp = (devconfig_t *)iter1->obj;
510 		boolean_t	found = B_FALSE;
511 
512 		if ((error = find_spare_for_component(
513 		    comp, allspares, hbas, disks, &found)) == 0) {
514 		    if (found != B_TRUE) {
515 			error = choose_spare_for_component(
516 				comp, &allspares, &newspares,
517 				&avail, hbas, disks, npaths);
518 		    }
519 		}
520 	    }
521 	    dlist_free_items(disks, NULL);
522 	    dlist_free_items(hbas, NULL);
523 	}
524 
525 	if (error == 0) {
526 	    /* existing spares are no longer needed */
527 	    dlist_free_items(curspares, free_devconfig_object);
528 	    curspares = NULL;
529 
530 	    error = assemble_hsp(hsp, newspares, devices);
531 	} else {
532 	    dlist_free_items(newspares, free_devconfig_object);
533 	    newspares = NULL;
534 	}
535 
536 	dlist_free_items(avail, NULL);
537 	dlist_free_items(slices, NULL);
538 	dlist_free_items(unique, NULL);
539 	dlist_free_items(allspares, NULL);
540 
541 	return (error);
542 }
543 
544 /*
545  * FUNCTION:	assemble_hsp(devconfig_t *hsp, dlist_t *newspares,
546  *			dlist_t *devices)
547  *
548  * INPUT:	request	- pointer to a HSP devconfig_t
549  *		newspare - pointer to a list of new spares for the HSP
550  *		devices - pointer to a list of devices to be served by the HSP
551  *
552  * RETURNS:	int	- 0 on success
553  *			 !0 otherwise.
554  *
555  * PURPOSE:	Final assembly of an HSP. Attach new spare components
556  *		and associate the HSP with each device in the input list.
557  */
558 static int
assemble_hsp(devconfig_t * hsp,dlist_t * newspares,dlist_t * devices)559 assemble_hsp(
560 	devconfig_t 	*hsp,
561 	dlist_t		*newspares,
562 	dlist_t		*devices)
563 {
564 	dlist_t		*iter;
565 	char		*hspname = NULL;
566 	int		error = 0;
567 
568 	/* add new spares to HSP */
569 	(void) devconfig_set_components(hsp, newspares);
570 	(void) devconfig_get_name(hsp, &hspname);
571 
572 	/* associate HSP with each of the devices */
573 	for (iter = devices;
574 	    (iter != NULL) && (error == 0);
575 	    iter = iter->next) {
576 
577 	    devconfig_t *dev = iter->obj;
578 	    devconfig_t *hspcomp = NULL;
579 	    dlist_t	*item = NULL;
580 	    char	*devname = NULL;
581 
582 	    ((error = devconfig_get_name(dev, &devname)) != 0) ||
583 	    (error = new_devconfig(&hspcomp, TYPE_HSP)) ||
584 	    (error = devconfig_set_name(hspcomp, hspname));
585 
586 	    if (error != 0) {
587 
588 		free_devconfig(hspcomp);
589 
590 	    } else if ((item = dlist_new_item(hspcomp)) == NULL) {
591 
592 		free_devconfig(hspcomp);
593 		error = ENOMEM;
594 
595 	    } else {
596 
597 		dlist_t	*comps = devconfig_get_components(dev);
598 		comps = dlist_append(comps, item, AT_TAIL);
599 		(void) devconfig_set_components(dev, comps);
600 
601 		oprintf(OUTPUT_VERBOSE,
602 			gettext("  --->volume %s will use HSP %s\n"),
603 			devname, hspname);
604 	    }
605 	}
606 
607 	return (error);
608 }
609 
610 /*
611  * FUNCTION:	get_uniquely_sized_slices(dlist_t *devices,
612  *			dlist_t **unique)
613  *
614  * INPUT:	devices	- pointer to a list of devconfig_t devices
615  *
616  * OUTPUT:	unique	- pointer to a list of uniquely size slices
617  *			from the input list of devices.
618  *
619  * RETURNS:	int	- 0 on success
620  *			 !0 otherwise.
621  *
622  * PURPOSE:	Examine each device's slice components and build a list
623  *		of uniquely sized slices.
624  */
625 static int
get_uniquely_sized_slices(dlist_t * devices,dlist_t ** unique)626 get_uniquely_sized_slices(
627 	dlist_t 	*devices,
628 	dlist_t 	**unique)
629 {
630 	int		error = 0;
631 	dlist_t		*iter = NULL;
632 
633 	for (iter = devices;
634 	    (iter != NULL) && (error == 0);
635 	    iter = iter->next) {
636 
637 	    dlist_t *iter1;
638 	    for (iter1 = devconfig_get_components((devconfig_t *)iter->obj);
639 		(iter1 != NULL) && (error == 0);
640 		iter1 = iter1->next) {
641 
642 		devconfig_t *comp = (devconfig_t *)iter1->obj;
643 		if (dlist_contains(*unique, comp,
644 		    compare_devconfig_sizes) != B_TRUE) {
645 
646 		    dlist_t *item = NULL;
647 		    if ((item = dlist_new_item(comp)) == NULL) {
648 			error = ENOMEM;
649 		    } else {
650 			*unique = dlist_insert_ordered(item, *unique,
651 				ASCENDING, compare_devconfig_sizes);
652 		    }
653 		}
654 	    }
655 	}
656 
657 	return (error);
658 }
659 
660 /*
661  * FUNCTION:	remove_undersized_slices(dlist_t *unique,
662  *			dlist_t **avail)
663  *
664  * INPUT:	avail	- pointer to a list of available slices
665  * 		unique	- pointer to a list of uniquely size slices
666  *
667  * OUTPUT:	avail - pointer to an updated list of available slices
668  *			that are at least as large as slices in the
669  *			unique list.
670  *
671  * RETURNS:	int	- 0 on success
672  *			 !0 otherwise.
673  *
674  * PURPOSE:	filter available slices and remove those that aren't
675  *		large enough for the device components which need spares.
676  *
677  *		For each uniquely sized slice, find all available slices
678  *		that are larger and add them to the filtered list.
679  */
680 static int
remove_undersized_slices(dlist_t * unique,dlist_t ** avail)681 remove_undersized_slices(
682 	dlist_t		*unique,
683 	dlist_t		**avail)
684 {
685 	dlist_t		*filtered = NULL;
686 	dlist_t		*iter = NULL;
687 	int		error = 0;
688 
689 	for (iter = unique;
690 	    (iter != NULL) && (error == 0);
691 	    iter = iter->next) {
692 
693 	    devconfig_t	*uslice = (devconfig_t *)iter->obj;
694 	    uint64_t	usize = 0;
695 	    dlist_t	*iter2 = NULL;
696 
697 	    error = devconfig_get_size(uslice, &usize);
698 
699 	    for (iter2 = *avail;
700 		(iter2 != NULL) && (error == 0);
701 		iter2 = iter2->next) {
702 
703 		dm_descriptor_t	aslice = (uintptr_t)iter2->obj;
704 		uint64_t	asize = 0;
705 
706 		error = slice_get_size(aslice, &asize);
707 		if (asize >= usize) {
708 
709 		    /* this slice is large enough */
710 		    dlist_t *item = NULL;
711 		    if ((item = dlist_new_item((void *)(uintptr_t)aslice)) ==
712 			NULL) {
713 			error = ENOMEM;
714 		    } else {
715 			filtered = dlist_insert_ordered(item, filtered,
716 				ASCENDING, compare_slice_sizes);
717 		    }
718 
719 		}
720 	    }
721 	}
722 
723 	if (error == 0) {
724 	    dlist_free_items(*avail, NULL);
725 	    *avail = filtered;
726 	} else {
727 	    dlist_free_items(filtered, NULL);
728 	}
729 
730 	return (error);
731 }
732 
733 /*
734  * FUNCTION:	find_spare_for_component(devconfig_t *component,
735  *			dlist_t *all_spares, dlist_t *hbas, dlist_t *disks,
736  *			boolean_t *found)
737  *
738  * INPUT:	comp	- pointer to a devconfig_t slice compenent that
739  *				needs to be spared
740  * 		all_spares - pointer to a list of spares currently
741  *				in the pool or that will be added
742  * 		hbas	- pointer to a list of HBAs the component's
743  *				parent device utilizes
744  * 		disks	- pointer to a list of disks the component's
745  *				parent device utilizes
746  *
747  * OUTPUT:	found - pointer to a boolean_t to hold the result.
748  *
749  * RETURNS:	int	- 0 on success
750  *			 !0 otherwise.
751  *
752  * PURPOSE:	Find a spare for the input component.
753  *
754  *		Searches the input list of spares to see if one is
755  *		sufficient.
756  *
757  *		A suffcient spare is one that is large enough to spare
758  *		for the input component and not on the same disk as any
759  *		of the components in the parent device.
760  *
761  *		The optimal spare would be on a different controller/HBA
762  *		as the component and any of the components in the parent
763  *		device.  We settle for sufficient.
764  */
765 static int
find_spare_for_component(devconfig_t * component,dlist_t * all_spares,dlist_t * hbas,dlist_t * disks,boolean_t * found)766 find_spare_for_component(
767 	devconfig_t	*component,
768 	dlist_t		*all_spares,
769 	dlist_t		*hbas,
770 	dlist_t		*disks,
771 	boolean_t	*found)
772 {
773 	dlist_t		*iter = NULL;
774 	uint64_t	csize = 0;
775 	int		error = 0;
776 
777 	*found = B_FALSE;
778 
779 	(void) devconfig_get_size(component, &csize);
780 
781 	for (iter = all_spares;
782 	    (iter != NULL) && (*found == B_FALSE) && (error == 0);
783 	    iter = iter->next) {
784 
785 	    devconfig_t		*spare = (devconfig_t *)iter->obj;
786 	    char 		*spname = NULL;
787 	    uint64_t 		spsize = 0;
788 
789 	    if (((error = devconfig_get_name(spare, &spname)) != 0) ||
790 		((error = devconfig_get_size(spare, &spsize)) != 0)) {
791 		continue;
792 	    }
793 
794 	    if (spsize >= csize) {
795 
796 		dm_descriptor_t	disk = NULL;
797 
798 		/* see if spare's disk is independent of the volume */
799 		error = get_disk_for_named_slice(spname, &disk);
800 		if ((error == 0) && (dlist_contains(disks,
801 		    (void *)(uintptr_t)disk, compare_descriptor_names) ==
802 		    B_FALSE)) {
803 		    *found = B_TRUE;
804 		}
805 	    }
806 	}
807 
808 	if ((*found == B_TRUE) && (get_max_verbosity() >= OUTPUT_DEBUG)) {
809 	    char *cname = NULL;
810 	    (void) devconfig_get_name(component, &cname);
811 	    oprintf(OUTPUT_DEBUG,
812 		    gettext("    found existing spare for: %s (%llu)\n"),
813 		    cname, csize);
814 	}
815 
816 	return (error);
817 }
818 
819 /*
820  * FUNCTION:	choose_spare_for_component(devconfig_t *component,
821  *			dlist_t *all_spares, dlist_t **new_spares,
822  *			dlist_t avail, uint16_t npaths, dlist_t *used_hbas,
823  *			dlist_t *used_disks)
824  *
825  * INPUT:	comp	- pointer to a devconfig_t slice compenent that
826  *				needs to be spared
827  * 		all_spares - pointer to a list of spares currently
828  *				in the pool and those to be added
829  * 		new_spares - pointer to a list of spares that need to
830  *				be added to the pool
831  *		avail	- list of available slices
832  *		npaths	- required number of paths for the spare
833  *		used_hbas - list of HBAs used by the component's parent
834  *		used_disks - list of disks used by the component's parent
835  *
836  * OUTPUT:	all_spares - the possibly updated list of all spares
837  *		new_spares - the possibly updated list of spares which
838  *			need to be added to the pool.
839  *
840  * RETURNS:	int	- 0 on success
841  *			 !0 otherwise.
842  *
843  * PURPOSE:	Find a new spare for the input component.
844  *
845  *		Select a spare from the available slice list and add
846  *		it to the new_spares list.
847  *
848  *		The spare slice chosen should be on a unique HBA and
849  *		disk relative to the input lists of used HBAs and disks
850  *		and any spares in the pool.
851  */
852 static int
choose_spare_for_component(devconfig_t * component,dlist_t ** all_spares,dlist_t ** new_spares,dlist_t ** avail,dlist_t * used_hbas,dlist_t * used_disks,uint16_t npaths)853 choose_spare_for_component(
854 	devconfig_t	*component,
855 	dlist_t		**all_spares,
856 	dlist_t		**new_spares,
857 	dlist_t		**avail,
858 	dlist_t		*used_hbas,
859 	dlist_t		*used_disks,
860 	uint16_t	npaths)
861 {
862 	devconfig_t	*spare = NULL;
863 	uint64_t	csize = 0;
864 	int		error = 0;
865 
866 	(void) devconfig_get_size(component, &csize);
867 
868 	if (get_max_verbosity() >= OUTPUT_DEBUG) {
869 	    char *cname = NULL;
870 	    (void) devconfig_get_name(component, &cname);
871 	    oprintf(OUTPUT_DEBUG,
872 		    gettext("    select new spare for: %s (%llu)\n"),
873 		    cname, csize);
874 	}
875 
876 	/*
877 	 * find a spare for the input component.
878 	 * select the best one from the available list that
879 	 * is on a unique disk.
880 	 */
881 
882 	/*
883 	 * 1st B_TRUE: require a different disk than those used by
884 	 *		all spares and devices
885 	 * 2nd B_TRUE: requested size is the minimum acceptable
886 	 * 1st B_FALSE: do not add an extra cylinder when resizing slice,
887 	 *		this is only necessary for Stripe components whose
888 	 *		sizes get rounded down to an interlace multiple and
889 	 *		then down to a cylinder boundary.
890 	 */
891 	error = choose_slice(csize, npaths, *avail, *all_spares,
892 		used_hbas, used_disks, B_TRUE, B_TRUE, B_FALSE, &spare);
893 
894 	if ((error == 0) && (spare == NULL)) {
895 	    /* can't find one on a unique disk, try again on any disk */
896 
897 	    /* BEGIN CSTYLED */
898 	    /*
899 	     * 1st B_FALSE: don't require a different disk than those used
900 	     *		by all spares and devices
901 	     * 2nd B_TRUE: requested size is still the minimum acceptable
902 	     * 2nd B_FALSE: do not add an extra cylinder when resizing slice
903 	     *		this is only necessary for Stripe components whose
904 	     *		sizes get rounded down to an interlace multiple and
905 	     *		then down to a cylinder boundary.
906 	     */
907 	    /* END CSTYLED */
908 	    error = choose_slice(
909 		    csize, npaths, *avail, *all_spares, used_hbas,
910 		    used_disks, B_FALSE, B_TRUE, B_FALSE, &spare);
911 	}
912 
913 	if ((error == 0) && (spare != NULL)) {
914 
915 	    dlist_t	*rmvd = NULL;
916 	    dlist_t	*item = NULL;
917 	    char	*spname = NULL;
918 
919 	    if ((item = dlist_new_item(spare)) == NULL) {
920 		error = ENOMEM;
921 	    } else {
922 
923 		/* add spare to the all spares list */
924 		*all_spares = dlist_append(item, *all_spares, AT_HEAD);
925 
926 		if ((item = dlist_new_item(spare)) == NULL) {
927 		    error = ENOMEM;
928 		} else {
929 
930 		    /* add spare to the new spares list */
931 		    *new_spares = dlist_insert_ordered(
932 			    item, *new_spares, ASCENDING,
933 			    compare_devconfig_sizes);
934 
935 		    /* remove it from the available list */
936 		    *avail = dlist_remove_equivalent_item(*avail, spare,
937 			    compare_devconfig_and_descriptor_names,
938 			    &rmvd);
939 
940 		    if (rmvd != NULL) {
941 			free(rmvd);
942 		    }
943 
944 		    /* add the spare to the used slice list */
945 		    error = devconfig_get_name(spare, &spname);
946 		    if (error == 0) {
947 			error = add_used_slice_by_name(spname);
948 		    }
949 		}
950 	    }
951 
952 	} else {
953 
954 	    /* no spare, give up on layout */
955 	    oprintf(OUTPUT_TERSE,
956 		    gettext("  <---Failed: insufficient suitable spares\n"));
957 
958 	    volume_set_error(
959 		    gettext("failed to find sufficient spares for HSP\n"));
960 
961 	    error = -1;
962 	}
963 
964 	return (error);
965 }
966