/*
* 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
*/
/*
*/
/*
* Just in case we're not in a build environment, make sure that
* TEXT_DOMAIN gets set to something.
*/
#if !defined(TEXT_DOMAIN)
#endif
#include <meta.h>
#include <sdssc.h>
/*
* Maximum amount of time to spend waiting for an ownership change to complete.
*/
/*
* FUNCTION: meta_is_mn_set()
* INPUT: sp - the set name
* OUTPUT: ep - return error pointer
* RETURNS: int - 1 if MultiNode set else 0
* PURPOSE: checks if the set is a MultiNode set
*/
int
)
{
/* Local set cannot be MultiNode */
return (0);
/*
* sd can be NULL if there is a difference between
* the setrecords and the setlistp caches. This can happen
* if this function is called while a set is being
* removed during a cluster reconfiguration.
*/
return (0);
return (1);
return (0);
}
/*
* FUNCTION: meta_is_mn_name()
* INPUT: spp - ptr to the set name, if NULL the setname is derived
* name - the metadevice/hsp name
* OUTPUT: ep - return error pointer
* RETURNS: int - 1 if MultiNode set else 0
* PURPOSE: checks if the metadevice is in a MultiNode set
*/
int
mdsetname_t **spp,
char *name,
)
{
char *cname;
/*
* if the setname is specified in uname and *spp is
* not set, then it is setup using that set name value.
* If *spp is set and a setname specified in uname and
* the set names don't agree then cname will be
* returned as NULL
*/
mdclrerror(ep);
return (0);
}
}
return (1);
}
return (0);
}
/*
* meta_ping_mnset(set_t setno)
* Send a test message for this set in order to make commd do some init stuff
* Don't bother changelog.
* If set is suspended, fail immediately.
*/
void
{
}
}
/*
*
* FUNCTION: print_stderr
* INPUT: errstr - the error message returned by the command
* context - the context string from metainit -a
* PURPOSE: called from meta_mn_send_command to print the error message
* to stderr. When context is NO_CONTEXT_STRING, the errstr string
* is output unchanged. When context is a string, it is the context
* string for the metainit -a command and in this case the errstr
* string has to be parsed to extract the command and node name
* and to send a message to stderr in the format
* command: node: context: error message
*/
static void
char *errstr,
char *context
)
{
char *command;
char *node;
char *message;
if (context == NO_CONTEXT_STRING) {
} else {
message) == 3) {
} else {
"%s: Invalid format error message"), errstr);
}
}
}
/*
* FUNCTION: meta_mn_send_command()
* INPUT: sp - the set name
* argc - number of arguments
* argv - arg list
* flags - some controlling flags
* initall_context - context string for metainit -a
* OUTPUT: ep - return error pointer
* RETURNS: return exitval from mdmn_send_message
* PURPOSE: sends the command to the master node for execution
*/
int
int argc,
char *argv[],
int flags,
char *initall_context,
)
{
int a;
int err;
int retval;
int send_message_type;
char *cmd;
for (a = 1; a < argc; a++) {
/* don't copy empty arguments */
if (*argv[a] == '\0') {
continue;
}
}
/*
* in dryrun mode stop on the first error
* use the CMD_RETRY message type if RETRY_BUSY flag set
*/
if (flags & MD_PANIC_WHEN_INCONSISTENT)
if (flags & MD_RETRY_BUSY) {
} else {
}
if (err == 0) {
/*
* stderr may be turned off by IGNORE_STDERR
* In dryrun we only print stderr if the exit_val is non-zero
*/
if ((resp->mmr_err_size != 0) &&
((flags & MD_IGNORE_STDERR) == 0)) {
(resp->mmr_exitval != 0)) {
}
}
/*
* If dryrun is set, we don't display stdout,
* because the real run has yet to follow.
*/
}
return (retval);
}
"rpc.mdcommd currently busy. "
"Retry operation later.\n"));
"Node %s must join the %s multi-owner diskset to "
"issue commands.\n"
"To join, use: metaset -s %s -j\n"),
(void) memset(&c, 0, sizeof (c));
"Command not attempted: Unable to log message "
if (c.c_flags & MDDB_C_STALE) {
}
} else {
"Command failed: Commd State %d "
}
} else {
"Command failed: mdmn_send_message returned %d.\n"),
err);
}
return (1);
}
/*
* FUNCTION: meta_mn_send_suspend_writes()
* INPUT: mnum - minor num of mirror
* OUTPUT: ep - return error pointer
* RETURNS: return value from mdmn_send_message()
* PURPOSE: sends message to all nodes to suspend writes to the mirror.
*/
int
)
{
int result;
/*
* This message is never directly issued.
* So we launch it with a suspend override flag.
* If the commd is suspended, and this message comes
* along it must be sent due to replaying a command or similar.
* In that case we don't want this message to be blocked.
* If the commd is not suspended, the flag does no harm.
*/
}
return (result);
}
/*
* Parse the multi-node list file
*
* Return Values: Zero - Success
* Non Zero - Failure
*
* File content: The content of the nodelist file should consist of
* triplets of nodeid, nodename and private interconnect
* address separated by one or more white space.
* e.g.
* 1 node_a 192.168.111.3
* 2 node_b 192.168.111.5
*
* Any missing fields will result in an error.
*/
int
int *nodecnt,
)
{
char *buf;
uint_t i;
int sz;
/* open file */
int err = 0;
/* return this node with id of 1 */
*nodecnt = 1;
/* retrieve info about our host */
err = EADDRNOTAVAIL;
/* We only do IPv4 addresses, for now */
err = EPFNOSUPPORT;
/* No addresses in the list */
err = EADDRNOTAVAIL;
} else {
/* We take the first address only */
sizeof (struct in_addr));
}
if (err) {
}
return (0);
}
*nodecnt = 0;
NULL)) {
/* skip leading spaces */
buf++;
/* skip comments and blank lines */
continue;
/* allocate memory and set tail pointer */
/* parse node id */
buf += i;
/* skip leading spaces */
buf++;
/* fields missing, return error */
*nodecnt = 0;
/* close file and return */
}
/* parse node name */
buf += i;
/* skip leading spaces */
buf++;
/* fields missing, return error */
*nodecnt = 0;
/* close file and return */
}
/* parse node address */
++*nodecnt;
}
/* close file */
}
return (0);
}
/*
* Populate the multi-node list file from a given list of node id's
* The nids must have only one node id in each cell. Range of node
* id's in the form 1-n are not allowed.
*
* Return Values: Zero - Success
* Non Zero - Failure
*/
int
int nodecnt,
char **nids,
)
{
int err = 0;
/* check if we are running on clustering */
}
/* open file for writing */
}
for (i = 0; i < nodecnt; i++) {
/* extract the node id */
errno = 0;
if (errno != 0) {
}
/* get node name */
/* finally get the private ip address */
}
}
/* close file */
return (0);
}
/*
* Free node list
*/
void
)
{
}
}
/*
* FUNCTION: meta_mn_send_setsync()
* INPUT: sp - setname
* mirnp - mirror name
* size - buffer size, 0 if none
* OUTPUT: ep - return error pointer
* RETURNS: return value from meta_mn_send_command()
* PURPOSE: Send a setsync command to all nodes to set resync status
*/
int
)
{
int ret;
setsyncmsg.setsync_flags = 0;
/*
* We do not log the metasync command as it will have no effect on the
* underlying metadb state. If we have a master change the
* reconfiguration process will issue a new 'metasync' to all affected
* mirrors, so we would actually end up sending the message twice.
* Removing the logging of the message helps reduce the processing
* time required.
*/
}
/*
* Unlike non-MN sets, the metasync command does not actually
* start a resync, it simply updates the state on all of the
* nodes. Therefore, to start a resync we send a resync starting
* message for the metadevice
*/
if (ret == 0)
return (ret);
}
/*
* FUNCTION: meta_mn_send_metaclear_command()
* INPUT: sp - setname
* name - metadevice name
* options - command options
* pflag - clear all soft partitions for a given device
* OUTPUT: ep - return error pointer
* RETURNS: return value from meta_mn_send_command()
* PURPOSE: Send a metaclear command to all nodes with force(-f) and
* recurse(-r) options set if required. For hotspare pool and
* the name refers to a metadevice or component and in the is case
* a '-s' argument is required to define the set.
*/
int
char *name,
int pflag,
)
{
int newargc;
char **newargv;
int ret;
/*
* Allocate an array large enough to hold all of the possible
* metaclear arguments
*/
newargv[0] = "metaclear";
newargc = 1;
if (pflag) {
newargc++;
newargc++;
}
if (options & MDCMD_FORCE) {
newargc++;
}
if (options & MDCMD_RECURSE) {
newargc++;
}
if (pflag) {
newargc++;
}
newargc++;
return (ret);
}
/*
* FUNCTION: meta_mn_send_resync_starting()
* INPUT: sp - setname
* mirnp - mirror name
* OUTPUT: ep - return error pointer
* RETURNS: return value from mdmn_send_message()
* PURPOSE: Send a resync starting message to all nodes.
*/
int
)
{
int result;
/*
* This message is never directly issued.
* So we launch it with a suspend override flag.
* If the commd is suspended, and this message comes
* along it must be sent due to replaying a command or similar.
* In that case we don't want this message to be blocked.
* If the commd is not suspended, the flag does no harm.
*/
}
return (result);
}
/*
* FUNCTION: meta_mn_change_owner()
* INPUT: opp - pointer to parameter block
* setno - set number of mirror metadevice
* mnum - minor number of mirror metadevice
* owner - node ID of mirror owner
* flags - flag field for ioctl
* OUTPUT: opp - parameter block used to send ioctl
* RETURNS: int - 0 success, -1 error
* PURPOSE: issue an ioctl to change the ownership of the specified mirror
* to our node ID. We need to be the owner before any watermarks
* are committed to the device otherwise we'll enter a deadly
* embrace when attempting to write the watermark.
* This function can also be used so set the owner on a node to
* NULL. In this case the change is only made on the local node.
* In addition by setting the MD_MN_MM_CHOOSE_OWNER flag, the
* function can also be used to choose a mirror resync owner. This
* function should only be called on the master and it will
* select the owner and request it to become the owner.
*/
int
)
{
int n = 0;
int rval;
} else {
}
/*
* Attempt to change the ownership to the specified node. We retry this
* up to 10 times if we receive EAGAIN from the metadevice. This only
* happens if the underlying metadevice is busy with outstanding i/o
* that requires ownership change.
*/
NULL)) != 0) {
break;
if (n++ >= 10)
break;
(void) sleep(1);
}
/*
* There is no need to wait for the ioctl completion if we are setting
* the owner to NULL or requesting the master to choose the owner
*/
return (0);
}
/*
* Wait for ioctl completion or a timeout to occur. If we
* timeout we fail the i/o request.
*/
rval = -1;
break;
}
(void) sleep(1);
}
}
/* we did not not timeout but ioctl failed set rval */
if (rval == 0) {
}
return (rval);
}
/*
* special handling is required when running on a single node
* non-SC3.x environment. This function determines tests
* for that case.
*
* Return values:
* 0 - no nodes or joined or in a SC3.x env
* 1 - 1 node and not in SC3.x env
*/
int
{
int nodecnt;
int mnset_single_node = 0;
/*
* If running on SunCluster, then don't validate MN sets,
* this is done during a reconfig cycle since all nodes must
* take the same action.
*
* Only cleanup in case of a single node situation
* when not running on SunCluster. This single node
* situation occurs when the nodelist only contains
* this node and the MN setrecords only contain this
* node.
*/
nodecnt = 0; /* no nodes are alive */
mdclrerror(&xep);
} else {
/*
* If only 1 node in nodelist and not running
* on SunCluster, set single_node flag.
*/
if ((nodecnt == 1) &&
((sdssc_bind_library()) != SDSSC_OKAY)) {
mnset_single_node = 1;
}
}
return (mnset_single_node);
}
/*
* FUNCTION: meta_mn_send_get_tstate()
* INPUT: dev - dev_t of device
* OUTPUT: tstatep - tstate value
* ep - return error pointer
* RETURNS: return value from mdmn_send_message()
* PURPOSE: Send a message to the master to get ui_tstate for a given device.
*/
int
)
{
int result;
if (result == 0)
else
/* If some error occurred set tstate to 0 */
*tstatep = 0;
}
return (result);
}