2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1993, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <meta.h>
2N/A#include <metad.h>
2N/A
2N/A#include <ctype.h>
2N/A#include <string.h>
2N/A#include <sys/fs/ufs_fsdir.h>
2N/A
2N/A/*
2N/A * Just in case we're not in a build environment, make sure that
2N/A * TEXT_DOMAIN gets set to something.
2N/A */
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*
2N/A * Macros to produce a quoted string containing the value of a
2N/A * preprocessor macro. For example, if SIZE is defined to be 256,
2N/A * VAL2STR(SIZE) is "256". This is used to construct format
2N/A * strings for scanf-family functions below.
2N/A */
2N/A#define QUOTE(x) #x
2N/A#define VAL2STR(x) QUOTE(x)
2N/A
2N/Aextern char *getfullblkname();
2N/A
2N/A/*
2N/A * caches
2N/A */
2N/Astatic mdsetnamelist_t *setlistp = NULL;
2N/Astatic mddrivenamelist_t *drivelistp = NULL;
2N/Astatic mdnamelist_t *fastnmlp = NULL;
2N/Astatic mdhspnamelist_t *hsplistp = NULL;
2N/A
2N/A/*
2N/A * Static definitions
2N/A */
2N/Astatic int chksetname(mdsetname_t **spp, char *sname, md_error_t *ep);
2N/A
2N/A/*
2N/A * FUNCTION: meta_dsk_to_rdsk()
2N/A * INPUT: str - Fully qualified pathname of a block or character device
2N/A * RETURNS: char * - The pathname of the raw device
2N/A * PURPOSE: Allocation of a new string representing the character device
2N/A * associated with the input string. Note that no checking is
2N/A * done to verify the existence of this device file.
2N/A */
2N/Astatic char *
2N/Ameta_dsk_to_rdsk(char *str)
2N/A{
2N/A char *dp = NULL;
2N/A char *rdskp = NULL;
2N/A
2N/A assert(*str == '/');
2N/A
2N/A if ((dp = strstr(str, "/rdsk/")) != NULL)
2N/A return (Strdup(str));
2N/A
2N/A /*
2N/A * If this is a malformed string, (i.e. containing neither
2N/A * "/rdsk/" nor "/dsk/") then check to see if the caller
2N/A * is passing old school device names like "/dev/[r]sd" or
2N/A * exotic hardware presenting "/dev/[r]dc" names.
2N/A */
2N/A if ((dp = strstr(str, "/dsk/")) == NULL) {
2N/A if (strncmp(str, "/dev/r", 6) == 0) {
2N/A return (Strdup(str));
2N/A } else if (strncmp(str, "/dev/", 5) == 0) {
2N/A dp = str + 4;
2N/A } else {
2N/A return (NULL);
2N/A }
2N/A }
2N/A
2N/A dp++;
2N/A if (*dp == '\0')
2N/A return (NULL);
2N/A
2N/A rdskp = Zalloc(strlen(str) + 2);
2N/A (void) strncpy(rdskp, str, dp - str);
2N/A rdskp[dp - str] = 'r';
2N/A (void) strcpy(rdskp + (dp - str) + 1, dp);
2N/A
2N/A return (rdskp);
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: rawname()
2N/A * INPUT: uname - Fully qualified pathname of a block or character device
2N/A * RETURNS: char * - The fully qualified character device pathname
2N/A * PURPOSE: Return the fully qualified pathname of the character device
2N/A * corresponding to the block or character device passed in.
2N/A */
2N/Astatic char *
2N/Arawname(char *uname)
2N/A{
2N/A char *new_path = NULL;
2N/A int ret = -1;
2N/A struct stat statbuf;
2N/A
2N/A if (*uname != '/')
2N/A return (NULL);
2N/A
2N/A if ((new_path = meta_dsk_to_rdsk(uname)) == NULL)
2N/A return (NULL);
2N/A
2N/A if (strncmp("/dev/", new_path, 5) == 0) {
2N/A ret = stat(new_path, &statbuf);
2N/A if (ret != 0 || (! S_ISCHR(statbuf.st_mode))) {
2N/A Free(new_path);
2N/A return (NULL);
2N/A }
2N/A }
2N/A
2N/A return (new_path);
2N/A}
2N/A
2N/Achar *
2N/Ablkname(
2N/A char *uname
2N/A)
2N/A{
2N/A char *p;
2N/A
2N/A if ((p = getfullblkname(uname)) == NULL) {
2N/A return (NULL);
2N/A } else if (*p == '\0') {
2N/A Free(p);
2N/A return (NULL);
2N/A } else {
2N/A return (p);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: parse_device()
2N/A * INPUT: sp - pointer to setname struct
2N/A * uname - Name of either a hotspare pool or metadevice
2N/A * This can either be a fully qualified path or
2N/A * in the form [set name/]device
2N/A * OUTPUT: snamep - name of the set that uname is in
2N/A * fnamep - metadevice or hsp with path and set name info stripped
2N/A * This parameter is dynamically allocated and must be
2N/A * freed by the calling function.
2N/A * PURPOSE: Parse uname and sp into the set name and device name strings.
2N/A * If the set name is specified as part of uname then use that
2N/A * otherwise attempt to get the set name from sp.
2N/A */
2N/Avoid
2N/Aparse_device(
2N/A mdsetname_t *sp,
2N/A char *uname,
2N/A char **fnamep, /* dynamically alloced - caller must free */
2N/A char **snamep /* dynamically alloced - caller must free */
2N/A)
2N/A{
2N/A char setname[FILENAME_MAX+1];
2N/A char devname[FILENAME_MAX+1];
2N/A char *tname = Malloc(strlen(uname) + 1);
2N/A
2N/A int len;
2N/A char *up;
2N/A char *tp;
2N/A int lcws; /* last character was slash */
2N/A
2N/A /* Now copy uname to tname by throwing away any duplicate '/' */
2N/A for (lcws = 0, tp = tname, up = uname; *up; up++) {
2N/A if (lcws) {
2N/A if (*up == '/') {
2N/A continue;
2N/A } else {
2N/A lcws = 0;
2N/A }
2N/A }
2N/A if (*up == '/') {
2N/A lcws = 1;
2N/A }
2N/A *tp++ = *up; /* ++ is done by for loop */
2N/A }
2N/A *tp = '\0';
2N/A
2N/A /* fully-qualified - local set */
2N/A if (((sscanf(tname, "/dev/md/dsk/%" VAL2STR(FILENAME_MAX) "s%n",
2N/A devname, &len) == 1) && (strlen(tname) == len)) ||
2N/A ((sscanf(tname, "/dev/md/rdsk/%" VAL2STR(FILENAME_MAX) "s%n",
2N/A devname, &len) == 1) && (strlen(tname) == len))) {
2N/A *snamep = Strdup(MD_LOCAL_NAME);
2N/A *fnamep = Strdup(devname);
2N/A Free(tname);
2N/A return;
2N/A }
2N/A
2N/A /* with setname specified - either fully qualified and relative spec */
2N/A if (((sscanf(tname, "%[^/]/%" VAL2STR(FILENAME_MAX) "s%n",
2N/A setname, devname, &len) == 2) && (strlen(tname) == len)) ||
2N/A ((sscanf(tname, "/dev/md/%[^/]/dsk/%" VAL2STR(FILENAME_MAX) "s%n",
2N/A setname, devname, &len) == 2) && (strlen(tname) == len)) ||
2N/A ((sscanf(tname, "/dev/md/%[^/]/rdsk/%" VAL2STR(FILENAME_MAX) "s%n",
2N/A setname, devname, &len) == 2) && (strlen(tname) == len))) {
2N/A
2N/A *snamep = Strdup(setname);
2N/A *fnamep = Strdup(devname);
2N/A Free(tname);
2N/A return;
2N/A }
2N/A
2N/A /* without setname specified */
2N/A *fnamep = tname;
2N/A if (sp != NULL && !metaislocalset(sp))
2N/A *snamep = Strdup(sp->setname);
2N/A else
2N/A *snamep = NULL;
2N/A}
2N/A
2N/A/*
2N/A * check for "all"
2N/A */
2N/Aint
2N/Ameta_is_all(char *s)
2N/A{
2N/A if ((strcoll(s, gettext("all")) == 0) ||
2N/A (strcoll(s, gettext("ALL")) == 0))
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check for "none"
2N/A */
2N/Aint
2N/Ameta_is_none(char *s)
2N/A{
2N/A if ((strcoll(s, gettext("none")) == 0) ||
2N/A (strcoll(s, gettext("NONE")) == 0))
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Avalid_name_syntax(char *uname)
2N/A{
2N/A int i;
2N/A int uname_len;
2N/A
2N/A if (uname == NULL || !isalpha(uname[0]))
2N/A return (0);
2N/A
2N/A uname_len = strlen(uname);
2N/A if (uname_len > MAXNAMLEN)
2N/A return (0);
2N/A
2N/A /* 'all' and 'none' are reserved */
2N/A if (meta_is_all(uname) || meta_is_none(uname))
2N/A return (0);
2N/A
2N/A for (i = 1; i < uname_len; i++) {
2N/A if ((isalnum(uname[i]) || uname[i] == '-' ||
2N/A uname[i] == '_' || uname[i] == '.'))
2N/A continue;
2N/A break;
2N/A }
2N/A
2N/A if (i < uname_len)
2N/A return (0);
2N/A
2N/A return (1);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * canonicalize name
2N/A */
2N/Achar *
2N/Ameta_canonicalize(
2N/A mdsetname_t *sp,
2N/A char *uname
2N/A)
2N/A{
2N/A char *sname = NULL;
2N/A char *tname = NULL;
2N/A char *cname;
2N/A
2N/A /* return the dev name and set name */
2N/A parse_device(sp, uname, &tname, &sname);
2N/A
2N/A if (!valid_name_syntax(tname)) {
2N/A Free(tname);
2N/A if (sname != NULL)
2N/A Free(sname);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((sname == NULL) || (strcmp(sname, MD_LOCAL_NAME) == 0))
2N/A cname = tname;
2N/A else {
2N/A size_t cname_len;
2N/A
2N/A cname_len = strlen(tname) + strlen(sname) + 2;
2N/A cname = Malloc(cname_len);
2N/A (void) snprintf(
2N/A cname, cname_len, "%s/%s", sname, tname);
2N/A Free(tname);
2N/A }
2N/A
2N/A if (sname != NULL)
2N/A Free(sname);
2N/A
2N/A return (cname);
2N/A}
2N/A
2N/A/*
2N/A * canonicalize name and check the set
2N/A */
2N/Achar *
2N/Ameta_canonicalize_check_set(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *sname = NULL;
2N/A char *tname = NULL;
2N/A char *cname;
2N/A
2N/A /* return the dev name and set name */
2N/A parse_device(*spp, uname, &tname, &sname);
2N/A
2N/A if (!valid_name_syntax(tname)) {
2N/A (void) mderror(ep, MDE_NAME_ILLEGAL, tname);
2N/A if (sname != NULL)
2N/A Free(sname);
2N/A Free(tname);
2N/A return (NULL);
2N/A }
2N/A
2N/A /* check the set name returned from the name for validity */
2N/A if (chksetname(spp, sname, ep) != 0) {
2N/A Free(tname);
2N/A if (sname != NULL)
2N/A Free(sname);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((sname == NULL) || (strcmp(sname, MD_LOCAL_NAME) == 0))
2N/A cname = tname;
2N/A else {
2N/A size_t cname_len;
2N/A
2N/A cname_len = strlen(tname) + strlen(sname) + 2;
2N/A cname = Malloc(cname_len);
2N/A (void) snprintf(
2N/A cname, cname_len, "%s/%s", sname, tname);
2N/A Free(tname);
2N/A }
2N/A
2N/A if (sname != NULL)
2N/A Free(sname);
2N/A
2N/A return (cname);
2N/A}
2N/A
2N/A/*
2N/A * Verify that the name is a valid hsp/metadevice name
2N/A */
2N/Astatic int
2N/Aparse_meta_hsp_name(char *uname)
2N/A{
2N/A char *sname = NULL;
2N/A char *tname = NULL;
2N/A int ret;
2N/A
2N/A /* return the dev name and set name */
2N/A parse_device(NULL, uname, &tname, &sname);
2N/A
2N/A ret = valid_name_syntax(tname);
2N/A if (sname != NULL)
2N/A Free(sname);
2N/A Free(tname);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * check that name is a metadevice
2N/A */
2N/Aint
2N/Ais_metaname(
2N/A char *uname
2N/A)
2N/A{
2N/A return (parse_meta_hsp_name(uname));
2N/A}
2N/A
2N/A/*
2N/A * check that name is a hotspare pool
2N/A */
2N/Aint
2N/Ais_hspname(
2N/A char *uname
2N/A)
2N/A{
2N/A return (parse_meta_hsp_name(uname));
2N/A}
2N/A
2N/A/*
2N/A * check to verify that name is an existing metadevice
2N/A */
2N/Aint
2N/Ais_existing_metadevice(
2N/A mdsetname_t *sp,
2N/A char *uname
2N/A)
2N/A{
2N/A char *raw_name;
2N/A char *set_name;
2N/A char *full_path;
2N/A char *fname = NULL;
2N/A int pathlen;
2N/A int retval = 0;
2N/A
2N/A assert(uname != NULL);
2N/A /*
2N/A * If it is an absolute name of a metadevice, then just call rawname
2N/A * on the input
2N/A */
2N/A if (uname[0] == '/') {
2N/A if (strncmp("/dev/md", uname, strlen("/dev/md")) == 0 &&
2N/A (raw_name = rawname(uname)) != NULL) {
2N/A Free(raw_name);
2N/A return (1);
2N/A }
2N/A return (0);
2N/A }
2N/A
2N/A /* create a fully specified path from the parsed string */
2N/A parse_device(sp, uname, &fname, &set_name);
2N/A
2N/A if ((set_name == NULL) || (strcmp(set_name, MD_LOCAL_NAME) == 0)) {
2N/A pathlen = strlen("/dev/md/rdsk/") + strlen(fname) + 1;
2N/A full_path = Zalloc(pathlen);
2N/A (void) snprintf(full_path, pathlen, "/dev/md/rdsk/%s", fname);
2N/A } else {
2N/A pathlen = strlen("/dev/md//rdsk/") + strlen(fname) +
2N/A strlen(set_name) + 1;
2N/A full_path = Zalloc(pathlen);
2N/A (void) snprintf(full_path, pathlen, "/dev/md/%s/rdsk/%s",
2N/A set_name, fname);
2N/A }
2N/A
2N/A if ((raw_name = rawname(full_path)) != NULL) {
2N/A Free(raw_name);
2N/A retval = 1;
2N/A }
2N/A
2N/A if (set_name != NULL)
2N/A Free(set_name);
2N/A
2N/A Free(fname);
2N/A Free(full_path);
2N/A return (retval);
2N/A}
2N/A
2N/A/*
2N/A * check to verify that name is an existing hsp
2N/A */
2N/Aint
2N/Ais_existing_hsp(
2N/A mdsetname_t *sp,
2N/A char *uname
2N/A)
2N/A{
2N/A md_error_t status = mdnullerror;
2N/A hsp_t hsp;
2N/A set_t cur_set;
2N/A
2N/A if (sp != NULL)
2N/A cur_set = sp->setno;
2N/A else
2N/A cur_set = 0;
2N/A
2N/A hsp = meta_gethspnmentbyname(cur_set, MD_SIDEWILD, uname, &status);
2N/A
2N/A if (hsp == MD_HSP_NONE) {
2N/A mdclrerror(&status);
2N/A return (0);
2N/A }
2N/A return (1);
2N/A}
2N/A
2N/A/*
2N/A * check to verify that name is an existing metadevice or hotspare pool
2N/A */
2N/Aint
2N/Ais_existing_meta_hsp(
2N/A mdsetname_t *sp,
2N/A char *uname
2N/A)
2N/A{
2N/A if (is_existing_metadevice(sp, uname) ||
2N/A is_existing_hsp(sp, uname))
2N/A return (1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * mdsetname_t stuff
2N/A */
2N/A
2N/A/*
2N/A * initialize setname
2N/A */
2N/Astatic void
2N/Ametainitsetname(
2N/A mdsetname_t *sp
2N/A)
2N/A{
2N/A (void) memset(sp, '\0', sizeof (*sp));
2N/A}
2N/A
2N/Astatic void
2N/Ametafreesetdesc(md_set_desc *sd)
2N/A{
2N/A md_mnnode_desc *nd;
2N/A
2N/A if (MD_MNSET_DESC(sd)) {
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A sd->sd_nodelist = nd->nd_next;
2N/A Free(nd);
2N/A nd = sd->sd_nodelist;
2N/A }
2N/A }
2N/A metafreedrivedesc(&sd->sd_drvs);
2N/A Free(sd);
2N/A}
2N/A
2N/A/*
2N/A * free allocated setname
2N/A */
2N/Astatic void
2N/Ametafreesetname(
2N/A mdsetname_t *sp
2N/A)
2N/A{
2N/A if (sp->setname != NULL)
2N/A Free(sp->setname);
2N/A if (sp->setdesc != NULL)
2N/A metafreesetdesc(sp->setdesc);
2N/A metainitsetname(sp);
2N/A}
2N/A
2N/A/*
2N/A * flush the setname cache
2N/A */
2N/Astatic void
2N/Ametaflushsetnames()
2N/A{
2N/A mdsetnamelist_t *p, *n;
2N/A
2N/A for (p = setlistp, n = NULL; (p != NULL); p = n) {
2N/A n = p->next;
2N/A metafreesetname(p->sp);
2N/A Free(p->sp);
2N/A Free(p);
2N/A }
2N/A setlistp = NULL;
2N/A}
2N/A
2N/A/*
2N/A * get set number
2N/A */
2N/Astatic int
2N/Agetsetno(
2N/A char *sname,
2N/A set_t *setnop,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_set_record *sr;
2N/A size_t len;
2N/A
2N/A /* local set */
2N/A if ((sname == NULL) || (strcmp(sname, MD_LOCAL_NAME) == 0)) {
2N/A *setnop = 0;
2N/A return (0);
2N/A }
2N/A
2N/A /* shared set */
2N/A if ((sr = getsetbyname(sname, ep)) == NULL) {
2N/A if (mdisrpcerror(ep, RPC_PROGNOTREGISTERED)) {
2N/A char *p;
2N/A
2N/A len = strlen(sname) + 30;
2N/A p = Malloc(len);
2N/A
2N/A (void) snprintf(p, len, "setname \"%s\"", sname);
2N/A (void) mderror(ep, MDE_NO_SET, p);
2N/A Free(p);
2N/A }
2N/A return (-1);
2N/A }
2N/A *setnop = sr->sr_setno;
2N/A mdclrerror(ep);
2N/A free_sr(sr);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * find setname from name
2N/A */
2N/Amdsetname_t *
2N/Ametasetname(
2N/A char *sname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdsetnamelist_t **tail;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A
2N/A /* look for cached value first */
2N/A assert(sname != NULL);
2N/A for (tail = &setlistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A sp = (*tail)->sp;
2N/A if (strcmp(sp->setname, sname) == 0) {
2N/A return (sp);
2N/A }
2N/A }
2N/A
2N/A /* setup set */
2N/A if (getsetno(sname, &setno, ep) != 0)
2N/A return (NULL);
2N/A
2N/A /* allocate new list element and setname */
2N/A *tail = Zalloc(sizeof (**tail));
2N/A sp = (*tail)->sp = Zalloc(sizeof (*sp));
2N/A
2N/A sp->setname = Strdup(sname);
2N/A sp->setno = setno;
2N/A sp->lockfd = MD_NO_LOCK;
2N/A
2N/A return (sp);
2N/A}
2N/A
2N/A/*
2N/A * find setname from setno
2N/A */
2N/Amdsetname_t *
2N/Ametasetnosetname(
2N/A set_t setno,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdsetnamelist_t *slp;
2N/A mdsetname_t *sp;
2N/A md_set_record *sr;
2N/A
2N/A /* look for cached value first */
2N/A for (slp = setlistp; (slp != NULL); slp = slp->next) {
2N/A sp = slp->sp;
2N/A if (sp->setno == setno)
2N/A return (sp);
2N/A }
2N/A
2N/A /* local set */
2N/A if (setno == MD_LOCAL_SET)
2N/A return (metasetname(MD_LOCAL_NAME, ep));
2N/A
2N/A /* shared set */
2N/A if ((sr = getsetbynum(setno, ep)) == NULL)
2N/A return (NULL);
2N/A sp = metasetname(sr->sr_setname, ep);
2N/A if (sp != NULL)
2N/A mdclrerror(ep);
2N/A free_sr(sr);
2N/A return (sp);
2N/A}
2N/A
2N/Amdsetname_t *
2N/Ametafakesetname(
2N/A set_t setno,
2N/A char *sname
2N/A)
2N/A{
2N/A mdsetnamelist_t **tail;
2N/A mdsetname_t *sp;
2N/A
2N/A /* look for cached value first */
2N/A for (tail = &setlistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A sp = (*tail)->sp;
2N/A if (sp->setno == setno) {
2N/A if ((sp->setname == NULL) && (sname != NULL))
2N/A sp->setname = Strdup(sname);
2N/A return (sp);
2N/A }
2N/A }
2N/A
2N/A /* allocate new list element and setname */
2N/A *tail = Zalloc(sizeof (**tail));
2N/A sp = (*tail)->sp = Zalloc(sizeof (*sp));
2N/A
2N/A if (sname != NULL)
2N/A sp->setname = Strdup(sname);
2N/A sp->setno = setno;
2N/A sp->lockfd = MD_NO_LOCK;
2N/A
2N/A return (sp);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * setup set record (sr) and cache it in the mdsetname_t struct
2N/A */
2N/Amd_set_desc *
2N/Asr2setdesc(
2N/A md_set_record *sr
2N/A)
2N/A{
2N/A md_set_desc *sd;
2N/A int i;
2N/A md_mnset_record *mnsr;
2N/A md_mnnode_desc *nd, *nd_prev = 0;
2N/A md_mnnode_record *nr;
2N/A md_error_t status = mdnullerror;
2N/A md_error_t *ep = &status;
2N/A int nodecnt, nrcnt;
2N/A mndiskset_membershiplist_t *nl, *nl2;
2N/A
2N/A sd = Zalloc(sizeof (*sd));
2N/A sd->sd_ctime = sr->sr_ctime;
2N/A sd->sd_genid = sr->sr_genid;
2N/A sd->sd_setno = sr->sr_setno;
2N/A sd->sd_flags = sr->sr_flags;
2N/A
2N/A if (MD_MNSET_DESC(sd)) {
2N/A mnsr = (md_mnset_record *)sr;
2N/A (void) strlcpy(sd->sd_mn_master_nodenm,
2N/A mnsr->sr_master_nodenm, sizeof (sd->sd_mn_master_nodenm));
2N/A sd->sd_mn_master_nodeid = mnsr->sr_master_nodeid;
2N/A if (strcmp(mnsr->sr_master_nodenm, mynode()) == 0) {
2N/A sd->sd_mn_am_i_master = 1;
2N/A }
2N/A
2N/A /*
2N/A * Get membershiplist from API routine. If there's
2N/A * an error, just use a NULL nodelist.
2N/A */
2N/A if (meta_read_nodelist(&nodecnt, &nl, ep) == -1) {
2N/A nodecnt = 0; /* no nodes are alive */
2N/A nl = NULL;
2N/A }
2N/A nr = mnsr->sr_nodechain;
2N/A nrcnt = 0;
2N/A /*
2N/A * Node descriptor node list must be built in
2N/A * ascending order of nodeid. The nodechain
2N/A * in the mnset record is in ascending order,
2N/A * so just make them the same.
2N/A */
2N/A while (nr) {
2N/A nd = Zalloc(sizeof (*nd));
2N/A if (nd_prev) {
2N/A nd_prev->nd_next = nd;
2N/A } else {
2N/A sd->sd_nodelist = nd;
2N/A }
2N/A nd->nd_ctime = nr->nr_ctime;
2N/A nd->nd_genid = nr->nr_genid;
2N/A nd->nd_flags = nr->nr_flags;
2N/A
2N/A (void) strlcpy(nd->nd_nodename, nr->nr_nodename,
2N/A sizeof (nd->nd_nodename));
2N/A nd->nd_nodeid = nr->nr_nodeid;
2N/A if (strcmp(nd->nd_nodename, mynode()) == 0) {
2N/A sd->sd_mn_mynode = nd;
2N/A }
2N/A if (nd->nd_nodeid == sd->sd_mn_master_nodeid) {
2N/A sd->sd_mn_masternode = nd;
2N/A }
2N/A
2N/A /*
2N/A * If node is marked ALIVE, then set priv_ic
2N/A * from membership list. During the early part
2N/A * of a reconfig cycle, the membership list may
2N/A * have been changed, (a node entering or leaving
2N/A * the cluster), but rpc.metad hasn't flushed
2N/A * its data yet. So, if node is marked alive, but
2N/A * is no longer in the membership list (node has
2N/A * left the cluster) then just leave priv_ic to NULL.
2N/A */
2N/A if (nd->nd_flags & MD_MN_NODE_ALIVE) {
2N/A nl2 = nl;
2N/A while (nl2) {
2N/A if (nl2->msl_node_id == nd->nd_nodeid) {
2N/A (void) strlcpy(nd->nd_priv_ic,
2N/A nl2->msl_node_addr,
2N/A sizeof (nd->nd_priv_ic));
2N/A break;
2N/A }
2N/A nl2 = nl2->next;
2N/A }
2N/A }
2N/A
2N/A nr = nr->nr_next;
2N/A nrcnt++;
2N/A nd_prev = nd;
2N/A }
2N/A sd->sd_mn_numnodes = nrcnt;
2N/A if (nodecnt)
2N/A meta_free_nodelist(nl);
2N/A
2N/A /* Just copying to keep consistent view between sr & sd */
2N/A (void) strlcpy(sd->sd_nodes[0], mnsr->sr_nodes_bw_compat[0],
2N/A sizeof (sd->sd_nodes[0]));
2N/A } else {
2N/A for (i = 0; i < MD_MAXSIDES; i++)
2N/A (void) strlcpy(sd->sd_nodes[i], sr->sr_nodes[i],
2N/A sizeof (sd->sd_nodes[i]));
2N/A }
2N/A
2N/A sd->sd_med = sr->sr_med; /* structure assignment */
2N/A
2N/A return (sd);
2N/A}
2N/A
2N/Amd_set_desc *
2N/Ametaget_setdesc(
2N/A mdsetname_t *sp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_set_record *sr;
2N/A
2N/A if (sp->setdesc != NULL)
2N/A return (sp->setdesc);
2N/A
2N/A if (sp->setname != NULL) {
2N/A if ((sr = getsetbyname(sp->setname, ep)) != NULL) {
2N/A sp->setdesc = sr2setdesc(sr);
2N/A mdclrerror(ep);
2N/A free_sr(sr);
2N/A return (sp->setdesc);
2N/A }
2N/A }
2N/A
2N/A if (sp->setno > 0) {
2N/A if ((sr = getsetbynum(sp->setno, ep)) != NULL) {
2N/A sp->setdesc = sr2setdesc(sr);
2N/A mdclrerror(ep);
2N/A free_sr(sr);
2N/A return (sp->setdesc);
2N/A }
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * metapurgesetcache:
2N/A * -----------------
2N/A * Purge the application setlistp cache for the given set number.
2N/A * This means a subsequent call to metasetname() or metasetnosetname() will
2N/A * incur a disk access to read the replica set contents instead of
2N/A * short-circuiting and returning potentially stale cached data.
2N/A */
2N/Astatic void
2N/Ametapurgesetcache(set_t setno)
2N/A{
2N/A mdsetnamelist_t **tail, **prev;
2N/A mdsetname_t *sp;
2N/A
2N/A for (prev = NULL, tail = &setlistp; (*tail != NULL);
2N/A tail = &(*tail)->next) {
2N/A sp = (*tail)->sp;
2N/A if (sp) {
2N/A if (sp->setno == setno ||
2N/A (sp->setdesc && sp->setdesc->sd_setno == setno)) {
2N/A if (prev == NULL) {
2N/A setlistp = (*tail)->next;
2N/A } else {
2N/A (*prev)->next = (*tail)->next;
2N/A }
2N/A return;
2N/A }
2N/A }
2N/A prev = tail;
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Ametaflushsetname(mdsetname_t *sp)
2N/A{
2N/A if (sp == NULL)
2N/A return;
2N/A
2N/A if (sp->setdesc == NULL)
2N/A return;
2N/A
2N/A /*
2N/A * Purge the setlistp cache for this setno
2N/A */
2N/A metapurgesetcache(sp->setdesc->sd_setno);
2N/A
2N/A metafreesetdesc(sp->setdesc);
2N/A sp->setdesc = NULL;
2N/A}
2N/A
2N/A/*
2N/A * metaflushsetno:
2N/A * --------------
2N/A * Flush the setlistp cache for the given non-local setno.
2N/A */
2N/Avoid
2N/Ametaflushsetno(set_t setno)
2N/A{
2N/A if (setno > 0 && setno < MD_MAXSETS) {
2N/A metapurgesetcache(setno);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * check for local set
2N/A */
2N/Aint
2N/Ametaislocalset(
2N/A mdsetname_t *sp
2N/A)
2N/A{
2N/A assert(sp->setname != NULL);
2N/A if (strcmp(sp->setname, MD_LOCAL_NAME) == 0) {
2N/A assert(sp->setno == MD_LOCAL_SET);
2N/A return (1);
2N/A } else {
2N/A assert(sp->setno != MD_LOCAL_SET);
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * check for same set
2N/A */
2N/Aint
2N/Ametaissameset(
2N/A mdsetname_t *sp1,
2N/A mdsetname_t *sp2
2N/A)
2N/A{
2N/A if (strcmp(sp1->setname, sp2->setname) == 0) {
2N/A assert(sp1->setno == sp2->setno);
2N/A return (1);
2N/A } else {
2N/A assert(sp1->setno != sp2->setno);
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * check to see if set changed
2N/A */
2N/Astatic int
2N/Achkset(
2N/A mdsetname_t **spp,
2N/A char *sname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A /* if we already have a set, make sure it's the same */
2N/A if (*spp != NULL && !metaislocalset(*spp)) {
2N/A if ((*spp)->setname != sname &&
2N/A strcmp((*spp)->setname, sname) != 0) {
2N/A return (mderror(ep, MDE_SET_DIFF, sname));
2N/A }
2N/A return (0);
2N/A }
2N/A
2N/A /* otherwise store new set name and number */
2N/A if ((*spp = metasetname(sname, ep)) == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * check to see if set changed from default
2N/A */
2N/Astatic int
2N/Achksetname(
2N/A mdsetname_t **spp,
2N/A char *sname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A /* default to *spp's setname, or if that is NULL to MD_LOCAL_NAME */
2N/A if (sname == NULL) {
2N/A if (*spp) {
2N/A return (0);
2N/A } else {
2N/A sname = MD_LOCAL_NAME;
2N/A }
2N/A }
2N/A
2N/A /* see if changed */
2N/A return (chkset(spp, sname, ep));
2N/A}
2N/A
2N/A/*
2N/A * check setname from setno
2N/A */
2N/Astatic int
2N/Achksetno(
2N/A mdsetname_t **spp,
2N/A set_t setno,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_set_record *sr;
2N/A int rval;
2N/A
2N/A /* local set */
2N/A if (setno == 0)
2N/A return (chkset(spp, MD_LOCAL_NAME, ep));
2N/A
2N/A /* shared set */
2N/A if ((sr = getsetbynum(setno, ep)) == NULL)
2N/A return (-1);
2N/A rval = chkset(spp, sr->sr_setname, ep);
2N/A if (rval != -1)
2N/A mdclrerror(ep);
2N/A free_sr(sr);
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * mddrivename_t stuff
2N/A */
2N/A
2N/A/*
2N/A * initialize name
2N/A */
2N/Astatic void
2N/Ametainitname(
2N/A mdname_t *np
2N/A)
2N/A{
2N/A (void) memset(np, 0, sizeof (*np));
2N/A np->dev = NODEV64;
2N/A np->key = MD_KEYBAD;
2N/A np->end_blk = -1;
2N/A np->start_blk = -1;
2N/A}
2N/A
2N/A/*
2N/A * free allocated name
2N/A */
2N/Astatic void
2N/Ametafreename(
2N/A mdname_t *np
2N/A)
2N/A{
2N/A if (np->cname != NULL)
2N/A Free(np->cname);
2N/A if (np->bname != NULL)
2N/A Free(np->bname);
2N/A if (np->rname != NULL)
2N/A Free(np->rname);
2N/A if (np->devicesname != NULL)
2N/A Free(np->devicesname);
2N/A metainitname(np);
2N/A}
2N/A
2N/A/*
2N/A * initialize drive name
2N/A */
2N/Astatic void
2N/Ametainitdrivename(
2N/A mddrivename_t *dnp
2N/A)
2N/A{
2N/A (void) memset(dnp, 0, sizeof (*dnp));
2N/A dnp->side_names_key = MD_KEYBAD;
2N/A}
2N/A
2N/A/*
2N/A * flush side names
2N/A */
2N/Avoid
2N/Ametaflushsidenames(
2N/A mddrivename_t *dnp
2N/A)
2N/A{
2N/A mdsidenames_t *p, *n;
2N/A
2N/A for (p = dnp->side_names, n = NULL; (p != NULL); p = n) {
2N/A n = p->next;
2N/A if (p->dname != NULL)
2N/A Free(p->dname);
2N/A if (p->cname != NULL)
2N/A Free(p->cname);
2N/A Free(p);
2N/A }
2N/A dnp->side_names = NULL;
2N/A}
2N/A
2N/A/*
2N/A * free drive name
2N/A */
2N/Avoid
2N/Ametafreedrivename(
2N/A mddrivename_t *dnp
2N/A)
2N/A{
2N/A uint_t slice;
2N/A
2N/A if (dnp->cname != NULL)
2N/A Free(dnp->cname);
2N/A if (dnp->rname != NULL)
2N/A Free(dnp->rname);
2N/A metafreevtoc(&dnp->vtoc);
2N/A for (slice = 0; (slice < dnp->parts.parts_len); ++slice)
2N/A metafreename(&dnp->parts.parts_val[slice]);
2N/A if (dnp->parts.parts_val != NULL)
2N/A Free(dnp->parts.parts_val);
2N/A metaflushsidenames(dnp);
2N/A if (dnp->miscname != NULL)
2N/A Free(dnp->miscname);
2N/A meta_free_unit(dnp);
2N/A metainitdrivename(dnp);
2N/A}
2N/A
2N/A/*
2N/A * flush the drive name cache
2N/A */
2N/Avoid
2N/Ametaflushdrivenames()
2N/A{
2N/A mddrivenamelist_t *p, *n;
2N/A
2N/A for (p = drivelistp, n = NULL; (p != NULL); p = n) {
2N/A n = p->next;
2N/A metafreedrivename(p->drivenamep);
2N/A Free(p->drivenamep);
2N/A Free(p);
2N/A }
2N/A drivelistp = NULL;
2N/A}
2N/A
2N/A/*
2N/A * peel off s%u from name
2N/A */
2N/Achar *
2N/Ametadiskname(
2N/A char *name
2N/A)
2N/A{
2N/A char *p, *e;
2N/A char onmb[BUFSIZ+1], cnmb[BUFSIZ];
2N/A uint_t d = 0;
2N/A int l = 0;
2N/A int cl = strlen(name);
2N/A
2N/A /*
2N/A * Handle old style names, which are of the form /dev/rXXNN[a-h].
2N/A */
2N/A if (sscanf(name, "/dev/r%" VAL2STR(BUFSIZ) "[^0-9/]%u%*[a-h]%n",
2N/A onmb, &d, &l) == 2 && l == cl) {
2N/A (void) snprintf(cnmb, sizeof (cnmb), "/dev/r%s%u", onmb, d);
2N/A return (Strdup(cnmb));
2N/A }
2N/A
2N/A /*
2N/A * Handle old style names, which are of the form /dev/XXNN[a-h].
2N/A */
2N/A if (sscanf(name, "/dev/%" VAL2STR(BUFSIZ) "[^0-9/]%u%*[a-h]%n",
2N/A onmb, &d, &l) == 2 && l == cl) {
2N/A (void) snprintf(cnmb, sizeof (cnmb), "/dev/%s%u", onmb, d);
2N/A return (Strdup(cnmb));
2N/A }
2N/A
2N/A /* gobble number and 's' */
2N/A p = e = name + strlen(name) - 1;
2N/A for (; (p > name); --p) {
2N/A if (!isdigit(*p))
2N/A break;
2N/A }
2N/A if ((p == e) || (p <= name))
2N/A return (Strdup(name));
2N/A
2N/A if (*p != 's' && strchr("dt", *p) == NULL)
2N/A return (Strdup(name));
2N/A else if (strchr("dt", *p) != NULL)
2N/A return (Strdup(name));
2N/A p--;
2N/A
2N/A if ((p <= name) || (!isdigit(*p)))
2N/A return (Strdup(name));
2N/A
2N/A *(++p) = '\0';
2N/A e = Strdup(name);
2N/A *p = 's';
2N/A
2N/A return (e);
2N/A}
2N/A
2N/A/*
2N/A * free list of drivenames
2N/A */
2N/Avoid
2N/Ametafreedrivenamelist(
2N/A mddrivenamelist_t *dnlp
2N/A)
2N/A{
2N/A mddrivenamelist_t *next = NULL;
2N/A
2N/A for (/* void */; (dnlp != NULL); dnlp = next) {
2N/A next = dnlp->next;
2N/A Free(dnlp);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * build list of drivenames
2N/A */
2N/Aint
2N/Ametadrivenamelist(
2N/A mdsetname_t **spp,
2N/A mddrivenamelist_t **dnlpp,
2N/A int argc,
2N/A char *argv[],
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mddrivenamelist_t **tailpp = dnlpp;
2N/A int count = 0;
2N/A
2N/A for (*dnlpp = NULL; (argc > 0); ++count, --argc, ++argv) {
2N/A mddrivenamelist_t *dnlp = Zalloc(sizeof (*dnlp));
2N/A
2N/A if ((dnlp->drivenamep = metadrivename(spp, argv[0],
2N/A ep)) == NULL) {
2N/A metafreedrivenamelist(*dnlpp);
2N/A *dnlpp = NULL;
2N/A return (-1);
2N/A }
2N/A *tailpp = dnlp;
2N/A tailpp = &dnlp->next;
2N/A }
2N/A return (count);
2N/A}
2N/A
2N/A/*
2N/A * append to end of drivename list
2N/A */
2N/Amddrivename_t *
2N/Ametadrivenamelist_append(
2N/A mddrivenamelist_t **dnlpp,
2N/A mddrivename_t *dnp
2N/A)
2N/A{
2N/A mddrivenamelist_t *dnlp;
2N/A
2N/A /* run to end of list */
2N/A for (; (*dnlpp != NULL); dnlpp = &(*dnlpp)->next)
2N/A ;
2N/A
2N/A /* allocate new list element */
2N/A dnlp = *dnlpp = Zalloc(sizeof (*dnlp));
2N/A
2N/A /* append drivename */
2N/A dnlp->drivenamep = dnp;
2N/A return (dnp);
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: meta_drivenamelist_append_wrapper()
2N/A * INPUT: tailpp - pointer to the list tail pointer
2N/A * dnp - name node to be appended to list
2N/A * OUTPUT: none
2N/A * RETURNS: mddrivenamelist_t * - new tail of the list.
2N/A * PURPOSE: wrapper to meta_namelist_append for performance.
2N/A * metanamelist_append finds the tail each time which slows
2N/A * down long lists. By keeping track of the tail ourselves
2N/A * we can change metadrivenamelist_append into a
2N/A * constant time operation.
2N/A */
2N/Amddrivenamelist_t **
2N/Ameta_drivenamelist_append_wrapper(
2N/A mddrivenamelist_t **tailpp,
2N/A mddrivename_t *dnp
2N/A)
2N/A{
2N/A (void) metadrivenamelist_append(tailpp, dnp);
2N/A
2N/A /* If it's the first item in the list, return it instead of the next */
2N/A if ((*tailpp)->next == NULL)
2N/A return (tailpp);
2N/A
2N/A return (&(*tailpp)->next);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * mdname_t stuff
2N/A */
2N/A
2N/A/*
2N/A * check set and get comparison name
2N/A *
2N/A * NOTE: This function has a side effect of setting *spp if the setname
2N/A * has been specified and *spp is not already set.
2N/A */
2N/Achar *
2N/Ameta_name_getname(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A meta_device_type_t uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if (uname_type == META_DEVICE || uname_type == HSP_DEVICE ||
2N/A (uname_type == UNKNOWN && is_existing_metadevice(*spp, uname))) {
2N/A
2N/A /*
2N/A * if the setname is specified in uname, *spp is set,
2N/A * and the set names don't agree then canonical name will be
2N/A * returned as NULL
2N/A */
2N/A return (meta_canonicalize_check_set(spp, uname, ep));
2N/A }
2N/A
2N/A /* if it is not a meta/hsp and *spp is not set then set it to local */
2N/A if (chksetname(spp, NULL, ep) != 0)
2N/A return (NULL);
2N/A
2N/A /* if it is not a meta/hsp name then just return uname */
2N/A return (Strdup(uname));
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: getrname()
2N/A * INPUT: spp - the setname struct
2N/A * uname - the possibly unqualified device name
2N/A * type - ptr to the device type of uname
2N/A * OUTPUT: ep - return error pointer
2N/A * RETURNS: char* - character string containing the fully
2N/A * qualified raw device name
2N/A * PURPOSE: Create the fully qualified raw name for the possibly
2N/A * unqualified device name. If uname is an absolute
2N/A * path the raw name is derived from the input string.
2N/A * Otherwise, an attempt is made to get the rawname by
2N/A * catting "/dev/md/rdsk" and "/dev/rdsk". If the input
2N/A * value of type is UNKNOWN and it can be successfully
2N/A * determined then update type to the correct value.
2N/A */
2N/Astatic char *
2N/Agetrname(mdsetname_t **spp, char *uname,
2N/A meta_device_type_t *type, md_error_t *ep)
2N/A{
2N/A char *rname;
2N/A char *fname;
2N/A int i;
2N/A int rname_cnt = 0;
2N/A char *rname_list[3];
2N/A meta_device_type_t tmp_type;
2N/A
2N/A assert(uname != NULL);
2N/A /* if it is an absolute name then just call rawname on the input */
2N/A if (uname[0] == '/') {
2N/A if ((rname = rawname(uname)) != NULL) {
2N/A /*
2N/A * If the returned rname does not match with
2N/A * the specified uname type, we'll return null.
2N/A */
2N/A if (strncmp(rname, "/dev/md", strlen("/dev/md")) == 0) {
2N/A if (*type == LOGICAL_DEVICE) {
2N/A (void) mdsyserror(ep, ENOENT, uname);
2N/A return (NULL);
2N/A }
2N/A *type = META_DEVICE;
2N/A } else {
2N/A if (*type == META_DEVICE) {
2N/A (void) mdsyserror(ep, ENOENT, uname);
2N/A return (NULL);
2N/A }
2N/A *type = LOGICAL_DEVICE;
2N/A }
2N/A return (rname);
2N/A }
2N/A
2N/A /* out of luck */
2N/A (void) mdsyserror(ep, ENOENT, uname);
2N/A return (NULL);
2N/A }
2N/A
2N/A /*
2N/A * Get device that matches the requested type. If
2N/A * a match is found, return immediately. If type is
2N/A * UNKNOWN, save all the found devices in rname_list
2N/A * so we can determine later whether the input uname
2N/A * is ambiguous.
2N/A *
2N/A * Check for metadevice before physical device.
2N/A * With the introduction of softpartitions it is more
2N/A * likely to be a metadevice.
2N/A */
2N/A
2N/A /* metadevice short form */
2N/A if (*type == META_DEVICE || *type == UNKNOWN) {
2N/A if (metaislocalset(*spp)) {
2N/A fname = Malloc(strlen(uname) +
2N/A strlen("/dev/md/rdsk/") + 1);
2N/A (void) strcpy(fname, "/dev/md/rdsk/");
2N/A (void) strcat(fname, uname);
2N/A } else {
2N/A char *p;
2N/A size_t len;
2N/A
2N/A if ((p = strchr(uname, '/')) != NULL) {
2N/A ++p;
2N/A } else {
2N/A p = uname;
2N/A }
2N/A len = strlen((*spp)->setname) + strlen(p) +
2N/A strlen("/dev/md//rdsk/") + 1;
2N/A fname = Malloc(len);
2N/A (void) snprintf(fname, len, "/dev/md/%s/rdsk/%s",
2N/A (*spp)->setname, p);
2N/A }
2N/A rname = rawname(fname);
2N/A
2N/A if (*type == META_DEVICE) {
2N/A /*
2N/A * Handle the case where we have a new metadevice
2N/A * that does not yet exist in the name-space(e.g
2N/A * metarecover in MN sets where /dev/md entry is
2N/A * not yet created in the non-master nodes). In
2N/A * this case we return the constructed metadevice
2N/A * name as that will exist after the metainit call
2N/A * has created it.
2N/A */
2N/A if (rname == NULL) {
2N/A rname = Strdup(fname);
2N/A }
2N/A
2N/A Free(fname);
2N/A return (rname);
2N/A }
2N/A
2N/A Free(fname);
2N/A if ((rname != NULL) && (*type == UNKNOWN)) {
2N/A /* Save this result */
2N/A rname_list[rname_cnt] = rname;
2N/A rname_cnt ++;
2N/A }
2N/A }
2N/A
2N/A if (*type == LOGICAL_DEVICE || *type == UNKNOWN) {
2N/A fname = Malloc(strlen(uname) + strlen("/dev/rdsk/") + 1);
2N/A (void) strcpy(fname, "/dev/rdsk/");
2N/A (void) strcat(fname, uname);
2N/A rname = rawname(fname);
2N/A
2N/A Free(fname);
2N/A if (rname != NULL) {
2N/A /* Simply return if a logical device was requested */
2N/A if (*type == LOGICAL_DEVICE) {
2N/A return (rname);
2N/A } else {
2N/A rname_list[rname_cnt] = rname;
2N/A rname_cnt ++;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * At this point, we've searched /dev/md/rdsk, /dev/rdsk and
2N/A * ./ for the specified device. rname_list contains all
2N/A * the matches we've found and rname_cnt is the number of
2N/A * matches.
2N/A *
2N/A * We know that either we don't have a match if a specific
2N/A * type was given, in which case we simply return NULL or
2N/A * we have an UNKNOWN device with 1-3 entries in rname_list.
2N/A *
2N/A * If we get 3 entries, rname_cnt == 3, it's ambiguous.
2N/A * If we only get 1 entry, rname_cnt == 1, return rname_list[0].
2N/A * If we get 2 entries that are not the same, it's ambigous.
2N/A */
2N/A rname = NULL;
2N/A if (rname_cnt == 0 || *type != UNKNOWN) {
2N/A /* out of luck */
2N/A (void) mdsyserror(ep, ENOENT, uname);
2N/A return (NULL);
2N/A } else {
2N/A if (rname_cnt == 3) {
2N/A (void) mderror(ep, MDE_AMBIGUOUS_DEV, uname);
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "Error: ambiguous device name.\n%s %s %s\n\n"),
2N/A rname_list[0], rname_list[1], rname_list[2]);
2N/A rname = NULL;
2N/A }
2N/A
2N/A /* grab the type in case it is not ambiguous */
2N/A if (strncmp(rname_list[0], "/dev/md", strlen("/dev/md")) == 0)
2N/A tmp_type = META_DEVICE;
2N/A else
2N/A tmp_type = LOGICAL_DEVICE;
2N/A
2N/A if (rname_cnt == 1) {
2N/A rname = Strdup(rname_list[0]);
2N/A *type = tmp_type;
2N/A } else {
2N/A /*
2N/A * Prevent the case where the command is run in
2N/A * either /dev/md/rdsk or /dev/rdsk so the both
2N/A * rname_list[0] and rname_list[1] are the same.
2N/A */
2N/A if (strcmp(rname_list[0], rname_list[1]) != 0) {
2N/A (void) mderror(ep, MDE_AMBIGUOUS_DEV, uname);
2N/A if (rname_cnt != 3) {
2N/A /*
2N/A * For the rname_cnt == 3 case, the
2N/A * error was printed above.
2N/A */
2N/A (void) printf(dgettext(TEXT_DOMAIN,
2N/A "Error: ambiguous device "
2N/A "name.\n%s %s\n\n"),
2N/A rname_list[0], rname_list[1]);
2N/A }
2N/A rname = NULL;
2N/A } else {
2N/A rname = Strdup(rname_list[0]);
2N/A *type = tmp_type;
2N/A }
2N/A }
2N/A for (i = 0; i < rname_cnt; i++)
2N/A Free(rname_list[i]);
2N/A return (rname);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * get raw slice and drive names
2N/A */
2N/Astatic char *
2N/Agetrawnames(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A char **dnamep,
2N/A meta_device_type_t *uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *rname = NULL;
2N/A size_t len;
2N/A
2N/A /*
2N/A * Incorrect code path if type is HSP_DEVICE
2N/A */
2N/A assert(*uname_type != HSP_DEVICE);
2N/A
2N/A /* initialize */
2N/A *dnamep = NULL;
2N/A
2N/A /* get slice name */
2N/A if ((rname = getrname(spp, uname, uname_type, ep)) != NULL) {
2N/A *dnamep = metadiskname(rname);
2N/A return (rname);
2N/A }
2N/A
2N/A /*
2N/A * If name cannot be found, if may be because is is not accessible.
2N/A * If it is an absolute name, try all possible disk name formats and
2N/A * if it is device name, assume it is /dev/rdsk/..
2N/A * Since the code below assumes logical devices, if the given
2N/A * uname_type is META_DEVICE, there's nothing to do.
2N/A */
2N/A if (mdissyserror(ep, ENOENT) && *uname_type != META_DEVICE) {
2N/A if (uname[0] == '/') {
2N/A /* Absolute name */
2N/A uint_t d = 0;
2N/A int l = 0;
2N/A char onmb[BUFSIZ+1], snm[BUFSIZ+1];
2N/A
2N/A /*
2N/A * Handle old style raw names
2N/A */
2N/A if (sscanf(uname,
2N/A "/dev/r%" VAL2STR(BUFSIZ) "[^0-9/]%u"
2N/A "%" VAL2STR(BUFSIZ) "[a-h]%n",
2N/A onmb, &d, snm, &l) == 3 && l == strlen(uname)) {
2N/A mdclrerror(ep);
2N/A rname = Strdup(uname);
2N/A *dnamep = metadiskname(rname);
2N/A *uname_type = LOGICAL_DEVICE;
2N/A return (rname);
2N/A }
2N/A
2N/A /*
2N/A * Handle old style block names
2N/A */
2N/A if (sscanf(uname,
2N/A "/dev/%" VAL2STR(BUFSIZ) "[^0-9/]%u"
2N/A "%" VAL2STR(BUFSIZ) "[a-h]%n",
2N/A onmb, &d, snm, &l) == 3 && l == strlen(uname)) {
2N/A len = strlen(uname) + 1 + 1;
2N/A rname = Malloc(len);
2N/A (void) snprintf(rname, len, "/dev/r%s%u%s",
2N/A onmb, d, snm);
2N/A *dnamep = metadiskname(rname);
2N/A *uname_type = LOGICAL_DEVICE;
2N/A return (rname);
2N/A }
2N/A
2N/A /* /.../dsk/... or /.../rdsk/... */
2N/A if ((rname = meta_dsk_to_rdsk(uname)) != NULL) {
2N/A mdclrerror(ep);
2N/A *dnamep = metadiskname(rname);
2N/A *uname_type = LOGICAL_DEVICE;
2N/A return (rname);
2N/A }
2N/A } else {
2N/A /*
2N/A * If it's not an absolute name but is a valid ctd name,
2N/A * guess at /dev/rdsk/...
2N/A */
2N/A uint_t s;
2N/A if (parse_ctd(uname, &s) == 0) {
2N/A len = strlen(uname) + strlen("/dev/rdsk/") + 1;
2N/A rname = Malloc(len);
2N/A (void) snprintf(rname, len, "/dev/rdsk/%s",
2N/A uname);
2N/A *dnamep = metadiskname(rname);
2N/A *uname_type = LOGICAL_DEVICE;
2N/A return (rname);
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* out of luck */
2N/A if (!mdiserror(ep, MDE_AMBIGUOUS_DEV))
2N/A (void) mderror(ep, MDE_UNIT_NOT_FOUND, uname);
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * get number of slices for name
2N/A */
2N/Astatic int
2N/Agetnslice(
2N/A char *rname,
2N/A char *dname,
2N/A uint_t *slicep
2N/A)
2N/A{
2N/A char *srname;
2N/A uint_t nslice;
2N/A size_t dl = strlen(dname);
2N/A size_t rl = strlen(rname);
2N/A size_t l = 0;
2N/A size_t len;
2N/A
2N/A /*
2N/A * get our slice number - works only with names that end in s%u -
2N/A * all others return -1.
2N/A */
2N/A if (dl >= rl ||
2N/A sscanf(&rname[dl], "s%u%n", slicep, &l) != 1 || l != rl ||
2N/A (int)*slicep < 0) {
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * go find how many slices there really are
2N/A */
2N/A len = strlen(dname) + 20 + 1;
2N/A srname = Malloc(len);
2N/A for (nslice = 0; /* void */; ++nslice) {
2N/A struct stat statbuf;
2N/A
2N/A /* build slice name */
2N/A (void) snprintf(srname, len, "%ss%u", dname, nslice);
2N/A
2N/A /* see if it's there */
2N/A if ((meta_stat(srname, &statbuf) != 0) ||
2N/A (! S_ISCHR(statbuf.st_mode))) {
2N/A break;
2N/A }
2N/A }
2N/A Free(srname);
2N/A
2N/A /* Need to make sure that we at least have V_NUMPAR */
2N/A nslice = max(nslice, V_NUMPAR);
2N/A
2N/A /* make sure we have at least our slice */
2N/A if (nslice < *slicep)
2N/A return (-1);
2N/A
2N/A /* return number of slices */
2N/A return (nslice);
2N/A}
2N/A
2N/A/*
2N/A * Attempt to parse the input string as a c[t]ds specifier
2N/A * The target can either be a SCSI target id or if the device
2N/A * is in a fabric configuration in a fibre channel setup then
2N/A * the target is a standard WWN (world wide name).
2N/A *
2N/A * if successful return 0
2N/A * if c[t]dp name return 1
2N/A * otherwise return -1
2N/A */
2N/Aint
2N/Aparse_ctd(
2N/A char *uname,
2N/A uint_t *slice)
2N/A{
2N/A uint_t channel;
2N/A uint_t target;
2N/A uint_t device;
2N/A int has_target = 1;
2N/A uint_t cl;
2N/A uint_t target_str_len;
2N/A char *partial_ctd_str;
2N/A char *target_str;
2N/A char *device_start_pos;
2N/A int l = -1;
2N/A
2N/A /* pull off the channel spec and the 't' for the target */
2N/A if (sscanf(uname, "c%ut%n", &channel, &l) != 1 || l == -1) {
2N/A /* check for cds style name */
2N/A if (sscanf(uname, "c%ud%n", &channel, &l) != 1 || l == -1) {
2N/A return (-1);
2N/A } else {
2N/A l--; /* we want to be on the 'd' */
2N/A has_target = 0;
2N/A }
2N/A }
2N/A partial_ctd_str = uname + l;
2N/A
2N/A /* find the beginning of the device specifier */
2N/A device_start_pos = strrchr(partial_ctd_str, 'd');
2N/A if (device_start_pos == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A /* check to see if it is a ctd with a WWN or SCSI target */
2N/A if (has_target) {
2N/A /* pull off the target and see if it is a WWN */
2N/A target_str_len = device_start_pos - partial_ctd_str + 2;
2N/A target_str = (char *)Malloc(target_str_len+1);
2N/A (void) strcpy(target_str, "0X");
2N/A (void) strncpy(target_str+2, partial_ctd_str,
2N/A target_str_len - 2);
2N/A target_str[target_str_len] = '\0';
2N/A if (sscanf(target_str, "%x%n", &target, &l) != 1 ||
2N/A l != target_str_len) {
2N/A Free(target_str);
2N/A return (-1);
2N/A }
2N/A Free(target_str);
2N/A }
2N/A
2N/A /* check the device and slice */
2N/A cl = strlen(device_start_pos);
2N/A if (sscanf(device_start_pos, "d%us%u%n", &device, slice, &l) != 2 ||
2N/A l != cl) {
2N/A /* check the device and partition */
2N/A if (sscanf(device_start_pos, "d%up%u%n", &device, slice, &l)
2N/A == 2 && l == cl) {
2N/A return (1);
2N/A }
2N/A return (-1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * get number of slices for name
2N/A */
2N/Astatic int
2N/Auname2sliceno(
2N/A char *uname,
2N/A meta_device_type_t uname_type,
2N/A uint_t *slicep,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t c = 0, t = 0, d = 0;
2N/A int l = 0, cl = 0;
2N/A int fd;
2N/A struct dk_cinfo cinfo;
2N/A char *p;
2N/A char *rname = NULL;
2N/A
2N/A
2N/A if (uname_type == META_DEVICE)
2N/A return (*slicep = 0);
2N/A
2N/A if ((p = strrchr(uname, '/')) != NULL)
2N/A p++;
2N/A else
2N/A p = uname;
2N/A
2N/A cl = strlen(p);
2N/A
2N/A if (parse_ctd(p, slicep) == 0)
2N/A return (*slicep);
2N/A else if (sscanf(p, "mc%ut%ud%us%u%n", &c, &t, &d, slicep, &l) == 4 &&
2N/A l == cl)
2N/A return (*slicep);
2N/A else if (sscanf(p, "d%us%u%n", &d, slicep, &l) == 2 && l == cl)
2N/A return (*slicep);
2N/A
2N/A /*
2N/A * If we can't get the slice from the name, then we have to do it the
2N/A * hard and expensive way.
2N/A */
2N/A if ((rname = rawname(uname)) == NULL)
2N/A return (-1);
2N/A
2N/A /* get controller info */
2N/A if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) {
2N/A Free(rname);
2N/A return (-1);
2N/A }
2N/A
2N/A if (ioctl(fd, DKIOCINFO, &cinfo) != 0) {
2N/A int save = errno;
2N/A
2N/A if (save == ENOTTY)
2N/A (void) mddeverror(ep, MDE_NOT_DISK, NODEV64, rname);
2N/A else
2N/A (void) mdsyserror(ep, save, rname);
2N/A
2N/A Free(rname);
2N/A (void) close(fd);
2N/A return (-1);
2N/A }
2N/A (void) close(fd); /* sd/ssd bug */
2N/A
2N/A if (cinfo.dki_partition < V_NUMPAR) {
2N/A Free(rname);
2N/A return (*slicep = cinfo.dki_partition);
2N/A }
2N/A
2N/A return (mddeverror(ep, MDE_NOT_DISK, NODEV64, rname));
2N/A}
2N/A
2N/A/*
2N/A * get partition info
2N/A */
2N/Astatic int
2N/Agetparts(
2N/A mddrivename_t *dnp,
2N/A char *rname,
2N/A char *dname,
2N/A meta_device_type_t uname_type,
2N/A uint_t *npartsp,
2N/A uint_t *partnop,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A int nparts;
2N/A uint_t partno;
2N/A mdname_t name;
2N/A mdvtoc_t *vtocp;
2N/A
2N/A /* metadevice */
2N/A if (uname_type == META_DEVICE) {
2N/A dnp->type = MDT_META;
2N/A nparts = 1;
2N/A partno = 0;
2N/A goto gotit;
2N/A }
2N/A
2N/A /* see how many partitions in drive, this is really tricky */
2N/A metainitname(&name);
2N/A name.rname = rname;
2N/A name.drivenamep = dnp;
2N/A if ((vtocp = metagetvtoc(&name, TRUE, &partno, ep)) != NULL) {
2N/A dnp->type = MDT_COMP;
2N/A nparts = vtocp->nparts;
2N/A /* partno already setup */
2N/A /* dname already setup */
2N/A goto gotit;
2N/A }
2N/A
2N/A if ((ep->info.errclass == MDEC_DEV) &&
2N/A (ep->info.md_error_info_t_u.dev_error.errnum == MDE_TOO_MANY_PARTS))
2N/A return (-1);
2N/A
2N/A /* fallback and try and guess (used to check for just EACCES here) */
2N/A if ((dname != NULL) &&
2N/A ((nparts = getnslice(rname, dname, &partno)) > 0)) {
2N/A dnp->type = MDT_ACCES;
2N/A if (mdanysyserror(ep)) {
2N/A dnp->errnum =
2N/A ep->info.md_error_info_t_u.sys_error.errnum;
2N/A } else {
2N/A dnp->errnum = ENOENT;
2N/A }
2N/A mdclrerror(ep);
2N/A /* nparts already setup */
2N/A /* partno already setup */
2N/A /* dname already setup */
2N/A nparts = roundup(nparts, V_NUMPAR);
2N/A goto gotit;
2N/A }
2N/A
2N/A /* nothing worked */
2N/A dnp->type = MDT_UNKNOWN;
2N/A if (mdissyserror(ep, EACCES))
2N/A dnp->type = MDT_ACCES;
2N/A
2N/A if (mdanysyserror(ep)) {
2N/A dnp->errnum = ep->info.md_error_info_t_u.sys_error.errnum;
2N/A } else {
2N/A dnp->errnum = ENOENT;
2N/A }
2N/A
2N/A mdclrerror(ep);
2N/A nparts = V_NUMPAR;
2N/A if (uname2sliceno(rname, uname_type, &partno, ep) < 0) {
2N/A mdclrerror(ep);
2N/A partno = 0;
2N/A }
2N/A
2N/A /* return success */
2N/Agotit:
2N/A assert(nparts > 0);
2N/A
2N/A if (partno >= nparts)
2N/A return (mdsyserror(ep, ENOENT, rname));
2N/A
2N/A *npartsp = nparts;
2N/A *partnop = partno;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * get block name
2N/A */
2N/Astatic int
2N/Agetbname(
2N/A mdname_t *np,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *rname = np->rname;
2N/A char *bname;
2N/A
2N/A /* fully qualified */
2N/A assert(rname != NULL);
2N/A if ((bname = blkname(rname)) != NULL) {
2N/A if (np->bname)
2N/A Free(np->bname);
2N/A np->bname = bname;
2N/A return (0);
2N/A }
2N/A
2N/A /* out of luck */
2N/A return (mdsyserror(ep, ENOENT, rname));
2N/A}
2N/A
2N/Astatic void
2N/Agetcname(
2N/A mdsetname_t *sp,
2N/A mdname_t *np
2N/A)
2N/A{
2N/A char *sname = sp->setname;
2N/A char *bname = np->bname;
2N/A char *p;
2N/A size_t len;
2N/A
2N/A assert(sname != NULL);
2N/A assert(bname != NULL);
2N/A assert(np->drivenamep->type != MDT_FAST_COMP &&
2N/A np->drivenamep->type != MDT_FAST_META);
2N/A
2N/A /* regular device */
2N/A if ((strncmp(bname, "/dev/dsk/", strlen("/dev/dsk/")) == 0) &&
2N/A (strchr((p = bname + strlen("/dev/dsk/")), '/') == NULL)) {
2N/A if (np->cname)
2N/A Free(np->cname);
2N/A np->cname = Strdup(p);
2N/A return;
2N/A }
2N/A
2N/A if ((strncmp(bname, "/dev/ap/dsk/", strlen("/dev/ap/dsk/")) == 0) &&
2N/A (strchr((p = bname + strlen("/dev/ap/dsk/")), '/') == NULL)) {
2N/A if (np->cname)
2N/A Free(np->cname);
2N/A np->cname = Strdup(p);
2N/A return;
2N/A }
2N/A
2N/A if ((strncmp(bname, "/dev/did/dsk/", strlen("/dev/did/dsk/")) == 0) &&
2N/A (strchr((p = bname + strlen("/dev/did/dsk/")), '/') == NULL)) {
2N/A if (np->cname)
2N/A Free(np->cname);
2N/A np->cname = Strdup(p);
2N/A return;
2N/A }
2N/A
2N/A /* anything else but metadevice */
2N/A if (np->drivenamep->type != MDT_META) {
2N/A if (np->cname)
2N/A Free(np->cname);
2N/A np->cname = Strdup(bname);
2N/A return;
2N/A }
2N/A
2N/A /* metadevice */
2N/A p = strrchr(bname, '/');
2N/A assert(p != NULL);
2N/A ++p;
2N/A if (metaislocalset(sp)) {
2N/A if (np->cname)
2N/A Free(np->cname);
2N/A np->cname = Strdup(p);
2N/A } else {
2N/A assert(sname[0] != '\0');
2N/A if (np->cname)
2N/A Free(np->cname);
2N/A len = strlen(sname) + 1 + strlen(p) + 1;
2N/A np->cname = Malloc(len);
2N/A (void) snprintf(np->cname, len, "%s/%s", sname, p);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * get dev
2N/A */
2N/Aint
2N/Ameta_getdev(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A struct stat statbuf;
2N/A
2N/A /* get dev */
2N/A if (meta_stat(np->rname, &statbuf) != 0)
2N/A return (mdsyserror(ep, errno, np->rname));
2N/A else if (! S_ISCHR(statbuf.st_mode))
2N/A return (mddeverror(ep, MDE_NOT_DISK, NODEV64, np->rname));
2N/A np->dev = meta_expldev(statbuf.st_rdev);
2N/A
2N/A assert(np->drivenamep->type != MDT_FAST_META &&
2N/A np->drivenamep->type != MDT_FAST_COMP);
2N/A
2N/A /* check set */
2N/A assert((np->drivenamep->type == MDT_META) ?
2N/A (sp->setno == MD_MIN2SET(meta_getminor(np->dev))) : 1);
2N/A
2N/A /* return sucess */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * set up names for a slice
2N/A */
2N/Astatic int
2N/Agetnames(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A char *rname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A /* get names */
2N/A if (np->rname)
2N/A Free(np->rname);
2N/A np->rname = Strdup(rname);
2N/A if (getbname(np, ep) != 0)
2N/A return (-1);
2N/A getcname(sp, np);
2N/A if (meta_getdev(sp, np, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * fake up names for a slice
2N/A */
2N/Astatic void
2N/Agetfakenames(
2N/A mdsetname_t *sp,
2N/A mdname_t *np,
2N/A char *rname
2N/A)
2N/A{
2N/A char *p;
2N/A char onmb[BUFSIZ+1], snm[BUFSIZ+1];
2N/A uint_t d = 0;
2N/A int l = 0;
2N/A
2N/A /* fake names */
2N/A if (np->rname != NULL)
2N/A Free(np->rname);
2N/A np->rname = Strdup(rname);
2N/A
2N/A if (np->bname != NULL)
2N/A Free(np->bname);
2N/A np->bname = Strdup(rname);
2N/A
2N/A /*
2N/A * Fixup old style names
2N/A */
2N/A if (sscanf(rname, "/dev/r%" VAL2STR(BUFSIZ) "[^0-9/]%u"
2N/A "%" VAL2STR(BUFSIZ) "[a-h]%n",
2N/A onmb, &d, snm, &l) == 3 && l == strlen(rname))
2N/A (void) snprintf(np->bname, l, "/dev/%s%u%s", onmb, d, snm);
2N/A
2N/A /*
2N/A * Fixup new style names
2N/A */
2N/A if ((p = strstr(np->bname, "/rdsk/")) != NULL) {
2N/A for (++p; (*(p + 1) != '\0'); ++p)
2N/A *p = *(p + 1);
2N/A *p = '\0';
2N/A }
2N/A
2N/A if (np->cname != NULL)
2N/A Free(np->cname);
2N/A getcname(sp, np);
2N/A}
2N/A
2N/Astatic mdname_t *
2N/Asetup_slice(
2N/A mdsetname_t *sp,
2N/A meta_device_type_t uname_type,
2N/A mddrivename_t *dnp,
2N/A char *uname,
2N/A char *rname,
2N/A char *dname,
2N/A uint_t partno,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *srname = NULL;
2N/A mdname_t *np;
2N/A
2N/A /* must have a set */
2N/A assert(sp != NULL);
2N/A assert(partno < dnp->parts.parts_len);
2N/A assert(dname != NULL);
2N/A
2N/A np = &dnp->parts.parts_val[partno];
2N/A
2N/A if (rname)
2N/A srname = rname;
2N/A else if (uname_type == META_DEVICE)
2N/A srname = dname;
2N/A else {
2N/A char onmb[BUFSIZ+1];
2N/A uint_t d = 0;
2N/A int l = 0, cl = strlen(dname);
2N/A size_t len;
2N/A
2N/A len = cl + 20 + 1;
2N/A srname = Malloc(len);
2N/A
2N/A /*
2N/A * Handle /dev/rXXNN.
2N/A */
2N/A if (sscanf(dname, "/dev/r%" VAL2STR(BUFSIZ) "[^0-9/]%u%n",
2N/A onmb, &d, &l) == 2 && l == cl) {
2N/A (void) snprintf(srname, len, "/dev/r%s%u%c", onmb, d,
2N/A 'a' + partno);
2N/A } else if (sscanf(dname, "/dev/%" VAL2STR(BUFSIZ) "[^0-9/]%u%n",
2N/A onmb, &d, &l) == 2 && l == cl) {
2N/A (void) snprintf(srname, len, "/dev/%s%u%c", onmb, d,
2N/A 'a' + partno);
2N/A } else {
2N/A /* build the slice that is wanted */
2N/A (void) snprintf(srname, len, "%ss%u", dname, partno);
2N/A }
2N/A }
2N/A
2N/A if (getnames(sp, np, srname, ep) != 0) {
2N/A if (dnp->type == MDT_UNKNOWN) {
2N/A mdclrerror(ep);
2N/A getfakenames(sp, np, srname);
2N/A } else if (dnp->type == MDT_COMP && mdissyserror(ep, ENOENT)) {
2N/A dnp->type = MDT_UNKNOWN;
2N/A if (mdanysyserror(ep)) {
2N/A dnp->errnum =
2N/A ep->info.md_error_info_t_u.sys_error.errnum;
2N/A } else {
2N/A dnp->errnum = ENOENT;
2N/A }
2N/A mdclrerror(ep);
2N/A getfakenames(sp, np, srname);
2N/A } else {
2N/A mdclrerror(ep);
2N/A if (getnames(sp, np, dname, ep) != 0) {
2N/A np = NULL;
2N/A goto fixup;
2N/A }
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A if ((srname != rname) && (srname != dname))
2N/A Free(srname);
2N/A
2N/A /* return name */
2N/A return (np);
2N/A
2N/Afixup:
2N/A if (mdanysyserror(ep)) {
2N/A char *p;
2N/A int errnum = ep->info.md_error_info_t_u.sys_error.errnum;
2N/A
2N/A mdclrerror(ep);
2N/A if (uname && *uname) {
2N/A if ((p = strrchr(uname, '/')) != NULL)
2N/A (void) mdsyserror(ep, errnum, ++p);
2N/A else
2N/A (void) mdsyserror(ep, errnum, uname);
2N/A } else {
2N/A if ((p = strrchr(srname, '/')) != NULL)
2N/A (void) mdsyserror(ep, errnum, ++p);
2N/A else
2N/A (void) mdsyserror(ep, errnum, srname);
2N/A }
2N/A }
2N/A goto out;
2N/A}
2N/A
2N/A/*
2N/A * flush the fast name cache
2N/A */
2N/Astatic void
2N/Ametafreefastnm(mdname_t **np)
2N/A{
2N/A mddrivename_t *dnp;
2N/A
2N/A assert(np != NULL && *np != NULL);
2N/A
2N/A if ((dnp = (*np)->drivenamep) != NULL) {
2N/A if (dnp->cname != NULL)
2N/A Free(dnp->cname);
2N/A if (dnp->rname != NULL)
2N/A Free(dnp->rname);
2N/A if (dnp->miscname != NULL)
2N/A Free(dnp->miscname);
2N/A meta_free_unit(dnp);
2N/A Free(dnp);
2N/A }
2N/A if ((*np)->cname != NULL)
2N/A Free((*np)->cname);
2N/A if ((*np)->bname != NULL)
2N/A Free((*np)->bname);
2N/A if ((*np)->rname != NULL)
2N/A Free((*np)->rname);
2N/A if ((*np)->devicesname != NULL)
2N/A Free((*np)->devicesname);
2N/A Free(*np);
2N/A *np = NULL;
2N/A}
2N/A
2N/A/*
2N/A * flush the fast name cache
2N/A */
2N/Astatic void
2N/Ametaflushfastnames()
2N/A{
2N/A mdnamelist_t *p, *n;
2N/A
2N/A for (p = fastnmlp, n = NULL; (p != NULL); p = n) {
2N/A n = p->next;
2N/A metafreefastnm(&p->namep);
2N/A Free(p);
2N/A }
2N/A fastnmlp = NULL;
2N/A}
2N/A
2N/Astatic char *
2N/Agetrname_fast(char *unm, meta_device_type_t uname_type, md_error_t *ep)
2N/A{
2N/A uint_t d = 0;
2N/A int l = 0;
2N/A int cl = strlen(unm);
2N/A char onmb[BUFSIZ+1], snm[BUFSIZ+1], cnmb[BUFSIZ];
2N/A char *rnm;
2N/A size_t len;
2N/A
2N/A if (uname_type == META_DEVICE) {
2N/A /* fully qualified - local set */
2N/A if (((sscanf(unm, "/dev/md/dsk/%" VAL2STR(BUFSIZ) "s%n",
2N/A onmb, &len) == 1) && (cl == len)) || ((sscanf(unm,
2N/A "/dev/md/rdsk/%" VAL2STR(BUFSIZ) "s%n",
2N/A onmb, &len) == 1) && (cl == len))) {
2N/A len = strlen("/dev/md/rdsk/") + strlen(onmb) + 1;
2N/A rnm = Zalloc(len);
2N/A (void) snprintf(rnm, len, "/dev/md/rdsk/%s", onmb);
2N/A return (rnm);
2N/A }
2N/A
2N/A /* fully qualified - setname specified */
2N/A if (((sscanf(unm, "/dev/md/%[^/]/dsk/%"
2N/A VAL2STR(BUFSIZ) "s%n", snm, onmb, &len) == 2) &&
2N/A (cl == len)) || ((sscanf(unm, "/dev/md/%[^/]/rdsk/%"
2N/A VAL2STR(BUFSIZ) "s%n", snm, onmb, &len) == 2) &&
2N/A (cl == len))) {
2N/A
2N/A len = strlen("/dev/md//rdsk/") + strlen(snm) +
2N/A strlen(onmb) + 1;
2N/A rnm = Zalloc(len);
2N/A (void) snprintf(rnm, len, "/dev/md/%s/rdsk/%s",
2N/A snm, onmb);
2N/A return (rnm);
2N/A }
2N/A
2N/A /* Fully qualified path - error */
2N/A if (unm[0] == '/') {
2N/A (void) mdsyserror(ep, EINVAL, unm);
2N/A return (NULL);
2N/A }
2N/A
2N/A /* setname specified <setname>/<metadev> */
2N/A if (((sscanf(unm, "%[^/]/%" VAL2STR(BUFSIZ) "s%n",
2N/A snm, onmb, &len) == 2) && (cl == len))) {
2N/A /* Not <setname>/<metadev> - error */
2N/A if (strchr(onmb, '/') != NULL) {
2N/A (void) mdsyserror(ep, EINVAL, unm);
2N/A return (NULL);
2N/A }
2N/A
2N/A len = strlen("/dev/md//rdsk/") + strlen(snm) +
2N/A strlen(onmb) + 1;
2N/A rnm = Zalloc(len);
2N/A (void) snprintf(rnm, len, "/dev/md/%s/rdsk/%s",
2N/A snm, onmb);
2N/A return (rnm);
2N/A }
2N/A
2N/A /* Must be simple metaname/hsp pool name */
2N/A len = strlen("/dev/md/rdsk/") + strlen(unm) + 1;
2N/A rnm = Zalloc(len);
2N/A (void) snprintf(rnm, len, "/dev/md/rdsk/%s", unm);
2N/A return (rnm);
2N/A }
2N/A
2N/A /* NOT Fully qualified path, done */
2N/A if (unm[0] != '/') {
2N/A (void) mdsyserror(ep, EINVAL, unm);
2N/A return (NULL);
2N/A }
2N/A
2N/A /*
2N/A * Get slice information from old style names of the form
2N/A * /dev/rXXNN[a-h] or /dev/XXNN[a-h], must be done before regular
2N/A * devices, but after metadevices.
2N/A */
2N/A if ((sscanf(unm, "/dev/r%" VAL2STR(BUFSIZ) "[^0-9/]%u"
2N/A "%" VAL2STR(BUFSIZ) "[a-h]%n",
2N/A onmb, &d, snm, &l) == 3 ||
2N/A sscanf(unm, "/dev/%" VAL2STR(BUFSIZ) "[^0-9/]%u"
2N/A "%" VAL2STR(BUFSIZ) "[a-h]%n",
2N/A onmb, &d, snm, &l) == 3) && l == cl) {
2N/A if (strchr("abcdefgh", snm[0]) != NULL) {
2N/A (void) snprintf(cnmb, sizeof (cnmb), "/dev/r%s%u%s",
2N/A onmb, d, snm);
2N/A return (Strdup(cnmb));
2N/A }
2N/A }
2N/A
2N/A /* /.../dsk/... or /.../rdsk/... */
2N/A if ((rnm = meta_dsk_to_rdsk(unm)) != NULL)
2N/A return (rnm);
2N/A
2N/A /*
2N/A * Shouldn't get here but if we do then we have an unrecognized
2N/A * fully qualified path - error
2N/A */
2N/A (void) mdsyserror(ep, EINVAL, unm);
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic mdname_t *
2N/Ametainitfastname(
2N/A mdsetname_t *sp,
2N/A char *uname,
2N/A meta_device_type_t uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t c = 0, t = 0, d = 0, s = 0;
2N/A int l = 0;
2N/A mddrivename_t *dnp;
2N/A mdname_t *np;
2N/A mdnamelist_t **fnlpp;
2N/A char *cname;
2N/A
2N/A for (fnlpp = &fastnmlp; (*fnlpp != NULL); fnlpp = &(*fnlpp)->next) {
2N/A np = (*fnlpp)->namep;
2N/A
2N/A if (strcmp(np->bname, uname) == 0)
2N/A return (np);
2N/A }
2N/A
2N/A *fnlpp = Zalloc(sizeof (**fnlpp));
2N/A np = (*fnlpp)->namep = Zalloc(sizeof (mdname_t));
2N/A metainitname(np);
2N/A dnp = np->drivenamep = Zalloc(sizeof (mddrivename_t));
2N/A metainitdrivename(dnp);
2N/A
2N/A
2N/A /* Metadevices */
2N/A if (uname_type == META_DEVICE &&
2N/A (cname = meta_canonicalize(sp, uname)) != NULL) {
2N/A
2N/A np->cname = cname;
2N/A dnp->type = MDT_FAST_META;
2N/A goto done;
2N/A }
2N/A
2N/A /* Others */
2N/A dnp->type = MDT_FAST_COMP;
2N/A
2N/A if (((sscanf(uname, "/dev/rdsk/c%ut%ud%us%u%n", &c, &t, &d,
2N/A &s, &l) == 4 ||
2N/A sscanf(uname, "/dev/dsk/c%ut%ud%us%u%n", &c, &t, &d,
2N/A &s, &l) == 4 ||
2N/A sscanf(uname, "/dev/ap/rdsk/mc%ut%ud%us%u%n", &c, &t, &d,
2N/A &s, &l) == 4 ||
2N/A sscanf(uname, "/dev/ap/dsk/mc%ut%ud%us%u%n", &c, &t, &d,
2N/A &s, &l) == 4 ||
2N/A sscanf(uname, "/dev/did/rdsk/d%us%u%n", &t, &s, &l) == 2 ||
2N/A sscanf(uname, "/dev/did/dsk/d%us%u%n", &t, &s, &l) == 2||
2N/A sscanf(uname, "/dev/rdsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
2N/A sscanf(uname, "/dev/dsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
2N/A sscanf(uname, "/dev/rdsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
2N/A sscanf(uname, "/dev/dsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
2N/A sscanf(uname, "/dev/ap/rdsk/mc%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
2N/A sscanf(uname, "/dev/ap/dsk/mc%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
2N/A sscanf(uname, "/dev/did/rdsk/d%u%n", &t, &l) == 1 ||
2N/A sscanf(uname, "/dev/did/dsk/d%u%n", &t, &l) == 1 ||
2N/A sscanf(uname, "/dev/rdsk/c%ud%u%n", &c, &d, &l) == 2 ||
2N/A sscanf(uname, "/dev/dsk/c%ud%u%n", &c, &d, &l) == 2) &&
2N/A l == strlen(uname))) {
2N/A if ((np->cname = strrchr(uname, '/')) == NULL)
2N/A np->cname = Strdup(uname);
2N/A else
2N/A np->cname = Strdup(++np->cname);
2N/A } else {
2N/A np->cname = Strdup(uname);
2N/A }
2N/A
2N/Adone:
2N/A /* Driver always gives us block names */
2N/A np->bname = Strdup(uname);
2N/A
2N/A /* canonical disk name */
2N/A if ((dnp->cname = metadiskname(np->cname)) == NULL)
2N/A dnp->cname = Strdup(np->cname);
2N/A
2N/A if ((np->rname = getrname_fast(uname, uname_type, ep)) != NULL) {
2N/A if ((dnp->rname = metadiskname(np->rname)) == NULL)
2N/A dnp->rname = Strdup(np->rname);
2N/A } else {
2N/A metafreefastnm(&(*fnlpp)->namep);
2N/A Free(*fnlpp);
2N/A *fnlpp = NULL;
2N/A return (NULL);
2N/A }
2N/A
2N/A /* cleanup, return success */
2N/A return (np);
2N/A}
2N/A
2N/A/*
2N/A * set up names for a device
2N/A */
2N/Astatic mdname_t *
2N/Ametaname_common(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A int fast,
2N/A meta_device_type_t uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mddrivenamelist_t **tail;
2N/A mddrivename_t *dnp;
2N/A uint_t slice;
2N/A mdname_t *np;
2N/A char *rname = NULL;
2N/A char *dname = NULL;
2N/A char *cname = NULL;
2N/A uint_t nparts, partno;
2N/A
2N/A assert(uname != NULL);
2N/A
2N/A /* check setname */
2N/A if ((cname = meta_name_getname(spp, uname, uname_type, ep)) == NULL)
2N/A return (NULL);
2N/A
2N/A assert(*spp != NULL);
2N/A Free(cname);
2N/A
2N/A /* get raw name (rname) of the slice and drive (dname) we have */
2N/A if ((rname = getrawnames(spp, uname,
2N/A &dname, &uname_type, ep)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A
2N/A assert(uname_type != UNKNOWN);
2N/A
2N/A /* look in cache first */
2N/A for (tail = &drivelistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A dnp = (*tail)->drivenamep;
2N/A
2N/A /* check to see if the drive name is already in the cache */
2N/A if ((dnp->rname != NULL) && strcmp(dnp->rname, dname) == 0) {
2N/A
2N/A Free(rname);
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A
2N/A if (uname2sliceno(uname, uname_type, &partno, ep) < 0)
2N/A return (NULL);
2N/A
2N/A return (metaslicename(dnp, partno, ep));
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If a fast names is OK, then get one, and be done.
2N/A */
2N/A if (fast) {
2N/A Free(rname);
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A
2N/A return (metainitfastname(*spp, uname, uname_type, ep));
2N/A }
2N/A
2N/A /* allocate new list element and drive */
2N/A *tail = Zalloc(sizeof (**tail));
2N/A dnp = (*tail)->drivenamep = Zalloc(sizeof (*dnp));
2N/A
2N/A metainitdrivename(dnp);
2N/A
2N/A /* get parts info */
2N/A if (getparts(dnp, rname, dname, uname_type, &nparts, &partno, ep) != 0)
2N/A goto out;
2N/A
2N/A /*
2N/A * libmeta needs at least V_NUMPAR partitions.
2N/A * If we have an EFI partition with less than V_NUMPAR slices,
2N/A * we nevertheless reserve space for V_NUMPAR
2N/A */
2N/A if (nparts < V_NUMPAR) {
2N/A nparts = V_NUMPAR;
2N/A }
2N/A
2N/A /* allocate and link in parts */
2N/A dnp->parts.parts_len = nparts;
2N/A dnp->parts.parts_val = Zalloc((sizeof (*dnp->parts.parts_val)) *
2N/A dnp->parts.parts_len);
2N/A for (slice = 0; (slice < nparts); ++slice) {
2N/A np = &dnp->parts.parts_val[slice];
2N/A metainitname(np);
2N/A np->drivenamep = dnp;
2N/A }
2N/A
2N/A /* setup name_t (or slice) wanted */
2N/A if ((np = setup_slice(*spp, uname_type, dnp, uname, rname,
2N/A dname, partno, ep)) == NULL)
2N/A goto out;
2N/A
2N/A /* canonical disk name */
2N/A if ((dnp->cname = metadiskname(np->cname)) == NULL)
2N/A dnp->cname = Strdup(np->cname);
2N/A if ((dnp->rname = metadiskname(np->rname)) == NULL)
2N/A dnp->rname = Strdup(np->rname);
2N/A
2N/A /* cleanup, return success */
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A Free(rname);
2N/A return (np);
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A if (rname != NULL)
2N/A Free(rname);
2N/A
2N/A metafreedrivename(dnp);
2N/A Free(dnp);
2N/A Free(*tail);
2N/A *tail = NULL;
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * metaname()
2N/A *
2N/A * Wrapper function for metaname_common()
2N/A * If the second arg is a metadevice name then it is important that this should
2N/A * be a canonical name (eg d30 rather than /dev/md/dsk/d30). If this is not the
2N/A * case then a bad entry may be placed into the drivelistp cache.
2N/A */
2N/Amdname_t *
2N/Ametaname(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A meta_device_type_t uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (metaname_common(spp, uname, 0, uname_type, ep));
2N/A}
2N/A
2N/Amdname_t *
2N/Ametaname_fast(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A meta_device_type_t uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (metaname_common(spp, uname, 1, uname_type, ep));
2N/A}
2N/A/*
2N/A * Get the dnp using the device id.
2N/A *
2N/A * We have the potential to have more than 1 dnp with the same disk name but
2N/A * have different device ids. This would happen in the case of a partial
2N/A * diskset. The unavailable disk name is relative to the prior host and could
2N/A * possibly be the same as a disk on this system. The only way to tell which
2N/A * dnp belongs with this disk is by searching by device id. We have the
2N/A * potential to have the case where 1) the disk who's device id we pass in is
2N/A * in the system. In this case the name and the device id are both valid for
2N/A * the disk. 2) The disk whose device id we've been passed is not in the
2N/A * system and no disk with the same name has a dnp on the list. And 3) The
2N/A * disk whose device id we've been passed is not on the system but there is
2N/A * a disk with the same name (different devid) that is on the system. Here's
2N/A * what we return for each of those cases:
2N/A * 1) If disk is in system:
2N/A * disk is found on drivelistp or we create a new drivename and it's
2N/A * fully populated as expected.
2N/A * 2) If disk not in system, no collision
2N/A * Disk with the same devid is not found on drivelistp, we create a new
2N/A * drivename structure and the dnp->devid is filled in not from getparts
2N/A * but from the devidp passed in. No other disk in the system has the
2N/A * same "name" or devid.
2N/A * This situation would be caused by the import of a partial diskset.
2N/A * 3) If disk not in system, collision
2N/A * Disk with the same devid is not found on the drivelistp, we create a
2N/A * new drivename struct but getparts will use the information from the
2N/A * name which is actually in reference to another disk of the same name
2N/A * in the system. getparts will fill in the dnp->devid with the value
2N/A * from the other disk and we overwrite this with the value of this disk.
2N/A * To get into this situation one of the disks is actually unavailable
2N/A * as in the case of a partial import.
2N/A */
2N/Amddrivename_t *
2N/Ameta_getdnp_bydevid(
2N/A mdsetname_t *sp,
2N/A side_t sideno,
2N/A ddi_devid_t devidp,
2N/A mdkey_t key,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A ddi_devid_t dnp_devidp;
2N/A char *nm;
2N/A mddrivenamelist_t **tail;
2N/A mddrivename_t *dnp;
2N/A uint_t slice;
2N/A mdname_t *np;
2N/A char *rname = NULL;
2N/A char *dname = NULL;
2N/A uint_t nparts, partno;
2N/A int ret;
2N/A md_set_desc *sd = NULL;
2N/A meta_device_type_t uname_type = LOGICAL_DEVICE;
2N/A
2N/A /* look in the cache first */
2N/A for (tail = &drivelistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A dnp = (*tail)->drivenamep;
2N/A if (dnp->type != MDT_COMP)
2N/A continue;
2N/A
2N/A /* Skip devices with no devid, e.g. ZFS based swap/dump */
2N/A if (dnp->devid == NULL)
2N/A continue;
2N/A
2N/A ret = devid_str_decode(dnp->devid, &dnp_devidp, NULL);
2N/A if (ret != 0) {
2N/A /* unable to decode the devid */
2N/A return (NULL);
2N/A }
2N/A /* compare with the devid passed in. */
2N/A if (devid_compare(devidp, dnp_devidp) == 0) {
2N/A /* match! We have the same disk */
2N/A devid_free(dnp_devidp);
2N/A return (dnp);
2N/A }
2N/A devid_free(dnp_devidp);
2N/A }
2N/A
2N/A /* drive not in the cache */
2N/A
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A /* get namespace info */
2N/A if (MD_MNSET_DESC(sd)) {
2N/A if ((nm = meta_getnmbykey(MD_LOCAL_SET, sideno,
2N/A key, ep)) == NULL)
2N/A return (NULL);
2N/A } else {
2N/A if ((nm = meta_getnmbykey(MD_LOCAL_SET,
2N/A sideno+SKEW, key, ep)) == NULL)
2N/A return (NULL);
2N/A }
2N/A
2N/A /* get raw name (rname) of the slice and drive name (dname) */
2N/A if ((rname = getrawnames(&sp, nm, &dname, &uname_type, ep)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A
2N/A /* allocate new list element and drive */
2N/A *tail = Zalloc(sizeof (**tail));
2N/A dnp = (*tail)->drivenamep = Zalloc(sizeof (*dnp));
2N/A metainitdrivename(dnp);
2N/A
2N/A /* get parts info */
2N/A /*
2N/A * Note that if the disk is unavailable this name will point to
2N/A * either a nonexistent disk and thus the part info and devid will
2N/A * be empty or the name will point to the wrong disk and this
2N/A * information will be invalid. Because of this, we overwrite the
2N/A * dnp->devid with the correct one after getparts returns.
2N/A */
2N/A if (getparts(dnp, rname, dname, uname_type, &nparts, &partno, ep) != 0)
2N/A goto out;
2N/A
2N/A dnp->devid = devid_str_encode(devidp, NULL);
2N/A
2N/A /*
2N/A * libmeta needs at least V_NUMPAR partitions.
2N/A * If we have an EFI partition with less than V_NUMPAR slices,
2N/A * we nevertheless reserve space for V_NUMPAR
2N/A */
2N/A if (nparts < V_NUMPAR) {
2N/A nparts = V_NUMPAR;
2N/A }
2N/A
2N/A /* allocate and link in parts */
2N/A dnp->parts.parts_len = nparts;
2N/A dnp->parts.parts_val = Zalloc((sizeof (*dnp->parts.parts_val)) *
2N/A dnp->parts.parts_len);
2N/A
2N/A for (slice = 0; (slice < nparts); ++slice) {
2N/A np = &dnp->parts.parts_val[slice];
2N/A metainitname(np);
2N/A np->drivenamep = dnp;
2N/A }
2N/A
2N/A /* setup name_t (or slice) wanted */
2N/A if ((np = setup_slice(sp, uname_type, dnp, nm, rname,
2N/A dname, partno, ep)) == NULL)
2N/A goto out;
2N/A
2N/A /* canonical disk name */
2N/A if ((dnp->cname = metadiskname(np->cname)) == NULL)
2N/A dnp->cname = Strdup(np->cname);
2N/A if ((dnp->rname = metadiskname(np->rname)) == NULL)
2N/A dnp->rname = Strdup(np->rname);
2N/A
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A Free(rname);
2N/A return (dnp);
2N/A
2N/Aout:
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A
2N/A if (rname != NULL)
2N/A Free(rname);
2N/A
2N/A metafreedrivename(dnp);
2N/A Free(dnp);
2N/A Free(*tail);
2N/A *tail = NULL;
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * Search the drivename list by devid instead of name. If you don't find
2N/A * an entry with the same device id, create one for the uname passed in.
2N/A */
2N/Amddrivename_t *
2N/Ametadrivenamebydevid(
2N/A mdsetname_t **spp,
2N/A char *devid,
2N/A char *uname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A ddi_devid_t dnp_devidp, in_devidp;
2N/A mdname_t *np;
2N/A mddrivenamelist_t **tail;
2N/A char *rname = NULL;
2N/A mddrivename_t *dnp;
2N/A char *dname;
2N/A int ret;
2N/A uint_t nparts, partno;
2N/A uint_t slice;
2N/A meta_device_type_t uname_type = LOGICAL_DEVICE;
2N/A
2N/A /* look in the cache first */
2N/A for (tail = &drivelistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A dnp = (*tail)->drivenamep;
2N/A if (dnp->type != MDT_COMP)
2N/A continue;
2N/A
2N/A /* decode the dnp devid */
2N/A ret = devid_str_decode(dnp->devid, &dnp_devidp, NULL);
2N/A if (ret != 0) {
2N/A /* unable to decode the devid */
2N/A return (NULL);
2N/A }
2N/A /* decode the passed in devid */
2N/A ret = devid_str_decode(devid, &in_devidp, NULL);
2N/A if (ret != 0) {
2N/A /* unable to decode the devid */
2N/A devid_free(dnp_devidp);
2N/A return (NULL);
2N/A }
2N/A /* compare with the devids */
2N/A if (devid_compare(in_devidp, dnp_devidp) == 0) {
2N/A /* match! We have the same disk */
2N/A devid_free(dnp_devidp);
2N/A devid_free(in_devidp);
2N/A return (dnp);
2N/A }
2N/A }
2N/A devid_free(dnp_devidp);
2N/A devid_free(in_devidp);
2N/A
2N/A /* not in the cache */
2N/A
2N/A /* get raw name (rname) of the slice and drive (dname) we have */
2N/A if ((rname = getrawnames(spp, uname, &dname, &uname_type,
2N/A ep)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A
2N/A /* allocate new list element and drive */
2N/A *tail = Zalloc(sizeof (**tail));
2N/A dnp = (*tail)->drivenamep = Zalloc(sizeof (*dnp));
2N/A
2N/A metainitdrivename(dnp);
2N/A
2N/A /* get parts info */
2N/A if (getparts(dnp, rname, dname, uname_type, &nparts, &partno, ep) != 0)
2N/A goto out;
2N/A
2N/A /*
2N/A * libmeta needs at least V_NUMPAR partitions.
2N/A * If we have an EFI partition with less than V_NUMPAR slices,
2N/A * we nevertheless reserve space for V_NUMPAR
2N/A */
2N/A if (nparts < V_NUMPAR) {
2N/A nparts = V_NUMPAR;
2N/A }
2N/A
2N/A /* allocate and link in parts */
2N/A dnp->parts.parts_len = nparts;
2N/A dnp->parts.parts_val = Zalloc((sizeof (*dnp->parts.parts_val)) *
2N/A dnp->parts.parts_len);
2N/A for (slice = 0; (slice < nparts); ++slice) {
2N/A np = &dnp->parts.parts_val[slice];
2N/A metainitname(np);
2N/A np->drivenamep = dnp;
2N/A }
2N/A
2N/A /* setup name_t (or slice) wanted */
2N/A if ((np = setup_slice(*spp, uname_type, dnp, uname, rname,
2N/A dname, partno, ep)) == NULL)
2N/A goto out;
2N/A
2N/A /* canonical disk name */
2N/A if ((dnp->cname = metadiskname(np->cname)) == NULL)
2N/A dnp->cname = Strdup(np->cname);
2N/A if ((dnp->rname = metadiskname(np->rname)) == NULL)
2N/A dnp->rname = Strdup(np->rname);
2N/A
2N/A /* cleanup, return success */
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A Free(rname);
2N/A return (dnp);
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (dname != NULL)
2N/A Free(dname);
2N/A if (rname != NULL)
2N/A Free(rname);
2N/A
2N/A metafreedrivename(dnp);
2N/A Free(dnp);
2N/A Free(*tail);
2N/A *tail = NULL;
2N/A return (NULL);
2N/A}
2N/A/*
2N/A * set up names for a drive
2N/A */
2N/Amddrivename_t *
2N/Ametadrivename(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *slicename;
2N/A mdname_t *np;
2N/A
2N/A mddrivenamelist_t **tail;
2N/A mddrivename_t *dnp;
2N/A char *dname;
2N/A int i;
2N/A int mplen;
2N/A size_t len;
2N/A
2N/A assert(uname != NULL);
2N/A
2N/A if ((dname = metadiskname(uname)) == NULL) {
2N/A (void) mdsyserror(ep, ENOENT, uname);
2N/A return (NULL);
2N/A }
2N/A
2N/A /* look in cache first */
2N/A for (tail = &drivelistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A dnp = (*tail)->drivenamep;
2N/A if ((dnp->cname != NULL &&
2N/A (strcmp(dnp->cname, dname) == 0)) ||
2N/A (dnp->rname != NULL &&
2N/A (strcmp(dnp->rname, dname) == 0))) {
2N/A Free(dname);
2N/A return (dnp);
2N/A }
2N/A }
2N/A Free(dname);
2N/A
2N/A /* Check each possible slice name based on MD_MAX_PARTS. */
2N/A
2N/A /*
2N/A * Figure out how much string space to reserve to fit
2N/A * (MD_MAX_PARTS - 1) into the name string; the loop will
2N/A * increment the mplen counter once for each decimal digit in
2N/A * (MD_MAX_PARTS - 1).
2N/A */
2N/A for (i = MD_MAX_PARTS - 1, mplen = 0; i; i /= 10, ++mplen)
2N/A ;
2N/A len = strlen(uname) + mplen + 2;
2N/A slicename = Malloc(len);
2N/A
2N/A /* Check for each slice in turn until we find one */
2N/A for (np = NULL, i = 0; ((np == NULL) && (i < MD_MAX_PARTS)); ++i) {
2N/A (void) snprintf(slicename, len, "%ss%d", uname, i);
2N/A np = metaname(spp, slicename, LOGICAL_DEVICE, ep);
2N/A }
2N/A Free(slicename);
2N/A
2N/A if (np == NULL) {
2N/A if ((mdiserror(ep, MDE_UNIT_NOT_FOUND)) &&
2N/A ((dname = metadiskname(uname)) != NULL)) {
2N/A Free(dname);
2N/A (void) mderror(ep, MDE_NOT_DRIVENAME, uname);
2N/A }
2N/A return (NULL);
2N/A }
2N/A return (np->drivenamep);
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: metaslicename_type()
2N/A * INPUT: dnp - the drivename structure
2N/A * sliceno - the slice on the drive to return
2N/A * type - LOGICAL_DEVICE or META_DEVICE
2N/A * OUTPUT: ep - return error pointer
2N/A * RETURNS: mdname_t- pointer the the slice name structure
2N/A * PURPOSE: interface to the parts struct in the drive name struct
2N/A * Since there is no guarantee that the slice name
2N/A * structures are populated users should call this
2N/A * function rather than accessing the structure directly
2N/A * since it will populate the structure values if they
2N/A * haven't already been populated before returning.
2N/A */
2N/Amdname_t *
2N/Ametaslicename_type(
2N/A mddrivename_t *dnp,
2N/A uint_t sliceno,
2N/A meta_device_type_t uname_type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdsetname_t *sp = NULL;
2N/A char *namep = NULL;
2N/A mdname_t *np;
2N/A
2N/A assert(dnp->type != MDT_FAST_COMP && dnp->type != MDT_FAST_META);
2N/A
2N/A if (sliceno >= dnp->parts.parts_len) {
2N/A (void) mderror(ep, MDE_NOSLICE, dnp->cname);
2N/A return (NULL);
2N/A }
2N/A
2N/A np = &dnp->parts.parts_val[sliceno];
2N/A
2N/A /* check to see if the struct is already populated */
2N/A if (np->cname) {
2N/A return (np);
2N/A }
2N/A
2N/A if ((namep = meta_name_getname(&sp, dnp->cname,
2N/A uname_type, ep)) == NULL)
2N/A return (NULL);
2N/A
2N/A np = setup_slice(sp, uname_type, dnp, NULL, NULL, dnp->rname,
2N/A sliceno, ep);
2N/A
2N/A Free(namep);
2N/A
2N/A return (np);
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: metaslicename()
2N/A * INPUT: dnp - the drivename structure
2N/A * sliceno - the slice on the drive to return
2N/A * OUTPUT: ep - return error pointer
2N/A * RETURNS: mdname_t- pointer the the slice name structure
2N/A * PURPOSE: interface to the parts struct in the drive name struct
2N/A * Since there is no guarantee that the slice name
2N/A * structures are populated users should call this
2N/A * function rather than accessing the structure directly
2N/A * since it will populate the structure values if they
2N/A * haven't already been populated before returning.
2N/A */
2N/Amdname_t *
2N/Ametaslicename(
2N/A mddrivename_t *dnp,
2N/A uint_t sliceno,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (metaslicename_type(dnp, sliceno, LOGICAL_DEVICE, ep));
2N/A}
2N/A
2N/A/*
2N/A * set up metadevice name from id
2N/A */
2N/Amdname_t *
2N/Ametamnumname(
2N/A mdsetname_t **spp,
2N/A minor_t mnum,
2N/A int fast,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A set_t setno = MD_MIN2SET(mnum);
2N/A mdsetname_t *sp = NULL;
2N/A char *uname;
2N/A mdname_t *np;
2N/A md_dev64_t dev;
2N/A mdkey_t key;
2N/A
2N/A /* check set first */
2N/A if (spp == NULL)
2N/A spp = &sp;
2N/A if (chksetno(spp, setno, ep) != 0)
2N/A return (NULL);
2N/A assert(*spp != NULL);
2N/A sp = *spp;
2N/A
2N/A /* get corresponding device name */
2N/A dev = metamakedev(mnum);
2N/A if ((uname = meta_getnmentbydev(sp->setno, MD_SIDEWILD, dev,
2N/A NULL, NULL, &key, ep)) == NULL)
2N/A return (NULL);
2N/A
2N/A /* setup name */
2N/A if (fast) {
2N/A np = metaname_fast(spp, uname, META_DEVICE, ep);
2N/A if (np) {
2N/A np->dev = dev;
2N/A np->key = key;
2N/A }
2N/A } else
2N/A np = metaname(spp, uname, META_DEVICE, ep);
2N/A
2N/A Free(uname);
2N/A return (np);
2N/A}
2N/A
2N/A/*
2N/A * return metadevice name
2N/A */
2N/Achar *
2N/Aget_mdname(
2N/A mdsetname_t *sp,
2N/A minor_t mnum
2N/A)
2N/A{
2N/A mdname_t *np;
2N/A md_error_t status = mdnullerror;
2N/A mdsetname_t **spp = NULL;
2N/A
2N/A if (sp != NULL)
2N/A spp = &sp;
2N/A
2N/A /* get name */
2N/A if ((np = metamnumname(spp, mnum, 0, &status)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A assert(meta_getminor(np->dev) == mnum);
2N/A
2N/A /* return name */
2N/A return (np->cname);
2N/A}
2N/A
2N/A/*
2N/A * check for device type
2N/A */
2N/Aint
2N/Ametaismeta(
2N/A mdname_t *np
2N/A)
2N/A{
2N/A return (np->drivenamep->type == MDT_META ||
2N/A np->drivenamep->type == MDT_FAST_META);
2N/A}
2N/A
2N/Aint
2N/Ametachkmeta(
2N/A mdname_t *np,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if (! metaismeta(np)) {
2N/A return (mddeverror(ep, MDE_NOT_META, np->dev,
2N/A np->cname));
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Ametachkdisk(
2N/A mdname_t *np,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mddrivename_t *dnp = np->drivenamep;
2N/A
2N/A assert(dnp->type != MDT_FAST_COMP && dnp->type != MDT_FAST_META);
2N/A
2N/A if ((! metaismeta(np)) && (dnp->type != MDT_COMP)) {
2N/A switch (dnp->type) {
2N/A case MDT_ACCES:
2N/A case MDT_UNKNOWN:
2N/A return (mdsyserror(ep, dnp->errnum, np->bname));
2N/A default:
2N/A assert(0);
2N/A return (mddeverror(ep, MDE_NOT_DISK, np->dev,
2N/A np->cname));
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Ametachkcomp(
2N/A mdname_t *np,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A if (metaismeta(np)) {
2N/A return (mddeverror(ep, MDE_IS_META, np->dev,
2N/A np->cname));
2N/A }
2N/A return (metachkdisk(np, ep));
2N/A}
2N/A
2N/A/*
2N/A * free list of names
2N/A */
2N/Avoid
2N/Ametafreenamelist(
2N/A mdnamelist_t *nlp
2N/A)
2N/A{
2N/A mdnamelist_t *next = NULL;
2N/A
2N/A for (/* void */; (nlp != NULL); nlp = next) {
2N/A next = nlp->next;
2N/A Free(nlp);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * build list of names
2N/A */
2N/Aint
2N/Ametanamelist(
2N/A mdsetname_t **spp,
2N/A mdnamelist_t **nlpp,
2N/A int argc,
2N/A char *argv[],
2N/A meta_device_type_t type,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdnamelist_t **tailpp = nlpp;
2N/A int count = 0;
2N/A
2N/A for (*nlpp = NULL; (argc > 0); ++count, --argc, ++argv) {
2N/A mdnamelist_t *nlp = Zalloc(sizeof (*nlp));
2N/A
2N/A if ((nlp->namep = metaname(spp, argv[0],
2N/A type, ep)) == NULL) {
2N/A metafreenamelist(*nlpp);
2N/A *nlpp = NULL;
2N/A return (-1);
2N/A }
2N/A *tailpp = nlp;
2N/A tailpp = &nlp->next;
2N/A }
2N/A return (count);
2N/A}
2N/A
2N/A/*
2N/A * append to end of name list
2N/A */
2N/Amdname_t *
2N/Ametanamelist_append(
2N/A mdnamelist_t **nlpp,
2N/A mdname_t *np
2N/A)
2N/A{
2N/A mdnamelist_t *nlp;
2N/A
2N/A /* run to end of list */
2N/A for (; (*nlpp != NULL); nlpp = &(*nlpp)->next)
2N/A ;
2N/A
2N/A /* allocate new list element */
2N/A nlp = *nlpp = Zalloc(sizeof (*nlp));
2N/A
2N/A /* append name */
2N/A nlp->namep = np;
2N/A return (np);
2N/A}
2N/A
2N/A/*
2N/A * FUNCTION: meta_namelist_append_wrapper()
2N/A * INPUT: tailpp - pointer to the list tail pointer
2N/A * np - name node to be appended to list
2N/A * OUTPUT: none
2N/A * RETURNS: mdnamelist_t * - new tail of the list.
2N/A * PURPOSE: wrapper to meta_namelist_append for performance.
2N/A * metanamelist_append finds the tail each time which slows
2N/A * down long lists. By keeping track of the tail ourselves
2N/A * we can change metanamelist_append into a constant time
2N/A * operation.
2N/A */
2N/Amdnamelist_t **
2N/Ameta_namelist_append_wrapper(
2N/A mdnamelist_t **tailpp,
2N/A mdname_t *np
2N/A)
2N/A{
2N/A (void) metanamelist_append(tailpp, np);
2N/A
2N/A /* If it's the first item in the list, return it instead of the next */
2N/A if ((*tailpp)->next == NULL)
2N/A return (tailpp);
2N/A
2N/A return (&(*tailpp)->next);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * mdhspname_t stuff
2N/A */
2N/A
2N/A/*
2N/A * initialize hspname
2N/A */
2N/Astatic void
2N/Ametainithspname(
2N/A mdhspname_t *hspnamep
2N/A)
2N/A{
2N/A (void) memset(hspnamep, '\0', sizeof (*hspnamep));
2N/A hspnamep->hsp = MD_HSP_NONE;
2N/A}
2N/A
2N/A/*
2N/A * free allocated hspname
2N/A */
2N/Astatic void
2N/Ametafreehspname(
2N/A mdhspname_t *hspnamep
2N/A)
2N/A{
2N/A if (hspnamep->hspname != NULL)
2N/A Free(hspnamep->hspname);
2N/A if (hspnamep->unitp != NULL)
2N/A meta_invalidate_hsp(hspnamep);
2N/A metainithspname(hspnamep);
2N/A}
2N/A
2N/A/*
2N/A * clear the hspname cache
2N/A */
2N/Astatic void
2N/Ametaflushhspnames()
2N/A{
2N/A mdhspnamelist_t *p, *n;
2N/A
2N/A for (p = hsplistp, n = NULL; (p != NULL); p = n) {
2N/A n = p->next;
2N/A metafreehspname(p->hspnamep);
2N/A Free(p->hspnamep);
2N/A Free(p);
2N/A }
2N/A hsplistp = NULL;
2N/A}
2N/A
2N/A/*
2N/A * check set and get comparison name
2N/A */
2N/Astatic char *
2N/Agethspname(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *cname = NULL;
2N/A
2N/A cname = meta_canonicalize(*spp, uname);
2N/A /* if it is not a meta/hsp name then flag an error */
2N/A if (cname == NULL) {
2N/A (void) mdsyserror(ep, ENOENT, uname);
2N/A return (NULL);
2N/A }
2N/A return (cname);
2N/A}
2N/A
2N/A/*
2N/A * set up a hotspare pool name structure using both the name
2N/A * and the self id
2N/A */
2N/Astatic mdhspname_t *
2N/Ametahspname_hsp(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A hsp_t hsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *cname;
2N/A mdhspnamelist_t **tail;
2N/A mdhspname_t *hspnp;
2N/A
2N/A /* check setname */
2N/A assert(uname != NULL);
2N/A if ((cname = gethspname(spp, uname, ep)) == NULL)
2N/A return (NULL);
2N/A assert(*spp != NULL);
2N/A
2N/A /* look in cache first */
2N/A for (tail = &hsplistp; (*tail != NULL); tail = &(*tail)->next) {
2N/A hspnp = (*tail)->hspnamep;
2N/A if (strcmp(hspnp->hspname, cname) == 0) {
2N/A Free(cname);
2N/A /* if the hsp value has not been set then set it now */
2N/A if (hspnp->hsp == MD_HSP_NONE)
2N/A hspnp->hsp = hsp;
2N/A return (hspnp);
2N/A }
2N/A }
2N/A
2N/A /* if the hsp number isn't specified then attempt to get it */
2N/A if (hsp == MD_HSP_NONE && (hsp = meta_gethspnmentbyname((*spp)->setno,
2N/A MD_SIDEWILD, cname, ep)) == MD_HSP_NONE) {
2N/A if (! mdisok(ep)) {
2N/A /*
2N/A * If the error is ENOENT, then we will continue on,
2N/A * because the device does not yet exist.
2N/A * For other types of errors, however, we'll bail out.
2N/A */
2N/A if (! mdissyserror(ep, ENOENT)) {
2N/A Free(cname);
2N/A return (NULL);
2N/A }
2N/A mdclrerror(ep);
2N/A }
2N/A }
2N/A
2N/A /* allocate new list element and hspname */
2N/A *tail = Zalloc(sizeof (**tail));
2N/A hspnp = (*tail)->hspnamep = Zalloc(sizeof (*hspnp));
2N/A metainithspname(hspnp);
2N/A
2N/A /* save hspname and number */
2N/A hspnp->hspname = cname;
2N/A hspnp->hsp = hsp;
2N/A
2N/A /* success */
2N/A return (hspnp);
2N/A}
2N/A
2N/A/*
2N/A * set up names for a hotspare pool
2N/A */
2N/Amdhspname_t *
2N/Ametahspname(
2N/A mdsetname_t **spp,
2N/A char *uname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A return (metahspname_hsp(spp, uname, MD_HSP_NONE, ep));
2N/A}
2N/A
2N/A/*
2N/A * set up hotspare pool name from key
2N/A */
2N/Amdhspname_t *
2N/Ametahsphspname(
2N/A mdsetname_t **spp,
2N/A hsp_t hsp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A set_t setno = HSP_SET(hsp);
2N/A mdsetname_t *sp = NULL;
2N/A char *uname;
2N/A mdhspname_t *hspnp;
2N/A
2N/A /* check set first */
2N/A if (spp == NULL)
2N/A spp = &sp;
2N/A if (chksetno(spp, setno, ep) != 0)
2N/A return (NULL);
2N/A assert(*spp != NULL);
2N/A sp = *spp;
2N/A
2N/A /* get corresponding hotspare pool name */
2N/A if ((uname = meta_gethspnmentbyid(sp->setno,
2N/A MD_SIDEWILD, hsp, ep)) == NULL)
2N/A return (NULL);
2N/A
2N/A /* setup name */
2N/A hspnp = metahspname_hsp(spp, uname, hsp, ep);
2N/A Free(uname);
2N/A return (hspnp);
2N/A}
2N/A
2N/A/*
2N/A * return hotspare pool name
2N/A */
2N/Achar *
2N/Aget_hspname(mdsetname_t *sp, hsp_t hsp)
2N/A{
2N/A mdhspname_t *hspnp;
2N/A md_error_t status = mdnullerror;
2N/A mdsetname_t **spp = NULL;
2N/A
2N/A if (sp != NULL)
2N/A spp = &sp;
2N/A
2N/A /* get name */
2N/A if ((hspnp = metahsphspname(spp, hsp, &status)) == NULL) {
2N/A mdclrerror(&status);
2N/A return (NULL);
2N/A }
2N/A
2N/A /* return name */
2N/A return (hspnp->hspname);
2N/A}
2N/A
2N/A/*
2N/A * free hotspare pool list
2N/A */
2N/Avoid
2N/Ametafreehspnamelist(mdhspnamelist_t *hspnlp)
2N/A{
2N/A mdhspnamelist_t *next = NULL;
2N/A
2N/A for (/* void */; (hspnlp != NULL); hspnlp = next) {
2N/A next = hspnlp->next;
2N/A Free(hspnlp);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * build list of hotspare pool names
2N/A */
2N/Aint
2N/Ametahspnamelist(
2N/A mdsetname_t **spp,
2N/A mdhspnamelist_t **hspnlpp,
2N/A int argc,
2N/A char *argv[],
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdhspnamelist_t **tailpp = hspnlpp;
2N/A int count = 0;
2N/A
2N/A for (*hspnlpp = NULL; (argc > 0); ++count, --argc, ++argv) {
2N/A mdhspnamelist_t *hspnlp = Zalloc(sizeof (*hspnlp));
2N/A
2N/A if ((hspnlp->hspnamep = metahspname(spp, argv[0],
2N/A ep)) == NULL) {
2N/A metafreehspnamelist(*hspnlpp);
2N/A *hspnlpp = NULL;
2N/A return (-1);
2N/A }
2N/A *tailpp = hspnlp;
2N/A tailpp = &hspnlp->next;
2N/A }
2N/A return (count);
2N/A}
2N/A
2N/A/*
2N/A * append to end of hotspare pool list
2N/A */
2N/Amdhspname_t *
2N/Ametahspnamelist_append(mdhspnamelist_t **hspnlpp, mdhspname_t *hspnp)
2N/A{
2N/A mdhspnamelist_t *hspnlp;
2N/A
2N/A /* run to end of list */
2N/A for (; (*hspnlpp != NULL); hspnlpp = &(*hspnlpp)->next)
2N/A ;
2N/A
2N/A /* allocate new list element */
2N/A hspnlp = *hspnlpp = Zalloc(sizeof (*hspnlp));
2N/A
2N/A /* append hotspare pool name */
2N/A hspnlp->hspnamep = hspnp;
2N/A return (hspnp);
2N/A}
2N/A
2N/A/*
2N/A * get name from dev
2N/A */
2N/Amdname_t *
2N/Ametadevname(
2N/A mdsetname_t **spp,
2N/A md_dev64_t dev,
2N/A md_error_t *ep)
2N/A{
2N/A char *device_name;
2N/A mdname_t *namep;
2N/A mdkey_t key;
2N/A
2N/A /* short circuit metadevices */
2N/A assert(dev != NODEV64);
2N/A if (meta_dev_ismeta(dev))
2N/A return (metamnumname(spp, meta_getminor(dev), 0, ep));
2N/A
2N/A /* create local set, if necessary */
2N/A if (*spp == NULL) {
2N/A if ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)
2N/A return (NULL);
2N/A }
2N/A
2N/A /* get name from namespace */
2N/A if ((device_name = meta_getnmentbydev((*spp)->setno, MD_SIDEWILD,
2N/A dev, NULL, NULL, &key, ep)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A namep = metaname_fast(spp, device_name, LOGICAL_DEVICE, ep);
2N/A if (namep != NULL)
2N/A namep->key = key;
2N/A
2N/A Free(device_name);
2N/A return (namep);
2N/A}
2N/A
2N/A/*
2N/A * return cached name from md_dev64_t
2N/A */
2N/Astatic char *
2N/Ametadevtocachename(md_dev64_t dev)
2N/A{
2N/A mddrivenamelist_t *dnlp;
2N/A
2N/A /* look in cache */
2N/A for (dnlp = drivelistp; (dnlp != NULL); dnlp = dnlp->next) {
2N/A mddrivename_t *dnp = dnlp->drivenamep;
2N/A uint_t i;
2N/A
2N/A for (i = 0; (i < dnp->parts.parts_len); ++i) {
2N/A mdname_t *np = &dnp->parts.parts_val[i];
2N/A
2N/A if (np->dev == dev)
2N/A return (np->cname);
2N/A }
2N/A }
2N/A
2N/A /* not found */
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * Ask the driver for the name, which has been stored in the
2N/A * metadevice state database (on behalf of the utilities).
2N/A * (by devno)
2N/A */
2N/Achar *
2N/Aget_devname(
2N/A set_t setno,
2N/A md_dev64_t dev)
2N/A{
2N/A mdsetname_t *sp;
2N/A mdname_t *np;
2N/A md_error_t status = mdnullerror;
2N/A
2N/A /* get name */
2N/A if ((setno == MD_SET_BAD) ||
2N/A ((sp = metasetnosetname(setno, &status)) == NULL) ||
2N/A ((np = metadevname(&sp, dev, &status)) == NULL)) {
2N/A mdclrerror(&status);
2N/A return (metadevtocachename(dev));
2N/A }
2N/A
2N/A /* return name */
2N/A return (np->cname);
2N/A}
2N/A
2N/A/*
2N/A * get name from key
2N/A */
2N/Amdname_t *
2N/Ametakeyname(
2N/A mdsetname_t **spp,
2N/A mdkey_t key,
2N/A int fast,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A char *device_name;
2N/A md_dev64_t dev = NODEV64;
2N/A mdname_t *namep;
2N/A
2N/A /* create local set, if necessary */
2N/A if (*spp == NULL) {
2N/A if ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)
2N/A return (NULL);
2N/A }
2N/A
2N/A /* get name from namespace */
2N/A if ((device_name = meta_getnmentbykey((*spp)->setno, MD_SIDEWILD,
2N/A key, NULL, NULL, &dev, ep)) == NULL) {
2N/A return (NULL);
2N/A }
2N/A if (fast)
2N/A namep = metaname_fast(spp, device_name, UNKNOWN, ep);
2N/A else
2N/A namep = metaname(spp, device_name, UNKNOWN, ep);
2N/A
2N/A assert(dev != NODEV64);
2N/A if (namep)
2N/A namep->dev = dev;
2N/A Free(device_name);
2N/A return (namep);
2N/A}
2N/A
2N/A/*
2N/A * completely flush metadev/hsp caches
2N/A */
2N/Avoid
2N/Ametaflushmetanames()
2N/A{
2N/A metaflushhspnames();
2N/A metaflushdrivenames();
2N/A metaflushfastnames();
2N/A metaflushstatcache();
2N/A}
2N/A
2N/A/*
2N/A * completely flush the caches
2N/A */
2N/Avoid
2N/Ametaflushnames(int flush_sr_cache)
2N/A{
2N/A metaflushhspnames();
2N/A metaflushdrivenames();
2N/A metaflushsetnames();
2N/A metaflushctlrcache();
2N/A metaflushfastnames();
2N/A metaflushstatcache();
2N/A if (flush_sr_cache)
2N/A sr_cache_flush(0);
2N/A}
2N/A
2N/A/*
2N/A * meta_get_hotspare_names
2N/A * returns an mdnamelist_t of hot spare names
2N/A */
2N/A
2N/Aint
2N/Ameta_get_hotspare_names(
2N/A mdsetname_t *sp,
2N/A mdnamelist_t **nlpp,
2N/A int options,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A mdhspnamelist_t *hspnlp = NULL;
2N/A mdhspnamelist_t *hspp;
2N/A int cnt = 0;
2N/A
2N/A assert(nlpp != NULL);
2N/A
2N/A /* get hotspare names */
2N/A if (meta_get_hsp_names(sp, &hspnlp, options, ep) < 0) {
2N/A cnt = -1;
2N/A goto out;
2N/A }
2N/A
2N/A /* build name list */
2N/A for (hspp = hspnlp; (hspp != NULL); hspp = hspp->next) {
2N/A md_hsp_t *hsp;
2N/A int i;
2N/A
2N/A if ((hsp = meta_get_hsp(sp, hspp->hspnamep, ep)) == NULL) {
2N/A cnt = -1;
2N/A goto out;
2N/A }
2N/A for (i = 0; (i < hsp->hotspares.hotspares_len); i++) {
2N/A md_hs_t *hs = &hsp->hotspares.hotspares_val[i];
2N/A
2N/A (void) metanamelist_append(nlpp, hs->hsnamep);
2N/A ++cnt;
2N/A }
2N/A }
2N/A
2N/A /* cleanup and return count or error */
2N/Aout:
2N/A metafreehspnamelist(hspnlp);
2N/A if ((cnt == -1) && mdisok(ep)) {
2N/A /*
2N/A * At least try to give some sort of meaningful error
2N/A */
2N/A (void) mderror(ep, MDE_NO_HSPS, "Generic Hotspare Error");
2N/A }
2N/A
2N/A return (cnt);
2N/A}
2N/A/*
2N/A * meta_create_non_dup_list
2N/A * INPUT: mdnp mdname_t pointer to add to the list if a new name
2N/A * ldevidp list of non-duplicate names.
2N/A * OUTPUT: ldevidp list of non-duplicate names.
2N/A * meta_create_non_dup_list will take a mdname_t pointer and if the device
2N/A * is not in the list (ldevidp) will add it to the list.
2N/A * User needs to free allocated memory.
2N/A */
2N/Avoid
2N/Ameta_create_non_dup_list(
2N/A mdname_t *mdnp,
2N/A mddevid_t **ldevidpp
2N/A)
2N/A{
2N/A char *lcname;
2N/A mddevid_t *tmp;
2N/A mddevid_t *lastdevidp;
2N/A mddevid_t *lldevidp;
2N/A char *ctd, *slice;
2N/A mddevid_t *ldevidp;
2N/A
2N/A if (mdnp == NULL)
2N/A return;
2N/A
2N/A ldevidp = *ldevidpp;
2N/A /*
2N/A * Grab the name of the device and strip off slice information
2N/A */
2N/A lcname = Strdup(mdnp->cname);
2N/A if (lcname == NULL) {
2N/A return;
2N/A }
2N/A ctd = strrchr(lcname, '/');
2N/A if (ctd != NULL)
2N/A slice = strrchr(ctd, 's');
2N/A else
2N/A slice = strrchr(lcname, 's');
2N/A
2N/A if (slice != NULL)
2N/A *slice = '\0';
2N/A
2N/A if (ldevidp == NULL) {
2N/A /* first item in list */
2N/A ldevidp = Zalloc(sizeof (mddevid_t));
2N/A ldevidp->ctdname = lcname;
2N/A ldevidp->key = mdnp->key;
2N/A *ldevidpp = ldevidp;
2N/A } else {
2N/A for (tmp = ldevidp; (tmp != NULL); tmp = tmp->next) {
2N/A if (strcmp(tmp->ctdname, lcname) == 0) {
2N/A /* already there so just return */
2N/A Free(lcname);
2N/A return;
2N/A }
2N/A lastdevidp = tmp;
2N/A }
2N/A lldevidp = Zalloc(sizeof (mddevid_t));
2N/A lldevidp->ctdname = lcname;
2N/A lldevidp->key = mdnp->key;
2N/A lastdevidp->next = lldevidp;
2N/A }
2N/A}