/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <syslog.h>
#include <meta.h>
/* we reserve 1024 bytes for stdout and the same for stderr */
/*ARGSUSED*/
void
{
/*
* We are given one string containing all the arguments
* For execvp() we have to regenerate the arguments again
*/
int i; /* helper for for loop */
arg = 0;
index = 0;
/* init the args array alloc the first one and null out the rest */
for (i = 1; i < MAX_N_ARGS; i++) {
}
while (*cp != '\0') {
if (arg == MAX_N_ARGS) {
"PANIC: too many arguments specified\n"));
goto out;
}
if (index == MAX_ARG_LEN) {
"PANIC: argument too long\n"));
goto out;
}
/*
* No space or tab: copy char into current
* argv and advance both pointers
*/
cp++; /* next char in command line */
index++; /* next char in argument */
} else {
/*
* space or tab: terminate current argv,
* advance arg, reset pointer into arg,
* advance pointer in command line
*/
arg++; /* next argument */
cp++; /* next char in command line */
index = 0; /* starts at char 0 */
}
}
/* terminate the last real argument */
/* the last argument is an NULL pointer */
"PANIC: pipe failed\n"));
goto out;
}
"PANIC: pipe failed\n"));
goto out;
}
"PANIC: fork failed\n"));
goto out;
/* child */
(void) close(0);
/* close the reading channels of pout and perr */
/* redirect stdout */
"PANIC: dup2 failed\n"));
return;
}
/* redirect stderr */
"PANIC: dup2 failed\n"));
return;
}
perror("execvp");
_exit(1);
} else {
/* parent process */
int stat_loc;
int i; /* index into the aboves */
int out_done = 0;
int err_done = 0;
int out_read = 0;
int err_read = 0;
int maxfd;
/* close the writing channels of pout and perr */
/*
* Did the child produce some output to stdout?
* If so, read it until we either reach the end of the
* output or until we read MAX_OUT bytes.
* Whatever comes first.
* In case we already read MAX_OUT bytes we simply
* read away the output into a junk buffer.
* Just to make the child happy
*/
out_read += i;
out += i;
} else {
/* buffer full, empty stdout */
}
if (i == 0) {
/* stdout is closed by child */
out_done++;
}
}
err_read += i;
err += i;
} else {
/* buffer full, empty stderr */
}
if (i == 0) {
/* stderr is closed by child */
err_done++;
}
}
}
break;
}
}
if (errno == 0)
}
out:
for (i = 0; i < MAX_N_ARGS; i++) {
}
}
}
}
/*
* This is for checking if a metadevice is opened, and for
* locking in case it is not and for
* unlocking a locked device
*/
/*ARGSUSED*/
void
{
md_isopen_t *d;
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
/*
* In case the ioctl succeeded, return the open state of
* the metadevice. Otherwise we return the error the ioctl
* produced. As this is not zero, no attempt is made to
*/
if (ret == 0) {
} else {
/*
* When doing a metaclear, one node after the other
* does the two steps:
* - check on all nodes if this md is opened.
* - remove the md locally.
* When the 2nd node asks all nodes if the md is
* open it starts with the first node.
* As this already removed the md, the check
* returns MDE_UNIT_NOT_SETUP.
* In order to not keep the 2nd node from proceeding,
* we map this to an Ok.
*/
mdclrerror(&(d->mde));
ret = 0;
}
}
}
}
/* handler for MD_MN_MSG_REQUIRE_OWNER */
/*ARGSUSED*/
void
{
int ret, n = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
/* Retry ownership change if we get EAGAIN returned */
!= 0) {
break;
}
if (n++ >= 10) {
break;
}
(void) sleep(1);
}
}
/*
* handler for MD_MN_MSG_CHOOSE_OWNER
* This is called when a mirror resync has no owner. The master node generates
* this message which is not broadcast to the other nodes. The message is
* required as the kernel does not have access to the nodelist for the set.
*/
/*ARGSUSED*/
void
{
int ret = 0;
int nodecnt;
int nodeno;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
/*
* The node to be chosen will be the resync count for the set
* modulo the number of live nodes in the set
*/
"MD_MN_MSG_CHOOSE_OWNER: Invalid setno %d\n"), setno);
return;
}
"MD_MN_MSG_CHOOSE_OWNER: Invalid set pointer\n"));
return;
}
/* Count the number of live nodes */
nodecnt = 0;
while (nd) {
nodecnt++;
}
/*
* If we've been called with msg_chooseid_set_node set TRUE then we
* are simply re-setting the owner id to ensure consistency across
* the cluster.
* If the flag is reset (B_FALSE) we are requesting a new owner to be
* determined.
*/
if (d->msg_chooseid_set_node) {
nodeid = d->msg_chooseid_rcnt;
} else {
/* scan the nodelist looking for the required node */
nodecnt = 0;
while (nd) {
break;
nodecnt++;
}
}
}
/* Send message to all nodes to make ownership change */
/* inherit some flags from the parent message */
}
/*
* Handler for MD_MN_MSG_CHANGE_OWNER
* This is called when we are perfoming a resync and wish to change from
* no mirror owner to an owner chosen by the master.
* This mesage is only relevant for the new owner, the message will be
* ignored by all other nodes
*/
/*ARGSUSED*/
void
{
int ret = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
"MD_MN_MSG_CHANGE_OWNER: Invalid setno %d\n"), setno);
return;
}
"MD_MN_MSG_CHANGE_OWNER: Invalid set pointer\n"));
return;
}
/*
* If we are the chosen owner, issue ioctl to make the
* ownership change
*/
MD_MIN2SET(d->msg_chowner_mnum));
/*
* Single shot at changing the the owner, if it fails EAGAIN,
* another node must have become the owner while we are in the
* process of making this choice.
*/
ret = 0;
}
}
/* handler for MD_MN_MSG_SUSPEND_WRITES */
/*ARGSUSED*/
void
{
/* Suspend writes to a region of a mirror */
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
MD_MIN2SET(d->msg_suspwr_mnum));
}
/*
* handler for MD_MN_MSG_STATE_UPDATE_RESWR
* This functions update a submirror component state and then resumes writes
* to the mirror
*/
/*ARGSUSED*/
void
{
/* Update the state of the component of a mirror */
md_mn_msg_stch_t *d;
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
MD_MIN2SET(d->msg_stch_mnum));
}
/*
* submessage generator for MD_MN_MSG_STATE_UPDATE and MD_MN_MSG_STATE_UPDATE2
* This generates 2 messages, the first is SUSPEND_WRITES and
* depending on the type of the original message the second one is
* either STATE_UPDATE_RESWR or STATE_UPDATE_RESWR2 which actually does
* the same, but runs on a higher class.
*/
int
{
md_mn_msg_stch_t *d;
} else {
}
return (2); /* Return the number of submessages generated */
}
/*
* handler for MD_MN_MSG_ALLOCATE_HOTSPARE and MD_MN_MSG_ALLOCATE_HOTSPARE2
* This sends a message to all nodes requesting them to allocate a hotspare
* for the specified component. The component is specified by the mnum of
* the mirror, the submirror index and the component index.
*/
/*ARGSUSED*/
void
{
/* Allocate a hotspare for a mirror component */
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
(void) memset(&allochsp_ioc, 0,
sizeof (md_alloc_hotsp_params_t));
MD_MIN2SET(d->msg_allochsp_mnum));
}
/*
* handler for MD_MN_MSG_RESYNC_STARTING,MD_MN_MSG_RESYNC_FIRST,
* MD_MN_MSG_RESYNC_NEXT, MD_MN_MSG_RESYNC_FINISH, MD_MN_MSG_RESYNC_PHASE_DONE
*/
/*ARGSUSED*/
void
{
int ret;
int smi;
int sleep_count = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
}
/*
* Prior to running the resync thread first check that the start_step
* flag (MD_SET_MN_START_RC) added by metaclust's MC_START step has been
* removed from the set record flags. Ordinarily, this would be removed
* at MC_STEP4 in metaclust - need to ensure this has happened on all
* nodes.
*/
/* Use magic to help protect ioctl against attack. */
"MDMN_DO_RESYNC: Invalid setno = %d\n"),
return;
}
/* start_flag always true initially */
while (start_flag) {
"MDMN_DO_RESYNC: Could not get start_step "
"flag for set %s - returning\n"),
return;
}
/* metaioctl returns successfully - is start flag cleared? */
start_flag = 1;
(void) sleep(sleep_time);
sleep_count++;
if ((sleep_count == 1) ||
(sleep_count % SLEEP_MOD) == 0) {
"MDMN_DO_RESYNC: Waiting for start_step "
"flag for set %s to be cleared\n"),
}
if (sleep_count == MAX_SLEEPS) {
"MDMN_DO_RESYNC: Could not clear "
"start_step flag for set %s "
return;
}
} else {
start_flag = 0;
}
}
if (ret) {
}
}
/*
* handler for MD_MN_MSG_SETSYNC
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
}
/*
* handler for MD_MN_MSG_SET_CAP. As this handler can deal with both mirrors
* and soft partitions, the driver name that is required for the ioctl call
* is included in the message.
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
mnum = d->msg_setcap_mnum;
}
/*
* Dummy handler for various CLASS0 messages like
* MD_MN_MSG_VERBOSITY / MD_MN_MSG_RESUME / MD_MN_MSG_SUSPEND ...
*/
/*ARGSUSED*/
void
{
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
resp->mmr_exitval = 0;
}
/*
* Overall description of mdcommd support that keeps all nodes in-sync
* with the ondisk diskset mddbs.
*
* or replicas must use a CLASS1 message to block out these changes.
* Changes to the state of existing replicas do not need to block CLASS1
* since there is no conflict when just updating the state of a replica.
*
* Error encountered when master writes to mddbs:
* As the master updates parts of the mddbs, flags are updated describing
* what has been written. When all locks are dropped (either in
* mddb_setexit or mdioctl), a PARSE message will be generated to all
* nodes with an index list of known good mddbs and the parse flags.
* The master node ignore the parse message since it sent it.
* The slave nodes re-read in the changed part of the mddb using the list
* of known good replicas that was passed.
* PARSE message does not block CLASS1.
* The PARSE message must be the highest class message. Since this
* message could be sent on any ioctl, this PARSE message class must
* be higher than any other class message that could issue an ioctl.
*
* Master Slave1 Slave2
* Handles_error
* PARSE PARSE PARSE
*
*
* metadb -s set_name -a/-d
* metaset -s set_name -a/-d disk
* metaset -s set_name -b
*
* messages on all nodes until this message is finished. The master
* The BLOCK message is only run on the master node and will BLOCK
* the PARSE messages from being sent to the nodes.
* removes the replica(s) from the given disk slice.
* The UNBLOCK message is only run on the master node and allows the
* sending of PARSE messages.
*
* Master Slave1 Slave2
* Add mddb cmd
* ATTACH msg to master
* BLOCK
* ATTACH ATTACH ATTACH
* UNBLOCK
* PARSE PARSE PARSE
* ATTACH msg finished
*
* metaset -s set_name -a/-d -h
*
* The metaset command is run on the node executing the command and
* sends a DB_NEWSIDE/DB_DELSIDE message and a MD_NEWSIDE/MD_DELSIDE
* message whenever a host is added to or deleted from the diskset.
*
* The side information contains the major name and minor number
* associated with a disk slice from a certain node's perspective
* in an (failed) effort to support clustered systems that don't have the
* same device name for a physical device. (The original designers of
* SVM eventually took the shortcut of assuming that all device names
* are the same on all systems, but left the side information in the
* mddb and namespace.) The side information is used for disk slices
*
* The DB_NEWSIDE/DELSIDE command adds or deletes the side information
* for each mddb for the host being added or deleted.
* The MD_ADDSIDE/MD_DELSIDE command adds or deletes the side information
* for all disk slice components that are in the namespace records for
* the host being added or deleted.
*
* The DB_NEWSIDE/DB_DELSIDE message does not change any mddb records
* and only needs to be executed on the master node since the slave
* nodes will be brought up to date by the PARSE message that is
* generated as a result of a change to the mddb.
* The MD_ADDSIDE/MD_DELSIDE message does modify the records in the mddb
* and needs to be run on all nodes. The message must block class1
* messages so that record changing commands don't interfere.
*
* Master Slave1 Slave2
* Add host
* DB_NEWSIDE msg to master
* DB_NEWSIDE
* PARSE PARSE PARSE
* DB_NEWSIDE msg finished
* MD_NEWSIDE msg to master
* MD_NEWSIDE MD_NEWSIDE MD_NEWSIDE
* MD_NEWSIDE msg finished
*
*
* Optimized resync record failure:
* When any node sees a failure to write an optimized resync record
* that node notifies the master node of the replica that failed.
* The master node handles the error and updates the rest of the
* nodes using a PARSE message. The PARSE message also calls
* fixoptrecord on each slave node causing each node to fix up
* the optimized resync records that are owned by that node (the mirror
* owner code also sets the optimized resync record owner). The master
* node will fix up all optimized resync records that have no owner or
* are owned by the master node.
*
* Master Slave1 Slave2
* Optimized Record Failure
* OPTRECERR msg to master
* Master handles opt rec failure
* PARSE PARSE PARSE
* OPTRECERR msg finished
* Slave rewrites optimized record
*
*/
/*
* Handler for MD_MN_MSG_MDDB_PARSE which send parse messages to the
* slave nodes in order to keep the incore view of the mddbs the
* same on all nodes.
*
* Since master node generated the mddb parse message, do nothing
* if this is the master node.
*
* If this is a slave node, send the parse message down to the kernel
* where this node will re-read in parts of the mddbs.
*
*/
void
{
int ret = 0;
int i;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
if (flags & MD_MSGF_ON_MASTER)
return;
for (i = 0; i < MDDB_NLB; i++) {
}
if (ret)
}
/*
* Handler for MD_MN_MSG_MDDB_BLOCK which blocks the generation
* of parse messages from this node.
*
* slave node is unable to handle a parse message until the slave node
* then unblock the parse messages which causes the parse message to
* be sent to all nodes.
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
if (ret)
}
/*
* Submessage generator for MD_MN_MSG_META_DB_ATTACH which generates
* a BLOCK message on the master node only, a MD_MN_MSG_SM_MDDB_ATTACH
* message on all nodes and then an UNBLOCK message on the master only.
*/
int
{
/* Don't log submessages and panic on inconsistent results */
(void *)nmsg->msg_event_data;
return (3); /* Return the number of submessages generated */
}
/*
* Submessage generator for MD_MN_MSG_META_DB_DETACH which generates
* a BLOCK message on the master node only, a MD_MN_MSG_SM_MDDB_DETACH
* message on all nodes and then an UNBLOCK message on the master only.
*/
int
{
/* Don't log submessages and panic on inconsistent results */
(void *)nmsg->msg_event_data;
return (3); /* Return the number of submessages generated */
}
/*
* Handler for MD_MN_MSG_SM_MDDB_ATTACH which is used to attach mddbs.
*
* Used when running:
* metadb -s set_name -a
* metaset -s set_name -a/-d disk
* metaset -s set_name -b
*/
/*ARGSUSED*/
void
{
struct mddb_config c;
int i;
int ret = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
(void) memset(&c, 0, sizeof (c));
c.c_devname = d->msg_splitname;
c.c_multi_node = 1;
return;
}
if (c.c_sideno == MD_SIDEWILD) {
return;
}
return;
}
/*
* All nodes in MN diskset must do meta_check_replica
* since this causes the shared namespace to be
* populated by the md driver names while checking
* to see if this device is already in use as a
* metadevice.
*/
return;
}
for (i = 0; i < d->msg_cnt; i++) {
if (setup_med_cfg(sp, &c,
ret = -1;
break;
}
/* If newdev was successful, continue with attach */
if (ret == 0) {
DB_ADDSIDENMS_NO_BCAST, &ep)) {
ret = -1;
break;
}
} else {
break;
}
}
} else {
ret = -1;
}
}
/*
* Handler for MD_MN_MSG_SM_MDDB_DETACH which is used to detach mddbs.
*
* Used when running:
* metadb -s set_name -d
* metaset -s set_name -a/-d disk
* metaset -s set_name -b
*/
/*ARGSUSED*/
void
{
struct mddb_config c;
int i;
int ret = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
return;
}
(void) memset(&c, 0, sizeof (c));
return;
}
i = 0;
while (i < c.c_dbcnt) {
c.c_id = i;
ret = -1;
break;
}
i++;
continue;
}
/* Found a match - delete mddb */
ret = -1;
break;
}
/* Not incrementing "i" intentionally (dbcnt is changed) */
}
} else {
ret = -1;
}
}
/*
* Handler for MD_MN_MSG_META_DB_NEWSIDE which is used to update the
* side information for each diskset mddb when a new host has been
* that the new node would use to access each mddb.
*
* Since this routine makes no changes to the records in the diskset mddb,
* this routine only needs to be run on the master node. The master node's
* kernel code will detect that portions of the mddb have changed and
* will send a parse message to all nodes to re-parse parts of the mddb.
*
* Used when running:
* metaset -s set_name -a -h new_hostname
*/
/*ARGSUSED*/
void
{
struct mddb_config c;
int ret = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
(void) memset(&c, 0, sizeof (c));
c.c_devname = d->msg_splitname;
c.c_multi_node = 1;
return;
}
c.c_sideno = d->msg_sideno;
}
}
/*
* Handler for MD_MN_MSG_META_DB_DELSIDE which is used to remove the
* side information for each diskset mddb when a host has been
* that the node would use to access each mddb.
*
* Since this routine makes no changes to the records in the diskset mddb,
* this routine only needs to be run on the master node. The master node's
* kernel code will detect that portions of the mddb have changed and
* will send a parse message to all nodes to re-parse parts of the mddb.
*
* Used when running:
* metaset -s set_name -d -h hostname
*/
/*ARGSUSED*/
void
{
int ret = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
(void) memset(&c, 0, sizeof (c));
c.c_multi_node = 1;
return;
}
c.c_sideno = d->msg_sideno;
}
}
/*
* Handler for MD_MN_MSG_META_MD_ADDSIDE which is used to add the
* side information for each diskset metadevice component (if that
* component is a disk) when a host has been added to the diskset.
* use to access the metadevice component.
*
* This routine makes changes to the mddb records and must be run
* on all nodes.
*
* Used when running:
* metaset -s set_name -a -h new_hostname
*/
/*ARGSUSED*/
void
{
int done, i;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
return;
}
/* While loop continues until IOCNXTKEY_NM gives nm.key of KEYWILD */
/*CONSTCOND*/
while (1) {
return;
}
/* Normal exit path is to eventually get a KEYWILD */
resp->mmr_exitval = 0;
return;
}
/*
* Okay we have a valid key
* Let's see if it is hsp or not
*/
if (drvnm)
return;
}
/*
* If it is hsp add here
*/
return;
} else {
continue;
}
}
return;
}
if (done != 1) {
return;
}
/*
* The device reference count can be greater than 1 if
* more than one softpart is configured on top of the
* same device. If this is the case then we want to
* increment the count to sync up with the other sides.
*/
return;
}
}
}
/*NOTREACHED*/
}
/*
* Handler for MD_MN_MSG_META_MD_DELSIDE which is used to delete the
* side information for each diskset metadevice component (if that
* component is a disk) when a host has been removed from the diskset.
* use to access the metadevice component.
*
* This routine makes changes to the mddb records and must be run
* on all nodes.
*
* Used when running:
* metaset -s set_name -d -h hostname
*/
/*ARGSUSED*/
void
{
int i;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
return;
}
/*CONSTCOND*/
while (1) {
return;
}
/* Normal exit path is to eventually get a KEYWILD */
resp->mmr_exitval = 0;
return;
}
/*
* The device reference count can be greater than 1 if
* more than one softpart is configured on top of the
* same device. If this is the case then we want to
* decrement the count to zero so the entry can be
* actually removed.
*/
return;
}
}
}
/*NOTREACHED*/
}
/*
* Handler for MD_MN_MSG_MDDB_OPTRECERR which is used to notify
* the master node that a node has seen an error when attempting to
* write to the optimized resync records that reside on 2 of the diskset
* mddbs. Master node will mark the failed replica in error and this
* will send a parse message to all nodes to re-read parts of the mddb
* and to fix their optimized resync records based on this information.
*/
/*ARGSUSED*/
void
{
int ret;
int i;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
for (i = 0; i < 2; i++) {
}
if (ret)
}
int
{
return (4); /* Return the number of submessages generated */
}
/*
* This is to send an MD_IOCSET ioctl to all nodes to create a soft
* partition.
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
"MD_MN_MSG_IOCSET: Invalid setno %d\n"), setno);
return;
}
/*
* Device should be in the namespace already
*/
"MD_MN_MSG_IOCSET: Invalid mnum %d\n"),
d->iocset_params.mnum);
return;
}
/*
* Create unit structure
*/
}
/*
* This is to update the status of a softpart
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
mnum = d->sp_setstat_mnum;
"MD_MN_MSG_IOCSET: Invalid setno %d\n"), setno);
return;
}
}
/*
* This is to add a key to the namespace
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
setno = d->addkeyname_setno;
"MD_MN_ADDKEYNAME: Invalid setno %d\n"), setno);
return;
}
if (ret < 0)
else
} else {
}
}
/*
* This is to delete a key from the namespace
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
setno = d->delkeyname_setno;
"MD_MN_DELKEYNAME: Invalid setno %d\n"), setno);
return;
}
/*
* Reset the key value for the name. This is required because
* any previous call of del_key_name for the same component
* will have resulted in the key value being reset to MD_KEYBAD
* even though there may still be references to this component.
*/
} else {
}
}
/*
* This is to get the value of tstate from the master node. We use this
* to get the ABR state of a metadevice from the master.
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
if (ret != 0) {
"MD_MN_GET_TSTATE: Invalid dev %llx\n"), d->gettstate_dev);
tstate = 0;
}
}
/*
* This is to get the mirror ABR state and the state of its submirrors from
* the master node. We need this to ensure consistent output from metastat
* when a new node joins the cluster during a resync. Without this the
* submirror status will be incorrect until the whole resync is complete which
* may take days for very large metadevices.
*/
/*ARGSUSED*/
void
{
int smi;
resp->mmr_err_size = 0;
/* Validate set information from minor number */
"MD_MN_GET_MIRROR_STATE: Invalid set %d\n"), setno);
resp->mmr_out_size = 0;
return;
}
/* Construct mirror name from minor number */
"MD_MN_GET_MIRROR_STATE: Invalid minor %lx\n"),
d->mir_state_mnum);
resp->mmr_out_size = 0;
return;
}
/* Get common mirror structure */
"MD_MN_GET_MIRROR_STATE: Invalid mirror minor %x\n"),
d->mir_state_mnum);
resp->mmr_out_size = 0;
return;
}
"MD_MN_GET_MIRROR_STATE: Invalid minor %lx\n"),
d->mir_state_mnum);
resp->mmr_out_size = 0;
return;
}
/*
* gets passed back to the message originator
*/
resp->mmr_exitval = 0;
}
/* Returm value of tstate for mirror */
}
/*
* This is to issue an ioctl to call poke_hotspares
*/
/*ARGSUSED*/
void
{
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
}
/*
* Called to create a softpart during a metarecover operation
*/
/*ARGSUSED*/
void
{
int init = 0;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
"MD_MN_MSG_ADDMDNAME: Invalid setno %d\n"),
d->addmdname_setno);
return;
}
/*
* If device node does not exist then init it
*/
&mde)) <= 0) {
"MD_MN_MSG_ADDMDNAME: Invalid name %s\n"),
d->addmdname_name);
return;
}
init = 1;
}
/*
* We should have it
*/
if (init) {
(void) metaioctl(
}
}
return;
}
resp->mmr_exitval = 0;
}
/*
* This is used to issue a MD_MN_RR_DIRTY ioctl to the mirror.
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
}
/*
* This is used to issue a MD_MN_RR_CLEAN ioctl to the mirror.
*/
/*ARGSUSED*/
void
{
int ret;
resp->mmr_out_size = 0;
resp->mmr_err_size = 0;
}