10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*1623Stw21770 * Common Development and Distribution License (the "License").
6*1623Stw21770 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*1623Stw21770 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <assert.h>
290Sstevel@tonic-gate #include <errno.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <meta.h>
350Sstevel@tonic-gate #include <sdssc.h>
360Sstevel@tonic-gate #include <mdiox.h>
370Sstevel@tonic-gate #include <meta_repartition.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include "volume_dlist.h"
400Sstevel@tonic-gate #include "volume_error.h"
410Sstevel@tonic-gate #include "volume_output.h"
420Sstevel@tonic-gate
430Sstevel@tonic-gate #include "layout_device_util.h"
440Sstevel@tonic-gate #include "layout_discovery.h"
450Sstevel@tonic-gate #include "layout_dlist_util.h"
460Sstevel@tonic-gate #include "layout_request.h"
470Sstevel@tonic-gate #include "layout_svm_util.h"
480Sstevel@tonic-gate
490Sstevel@tonic-gate static int _max_hsps = 1000; /* # of HSPs (arbitrary limit) */
500Sstevel@tonic-gate static int _max_devs = 8192; /* # of SVM volumes allowed */
510Sstevel@tonic-gate static int _max_devs_cfg = 128; /* # of SVM volumes configured */
520Sstevel@tonic-gate static int _max_sets = 4; /* # of SVM disk sets */
530Sstevel@tonic-gate
540Sstevel@tonic-gate /* volume name prefixes for generating new names */
550Sstevel@tonic-gate static const char *_hsp_prefix = "hsp";
560Sstevel@tonic-gate static const char *_dev_prefix = "d";
570Sstevel@tonic-gate
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate * dynamically allocated arrays to track used HSP (hspXXX) and volume
600Sstevel@tonic-gate * names (dXXX) by number
610Sstevel@tonic-gate */
620Sstevel@tonic-gate static boolean_t *hsps_by_number = NULL;
630Sstevel@tonic-gate static boolean_t *devs_by_number = NULL;
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * This struct remembers a diskset and the names of
670Sstevel@tonic-gate * the disks in the set
680Sstevel@tonic-gate */
690Sstevel@tonic-gate typedef struct {
700Sstevel@tonic-gate char *name;
710Sstevel@tonic-gate dlist_t *disknames;
720Sstevel@tonic-gate dlist_t *hsps;
730Sstevel@tonic-gate } diskset_t;
740Sstevel@tonic-gate
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate * list of diskset_t for known disksets
770Sstevel@tonic-gate */
780Sstevel@tonic-gate static dlist_t *_disksets = NULL;
790Sstevel@tonic-gate
800Sstevel@tonic-gate static int add_diskset(
810Sstevel@tonic-gate char *diskset);
820Sstevel@tonic-gate
830Sstevel@tonic-gate static int add_diskset_diskname(
840Sstevel@tonic-gate char *diskset,
850Sstevel@tonic-gate char *diskname);
860Sstevel@tonic-gate
870Sstevel@tonic-gate static int add_diskset_hsp(
880Sstevel@tonic-gate char *diskset,
890Sstevel@tonic-gate char *hspname);
900Sstevel@tonic-gate
910Sstevel@tonic-gate static int add_diskset_hsp_spare(
920Sstevel@tonic-gate char *diskset,
930Sstevel@tonic-gate char *hspname,
940Sstevel@tonic-gate char *spare);
950Sstevel@tonic-gate
960Sstevel@tonic-gate static int is_disk_in_local_diskset(
970Sstevel@tonic-gate dm_descriptor_t disk,
980Sstevel@tonic-gate boolean_t *bool);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate static int is_disk_in_named_diskset(
1010Sstevel@tonic-gate dm_descriptor_t disk,
1020Sstevel@tonic-gate char *dsname,
1030Sstevel@tonic-gate boolean_t *bool);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate /* SVM snapshot stuff */
1060Sstevel@tonic-gate typedef enum {
1070Sstevel@tonic-gate SVM_DISKSET = 0,
1080Sstevel@tonic-gate SVM_MDB,
1090Sstevel@tonic-gate SVM_STRIPE,
1100Sstevel@tonic-gate SVM_MIRROR,
1110Sstevel@tonic-gate SVM_RAID,
1120Sstevel@tonic-gate SVM_TRANS,
1130Sstevel@tonic-gate SVM_SP,
1140Sstevel@tonic-gate SVM_HSP,
1150Sstevel@tonic-gate SVM_HS,
1160Sstevel@tonic-gate SVM_DRIVE
1170Sstevel@tonic-gate } svm_type_t;
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate typedef struct svm_snap_entry {
1200Sstevel@tonic-gate struct svm_snap_entry *next;
1210Sstevel@tonic-gate char *diskset;
1220Sstevel@tonic-gate svm_type_t type;
1230Sstevel@tonic-gate char *name;
1240Sstevel@tonic-gate char *slice;
1250Sstevel@tonic-gate } svm_snap_t;
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate static svm_snap_t *svm_snapshot(int *errp);
1280Sstevel@tonic-gate static void free_svm_snapshot(svm_snap_t *listp);
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate static char *type_name(svm_type_t type);
1310Sstevel@tonic-gate static int add_record(
1320Sstevel@tonic-gate svm_snap_t **listp,
1330Sstevel@tonic-gate char *setname,
1340Sstevel@tonic-gate svm_type_t type,
1350Sstevel@tonic-gate char *mname,
1360Sstevel@tonic-gate char *slice_name);
1370Sstevel@tonic-gate static int diskset_info(svm_snap_t **listp, mdsetname_t *sp);
1380Sstevel@tonic-gate static void free_names(mdnamelist_t *nlp);
1390Sstevel@tonic-gate static int load_svm(svm_snap_t **listp);
1400Sstevel@tonic-gate static int new_entry(
1410Sstevel@tonic-gate svm_snap_t **listp,
1420Sstevel@tonic-gate char *sname,
1430Sstevel@tonic-gate svm_type_t type,
1440Sstevel@tonic-gate char *mname,
1450Sstevel@tonic-gate mdsetname_t *sp);
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * FUNCTION: scan_svm_names(char *diskset)
1490Sstevel@tonic-gate *
1500Sstevel@tonic-gate * INPUT: diskset - a char * disk set name
1510Sstevel@tonic-gate *
1520Sstevel@tonic-gate * PURPOSE: Take a snapshot of the current SVM config.
1530Sstevel@tonic-gate *
1540Sstevel@tonic-gate * Scan it and remember:
1550Sstevel@tonic-gate * 1. all known disk sets
1560Sstevel@tonic-gate * s. the disks in the named disk set
1570Sstevel@tonic-gate * 3. the used device and HSP names in the named disk set
1580Sstevel@tonic-gate * 4. the HSPs in the disk set
1590Sstevel@tonic-gate * 5. the spares in the HSPs
1600Sstevel@tonic-gate */
1610Sstevel@tonic-gate int
scan_svm_names(char * diskset)1620Sstevel@tonic-gate scan_svm_names(
1630Sstevel@tonic-gate char *diskset)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate int ndisks = 0;
1660Sstevel@tonic-gate int nhsps = 0;
1670Sstevel@tonic-gate int ndevices = 0;
1680Sstevel@tonic-gate int nsets = 0;
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate int number = 0;
1710Sstevel@tonic-gate int error = 0;
1720Sstevel@tonic-gate svm_snap_t *headp = NULL;
1730Sstevel@tonic-gate svm_snap_t *listp = NULL;
1740Sstevel@tonic-gate char *tablefmt = " %-20s %-10s %-20s %-10s\n";
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
1770Sstevel@tonic-gate gettext("\nScanning system SVM configuration...\n"));
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate headp = svm_snapshot(&error);
1800Sstevel@tonic-gate if (error != 0) {
1810Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
1820Sstevel@tonic-gate gettext("failed to scan SVM devices\n"));
1830Sstevel@tonic-gate return (error);
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate if (error == 0) {
1870Sstevel@tonic-gate if ((error = get_max_number_of_devices(&_max_devs_cfg)) == 0) {
1880Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
1890Sstevel@tonic-gate gettext(" configured maximum number of "
1900Sstevel@tonic-gate "volumes: %d\n"),
1910Sstevel@tonic-gate _max_devs_cfg);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate if (error == 0) {
1960Sstevel@tonic-gate if ((error = get_max_number_of_disksets(&_max_sets)) == 0) {
1970Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
1980Sstevel@tonic-gate gettext(" configured maximum number of "
1990Sstevel@tonic-gate "disk sets: %d\n"),
2000Sstevel@tonic-gate _max_sets);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate if (error == 0) {
2050Sstevel@tonic-gate /* array is realloc'ed as necessary */
2060Sstevel@tonic-gate if ((hsps_by_number =
2070Sstevel@tonic-gate (boolean_t *)calloc(_max_hsps, sizeof (boolean_t))) == NULL) {
2080Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
2090Sstevel@tonic-gate gettext("failed to allocate HSP name array\n"));
2100Sstevel@tonic-gate error = ENOMEM;
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate if (error == 0) {
2150Sstevel@tonic-gate /* array is realloc'ed as necessary */
2160Sstevel@tonic-gate if ((devs_by_number =
2170Sstevel@tonic-gate (boolean_t *)calloc(_max_devs, sizeof (boolean_t))) == NULL) {
2180Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
2190Sstevel@tonic-gate gettext("failed to allocate volume name array\n"));
2200Sstevel@tonic-gate error = ENOMEM;
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate if ((error == 0) && (get_max_verbosity() >= OUTPUT_DEBUG)) {
2250Sstevel@tonic-gate (void) oprintf(OUTPUT_DEBUG, "\n");
2260Sstevel@tonic-gate (void) oprintf(OUTPUT_DEBUG,
2270Sstevel@tonic-gate tablefmt,
2280Sstevel@tonic-gate gettext("disk set"),
2290Sstevel@tonic-gate gettext("dev type"),
2300Sstevel@tonic-gate gettext("name"),
2310Sstevel@tonic-gate gettext("slice"));
2320Sstevel@tonic-gate (void) oprintf(OUTPUT_DEBUG,
2330Sstevel@tonic-gate " -----------------------------------"
2340Sstevel@tonic-gate "-----------------------------------\n");
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate for (listp = headp; listp != NULL && error == 0; listp = listp->next) {
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
2400Sstevel@tonic-gate tablefmt,
2410Sstevel@tonic-gate listp->diskset,
2420Sstevel@tonic-gate type_name(listp->type),
2430Sstevel@tonic-gate listp->name,
2440Sstevel@tonic-gate listp->slice);
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate switch (listp->type) {
2470Sstevel@tonic-gate case SVM_DISKSET:
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate error = add_diskset(listp->name);
2500Sstevel@tonic-gate ++nsets;
2510Sstevel@tonic-gate break;
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate case SVM_DRIVE:
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate error = add_diskset_diskname(listp->diskset, listp->name);
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /* is this drive in the requested diskset? */
2580Sstevel@tonic-gate if (string_case_compare(diskset, listp->diskset) == 0) {
2590Sstevel@tonic-gate ++ndisks;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate break;
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate case SVM_MIRROR:
2640Sstevel@tonic-gate case SVM_RAID:
2650Sstevel@tonic-gate case SVM_TRANS:
2660Sstevel@tonic-gate case SVM_SP:
2670Sstevel@tonic-gate case SVM_STRIPE:
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /* is this SVM volume in the requested diskset? */
2700Sstevel@tonic-gate if (string_case_compare(diskset, listp->diskset) == 0) {
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /* isolate device name from "poolname/dXXXX" */
2730Sstevel@tonic-gate char *cp = strrchr(listp->name, '/');
2740Sstevel@tonic-gate if (cp != NULL) {
2750Sstevel@tonic-gate ++cp;
2760Sstevel@tonic-gate } else {
2770Sstevel@tonic-gate cp = listp->name;
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /* BEGIN CSTYLED */
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate * names for requested devices and HSPs are remembered
2830Sstevel@tonic-gate * so that the default name generation scheme knows
2840Sstevel@tonic-gate * which names are already being used
2850Sstevel@tonic-gate */
2860Sstevel@tonic-gate /* END CSTYLED */
2870Sstevel@tonic-gate /* extract device number from name "dXXXX" */
2880Sstevel@tonic-gate if (sscanf(cp, "d%d", &number) != EOF) {
2890Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
2900Sstevel@tonic-gate gettext(" device: %6s number: %3d\n"),
2910Sstevel@tonic-gate cp, number);
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate if (number > _max_devs) {
2940Sstevel@tonic-gate /* hit current limit, expand it */
2950Sstevel@tonic-gate boolean_t *tmp =
2960Sstevel@tonic-gate (boolean_t *)realloc((void *)_max_devs,
2970Sstevel@tonic-gate (number * sizeof (boolean_t)));
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate if (tmp == NULL) {
3000Sstevel@tonic-gate error = ENOMEM;
3010Sstevel@tonic-gate } else {
3020Sstevel@tonic-gate _max_devs = number;
3030Sstevel@tonic-gate devs_by_number = tmp;
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate if ((error == 0) &&
3080Sstevel@tonic-gate (devs_by_number[number] == B_FALSE)) {
3090Sstevel@tonic-gate devs_by_number[number] = B_TRUE;
3100Sstevel@tonic-gate ++ndevices;
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate break;
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate case SVM_HSP:
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /* is this HSP in the requested diskset? */
3190Sstevel@tonic-gate if (string_case_compare(diskset, listp->diskset) == 0) {
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate /* isolate HSP name from "poolname/hspXXX" */
3220Sstevel@tonic-gate char *cp = strrchr(listp->name, '/');
3230Sstevel@tonic-gate if (cp != NULL) {
3240Sstevel@tonic-gate ++cp;
3250Sstevel@tonic-gate } else {
3260Sstevel@tonic-gate cp = listp->name;
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /* extract pool number from name "hspXXX" */
3300Sstevel@tonic-gate if (sscanf(cp, "hsp%03d", &number) != EOF) {
3310Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
3320Sstevel@tonic-gate gettext(" HSP: %6s number: %3d\n"),
3330Sstevel@tonic-gate cp, number);
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate if (number > _max_hsps) {
3360Sstevel@tonic-gate /* hit our arbitrary limit, double it */
3370Sstevel@tonic-gate boolean_t *tmp =
3380Sstevel@tonic-gate (boolean_t *)realloc((void *)hsps_by_number,
3390Sstevel@tonic-gate 2 * _max_hsps * sizeof (boolean_t));
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (tmp != NULL) {
3420Sstevel@tonic-gate _max_hsps *= 2;
3430Sstevel@tonic-gate hsps_by_number = tmp;
3440Sstevel@tonic-gate } else {
3450Sstevel@tonic-gate error = ENOMEM;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate if ((error == 0) &&
3500Sstevel@tonic-gate (hsps_by_number[number] == B_FALSE)) {
3510Sstevel@tonic-gate hsps_by_number[number] = B_TRUE;
3520Sstevel@tonic-gate error = add_diskset_hsp(diskset, cp);
3530Sstevel@tonic-gate ++nhsps;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate break;
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate case SVM_HS:
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /* is this hot spare in the requested disk set? */
3630Sstevel@tonic-gate if (string_case_compare(diskset, listp->diskset) == 0) {
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /* isolate HSP name from "poolname/hspXXXX" */
3660Sstevel@tonic-gate char *cp = strrchr(listp->name, '/');
3670Sstevel@tonic-gate if (cp != NULL) {
3680Sstevel@tonic-gate ++cp;
3690Sstevel@tonic-gate } else {
3700Sstevel@tonic-gate cp = listp->name;
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate error = add_diskset_hsp_spare(diskset, cp, listp->slice);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate break;
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate case SVM_MDB:
3780Sstevel@tonic-gate default:
3790Sstevel@tonic-gate break;
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate free_svm_snapshot(headp);
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate if (error == 0) {
3860Sstevel@tonic-gate /* available diskset? subtract 1 for the local set */
3870Sstevel@tonic-gate if ((diskset_exists(diskset) != B_TRUE) &&
3880Sstevel@tonic-gate (nsets >= _max_sets)) {
3890Sstevel@tonic-gate volume_set_error(
3900Sstevel@tonic-gate gettext("Disk set \"%s\" cannot be created, the "
3910Sstevel@tonic-gate "maximum number of disk sets (%d) already "
3920Sstevel@tonic-gate "exists.\n"),
3930Sstevel@tonic-gate diskset, _max_sets);
3940Sstevel@tonic-gate error = -1;
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate if (error == 0) {
3990Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
4000Sstevel@tonic-gate gettext("\n Disk set \"%s\" has:\n\n"), diskset);
4010Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
4020Sstevel@tonic-gate gettext(" %d drives\n"), ndisks);
4030Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
4040Sstevel@tonic-gate gettext(" %d volumes\n"), ndevices);
4050Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
4060Sstevel@tonic-gate gettext(" %d HSPs\n"), nhsps);
4070Sstevel@tonic-gate } else {
4080Sstevel@tonic-gate free(hsps_by_number);
4090Sstevel@tonic-gate free(devs_by_number);
4100Sstevel@tonic-gate hsps_by_number = (boolean_t *)NULL;
4110Sstevel@tonic-gate devs_by_number = (boolean_t *)NULL;
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate return (error);
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate * FUNCTION: release_svm_names()
4190Sstevel@tonic-gate *
4200Sstevel@tonic-gate * PURPOSE: Release snapshot of the current SVM config.
4210Sstevel@tonic-gate *
4220Sstevel@tonic-gate * Free memory allocated by scan_svm_names()
4230Sstevel@tonic-gate */
4240Sstevel@tonic-gate void
release_svm_names()4250Sstevel@tonic-gate release_svm_names()
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate dlist_t *iter;
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate for (iter = _disksets; iter != NULL; iter = iter->next) {
4300Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
4310Sstevel@tonic-gate dlist_free_items(diskset->disknames, free);
4320Sstevel@tonic-gate dlist_free_items(diskset->hsps, free_devconfig);
4330Sstevel@tonic-gate free(diskset->name);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate dlist_free_items(_disksets, free);
4360Sstevel@tonic-gate _disksets = NULL;
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate if (hsps_by_number != NULL)
4390Sstevel@tonic-gate free(hsps_by_number);
4400Sstevel@tonic-gate if (devs_by_number != NULL)
4410Sstevel@tonic-gate free(devs_by_number);
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate hsps_by_number = (boolean_t *)NULL;
4440Sstevel@tonic-gate devs_by_number = (boolean_t *)NULL;
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * FUNCTION: diskset_exists(char *diskset)
4490Sstevel@tonic-gate *
4500Sstevel@tonic-gate * INPUT: dsname - a char * diskset name
4510Sstevel@tonic-gate *
4520Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the named diskset exists
4530Sstevel@tonic-gate * B_FALSE otherwise
4540Sstevel@tonic-gate *
4550Sstevel@tonic-gate * PURPOSE: Checks the list of known disk sets and determines
4560Sstevel@tonic-gate * if the input name is in that list.
4570Sstevel@tonic-gate */
4580Sstevel@tonic-gate boolean_t
diskset_exists(char * dsname)4590Sstevel@tonic-gate diskset_exists(
4600Sstevel@tonic-gate char *dsname)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate dlist_t *iter;
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate for (iter = _disksets; iter != NULL; iter = iter->next) {
4650Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
4660Sstevel@tonic-gate if (string_case_compare(dsname, diskset->name) == 0) {
4670Sstevel@tonic-gate return (B_TRUE);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate return (B_FALSE);
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate /*
4750Sstevel@tonic-gate * FUNCTION: add_diskset(char *dsname)
4760Sstevel@tonic-gate *
4770Sstevel@tonic-gate * INPUT: dsname - a char * disk set name
4780Sstevel@tonic-gate *
4790Sstevel@tonic-gate * RETURNS: int - 0 on success
4800Sstevel@tonic-gate * !0 otherwise
4810Sstevel@tonic-gate *
4820Sstevel@tonic-gate * PURPOSE: Add the named disk set to the list of known disk sets.
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate static int
add_diskset(char * dsname)4850Sstevel@tonic-gate add_diskset(
4860Sstevel@tonic-gate char *dsname)
4870Sstevel@tonic-gate {
4880Sstevel@tonic-gate dlist_t *iter;
4890Sstevel@tonic-gate int error = 0;
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate for (iter = _disksets; iter != NULL; iter = iter->next) {
4920Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
4930Sstevel@tonic-gate if (string_case_compare(diskset->name, dsname) == 0) {
4940Sstevel@tonic-gate break;
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate if (iter == NULL) {
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate dlist_t *item = NULL;
5010Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)calloc(1, sizeof (diskset_t));
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate if (diskset == NULL) {
5040Sstevel@tonic-gate error = ENOMEM;
5050Sstevel@tonic-gate } else {
5060Sstevel@tonic-gate diskset->hsps = NULL;
5070Sstevel@tonic-gate diskset->name = strdup(dsname);
5080Sstevel@tonic-gate if (diskset->name == NULL) {
5090Sstevel@tonic-gate free(diskset);
5100Sstevel@tonic-gate error = ENOMEM;
5110Sstevel@tonic-gate } else {
5120Sstevel@tonic-gate if ((item = dlist_new_item(diskset)) == NULL) {
5130Sstevel@tonic-gate free(diskset->name);
5140Sstevel@tonic-gate free(diskset);
5150Sstevel@tonic-gate error = ENOMEM;
5160Sstevel@tonic-gate } else {
5170Sstevel@tonic-gate _disksets = dlist_append(item, _disksets, AT_HEAD);
5180Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
5190Sstevel@tonic-gate gettext(" added disk set %s \n"), dsname);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate return (error);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate * FUNCTION: add_diskset_diskname(char *diskset, char *diskname)
5300Sstevel@tonic-gate *
5310Sstevel@tonic-gate * INPUT: dsname - a char * disk set name
5320Sstevel@tonic-gate * diskname - a char * disk name
5330Sstevel@tonic-gate *
5340Sstevel@tonic-gate * RETURNS: int - 0 on success
5350Sstevel@tonic-gate * !0 otherwise
5360Sstevel@tonic-gate *
5370Sstevel@tonic-gate * PURPOSE: Add the disk name to the named disk set's list of disks.
5380Sstevel@tonic-gate *
5390Sstevel@tonic-gate * The input diskname is fully qualified with the path
5400Sstevel@tonic-gate * to the raw disk device (/dev/rdsk/cXtXdXsX) which is
5410Sstevel@tonic-gate * not relevant, so it is removed.
5420Sstevel@tonic-gate */
5430Sstevel@tonic-gate static int
add_diskset_diskname(char * dsname,char * diskname)5440Sstevel@tonic-gate add_diskset_diskname(
5450Sstevel@tonic-gate char *dsname,
5460Sstevel@tonic-gate char *diskname)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate dlist_t *iter;
5490Sstevel@tonic-gate int error = 0;
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate for (iter = _disksets; iter != NULL; iter = iter->next) {
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
5540Sstevel@tonic-gate if (string_case_compare(diskset->name, dsname) == 0) {
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate dlist_t *item = NULL;
5570Sstevel@tonic-gate char *name = NULL;
5580Sstevel@tonic-gate char *cp = NULL;
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate /* trim leading path */
5610Sstevel@tonic-gate if ((cp = strrchr(diskname, '/')) != 0) {
5620Sstevel@tonic-gate if ((name = strdup(cp+1)) == NULL) {
5630Sstevel@tonic-gate error = ENOMEM;
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate } else if ((name = strdup(diskname)) == NULL) {
5660Sstevel@tonic-gate error = ENOMEM;
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate if ((item = dlist_new_item(name)) == NULL) {
5700Sstevel@tonic-gate free(name);
5710Sstevel@tonic-gate error = ENOMEM;
5720Sstevel@tonic-gate } else {
5730Sstevel@tonic-gate diskset->disknames =
5740Sstevel@tonic-gate dlist_append(item, diskset->disknames, AT_HEAD);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if ((error == 0) && (iter == NULL)) {
5820Sstevel@tonic-gate /* new disk set */
5830Sstevel@tonic-gate if ((error = add_diskset(dsname)) == 0) {
5840Sstevel@tonic-gate return (add_diskset_diskname(dsname, diskname));
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate return (error);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate * FUNCTION: add_diskset_hsp(char *dsname, char *hspname)
5930Sstevel@tonic-gate *
5940Sstevel@tonic-gate * INPUT: dsname - a char * disk set name
5950Sstevel@tonic-gate * hspname - a char * HSP name
5960Sstevel@tonic-gate *
5970Sstevel@tonic-gate * RETURNS: int - 0 on success
5980Sstevel@tonic-gate * !0 otherwise
5990Sstevel@tonic-gate *
6000Sstevel@tonic-gate * PURPOSE: Model a new HSP for the named disk set.
6010Sstevel@tonic-gate *
6020Sstevel@tonic-gate * Metassist can use existing HSPs to service new volumes.
6030Sstevel@tonic-gate *
6040Sstevel@tonic-gate * It is necessary to have a model of what HSPs currently
6050Sstevel@tonic-gate * exist for each disk set.
6060Sstevel@tonic-gate *
6070Sstevel@tonic-gate * This function takes information found during discovery
6080Sstevel@tonic-gate * and turns it into a form usable by the HSP layout code.
6090Sstevel@tonic-gate */
6100Sstevel@tonic-gate static int
add_diskset_hsp(char * dsname,char * hspname)6110Sstevel@tonic-gate add_diskset_hsp(
6120Sstevel@tonic-gate char *dsname,
6130Sstevel@tonic-gate char *hspname)
6140Sstevel@tonic-gate {
6150Sstevel@tonic-gate dlist_t *iter;
6160Sstevel@tonic-gate int error = 0;
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate for (iter = _disksets; iter != NULL; iter = iter->next) {
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate if (string_case_compare(diskset->name, dsname) == 0) {
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate dlist_t *item = NULL;
6250Sstevel@tonic-gate devconfig_t *hsp = NULL;
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate if (((error = new_devconfig(&hsp, TYPE_HSP)) != 0) ||
6280Sstevel@tonic-gate (error = devconfig_set_name(hsp, hspname))) {
6290Sstevel@tonic-gate free_devconfig(hsp);
6300Sstevel@tonic-gate } else {
6310Sstevel@tonic-gate if ((item = dlist_new_item(hsp)) == NULL) {
6320Sstevel@tonic-gate free_devconfig(hsp);
6330Sstevel@tonic-gate error = ENOMEM;
6340Sstevel@tonic-gate } else {
6350Sstevel@tonic-gate diskset->hsps =
6360Sstevel@tonic-gate dlist_append(item, diskset->hsps, AT_TAIL);
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
6390Sstevel@tonic-gate gettext(" added %s to disk set %s\n"),
6400Sstevel@tonic-gate hspname, dsname);
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate break;
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate if ((error == 0) && (iter == NULL)) {
6480Sstevel@tonic-gate if ((error = add_diskset(dsname)) == 0) {
6490Sstevel@tonic-gate return (add_diskset_hsp(dsname, hspname));
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate return (error);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate /*
6570Sstevel@tonic-gate * FUNCTION: add_diskset_hsp_spare(char *dsname, char *hspname,
6580Sstevel@tonic-gate * char *sparename)
6590Sstevel@tonic-gate *
6600Sstevel@tonic-gate * INPUT: dsname - a char * diskset name
6610Sstevel@tonic-gate * hspname - a char * HSP name
6620Sstevel@tonic-gate * sparename - a char * hot spare (slice) name
6630Sstevel@tonic-gate *
6640Sstevel@tonic-gate * RETURNS: int - 0 on success
6650Sstevel@tonic-gate * !0 otherwise
6660Sstevel@tonic-gate *
6670Sstevel@tonic-gate * PURPOSE: Locate the named hot spare pool in the named disk set and
6680Sstevel@tonic-gate * add the named spare slice to its list of spares.
6690Sstevel@tonic-gate *
6700Sstevel@tonic-gate * Metassist can use existing HSPs to service new volumes.
6710Sstevel@tonic-gate *
6720Sstevel@tonic-gate * It is necessary to have a model of what HSPs currently
6730Sstevel@tonic-gate * exist for each disk set.
6740Sstevel@tonic-gate *
6750Sstevel@tonic-gate * This function takes information found during discovery
6760Sstevel@tonic-gate * and turns it into a form usable by the HSP layout code.
6770Sstevel@tonic-gate */
6780Sstevel@tonic-gate static int
add_diskset_hsp_spare(char * dsname,char * hspname,char * sparename)6790Sstevel@tonic-gate add_diskset_hsp_spare(
6800Sstevel@tonic-gate char *dsname,
6810Sstevel@tonic-gate char *hspname,
6820Sstevel@tonic-gate char *sparename)
6830Sstevel@tonic-gate {
6840Sstevel@tonic-gate dlist_t *iter;
6850Sstevel@tonic-gate int error = 0;
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate for (iter = _disksets; iter != NULL; iter = iter->next) {
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate if (string_case_compare(diskset->name, dsname) == 0) {
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate dlist_t *item =
6940Sstevel@tonic-gate dlist_find(
6950Sstevel@tonic-gate diskset->hsps, hspname,
6960Sstevel@tonic-gate compare_string_to_devconfig_name);
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate if (item != NULL) {
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate /* add spare to HSP */
7010Sstevel@tonic-gate devconfig_t *hsp = (devconfig_t *)item->obj;
7020Sstevel@tonic-gate dm_descriptor_t slice = (dm_descriptor_t)0;
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate (void) slice_get_by_name(sparename, &slice);
7050Sstevel@tonic-gate if (slice == (dm_descriptor_t)0) {
7060Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
7070Sstevel@tonic-gate gettext("warning: ignoring nonexistent "
7080Sstevel@tonic-gate "slice %s defined in %s\n"),
7090Sstevel@tonic-gate sparename, hspname);
7100Sstevel@tonic-gate } else {
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate uint64_t nbytes = 0;
7130Sstevel@tonic-gate uint32_t index = 0;
7140Sstevel@tonic-gate devconfig_t *spare = NULL;
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate /* build a devconfig_t model of the slice */
7170Sstevel@tonic-gate if (((error = slice_get_size(slice, &nbytes)) != 0) ||
7180Sstevel@tonic-gate (error = slice_get_index(slice, &index)) ||
7190Sstevel@tonic-gate (error = new_devconfig(&spare, TYPE_SLICE)) ||
7200Sstevel@tonic-gate (error = devconfig_set_name(spare, sparename)) ||
7210Sstevel@tonic-gate (error = devconfig_set_size(spare, nbytes)) ||
7220Sstevel@tonic-gate (error = devconfig_set_slice_index(spare, index))) {
7230Sstevel@tonic-gate free_devconfig(spare);
7240Sstevel@tonic-gate } else {
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate if ((item = dlist_new_item(spare)) == NULL) {
7270Sstevel@tonic-gate error = ENOMEM;
7280Sstevel@tonic-gate free_devconfig(spare);
7290Sstevel@tonic-gate } else {
7300Sstevel@tonic-gate dlist_t *spares;
7310Sstevel@tonic-gate spares = devconfig_get_components(hsp);
7320Sstevel@tonic-gate spares = dlist_append(item, spares, AT_TAIL);
7330Sstevel@tonic-gate devconfig_set_components(hsp, spares);
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
7360Sstevel@tonic-gate gettext(" added %s to %s in "
7370Sstevel@tonic-gate "disk set %s\n"),
7380Sstevel@tonic-gate sparename, hspname, dsname);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate break;
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate } else {
7460Sstevel@tonic-gate if ((error = add_diskset_hsp(dsname, hspname)) == 0) {
7470Sstevel@tonic-gate return (add_diskset_hsp_spare(
7480Sstevel@tonic-gate dsname, hspname, sparename));
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate return (error);
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate /*
7580Sstevel@tonic-gate * Return a list of disks in the given diskset.
7590Sstevel@tonic-gate *
7600Sstevel@tonic-gate * @param dsname
7610Sstevel@tonic-gate * The name of the named disk set, or "" for the local
7620Sstevel@tonic-gate * set.
7630Sstevel@tonic-gate *
7640Sstevel@tonic-gate * @param disks
7650Sstevel@tonic-gate * RETURN: pointer to the list of disks in the given disk
7660Sstevel@tonic-gate * set
7670Sstevel@tonic-gate *
7680Sstevel@tonic-gate * @return 0 if succesful, non-zero otherwise
7690Sstevel@tonic-gate */
7700Sstevel@tonic-gate int
get_disks_in_diskset(char * dsname,dlist_t ** disks)7710Sstevel@tonic-gate get_disks_in_diskset(
7720Sstevel@tonic-gate char *dsname,
7730Sstevel@tonic-gate dlist_t **disks)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate dlist_t *known_disks;
7760Sstevel@tonic-gate int error = 0;
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate *disks = NULL;
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate if ((error = get_known_disks(&known_disks)) == 0) {
7810Sstevel@tonic-gate dlist_t *iter;
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate /* For each known disk... */
7840Sstevel@tonic-gate for (iter = known_disks;
7850Sstevel@tonic-gate iter != NULL && error == 0;
7860Sstevel@tonic-gate iter = iter->next) {
7870Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj;
7880Sstevel@tonic-gate boolean_t in_diskset = B_FALSE;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate /* If this disk is in the given set... */
7910Sstevel@tonic-gate error = is_disk_in_diskset(disk, dsname, &in_diskset);
7920Sstevel@tonic-gate if (error == 0 && in_diskset == B_TRUE) {
79362Sjeanm dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
7940Sstevel@tonic-gate *disks = dlist_append(item, *disks, AT_TAIL);
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate }
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate return (error);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate /*
8030Sstevel@tonic-gate * FUNCTION: is_disk_in_diskset(dm_descriptor_t disk, char *dsname,
8040Sstevel@tonic-gate * boolean_t *bool)
8050Sstevel@tonic-gate *
8060Sstevel@tonic-gate * INPUT: disk - dm_descriptor_t disk handle
8070Sstevel@tonic-gate * dsname - char * diskset name, or MD_LOCAL_NAME for
8080Sstevel@tonic-gate * the local set.
8090Sstevel@tonic-gate *
8100Sstevel@tonic-gate * OUTPUT: bool - pointer to a boolean_t to hold the result
8110Sstevel@tonic-gate *
8120Sstevel@tonic-gate * RETURNS: int - 0 on success
8130Sstevel@tonic-gate * !0 otherwise
8140Sstevel@tonic-gate *
8150Sstevel@tonic-gate * PURPOSE: Determine if the input disk is known to be in the
8160Sstevel@tonic-gate * given diskset.
8170Sstevel@tonic-gate */
8180Sstevel@tonic-gate int
is_disk_in_diskset(dm_descriptor_t disk,char * dsname,boolean_t * bool)8190Sstevel@tonic-gate is_disk_in_diskset(
8200Sstevel@tonic-gate dm_descriptor_t disk,
8210Sstevel@tonic-gate char *dsname,
8220Sstevel@tonic-gate boolean_t *bool)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate if (string_case_compare(dsname, MD_LOCAL_NAME) == 0) {
8250Sstevel@tonic-gate return (is_disk_in_local_diskset(disk, bool));
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate return (is_disk_in_named_diskset(disk, dsname, bool));
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate static int
is_disk_in_local_diskset(dm_descriptor_t disk,boolean_t * bool)8320Sstevel@tonic-gate is_disk_in_local_diskset(
8330Sstevel@tonic-gate dm_descriptor_t disk,
8340Sstevel@tonic-gate boolean_t *bool)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate dlist_t *iter;
8370Sstevel@tonic-gate dlist_t *aliases = NULL;
8380Sstevel@tonic-gate boolean_t in_named_diskset = B_FALSE;
8390Sstevel@tonic-gate char *name = NULL;
8400Sstevel@tonic-gate int error = 0;
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate *bool = B_FALSE;
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate error = get_display_name(disk, &name);
8450Sstevel@tonic-gate if (error == 0) {
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate error = get_aliases(disk, &aliases);
8480Sstevel@tonic-gate if (error == 0) {
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate /* For each known disk set... */
8510Sstevel@tonic-gate for (iter = _disksets;
8520Sstevel@tonic-gate iter != NULL && in_named_diskset == B_FALSE;
8530Sstevel@tonic-gate iter = iter->next) {
8540Sstevel@tonic-gate
8550Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
8560Sstevel@tonic-gate dlist_t *names = diskset->disknames;
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate /* Check disk name */
8590Sstevel@tonic-gate in_named_diskset = dlist_contains(
8600Sstevel@tonic-gate names, name, compare_device_names);
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate /* Check disk aliases */
8630Sstevel@tonic-gate if (in_named_diskset == B_FALSE) {
8640Sstevel@tonic-gate dlist_t *iter2;
8650Sstevel@tonic-gate for (iter2 = aliases;
8660Sstevel@tonic-gate iter2 != NULL && in_named_diskset == B_FALSE;
8670Sstevel@tonic-gate iter2 = iter2->next) {
8680Sstevel@tonic-gate in_named_diskset = dlist_contains(names,
8690Sstevel@tonic-gate (char *)iter2->obj, compare_device_names);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate if (error == 0) {
8770Sstevel@tonic-gate *bool = (in_named_diskset == B_TRUE ? B_FALSE : B_TRUE);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate return (error);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate static int
is_disk_in_named_diskset(dm_descriptor_t disk,char * dsname,boolean_t * bool)8840Sstevel@tonic-gate is_disk_in_named_diskset(
8850Sstevel@tonic-gate dm_descriptor_t disk,
8860Sstevel@tonic-gate char *dsname,
8870Sstevel@tonic-gate boolean_t *bool)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate dlist_t *iter;
8900Sstevel@tonic-gate int error = 0;
8910Sstevel@tonic-gate boolean_t in_diskset = B_FALSE;
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate *bool = B_FALSE;
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate for (iter = _disksets;
8960Sstevel@tonic-gate (iter != NULL) && (in_diskset == B_FALSE);
8970Sstevel@tonic-gate iter = iter->next) {
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate if (string_case_compare(diskset->name, dsname) == 0) {
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate dlist_t *names = diskset->disknames;
9040Sstevel@tonic-gate dlist_t *aliases = NULL;
9050Sstevel@tonic-gate char *name = NULL;
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate ((error = get_display_name(disk, &name)) != 0) ||
9080Sstevel@tonic-gate (error = get_aliases(disk, &aliases));
9090Sstevel@tonic-gate if (error != 0) {
9100Sstevel@tonic-gate break;
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate /* check disk name */
9140Sstevel@tonic-gate in_diskset = dlist_contains(names, name, compare_device_names);
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate /* check disk aliases */
9170Sstevel@tonic-gate if (in_diskset == B_FALSE) {
9180Sstevel@tonic-gate dlist_t *iter2;
9190Sstevel@tonic-gate for (iter2 = aliases;
9200Sstevel@tonic-gate (iter2 != NULL) && (in_diskset == B_FALSE);
9210Sstevel@tonic-gate iter2 = iter2->next) {
9220Sstevel@tonic-gate in_diskset = dlist_contains(names,
9230Sstevel@tonic-gate (char *)iter2->obj, compare_device_names);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate *bool = in_diskset;
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate return (error);
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate /*
9350Sstevel@tonic-gate * FUNCTION: is_disk_in_other_diskset(dm_descriptor_t disk, char *dsname,
9360Sstevel@tonic-gate * boolean_t *bool)
9370Sstevel@tonic-gate *
9380Sstevel@tonic-gate * INPUT: disk - dm_descriptor_t disk handle
9390Sstevel@tonic-gate * dsname - char * disk set name
9400Sstevel@tonic-gate *
9410Sstevel@tonic-gate * OUTPUT: bool - pointer to a boolean_t to hold the result.
9420Sstevel@tonic-gate *
9430Sstevel@tonic-gate * RETURNS: int - 0 on success
9440Sstevel@tonic-gate * !0 otherwise
9450Sstevel@tonic-gate *
9460Sstevel@tonic-gate * PURPOSE: Determine if the named disk is known to be in a disk set
9470Sstevel@tonic-gate * other than the named disk set.
9480Sstevel@tonic-gate */
9490Sstevel@tonic-gate int
is_disk_in_other_diskset(dm_descriptor_t disk,char * dsname,boolean_t * bool)9500Sstevel@tonic-gate is_disk_in_other_diskset(
9510Sstevel@tonic-gate dm_descriptor_t disk,
9520Sstevel@tonic-gate char *dsname,
9530Sstevel@tonic-gate boolean_t *bool)
9540Sstevel@tonic-gate {
9550Sstevel@tonic-gate boolean_t in_other = B_FALSE;
9560Sstevel@tonic-gate dlist_t *iter;
9570Sstevel@tonic-gate dlist_t *aliases = NULL;
9580Sstevel@tonic-gate char *name = NULL;
9590Sstevel@tonic-gate char *cp = NULL;
9600Sstevel@tonic-gate int error = 0;
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate ((error = get_display_name(disk, &name)) != 0) ||
9630Sstevel@tonic-gate (error = get_aliases(disk, &aliases));
9640Sstevel@tonic-gate if (error != 0) {
9650Sstevel@tonic-gate return (error);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate * discard the leading path, it is probably /dev/dsk
9700Sstevel@tonic-gate * and the disk set disk names are all /dev/rdsk/...
9710Sstevel@tonic-gate *
9720Sstevel@tonic-gate * aliases do not have leading paths
9730Sstevel@tonic-gate */
9740Sstevel@tonic-gate cp = strrchr(name, '/');
9750Sstevel@tonic-gate if (cp != NULL) {
9760Sstevel@tonic-gate ++cp;
9770Sstevel@tonic-gate } else {
9780Sstevel@tonic-gate cp = name;
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate name = cp;
9810Sstevel@tonic-gate
9820Sstevel@tonic-gate for (iter = _disksets;
9830Sstevel@tonic-gate (iter != NULL) && (in_other == B_FALSE);
9840Sstevel@tonic-gate iter = iter->next) {
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate diskset_t *diskset = (diskset_t *)iter->obj;
9870Sstevel@tonic-gate dlist_t *names = diskset->disknames;
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate if (string_case_compare(diskset->name, dsname) == 0) {
9900Sstevel@tonic-gate /* skip named disk set */
9910Sstevel@tonic-gate continue;
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate /* see if disk's name is in disk set's name list */
9950Sstevel@tonic-gate in_other = dlist_contains(names, name, compare_device_names);
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate /* see if any of the disk's aliases is in name list */
9980Sstevel@tonic-gate if (in_other == B_FALSE) {
9990Sstevel@tonic-gate dlist_t *iter2;
10000Sstevel@tonic-gate for (iter2 = aliases;
10010Sstevel@tonic-gate (iter2 != NULL) && (in_other == B_FALSE);
10020Sstevel@tonic-gate iter2 = iter2->next) {
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate in_other = dlist_contains(names,
10050Sstevel@tonic-gate (char *)iter2->obj, compare_device_names);
10060Sstevel@tonic-gate }
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate *bool = in_other;
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate return (error);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate * FUNCTION: hsp_get_default_for_diskset(char *diskset,
10170Sstevel@tonic-gate * devconfig_t **hsp)
10180Sstevel@tonic-gate *
10190Sstevel@tonic-gate * INPUT: diskset - char * disk set name
10200Sstevel@tonic-gate *
10210Sstevel@tonic-gate * RETURNS: devconfig_t * - pointer to the first HSP in the disk set
10220Sstevel@tonic-gate * NULL if none found
10230Sstevel@tonic-gate *
10240Sstevel@tonic-gate * PURPOSE: Locate the first HSP in the named disk set.
10250Sstevel@tonic-gate */
10260Sstevel@tonic-gate int
hsp_get_default_for_diskset(char * diskset,devconfig_t ** hsp)10270Sstevel@tonic-gate hsp_get_default_for_diskset(
10280Sstevel@tonic-gate char *diskset,
10290Sstevel@tonic-gate devconfig_t **hsp)
10300Sstevel@tonic-gate {
10310Sstevel@tonic-gate dlist_t *iter = _disksets;
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate *hsp = NULL;
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate for (; (iter != NULL) && (*hsp == NULL); iter = iter->next) {
10360Sstevel@tonic-gate diskset_t *set = (diskset_t *)iter->obj;
10370Sstevel@tonic-gate if (string_case_compare(set->name, diskset) == 0) {
10380Sstevel@tonic-gate dlist_t *item = set->hsps;
10390Sstevel@tonic-gate if (item != NULL) {
10400Sstevel@tonic-gate *hsp = item->obj;
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate }
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate return (0);
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate /*
10490Sstevel@tonic-gate * FUNCTION: get_n_metadb_replicas(int *nreplicas)
10500Sstevel@tonic-gate *
10510Sstevel@tonic-gate * OUTPUT: nreplicas - pointer to int to hold the result
10520Sstevel@tonic-gate *
10530Sstevel@tonic-gate * RETURNS: int - 0 on success
10540Sstevel@tonic-gate * !0 on failure
10550Sstevel@tonic-gate *
10560Sstevel@tonic-gate * PURPOSE: Check the number of replicas configured for the local set.
10570Sstevel@tonic-gate */
10580Sstevel@tonic-gate int
get_n_metadb_replicas(int * nreplicas)10590Sstevel@tonic-gate get_n_metadb_replicas(
10600Sstevel@tonic-gate int *nreplicas)
10610Sstevel@tonic-gate {
10620Sstevel@tonic-gate mdsetname_t *sp;
10630Sstevel@tonic-gate md_replicalist_t *rlp = NULL;
10640Sstevel@tonic-gate md_error_t mderror = mdnullerror;
10650Sstevel@tonic-gate int error = 0;
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate *nreplicas = 0;
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate sp = metasetname(MD_LOCAL_NAME, &mderror);
10700Sstevel@tonic-gate if (!mdisok(&mderror)) {
10710Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
10720Sstevel@tonic-gate mdclrerror(&mderror);
10730Sstevel@tonic-gate error = -1;
10740Sstevel@tonic-gate } else {
10750Sstevel@tonic-gate *nreplicas = metareplicalist(sp, MD_BASICNAME_OK, &rlp, &mderror);
10760Sstevel@tonic-gate if (!mdisok(&mderror)) {
10770Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
10780Sstevel@tonic-gate mdclrerror(&mderror);
10790Sstevel@tonic-gate error = -1;
10800Sstevel@tonic-gate } else if (rlp != NULL) {
10810Sstevel@tonic-gate metafreereplicalist(rlp);
10820Sstevel@tonic-gate rlp = NULL;
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate if (*nreplicas < 0) {
10860Sstevel@tonic-gate *nreplicas = 0;
10870Sstevel@tonic-gate }
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate return (error);
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate /*
10940Sstevel@tonic-gate * FUNCTION: hsp_get_by_name(char *diskset, char *name,
10950Sstevel@tonic-gate * devconfig_t **hsp)
10960Sstevel@tonic-gate *
10970Sstevel@tonic-gate * INPUT: diskset - char * disk set name
10980Sstevel@tonic-gate * name - char * HSP name
10990Sstevel@tonic-gate *
11000Sstevel@tonic-gate * OUTPUT: hsp - a devconfig_t * - pointer to hold
11010Sstevel@tonic-gate * the named HSP if none found
11020Sstevel@tonic-gate *
11030Sstevel@tonic-gate * PURPOSE: Locate the named HSP in the named disk set.
11040Sstevel@tonic-gate */
11050Sstevel@tonic-gate int
hsp_get_by_name(char * diskset,char * name,devconfig_t ** hsp)11060Sstevel@tonic-gate hsp_get_by_name(
11070Sstevel@tonic-gate char *diskset,
11080Sstevel@tonic-gate char *name,
11090Sstevel@tonic-gate devconfig_t **hsp)
11100Sstevel@tonic-gate {
11110Sstevel@tonic-gate dlist_t *iter = _disksets;
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate *hsp = NULL;
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate for (; (iter != NULL) && (*hsp == NULL); iter = iter->next) {
11160Sstevel@tonic-gate diskset_t *set = (diskset_t *)iter->obj;
11170Sstevel@tonic-gate if (string_case_compare(set->name, diskset) == 0) {
11180Sstevel@tonic-gate dlist_t *item = dlist_find(
11190Sstevel@tonic-gate set->hsps, name, compare_string_to_devconfig_name);
11200Sstevel@tonic-gate if (item != NULL) {
11210Sstevel@tonic-gate *hsp = item->obj;
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate return (0);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate * FUNCTION: is_volume_name_valid(char *name)
11310Sstevel@tonic-gate *
11320Sstevel@tonic-gate * OUTPUT: name - pointer to a char * volume name
11330Sstevel@tonic-gate *
11340Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the input name is valid
11350Sstevel@tonic-gate * B_FALSE otherwise
11360Sstevel@tonic-gate *
11370Sstevel@tonic-gate * PURPOSE: Wrapper around libmeta volume name validation method.
11380Sstevel@tonic-gate */
11390Sstevel@tonic-gate boolean_t
is_volume_name_valid(char * name)11400Sstevel@tonic-gate is_volume_name_valid(
11410Sstevel@tonic-gate char *name)
11420Sstevel@tonic-gate {
11430Sstevel@tonic-gate return (is_metaname(name));
11440Sstevel@tonic-gate }
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate /*
11470Sstevel@tonic-gate * FUNCTION: is_hsp_name_valid(char *name)
11480Sstevel@tonic-gate *
11490Sstevel@tonic-gate * INPUT: name - char * HSP name
11500Sstevel@tonic-gate *
11510Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the input name is valid
11520Sstevel@tonic-gate * B_FALSE otherwise
11530Sstevel@tonic-gate *
11540Sstevel@tonic-gate * PURPOSE: Wrapper around libmeta HSP name validation method.
11550Sstevel@tonic-gate */
11560Sstevel@tonic-gate boolean_t
is_hsp_name_valid(char * name)11570Sstevel@tonic-gate is_hsp_name_valid(
11580Sstevel@tonic-gate char *name)
11590Sstevel@tonic-gate {
11600Sstevel@tonic-gate return (is_hspname(name));
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate /*
11640Sstevel@tonic-gate * FUNCTION: extract_index(char *name, char *prefix, char *num_fmt,
11650Sstevel@tonic-gate * int *index)
11660Sstevel@tonic-gate *
11670Sstevel@tonic-gate * INPUT: name - const char * volume name
11680Sstevel@tonic-gate * prefix - const char * fixed part of format string
11690Sstevel@tonic-gate * num_fmt - const char * format of number to extract (e.g. %d)
11700Sstevel@tonic-gate *
11710Sstevel@tonic-gate * OUTPUT: index - pointer to int to hold numeric part of name
11720Sstevel@tonic-gate *
11730Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the input name is parsed correctly
11740Sstevel@tonic-gate * B_FALSE otherwise
11750Sstevel@tonic-gate *
11760Sstevel@tonic-gate * PURPOSE: Extract the numeric portion of a device name for use
11770Sstevel@tonic-gate * by higher-level functions.
11780Sstevel@tonic-gate */
11790Sstevel@tonic-gate static boolean_t
extract_index(const char * name,const char * prefix,const char * num_fmt,int * index)11800Sstevel@tonic-gate extract_index(
11810Sstevel@tonic-gate const char *name,
11820Sstevel@tonic-gate const char *prefix,
11830Sstevel@tonic-gate const char *num_fmt,
11840Sstevel@tonic-gate int *index)
11850Sstevel@tonic-gate {
11860Sstevel@tonic-gate char buf[MAXNAMELEN];
11870Sstevel@tonic-gate const char *cp;
11880Sstevel@tonic-gate const char *fmt = buf;
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate if ((cp = strrchr(name, '/')) != NULL) {
11910Sstevel@tonic-gate ++cp;
11920Sstevel@tonic-gate } else {
11930Sstevel@tonic-gate cp = name;
11940Sstevel@tonic-gate }
11950Sstevel@tonic-gate
11960Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s%s", prefix, num_fmt);
11970Sstevel@tonic-gate if (sscanf(cp, fmt, index) == 1)
11980Sstevel@tonic-gate return (B_TRUE);
11990Sstevel@tonic-gate else
12000Sstevel@tonic-gate return (B_FALSE);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate * FUNCTION: is_volume_name_in_range(char *name)
12050Sstevel@tonic-gate *
12060Sstevel@tonic-gate * INPUT: name - char * volume name
12070Sstevel@tonic-gate *
12080Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the input name is in the allowed
12090Sstevel@tonic-gate * range of names
12100Sstevel@tonic-gate * B_FALSE otherwise
12110Sstevel@tonic-gate *
12120Sstevel@tonic-gate * PURPOSE: Determine if the input volume name is within the allowed
12130Sstevel@tonic-gate * range of device names (0 <= n < max # of devices configured).
12140Sstevel@tonic-gate */
12150Sstevel@tonic-gate boolean_t
is_volume_name_in_range(char * name)12160Sstevel@tonic-gate is_volume_name_in_range(
12170Sstevel@tonic-gate char *name)
12180Sstevel@tonic-gate {
12190Sstevel@tonic-gate int index = -1;
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate if (extract_index(name, _dev_prefix, "%d", &index)) {
12220Sstevel@tonic-gate if (index >= 0 && index < _max_devs_cfg) {
12230Sstevel@tonic-gate return (B_TRUE);
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate return (B_FALSE);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate * FUNCTION: reserve_volume_name(char *name)
12320Sstevel@tonic-gate *
12330Sstevel@tonic-gate * INPUT: name - a char * volume name
12340Sstevel@tonic-gate *
12350Sstevel@tonic-gate * RETURNS: int - 0 on success
12360Sstevel@tonic-gate * !0 otherwise
12370Sstevel@tonic-gate *
12380Sstevel@tonic-gate * PURPOSE: Mark a volume name/number as used.
12390Sstevel@tonic-gate *
12400Sstevel@tonic-gate * Assumes that the input name has been validated.
12410Sstevel@tonic-gate *
12420Sstevel@tonic-gate * if the name is not currently available, return -1
12430Sstevel@tonic-gate */
12440Sstevel@tonic-gate int
reserve_volume_name(char * name)12450Sstevel@tonic-gate reserve_volume_name(
12460Sstevel@tonic-gate char *name)
12470Sstevel@tonic-gate {
12480Sstevel@tonic-gate int index = -1;
12490Sstevel@tonic-gate
12500Sstevel@tonic-gate if (extract_index(name, _dev_prefix, "%d", &index)) {
12510Sstevel@tonic-gate if (devs_by_number[index] != B_TRUE) {
12520Sstevel@tonic-gate devs_by_number[index] = B_TRUE;
12530Sstevel@tonic-gate return (0);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate return (-1);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate /*
12610Sstevel@tonic-gate * FUNCTION: reserve_hsp_name(char *name)
12620Sstevel@tonic-gate *
12630Sstevel@tonic-gate * INPUT: name - a char * hsp name
12640Sstevel@tonic-gate *
12650Sstevel@tonic-gate * RETURNS: int - 0 on success
12660Sstevel@tonic-gate * !0 otherwise
12670Sstevel@tonic-gate *
12680Sstevel@tonic-gate * PURPOSE: Mark a HSP name/number as used.
12690Sstevel@tonic-gate *
12700Sstevel@tonic-gate * Assumes that the input name has been validated.
12710Sstevel@tonic-gate *
12720Sstevel@tonic-gate * if the name is not currently available, return -1
12730Sstevel@tonic-gate */
12740Sstevel@tonic-gate int
reserve_hsp_name(char * name)12750Sstevel@tonic-gate reserve_hsp_name(
12760Sstevel@tonic-gate char *name)
12770Sstevel@tonic-gate {
12780Sstevel@tonic-gate int index = -1;
12790Sstevel@tonic-gate
12800Sstevel@tonic-gate if (extract_index(name, _hsp_prefix, "%03d", &index)) {
12810Sstevel@tonic-gate if (hsps_by_number[index] != B_TRUE) {
12820Sstevel@tonic-gate hsps_by_number[index] = B_TRUE;
12830Sstevel@tonic-gate return (0);
12840Sstevel@tonic-gate }
12850Sstevel@tonic-gate }
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate return (-1);
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate
12900Sstevel@tonic-gate /*
12910Sstevel@tonic-gate * FUNCTION: release_volume_name(char *name)
12920Sstevel@tonic-gate *
12930Sstevel@tonic-gate * INPUT: name - a char * volume name
12940Sstevel@tonic-gate *
12950Sstevel@tonic-gate * PURPOSE: release the input volume name.
12960Sstevel@tonic-gate *
12970Sstevel@tonic-gate * Extract volume number from the input name
12980Sstevel@tonic-gate * and use it to index into the array of used
12990Sstevel@tonic-gate * volume numbers. Make that volume number
13000Sstevel@tonic-gate * available for use again.
13010Sstevel@tonic-gate */
13020Sstevel@tonic-gate void
release_volume_name(char * name)13030Sstevel@tonic-gate release_volume_name(
13040Sstevel@tonic-gate char *name)
13050Sstevel@tonic-gate {
13060Sstevel@tonic-gate int index = -1;
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate if (name != NULL && extract_index(name, _dev_prefix, "%d", &index)) {
13090Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
13100Sstevel@tonic-gate gettext("released volume name %s%d\n"),
13110Sstevel@tonic-gate _dev_prefix, index);
13120Sstevel@tonic-gate devs_by_number[index] = B_FALSE;
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate
13160Sstevel@tonic-gate /*
13170Sstevel@tonic-gate * FUNCTION: release_hsp_name(char *name)
13180Sstevel@tonic-gate *
13190Sstevel@tonic-gate * INPUT: name - a char * HSP name
13200Sstevel@tonic-gate *
13210Sstevel@tonic-gate * PURPOSE: release the input HSP name.
13220Sstevel@tonic-gate *
13230Sstevel@tonic-gate * Extract volume number from the input name
13240Sstevel@tonic-gate * and use it to index into the array of used
13250Sstevel@tonic-gate * hsp numbers. Make that hsp number available
13260Sstevel@tonic-gate * for use again.
13270Sstevel@tonic-gate */
13280Sstevel@tonic-gate void
release_hsp_name(char * name)13290Sstevel@tonic-gate release_hsp_name(
13300Sstevel@tonic-gate char *name)
13310Sstevel@tonic-gate {
13320Sstevel@tonic-gate int index = -1;
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate if (name != NULL && extract_index(name, _hsp_prefix, "%d", &index)) {
13350Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
13360Sstevel@tonic-gate gettext("released hsp name %s%d\n"),
13370Sstevel@tonic-gate _hsp_prefix, index);
13380Sstevel@tonic-gate hsps_by_number[index] = B_FALSE;
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate /*
13430Sstevel@tonic-gate * FUNCTION: get_next_volume_name(char **name)
13440Sstevel@tonic-gate *
13450Sstevel@tonic-gate * OUTPUT: name - pointer to a char * to hold volume name
13460Sstevel@tonic-gate *
13470Sstevel@tonic-gate * RETURNS: int - 0 on success
13480Sstevel@tonic-gate * !0 otherwise
13490Sstevel@tonic-gate *
13500Sstevel@tonic-gate * PURPOSE: generate a new volume name using the standard device
13510Sstevel@tonic-gate * name prefix and the lowest available device number.
13520Sstevel@tonic-gate *
13530Sstevel@tonic-gate * if type == MIRROR, determine the next available mirror
13540Sstevel@tonic-gate * name according to the convention that a mirror name is
13550Sstevel@tonic-gate * a multiple of 10.
13560Sstevel@tonic-gate *
13570Sstevel@tonic-gate * If such a name is unavailable, use the next available name.
13580Sstevel@tonic-gate */
13590Sstevel@tonic-gate int
get_next_volume_name(char ** name,component_type_t type)13600Sstevel@tonic-gate get_next_volume_name(
13610Sstevel@tonic-gate char **name,
13620Sstevel@tonic-gate component_type_t type)
13630Sstevel@tonic-gate {
13640Sstevel@tonic-gate int next = 0;
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate for (next = 0; next < _max_devs_cfg; ++next) {
13670Sstevel@tonic-gate if ((type == TYPE_MIRROR && ((next % 10) != 0)) ||
13680Sstevel@tonic-gate (type != TYPE_MIRROR && ((next % 10) == 0))) {
13690Sstevel@tonic-gate /* use/save multiples of 10 for mirrors */
13700Sstevel@tonic-gate continue;
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate if (devs_by_number[next] != B_TRUE) {
13730Sstevel@tonic-gate break;
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate }
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate if ((next == _max_devs_cfg) && (type == TYPE_MIRROR)) {
13780Sstevel@tonic-gate /* try next sequentially available name */
13790Sstevel@tonic-gate for (next = 0; next < _max_devs_cfg; ++next) {
13800Sstevel@tonic-gate if (devs_by_number[next] != B_TRUE) {
13810Sstevel@tonic-gate break;
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate
13860Sstevel@tonic-gate if (next == _max_devs_cfg) {
13870Sstevel@tonic-gate volume_set_error(
13880Sstevel@tonic-gate gettext("ran out of logical volume names.\n"));
13890Sstevel@tonic-gate return (-1);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate *name = (char *)calloc(MAXNAMELEN, sizeof (char));
13930Sstevel@tonic-gate if (*name == NULL) {
13940Sstevel@tonic-gate return (ENOMEM);
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate (void) snprintf(*name, MAXNAMELEN-1, "%s%d", _dev_prefix, next);
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate devs_by_number[next] = B_TRUE;
14000Sstevel@tonic-gate return (0);
14010Sstevel@tonic-gate }
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate /*
14040Sstevel@tonic-gate * FUNCTION: get_next_submirror_name(char *mname, char **subname)
14050Sstevel@tonic-gate *
14060Sstevel@tonic-gate * INPUT: mname - pointer to a char * mirror name
14070Sstevel@tonic-gate * OUTPUT: subname - pointer to a char * to hold submirror name
14080Sstevel@tonic-gate *
14090Sstevel@tonic-gate * RETURNS: int - 0 on success
14100Sstevel@tonic-gate * !0 otherwise
14110Sstevel@tonic-gate *
14120Sstevel@tonic-gate * PURPOSE: Determine the next available submirror name according
14130Sstevel@tonic-gate * to the convention that each submirror name is a sequential
14140Sstevel@tonic-gate * increment of its mirror's name.
14150Sstevel@tonic-gate *
14160Sstevel@tonic-gate * If such a name is unavailable, return the next sequentially
14170Sstevel@tonic-gate * available volume name.
14180Sstevel@tonic-gate */
14190Sstevel@tonic-gate int
get_next_submirror_name(char * mname,char ** subname)14200Sstevel@tonic-gate get_next_submirror_name(
14210Sstevel@tonic-gate char *mname,
14220Sstevel@tonic-gate char **subname)
14230Sstevel@tonic-gate {
14240Sstevel@tonic-gate char buf[MAXNAMELEN];
14250Sstevel@tonic-gate int error = 0;
14260Sstevel@tonic-gate int next = 0;
14270Sstevel@tonic-gate int i = 0;
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate *subname = NULL;
14300Sstevel@tonic-gate
14310Sstevel@tonic-gate /* try next sequential name: mirror + 1... */
14320Sstevel@tonic-gate if (extract_index(mname, _dev_prefix, "%d", &next)) {
14330Sstevel@tonic-gate for (i = next + 1; i < _max_devs_cfg; i++) {
14340Sstevel@tonic-gate if ((i % 10) == 0) {
14350Sstevel@tonic-gate /* save for mirrors */
14360Sstevel@tonic-gate continue;
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate if (devs_by_number[i] == B_FALSE) {
14390Sstevel@tonic-gate (void) snprintf(buf, MAXNAMELEN-1, "%s%d", _dev_prefix, i);
14400Sstevel@tonic-gate if ((*subname = strdup(buf)) != NULL) {
14410Sstevel@tonic-gate devs_by_number[i] = B_TRUE;
14420Sstevel@tonic-gate } else {
14430Sstevel@tonic-gate error = ENOMEM;
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate break;
14460Sstevel@tonic-gate }
14470Sstevel@tonic-gate }
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate if ((error == 0) && (*subname == NULL)) {
14510Sstevel@tonic-gate /* name adhering to convention isn't available, */
14520Sstevel@tonic-gate /* use next sequentially available name */
14530Sstevel@tonic-gate error = get_next_volume_name(subname, TYPE_STRIPE);
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate return (error);
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate /*
14600Sstevel@tonic-gate * FUNCTION: get_next_hsp_name(char **name)
14610Sstevel@tonic-gate *
14620Sstevel@tonic-gate * OUTPUT: name - pointer to a char * to hold name
14630Sstevel@tonic-gate *
14640Sstevel@tonic-gate * RETURNS: int - 0 on success
14650Sstevel@tonic-gate * !0 otherwise
14660Sstevel@tonic-gate *
14670Sstevel@tonic-gate * PURPOSE: Helper which generates a new hotsparepool name
14680Sstevel@tonic-gate * using the standard name prefix and the lowest
14690Sstevel@tonic-gate * available hsp number.
14700Sstevel@tonic-gate */
14710Sstevel@tonic-gate int
get_next_hsp_name(char ** name)14720Sstevel@tonic-gate get_next_hsp_name(
14730Sstevel@tonic-gate char **name)
14740Sstevel@tonic-gate {
14750Sstevel@tonic-gate int next = 0;
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate for (next = 0; next < _max_hsps; ++next) {
14780Sstevel@tonic-gate if (hsps_by_number[next] != B_TRUE) {
14790Sstevel@tonic-gate break;
14800Sstevel@tonic-gate }
14810Sstevel@tonic-gate }
14820Sstevel@tonic-gate
14830Sstevel@tonic-gate if (next == _max_hsps) {
14840Sstevel@tonic-gate volume_set_error(gettext("ran out of HSP names"));
14850Sstevel@tonic-gate return (-1);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate *name = (char *)calloc(MAXNAMELEN, sizeof (char));
14890Sstevel@tonic-gate if (*name == NULL) {
14900Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
14910Sstevel@tonic-gate gettext("failed to allocate volume name string, "
14920Sstevel@tonic-gate "out of memory"));
14930Sstevel@tonic-gate return (ENOMEM);
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate (void) snprintf(*name, MAXNAMELEN-1, "%s%03d", _hsp_prefix, next);
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate hsps_by_number[next] = B_TRUE;
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate return (0);
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate static char *
type_name(svm_type_t type)15040Sstevel@tonic-gate type_name(
15050Sstevel@tonic-gate svm_type_t type)
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate switch (type) {
15080Sstevel@tonic-gate case SVM_DISKSET: return (gettext("disk set"));
15090Sstevel@tonic-gate case SVM_MDB: return (gettext("metadb"));
15100Sstevel@tonic-gate case SVM_STRIPE: return (gettext("stripe"));
15110Sstevel@tonic-gate case SVM_MIRROR: return (gettext("mirror"));
15120Sstevel@tonic-gate case SVM_RAID: return (gettext("raid"));
15130Sstevel@tonic-gate case SVM_TRANS: return (gettext("trans"));
15140Sstevel@tonic-gate case SVM_SP: return (gettext("soft partition"));
15150Sstevel@tonic-gate case SVM_HSP: return (gettext("hot spare pool"));
15160Sstevel@tonic-gate case SVM_HS: return (gettext("hot spare"));
15170Sstevel@tonic-gate case SVM_DRIVE: return (gettext("drive"));
15180Sstevel@tonic-gate default: return (gettext("unknown"));
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate }
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate static svm_snap_t *
svm_snapshot(int * errp)15230Sstevel@tonic-gate svm_snapshot(int *errp)
15240Sstevel@tonic-gate {
15250Sstevel@tonic-gate svm_snap_t *svm_listp = NULL;
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate *errp = 0;
15280Sstevel@tonic-gate
15290Sstevel@tonic-gate /* initialize the cluster library entry points */
15300Sstevel@tonic-gate if (sdssc_bind_library() == SDSSC_ERROR) {
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate volume_set_error(gettext("sdssc_bin_library() failed\n"));
15330Sstevel@tonic-gate *errp = -1;
15340Sstevel@tonic-gate
15350Sstevel@tonic-gate } else {
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate /* load the SVM cache */
15380Sstevel@tonic-gate *errp = load_svm(&svm_listp);
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate if (*errp != 0) {
15410Sstevel@tonic-gate free_svm_snapshot(svm_listp);
15420Sstevel@tonic-gate svm_listp = NULL;
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate }
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate return (svm_listp);
15480Sstevel@tonic-gate }
15490Sstevel@tonic-gate
15500Sstevel@tonic-gate static void
free_svm_snapshot(svm_snap_t * listp)15510Sstevel@tonic-gate free_svm_snapshot(svm_snap_t *listp) {
15520Sstevel@tonic-gate
15530Sstevel@tonic-gate svm_snap_t *nextp;
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate while (listp != NULL) {
15560Sstevel@tonic-gate nextp = listp->next;
15570Sstevel@tonic-gate free((void *)listp->diskset);
15580Sstevel@tonic-gate free((void *)listp->name);
15590Sstevel@tonic-gate free((void *)listp->slice);
15600Sstevel@tonic-gate free((void *)listp);
15610Sstevel@tonic-gate listp = nextp;
15620Sstevel@tonic-gate }
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate static int
add_record(svm_snap_t ** listp,char * setname,svm_type_t type,char * mname,char * slice_name)15660Sstevel@tonic-gate add_record(
15670Sstevel@tonic-gate svm_snap_t **listp,
15680Sstevel@tonic-gate char *setname,
15690Sstevel@tonic-gate svm_type_t type,
15700Sstevel@tonic-gate char *mname,
15710Sstevel@tonic-gate char *slice_name)
15720Sstevel@tonic-gate {
15730Sstevel@tonic-gate svm_snap_t *sp;
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate sp = (svm_snap_t *)malloc(sizeof (svm_snap_t));
15760Sstevel@tonic-gate if (sp == NULL) {
15770Sstevel@tonic-gate return (ENOMEM);
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate if ((sp->diskset = strdup(setname)) == NULL) {
15810Sstevel@tonic-gate free(sp);
15820Sstevel@tonic-gate return (ENOMEM);
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate
15850Sstevel@tonic-gate if ((sp->name = strdup(mname)) == NULL) {
15860Sstevel@tonic-gate free(sp->diskset);
15870Sstevel@tonic-gate free(sp);
15880Sstevel@tonic-gate return (ENOMEM);
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate sp->type = type;
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate if ((sp->slice = strdup(slice_name)) == NULL) {
15940Sstevel@tonic-gate free(sp->diskset);
15950Sstevel@tonic-gate free(sp->name);
15960Sstevel@tonic-gate free(sp);
15970Sstevel@tonic-gate return (ENOMEM);
15980Sstevel@tonic-gate }
15990Sstevel@tonic-gate
16000Sstevel@tonic-gate sp->next = *listp;
16010Sstevel@tonic-gate *listp = sp;
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate return (0);
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate
16060Sstevel@tonic-gate static int
diskset_info(svm_snap_t ** listp,mdsetname_t * sp)16070Sstevel@tonic-gate diskset_info(
16080Sstevel@tonic-gate svm_snap_t **listp,
16090Sstevel@tonic-gate mdsetname_t *sp)
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate md_error_t error = mdnullerror;
16120Sstevel@tonic-gate md_replicalist_t *replica_list = NULL;
16130Sstevel@tonic-gate md_replicalist_t *mdbp;
16140Sstevel@tonic-gate mdnamelist_t *nlp;
16150Sstevel@tonic-gate mdnamelist_t *trans_list = NULL;
16160Sstevel@tonic-gate mdnamelist_t *mirror_list = NULL;
16170Sstevel@tonic-gate mdnamelist_t *raid_list = NULL;
16180Sstevel@tonic-gate mdnamelist_t *stripe_list = NULL;
16190Sstevel@tonic-gate mdnamelist_t *sp_list = NULL;
16200Sstevel@tonic-gate mdhspnamelist_t *hsp_list = NULL;
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate if (metareplicalist(sp, MD_BASICNAME_OK, &replica_list, &error) < 0) {
16230Sstevel@tonic-gate /* there are no metadb's; that is ok, no need to check the rest */
16240Sstevel@tonic-gate mdclrerror(&error);
16250Sstevel@tonic-gate return (0);
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate mdclrerror(&error);
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate for (mdbp = replica_list; mdbp != NULL; mdbp = mdbp->rl_next) {
16300Sstevel@tonic-gate char size[MAXPATHLEN];
16310Sstevel@tonic-gate
16320Sstevel@tonic-gate (void) snprintf(size, sizeof (size), "%d",
16330Sstevel@tonic-gate (int)mdbp->rl_repp->r_nblk);
16340Sstevel@tonic-gate
16350Sstevel@tonic-gate if (new_entry(listp, mdbp->rl_repp->r_namep->cname, SVM_MDB, size,
16360Sstevel@tonic-gate sp)) {
16370Sstevel@tonic-gate metafreereplicalist(replica_list);
16380Sstevel@tonic-gate return (ENOMEM);
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate }
16410Sstevel@tonic-gate metafreereplicalist(replica_list);
16420Sstevel@tonic-gate
16430Sstevel@tonic-gate if (meta_get_trans_names(sp, &trans_list, 0, &error) >= 0) {
16440Sstevel@tonic-gate for (nlp = trans_list; nlp != NULL; nlp = nlp->next) {
16450Sstevel@tonic-gate if (new_entry(listp, nlp->namep->cname, SVM_TRANS,
16460Sstevel@tonic-gate nlp->namep->cname, sp)) {
16470Sstevel@tonic-gate free_names(trans_list);
16480Sstevel@tonic-gate return (ENOMEM);
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate free_names(trans_list);
16530Sstevel@tonic-gate }
16540Sstevel@tonic-gate mdclrerror(&error);
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate if (meta_get_mirror_names(sp, &mirror_list, 0, &error) >= 0) {
16570Sstevel@tonic-gate for (nlp = mirror_list; nlp != NULL; nlp = nlp->next) {
16580Sstevel@tonic-gate if (add_record(listp, sp->setname, SVM_MIRROR,
16590Sstevel@tonic-gate nlp->namep->cname, "")) {
16600Sstevel@tonic-gate free_names(mirror_list);
16610Sstevel@tonic-gate return (ENOMEM);
16620Sstevel@tonic-gate }
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate
16650Sstevel@tonic-gate free_names(mirror_list);
16660Sstevel@tonic-gate }
16670Sstevel@tonic-gate mdclrerror(&error);
16680Sstevel@tonic-gate
16690Sstevel@tonic-gate if (meta_get_raid_names(sp, &raid_list, 0, &error) >= 0) {
16700Sstevel@tonic-gate for (nlp = raid_list; nlp != NULL; nlp = nlp->next) {
16710Sstevel@tonic-gate mdname_t *mdn;
16720Sstevel@tonic-gate md_raid_t *raid;
16730Sstevel@tonic-gate
1674*1623Stw21770 mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
16750Sstevel@tonic-gate mdclrerror(&error);
16760Sstevel@tonic-gate if (mdn == NULL) {
16770Sstevel@tonic-gate continue;
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate raid = meta_get_raid(sp, mdn, &error);
16810Sstevel@tonic-gate mdclrerror(&error);
16820Sstevel@tonic-gate
16830Sstevel@tonic-gate if (raid != NULL) {
16840Sstevel@tonic-gate int i;
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate for (i = 0; i < raid->cols.cols_len; i++) {
16870Sstevel@tonic-gate if (new_entry(listp,
16880Sstevel@tonic-gate raid->cols.cols_val[i].colnamep->cname, SVM_RAID,
16890Sstevel@tonic-gate nlp->namep->cname, sp)) {
16900Sstevel@tonic-gate free_names(raid_list);
16910Sstevel@tonic-gate return (ENOMEM);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate }
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate }
16960Sstevel@tonic-gate
16970Sstevel@tonic-gate free_names(raid_list);
16980Sstevel@tonic-gate }
16990Sstevel@tonic-gate mdclrerror(&error);
17000Sstevel@tonic-gate
17010Sstevel@tonic-gate if (meta_get_stripe_names(sp, &stripe_list, 0, &error) >= 0) {
17020Sstevel@tonic-gate for (nlp = stripe_list; nlp != NULL; nlp = nlp->next) {
17030Sstevel@tonic-gate mdname_t *mdn;
17040Sstevel@tonic-gate md_stripe_t *stripe;
17050Sstevel@tonic-gate
1706*1623Stw21770 mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
17070Sstevel@tonic-gate mdclrerror(&error);
17080Sstevel@tonic-gate if (mdn == NULL) {
17090Sstevel@tonic-gate continue;
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate stripe = meta_get_stripe(sp, mdn, &error);
17130Sstevel@tonic-gate mdclrerror(&error);
17140Sstevel@tonic-gate
17150Sstevel@tonic-gate if (stripe != NULL) {
17160Sstevel@tonic-gate int i;
17170Sstevel@tonic-gate
17180Sstevel@tonic-gate for (i = 0; i < stripe->rows.rows_len; i++) {
17190Sstevel@tonic-gate md_row_t *rowp;
17200Sstevel@tonic-gate int j;
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate rowp = &stripe->rows.rows_val[i];
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate for (j = 0; j < rowp->comps.comps_len; j++) {
17250Sstevel@tonic-gate md_comp_t *component;
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate component = &rowp->comps.comps_val[j];
17280Sstevel@tonic-gate if (new_entry(listp, component->compnamep->cname,
17290Sstevel@tonic-gate SVM_STRIPE, nlp->namep->cname, sp)) {
17300Sstevel@tonic-gate free_names(stripe_list);
17310Sstevel@tonic-gate return (ENOMEM);
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate }
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate }
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate free_names(stripe_list);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate mdclrerror(&error);
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate if (meta_get_sp_names(sp, &sp_list, 0, &error) >= 0) {
17430Sstevel@tonic-gate for (nlp = sp_list; nlp != NULL; nlp = nlp->next) {
17440Sstevel@tonic-gate mdname_t *mdn;
17450Sstevel@tonic-gate md_sp_t *soft_part;
17460Sstevel@tonic-gate
1747*1623Stw21770 mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
17480Sstevel@tonic-gate mdclrerror(&error);
17490Sstevel@tonic-gate if (mdn == NULL) {
17500Sstevel@tonic-gate continue;
17510Sstevel@tonic-gate }
17520Sstevel@tonic-gate
17530Sstevel@tonic-gate soft_part = meta_get_sp(sp, mdn, &error);
17540Sstevel@tonic-gate mdclrerror(&error);
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate if (soft_part != NULL) {
17570Sstevel@tonic-gate if (new_entry(listp, soft_part->compnamep->cname, SVM_SP,
17580Sstevel@tonic-gate nlp->namep->cname, sp)) {
17590Sstevel@tonic-gate free_names(sp_list);
17600Sstevel@tonic-gate return (ENOMEM);
17610Sstevel@tonic-gate }
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate }
17640Sstevel@tonic-gate
17650Sstevel@tonic-gate free_names(sp_list);
17660Sstevel@tonic-gate }
17670Sstevel@tonic-gate mdclrerror(&error);
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) {
17700Sstevel@tonic-gate mdhspnamelist_t *nlp;
17710Sstevel@tonic-gate
17720Sstevel@tonic-gate for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) {
17730Sstevel@tonic-gate md_hsp_t *hsp;
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate hsp = meta_get_hsp(sp, nlp->hspnamep, &error);
17760Sstevel@tonic-gate mdclrerror(&error);
17770Sstevel@tonic-gate if (hsp != NULL) {
17780Sstevel@tonic-gate int i;
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate for (i = 0; i < hsp->hotspares.hotspares_len; i++) {
17810Sstevel@tonic-gate md_hs_t *hs;
17820Sstevel@tonic-gate
17830Sstevel@tonic-gate hs = &hsp->hotspares.hotspares_val[i];
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate if (add_record(listp, sp->setname, SVM_HS,
17860Sstevel@tonic-gate nlp->hspnamep->hspname, hs->hsnamep->bname)) {
17870Sstevel@tonic-gate metafreehspnamelist(hsp_list);
17880Sstevel@tonic-gate return (ENOMEM);
17890Sstevel@tonic-gate }
17900Sstevel@tonic-gate }
17910Sstevel@tonic-gate }
17920Sstevel@tonic-gate
17930Sstevel@tonic-gate if (add_record(listp, sp->setname, SVM_HSP,
17940Sstevel@tonic-gate nlp->hspnamep->hspname, "")) {
17950Sstevel@tonic-gate metafreehspnamelist(hsp_list);
17960Sstevel@tonic-gate return (ENOMEM);
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate }
17990Sstevel@tonic-gate
18000Sstevel@tonic-gate metafreehspnamelist(hsp_list);
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate mdclrerror(&error);
18040Sstevel@tonic-gate
18050Sstevel@tonic-gate return (0);
18060Sstevel@tonic-gate }
18070Sstevel@tonic-gate
18080Sstevel@tonic-gate static void
free_names(mdnamelist_t * nlp)18090Sstevel@tonic-gate free_names(
18100Sstevel@tonic-gate mdnamelist_t *nlp)
18110Sstevel@tonic-gate {
18120Sstevel@tonic-gate mdnamelist_t *p;
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate for (p = nlp; p != NULL; p = p->next) {
18150Sstevel@tonic-gate meta_invalidate_name(p->namep);
18160Sstevel@tonic-gate }
18170Sstevel@tonic-gate metafreenamelist(nlp);
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate
18200Sstevel@tonic-gate /*
18210Sstevel@tonic-gate * Create a list of SVM devices
18220Sstevel@tonic-gate */
18230Sstevel@tonic-gate static int
load_svm(svm_snap_t ** listp)18240Sstevel@tonic-gate load_svm(
18250Sstevel@tonic-gate svm_snap_t **listp)
18260Sstevel@tonic-gate {
18270Sstevel@tonic-gate int max_sets;
18280Sstevel@tonic-gate md_error_t error = mdnullerror;
18290Sstevel@tonic-gate int i;
18300Sstevel@tonic-gate
18310Sstevel@tonic-gate if ((max_sets = get_max_sets(&error)) == 0) {
18320Sstevel@tonic-gate return (0);
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate if (!mdisok(&error)) {
18360Sstevel@tonic-gate volume_set_error(
18370Sstevel@tonic-gate gettext("failed to get maximum number of disk sets.\n"));
18380Sstevel@tonic-gate mdclrerror(&error);
18390Sstevel@tonic-gate return (-1);
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate /* for each possible set number, see if we really have a disk set */
18430Sstevel@tonic-gate for (i = 0; i < max_sets; i++) {
18440Sstevel@tonic-gate mdsetname_t *sp;
18450Sstevel@tonic-gate
18460Sstevel@tonic-gate if ((sp = metasetnosetname(i, &error)) == NULL) {
18470Sstevel@tonic-gate if (!mdisok(&error) && error.info.errclass == MDEC_RPC) {
18480Sstevel@tonic-gate /* rpc error - no metasets */
18490Sstevel@tonic-gate break;
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate mdclrerror(&error);
18530Sstevel@tonic-gate continue;
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate mdclrerror(&error);
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate if (add_record(listp, sp->setname, SVM_DISKSET, sp->setname, "")) {
18590Sstevel@tonic-gate metaflushsetname(sp);
18600Sstevel@tonic-gate return (ENOMEM);
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate
18630Sstevel@tonic-gate /* check for drives in disk sets */
18640Sstevel@tonic-gate if (sp->setno != 0) {
18650Sstevel@tonic-gate md_drive_desc *dd;
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate dd = metaget_drivedesc(sp, MD_BASICNAME_OK | PRINT_FAST,
18680Sstevel@tonic-gate &error);
18690Sstevel@tonic-gate mdclrerror(&error);
18700Sstevel@tonic-gate for (; dd != NULL; dd = dd->dd_next) {
18710Sstevel@tonic-gate if (add_record(listp, sp->setname, SVM_DRIVE,
18720Sstevel@tonic-gate dd->dd_dnp->rname, "")) {
18730Sstevel@tonic-gate metaflushsetname(sp);
18740Sstevel@tonic-gate return (ENOMEM);
18750Sstevel@tonic-gate }
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate if (diskset_info(listp, sp)) {
18800Sstevel@tonic-gate metaflushsetname(sp);
18810Sstevel@tonic-gate return (ENOMEM);
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18840Sstevel@tonic-gate metaflushsetname(sp);
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate mdclrerror(&error);
18880Sstevel@tonic-gate
18890Sstevel@tonic-gate return (0);
18900Sstevel@tonic-gate }
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate /* determine if 'sp' is built on a slice */
18930Sstevel@tonic-gate static int
new_entry(svm_snap_t ** listp,char * slice_name,svm_type_t type,char * mname,mdsetname_t * sp)18940Sstevel@tonic-gate new_entry(
18950Sstevel@tonic-gate svm_snap_t **listp,
18960Sstevel@tonic-gate char *slice_name,
18970Sstevel@tonic-gate svm_type_t type,
18980Sstevel@tonic-gate char *mname,
18990Sstevel@tonic-gate mdsetname_t *sp)
19000Sstevel@tonic-gate {
19010Sstevel@tonic-gate mdname_t *mdn;
19020Sstevel@tonic-gate md_error_t error = mdnullerror;
1903*1623Stw21770 meta_device_type_t uname_type = UNKNOWN;
19040Sstevel@tonic-gate
1905*1623Stw21770 /* Determine the appropriate uname type for metaname */
1906*1623Stw21770 if (type == SVM_MDB || type == SVM_DRIVE || type == SVM_TRANS)
1907*1623Stw21770 uname_type = LOGICAL_DEVICE;
1908*1623Stw21770
1909*1623Stw21770 mdn = metaname(&sp, slice_name, uname_type, &error);
19100Sstevel@tonic-gate if (!mdisok(&error)) {
19110Sstevel@tonic-gate mdn = NULL;
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate mdclrerror(&error);
19140Sstevel@tonic-gate
19150Sstevel@tonic-gate if (mdn != NULL && (
19160Sstevel@tonic-gate mdn->drivenamep->type == MDT_ACCES ||
19170Sstevel@tonic-gate mdn->drivenamep->type == MDT_COMP ||
19180Sstevel@tonic-gate mdn->drivenamep->type == MDT_FAST_COMP)) {
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate return (add_record(listp, sp->setname, type, mname, mdn->bname));
19210Sstevel@tonic-gate } else {
19220Sstevel@tonic-gate return (add_record(listp, sp->setname, type, mname, ""));
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate /*
19270Sstevel@tonic-gate * FUNCTION: get_default_stripe_interlace()
19280Sstevel@tonic-gate *
19290Sstevel@tonic-gate * RETURNS: uint64_t - default stripe interlace value
19300Sstevel@tonic-gate *
19310Sstevel@tonic-gate * PURPOSE: Helper which retrieves the default stripe interlace
19320Sstevel@tonic-gate * from libmeta.
19330Sstevel@tonic-gate */
19340Sstevel@tonic-gate uint64_t
get_default_stripe_interlace()19350Sstevel@tonic-gate get_default_stripe_interlace()
19360Sstevel@tonic-gate {
19370Sstevel@tonic-gate /* convert back to bytes */
19380Sstevel@tonic-gate return ((uint64_t)meta_default_stripe_interlace() * DEV_BSIZE);
19390Sstevel@tonic-gate }
19400Sstevel@tonic-gate
19410Sstevel@tonic-gate /*
19420Sstevel@tonic-gate * FUNCTION: get_max_number_of_devices(int *max)
19430Sstevel@tonic-gate *
19440Sstevel@tonic-gate * OUTPUT: max - pointer to int to hold the configured maximum number
19450Sstevel@tonic-gate * of SVM devices
19460Sstevel@tonic-gate *
19470Sstevel@tonic-gate * RETURNS: int - 0 on success
19480Sstevel@tonic-gate * !0 otherwise
19490Sstevel@tonic-gate *
19500Sstevel@tonic-gate * PURPOSE: Helper which determines the maximum number of allowed
19510Sstevel@tonic-gate * SVM devices configured for the system.
19520Sstevel@tonic-gate *
19530Sstevel@tonic-gate * Wrapper around libmeta function meta_get_max_nunits().
19540Sstevel@tonic-gate */
19550Sstevel@tonic-gate int
get_max_number_of_devices(int * max)19560Sstevel@tonic-gate get_max_number_of_devices(
19570Sstevel@tonic-gate int *max)
19580Sstevel@tonic-gate {
19590Sstevel@tonic-gate md_error_t mderror = mdnullerror;
19600Sstevel@tonic-gate
19610Sstevel@tonic-gate *max = meta_get_nunits(&mderror);
19620Sstevel@tonic-gate if (!mdisok(&mderror)) {
19630Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
19640Sstevel@tonic-gate mdclrerror(&mderror);
19650Sstevel@tonic-gate return (-1);
19660Sstevel@tonic-gate }
19670Sstevel@tonic-gate
19680Sstevel@tonic-gate return (0);
19690Sstevel@tonic-gate }
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate /*
19720Sstevel@tonic-gate * FUNCTION: get_max_number_of_disksets(int *max)
19730Sstevel@tonic-gate *
19740Sstevel@tonic-gate * OUTPUT: max - pointer to in to hold the configured maximum number
19750Sstevel@tonic-gate * of disk sets
19760Sstevel@tonic-gate *
19770Sstevel@tonic-gate * RETURNS: int - 0 on success
19780Sstevel@tonic-gate * !0 otherwise
19790Sstevel@tonic-gate *
19800Sstevel@tonic-gate * PURPOSE: Helper which determines the maximum number of allowed
19810Sstevel@tonic-gate * disk sets which has been configured for the system.
19820Sstevel@tonic-gate *
19830Sstevel@tonic-gate * Wrapper around libmeta function get_max_sets().
19840Sstevel@tonic-gate */
19850Sstevel@tonic-gate int
get_max_number_of_disksets(int * max)19860Sstevel@tonic-gate get_max_number_of_disksets(
19870Sstevel@tonic-gate int *max)
19880Sstevel@tonic-gate {
19890Sstevel@tonic-gate md_error_t mderror = mdnullerror;
19900Sstevel@tonic-gate
19910Sstevel@tonic-gate *max = get_max_sets(&mderror);
19920Sstevel@tonic-gate if (!mdisok(&mderror)) {
19930Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
19940Sstevel@tonic-gate mdclrerror(&mderror);
19950Sstevel@tonic-gate return (-1);
19960Sstevel@tonic-gate }
19970Sstevel@tonic-gate
19980Sstevel@tonic-gate return (0);
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate /*
20020Sstevel@tonic-gate * FUNCTION: is_reserved_replica_slice_index(char *diskset, char *dname,
20030Sstevel@tonic-gate * uint32_t index, boolean_t *bool)
20040Sstevel@tonic-gate *
20050Sstevel@tonic-gate * INPUT: diskset - char * disk set name
20060Sstevel@tonic-gate * dname - char * disk name
20070Sstevel@tonic-gate * index - integer index of interest
20080Sstevel@tonic-gate *
20090Sstevel@tonic-gate * OUTPUT: bool - pointer to a boolean_t to hold the result
20100Sstevel@tonic-gate *
20110Sstevel@tonic-gate * RETURNS: int - 0 - success
20120Sstevel@tonic-gate * !0 - failure
20130Sstevel@tonic-gate *
20140Sstevel@tonic-gate * PURPOSE: Helper which determines if the input slice index on
20150Sstevel@tonic-gate * the named disk in the named disk set is the replica
20160Sstevel@tonic-gate * slice that is reserved on disks in disk sets.
20170Sstevel@tonic-gate *
20180Sstevel@tonic-gate * The named disk is assumed to be in the named disk set.
20190Sstevel@tonic-gate *
20200Sstevel@tonic-gate * Determines if metassist is being run in a simulated
20210Sstevel@tonic-gate * hardware enironment, if not the libmeta function to
20220Sstevel@tonic-gate * determine the replica slice index is called.
20230Sstevel@tonic-gate *
20240Sstevel@tonic-gate * If simulation is active, then a local implementation
20250Sstevel@tonic-gate * is used to determine the replica slice index.
20260Sstevel@tonic-gate */
20270Sstevel@tonic-gate int
is_reserved_replica_slice_index(char * diskset,char * dname,uint32_t index,boolean_t * bool)20280Sstevel@tonic-gate is_reserved_replica_slice_index(
20290Sstevel@tonic-gate char *diskset,
20300Sstevel@tonic-gate char *dname,
20310Sstevel@tonic-gate uint32_t index,
20320Sstevel@tonic-gate boolean_t *bool)
20330Sstevel@tonic-gate {
20340Sstevel@tonic-gate int error = 0;
20350Sstevel@tonic-gate boolean_t sim = B_FALSE;
20360Sstevel@tonic-gate static char *simfile = "METASSISTSIMFILE";
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0));
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate if (sim != B_TRUE) {
20410Sstevel@tonic-gate
20420Sstevel@tonic-gate /* sim disabled: use meta_replicaslice() */
20430Sstevel@tonic-gate
20440Sstevel@tonic-gate md_error_t mderror = mdnullerror;
20450Sstevel@tonic-gate mdsetname_t *sp;
20460Sstevel@tonic-gate mddrivename_t *dnp;
20470Sstevel@tonic-gate uint_t replicaslice;
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate /* slice assumed to be on disk in the named disk set */
20500Sstevel@tonic-gate sp = metasetname(diskset, &mderror);
20510Sstevel@tonic-gate if (!mdisok(&mderror)) {
20520Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
20530Sstevel@tonic-gate mdclrerror(&mderror);
20540Sstevel@tonic-gate return (-1);
20550Sstevel@tonic-gate }
20560Sstevel@tonic-gate
20570Sstevel@tonic-gate dnp = metadrivename(&sp, dname, &mderror);
20580Sstevel@tonic-gate if (!mdisok(&mderror)) {
20590Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
20600Sstevel@tonic-gate mdclrerror(&mderror);
20610Sstevel@tonic-gate return (-1);
20620Sstevel@tonic-gate }
20630Sstevel@tonic-gate
20640Sstevel@tonic-gate if (meta_replicaslice(dnp, &replicaslice, &mderror) != 0) {
20650Sstevel@tonic-gate volume_set_error(mde_sperror(&mderror, NULL));
20660Sstevel@tonic-gate mdclrerror(&mderror);
20670Sstevel@tonic-gate return (-1);
20680Sstevel@tonic-gate }
20690Sstevel@tonic-gate
20700Sstevel@tonic-gate *bool = (replicaslice == (uint_t)index);
20710Sstevel@tonic-gate
20720Sstevel@tonic-gate } else {
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate dm_descriptor_t disk;
20750Sstevel@tonic-gate boolean_t efi = B_FALSE;
20760Sstevel@tonic-gate
20770Sstevel@tonic-gate /* sim enabled: use same logic as meta_replicaslice() */
20780Sstevel@tonic-gate ((error = disk_get_by_name(dname, &disk)) != 0) ||
20790Sstevel@tonic-gate (error = disk_get_is_efi(disk, &efi));
20800Sstevel@tonic-gate if (error == 0) {
20810Sstevel@tonic-gate
20820Sstevel@tonic-gate if (efi == B_FALSE) {
20830Sstevel@tonic-gate *bool = (index == MD_SLICE7);
20840Sstevel@tonic-gate } else {
20850Sstevel@tonic-gate *bool = (index == MD_SLICE6);
20860Sstevel@tonic-gate }
20870Sstevel@tonic-gate }
20880Sstevel@tonic-gate }
20890Sstevel@tonic-gate
20900Sstevel@tonic-gate return (error);
20910Sstevel@tonic-gate }
2092