/*
* 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
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <limits.h>
#include <libdiskmgt.h>
#include <libintl.h>
#include <meta.h>
#define _LAYOUT_DISCOVERY_C
#include "volume_dlist.h"
#include "volume_error.h"
#include "volume_nvpair.h"
#include "volume_output.h"
#include "layout_device_cache.h"
#include "layout_device_util.h"
#include "layout_dlist_util.h"
#include "layout_discovery.h"
#include "layout_request.h"
#include "layout_slice.h"
#include "layout_svm_util.h"
/*
* lists of device dm_descriptor_t handles discovered during
* the initial system probe. Lists are populated by
* discover_known_devices.
*
* "bad" slices are those that are known to libdiskmgt but
* cannot be accessed. An example would be a slice that has
* disappeared due to disk re-slicing: libdiskmgt may have a
* cached handle for it, but the slice no longer exists.
*
* "bad" disks are thoese that are known to libdiskmgt but
* cannot be accessed. An example would be a disk that has
* failed or has gone offline: libdiskmgt may have a cached
* handle for it, but the disk does not respond.
*/
/*
* helper functions for building known device lists, used by
* discover_known_devices.
*/
static int generate_known_hba_name(
static void print_known_devices();
/*
* lists of device dm_descriptor_t handles that are usable by layout.
* These devices must still pass the user specified available/unavailable
* filter before they're actually considered available.
*
* Lists are populated by discover_usable_devices.
*/
/*
* private flag that remembers if any HBA is known to support MPXIO
*/
/*
* The slice_class struct is used to group slices by usage class.
*/
typedef struct {
static int check_slice_usage(
char *dsname,
static int check_svm_slice_usage(
char *dsname,
static int save_slice_classification(
char *dsname,
char *usage,
char *usage_detail,
static int generate_usable_disks_and_slices_in_local_set(
dlist_t **usable_slices);
static int generate_usable_disks_and_slices_in_named_set(
char *dsname,
dlist_t **usable_slices);
static int create_usable_slices(
static int add_new_usable(
static int update_slice_attributes(
static int generate_usable_hbas(
static void print_usable_devices();
static void print_unusable_devices(
static char *get_slice_usage_msg(
char *usage);
/*
* virtual slices...
*/
static int generate_virtual_slices(
/*
* multipathed disks have aliases, as do slices on those disks.
* these need to be tracked since the user may specify them.
* A multi-pathed disk is one connected to the system thru
* more than one physical HBA, each connection gets a distinct
* name in the device tree and they're all more or less equivalent.
* No indication as to how many possible physical connections a
* disk may have, so we pick an arbitrary number of aliases to
* support. There is nothing significant about this number,
* it just controls the number of alias slots that get allocated.
*/
/*
* attribute name for layout private information stored in
* device nvpair attribute lists.
*/
static int compare_start_blocks(
static int compare_desc_display_names(
/*
* FUNCTION: is_mpxio_enabled()
*
* RETURNS: boolean_t - B_TRUE - if MPXIO appears enabled for the system
* B_FALSE - otherwise
*
* PURPOSE: returns the value of _mpxio_enabled which is set to B_TRUE
* during system configuration discovery if any of the knwon
* HBAs advertises itself as a "multiplex" controller.
*/
{
return (_mpxio_enabled);
}
/*
* FUNCTION: discover_known_devices()
*
* SIDEEFFECT: populates the module private lists of known devices
* (_known_slices, _known_disks, _known_hbas).
*
* All known devices will also have had their CTD
* short names inferred and stored.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Load physical devices discovered thru libdiskmgt.
*/
int
{
int error = 0;
gettext("\nScanning system physical "
"device configuration...\n"));
/* initialize layout_device_cache */
((error = create_device_caches()) != 0) ||
&_bad_slices)) ||
if (error == 0) {
}
return (error);
}
/*
* FUNCTION: release_known_devices()
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Unloads all state currently held for known
* physical devices.
*/
int
char *diskset)
{
/* these lists are module private */
_bad_slices = NULL;
_bad_disks = NULL;
_known_disks = NULL;
_known_hbas = NULL;
/* clean up state kept in layout_device_cache */
return (0);
}
/*
* FUNCTION: discover_usable_devices(char *diskset)
*
* INPUT: diskset - a char * diskset name.
*
* SIDEEFFECT: Traverses the lists of known devices and populates the
* module private lists of usable devices (_usable_slices,
* _usable_disks, _usable_hbas), as well as the module
* private list of used slices.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Process the known devices and determine which of them are
* usable for generating volumes in the specified diskset.
*
* The specified diskset's name cannot be NULL or 0 length.
*/
int
char *diskset)
{
int error = 0;
gettext("a diskset name must be specified in "
"the request\n"));
return (-1);
}
gettext("\nDetermining usable physical devices "
"for disk set \"%s\"...\n"),
diskset);
if (error == 0) {
if (error == 0) {
if (error == 0) {
}
}
}
/*
* free slice classification usage and lists, items are char*
* the used_classes structure is only filled in if verbose
* output was requested.
*/
}
return (error);
}
/*
* FUNCTION: release_usable_devices()
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Unloads all state currently held for usable
* physical devices.
*/
int
{
/* list items are shared with _known_XXX lists */
_usable_hbas = NULL;
/* clean up state kept in layout_device_util */
return (0);
}
/*
* FUNCTION: get_known_slices(dlist_t **list)
* get_known_disks(dlist_t **list)
* get_known_hbas(dlist_t **list)
*
* OUTPUT: list - a dlist_t pointer to hold the returned list of
* devices.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Public accessors for the module private lists of
* available devices.
*/
int
{
*list = _known_slices;
return (0);
}
int
{
*list = _known_disks;
return (0);
}
int
{
*list = _known_hbas;
return (0);
}
/* make fully qualified DID device name */
static char *
char *device)
{
return (buf);
}
return (device);
}
/*
* FUNCTION: generate_known_disks(dlist_t **known,
* dlist_t **bad)
*
* INPUT: NONE
*
* OUTPUT: known - populated list of known disks
* bad - populated list of known bad disks
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Does the system configuration discovery to determine
* what disks are known to be attached to the system.
*
* Determines the CTD name for each disk and saves it.
*/
static int
{
int i;
int error = 0;
(void) add_descriptors_to_free(ddp);
if (error != 0) {
gettext("Error discovering system hardware configuration,\n"
"unable to communicate with libdiskmgt or diskmgtd.\n"));
return (-1);
}
return (-1);
}
/* iterate all returned disks and add them to the known list */
#if defined(i386)
/* on X86, disks must have a solaris FDISK partition */
#endif /* defined(i386) */
/* if the disk is offline, report it as bad */
error = 0;
} else
if (error == 0 &&
/*
* if any disk attribute access fails with ENODEV
* report it as bad
*/
error = 0;
} else {
/*
* Determine whether disk is fixed by checking its
* drive type. If drive type is unknown, check media
* type.
*/
if (!isfixed) {
continue; /* ignore non-fixed disks */
}
#if defined(i386)
/* X86 drive has no solaris partition, report as bad */
gettext("%s has no solaris FDISK partition.\n"));
}
#endif /* defined(i386) */
}
if (bad_disk) {
/* remember bad disks and continue */
compare_descriptor_names) != B_TRUE) {
} else {
}
}
continue;
}
/* get disk name and multipath aliases */
char *alias;
/* save first alias as display name */
if (disk_name_set != B_TRUE) {
/* make sure DID disk alias is fully qualified */
char *qual_name =
gettext("DID disk name: %s\n"),
} else {
gettext("disk name: %s\n"),
alias);
}
} else {
/* save others as aliases */
gettext(" alias: %s\n"),
alias);
}
}
}
}
if (error == 0) {
} else {
*known =
}
}
}
}
return (error);
}
/*
* FUNCTION: generate_known_slices(dlist_t *disks,
* dlist_t **known, dlist_t **bad)
*
* OUTPUT: disks - a pointer to a list of known disks
* known - a pointer to a dlist_t list to hold the known slices
* bad - a pointer to a dlist_t to hold the bad slices
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Examines input list of known disks and determines the slices
* attached to each.
*
* Some slices returned from libdiskmgt may not really exist,
* this is detected when trying to get more information about
* the slice -- ENODEV is returned. Any such slices will be
* added to the bad slice list.
*/
static int
{
int error = 0;
/* iterate list of disks and add their slices to the known list */
continue;
}
/* bad slice, remember it and continue */
} else {
error = 0;
}
}
continue;
}
(disk_ctd_alias_derived == B_FALSE)) {
/* BEGIN CSTYLED */
/*
* If the slice name is a DID name, get the local CTD
* name for slice, extract the disk name and add it as
* an alias for the disk.
*
* This is the only way to derive the CTD alias for the
* disk when DID is enabled.
*
* The disk_ctd_alias_derived flag ensure the disk's
* CTD alias is only set once.
*
* The slice's CTD aliases are then derived from the
* disk's CTD alias in the normal, non-DID name processing
* which happens below.
*/
/* END CSTYLED */
&local)) != 0) {
/* no local name -> no DID */
error = 0;
}
} else {
&localdisk)) == 0) {
++diskonly;
} else {
}
gettext(" set DID disk CTD alias: %s\n"),
diskonly);
}
}
}
/* derive slice display name from disk's display name */
if (error == 0) {
}
}
/* set slice aliases using disk aliases */
if (error == 0) {
}
}
}
}
if (error == 0) {
} else {
*known =
}
}
}
}
return (error);
}
/*
* FUNCTION: generate_known_hbas(dlist_t *disks, dlist_t **known)
*
* INPUT: diskset - a char * diskset name.
*
* OUTPUT: populates the list of known HBAs.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Examines known disk list and derives the list of known HBAs.
*
* Determines the CTD name for an HBA and saves it.
*/
static int
{
int error = 0;
/*
* for each known disk follow its HBA connections and
* assemble the list of known HBAs.
*/
if (error == 0) {
gettext("Disk %s has no HBA/Controller?!\n"),
dname);
error = -1;
continue;
}
/* scan list of known HBAs and see if known */
compare_descriptor_names) == B_TRUE) {
/* known HBA */
continue;
}
/* see if HBA supports MPXIO */
}
/* generate a CTD name for HBA */
if (error == 0) {
/* add to known HBA list */
NULL) {
} else {
*known =
}
}
}
}
}
return (error);
}
/*
* FUNCTION: generate_known_hba_name(dm_descriptor_t hba,
* dm_descriptor_t alias, char *diskname)
*
* INPUT: hba - a dm_descriptor_t HBA handle.
* alias - a dm_descriptor_t disk alias handle.
* diskname - a char * disk name
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Sets the CTD name for the input HBA.
*
* The CTD name for the HBA is generated from the input
* disk alias (ex: cXdXtXsX) or from the disk name if
* the input alias is a DID name (ex: dX).
*/
static int
{
int error = 0;
if (error != 0) {
return (error);
}
/* see if the input alias is a DID name... */
/* look for a non-DID name in disk's aliases */
/* this is the "local" CTD name generated by */
/* generate_known_disks() above */
break;
}
}
}
} else {
/* use whatever was derived from the alias name */
}
return (error);
}
/*
* FUNCTION: print_known_devices()
*
* PURPOSE: Print out the known devices.
*
* Iterates the lists of known slices, disks and HBAs
* and prints out their CTD and device names.
*/
static void
char *diskset)
{
int i = 0;
struct {
char *msg;
for (i = 0; i < 3; i++) {
gettext("\n These %s are known:\n\n"),
}
}
/*
* FUNCTION: get_usable_slices(dlist_t **list)
*
* OUTPUT: list - a dlist_t pointer to hold the returned list of
* devices.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Public accessors the the modules private lists of
* available devices.
*
* The functions are keyed by diskset name in the event
* objects in different disksets are loaded concurrently.
*/
int
{
*list = _usable_slices;
return (0);
}
int
{
*list = _usable_disks;
return (0);
}
int
{
*list = _usable_hbas;
return (0);
}
/*
* FUNCTION: generate_usable_disks_and_slices_in_local_set(dlist_t **classes,
* dlist_t **bad_disks, dlist_t **usable_disks,
* dlist_t **usable_slices)
*
* OUTPUT: used_classes - a pointer to a list of slice_class_t structs
* updated with known slices that have detected uses
* added to the correct class'e list of slices.
* with any bad disks that were detected
* useable_disks - a pointer to a list of usable disks
* useable_slices - a pointer to a list of usable slices
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Scans the disks in the local set to determine which are
* usable during layout processing.
*
* Determines which are usable by layout using usages detected
* by libdiskmgt.
*/
static int
{
int error;
/* Get disks in local set */
if (error != 0) {
return (error);
}
/* For each disk in this set... */
/* Get slices on this disk */
if (error == 0) {
/*
* Assume disk is available until a bad or unavailable
* slice is found
*/
/* For each slice on this disk... */
/* Is this slice available? */
/* Is the slice bad (inaccessible)? */
}
}
/* Is the disk available? */
}
}
}
if (error == 0) {
/* BEGIN CSTYLED */
/*
* Now reslice usable disks in the local set to
* simulate the slices they'll have when they're added
* to the named disk set, and add these resulting
* virtual slices to the list of available slices.
*/
/* END CSTYLED */
}
return (error);
}
/*
* FUNCTION: generate_virtual_slices(dlist_t *unused, dlist_t **usable)
*
* INPUT: slice_classes - a list of unused slice dm_descriptor_t handles.
*
* OUTPUT: usable - pointer to the list of usable slices, updated
* with any created virtual slices.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Helper which creates virtual slices for each disk which
* could be added to a diskset if necessary...
*
* Search the input list of slice classes for the entry
* containing slices known to be available for use by layout.
*
* Iterate the list of unused slices and determine the set
* of unique disks.
*
* For each unique disk, create virtual slice descriptors to
* to the diskset.
*
* Add theese virtual slices to the list of usable slices.
*/
static int
{
int error = 0;
/* generate virtual slices */
if (error == 0) {
} else {
*usable =
}
}
}
return (error);
}
/*
* FUNCTION: generate_usable_disks_and_slices_in_named_set(char *dsname,
* dlist_t **classes, dlist_t **bad_slices,
* dlist_t **usable_slices, dlist_t **usable_disks)
*
* INPUT: dsname - a char * diskset name.
*
* OUTPUT: classes - pointer to a list of slice_class_t structs,
* updated to include slices in the disk set with
* known uses.
* updated to include slices in the disk set that
* are inaccessible or no longer existent.
* usable_slices - pointer to a list of usable slices in the
* disk set.
* usable_disks - pointer to a list of usable disks in the
* disk set.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: 1. determine the disks in the named disk set
* 2. determine the used slices on the disks
* 3. determine the unused slices on the disks
* 4. look for unused space on the disks and collect it
* into an existing unused slice, or create a new
* virtual slice.
*/
static int
char *dsname,
{
int error = 0;
if (error != 0) {
return (error);
}
/* For each disk... */
if (error != 0) {
break;
}
/* Determine the used, unused, and bad slices on the disk */
/* For each slice... */
/* Get slice usage */
&bad_slices_on_this_disk, classes)) == 0)) {
/* Is the slice bad (inaccessible)? */
if (bad_slices_on_this_disk != NULL) {
/*
* Since one slice on this disk is bad, don't
* use any slices on this disk
*/
} else {
} else {
} else {
}
}
}
}
}
/* Done iterating slices */
/* For each unused slice... */
for (iter2 = unused_slices_on_this_disk;
/* Only do this once */
}
}
if (error == 0) {
if (error == 0) {
}
}
}
}
return (error);
}
/*
* FUNCTION: create_usable_slices(dm_descriptor_t disk, dlist_t *used,
* dlist_t *unused, dlist_t **usable);
*
* INPUT: disk - a dm_descriptor_t disk handle
* used - pointer to a list of pvt_t structs
* representing existing used slices
* on the input disk.
* unused - pointer to a list of pvt_t structs
* representing existing unused slices
* on the input disk.
*
* OUTPUT: usable - pointer to a list of pvts representing slices
* which can be used for new volume layouts.
*
* Slices in this list have any available space on the
* disk collected into the fewest, lowest indexed slices
* possible.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: helper for generate_usable_slices_and_disks_in_diskset() which
* turns any detected free space on the input disk into one or
* more slices.
*/
static int
{
int error = 0;
gettext("\n create_usable_slices for disk\n"));
/* get necessary info about disk: */
if (error != 0) {
return (error);
}
/* disk start block is first usable block */
if (error != 0) {
return (error);
}
/* disk size determines last usable disk block */
if (error != 0) {
return (error);
}
/* search for gaps before, between and after used slices */
continue;
}
gettext(" used slice %d (%10llu to %10llu)\n"),
/* first slice: make sure it starts at disk_firstblk */
if (cur_stblk != disk_firstblk) {
/* close gap at beginning of disk */
gettext(" unused space before first "
"used slice\n"));
}
}
/* check for gap between slices */
/* close gap between slices */
gettext(" unused space between slices "
}
}
} else {
/* last slice: make sure it includes last block on disk */
if (cur_endblk != disk_endblk) {
/* close gap at end of disk */
gettext(" unused space after last slice "
"cur_endblk: %llu disk_endblk: %llu\n"),
}
}
if ((error == 0) && (new_endblk != 0)) {
}
}
if (error != 0) {
}
return (error);
}
/*
* FUNCTION: add_new_usable(dm_descriptor_t disk, uint64_t stblk,
* uint64_t nblks, dlist_t **next_unused,
* dlist_t **usable);
*
* INPUT: disk - a dm_descriptor_t disk handle
* stblk - start block of the usable space
* nblks - number of usable blocks
* next_unused - pointer to the next unused slice
*
* OUTPUT: next_unused - updated pointer to the next unused slice
* usable - possibly updated pointer to a list of slices on
* the disk with usable space
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: helper for create_usable_slices() which turns free space
* on the input disk into a usable slice.
*
* If possible an existing unused slice will be recycled
* into a usable slice. If there are none, a new virtual
* slice will be created.
*/
static int
{
int error = 0;
/* try to use an existing unused slice for the usable slice */
if (*next_unused != NULL) {
gettext("\trecyling used slice into usable slice "
"start: %llu, end: %llu\n"),
}
if (new_usable == NULL) {
/* no unused slices, try to make a new virtual slice */
if (error == 0) {
if (error == 0) {
/* retrieve the virtual slice */
}
}
}
}
/* BEGIN CSTYLED */
/*
* have an unused slice, update its attributes to reflect
* the usable space it represents
*/
/* END CSTYLED */
if (error == 0) {
if (error == 0) {
}
}
}
return (error);
}
/*
* FUNCTION: update_slice_attributes(dm_descriptor_t slice, uint64_t stblk,
* uint64_t nblks, uint64_t nbytes)
*
* INPUT: slice - a dm_descriptor_t slice handle
* stblk - start block of the usable space
* nblks - size of slice in blocks
* nbytes - size of slice in bytes
*
* SIDEEFFECT: adds a modification record for the slice.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: utility which updates several slice attributes in one call.
*/
static int
{
int error = 0;
if (nblks == 0) {
} else {
}
}
}
}
}
return (error);
}
/*
* FUNCTION: generate_usable_hbas(dlist_t *slices,
* dlist_t **usable)
*
* INPUT: disks - a list of usable disks.
*
* OUTPUT: usable - a populated list of usable HBAs.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Examines usable disk list and derives the list of usable HBAs.
*
*/
static int
{
int error = 0;
/*
* for each usable disk, follow its HBA connections and
* add them to the list of usable HBAs.
*/
if (error == 0) {
/* scan list of usable HBAs and see if known */
compare_descriptor_names) == B_TRUE) {
continue;
}
/* add this HBA to the usable list */
NULL) {
} else {
*usable =
}
}
}
}
return (error);
}
/*
* FUNCTION: check_slice_usage(char *dsname, dm_descriptor_t slice,
* dm_descriptor_t disk, boolean_t *avail,
* dlist_t **bad, dlist_t **classes)
*
* INPUT: dsname - a char * diskset name.
* slice - a dm_descriptor_t handle for a known slices.
* disk - a dm_descriptor_t handle the slice's disk.
*
* OUTPUT: avail - a boolean_t to hold the slice's availability.
* possibly updated if the input slice
* was determined to be inaccessible.
* classes - pointer to a list of slice_class_t structs,
* possibly updated to include the input slice
* if it has a known use.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Handles the details of
*
* Queries the device library for the input slice's detectable
* usage status.
*
* If the slice has a detected usage, its name is added to
* the appropriate slice_class_t list in the input list of
* slice classes, this is only done if verbose output was
* requested.
*/
static int
char *dsname,
{
int error = 0;
return (error);
}
/*
* if the disk is known to be offline, skip getting status
* for the slice since it will just fail and return ENODEV.
*/
} else {
}
if (error != 0) {
gettext("Warning: unable to get slice information "
"for %s, it will not be used.\n"), name);
} else {
error = 0;
}
} else {
gettext("check_slice_usage: dm_get_stats for "
"%s failed %d\n"),
}
return (error);
}
/*
* device library provides this info in the nvpair_t list:
*
* stat_type is DM_SLICE_STAT_USE
* used_by: string (mount, svm, lu, vxvm, fs)
* used_name: string
*
*/
if (error != 0) {
error = 0;
} else {
gettext("check_slice_usage: dm_get_stats.%s for "
"%s failed %d\n"),
}
}
if (error == 0) {
if (error != 0) {
use_detail = NULL;
error = 0;
} else {
gettext("check_slice_usage: "
"dm_get_stats.%s for "
"%s failed %d\n"),
}
}
}
}
/* was detected usage SVM? */
/* check use_detail, it is in the form diskset:name */
/* check disk set name */
/* slice in the right diskset */
} else {
/* slice in other diskset */
classes);
}
} else {
/* slice is volume component */
classes);
}
} else {
/* save usage */
classes);
}
}
if (error == 0) {
} else {
}
}
return (error);
}
/*
* FUNCTION: check_svm_slice_usage(char *dsname, dm_descriptor_t slice,
* dm_descriptor_t disk, boolean_t *used,
* dlist_t **classes)
*
* INPUT: dsname - a char * diskset name.
* slice - a dm_descriptor_t handle for a known slices.
* disk - a dm_descriptor_t handle the slice's disk.
*
* OUTPUT: used - a boolean_t to hold the slice usage status.
* classes - pointer to a list of slice_class_t possibly updated
* with the input slice's SVM specific usage
* classification.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Handles the finer details of
* a single slice is being used in the context of SVM.
*
* Currently, one thing is checked:
*
* 1. determine if the slice is reserved for metadb replicas.
* The convention for disks in disksets is that a single slice
* (index 6 or 7) is set aside for metadb replicas.
*
* If this condition does not hold, the slice is considered
* available for use by layout and 'used' is set to B_FALSE.
*/
static int
char *dsname,
{
int error = 0;
if (error == 0) {
if (is_replica == B_TRUE) {
/* is replica slice -> used */
} else {
}
}
return (error);
}
/*
* FUNCTION: save_slice_classification(char *dsname, dm_descriptor_t slice,
* dm_descriptor_t disk, char *used_by, char *usage_detail,
* dlist_t **classes)
*
* INPUT: dsname - a char * disk set name
* slice - a dm_descriptor_t slice handle.
* disk - a dm_descriptor_t handle for the slice's disk.
* used_by - a char * usage classification.
* usage_detail - a char * usage description for the slice.
*
* OUTPUT: classes - a list of slice_class_t updated to hold a usage
* entry for the input slicexs.
*
* SIDEEFFECT: adds the input slice to the list of known, used slices.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Adds an entry to the
* appropriate slice_class_t list of slices. If there is
* not an appropriate slice_class_t entry in the input list
* of classes, one is added.
*
* As a performance optimization the slice usage classification
* information is only saved if verbose output was requested by
* the user.
*/
static int
char *dsname,
char *usage,
char *usage_detail,
{
int error = 0;
/* locate class struct matching 'usage' */
break;
}
}
/* add a new class to the list of classes */
} else {
} else {
} else {
}
}
}
}
} else {
} else {
}
}
}
}
return (error);
}
/*
* FUNCTION: print_usable_devices()
*
* PURPOSE: Print out the devices determined to be available for
* use by layout.
*
* Iterates the lists of usable slices, disks and HBAs
* and prints out their CTD and device names.
*/
static void
{
int i = 0;
struct {
char *msg;
for (i = 0; i < 3; i++) {
gettext("\n These %s are usable:\n\n"),
}
}
/*
* FUNCTION: print_device_list(dlist_t *devices)
*
* INPUT: devices - a list of device descriptor handles
*
* PURPOSE: A helper for the print_XXX_devices() routines which iterates
* the input list and prints out each device name, CTD name and
* alias(es).
*/
static void
{
gettext(" (alias: %s)\n"),
}
}
}
/*
* FUNCTION: print_unusable_devices(
* dlist_t *bad_slices, dlist_t *bad_disks,
* dlist_t *used_classes)
*
* INPUT: used_classes - a list of slice_class_t structs
*
* PURPOSE: Print out the devices determined to be unavailable for
* use by layout.
*
* Iterates the input list of slice classifications and prints
* out a description of the class and the slices so classified.
*
* Also iterates the lists of bad slices and disks (those that
* libdiskmgt returned descriptors for but cannot be accessed)
* and notes them as unusable.
*/
static void
{
char *preamble;
struct {
char *msg;
/* report bad disks and slices */
#if defined(sparc)
gettext("\n These disks are not usable, they may "
"may be offline or cannot be accessed:\n\n"));
gettext("\n These disks are not usable, they may "
"may be offline,\n missing a Solaris FDISK "
"partition or cannot be accessed:\n\n"));
#endif
}
if (bad_slices != NULL) {
"\n These slices, and subsequently the disks on which they\n"
"reside, are not usable, they cannot be accessed:\n\n"));
}
/* report used slices and usages */
}
}
}
}
/*
* FUNCTION: char * get_slice_usage_msg(char *usage)
*
* INPUT: usage - char * string representing a slice usage classification
*
* OUTPUT: char * "friendly" usage message
*
* PURPOSE: the input usage string comes from libdiskmgt and is very terse.
*
* Convert it into a friendlier usage description suitable for user
* consumption.
*/
static char *
char *usage)
{
} else {
/* libdiskmgt has detected a usage unknown to layout */
}
return (str);
}
/*
* FUNCTION: set_alias(dm_descriptor_t desc, char *alias)
*
* INPUT: desc - a dm_descriptor_t handle.
* alias - a char * alias for the device represented
* by the descriptor.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Adds the specified alias to the known aliases for the
* device associated with the input descriptor.
*/
int
char *alias)
{
int error = 0;
int i = 0;
return (error);
}
if ((error = get_string_array(
return (error);
}
/* no aliases yet */
error = 0;
}
/* add new alias */
if (new_aliases != NULL) {
for (i = 0; i < nelem && i < MAX_ALIASES; i++) {
new_aliases[i] = dup;
} else {
}
}
if (error == 0) {
if (i == MAX_ALIASES) {
gettext("Maximum number of device aliases "
"(8) reached\n"),
error = -1;
} else {
new_aliases[i] = alias;
new_aliases, i + 1);
}
}
}
if (error == 0) {
/* cache descriptor under this alias */
}
return (error);
}
/*
* FUNCTION: get_aliases(dm_descriptor_t desc, dlist_t **list)
*
* INPUT: desc - a dm_descriptor_t handle.
*
* OUTPUT: list - a dlist_t list pointing to the list of
* aliases associated with the device
* represented by the descriptor.
*
* RETURNS: int - 0 on success
* !0 otherwise
*
* PURPOSE: Retrieves aliases for the input descriptor and
* appends them to the input list.
*
* The list of returned items must be freed by calling
* dlist_free_items(list, free)
*/
int
{
int error = 0;
int i;
return (error);
}
if ((error = get_string_array(
/* no aliases */
return (0);
}
}
for (i = 0; i < nelem; i++) {
char *dup;
break;
}
break;
}
}
return (error);
}
/*
* FUNCTION: compare_start_blocks(
* void *obj1, void *obj2)
*
* INPUT: desc1 - opaque pointer to a dm_descriptor_t
* desc2 - opaque pointer to a dm_descriptor_t
*
*
* PURPOSE: dlist_t helper which compares the start blocks of
* the two input dm_descriptor_t slice handles.
*/
static int
void *desc1,
void *desc2)
{
}
/*
* FUNCTION: compare_desc_display_names(
* void *desc1, void *desc2)
*
* INPUT: desc1 - opaque pointer to a dm_descriptor_t
* desc2 - opaque pointer to a dm_descriptor_t
*
* RETURNS: int - <0 - if desc1.name < desc2.name
* 0 - if desc1.name == desc2.name
* >0 - if desc1.name > desc.name
*
* PURPOSE: dlist_t helper which compares the CTD names of the
* two input dm_descriptor_t objects.
*/
static int
void *desc1,
void *desc2)
{
}