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