/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 * or http://www.opensolaris.org/os/licensing. * 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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "volume_devconfig.h" #include #include #include #include "volume_nvpair.h" #include "volume_error.h" #include "volume_output.h" #include "volume_string.h" /* * Methods which manipulate a devconfig_t struct */ /* * Constructor: Create a devconfig_t struct. This devconfig_t must be * freed with free_devconfig(). * * @param devconfig * RETURN: a new devconfig_t * * @param type * the type of devconfig_t to create * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int new_devconfig( devconfig_t **devconfig, component_type_t type) { int error; *devconfig = (devconfig_t *)calloc(1, sizeof (devconfig_t)); if (*devconfig == NULL) { volume_set_error(gettext("new_devconfig() calloc() failed\n")); return (-1); } /* Create attribute list */ if ((error = nvlist_alloc(&((*devconfig)->attributes), NV_UNIQUE_NAME_TYPE, 0)) != 0) { volume_set_error(gettext("devconfig_t nvlist_alloc() failed\n")); free_devconfig(*devconfig); return (error); } if ((error = devconfig_set_type(*devconfig, type)) != 0) { free_devconfig(*devconfig); return (error); } return (0); } /* * Free memory (recursively) allocated to a devconfig_t struct * * @param arg * pointer to the devconfig_t to be freed */ void free_devconfig( void *arg) { devconfig_t *devconfig = (devconfig_t *)arg; if (devconfig == NULL) { return; } /* Free the attributes nvlist */ if (devconfig->attributes != NULL) { nvlist_free(devconfig->attributes); } /* Free available devices */ if (devconfig->available != NULL) { free_string_array(devconfig->available); } /* Free unavailable devices */ if (devconfig->unavailable != NULL) { free_string_array(devconfig->unavailable); } /* Free the components */ if (devconfig->components != NULL) { dlist_free_items(devconfig->components, free_devconfig); } /* Free the devconfig itself */ free(devconfig); } /* * Check the type of the given device. * * @param device * the device whose type to check * * @param type * the type of the device against which to compare * * @return B_TRUE if the device is of the given type, B_FALSE * otherwise */ boolean_t devconfig_isA( devconfig_t *device, component_type_t type) { component_type_t curtype; if (device == NULL) { return (B_FALSE); } if (devconfig_get_type(device, &curtype) != 0) { return (B_FALSE); } if (curtype != type) { return (B_FALSE); } return (B_TRUE); } /* * Get the first component of the given type from the given * devconfig_t. Create the component if create is B_TRUE. * * @return ENOENT * if the requested component does not exist and its * creation was not requested * * @return 0 * if the requested component exists or was created * * @return non-zero * if the requested component did not exist and could not * be created */ int devconfig_get_component( devconfig_t *device, component_type_t type, devconfig_t **component, boolean_t create) { dlist_t *list; int error = 0; char *typestr = devconfig_type_to_str(type); oprintf(OUTPUT_DEBUG, gettext("Searching for singleton %s\n"), typestr); /* For each component of this device... */ for (list = devconfig_get_components(device); list != NULL; list = list->next) { *component = (devconfig_t *)list->obj; /* Is this subcomponent an instance of the given type? */ if (*component != NULL && devconfig_isA(*component, type)) { oprintf(OUTPUT_DEBUG, gettext("Found %s\n"), typestr); return (0); } } /* No component found */ error = ENOENT; *component = NULL; oprintf(OUTPUT_DEBUG, gettext("%s not found\n"), typestr); if (create == B_TRUE) { oprintf(OUTPUT_DEBUG, gettext("Creating %s\n"), typestr); /* * An existing singleton component of the given type was * not found under the given disk set. So, create one. */ if ((error = new_devconfig(component, type)) == 0) { /* Attach new component to given device */ devconfig_set_components( device, dlist_append(dlist_new_item(*component), devconfig_get_components(device), AT_TAIL)); } } return (error); } /* * Set the available devices for use in creating this device * * @param device * a devconfig_t representing the device to modify * * @param available * A NULL-terminated array of device names */ void devconfig_set_available( devconfig_t *device, char **available) { device->available = available; } /* * Get the available devices for use in creating this device * * @param device * a devconfig_t representing the device to examine * * @return available * A NULL-terminated array of device names */ char ** devconfig_get_available( devconfig_t *device) { return (device->available); } /* * Set the unavailable devices which may not be used in creating this * device * * @param device * a devconfig_t representing the device to modify * * @param available * A NULL-terminated array of device names */ void devconfig_set_unavailable( devconfig_t *device, char **unavailable) { device->unavailable = unavailable; } /* * Get the unavailable devices for use in creating this device * * @param device * a devconfig_t representing the device to examine * * @return unavailable * A NULL-terminated array of device names */ char ** devconfig_get_unavailable( devconfig_t *device) { return (device->unavailable); } /* * Set the subcomponent devices of a given device * * @param device * a devconfig_t representing the device to examine * * @param components * A dlist_t containing devconfig_t devices */ void devconfig_set_components( devconfig_t *device, dlist_t *components) { device->components = components; } /* * Get the subcomponent devices of a given device * * @param device * a devconfig_t representing the device to examine * * @return A dlist_t containing devconfig_t devices */ dlist_t * devconfig_get_components( devconfig_t *device) { return (device->components); } /* * Set the device name * * @param device * a devconfig_t representing the device to modify * * @param name * the value to set as the device name * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_name( devconfig_t *device, char *name) { return (set_string(device->attributes, ATTR_NAME, name)); } /* * Set the disk set name * * @param diskset * a devconfig_t representing the diskset to modify * * @param name * the value to set as the device name * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_diskset_name( devconfig_t *diskset, char *name) { md_error_t error = mdnullerror; /* Verify syntax of disk set name */ if (meta_set_checkname(name, &error)) { volume_set_error(gettext("invalid disk set name: %s"), name); return (-1); } return (devconfig_set_name(diskset, name)); } /* * Set the device name * * @param hsp * a devconfig_t representing the hsp to modify * * @param name * the value to set as the device name * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_hsp_name( devconfig_t *hsp, char *name) { /* Validate name */ if (!is_hspname(name)) { volume_set_error(gettext("invalid hot spare pool name: %s"), name); return (-1); } return (devconfig_set_name(hsp, name)); } /* * Set the device name * * @param volume * a devconfig_t representing the volume to modify * * @param name * the value to set as the device name * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_volume_name( devconfig_t *volume, char *name) { /* Validate name */ if (!is_metaname(name)) { volume_set_error(gettext("invalid volume name: %s"), name); return (-1); } return (devconfig_set_name(volume, name)); } /* * Get the device name * * @param volume * a devconfig_t representing the volume to examine * * @param name * RETURN: the device name * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_name( devconfig_t *device, char **name) { int error = get_string(device->attributes, ATTR_NAME, name); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("device name not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the device type * * @param device * a devconfig_t representing the device to modify * * @param type * the value to set as the device type * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_type( devconfig_t *device, component_type_t type) { return (set_uint16(device->attributes, ATTR_TYPE, (uint16_t)type)); } /* * Get the device type * * @param device * a devconfig_t representing the device to examine * * @param type * RETURN: the device type * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_type( devconfig_t *device, component_type_t *type) { uint16_t val; int error = get_uint16(device->attributes, ATTR_TYPE, &val); switch (error) { /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ case ENOENT: volume_set_error(gettext("device type not set")); error = ERR_ATTR_UNSET; break; /* Success */ case 0: *type = (component_type_t)val; } return (error); } /* * Set the device size (for volume, mirror, stripe, concat) in bytes * * Note that size in bytes in a 64-bit field cannot hold the size that * can be accessed in a 16 byte CDB. Since CDBs operate on blocks, * the max capacity is 2^73 bytes with 512 byte blocks. * * @param device * a devconfig_t representing the device to modify * * @param size_in_bytes * the value to set as the device size in bytes * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_size( devconfig_t *device, uint64_t size_in_bytes) { /* Validate against limits */ /* LINTED -- MIN_SIZE may be 0 */ if (size_in_bytes < MIN_SIZE) { volume_set_error(gettext("size (in bytes) too small: %llu"), (unsigned long long)size_in_bytes); return (-1); } return (set_uint64(device->attributes, ATTR_SIZEINBYTES, size_in_bytes)); } /* * Get the device size (for volume, mirror, stripe, concat) in bytes * * Note that size in bytes in a 64-bit field cannot hold the size that * can be accessed in a 16 byte CDB. Since CDBs operate on blocks, * the max capacity is 2^73 bytes with 512 byte blocks. * * @param device * a devconfig_t representing the device to examine * * @param size_in_bytes * RETURN: the device size in bytes * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_size( devconfig_t *device, uint64_t *size_in_bytes) { int error = get_uint64( device->attributes, ATTR_SIZEINBYTES, size_in_bytes); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("size (in bytes) not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the device size in blocks * * @param device * a devconfig_t representing the device to modify * * @param type * the value to set as the device size in blocks * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_size_in_blocks( devconfig_t *device, uint64_t size_in_blocks) { /* Validate against limits */ /* LINTED -- MIN_SIZE_IN_BLOCKS may be 0 */ if (size_in_blocks < MIN_SIZE_IN_BLOCKS) { volume_set_error(gettext("size (in blocks) too small: %llu"), (unsigned long long)size_in_blocks); return (-1); } return (set_uint64(device->attributes, ATTR_SIZEINBLOCKS, size_in_blocks)); } /* * Get the device size in blocks * * @param device * a devconfig_t representing the device to examine * * @param size_in_blocks * RETURN: the device size in blocks * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_size_in_blocks( devconfig_t *device, uint64_t *size_in_blocks) { int error = get_uint64( device->attributes, ATTR_SIZEINBLOCKS, size_in_blocks); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("size (in blocks) not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the the slice index * * @param slice * a devconfig_t representing the slice to modify * * @param index * the value to set as the the slice index * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_slice_index( devconfig_t *slice, uint16_t index) { return (set_uint16(slice->attributes, ATTR_SLICE_INDEX, index)); } /* * Get the slice index * * @param device * a devconfig_t representing the device to examine * * @param index * RETURN: the slice index * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_slice_index( devconfig_t *slice, uint16_t *index) { int error = get_uint16(slice->attributes, ATTR_SLICE_INDEX, index); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("slice index not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the the slice start block * * @param slice * a devconfig_t representing the slice to modify * * @param start_block * the value to set as the the slice start block * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_slice_start_block( devconfig_t *slice, uint64_t start_block) { return (set_uint64(slice->attributes, ATTR_SLICE_STARTSECTOR, start_block)); } /* * Get the slice start block * * @param device * a devconfig_t representing the device to examine * * @param start_block * RETURN: the slice start block * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_slice_start_block( devconfig_t *slice, uint64_t *start_block) { int error = get_uint64( slice->attributes, ATTR_SLICE_STARTSECTOR, start_block); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("slice start block not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the number of subcomponents in mirror * * @param mirror * a devconfig_t representing the mirror to modify * * @param nsubs * the value to set as the number of subcomponents in * mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_mirror_nsubs( devconfig_t *mirror, uint16_t nsubs) { /* Validate against limits */ if (nsubs < 1 || nsubs > NMIRROR) { volume_set_error( gettext("number of submirrors (%d) out of valid range (%d-%d)"), nsubs, 1, NMIRROR); return (-1); } return (set_uint16(mirror->attributes, ATTR_MIRROR_NSUBMIRRORS, nsubs)); } /* * Get number of subcomponents in mirror * * @param device * a devconfig_t representing the device to examine * * @param nsubs * RETURN: number of subcomponents in mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_mirror_nsubs( devconfig_t *mirror, uint16_t *nsubs) { int error = get_uint16( mirror->attributes, ATTR_MIRROR_NSUBMIRRORS, nsubs); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("number or submirrors not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the read strategy for mirror * * @param mirror * a devconfig_t representing the mirror to modify * * @param read * the value to set as the read strategy for mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_mirror_read( devconfig_t *mirror, mirror_read_strategy_t read) { return (set_uint16(mirror->attributes, ATTR_MIRROR_READ, (uint16_t)read)); } /* * Get read strategy for mirror * * @param device * a devconfig_t representing the device to examine * * @param read * RETURN: read strategy for mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_mirror_read( devconfig_t *mirror, mirror_read_strategy_t *read) { uint16_t val; int error = get_uint16(mirror->attributes, ATTR_MIRROR_READ, &val); switch (error) { /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ case ENOENT: volume_set_error(gettext("mirror read strategy not set")); error = ERR_ATTR_UNSET; break; /* Success */ case 0: *read = (mirror_read_strategy_t)val; } return (error); } /* * Set the write strategy for mirror * * @param mirror * a devconfig_t representing the mirror to modify * * @param write * the value to set as the write strategy for mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_mirror_write( devconfig_t *mirror, mirror_write_strategy_t write) { return (set_uint16(mirror->attributes, ATTR_MIRROR_WRITE, (uint16_t)write)); } /* * Get write strategy for mirror * * @param device * a devconfig_t representing the device to examine * * @param write * RETURN: write strategy for mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_mirror_write( devconfig_t *mirror, mirror_write_strategy_t *write) { uint16_t val; int error = get_uint16(mirror->attributes, ATTR_MIRROR_WRITE, &val); switch (error) { /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ case ENOENT: volume_set_error(gettext("mirror write strategy not set")); error = ERR_ATTR_UNSET; break; /* Success */ case 0: *write = (mirror_write_strategy_t)val; } return (error); } /* * Set the resync pass for mirror * * @param mirror * a devconfig_t representing the mirror to modify * * @param pass * the value to set as the resync pass for mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_mirror_pass( devconfig_t *mirror, uint16_t pass) { /* Validate against max value */ if (pass > MD_PASS_MAX) { volume_set_error( gettext("mirror pass number (%d) out of valid range (0-%d)"), pass, MD_PASS_MAX); return (-1); } return (set_uint16(mirror->attributes, ATTR_MIRROR_PASSNUM, pass)); } /* * Get resync pass for mirror * * @param device * a devconfig_t representing the device to examine * * @param pass * RETURN: resync pass for mirror * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_mirror_pass( devconfig_t *mirror, uint16_t *pass) { int error = get_uint16(mirror->attributes, ATTR_MIRROR_PASSNUM, pass); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("mirror pass number not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the minimum number of components in stripe * * @param stripe * a devconfig_t representing the stripe to modify * * @param mincomp * the value to set as the minimum number of components * in stripe * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_stripe_mincomp( devconfig_t *stripe, uint16_t mincomp) { /* Validate against minimum value */ if (mincomp < MIN_NSTRIPE_COMP) { volume_set_error(gettext( "minimum stripe components (%d) below minimum allowable (%d)"), mincomp, MIN_NSTRIPE_COMP); return (-1); } return (set_uint16(stripe->attributes, ATTR_STRIPE_MINCOMP, mincomp)); } /* * Get minimum number of components in stripe * * @param device * a devconfig_t representing the device to examine * * @param mincomp * RETURN: minimum number of components in stripe * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_stripe_mincomp( devconfig_t *stripe, uint16_t *mincomp) { int error = get_uint16( stripe->attributes, ATTR_STRIPE_MINCOMP, mincomp); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error( gettext("minimum number of stripe components not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the maximum number of components in stripe * * @param stripe * a devconfig_t representing the stripe to modify * * @param maxcomp * the value to set as the maximum number of components * in stripe * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_stripe_maxcomp( devconfig_t *stripe, uint16_t maxcomp) { /* Validate against minimum value */ if (maxcomp < MIN_NSTRIPE_COMP) { volume_set_error(gettext( "maximum stripe components (%d) below minimum allowable (%d)"), maxcomp, MIN_NSTRIPE_COMP); return (-1); } return (set_uint16(stripe->attributes, ATTR_STRIPE_MAXCOMP, maxcomp)); } /* * Get maximum number of components in stripe * * @param device * a devconfig_t representing the device to examine * * @param maxcomp * RETURN: maximum number of components in stripe * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_stripe_maxcomp( devconfig_t *stripe, uint16_t *maxcomp) { int error = get_uint16( stripe->attributes, ATTR_STRIPE_MAXCOMP, maxcomp); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error( gettext("maximum number of stripe components not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the stripe interlace * * @param stripe * a devconfig_t representing the stripe to modify * * @param interlace * the value to set as the stripe interlace * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_stripe_interlace( devconfig_t *stripe, uint64_t interlace) { if (interlace < MININTERLACE || interlace > MAXINTERLACE) { char *intstr = NULL; char *minstr = NULL; char *maxstr = NULL; /* Get string representations of interlaces */ bytes_to_sizestr(interlace, &intstr, universal_units, B_FALSE); bytes_to_sizestr(MININTERLACE, &minstr, universal_units, B_FALSE); bytes_to_sizestr(MAXINTERLACE, &maxstr, universal_units, B_FALSE); volume_set_error( gettext("interlace (%s) out of valid range (%s - %s)"), intstr, minstr, maxstr); free(intstr); free(minstr); free(maxstr); return (-1); } return (set_uint64(stripe->attributes, ATTR_STRIPE_INTERLACE, interlace)); } /* * Get stripe interlace * * @param device * a devconfig_t representing the device to examine * * @param interlace * RETURN: stripe interlace * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_stripe_interlace( devconfig_t *stripe, uint64_t *interlace) { int error = get_uint64( stripe->attributes, ATTR_STRIPE_INTERLACE, interlace); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("stripe interlace not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the redundancy level for a volume. * * @param volume * a devconfig_t representing the volume to modify * * @param rlevel * If 0, a stripe will be created. If > 0, a mirror with * this number of submirrors will be created. * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_volume_redundancy_level( devconfig_t *volume, uint16_t rlevel) { /* Validate against limits */ if (rlevel > NMIRROR) { volume_set_error(gettext( "volume redundancy level (%d) out of valid range (%d-%d)"), rlevel, 0, NMIRROR); return (-1); } return (set_uint16(volume->attributes, ATTR_VOLUME_REDUNDANCY, rlevel)); } /* * Get the redundancy level for a volume. * * @param device * a devconfig_t representing the device to examine * * @param rlevel * RETURN: the redundancy level for a volume * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_volume_redundancy_level( devconfig_t *volume, uint16_t *rlevel) { int error = get_uint16( volume->attributes, ATTR_VOLUME_REDUNDANCY, rlevel); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("volume redundancy level not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the number of paths in volume * * @param volume * a devconfig_t representing the volume to modify * * @param npaths * the value to set as the number of paths in volume * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_volume_npaths( devconfig_t *volume, uint16_t npaths) { /* Validate against limits */ if (npaths < MIN_NDATAPATHS || npaths > MAX_NDATAPATHS) { volume_set_error( gettext("number of data paths (%d) out of valid range (%d-%d)"), npaths, MIN_NDATAPATHS, MAX_NDATAPATHS); return (-1); } return (set_uint16(volume->attributes, ATTR_VOLUME_DATAPATHS, npaths)); } /* * Get number of paths in volume * * @param device * a devconfig_t representing the device to examine * * @param npaths * RETURN: number of paths in volume * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_volume_npaths( devconfig_t *volume, uint16_t *npaths) { int error = get_uint16( volume->attributes, ATTR_VOLUME_DATAPATHS, npaths); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("number of data paths not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Set the HSP creation option (for volume, stripe, concat, mirror) * * @param volume * a devconfig_t representing the volume to modify * * @param usehsp * the value to set as the HSP creation option * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_set_volume_usehsp( devconfig_t *volume, boolean_t usehsp) { return (set_boolean(volume->attributes, ATTR_VOLUME_USEHSP, usehsp)); } /* * Get HSP creation option (for volume, stripe, concat, mirror) * * @param device * a devconfig_t representing the device to examine * * @param usehsp * RETURN: HSP creation option (for volume, stripe, * concat, mirror) * * @return 0 * if successful * * @return non-zero * if an error occurred. Use get_error_string() to * retrieve the associated error message. */ int devconfig_get_volume_usehsp( devconfig_t *volume, boolean_t *usehsp) { int error = get_boolean( volume->attributes, ATTR_VOLUME_USEHSP, usehsp); /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ if (error == ENOENT) { volume_set_error(gettext("volume usehsp not set")); error = ERR_ATTR_UNSET; } return (error); } /* * Get the string representation of the volume's type * * @param type * a valid component_type_t * * @return an internationalized string representing the given * type */ char * devconfig_type_to_str( component_type_t type) { char *str; switch (type) { case TYPE_CONCAT: str = gettext("Concat"); break; case TYPE_CONTROLLER: str = gettext("Controller"); break; case TYPE_DISKSET: str = gettext("Diskset"); break; case TYPE_DRIVE: str = gettext("Disk"); break; case TYPE_EXTENT: str = gettext("Extent"); break; case TYPE_HOST: str = gettext("Host"); break; case TYPE_HSP: str = gettext("Hot Spare Pool"); break; case TYPE_MIRROR: str = gettext("Mirror"); break; case TYPE_RAID5: str = gettext("Raid5"); break; case TYPE_SLICE: str = gettext("Slice"); break; case TYPE_SOFTPART: str = gettext("Soft Partition"); break; case TYPE_STRIPE: str = gettext("Stripe"); break; case TYPE_TRANS: str = gettext("Trans"); break; case TYPE_VOLUME: str = gettext("Volume"); break; default: case TYPE_UNKNOWN: str = gettext("Unknown"); break; } return (str); } /* * Get the string representation of the mirror's read strategy * * @param read * a valid mirror_read_strategy_t * * @return an internationalized string representing the given * read strategy */ char * devconfig_read_strategy_to_str( mirror_read_strategy_t read) { char *str; switch (read) { case MIRROR_READ_ROUNDROBIN: str = gettext("ROUNDROBIN"); break; case MIRROR_READ_GEOMETRIC: str = gettext("GEOMETRIC"); break; case MIRROR_READ_FIRST: str = gettext("FIRST"); break; default: str = ""; } return (str); } /* * Get the string representation of the mirror's write strategy * * @param write * a valid mirror_write_strategy_t * * @return an internationalized string representing the given * write strategy */ char * devconfig_write_strategy_to_str( mirror_write_strategy_t write) { char *str; switch (write) { case MIRROR_WRITE_PARALLEL: str = gettext("PARALLEL"); break; case MIRROR_WRITE_SERIAL: str = gettext("SERIAL"); break; default: str = ""; } return (str); } #ifdef DEBUG /* * Dump the contents of a devconfig_t struct to stdout. * * @param device * the devconfig_t to examine * * @param prefix * a prefix string to print before each line */ void devconfig_dump( devconfig_t *device, char *prefix) { dlist_t *comps = NULL; char **array = NULL; char *str = NULL; int i = 0; component_type_t type = TYPE_UNKNOWN; boolean_t bool = B_FALSE; uint16_t val16 = 0; uint64_t val64 = 0; mirror_read_strategy_t read; mirror_write_strategy_t write; if (device == NULL) { return; } /* Type */ if (devconfig_get_type(device, &type) == 0) { printf("%s%s\n", prefix, devconfig_type_to_str(type)); } /* Name */ if (devconfig_get_name(device, &str) == 0) { printf("%s name: %s\n", prefix, str); } /* Size in bytes */ if (devconfig_get_size(device, &val64) == 0) { printf("%s size in bytes: %llu\n", prefix, val64); } /* Size in blocks */ if (devconfig_get_size_in_blocks(device, &val64) == 0) { printf("%s size in blocks: %llu\n", prefix, val64); } /* Use HSP */ if (devconfig_get_volume_usehsp(device, &bool) == 0) { printf("%s usehsp: %s\n", prefix, bool? "TRUE" : "FALSE"); } switch (type) { case TYPE_VOLUME: /* Volume rlevel */ if (devconfig_get_volume_redundancy_level( device, &val16) == 0) { printf("%s volume redundancy level: %d\n", prefix, val16); } /* Volume npaths */ if (devconfig_get_volume_npaths(device, &val16) == 0) { printf("%s volume npaths: %d\n", prefix, val16); } break; case TYPE_MIRROR: /* Mirror nsubs */ if (devconfig_get_mirror_nsubs(device, &val16) == 0) { printf("%s mirror nsubs: %d\n", prefix, val16); } /* Mirror read */ if (devconfig_get_mirror_read(device, &read) == 0) { printf("%s mirror read: %s\n", prefix, devconfig_read_strategy_to_str(read)); } /* Mirror write */ if (devconfig_get_mirror_write(device, &write) == 0) { printf("%s mirror write: %s\n", prefix, devconfig_write_strategy_to_str(write)); } /* Mirror pass */ if (devconfig_get_mirror_pass(device, &val16) == 0) { printf("%s mirror pass: %d\n", prefix, val16); } break; case TYPE_STRIPE: /* Stripe mincomp */ if (devconfig_get_stripe_mincomp(device, &val16) == 0) { printf("%s stripe mincomp: %d\n", prefix, val16); } /* Stripe maxcomp */ if (devconfig_get_stripe_maxcomp(device, &val16) == 0) { printf("%s stripe maxcomp: %d\n", prefix, val16); } /* Stripe interlace */ if (devconfig_get_stripe_interlace(device, &val64) == 0) { printf("%s stripe interlace: %lld\n", prefix, val64); } break; case TYPE_SLICE: /* Slice index */ if (devconfig_get_slice_index(device, &val16) == 0) { printf("%s slice index: %d\n", prefix, val16); } /* Slice start block */ if (devconfig_get_slice_start_block(device, &val64) == 0) { printf("%s slice start block: %llu\n", prefix, val64); } break; } array = devconfig_get_available(device); if (array != NULL) { printf("%s available:\n", prefix); for (i = 0; array[i] != NULL; i++) { printf("%s %s\n", prefix, array[i]); } } array = devconfig_get_unavailable(device); if (array != NULL) { printf("%s unavailable:\n", prefix); for (i = 0; array[i] != NULL; i++) { printf("%s %s\n", prefix, array[i]); } } printf("\n"); comps = devconfig_get_components(device); if (comps != NULL) { char buf[128]; snprintf(buf, 128, "%s%s", prefix, " "); for (; comps != NULL; comps = comps->next) { devconfig_dump((devconfig_t *)comps->obj, buf); } } } #endif /* DEBUG */