7712 mandoc -Tlint does always exit with error code 0
[unleashed.git] / usr / src / cmd / lvm / metassist / layout / layout.c
blob0e6ad4596ac26e45d08a03920437fbc09ed61504
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <assert.h>
30 #include <string.h>
31 #include <libintl.h>
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"
39 #include "layout.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"
54 #define _LAYOUT_C
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
80 typedef struct {
81 dm_descriptor_t disk;
82 char *accessname;
83 dlist_t *slices;
84 } moddisk_t;
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(
94 dlist_t *devices,
95 devconfig_t *diskset);
96 static int release_modified_disks();
97 static int get_removed_slices_for_disks(
98 dlist_t *mod_disks);
99 static int get_modified_slices_for_disks(
100 dlist_t *moddisks);
101 static int compare_disk_to_moddisk_disk(
102 void *disk,
103 void *moddisk);
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
114 * !0 - otherwise
116 * PURPOSE: Public entry point to layout module.
119 get_layout(
120 request_t *request,
121 defaults_t *defaults)
123 devconfig_t *diskset_req = NULL;
124 dlist_t *iter = NULL;
125 dlist_t *results = NULL;
126 int error = 0;
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) {
132 return (error);
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));
148 if (error == 0) {
149 results = dlist_append(subres, results, AT_TAIL);
153 if (error == 0) {
154 /* process HSP request */
155 dlist_t *subres = NULL;
156 error = process_hsp_request(diskset_req, &subres);
157 if (error == 0) {
158 results = dlist_append(subres, results, AT_TAIL);
162 if (error == 0) {
163 oprintf(OUTPUT_TERSE,
164 gettext("\nAssembling volume specification...\n"));
165 /* determine required diskset modifications */
166 error = layout_diskset(request, results);
169 layout_clean_up();
171 if (error == 0) {
172 oprintf(OUTPUT_TERSE,
173 gettext("\nVolume request completed successfully.\n"));
176 } else {
177 volume_set_error(
178 gettext("Malformed request, missing top level "
179 "disk set request."));
182 return (error);
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
190 * process.
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
203 * process.
205 void
206 layout_clean_up()
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
235 * !0 - otherwise
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.
248 static int
249 layout_init(
250 devconfig_t *diskset,
251 defaults_t *defaults)
253 dlist_t *iter = NULL;
254 int error = 0;
255 char *dsname = 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));
273 if (error != 0) {
274 return (error);
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);
286 if (error == 0) {
287 error = discover_usable_devices(dsname);
290 if (error == 0) {
291 /* final validation on explicitly requested components */
292 error = validate_reserved_slices();
295 if (error == 0) {
296 /* final validation on request sizes vs. actual avail space */
297 error = validate_request_sizes(diskset);
300 return (error);
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
310 * !0 - otherwise
312 * PURPOSE: function which handles the details of an explicit
313 * volume request.
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
324 * those volumes.
326 static int
327 process_request(
328 devconfig_t *req,
329 dlist_t **results)
331 component_type_t type = TYPE_UNKNOWN;
332 uint64_t nbytes = 0; /* requested volume size */
333 dlist_t *comps = NULL;
334 int ncomps = 0;
335 int error = 0;
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);
346 return (0);
349 oprintf(OUTPUT_TERSE, "\n");
350 oprintf(OUTPUT_VERBOSE, "******************\n");
352 ncomps = dlist_length(comps);
354 if (type == TYPE_STRIPE) {
355 if (ncomps > 0) {
356 return (populate_explicit_stripe(req, results));
357 } else {
358 return (layout_stripe(req, nbytes, results));
362 if (type == TYPE_CONCAT) {
363 if (ncomps > 0) {
364 return (populate_explicit_concat(req, results));
365 } else {
366 return (layout_concat(req, nbytes, results));
370 if (type == TYPE_MIRROR) {
371 if (ncomps > 0) {
372 return (populate_explicit_mirror(req, results));
373 } else {
374 uint16_t nsubs = 0;
375 if ((error = get_mirror_nsubs(req, &nsubs)) != 0) {
376 return (error);
377 } else {
378 return (layout_mirror(req, nsubs, nbytes, results));
383 if (type == TYPE_VOLUME) {
384 error = process_qos_request(req, results);
387 return (error);
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
397 * !0 - otherwise
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.
404 static int
405 process_qos_request(
406 devconfig_t *req,
407 dlist_t **results)
409 int error = 0;
411 uint64_t nbytes = 0;
412 uint16_t rlevel = 0;
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) {
419 error = 0;
420 rlevel = 0;
424 if (error == 0) {
425 if (rlevel == 0) {
426 error = layout_stripe(req, nbytes, results);
427 } else {
428 error = layout_mirror(req, rlevel, nbytes, results);
432 return (error);
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
442 * !0 - otherwise
444 * PURPOSE: function which handles the details of completing an layout
445 * request.
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.
458 static int
459 layout_diskset(
460 request_t *request,
461 dlist_t *results)
463 int error = 0;
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));
470 if (error != 0) {
471 free_devconfig(diskset);
472 return (error);
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);
484 return (error);
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
494 * !0 - on any error
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.
503 static int
504 convert_device_names(
505 devconfig_t *request,
506 dlist_t *devices)
508 int error = 0;
509 dlist_t *iter;
511 for (iter = devices;
512 (iter != NULL) && (error == 0);
513 iter = iter->next) {
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;
521 uint16_t index;
523 if ((error = devconfig_get_type(dev, &type)) == 0) {
524 switch (type) {
526 case TYPE_MIRROR:
527 case TYPE_STRIPE:
528 case TYPE_CONCAT:
529 case TYPE_HSP:
531 error = convert_device_names(request,
532 devconfig_get_components(dev));
534 break;
536 case TYPE_SLICE:
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,
542 &diskname)) ||
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);
548 free(slicename);
551 break;
556 return (error);
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
567 * the layout code.
569 * RETURNS: int - 0 on success
570 * !0 otherwise
572 * PURPOSE: Adds the input disk to the list of those that have been
573 * modified.
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.
584 add_modified_disk(
585 devconfig_t *request,
586 dm_descriptor_t disk)
588 dlist_t *iter = NULL;
589 moddisk_t *moddisk = NULL;
590 dlist_t *item = NULL;
591 int error = 0;
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 */
599 return (0);
603 moddisk = (moddisk_t *)calloc(1, sizeof (moddisk_t));
604 if (moddisk == NULL) {
605 error = ENOMEM;
606 } else {
607 char *aname = NULL;
608 error = get_device_access_name(request, disk, &aname);
609 if (error == 0) {
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) {
617 free(moddisk);
618 error = ENOMEM;
619 } else {
620 _modified_disks =
621 dlist_append(item, _modified_disks, AT_HEAD);
626 return (error);
630 * FUNCTION: collect_modified_disks(devconfig_t *request, dlist_t* devs)
632 * INPUT: devs - pointer to a list of composed volumes
633 * OUTPUT: none -
634 * SIDEEFFECT: updates the module global list _modified_disks
636 * RETURNS: int - 0 - success
637 * !0 - failure
639 * PURPOSE: Helper to maintain the list of disks to be added to the
640 * disk set.
642 * Iterates the input list of devices and determines which
643 * disks they use. If a disk is not in the _modified_disks
644 * list, it is added.
646 static int
647 collect_modified_disks(
648 devconfig_t *request,
649 dlist_t *devs)
651 int error = 0;
653 char *sname = NULL;
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) {
663 switch (type) {
664 case TYPE_MIRROR:
665 case TYPE_STRIPE:
666 case TYPE_CONCAT:
667 case TYPE_HSP:
669 error = collect_modified_disks(request,
670 devconfig_get_components(dev));
671 break;
673 case TYPE_SLICE:
675 ((error = devconfig_get_name(dev, &sname)) != 0) ||
676 (error = get_disk_for_named_slice(sname, &disk)) ||
677 (error = add_modified_disk(request, disk));
679 break;
684 return (error);
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
695 * components.
697 * RETURNS: int - 0 - success
698 * !0 - failure
700 * PURPOSE: Helper to add devconfig_t structs for disks and slices
701 * to the disk set.
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.
712 static int
713 add_modified_disks_to_diskset(
714 dlist_t *results,
715 devconfig_t *diskset)
717 int error = 0;
719 dlist_t *iter;
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);
737 iter = iter->next) {
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));
751 if (error == 0) {
752 dlist_t *item = dlist_new_item(newdisk);
753 if (item == NULL) {
754 error = ENOMEM;
755 } else {
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);
761 } else {
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;
773 if (error == 0) {
774 devconfig_set_components(diskset, list);
775 } else {
776 dlist_free_items(list, NULL);
779 return (error);
783 * FUNCTIONS: void release_modified_disks()
785 * INPUT: none -
786 * OUTPUT: none -
788 * PURPOSE: cleanup the module global list of disks that need
789 * to be added to the disk set to satisfy the request.
791 static int
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;
802 free(moddisk);
803 iter->obj = NULL;
806 dlist_free_items(_modified_disks, NULL);
807 _modified_disks = NULL;
809 return (0);
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
821 * !0 - failure
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
830 * disks.
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.
836 static int
837 get_removed_slices_for_disks(
838 dlist_t *mod_disks)
840 int error = 0;
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);
846 iter = iter->next) {
848 rmvdslice_t *rmvd = (rmvdslice_t *)iter->obj;
849 dm_descriptor_t disk = (dm_descriptor_t)0;
850 moddisk_t *moddisk = NULL;
851 char *sname = 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 */
860 continue;
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 */
873 if (error == 0) {
874 if ((item = dlist_new_item(newslice)) == NULL) {
875 free_devconfig(newslice);
876 error = ENOMEM;
877 } else {
878 moddisk->slices =
879 dlist_append(item, moddisk->slices, AT_TAIL);
881 } else {
882 free_devconfig(newslice);
886 return (error);
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
898 * !0 - failure
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(
914 dlist_t *mod_disks)
916 int error = 0;
917 dlist_t *iter = NULL;
919 for (iter = get_modified_slices();
920 (iter != NULL) && (error == 0);
921 iter = iter->next) {
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;
927 moddisk_t *moddisk;
928 dlist_t *item;
929 char *sname = NULL;
930 uint64_t stblk = 0;
931 uint64_t nblks = 0;
932 uint16_t index;
934 /* only add modified slices that were sources */
935 if ((mods->times_modified == 0) ||
936 (mods->src_slice_desc != (dm_descriptor_t)0)) {
937 continue;
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 */
946 continue;
949 moddisk = (moddisk_t *)item->obj;
951 /* create output slice struct for the modified slice */
952 ((error = devconfig_get_slice_start_block(slice,
953 &stblk)) != 0) ||
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 */
964 if (error == 0) {
965 if ((item = dlist_new_item(newslice)) == NULL) {
966 free_devconfig(newslice);
967 error = ENOMEM;
968 } else {
969 moddisk->slices =
970 dlist_append(item, moddisk->slices, AT_TAIL);
972 } else {
973 free_devconfig(newslice);
977 return (error);
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
987 * !0 - otherwise
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
991 * moddisk_t struct.
993 * Comparison is done via compare_descriptor_names.
995 static int
996 compare_disk_to_moddisk_disk(
997 void *disk,
998 void *moddisk)
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()
1010 * INPUT: none -
1011 * OUTPUT: none -
1013 * PURPOSE: set the module global HSP request struct.
1015 static void
1016 set_hsp_request(
1017 devconfig_t *req)
1019 _hsp_request = req;
1023 * FUNCTIONS: void unset_hsp_request()
1025 * INPUT: none -
1026 * OUTPUT: none -
1028 * PURPOSE: unset the module global HSP request struct.
1030 static void
1031 unset_hsp_request()
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
1042 * !0 - failure
1044 * PURPOSE: Helper which determines HSP processing for the
1045 * composed volumes which need HSP spares.
1047 static int
1048 process_hsp_request(
1049 devconfig_t *req,
1050 dlist_t **results)
1052 int error = 0;
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"));
1063 } else {
1065 oprintf(OUTPUT_TERSE, "\n");
1067 ((error = layout_hsp(req, _hsp_request, _hsp_devices,
1068 results)) != 0) ||
1069 (error = collect_modified_disks(_hsp_request, *results)) ||
1070 (error = convert_device_names(_hsp_request, *results));
1073 return (error);
1077 * FUNCTION: add_to_hsp_list(dlist_t* list)
1078 * INPUT: devs - pointer to a list of composed volumes
1079 * OUTPUT: none -
1080 * SIDEEFFECT: updates the module global list _hsp_devices
1082 * RETURNS: int - 0 - success
1083 * !0 - failure
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.
1091 add_to_hsp_list(
1092 dlist_t *list)
1094 dlist_t *iter = NULL;
1095 int error = 0;
1097 for (iter = list; iter != NULL; iter = iter->next) {
1098 dlist_t *item = NULL;
1100 if ((item = dlist_new_item(iter->obj)) == NULL) {
1101 error = ENOMEM;
1102 break;
1104 _hsp_devices = dlist_append(item, _hsp_devices, AT_HEAD);
1107 return (error);
1111 * FUNCTION: string_case_compare(
1112 * char *str1, char *str2)
1114 * INPUT: str1 - char *
1115 * str2 - 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(
1130 char *str1,
1131 char *str2)
1133 int result = 0;
1135 assert(str1 != NULL);
1136 assert(str2 != NULL);
1138 if ((result = (strlen(str1) - strlen(str2))) == 0) {
1139 result = strcasecmp(str1, str2);
1142 return (result);