xref: /onnv-gate/usr/src/cmd/lvm/metassist/layout/layout.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <assert.h>
30*0Sstevel@tonic-gate #include <string.h>
31*0Sstevel@tonic-gate #include <libintl.h>
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include "volume_error.h"
34*0Sstevel@tonic-gate #include "volume_defaults.h"
35*0Sstevel@tonic-gate #include "volume_dlist.h"
36*0Sstevel@tonic-gate #include "volume_output.h"
37*0Sstevel@tonic-gate #include "volume_request.h"
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include "layout.h"
40*0Sstevel@tonic-gate #include "layout_request.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include "layout_concat.h"
43*0Sstevel@tonic-gate #include "layout_discovery.h"
44*0Sstevel@tonic-gate #include "layout_device_cache.h"
45*0Sstevel@tonic-gate #include "layout_device_util.h"
46*0Sstevel@tonic-gate #include "layout_dlist_util.h"
47*0Sstevel@tonic-gate #include "layout_hsp.h"
48*0Sstevel@tonic-gate #include "layout_mirror.h"
49*0Sstevel@tonic-gate #include "layout_slice.h"
50*0Sstevel@tonic-gate #include "layout_stripe.h"
51*0Sstevel@tonic-gate #include "layout_svm_util.h"
52*0Sstevel@tonic-gate #include "layout_validate.h"
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #define	_LAYOUT_C
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate static int layout_init(devconfig_t *request, defaults_t *defaults);
57*0Sstevel@tonic-gate static int layout_diskset(request_t *request, dlist_t *results);
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static int process_request(devconfig_t *request, dlist_t **results);
60*0Sstevel@tonic-gate static int process_qos_request(devconfig_t *request, dlist_t **results);
61*0Sstevel@tonic-gate static int process_hsp_request(devconfig_t *request, dlist_t **results);
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate /*
64*0Sstevel@tonic-gate  * stuff for making/updating the HSP to service devices
65*0Sstevel@tonic-gate  * created by the toplevel request
66*0Sstevel@tonic-gate  */
67*0Sstevel@tonic-gate static devconfig_t	*_hsp_request = NULL;
68*0Sstevel@tonic-gate static dlist_t		*_hsp_devices = NULL;
69*0Sstevel@tonic-gate static void set_hsp_request(devconfig_t *request);
70*0Sstevel@tonic-gate static void unset_hsp_request();
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * struct to track which disks have been explicitly modified
74*0Sstevel@tonic-gate  * during the layout process...
75*0Sstevel@tonic-gate  *
76*0Sstevel@tonic-gate  * disk is the dm_descriptor_t of the modified disk
77*0Sstevel@tonic-gate  * accessname is the name to access the disk thru
78*0Sstevel@tonic-gate  * slices is the list of modified slices on the disk
79*0Sstevel@tonic-gate  */
80*0Sstevel@tonic-gate typedef struct {
81*0Sstevel@tonic-gate 	dm_descriptor_t	disk;
82*0Sstevel@tonic-gate 	char		*accessname;
83*0Sstevel@tonic-gate 	dlist_t		*slices;
84*0Sstevel@tonic-gate } moddisk_t;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate /*
87*0Sstevel@tonic-gate  * modified_disks is a list of moddisk_t structs
88*0Sstevel@tonic-gate  * tracking disks have been modified during layout.
89*0Sstevel@tonic-gate  */
90*0Sstevel@tonic-gate static dlist_t *_modified_disks = NULL;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static int collect_modified_disks(devconfig_t *request, dlist_t *results);
93*0Sstevel@tonic-gate static int add_modified_disks_to_diskset(
94*0Sstevel@tonic-gate 	dlist_t		*devices,
95*0Sstevel@tonic-gate 	devconfig_t	*diskset);
96*0Sstevel@tonic-gate static int release_modified_disks();
97*0Sstevel@tonic-gate static int get_removed_slices_for_disks(
98*0Sstevel@tonic-gate 	dlist_t		*mod_disks);
99*0Sstevel@tonic-gate static int get_modified_slices_for_disks(
100*0Sstevel@tonic-gate 	dlist_t		*moddisks);
101*0Sstevel@tonic-gate static int compare_disk_to_moddisk_disk(
102*0Sstevel@tonic-gate 	void		*disk,
103*0Sstevel@tonic-gate 	void		*moddisk);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate static int convert_device_names(devconfig_t *request, dlist_t *devs);
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * FUNCTION:	get_layout(devconfig_t *request, defaults_t *defaults)
109*0Sstevel@tonic-gate  *
110*0Sstevel@tonic-gate  * INPUT:	request	- a devconfig_t pointer to the toplevel request
111*0Sstevel@tonic-gate  *		defaults - a results_t pointer to the defaults
112*0Sstevel@tonic-gate  *
113*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
114*0Sstevel@tonic-gate  *			  !0 - otherwise
115*0Sstevel@tonic-gate  *
116*0Sstevel@tonic-gate  * PURPOSE:	Public entry point to layout module.
117*0Sstevel@tonic-gate  */
118*0Sstevel@tonic-gate int
119*0Sstevel@tonic-gate get_layout(
120*0Sstevel@tonic-gate 	request_t	*request,
121*0Sstevel@tonic-gate 	defaults_t	*defaults)
122*0Sstevel@tonic-gate {
123*0Sstevel@tonic-gate 	devconfig_t	*diskset_req = NULL;
124*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
125*0Sstevel@tonic-gate 	dlist_t		*results = NULL;
126*0Sstevel@tonic-gate 	int		error = 0;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	if ((diskset_req = request_get_diskset_req(request)) != NULL) {
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	    /* initialize using the the top-level disk set request... */
131*0Sstevel@tonic-gate 	    if ((error = layout_init(diskset_req, defaults)) != 0) {
132*0Sstevel@tonic-gate 		return (error);
133*0Sstevel@tonic-gate 	    }
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	    oprintf(OUTPUT_TERSE,
136*0Sstevel@tonic-gate 		    gettext("\nProcessing volume request...\n"));
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	    iter = devconfig_get_components(diskset_req);
139*0Sstevel@tonic-gate 	    for (; (iter != NULL) && (error == 0); iter = iter->next) {
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 		/* process each volume request, stop on any error */
142*0Sstevel@tonic-gate 		devconfig_t	*subreq = (devconfig_t *)iter->obj;
143*0Sstevel@tonic-gate 		dlist_t		*subres = NULL;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 		((error = process_request(subreq, &subres)) != 0) ||
146*0Sstevel@tonic-gate 		(error = collect_modified_disks(subreq, subres)) ||
147*0Sstevel@tonic-gate 		(error = convert_device_names(subreq, subres));
148*0Sstevel@tonic-gate 		if (error == 0) {
149*0Sstevel@tonic-gate 		    results = dlist_append(subres, results, AT_TAIL);
150*0Sstevel@tonic-gate 		}
151*0Sstevel@tonic-gate 	    }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	    if (error == 0) {
154*0Sstevel@tonic-gate 		/* process HSP request */
155*0Sstevel@tonic-gate 		dlist_t *subres = NULL;
156*0Sstevel@tonic-gate 		error = process_hsp_request(diskset_req, &subres);
157*0Sstevel@tonic-gate 		if (error == 0) {
158*0Sstevel@tonic-gate 		    results = dlist_append(subres, results, AT_TAIL);
159*0Sstevel@tonic-gate 		}
160*0Sstevel@tonic-gate 	    }
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	    if (error == 0) {
163*0Sstevel@tonic-gate 		oprintf(OUTPUT_TERSE,
164*0Sstevel@tonic-gate 			gettext("\nAssembling volume specification...\n"));
165*0Sstevel@tonic-gate 		/* determine required diskset modifications */
166*0Sstevel@tonic-gate 		error = layout_diskset(request, results);
167*0Sstevel@tonic-gate 	    }
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	    layout_clean_up();
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	    if (error == 0) {
172*0Sstevel@tonic-gate 		oprintf(OUTPUT_TERSE,
173*0Sstevel@tonic-gate 			gettext("\nVolume request completed successfully.\n"));
174*0Sstevel@tonic-gate 	    }
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	} else {
177*0Sstevel@tonic-gate 	    volume_set_error(
178*0Sstevel@tonic-gate 		    gettext("Malformed request, missing top level "
179*0Sstevel@tonic-gate 			    "disk set request."));
180*0Sstevel@tonic-gate 	}
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 	return (error);
183*0Sstevel@tonic-gate }
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate /*
186*0Sstevel@tonic-gate  * FUNCTION:	layout_clean_up()
187*0Sstevel@tonic-gate  *
188*0Sstevel@tonic-gate  * PURPOSE:	function which handles the details of cleaning up cached
189*0Sstevel@tonic-gate  *		data and any other memory allocated during the layout
190*0Sstevel@tonic-gate  *		process.
191*0Sstevel@tonic-gate  *
192*0Sstevel@tonic-gate  *		release physical device data structs
193*0Sstevel@tonic-gate  *		release SVM logical device data structs
194*0Sstevel@tonic-gate  *		release validation data structs
195*0Sstevel@tonic-gate  *		release modified device data structs
196*0Sstevel@tonic-gate  *		release request processing data structs
197*0Sstevel@tonic-gate  *
198*0Sstevel@tonic-gate  *		This function is also exported as part of the public
199*0Sstevel@tonic-gate  *		interface to the layout module, clients of layout
200*0Sstevel@tonic-gate  *		are required to call this function if get_layout()
201*0Sstevel@tonic-gate  *		was called and was not allowed to return.  For example,
202*0Sstevel@tonic-gate  *		if SIGINT was received while a layout request was in
203*0Sstevel@tonic-gate  *		process.
204*0Sstevel@tonic-gate  */
205*0Sstevel@tonic-gate void
206*0Sstevel@tonic-gate layout_clean_up()
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate 	(void) release_request_caches();
209*0Sstevel@tonic-gate 	(void) release_validation_caches();
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	(void) release_slices_to_remove();
212*0Sstevel@tonic-gate 	(void) release_modified_slices();
213*0Sstevel@tonic-gate 	(void) release_modified_disks();
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	(void) release_reserved_slices();
216*0Sstevel@tonic-gate 	(void) release_used_slices();
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	(void) release_usable_devices();
219*0Sstevel@tonic-gate 	(void) release_svm_names(get_request_diskset());
220*0Sstevel@tonic-gate 	(void) release_known_devices();
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	(void) unset_hsp_request(NULL);
223*0Sstevel@tonic-gate 	(void) unset_request_defaults(NULL);
224*0Sstevel@tonic-gate 	(void) unset_request_diskset(NULL);
225*0Sstevel@tonic-gate 	(void) unset_toplevel_request(NULL);
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate /*
229*0Sstevel@tonic-gate  * FUNCTION:	layout_init(devconfig_t *diskset, defaults_t *defaults)
230*0Sstevel@tonic-gate  *
231*0Sstevel@tonic-gate  * INPUT:	diskset	- a devconfig_t pointer to the toplevel request
232*0Sstevel@tonic-gate  *		defaults - a results_t pointer to the defaults
233*0Sstevel@tonic-gate  *
234*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
235*0Sstevel@tonic-gate  *			  !0 - otherwise
236*0Sstevel@tonic-gate  *
237*0Sstevel@tonic-gate  * PURPOSE:	function which handles the details of initializing the layout
238*0Sstevel@tonic-gate  *		module prior to processing a request.
239*0Sstevel@tonic-gate  *
240*0Sstevel@tonic-gate  *		Determines the requested disk set and validates it.
241*0Sstevel@tonic-gate  *
242*0Sstevel@tonic-gate  *		Scans the physical device configuration.
243*0Sstevel@tonic-gate  *		Scans the SVM logical device configuration.
244*0Sstevel@tonic-gate  *
245*0Sstevel@tonic-gate  *		Initializes layout private global data structures and does
246*0Sstevel@tonic-gate  *		semantic validation of the request.
247*0Sstevel@tonic-gate  */
248*0Sstevel@tonic-gate static int
249*0Sstevel@tonic-gate layout_init(
250*0Sstevel@tonic-gate 	devconfig_t	*diskset,
251*0Sstevel@tonic-gate 	defaults_t	*defaults)
252*0Sstevel@tonic-gate {
253*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
254*0Sstevel@tonic-gate 	int		error = 0;
255*0Sstevel@tonic-gate 	char		*dsname = NULL;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	((error = validate_basic_svm_config()) != 0) ||
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	/* determine & validate requested disk set name */
260*0Sstevel@tonic-gate 	(error = devconfig_get_name(diskset, &dsname)) ||
261*0Sstevel@tonic-gate 	(error = set_request_diskset(dsname)) ||
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/* discover known physical and logical devices */
264*0Sstevel@tonic-gate 	(error = discover_known_devices()) ||
265*0Sstevel@tonic-gate 	(error = scan_svm_names(dsname)) ||
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	/* validate and remember toplevel request */
268*0Sstevel@tonic-gate 	(error = set_toplevel_request(diskset)) ||
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	/* validate and remember defaults for this request */
271*0Sstevel@tonic-gate 	(error = set_request_defaults(defaults));
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	if (error != 0) {
274*0Sstevel@tonic-gate 	    return (error);
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
278*0Sstevel@tonic-gate 		gettext("\nValidating volume request...\n"));
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	iter = devconfig_get_components(diskset);
281*0Sstevel@tonic-gate 	for (; (iter != NULL) && (error == 0); iter = iter->next) {
282*0Sstevel@tonic-gate 	    devconfig_t	*subreq = (devconfig_t *)iter->obj;
283*0Sstevel@tonic-gate 	    error = validate_request(subreq);
284*0Sstevel@tonic-gate 	}
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	if (error == 0) {
287*0Sstevel@tonic-gate 	    error = discover_usable_devices(dsname);
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	if (error == 0) {
291*0Sstevel@tonic-gate 	    /* final validation on explicitly requested components */
292*0Sstevel@tonic-gate 	    error = validate_reserved_slices();
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	if (error == 0) {
296*0Sstevel@tonic-gate 	    /* final validation on request sizes vs. actual avail space */
297*0Sstevel@tonic-gate 	    error = validate_request_sizes(diskset);
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	return (error);
301*0Sstevel@tonic-gate }
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate /*
304*0Sstevel@tonic-gate  * FUNCTION:	process_request(devconfig_t *req, dlist_t **results)
305*0Sstevel@tonic-gate  *
306*0Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
307*0Sstevel@tonic-gate  *		results	- pointer to a list of resulting volumes
308*0Sstevel@tonic-gate  *
309*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
310*0Sstevel@tonic-gate  *			  !0 - otherwise
311*0Sstevel@tonic-gate  *
312*0Sstevel@tonic-gate  * PURPOSE:	function which handles the details of an explicit
313*0Sstevel@tonic-gate  *		volume request.
314*0Sstevel@tonic-gate  *
315*0Sstevel@tonic-gate  *		Determines the requested volume type, whether the
316*0Sstevel@tonic-gate  *		request	contains specific subcomponents and dispatches
317*0Sstevel@tonic-gate  *		to the appropriate layout function for that type.
318*0Sstevel@tonic-gate  *
319*0Sstevel@tonic-gate  *		Resulting volumes are appended to the results list.
320*0Sstevel@tonic-gate  *
321*0Sstevel@tonic-gate  *		Note that an HSP request is held until all the volumes
322*0Sstevel@tonic-gate  *		in the request have been successfully composed. This
323*0Sstevel@tonic-gate  *		ensures that HSP spare sizing can be appropriate to
324*0Sstevel@tonic-gate  *		those volumes.
325*0Sstevel@tonic-gate  */
326*0Sstevel@tonic-gate static int
327*0Sstevel@tonic-gate process_request(
328*0Sstevel@tonic-gate 	devconfig_t	*req,
329*0Sstevel@tonic-gate 	dlist_t		**results)
330*0Sstevel@tonic-gate {
331*0Sstevel@tonic-gate 	component_type_t	type = TYPE_UNKNOWN;
332*0Sstevel@tonic-gate 	uint64_t	nbytes = 0;   /* requested volume size */
333*0Sstevel@tonic-gate 	dlist_t		*comps = NULL;
334*0Sstevel@tonic-gate 	int		ncomps = 0;
335*0Sstevel@tonic-gate 	int		error = 0;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	(void) devconfig_get_type(req, &type);
338*0Sstevel@tonic-gate 	(void) devconfig_get_size(req, &nbytes);
339*0Sstevel@tonic-gate 	comps = devconfig_get_components(req);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	if (type == TYPE_HSP) {
342*0Sstevel@tonic-gate 	    /* HSP processing needs to happen after all other volumes. */
343*0Sstevel@tonic-gate 	    /* set the HSP request aside until all other requests have */
344*0Sstevel@tonic-gate 	    /* been completed successfully */
345*0Sstevel@tonic-gate 	    set_hsp_request(req);
346*0Sstevel@tonic-gate 	    return (0);
347*0Sstevel@tonic-gate 	}
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE, "\n");
350*0Sstevel@tonic-gate 	oprintf(OUTPUT_VERBOSE, "******************\n");
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	ncomps = dlist_length(comps);
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	if (type == TYPE_STRIPE) {
355*0Sstevel@tonic-gate 	    if (ncomps > 0) {
356*0Sstevel@tonic-gate 		return (populate_explicit_stripe(req, results));
357*0Sstevel@tonic-gate 	    } else {
358*0Sstevel@tonic-gate 		return (layout_stripe(req, nbytes, results));
359*0Sstevel@tonic-gate 	    }
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	if (type == TYPE_CONCAT) {
363*0Sstevel@tonic-gate 	    if (ncomps > 0) {
364*0Sstevel@tonic-gate 		return (populate_explicit_concat(req, results));
365*0Sstevel@tonic-gate 	    } else {
366*0Sstevel@tonic-gate 		return (layout_concat(req, nbytes, results));
367*0Sstevel@tonic-gate 	    }
368*0Sstevel@tonic-gate 	}
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	if (type == TYPE_MIRROR) {
371*0Sstevel@tonic-gate 	    if (ncomps > 0) {
372*0Sstevel@tonic-gate 		return (populate_explicit_mirror(req, results));
373*0Sstevel@tonic-gate 	    } else {
374*0Sstevel@tonic-gate 		uint16_t nsubs = 0;
375*0Sstevel@tonic-gate 		if ((error = get_mirror_nsubs(req, &nsubs)) != 0) {
376*0Sstevel@tonic-gate 		    return (error);
377*0Sstevel@tonic-gate 		} else {
378*0Sstevel@tonic-gate 		    return (layout_mirror(req, nsubs, nbytes, results));
379*0Sstevel@tonic-gate 		}
380*0Sstevel@tonic-gate 	    }
381*0Sstevel@tonic-gate 	}
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	if (type == TYPE_VOLUME) {
384*0Sstevel@tonic-gate 	    error = process_qos_request(req, results);
385*0Sstevel@tonic-gate 	}
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	return (error);
388*0Sstevel@tonic-gate }
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate /*
391*0Sstevel@tonic-gate  * FUNCTION:	process_qos_request(devconfig_t *req, dlist_t **results)
392*0Sstevel@tonic-gate  *
393*0Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
394*0Sstevel@tonic-gate  *		results	- pointer to a list of resulting volumes
395*0Sstevel@tonic-gate  *
396*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
397*0Sstevel@tonic-gate  *			  !0 - otherwise
398*0Sstevel@tonic-gate  *
399*0Sstevel@tonic-gate  * PURPOSE:	function which handles the details of mapping an implicit
400*0Sstevel@tonic-gate  *		volume request of QoS attributes into a volume type.
401*0Sstevel@tonic-gate  *
402*0Sstevel@tonic-gate  *		Resulting volumes are appended to the results list.
403*0Sstevel@tonic-gate  */
404*0Sstevel@tonic-gate static int
405*0Sstevel@tonic-gate process_qos_request(
406*0Sstevel@tonic-gate 	devconfig_t	*req,
407*0Sstevel@tonic-gate 	dlist_t		**results)
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	int		error = 0;
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	uint64_t	nbytes = 0;
412*0Sstevel@tonic-gate 	uint16_t	rlevel = 0;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/* get QoS attributes */
415*0Sstevel@tonic-gate 	(void) devconfig_get_size(req, &nbytes);
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	if ((error = get_volume_redundancy_level(req, &rlevel)) != 0) {
418*0Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
419*0Sstevel@tonic-gate 		error = 0;
420*0Sstevel@tonic-gate 		rlevel = 0;
421*0Sstevel@tonic-gate 	    }
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	if (error == 0) {
425*0Sstevel@tonic-gate 	    if (rlevel == 0) {
426*0Sstevel@tonic-gate 		error = layout_stripe(req, nbytes, results);
427*0Sstevel@tonic-gate 	    } else {
428*0Sstevel@tonic-gate 		error = layout_mirror(req, rlevel, nbytes, results);
429*0Sstevel@tonic-gate 	    }
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	return (error);
433*0Sstevel@tonic-gate }
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate /*
436*0Sstevel@tonic-gate  * FUNCTION:	layout_diskset(request_t *req, dlist_t **results)
437*0Sstevel@tonic-gate  *
438*0Sstevel@tonic-gate  * INPUT:	req	- a request_t pointer to the toplevel request
439*0Sstevel@tonic-gate  *		results	- pointer to the list of composed result volumes
440*0Sstevel@tonic-gate  *
441*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
442*0Sstevel@tonic-gate  *			  !0 - otherwise
443*0Sstevel@tonic-gate  *
444*0Sstevel@tonic-gate  * PURPOSE:	function which handles the details of completing an layout
445*0Sstevel@tonic-gate  *		request.
446*0Sstevel@tonic-gate  *
447*0Sstevel@tonic-gate  *		Determines if the disk set specified in the request currently
448*0Sstevel@tonic-gate  *		exists and sets it up for creation if it doesn't.
449*0Sstevel@tonic-gate  *
450*0Sstevel@tonic-gate  *		Adds new disks required by the result volumes to the disk set.
451*0Sstevel@tonic-gate  *
452*0Sstevel@tonic-gate  *		Attaches the result volumes to the disk set result.
453*0Sstevel@tonic-gate  *
454*0Sstevel@tonic-gate  *		Convert slice and disk names to preferred names.
455*0Sstevel@tonic-gate  *
456*0Sstevel@tonic-gate  *		Attaches the disk set result to the toplevel request.
457*0Sstevel@tonic-gate  */
458*0Sstevel@tonic-gate static int
459*0Sstevel@tonic-gate layout_diskset(
460*0Sstevel@tonic-gate 	request_t	*request,
461*0Sstevel@tonic-gate 	dlist_t		*results)
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	int		error = 0;
464*0Sstevel@tonic-gate 	devconfig_t	*diskset = NULL;
465*0Sstevel@tonic-gate 	dlist_t		*comps = NULL;
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	((error = new_devconfig(&diskset, TYPE_DISKSET)) != 0) ||
468*0Sstevel@tonic-gate 	(error = devconfig_set_name(diskset, get_request_diskset())) ||
469*0Sstevel@tonic-gate 	(error = add_modified_disks_to_diskset(results, diskset));
470*0Sstevel@tonic-gate 	if (error != 0) {
471*0Sstevel@tonic-gate 	    free_devconfig(diskset);
472*0Sstevel@tonic-gate 	    return (error);
473*0Sstevel@tonic-gate 	}
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	/* add resulting volumes */
476*0Sstevel@tonic-gate 	if (results != NULL) {
477*0Sstevel@tonic-gate 	    comps = devconfig_get_components(diskset);
478*0Sstevel@tonic-gate 	    comps = dlist_append(results, comps, AT_TAIL);
479*0Sstevel@tonic-gate 	    devconfig_set_components(diskset, comps);
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	request_set_diskset_config(request, diskset);
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	return (error);
485*0Sstevel@tonic-gate }
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate /*
488*0Sstevel@tonic-gate  * FUNCTION:	convert_device_names(devconfig_t request, dlist_t *devices)
489*0Sstevel@tonic-gate  *
490*0Sstevel@tonic-gate  * INPUT:	request	- a devconfig_t request pointer
491*0Sstevel@tonic-gate  * 		devices	- a list of devconfig_t devices
492*0Sstevel@tonic-gate  *
493*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - on success
494*0Sstevel@tonic-gate  *			  !0 - on any error
495*0Sstevel@tonic-gate  *
496*0Sstevel@tonic-gate  * PURPOSE:	Utility function to convert any slice or disk drive
497*0Sstevel@tonic-gate  *		names in a result devconfig_t to the preferred name
498*0Sstevel@tonic-gate  *		which should be used to access the device.
499*0Sstevel@tonic-gate  *
500*0Sstevel@tonic-gate  *		This convert the temporary names used by layout to
501*0Sstevel@tonic-gate  *		the proper DID or /dev/dsk alias.
502*0Sstevel@tonic-gate  */
503*0Sstevel@tonic-gate static int
504*0Sstevel@tonic-gate convert_device_names(
505*0Sstevel@tonic-gate 	devconfig_t *request,
506*0Sstevel@tonic-gate 	dlist_t	*devices)
507*0Sstevel@tonic-gate {
508*0Sstevel@tonic-gate 	int	error = 0;
509*0Sstevel@tonic-gate 	dlist_t	*iter;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	for (iter = devices;
512*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
513*0Sstevel@tonic-gate 	    iter = iter->next) {
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	    devconfig_t		*dev = (devconfig_t *)iter->obj;
516*0Sstevel@tonic-gate 	    component_type_t	type = TYPE_UNKNOWN;
517*0Sstevel@tonic-gate 	    dm_descriptor_t	disk = (dm_descriptor_t)0;
518*0Sstevel@tonic-gate 	    char		*devname = NULL;
519*0Sstevel@tonic-gate 	    char		*diskname = NULL;
520*0Sstevel@tonic-gate 	    char		*slicename = NULL;
521*0Sstevel@tonic-gate 	    uint16_t		index;
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	    if ((error = devconfig_get_type(dev, &type)) == 0) {
524*0Sstevel@tonic-gate 		switch (type) {
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 		case TYPE_MIRROR:
527*0Sstevel@tonic-gate 		case TYPE_STRIPE:
528*0Sstevel@tonic-gate 		case TYPE_CONCAT:
529*0Sstevel@tonic-gate 		case TYPE_HSP:
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 		    error = convert_device_names(request,
532*0Sstevel@tonic-gate 			    devconfig_get_components(dev));
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 		    break;
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 		case TYPE_SLICE:
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 		    ((error = devconfig_get_name(dev, &devname)) != 0) ||
539*0Sstevel@tonic-gate 		    (error = devconfig_get_slice_index(dev, &index)) ||
540*0Sstevel@tonic-gate 		    (error = get_disk_for_named_slice(devname, &disk)) ||
541*0Sstevel@tonic-gate 		    (error = get_device_access_name(request, disk,
542*0Sstevel@tonic-gate 			    &diskname)) ||
543*0Sstevel@tonic-gate 		    (error = make_slicename_for_diskname_and_index(
544*0Sstevel@tonic-gate 			    diskname, index, &slicename));
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		    if ((error == 0) && (slicename != NULL)) {
547*0Sstevel@tonic-gate 			error = devconfig_set_name(dev, slicename);
548*0Sstevel@tonic-gate 			free(slicename);
549*0Sstevel@tonic-gate 		    }
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 		    break;
552*0Sstevel@tonic-gate 		}
553*0Sstevel@tonic-gate 	    }
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	return (error);
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate /*
560*0Sstevel@tonic-gate  * FUNCTION:	add_modified_disk(devconfig_t request, dm_descriptor_t disk);
561*0Sstevel@tonic-gate  *
562*0Sstevel@tonic-gate  * INPUT:	request	- a pointr to a devconfig_t request
563*0Sstevel@tonic-gate  *		disk - dm_descriptor_t handle for a disk that has been modified
564*0Sstevel@tonic-gate  *
565*0Sstevel@tonic-gate  * SIDEEFFECTS: adds an entry to the _modified_disks list which tracks
566*0Sstevel@tonic-gate  *		the disks that have been explicitly modified by
567*0Sstevel@tonic-gate  *		the layout code.
568*0Sstevel@tonic-gate  *
569*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
570*0Sstevel@tonic-gate  *			 !0 otherwise
571*0Sstevel@tonic-gate  *
572*0Sstevel@tonic-gate  * PURPOSE:	Adds the input disk to the list of those that have been
573*0Sstevel@tonic-gate  *		modified.
574*0Sstevel@tonic-gate  *
575*0Sstevel@tonic-gate  *		Disks are modified during layout for two reasons:
576*0Sstevel@tonic-gate  *
577*0Sstevel@tonic-gate  *		1. any disk that is to be added to the disk set gets
578*0Sstevel@tonic-gate  *		   an explicitly updated label.
579*0Sstevel@tonic-gate  *
580*0Sstevel@tonic-gate  *		2. once a disk is in the disk set, existing slices
581*0Sstevel@tonic-gate  *		   may be resized or new slices can be added.
582*0Sstevel@tonic-gate  */
583*0Sstevel@tonic-gate int
584*0Sstevel@tonic-gate add_modified_disk(
585*0Sstevel@tonic-gate 	devconfig_t	*request,
586*0Sstevel@tonic-gate 	dm_descriptor_t disk)
587*0Sstevel@tonic-gate {
588*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
589*0Sstevel@tonic-gate 	moddisk_t	*moddisk = NULL;
590*0Sstevel@tonic-gate 	dlist_t		*item = NULL;
591*0Sstevel@tonic-gate 	int		error = 0;
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	for (iter = _modified_disks; iter != NULL; iter = iter->next) {
594*0Sstevel@tonic-gate 	    moddisk = (moddisk_t *)iter->obj;
595*0Sstevel@tonic-gate 	    if (compare_descriptor_names(
596*0Sstevel@tonic-gate 		(void *)moddisk->disk, (void *)disk) == 0) {
597*0Sstevel@tonic-gate 		/* already in list */
598*0Sstevel@tonic-gate 		return (0);
599*0Sstevel@tonic-gate 	    }
600*0Sstevel@tonic-gate 	}
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	moddisk = (moddisk_t *)calloc(1, sizeof (moddisk_t));
603*0Sstevel@tonic-gate 	if (moddisk == NULL) {
604*0Sstevel@tonic-gate 	    error = ENOMEM;
605*0Sstevel@tonic-gate 	} else {
606*0Sstevel@tonic-gate 	    char *aname = NULL;
607*0Sstevel@tonic-gate 	    error = get_device_access_name(request, disk, &aname);
608*0Sstevel@tonic-gate 	    if (error == 0) {
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 		/* add to list of modified disks */
611*0Sstevel@tonic-gate 		moddisk->disk = disk;
612*0Sstevel@tonic-gate 		moddisk->accessname = aname;
613*0Sstevel@tonic-gate 		moddisk->slices = NULL;
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 		if ((item = dlist_new_item((void *)moddisk)) == NULL) {
616*0Sstevel@tonic-gate 		    free(moddisk);
617*0Sstevel@tonic-gate 		    error = ENOMEM;
618*0Sstevel@tonic-gate 		} else {
619*0Sstevel@tonic-gate 		    _modified_disks =
620*0Sstevel@tonic-gate 			dlist_append(item, _modified_disks, AT_HEAD);
621*0Sstevel@tonic-gate 		}
622*0Sstevel@tonic-gate 	    }
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	return (error);
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate /*
629*0Sstevel@tonic-gate  * FUNCTION:	collect_modified_disks(devconfig_t *request, dlist_t* devs)
630*0Sstevel@tonic-gate  *
631*0Sstevel@tonic-gate  * INPUT:	devs	- pointer to a list of composed volumes
632*0Sstevel@tonic-gate  * OUTPUT:	none	-
633*0Sstevel@tonic-gate  * SIDEEFFECT:	updates the module global list _modified_disks
634*0Sstevel@tonic-gate  *
635*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - success
636*0Sstevel@tonic-gate  *			  !0 - failure
637*0Sstevel@tonic-gate  *
638*0Sstevel@tonic-gate  * PURPOSE:	Helper to maintain the list of disks to be added to the
639*0Sstevel@tonic-gate  * 		disk set.
640*0Sstevel@tonic-gate  *
641*0Sstevel@tonic-gate  *		Iterates the input list of devices and determines which
642*0Sstevel@tonic-gate  *		disks they use. If a disk is not in the _modified_disks
643*0Sstevel@tonic-gate  *		list, it is added.
644*0Sstevel@tonic-gate  */
645*0Sstevel@tonic-gate static int
646*0Sstevel@tonic-gate collect_modified_disks(
647*0Sstevel@tonic-gate 	devconfig_t *request,
648*0Sstevel@tonic-gate 	dlist_t *devs)
649*0Sstevel@tonic-gate {
650*0Sstevel@tonic-gate 	int	error = 0;
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	char	*sname = NULL;
653*0Sstevel@tonic-gate 	dm_descriptor_t	disk = (dm_descriptor_t)0;
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	for (; (devs != NULL) && (error == 0); devs = devs->next) {
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	    devconfig_t		*dev = (devconfig_t *)devs->obj;
658*0Sstevel@tonic-gate 	    component_type_t	type = TYPE_UNKNOWN;
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	    if ((error = devconfig_get_type(dev, &type)) == 0) {
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 		switch (type) {
663*0Sstevel@tonic-gate 		case TYPE_MIRROR:
664*0Sstevel@tonic-gate 		case TYPE_STRIPE:
665*0Sstevel@tonic-gate 		case TYPE_CONCAT:
666*0Sstevel@tonic-gate 		case TYPE_HSP:
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		    error = collect_modified_disks(request,
669*0Sstevel@tonic-gate 			    devconfig_get_components(dev));
670*0Sstevel@tonic-gate 		    break;
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 		case TYPE_SLICE:
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 		    ((error = devconfig_get_name(dev, &sname)) != 0) ||
675*0Sstevel@tonic-gate 		    (error = get_disk_for_named_slice(sname, &disk)) ||
676*0Sstevel@tonic-gate 		    (error = add_modified_disk(request, disk));
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 		    break;
679*0Sstevel@tonic-gate 		}
680*0Sstevel@tonic-gate 	    }
681*0Sstevel@tonic-gate 	}
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	return (error);
684*0Sstevel@tonic-gate }
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate /*
687*0Sstevel@tonic-gate  * FUNCTION:	add_modified_disks_to_diskset(dlist_t *devices,
688*0Sstevel@tonic-gate  *			devconfig_t *diskset)
689*0Sstevel@tonic-gate  *
690*0Sstevel@tonic-gate  * INPUT:	devices	- pointer to a list of devices
691*0Sstevel@tonic-gate  *
692*0Sstevel@tonic-gate  * OUTPUT:	diskset	- pointer to a devconfig_t representing the disk set,
693*0Sstevel@tonic-gate  *			updated to include modified disks and slices as
694*0Sstevel@tonic-gate  *			components.
695*0Sstevel@tonic-gate  *
696*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - success
697*0Sstevel@tonic-gate  *			  !0 - failure
698*0Sstevel@tonic-gate  *
699*0Sstevel@tonic-gate  * PURPOSE:	Helper to add devconfig_t structs for disks and slices
700*0Sstevel@tonic-gate  *	        to the disk set.
701*0Sstevel@tonic-gate  *
702*0Sstevel@tonic-gate  *		Updates the list of _modified_disks by examining the input
703*0Sstevel@tonic-gate  *		list of composed devices.
704*0Sstevel@tonic-gate  *
705*0Sstevel@tonic-gate  *		Iterates _modified_disks and creates a devconfig_t component
706*0Sstevel@tonic-gate  *		for each disk in the list, the list of disks is then attached
707*0Sstevel@tonic-gate  *		to the input disk set.
708*0Sstevel@tonic-gate  *
709*0Sstevel@tonic-gate  *		Modified slices for disks in the disk set are added as well.
710*0Sstevel@tonic-gate  */
711*0Sstevel@tonic-gate static int
712*0Sstevel@tonic-gate add_modified_disks_to_diskset(
713*0Sstevel@tonic-gate 	dlist_t		*results,
714*0Sstevel@tonic-gate 	devconfig_t	*diskset)
715*0Sstevel@tonic-gate {
716*0Sstevel@tonic-gate 	int		error = 0;
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	dlist_t		*iter;
719*0Sstevel@tonic-gate 	dlist_t		*list = NULL;
720*0Sstevel@tonic-gate 	char		*dsname = get_request_diskset();
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	/* add modified disks to disk set's component list */
723*0Sstevel@tonic-gate 	list = devconfig_get_components(diskset);
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
726*0Sstevel@tonic-gate 		gettext("  Collecting modified disks...\n"));
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	/* collect removed slices for modified disks */
729*0Sstevel@tonic-gate 	error = get_removed_slices_for_disks(_modified_disks);
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	/* collect modified slices for modified disks */
732*0Sstevel@tonic-gate 	error = get_modified_slices_for_disks(_modified_disks);
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	for (iter = _modified_disks;
735*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
736*0Sstevel@tonic-gate 	    iter = iter->next) {
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	    moddisk_t	*moddisk = (moddisk_t *)iter->obj;
739*0Sstevel@tonic-gate 	    dm_descriptor_t disk = moddisk->disk;
740*0Sstevel@tonic-gate 	    devconfig_t	*newdisk = NULL;
741*0Sstevel@tonic-gate 	    boolean_t	in_set = B_FALSE;
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE, "      %s\n", moddisk->accessname);
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	    error = is_disk_in_diskset(disk, dsname, &in_set);
746*0Sstevel@tonic-gate 	    if ((error == 0) && (in_set != B_TRUE)) {
747*0Sstevel@tonic-gate 		/* New disk, add it to the disk set */
748*0Sstevel@tonic-gate 		((error = new_devconfig(&newdisk, TYPE_DRIVE)) != 0) ||
749*0Sstevel@tonic-gate 		(error = devconfig_set_name(newdisk, moddisk->accessname));
750*0Sstevel@tonic-gate 		if (error == 0) {
751*0Sstevel@tonic-gate 		    dlist_t *item = dlist_new_item(newdisk);
752*0Sstevel@tonic-gate 		    if (item == NULL) {
753*0Sstevel@tonic-gate 			error = ENOMEM;
754*0Sstevel@tonic-gate 		    } else {
755*0Sstevel@tonic-gate 			list = dlist_append(item, list, AT_TAIL);
756*0Sstevel@tonic-gate 			oprintf(OUTPUT_DEBUG,
757*0Sstevel@tonic-gate 				gettext("  must add %s to disk set \"%s\"\n"),
758*0Sstevel@tonic-gate 				moddisk->accessname, dsname);
759*0Sstevel@tonic-gate 		    }
760*0Sstevel@tonic-gate 		} else {
761*0Sstevel@tonic-gate 		    free_devconfig(newdisk);
762*0Sstevel@tonic-gate 		}
763*0Sstevel@tonic-gate 	    }
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	    if ((error == 0) && (moddisk->slices != NULL)) {
766*0Sstevel@tonic-gate 		/* move moddisk's slice list to disk set comp list */
767*0Sstevel@tonic-gate 		list = dlist_append(moddisk->slices, list, AT_TAIL);
768*0Sstevel@tonic-gate 		moddisk->slices = NULL;
769*0Sstevel@tonic-gate 	    }
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	if (error == 0) {
773*0Sstevel@tonic-gate 	    devconfig_set_components(diskset, list);
774*0Sstevel@tonic-gate 	} else {
775*0Sstevel@tonic-gate 	    dlist_free_items(list, NULL);
776*0Sstevel@tonic-gate 	}
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	return (error);
779*0Sstevel@tonic-gate }
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate /*
782*0Sstevel@tonic-gate  * FUNCTIONS:	void release_modified_disks()
783*0Sstevel@tonic-gate  *
784*0Sstevel@tonic-gate  * INPUT:	none   -
785*0Sstevel@tonic-gate  * OUTPUT:	none   -
786*0Sstevel@tonic-gate  *
787*0Sstevel@tonic-gate  * PURPOSE:	cleanup the module global list of disks that need
788*0Sstevel@tonic-gate  *		to be added to the disk set to satisfy the request.
789*0Sstevel@tonic-gate  */
790*0Sstevel@tonic-gate static int
791*0Sstevel@tonic-gate release_modified_disks()
792*0Sstevel@tonic-gate {
793*0Sstevel@tonic-gate 	dlist_t *iter = _modified_disks;
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 	for (; iter != NULL; iter = iter->next) {
796*0Sstevel@tonic-gate 	    moddisk_t *moddisk = (moddisk_t *)iter->obj;
797*0Sstevel@tonic-gate 	    if (moddisk->slices != NULL) {
798*0Sstevel@tonic-gate 		dlist_free_items(moddisk->slices, free_devconfig);
799*0Sstevel@tonic-gate 		moddisk->slices = NULL;
800*0Sstevel@tonic-gate 	    }
801*0Sstevel@tonic-gate 	    free(moddisk);
802*0Sstevel@tonic-gate 	    iter->obj = NULL;
803*0Sstevel@tonic-gate 	}
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate 	dlist_free_items(_modified_disks, NULL);
806*0Sstevel@tonic-gate 	_modified_disks = NULL;
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	return (0);
809*0Sstevel@tonic-gate }
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate /*
812*0Sstevel@tonic-gate  * FUNCTION:	get_removed_slices_for_disks(dlist_t *mod_disks)
813*0Sstevel@tonic-gate  *
814*0Sstevel@tonic-gate  * INPUT:	mod_disks - a list of moddisk_t structs
815*0Sstevel@tonic-gate  *
816*0Sstevel@tonic-gate  * OUTPUT:	mod_disks - the list of moddisk_t structs updated with
817*0Sstevel@tonic-gate  *			the slices to be removed for each disk
818*0Sstevel@tonic-gate  *
819*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - success
820*0Sstevel@tonic-gate  *			  !0 - failure
821*0Sstevel@tonic-gate  *
822*0Sstevel@tonic-gate  * PURPOSE:	Helper to create a list of devconfig_t structs
823*0Sstevel@tonic-gate  *		for slices on the input disks which need to be
824*0Sstevel@tonic-gate  *		removed from the system.
825*0Sstevel@tonic-gate  *
826*0Sstevel@tonic-gate  *		Iterates the list of slices to be removed and
827*0Sstevel@tonic-gate  *		creates a devconfig_t component for each slice
828*0Sstevel@tonic-gate  *		in the list that is on any of the input modified
829*0Sstevel@tonic-gate  *		disks.
830*0Sstevel@tonic-gate  *
831*0Sstevel@tonic-gate  *		Slice names are constructed using the modified disk's
832*0Sstevel@tonic-gate  *		access name to ensure that the correct alias is
833*0Sstevel@tonic-gate  *		used to get to the slice.
834*0Sstevel@tonic-gate  */
835*0Sstevel@tonic-gate static int
836*0Sstevel@tonic-gate get_removed_slices_for_disks(
837*0Sstevel@tonic-gate 	dlist_t		*mod_disks)
838*0Sstevel@tonic-gate {
839*0Sstevel@tonic-gate 	int		error = 0;
840*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	/* collect slices to be removed for the modified disks */
843*0Sstevel@tonic-gate 	for (iter = get_slices_to_remove();
844*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
845*0Sstevel@tonic-gate 	    iter = iter->next) {
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	    rmvdslice_t	*rmvd = (rmvdslice_t *)iter->obj;
848*0Sstevel@tonic-gate 	    dm_descriptor_t disk = (dm_descriptor_t)0;
849*0Sstevel@tonic-gate 	    moddisk_t	*moddisk = NULL;
850*0Sstevel@tonic-gate 	    char	*sname = NULL;
851*0Sstevel@tonic-gate 	    devconfig_t	*newslice = NULL;
852*0Sstevel@tonic-gate 	    dlist_t	*item = NULL;
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate 	    (void) get_disk_for_named_slice(rmvd->slice_name, &disk);
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	    if ((item = dlist_find(mod_disks, (void *)disk,
857*0Sstevel@tonic-gate 		compare_disk_to_moddisk_disk)) == NULL) {
858*0Sstevel@tonic-gate 		/* slice on disk that we don't care about */
859*0Sstevel@tonic-gate 		continue;
860*0Sstevel@tonic-gate 	    }
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	    moddisk = (moddisk_t *)item->obj;
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 	    /* create output slice struct for the removed slice */
865*0Sstevel@tonic-gate 	    ((error = make_slicename_for_diskname_and_index(
866*0Sstevel@tonic-gate 		    moddisk->accessname, rmvd->slice_index, &sname)) != 0) ||
867*0Sstevel@tonic-gate 	    (error = new_devconfig(&newslice, TYPE_SLICE)) ||
868*0Sstevel@tonic-gate 	    (error = devconfig_set_name(newslice, sname)) ||
869*0Sstevel@tonic-gate 	    (error = devconfig_set_size_in_blocks(newslice, 0));
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	    /* add to the moddisk's list of slices */
872*0Sstevel@tonic-gate 	    if (error == 0) {
873*0Sstevel@tonic-gate 		if ((item = dlist_new_item(newslice)) == NULL) {
874*0Sstevel@tonic-gate 		    free_devconfig(newslice);
875*0Sstevel@tonic-gate 		    error = ENOMEM;
876*0Sstevel@tonic-gate 		} else {
877*0Sstevel@tonic-gate 		    moddisk->slices =
878*0Sstevel@tonic-gate 			dlist_append(item, moddisk->slices, AT_TAIL);
879*0Sstevel@tonic-gate 		}
880*0Sstevel@tonic-gate 	    } else {
881*0Sstevel@tonic-gate 		free_devconfig(newslice);
882*0Sstevel@tonic-gate 	    }
883*0Sstevel@tonic-gate 	}
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	return (error);
886*0Sstevel@tonic-gate }
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate /*
889*0Sstevel@tonic-gate  * FUNCTION:	get_modified_slices_for_disks(dlist_t *mod_disks)
890*0Sstevel@tonic-gate  *
891*0Sstevel@tonic-gate  * INPUT:	mod_disks - a list of moddisk_t structs
892*0Sstevel@tonic-gate  *
893*0Sstevel@tonic-gate  * OUTPUT:	mod_disks - the list of moddisk_t structs updated with
894*0Sstevel@tonic-gate  *			the modified slices for each disk
895*0Sstevel@tonic-gate  *
896*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - success
897*0Sstevel@tonic-gate  *			  !0 - failure
898*0Sstevel@tonic-gate  *
899*0Sstevel@tonic-gate  * PURPOSE:	Helper to create a list of devconfig_t structs
900*0Sstevel@tonic-gate  *		for slices on the input disks which have been
901*0Sstevel@tonic-gate  *		modified for use by layout.
902*0Sstevel@tonic-gate  *
903*0Sstevel@tonic-gate  *		Iterates the list of modified slices and creates a
904*0Sstevel@tonic-gate  *		devconfig_t component for each slice in the list
905*0Sstevel@tonic-gate  *		that is on any of the input modified disks.
906*0Sstevel@tonic-gate  *
907*0Sstevel@tonic-gate  *		Slice names are constructed using the modified disk's
908*0Sstevel@tonic-gate  *		access name to ensure that the correct alias is
909*0Sstevel@tonic-gate  *		used to get to the slice.
910*0Sstevel@tonic-gate  */
911*0Sstevel@tonic-gate int
912*0Sstevel@tonic-gate get_modified_slices_for_disks(
913*0Sstevel@tonic-gate 	dlist_t		*mod_disks)
914*0Sstevel@tonic-gate {
915*0Sstevel@tonic-gate 	int		error = 0;
916*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	for (iter = get_modified_slices();
919*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
920*0Sstevel@tonic-gate 	    iter = iter->next) {
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	    modslice_t *mods = (modslice_t *)iter->obj;
923*0Sstevel@tonic-gate 	    devconfig_t	*slice = mods->slice_devcfg;
924*0Sstevel@tonic-gate 	    devconfig_t	*newslice = NULL;
925*0Sstevel@tonic-gate 	    dm_descriptor_t disk;
926*0Sstevel@tonic-gate 	    moddisk_t	*moddisk;
927*0Sstevel@tonic-gate 	    dlist_t	*item;
928*0Sstevel@tonic-gate 	    char	*sname = NULL;
929*0Sstevel@tonic-gate 	    uint64_t	stblk = 0;
930*0Sstevel@tonic-gate 	    uint64_t	nblks = 0;
931*0Sstevel@tonic-gate 	    uint16_t	index;
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 	    /* only add modified slices that were sources */
934*0Sstevel@tonic-gate 	    if ((mods->times_modified == 0) ||
935*0Sstevel@tonic-gate 		(mods->src_slice_desc != (dm_descriptor_t)0)) {
936*0Sstevel@tonic-gate 		continue;
937*0Sstevel@tonic-gate 	    }
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 	    (void) devconfig_get_name(slice, &sname);
940*0Sstevel@tonic-gate 	    (void) get_disk_for_named_slice(sname, &disk);
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 	    if ((item = dlist_find(mod_disks, (void *)disk,
943*0Sstevel@tonic-gate 		compare_disk_to_moddisk_disk)) == NULL) {
944*0Sstevel@tonic-gate 		/* slice on disk that we don't care about */
945*0Sstevel@tonic-gate 		continue;
946*0Sstevel@tonic-gate 	    }
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 	    moddisk = (moddisk_t *)item->obj;
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	    /* create output slice struct for the modified slice */
951*0Sstevel@tonic-gate 	    ((error = devconfig_get_slice_start_block(slice,
952*0Sstevel@tonic-gate 		    &stblk)) != 0) ||
953*0Sstevel@tonic-gate 	    (error = devconfig_get_size_in_blocks(slice, &nblks)) ||
954*0Sstevel@tonic-gate 	    (error = devconfig_get_slice_index(slice, &index)) ||
955*0Sstevel@tonic-gate 	    (error = make_slicename_for_diskname_and_index(
956*0Sstevel@tonic-gate 		    moddisk->accessname, index, &sname)) ||
957*0Sstevel@tonic-gate 	    (error = new_devconfig(&newslice, TYPE_SLICE)) ||
958*0Sstevel@tonic-gate 	    (error = devconfig_set_name(newslice, sname)) ||
959*0Sstevel@tonic-gate 	    (error = devconfig_set_slice_start_block(newslice, stblk)) ||
960*0Sstevel@tonic-gate 	    (error = devconfig_set_size_in_blocks(newslice, nblks));
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 	    /* add to the moddisk's list of slices */
963*0Sstevel@tonic-gate 	    if (error == 0) {
964*0Sstevel@tonic-gate 		if ((item = dlist_new_item(newslice)) == NULL) {
965*0Sstevel@tonic-gate 		    free_devconfig(newslice);
966*0Sstevel@tonic-gate 		    error = ENOMEM;
967*0Sstevel@tonic-gate 		} else {
968*0Sstevel@tonic-gate 		    moddisk->slices =
969*0Sstevel@tonic-gate 			dlist_append(item, moddisk->slices, AT_TAIL);
970*0Sstevel@tonic-gate 		}
971*0Sstevel@tonic-gate 	    } else {
972*0Sstevel@tonic-gate 		free_devconfig(newslice);
973*0Sstevel@tonic-gate 	    }
974*0Sstevel@tonic-gate 	}
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 	return (error);
977*0Sstevel@tonic-gate }
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate /*
980*0Sstevel@tonic-gate  * FUNCTION:	compare_disk_to_moddisk_disk(void *disk, void *moddisk)
981*0Sstevel@tonic-gate  *
982*0Sstevel@tonic-gate  * INPUT:	disk	- opaque pointer to a dm_descriptor_t
983*0Sstevel@tonic-gate  * 		moddisk - opaque moddisk_t pointer
984*0Sstevel@tonic-gate  *
985*0Sstevel@tonic-gate  * RETURNS:	int	- 0 - if disk == moddisk->disk
986*0Sstevel@tonic-gate  *			 !0 - otherwise
987*0Sstevel@tonic-gate  *
988*0Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the input disk dm_descriptor_t
989*0Sstevel@tonic-gate  *		handle to the disk dm_descriptor_t handle in the input
990*0Sstevel@tonic-gate  *		moddisk_t struct.
991*0Sstevel@tonic-gate  *
992*0Sstevel@tonic-gate  *		Comparison is done via compare_descriptor_names.
993*0Sstevel@tonic-gate  */
994*0Sstevel@tonic-gate static int
995*0Sstevel@tonic-gate compare_disk_to_moddisk_disk(
996*0Sstevel@tonic-gate 	void		*disk,
997*0Sstevel@tonic-gate 	void		*moddisk)
998*0Sstevel@tonic-gate {
999*0Sstevel@tonic-gate 	assert(disk != (dm_descriptor_t)0);
1000*0Sstevel@tonic-gate 	assert(moddisk != NULL);
1001*0Sstevel@tonic-gate 
1002*0Sstevel@tonic-gate 	return (compare_descriptor_names((void *)disk,
1003*0Sstevel@tonic-gate 			(void *)((moddisk_t *)moddisk)->disk));
1004*0Sstevel@tonic-gate }
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate /*
1007*0Sstevel@tonic-gate  * FUNCTIONS:	void set_hsp_request()
1008*0Sstevel@tonic-gate  *
1009*0Sstevel@tonic-gate  * INPUT:	none   -
1010*0Sstevel@tonic-gate  * OUTPUT:	none   -
1011*0Sstevel@tonic-gate  *
1012*0Sstevel@tonic-gate  * PURPOSE:	set the module global HSP request struct.
1013*0Sstevel@tonic-gate  */
1014*0Sstevel@tonic-gate static void
1015*0Sstevel@tonic-gate set_hsp_request(
1016*0Sstevel@tonic-gate 	devconfig_t	*req)
1017*0Sstevel@tonic-gate {
1018*0Sstevel@tonic-gate 	_hsp_request = req;
1019*0Sstevel@tonic-gate }
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate /*
1022*0Sstevel@tonic-gate  * FUNCTIONS:	void unset_hsp_request()
1023*0Sstevel@tonic-gate  *
1024*0Sstevel@tonic-gate  * INPUT:	none   -
1025*0Sstevel@tonic-gate  * OUTPUT:	none   -
1026*0Sstevel@tonic-gate  *
1027*0Sstevel@tonic-gate  * PURPOSE:	unset the module global HSP request struct.
1028*0Sstevel@tonic-gate  */
1029*0Sstevel@tonic-gate static void
1030*0Sstevel@tonic-gate unset_hsp_request()
1031*0Sstevel@tonic-gate {
1032*0Sstevel@tonic-gate 	_hsp_request = NULL;
1033*0Sstevel@tonic-gate }
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate /*
1036*0Sstevel@tonic-gate  * FUNCTION:	process_hsp_request(devconfig_t *req, dlist_t **results)
1037*0Sstevel@tonic-gate  * INPUT:	req	- pointer to the toplevel disk set devconfig_t request
1038*0Sstevel@tonic-gate  * 		results	- pointer to a list of composed results
1039*0Sstevel@tonic-gate  *
1040*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - success
1041*0Sstevel@tonic-gate  *			  !0 - failure
1042*0Sstevel@tonic-gate  *
1043*0Sstevel@tonic-gate  * PURPOSE:	Helper which determines HSP processing for the
1044*0Sstevel@tonic-gate  *		composed volumes which need HSP spares.
1045*0Sstevel@tonic-gate  */
1046*0Sstevel@tonic-gate static int
1047*0Sstevel@tonic-gate process_hsp_request(
1048*0Sstevel@tonic-gate 	devconfig_t	*req,
1049*0Sstevel@tonic-gate 	dlist_t		**results)
1050*0Sstevel@tonic-gate {
1051*0Sstevel@tonic-gate 	int error = 0;
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 	if (_hsp_request != NULL) {
1054*0Sstevel@tonic-gate 	    oprintf(OUTPUT_TERSE,
1055*0Sstevel@tonic-gate 		    gettext("\nProcessing HSP...\n"));
1056*0Sstevel@tonic-gate 	}
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate 	if (_hsp_devices == NULL) {
1059*0Sstevel@tonic-gate 	    /* no devices -> no HSP */
1060*0Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE,
1061*0Sstevel@tonic-gate 		    gettext("  No devices require hot spares...\n"));
1062*0Sstevel@tonic-gate 	} else {
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	    oprintf(OUTPUT_TERSE, "\n");
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate 	    ((error = layout_hsp(req, _hsp_request, _hsp_devices,
1067*0Sstevel@tonic-gate 		results)) != 0) ||
1068*0Sstevel@tonic-gate 	    (error = collect_modified_disks(_hsp_request, *results)) ||
1069*0Sstevel@tonic-gate 	    (error = convert_device_names(_hsp_request, *results));
1070*0Sstevel@tonic-gate 	}
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	return (error);
1073*0Sstevel@tonic-gate }
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate /*
1076*0Sstevel@tonic-gate  * FUNCTION:	add_to_hsp_list(dlist_t* list)
1077*0Sstevel@tonic-gate  * INPUT:	devs	- pointer to a list of composed volumes
1078*0Sstevel@tonic-gate  * OUTPUT:	none	-
1079*0Sstevel@tonic-gate  * SIDEEFFECT:	updates the module global list _hsp_devices
1080*0Sstevel@tonic-gate  *
1081*0Sstevel@tonic-gate  * RETURNS:	int	-  0 - success
1082*0Sstevel@tonic-gate  *			  !0 - failure
1083*0Sstevel@tonic-gate  *
1084*0Sstevel@tonic-gate  * PURPOSE:	Helper to update the list of devices which need HSP spares.
1085*0Sstevel@tonic-gate  *
1086*0Sstevel@tonic-gate  *		Iterates the input list of devices and adds them them to the
1087*0Sstevel@tonic-gate  *		module provate list of devices needing spares.
1088*0Sstevel@tonic-gate  */
1089*0Sstevel@tonic-gate int
1090*0Sstevel@tonic-gate add_to_hsp_list(
1091*0Sstevel@tonic-gate 	dlist_t	*list)
1092*0Sstevel@tonic-gate {
1093*0Sstevel@tonic-gate 	dlist_t	*iter = NULL;
1094*0Sstevel@tonic-gate 	int	error = 0;
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate 	for (iter = list; iter != NULL; iter = iter->next) {
1097*0Sstevel@tonic-gate 	    dlist_t *item = NULL;
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 	    if ((item = dlist_new_item(iter->obj)) == NULL) {
1100*0Sstevel@tonic-gate 		error = ENOMEM;
1101*0Sstevel@tonic-gate 		break;
1102*0Sstevel@tonic-gate 	    }
1103*0Sstevel@tonic-gate 	    _hsp_devices = dlist_append(item, _hsp_devices, AT_HEAD);
1104*0Sstevel@tonic-gate 	}
1105*0Sstevel@tonic-gate 
1106*0Sstevel@tonic-gate 	return (error);
1107*0Sstevel@tonic-gate }
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate /*
1110*0Sstevel@tonic-gate  * FUNCTION:	string_case_compare(
1111*0Sstevel@tonic-gate  *			char *str1, char *str2)
1112*0Sstevel@tonic-gate  *
1113*0Sstevel@tonic-gate  * INPUT:	str1	- char *
1114*0Sstevel@tonic-gate  * 		str2	- char *
1115*0Sstevel@tonic-gate  *
1116*0Sstevel@tonic-gate  * RETURNS:	int	- <0 - if str1 < str2
1117*0Sstevel@tonic-gate  *			   0 - if str1 == str2
1118*0Sstevel@tonic-gate  *			  >0 - if str1 > str2
1119*0Sstevel@tonic-gate  *
1120*0Sstevel@tonic-gate  * PURPOSE:	More robust case independent string comparison function.
1121*0Sstevel@tonic-gate  *
1122*0Sstevel@tonic-gate  *		Assumes str1 and str2 are both char *
1123*0Sstevel@tonic-gate  *
1124*0Sstevel@tonic-gate  *		Compares the lengths of each and if equivalent compares
1125*0Sstevel@tonic-gate  *		the strings using strcasecmp.
1126*0Sstevel@tonic-gate  */
1127*0Sstevel@tonic-gate int
1128*0Sstevel@tonic-gate string_case_compare(
1129*0Sstevel@tonic-gate 	char	*str1,
1130*0Sstevel@tonic-gate 	char	*str2)
1131*0Sstevel@tonic-gate {
1132*0Sstevel@tonic-gate 	int	result = 0;
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 	assert(str1 != NULL);
1135*0Sstevel@tonic-gate 	assert(str2 != NULL);
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 	if ((result = (strlen(str1) - strlen(str2))) == 0) {
1138*0Sstevel@tonic-gate 	    result = strcasecmp(str1, str2);
1139*0Sstevel@tonic-gate 	}
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	return (result);
1142*0Sstevel@tonic-gate }
1143