xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_slice.c (revision 6be356c5780a1ccb886bba08d6eb56b61f021564)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/param.h>
30 #include <meta.h>
31 
32 #include "volume_string.h"
33 
34 #include "volume_devconfig.h"
35 #include "volume_error.h"
36 #include "volume_dlist.h"
37 #include "volume_output.h"
38 
39 #include "layout_device_cache.h"
40 #include "layout_device_util.h"
41 #include "layout_discovery.h"
42 #include "layout_dlist_util.h"
43 #include "layout_messages.h"
44 #include "layout_request.h"
45 #include "layout_slice.h"
46 
47 #define	_LAYOUT_SLICE_C
48 
49 static int pick_from_best_hba_and_disk(
50 	dlist_t   	*list,
51 	dlist_t   	*used,
52 	dm_descriptor_t *chosen);
53 
54 static int slice_has_same_disk_geom(
55 	dm_descriptor_t slice,
56 	dlist_t		*used,
57 	boolean_t	*bool);
58 
59 static int slice_on_unique_disk(
60 	dm_descriptor_t slice,
61 	dlist_t		*used,
62 	dlist_t		*othervols,
63 	boolean_t	*bool);
64 
65 static int slice_on_unique_hba(
66 	dm_descriptor_t slice,
67 	dlist_t		*used,
68 	dlist_t		*othervols,
69 	boolean_t	*bool);
70 
71 static int slice_on_similar_bus(
72 	dm_descriptor_t slice,
73 	dlist_t		*used,
74 	boolean_t	*bool);
75 
76 static int slice_has_n_paths(
77 	dm_descriptor_t	slice,
78 	uint16_t	npaths,
79 	boolean_t	*bool);
80 
81 static int compare_modslice_names(
82 	void 		*obj1,
83 	void		*obj2);
84 
85 static int compare_string_to_modslice_name(
86 	void		*str,
87 	void		*modslice);
88 
89 static int create_new_slice(
90 	dm_descriptor_t oslice,
91 	uint64_t	nbytes,
92 	boolean_t	add_extra_cyl,
93 	devconfig_t	**nslice);
94 
95 static int create_modified_slice(
96 	dm_descriptor_t	oslice,
97 	char		*oname,
98 	uint32_t	oindex,
99 	uint64_t	ostart,
100 	uint64_t	osize,
101 	uint64_t	bps,
102 	char		*nname,
103 	uint32_t	nindex,
104 	uint64_t	nsize,
105 	devconfig_t	**nslice);
106 
107 /*
108  * list to track resized slices
109  */
110 static  dlist_t	*_modified_slices = NULL;
111 
112 /*
113  * struct to track used slices and their disks...
114  */
115 typedef struct {
116 	char		*slicename;
117 	dm_descriptor_t	disk;
118 } usedslice_t;
119 
120 /*
121  * list to of usedslice_t to track slices that have been
122  * used for any reason.
123  */
124 static dlist_t	*_used_slices = NULL;
125 
126 static int add_used_slice_list_entry(char *slicename, dm_descriptor_t disk);
127 static int compare_usedslice_name_to_string(void *obj1, void *obj2);
128 static void free_used_slice(void *obj);
129 
130 /*
131  * list of slices reserved to be used for explicit
132  * volume requests
133  */
134 static dlist_t *_rsvd_slices = NULL;
135 
136 /*
137  * list of slices needing to be removed (zeroed out) prior to
138  * applying any metassist modifications to the system.
139  */
140 static dlist_t *_rmvd_slices = NULL;
141 
142 /*
143  * FUNCTION:	choose_slice(
144  *		uint64_t	nbytes,
145  *		uint16_t	npaths,
146  *		dlist_t		*slices,
147  *		dlist_t		*used,
148  *		dlist_t		*used_hbas,
149  *		dlist_t		*used_disks,
150  *		boolean_t	unused_disk,
151  *		boolean_t	nbytes_is_min,
152  *		boolean_t	add_extra_cyl,
153  *		devconfig_t	**chosen)
154  *
155  * INPUT:	nbytes -	required size
156  *		npaths -	minimum required data paths
157  *		*slices -	slices from which to choose
158  *		*used -		slices used by the volume under construction
159  *		*used_hbas -	hbas used by other volumes relevant to
160  *					the volume under construction
161  *		*used_disks -	disks used by other volumes relevant to
162  *					the volume under construction
163  *		unused_disk -	if true, the chosen slice must be from an
164  *					unused disk
165  *		nbytes_is_min -	if true, the chosen slice may be larger than
166  *					nbytes.
167  *		add_extra_cyl -	passed to create_new_slice, see comment there.
168  *		**chosen -	pointer to hold the chosen slice
169  *
170  * RETURNS:	int	- 0 on success
171  *			 !0 otherwise
172  *
173  * PURPOSE:	Choosen a slice from the list of those available.
174  *
175  *		Of those available, choose in order of preference:
176  *
177  *		- one on a unique HBA and disk that is of the exact size
178  *		- one on a unique HBA and disk that is of sufficient size
179  *		- one on unique HBA that is of the exact size
180  *		- one on unique HBA that is of sufficient size
181  *		- one on unique disk that is of the exact size
182  *		- one on unique disk that is of sufficient size
183  *		- one on any HBA that is of exact size
184  *		- one on any HBA that is of sufficient size
185  *		- one on a unique HBA that is the largest size
186  *		- one on a unique disk that is the largest size
187  *		- one on any HBA that is the largest size
188  *
189  *		The function scans the available slices and builds lists of
190  *		those meeting the criteria above.  After the scan is complete,
191  *		the lists are examined in order, the first non-empty list is
192  *		chosen.  If there are several possibilities in the chosen list,
193  *		see if it is possible select the slice from the least used HBA
194  *		and/or disk.
195  *
196  *		If nbytes_is_min is true, the returned slice will be
197  *		at least nbytes in capacity.
198  *
199  *		If unused_disk is true, the returned slice will be from
200  *		a disk with no other known uses.
201  */
202 int
203 choose_slice(
204 	uint64_t	nbytes,
205 	uint16_t	npaths,
206 	dlist_t		*slices,
207 	dlist_t		*used,
208 	dlist_t		*used_hbas,
209 	dlist_t		*used_disks,
210 	boolean_t	unused_disk,
211 	boolean_t	nbytes_is_min,
212 	boolean_t	add_extra_cyl,
213 	devconfig_t	**chosen)
214 {
215 	dlist_t		*iter	= NULL;
216 
217 	dm_descriptor_t	slice	= NULL;
218 	boolean_t	resize  = B_FALSE;
219 	boolean_t	verbose = (get_max_verbosity() == OUTPUT_VERBOSE);
220 
221 	int		error	= 0;
222 
223 	/*
224 	 * indexes into the list array:
225 	 * i -> unique controller	0 = yes, 1 = no
226 	 * j -> same bus type		0 = yes, 1 = no
227 	 * k -> unique disk		0 = yes, 1 = no
228 	 * l -> same disk geom		0 = yes, 1 = no
229 	 * m -> size			0 == exact, 1 = larger, 2 = any
230 	 */
231 	int		i, j, k, l, m;
232 	dlist_t		*list[2][2][2][2][3];
233 
234 	/* output string arrays for each array dimension and index */
235 	char	*uniqhba[2];
236 	char	*samebus[2];
237 	char	*uniqdisk[2];
238 	char	*samegeom[2];
239 	char	*sizes[3];
240 
241 	/* other output strings */
242 	char	*look_msg = NULL;
243 	char	*npaths_msg = NULL;
244 	char	*samegeom_msg = NULL;
245 	char	*samebus_msg = NULL;
246 	char	*uniqhba_msg = NULL;
247 	char	*uniqdisk_msg = NULL;
248 	char	*exact_msg = NULL;
249 	char	*larger_msg = NULL;
250 	char	*smaller_msg = NULL;
251 	char	*insuff_paths = NULL;
252 	char	*too_small = NULL;
253 	char	*useddisk_msg = NULL;
254 
255 	if (verbose == B_TRUE) {
256 	    /* only initialize the output strings if needed */
257 
258 	    /* BEGIN CSTYLED */
259 	    look_msg = gettext(
260 		    "\tlooking at slice: %s (%s)\n");
261 	    npaths_msg = gettext(
262 		    "\t    has the requested number of data paths (%d)\n");
263 	    samegeom_msg = gettext(
264 		    "\t    has the same disk geometry relative to used slices\n");
265 	    samebus_msg = gettext(
266 		    "\t    on a similar I/O bus/HBA relative to used slices\n");
267 	    uniqhba_msg = gettext(
268 		    "\t    on a unique HBA relative to used slices\n");
269 	    uniqdisk_msg = gettext(
270 		    "\t    on a unique disk relative to used slices\n");
271 	    exact_msg = gettext(
272 		    "\t    the exact size necessary\n");
273 	    larger_msg = gettext(
274 		    "\t    larger than necessary\n");
275 	    smaller_msg = gettext(
276 		    "\t    smaller than necessary\n");
277 	    insuff_paths = gettext(
278 		    "\t    rejected: not enough paths (%d requested)\n");
279 	    too_small = gettext(
280 		    "\t    rejected: too small\n");
281 	    useddisk_msg = gettext(
282 		    "\t    rejected: on a disk with other volume component(s)\n");
283 
284 	    uniqhba[0] = gettext("unique HBA");
285 	    uniqhba[1] = gettext("non unique HBA");
286 	    samebus[0] = gettext("same bus type");
287 	    samebus[1] = gettext("different bus type");
288 	    uniqdisk[0] = gettext("unique disk");
289 	    uniqdisk[1] = gettext("non unique disk");
290 	    samegeom[0] = gettext("same geometry");
291 	    samegeom[1] = gettext("different geometry");
292 	    sizes[0] = gettext("an exact size slice");
293 	    sizes[1] = gettext("a larger slice");
294 	    sizes[2] = gettext("a smaller slice");
295 
296 	    /* END CSTYLED */
297 	}
298 
299 	/* init list array pointers */
300 	(void) memset(list, 0,  2*2*2*2*3 * sizeof (dlist_t *));
301 
302 	for (iter = slices;
303 	    (iter != NULL) && (error == 0); iter = iter->next) {
304 
305 	    dm_descriptor_t	slice = (uintptr_t)iter->obj;
306 	    uint64_t		snbytes = 0;
307 	    boolean_t		uniqdisk = B_FALSE;
308 	    boolean_t		uniqhba = B_FALSE;
309 	    boolean_t		samegeom = B_FALSE;
310 	    boolean_t		samebus = B_FALSE;
311 	    boolean_t		paths = B_FALSE;
312 	    dlist_t		*item = NULL;
313 
314 	    ((error = slice_get_size(slice, &snbytes)) != 0) ||
315 	    (error = slice_has_n_paths(slice, npaths, &paths)) ||
316 	    (error = slice_on_unique_hba(slice, used, used_hbas, &uniqhba)) ||
317 	    (error = slice_on_unique_disk(slice, used, used_disks,
318 		    &uniqdisk)) ||
319 	    (error = slice_on_similar_bus(slice, used, &samebus)) ||
320 	    (error = slice_has_same_disk_geom(slice, used, &samegeom));
321 	    if (error != 0) {
322 		continue;
323 	    }
324 
325 	    if (verbose == B_TRUE) {
326 		char *sname = NULL;
327 		char *sizestr = NULL;
328 		(void) get_display_name(slice, &sname);
329 		if (bytes_to_sizestr(snbytes, &sizestr,
330 			    universal_units, B_FALSE) == 0) {
331 		    oprintf(OUTPUT_VERBOSE, look_msg, sname, sizestr);
332 		    free(sizestr);
333 		}
334 	    }
335 
336 	    if (npaths > 1) {
337 		if (paths && verbose) {
338 		    /* specifically asked for more paths, ... */
339 		    oprintf(OUTPUT_VERBOSE, npaths_msg);
340 		}
341 	    } else if (npaths == 1) {
342 		/* every disk has at least 1 path */
343 		paths = B_TRUE;
344 	    }
345 
346 	    if (verbose == B_TRUE) {
347 		if (uniqhba) {
348 		    oprintf(OUTPUT_VERBOSE, uniqhba_msg);
349 		}
350 		if (uniqdisk) {
351 		    oprintf(OUTPUT_VERBOSE, uniqdisk_msg);
352 		}
353 
354 		if (used != NULL) {
355 		    if (samebus) {
356 			oprintf(OUTPUT_VERBOSE, samebus_msg);
357 		    }
358 		    if (samegeom) {
359 			oprintf(OUTPUT_VERBOSE, samegeom_msg);
360 		    }
361 		}
362 
363 		if (snbytes > nbytes) {
364 		    oprintf(OUTPUT_VERBOSE, larger_msg);
365 		} else if (snbytes == nbytes) {
366 		    oprintf(OUTPUT_VERBOSE, exact_msg);
367 		} else {
368 		    oprintf(OUTPUT_VERBOSE, smaller_msg);
369 		}
370 	    }
371 
372 	    /* filter slices not meeting minimum criteria */
373 	    if (nbytes_is_min && (snbytes < nbytes)) {
374 		/* not large enough */
375 		if (verbose == B_TRUE) {
376 		    oprintf(OUTPUT_VERBOSE, too_small);
377 		}
378 		continue;
379 	    }
380 
381 	    if (paths == B_FALSE) {
382 		/* not connected thru enough paths */
383 		if (verbose == B_TRUE) {
384 		    oprintf(OUTPUT_VERBOSE, insuff_paths, npaths);
385 		}
386 		continue;
387 	    }
388 
389 	    if (uniqdisk != B_TRUE && unused_disk == TRUE) {
390 		/* not on a unique disk */
391 		if (verbose == B_TRUE) {
392 		    oprintf(OUTPUT_VERBOSE, useddisk_msg);
393 		}
394 		continue;
395 	    }
396 
397 	    /* map slice properties into array indices */
398 	    i = (uniqhba ? 0 : 1);
399 	    j = (samebus ? 0 : 1);
400 	    k = (uniqdisk ? 0 : 1);
401 	    l = (samegeom ? 0 : 1);
402 	    m = (snbytes == nbytes ? 0 : (snbytes > nbytes ? 1 : 2));
403 
404 		/*
405 		 * insert slice into the list array using derived indices.
406 		 * NB: lists of slices larger than necessary are kept in
407 		 * ascending order (results in best fit, not worst fit)
408 		 */
409 	    if ((item = dlist_new_item((void*)(uintptr_t)slice)) == NULL) {
410 		error = ENOMEM;
411 	    } else {
412 		list[i][j][k][l][m] =
413 		    dlist_insert_ordered(
414 			    item,
415 			    list[i][j][k][l][m],
416 			    (m == 1 ? ASCENDING : DESCENDING),
417 			    compare_slice_sizes);
418 	    }
419 	}
420 
421 	/*
422 	 * Select a slice from one of the lists.
423 	 *
424 	 * The list with the combination of lowest indices
425 	 * is the most preferred list... in rough order:
426 	 *
427 	 *   one on a unique HBA and disk that is of the exact size
428 	 *   one on a unique HBA and disk that is of sufficient size (resize)
429 	 *   one on unique HBA that is of the exact size
430 	 *   one on unique HBA that is of sufficient size (resize)
431 	 *   one on unique disk that is of the exact size
432 	 *   one on unique disk that is of sufficient size (resize)
433 	 *   one on any HBA that is of exact size
434 	 *   one on any HBA that is of sufficient size (resize)
435 	 *   one on a unique HBA that is the largest size
436 	 *   one on a unique disk that is the largest size
437 	 *   one on any HBA that is the largest size
438 	 */
439 	slice = NULL;
440 
441 	for (i = 0; i < 2; i++) {
442 	    for (j = 0; j < 2; j++) {
443 		for (k = 0; k < 2; k++) {
444 		    for (l = 0; l < 2; l++) {
445 			for (m = 0; m < 3; m++) {
446 			    if (list[i][j][k][l][m] != NULL) {
447 
448 				/* pick least used slice from this list */
449 				error = pick_from_best_hba_and_disk(
450 					list[i][j][k][l][m],
451 					used, &slice);
452 
453 				resize = (m == 1);
454 
455 				/* terminate all loops */
456 				goto stop;
457 			    }
458 			}
459 		    }
460 		}
461 	    }
462 	}
463 stop:
464 
465 	/*
466 	 * Slice chosen, is a resize necessary?
467 	 */
468 	if ((error == 0) && (slice != NULL)) {
469 
470 	    if (error == 0) {
471 		if (verbose == B_TRUE) {
472 		    uint64_t	snbytes = 0;
473 		    char	*sname = NULL;
474 		    char	*sizestr = NULL;
475 
476 		    (void) get_display_name(slice, &sname);
477 		    (void) slice_get_size(slice, &snbytes);
478 
479 		    if (bytes_to_sizestr(snbytes, &sizestr,
480 				universal_units, B_FALSE) == 0) {
481 			oprintf(OUTPUT_VERBOSE,
482 				gettext("      selected %s (%s)\n"
483 					"        it is %s on a\n"
484 					"          %s (%s) and a\n"
485 					"          %s (%s)\n"),
486 				sname, sizestr,
487 				sizes[m],
488 				uniqhba[i], samebus[j],
489 				uniqdisk[k], samegeom[l]);
490 			free(sizestr);
491 		    }
492 		}
493 
494 		if (resize) {
495 		    if (verbose == B_TRUE) {
496 			oprintf(OUTPUT_VERBOSE,
497 				gettext("        it has excess space, "
498 					"resizing...\n"));
499 		    }
500 
501 		    error = create_new_slice(slice, nbytes, add_extra_cyl,
502 			    chosen);
503 		    if ((error == 0) &&	(*chosen != NULL) && verbose) {
504 			oprintf(OUTPUT_VERBOSE,
505 				gettext("        exactly resized\n"));
506 		    }
507 		}
508 
509 		if (error == 0) {
510 		    /* either no resize was necessary or the resize failed */
511 		    if (*chosen == NULL) {
512 			/*
513 			 * use the original slice as it is.
514 			 * Make a devconfig_t for it.
515 			 */
516 			error = create_devconfig_for_slice(slice, chosen);
517 		    }
518 		}
519 	    }
520 	} else if (slice == NULL) {
521 	    oprintf(OUTPUT_DEBUG,
522 		    gettext("      no possible slice\n"));
523 	}
524 
525 	for (i = 0; i < 2; i++) {
526 	    for (j = 0; j < 2; j++) {
527 		for (k = 0; k < 2; k++) {
528 		    for (l = 0; l < 2; l++) {
529 			for (m = 0; m < 3; m++) {
530 			    if (list[i][j][k][l][m] != NULL) {
531 				dlist_free_items(list[i][j][k][l][m], NULL);
532 			    }
533 			}
534 		    }
535 		}
536 	    }
537 	}
538 
539 	return (error);
540 }
541 
542 /*
543  * FUNCTION:	create_devconfig_for_slice(dm_descriptor_t slice,
544  *			devconfig_t **nslice)
545  *
546  * INPUT:	slice	- dm_descriptor_t handle to an existing slice
547  *		nslice	- devconfig_t pointer to hold the new slice
548  *
549  * RETURNS:	int	- 0 on success
550  *			 !0 otherwise
551  *
552  * PURPOSE:	Creates a devconfig_t struct representation of the input
553  *		slice dm_descriptor.
554  */
555 int
556 create_devconfig_for_slice(
557 	dm_descriptor_t slice,
558 	devconfig_t 	**nslice)
559 {
560 	uint64_t 	nbytes = 0;
561 	uint64_t 	nblks = 0;
562 	uint64_t 	stblk = 0;
563 	uint32_t 	index = 0;
564 	char		*name = NULL;
565 	int		error = 0;
566 
567 	((error = get_display_name(slice, &name)) != 0) ||
568 	(error = slice_get_size(slice, &nbytes)) ||
569 	(error = slice_get_size_in_blocks(slice, &nblks)) ||
570 	(error = slice_get_start_block(slice, &stblk)) ||
571 	(error = slice_get_index(slice, &index));
572 	if (error != 0) {
573 	    return (error);
574 	}
575 
576 	((error = new_devconfig(nslice, TYPE_SLICE)) != 0) ||
577 	(error = devconfig_set_name(*nslice, name)) ||
578 	(error = devconfig_set_slice_index(*nslice, index)) ||
579 	(error = devconfig_set_slice_start_block(*nslice, stblk)) ||
580 	(error = devconfig_set_size_in_blocks(*nslice, nblks)) ||
581 	(error = devconfig_set_size(*nslice, nbytes));
582 	if (error != 0) {
583 	    free_devconfig(*nslice);
584 	}
585 
586 	return (error);
587 }
588 
589 /*
590  * FUNCTION:	make_slicename_for_disk_and_index(dm_descriptor_t disk,
591  *			uint32_t index, char **slicename)
592  *
593  * INPUT:	disk	- a dm_descriptor_t disk handle
594  *		index	- a slice index
595  *
596  * OUTPUT	slicename - a char * pointer to hold the resulting slicename
597  *
598  * RETURNS:	int	- 0 on success
599  *			 !0 otherwise
600  *
601  * PURPOSE:	Utility function to manufacture a new slice name given the
602  *		"parent" disk and an available slice index.
603  *
604  *		The caller should free the returned name when done with it.
605  */
606 static int
607 make_slicename_for_disk_and_index(
608 	dm_descriptor_t	disk,
609 	uint16_t	index,
610 	char		**slicename)
611 {
612 	char *dname;
613 	int error = 0;
614 
615 	if ((error = get_display_name(disk, &dname)) == 0) {
616 	    error = make_slicename_for_diskname_and_index(dname,
617 		    index, slicename);
618 	}
619 
620 	return (error);
621 }
622 
623 /*
624  * FUNCTION:	make_slicename_for_diskname_and_index(char *diskname,
625  *			uint32_t index, char **slicename)
626  *
627  * INPUT:	diskname - a char * disk name
628  *		index	- a slice index
629  *
630  * OUTPUT	slicename - a char * pointer to hold the resulting slicename
631  *
632  * RETURNS:	int	- 0 on success
633  *			 !0 otherwise
634  *
635  * PURPOSE:	Utility function to manufacture a new slice name given the
636  *		name of a disk and an available slice index.
637  *
638  *		The caller should free the returned name when done with it.
639  */
640 int
641 make_slicename_for_diskname_and_index(
642 	char	*diskname,
643 	uint16_t index,
644 	char	**slicename)
645 {
646 	int error = 0;
647 	char buf[MAXNAMELEN+1];
648 
649 	(void) snprintf(buf, sizeof (buf), "%ss%u", diskname, index);
650 	if ((*slicename = strdup(buf)) == NULL) {
651 	    *slicename = NULL;
652 	    error = ENOMEM;
653 	}
654 
655 	return (error);
656 }
657 
658 /*
659  * FUNCTION:	create_new_slice(dm_descriptor_t oslice, uint64_t nbytes,
660  *			boolean_t add_extra_cyl, devconfig_t **nslice)
661  *
662  * INPUT:	oslice	- dm_descriptor_t handle to an existing slice
663  *		nbytes	- desired minimum size of the new slice
664  *		add_extra_cyl - boolean indicating whether the resized slice
665  *			needs to be oversized by 1 cylinder to account for
666  *			interlace rounding done for stripe components.
667  *		nslice	- devconfig_t pointer to hold the new slice
668  *
669  * RETURNS:	int	- 0 on success
670  *			 !0 otherwise
671  *
672  * PURPOSE:	Creates a new slice object using space from the input slice.
673  *
674  *		If there is an open slice slot in the disk VTOC, it will be
675  *		reserved for the new slice.  Space for the new slice will be
676  *		taken from the original slice.
677  *
678  *		If there is no open slice slot, the original slice will be
679  *		returned as the usable new slice.
680  *
681  *		The new slice will be of at least 'nbytes' bytes and possibly
682  *		larger due to sector and cylinder boundary alignment.
683  *
684  *		For EFI labeled disks, nbytes is rounded up to the next block
685  *		boundary.
686  *
687  *		For VTOC labeled disks, nbytes is rounded up to the next
688  *		cylinder boundary.
689  *
690  *		Additionally, if add_extra_cyl is true, the new slice will be
691  *		made 1 cylinder larger than necessary. This accounts for the
692  *		interlace rounding done within libmeta when computing the
693  *		usable size of stripe components on disks with VTOC labels.
694  *		Rounding the size up to the next cylinder boundary is not
695  *		sufficient because libmeta will round this size down to an
696  *		integral multiple of the stripe	interlace and then round that
697  *		result down to a cylinder boundary.  This makes the usable
698  *		size of the slice one cylinder smaller and possibly less than
699  *		nbytes.  Adding an extra cylinder ensures the usable size is
700  *		greater than nbytes despite the rounding.
701  *
702  *		If the resize is successful a pointer to the devconfig_t
703  *		representing the new slice will be returned in "newslice".
704  *
705  *		If the resize cannot be done, the newslice pointer will
706  *		be NULL.
707  */
708 static int
709 create_new_slice(
710 	dm_descriptor_t	oslice,
711 	uint64_t	nbytes,
712 	boolean_t	add_extra_cyl,
713 	devconfig_t	**nslice)
714 {
715 	dm_descriptor_t odisk = NULL;
716 	boolean_t	efi = B_FALSE;
717 
718 	char		*oname = NULL;
719 	uint64_t	osize = 0;	/* orig size (bytes) */
720 	uint64_t	ostart = 0;	/* orig start (byte) */
721 	uint64_t	ostblk = 0;	/* orig start (blk) */
722 	uint64_t	nsize = 0;	/* new size (bytes) */
723 	uint64_t	bytes_per_sect = 0;
724 
725 	uint32_t 	oindex = 0;
726 	uint32_t	nindex = oindex;
727 
728 	int		error = 0;
729 
730 	*nslice = NULL;
731 
732 	((error = slice_get_disk(oslice, &odisk)) != 0) ||
733 	(error = slice_get_index(oslice, &oindex));
734 	if (error != 0) {
735 	    return (error);
736 	}
737 
738 	/* find an unused slice number, default to oindex */
739 	nindex = oindex;
740 	if ((error = disk_get_available_slice_index(odisk, &nindex)) != 0) {
741 	    return (error);
742 	}
743 
744 	((error = get_display_name(oslice, &oname)) != 0) ||
745 	(error = slice_get_size(oslice, &osize)) ||
746 	(error = slice_get_start(oslice, &ostart)) ||
747 	(error = slice_get_start_block(oslice, &ostblk)) ||
748 	(error = disk_get_is_efi(odisk, &efi)) ||
749 	(error = disk_get_blocksize(odisk, &bytes_per_sect));
750 	if (error != 0) {
751 	    return (error);
752 	}
753 
754 	if (efi) {
755 
756 	    /* EFI: round size to an integral number of blocks (sectors) */
757 	    nsize = bytes_per_sect *
758 		((nbytes + (bytes_per_sect - 1)) / bytes_per_sect);
759 
760 	    oprintf(OUTPUT_DEBUG,
761 		    gettext("          "
762 			    "rounded up to %10.2f blocks\n"),
763 		    (double)(nsize/bytes_per_sect));
764 
765 	} else {
766 
767 	    /* VTOC: round size to an integral number of cylinders */
768 	    uint64_t	nhead = 0;
769 	    uint64_t	nsect = 0;
770 	    uint64_t	ncyls = 0;
771 
772 	    ((error = disk_get_ncylinders(odisk, &ncyls)) != 0) ||
773 	    (error = disk_get_nheads(odisk, &nhead)) ||
774 	    (error = disk_get_nsectors(odisk, &nsect));
775 	    if (error == 0) {
776 		uint64_t bytes_per_cyl = nhead * nsect * bytes_per_sect;
777 		nsize = bytes_per_cyl *
778 		    ((nbytes + (bytes_per_cyl - 1)) / bytes_per_cyl);
779 
780 		if (add_extra_cyl == TRUE) {
781 		    nsize += bytes_per_cyl;
782 		}
783 
784 		oprintf(OUTPUT_DEBUG,
785 			gettext("          "
786 				"rounded VTOC slice to %10.2f cylinders "
787 				"(out of %llu)\n"),
788 			(double)(nsize/bytes_per_cyl), ncyls);
789 	    }
790 	}
791 
792 	/* is sufficient space still available? */
793 	if (error == 0) {
794 	    if (osize == nsize) {
795 		/* use existing slice as is */
796 		((error = create_devconfig_for_slice(oslice, nslice)) != 0) ||
797 		(error = disk_reserve_index(odisk, (uint16_t)nindex));
798 	    } else if (osize > nsize) {
799 
800 		if (nindex == oindex) {
801 		    /* no more slices, resize existing slice */
802 		    ((error = create_devconfig_for_slice(oslice,
803 			nslice)) != 0) ||
804 		    (error = devconfig_set_size(*nslice, nsize)) ||
805 		    (error = devconfig_set_size_in_blocks(*nslice,
806 			nsize/bytes_per_sect));
807 		    (error = disk_reserve_index(odisk, (uint16_t)nindex));
808 
809 		} else {
810 		    /* make a new slice */
811 		    char *nname = NULL;
812 
813 		    ((error = make_slicename_for_disk_and_index(odisk,
814 			nindex, &nname)) != 0) ||
815 		    (error = create_modified_slice(oslice, oname, oindex,
816 			ostart, osize, bytes_per_sect, nname, nindex, nsize,
817 			nslice)) ||
818 			/* mark the new slice's index as used */
819 		    (error = disk_reserve_index(odisk, (uint16_t)nindex));
820 
821 		    if ((error != 0) && (*nslice == NULL)) {
822 			free(nname);
823 		    }
824 		}
825 	    }
826 	}
827 
828 	return (error);
829 }
830 
831 /*
832  * FUNCTION:	create_modified_slice(dm_descriptor_t oslice, char *oname,
833  *			uint32_t oindex, uint64_t ostart, uint64_t osize,
834  *			uint64_t bytes_per_sect, uint64_t nsize,
835  *			char *nname, uint32_t nindex, devconfig_t **nslice)
836  *
837  * INPUT:	oslice	- dm_descriptor_t handle for the original slice
838  *		oname - existing source slice name
839  *		oindex - existing source slice VTOC index
840  *		ostart - existing source slice start byte
841  *		osize - existing source slice size in bytes
842  *		bytes_per_sect - bytes per block (sector) for the disk
843  *		nname - new slice name
844  *		nindex - new slice VTOC index
845  *		nsize - new slice size in bytes (cylinder and block aligned)
846  *
847  * SIDEEFFECTS: updates the module private list of modified slices
848  *
849  * OUTPUT:	nslice - pointer to a devconfig_t to hold the new slice
850  *
851  * PURPOSE:	create a new VTOC slice by taking space from an
852  *		existing slice.
853  *
854  *		The input size for the new slice is expected to be
855  *		cylinder aligned.
856  */
857 static int
858 create_modified_slice(
859 	dm_descriptor_t	oslice,
860 	char		*oname,
861 	uint32_t	oindex,
862 	uint64_t	ostart,
863 	uint64_t	osize,
864 	uint64_t	bytes_per_sect,
865 	char		*nname,
866 	uint32_t	nindex,
867 	uint64_t	nsize,
868 	devconfig_t	**nslice)
869 {
870 	int		error = 0;
871 
872 	/* compute start sector and size in sectors for the new slice */
873 
874 	/* subtract nsize from original slice to get starting byte */
875 	uint64_t	nstart = (ostart + osize) - nsize;
876 
877 	/* convert starting byte to a sector */
878 	uint64_t	nstblk = (uint64_t)(nstart / bytes_per_sect);
879 
880 	/* convert nsize to an integral number of blocks (sectors) */
881 	uint64_t	nblks = (uint64_t)(nsize / bytes_per_sect);
882 
883 	/* create a modified slice record for the new slice */
884 	error = assemble_modified_slice(oslice, nname, nindex,
885 		nstblk, nblks, nsize, nslice);
886 	if (error != 0) {
887 	    free(nname);
888 	    return (error);
889 	}
890 
891 	/* update the existing source slice's new size */
892 	osize = osize - nsize;
893 	(void) slice_set_size(oslice, osize);
894 
895 	/* update/create the modified slice record gfor the source slice */
896 	error = assemble_modified_slice((dm_descriptor_t)0,
897 		oname, oindex, (uint64_t)(ostart / bytes_per_sect),
898 		(uint64_t)(osize / bytes_per_sect),
899 		osize, NULL);
900 
901 	return (error);
902 }
903 
904 /*
905  * FUNCTION:	assemble_modified_slice(dm_descriptor_t src_slice,
906  *			char *mod_name,	uint32_t mod_index,
907  *			uint64_t mod_stblk, uint64_t mod_nblks,
908  *			uint64_t mod_size, devconfig_t **modslice)
909  *
910  * INPUT:	src_slice - dm_descriptor_t handle of the slice space
911  *			was taken from to create the modified slice
912  *		mod_name - name of the modified slice
913  *		mod_index - name of the modified slice
914  *		mod_stblk - start block of the modified slice
915  *		mod_nblks - size in blocks of the modified slice
916  *		mod_size - size in bytes of the modified slice
917  *
918  * OUTPUT:	mod_slice	- if non-NULL, will be populated with a
919  *			devconfig_t representing the modified slice.
920  *
921  * SIDEEFFECTS: adds or updates an entry in the modified slice list
922  *		tracking the slices that have been explicitly modified
923  *		by the layout code.
924  *
925  * RETURNS:	int	- 0 on success
926  *			 !0 otherwise
927  *
928  * PURPOSE:	Utility function to which updates or creates a devconfig_t
929  *		representing a slice that needs to be modified.
930  *
931  *		If a modified slice record does not exist for the named
932  *		slice, a new devconfig_t struct is allocated and added
933  *		to the modified slice list.
934  *
935  *		The existing or created devconfig_t struct is updated with
936  *		the input values.
937  *
938  *		The information about the slices in the modified slice list
939  *		will eventually be handed to fmthard.
940  */
941 int
942 assemble_modified_slice(
943 	dm_descriptor_t	src_slice,
944 	char		*mod_name,
945 	uint32_t	mod_index,
946 	uint64_t	mod_stblk,
947 	uint64_t	mod_nblks,
948 	uint64_t	mod_size,
949 	devconfig_t	**mod_slice)
950 {
951 	devconfig_t	*slice = NULL;
952 	modslice_t	*mstp = NULL;
953 	dlist_t		*item = NULL;
954 	int		error = 0;
955 
956 	/* see if the slice has been modified before */
957 	if ((item = dlist_find(_modified_slices, mod_name,
958 	    compare_string_to_modslice_name)) != NULL) {
959 
960 	    /* yes, update the resize count and attributes */
961 	    mstp = (modslice_t *)item->obj;
962 	    slice = mstp->slice_devcfg;
963 
964 	    mstp->times_modified += 1;
965 	    mstp->src_slice_desc = src_slice;
966 
967 	    ((error = devconfig_set_slice_start_block(slice,
968 		mod_stblk)) != 0) ||
969 	    (error = devconfig_set_size(slice, mod_size)) ||
970 	    (error = devconfig_set_size_in_blocks(slice, mod_nblks));
971 
972 	} else {
973 
974 	    /* no, first modification... */
975 	    /* create a devconfig_t representing the new slice */
976 	    ((error = new_devconfig(&slice, TYPE_SLICE)) != 0) ||
977 	    (error = devconfig_set_name(slice, mod_name)) ||
978 	    (error = devconfig_set_slice_index(slice, mod_index)) ||
979 	    (error = devconfig_set_slice_start_block(slice, mod_stblk)) ||
980 	    (error = devconfig_set_size_in_blocks(slice, mod_nblks)) ||
981 	    (error = devconfig_set_size(slice, mod_size));
982 	    if (error == 0) {
983 		/* add to list of modified slices */
984 		if ((mstp = (modslice_t *)
985 		    calloc(1, sizeof (modslice_t))) != NULL) {
986 
987 		    /* count # of times source slice has been modified */
988 		    if (src_slice != (dm_descriptor_t)0) {
989 			mstp->times_modified = 0;
990 		    } else {
991 			mstp->times_modified = 1;
992 		    }
993 		    mstp->src_slice_desc = src_slice;
994 		    mstp->slice_devcfg = slice;
995 
996 		    if ((item = dlist_new_item(mstp)) != NULL) {
997 			_modified_slices =
998 			    dlist_insert_ordered(
999 				    item,
1000 				    _modified_slices,
1001 				    ASCENDING,
1002 				    compare_modslice_names);
1003 		    } else {
1004 			error = ENOMEM;
1005 		    }
1006 		} else {
1007 		    error = ENOMEM;
1008 		}
1009 	    }
1010 
1011 	    if (error != 0) {
1012 		free_devconfig(mstp);
1013 		free_devconfig(slice);
1014 	    }
1015 	}
1016 
1017 	if (error == 0) {
1018 	    oprintf(OUTPUT_DEBUG,
1019 		    "          "
1020 		    "modified %s (start blk: %9llu, nblks: %9llu)\n",
1021 		    mod_name, mod_stblk, mod_nblks);
1022 
1023 	    /* return devconfig_t for modified slice */
1024 	    if (mod_slice != NULL) {
1025 		*mod_slice = slice;
1026 		mstp->volume_component = B_TRUE;
1027 	    }
1028 	}
1029 
1030 	return (error);
1031 }
1032 
1033 /*
1034  * FUNCTION:	dlist_t *get_modified_slices()
1035  *
1036  * RETURNS:	pointer to the list of modslice_t structs representing
1037  *		modified slices
1038  *
1039  * PURPOSE:	public accessor to the list of slices modified while
1040  *		processing a request.
1041  */
1042 dlist_t *
1043 get_modified_slices()
1044 {
1045 	return (_modified_slices);
1046 }
1047 
1048 /*
1049  * FUNCTION:	free_modslice_object(void *obj)
1050  *
1051  * INPUT:	obj	- opaque pointer
1052  *
1053  * PURPOSE:	Frees memory associated with a modslice_t struct.
1054  */
1055 static void
1056 free_modslice_object(
1057 	void	*obj)
1058 {
1059 	assert(obj != (modslice_t *)NULL);
1060 
1061 	if (((modslice_t *)obj)->slice_devcfg != NULL) {
1062 	    if (((modslice_t *)obj)->volume_component != B_TRUE) {
1063 		free_devconfig(((modslice_t *)obj)->slice_devcfg);
1064 	    }
1065 	}
1066 
1067 	free(obj);
1068 }
1069 
1070 /*
1071  * FUNCTION:	void release_modified_slices()
1072  *
1073  * INPUT:	none   -
1074  * OUTPUT:	none   -
1075  *
1076  * PURPOSE:	cleanup the module global list of slices modified
1077  *		while processing a request.
1078  */
1079 int
1080 release_modified_slices()
1081 {
1082 	dlist_free_items(_modified_slices, free_modslice_object);
1083 	_modified_slices = NULL;
1084 
1085 	return (0);
1086 }
1087 
1088 /*
1089  * FUNCTION:	destroy_new_slice(devconfig_t *dev)
1090  *
1091  * INPUT:	dev	- a devconfig_t pointer to a slice object
1092  *
1093  * RETURNS:	int	- 0 on success
1094  *			 !0 otherwise
1095  *
1096  * PURPOSE:	Undoes slice creation done by create_new_slice():
1097  *
1098  *		release index
1099  *		remove from used_slices
1100  *		remove from modified_slices
1101  *		return space to source slice
1102  *		free memory
1103  */
1104 int
1105 destroy_new_slice(
1106 	devconfig_t	*dev)
1107 {
1108 	dm_descriptor_t disk = NULL;
1109 	uint64_t	size = 0;
1110 	uint16_t	index = 0;
1111 	modslice_t	*modified = NULL;
1112 	dlist_t		*item = NULL;
1113 	char		*name = NULL;
1114 	int		error = 0;
1115 
1116 	((error = devconfig_get_name(dev, &name)) != 0) ||
1117 	(error = devconfig_get_slice_index(dev, &index)) ||
1118 	(error = devconfig_get_size(dev, &size)) ||
1119 	(error = get_disk_for_named_slice(name, &disk)) ||
1120 	(error = disk_release_index(disk, index)) ||
1121 	(error = remove_used_slice_by_name(name));
1122 	if (error != 0) {
1123 	    return (error);
1124 	}
1125 
1126 	/* remove from the modified_slices list */
1127 	_modified_slices =
1128 	    dlist_remove_equivalent_item(
1129 		    _modified_slices, name,
1130 		    compare_string_to_modslice_name, &item);
1131 
1132 	if (item != NULL) {
1133 	    modified = (modslice_t *)item->obj;
1134 	    free((void*) item);
1135 	}
1136 
1137 	/* space from an existing slice? if so reclaim it. */
1138 	if (modified != NULL) {
1139 
1140 	    dm_descriptor_t src = modified->src_slice_desc;
1141 	    char	*srcname = NULL;
1142 	    dlist_t	*srcitem = NULL;
1143 
1144 	    if (src != (dm_descriptor_t)0) {
1145 		if ((error = get_display_name(src, &srcname)) == 0) {
1146 		    srcitem =
1147 			dlist_find(
1148 				_modified_slices,
1149 				srcname,
1150 				compare_string_to_modslice_name);
1151 		}
1152 	    }
1153 
1154 	    if ((error == 0) && (srcitem != NULL)) {
1155 
1156 		modslice_t	*source = (modslice_t *)srcitem->obj;
1157 		devconfig_t	*srcdevcfg = NULL;
1158 		uint64_t	srcsize = NULL;
1159 		uint64_t	srcsizeblks = NULL;
1160 		uint64_t	inblks = NULL;
1161 
1162 		srcdevcfg = source->slice_devcfg;
1163 		source->times_modified -= 1;
1164 
1165 		((error = devconfig_get_size(srcdevcfg, &srcsize)) != 0) ||
1166 		(error = devconfig_set_size(srcdevcfg, srcsize + size)) ||
1167 		(error = slice_set_size(src, srcsize + size)) ||
1168 		(error = slice_get_size_in_blocks(src, &srcsizeblks)) ||
1169 		(error = devconfig_get_size_in_blocks(srcdevcfg, &inblks));
1170 		(error = devconfig_set_size_in_blocks(srcdevcfg, srcsizeblks));
1171 
1172 		if (error == 0) {
1173 
1174 		    /* was only modification undone? */
1175 		    if (source->times_modified == 0) {
1176 
1177 			_modified_slices =
1178 			    dlist_remove_equivalent_item(
1179 				    _modified_slices, srcname,
1180 				    compare_string_to_modslice_name,
1181 				    &srcitem);
1182 
1183 			free_modslice_object((modslice_t *)srcitem->obj);
1184 			free((void *)srcitem);
1185 		    }
1186 		}
1187 	    }
1188 
1189 	    free_modslice_object(modified);
1190 	}
1191 
1192 	return (error);
1193 }
1194 
1195 /*
1196  * FUNCTION:	pick_from_best_hba_and_disk(dlist_t *slices,
1197  *			dlist_t *used, dm_descriptor_t *chosen)
1198  *
1199  * INPUT:	slices	- a dlist_t poitner to a list of slices
1200  *		used	- a dlist_t pointer to a list of used slices
1201  *		chosen  - a dm_descriptor_t pointer to hold the result
1202  *
1203  * RETURNS:	int	- 0 on success
1204  *			 !0 otherwise
1205  *
1206  * PURPOSE:	Examines the input list of slices and chooses the one
1207  *		that is on the least used HBA and disk.
1208  *
1209  *		HBA and disk usage is determined by examining the input
1210  *		list of used slices and counting the number of slices
1211  *		each HBA and disk contributes.
1212  *
1213  * 		The HBA which contributes the fewest is selected, and
1214  *		then the disk on that HBA which contributes the fewest
1215  *		is selected.
1216  *
1217  *		The largest slice from that disk is then returned.
1218  */
1219 static int
1220 pick_from_best_hba_and_disk(
1221 	dlist_t		*slices,
1222 	dlist_t		*used,
1223 	dm_descriptor_t *chosen)
1224 {
1225 	dlist_t		*iter = NULL;
1226 	dlist_t		*iter1 = NULL;
1227 	dlist_t		*iter2 = NULL;
1228 	dlist_t		*item = NULL;
1229 
1230 	dlist_t		*used_slice_hbas = NULL;
1231 
1232 	int		maxuses = 128;
1233 	int		maxslices = VTOC_SIZE;  /* meta.h */
1234 
1235 	int		i = 0;
1236 	int 		error = 0;
1237 
1238 	/*
1239 	 * allocate an array to hold lists of slices grouped by
1240 	 * HBA contribution... the list indexed by N is the list
1241 	 * of slices that are on HBAs contributing N slices
1242 	 */
1243 	dlist_t **prefhbas = (dlist_t **)calloc(maxuses, sizeof (dlist_t *));
1244 
1245 	/*
1246 	 * allocate an array to hold lists of slices grouped by
1247 	 * disk contribution... the list indexed by N is the list
1248 	 * of slices that are on disks contributing N slices
1249 	 */
1250 	dlist_t **prefdisks = (dlist_t **)calloc(maxslices, sizeof (dlist_t *));
1251 
1252 	*chosen = (dm_descriptor_t)0;
1253 
1254 	if (prefhbas == NULL || prefdisks == NULL) {
1255 	    free(prefhbas);
1256 	    free(prefdisks);
1257 	    return (ENOMEM);
1258 	}
1259 
1260 	/*
1261 	 * precompute the used slices' lists of HBAS: iterate the list
1262 	 * of used slices and determine the HBA(s) each is connected thru.
1263 	 * construct a list of lists containing the HBAs.
1264 	 */
1265 	for (iter = used;
1266 	    (iter != NULL) && (error == 0);
1267 	    iter = iter->next) {
1268 
1269 	    devconfig_t	*uslice = (devconfig_t *)iter->obj;
1270 	    dm_descriptor_t udisk = NULL;
1271 	    char	*uname = NULL;
1272 	    dlist_t	*uhbas = NULL;
1273 
1274 	    /* need to use disk to get to HBAs because */
1275 	    /* the slice doesn't exist yet */
1276 	    ((error = devconfig_get_name(uslice, &uname)) != 0) ||
1277 	    (error = get_disk_for_named_slice(uname, &udisk)) ||
1278 	    (error = disk_get_hbas(udisk, &uhbas));
1279 	    if (error == 0) {
1280 		if ((item = dlist_new_item((void *)uhbas)) == NULL) {
1281 		    error = ENOMEM;
1282 		} else {
1283 		    used_slice_hbas = dlist_append(
1284 			    item, used_slice_hbas, AT_HEAD);
1285 		}
1286 	    }
1287 	}
1288 
1289 	/*
1290 	 * iterate the list of chosen slices and for each,
1291 	 * determine how many other slices from its HBA(s)
1292 	 * are already being used...
1293 	 *
1294 	 * iter steps thru the list of slices
1295 	 * iter1 steps thru each of the slice's HBAs
1296 	 * iter2 steps thru the precomputed list of used slice's HBAs
1297 	 * dlist_contains then searches each used slice's HBAs
1298 	 *   to see if it contains iter1's HBA
1299 	 *
1300 	 * If it does, increment the count for that HBA.
1301 	 */
1302 	for (iter = slices;
1303 	    (iter != NULL) && (error == 0);
1304 	    iter = iter->next) {
1305 
1306 	    dm_descriptor_t slice = (uintptr_t)iter->obj;
1307 	    dlist_t	*hbas = NULL;
1308 	    int		n = 0; /* # slices each HBA contributes */
1309 
1310 	    if ((error = slice_get_hbas(slice, &hbas)) != 0) {
1311 		continue;
1312 	    }
1313 
1314 	    for (iter1 = hbas; iter1 != NULL; iter1 = iter1->next) {
1315 		for (iter2 = used_slice_hbas; iter2 != NULL;
1316 		    iter2 = iter2->next) {
1317 
1318 		    dlist_t *uhbas = (dlist_t *)iter2->obj;
1319 		    if (dlist_contains(uhbas, iter1->obj,
1320 				compare_descriptor_names) == B_TRUE) {
1321 			n++;
1322 		    }
1323 		}
1324 	    }
1325 
1326 	    dlist_free_items(hbas, NULL);
1327 
1328 	    /* group slices from HBAs contributing more than maxuses */
1329 	    if (n >= maxuses) {
1330 		n = maxuses - 1;
1331 	    }
1332 
1333 	    /* add slice to list in descending size order */
1334 	    if ((item = dlist_new_item((void*)(uintptr_t)slice)) == NULL) {
1335 		error = ENOMEM;
1336 	    } else {
1337 		prefhbas[n] =
1338 		    dlist_insert_ordered(
1339 			    item,
1340 			    prefhbas[n],
1341 			    DESCENDING,
1342 			    compare_slice_sizes);
1343 	    }
1344 	}
1345 
1346 	/* free list of lists of used slices HBAs */
1347 	for (iter = used_slice_hbas; iter != NULL; iter = iter->next) {
1348 	    dlist_free_items((dlist_t *)iter->obj, NULL);
1349 	}
1350 	dlist_free_items(used_slice_hbas, NULL);
1351 
1352 	/*
1353 	 * Select the list of slices that are on the HBA(s) contributing
1354 	 * the fewest slices... iterate these slices and for each, detemmine
1355 	 * how many other slices from its disk are already being used...
1356 	 */
1357 	for (i = 0; (i < maxuses) && (error == 0); i++) {
1358 
1359 	    for (iter = (dlist_t *)prefhbas[i];
1360 		(iter != NULL) && (error == 0);
1361 		iter = iter->next) {
1362 
1363 		dm_descriptor_t slice = (uintptr_t)iter->obj;
1364 		dm_descriptor_t disk;
1365 		int		n = 0;
1366 
1367 		(void) slice_get_disk(slice, &disk);
1368 
1369 		/*
1370 		 * count how many slices this slice's disk is contributing
1371 		 * by comparing it to the list of used slices
1372 		 */
1373 		for (iter1 = _used_slices; iter1 != NULL; iter1 = iter1->next) {
1374 		    usedslice_t *used = (usedslice_t *)iter1->obj;
1375 		    if (compare_descriptors((void *)(uintptr_t)disk,
1376 			(void *)(uintptr_t)used->disk) == 0) {
1377 			n++;
1378 		    }
1379 		}
1380 
1381 		/* add slice to list in descending size order */
1382 		if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) {
1383 		    error = ENOMEM;
1384 		} else {
1385 		    prefdisks[n] =
1386 			dlist_insert_ordered(
1387 				item,
1388 				prefdisks[n],
1389 				DESCENDING,
1390 				compare_slice_sizes);
1391 		}
1392 	    }
1393 	}
1394 
1395 	if (error == 0) {
1396 	    /* select largest slice from least used disk */
1397 	    for (i = 0; (i < maxslices) && (*chosen == NULL); i++) {
1398 		if (prefdisks[i] != NULL) {
1399 		    *chosen = (uintptr_t)prefdisks[i]->obj;
1400 		}
1401 	    }
1402 	}
1403 
1404 	for (i = 0; i < maxuses; i++) {
1405 	    dlist_free_items(prefhbas[i], NULL);
1406 	}
1407 	for (i = 0; i < maxslices; i++) {
1408 	    dlist_free_items(prefdisks[i], NULL);
1409 	}
1410 
1411 	free((void*)prefhbas);
1412 	free((void*)prefdisks);
1413 
1414 	return (error);
1415 }
1416 
1417 /*
1418  * FUNCTION:	slice_on_unique_hba(dm_descriptor_t slice,
1419  *			dlist_t *used, dlist_t *used_hbas,
1420  *			boolean_t *unique)
1421  *
1422  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1423  *		used	- a dlist_t pointer to a list of used slices
1424  *		used_hbas - a dlist_t pointer to a list of used_hbas
1425  *		unique	- a boolean_t pointer to hold the result
1426  *
1427  * RETURNS:	int	- 0 on success
1428  *			 !0 otherwise
1429  *
1430  * PURPOSE:	Determines if the input slice is connected thru the same HBA
1431  *		as a slice in the used list.
1432  *
1433  *		Also checks to see if the input slice is connected thru any
1434  *		HBA in the used_hbas list.
1435  *
1436  *		If the slice is found to be on a unique HBA, bool is set
1437  *		to B_TRUE, B_FALSE otherwise.
1438  */
1439 static int
1440 slice_on_unique_hba(
1441 	dm_descriptor_t	slice,
1442 	dlist_t		*used,
1443 	dlist_t		*used_hbas,
1444 	boolean_t	*unique)
1445 {
1446 	dlist_t		*iter	= NULL;
1447 	dlist_t		*iter1	= NULL;
1448 
1449 	dlist_t		*hbas = NULL;
1450 
1451 	int		error	= 0;
1452 
1453 	*unique = B_TRUE;
1454 
1455 	if ((error = slice_get_hbas(slice, &hbas)) != 0) {
1456 	    return (error);
1457 	}
1458 
1459 	/*
1460 	 * check to see if any of slice's HBAs is the same
1461 	 * as the HBA for any of the used
1462 	 */
1463 	for (iter = used;
1464 	    (iter != NULL) && (*unique == B_TRUE) && (error == 0);
1465 	    iter = iter->next) {
1466 
1467 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
1468 	    if (devconfig_isA(dev, TYPE_SLICE)) {
1469 
1470 		dm_descriptor_t	odisk = NULL;
1471 		char		*oname = NULL;
1472 		dlist_t		*ohbas = NULL;
1473 
1474 		/* get HBAs for other slice using its disk */
1475 		/* because the slice doesn't exist yet. */
1476 		((error = devconfig_get_name(dev, &oname)) != 0) ||
1477 		(error = get_disk_for_named_slice(oname, &odisk)) ||
1478 		(error = disk_get_hbas(odisk, &ohbas));
1479 
1480 		/* any HBA overlap? */
1481 		for (iter1 = hbas;
1482 		    (iter1 != NULL) && (*unique == B_TRUE) && (error == 0);
1483 		    iter1 = iter1->next) {
1484 
1485 		    if (dlist_contains(ohbas, iter1->obj,
1486 				compare_descriptor_names) == B_TRUE) {
1487 			*unique = B_FALSE;
1488 		    }
1489 		}
1490 		dlist_free_items(ohbas, NULL);
1491 	    }
1492 	}
1493 
1494 	/*
1495 	 * check to see if any of slice's HBAs is the contained
1496 	 * in the list of used hbas
1497 	 */
1498 	for (iter = hbas;
1499 	    (iter != NULL) && (*unique == B_TRUE) && (error == 0);
1500 	    iter = iter->next) {
1501 	    if (dlist_contains(used_hbas,
1502 		iter->obj, compare_descriptor_names) == B_TRUE) {
1503 		*unique = B_FALSE;
1504 	    }
1505 	}
1506 
1507 	dlist_free_items(hbas, NULL);
1508 
1509 	return (error);
1510 }
1511 
1512 /*
1513  * FUNCTION:	slice_on_unique_disk(dm_descriptor_t slice,
1514  *			dlist_t *used, dlist_t *used_disks,
1515  *			boolean_t *unique)
1516  *
1517  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1518  *		used	- a dlist_t pointer to a list of used slices
1519  *		othervols - a dlist_t pointer to a list of other volumes
1520  *		bool	- a boolean_t pointer to hold the result
1521  *
1522  * RETURNS:	int	- 0 on success
1523  *			 !0 otherwise
1524  *
1525  * PURPOSE:	Determines if the input slice is on a drive that is not
1526  *		part of any volume in the othervols list, or on the same
1527  *		drive as any slice in the used list.
1528  *
1529  *		If the slice is found to be on a unique disk, bool is set
1530  *		to B_TRUE, B_FALSE otherwise.
1531  */
1532 static int
1533 slice_on_unique_disk(
1534 	dm_descriptor_t	slice,
1535 	dlist_t		*used,
1536 	dlist_t		*used_disks,
1537 	boolean_t	*unique)
1538 {
1539 	dm_descriptor_t	disk = NULL;
1540 	dlist_t		*iter = NULL;
1541 	int		error = 0;
1542 
1543 	*unique = B_TRUE;
1544 
1545 	if ((error = slice_get_disk(slice, &disk)) != 0) {
1546 	    return (error);
1547 	}
1548 
1549 	/*
1550 	 * check to see if this disk is the same as the
1551 	 * disk for any of the used
1552 	 */
1553 	for (iter = used;
1554 	    (iter != NULL) && (*unique == B_TRUE) && (error == 0);
1555 	    iter = iter->next) {
1556 
1557 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
1558 
1559 	    if (devconfig_isA(dev, TYPE_SLICE)) {
1560 
1561 		/* get disk for otherslice */
1562 		dm_descriptor_t	odisk = NULL;
1563 		char		*oname = NULL;
1564 
1565 		((error = devconfig_get_name(dev, &oname)) != 0) ||
1566 		(error = get_disk_for_named_slice(oname, &odisk));
1567 
1568 		if ((error == 0) &&
1569 			(compare_descriptor_names((void*)(uintptr_t)disk,
1570 			    (void*)(uintptr_t)odisk) == 0)) {
1571 		    /* origslice is on same disk, stop */
1572 		    *unique = B_FALSE;
1573 		}
1574 	    }
1575 	}
1576 
1577 	/* check disk against the used disks */
1578 	if ((error == 0) && (*unique == B_TRUE) &&
1579 		dlist_contains(used_disks, (void *)(uintptr_t)disk,
1580 			compare_descriptor_names) == B_TRUE) {
1581 		*unique = B_FALSE;
1582 	}
1583 
1584 	return (error);
1585 }
1586 
1587 /*
1588  * FUNCTION:	slice_has_same_disk_geom(dm_descriptor_t slice,
1589  *			dlist_t *used, boolean_t *has_same_geom)
1590  *
1591  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1592  *		used	- a dlist_t pointer to a list of used slices
1593  *		bool	- a boolean_t pointer to hold the result
1594  *
1595  * RETURNS:	int	- 0 on success
1596  *			 !0 otherwise
1597  *
1598  * PURPOSE:	Determines if the input slice is on a drive with similar
1599  *		hardware geometry as the slices in the used list.
1600  *
1601  *		If the slice is found to be on a disk with similar geometry,
1602  *		bool is set to B_TRUE, B_FALSE otherwise.
1603  *
1604  *		The comparison is based on the available disk geometry
1605  *		information which may not be relevant or accurate for
1606  *		EFI labeled disks, so the disk drive type needs to be
1607  *		checked	as well.
1608  */
1609 static int
1610 slice_has_same_disk_geom(
1611 	dm_descriptor_t	slice,
1612 	dlist_t		*used,
1613 	boolean_t	*has_same_geom)
1614 {
1615 	dm_descriptor_t	disk = NULL;
1616 	boolean_t	efi = B_FALSE;
1617 	uint64_t	bsize	= 0;
1618 	uint64_t	ncyls	= 0;
1619 	uint64_t	nsects	= 0;
1620 	uint64_t	nheads	= 0;
1621 	dlist_t		*iter	= NULL;
1622 	int		error	= 0;
1623 
1624 	*has_same_geom = B_TRUE;
1625 
1626 	((error = slice_get_disk(slice, &disk)) != 0) ||
1627 	(error = disk_get_is_efi(disk, &efi)) ||
1628 	(error = disk_get_blocksize(disk, &bsize));
1629 
1630 	if ((error == 0) && (efi == B_FALSE)) {
1631 	    ((error = disk_get_ncylinders(disk, &ncyls)) != 0) ||
1632 	    (error = disk_get_nheads(disk, &nheads)) ||
1633 	    (error = disk_get_nsectors(disk, &nsects));
1634 	}
1635 
1636 	if (error != 0) {
1637 	    return (error);
1638 	}
1639 
1640 	/*
1641 	 * check to see if slice's disk has the same geometry
1642 	 * as the disks for the slices in the used list
1643 	 */
1644 	for (iter = used;
1645 	    (iter != NULL) && (*has_same_geom == B_TRUE) && (error = 0);
1646 	    iter = iter->next) {
1647 
1648 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
1649 
1650 	    if (devconfig_isA(dev, TYPE_SLICE)) {
1651 
1652 		/* get disk info for otherslice */
1653 		dm_descriptor_t	odisk	= NULL;
1654 		char		*oname	= NULL;
1655 		boolean_t	oefi = B_FALSE;
1656 		uint64_t	obsize	= 0;
1657 		uint64_t	oncyls	= 0;
1658 		uint64_t	onsects = 0;
1659 		uint64_t	onheads = 0;
1660 
1661 		((error = devconfig_get_name(dev, &oname)) != 0) ||
1662 		(error = get_disk_for_named_slice(oname, &odisk)) ||
1663 		(error = disk_get_is_efi(odisk, &oefi)) ||
1664 		(error = disk_get_blocksize(odisk, &obsize));
1665 
1666 		if ((error == 0) && (oefi == B_FALSE)) {
1667 		    ((error = disk_get_ncylinders(odisk, &oncyls)) != 0) ||
1668 		    (error = disk_get_nheads(odisk, &onheads)) ||
1669 		    (error = disk_get_nsectors(odisk, &onsects));
1670 		}
1671 
1672 		if (error == 0) {
1673 		    if ((bsize != obsize) || (ncyls != oncyls) ||
1674 			(nsects != onsects) || (nheads != onheads)) {
1675 			/* this disk has a different geometry */
1676 			*has_same_geom = B_FALSE;
1677 		    }
1678 		}
1679 	    }
1680 	}
1681 
1682 	return (error);
1683 }
1684 
1685 /*
1686  * FUNCTION:	slice_on_similar_bus(dm_descriptor_t slice,
1687  *			dlist_t *used, boolean_t *on_smlr_bus)
1688  *
1689  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1690  *		used	- a dlist_t pointer to a list of used slices
1691  *		bool	- a boolean_t pointer to hold the result
1692  *
1693  * RETURNS:	int	- 0 on success
1694  *			 !0 otherwise
1695  *
1696  * PURPOSE:	Determines if the input slice is connected thru a bus with
1697  *		characteristics similar to the slices in the used list.
1698  *
1699  *		If the slice is found to be on a similar bus, bool is set
1700  *		to B_TRUE, B_FALSE otherwise.
1701  *
1702  *		The comparison is actually between any of the HBA/controllers
1703  *		thru which the slices are connected to the system.
1704  *		If any are of similar type (e.g., fibre, SCSI) and
1705  *		protocol (SCSI-2, -3, fast/wide), then the slices are
1706  *		considered to be on similar busses.
1707  */
1708 static int
1709 slice_on_similar_bus(
1710 	dm_descriptor_t	slice,
1711 	dlist_t		*used,
1712 	boolean_t	*on_smlr_bus)
1713 {
1714 	dlist_t		*iter	= NULL;
1715 	dlist_t		*iter1	= NULL;
1716 	dlist_t		*hbas = NULL;
1717 	int		error	= 0;
1718 
1719 	/* if there are no used slices, then the bus is similar */
1720 	*on_smlr_bus = B_TRUE;
1721 	if (dlist_length(used) == 0) {
1722 	    return (0);
1723 	}
1724 
1725 	(error = slice_get_hbas(slice, &hbas));
1726 	if (error != 0) {
1727 	    return (error);
1728 	}
1729 
1730 	/* if there are used slices, then make sure the bus is similar */
1731 	*on_smlr_bus = B_FALSE;
1732 	for (iter = hbas;
1733 	    (iter != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0);
1734 	    iter = iter->next) {
1735 
1736 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
1737 	    char	*type	= NULL;
1738 	    boolean_t	fast80	= B_FALSE;
1739 	    boolean_t	fast40	= B_FALSE;
1740 	    boolean_t	fast20	= B_FALSE;
1741 	    boolean_t	wide	= B_FALSE;
1742 
1743 	    ((error = hba_get_type(hba, &type)) != 0) ||
1744 	    (error = hba_is_fast_80(hba, &fast80)) ||
1745 	    (error = hba_is_fast_40(hba, &fast40)) ||
1746 	    (error = hba_is_fast_20(hba, &fast20)) ||
1747 	    (error = hba_supports_wide(hba, &wide));
1748 	    if (error != 0) {
1749 		continue;
1750 	    }
1751 
1752 	    /* check against the HBAs for the used slices */
1753 	    for (iter1 = used;
1754 		(iter1 != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0);
1755 		iter1 = iter1->next) {
1756 
1757 		devconfig_t *used = (devconfig_t *)iter1->obj;
1758 
1759 		/* get HBAs for otherslice */
1760 		dm_descriptor_t	udisk = NULL;
1761 		char		*uname = NULL;
1762 		dlist_t		*uhbas = NULL;
1763 		dlist_t		*iter2 = NULL;
1764 
1765 		((error = devconfig_get_name(used, &uname)) != 0) ||
1766 		(error = get_disk_for_named_slice(uname, &udisk)) ||
1767 		(error = disk_get_hbas(udisk, &uhbas));
1768 
1769 		for (iter2 = uhbas;
1770 		    (iter2 != NULL) && (*on_smlr_bus == B_FALSE) &&
1771 			(error == 0);
1772 		    iter2 = iter2 ->next) {
1773 
1774 		    dm_descriptor_t uhba = (uintptr_t)iter2->obj;
1775 		    char		*utype	= NULL;
1776 		    boolean_t	ufast80	= B_FALSE;
1777 		    boolean_t	ufast40	= B_FALSE;
1778 		    boolean_t	ufast20	= B_FALSE;
1779 		    boolean_t	uwide	= B_FALSE;
1780 
1781 		    ((error = hba_get_type(uhba, &utype)) != 0) ||
1782 		    (error = hba_is_fast_80(uhba, &ufast80)) ||
1783 		    (error = hba_is_fast_40(uhba, &ufast40)) ||
1784 		    (error = hba_is_fast_20(uhba, &ufast20)) ||
1785 		    (error = hba_supports_wide(uhba, &uwide));
1786 
1787 		    if (error == 0) {
1788 			/* check sync speed ? */
1789 			if ((fast80 == ufast80) && (fast40 == ufast40) &&
1790 			    (fast20 == ufast20) && (wide == uwide) &&
1791 			    (type == utype)) {
1792 			    *on_smlr_bus = B_TRUE;
1793 			}
1794 		    }
1795 		}
1796 		dlist_free_items(uhbas, NULL);
1797 	    }
1798 	}
1799 
1800 	dlist_free_items(hbas, NULL);
1801 
1802 	return (error);
1803 }
1804 
1805 /*
1806  * FUNCTION:	slice_has_n_paths(dm_descriptor_t slice,
1807  *			uint16_t npaths, boolean_t *has_n_paths)
1808  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1809  * 		npaths	- the number of paths desired
1810  *		has_n_paths - a boolean_t pointer to hold the result
1811  *
1812  * RETURNS:	int	- 0 on success
1813  *			 !0 otherwise
1814  *
1815  * PURPOSE:	Determines if the input slice is connected via npaths.
1816  *		has_n_paths is set to B_TRUE if so, B_FALSE otherwise.
1817  *
1818  *		In order for a disk to have multiple paths, MPXIO must
1819  *		be enabled and these conditions should hold:
1820  *
1821  *			Slice will have one drive object.
1822  *			Drive will have one HBA (scsi_vhci)
1823  *			Drive will have one alias.
1824  *			Drive will have possibly > 1 paths.
1825  *
1826  *		Getting the HBAs and aliases for the disk is relatively
1827  *		expensive, so they aren't checked.  The actual number of
1828  *		paths is only checked if MPXIO is known to be enabled on
1829  *		the system and the input npaths is > 1.
1830  */
1831 static int
1832 slice_has_n_paths(
1833 	dm_descriptor_t	slice,
1834 	uint16_t	npaths,
1835 	boolean_t	*has_n_paths)
1836 {
1837 	int		error	= 0;
1838 
1839 	*has_n_paths = B_FALSE;
1840 
1841 	if ((npaths > 1) && (is_mpxio_enabled() == B_TRUE)) {
1842 
1843 	    dm_descriptor_t	disk	= NULL;
1844 	    dlist_t		*paths	= NULL;
1845 
1846 	    ((error = slice_get_disk(slice, &disk)) != 0) ||
1847 	    (error = disk_get_paths(disk, &paths));
1848 
1849 	    if ((error == 0) && (dlist_length(paths) == npaths)) {
1850 		*has_n_paths = B_TRUE;
1851 	    }
1852 	    dlist_free_items(paths, NULL);
1853 	}
1854 
1855 	return (error);
1856 }
1857 
1858 /*
1859  * FUNCTION:	compare_string_to_modslice_name(void *str, void *modslice)
1860  *
1861  * INPUT:	str	- opaque char * pointer
1862  * 		modslice - opaque modslice_t pointer
1863  *
1864  * RETURNS:	int	- <0 - if str < modslice->slice_devcfg.name
1865  *			   0 - if str == modslice->slice_devcfg.name
1866  *			  >0 - if str > modslice->slice_devcfg.name
1867  *
1868  * PURPOSE:	dlist_t helper which compares the input string to
1869  *		the name of a slice represented as modslice_t struct.
1870  *
1871  *		Comparison is done via string_case_compare.
1872  */
1873 static int
1874 compare_string_to_modslice_name(
1875 	void		*str,
1876 	void		*modslice)
1877 {
1878 	char		*name = NULL;
1879 
1880 	assert(str != NULL);
1881 	assert(modslice != NULL);
1882 
1883 	(void) devconfig_get_name(
1884 		((modslice_t *)modslice)->slice_devcfg, &name);
1885 
1886 	return (string_case_compare((char *)str, name));
1887 }
1888 
1889 /*
1890  * FUNCTION:	compare_modslice_names(void *obj1, void *obj2)
1891  *
1892  * INPUT:	obj1	- opaque pointer
1893  * 		obj2	- opaque pointer
1894  *
1895  * RETURNS:	int	- <0 - if obj1 name < obj2 name
1896  *			   0 - if obj1 name == obj2 name
1897  *			  >0 - if obj1 name > obj2 name
1898  *
1899  * PURPOSE:	dlist_t helper which compares the names of two slices
1900  *		represented as modslice_t structs.
1901  *
1902  *		Comparison is done by string_case_compare
1903  */
1904 static int
1905 compare_modslice_names(
1906 	void		*obj1,
1907 	void		*obj2)
1908 {
1909 	char		*name1 = NULL;
1910 	char		*name2 = NULL;
1911 
1912 	assert(obj1 != NULL);
1913 	assert(obj2 != NULL);
1914 
1915 	(void) devconfig_get_name(
1916 		((modslice_t *)obj1)->slice_devcfg, &name1);
1917 	(void) devconfig_get_name(
1918 		((modslice_t *)obj2)->slice_devcfg, &name2);
1919 
1920 	return (string_case_compare(name1, name2));
1921 }
1922 
1923 /*
1924  * FUNCTION:	release_used_slices()
1925  *
1926  * PURPOSE:	Helper which cleans up the module private list of used
1927  *		slices.
1928  */
1929 void
1930 release_used_slices()
1931 {
1932 	dlist_free_items(_used_slices, free_used_slice);
1933 	_used_slices = NULL;
1934 }
1935 
1936 static void
1937 free_used_slice(
1938 	void *obj)
1939 {
1940 	if (obj != NULL) {
1941 	    usedslice_t *used = (usedslice_t *)obj;
1942 	    free(used->slicename);
1943 	    free(used);
1944 	}
1945 }
1946 
1947 /*
1948  * FUNCTION:	is_used_slice(dm_descriptor_t slice, boolean_t *is_used)
1949  *
1950  * INPUT:	slice	- a dm_descriptor_t slice handle
1951  *
1952  * OUTPUT:	is_reserved - pointer to a boolean_t to hold the
1953  *			return result.
1954  *
1955  * PURPOSE:	Helper which checks to see if the input slice
1956  *		is in the used_slice list.
1957  *
1958  *		Check the input name against any used slice name or alias.
1959  *		is_used is set to B_TRUE if the	input slice is already used,
1960  *		B_FALSE otherwise.
1961  */
1962 int
1963 is_used_slice(
1964 	dm_descriptor_t	slice,
1965 	boolean_t	*is_used)
1966 {
1967 	char	*name;
1968 	int	error = 0;
1969 
1970 	if ((error = get_display_name(slice, &name)) == 0) {
1971 	    *is_used = dlist_contains(_used_slices, (void *)name,
1972 		    compare_usedslice_name_to_string);
1973 	}
1974 
1975 	return (error);
1976 }
1977 
1978 /*
1979  * FUNCTIONS:	add_used_slice(dm_descriptor_t slice)
1980  *		add_used_slice_by_name(char *slicename)
1981  *		add_used_slice_list_entry(char *slice)
1982  *		remove_used_slice_by_name(char *slicename)
1983  *
1984  * INPUT:	diskset	- a char * diskset name.
1985  *		slice	- a dm_descriptor_t slice handle
1986  *
1987  * RETURNS:	int	- 0 on success
1988  *			 !0 otherwise
1989  *
1990  * PURPOSE:	Access or maintain the list of used slices.
1991  */
1992 int
1993 add_used_slice(
1994 	dm_descriptor_t	slice)
1995 {
1996 	dm_descriptor_t disk;
1997 	char	*name;
1998 	int	error = 0;
1999 
2000 	assert(slice != (dm_descriptor_t)0);
2001 
2002 	((error = get_display_name(slice, &name)) != 0) ||
2003 	(error = slice_get_disk(slice, &disk)) ||
2004 	(error = add_used_slice_list_entry(name, disk));
2005 
2006 	return (error);
2007 }
2008 
2009 int
2010 add_used_slice_by_name(
2011 	char	*slicename)
2012 {
2013 	dm_descriptor_t disk = (dm_descriptor_t)0;
2014 	int	error = 0;
2015 
2016 	assert(slicename != NULL);
2017 
2018 	/* find disk for slice */
2019 	error = get_disk_for_named_slice(slicename, &disk);
2020 	if (error == 0) {
2021 	    error = add_used_slice_list_entry(slicename, disk);
2022 	}
2023 
2024 	return (error);
2025 }
2026 
2027 static int
2028 add_used_slice_list_entry(
2029 	char	*slicename,
2030 	dm_descriptor_t	disk)
2031 {
2032 	usedslice_t *used = NULL;
2033 	int	error = 0;
2034 
2035 	assert(slicename != NULL);
2036 	assert(disk != (dm_descriptor_t)0);
2037 
2038 	used = (usedslice_t *)calloc(1, sizeof (usedslice_t));
2039 	if (used == NULL) {
2040 	    error = ENOMEM;
2041 	} else {
2042 
2043 	    used->disk = disk;
2044 	    if ((used->slicename = strdup(slicename)) == NULL) {
2045 		free(used);
2046 		error = ENOMEM;
2047 	    } else {
2048 		dlist_t *item = dlist_new_item((void *) used);
2049 		if (item == NULL) {
2050 		    free(used->slicename);
2051 		    free(used);
2052 		    error = ENOMEM;
2053 		} else {
2054 		    _used_slices =
2055 			dlist_append(item, _used_slices, AT_HEAD);
2056 		}
2057 	    }
2058 	}
2059 	return (error);
2060 }
2061 
2062 int
2063 remove_used_slice_by_name(
2064 	char	*slice)
2065 {
2066 	dlist_t *removed = NULL;
2067 
2068 	_used_slices =
2069 	    dlist_remove_equivalent_item(_used_slices, (void *)slice,
2070 		    compare_usedslice_name_to_string, &removed);
2071 
2072 	if (removed != NULL) {
2073 	    free_used_slice(removed->obj);
2074 	    removed->obj = NULL;
2075 	    free(removed);
2076 	}
2077 
2078 	return (0);
2079 }
2080 
2081 /*
2082  * FUNCTION:	compare_usedslice_name_to_string(void *obj1, void *obj2)
2083  * INPUT:	obj1	- opaque pointer
2084  * 		obj2	- opaque pointer
2085  *
2086  * RETURNS:	int	- <0 - if obj1 name < obj2 name
2087  *			   0 - if obj1 name == obj2 name
2088  *			  >0 - if obj1 name > obj2 name
2089  *
2090  * PURPOSE:	dlist_t helper which compares the names of a slice
2091  *		represented as modslice_t struct to a string.
2092  *
2093  *		obj1 is assumed to be a char *
2094  *		obj2 is assumed to be a usedslice_t *
2095  *
2096  *		Comparison is done via string_case_compare.
2097  */
2098 static int
2099 compare_usedslice_name_to_string(
2100 	void		*obj1,
2101 	void		*obj2)
2102 {
2103 	assert(obj1 != NULL);
2104 	assert(obj2 != NULL);
2105 
2106 	return (string_case_compare((char *)obj1,
2107 			((usedslice_t *)obj2)->slicename));
2108 }
2109 
2110 /*
2111  * FUNCTION:	disk_has_used_slice(dm_descriptor_t disk, boolean_t *hasused)
2112  *
2113  * INPUT:	disk	- a dm_descriptor_t disk handle.
2114  *		inuse	- a boolean_t pointer to hold the result
2115  *
2116  * RETURNS:	int	- 0 on success
2117  *			 !0 othersize.
2118  *
2119  * PURPOSE:	Determines if any of the known used slices is on the
2120  *		input disk.
2121  */
2122 int
2123 disk_has_used_slice(
2124 	dm_descriptor_t disk,
2125 	boolean_t	*hasused)
2126 {
2127 	dlist_t		*iter;
2128 	int		error = 0;
2129 
2130 	*hasused = B_FALSE;
2131 	for (iter = _used_slices;
2132 	    (iter != NULL) && (*hasused == B_FALSE);
2133 	    iter = iter->next) {
2134 
2135 	    usedslice_t *used = (usedslice_t *)iter->obj;
2136 
2137 	    /* compare used slice's disk to disk */
2138 	    if (compare_descriptors((void *)(uintptr_t)disk,
2139 		(void *)(uintptr_t)used->disk) == 0) {
2140 		*hasused = B_TRUE;
2141 	    }
2142 	}
2143 
2144 	return (error);
2145 }
2146 
2147 /*
2148  * FUNCTION:	add_reserved_slice(dm_descriptor_t slice)
2149  *
2150  * INPUT:	slice	- a dm_descriptor_t slice handle
2151  *
2152  * RETURNS:	int	- 0 on success
2153  *			 !0 otherwise.
2154  *
2155  * PURPOSE:	Helper which remembers specfically requested slices
2156  *		in a private list to ensure that the same slice isn't
2157  *		requested more than once.
2158  *
2159  *		Does not check to see if the slice already exists
2160  *		in the list of reserved slices. Assumes that the
2161  *		caller has checked using is_reserved_slice().
2162  *
2163  *		The reserved slice list is used by several functions:
2164  *
2165  *		1. layout_validate.validate_slice_components() adds user
2166  *		   requested slices to the list.
2167  *
2168  *		2. After all potentially usable slices have been scanned,
2169  *		   layout_validate.validate_reserved_slices() checks the
2170  *		   slices in the reserved and ensures that each slice is
2171  *		   actually usable as a volume component.
2172  *
2173  *		3. layout.disk_get_avail_space(), layout.disk_get_avail_slices()
2174  *		   exclude slices in the reserved list from being considered
2175  *		   available for general layout use.
2176  */
2177 int
2178 add_reserved_slice(
2179 	dm_descriptor_t	slice)
2180 {
2181 	dlist_t	*item = NULL;
2182 
2183 	if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) {
2184 	    return (ENOMEM);
2185 	}
2186 
2187 	_rsvd_slices = dlist_append(item, _rsvd_slices, AT_HEAD);
2188 
2189 	return (0);
2190 }
2191 
2192 /*
2193  * FUNCTION:	is_reserved_slice(dm_descriptor_t slice,
2194  *			boolean_t *is_reserved)
2195  *
2196  * INPUT:	slice	- a dm_descriptor_t slice handle
2197  *
2198  * OUTPUT:	is_reserved - pointer to a boolean_t to hold the
2199  *			return result.
2200  *
2201  * PURPOSE:	Helper which checks to see if the input slice
2202  *		was previously reserved.
2203  *
2204  *		Check the input name against any reserved slice
2205  *		name or alias. is_reserved is set to B_TRUE if the
2206  *		input slice is already reserved, B_FALSE otherwise.
2207  */
2208 int
2209 is_reserved_slice(
2210 	dm_descriptor_t	slice,
2211 	boolean_t	*is_reserved)
2212 {
2213 	*is_reserved = dlist_contains(_rsvd_slices,
2214 	    (void *)(uintptr_t)slice, compare_descriptor_names);
2215 
2216 	return (0);
2217 }
2218 
2219 /*
2220  * FUNCTION:	release_reserved_slice()
2221  *
2222  * PURPOSE:	Helper which cleans up the module private list of reserved
2223  *		slices.
2224  */
2225 void
2226 release_reserved_slices()
2227 {
2228 	dlist_free_items(_rsvd_slices, free);
2229 	_rsvd_slices = NULL;
2230 }
2231 
2232 /*
2233  * FUNCTION:	get_reserved_slices(dlist_t **list)
2234  *
2235  * OUTPUT:	list	- a dlist_t pointer to hold the returned list of
2236  *			reserverd slices.
2237  *
2238  * RETURNS:	int	- 0 on success
2239  *			 !0 otherwise
2240  *
2241  * PURPOSE:	Accessor to retrieve the current list of reserved slice
2242  *		dm_descriptor_t handles.
2243  */
2244 int
2245 get_reserved_slices(
2246 	dlist_t **list)
2247 {
2248 	*list = _rsvd_slices;
2249 
2250 	return (0);
2251 }
2252 
2253 /*
2254  * FUNCTION:	add_slice_to_remove(char *name, uint32_t index)
2255  *
2256  * INPUT:	name	-	name of a slice
2257  *		index	-	index for the slice
2258  *
2259  * RETURNS:	int	- 0 on success
2260  *			 !0 otherwise
2261  *
2262  * PURPOSE:	Utility function to add the named slice to the list of
2263  *		those that need to be "removed" by having their sizes
2264  *		set to 0.
2265  */
2266 int
2267 add_slice_to_remove(
2268 	char		*name,
2269 	uint32_t	index)
2270 {
2271 	rmvdslice_t *rmvd = NULL;
2272 	int	error = 0;
2273 
2274 	assert(name != NULL);
2275 
2276 	rmvd = (rmvdslice_t *)calloc(1, sizeof (rmvdslice_t));
2277 	if (rmvd == NULL) {
2278 	    error = ENOMEM;
2279 	} else {
2280 	    rmvd->slice_index = index;
2281 	    if ((rmvd->slice_name = strdup(name)) == NULL) {
2282 		free(rmvd);
2283 		error = ENOMEM;
2284 	    } else {
2285 		dlist_t *item = dlist_new_item((void *) rmvd);
2286 		if (item == NULL) {
2287 		    free(rmvd->slice_name);
2288 		    free(rmvd);
2289 		    error = ENOMEM;
2290 		} else {
2291 		    _rmvd_slices =
2292 			dlist_append(item, _rmvd_slices, AT_HEAD);
2293 		}
2294 	    }
2295 	}
2296 	return (error);
2297 }
2298 
2299 /*
2300  * FUNCTION:	get_removed_slices()
2301  *
2302  * RETURNS:	dlist_t * - pointer to a list of rmvdslice_t structs
2303  *
2304  * PURPOSE:	Accessor to retrieve the current list of names of slices
2305  *		to be removed.
2306  */
2307 dlist_t *
2308 get_slices_to_remove(
2309 	dlist_t **list)
2310 {
2311 	return (_rmvd_slices);
2312 }
2313 
2314 static void
2315 free_rmvd_slice(
2316 	void *obj)
2317 {
2318 	if (obj != NULL) {
2319 	    rmvdslice_t *rmvd = (rmvdslice_t *)obj;
2320 	    free(rmvd->slice_name);
2321 	    free(rmvd);
2322 	}
2323 }
2324 
2325 /*
2326  * FUNCTION:	release_removed_slices()
2327  *
2328  * PURPOSE:	Helper which cleans up the module private list of removed
2329  *		slices.
2330  */
2331 void
2332 release_slices_to_remove()
2333 {
2334 	dlist_free_items(_rmvd_slices, free_rmvd_slice);
2335 	_rmvd_slices = NULL;
2336 }
2337