/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "metad_local.h"
#include <metad.h>
#include <sdssc.h>
#include <syslog.h>
#include <thread.h>
/*
* rpc.metad daemon
*
* The rpc.metad deamon supports two versions of the svm rpc calls - version 1
* and version 2. The over-the-wire structures sent as part of these rpc calls
* are also versioned - version 1 and version 2 exist. It must be noted that
* the version 2 structures have sub-versions or revisions as well. The
* revisions in the version 2 structures allow for flexiblility in changing
* over the wire structures without creating a new version of the svm rpc
* calls. No changes may be made to the version 1 routines or structures used
* by these routines.
*
* If, for example, the version 2 mdrpc_devinfo_args over the wire structure
* (mdrpc_devinfo_2_args*) is changed then the structure change must be
* accompanied by the following:
*
* Header file changes:
* . May need to introduce a new structure revision MD_METAD_ARGS_REV_X, where
* X is the revision number.
* . Create mdrpc_devinfo_2_args_rX, where X is the new revision of the
* structure.
* . Add a switch statement in mdrpc_devinfo_2_args.
*
* rpc.metad changes:
* . Check for the structure revision in the appropriate mdrpc_devinfo_svc
* routine (mdrpc_devinfo_2_svc).
*
* libmeta changes:
* . In the libmeta code that makes the mdrpc_devinfo rpc call, the arguments
* being passed as part of this call (namely mdrpc_devinfo_Y_args) must have
* the revision field and associated structure populated correctly.
*/
/*
* Add namespace entry to local mddb for using given sideno, key
* and names.
*/
static int
)
{
char *nm;
return (-1);
break;
/*
* SKEW will be used on the traditional diskset despite of the
* rpc version. SKEW is not used on the multinode diskset
*/
if (MD_MNSET_DESC(sd)) {
} else {
}
return (-1);
mdclrerror(ep);
}
/*
* Ignore returned key from add_name, only care about errs
*
* SKEW is used for a regular diskset since sideno could
* have a value of 0 in that diskset type. add_name is
* writing to the local mddb and a sideno of 0 in the
* local mddb is reserved for non-diskset names.
* SKEW is added to the sideno in the local mddb so that
* the sideno for the diskset will never be 0.
*
* In a MNdiskset, the sideno will never be 0 (by design).
* So, no SKEW is needed when writing to the local mddb.
*/
if (MD_MNSET_DESC(sd)) {
ep) == -1)
return (-1);
} else {
ep) == -1)
return (-1);
}
} else
return (0);
}
/*
* Delete sidename entry from local set using key and sideno.
*/
static int
)
{
return (-1);
return (0);
}
/*
* Add namespace entries to local mddb for drives in drive list in
* set descriptor.
*
* If a MNset and if this host is being added to the set (this host
* is in the node_v list), add a namespace entry for the name of
* each drive using this host's sideno.
*
* If not a MNset, add namespace entries for all the new hosts being
* added to this set (list in node_v).
*/
static void
char *hostname,
int node_c,
char **node_v,
)
{
int i;
int using_devid = 0;
return;
return;
/* If a MN diskset */
if (MD_MNSET_DESC(sd)) {
/* Find sideno associated with RPC client. */
while (nd) {
}
/* While looping, find my side num as well */
}
break;
}
}
if (!sideno) {
return;
}
} else {
/*
* if not a MN diskset
* do action for traditional diskset.
* despite of the rpc version
*/
/* Skip empty slots */
continue;
break;
}
if (sideno == MD_MAXSIDES) {
return;
}
}
return;
/* we are supposed to have drives!!!! */
assert(0);
}
/*
* The system is either all devid or all
* non-devid so we look at the first item
* in the list to determine if we're using devids or not.
* We also check to make sure it's not a multi-node diskset.
* If it is, we don't use devid's.
*
* For did disks, the dd_dnp->devid is a valid pointer which
* points to a '' string of devid. We need to check this
* before set the using_devid.
*/
(!(MD_MNSET_DESC(sd))))
using_devid = 1;
/*
* We have to match-up the dd that were passed
* across the wire to the dd we have in this daemon.
* That way we can pick up the new sidenames that were
* passed to us and match them up with the local namespace key.
* Only we have the key, this cannot be passed in.
*/
devid_remote = NULL;
using_devid) {
/*
* We have a devid so use it
*/
}
/* check to make sure using_devid agrees with reality... */
/* something went really wrong. Can't process */
return;
}
devid_same = -1;
&devid_local, NULL) == 0) {
}
}
if (using_devid && devid_same == 0) {
break;
}
if (!using_devid &&
break;
}
if (devid_remote) {
}
if (MD_MNSET_DESC(sd)) {
/*
* Add the side names to the local db
* for this node only.
*/
return;
/*
* Sidenames for this drive were added
* to this host during the routine adddrvs.
* The sidenames that were added are the
* names associated with this drive on
* each of the hosts that were previously
* in the set.
* When the sidename for this drive on
* this host is added, the sidename
* from the host executing the command
* (not this host) is sent to this host.
* This host finds the originating host's
* sidename and can then determine this
* host's sidename.
* The sidenames from the other hosts serve
* only as temporary sidenames until this
* host's sidename can be added.
* In order to conserve space in the
* local mddb, the code now deletes the
* temporary sidenames added during adddrvs.
* When finished, only the sidename for this
* node should be left.
* Ignore any errors during this process since
* a failure to delete the extraneous
* sidenames shouldn't cause this routine
* to fail (in case that sidename didn't exist).
*/
while (nd) {
if (del_sideno_sidenm(
mdclrerror(ep);
}
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
/* Skip nodes not being added */
continue;
/* Add the per side names to local db */
return;
}
}
}
}
/* ARGSUSED */
{
return (FALSE);
else if (err != 0)
return (TRUE);
metaflushnames(1);
return (TRUE);
}
{
}
{
}
/*
* add 1 or more namespace entries per drive record.
* (into the local namespace)
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
int i, j;
/* allocate memory */
/* build args */
/* set descriptor */
for (i = 0; i < MD_MAXSIDES; i++) {
for (j = 0; j < MD_MAX_NODENAME_PLUS_1; j++)
}
/* convert v1 args to v2 (revision 1) args */
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_add_drv_sidenms_common(
default:
return (FALSE);
}
}
static int
)
{
int err;
return (-1);
key = MD_KEYWILD;
/*
* If a multi-node diskset, find nodeid associated with this node.
*/
if (MD_MNSET_REC(sr)) {
while (nr) {
break;
}
}
/*
* If node is found, then a new drive is being added to
* a MN set of which this node is a member.
* If node is not found, then this host is being added to
* a MN set that has drives associated with it.
*/
if (nr)
}
if (MD_MNSET_REC(sr)) {
/*
* In multi-node disksets, only add side information
* to the local mddb about this node.
* If the sideno for this node is found, then
* a new drive is being added to a MN set of
* which this node is a member.
* If the sideno for this node is not found, then
* this host is being added to a MNset that
* has drives associated with it. In this case,
* need to add the sidename associated with the
* rpc client, but since we don't know which node
* is the client, then add temp entries for all sides.
* Later, the sidename for this node will be set
* via add_drv_sidenms and then the temp
* sidenames can be removed.
*/
return (-1);
break;
}
} else {
/*
* When a sidename is added into the namespace the local
* side information for the name is added first of all.
* When the first sidename is created this causes the
* devid of the disk to be recorded in the namespace, if
* the non-local side information is added first then
* there is the possibility of getting the wrong devid
* because there is no guarantee that the dev_t (mnum in
* this instance) is the same across all the nodes in
* the set. So the only way to make sure that the
* correct dev_t is used is to force the adding in of
* the local sidename record first of all. This same
* issue affects add_key_name().
*/
continue;
return (-1);
break;
}
}
/*
* Now the other sides for non-MN set
*/
if (!MD_MNSET_REC(sr)) {
continue;
ep)) == -1)
return (-1);
}
}
/* Temporarily add all sides. */
if (sn) {
return (-1);
}
}
}
return (0);
}
/*
* imp_adddrvs
* This is a version of adddrvs that is specific to the
* metaimport command. Due to the unavailability of some disks,
* information needs to be obtained about the disk from the devid so
* it can eventually be passed down to add_sidenamelist.
* Go ahead and set drive state to MD_DR_OK here so that no
* later RPC is needed to set OK where UNRLSV_REPLICATED could
* be cleared. Set record is still set to MD_SR_ADD which will force
* a cleanup of the set in case of panic.
*/
void
char *setname,
)
{
md_drive_desc *p;
return;
}
return;
int ret = 0;
/*
* We need the minorname and devid string decoded from the
* devid to add the sidename for this drive to the
* local set.
*/
if (ret != 0) {
/* failed to decode the devid */
goto out;
}
continue;
}
ep)) == -1) {
goto out;
}
/* Create the drive record */
goto out;
}
/* Fill in the drive record values */
if (p->dd_flags & MD_DR_UNRSLV_REPLICATED) {
}
/* Link the drive records and fill in in-core data */
else
mdclrerror(&xep);
MD_LOCAL_SET, dev);
}
/* Commit all the records atomically */
return;
out:
/* If failures, remove drive records. */
mdclrerror(&xep);
}
}
static void
char *setname,
)
{
md_drive_desc *p;
int i;
return;
if (MD_MNSET_REC(sr))
i = 0;
else {
/* get thisside */
for (i = 0; i < MD_MAXSIDES; i++) {
continue;
break;
}
if (i == MD_MAXSIDES) {
/* so find the first free slot! */
for (i = 0; i < MD_MAXSIDES; i++) {
break;
}
}
}
/* Add the per side names to the local db */
return;
}
/* Create the drive record */
return;
}
/* Fill in the drive record values */
/* Link the drive records and fill in in-core data */
else
mdclrerror(&xep);
MD_LOCAL_SET, dev);
}
/* Commit all the records atomically */
}
/*
* add 1 or more drive records to a set.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
/* allocate memory */
/* build args */
/* convert v1 args to v2 (revision 1) args */
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_adddrvs_common(
default:
return (FALSE);
}
}
/*
* add 1 or more drive records to a set when importing.
*/
)
{
int err;
case MD_METAD_ARGS_REV_1:
return (FALSE);
}
break;
default:
return (FALSE);
}
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
static void
char *setname,
int node_c,
char **node_v,
int version, /* RPC version of calling routine */
)
{
int i, j;
int nodecnt;
return;
/* Do MN operation if rpc version supports it and if a MN set */
/*
* Verify nodes are in membership list on THIS node.
* Initiating node has verified that nodes are in membership
* list on the initiating node.
* Get membershiplist from API routine. If there's
* an error, fail to add hosts and pass back error.
*/
return;
}
/* Verify that all nodes are in member list */
for (i = 0; i < node_c; i++) {
/*
* If node in list isn't a member of the membership,
* just return error.
*/
return;
}
}
}
for (i = 0; i < node_c; i++) {
/* Do MN operation if rpc version supports it and if a MN set */
/* Create the node record */
!= 0) {
return;
}
while (nl2) {
== 0) {
break;
}
}
/*
* When a node is added to a MN diskset, set the
* nodeid of this node in the md_set structure
* in the kernel.
*/
return;
}
}
/* Link the node records and fill in in-core data */
} else {
for (j = 0; j < MD_MAXSIDES; j++) {
continue;
break;
}
}
}
/* Do MN operation if rpc version supports it and if a MN set */
}
/* Do MN operation if rpc version supports it and if a MN set */
} else {
}
return;
}
}
/*
* add 1 or more hosts to a set.
*/
int version /* RPC version */
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
/* Pass RPC version (METAD_VERSION) to common routine */
}
)
{
case MD_METAD_ARGS_REV_1:
/* Pass RPC version (METAD_VERSION_DEVID) to common routine */
return (mdrpc_addhosts_common(
default:
return (FALSE);
}
}
static void
)
{
int i;
return;
}
NODEV64);
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
i);
}
}
static void
int master_nodeid,
)
{
int nodecnt;
/*
* Validate that nodes in set being created are in the
* membership list on THIS node.
* Initiating node has verified that nodes are in membership
* list on the initiating node.
* Get membershiplist from API routine. If there's
* an error, fail to add set and pass back error.
*/
return;
}
/* Verify that all nodes are in member list */
while (nd) {
/*
* If node in list isn't a member of the membership,
* just return error.
*/
return;
}
}
return;
}
NODEV64);
while (nd) {
/* Create the node record */
/* Frees mnsr and any alloc'd node records */
return;
}
/* Link the node records and fill in in-core data */
}
/*
* For backward compatibility, fill in mynode name
* as the only name in the sr_nodes array. This
* allows the pre-MNdiskset code to see that there
* is a node in this diskset. This will keep the
* pre-MNdiskset code from removing this set.
*/
/*
* When a set is created for the first time, the nodelist
* will contain this node.
* When a node is just being added to a set, the nodelist
* will not contain this node. This node is added to the
* set structure with a later call to addhosts.
*
* So, if the nodelist contains an entry for this node
* then set the nodeid of this node in the md_set kernel
* data structure.
*/
while (nd) {
break;
}
}
if (nd) {
return;
}
}
}
/*
* create a set on a host
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* create the arguments for the symlink() and unlink() calls */
/*
* Since we already verified that the setname was OK, make sure to
* cleanup before proceeding.
*/
return (TRUE);
}
}
/* create the set */
return (TRUE);
/* create the symlink */
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_createset_common(
default:
return (FALSE);
}
}
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* create the arguments for the symlink() and unlink() calls */
/*
* Since we already verified that the setname was OK, make sure to
* cleanup before proceeding.
*/
return (TRUE);
}
}
/* create the set */
return (TRUE);
}
/* create the symlink */
return (TRUE);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_mncreateset_common(
default:
return (FALSE);
}
}
static void
int version, /* RPC version of calling routine */
)
{
int i;
int rb_mode = 0;
return;
return;
/* Do MN operation if rpc version supports it and if a MN set */
/*
* In the multi-node diskset, there are no diskset
* entries in the local set for other nodes, so there's
* nothing to do.
*/
return;
}
return;
}
/* we are supposed to have drives!!!! */
assert(0);
}
rb_mode = 1;
mdclrerror(ep);
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty sides of the diskset */
continue;
/* Got dd, get out of loop */
break;
/* some error occurred, get out of loop */
break;
}
/*
* At this point, we have one of three possibilities:
* 1) dd != NULL (we have found drives using an alternate
* side.)
* 2) dd == NULL (no drives) && mdisok(ep) : assert(0)
* 3) dd == NULL (no drives) && ! mdisok(ep) : return
* error information to caller.
*/
return;
}
/* we are supposed to have drives!!!! */
assert(0);
}
}
/*
* Let's run through each drive descriptor, and delete the
* sidename for all sides that are not in the sr_nodes array.
* We will ignore errors, cause the empty side may not
* have had any names to begin with.
*/
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip existing sides of the diskset */
continue;
/* An empty side, delete the sidename */
return;
}
mdclrerror(ep);
}
}
}
}
/*
* delete 1 or more sidenames per drive desc, from the local namespace
*/
int version /* RPC version */
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
/* Pass RPC version (METAD_VERSION) to common routine */
}
)
{
case MD_METAD_ARGS_REV_1:
/* Pass RPC version (METAD_VERSION_DEVID) to common routine */
return (mdrpc_del_drv_sidenms_common(
default:
return (FALSE);
}
}
static int
)
{
return (-1);
if (MD_MNSET_REC(sr)) {
/*
* Only delete side name entries for this node
* on a multi-node diskset.
*/
while (nr) {
break;
}
}
} else {
}
return (0);
}
static void
char *setname,
)
{
md_drive_desc *p;
int i;
int rb_mode = 0;
int using_devid = 0;
return;
return;
mdclrerror(ep);
/*
* The set record is incomplete, so we need to make note
* here so that we can do some special handling later.
*/
rb_mode = 1;
}
return;
return;
/*
* The system is either all devid or all
* non-devid so we determine this by looking
* at the first item in the list.
*
* For did disks, the dd_dnp->devid is a valid pointer which
* points to a '' string of devid. We need to check this
* before set the using_devid.
*/
(!(MD_MNSET_REC(sr))))
using_devid = 1;
devid_remote = NULL;
using_devid) {
/*
* We have a devid so use it
*/
}
/* check to make sure using_devid agrees with reality... */
/* something went really wrong. Can't process */
return;
}
devid_same = -1;
if (! rb_mode) {
if (devid_remote)
return;
}
} else {
/*
* Handle special case here where sidenames
* from other hosts for this drive may be
* in the local mddb, but there is no
* sidename entry for this host for this drive.
* This could have happened if the node
* panic'd between the 2 operations when
* adding this node to the set.
* So, delete all sidename entries for this
* drive.
*/
if (MD_MNSET_REC(sr)) {
while (nr) {
/* We delete all dr sides */
/* if we do, get out of loop */
break;
/* save error for later */
mdclrerror(ep);
}
} else {
/*
* Handle special case here
* for traditional diskset
*/
for (i = 0; i < MD_MAXSIDES; i++) {
/* We delete all dr sides */
/* if we do, get out of loop */
break;
/* save error for later */
mdclrerror(ep);
}
}
if (devid_remote)
return;
}
if (!using_devid)
mdclrerror(ep);
}
NULL) == 0) {
}
}
/*
* Has the required disk been found - either the devids
* match if devid are being used or the actual name of
* the disk matches.
*/
if ((using_devid && devid_same == 0) ||
(!using_devid &&
if (meta_replicaslice(dn1,
}
else
mdclrerror(&xep);
break;
}
}
if (dr) {
!= 0) {
if (devid_remote)
return;
}
goto out;
}
MD_LOCAL_SET, dev);
continue;
}
if (devid_remote)
}
out:
}
/*
* delete 1 or more drive records from a host.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
/* allocate memory */
/* build args */
/* convert v1 args to v2 (revision 1) args */
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_deldrvs_common(
default:
return (FALSE);
}
}
static void
char *setname,
int node_c,
char **node_v,
int version, /* RPC version of calling routine */
)
{
int i, j;
return;
for (i = 0; i < node_c; i++) {
/* Do MN operation if rpc version supports it and if a MN set */
while (nr) {
(void) mdstealerror(ep,
return;
}
break;
}
}
} else {
for (j = 0; j < MD_MAXSIDES; j++) {
continue;
continue;
break;
}
}
}
/* Do MN operation if rpc version supports it and if a MN set */
} else {
}
return;
}
}
/*
* delete 1 or more a hosts from a set.
*/
int version /* RPC version */
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
/* Pass RPC version (METAD_VERSION) to common routine */
}
)
{
case MD_METAD_ARGS_REV_1:
/* Pass RPC version (METAD_VERSION_DEVID) to common routine */
return (mdrpc_delhosts_common(
default:
return (FALSE);
}
}
/*
* delete a set.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_delset_common(
default:
return (FALSE);
}
}
/*
* return device info
*/
static void
)
{
return;
return;
}
)
{
int slice;
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/*
* fix all the drivenamep's in the mdname_t's to
* point to the right place.
*/
return (TRUE);
}
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
/* allocate memory */
/* convert v1 args to v2 (revision 1) args */
/*
* Fill in the result appropriately.
* Since dev_t's for version 2 are 64-bit,
* we need to convert them to 32-bit for version 1.
*/
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_devinfo_common(
default:
return (FALSE);
}
}
/*
* return device id
*/
static void
)
{
return;
return;
}
)
{
int slice;
int err;
case MD_METAD_ARGS_REV_1:
break;
default:
return (FALSE);
}
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/*
* fix all the drivenamep's in the mdname_t's to
* point to the right place.
*/
return (TRUE);
}
/* doit */
return (TRUE);
}
/*
* This routine should not be called for a multi-node diskset.
*
* The devid support is disabled for MN diskset so this routine
* will not be called if the set is MN diskset. The check has
* been done early in meta_getnextside_devinfo. However this
* routine will be called when the devid support for MN set is
* enabled and check is removed.
*/
)
{
int ret = 0;
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
return (TRUE);
/*
* if we do not have a minor name then look for a character device.
* This is because the caller (checkdrive_onnode) expects a character
* device to be returned. The other client of this interface is
* meta_getnextside_devinfo and this supplies a minor name.
*/
if (minor_name == NULL) {
} else {
&disklist);
}
if (ret != 0) {
return (TRUE);
}
}
}
return (TRUE);
}
/*
* This routine should not be called for a multi-node diskset.
*
* The devid support is disabled for MN diskset so this routine
* will not be called if the set is MN diskset. The check has
* been done early in meta_getnextside_devinfo. However this
* routine will be called when the devid support for MN set is
* enabled and check is removed.
*
* This function will return the device info attempting to use
* both the passed in devid and device name. This is to deal
* with systems that use multi-path disks but not running mpxio.
* In this situation meta_deviceid_to_nmlist will return multiple
* devices. The orig_devname is used to disambiguate.
*
*/
)
{
char *devidstr;
char *orig_devname;
int ret = 0;
int err;
int i;
case MD_METAD_ARGS_REV_1:
break;
default:
return (FALSE);
}
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
return (TRUE);
/*
* if we do not have a minor name then look for a character device.
* This is because the caller (checkdrive_onnode) expects a character
* device to be returned. The other client of this interface is
* meta_getnextside_devinfo and this supplies a minor name.
*/
if (minor_name == NULL) {
} else {
&disklist);
}
if (ret != 0) {
return (TRUE);
}
/* attempt to match to the device name on the originating node */
break;
}
/* if it's not found then use the first disk in the list */
i = 0;
}
}
return (TRUE);
}
static void
{
return;
return;
return;
}
/*
* determine if a device is in use.
*/
)
{
int slice;
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* no drive pointer specified */
return (TRUE);
}
/*
* fix all the drivenamep's in the mdname_t's to
* point to the right place.
*/
return (TRUE);
}
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
/* allocate memory */
/* build args */
/* convert v1 args to v2 (revision 1) args */
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_drvused_common(
default:
return (FALSE);
}
}
/*
* return a set records selected by name or number.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/* Don't have a setno, so we don't check the lock */
return (TRUE);
/* doit */
else
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_getset_common(
default:
return (FALSE);
}
}
/*
* return a MN set record selected by name or number.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/* Don't have a setno, so we don't check the lock */
return (TRUE);
/* doit */
}
return (TRUE);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_mngetset_common(
default:
return (FALSE);
}
}
static void
int master_nodeid,
)
{
return;
return;
if (MD_MNSET_REC(sr)) {
if (master_nodeid != 0) {
/* Use magic to help protect ioctl against attack. */
} else {
sm.c_current_host_master = 0;
}
}
}
out:
}
/*
* set the master and nodeid in node record
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_mnsetmaster_common(
default:
return (FALSE);
}
}
/*
* Join this node to the diskset.
* Pass stale_flag information to snarf_set so that snarf code
* can choose a STALE or non-STALE state when starting the set.
* If master is STALE, any joining node will join a stale set regardless
* of the number of accessible mddbs. Also, if master is at 50%
* accessible replicas and is in the TOOFEW state, don't mark newly
* joining node as STALE; mark it TOOFEW instead.
*/
static void
int flags,
)
{
return;
/*
* Start mddoors daemon here.
* mddoors itself takes care there will be
* only one instance running, so starting it twice won't hurt
*/
/*
* Get latest copy of data. If a drive was just added causing
* nodes to get joined - this drive won't be in the local
* name caches drive list yet.
*/
if (mydd) {
/*
* Causes mddbs to be loaded into the kernel.
* Set the force flag so that replica locations can be loaded
* into the kernel even if a mediator node was unavailable.
* This allows a node to join an MO diskset when there are
* sufficient replicas available, but a mediator node
* in unavailable.
*/
/* If ep isn't set for some reason, set it */
}
return;
}
if (flags & MNSET_IS_STALE)
stale_bool = TRUE;
else
stale_bool = FALSE;
/*
* Snarf the set. No failure has occurred if STALE or
* ACCOK error was set. Otherwise, fail the call setting
* a generic error if no error was already set.
*
* STALE means that set has < 50% mddbs.
* ACCOK means that the mediator provided an extra vote.
*/
return;
/* If snarf failed, but no error set - set it */
return;
}
}
/*
* If node is joining during reconfig cycle, then
* set mddb_parse to be in blocked state so that
* mddb reparse messages are not generated until
* the commd has been resumed later in the reconfig
* cycle.
*/
if (flags & MNSET_IN_RECONFIG) {
"Could not block set %s"),
return;
}
}
/*
* If s_ownset fails and snarf_set succeeded,
* then can steal the ownset failure information
* and store it into ep. If snarf_set failed,
* don't overwrite critical ep information even
* if s_ownset failed.
*/
/*
* If snarf_set succeeded or snarf_set failed
* with MDE_DB_ACCOK (which is set if the
* mediator provided the extra vote) then
* steal the xep failure information and put
* into ep.
*/
}
}
}
}
}
/*
* Have this node join the set.
* This is called when a node has been
* added to a MN diskset that has drives.
* Also, called when a node is an alive
* member of a MN diskset and the first
* drive has been added.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/*
* During reconfig, joinset can happen without
* locking first. Turn off reconfig flag before calling
* joinset.
*/
return (TRUE);
}
/* doit */
return (TRUE);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_joinset_common(
default:
return (FALSE);
}
}
static void
)
{
return;
}
/*
* Have this node withdraw from set.
* In response to a failure that occurred
* on the client after a joinset.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_withdrawset_common(
default:
return (FALSE);
}
}
static mhd_mhiargs_t *
{
return (NULL);
return (mhiargs);
}
/*
* Get the MH timeout values for this set.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_gtimeout_common(
default:
return (FALSE);
}
}
/*
* return the official host name for the callee
*/
/*ARGSUSED*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
}
)
{
}
/*
* return a response
*/
/*ARGSUSED*/
void *args,
md_error_t *ep,
)
{
*ep = mdnullerror;
/* do nothing */
return (TRUE);
}
void *args,
md_error_t *ep,
)
{
}
void *args,
md_error_t *ep,
)
{
}
/*
* determine if the caller owns the set.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
else
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_ownset_common(
default:
return (FALSE);
}
}
static int
{
int rval = 0;
/*
* If lstat() fails with ENOENT, setname is OK, if it
* fails for other than that, we fail the RPC
*/
rval = 1;
goto out;
}
goto out;
}
/*
* If the lstat() succeeded, then we see what type of object
* we are dealing with, if it is a symlink, we do some further
* checking, if it is not a symlink, then we return an
* indication that the set name is NOT acceptable.
*/
goto out;
/*
* We look up the setname to see if there is a set
* with that name, if there is, then we return
* an indication that the set name is NOT acceptable.
*/
goto out;
goto out;
mdclrerror(ep);
rval = 1;
out:
return (rval);
}
/*
* Make sure the name of the set is OK.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_setnameok_common(
default:
return (FALSE);
}
}
/*
* determine if the setnumber we want to share is in use.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
mdclrerror(ep);
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_setnumbusy_common(
default:
return (FALSE);
}
}
static void
int version, /* RPC version of calling routine */
)
{
return;
/* Do MN operation if rpc version supports it and if a MN set */
} else {
}
/*
* Cluster nodename support
* Convert nodename -> nodeid
* Don't do this for MN disksets since we've already stored
* both the nodeid and name.
*/
if ((version == METAD_VERSION) ||
return;
}
/*
* Cluster nodename support
* Convert nodeid -> nodename
* Don't do this for MN disksets since we've already stored
* both the nodeid and name.
*/
if ((version == METAD_VERSION) ||
}
/*
* Set MH ioctl timeout values.
*/
int version /* RPC version */
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
/* Pass RPC version (METAD_VERSION) to common routine */
}
)
{
case MD_METAD_ARGS_REV_1:
/* Pass RPC version (METAD_VERSION_DEVID) to common routine */
return (mdrpc_stimeout_common(
default:
return (FALSE);
}
}
static void
)
{
md_drive_desc *p;
int using_devid = 0;
return;
return;
return;
return;
/*
* The system is either all devid or all
* non-devid so we determine this by looking
* at the first item in the list.
*
* For did disks, the dd_dnp->devid is a valid pointer which
* points to a '' string of devid. We need to check this
* before set the using_devid.
*/
(!(MD_MNSET_REC(sr))))
using_devid = 1;
devid_remote = NULL;
using_devid) {
/*
* We have a devid so use it.
*/
}
/* check to make sure using_devid agrees with reality... */
/* something went really wrong. Can't process */
return;
}
devid_same = -1;
if (devid_remote)
goto out;
}
NULL) == 0) {
}
}
if (using_devid && devid_same == 0)
break;
if (!using_devid &&
break;
}
if (dr) {
/* Adjust the fields in the copy */
}
if (devid_remote)
}
out:
}
/*
* update the database count and size field of drive records.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
/* allocate memory */
/* build args */
/* convert v1 args to v2 (revision 1) args */
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_upd_dr_dbinfo_common(
default:
return (FALSE);
}
}
static void
)
{
md_drive_desc *p;
int using_devid = 0;
return;
return;
return;
return;
/*
* The system is either all devid or all
* non-devid so we determine this by looking
* at the first item in the list.
*
* For did disks, the dd_dnp->devid is a valid pointer which
* points to a '' string of devid. We need to check this
* before set the using_devid.
*/
(!(MD_MNSET_REC(sr))))
using_devid = 1;
devid_remote = NULL;
using_devid) {
/*
* We have a devid so use it.
*/
}
/* check to make sure using_devid agrees with reality... */
/* something went really wrong. Can't process */
return;
}
devid_same = -1;
if (devid_remote)
goto out;
}
&devid_local, NULL) == 0) {
}
}
if (using_devid && devid_same == 0)
break;
if (!using_devid &&
break;
}
if (dr)
if (devid_remote)
}
out:
}
/*
* update the database count and size field of drive records.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
/*
* version 1 of the remote procedure. This procedure is called if the
* client is running in version 1. We first convert version 1 arguments
* into version 2 arguments and then call the common remote procedure.
*/
)
{
/* allocate memory */
/* build args */
/* convert v1 args to v2 (revision 1) args */
return (retval);
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_upd_dr_flags_common(
default:
return (FALSE);
}
}
static void
)
{
return;
}
/*
* update the set record flags
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
}
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_upd_sr_flags_common(
default:
return (FALSE);
}
}
/*
* upd_nr_flags updates the node records stored in this node's local mddb
* given a node desciptor list and an action. upd_nr_flags then commits
* the node records to the local mddb.
*
* nd - A linked list of node descriptors that describes the node records
* in this diskset on which the action applies.
* flag_action: action to be taken on node records that match the nd list.
* flag_action can be:
* MD_NR_JOIN: set OWN flag in node records
* MD_NR_WITHDRAW: reset OWN flag in node records
* MD_NR_OK: reset ADD flags and set OK flag in node records
* MD_NR_SET: set node record flags based on flags stored in nd
*
* Typically, the JOIN, WITHDRAW and OK flag_actions are used when setting
* all nodes in a diskset to JOIN (add first disk to set), WITHDRAW
* (remove last disk from set) or OK (after addition of host to set).
*
* The SET flag_action is typically used when nodelist contains all nodes
* in the diskset, but specific nodes have had flag changes. An example of
*
* Ignore the MD_MN_NODE_RB_JOIN flag if set in node record flag. This
* flag is used by the client to recover in case of failure and should not
* be set in the node record flags.
*/
static void
)
{
return;
return;
if (!(MD_MNSET_REC(sr))) {
return;
}
switch (flag_action) {
case MD_NR_JOIN:
case MD_NR_WITHDRAW:
case MD_NR_SET:
case MD_NR_OK:
case MD_NR_DEL:
break;
default:
return;
}
/* Find matching node record for given node descriptor */
switch (flag_action) {
case MD_NR_JOIN:
break;
case MD_NR_WITHDRAW:
break;
case MD_NR_OK:
~(MD_MN_NODE_ADD | MD_MN_NODE_DEL);
break;
case MD_NR_DEL:
~(MD_MN_NODE_OK | MD_MN_NODE_ADD);
break;
case MD_NR_SET:
/* Do not set RB_JOIN flag */
break;
}
break;
}
}
}
out:
/* Don't increment set genid for node record flag update */
}
/*
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/*
* During reconfig, node record flags can be updated without
* locking first.
*/
return (TRUE);
}
/* doit */
return (TRUE);
}
/*
* update the node records using given flag action.
*/
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_upd_nr_flags_common(
default:
return (FALSE);
}
}
void
{
}
void
{
else
break;
}
}
}
{
return (tskp);
}
{
return (NULL);
}
void
{
return;
}
}
/*
* Unlock the set
*
* To unlock the set, the user must have the correct key, once this is verified
* the set is unlocked and the cached information for the set is flushed.
*/
)
{
int err;
int multi_node = 0;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/*
* Is diskset a MN diskset?
* Don't set error from this check since unlock set can be
* called after a set has been deleted.
*/
if ((MD_MNSET_DESC(sd))) {
multi_node = 1;
}
}
/* Get the set key, if any */
/* The set is locked */
/* Make sure the opener has the right key. */
return (TRUE);
}
/* Unlock the set */
/* Cleanup */
goto out;
}
/*
* It is possible on a MN diskset to attempt to unlock a set that
* is unlocked. This could occur when the metaset or metadb command
* is failing due to another metaset or metadb command running.
* So, print no warning for MN disksets.
*/
if (multi_node == 0) {
md_eprintf("Warning: set unlocked when unlock_set called!\n");
}
out:
/* Flush the set cache */
return (TRUE);
}
)
{
}
)
{
}
/*
* Lock the set
*
* If the user does not hand us a key, then we generate a new key and lock the
* set using this new key that was generated, if the user hands us a key then
* we use the key to lock the set.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/* The set is locked */
/*
* This lock request could be for a new diskset, as
* such metasetnosetname() may not return anything
* useful. Only call it if there is already a key.
*/
!= NULL) {
}
/*
* meta_lock() provides local locking for non-MN
* disksets. The local lock is held before we call
* this RPC function. We should not receive a lock
* request from the host which owns the lock. If we
* do, release the lock.
*/
"Warning: set locked when lock_set called!\n");
md_eprintf("Held lock info:\n");
md_eprintf("\tLock:\n");
md_eprintf("\t\tKey: %d/%d %s\n",
/* Unlock set */
md_eprintf("Released lock held by requesting host\n");
}
}
/* The set is unlocked */
/* If we have been given a key, use it. */
goto out;
}
/* We need to lock it, with a new key */
}
goto out;
}
/*
* If a MN diskset, the lock_set routine is used as a locking
* commands are issued at the same time - one will complete
* and the other command will fail with MDE_DS_NOTNOW_CMD.
*/
goto out;
}
md_eprintf("Warning: set locked when lock_set called!\n");
md_eprintf("Lock info:\n");
md_eprintf("\tLock(svc):\n");
md_eprintf("\t\tKey: %d/%d %s",
md_eprintf("\tLock(cl):\n");
md_eprintf("\t\tKey: %d/%d %s",
/* The set is locked, do we have the key? */
goto out;
}
/*
* The set is locked and we do not have the key, so we set up an error.
*/
out:
/* Flush the set cache */
return (TRUE);
}
)
{
}
)
{
}
static void
char *setname,
int version, /* RPC version of calling routine */
)
{
return;
/* Do MN operation if rpc version supports it and if a MN set */
} else {
}
return;
}
/*
* If a MN disket, send the mediator list to the kernel.
*/
if (MD_MNSET_REC(sr)) {
return;
}
/* Resolve the IP addresses for the host list */
return;
}
/* If node not yet joined to set, failure is ok. */
}
}
}
}
/*
* Update the mediator data in the set record
*/
int version /* RPC version */
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
)
{
/* Pass RPC version (METAD_VERSION) to common routine */
}
)
{
case MD_METAD_ARGS_REV_1:
/* Pass RPC version (METAD_VERSION_DEVID) to common routine */
return (mdrpc_updmeds_common(
default:
return (FALSE);
}
}
/*
* Call routines to suspend, reinit and resume mdcommd.
* Called during metaset and metadb command.
* NOT called during reconfig cycle.
*/
)
{
int err;
int suspend_ret;
case MD_METAD_ARGS_REV_1:
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
switch (args_cc->flag_action) {
case COMMDCTL_SUSPEND:
if (suspend_ret != 0) {
}
break;
case COMMDCTL_RESUME:
}
break;
case COMMDCTL_REINIT:
}
break;
}
return (TRUE);
default:
return (FALSE);
}
}
/*
* Return TRUE if set is stale.
*/
)
{
int err;
(void) memset(&c, 0, sizeof (c));
case MD_METAD_ARGS_REV_1:
c.c_id = 0;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
}
if (c.c_flags & MDDB_C_STALE) {
} else {
}
return (TRUE);
default:
return (FALSE);
}
}
/*
* Clear out all clnt_locks held by all MN disksets.
* This is only used during a reconfig cycle.
*/
/* ARGSUSED */
int
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/*
* Walk through all possible disksets.
* For each MN set, delete all keys associated with that set.
*/
return (TRUE);
}
/* start walking through all possible disksets */
/* No set for this setno - continue */
mdclrerror(ep);
continue;
} else {
"Unable to get set %s information"),
mdclrerror(ep);
continue;
}
}
/* only check multi-node disksets */
mdclrerror(ep);
continue;
}
/* Delete keys associated with rpc.metad clnt_lock */
}
*ep = mdnullerror;
return (TRUE);
}
/*
* Get drive desc on this host for given setno.
* This is only used during a reconfig cycle.
* Returns a drive desc structure for the given mdsetname
* from this host.
*
* Returned drive desc structure is partially filled in with
* the drive name but is not filled in with any other strings
* in the drivename structure.
*/
)
{
int err;
case MD_METAD_ARGS_REV_1:
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/* doit */
return (TRUE);
return (TRUE);
default:
return (FALSE);
}
}
/*
* Update drive records given list from master during reconfig.
* Make this node's list match the master's list which may include
* deleting a drive record that is known by this node and not known
* by the master node.
*
* passed in the dd structure (all genids in this structure
* are the same).
*/
)
{
int err;
int change = 0;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
return (TRUE);
return (TRUE);
if (!(MD_MNSET_REC(sr))) {
return (TRUE);
}
/* Setup genid on set and node records */
if (args->drivedescs) {
change = 1;
}
while (nrp) {
change = 1;
}
}
}
goto out;
/* Found this node's drive rec to match dd */
break;
}
/*
* If drive found in master's list, make slave match master.
* If drive not found in master's list, remove drive.
*/
if (dd) {
change = 1;
}
} else {
/*
* Delete entry from linked list. Need to use
* dr_placeholder so that dr->dr_next points to
* the next drive record in the list.
*/
if (dr_placeholder == NULL) {
Zalloc(sizeof (md_drive_record));
}
change = 1;
dr = dr_placeholder;
}
}
out:
/* If incore records are correct, don't need to write to disk */
if (change) {
/* Don't increment the genid in commitset */
}
if (dr_placeholder != NULL)
return (TRUE);
}
/*
* Version 2 routine to update this node's drive records based on
* list passed in from master node.
*/
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_upd_dr_reconfig_common(
default:
return (FALSE);
}
}
/*
* reset mirror owner for mirrors owned by deleted
* or withdrawn host(s). Hosts being deleted or
* withdrawn are designated by nodeid since host is
* already deleted or withdrawn from set and may not
* be able to translate between a nodename and a nodeid.
* If an error occurs, ep will be set to that error information.
*/
static void
char *setname,
int node_c,
int *node_id, /* Array of node ids */
)
{
int i;
mdnamelist_t *p;
char *miscname;
return;
/* get a list of all the mirrors for current set */
return;
/* for each mirror */
/*
* we can only do these for mirrors so make sure we
* really have a mirror device and not a softpartition
* imitating one. meta_get_mirror_names seems to think
* softparts on top of a mirror are mirrors!
*/
goto out;
continue;
/* get the current owner id */
"MD_MN_GET_MM_OWNER") != 0) {
"Unable to get mirror owner for %s/%s"),
goto out;
}
mdclrerror(ep);
continue;
}
/*
* reset owner only if the current owner is
* in the list of nodes being deleted.
*/
for (i = 0; i < node_c; i++) {
if (meta_mn_change_owner(&ownpar,
MD_MN_MM_ALLOW_CHANGE) == -1) {
"Unable to reset mirror owner for"
goto out;
}
break;
}
}
}
out:
/* cleanup */
}
/*
* Wrapper routine for reset_mirror_owner.
* Called when hosts are deleted or withdrawn
* in order to reset any mirror owners that are needed.
*/
)
{
int err;
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
/* doit */
return (TRUE);
}
/*
* RPC service routine to reset the mirror owner for mirrors owned
* by the given hosts. Typically, the list of given hosts is a list
* of nodes being deleted or withdrawn from a diskset.
* The given hosts are designated by nodeid since host may
* already be deleted or withdrawn from set and may not
* be able to translate between a nodename and a nodeid.
*/
)
{
case MD_METAD_ARGS_REV_1:
return (mdrpc_reset_mirror_owner_common(
rqstp));
default:
return (FALSE);
}
}
/*
* Call routines to suspend and resume I/O for the given diskset(s).
* Called during reconfig cycle.
* Diskset of 0 represents all MN disksets.
*/
)
{
int err;
case MD_METAD_ARGS_REV_1:
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
switch (args_sr->susp_res_cmd) {
case MN_SUSP_IO:
(void) (metaioctl(MD_MN_SUSPEND_SET,
break;
case MN_RES_IO:
(void) (metaioctl(MD_MN_RESUME_SET,
break;
}
return (TRUE);
default:
return (FALSE);
}
}
/*
* Resnarf a set after it has been imported
*/
)
{
int err;
case MD_METAD_ARGS_REV_1:
break;
default:
return (FALSE);
}
return (FALSE);
else if (err != 0)
return (TRUE);
/* do it */
return (FALSE);
return (TRUE);
}
/*
* Creates a resync thread.
* Always returns true.
*/
)
{
int err;
case MD_METAD_ARGS_REV_1:
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
/*
* Need to invoke a metasync on a node newly added to a set.
*/
return (TRUE);
default:
return (FALSE);
}
}
/*
* Updates ABR state for all softpartitions. Calls meta_mn_sp_update_abr(),
* which forks a daemon process to perform this action.
* Always returns true.
*/
)
{
int err;
case MD_METAD_ARGS_REV_1:
/* setup, check permissions */
return (FALSE);
else if (err != 0)
return (TRUE);
return (TRUE);
default:
return (FALSE);
}
}