/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <meta.h>
#include <sdssc.h>
#include <mdiox.h>
#include <meta_repartition.h>
#include "volume_dlist.h"
#include "volume_error.h"
#include "volume_output.h"
#include "layout_device_util.h"
#include "layout_discovery.h"
#include "layout_dlist_util.h"
#include "layout_request.h"
#include "layout_svm_util.h"
/* volume name prefixes for generating new names */
/*
* dynamically allocated arrays to track used HSP (hspXXX) and volume
* names (dXXX) by number
*/
/*
* This struct remembers a diskset and the names of
* the disks in the set
*/
typedef struct {
char *name;
} diskset_t;
/*
* list of diskset_t for known disksets
*/
static int add_diskset(
char *diskset);
static int add_diskset_diskname(
char *diskset,
char *diskname);
static int add_diskset_hsp(
char *diskset,
char *hspname);
static int add_diskset_hsp_spare(
char *diskset,
char *hspname,
char *spare);
static int is_disk_in_local_diskset(
boolean_t *bool);
static int is_disk_in_named_diskset(
char *dsname,
boolean_t *bool);
/* SVM snapshot stuff */
typedef enum {
SVM_DISKSET = 0,
} svm_type_t;
typedef struct svm_snap_entry {
char *diskset;
char *name;
char *slice;
} svm_snap_t;
static int add_record(
svm_snap_t **listp,
char *setname,
char *mname,
char *slice_name);
static int new_entry(
svm_snap_t **listp,
char *sname,
char *mname,
mdsetname_t *sp);
/*
* FUNCTION: scan_svm_names(char *diskset)
*
* INPUT: diskset - a char * disk set name
*
* PURPOSE: Take a snapshot of the current SVM config.
*
* Scan it and remember:
* 1. all known disk sets
* s. the disks in the named disk set
* 3. the used device and HSP names in the named disk set
* 4. the HSPs in the disk set
* 5. the spares in the HSPs
*/
int
char *diskset)
{
int ndisks = 0;
int nhsps = 0;
int ndevices = 0;
int nsets = 0;
int number = 0;
int error = 0;
gettext("\nScanning system SVM configuration...\n"));
if (error != 0) {
gettext("failed to scan SVM devices\n"));
return (error);
}
if (error == 0) {
gettext(" configured maximum number of "
"volumes: %d\n"),
}
}
if (error == 0) {
gettext(" configured maximum number of "
"disk sets: %d\n"),
}
}
if (error == 0) {
/* array is realloc'ed as necessary */
if ((hsps_by_number =
gettext("failed to allocate HSP name array\n"));
}
}
if (error == 0) {
/* array is realloc'ed as necessary */
if ((devs_by_number =
gettext("failed to allocate volume name array\n"));
}
}
(void) oprintf(OUTPUT_DEBUG,
gettext("disk set"),
gettext("dev type"),
gettext("name"),
gettext("slice"));
(void) oprintf(OUTPUT_DEBUG,
" -----------------------------------"
"-----------------------------------\n");
}
case SVM_DISKSET:
++nsets;
break;
case SVM_DRIVE:
/* is this drive in the requested diskset? */
++ndisks;
}
break;
case SVM_MIRROR:
case SVM_RAID:
case SVM_TRANS:
case SVM_SP:
case SVM_STRIPE:
/* is this SVM volume in the requested diskset? */
++cp;
} else {
}
/* BEGIN CSTYLED */
/*
* names for requested devices and HSPs are remembered
* so that the default name generation scheme knows
* which names are already being used
*/
/* END CSTYLED */
/* extract device number from name "dXXXX" */
gettext(" device: %6s number: %3d\n"),
/* hit current limit, expand it */
} else {
}
}
if ((error == 0) &&
++ndevices;
}
}
}
break;
case SVM_HSP:
/* is this HSP in the requested diskset? */
++cp;
} else {
}
/* extract pool number from name "hspXXX" */
gettext(" HSP: %6s number: %3d\n"),
/* hit our arbitrary limit, double it */
_max_hsps *= 2;
} else {
}
}
if ((error == 0) &&
++nhsps;
}
}
}
break;
case SVM_HS:
/* is this hot spare in the requested disk set? */
++cp;
} else {
}
}
break;
case SVM_MDB:
default:
break;
}
}
if (error == 0) {
/* available diskset? subtract 1 for the local set */
gettext("Disk set \"%s\" cannot be created, the "
"maximum number of disk sets (%d) already "
"exists.\n"),
error = -1;
}
}
if (error == 0) {
} else {
}
return (error);
}
/*
* FUNCTION: release_svm_names()
*
* PURPOSE: Release snapshot of the current SVM config.
*
* Free memory allocated by scan_svm_names()
*/
void
{
}
if (hsps_by_number != NULL)
if (devs_by_number != NULL)
}
/*
* FUNCTION: diskset_exists(char *diskset)
*
* INPUT: dsname - a char * diskset name
*
* RETURNS: boolean_t - B_TRUE if the named diskset exists
* B_FALSE otherwise
*
* PURPOSE: Checks the list of known disk sets and determines
* if the input name is in that list.
*/
char *dsname)
{
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* FUNCTION: add_diskset(char *dsname)
*
* INPUT: dsname - a char * disk set name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Add the named disk set to the list of known disk sets.
*/
static int
char *dsname)
{
int error = 0;
break;
}
}
} else {
} else {
} else {
}
}
}
}
return (error);
}
/*
* FUNCTION: add_diskset_diskname(char *diskset, char *diskname)
*
* INPUT: dsname - a char * disk set name
* diskname - a char * disk name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Add the disk name to the named disk set's list of disks.
*
* The input diskname is fully qualified with the path
* not relevant, so it is removed.
*/
static int
char *dsname,
char *diskname)
{
int error = 0;
/* trim leading path */
}
}
} else {
}
break;
}
}
/* new disk set */
}
}
return (error);
}
/*
* FUNCTION: add_diskset_hsp(char *dsname, char *hspname)
*
* INPUT: dsname - a char * disk set name
* hspname - a char * HSP name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Model a new HSP for the named disk set.
*
* Metassist can use existing HSPs to service new volumes.
*
* It is necessary to have a model of what HSPs currently
* exist for each disk set.
*
* This function takes information found during discovery
* and turns it into a form usable by the HSP layout code.
*/
static int
char *dsname,
char *hspname)
{
int error = 0;
} else {
} else {
gettext(" added %s to disk set %s\n"),
}
}
break;
}
}
}
}
return (error);
}
/*
* FUNCTION: add_diskset_hsp_spare(char *dsname, char *hspname,
* char *sparename)
*
* INPUT: dsname - a char * diskset name
* hspname - a char * HSP name
* sparename - a char * hot spare (slice) name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Locate the named hot spare pool in the named disk set and
* add the named spare slice to its list of spares.
*
* Metassist can use existing HSPs to service new volumes.
*
* It is necessary to have a model of what HSPs currently
* exist for each disk set.
*
* This function takes information found during discovery
* and turns it into a form usable by the HSP layout code.
*/
static int
char *dsname,
char *hspname,
char *sparename)
{
int error = 0;
/* add spare to HSP */
if (slice == (dm_descriptor_t)0) {
gettext("warning: ignoring nonexistent "
"slice %s defined in %s\n"),
} else {
/* build a devconfig_t model of the slice */
} else {
} else {
gettext(" added %s to %s in "
"disk set %s\n"),
}
}
}
break;
} else {
return (add_diskset_hsp_spare(
}
}
}
}
return (error);
}
/*
* Return a list of disks in the given diskset.
*
* @param dsname
* The name of the named disk set, or "" for the local
* set.
*
* @param disks
* RETURN: pointer to the list of disks in the given disk
* set
*
* @return 0 if succesful, non-zero otherwise
*/
int
char *dsname,
{
int error = 0;
/* For each known disk... */
for (iter = known_disks;
/* If this disk is in the given set... */
}
}
}
return (error);
}
/*
* FUNCTION: is_disk_in_diskset(dm_descriptor_t disk, char *dsname,
* boolean_t *bool)
*
* INPUT: disk - dm_descriptor_t disk handle
* dsname - char * diskset name, or MD_LOCAL_NAME for
* the local set.
*
* OUTPUT: bool - pointer to a boolean_t to hold the result
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Determine if the input disk is known to be in the
* given diskset.
*/
int
char *dsname,
boolean_t *bool)
{
return (is_disk_in_local_diskset(disk, bool));
}
}
static int
boolean_t *bool)
{
int error = 0;
*bool = B_FALSE;
if (error == 0) {
if (error == 0) {
/* For each known disk set... */
/* Check disk name */
/* Check disk aliases */
if (in_named_diskset == B_FALSE) {
}
}
}
}
}
if (error == 0) {
}
return (error);
}
static int
char *dsname,
boolean_t *bool)
{
int error = 0;
*bool = B_FALSE;
if (error != 0) {
break;
}
/* check disk name */
/* check disk aliases */
if (in_diskset == B_FALSE) {
}
}
}
}
*bool = in_diskset;
return (error);
}
/*
* FUNCTION: is_disk_in_other_diskset(dm_descriptor_t disk, char *dsname,
* boolean_t *bool)
*
* INPUT: disk - dm_descriptor_t disk handle
* dsname - char * disk set name
*
* OUTPUT: bool - pointer to a boolean_t to hold the result.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Determine if the named disk is known to be in a disk set
* other than the named disk set.
*/
int
char *dsname,
boolean_t *bool)
{
int error = 0;
if (error != 0) {
return (error);
}
/*
*
* aliases do not have leading paths
*/
++cp;
} else {
}
/* skip named disk set */
continue;
}
/* see if disk's name is in disk set's name list */
/* see if any of the disk's aliases is in name list */
}
}
}
*bool = in_other;
return (error);
}
/*
* FUNCTION: hsp_get_default_for_diskset(char *diskset,
* devconfig_t **hsp)
*
* INPUT: diskset - char * disk set name
*
* RETURNS: devconfig_t * - pointer to the first HSP in the disk set
* NULL if none found
*
* PURPOSE: Locate the first HSP in the named disk set.
*/
int
char *diskset,
devconfig_t **hsp)
{
}
}
}
return (0);
}
/*
* FUNCTION: get_n_metadb_replicas(int *nreplicas)
*
* OUTPUT: nreplicas - pointer to int to hold the result
*
* RETURNS: int - 0 on success
* !0 on failure
*
* PURPOSE: Check the number of replicas configured for the local set.
*/
int
int *nreplicas)
{
int error = 0;
*nreplicas = 0;
error = -1;
} else {
error = -1;
}
if (*nreplicas < 0) {
*nreplicas = 0;
}
}
return (error);
}
/*
* FUNCTION: hsp_get_by_name(char *diskset, char *name,
* devconfig_t **hsp)
*
* INPUT: diskset - char * disk set name
* name - char * HSP name
*
* OUTPUT: hsp - a devconfig_t * - pointer to hold
* the named HSP if none found
*
* PURPOSE: Locate the named HSP in the named disk set.
*/
int
char *diskset,
char *name,
devconfig_t **hsp)
{
}
}
}
return (0);
}
/*
* FUNCTION: is_volume_name_valid(char *name)
*
* OUTPUT: name - pointer to a char * volume name
*
* RETURNS: boolean_t - B_TRUE if the input name is valid
* B_FALSE otherwise
*
* PURPOSE: Wrapper around libmeta volume name validation method.
*/
char *name)
{
return (is_metaname(name));
}
/*
* FUNCTION: is_hsp_name_valid(char *name)
*
* INPUT: name - char * HSP name
*
* RETURNS: boolean_t - B_TRUE if the input name is valid
* B_FALSE otherwise
*
* PURPOSE: Wrapper around libmeta HSP name validation method.
*/
char *name)
{
return (is_hspname(name));
}
/*
* FUNCTION: extract_index(char *name, char *prefix, char *num_fmt,
* int *index)
*
* INPUT: name - const char * volume name
* prefix - const char * fixed part of format string
* num_fmt - const char * format of number to extract (e.g. %d)
*
* OUTPUT: index - pointer to int to hold numeric part of name
*
* RETURNS: boolean_t - B_TRUE if the input name is parsed correctly
* B_FALSE otherwise
*
* PURPOSE: Extract the numeric portion of a device name for use
* by higher-level functions.
*/
static boolean_t
const char *name,
const char *prefix,
const char *num_fmt,
int *index)
{
const char *cp;
++cp;
} else {
}
return (B_TRUE);
else
return (B_FALSE);
}
/*
* FUNCTION: is_volume_name_in_range(char *name)
*
* INPUT: name - char * volume name
*
* RETURNS: boolean_t - B_TRUE if the input name is in the allowed
* range of names
* B_FALSE otherwise
*
* PURPOSE: Determine if the input volume name is within the allowed
* range of device names (0 <= n < max # of devices configured).
*/
char *name)
{
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* FUNCTION: reserve_volume_name(char *name)
*
* INPUT: name - a char * volume name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
*
* Assumes that the input name has been validated.
*
* if the name is not currently available, return -1
*/
int
char *name)
{
return (0);
}
}
return (-1);
}
/*
* FUNCTION: reserve_hsp_name(char *name)
*
* INPUT: name - a char * hsp name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
*
* Assumes that the input name has been validated.
*
* if the name is not currently available, return -1
*/
int
char *name)
{
return (0);
}
}
return (-1);
}
/*
* FUNCTION: release_volume_name(char *name)
*
* INPUT: name - a char * volume name
*
* PURPOSE: release the input volume name.
*
* Extract volume number from the input name
* and use it to index into the array of used
* volume numbers. Make that volume number
* available for use again.
*/
void
char *name)
{
gettext("released volume name %s%d\n"),
_dev_prefix, index);
}
}
/*
* FUNCTION: release_hsp_name(char *name)
*
* INPUT: name - a char * HSP name
*
* PURPOSE: release the input HSP name.
*
* Extract volume number from the input name
* and use it to index into the array of used
* hsp numbers. Make that hsp number available
* for use again.
*/
void
char *name)
{
gettext("released hsp name %s%d\n"),
_hsp_prefix, index);
}
}
/*
* FUNCTION: get_next_volume_name(char **name)
*
* OUTPUT: name - pointer to a char * to hold volume name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: generate a new volume name using the standard device
* name prefix and the lowest available device number.
*
* if type == MIRROR, determine the next available mirror
* name according to the convention that a mirror name is
* a multiple of 10.
*
* If such a name is unavailable, use the next available name.
*/
int
char **name,
{
int next = 0;
continue;
}
break;
}
}
/* try next sequentially available name */
break;
}
}
}
if (next == _max_devs_cfg) {
gettext("ran out of logical volume names.\n"));
return (-1);
}
return (ENOMEM);
}
return (0);
}
/*
* FUNCTION: get_next_submirror_name(char *mname, char **subname)
*
* INPUT: mname - pointer to a char * mirror name
* OUTPUT: subname - pointer to a char * to hold submirror name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Determine the next available submirror name according
* to the convention that each submirror name is a sequential
* increment of its mirror's name.
*
* If such a name is unavailable, return the next sequentially
* available volume name.
*/
int
char *mname,
char **subname)
{
int error = 0;
int next = 0;
int i = 0;
/* try next sequential name: mirror + 1... */
if ((i % 10) == 0) {
/* save for mirrors */
continue;
}
if (devs_by_number[i] == B_FALSE) {
devs_by_number[i] = B_TRUE;
} else {
}
break;
}
}
}
/* name adhering to convention isn't available, */
/* use next sequentially available name */
}
return (error);
}
/*
* FUNCTION: get_next_hsp_name(char **name)
*
* OUTPUT: name - pointer to a char * to hold name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Helper which generates a new hotsparepool name
* using the standard name prefix and the lowest
* available hsp number.
*/
int
char **name)
{
int next = 0;
break;
}
}
return (-1);
}
gettext("failed to allocate volume name string, "
"out of memory"));
return (ENOMEM);
}
return (0);
}
static char *
{
switch (type) {
default: return (gettext("unknown"));
}
}
static svm_snap_t *
{
*errp = 0;
/* initialize the cluster library entry points */
if (sdssc_bind_library() == SDSSC_ERROR) {
*errp = -1;
} else {
/* load the SVM cache */
if (*errp != 0) {
}
}
return (svm_listp);
}
static void
}
}
static int
svm_snap_t **listp,
char *setname,
char *mname,
char *slice_name)
{
return (ENOMEM);
}
return (ENOMEM);
}
return (ENOMEM);
}
return (ENOMEM);
}
return (0);
}
static int
svm_snap_t **listp,
{
/* there are no metadb's; that is ok, no need to check the rest */
mdclrerror(&error);
return (0);
}
mdclrerror(&error);
sp)) {
return (ENOMEM);
}
}
return (ENOMEM);
}
}
}
mdclrerror(&error);
return (ENOMEM);
}
}
}
mdclrerror(&error);
mdclrerror(&error);
continue;
}
mdclrerror(&error);
int i;
return (ENOMEM);
}
}
}
}
}
mdclrerror(&error);
mdclrerror(&error);
continue;
}
mdclrerror(&error);
int i;
int j;
return (ENOMEM);
}
}
}
}
}
}
mdclrerror(&error);
mdclrerror(&error);
continue;
}
mdclrerror(&error);
return (ENOMEM);
}
}
}
}
mdclrerror(&error);
mdclrerror(&error);
int i;
return (ENOMEM);
}
}
}
return (ENOMEM);
}
}
}
mdclrerror(&error);
return (0);
}
static void
{
mdnamelist_t *p;
}
}
/*
* Create a list of SVM devices
*/
static int
svm_snap_t **listp)
{
int max_sets;
int i;
return (0);
}
gettext("failed to get maximum number of disk sets.\n"));
mdclrerror(&error);
return (-1);
}
/* for each possible set number, see if we really have a disk set */
for (i = 0; i < max_sets; i++) {
/* rpc error - no metasets */
break;
}
mdclrerror(&error);
continue;
}
mdclrerror(&error);
return (ENOMEM);
}
/* check for drives in disk sets */
&error);
mdclrerror(&error);
return (ENOMEM);
}
}
}
return (ENOMEM);
}
}
mdclrerror(&error);
return (0);
}
/* determine if 'sp' is built on a slice */
static int
svm_snap_t **listp,
char *slice_name,
char *mname,
{
/* Determine the appropriate uname type for metaname */
}
mdclrerror(&error);
} else {
}
}
/*
* FUNCTION: get_default_stripe_interlace()
*
* RETURNS: uint64_t - default stripe interlace value
*
* PURPOSE: Helper which retrieves the default stripe interlace
* from libmeta.
*/
{
/* convert back to bytes */
}
/*
* FUNCTION: get_max_number_of_devices(int *max)
*
* OUTPUT: max - pointer to int to hold the configured maximum number
* of SVM devices
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Helper which determines the maximum number of allowed
* SVM devices configured for the system.
*
* Wrapper around libmeta function meta_get_max_nunits().
*/
int
int *max)
{
return (-1);
}
return (0);
}
/*
* FUNCTION: get_max_number_of_disksets(int *max)
*
* OUTPUT: max - pointer to in to hold the configured maximum number
* of disk sets
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Helper which determines the maximum number of allowed
* disk sets which has been configured for the system.
*
* Wrapper around libmeta function get_max_sets().
*/
int
int *max)
{
return (-1);
}
return (0);
}
/*
* FUNCTION: is_reserved_replica_slice_index(char *diskset, char *dname,
* uint32_t index, boolean_t *bool)
*
* INPUT: diskset - char * disk set name
* dname - char * disk name
* index - integer index of interest
*
* OUTPUT: bool - pointer to a boolean_t to hold the result
*
* RETURNS: int - 0 - success
* !0 - failure
*
* PURPOSE: Helper which determines if the input slice index on
* the named disk in the named disk set is the replica
* slice that is reserved on disks in disk sets.
*
* The named disk is assumed to be in the named disk set.
*
* Determines if metassist is being run in a simulated
* hardware enironment, if not the libmeta function to
* determine the replica slice index is called.
*
* If simulation is active, then a local implementation
* is used to determine the replica slice index.
*/
int
char *diskset,
char *dname,
boolean_t *bool)
{
int error = 0;
/* sim disabled: use meta_replicaslice() */
/* slice assumed to be on disk in the named disk set */
return (-1);
}
return (-1);
}
return (-1);
}
} else {
/* sim enabled: use same logic as meta_replicaslice() */
if (error == 0) {
} else {
}
}
}
return (error);
}