md_names.c revision d7cd82522afdd890a66c7600b499590ad44e84bd
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#define MDDB
extern int *md_nm_snarfed;
void *lookup_shared_entry(struct nm_next_hdr *,
mdkey_t, char *, mddb_recid_t *, int);
extern md_krwlock_t nm_lock;
typedef enum lookup_dev_result {
LOOKUP_DEV_FOUND, /* Found a good record. */
LOOKUP_DEV_NOMATCH, /* No matching record in DB. */
LOOKUP_DEV_CONFLICT /* Name conflicts with existing record. */
/* List of SVM module names. */
static char *meta_names[] = {
"md",
};
#define META_NAME_COUNT (sizeof (meta_names) / sizeof (char *))
/*
* Used in translating from the md major name on miniroot to
* md major name on target system. This is only needed during
* upgrade.
*/
/*
* During upgrade, SVM basically runs with the devt from the target
* target devt when the devt is to be stored in the SVM metadriver's
* unit structures.
*
* The following routines return a translated (aka miniroot) devt:
* - md_getdevnum
* - the metadriver's get_devs routines (stripe_getdevs, etc.)
*
* By the same token, the major number and major name conversion operations
* need to use the name_to_major file from the target system instead
* of the name_to_major file on the miniroot. So, calls to
* ddi_name_to_major must be replaced with calls to md_targ_name_to_major
* when running on an upgrade. Same is true with calls to
* ddi_major_to_name.
*/
static mdkey_t
{
/* increment the next_key, keeps them unique */
rh->r_next_key++;
return (retval);
}
static int
{
int nmspace;
min_value = 1;
} else {
nmspace = 0;
}
/* Just say no if the key passed in is less than the initial */
return (0);
return (0);
/*
* The set num in lookup_entry is not used in this case
* we dont keep track of the nonshared in the devid nmspace
*/
if (!(shared & NM_NOTSHARED) &&
return (0);
return (1);
}
static void
{
return;
key--;
}
static void
{
}
static int
{
struct nm_header_hdr *hhdr;
/*
* Deal with the device id name space
*/
mddb_createrec(sizeof (struct nm_header),
/*
* Out of space
*/
if (nmid < 0)
return (nmid);
} else {
mddb_createrec(sizeof (struct nm_header),
/*
* Out of space
*/
if (nmid < 0)
return (nmid);
}
} else {
}
/*
* h_names.r_next_key is set to zero in devid nmspace
* since we dont keep track of it
*/
} else {
}
return (0);
}
static int
int shared,
{
struct nm_next_hdr *new_nh;
/*
* Device id name space
*/
(sizeof (struct devid_shr_rec) -
sizeof (struct did_shr_name)) :
(sizeof (struct devid_min_rec) -
sizeof (struct did_min_name)));
} else {
MDDB_SHR_NM : MDDB_NM);
(sizeof (struct nm_shr_rec) -
sizeof (struct nm_shared_name)) :
}
if (new_id < 0)
return (new_id);
recids[2] = 0;
return (0);
}
static int
int shared) /* boolean - shared or not */
{
struct nm_rec_hdr *new_rh;
void *new_rec;
/*
* Device id name space
*/
} else {
}
/*
* No space
*/
if (new_id < 0)
return (new_id);
recids[0] = parent_recid;
recids[2] = 0;
/* Fix up rec hdr to point at this new record */
/*
* Device id name space
*/
else
if (!(shared & NM_NOCOMMIT))
/* delete the old record */
return (0);
}
struct nm_next_hdr *
{
struct nm_next_hdr *nh;
/*
* We are dealing with the device id name space.
* If set is a MN diskset, just return 0 since
* devids aren't yet supported in MN disksets.
*/
if (MD_MNSET_SETNO(setno))
return ((struct nm_next_hdr *)0);
return ((struct nm_next_hdr *)0);
:
&((struct nm_header_hdr *)
} else {
/*
* We are dealing with the regular one (non-devid)
*/
return ((struct nm_next_hdr *)0);
:
}
/*
* Name space exists
*/
return (nh);
/*
* If name space is expected and is empty
*/
if (! alloc)
return ((struct nm_next_hdr *)0);
/*
* Empty is okay alloc it
*/
return ((struct nm_next_hdr *)0);
return (nh);
}
void *
int shared, /* shared boolean */
{
struct nm_next_hdr *this_nh;
struct nm_rec_hdr *this_rh;
void *this_rec;
char *name;
/*
* Device id name space
*/
sizeof (struct did_shr_name) :
else
sizeof (struct nm_shared_name) :
/* check the next record to see if it has space */
/*CONSTCOND*/
while (1) {
else
/* check for space in this record */
needed_space) {
/* allocate space in this record */
if (!(shared & NM_NOCOMMIT))
*id = this_recid;
}
/* if we can expand the record we look again */
continue;
/* advance parent to this record, and go try next */
recid = this_recid;
}
/* no space, try creating a new record after parent */
return ((caddr_t)0);
} /* go check the new record */
/* can't get here, but lint seems to think so */
/* NOTREACHED */
}
static void *
struct nm_next_hdr *nh,
{
return ((caddr_t)0);
/* offset == 0, means go to next record */
*off = 0;
return ((caddr_t)0);
}
}
static int
void *ent, /* address of entry to be removed */
int devid_nm) /* which name space? 0 - primary */
{
struct nm_next_hdr *first_nh;
size_t c = ((struct nm_rec_hdr *)
recids[2] = 0;
if (c == 0)
else {
}
/*
* We don't keep track of keys in the device id nonshared namespace
*/
if (!devid_nm)
return (0);
}
static int
void *ent, /* address of entry to be removed */
int devid_nm) /* which name space? 0 - primary */
{
struct nm_next_hdr *first_nh;
size_t c = ((struct nm_rec_hdr *)
recids[2] = 0;
} else {
}
if (c == 0)
else {
}
}
if (!(devid_nm & NM_NOCOMMIT))
return (0);
}
static mdkey_t
{
struct nm_next_hdr *nh;
struct nm_shared_name *shn;
if (shrkey == MD_KEYWILD) {
}
/*
* If devid_nm is not NULL, nh will point to the did name space
*/
if (devid_nm & NM_NOCOMMIT) {
== NULL)
return (MD_KEYBAD);
} else {
== NULL)
return (MD_KEYBAD);
}
if (devid_nm & NM_NOCOMMIT)
/*
* A key has been supplied so find the corresponding entry
* which must exist.
*/
if (shrkey != MD_KEYWILD) {
return (MD_KEYBAD);
} else {
}
if (!(devid_nm & NM_NOCOMMIT))
}
/* allocate an entry and fill it in */
return (MD_KEYBAD);
/*
* Let the whole world know it is valid devid
*/
} else {
/* Increment reference count */
if (!(devid_nm & NM_NOCOMMIT))
}
/* allocate an entry and fill it in */
return (MD_KEYBAD);
}
recids[2] = 0;
if (!(devid_nm & NM_NOCOMMIT))
return (key);
}
void *
{
char *shn;
struct nm_next_hdr *nh;
return ((void *)0);
return ((void *)0);
}
static mdkey_t
{
struct nm_next_hdr *nh;
char *shn;
return (MD_KEYBAD);
return (MD_KEYBAD);
}
static int
{
struct nm_shared_name *shn;
struct nm_next_hdr *nh;
return (ENOENT);
(char *)0, &recid, 0L);
return (ENOENT);
return (0);
}
int
int devid_nm) /* Which name space? */
{
struct nm_rec_hdr *this_rh;
caddr_t n;
(sizeof (struct devid_min_rec) - sizeof (struct did_min_name))
:
/*CONSTCOND*/
while (1) {
} else {
}
return (0);
}
if (n == NULL) {
if (offset)
return (ENOENT);
/* Go to next record */
:
((caddr_t)&((struct devid_min_rec *)
record)->minor_name[0]) :
}
}
/*NOTREACHED*/
}
int
int devid_nm) /* which name space? */
{
struct nm_rec_hdr *this_rh;
caddr_t n;
(sizeof (struct devid_min_rec) - sizeof (struct did_min_name))
:
/*CONSTCOND*/
while (1) {
} else {
}
if (n == NULL) {
if (offset)
return (ENOENT);
/* Go to next record */
:
((caddr_t)&((struct devid_min_rec *)
record)->minor_name[0]) :
}
}
/*NOTREACHED*/
}
int
char *nm, /* Shared name, used as key if non-NULL */
int devid_nm) /* which name space? */
{
struct nm_rec_hdr *this_rh;
if (nm == (char *)0) {
/* No name. Search by key only. */
/* No key either. Nothing to remove. */
return (0);
}
} else {
/* How long is the name? */
}
(sizeof (struct devid_shr_rec) - sizeof (struct did_shr_name))
:
(sizeof (struct nm_shr_rec) - sizeof (struct nm_shared_name)));
/*CONSTCOND*/
while (1) {
} else {
}
if (nm_len == shn_namlen) {
if (!devid_nm) {
devid_nm));
} else {
== NULL) {
return (0);
}
did_devid)) == 0)
devid_nm));
}
}
if (offset)
return (ENOENT);
/* Go to next record */
offset = shn_offset;
((caddr_t)&((struct devid_shr_rec *)
((caddr_t)&((struct nm_shr_rec *)
}
}
/*NOTREACHED*/
}
static md_dev64_t
{
char *shn;
/*
* Can't determine the driver name
*/
return (NODEV64);
if (MD_UPGRADE)
else
return (NODEV64);
return (dev);
}
void *
int devid_nm /* Which name space? */
)
{
void *record;
struct nm_rec_hdr *this_rh;
caddr_t n;
return ((void *)0);
return ((void *)0);
/* code to see if EMPTY record */
/* Go to next record */
return ((void *)0);
}
/*
* n_offset will be used to reset offset
*/
(sizeof (struct devid_min_rec) - sizeof (struct did_min_name)) :
/*CONSTCOND*/
while (1) {
} else {
}
return ((void *)n);
(struct nm_name *)n)))
return ((void *)n);
}
if (n == NULL) {
/*
* No next record, return
*/
if (offset)
return ((void *)n);
/* Go to next record */
((caddr_t)&((struct devid_min_rec *)
record)->minor_name[0]) :
}
}
/*NOTREACHED*/
}
static int
{
int i;
struct nm_next_hdr *nh;
struct nm_shared_name *shn;
return (FALSE);
return (FALSE);
}
/* See if the name is a metadevice. */
for (i = 0; i < META_NAME_COUNT; i++) {
return (TRUE);
}
return (FALSE);
}
static lookup_dev_result_t
char *drvnm, /* drvnm to be stored */
char *dirnm, /* directory name to be stored */
char *filenm, /* device filename to be stored */
)
{
struct nm_rec_hdr *this_rh;
struct nm_name *n;
return (LOOKUP_DEV_NOMATCH);
return (LOOKUP_DEV_NOMATCH);
/* No directory name to look up. */
} else {
/* Look up the directory name */
return (LOOKUP_DEV_NOMATCH);
}
/* code to see if EMPTY record */
/* Go to next record */
return (LOOKUP_DEV_NOMATCH);
}
/*CONSTCOND*/
while (1) {
*ret_rec = n;
return (LOOKUP_DEV_FOUND);
}
/*
* Now check for a name conflict. If the filenm of the
* current record matches filename passed in we have a
* potential conflict. If all the other parameters match
* except for the side number, then this is not a
* conflict. The reason is that there are cases where name
* record is added to each side of a set.
*
* There is one additional complication. It is only a
* conflict if the drvkeys both represent metadevices. It
* is legal for a metadevice and a physical device to have
* the same name.
*/
int both_meta;
/*
* It is hsp and we are trying to add it twice
*/
/*
* All entries removed
*/
return (LOOKUP_DEV_NOMATCH);
}
/*
* It is metadevice and we are trying to add it twice
*/
/*
* Apparently it is invalid so
* clean it up
*/
(void) md_remove_minor_node(n->n_minor);
(void) md_rem_selfname(n->n_minor);
return (LOOKUP_DEV_NOMATCH);
}
/* First see if the two drives are metadevices. */
} else {
}
/* Check rest of the parameters. */
return (LOOKUP_DEV_CONFLICT);
}
}
if (n == (struct nm_name *)0) {
if (offset)
return (LOOKUP_DEV_NOMATCH);
/* Go to next record */
sizeof (struct nm_name);
}
}
/*NOTREACHED*/
}
void *
char *nm, /* Shared name, used as key if non-NULL */
int devid_nm) /* which name space? */
{
void *record;
struct nm_rec_hdr *this_rh;
return ((void *)0);
if (nm != (char *)0)
/* code to see if EMPTY record */
/* Go to next record */
return ((void *)0);
}
/*
* shn_offset will be used to reset offset
*/
(sizeof (struct devid_shr_rec) - sizeof (struct did_shr_name)) :
(sizeof (struct nm_shr_rec) - sizeof (struct nm_shared_name)));
/*CONSTCOND*/
while (1) {
} else {
}
return ((void *)shn);
/* Lookup by name */
if (devid_nm & NM_IMP_SHARED) {
/*
* and we want to do a partial match on that.
*/
return ((void *)shn);
} else if (nm_len == shn_namlen) {
did_devid)) == 0)
return ((void *)shn);
} else {
return ((void *)shn);
}
}
}
/*
* No next record, return
*/
if (offset)
return ((void *)shn);
/* Go to next record */
offset = shn_offset;
((caddr_t)&((struct devid_shr_rec *)
((caddr_t)&((struct nm_shr_rec *)
}
}
/*NOTREACHED*/
}
/*
* lookup_hspentry - Getting a hotspare pool entry from the namespace.
* Use either the NM key or the hotspare name to find
* a matching record in the namespace of the set.
*/
void *
char *name /* (alt. key 2), if key == MD_KEYWILD */
)
{
struct nm_rec_hdr *this_rh;
struct nm_name *n;
char *drv_name;
char *tmpname;
return ((void *)0);
return ((void *)0);
if (setno != MD_LOCAL_SET) {
return ((void *)0);
}
/* code to see if EMPTY record */
/* Go to next record */
return ((void *)0);
}
/*
* n_offset will be used to reset offset
*/
/*CONSTCOND*/
while (1) {
/* We're only interested in hsp NM records */
goto done;
/*
* Searching by a hotspare pool name.
* Since the input name is of the form
* the string 'setname/' in front of the
* n->n_name.
*/
if (key == MD_KEYWILD) {
"%s/%s", setname,
else
"%s",
goto done;
}
}
}
if (n == NULL) {
/*
* No next record, return
*/
if (offset)
goto done;
/* Go to next record */
}
}
done:
return ((void *)n);
}
static int
{
char *dir_name;
/*
* Can't determine the path
*/
if ((dir_name =
return ((int)NODEV64);
return (EFAULT);
/* Tack the directory and device strings together */
return (0);
}
static void
{
struct nm_rec_hdr *this_rh;
struct nm_next_hdr *this_nh;
int multi_node = 0;
/* If given record is for a multi_node set, set flag */
if (MD_MNSET_SETNO(setno))
multi_node = 1;
(sizeof (struct devid_shr_rec) - sizeof (struct did_shr_name))
:
(sizeof (struct devid_min_rec) - sizeof (struct did_min_name)));
else
(sizeof (struct nm_shr_rec) - sizeof (struct nm_shared_name)) :
while (rh->r_next_recid > 0) {
:
&((struct devid_min_rec *)
else
/*
* Check for empty records and clean them up.
* For a MN diskset, only do this if master.
*/
if ((!multi_node) ||
continue;
}
}
}
}
static void
{
mdkey_t i;
if (rh->r_next_recid == 0)
return;
}
/*
* md_setdevname - Allows putting a device name into the database
*/
char *drvnm, /* store this driver name with devicename */
char *devname, /* device name to be stored */
)
{
struct nm_name *n;
struct did_min_name *did_n;
struct did_min_name *new_did_n;
char c;
/*
* Don't allow addition of new names to namespace during upgrade.
*/
if (MD_UPGRADE) {
return (MD_KEYBAD);
}
/*
* Make sure devname is not empty
*/
mnum);
return (MD_KEYBAD);
}
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (MD_KEYBAD);
}
/*
* being dealt with. If this is not done then we stand a
* chance of adding in incorrect devid dealts to match
* the remote side's disk information. For example:
* disk c2t0d0s0 may have devt of 32,256 on this side
* but 32,567 on the remote side and if this is the case
* we do not want to add the devid for disk 32,567 on
* this side into the namespace.
*/
/*
*
* if the key is not set then this is the first time
* through this code which means this is the first record
* which then means the record to be added is for this node
*/
if (key == MD_KEYWILD) {
}
} else if (setno != MD_LOCAL_SET) {
/* set record */
}
/*
* Check to see if it has a device id associated with
* and if the MDDB_DEVID_STYLE flag is set. If the device
* is a metadevice the get_minor_name will fail. No account
* of the side information is taken here because it is dealt
* with later on.
*/
DDI_SUCCESS) &&
/*
* Reference the device id namespace
*/
else
/*
* Always lookup the primary name space
*/
goto out;
}
/*
* If it has a device id then get the header for the devid namespace
*/
goto out;
}
}
/* find boundary between filename and directory */
/* No directory part to the name. */
} else {
/* Isolate the directory name only; save character after '/' */
c = *(cp + 1);
/* Restore character after '/' */
*(cp + 1) = c;
}
/*
* If it already there in the name space
*/
fname, &n);
switch (lookup_res) {
case LOOKUP_DEV_FOUND:
/* If we are importing the set */
retval = 0;
goto out;
}
/* Increment reference count */
n->n_count++;
/* Also in the device id name space if there is one */
if (did_nh) {
/*
* Use thisside for the sideno as this is the
* side this is running on.
*/
if ((did_n = (struct did_min_name *)
} else {
/*
* If a disk device does not support
* devid then we would fail to find the
* device and then try and add it, bit
* silly.
*/
goto add_devid;
}
}
goto out;
case LOOKUP_DEV_CONFLICT:
goto out;
case LOOKUP_DEV_NOMATCH:
/* Create a new name entry */
new = 1;
if (n == NULL)
goto out;
n->n_count = 1;
/* fill-in filename */
/*
* If MDE_DB_NOSPACE occurs
*/
if (((n->n_drv_key =
MD_KEYBAD)) {
/*
* Remove entry allocated by alloc_entry
* and return MD_KEYBAD
*/
goto out;
}
/* No directory name implies no key. */
} else {
/* We have a directory name to save. */
if ((n->n_dir_key =
MD_KEYBAD) {
/*
* Remove entry allocated by alloc_entry
* and return MD_KEYBAD
*/
0L);
goto out;
}
}
recids[2] = 0;
/*
* Now to find out if devid's were used for thisside and if
* so what is the devid_key for the entry so that the correct
* minor name entry (did_n) has the correct devid key.
* Also get the minor name of the device, use the minor name
* on this side because the assumption is that the slices are
* going to be consistant across the nodes.
*/
if ((did_n = (struct did_min_name *)
} else {
}
} else {
/*
* It is possible for the minor name to be null, for
* example a metadevice which means the minor name is
* not initialised.
*/
goto out;
}
break;
}
/*
* We have the key and if the NM_DEVID bit is on
* use the key to add the device id into the device id name space
*/
/*
* No space
*/
if (new) {
}
goto out;
}
/*
* If the key is set then we know that there should
* be a corresponding devid entry because when the record
* associated with the key was created it would have created
* a corresponding devid entry, all we need to do is find
* that record and increment the count.
*/
if (key != MD_KEYWILD) {
/*
* Need to copy the information from the original
* side (thisside).
*/
"addname: failed to add to record");
}
} else {
/* use the did_n allocated above! */
}
/*
* If MDE_DB_NOSPACE occurs
*/
/*
* Remove entry allocated by alloc_entry
*/
if (new) {
}
} else {
recids[2] = 0;
}
}
out:
if (devid)
if (dname)
if (mname)
return (retval);
}
/*
* md_get_invdid - return the invalid device id's
*/
int
int count,
int size,
void *ctdptr
)
{
struct did_shr_name *did_shr_n;
struct did_min_name *did_n;
struct nm_name *n;
int key = MD_KEYWILD;
int cnt = 0;
int i, dont_add_it;
char *tmpctd;
char *diskname;
char *tmpname;
/* first get the invalid devid's from the loc block */
return (-1);
}
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (0);
}
if (did_shr_nh == NULL) {
return (0);
}
return (0);
}
int get_rc;
int compare_rc = 1;
continue;
}
continue;
}
/* found invalid device id. Add to list */
if (get_rc == DDI_SUCCESS) {
}
} else {
return (-1);
}
n = (struct nm_name *)lookup_entry(
if (n == NULL) {
return ((int)NODEV64);
}
return (-1);
}
*tmpname = '\0';
dont_add_it = 0;
for (i = 0; i < (cnt - 1); i++) {
dont_add_it = 1;
break;
}
}
if (dont_add_it == 0) {
}
}
}
*cptr = '\0';
return (0);
}
/*
* md_validate_devid - Checks the device id's to see if they're valid.
* Returns a count of the number of invalid device id's
*/
int
int *rmaxsz
)
{
struct did_shr_name *did_shr_n;
struct did_min_name *did_n;
struct nm_name *n;
int cnt = 0;
int key = MD_KEYWILD;
int maxsz = 0;
int len;
/*
* do the locator blocks first...
*/
return (-1);
}
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (-1);
}
return (cnt);
}
if (did_shr_nh == NULL) {
return (cnt);
}
return (cnt);
}
int get_rc;
int compare_rc = 1;
continue;
}
continue;
}
if (get_rc == DDI_SUCCESS) {
}
} else {
/* device id is invalid */
cnt++;
n = (struct nm_name *)lookup_entry(
if (n == NULL) {
return ((int)NODEV64);
}
/* update max size if necessary */
}
}
return (cnt);
}
/*
* md_getdevname - Allows getting a device name from the database.
* A pointer to a character array is passed in for
* the device name to be built in. Also the max_size
* is the maximum number of characters which can be put
* in the devname[].
*/
int
char *devname, /* char array to put device name in */
)
{
struct nm_next_hdr *nh;
struct nm_name *n;
int err;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (ENOENT);
}
dev, 0L))
== NULL) {
return (ENOENT);
}
return (err);
}
/*
* md_gethspinfo - Getting a hsp name or id from the database.
* A pointer to a character array is passed in for
* the hsp name to be built in. If a match is found,
* the corresponding hspid is stored in ret_hspid.
*/
int
char *drvnm, /* return driver name here */
char *hspname /* alternate key or returned device name */
)
{
struct nm_next_hdr *nh;
struct nm_name *n;
char *drv_name;
int err = 0;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (ENOENT);
}
return (ENOENT);
}
/* Copy the driver name, device name and key for return */
return (EFAULT);
}
/*
* Pre-friendly hsp names are of the form hspxxx and we
* should not have an entry in the namespace for them.
* So make sure the NM entry we get is a hotspare pool.
*/
return (ENOENT);
}
/*
* If the input key is not MD_KEYWILD, return the
* hspname we found.
*/
if (key != MD_KEYWILD) {
else
"%s", n->n_name);
}
return (err);
}
/*
* md_devid_found - Check to see if this key has devid entry or not
* Return 1 if there is one or 0 if none
*/
int
)
{
struct nm_next_hdr *nh;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (0);
}
return (0);
}
/*
* Look up the key
*/
/* This key not in database */
return (0);
}
/* found a key */
return (1);
}
/*
* md_getkeyfromdev - Allows getting a key from the database by using the dev.
* Returns the first key found and the number of keys
* found that match dev.
*/
int
int *numkeysmatch /* ptr to number of keys matching dev */
)
{
struct nm_next_hdr *nh;
struct nm_name *n;
int keynum;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (ENOENT);
}
/*
* Walk through all keys in the namespace looking for a match
* against the given dev. Count the number of matches and
* set firstkey to be first matched key.
*/
*numkeysmatch = 0;
/* This key not in database */
continue;
} else {
/* found a key, look for the dev match */
(struct nm_name *)n)) {
/* found a dev match */
(*numkeysmatch)++;
if (*numkeysmatch == 1) {
}
}
}
}
return (0);
}
/*
* md_getnment - Allows getting a driver name and minor # from the database.
*/
int
char *drvnm, /* char array to put driver name in */
)
{
struct nm_next_hdr *nh;
struct nm_name *n;
char *drv_name;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (ENOENT);
}
dev, 0L))
== NULL) {
return (ENOENT);
}
return (EFAULT);
}
/* Copy the driver name, and fill in the minor number */
if (MD_UPGRADE)
else
return (0);
}
/*
* md_getdevnum - Allows getting a device number from the database.
* This routine returns a translated (aka miniroot) md_dev64_t.
*/
int flag) /* If set then return devt from namespace */
{
struct nm_name *n;
struct did_min_name *did_n;
struct did_shr_name *did_shr_n;
int did_found = 0;
int ndevs;
int devid_nm = 0;
/*
* If a MN diskset and this node is the master OR
* if a traditional diskset, then check to see if the
* did namespace should be cleaned up.
*
* Always set MD_SET_DIDCLUP bit in set's status field
* so that this check is only done once.
*/
(!(MD_MNSET_SETNO(setno)))) {
& MDDB_DEVID_STYLE) || md_devid_destroy) {
}
}
}
/*
* Test the MDDB_DEVID_STYLE bit
*/
& MDDB_DEVID_STYLE) {
devid_nm = 1;
} else {
}
/*
* Load the primary name space
*/
/*
* Unload the devid namespace
*/
return (NODEV64);
}
/*
* If not even in the primary name space, bail out
*/
return (NODEV64);
}
/*
* Entry corresponds to this key is referenced and snarfed so
* we set the value to 1. During the name space cleanup we will check
* this value and if it is set then we know it is part of the
* current configuration. For any 'key' whose value is not set
* then we know it is an 'orphan' entry and will be removed.
*/
if (md_nm_snarfed)
/*
* Reference the device id namespace
*/
if (devid_nm) {
devid_nm = 0;
}
}
/*
* If the key is in the device id name space then
* this device has disk tracking info stored
*/
/*
* Get the minor name and the device id
*/
return (NODEV64);
}
&devs) == DDI_SUCCESS) {
int cnt;
did_found = 1;
/*
* Save the first available devt
* During upgrade, this is a miniroot devt.
*/
/*
* For a multipath device more than 1 md_dev64_t will
* occur. In this case retval will be set to
* the md_dev64_t that was previously set.
*/
if (ndevs > 1) {
/* get the stored md_dev64_t */
break;
}
}
}
/*
* If during upgrade, switch drvnm to be target
* device's name, not miniroot's name.
*/
if (MD_UPGRADE)
else
/*
* It is a valid device id
*/
/*
* Free the memory
*/
} else {
/*
* Invalid device id, say so
* and check flag to see if we can return
* devt stored in the namespace
*/
/*
* If flag does not have MD_TRUST_DEVT bit on
* then with the invalid device id we simply cant
* trust the devt in the namespace at all
*
* Bit MD_TRUST_DEVT is set by metadevadm or
* when a diskset is taken and it does not have
* any associated devid records for the drive
* records in the set.
*
* When this bit is set that means devt can be
* trusted and we just go ahead do whatever user
* ask for
*/
if (!(flag & MD_TRUST_DEVT))
return (NODEV64);
/* build_device_number returns a target devt */
/* translate devt to miniroot devt */
== NODEV64) {
return (NODEV64);
}
return (retval);
}
}
/*
* If no entry is found in the device id name space
* It can be one of:
* underlying meta device
* No device id associated
* Has a device id but mddb is in the old fromat
*/
if (did_found) {
/*
* Update the name entry if necessary
*/
return (NODEV64);
}
if ((drv =
return (NODEV64);
}
MD_KEYWILD, 0L);
} else {
/*
* Has a device id associated with it?
* If yes, then we will try to add them into the device id nm
* build_device_number returns a target devt.
*/
return (NODEV64);
}
/*
* We don't translate the devt of the meta device
* and currently no device id associated with metadevice
*/
== NODEV64) {
return (NODEV64);
}
/*
* Add the device id info only if
* MDDB_DEVID_STYLE bit is set
*
*/
if (!devid_nm) {
return (retval);
}
/*
* We can continue if we are here
* If retval has a device id, add them
*/
== DDI_SUCCESS) &&
== DDI_SUCCESS)) {
/*
* Add them into the devid name space
*/
&recids[0]);
if (did_n) {
did_n->min_namlen =
(char *)devid, MD_KEYWILD,
NM_DEVID);
/*
* Commit the change to the record
*/
(void) remove_entry(did_nh,
NM_DEVID);
} else {
recids[1] =
recids[2] = 0;
}
}
}
/*
* Free all the memory
*/
if (devid)
if (mname)
} else {
}
}
return (retval);
}
/*
* md_getnextkey - Allows running thru the list of defined device names.
*/
{
struct nm_next_hdr *nh;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (MD_KEYWILD);
}
return (MD_KEYWILD);
}
key++) {
break;
}
if (n != NULL) {
}
return (retval);
}
/*
* md_update_namespace_did - update the devid portion of the namespace
*/
int
)
{
struct nm_next_hdr *did_shr_nh;
struct nm_next_hdr *this_did_shr_nh;
void *record;
struct did_shr_name *shn;
struct nm_next_hdr *nh;
struct nm_next_hdr *this_did_nh;
struct did_min_name *n;
struct did_shr_name *shr_n;
return ((int)NODEV64);
}
NULL) {
return (ENOENT);
}
if (this_did_nh == NULL) {
return (ENOENT);
}
return (ENOENT);
}
return (ENOENT);
}
devid_key = n->min_devid_key;
if (did_shr_nh == NULL) {
return ((int)NODEV64);
}
did_shr_nh, n->min_devid_key, (char *)0,
return (ENOENT);
}
if (offset) {
return (ENOENT);
}
}
}
/* remove old devid info */
if (size == 0) {
} else {
size);
}
r_used_size -= ent_size;
/* add in new devid info */
return (ENOMEM);
}
recids[2] = 0;
}
} else {
return (ENOENT);
}
return (0);
}
/*
* md_update_namespace - update namespace device name and pathname
*
*/
int
char *devname, /* device name */
char *pathname, /* pathname to device */
)
{
struct nm_next_hdr *nh;
struct nm_name *n;
struct nm_next_hdr *this_nh;
struct nm_next_hdr *snh;
struct nm_shared_name *shn;
void *record;
char *old_pathname;
int ent_size;
return (ENOENT);
}
return (ENOENT);
}
0L)) == NULL) {
return (ENOENT);
}
if (offset) {
return (ENOENT);
}
}
}
/* save the values from the old record */
ent_drv_key = n->n_drv_key;
ent_dir_key = n->n_dir_key;
- ent_size;
if (size == 0) {
} else {
}
/* check to see if we have a new pathname */
/* now see if the new pathname actually exists in our nsp */
return (ENOENT);
if (shn) {
/* pathname exists so get it's key */
} else {
/* pathname doesn't exist so create it */
}
/* update dir key */
}
/* Create a name entry */
if (n == NULL) {
return (ENOMEM);
}
n->n_drv_key = ent_drv_key;
/* fill-in filename */
/* directory name */
n->n_dir_key = ent_dir_key;
recids[2] = 0;
return (0);
}
/*
* md_getdevidminor - Get the minor name from the database. The minor
* name and the devid id uniquely identify the disk
* slice.
*/
int
char *minorname,
)
{
struct nm_next_hdr *nh;
struct did_min_name *n;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
/*
* The key we have is for the non-shared, regular namespace. We
* have to lookup the min_key in the non-shared, devid namespace.
*/
== NULL) {
return (ENOENT);
}
return (ENOENT);
}
if (n->min_namlen > max_size) {
return (EFAULT);
}
n->min_namlen);
return (0);
}
/*
* md_getdevid - Allows getting a device id from the database.
* A pointer to a character array is passed in for
* the device id to be copied to. The size is returned
* in *did_size.
*/
int
)
{
struct nm_next_hdr *nh;
void *n;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
/*
* The key we have is for the non-shared, regular namespace. We
* have to lookup the min_key in the non-shared, devid namespace.
*/
== NULL) {
return (ENOENT);
}
return (ENOENT);
}
/*
* Now go get the devid.
*/
return (ENOENT);
}
return (ENOENT);
}
/*
* If did is non-zero then copy devid to buffer, else return
* devid size to user. These are exclusive operations.
*/
*did_size);
} else {
}
return (0);
}
/*
* md_remdevname - Allows removing a device name from the database.
*/
int
)
{
struct nm_name *n;
int err;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (ENOENT);
}
/*
* If it is not in the primary name space, nothing to remove
*/
0L)) == NULL) {
return (ENOENT);
}
/*
* If there is non-empty device id name space
* Try to locate the entry
*/
!= NULL) &&
!= NULL)) {
}
n->n_count--;
if (n->n_count) {
/*
* Update the device id namespace as well
*/
if (did_n) {
}
return (err);
}
/* reference count is zero, actually remove the name entry */
return (EINVAL);
}
return (EINVAL);
}
/*
* Remove from the device id name space
*/
if (did_n) {
return (EINVAL);
}
NM_DEVID)) {
return (EINVAL);
}
}
return (0);
}
/*
* md_setshared_name - Puts a name into the shared namespace database, and
* returns a key (used to get the string back).
* If the name does not already exist in the namespace
* then it will be added and the reference count will
* be set to one;
* Otherwise the reference count is incremented.
*/
{
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (MD_KEYBAD);
}
return (key);
}
/*
* md_getshared_name - Allows converting a key, into the shared namespace
* database, to the string which it represents.
*/
char *
{
char *string;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return ((char *)0);
}
return (string);
}
/*
* md_remshared_name - Allows removing of shared name by key.
*/
int
{
struct nm_next_hdr *nh;
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (ENOENT);
}
return (ENOENT);
}
return (ENOENT);
}
return (0);
}
/*
* md_getshared_key - get the key for the given string.
*/
{
/*
* Load the devid name space if it exists
*/
/*
* Unload the devid namespace
*/
return (MD_KEYBAD);
}
return (retval);
}
/*
* md_load_namespace - Get all the records associated with the namespace
* out of the database and setup all the incore
* structures (i.e., pointers).
*/
int
{
return (1);
return (1);
if (hdr_recid < 0) {
setno));
return (0);
}
if (hdr_recid != 0) {
if (status == MDDB_NODATA) {
hdr_recid = 0;
} else if (status == MDDB_STALE) {
}
}
}
if (hdr_recid != 0) {
if (devid_nm) {
} else {
}
devid_nm | NM_NOTSHARED);
/*
* Only cleanup a MN diskset if this node is master.
* Always cleanup traditional diskset.
*/
if (!(MD_MNSET_SETNO(setno)) ||
if (devid_nm) {
} else {
cleanup_unused_rec(setno, 0L);
}
}
}
if (!devid_nm)
return (1);
}
void
{
struct nm_header_hdr *hhdr;
return;
return;
if (devid_nm) {
} else {
}
/*
* Clear MD_SET_NM_LOADED when the primary is unloaded
*/
if (!devid_nm)
/*
* Free the memory occupied by the namespace records if any has been
* allocated. For the case of a namespace which contains drives not
* supporting device id's we must be careful.
*/
}
}
}
}
/*
* md_nm_did_chkspace - calculate the approximate DID namespace size based
* on the component disk devices defined in the primary
* non-shared namespace for this set. This is done on
* the conservative side and may be a block or two too
* large. These are MDDB blocks.
*
* This is intended to be called during a replica conversion from non-devid
* format to devid format. As such no special precautions were taken to
* insure reentrancy. In particular the code in free_devid_list() that
* initializes the devid_list anchor linkages makes this function non-MT-safe.
*/
int
{
struct nm_next_hdr *nh;
struct nm_name *n;
int total_size = 0; /* Total required size */
int devid_size = 0; /* Device id total size */
int mname_size = 0; /* Minor name total size */
int namelen = 0;
int comp_count = 0; /* Total number of components */
int devid_count = 0; /* Total number of devids */
return (total_size);
}
/*
* For each key in the non-shared, primary namespace, lookup the
* minor name and any associated device id. These will reside in
* the device id namespace of the upgraded system.
*/
break;
} else {
!= DDI_SUCCESS) {
continue;
} else {
if (mname) {
mname_size += namelen;
comp_count++;
}
}
continue;
} else {
if (devid_is_unique(devid)) {
} else {
}
}
}
}
/*
* Sum things up in this order:
* 1) # blocks to hold devid non-shared record blocks
* 2) # blocks to hold devid shared record blocks
* 3) 1 block to hold devid non-shared nm_rec_hdr's
* 4) 1 block to hold mddb_de's for both of these spaces
*/
/*
* 1)
*/
sizeof (struct nm_rec_hdr) + (sizeof (struct did_min_name) *
/*
* 2)
*/
sizeof (struct nm_rec_hdr) + (sizeof (struct did_shr_name) *
/*
* 3) and 4)
*/
return (total_size/MDDB_BSIZE);
}
/*
* devid_list - forward list of devid_list structs.
* Managed by routines add_to_devid_list() and free_devid_list() to keep
* track of unique devids associated with components of metadevices. Entries
* are made at the beginning of the list.
*/
static struct devid_list {
struct devid_list *next;
/*
* add_to_devid_list - add a struct devid_list to the head of the devid_list
* list.
*/
static void
{
struct devid_list *curdlp;
}
/*
* free_devid_list - free storage allocated to dev_list list. Return number
* of entries on list at address supplied by argument count. Return total
* size of all device ids that were on the list.
*/
static size_t
free_devid_list(int *count)
{
struct devid_list *curdlp;
struct devid_list *nextlp;
size_t total_size = 0;
int n = 0;
/*
* If there's nothing on the list.
*/
*count = 0;
return (total_size);
}
while (curdlp) {
n++;
}
/*
* Insure that the devid_list anchor linkages are reinitialized in
* case of multiple calls (eg during testsuite execution).
*/
*count = n;
return (total_size);
}
/*
* devid_is_unique - search for did on devid_list list. Return "false" if
* found.
*/
static int
{
struct devid_list *curdlp;
/*
* If first call.
*/
return (1);
}
while (curdlp) {
unique = 0;
break;
}
}
return (unique);
}
/*
* Called after the unit's snarf to cleanup the device id name space
*/
void
{
struct did_min_name *did_n;
struct devid_min_rec *record;
int doit;
/*
* If it is an empty name space
*/
== NULL) ||
return;
}
/*
* Or the name space is empty
*/
sizeof (struct nm_rec_hdr)) {
return;
}
/*
* Not empty
*/
sizeof (struct did_min_name));
/*CONSTCOND*/
while (1) {
/*
* It is not in the primary, remove it from the devid nmspace
*/
if (doit) {
(char *)0, NM_DEVID);
/*
* We delete something so reset scan
*/
continue;
} else {
return;
}
}
/*
* Next record?
*/
if (offset)
return;
/*
* Goto next record
*/
}
}
/*NOTREACHED*/
}
/*
* Resolve md_dev64_t by device id when current configure changes. This
* can happen before the system reboot or between snarf
* and the first use of metadevice. The configure change can
* mean poweroff before boot and poweron after boot or recable
* disks between snarf and the first open of metadevice.
*/
{
struct nm_name *n;
struct did_min_name *did_n;
int ndevs,
cnt;
int update = 0;
/* assign here so that lint does not complain */
return (device);
return (NODEV64);
}
/*
* Something can be resolved by device id
* Resolve by the device id and if it can't be resolved
* then return whatever passed in
*/
!= NULL)) {
/*
* Get the current devt and update mddb devt if necessary
*/
/*
* This device has been powered off
*/
update = 1;
} else {
break;
}
update = 1;
}
}
/*
* Have devt so update name space also
*/
return (NODEV64);
if (update &&
MD_KEYWILD, 0L);
(void) update_entry(nh,
MD_SIDEWILD, n->n_key, 0L);
}
/*
* Free memory
*/
} else {
/*
* if input devid is null or ddi_devid_lyr_devlist
* does not return success then return NODEV64
*/
}
}
return (device);
}