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