xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_svm_util.c (revision d7cd82522afdd890a66c7600b499590ad44e84bd)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <assert.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 
34 #include <meta.h>
35 #include <sdssc.h>
36 #include <mdiox.h>
37 #include <meta_repartition.h>
38 
39 #include "volume_dlist.h"
40 #include "volume_error.h"
41 #include "volume_output.h"
42 
43 #include "layout_device_util.h"
44 #include "layout_discovery.h"
45 #include "layout_dlist_util.h"
46 #include "layout_request.h"
47 #include "layout_svm_util.h"
48 
49 static int	_max_hsps = 1000;	/* # of HSPs (arbitrary limit) */
50 static int	_max_devs = 8192;	/* # of SVM volumes allowed */
51 static int	_max_devs_cfg = 128;	/* # of SVM volumes configured */
52 static int	_max_sets = 4;		/* # of SVM disk sets */
53 
54 /* volume name prefixes for generating new names */
55 static const char	*_hsp_prefix	= "hsp";
56 static const char	*_dev_prefix	= "d";
57 
58 /*
59  * dynamically allocated arrays to track used HSP (hspXXX) and volume
60  * names (dXXX) by number
61  */
62 static	boolean_t	*hsps_by_number	= NULL;
63 static	boolean_t	*devs_by_number	= NULL;
64 
65 /*
66  * This struct remembers a diskset and the names of
67  * the disks in the set
68  */
69 typedef struct {
70 	char	*name;
71 	dlist_t	*disknames;
72 	dlist_t	*hsps;
73 } diskset_t;
74 
75 /*
76  * list of diskset_t for known disksets
77  */
78 static dlist_t	*_disksets = NULL;
79 
80 static int add_diskset(
81 	char *diskset);
82 
83 static int add_diskset_diskname(
84 	char *diskset,
85 	char *diskname);
86 
87 static int add_diskset_hsp(
88 	char *diskset,
89 	char *hspname);
90 
91 static int add_diskset_hsp_spare(
92 	char *diskset,
93 	char *hspname,
94 	char *spare);
95 
96 static int is_disk_in_local_diskset(
97 	dm_descriptor_t	disk,
98 	boolean_t	*bool);
99 
100 static int is_disk_in_named_diskset(
101 	dm_descriptor_t	disk,
102 	char		*dsname,
103 	boolean_t	*bool);
104 
105 /* SVM snapshot stuff */
106 typedef enum {
107 	SVM_DISKSET = 0,
108 	SVM_MDB,
109 	SVM_STRIPE,
110 	SVM_MIRROR,
111 	SVM_RAID,
112 	SVM_TRANS,
113 	SVM_SP,
114 	SVM_HSP,
115 	SVM_HS,
116 	SVM_DRIVE
117 } svm_type_t;
118 
119 typedef struct svm_snap_entry {
120 	struct svm_snap_entry	*next;
121 	char			*diskset;
122 	svm_type_t		type;
123 	char			*name;
124 	char			*slice;
125 } svm_snap_t;
126 
127 static svm_snap_t	*svm_snapshot(int *errp);
128 static void	free_svm_snapshot(svm_snap_t *listp);
129 
130 static char	*type_name(svm_type_t type);
131 static int	add_record(
132 	svm_snap_t **listp,
133 	char	*setname,
134 	svm_type_t type,
135 	char	*mname,
136 	char	*slice_name);
137 static int	diskset_info(svm_snap_t **listp, mdsetname_t *sp);
138 static void	free_names(mdnamelist_t *nlp);
139 static int	load_svm(svm_snap_t **listp);
140 static int	new_entry(
141 	svm_snap_t **listp,
142 	char	*sname,
143 	svm_type_t type,
144 	char	*mname,
145 	mdsetname_t *sp);
146 
147 /*
148  * FUNCTION:	scan_svm_names(char *diskset)
149  *
150  * INPUT:	diskset	- a char * disk set name
151  *
152  * PURPOSE:	Take a snapshot of the current SVM config.
153  *
154  *		Scan it and remember:
155  *		1. all known disk sets
156  * 		s. the disks in the named disk set
157  *		3. the used device and HSP names in the named disk set
158  *		4. the HSPs in the disk set
159  *		5. the spares in the HSPs
160  */
161 int
scan_svm_names(char * diskset)162 scan_svm_names(
163 	char	*diskset)
164 {
165 	int		ndisks = 0;
166 	int		nhsps = 0;
167 	int		ndevices = 0;
168 	int		nsets = 0;
169 
170 	int		number = 0;
171 	int		error = 0;
172 	svm_snap_t	*headp = NULL;
173 	svm_snap_t	*listp = NULL;
174 	char		*tablefmt = "  %-20s %-10s %-20s %-10s\n";
175 
176 	oprintf(OUTPUT_TERSE,
177 		gettext("\nScanning system SVM configuration...\n"));
178 
179 	headp = svm_snapshot(&error);
180 	if (error != 0) {
181 	    oprintf(OUTPUT_TERSE,
182 		    gettext("failed to scan SVM devices\n"));
183 	    return (error);
184 	}
185 
186 	if (error == 0) {
187 	    if ((error = get_max_number_of_devices(&_max_devs_cfg)) == 0) {
188 		oprintf(OUTPUT_VERBOSE,
189 			gettext("  configured maximum number of "
190 				"volumes: %d\n"),
191 			_max_devs_cfg);
192 	    }
193 	}
194 
195 	if (error == 0) {
196 	    if ((error = get_max_number_of_disksets(&_max_sets)) == 0) {
197 		oprintf(OUTPUT_VERBOSE,
198 			gettext("  configured maximum number of "
199 				"disk sets: %d\n"),
200 			_max_sets);
201 	    }
202 	}
203 
204 	if (error == 0) {
205 	    /* array is realloc'ed as necessary */
206 	    if ((hsps_by_number =
207 		(boolean_t *)calloc(_max_hsps, sizeof (boolean_t))) == NULL) {
208 		oprintf(OUTPUT_TERSE,
209 			gettext("failed to allocate HSP name array\n"));
210 		error = ENOMEM;
211 	    }
212 	}
213 
214 	if (error == 0) {
215 	    /* array is realloc'ed as necessary */
216 	    if ((devs_by_number =
217 		(boolean_t *)calloc(_max_devs, sizeof (boolean_t))) == NULL) {
218 		oprintf(OUTPUT_TERSE,
219 			gettext("failed to allocate volume name array\n"));
220 		error = ENOMEM;
221 	    }
222 	}
223 
224 	if ((error == 0) && (get_max_verbosity() >= OUTPUT_DEBUG)) {
225 	    (void) oprintf(OUTPUT_DEBUG, "\n");
226 	    (void) oprintf(OUTPUT_DEBUG,
227 		    tablefmt,
228 		    gettext("disk set"),
229 		    gettext("dev type"),
230 		    gettext("name"),
231 		    gettext("slice"));
232 	    (void) oprintf(OUTPUT_DEBUG,
233 		    "  -----------------------------------"
234 		    "-----------------------------------\n");
235 	}
236 
237 	for (listp = headp; listp != NULL && error == 0; listp = listp->next) {
238 
239 	    oprintf(OUTPUT_DEBUG,
240 		    tablefmt,
241 		    listp->diskset,
242 		    type_name(listp->type),
243 		    listp->name,
244 		    listp->slice);
245 
246 	    switch (listp->type) {
247 	    case SVM_DISKSET:
248 
249 		error = add_diskset(listp->name);
250 		++nsets;
251 		break;
252 
253 	    case SVM_DRIVE:
254 
255 		error = add_diskset_diskname(listp->diskset, listp->name);
256 
257 		/* is this drive in the requested diskset? */
258 		if (string_case_compare(diskset, listp->diskset) == 0) {
259 		    ++ndisks;
260 		}
261 		break;
262 
263 	    case SVM_MIRROR:
264 	    case SVM_RAID:
265 	    case SVM_TRANS:
266 	    case SVM_SP:
267 	    case SVM_STRIPE:
268 
269 		/* is this SVM volume in the requested diskset? */
270 		if (string_case_compare(diskset, listp->diskset) == 0) {
271 
272 		    /* isolate device name from "poolname/dXXXX" */
273 		    char *cp = strrchr(listp->name, '/');
274 		    if (cp != NULL) {
275 			++cp;
276 		    } else {
277 			cp = listp->name;
278 		    }
279 
280 		    /* BEGIN CSTYLED */
281 		    /*
282 		     * names for requested devices and HSPs are remembered
283 		     * so that the default name generation scheme knows
284 		     * which names are already being used
285 		     */
286 		    /* END CSTYLED */
287 		    /* extract device number from name "dXXXX" */
288 		    if (sscanf(cp, "d%d", &number) != EOF) {
289 			oprintf(OUTPUT_DEBUG,
290 				gettext("  device: %6s   number: %3d\n"),
291 				cp, number);
292 
293 			if (number > _max_devs) {
294 			    /* hit current limit, expand it */
295 			    boolean_t *tmp =
296 				(boolean_t *)realloc((void *)_max_devs,
297 					(number * sizeof (boolean_t)));
298 
299 			    if (tmp == NULL) {
300 				error = ENOMEM;
301 			    } else {
302 				_max_devs = number;
303 				devs_by_number = tmp;
304 			    }
305 			}
306 
307 			if ((error == 0) &&
308 				(devs_by_number[number] == B_FALSE)) {
309 			    devs_by_number[number] = B_TRUE;
310 			    ++ndevices;
311 			}
312 		    }
313 		}
314 		break;
315 
316 	    case SVM_HSP:
317 
318 		/* is this HSP in the requested diskset? */
319 		if (string_case_compare(diskset, listp->diskset) == 0) {
320 
321 		    /* isolate HSP name from "poolname/hspXXX" */
322 		    char *cp = strrchr(listp->name, '/');
323 		    if (cp != NULL) {
324 			++cp;
325 		    } else {
326 			cp = listp->name;
327 		    }
328 
329 		    /* extract pool number from name "hspXXX" */
330 		    if (sscanf(cp, "hsp%03d", &number) != EOF) {
331 			oprintf(OUTPUT_DEBUG,
332 				gettext("     HSP: %6s   number: %3d\n"),
333 				cp, number);
334 
335 			if (number > _max_hsps) {
336 			    /* hit our arbitrary limit, double it */
337 			    boolean_t *tmp =
338 				(boolean_t *)realloc((void *)hsps_by_number,
339 					2 * _max_hsps * sizeof (boolean_t));
340 
341 			    if (tmp != NULL) {
342 				_max_hsps *= 2;
343 				hsps_by_number = tmp;
344 			    } else {
345 				error = ENOMEM;
346 			    }
347 			}
348 
349 			if ((error == 0) &&
350 				(hsps_by_number[number] == B_FALSE)) {
351 			    hsps_by_number[number] = B_TRUE;
352 			    error = add_diskset_hsp(diskset, cp);
353 			    ++nhsps;
354 			}
355 		    }
356 		}
357 
358 		break;
359 
360 	    case SVM_HS:
361 
362 		/* is this hot spare in the requested disk set? */
363 		if (string_case_compare(diskset, listp->diskset) == 0) {
364 
365 		    /* isolate HSP name from "poolname/hspXXXX" */
366 		    char *cp = strrchr(listp->name, '/');
367 		    if (cp != NULL) {
368 			++cp;
369 		    } else {
370 			cp = listp->name;
371 		    }
372 
373 		    error = add_diskset_hsp_spare(diskset, cp, listp->slice);
374 		}
375 		break;
376 
377 	    case SVM_MDB:
378 	    default:
379 		break;
380 	    }
381 	}
382 
383 	free_svm_snapshot(headp);
384 
385 	if (error == 0) {
386 	    /* available diskset?  subtract 1 for the local set */
387 	    if ((diskset_exists(diskset) != B_TRUE) &&
388 		(nsets >= _max_sets)) {
389 		volume_set_error(
390 			gettext("Disk set \"%s\" cannot be created, the "
391 				"maximum number of disk sets (%d) already "
392 				"exists.\n"),
393 			diskset, _max_sets);
394 		error = -1;
395 	    }
396 	}
397 
398 	if (error == 0) {
399 	    oprintf(OUTPUT_VERBOSE,
400 		    gettext("\n  Disk set \"%s\" has:\n\n"), diskset);
401 	    oprintf(OUTPUT_VERBOSE,
402 		    gettext("    %d drives\n"), ndisks);
403 	    oprintf(OUTPUT_VERBOSE,
404 		    gettext("    %d volumes\n"), ndevices);
405 	    oprintf(OUTPUT_VERBOSE,
406 		    gettext("    %d HSPs\n"), nhsps);
407 	} else {
408 	    free(hsps_by_number);
409 	    free(devs_by_number);
410 	    hsps_by_number = (boolean_t *)NULL;
411 	    devs_by_number = (boolean_t *)NULL;
412 	}
413 
414 	return (error);
415 }
416 
417 /*
418  * FUNCTION:	release_svm_names()
419  *
420  * PURPOSE:	Release snapshot of the current SVM config.
421  *
422  *		Free memory allocated by scan_svm_names()
423  */
424 void
release_svm_names()425 release_svm_names()
426 {
427 	dlist_t *iter;
428 
429 	for (iter = _disksets; iter != NULL; iter = iter->next) {
430 	    diskset_t *diskset = (diskset_t *)iter->obj;
431 	    dlist_free_items(diskset->disknames, free);
432 	    dlist_free_items(diskset->hsps, free_devconfig);
433 	    free(diskset->name);
434 	}
435 	dlist_free_items(_disksets, free);
436 	_disksets = NULL;
437 
438 	if (hsps_by_number != NULL)
439 	    free(hsps_by_number);
440 	if (devs_by_number != NULL)
441 	    free(devs_by_number);
442 
443 	hsps_by_number = (boolean_t *)NULL;
444 	devs_by_number = (boolean_t *)NULL;
445 }
446 
447 /*
448  * FUNCTION:	diskset_exists(char *diskset)
449  *
450  * INPUT:	dsname	- a char * diskset name
451  *
452  * RETURNS:	boolean_t - B_TRUE if the named diskset exists
453  *			 B_FALSE otherwise
454  *
455  * PURPOSE:	Checks the list of known disk sets and determines
456  *		if the input name is in that list.
457  */
458 boolean_t
diskset_exists(char * dsname)459 diskset_exists(
460 	char	*dsname)
461 {
462 	dlist_t *iter;
463 
464 	for (iter = _disksets; iter != NULL; iter = iter->next) {
465 	    diskset_t *diskset = (diskset_t *)iter->obj;
466 	    if (string_case_compare(dsname, diskset->name) == 0) {
467 		return (B_TRUE);
468 	    }
469 	}
470 
471 	return (B_FALSE);
472 }
473 
474 /*
475  * FUNCTION:	add_diskset(char *dsname)
476  *
477  * INPUT:	dsname	- a char * disk set name
478  *
479  * RETURNS:	int	- 0 on success
480  *			 !0 otherwise
481  *
482  * PURPOSE:	Add the named disk set to the list of known disk sets.
483  */
484 static int
add_diskset(char * dsname)485 add_diskset(
486 	char	*dsname)
487 {
488 	dlist_t	*iter;
489 	int	error = 0;
490 
491 	for (iter = _disksets; iter != NULL; iter = iter->next) {
492 	    diskset_t *diskset = (diskset_t *)iter->obj;
493 	    if (string_case_compare(diskset->name, dsname) == 0) {
494 		break;
495 	    }
496 	}
497 
498 	if (iter == NULL) {
499 
500 	    dlist_t *item = NULL;
501 	    diskset_t *diskset = (diskset_t *)calloc(1, sizeof (diskset_t));
502 
503 	    if (diskset == NULL) {
504 		error = ENOMEM;
505 	    } else {
506 		diskset->hsps = NULL;
507 		diskset->name = strdup(dsname);
508 		if (diskset->name == NULL) {
509 		    free(diskset);
510 		    error = ENOMEM;
511 		} else {
512 		    if ((item = dlist_new_item(diskset)) == NULL) {
513 			free(diskset->name);
514 			free(diskset);
515 			error = ENOMEM;
516 		    } else {
517 			_disksets = dlist_append(item, _disksets, AT_HEAD);
518 			oprintf(OUTPUT_DEBUG,
519 				gettext("  added disk set %s \n"), dsname);
520 		    }
521 		}
522 	    }
523 	}
524 
525 	return (error);
526 }
527 
528 /*
529  * FUNCTION:	add_diskset_diskname(char *diskset, char *diskname)
530  *
531  * INPUT:	dsname	- a char * disk set name
532  *		diskname - a char * disk name
533  *
534  * RETURNS:	int	- 0 on success
535  *			 !0 otherwise
536  *
537  * PURPOSE:	Add the disk name to the named disk set's list of disks.
538  *
539  *		The input diskname is fully qualified with the path
540  *		to the raw disk device (/dev/rdsk/cXtXdXsX) which is
541  *		not relevant, so it is removed.
542  */
543 static int
add_diskset_diskname(char * dsname,char * diskname)544 add_diskset_diskname(
545 	char	*dsname,
546 	char	*diskname)
547 {
548 	dlist_t *iter;
549 	int error = 0;
550 
551 	for (iter = _disksets; iter != NULL; iter = iter->next) {
552 
553 	    diskset_t *diskset = (diskset_t *)iter->obj;
554 	    if (string_case_compare(diskset->name, dsname) == 0) {
555 
556 		dlist_t *item = NULL;
557 		char *name = NULL;
558 		char *cp = NULL;
559 
560 		/* trim leading path */
561 		if ((cp = strrchr(diskname, '/')) != 0) {
562 		    if ((name = strdup(cp+1)) == NULL) {
563 			error = ENOMEM;
564 		    }
565 		} else if ((name = strdup(diskname)) == NULL) {
566 		    error = ENOMEM;
567 		}
568 
569 		if ((item = dlist_new_item(name)) == NULL) {
570 		    free(name);
571 		    error = ENOMEM;
572 		} else {
573 		    diskset->disknames =
574 			dlist_append(item, diskset->disknames, AT_HEAD);
575 		}
576 
577 		break;
578 	    }
579 	}
580 
581 	if ((error == 0) && (iter == NULL)) {
582 	    /* new disk set */
583 	    if ((error = add_diskset(dsname)) == 0) {
584 		return (add_diskset_diskname(dsname, diskname));
585 	    }
586 	}
587 
588 	return (error);
589 }
590 
591 /*
592  * FUNCTION:	add_diskset_hsp(char *dsname, char *hspname)
593  *
594  * INPUT:	dsname	- a char * disk set name
595  *		hspname	- a char * HSP name
596  *
597  * RETURNS:	int	- 0 on success
598  *			 !0 otherwise
599  *
600  * PURPOSE:	Model a new HSP for the named disk set.
601  *
602  *		Metassist can use existing HSPs to service new volumes.
603  *
604  *		It is necessary to have a model of what HSPs currently
605  *		exist for each disk set.
606  *
607  *		This function takes information found during discovery
608  *		and turns it into a form usable by the HSP layout code.
609  */
610 static int
add_diskset_hsp(char * dsname,char * hspname)611 add_diskset_hsp(
612 	char	*dsname,
613 	char	*hspname)
614 {
615 	dlist_t	*iter;
616 	int	error = 0;
617 
618 	for (iter = _disksets; iter != NULL; iter = iter->next) {
619 
620 	    diskset_t	*diskset = (diskset_t *)iter->obj;
621 
622 	    if (string_case_compare(diskset->name, dsname) == 0) {
623 
624 		dlist_t		*item = NULL;
625 		devconfig_t	*hsp = NULL;
626 
627 		if (((error = new_devconfig(&hsp, TYPE_HSP)) != 0) ||
628 		    (error = devconfig_set_name(hsp, hspname))) {
629 		    free_devconfig(hsp);
630 		} else {
631 		    if ((item = dlist_new_item(hsp)) == NULL) {
632 			free_devconfig(hsp);
633 			error = ENOMEM;
634 		    } else {
635 			diskset->hsps =
636 			    dlist_append(item, diskset->hsps, AT_TAIL);
637 
638 			oprintf(OUTPUT_DEBUG,
639 				gettext("  added %s to disk set %s\n"),
640 				hspname, dsname);
641 		    }
642 		}
643 		break;
644 	    }
645 	}
646 
647 	if ((error == 0) && (iter == NULL)) {
648 	    if ((error = add_diskset(dsname)) == 0) {
649 		return (add_diskset_hsp(dsname, hspname));
650 	    }
651 	}
652 
653 	return (error);
654 }
655 
656 /*
657  * FUNCTION:	add_diskset_hsp_spare(char *dsname, char *hspname,
658  *			char *sparename)
659  *
660  * INPUT:	dsname	- a char * diskset name
661  *		hspname	- a char * HSP name
662  *		sparename - a char * hot spare (slice) name
663  *
664  * RETURNS:	int	- 0 on success
665  *			 !0 otherwise
666  *
667  * PURPOSE:	Locate the named hot spare pool in the named disk set and
668  *		add the named spare slice to its list of spares.
669  *
670  *		Metassist can use existing HSPs to service new volumes.
671  *
672  *		It is necessary to have a model of what HSPs currently
673  *		exist for each disk set.
674  *
675  *		This function takes information found during discovery
676  *		and turns it into a form usable by the HSP layout code.
677  */
678 static int
add_diskset_hsp_spare(char * dsname,char * hspname,char * sparename)679 add_diskset_hsp_spare(
680 	char	*dsname,
681 	char	*hspname,
682 	char	*sparename)
683 {
684 	dlist_t	*iter;
685 	int	error = 0;
686 
687 	for (iter = _disksets; iter != NULL; iter = iter->next) {
688 
689 	    diskset_t	*diskset = (diskset_t *)iter->obj;
690 
691 	    if (string_case_compare(diskset->name, dsname) == 0) {
692 
693 		dlist_t *item =
694 		    dlist_find(
695 			    diskset->hsps, hspname,
696 			    compare_string_to_devconfig_name);
697 
698 		if (item != NULL) {
699 
700 		    /* add spare to HSP */
701 		    devconfig_t	*hsp = (devconfig_t *)item->obj;
702 		    dm_descriptor_t slice = (dm_descriptor_t)0;
703 
704 		    (void) slice_get_by_name(sparename, &slice);
705 		    if (slice == (dm_descriptor_t)0) {
706 			oprintf(OUTPUT_TERSE,
707 				gettext("warning: ignoring nonexistent "
708 					"slice %s defined in %s\n"),
709 				sparename, hspname);
710 		    } else {
711 
712 			uint64_t nbytes = 0;
713 			uint32_t index = 0;
714 			devconfig_t *spare = NULL;
715 
716 			/* build a devconfig_t model of the slice */
717 			if (((error = slice_get_size(slice, &nbytes)) != 0) ||
718 			    (error = slice_get_index(slice, &index)) ||
719 			    (error = new_devconfig(&spare, TYPE_SLICE)) ||
720 			    (error = devconfig_set_name(spare, sparename)) ||
721 			    (error = devconfig_set_size(spare, nbytes)) ||
722 			    (error = devconfig_set_slice_index(spare, index))) {
723 			    free_devconfig(spare);
724 			} else {
725 
726 			    if ((item = dlist_new_item(spare)) == NULL) {
727 				error = ENOMEM;
728 				free_devconfig(spare);
729 			    } else {
730 				dlist_t	*spares;
731 				spares = devconfig_get_components(hsp);
732 				spares = dlist_append(item, spares, AT_TAIL);
733 				devconfig_set_components(hsp, spares);
734 
735 				oprintf(OUTPUT_DEBUG,
736 					gettext("  added %s to %s in "
737 						"disk set %s\n"),
738 					sparename, hspname, dsname);
739 			    }
740 			}
741 		    }
742 
743 		    break;
744 
745 		} else {
746 		    if ((error = add_diskset_hsp(dsname, hspname)) == 0) {
747 			return (add_diskset_hsp_spare(
748 					dsname, hspname, sparename));
749 		    }
750 		}
751 	    }
752 	}
753 
754 	return (error);
755 }
756 
757 /*
758  * Return a list of disks in the given diskset.
759  *
760  * @param       dsname
761  *              The name of the named disk set, or "" for the local
762  *              set.
763  *
764  * @param       disks
765  *              RETURN: pointer to the list of disks in the given disk
766  *              set
767  *
768  * @return      0 if succesful, non-zero otherwise
769  */
770 int
get_disks_in_diskset(char * dsname,dlist_t ** disks)771 get_disks_in_diskset(
772 	char *dsname,
773 	dlist_t **disks)
774 {
775 	dlist_t *known_disks;
776 	int error = 0;
777 
778 	*disks = NULL;
779 
780 	if ((error = get_known_disks(&known_disks)) == 0) {
781 	    dlist_t *iter;
782 
783 	    /* For each known disk... */
784 	    for (iter = known_disks;
785 		iter != NULL && error == 0;
786 		iter = iter->next) {
787 		dm_descriptor_t disk = (uintptr_t)iter->obj;
788 		boolean_t in_diskset = B_FALSE;
789 
790 		/* If this disk is in the given set... */
791 		error = is_disk_in_diskset(disk, dsname, &in_diskset);
792 		if (error == 0 && in_diskset == B_TRUE) {
793 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
794 		    *disks = dlist_append(item, *disks, AT_TAIL);
795 		}
796 	    }
797 	}
798 
799 	return (error);
800 }
801 
802 /*
803  * FUNCTION:	is_disk_in_diskset(dm_descriptor_t disk, char *dsname,
804  *			boolean_t *bool)
805  *
806  * INPUT:	disk	- dm_descriptor_t disk handle
807  *		dsname	- char * diskset name, or MD_LOCAL_NAME for
808  *		the local set.
809  *
810  * OUTPUT:	bool	- pointer to a boolean_t to hold the result
811  *
812  * RETURNS:	int	- 0 on success
813  *			 !0 otherwise
814  *
815  * PURPOSE:	Determine if the input disk is known to be in the
816  *		given diskset.
817  */
818 int
is_disk_in_diskset(dm_descriptor_t disk,char * dsname,boolean_t * bool)819 is_disk_in_diskset(
820 	dm_descriptor_t	disk,
821 	char		*dsname,
822 	boolean_t	*bool)
823 {
824 	if (string_case_compare(dsname, MD_LOCAL_NAME) == 0) {
825 	    return (is_disk_in_local_diskset(disk, bool));
826 	}
827 
828 	return (is_disk_in_named_diskset(disk, dsname, bool));
829 }
830 
831 static int
is_disk_in_local_diskset(dm_descriptor_t disk,boolean_t * bool)832 is_disk_in_local_diskset(
833 	dm_descriptor_t	disk,
834 	boolean_t	*bool)
835 {
836 	dlist_t *iter;
837 	dlist_t *aliases = NULL;
838 	boolean_t in_named_diskset = B_FALSE;
839 	char *name = NULL;
840 	int error = 0;
841 
842 	*bool = B_FALSE;
843 
844 	error = get_display_name(disk, &name);
845 	if (error == 0) {
846 
847 	    error = get_aliases(disk, &aliases);
848 	    if (error == 0) {
849 
850 		/* For each known disk set... */
851 		for (iter = _disksets;
852 		    iter != NULL && in_named_diskset == B_FALSE;
853 		    iter = iter->next) {
854 
855 		    diskset_t *diskset = (diskset_t *)iter->obj;
856 		    dlist_t *names = diskset->disknames;
857 
858 		    /* Check disk name */
859 		    in_named_diskset = dlist_contains(
860 			names, name, compare_device_names);
861 
862 		    /* Check disk aliases */
863 		    if (in_named_diskset == B_FALSE) {
864 			dlist_t *iter2;
865 			for (iter2 = aliases;
866 			    iter2 != NULL && in_named_diskset == B_FALSE;
867 			    iter2 = iter2->next) {
868 			    in_named_diskset = dlist_contains(names,
869 				(char *)iter2->obj, compare_device_names);
870 			}
871 		    }
872 		}
873 	    }
874 	}
875 
876 	if (error == 0) {
877 	    *bool = (in_named_diskset == B_TRUE ? B_FALSE : B_TRUE);
878 	}
879 
880 	return (error);
881 }
882 
883 static int
is_disk_in_named_diskset(dm_descriptor_t disk,char * dsname,boolean_t * bool)884 is_disk_in_named_diskset(
885 	dm_descriptor_t	disk,
886 	char		*dsname,
887 	boolean_t	*bool)
888 {
889 	dlist_t		*iter;
890 	int		error = 0;
891 	boolean_t 	in_diskset = B_FALSE;
892 
893 	*bool = B_FALSE;
894 
895 	for (iter = _disksets;
896 	    (iter != NULL) && (in_diskset == B_FALSE);
897 	    iter = iter->next) {
898 
899 	    diskset_t *diskset = (diskset_t *)iter->obj;
900 
901 	    if (string_case_compare(diskset->name, dsname) == 0) {
902 
903 		dlist_t *names = diskset->disknames;
904 		dlist_t *aliases = NULL;
905 		char	*name = NULL;
906 
907 		((error = get_display_name(disk, &name)) != 0) ||
908 		(error = get_aliases(disk, &aliases));
909 		if (error != 0) {
910 		    break;
911 		}
912 
913 		/* check disk name */
914 		in_diskset = dlist_contains(names, name, compare_device_names);
915 
916 		/* check disk aliases */
917 		if (in_diskset == B_FALSE) {
918 		    dlist_t *iter2;
919 		    for (iter2 = aliases;
920 			(iter2 != NULL) && (in_diskset == B_FALSE);
921 			iter2 = iter2->next) {
922 			in_diskset = dlist_contains(names,
923 				(char *)iter2->obj, compare_device_names);
924 		    }
925 		}
926 	    }
927 	}
928 
929 	*bool = in_diskset;
930 
931 	return (error);
932 }
933 
934 /*
935  * FUNCTION:	is_disk_in_other_diskset(dm_descriptor_t disk, char *dsname,
936  *			boolean_t *bool)
937  *
938  * INPUT:	disk	- dm_descriptor_t disk handle
939  *		dsname	- char * disk set name
940  *
941  * OUTPUT:	bool	- pointer to a boolean_t to hold the result.
942  *
943  * RETURNS:	int	- 0 on success
944  *			 !0 otherwise
945  *
946  * PURPOSE:	Determine if the named disk is known to be in a disk set
947  *		other than the named disk set.
948  */
949 int
is_disk_in_other_diskset(dm_descriptor_t disk,char * dsname,boolean_t * bool)950 is_disk_in_other_diskset(
951 	dm_descriptor_t disk,
952 	char	*dsname,
953 	boolean_t *bool)
954 {
955 	boolean_t in_other = B_FALSE;
956 	dlist_t	*iter;
957 	dlist_t *aliases = NULL;
958 	char	*name = NULL;
959 	char	*cp = NULL;
960 	int	error = 0;
961 
962 	((error = get_display_name(disk, &name)) != 0) ||
963 	(error = get_aliases(disk, &aliases));
964 	if (error != 0) {
965 	    return (error);
966 	}
967 
968 	/*
969 	 * discard the leading path, it is probably /dev/dsk
970 	 * and the disk set disk names are all /dev/rdsk/...
971 	 *
972 	 * aliases do not have leading paths
973 	 */
974 	cp = strrchr(name, '/');
975 	if (cp != NULL) {
976 	    ++cp;
977 	} else {
978 	    cp = name;
979 	}
980 	name = cp;
981 
982 	for (iter = _disksets;
983 	    (iter != NULL) && (in_other == B_FALSE);
984 	    iter = iter->next) {
985 
986 	    diskset_t	*diskset = (diskset_t *)iter->obj;
987 	    dlist_t	*names = diskset->disknames;
988 
989 	    if (string_case_compare(diskset->name, dsname) == 0) {
990 		/* skip named disk set */
991 		continue;
992 	    }
993 
994 	    /* see if disk's name is in disk set's name list */
995 	    in_other = dlist_contains(names, name, compare_device_names);
996 
997 	    /* see if any of the disk's aliases is in name list */
998 	    if (in_other == B_FALSE) {
999 		dlist_t *iter2;
1000 		for (iter2 = aliases;
1001 		    (iter2 != NULL) && (in_other == B_FALSE);
1002 		    iter2 = iter2->next) {
1003 
1004 		    in_other = dlist_contains(names,
1005 			    (char *)iter2->obj, compare_device_names);
1006 		}
1007 	    }
1008 	}
1009 
1010 	*bool = in_other;
1011 
1012 	return (error);
1013 }
1014 
1015 /*
1016  * FUNCTION:	hsp_get_default_for_diskset(char *diskset,
1017  *			devconfig_t **hsp)
1018  *
1019  * INPUT:	diskset	- char * disk set name
1020  *
1021  * RETURNS:	devconfig_t * - pointer to the first HSP in the disk set
1022  *			NULL if none found
1023  *
1024  * PURPOSE:	Locate the first HSP in the named disk set.
1025  */
1026 int
hsp_get_default_for_diskset(char * diskset,devconfig_t ** hsp)1027 hsp_get_default_for_diskset(
1028 	char	*diskset,
1029 	devconfig_t **hsp)
1030 {
1031 	dlist_t		*iter = _disksets;
1032 
1033 	*hsp = NULL;
1034 
1035 	for (; (iter != NULL) && (*hsp == NULL); iter = iter->next) {
1036 	    diskset_t *set = (diskset_t *)iter->obj;
1037 	    if (string_case_compare(set->name, diskset) == 0) {
1038 		dlist_t *item = set->hsps;
1039 		if (item != NULL) {
1040 		    *hsp = item->obj;
1041 		}
1042 	    }
1043 	}
1044 
1045 	return (0);
1046 }
1047 
1048 /*
1049  * FUNCTION:	get_n_metadb_replicas(int *nreplicas)
1050  *
1051  * OUTPUT:	nreplicas - pointer to int to hold the result
1052  *
1053  * RETURNS:	int	- 0 on success
1054  *			 !0 on failure
1055  *
1056  * PURPOSE:	Check the number of replicas configured for the local set.
1057  */
1058 int
get_n_metadb_replicas(int * nreplicas)1059 get_n_metadb_replicas(
1060 	int	*nreplicas)
1061 {
1062 	mdsetname_t	*sp;
1063 	md_replicalist_t *rlp = NULL;
1064 	md_error_t	mderror = mdnullerror;
1065 	int		error = 0;
1066 
1067 	*nreplicas = 0;
1068 
1069 	sp = metasetname(MD_LOCAL_NAME, &mderror);
1070 	if (!mdisok(&mderror)) {
1071 	    volume_set_error(mde_sperror(&mderror, NULL));
1072 	    mdclrerror(&mderror);
1073 	    error = -1;
1074 	} else {
1075 	    *nreplicas = metareplicalist(sp, MD_BASICNAME_OK, &rlp, &mderror);
1076 	    if (!mdisok(&mderror)) {
1077 		volume_set_error(mde_sperror(&mderror, NULL));
1078 		mdclrerror(&mderror);
1079 		error = -1;
1080 	    } else if (rlp != NULL) {
1081 		metafreereplicalist(rlp);
1082 		rlp = NULL;
1083 	    }
1084 
1085 	    if (*nreplicas < 0) {
1086 		*nreplicas = 0;
1087 	    }
1088 	}
1089 
1090 	return (error);
1091 }
1092 
1093 /*
1094  * FUNCTION:	hsp_get_by_name(char *diskset, char *name,
1095  *		devconfig_t **hsp)
1096  *
1097  * INPUT:	diskset	- char * disk set name
1098  *		name	- char * HSP name
1099  *
1100  * OUTPUT:	hsp	- a devconfig_t * - pointer to hold
1101  *			  the named HSP if none found
1102  *
1103  * PURPOSE:	Locate the named HSP in the named disk set.
1104  */
1105 int
hsp_get_by_name(char * diskset,char * name,devconfig_t ** hsp)1106 hsp_get_by_name(
1107 	char		*diskset,
1108 	char		*name,
1109 	devconfig_t	**hsp)
1110 {
1111 	dlist_t		*iter = _disksets;
1112 
1113 	*hsp = NULL;
1114 
1115 	for (; (iter != NULL) && (*hsp == NULL); iter = iter->next) {
1116 	    diskset_t *set = (diskset_t *)iter->obj;
1117 	    if (string_case_compare(set->name, diskset) == 0) {
1118 		dlist_t *item = dlist_find(
1119 			set->hsps, name, compare_string_to_devconfig_name);
1120 		if (item != NULL) {
1121 		    *hsp = item->obj;
1122 		}
1123 	    }
1124 	}
1125 
1126 	return (0);
1127 }
1128 
1129 /*
1130  * FUNCTION:	is_volume_name_valid(char *name)
1131  *
1132  * OUTPUT:	name	- pointer to a char * volume name
1133  *
1134  * RETURNS:	boolean_t - B_TRUE if the input name is valid
1135  *			 B_FALSE otherwise
1136  *
1137  * PURPOSE:	Wrapper around libmeta volume name validation method.
1138  */
1139 boolean_t
is_volume_name_valid(char * name)1140 is_volume_name_valid(
1141 	char		*name)
1142 {
1143 	return (is_metaname(name));
1144 }
1145 
1146 /*
1147  * FUNCTION:	is_hsp_name_valid(char *name)
1148  *
1149  * INPUT:	name	- char * HSP name
1150  *
1151  * RETURNS:	boolean_t - B_TRUE if the input name is valid
1152  *			 B_FALSE otherwise
1153  *
1154  * PURPOSE:	Wrapper around libmeta HSP name validation method.
1155  */
1156 boolean_t
is_hsp_name_valid(char * name)1157 is_hsp_name_valid(
1158 	char		*name)
1159 {
1160 	return (is_hspname(name));
1161 }
1162 
1163 /*
1164  * FUNCTION:	extract_index(char *name, char *prefix, char *num_fmt,
1165  *			int *index)
1166  *
1167  * INPUT:	name	- const char * volume name
1168  *		prefix	- const char * fixed part of format string
1169  *		num_fmt	- const char * format of number to extract (e.g. %d)
1170  *
1171  * OUTPUT:	index	- pointer to int to hold numeric part of name
1172  *
1173  * RETURNS:	boolean_t - B_TRUE if the input name is parsed correctly
1174  *			 B_FALSE otherwise
1175  *
1176  * PURPOSE:	Extract the numeric portion of a device name for use
1177  *		by higher-level functions.
1178  */
1179 static boolean_t
extract_index(const char * name,const char * prefix,const char * num_fmt,int * index)1180 extract_index(
1181 	const char	*name,
1182 	const char	*prefix,
1183 	const char	*num_fmt,
1184 	int		*index)
1185 {
1186 	char		buf[MAXNAMELEN];
1187 	const char	*cp;
1188 	const char	*fmt = buf;
1189 
1190 	if ((cp = strrchr(name, '/')) != NULL) {
1191 	    ++cp;
1192 	} else {
1193 	    cp = name;
1194 	}
1195 
1196 	(void) snprintf(buf, sizeof (buf), "%s%s", prefix, num_fmt);
1197 	if (sscanf(cp, fmt, index) == 1)
1198 		return (B_TRUE);
1199 	else
1200 		return (B_FALSE);
1201 }
1202 
1203 /*
1204  * FUNCTION:	is_volume_name_in_range(char *name)
1205  *
1206  * INPUT:	name	- char * volume name
1207  *
1208  * RETURNS:	boolean_t - B_TRUE if the input name is in the allowed
1209  *				range of names
1210  *			 B_FALSE otherwise
1211  *
1212  * PURPOSE:	Determine if the input volume name is within the allowed
1213  *		range of device names (0 <= n < max # of devices configured).
1214  */
1215 boolean_t
is_volume_name_in_range(char * name)1216 is_volume_name_in_range(
1217 	char		*name)
1218 {
1219 	int		index = -1;
1220 
1221 	if (extract_index(name, _dev_prefix, "%d", &index)) {
1222 	    if (index >= 0 && index < _max_devs_cfg) {
1223 		return (B_TRUE);
1224 	    }
1225 	}
1226 
1227 	return (B_FALSE);
1228 }
1229 
1230 /*
1231  * FUNCTION:	reserve_volume_name(char *name)
1232  *
1233  * INPUT:	name	- a char * volume name
1234  *
1235  * RETURNS:	int	- 0 on success
1236  *			 !0 otherwise
1237  *
1238  * PURPOSE:	Mark a volume name/number as used.
1239  *
1240  *		Assumes that the input name has been validated.
1241  *
1242  *		if the name is not currently available, return -1
1243  */
1244 int
reserve_volume_name(char * name)1245 reserve_volume_name(
1246 	char		*name)
1247 {
1248 	int		index = -1;
1249 
1250 	if (extract_index(name, _dev_prefix, "%d", &index)) {
1251 	    if (devs_by_number[index] != B_TRUE) {
1252 		devs_by_number[index] = B_TRUE;
1253 		return (0);
1254 	    }
1255 	}
1256 
1257 	return (-1);
1258 }
1259 
1260 /*
1261  * FUNCTION:	reserve_hsp_name(char *name)
1262  *
1263  * INPUT:	name	- a char * hsp name
1264  *
1265  * RETURNS:	int	- 0 on success
1266  *			 !0 otherwise
1267  *
1268  * PURPOSE:	Mark a HSP name/number as used.
1269  *
1270  *		Assumes that the input name has been validated.
1271  *
1272  *		if the name is not currently available, return -1
1273  */
1274 int
reserve_hsp_name(char * name)1275 reserve_hsp_name(
1276 	char		*name)
1277 {
1278 	int		index = -1;
1279 
1280 	if (extract_index(name, _hsp_prefix, "%03d", &index)) {
1281 	    if (hsps_by_number[index] != B_TRUE) {
1282 		hsps_by_number[index] = B_TRUE;
1283 		return (0);
1284 	    }
1285 	}
1286 
1287 	return (-1);
1288 }
1289 
1290 /*
1291  * FUNCTION:	release_volume_name(char *name)
1292  *
1293  * INPUT:	name	- a char * volume name
1294  *
1295  * PURPOSE:	release the input volume name.
1296  *
1297  *		Extract volume number from the input name
1298  *		and use it to index into the array of used
1299  *		volume numbers.  Make that volume number
1300  *		available for use again.
1301  */
1302 void
release_volume_name(char * name)1303 release_volume_name(
1304 	char		*name)
1305 {
1306 	int		index = -1;
1307 
1308 	if (name != NULL && extract_index(name, _dev_prefix, "%d", &index)) {
1309 		oprintf(OUTPUT_DEBUG,
1310 			gettext("released volume name %s%d\n"),
1311 			_dev_prefix, index);
1312 		devs_by_number[index] = B_FALSE;
1313 	}
1314 }
1315 
1316 /*
1317  * FUNCTION:	release_hsp_name(char *name)
1318  *
1319  * INPUT:	name	- a char * HSP name
1320  *
1321  * PURPOSE:	release the input HSP name.
1322  *
1323  *		Extract volume number from the input name
1324  *		and use it to index into the array of used
1325  *		hsp numbers.  Make that hsp number available
1326  *		for use again.
1327  */
1328 void
release_hsp_name(char * name)1329 release_hsp_name(
1330 	char		*name)
1331 {
1332 	int		index = -1;
1333 
1334 	if (name != NULL && extract_index(name, _hsp_prefix, "%d", &index)) {
1335 		oprintf(OUTPUT_DEBUG,
1336 			gettext("released hsp name %s%d\n"),
1337 			_hsp_prefix, index);
1338 		hsps_by_number[index] = B_FALSE;
1339 	}
1340 }
1341 
1342 /*
1343  * FUNCTION:	get_next_volume_name(char **name)
1344  *
1345  * OUTPUT:	name	- pointer to a char * to hold volume name
1346  *
1347  * RETURNS:	int	- 0 on success
1348  *			 !0 otherwise
1349  *
1350  * PURPOSE:	generate a new volume name using the standard device
1351  *		name prefix and the lowest available device number.
1352  *
1353  *		if type == MIRROR, determine the next available mirror
1354  *		name according to the convention that a mirror name is
1355  *		a multiple of 10.
1356  *
1357  *		If such a name is unavailable, use the next available name.
1358  */
1359 int
get_next_volume_name(char ** name,component_type_t type)1360 get_next_volume_name(
1361     char		**name,
1362     component_type_t	type)
1363 {
1364 	int	next = 0;
1365 
1366 	for (next = 0; next < _max_devs_cfg; ++next) {
1367 	    if ((type == TYPE_MIRROR && ((next % 10) != 0)) ||
1368 		(type != TYPE_MIRROR && ((next % 10) == 0))) {
1369 		/* use/save multiples of 10 for mirrors */
1370 		continue;
1371 	    }
1372 	    if (devs_by_number[next] != B_TRUE) {
1373 		break;
1374 	    }
1375 	}
1376 
1377 	if ((next == _max_devs_cfg) && (type == TYPE_MIRROR)) {
1378 	    /* try next sequentially available name */
1379 	    for (next = 0; next < _max_devs_cfg; ++next) {
1380 		if (devs_by_number[next] != B_TRUE) {
1381 		    break;
1382 		}
1383 	    }
1384 	}
1385 
1386 	if (next == _max_devs_cfg) {
1387 	    volume_set_error(
1388 		    gettext("ran out of logical volume names.\n"));
1389 	    return (-1);
1390 	}
1391 
1392 	*name = (char *)calloc(MAXNAMELEN, sizeof (char));
1393 	if (*name == NULL) {
1394 	    return (ENOMEM);
1395 	}
1396 
1397 	(void) snprintf(*name, MAXNAMELEN-1, "%s%d", _dev_prefix, next);
1398 
1399 	devs_by_number[next] = B_TRUE;
1400 	return (0);
1401 }
1402 
1403 /*
1404  * FUNCTION:	get_next_submirror_name(char *mname, char **subname)
1405  *
1406  * INPUT:	mname	- pointer to a char * mirror name
1407  * OUTPUT:	subname	- pointer to a char * to hold submirror name
1408  *
1409  * RETURNS:	int	- 0 on success
1410  *			 !0 otherwise
1411  *
1412  * PURPOSE:	Determine the next available submirror name according
1413  *		to the convention that each submirror name is a sequential
1414  *		increment of its mirror's name.
1415  *
1416  *		If such a name is unavailable, return the next sequentially
1417  *		available volume name.
1418  */
1419 int
get_next_submirror_name(char * mname,char ** subname)1420 get_next_submirror_name(
1421 	char	*mname,
1422 	char	**subname)
1423 {
1424 	char	buf[MAXNAMELEN];
1425 	int 	error = 0;
1426 	int	next = 0;
1427 	int	i = 0;
1428 
1429 	*subname = NULL;
1430 
1431 	/* try next sequential name: mirror + 1... */
1432 	if (extract_index(mname, _dev_prefix, "%d", &next)) {
1433 	    for (i = next + 1; i < _max_devs_cfg; i++) {
1434 		if ((i % 10) == 0) {
1435 		    /* save for mirrors */
1436 		    continue;
1437 		}
1438 		if (devs_by_number[i] == B_FALSE) {
1439 		    (void) snprintf(buf, MAXNAMELEN-1, "%s%d", _dev_prefix, i);
1440 		    if ((*subname = strdup(buf)) != NULL) {
1441 			devs_by_number[i] = B_TRUE;
1442 		    } else {
1443 			error = ENOMEM;
1444 		    }
1445 		    break;
1446 		}
1447 	    }
1448 	}
1449 
1450 	if ((error == 0) && (*subname == NULL)) {
1451 	    /* name adhering to convention isn't available, */
1452 	    /* use next sequentially available name */
1453 	    error = get_next_volume_name(subname, TYPE_STRIPE);
1454 	}
1455 
1456 	return (error);
1457 }
1458 
1459 /*
1460  * FUNCTION:	get_next_hsp_name(char **name)
1461  *
1462  * OUTPUT:	name	- pointer to a char * to hold name
1463  *
1464  * RETURNS:	int	- 0 on success
1465  *			 !0 otherwise
1466  *
1467  * PURPOSE:	Helper which generates a new hotsparepool name
1468  *		using the standard name prefix and the lowest
1469  *		available hsp number.
1470  */
1471 int
get_next_hsp_name(char ** name)1472 get_next_hsp_name(
1473     char	**name)
1474 {
1475 	int	 next = 0;
1476 
1477 	for (next = 0; next < _max_hsps; ++next) {
1478 	    if (hsps_by_number[next] != B_TRUE) {
1479 		break;
1480 	    }
1481 	}
1482 
1483 	if (next == _max_hsps) {
1484 	    volume_set_error(gettext("ran out of HSP names"));
1485 	    return (-1);
1486 	}
1487 
1488 	*name = (char *)calloc(MAXNAMELEN, sizeof (char));
1489 	if (*name == NULL) {
1490 	    oprintf(OUTPUT_TERSE,
1491 		    gettext("failed to allocate volume name string, "
1492 			    "out of memory"));
1493 	    return (ENOMEM);
1494 	}
1495 
1496 	(void) snprintf(*name, MAXNAMELEN-1, "%s%03d", _hsp_prefix, next);
1497 
1498 	hsps_by_number[next] = B_TRUE;
1499 
1500 	return (0);
1501 }
1502 
1503 static char *
type_name(svm_type_t type)1504 type_name(
1505 	svm_type_t type)
1506 {
1507 	switch (type) {
1508 	case SVM_DISKSET:	return (gettext("disk set"));
1509 	case SVM_MDB:		return (gettext("metadb"));
1510 	case SVM_STRIPE:	return (gettext("stripe"));
1511 	case SVM_MIRROR:	return (gettext("mirror"));
1512 	case SVM_RAID:		return (gettext("raid"));
1513 	case SVM_TRANS:		return (gettext("trans"));
1514 	case SVM_SP:		return (gettext("soft partition"));
1515 	case SVM_HSP:		return (gettext("hot spare pool"));
1516 	case SVM_HS:		return (gettext("hot spare"));
1517 	case SVM_DRIVE:		return (gettext("drive"));
1518 	default:		return (gettext("unknown"));
1519 	}
1520 }
1521 
1522 static svm_snap_t *
svm_snapshot(int * errp)1523 svm_snapshot(int *errp)
1524 {
1525 	svm_snap_t	*svm_listp = NULL;
1526 
1527 	*errp = 0;
1528 
1529 	/* initialize the cluster library entry points */
1530 	if (sdssc_bind_library() == SDSSC_ERROR) {
1531 
1532 	    volume_set_error(gettext("sdssc_bin_library() failed\n"));
1533 	    *errp = -1;
1534 
1535 	} else {
1536 
1537 	    /* load the SVM cache */
1538 	    *errp = load_svm(&svm_listp);
1539 
1540 	    if (*errp != 0) {
1541 		free_svm_snapshot(svm_listp);
1542 		svm_listp = NULL;
1543 	    }
1544 
1545 	}
1546 
1547 	return (svm_listp);
1548 }
1549 
1550 static void
free_svm_snapshot(svm_snap_t * listp)1551 free_svm_snapshot(svm_snap_t *listp) {
1552 
1553 	svm_snap_t	*nextp;
1554 
1555 	while (listp != NULL) {
1556 	    nextp = listp->next;
1557 	    free((void *)listp->diskset);
1558 	    free((void *)listp->name);
1559 	    free((void *)listp->slice);
1560 	    free((void *)listp);
1561 	    listp = nextp;
1562 	}
1563 }
1564 
1565 static int
add_record(svm_snap_t ** listp,char * setname,svm_type_t type,char * mname,char * slice_name)1566 add_record(
1567 	svm_snap_t **listp,
1568 	char *setname,
1569 	svm_type_t type,
1570 	char *mname,
1571 	char *slice_name)
1572 {
1573 	svm_snap_t *sp;
1574 
1575 	sp = (svm_snap_t *)malloc(sizeof (svm_snap_t));
1576 	if (sp == NULL) {
1577 	    return (ENOMEM);
1578 	}
1579 
1580 	if ((sp->diskset = strdup(setname)) == NULL) {
1581 	    free(sp);
1582 	    return (ENOMEM);
1583 	}
1584 
1585 	if ((sp->name = strdup(mname)) == NULL) {
1586 	    free(sp->diskset);
1587 	    free(sp);
1588 	    return (ENOMEM);
1589 	}
1590 
1591 	sp->type = type;
1592 
1593 	if ((sp->slice = strdup(slice_name)) == NULL) {
1594 	    free(sp->diskset);
1595 	    free(sp->name);
1596 	    free(sp);
1597 	    return (ENOMEM);
1598 	}
1599 
1600 	sp->next = *listp;
1601 	*listp = sp;
1602 
1603 	return (0);
1604 }
1605 
1606 static int
diskset_info(svm_snap_t ** listp,mdsetname_t * sp)1607 diskset_info(
1608 	svm_snap_t **listp,
1609 	mdsetname_t *sp)
1610 {
1611 	md_error_t		error = mdnullerror;
1612 	md_replicalist_t	*replica_list = NULL;
1613 	md_replicalist_t	*mdbp;
1614 	mdnamelist_t		*nlp;
1615 	mdnamelist_t		*trans_list = NULL;
1616 	mdnamelist_t		*mirror_list = NULL;
1617 	mdnamelist_t		*raid_list = NULL;
1618 	mdnamelist_t		*stripe_list = NULL;
1619 	mdnamelist_t		*sp_list = NULL;
1620 	mdhspnamelist_t		*hsp_list = NULL;
1621 
1622 	if (metareplicalist(sp, MD_BASICNAME_OK, &replica_list, &error) < 0) {
1623 	    /* there are no metadb's; that is ok, no need to check the rest */
1624 	    mdclrerror(&error);
1625 	    return (0);
1626 	}
1627 	mdclrerror(&error);
1628 
1629 	for (mdbp = replica_list; mdbp != NULL; mdbp = mdbp->rl_next) {
1630 	    char size[MAXPATHLEN];
1631 
1632 	    (void) snprintf(size, sizeof (size), "%d",
1633 		    (int)mdbp->rl_repp->r_nblk);
1634 
1635 	    if (new_entry(listp, mdbp->rl_repp->r_namep->cname, SVM_MDB, size,
1636 		sp)) {
1637 		metafreereplicalist(replica_list);
1638 		return (ENOMEM);
1639 	    }
1640 	}
1641 	metafreereplicalist(replica_list);
1642 
1643 	if (meta_get_trans_names(sp, &trans_list, 0, &error) >= 0) {
1644 	    for (nlp = trans_list; nlp != NULL; nlp = nlp->next) {
1645 		if (new_entry(listp, nlp->namep->cname, SVM_TRANS,
1646 		    nlp->namep->cname, sp)) {
1647 		    free_names(trans_list);
1648 		    return (ENOMEM);
1649 		}
1650 	    }
1651 
1652 	    free_names(trans_list);
1653 	}
1654 	mdclrerror(&error);
1655 
1656 	if (meta_get_mirror_names(sp, &mirror_list, 0, &error) >= 0) {
1657 	    for (nlp = mirror_list; nlp != NULL; nlp = nlp->next) {
1658 		if (add_record(listp, sp->setname, SVM_MIRROR,
1659 		    nlp->namep->cname, "")) {
1660 		    free_names(mirror_list);
1661 		    return (ENOMEM);
1662 		}
1663 	    }
1664 
1665 	    free_names(mirror_list);
1666 	}
1667 	mdclrerror(&error);
1668 
1669 	if (meta_get_raid_names(sp, &raid_list, 0, &error) >= 0) {
1670 	    for (nlp = raid_list; nlp != NULL; nlp = nlp->next) {
1671 		mdname_t	*mdn;
1672 		md_raid_t	*raid;
1673 
1674 		mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
1675 		mdclrerror(&error);
1676 		if (mdn == NULL) {
1677 		    continue;
1678 		}
1679 
1680 		raid = meta_get_raid(sp, mdn, &error);
1681 		mdclrerror(&error);
1682 
1683 		if (raid != NULL) {
1684 		    int i;
1685 
1686 		    for (i = 0; i < raid->cols.cols_len; i++) {
1687 			if (new_entry(listp,
1688 			    raid->cols.cols_val[i].colnamep->cname, SVM_RAID,
1689 			    nlp->namep->cname, sp)) {
1690 			    free_names(raid_list);
1691 			    return (ENOMEM);
1692 			}
1693 		    }
1694 		}
1695 	    }
1696 
1697 	    free_names(raid_list);
1698 	}
1699 	mdclrerror(&error);
1700 
1701 	if (meta_get_stripe_names(sp, &stripe_list, 0, &error) >= 0) {
1702 	    for (nlp = stripe_list; nlp != NULL; nlp = nlp->next) {
1703 		mdname_t	*mdn;
1704 		md_stripe_t	*stripe;
1705 
1706 		mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
1707 		mdclrerror(&error);
1708 		if (mdn == NULL) {
1709 		    continue;
1710 		}
1711 
1712 		stripe = meta_get_stripe(sp, mdn, &error);
1713 		mdclrerror(&error);
1714 
1715 		if (stripe != NULL) {
1716 		    int i;
1717 
1718 		    for (i = 0; i < stripe->rows.rows_len; i++) {
1719 			md_row_t	*rowp;
1720 			int		j;
1721 
1722 			rowp = &stripe->rows.rows_val[i];
1723 
1724 			for (j = 0; j < rowp->comps.comps_len; j++) {
1725 			    md_comp_t	*component;
1726 
1727 			    component = &rowp->comps.comps_val[j];
1728 			    if (new_entry(listp, component->compnamep->cname,
1729 				SVM_STRIPE, nlp->namep->cname, sp)) {
1730 				free_names(stripe_list);
1731 				return (ENOMEM);
1732 			    }
1733 			}
1734 		    }
1735 		}
1736 	    }
1737 
1738 	    free_names(stripe_list);
1739 	}
1740 	mdclrerror(&error);
1741 
1742 	if (meta_get_sp_names(sp, &sp_list, 0, &error) >= 0) {
1743 	    for (nlp = sp_list; nlp != NULL; nlp = nlp->next) {
1744 		mdname_t	*mdn;
1745 		md_sp_t		*soft_part;
1746 
1747 		mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
1748 		mdclrerror(&error);
1749 		if (mdn == NULL) {
1750 		    continue;
1751 		}
1752 
1753 		soft_part = meta_get_sp(sp, mdn, &error);
1754 		mdclrerror(&error);
1755 
1756 		if (soft_part != NULL) {
1757 		    if (new_entry(listp, soft_part->compnamep->cname, SVM_SP,
1758 			nlp->namep->cname, sp)) {
1759 			free_names(sp_list);
1760 			return (ENOMEM);
1761 		    }
1762 		}
1763 	    }
1764 
1765 	    free_names(sp_list);
1766 	}
1767 	mdclrerror(&error);
1768 
1769 	if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) {
1770 	    mdhspnamelist_t *nlp;
1771 
1772 	    for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) {
1773 		md_hsp_t	*hsp;
1774 
1775 		hsp = meta_get_hsp(sp, nlp->hspnamep, &error);
1776 		mdclrerror(&error);
1777 		if (hsp != NULL) {
1778 		    int	i;
1779 
1780 		    for (i = 0; i < hsp->hotspares.hotspares_len; i++) {
1781 			md_hs_t	*hs;
1782 
1783 			hs = &hsp->hotspares.hotspares_val[i];
1784 
1785 			if (add_record(listp, sp->setname, SVM_HS,
1786 			    nlp->hspnamep->hspname, hs->hsnamep->bname)) {
1787 			    metafreehspnamelist(hsp_list);
1788 			    return (ENOMEM);
1789 			}
1790 		    }
1791 		}
1792 
1793 		if (add_record(listp, sp->setname, SVM_HSP,
1794 		    nlp->hspnamep->hspname, "")) {
1795 		    metafreehspnamelist(hsp_list);
1796 		    return (ENOMEM);
1797 		}
1798 	    }
1799 
1800 	    metafreehspnamelist(hsp_list);
1801 	}
1802 
1803 	mdclrerror(&error);
1804 
1805 	return (0);
1806 }
1807 
1808 static void
free_names(mdnamelist_t * nlp)1809 free_names(
1810 	mdnamelist_t *nlp)
1811 {
1812 	mdnamelist_t *p;
1813 
1814 	for (p = nlp; p != NULL; p = p->next) {
1815 	    meta_invalidate_name(p->namep);
1816 	}
1817 	metafreenamelist(nlp);
1818 }
1819 
1820 /*
1821  * Create a list of SVM devices
1822  */
1823 static int
load_svm(svm_snap_t ** listp)1824 load_svm(
1825 	svm_snap_t **listp)
1826 {
1827 	int		max_sets;
1828 	md_error_t	error = mdnullerror;
1829 	int		i;
1830 
1831 	if ((max_sets = get_max_sets(&error)) == 0) {
1832 	    return (0);
1833 	}
1834 
1835 	if (!mdisok(&error)) {
1836 	    volume_set_error(
1837 		    gettext("failed to get maximum number of disk sets.\n"));
1838 	    mdclrerror(&error);
1839 	    return (-1);
1840 	}
1841 
1842 	/* for each possible set number, see if we really have a disk set */
1843 	for (i = 0; i < max_sets; i++) {
1844 	    mdsetname_t		*sp;
1845 
1846 	    if ((sp = metasetnosetname(i, &error)) == NULL) {
1847 		if (!mdisok(&error) && error.info.errclass == MDEC_RPC) {
1848 		    /* rpc error - no metasets */
1849 		    break;
1850 		}
1851 
1852 		mdclrerror(&error);
1853 		continue;
1854 	    }
1855 
1856 	    mdclrerror(&error);
1857 
1858 	    if (add_record(listp, sp->setname, SVM_DISKSET, sp->setname, "")) {
1859 		metaflushsetname(sp);
1860 		return (ENOMEM);
1861 	    }
1862 
1863 	    /* check for drives in disk sets */
1864 	    if (sp->setno != 0) {
1865 		md_drive_desc	*dd;
1866 
1867 		dd = metaget_drivedesc(sp, MD_BASICNAME_OK | PRINT_FAST,
1868 		    &error);
1869 		mdclrerror(&error);
1870 		for (; dd != NULL; dd = dd->dd_next) {
1871 		    if (add_record(listp, sp->setname, SVM_DRIVE,
1872 			dd->dd_dnp->rname, "")) {
1873 			metaflushsetname(sp);
1874 			return (ENOMEM);
1875 		    }
1876 		}
1877 	    }
1878 
1879 	    if (diskset_info(listp, sp)) {
1880 		metaflushsetname(sp);
1881 		return (ENOMEM);
1882 	    }
1883 
1884 	    metaflushsetname(sp);
1885 	}
1886 
1887 	mdclrerror(&error);
1888 
1889 	return (0);
1890 }
1891 
1892 /* determine if 'sp' is built on a slice */
1893 static int
new_entry(svm_snap_t ** listp,char * slice_name,svm_type_t type,char * mname,mdsetname_t * sp)1894 new_entry(
1895 	svm_snap_t **listp,
1896 	char *slice_name,
1897 	svm_type_t type,
1898 	char *mname,
1899 	mdsetname_t *sp)
1900 {
1901 	mdname_t	*mdn;
1902 	md_error_t	 error = mdnullerror;
1903 	meta_device_type_t	uname_type = UNKNOWN;
1904 
1905 	/* Determine the appropriate uname type for metaname */
1906 	if (type == SVM_MDB || type == SVM_DRIVE || type == SVM_TRANS)
1907 		uname_type = LOGICAL_DEVICE;
1908 
1909 	mdn = metaname(&sp, slice_name, uname_type, &error);
1910 	if (!mdisok(&error)) {
1911 	    mdn = NULL;
1912 	}
1913 	mdclrerror(&error);
1914 
1915 	if (mdn != NULL && (
1916 	    mdn->drivenamep->type == MDT_ACCES ||
1917 	    mdn->drivenamep->type == MDT_COMP ||
1918 	    mdn->drivenamep->type == MDT_FAST_COMP)) {
1919 
1920 	    return (add_record(listp, sp->setname, type, mname, mdn->bname));
1921 	} else {
1922 	    return (add_record(listp, sp->setname, type, mname, ""));
1923 	}
1924 }
1925 
1926 /*
1927  * FUNCTION:	get_default_stripe_interlace()
1928  *
1929  * RETURNS:	uint64_t - default stripe interlace value
1930  *
1931  * PURPOSE:	Helper which retrieves the default stripe interlace
1932  *		from libmeta.
1933  */
1934 uint64_t
get_default_stripe_interlace()1935 get_default_stripe_interlace()
1936 {
1937 	/* convert back to bytes */
1938 	return ((uint64_t)meta_default_stripe_interlace() * DEV_BSIZE);
1939 }
1940 
1941 /*
1942  * FUNCTION:	get_max_number_of_devices(int *max)
1943  *
1944  * OUTPUT:	max	- pointer to int to hold the configured maximum number
1945  *				of SVM devices
1946  *
1947  * RETURNS:	int	- 0 on success
1948  *			 !0 otherwise
1949  *
1950  * PURPOSE:	Helper which determines the maximum number of allowed
1951  *		SVM devices configured for the system.
1952  *
1953  *		Wrapper around libmeta function meta_get_max_nunits().
1954  */
1955 int
get_max_number_of_devices(int * max)1956 get_max_number_of_devices(
1957 	int	*max)
1958 {
1959 	md_error_t	mderror = mdnullerror;
1960 
1961 	*max = meta_get_nunits(&mderror);
1962 	if (!mdisok(&mderror)) {
1963 	    volume_set_error(mde_sperror(&mderror, NULL));
1964 	    mdclrerror(&mderror);
1965 	    return (-1);
1966 	}
1967 
1968 	return (0);
1969 }
1970 
1971 /*
1972  * FUNCTION:	get_max_number_of_disksets(int *max)
1973  *
1974  * OUTPUT:	max	- pointer to in to hold the configured maximum number
1975  *				of disk sets
1976  *
1977  * RETURNS:	int	- 0 on success
1978  *			 !0 otherwise
1979  *
1980  * PURPOSE:	Helper which determines the maximum number of allowed
1981  *		disk sets which has been configured for the system.
1982  *
1983  *		Wrapper around libmeta function get_max_sets().
1984  */
1985 int
get_max_number_of_disksets(int * max)1986 get_max_number_of_disksets(
1987 	int	*max)
1988 {
1989 	md_error_t	mderror = mdnullerror;
1990 
1991 	*max = get_max_sets(&mderror);
1992 	if (!mdisok(&mderror)) {
1993 	    volume_set_error(mde_sperror(&mderror, NULL));
1994 	    mdclrerror(&mderror);
1995 	    return (-1);
1996 	}
1997 
1998 	return (0);
1999 }
2000 
2001 /*
2002  * FUNCTION:	is_reserved_replica_slice_index(char *diskset, char *dname,
2003  *			uint32_t index, boolean_t *bool)
2004  *
2005  * INPUT:	diskset	- char * disk set name
2006  *		dname	- char * disk name
2007  *		index	- integer index of interest
2008  *
2009  * OUTPUT:	bool	- pointer to a boolean_t to hold the result
2010  *
2011  * RETURNS:	int	-  0 - success
2012  *			  !0 - failure
2013  *
2014  * PURPOSE:	Helper which determines if the input slice index on
2015  *		the named disk in the named disk set is the replica
2016  *		slice that is reserved on disks in disk sets.
2017  *
2018  *		The named disk is assumed to be in the named disk set.
2019  *
2020  *		Determines if metassist is being run in a simulated
2021  *		hardware enironment, if not the libmeta function to
2022  *		determine the replica slice index is called.
2023  *
2024  *		If simulation is active, then a local implementation
2025  *		is used to determine the replica slice index.
2026  */
2027 int
is_reserved_replica_slice_index(char * diskset,char * dname,uint32_t index,boolean_t * bool)2028 is_reserved_replica_slice_index(
2029 	char *diskset,
2030 	char *dname,
2031 	uint32_t index,
2032 	boolean_t *bool)
2033 {
2034 	int		error = 0;
2035 	boolean_t	sim = B_FALSE;
2036 	static char	*simfile = "METASSISTSIMFILE";
2037 
2038 	sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0));
2039 
2040 	if (sim != B_TRUE) {
2041 
2042 	    /* sim disabled: use meta_replicaslice() */
2043 
2044 	    md_error_t		mderror = mdnullerror;
2045 	    mdsetname_t		*sp;
2046 	    mddrivename_t	*dnp;
2047 	    uint_t		replicaslice;
2048 
2049 	    /* slice assumed to be on disk in the named disk set */
2050 	    sp = metasetname(diskset, &mderror);
2051 	    if (!mdisok(&mderror)) {
2052 		volume_set_error(mde_sperror(&mderror, NULL));
2053 		mdclrerror(&mderror);
2054 		return (-1);
2055 	    }
2056 
2057 	    dnp = metadrivename(&sp, dname, &mderror);
2058 	    if (!mdisok(&mderror)) {
2059 		volume_set_error(mde_sperror(&mderror, NULL));
2060 		mdclrerror(&mderror);
2061 		return (-1);
2062 	    }
2063 
2064 	    if (meta_replicaslice(dnp, &replicaslice, &mderror) != 0) {
2065 		volume_set_error(mde_sperror(&mderror, NULL));
2066 		mdclrerror(&mderror);
2067 		return (-1);
2068 	    }
2069 
2070 	    *bool = (replicaslice == (uint_t)index);
2071 
2072 	} else {
2073 
2074 	    dm_descriptor_t	disk;
2075 	    boolean_t		efi = B_FALSE;
2076 
2077 	    /* sim enabled: use same logic as meta_replicaslice() */
2078 	    ((error = disk_get_by_name(dname, &disk)) != 0) ||
2079 	    (error = disk_get_is_efi(disk, &efi));
2080 	    if (error == 0) {
2081 
2082 		if (efi == B_FALSE) {
2083 		    *bool = (index == MD_SLICE7);
2084 		} else {
2085 		    *bool = (index == MD_SLICE6);
2086 		}
2087 	    }
2088 	}
2089 
2090 	return (error);
2091 }
2092