/*
* 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
*/
/*
*/
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <devid.h>
#include <ftw.h>
#include <string.h>
#include <mdiox.h>
#include <meta.h>
#include <syslog.h>
#include <sdssc.h>
#include <libdevinfo.h>
#include "meta_set_prv.h"
/*
* Just in case we're not in a build environment, make sure that
* TEXT_DOMAIN gets set to something.
*/
#if !defined(TEXT_DOMAIN)
#endif
typedef struct path_list {
char *search_path;
char *search_type;
int path_type;
} path_list_t;
/*
* A table of the supported path types - this should ideally be generated
*/
};
/* indicate whether to print an error message or not */
/*
* Debug function: to turn on devadm function debugging include DEVADM
* in the MD_DEBUG enviroment variable: MD_DEBUG=...,DEVADM...
*/
/*PRINTFLIKE1*/
static void
{
char *p;
static int debug_set = 0;
if (debug_set == 0) {
else
}
}
}
/* print error messages to the terminal or syslog */
/*PRINTFLIKE1*/
static void
{
if (dev_options & DEV_LOG) {
/*
* The program is a daemon in the sense that it
* is a system utility.
*/
} else {
}
}
/*
* Utility to find the correct options to use for the devid search
* based upon the path of the device.
*
* RETURN:
* -1 Error, the path passed in is not in the table
* >= 0 The element number for the options within the table
*/
static int
{
int i = 0;
for (i = 0; i < num; i++) {
return (i);
}
return (-1);
}
/*
* Utility to get the path of a device
*/
static char *
{
char *ptr;
char *pathname;
return (NULL);
}
ptr++;
return (pathname);
}
/*
*
* Only update the specific link if a valid minor(not NODEV) is given.
*/
int
{
/*
* di_devlink_init() returns once the /dev links have been
* updated(created or removed). If di_devlink_init returns
* a NULL, the link operation failed.
*
* Use the enhanced di_devlink_init interface if the mnum
* is available.
*/
/*
* NOTE: This will take a _long_ time for large numbers
* of metadevices.
*/
} else {
/* Call di_devlink_init twice, for block and raw devices */
return (-1);
else
(void) di_devlink_fini(&hdl);
}
(void) di_devlink_fini(&hdl);
return (0);
}
return (-1);
}
/*
* update_locator_namespace -- Contains the ioctl call that will update
* locator block namespace.
*
* RETURN
* METADEVADM_ERR ioctl failed and ep is updated with the error
* METADEVADM_SUCCESS success
*/
static int
char *devname,
char *pname,
)
{
return (METADEVADM_ERR);
}
return (METADEVADM_SUCCESS);
}
/*
* meta_update_namespace -- Contains the ioctl call that will update the
* device name and pathname in the namespace area.
*
* RETURN
* METADEVADM_ERR ioctl failed and ep is updated with the error
* METADEVADM_SUCCESS success
*/
int
char *devname,
char *pname,
)
{
return (METADEVADM_ERR);
}
return (METADEVADM_SUCCESS);
}
/*
* stripS - Strip s<digits> off the end of the ctds name if it exists
*/
static void
{
char *p;
/* gobble number and 's' */
for (; (p > name); --p) {
if (!isdigit(*p))
break;
}
if (*p == 's') {
*p = '\0';
}
}
/*
* getdiskname -- to be used when scanning the input from the -u arg.
* This routine will strip off input that is anything but cxtxdx.
* ie. it will call stripS to get rid of slice info. Will also
* the return value.
*
* RETURN
* string that has the disk name in it ie. c0t0d0
*/
static char *
char *name
)
{
char *p;
char *diskname;
/* regular device */
return (diskname);
}
return (diskname);
}
return (diskname);
}
return (diskname);
}
return (diskname);
}
return (diskname);
}
return (diskname);
}
/*
* has_devid -- return the device ID for a given key
*
* RETURN
* NULL error
* devid devid found that corresponds to the given key.
*/
static ddi_devid_t
{
}
/*
* Go through the existing list of replicas and check to see
* if their disk has moved, if so update the replica list
*
* RETURN
* -1 error
* 0 success
*/
static int
)
{
int match_type = 0;
char *search_path;
int search_number;
char *ctds_name;
char *path_name;
int i;
if (sideno == MD_SIDEWILD) {
mda_debug("Failed to find the side number\n");
return (-1);
}
mda_debug("Unable to get a list of replicas\n");
return (METADEVADM_ERR);
}
if (search_number == -1) {
mda_debug("replica update: invalid path: %s",
continue;
} else {
}
continue;
r->r_minor_name, &disklist);
if (ret != 0) {
/*
* Failed to find the disk, nothing can be done.
* The replica will be marked as bad later.
*/
mda_debug("replica update: failed to find disk %s\n",
continue;
}
mda_debug("replica update: current %s (%p)\n",
/*
* Check to see if the returned disk matches the stored one
*/
match_type = 0;
mda_debug("replica update: devid list: %s (%p)\n",
match_type |= DEV_MATCH;
}
match_type |= NAME_MATCH;
}
/*
* break out if some sort of match is found because
* we already match on the devid.
*/
if (match_type != 0)
break;
}
/* no change */
mda_debug("replica update: no change %s\n",
continue;
}
/* No match found - use the first entry in disklist */
i = 0;
mda_debug("replica update: reloading %s %p\n",
if (firsttime) {
"Disk movement detected\n"));
"Updating device names in Solaris Volume "
"Manager\n"));
firsttime = 0;
}
if (dev_options & DEV_VERBOSE) {
char *devidstr;
devidstr =
"Failed to encode the devid\n"));
continue;
}
"%s changed to %s from device relocation "
"information %s\n"),
devidstr);
}
if (!(dev_options & DEV_NOACTION)) {
mda_debug("Updating locator name\n");
ctds_name++;
== NULL) {
continue;
}
mda_debug("replica update: ioctl failed\n");
if (dev_options & DEV_VERBOSE) {
"Failed to update locator "
"namespace on change from %s "
"to %s\n"), ctds_name,
}
}
}
}
return (0);
}
/*
* pathname_reload - main function for the -r option. Will reload the
* pathname in both the main namespace and the locator namespace.
* Also, checks both areas for invalid device ID's and prints them
* out.
*
* If the set is a multi-node diskset that means there are no devid's
* so just return.
*
* RETURN
* METADEVADM_ERR error
* METADEVADM_SUCCESS success
* METADEVADM_DEVIDINVALID success, but invalid devids detected
*/
int
mdsetname_t **spp,
md_error_t *ep)
{
char *drvnmp;
char *ctds_name;
int search_number;
int ret;
int match_type;
int i;
/*
* Check for multi-node diskset and return if it is one.
*/
if (!metaislocalset(sp)) {
return (METADEVADM_ERR);
if (MD_MNSET_DESC(sd))
return (METADEVADM_SUCCESS);
}
/*
* Get the entry of the namespace via the key. To do this
* call MD_IOCNXTKEY until no more.
* For each entry in the namespace we want to check
* for devid and update
*/
if (sideno == MD_SIDEWILD) {
/* failed to find this node in the set */
mda_debug("Failed to find the side number\n");
return (METADEVADM_ERR);
}
/* LINTED */
while (1) {
/* look at each key in the namespace */
return (METADEVADM_ERR);
}
/* no more entries */
break;
}
/*
* get the nm entry using the key. Then check to see if
* there's a devid associated with this entry
* If not, go onto next key.
*/
mda_debug("pathname_reload: no name for key: %d\n",
continue;
}
mda_debug("pathname_reload: examining %s\n",
/* metadevices do not have devid's in them */
mda_debug("pathname_reload: no devid for %s\n",
/* Clear error if no devid and go to next nm entry */
mdclrerror(ep);
continue;
}
/*
* In theory this is impossible because if the
* devidp is non-null then the minor_name has
* already been looked up.
*/
mda_debug("No minor name for %s\n",
continue;
}
/*
* If there is a devid then we have a real device that
* could have moved.
*/
mda_debug("Failed to encode the devid\n");
continue;
}
/*
* Find the search path that should be used. This is an
* optimization to try and prevent a search for the complete
* /dev namespace.
*/
if (search_number == -1) {
search_path = "/dev";
} else {
}
/* now look for the disk name using the devid */
minor_name, &disklist);
if (ret != 0) {
/*
* Failed to find the disk
*/
continue;
}
mda_debug("Old device lookup: %s (%p)\n",
/*
* Check to see if the returned disk matches the stored one
*/
match_type = 0;
mda_debug("From devid lookup: %s (%p)\n",
match_type |= DEV_MATCH;
}
mda_debug("Name match: %s and %s (%d)\n",
match_type |= NAME_MATCH;
}
break;
}
/* no change */
continue;
}
/* No match found - use the first entry in disklist */
i = 0;
if (firsttime) {
"Disk movement detected\n"));
"Updating device names in "
"Solaris Volume Manager\n"));
firsttime = 0;
}
if (dev_options & DEV_VERBOSE) {
"%s changed to %s from device relocation "
"information %s\n"),
devidstr);
}
/* need to build up the path of the disk */
mda_debug("Failed to duplicate path: %s\n",
continue;
}
continue;
}
tmp += sizeof (char);
*tmp = '\0';
mda_debug("Failed to parse ctds name: %s\n",
continue;
}
ctds_name += sizeof (char);
mda_debug("Reloading disk %s %s %p\n",
if (!(dev_options & DEV_NOACTION)) {
/* Something has changed so update the namespace */
ep) != 0) {
mda_debug("Failed to update namespace\n");
if (dev_options & DEV_VERBOSE) {
"Failed to update namespace on "
"change from %s to %s\n"),
}
}
}
}
mda_debug("Failed to update replicas\n");
/*
* check for invalid device id's
*/
/* get count of number of invalid device id's */
return (METADEVADM_ERR);
}
/*
* we have some invalid device id's so we need to
* print them out
*/
/* malloc buffer for kernel to place devid list into */
return (METADEVADM_ERR);
}
/* get actual list of invalid device id's */
return (METADEVADM_ERR);
}
/* print out the invalid devid's */
"Invalid device relocation information "
"detected in Solaris Volume Manager\n"));
"Please check the status of the following disk(s):\n"));
}
return (METADEVADM_DEVIDINVALID);
}
return (METADEVADM_SUCCESS);
}
/*
* replica_update_devid - cycle through the replica list, rlp, and
* update the device ids on all of the replicas that are on the
* device specified by lp. A side effect is to update the value of
* cdevidpp to contain the character representation of the device
* id before updating if it is not already set.
*
* RETURN
* METADEVADM_ERR error
* METADEVADM_SUCCESS success
*/
static int
char **cdevidpp,
)
{
int ret;
return (METADEVADM_ERR);
if (ret != 0) {
/* failed to encode the devid */
mda_debug("Failed to decode %s into a valid devid\n",
return (METADEVADM_ERR);
}
/* search replica list for give ctd name */
/* found the replica, now grab the devid */
}
return (METADEVADM_ERR);
}
mda_debug("Updating replica %s, set %d, old devid %s\n",
if (dev_options & DEV_VERBOSE) {
"Updating replica %s of set number %d from "
"device id %s to device id %s\n"),
}
if (!(dev_options & DEV_NOACTION)) {
mda_debug("Updating replica\n");
/*
* call into kernel to update lb
* namespace device id
* of given devt
*/
return (METADEVADM_ERR);
}
}
}
}
return (METADEVADM_SUCCESS);
}
/*
* devid_update -- main routine for the -u option. Will update both the
* namespace and the locator block with the correct devid for the
* disk specified.
*
* RETURN
* METADEVADM_ERR error
* METADEVADM_SUCCESS success
*/
static int
mdsetname_t **spp,
char *ctd,
)
{
int len;
char *fp;
if (side == MD_SIDEWILD) {
/* failed to find this node in the set */
mda_debug("Failed to find the side number\n");
return (METADEVADM_ERR);
}
return (METADEVADM_ERR);
}
/*
* Disk does not have a devid! So cannot update the
* devid within the replica.
*/
if (dev_options & DEV_VERBOSE) {
"%s does not have a device id. Cannot update "
"device id if none exists\n"), ctd);
}
return (METADEVADM_ERR);
}
/*
* Check if we own the set, if we do then do some processing
* on the replicas.
*/
/* get the replicas */
ep) < 0)
return (METADEVADM_ERR);
/* update the devids in the replicas if necessary */
ep) != METADEVADM_SUCCESS) {
return (METADEVADM_ERR);
}
}
/*
* If this is not the LOCAL set then need to update the LOCAL
* replica with the new disk record.
*/
if (setno != MD_LOCAL_SET) {
/*
* Need to find the disk record within the set and then
* update it.
*/
if ((dd =
goto out;
/* no disks in the set - no point continuing */
mda_debug("No disks in diskset\n");
goto out;
}
break;
}
/* failed to finddisk in the set */
"%s not found in set %s. Check your syntax\n"),
goto out;
}
/*
* Now figure out the correct slice, for a diskset the slice
* we care about is always the 'replica' slice.
*/
mda_debug("Unable to find replica slice for %s\n",
goto out;
}
mda_debug("Unable to build namespace\n");
goto out;
}
if (!(dev_options & DEV_NOACTION)) {
mda_debug("Updating record: key %d name %s\n",
goto out;
}
/*
* Now update the devid entry as well, this works
* correctly because the prior call to
* meta_update_namespace() above puts the correct dev_t
* in the namespace which will then be resolved
* to the new devid by the ioctl now called.
*/
goto out;
}
}
}
/*
* Only want to update the local set so do not continue.
*/
goto out;
}
/*
* Iterate through all of the metadevices looking for the
* passed in ctd. If found then update the devid
*/
/* LINTED */
while (1) {
/* search each namespace entry */
goto out;
}
if (setno != MD_LOCAL_SET) {
"%s not found in set %s. Check your "
goto out;
} else {
"%s not found in local set. "
"Check your syntax\n"), ctd);
goto out;
}
}
goto out;
}
continue;
mda_debug("Updating device %s in namespace\n",
/*
* found disk, does it have a devid within the namespace ?
* It might not because it does not support devid's or was
* put into the namespace when there was no devid support
*/
mda_debug("%s has no devid in the namespace",
if (dev_options & DEV_VERBOSE) {
"SVM has no device id for "
"%s, cannot update.\n"),
}
continue; /* no devid. go on to next */
}
if (old_cdevidp == NULL) {
}
/*
* has devid so update namespace, note the key has been set
* by the prior MD_IOCNXTKEY_NM ioctl.
*/
if (!(dev_options & DEV_NOACTION)) {
/*
* The call below may fail if the -u option is being
* used to update a disk that has been replaced.
* The -u option to metadevadm should not be used
* for this purpose because we trust the dev_t of
* the device in the replica and if we have replaced
* the device and it is a fibre one then the dev_t
* will have changed. This means we end up looking for
* the devid of a non-existant disk and we subsequently
* fail with NODEVID.
*/
if (dev_options & DEV_VERBOSE) {
"SVM failed to update the device "
"id for %s probably due to both "
"devt and device id changing.\n"),
}
goto out;
}
}
if (old_cdevidp == NULL) {
goto out;
}
break;
} /* end while */
"Updating Solaris Volume Manager device relocation "
"information for %s\n"), ctd);
"Old device reloc information:\n\t%s\n"), old_cdevidp);
"insufficient memory, device Reloc info not "
"available\n"));
} else {
"Open of %s failed\n"), fp);
} else {
char *cdevidp;
"Close of %s failed\n"), fp);
}
if (rc != 0) {
"Unable to obtain device "
"Reloc info for %s\n"), fp);
} else {
"Unable to print "
"device Reloc info for %s\n"), fp);
} else {
"New device reloc "
"information:\n\t%s\n"), cdevidp);
}
}
}
}
out:
if (diskname)
if (pathname)
if (old_cdevidp) {
}
return (rval);
}
/*
* Check the ctd name of the disk to see if the disk has moved. If it
* has moved then the newname is returned in 'newname', it is up to
* the caller to free the memory associated with it.
*
* RETURN
* METADEVADM_ERR error
* METADEVADM_SUCCESS success
* METADEVADM_DISKMOVE success, and the disk has moved
* METADEVADM_DSKNAME_ERR error creating the disk name structures.
*/
int
mdsetname_t **spp,
char **newname,
)
{
char *drvnmp;
int i;
char *pathname;
int ret = 0;
int match_type;
/*
* setno should always be 0 but we're going to
* check for multi-node diskset and return if it is one.
*/
if (!metaislocalset(sp)) {
return (METADEVADM_ERR);
if (MD_MNSET_DESC(sd))
return (METADEVADM_SUCCESS);
}
/* no devid, nothing can be done */
if (dev_options & DEV_VERBOSE) {
"%s has no devid, cannot detect "
}
return (ret);
}
/*
* Find the correct side name for the disk. There is a sidename
* for each host associated with the diskset.
*/
mda_debug("meta_upd_ctdnames: %s %d args: setno %d sideno %d\n",
/* only use SKEW for the local replica */
if (setno == 0) {
break;
} else {
break;
}
}
/*
* Failed to find the side name, this should not
* be possible. However if it does happen this is an
* indication of an inconsistant replica - something
* might have gone wrong during an add or a delete of
* a host.
*/
mda_debug("Unable to find the side information for disk %s",
return (METADEVADM_ERR);
}
/*
* Find the type of device we are to be searching on
*/
if (search_number == -1) {
search_path = "/dev";
} else {
}
mda_debug("Search path :%s searth_type: %x\n",
search_path, (int)search_type);
/*
* Get the devname from the name space.
*/
return (METADEVADM_ERR);
}
if (ret != 0) {
/*
* Failed to encode the devid.
*/
return (METADEVADM_ERR);
}
/*
* Use the stored devid to find the existing device node and check
* to see if the disk has moved. Use the raw devices as the name
* of the disk is stored as the raw device, if this is not done
* then the disk will not be found.
*/
search_type, &disklist);
if (ret != 0) {
if (dev_options & DEV_VERBOSE) {
"Device ID %s last associated with "
"disk %s no longer found in system\n"),
}
return (METADEVADM_SUCCESS);
}
mda_debug("Old device lookup: %s (%p)\n",
/*
* Check to see if the returned disk matches the stored one
*/
match_type = 0;
mda_debug("From devid lookup: %s (%p)\n",
match_type |= DEV_MATCH;
}
match_type |= NAME_MATCH;
}
if (match_type != 0)
break;
}
/* no change */
return (METADEVADM_SUCCESS);
}
/* No match found - use the first entry in disklist */
i = 0;
if (!(match_type & DEV_MATCH)) {
/* did not match on the dev, so dev_t has changed */
mda_debug("Did not match on dev: %p %p\n",
}
if (!(match_type & NAME_MATCH)) {
mda_debug("Did not match on name: %s (%p)\n",
}
/*
* If here, then the name in the disklist is the one we
* want in any case so use it.
*/
/*
* Need to remove the slice as metadrivename() expects a diskname
*/
/*
* Build an mddrivename_t to use
*/
mda_debug("Unable to make a dnp out of %s\n",
return (METADEVADM_DSKNAME_ERR);
}
/*
* Need to find the correct slice used for the replica
*/
return (METADEVADM_DSKNAME_ERR);
}
return (METADEVADM_DSKNAME_ERR);
}
if (!(dev_options & DEV_NOACTION)) {
mda_debug("update namespace\n");
/* get the block path */
/* finished with the list so return the memory */
return (METADEVADM_ERR);
}
}
/* finished with the list so return the memory */
return (ret);
}
int
char *diskname,
)
{
int ret = 0;
md_drive_desc *d = NULL;
/* if MN diskset just return */
if (!metaislocalset(sp)) {
return (METADEVADM_ERR);
}
if (MD_MNSET_DESC(sd))
return (METADEVADM_SUCCESS);
}
dev_options |= options;
if (dev_options & DEV_RELOAD) {
/*
* If it's not the local set we need to check the local
* namespace to see if disks have moved as it contains
* entries for the disks in the set.
*/
if (setno != MD_LOCAL_SET) {
mdclrerror(ep);
return (METADEVADM_ERR);
}
/*
* Actually do the check of the disks.
*/
if ((ret == METADEVADM_ERR) ||
(ret == METADEVADM_DSKNAME_ERR)) {
/* check failed in unknown manner */
mda_debug("meta_upd_ctdnames failed\n");
return (METADEVADM_ERR);
}
}
}
/* do a reload of the devid namespace */
} else if (dev_options & DEV_UPDATE) {
}
return (ret);
}