10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*62Sjeanm * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <assert.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include "volume_error.h"
340Sstevel@tonic-gate #include "volume_defaults.h"
350Sstevel@tonic-gate #include "volume_dlist.h"
360Sstevel@tonic-gate #include "volume_output.h"
370Sstevel@tonic-gate #include "volume_request.h"
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include "layout.h"
400Sstevel@tonic-gate #include "layout_request.h"
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include "layout_concat.h"
430Sstevel@tonic-gate #include "layout_discovery.h"
440Sstevel@tonic-gate #include "layout_device_cache.h"
450Sstevel@tonic-gate #include "layout_device_util.h"
460Sstevel@tonic-gate #include "layout_dlist_util.h"
470Sstevel@tonic-gate #include "layout_hsp.h"
480Sstevel@tonic-gate #include "layout_mirror.h"
490Sstevel@tonic-gate #include "layout_slice.h"
500Sstevel@tonic-gate #include "layout_stripe.h"
510Sstevel@tonic-gate #include "layout_svm_util.h"
520Sstevel@tonic-gate #include "layout_validate.h"
530Sstevel@tonic-gate
540Sstevel@tonic-gate #define _LAYOUT_C
550Sstevel@tonic-gate
560Sstevel@tonic-gate static int layout_init(devconfig_t *request, defaults_t *defaults);
570Sstevel@tonic-gate static int layout_diskset(request_t *request, dlist_t *results);
580Sstevel@tonic-gate
590Sstevel@tonic-gate static int process_request(devconfig_t *request, dlist_t **results);
600Sstevel@tonic-gate static int process_qos_request(devconfig_t *request, dlist_t **results);
610Sstevel@tonic-gate static int process_hsp_request(devconfig_t *request, dlist_t **results);
620Sstevel@tonic-gate
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate * stuff for making/updating the HSP to service devices
650Sstevel@tonic-gate * created by the toplevel request
660Sstevel@tonic-gate */
670Sstevel@tonic-gate static devconfig_t *_hsp_request = NULL;
680Sstevel@tonic-gate static dlist_t *_hsp_devices = NULL;
690Sstevel@tonic-gate static void set_hsp_request(devconfig_t *request);
700Sstevel@tonic-gate static void unset_hsp_request();
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * struct to track which disks have been explicitly modified
740Sstevel@tonic-gate * during the layout process...
750Sstevel@tonic-gate *
760Sstevel@tonic-gate * disk is the dm_descriptor_t of the modified disk
770Sstevel@tonic-gate * accessname is the name to access the disk thru
780Sstevel@tonic-gate * slices is the list of modified slices on the disk
790Sstevel@tonic-gate */
800Sstevel@tonic-gate typedef struct {
810Sstevel@tonic-gate dm_descriptor_t disk;
820Sstevel@tonic-gate char *accessname;
830Sstevel@tonic-gate dlist_t *slices;
840Sstevel@tonic-gate } moddisk_t;
850Sstevel@tonic-gate
860Sstevel@tonic-gate /*
870Sstevel@tonic-gate * modified_disks is a list of moddisk_t structs
880Sstevel@tonic-gate * tracking disks have been modified during layout.
890Sstevel@tonic-gate */
900Sstevel@tonic-gate static dlist_t *_modified_disks = NULL;
910Sstevel@tonic-gate
920Sstevel@tonic-gate static int collect_modified_disks(devconfig_t *request, dlist_t *results);
930Sstevel@tonic-gate static int add_modified_disks_to_diskset(
940Sstevel@tonic-gate dlist_t *devices,
950Sstevel@tonic-gate devconfig_t *diskset);
960Sstevel@tonic-gate static int release_modified_disks();
970Sstevel@tonic-gate static int get_removed_slices_for_disks(
980Sstevel@tonic-gate dlist_t *mod_disks);
990Sstevel@tonic-gate static int get_modified_slices_for_disks(
1000Sstevel@tonic-gate dlist_t *moddisks);
1010Sstevel@tonic-gate static int compare_disk_to_moddisk_disk(
1020Sstevel@tonic-gate void *disk,
1030Sstevel@tonic-gate void *moddisk);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate static int convert_device_names(devconfig_t *request, dlist_t *devs);
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate * FUNCTION: get_layout(devconfig_t *request, defaults_t *defaults)
1090Sstevel@tonic-gate *
1100Sstevel@tonic-gate * INPUT: request - a devconfig_t pointer to the toplevel request
1110Sstevel@tonic-gate * defaults - a results_t pointer to the defaults
1120Sstevel@tonic-gate *
1130Sstevel@tonic-gate * RETURNS: int - 0 - on success
1140Sstevel@tonic-gate * !0 - otherwise
1150Sstevel@tonic-gate *
1160Sstevel@tonic-gate * PURPOSE: Public entry point to layout module.
1170Sstevel@tonic-gate */
1180Sstevel@tonic-gate int
get_layout(request_t * request,defaults_t * defaults)1190Sstevel@tonic-gate get_layout(
1200Sstevel@tonic-gate request_t *request,
1210Sstevel@tonic-gate defaults_t *defaults)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate devconfig_t *diskset_req = NULL;
1240Sstevel@tonic-gate dlist_t *iter = NULL;
1250Sstevel@tonic-gate dlist_t *results = NULL;
1260Sstevel@tonic-gate int error = 0;
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate if ((diskset_req = request_get_diskset_req(request)) != NULL) {
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate /* initialize using the the top-level disk set request... */
1310Sstevel@tonic-gate if ((error = layout_init(diskset_req, defaults)) != 0) {
1320Sstevel@tonic-gate return (error);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
1360Sstevel@tonic-gate gettext("\nProcessing volume request...\n"));
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate iter = devconfig_get_components(diskset_req);
1390Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) {
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /* process each volume request, stop on any error */
1420Sstevel@tonic-gate devconfig_t *subreq = (devconfig_t *)iter->obj;
1430Sstevel@tonic-gate dlist_t *subres = NULL;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate ((error = process_request(subreq, &subres)) != 0) ||
1460Sstevel@tonic-gate (error = collect_modified_disks(subreq, subres)) ||
1470Sstevel@tonic-gate (error = convert_device_names(subreq, subres));
1480Sstevel@tonic-gate if (error == 0) {
1490Sstevel@tonic-gate results = dlist_append(subres, results, AT_TAIL);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate if (error == 0) {
1540Sstevel@tonic-gate /* process HSP request */
1550Sstevel@tonic-gate dlist_t *subres = NULL;
1560Sstevel@tonic-gate error = process_hsp_request(diskset_req, &subres);
1570Sstevel@tonic-gate if (error == 0) {
1580Sstevel@tonic-gate results = dlist_append(subres, results, AT_TAIL);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate if (error == 0) {
1630Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
1640Sstevel@tonic-gate gettext("\nAssembling volume specification...\n"));
1650Sstevel@tonic-gate /* determine required diskset modifications */
1660Sstevel@tonic-gate error = layout_diskset(request, results);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate layout_clean_up();
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate if (error == 0) {
1720Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
1730Sstevel@tonic-gate gettext("\nVolume request completed successfully.\n"));
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate } else {
1770Sstevel@tonic-gate volume_set_error(
1780Sstevel@tonic-gate gettext("Malformed request, missing top level "
1790Sstevel@tonic-gate "disk set request."));
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate return (error);
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate * FUNCTION: layout_clean_up()
1870Sstevel@tonic-gate *
1880Sstevel@tonic-gate * PURPOSE: function which handles the details of cleaning up cached
1890Sstevel@tonic-gate * data and any other memory allocated during the layout
1900Sstevel@tonic-gate * process.
1910Sstevel@tonic-gate *
1920Sstevel@tonic-gate * release physical device data structs
1930Sstevel@tonic-gate * release SVM logical device data structs
1940Sstevel@tonic-gate * release validation data structs
1950Sstevel@tonic-gate * release modified device data structs
1960Sstevel@tonic-gate * release request processing data structs
1970Sstevel@tonic-gate *
1980Sstevel@tonic-gate * This function is also exported as part of the public
1990Sstevel@tonic-gate * interface to the layout module, clients of layout
2000Sstevel@tonic-gate * are required to call this function if get_layout()
2010Sstevel@tonic-gate * was called and was not allowed to return. For example,
2020Sstevel@tonic-gate * if SIGINT was received while a layout request was in
2030Sstevel@tonic-gate * process.
2040Sstevel@tonic-gate */
2050Sstevel@tonic-gate void
layout_clean_up()2060Sstevel@tonic-gate layout_clean_up()
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate (void) release_request_caches();
2090Sstevel@tonic-gate (void) release_validation_caches();
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate (void) release_slices_to_remove();
2120Sstevel@tonic-gate (void) release_modified_slices();
2130Sstevel@tonic-gate (void) release_modified_disks();
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate (void) release_reserved_slices();
2160Sstevel@tonic-gate (void) release_used_slices();
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate (void) release_usable_devices();
2190Sstevel@tonic-gate (void) release_svm_names(get_request_diskset());
2200Sstevel@tonic-gate (void) release_known_devices();
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate (void) unset_hsp_request(NULL);
2230Sstevel@tonic-gate (void) unset_request_defaults(NULL);
2240Sstevel@tonic-gate (void) unset_request_diskset(NULL);
2250Sstevel@tonic-gate (void) unset_toplevel_request(NULL);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * FUNCTION: layout_init(devconfig_t *diskset, defaults_t *defaults)
2300Sstevel@tonic-gate *
2310Sstevel@tonic-gate * INPUT: diskset - a devconfig_t pointer to the toplevel request
2320Sstevel@tonic-gate * defaults - a results_t pointer to the defaults
2330Sstevel@tonic-gate *
2340Sstevel@tonic-gate * RETURNS: int - 0 - on success
2350Sstevel@tonic-gate * !0 - otherwise
2360Sstevel@tonic-gate *
2370Sstevel@tonic-gate * PURPOSE: function which handles the details of initializing the layout
2380Sstevel@tonic-gate * module prior to processing a request.
2390Sstevel@tonic-gate *
2400Sstevel@tonic-gate * Determines the requested disk set and validates it.
2410Sstevel@tonic-gate *
2420Sstevel@tonic-gate * Scans the physical device configuration.
2430Sstevel@tonic-gate * Scans the SVM logical device configuration.
2440Sstevel@tonic-gate *
2450Sstevel@tonic-gate * Initializes layout private global data structures and does
2460Sstevel@tonic-gate * semantic validation of the request.
2470Sstevel@tonic-gate */
2480Sstevel@tonic-gate static int
layout_init(devconfig_t * diskset,defaults_t * defaults)2490Sstevel@tonic-gate layout_init(
2500Sstevel@tonic-gate devconfig_t *diskset,
2510Sstevel@tonic-gate defaults_t *defaults)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate dlist_t *iter = NULL;
2540Sstevel@tonic-gate int error = 0;
2550Sstevel@tonic-gate char *dsname = NULL;
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate ((error = validate_basic_svm_config()) != 0) ||
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate /* determine & validate requested disk set name */
2600Sstevel@tonic-gate (error = devconfig_get_name(diskset, &dsname)) ||
2610Sstevel@tonic-gate (error = set_request_diskset(dsname)) ||
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /* discover known physical and logical devices */
2640Sstevel@tonic-gate (error = discover_known_devices()) ||
2650Sstevel@tonic-gate (error = scan_svm_names(dsname)) ||
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /* validate and remember toplevel request */
2680Sstevel@tonic-gate (error = set_toplevel_request(diskset)) ||
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /* validate and remember defaults for this request */
2710Sstevel@tonic-gate (error = set_request_defaults(defaults));
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate if (error != 0) {
2740Sstevel@tonic-gate return (error);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
2780Sstevel@tonic-gate gettext("\nValidating volume request...\n"));
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate iter = devconfig_get_components(diskset);
2810Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) {
2820Sstevel@tonic-gate devconfig_t *subreq = (devconfig_t *)iter->obj;
2830Sstevel@tonic-gate error = validate_request(subreq);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate if (error == 0) {
2870Sstevel@tonic-gate error = discover_usable_devices(dsname);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate if (error == 0) {
2910Sstevel@tonic-gate /* final validation on explicitly requested components */
2920Sstevel@tonic-gate error = validate_reserved_slices();
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate if (error == 0) {
2960Sstevel@tonic-gate /* final validation on request sizes vs. actual avail space */
2970Sstevel@tonic-gate error = validate_request_sizes(diskset);
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate return (error);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /*
3040Sstevel@tonic-gate * FUNCTION: process_request(devconfig_t *req, dlist_t **results)
3050Sstevel@tonic-gate *
3060Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request
3070Sstevel@tonic-gate * results - pointer to a list of resulting volumes
3080Sstevel@tonic-gate *
3090Sstevel@tonic-gate * RETURNS: int - 0 - on success
3100Sstevel@tonic-gate * !0 - otherwise
3110Sstevel@tonic-gate *
3120Sstevel@tonic-gate * PURPOSE: function which handles the details of an explicit
3130Sstevel@tonic-gate * volume request.
3140Sstevel@tonic-gate *
3150Sstevel@tonic-gate * Determines the requested volume type, whether the
3160Sstevel@tonic-gate * request contains specific subcomponents and dispatches
3170Sstevel@tonic-gate * to the appropriate layout function for that type.
3180Sstevel@tonic-gate *
3190Sstevel@tonic-gate * Resulting volumes are appended to the results list.
3200Sstevel@tonic-gate *
3210Sstevel@tonic-gate * Note that an HSP request is held until all the volumes
3220Sstevel@tonic-gate * in the request have been successfully composed. This
3230Sstevel@tonic-gate * ensures that HSP spare sizing can be appropriate to
3240Sstevel@tonic-gate * those volumes.
3250Sstevel@tonic-gate */
3260Sstevel@tonic-gate static int
process_request(devconfig_t * req,dlist_t ** results)3270Sstevel@tonic-gate process_request(
3280Sstevel@tonic-gate devconfig_t *req,
3290Sstevel@tonic-gate dlist_t **results)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN;
3320Sstevel@tonic-gate uint64_t nbytes = 0; /* requested volume size */
3330Sstevel@tonic-gate dlist_t *comps = NULL;
3340Sstevel@tonic-gate int ncomps = 0;
3350Sstevel@tonic-gate int error = 0;
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate (void) devconfig_get_type(req, &type);
3380Sstevel@tonic-gate (void) devconfig_get_size(req, &nbytes);
3390Sstevel@tonic-gate comps = devconfig_get_components(req);
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (type == TYPE_HSP) {
3420Sstevel@tonic-gate /* HSP processing needs to happen after all other volumes. */
3430Sstevel@tonic-gate /* set the HSP request aside until all other requests have */
3440Sstevel@tonic-gate /* been completed successfully */
3450Sstevel@tonic-gate set_hsp_request(req);
3460Sstevel@tonic-gate return (0);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate oprintf(OUTPUT_TERSE, "\n");
3500Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, "******************\n");
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate ncomps = dlist_length(comps);
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate if (type == TYPE_STRIPE) {
3550Sstevel@tonic-gate if (ncomps > 0) {
3560Sstevel@tonic-gate return (populate_explicit_stripe(req, results));
3570Sstevel@tonic-gate } else {
3580Sstevel@tonic-gate return (layout_stripe(req, nbytes, results));
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate if (type == TYPE_CONCAT) {
3630Sstevel@tonic-gate if (ncomps > 0) {
3640Sstevel@tonic-gate return (populate_explicit_concat(req, results));
3650Sstevel@tonic-gate } else {
3660Sstevel@tonic-gate return (layout_concat(req, nbytes, results));
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate if (type == TYPE_MIRROR) {
3710Sstevel@tonic-gate if (ncomps > 0) {
3720Sstevel@tonic-gate return (populate_explicit_mirror(req, results));
3730Sstevel@tonic-gate } else {
3740Sstevel@tonic-gate uint16_t nsubs = 0;
3750Sstevel@tonic-gate if ((error = get_mirror_nsubs(req, &nsubs)) != 0) {
3760Sstevel@tonic-gate return (error);
3770Sstevel@tonic-gate } else {
3780Sstevel@tonic-gate return (layout_mirror(req, nsubs, nbytes, results));
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate if (type == TYPE_VOLUME) {
3840Sstevel@tonic-gate error = process_qos_request(req, results);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate return (error);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /*
3910Sstevel@tonic-gate * FUNCTION: process_qos_request(devconfig_t *req, dlist_t **results)
3920Sstevel@tonic-gate *
3930Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request
3940Sstevel@tonic-gate * results - pointer to a list of resulting volumes
3950Sstevel@tonic-gate *
3960Sstevel@tonic-gate * RETURNS: int - 0 - on success
3970Sstevel@tonic-gate * !0 - otherwise
3980Sstevel@tonic-gate *
3990Sstevel@tonic-gate * PURPOSE: function which handles the details of mapping an implicit
4000Sstevel@tonic-gate * volume request of QoS attributes into a volume type.
4010Sstevel@tonic-gate *
4020Sstevel@tonic-gate * Resulting volumes are appended to the results list.
4030Sstevel@tonic-gate */
4040Sstevel@tonic-gate static int
process_qos_request(devconfig_t * req,dlist_t ** results)4050Sstevel@tonic-gate process_qos_request(
4060Sstevel@tonic-gate devconfig_t *req,
4070Sstevel@tonic-gate dlist_t **results)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate int error = 0;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate uint64_t nbytes = 0;
4120Sstevel@tonic-gate uint16_t rlevel = 0;
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate /* get QoS attributes */
4150Sstevel@tonic-gate (void) devconfig_get_size(req, &nbytes);
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate if ((error = get_volume_redundancy_level(req, &rlevel)) != 0) {
4180Sstevel@tonic-gate if (error == ERR_ATTR_UNSET) {
4190Sstevel@tonic-gate error = 0;
4200Sstevel@tonic-gate rlevel = 0;
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate if (error == 0) {
4250Sstevel@tonic-gate if (rlevel == 0) {
4260Sstevel@tonic-gate error = layout_stripe(req, nbytes, results);
4270Sstevel@tonic-gate } else {
4280Sstevel@tonic-gate error = layout_mirror(req, rlevel, nbytes, results);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate return (error);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate * FUNCTION: layout_diskset(request_t *req, dlist_t **results)
4370Sstevel@tonic-gate *
4380Sstevel@tonic-gate * INPUT: req - a request_t pointer to the toplevel request
4390Sstevel@tonic-gate * results - pointer to the list of composed result volumes
4400Sstevel@tonic-gate *
4410Sstevel@tonic-gate * RETURNS: int - 0 - on success
4420Sstevel@tonic-gate * !0 - otherwise
4430Sstevel@tonic-gate *
4440Sstevel@tonic-gate * PURPOSE: function which handles the details of completing an layout
4450Sstevel@tonic-gate * request.
4460Sstevel@tonic-gate *
4470Sstevel@tonic-gate * Determines if the disk set specified in the request currently
4480Sstevel@tonic-gate * exists and sets it up for creation if it doesn't.
4490Sstevel@tonic-gate *
4500Sstevel@tonic-gate * Adds new disks required by the result volumes to the disk set.
4510Sstevel@tonic-gate *
4520Sstevel@tonic-gate * Attaches the result volumes to the disk set result.
4530Sstevel@tonic-gate *
4540Sstevel@tonic-gate * Convert slice and disk names to preferred names.
4550Sstevel@tonic-gate *
4560Sstevel@tonic-gate * Attaches the disk set result to the toplevel request.
4570Sstevel@tonic-gate */
4580Sstevel@tonic-gate static int
layout_diskset(request_t * request,dlist_t * results)4590Sstevel@tonic-gate layout_diskset(
4600Sstevel@tonic-gate request_t *request,
4610Sstevel@tonic-gate dlist_t *results)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate int error = 0;
4640Sstevel@tonic-gate devconfig_t *diskset = NULL;
4650Sstevel@tonic-gate dlist_t *comps = NULL;
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate ((error = new_devconfig(&diskset, TYPE_DISKSET)) != 0) ||
4680Sstevel@tonic-gate (error = devconfig_set_name(diskset, get_request_diskset())) ||
4690Sstevel@tonic-gate (error = add_modified_disks_to_diskset(results, diskset));
4700Sstevel@tonic-gate if (error != 0) {
4710Sstevel@tonic-gate free_devconfig(diskset);
4720Sstevel@tonic-gate return (error);
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate /* add resulting volumes */
4760Sstevel@tonic-gate if (results != NULL) {
4770Sstevel@tonic-gate comps = devconfig_get_components(diskset);
4780Sstevel@tonic-gate comps = dlist_append(results, comps, AT_TAIL);
4790Sstevel@tonic-gate devconfig_set_components(diskset, comps);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate request_set_diskset_config(request, diskset);
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate return (error);
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate /*
4880Sstevel@tonic-gate * FUNCTION: convert_device_names(devconfig_t request, dlist_t *devices)
4890Sstevel@tonic-gate *
4900Sstevel@tonic-gate * INPUT: request - a devconfig_t request pointer
4910Sstevel@tonic-gate * devices - a list of devconfig_t devices
4920Sstevel@tonic-gate *
4930Sstevel@tonic-gate * RETURNS: int - 0 - on success
4940Sstevel@tonic-gate * !0 - on any error
4950Sstevel@tonic-gate *
4960Sstevel@tonic-gate * PURPOSE: Utility function to convert any slice or disk drive
4970Sstevel@tonic-gate * names in a result devconfig_t to the preferred name
4980Sstevel@tonic-gate * which should be used to access the device.
4990Sstevel@tonic-gate *
5000Sstevel@tonic-gate * This convert the temporary names used by layout to
5010Sstevel@tonic-gate * the proper DID or /dev/dsk alias.
5020Sstevel@tonic-gate */
5030Sstevel@tonic-gate static int
convert_device_names(devconfig_t * request,dlist_t * devices)5040Sstevel@tonic-gate convert_device_names(
5050Sstevel@tonic-gate devconfig_t *request,
5060Sstevel@tonic-gate dlist_t *devices)
5070Sstevel@tonic-gate {
5080Sstevel@tonic-gate int error = 0;
5090Sstevel@tonic-gate dlist_t *iter;
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate for (iter = devices;
5120Sstevel@tonic-gate (iter != NULL) && (error == 0);
5130Sstevel@tonic-gate iter = iter->next) {
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate devconfig_t *dev = (devconfig_t *)iter->obj;
5160Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN;
5170Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0;
5180Sstevel@tonic-gate char *devname = NULL;
5190Sstevel@tonic-gate char *diskname = NULL;
5200Sstevel@tonic-gate char *slicename = NULL;
5210Sstevel@tonic-gate uint16_t index;
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate if ((error = devconfig_get_type(dev, &type)) == 0) {
5240Sstevel@tonic-gate switch (type) {
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate case TYPE_MIRROR:
5270Sstevel@tonic-gate case TYPE_STRIPE:
5280Sstevel@tonic-gate case TYPE_CONCAT:
5290Sstevel@tonic-gate case TYPE_HSP:
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate error = convert_device_names(request,
5320Sstevel@tonic-gate devconfig_get_components(dev));
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate break;
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate case TYPE_SLICE:
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate ((error = devconfig_get_name(dev, &devname)) != 0) ||
5390Sstevel@tonic-gate (error = devconfig_get_slice_index(dev, &index)) ||
5400Sstevel@tonic-gate (error = get_disk_for_named_slice(devname, &disk)) ||
5410Sstevel@tonic-gate (error = get_device_access_name(request, disk,
5420Sstevel@tonic-gate &diskname)) ||
5430Sstevel@tonic-gate (error = make_slicename_for_diskname_and_index(
5440Sstevel@tonic-gate diskname, index, &slicename));
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate if ((error == 0) && (slicename != NULL)) {
5470Sstevel@tonic-gate error = devconfig_set_name(dev, slicename);
5480Sstevel@tonic-gate free(slicename);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate break;
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate return (error);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate /*
5600Sstevel@tonic-gate * FUNCTION: add_modified_disk(devconfig_t request, dm_descriptor_t disk);
5610Sstevel@tonic-gate *
5620Sstevel@tonic-gate * INPUT: request - a pointr to a devconfig_t request
5630Sstevel@tonic-gate * disk - dm_descriptor_t handle for a disk that has been modified
5640Sstevel@tonic-gate *
5650Sstevel@tonic-gate * SIDEEFFECTS: adds an entry to the _modified_disks list which tracks
5660Sstevel@tonic-gate * the disks that have been explicitly modified by
5670Sstevel@tonic-gate * the layout code.
5680Sstevel@tonic-gate *
5690Sstevel@tonic-gate * RETURNS: int - 0 on success
5700Sstevel@tonic-gate * !0 otherwise
5710Sstevel@tonic-gate *
5720Sstevel@tonic-gate * PURPOSE: Adds the input disk to the list of those that have been
5730Sstevel@tonic-gate * modified.
5740Sstevel@tonic-gate *
5750Sstevel@tonic-gate * Disks are modified during layout for two reasons:
5760Sstevel@tonic-gate *
5770Sstevel@tonic-gate * 1. any disk that is to be added to the disk set gets
5780Sstevel@tonic-gate * an explicitly updated label.
5790Sstevel@tonic-gate *
5800Sstevel@tonic-gate * 2. once a disk is in the disk set, existing slices
5810Sstevel@tonic-gate * may be resized or new slices can be added.
5820Sstevel@tonic-gate */
5830Sstevel@tonic-gate int
add_modified_disk(devconfig_t * request,dm_descriptor_t disk)5840Sstevel@tonic-gate add_modified_disk(
5850Sstevel@tonic-gate devconfig_t *request,
5860Sstevel@tonic-gate dm_descriptor_t disk)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate dlist_t *iter = NULL;
5890Sstevel@tonic-gate moddisk_t *moddisk = NULL;
5900Sstevel@tonic-gate dlist_t *item = NULL;
5910Sstevel@tonic-gate int error = 0;
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate for (iter = _modified_disks; iter != NULL; iter = iter->next) {
5940Sstevel@tonic-gate moddisk = (moddisk_t *)iter->obj;
5950Sstevel@tonic-gate if (compare_descriptor_names(
596*62Sjeanm (void *)(uintptr_t)moddisk->disk,
597*62Sjeanm (void *)(uintptr_t)disk) == 0) {
5980Sstevel@tonic-gate /* already in list */
5990Sstevel@tonic-gate return (0);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate moddisk = (moddisk_t *)calloc(1, sizeof (moddisk_t));
6040Sstevel@tonic-gate if (moddisk == NULL) {
6050Sstevel@tonic-gate error = ENOMEM;
6060Sstevel@tonic-gate } else {
6070Sstevel@tonic-gate char *aname = NULL;
6080Sstevel@tonic-gate error = get_device_access_name(request, disk, &aname);
6090Sstevel@tonic-gate if (error == 0) {
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate /* add to list of modified disks */
6120Sstevel@tonic-gate moddisk->disk = disk;
6130Sstevel@tonic-gate moddisk->accessname = aname;
6140Sstevel@tonic-gate moddisk->slices = NULL;
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate if ((item = dlist_new_item((void *)moddisk)) == NULL) {
6170Sstevel@tonic-gate free(moddisk);
6180Sstevel@tonic-gate error = ENOMEM;
6190Sstevel@tonic-gate } else {
6200Sstevel@tonic-gate _modified_disks =
6210Sstevel@tonic-gate dlist_append(item, _modified_disks, AT_HEAD);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate return (error);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * FUNCTION: collect_modified_disks(devconfig_t *request, dlist_t* devs)
6310Sstevel@tonic-gate *
6320Sstevel@tonic-gate * INPUT: devs - pointer to a list of composed volumes
6330Sstevel@tonic-gate * OUTPUT: none -
6340Sstevel@tonic-gate * SIDEEFFECT: updates the module global list _modified_disks
6350Sstevel@tonic-gate *
6360Sstevel@tonic-gate * RETURNS: int - 0 - success
6370Sstevel@tonic-gate * !0 - failure
6380Sstevel@tonic-gate *
6390Sstevel@tonic-gate * PURPOSE: Helper to maintain the list of disks to be added to the
6400Sstevel@tonic-gate * disk set.
6410Sstevel@tonic-gate *
6420Sstevel@tonic-gate * Iterates the input list of devices and determines which
6430Sstevel@tonic-gate * disks they use. If a disk is not in the _modified_disks
6440Sstevel@tonic-gate * list, it is added.
6450Sstevel@tonic-gate */
6460Sstevel@tonic-gate static int
collect_modified_disks(devconfig_t * request,dlist_t * devs)6470Sstevel@tonic-gate collect_modified_disks(
6480Sstevel@tonic-gate devconfig_t *request,
6490Sstevel@tonic-gate dlist_t *devs)
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate int error = 0;
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate char *sname = NULL;
6540Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0;
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate for (; (devs != NULL) && (error == 0); devs = devs->next) {
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate devconfig_t *dev = (devconfig_t *)devs->obj;
6590Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN;
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate if ((error = devconfig_get_type(dev, &type)) == 0) {
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate switch (type) {
6640Sstevel@tonic-gate case TYPE_MIRROR:
6650Sstevel@tonic-gate case TYPE_STRIPE:
6660Sstevel@tonic-gate case TYPE_CONCAT:
6670Sstevel@tonic-gate case TYPE_HSP:
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate error = collect_modified_disks(request,
6700Sstevel@tonic-gate devconfig_get_components(dev));
6710Sstevel@tonic-gate break;
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate case TYPE_SLICE:
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate ((error = devconfig_get_name(dev, &sname)) != 0) ||
6760Sstevel@tonic-gate (error = get_disk_for_named_slice(sname, &disk)) ||
6770Sstevel@tonic-gate (error = add_modified_disk(request, disk));
6780Sstevel@tonic-gate
6790Sstevel@tonic-gate break;
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate return (error);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate * FUNCTION: add_modified_disks_to_diskset(dlist_t *devices,
6890Sstevel@tonic-gate * devconfig_t *diskset)
6900Sstevel@tonic-gate *
6910Sstevel@tonic-gate * INPUT: devices - pointer to a list of devices
6920Sstevel@tonic-gate *
6930Sstevel@tonic-gate * OUTPUT: diskset - pointer to a devconfig_t representing the disk set,
6940Sstevel@tonic-gate * updated to include modified disks and slices as
6950Sstevel@tonic-gate * components.
6960Sstevel@tonic-gate *
6970Sstevel@tonic-gate * RETURNS: int - 0 - success
6980Sstevel@tonic-gate * !0 - failure
6990Sstevel@tonic-gate *
7000Sstevel@tonic-gate * PURPOSE: Helper to add devconfig_t structs for disks and slices
7010Sstevel@tonic-gate * to the disk set.
7020Sstevel@tonic-gate *
7030Sstevel@tonic-gate * Updates the list of _modified_disks by examining the input
7040Sstevel@tonic-gate * list of composed devices.
7050Sstevel@tonic-gate *
7060Sstevel@tonic-gate * Iterates _modified_disks and creates a devconfig_t component
7070Sstevel@tonic-gate * for each disk in the list, the list of disks is then attached
7080Sstevel@tonic-gate * to the input disk set.
7090Sstevel@tonic-gate *
7100Sstevel@tonic-gate * Modified slices for disks in the disk set are added as well.
7110Sstevel@tonic-gate */
7120Sstevel@tonic-gate static int
add_modified_disks_to_diskset(dlist_t * results,devconfig_t * diskset)7130Sstevel@tonic-gate add_modified_disks_to_diskset(
7140Sstevel@tonic-gate dlist_t *results,
7150Sstevel@tonic-gate devconfig_t *diskset)
7160Sstevel@tonic-gate {
7170Sstevel@tonic-gate int error = 0;
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate dlist_t *iter;
7200Sstevel@tonic-gate dlist_t *list = NULL;
7210Sstevel@tonic-gate char *dsname = get_request_diskset();
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate /* add modified disks to disk set's component list */
7240Sstevel@tonic-gate list = devconfig_get_components(diskset);
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
7270Sstevel@tonic-gate gettext(" Collecting modified disks...\n"));
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate /* collect removed slices for modified disks */
7300Sstevel@tonic-gate error = get_removed_slices_for_disks(_modified_disks);
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate /* collect modified slices for modified disks */
7330Sstevel@tonic-gate error = get_modified_slices_for_disks(_modified_disks);
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate for (iter = _modified_disks;
7360Sstevel@tonic-gate (iter != NULL) && (error == 0);
7370Sstevel@tonic-gate iter = iter->next) {
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate moddisk_t *moddisk = (moddisk_t *)iter->obj;
7400Sstevel@tonic-gate dm_descriptor_t disk = moddisk->disk;
7410Sstevel@tonic-gate devconfig_t *newdisk = NULL;
7420Sstevel@tonic-gate boolean_t in_set = B_FALSE;
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, " %s\n", moddisk->accessname);
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate error = is_disk_in_diskset(disk, dsname, &in_set);
7470Sstevel@tonic-gate if ((error == 0) && (in_set != B_TRUE)) {
7480Sstevel@tonic-gate /* New disk, add it to the disk set */
7490Sstevel@tonic-gate ((error = new_devconfig(&newdisk, TYPE_DRIVE)) != 0) ||
7500Sstevel@tonic-gate (error = devconfig_set_name(newdisk, moddisk->accessname));
7510Sstevel@tonic-gate if (error == 0) {
7520Sstevel@tonic-gate dlist_t *item = dlist_new_item(newdisk);
7530Sstevel@tonic-gate if (item == NULL) {
7540Sstevel@tonic-gate error = ENOMEM;
7550Sstevel@tonic-gate } else {
7560Sstevel@tonic-gate list = dlist_append(item, list, AT_TAIL);
7570Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
7580Sstevel@tonic-gate gettext(" must add %s to disk set \"%s\"\n"),
7590Sstevel@tonic-gate moddisk->accessname, dsname);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate } else {
7620Sstevel@tonic-gate free_devconfig(newdisk);
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate if ((error == 0) && (moddisk->slices != NULL)) {
7670Sstevel@tonic-gate /* move moddisk's slice list to disk set comp list */
7680Sstevel@tonic-gate list = dlist_append(moddisk->slices, list, AT_TAIL);
7690Sstevel@tonic-gate moddisk->slices = NULL;
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate if (error == 0) {
7740Sstevel@tonic-gate devconfig_set_components(diskset, list);
7750Sstevel@tonic-gate } else {
7760Sstevel@tonic-gate dlist_free_items(list, NULL);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate return (error);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate /*
7830Sstevel@tonic-gate * FUNCTIONS: void release_modified_disks()
7840Sstevel@tonic-gate *
7850Sstevel@tonic-gate * INPUT: none -
7860Sstevel@tonic-gate * OUTPUT: none -
7870Sstevel@tonic-gate *
7880Sstevel@tonic-gate * PURPOSE: cleanup the module global list of disks that need
7890Sstevel@tonic-gate * to be added to the disk set to satisfy the request.
7900Sstevel@tonic-gate */
7910Sstevel@tonic-gate static int
release_modified_disks()7920Sstevel@tonic-gate release_modified_disks()
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate dlist_t *iter = _modified_disks;
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate for (; iter != NULL; iter = iter->next) {
7970Sstevel@tonic-gate moddisk_t *moddisk = (moddisk_t *)iter->obj;
7980Sstevel@tonic-gate if (moddisk->slices != NULL) {
7990Sstevel@tonic-gate dlist_free_items(moddisk->slices, free_devconfig);
8000Sstevel@tonic-gate moddisk->slices = NULL;
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate free(moddisk);
8030Sstevel@tonic-gate iter->obj = NULL;
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate dlist_free_items(_modified_disks, NULL);
8070Sstevel@tonic-gate _modified_disks = NULL;
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate return (0);
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate
8120Sstevel@tonic-gate /*
8130Sstevel@tonic-gate * FUNCTION: get_removed_slices_for_disks(dlist_t *mod_disks)
8140Sstevel@tonic-gate *
8150Sstevel@tonic-gate * INPUT: mod_disks - a list of moddisk_t structs
8160Sstevel@tonic-gate *
8170Sstevel@tonic-gate * OUTPUT: mod_disks - the list of moddisk_t structs updated with
8180Sstevel@tonic-gate * the slices to be removed for each disk
8190Sstevel@tonic-gate *
8200Sstevel@tonic-gate * RETURNS: int - 0 - success
8210Sstevel@tonic-gate * !0 - failure
8220Sstevel@tonic-gate *
8230Sstevel@tonic-gate * PURPOSE: Helper to create a list of devconfig_t structs
8240Sstevel@tonic-gate * for slices on the input disks which need to be
8250Sstevel@tonic-gate * removed from the system.
8260Sstevel@tonic-gate *
8270Sstevel@tonic-gate * Iterates the list of slices to be removed and
8280Sstevel@tonic-gate * creates a devconfig_t component for each slice
8290Sstevel@tonic-gate * in the list that is on any of the input modified
8300Sstevel@tonic-gate * disks.
8310Sstevel@tonic-gate *
8320Sstevel@tonic-gate * Slice names are constructed using the modified disk's
8330Sstevel@tonic-gate * access name to ensure that the correct alias is
8340Sstevel@tonic-gate * used to get to the slice.
8350Sstevel@tonic-gate */
8360Sstevel@tonic-gate static int
get_removed_slices_for_disks(dlist_t * mod_disks)8370Sstevel@tonic-gate get_removed_slices_for_disks(
8380Sstevel@tonic-gate dlist_t *mod_disks)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate int error = 0;
8410Sstevel@tonic-gate dlist_t *iter = NULL;
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate /* collect slices to be removed for the modified disks */
8440Sstevel@tonic-gate for (iter = get_slices_to_remove();
8450Sstevel@tonic-gate (iter != NULL) && (error == 0);
8460Sstevel@tonic-gate iter = iter->next) {
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate rmvdslice_t *rmvd = (rmvdslice_t *)iter->obj;
8490Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0;
8500Sstevel@tonic-gate moddisk_t *moddisk = NULL;
8510Sstevel@tonic-gate char *sname = NULL;
8520Sstevel@tonic-gate devconfig_t *newslice = NULL;
8530Sstevel@tonic-gate dlist_t *item = NULL;
8540Sstevel@tonic-gate
8550Sstevel@tonic-gate (void) get_disk_for_named_slice(rmvd->slice_name, &disk);
8560Sstevel@tonic-gate
857*62Sjeanm if ((item = dlist_find(mod_disks, (void *)(uintptr_t)disk,
8580Sstevel@tonic-gate compare_disk_to_moddisk_disk)) == NULL) {
8590Sstevel@tonic-gate /* slice on disk that we don't care about */
8600Sstevel@tonic-gate continue;
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate moddisk = (moddisk_t *)item->obj;
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate /* create output slice struct for the removed slice */
8660Sstevel@tonic-gate ((error = make_slicename_for_diskname_and_index(
8670Sstevel@tonic-gate moddisk->accessname, rmvd->slice_index, &sname)) != 0) ||
8680Sstevel@tonic-gate (error = new_devconfig(&newslice, TYPE_SLICE)) ||
8690Sstevel@tonic-gate (error = devconfig_set_name(newslice, sname)) ||
8700Sstevel@tonic-gate (error = devconfig_set_size_in_blocks(newslice, 0));
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate /* add to the moddisk's list of slices */
8730Sstevel@tonic-gate if (error == 0) {
8740Sstevel@tonic-gate if ((item = dlist_new_item(newslice)) == NULL) {
8750Sstevel@tonic-gate free_devconfig(newslice);
8760Sstevel@tonic-gate error = ENOMEM;
8770Sstevel@tonic-gate } else {
8780Sstevel@tonic-gate moddisk->slices =
8790Sstevel@tonic-gate dlist_append(item, moddisk->slices, AT_TAIL);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate } else {
8820Sstevel@tonic-gate free_devconfig(newslice);
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate }
8850Sstevel@tonic-gate
8860Sstevel@tonic-gate return (error);
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate /*
8900Sstevel@tonic-gate * FUNCTION: get_modified_slices_for_disks(dlist_t *mod_disks)
8910Sstevel@tonic-gate *
8920Sstevel@tonic-gate * INPUT: mod_disks - a list of moddisk_t structs
8930Sstevel@tonic-gate *
8940Sstevel@tonic-gate * OUTPUT: mod_disks - the list of moddisk_t structs updated with
8950Sstevel@tonic-gate * the modified slices for each disk
8960Sstevel@tonic-gate *
8970Sstevel@tonic-gate * RETURNS: int - 0 - success
8980Sstevel@tonic-gate * !0 - failure
8990Sstevel@tonic-gate *
9000Sstevel@tonic-gate * PURPOSE: Helper to create a list of devconfig_t structs
9010Sstevel@tonic-gate * for slices on the input disks which have been
9020Sstevel@tonic-gate * modified for use by layout.
9030Sstevel@tonic-gate *
9040Sstevel@tonic-gate * Iterates the list of modified slices and creates a
9050Sstevel@tonic-gate * devconfig_t component for each slice in the list
9060Sstevel@tonic-gate * that is on any of the input modified disks.
9070Sstevel@tonic-gate *
9080Sstevel@tonic-gate * Slice names are constructed using the modified disk's
9090Sstevel@tonic-gate * access name to ensure that the correct alias is
9100Sstevel@tonic-gate * used to get to the slice.
9110Sstevel@tonic-gate */
9120Sstevel@tonic-gate int
get_modified_slices_for_disks(dlist_t * mod_disks)9130Sstevel@tonic-gate get_modified_slices_for_disks(
9140Sstevel@tonic-gate dlist_t *mod_disks)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate int error = 0;
9170Sstevel@tonic-gate dlist_t *iter = NULL;
9180Sstevel@tonic-gate
9190Sstevel@tonic-gate for (iter = get_modified_slices();
9200Sstevel@tonic-gate (iter != NULL) && (error == 0);
9210Sstevel@tonic-gate iter = iter->next) {
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate modslice_t *mods = (modslice_t *)iter->obj;
9240Sstevel@tonic-gate devconfig_t *slice = mods->slice_devcfg;
9250Sstevel@tonic-gate devconfig_t *newslice = NULL;
9260Sstevel@tonic-gate dm_descriptor_t disk;
9270Sstevel@tonic-gate moddisk_t *moddisk;
9280Sstevel@tonic-gate dlist_t *item;
9290Sstevel@tonic-gate char *sname = NULL;
9300Sstevel@tonic-gate uint64_t stblk = 0;
9310Sstevel@tonic-gate uint64_t nblks = 0;
9320Sstevel@tonic-gate uint16_t index;
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate /* only add modified slices that were sources */
9350Sstevel@tonic-gate if ((mods->times_modified == 0) ||
9360Sstevel@tonic-gate (mods->src_slice_desc != (dm_descriptor_t)0)) {
9370Sstevel@tonic-gate continue;
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate (void) devconfig_get_name(slice, &sname);
9410Sstevel@tonic-gate (void) get_disk_for_named_slice(sname, &disk);
9420Sstevel@tonic-gate
943*62Sjeanm if ((item = dlist_find(mod_disks, (void *)(uintptr_t)disk,
9440Sstevel@tonic-gate compare_disk_to_moddisk_disk)) == NULL) {
9450Sstevel@tonic-gate /* slice on disk that we don't care about */
9460Sstevel@tonic-gate continue;
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate moddisk = (moddisk_t *)item->obj;
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate /* create output slice struct for the modified slice */
9520Sstevel@tonic-gate ((error = devconfig_get_slice_start_block(slice,
9530Sstevel@tonic-gate &stblk)) != 0) ||
9540Sstevel@tonic-gate (error = devconfig_get_size_in_blocks(slice, &nblks)) ||
9550Sstevel@tonic-gate (error = devconfig_get_slice_index(slice, &index)) ||
9560Sstevel@tonic-gate (error = make_slicename_for_diskname_and_index(
9570Sstevel@tonic-gate moddisk->accessname, index, &sname)) ||
9580Sstevel@tonic-gate (error = new_devconfig(&newslice, TYPE_SLICE)) ||
9590Sstevel@tonic-gate (error = devconfig_set_name(newslice, sname)) ||
9600Sstevel@tonic-gate (error = devconfig_set_slice_start_block(newslice, stblk)) ||
9610Sstevel@tonic-gate (error = devconfig_set_size_in_blocks(newslice, nblks));
9620Sstevel@tonic-gate
9630Sstevel@tonic-gate /* add to the moddisk's list of slices */
9640Sstevel@tonic-gate if (error == 0) {
9650Sstevel@tonic-gate if ((item = dlist_new_item(newslice)) == NULL) {
9660Sstevel@tonic-gate free_devconfig(newslice);
9670Sstevel@tonic-gate error = ENOMEM;
9680Sstevel@tonic-gate } else {
9690Sstevel@tonic-gate moddisk->slices =
9700Sstevel@tonic-gate dlist_append(item, moddisk->slices, AT_TAIL);
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate } else {
9730Sstevel@tonic-gate free_devconfig(newslice);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate return (error);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate * FUNCTION: compare_disk_to_moddisk_disk(void *disk, void *moddisk)
9820Sstevel@tonic-gate *
9830Sstevel@tonic-gate * INPUT: disk - opaque pointer to a dm_descriptor_t
9840Sstevel@tonic-gate * moddisk - opaque moddisk_t pointer
9850Sstevel@tonic-gate *
9860Sstevel@tonic-gate * RETURNS: int - 0 - if disk == moddisk->disk
9870Sstevel@tonic-gate * !0 - otherwise
9880Sstevel@tonic-gate *
9890Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the input disk dm_descriptor_t
9900Sstevel@tonic-gate * handle to the disk dm_descriptor_t handle in the input
9910Sstevel@tonic-gate * moddisk_t struct.
9920Sstevel@tonic-gate *
9930Sstevel@tonic-gate * Comparison is done via compare_descriptor_names.
9940Sstevel@tonic-gate */
9950Sstevel@tonic-gate static int
compare_disk_to_moddisk_disk(void * disk,void * moddisk)9960Sstevel@tonic-gate compare_disk_to_moddisk_disk(
9970Sstevel@tonic-gate void *disk,
9980Sstevel@tonic-gate void *moddisk)
9990Sstevel@tonic-gate {
10000Sstevel@tonic-gate assert(disk != (dm_descriptor_t)0);
10010Sstevel@tonic-gate assert(moddisk != NULL);
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate return (compare_descriptor_names((void *)disk,
1004*62Sjeanm (void *)(uintptr_t)((moddisk_t *)moddisk)->disk));
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate
10070Sstevel@tonic-gate /*
10080Sstevel@tonic-gate * FUNCTIONS: void set_hsp_request()
10090Sstevel@tonic-gate *
10100Sstevel@tonic-gate * INPUT: none -
10110Sstevel@tonic-gate * OUTPUT: none -
10120Sstevel@tonic-gate *
10130Sstevel@tonic-gate * PURPOSE: set the module global HSP request struct.
10140Sstevel@tonic-gate */
10150Sstevel@tonic-gate static void
set_hsp_request(devconfig_t * req)10160Sstevel@tonic-gate set_hsp_request(
10170Sstevel@tonic-gate devconfig_t *req)
10180Sstevel@tonic-gate {
10190Sstevel@tonic-gate _hsp_request = req;
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate
10220Sstevel@tonic-gate /*
10230Sstevel@tonic-gate * FUNCTIONS: void unset_hsp_request()
10240Sstevel@tonic-gate *
10250Sstevel@tonic-gate * INPUT: none -
10260Sstevel@tonic-gate * OUTPUT: none -
10270Sstevel@tonic-gate *
10280Sstevel@tonic-gate * PURPOSE: unset the module global HSP request struct.
10290Sstevel@tonic-gate */
10300Sstevel@tonic-gate static void
unset_hsp_request()10310Sstevel@tonic-gate unset_hsp_request()
10320Sstevel@tonic-gate {
10330Sstevel@tonic-gate _hsp_request = NULL;
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate * FUNCTION: process_hsp_request(devconfig_t *req, dlist_t **results)
10380Sstevel@tonic-gate * INPUT: req - pointer to the toplevel disk set devconfig_t request
10390Sstevel@tonic-gate * results - pointer to a list of composed results
10400Sstevel@tonic-gate *
10410Sstevel@tonic-gate * RETURNS: int - 0 - success
10420Sstevel@tonic-gate * !0 - failure
10430Sstevel@tonic-gate *
10440Sstevel@tonic-gate * PURPOSE: Helper which determines HSP processing for the
10450Sstevel@tonic-gate * composed volumes which need HSP spares.
10460Sstevel@tonic-gate */
10470Sstevel@tonic-gate static int
process_hsp_request(devconfig_t * req,dlist_t ** results)10480Sstevel@tonic-gate process_hsp_request(
10490Sstevel@tonic-gate devconfig_t *req,
10500Sstevel@tonic-gate dlist_t **results)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate int error = 0;
10530Sstevel@tonic-gate
10540Sstevel@tonic-gate if (_hsp_request != NULL) {
10550Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
10560Sstevel@tonic-gate gettext("\nProcessing HSP...\n"));
10570Sstevel@tonic-gate }
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate if (_hsp_devices == NULL) {
10600Sstevel@tonic-gate /* no devices -> no HSP */
10610Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
10620Sstevel@tonic-gate gettext(" No devices require hot spares...\n"));
10630Sstevel@tonic-gate } else {
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate oprintf(OUTPUT_TERSE, "\n");
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate ((error = layout_hsp(req, _hsp_request, _hsp_devices,
10680Sstevel@tonic-gate results)) != 0) ||
10690Sstevel@tonic-gate (error = collect_modified_disks(_hsp_request, *results)) ||
10700Sstevel@tonic-gate (error = convert_device_names(_hsp_request, *results));
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate return (error);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate * FUNCTION: add_to_hsp_list(dlist_t* list)
10780Sstevel@tonic-gate * INPUT: devs - pointer to a list of composed volumes
10790Sstevel@tonic-gate * OUTPUT: none -
10800Sstevel@tonic-gate * SIDEEFFECT: updates the module global list _hsp_devices
10810Sstevel@tonic-gate *
10820Sstevel@tonic-gate * RETURNS: int - 0 - success
10830Sstevel@tonic-gate * !0 - failure
10840Sstevel@tonic-gate *
10850Sstevel@tonic-gate * PURPOSE: Helper to update the list of devices which need HSP spares.
10860Sstevel@tonic-gate *
10870Sstevel@tonic-gate * Iterates the input list of devices and adds them them to the
10880Sstevel@tonic-gate * module provate list of devices needing spares.
10890Sstevel@tonic-gate */
10900Sstevel@tonic-gate int
add_to_hsp_list(dlist_t * list)10910Sstevel@tonic-gate add_to_hsp_list(
10920Sstevel@tonic-gate dlist_t *list)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate dlist_t *iter = NULL;
10950Sstevel@tonic-gate int error = 0;
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate for (iter = list; iter != NULL; iter = iter->next) {
10980Sstevel@tonic-gate dlist_t *item = NULL;
10990Sstevel@tonic-gate
11000Sstevel@tonic-gate if ((item = dlist_new_item(iter->obj)) == NULL) {
11010Sstevel@tonic-gate error = ENOMEM;
11020Sstevel@tonic-gate break;
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate _hsp_devices = dlist_append(item, _hsp_devices, AT_HEAD);
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate return (error);
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate /*
11110Sstevel@tonic-gate * FUNCTION: string_case_compare(
11120Sstevel@tonic-gate * char *str1, char *str2)
11130Sstevel@tonic-gate *
11140Sstevel@tonic-gate * INPUT: str1 - char *
11150Sstevel@tonic-gate * str2 - char *
11160Sstevel@tonic-gate *
11170Sstevel@tonic-gate * RETURNS: int - <0 - if str1 < str2
11180Sstevel@tonic-gate * 0 - if str1 == str2
11190Sstevel@tonic-gate * >0 - if str1 > str2
11200Sstevel@tonic-gate *
11210Sstevel@tonic-gate * PURPOSE: More robust case independent string comparison function.
11220Sstevel@tonic-gate *
11230Sstevel@tonic-gate * Assumes str1 and str2 are both char *
11240Sstevel@tonic-gate *
11250Sstevel@tonic-gate * Compares the lengths of each and if equivalent compares
11260Sstevel@tonic-gate * the strings using strcasecmp.
11270Sstevel@tonic-gate */
11280Sstevel@tonic-gate int
string_case_compare(char * str1,char * str2)11290Sstevel@tonic-gate string_case_compare(
11300Sstevel@tonic-gate char *str1,
11310Sstevel@tonic-gate char *str2)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate int result = 0;
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate assert(str1 != NULL);
11360Sstevel@tonic-gate assert(str2 != NULL);
11370Sstevel@tonic-gate
11380Sstevel@tonic-gate if ((result = (strlen(str1) - strlen(str2))) == 0) {
11390Sstevel@tonic-gate result = strcasecmp(str1, str2);
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate
11420Sstevel@tonic-gate return (result);
11430Sstevel@tonic-gate }
1144