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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include "volume_error.h"
34 #include "volume_defaults.h"
35 #include "volume_dlist.h"
36 #include "volume_output.h"
37 #include "volume_request.h"
40 #include "layout_request.h"
42 #include "layout_concat.h"
43 #include "layout_discovery.h"
44 #include "layout_device_cache.h"
45 #include "layout_device_util.h"
46 #include "layout_dlist_util.h"
47 #include "layout_hsp.h"
48 #include "layout_mirror.h"
49 #include "layout_slice.h"
50 #include "layout_stripe.h"
51 #include "layout_svm_util.h"
52 #include "layout_validate.h"
56 static int layout_init(devconfig_t
*request
, defaults_t
*defaults
);
57 static int layout_diskset(request_t
*request
, dlist_t
*results
);
59 static int process_request(devconfig_t
*request
, dlist_t
**results
);
60 static int process_qos_request(devconfig_t
*request
, dlist_t
**results
);
61 static int process_hsp_request(devconfig_t
*request
, dlist_t
**results
);
64 * stuff for making/updating the HSP to service devices
65 * created by the toplevel request
67 static devconfig_t
*_hsp_request
= NULL
;
68 static dlist_t
*_hsp_devices
= NULL
;
69 static void set_hsp_request(devconfig_t
*request
);
70 static void unset_hsp_request();
73 * struct to track which disks have been explicitly modified
74 * during the layout process...
76 * disk is the dm_descriptor_t of the modified disk
77 * accessname is the name to access the disk thru
78 * slices is the list of modified slices on the disk
87 * modified_disks is a list of moddisk_t structs
88 * tracking disks have been modified during layout.
90 static dlist_t
*_modified_disks
= NULL
;
92 static int collect_modified_disks(devconfig_t
*request
, dlist_t
*results
);
93 static int add_modified_disks_to_diskset(
95 devconfig_t
*diskset
);
96 static int release_modified_disks();
97 static int get_removed_slices_for_disks(
99 static int get_modified_slices_for_disks(
101 static int compare_disk_to_moddisk_disk(
105 static int convert_device_names(devconfig_t
*request
, dlist_t
*devs
);
108 * FUNCTION: get_layout(devconfig_t *request, defaults_t *defaults)
110 * INPUT: request - a devconfig_t pointer to the toplevel request
111 * defaults - a results_t pointer to the defaults
113 * RETURNS: int - 0 - on success
116 * PURPOSE: Public entry point to layout module.
121 defaults_t
*defaults
)
123 devconfig_t
*diskset_req
= NULL
;
124 dlist_t
*iter
= NULL
;
125 dlist_t
*results
= NULL
;
128 if ((diskset_req
= request_get_diskset_req(request
)) != NULL
) {
130 /* initialize using the the top-level disk set request... */
131 if ((error
= layout_init(diskset_req
, defaults
)) != 0) {
135 oprintf(OUTPUT_TERSE
,
136 gettext("\nProcessing volume request...\n"));
138 iter
= devconfig_get_components(diskset_req
);
139 for (; (iter
!= NULL
) && (error
== 0); iter
= iter
->next
) {
141 /* process each volume request, stop on any error */
142 devconfig_t
*subreq
= (devconfig_t
*)iter
->obj
;
143 dlist_t
*subres
= NULL
;
145 ((error
= process_request(subreq
, &subres
)) != 0) ||
146 (error
= collect_modified_disks(subreq
, subres
)) ||
147 (error
= convert_device_names(subreq
, subres
));
149 results
= dlist_append(subres
, results
, AT_TAIL
);
154 /* process HSP request */
155 dlist_t
*subres
= NULL
;
156 error
= process_hsp_request(diskset_req
, &subres
);
158 results
= dlist_append(subres
, results
, AT_TAIL
);
163 oprintf(OUTPUT_TERSE
,
164 gettext("\nAssembling volume specification...\n"));
165 /* determine required diskset modifications */
166 error
= layout_diskset(request
, results
);
172 oprintf(OUTPUT_TERSE
,
173 gettext("\nVolume request completed successfully.\n"));
178 gettext("Malformed request, missing top level "
179 "disk set request."));
186 * FUNCTION: layout_clean_up()
188 * PURPOSE: function which handles the details of cleaning up cached
189 * data and any other memory allocated during the layout
192 * release physical device data structs
193 * release SVM logical device data structs
194 * release validation data structs
195 * release modified device data structs
196 * release request processing data structs
198 * This function is also exported as part of the public
199 * interface to the layout module, clients of layout
200 * are required to call this function if get_layout()
201 * was called and was not allowed to return. For example,
202 * if SIGINT was received while a layout request was in
208 (void) release_request_caches();
209 (void) release_validation_caches();
211 (void) release_slices_to_remove();
212 (void) release_modified_slices();
213 (void) release_modified_disks();
215 (void) release_reserved_slices();
216 (void) release_used_slices();
218 (void) release_usable_devices();
219 (void) release_svm_names(get_request_diskset());
220 (void) release_known_devices();
222 (void) unset_hsp_request(NULL
);
223 (void) unset_request_defaults(NULL
);
224 (void) unset_request_diskset(NULL
);
225 (void) unset_toplevel_request(NULL
);
229 * FUNCTION: layout_init(devconfig_t *diskset, defaults_t *defaults)
231 * INPUT: diskset - a devconfig_t pointer to the toplevel request
232 * defaults - a results_t pointer to the defaults
234 * RETURNS: int - 0 - on success
237 * PURPOSE: function which handles the details of initializing the layout
238 * module prior to processing a request.
240 * Determines the requested disk set and validates it.
242 * Scans the physical device configuration.
243 * Scans the SVM logical device configuration.
245 * Initializes layout private global data structures and does
246 * semantic validation of the request.
250 devconfig_t
*diskset
,
251 defaults_t
*defaults
)
253 dlist_t
*iter
= NULL
;
257 ((error
= validate_basic_svm_config()) != 0) ||
259 /* determine & validate requested disk set name */
260 (error
= devconfig_get_name(diskset
, &dsname
)) ||
261 (error
= set_request_diskset(dsname
)) ||
263 /* discover known physical and logical devices */
264 (error
= discover_known_devices()) ||
265 (error
= scan_svm_names(dsname
)) ||
267 /* validate and remember toplevel request */
268 (error
= set_toplevel_request(diskset
)) ||
270 /* validate and remember defaults for this request */
271 (error
= set_request_defaults(defaults
));
277 oprintf(OUTPUT_TERSE
,
278 gettext("\nValidating volume request...\n"));
280 iter
= devconfig_get_components(diskset
);
281 for (; (iter
!= NULL
) && (error
== 0); iter
= iter
->next
) {
282 devconfig_t
*subreq
= (devconfig_t
*)iter
->obj
;
283 error
= validate_request(subreq
);
287 error
= discover_usable_devices(dsname
);
291 /* final validation on explicitly requested components */
292 error
= validate_reserved_slices();
296 /* final validation on request sizes vs. actual avail space */
297 error
= validate_request_sizes(diskset
);
304 * FUNCTION: process_request(devconfig_t *req, dlist_t **results)
306 * INPUT: req - a devconfig_t pointer to the current request
307 * results - pointer to a list of resulting volumes
309 * RETURNS: int - 0 - on success
312 * PURPOSE: function which handles the details of an explicit
315 * Determines the requested volume type, whether the
316 * request contains specific subcomponents and dispatches
317 * to the appropriate layout function for that type.
319 * Resulting volumes are appended to the results list.
321 * Note that an HSP request is held until all the volumes
322 * in the request have been successfully composed. This
323 * ensures that HSP spare sizing can be appropriate to
331 component_type_t type
= TYPE_UNKNOWN
;
332 uint64_t nbytes
= 0; /* requested volume size */
333 dlist_t
*comps
= NULL
;
337 (void) devconfig_get_type(req
, &type
);
338 (void) devconfig_get_size(req
, &nbytes
);
339 comps
= devconfig_get_components(req
);
341 if (type
== TYPE_HSP
) {
342 /* HSP processing needs to happen after all other volumes. */
343 /* set the HSP request aside until all other requests have */
344 /* been completed successfully */
345 set_hsp_request(req
);
349 oprintf(OUTPUT_TERSE
, "\n");
350 oprintf(OUTPUT_VERBOSE
, "******************\n");
352 ncomps
= dlist_length(comps
);
354 if (type
== TYPE_STRIPE
) {
356 return (populate_explicit_stripe(req
, results
));
358 return (layout_stripe(req
, nbytes
, results
));
362 if (type
== TYPE_CONCAT
) {
364 return (populate_explicit_concat(req
, results
));
366 return (layout_concat(req
, nbytes
, results
));
370 if (type
== TYPE_MIRROR
) {
372 return (populate_explicit_mirror(req
, results
));
375 if ((error
= get_mirror_nsubs(req
, &nsubs
)) != 0) {
378 return (layout_mirror(req
, nsubs
, nbytes
, results
));
383 if (type
== TYPE_VOLUME
) {
384 error
= process_qos_request(req
, results
);
391 * FUNCTION: process_qos_request(devconfig_t *req, dlist_t **results)
393 * INPUT: req - a devconfig_t pointer to the current request
394 * results - pointer to a list of resulting volumes
396 * RETURNS: int - 0 - on success
399 * PURPOSE: function which handles the details of mapping an implicit
400 * volume request of QoS attributes into a volume type.
402 * Resulting volumes are appended to the results list.
414 /* get QoS attributes */
415 (void) devconfig_get_size(req
, &nbytes
);
417 if ((error
= get_volume_redundancy_level(req
, &rlevel
)) != 0) {
418 if (error
== ERR_ATTR_UNSET
) {
426 error
= layout_stripe(req
, nbytes
, results
);
428 error
= layout_mirror(req
, rlevel
, nbytes
, results
);
436 * FUNCTION: layout_diskset(request_t *req, dlist_t **results)
438 * INPUT: req - a request_t pointer to the toplevel request
439 * results - pointer to the list of composed result volumes
441 * RETURNS: int - 0 - on success
444 * PURPOSE: function which handles the details of completing an layout
447 * Determines if the disk set specified in the request currently
448 * exists and sets it up for creation if it doesn't.
450 * Adds new disks required by the result volumes to the disk set.
452 * Attaches the result volumes to the disk set result.
454 * Convert slice and disk names to preferred names.
456 * Attaches the disk set result to the toplevel request.
464 devconfig_t
*diskset
= NULL
;
465 dlist_t
*comps
= NULL
;
467 ((error
= new_devconfig(&diskset
, TYPE_DISKSET
)) != 0) ||
468 (error
= devconfig_set_name(diskset
, get_request_diskset())) ||
469 (error
= add_modified_disks_to_diskset(results
, diskset
));
471 free_devconfig(diskset
);
475 /* add resulting volumes */
476 if (results
!= NULL
) {
477 comps
= devconfig_get_components(diskset
);
478 comps
= dlist_append(results
, comps
, AT_TAIL
);
479 devconfig_set_components(diskset
, comps
);
482 request_set_diskset_config(request
, diskset
);
488 * FUNCTION: convert_device_names(devconfig_t request, dlist_t *devices)
490 * INPUT: request - a devconfig_t request pointer
491 * devices - a list of devconfig_t devices
493 * RETURNS: int - 0 - on success
496 * PURPOSE: Utility function to convert any slice or disk drive
497 * names in a result devconfig_t to the preferred name
498 * which should be used to access the device.
500 * This convert the temporary names used by layout to
501 * the proper DID or /dev/dsk alias.
504 convert_device_names(
505 devconfig_t
*request
,
512 (iter
!= NULL
) && (error
== 0);
515 devconfig_t
*dev
= (devconfig_t
*)iter
->obj
;
516 component_type_t type
= TYPE_UNKNOWN
;
517 dm_descriptor_t disk
= (dm_descriptor_t
)0;
518 char *devname
= NULL
;
519 char *diskname
= NULL
;
520 char *slicename
= NULL
;
523 if ((error
= devconfig_get_type(dev
, &type
)) == 0) {
531 error
= convert_device_names(request
,
532 devconfig_get_components(dev
));
538 ((error
= devconfig_get_name(dev
, &devname
)) != 0) ||
539 (error
= devconfig_get_slice_index(dev
, &index
)) ||
540 (error
= get_disk_for_named_slice(devname
, &disk
)) ||
541 (error
= get_device_access_name(request
, disk
,
543 (error
= make_slicename_for_diskname_and_index(
544 diskname
, index
, &slicename
));
546 if ((error
== 0) && (slicename
!= NULL
)) {
547 error
= devconfig_set_name(dev
, slicename
);
560 * FUNCTION: add_modified_disk(devconfig_t request, dm_descriptor_t disk);
562 * INPUT: request - a pointr to a devconfig_t request
563 * disk - dm_descriptor_t handle for a disk that has been modified
565 * SIDEEFFECTS: adds an entry to the _modified_disks list which tracks
566 * the disks that have been explicitly modified by
569 * RETURNS: int - 0 on success
572 * PURPOSE: Adds the input disk to the list of those that have been
575 * Disks are modified during layout for two reasons:
577 * 1. any disk that is to be added to the disk set gets
578 * an explicitly updated label.
580 * 2. once a disk is in the disk set, existing slices
581 * may be resized or new slices can be added.
585 devconfig_t
*request
,
586 dm_descriptor_t disk
)
588 dlist_t
*iter
= NULL
;
589 moddisk_t
*moddisk
= NULL
;
590 dlist_t
*item
= NULL
;
593 for (iter
= _modified_disks
; iter
!= NULL
; iter
= iter
->next
) {
594 moddisk
= (moddisk_t
*)iter
->obj
;
595 if (compare_descriptor_names(
596 (void *)(uintptr_t)moddisk
->disk
,
597 (void *)(uintptr_t)disk
) == 0) {
598 /* already in list */
603 moddisk
= (moddisk_t
*)calloc(1, sizeof (moddisk_t
));
604 if (moddisk
== NULL
) {
608 error
= get_device_access_name(request
, disk
, &aname
);
611 /* add to list of modified disks */
612 moddisk
->disk
= disk
;
613 moddisk
->accessname
= aname
;
614 moddisk
->slices
= NULL
;
616 if ((item
= dlist_new_item((void *)moddisk
)) == NULL
) {
621 dlist_append(item
, _modified_disks
, AT_HEAD
);
630 * FUNCTION: collect_modified_disks(devconfig_t *request, dlist_t* devs)
632 * INPUT: devs - pointer to a list of composed volumes
634 * SIDEEFFECT: updates the module global list _modified_disks
636 * RETURNS: int - 0 - success
639 * PURPOSE: Helper to maintain the list of disks to be added to the
642 * Iterates the input list of devices and determines which
643 * disks they use. If a disk is not in the _modified_disks
647 collect_modified_disks(
648 devconfig_t
*request
,
654 dm_descriptor_t disk
= (dm_descriptor_t
)0;
656 for (; (devs
!= NULL
) && (error
== 0); devs
= devs
->next
) {
658 devconfig_t
*dev
= (devconfig_t
*)devs
->obj
;
659 component_type_t type
= TYPE_UNKNOWN
;
661 if ((error
= devconfig_get_type(dev
, &type
)) == 0) {
669 error
= collect_modified_disks(request
,
670 devconfig_get_components(dev
));
675 ((error
= devconfig_get_name(dev
, &sname
)) != 0) ||
676 (error
= get_disk_for_named_slice(sname
, &disk
)) ||
677 (error
= add_modified_disk(request
, disk
));
688 * FUNCTION: add_modified_disks_to_diskset(dlist_t *devices,
689 * devconfig_t *diskset)
691 * INPUT: devices - pointer to a list of devices
693 * OUTPUT: diskset - pointer to a devconfig_t representing the disk set,
694 * updated to include modified disks and slices as
697 * RETURNS: int - 0 - success
700 * PURPOSE: Helper to add devconfig_t structs for disks and slices
703 * Updates the list of _modified_disks by examining the input
704 * list of composed devices.
706 * Iterates _modified_disks and creates a devconfig_t component
707 * for each disk in the list, the list of disks is then attached
708 * to the input disk set.
710 * Modified slices for disks in the disk set are added as well.
713 add_modified_disks_to_diskset(
715 devconfig_t
*diskset
)
720 dlist_t
*list
= NULL
;
721 char *dsname
= get_request_diskset();
723 /* add modified disks to disk set's component list */
724 list
= devconfig_get_components(diskset
);
726 oprintf(OUTPUT_TERSE
,
727 gettext(" Collecting modified disks...\n"));
729 /* collect removed slices for modified disks */
730 error
= get_removed_slices_for_disks(_modified_disks
);
732 /* collect modified slices for modified disks */
733 error
= get_modified_slices_for_disks(_modified_disks
);
735 for (iter
= _modified_disks
;
736 (iter
!= NULL
) && (error
== 0);
739 moddisk_t
*moddisk
= (moddisk_t
*)iter
->obj
;
740 dm_descriptor_t disk
= moddisk
->disk
;
741 devconfig_t
*newdisk
= NULL
;
742 boolean_t in_set
= B_FALSE
;
744 oprintf(OUTPUT_VERBOSE
, " %s\n", moddisk
->accessname
);
746 error
= is_disk_in_diskset(disk
, dsname
, &in_set
);
747 if ((error
== 0) && (in_set
!= B_TRUE
)) {
748 /* New disk, add it to the disk set */
749 ((error
= new_devconfig(&newdisk
, TYPE_DRIVE
)) != 0) ||
750 (error
= devconfig_set_name(newdisk
, moddisk
->accessname
));
752 dlist_t
*item
= dlist_new_item(newdisk
);
756 list
= dlist_append(item
, list
, AT_TAIL
);
757 oprintf(OUTPUT_DEBUG
,
758 gettext(" must add %s to disk set \"%s\"\n"),
759 moddisk
->accessname
, dsname
);
762 free_devconfig(newdisk
);
766 if ((error
== 0) && (moddisk
->slices
!= NULL
)) {
767 /* move moddisk's slice list to disk set comp list */
768 list
= dlist_append(moddisk
->slices
, list
, AT_TAIL
);
769 moddisk
->slices
= NULL
;
774 devconfig_set_components(diskset
, list
);
776 dlist_free_items(list
, NULL
);
783 * FUNCTIONS: void release_modified_disks()
788 * PURPOSE: cleanup the module global list of disks that need
789 * to be added to the disk set to satisfy the request.
792 release_modified_disks()
794 dlist_t
*iter
= _modified_disks
;
796 for (; iter
!= NULL
; iter
= iter
->next
) {
797 moddisk_t
*moddisk
= (moddisk_t
*)iter
->obj
;
798 if (moddisk
->slices
!= NULL
) {
799 dlist_free_items(moddisk
->slices
, free_devconfig
);
800 moddisk
->slices
= NULL
;
806 dlist_free_items(_modified_disks
, NULL
);
807 _modified_disks
= NULL
;
813 * FUNCTION: get_removed_slices_for_disks(dlist_t *mod_disks)
815 * INPUT: mod_disks - a list of moddisk_t structs
817 * OUTPUT: mod_disks - the list of moddisk_t structs updated with
818 * the slices to be removed for each disk
820 * RETURNS: int - 0 - success
823 * PURPOSE: Helper to create a list of devconfig_t structs
824 * for slices on the input disks which need to be
825 * removed from the system.
827 * Iterates the list of slices to be removed and
828 * creates a devconfig_t component for each slice
829 * in the list that is on any of the input modified
832 * Slice names are constructed using the modified disk's
833 * access name to ensure that the correct alias is
834 * used to get to the slice.
837 get_removed_slices_for_disks(
841 dlist_t
*iter
= NULL
;
843 /* collect slices to be removed for the modified disks */
844 for (iter
= get_slices_to_remove();
845 (iter
!= NULL
) && (error
== 0);
848 rmvdslice_t
*rmvd
= (rmvdslice_t
*)iter
->obj
;
849 dm_descriptor_t disk
= (dm_descriptor_t
)0;
850 moddisk_t
*moddisk
= NULL
;
852 devconfig_t
*newslice
= NULL
;
853 dlist_t
*item
= NULL
;
855 (void) get_disk_for_named_slice(rmvd
->slice_name
, &disk
);
857 if ((item
= dlist_find(mod_disks
, (void *)(uintptr_t)disk
,
858 compare_disk_to_moddisk_disk
)) == NULL
) {
859 /* slice on disk that we don't care about */
863 moddisk
= (moddisk_t
*)item
->obj
;
865 /* create output slice struct for the removed slice */
866 ((error
= make_slicename_for_diskname_and_index(
867 moddisk
->accessname
, rmvd
->slice_index
, &sname
)) != 0) ||
868 (error
= new_devconfig(&newslice
, TYPE_SLICE
)) ||
869 (error
= devconfig_set_name(newslice
, sname
)) ||
870 (error
= devconfig_set_size_in_blocks(newslice
, 0));
872 /* add to the moddisk's list of slices */
874 if ((item
= dlist_new_item(newslice
)) == NULL
) {
875 free_devconfig(newslice
);
879 dlist_append(item
, moddisk
->slices
, AT_TAIL
);
882 free_devconfig(newslice
);
890 * FUNCTION: get_modified_slices_for_disks(dlist_t *mod_disks)
892 * INPUT: mod_disks - a list of moddisk_t structs
894 * OUTPUT: mod_disks - the list of moddisk_t structs updated with
895 * the modified slices for each disk
897 * RETURNS: int - 0 - success
900 * PURPOSE: Helper to create a list of devconfig_t structs
901 * for slices on the input disks which have been
902 * modified for use by layout.
904 * Iterates the list of modified slices and creates a
905 * devconfig_t component for each slice in the list
906 * that is on any of the input modified disks.
908 * Slice names are constructed using the modified disk's
909 * access name to ensure that the correct alias is
910 * used to get to the slice.
913 get_modified_slices_for_disks(
917 dlist_t
*iter
= NULL
;
919 for (iter
= get_modified_slices();
920 (iter
!= NULL
) && (error
== 0);
923 modslice_t
*mods
= (modslice_t
*)iter
->obj
;
924 devconfig_t
*slice
= mods
->slice_devcfg
;
925 devconfig_t
*newslice
= NULL
;
926 dm_descriptor_t disk
;
934 /* only add modified slices that were sources */
935 if ((mods
->times_modified
== 0) ||
936 (mods
->src_slice_desc
!= (dm_descriptor_t
)0)) {
940 (void) devconfig_get_name(slice
, &sname
);
941 (void) get_disk_for_named_slice(sname
, &disk
);
943 if ((item
= dlist_find(mod_disks
, (void *)(uintptr_t)disk
,
944 compare_disk_to_moddisk_disk
)) == NULL
) {
945 /* slice on disk that we don't care about */
949 moddisk
= (moddisk_t
*)item
->obj
;
951 /* create output slice struct for the modified slice */
952 ((error
= devconfig_get_slice_start_block(slice
,
954 (error
= devconfig_get_size_in_blocks(slice
, &nblks
)) ||
955 (error
= devconfig_get_slice_index(slice
, &index
)) ||
956 (error
= make_slicename_for_diskname_and_index(
957 moddisk
->accessname
, index
, &sname
)) ||
958 (error
= new_devconfig(&newslice
, TYPE_SLICE
)) ||
959 (error
= devconfig_set_name(newslice
, sname
)) ||
960 (error
= devconfig_set_slice_start_block(newslice
, stblk
)) ||
961 (error
= devconfig_set_size_in_blocks(newslice
, nblks
));
963 /* add to the moddisk's list of slices */
965 if ((item
= dlist_new_item(newslice
)) == NULL
) {
966 free_devconfig(newslice
);
970 dlist_append(item
, moddisk
->slices
, AT_TAIL
);
973 free_devconfig(newslice
);
981 * FUNCTION: compare_disk_to_moddisk_disk(void *disk, void *moddisk)
983 * INPUT: disk - opaque pointer to a dm_descriptor_t
984 * moddisk - opaque moddisk_t pointer
986 * RETURNS: int - 0 - if disk == moddisk->disk
989 * PURPOSE: dlist_t helper which compares the input disk dm_descriptor_t
990 * handle to the disk dm_descriptor_t handle in the input
993 * Comparison is done via compare_descriptor_names.
996 compare_disk_to_moddisk_disk(
1000 assert(disk
!= (dm_descriptor_t
)0);
1001 assert(moddisk
!= NULL
);
1003 return (compare_descriptor_names((void *)disk
,
1004 (void *)(uintptr_t)((moddisk_t
*)moddisk
)->disk
));
1008 * FUNCTIONS: void set_hsp_request()
1013 * PURPOSE: set the module global HSP request struct.
1023 * FUNCTIONS: void unset_hsp_request()
1028 * PURPOSE: unset the module global HSP request struct.
1033 _hsp_request
= NULL
;
1037 * FUNCTION: process_hsp_request(devconfig_t *req, dlist_t **results)
1038 * INPUT: req - pointer to the toplevel disk set devconfig_t request
1039 * results - pointer to a list of composed results
1041 * RETURNS: int - 0 - success
1044 * PURPOSE: Helper which determines HSP processing for the
1045 * composed volumes which need HSP spares.
1048 process_hsp_request(
1054 if (_hsp_request
!= NULL
) {
1055 oprintf(OUTPUT_TERSE
,
1056 gettext("\nProcessing HSP...\n"));
1059 if (_hsp_devices
== NULL
) {
1060 /* no devices -> no HSP */
1061 oprintf(OUTPUT_VERBOSE
,
1062 gettext(" No devices require hot spares...\n"));
1065 oprintf(OUTPUT_TERSE
, "\n");
1067 ((error
= layout_hsp(req
, _hsp_request
, _hsp_devices
,
1069 (error
= collect_modified_disks(_hsp_request
, *results
)) ||
1070 (error
= convert_device_names(_hsp_request
, *results
));
1077 * FUNCTION: add_to_hsp_list(dlist_t* list)
1078 * INPUT: devs - pointer to a list of composed volumes
1080 * SIDEEFFECT: updates the module global list _hsp_devices
1082 * RETURNS: int - 0 - success
1085 * PURPOSE: Helper to update the list of devices which need HSP spares.
1087 * Iterates the input list of devices and adds them them to the
1088 * module provate list of devices needing spares.
1094 dlist_t
*iter
= NULL
;
1097 for (iter
= list
; iter
!= NULL
; iter
= iter
->next
) {
1098 dlist_t
*item
= NULL
;
1100 if ((item
= dlist_new_item(iter
->obj
)) == NULL
) {
1104 _hsp_devices
= dlist_append(item
, _hsp_devices
, AT_HEAD
);
1111 * FUNCTION: string_case_compare(
1112 * char *str1, char *str2)
1114 * INPUT: str1 - char *
1117 * RETURNS: int - <0 - if str1 < str2
1118 * 0 - if str1 == str2
1119 * >0 - if str1 > str2
1121 * PURPOSE: More robust case independent string comparison function.
1123 * Assumes str1 and str2 are both char *
1125 * Compares the lengths of each and if equivalent compares
1126 * the strings using strcasecmp.
1129 string_case_compare(
1135 assert(str1
!= NULL
);
1136 assert(str2
!= NULL
);
1138 if ((result
= (strlen(str1
) - strlen(str2
))) == 0) {
1139 result
= strcasecmp(str1
, str2
);