/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Metadevice diskset interfaces
*/
#include "meta_set_prv.h"
static int
{
int i, j;
if (*listp) {
for (i = 0; (*listp)[i]; i++)
/* void */;
} else {
i = 0;
}
if ((++i % MALSIZ) == 0) {
(i + MALSIZ) * sizeof (char *));
for (j = i; j < (i + MALSIZ); j++)
}
return (i);
}
static int
{
int i;
if (*listp) {
for (i = 0; (*listp)[i]; i++)
return (1);
} else
return (0);
}
static int
)
{
char *hostname;
char *nodename;
char *nm;
char *cp;
int i, j;
for (i = 0; i < MED_MAX_HOSTS; i++) {
continue;
return (-1);
if (j == 0) {
}
} else {
}
}
}
}
return (0);
}
/*
* Exported Entry Points
*/
int
int node_c,
char **node_v,
)
{
md_h_arr_t t;
char *cp;
int n_c = 0;
int i, j;
int rb_level = 0;
int rval = 0;
int max_meds;
int suspend1_flag = 0;
int lock_flag = 0;
/* Initialize */
(void) memset(&t, '\0', sizeof (t));
mdclrerror(ep);
return (-1);
/* Make sure we own the set */
return (-1);
return (-1);
/*
* The mediator information (which is part of the set record) is
* stored in the local mddbs of each node in the diskset.
* Each node's rpc.metad daemon reads in the set
* records from that node's local mddb and caches them
* internally. Any process needing diskset information contacts its
* local rpc.metad to get this information. Since each node in the
* diskset is independently reading the set information from its local
* mddb, the set records in the local mddbs must stay
* in-sync, so that all nodes have a consistent view of the diskset.
*
* For a multinode diskset, explicitly verify that all nodes in the
* diskset are ALIVE (i.e. are in the API membership list). Otherwise,
* fail this operation since all nodes must be ALIVE in order to add
* the mediator information to the set record in their local mddb.
* If a panic of this node leaves the local mddbs set records
* out-of-sync, the reconfig cycle will fix the local mddbs and
* force them back into synchronization.
*/
if (MD_MNSET_DESC(sd)) {
while (nd) {
return (-1);
}
}
}
/* Parse the command line into a the md_h_arr_t structure */
for (i = 0; i < t.n_cnt; i++) {
j = 0;
while (cp) {
if (j >= MAX_HOST_ADDRS)
j++;
}
}
/* Make a list of nodes to check */
for (i = 0; i < t.n_cnt; i++)
/* Make sure that there are no redundant nodes */
if (rval != 0)
return (rval);
/*
* Lock the set on current set members.
* Set locking done much earlier for MN diskset than for traditional
* diskset since lock_set and SUSPEND are used to protect against
* other metaset commands running on the other nodes.
*/
if (MD_MNSET_DESC(sd)) {
/* Make sure we are blocking all signals */
mdclrerror(&xep);
/* All nodes are guaranteed to be ALIVE */
while (nd) {
rval = -1;
goto out;
}
lock_flag = 1;
}
/*
* Lock out other meta* commands by suspending
* class 1 messages across the diskset.
*/
/* All nodes are guaranteed to be ALIVE */
while (nd) {
MD_MSCF_NO_FLAGS, ep)) {
rval = -1;
goto out;
}
suspend1_flag = 1;
}
}
rval = -1;
goto out;
}
/* Check existing mediators against new, if any */
for (i = 0; i < max_meds; i++)
for (i = 0; i < t.n_cnt; i++) {
rval = -1;
goto out;
}
}
}
rval = -1;
goto out;
}
/* Copy the current mediator list for rollback */
/* Setup the mediator record roll-back structure */
rb_medr.med_rec_fl = 0;
if (MD_MNSET_DESC(sd)) {
/*
* For a MN diskset the mediator is not given a list of
* hosts in the set. Instead a generic name (multiowner) is
* given to the mediator which will allow any node to access
* the mediator data as long as it provides the correct
* setname and set number. In a MN diskset, the mediator
* data is only used when a first node joins the diskset
* and becomes the master of the MN diskset.
*
* The traditional diskset code keeps the host list in
* the mediator record up to date with respect to the host
* list in the traditional diskset. This keeps an unauthorized
* node in the traditional diskset from accessing the data
* in the mediator record and being able to 'take' the
* diskset.
*
* This additional check is needed in the traditional diskset
* since a panic during the metaset command can leave
* the diskset with some nodes thinking that an
* action has occurred and other nodes thinking the opposite.
* A node may have really been removed from a diskset, but
* that node doesn't realize this so this node must be
* blocked from using the mediator data when attempting
* to 'take' the diskset.
* (Traditional diskset code has each node's rpc.metad
* cleaning up from an inconsistent state without any
* knowledge from the other nodes in the diskset).
*
* In the MN diskset, the reconfig steps force a consistent
* state across all nodes in the diskset, so no node
* needs to be blocked from accessing the mediator data.
* This allow the MN diskset to use a common 'nodename'
* in the mediator record. This allows the mediator
* daemon to remain unchanged even though a large number of
* nodes are supported by the MN diskset.
*/
} else {
for (i = 0; i < MD_MAXSIDES; i++)
}
rb_medr.med_rec_foff = 0;
/* Merge new mediators into the set record */
for (i = 0; i < t.n_cnt; i++) {
for (j = 0; j < max_meds; j++) {
continue;
break;
}
}
/*
* Setup the kernel mediator list, which also validates that the
* hosts have valid IP addresses
*/
/* Copy the hostnames */
rval = -1;
goto out;
}
/* Resolve the IP addresses for the host list */
rval = -1;
goto out;
}
/* Bring the mediator record up to date with the set record */
/* END CHECK CODE */
/* Lock the set on current set members */
if (!(MD_MNSET_DESC(sd))) {
/* all signals already blocked for MN disket */
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
rval = -1;
goto out;
}
lock_flag = 1;
}
}
/*
* Add the new mediator information to all hosts in the set.
* For MN diskset, each node sends mediator list to its kernel.
*/
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
goto rollback;
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
goto rollback;
}
}
goto rollback;
}
/* Inform the mediator hosts of the new information */
for (i = 0; i < max_meds; i++) {
continue;
/* medr contains new mediator node list */
goto rollback;
}
/* In MN diskset, mediator list updated in clnt_updmeds call */
if (!(MD_MNSET_DESC(sd))) {
NULL) != 0) {
goto rollback;
}
}
/*
* If only 50% mddbs available, mediator will be
* golden by this ioctl on a traditional diskset.
*
* On a MN disket, this only happens if the mediator
* add operation is executed on the master node.
* If a slave node is adding the mediator, the mediator
* won't be marked golden until the next mddb change.
*/
}
out:
if (suspend1_flag) {
/*
* Unlock diskset by resuming messages across the diskset.
* Just resume all classes so that resume is the same whether
* just one class was locked or all classes were locked.
*/
/* All nodes are guaranteed to be ALIVE */
while (nd) {
if (rval == 0)
rval = -1;
"Unable to resume rpc.mdcommd.\n"));
}
}
}
if (lock_flag) {
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
if (rval == 0)
rval = -1;
}
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
if (rval == 0)
rval = -1;
}
}
}
}
if (MD_MNSET_DESC(sd)) {
/* release signals back to what they were on entry */
mdclrerror(&xep);
} else {
}
return (rval);
/* all signals already blocked for MN disket */
if (!(MD_MNSET_DESC(sd))) {
mdclrerror(&xep);
}
rval = -1;
/*
* level 4
* In MN diskset, mediator list updated in clnt_updmeds call
*/
mdclrerror(&xep);
mdclrerror(&xep);
}
/* level 3 */
if (rb_level > 2) {
for (i = 0; i < max_meds; i++) {
continue;
/*
* rb_medr contains the rollback mediator node list.
* Send the rollback mediator information to the
* new mediator node list. If a node had this RPC
* called, but its node is not in the mediator node
* list, rpc.metamedd will delete the mediator
* record on that node.
*/
mdclrerror(&xep);
}
}
/* level 2 */
if (rb_level > 1) {
}
/* level 1 */
if (rb_level > 0) {
/* Delete mediator information from all hosts in the set */
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
&xep))
mdclrerror(&xep);
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
&xep))
mdclrerror(&xep);
}
}
}
/* level 0 */
if (suspend1_flag) {
/*
* Unlock diskset by resuming messages across the diskset.
* Just resume all classes so that resume is the same whether
* just one class was locked or all classes were locked.
*/
/* All nodes are guaranteed to be ALIVE */
while (nd) {
mdclrerror(&xep);
"Unable to resume rpc.mdcommd.\n"));
}
}
}
if (lock_flag) {
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
mdclrerror(&xep);
}
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
mdclrerror(&xep);
}
}
}
}
/* release signals back to what they were on entry */
mdclrerror(&xep);
if (!(MD_MNSET_DESC(sd))) {
}
return (rval);
}
int
int node_c,
char **node_v,
int forceflg,
)
{
int i, j;
int n_c = 0;
int rb_level = 0;
int rval = 0;
int max_meds;
int suspend1_flag = 0;
int lock_flag = 0;
mdclrerror(ep);
return (-1);
/* Make sure we own the set */
return (-1);
for (i = 0; i < node_c; i++)
return (-1);
return (-1);
/*
* The mediator information (which is part of the set record) is
* stored in the local mddbs of each node in the diskset.
* Each node's rpc.metad daemon reads in the set
* records from that node's local mddb and caches them
* internally. Any process needing diskset information contacts its
* local rpc.metad to get this information. Since each node in the
* diskset is independently reading the set information from its local
* mddb, the set records in the local mddbs must stay
* in-sync, so that all nodes have a consistent view of the diskset.
*
* For a multinode diskset, explicitly verify that all nodes in the
* diskset are ALIVE (i.e. are in the API membership list). Otherwise,
* fail this operation since all nodes must be ALIVE in order to delete
* the mediator information from the set record in their local mddb.
* If a panic of this node leaves the local mddbs set records
* out-of-sync, the reconfig cycle will fix the local mddbs and
* force them back into synchronization.
*/
if (MD_MNSET_DESC(sd)) {
while (nd) {
return (-1);
}
}
}
/* Make a list of nodes to check */
for (i = 0; i < max_meds; i++)
for (i = 0; i < node_c; i++) {
}
}
/* Save a copy of the current mediator information */
/* Setup the mediator record for rollback */
rb_medr.med_rec_fl = 0;
if (MD_MNSET_DESC(sd)) {
/*
* In MN diskset, use a generic nodename, multiowner, in the
* mediator record which allows any node to access mediator
* information. MN diskset reconfig cycle forces consistent
* in the MN diskset. This allows the relaxation of
* node name checking in rpc.metamedd for MN disksets.
*
* In the traditional diskset, only a node that is in the
* mediator record's diskset nodelist can access mediator
* data.
*/
} else {
for (i = 0; i < MD_MAXSIDES; i++)
}
rb_medr.med_rec_foff = 0;
/* Delete the mediators requested from the set */
for (i = 0; i < node_c; i++) {
for (j = 0; j < max_meds; j++) {
continue;
continue;
sizeof (md_h_t));
break;
}
}
/* END CHECK CODE */
/* Lock the set on current set members */
if (MD_MNSET_DESC(sd)) {
/* Make sure we are blocking all signals */
mdclrerror(&xep);
/*
* Lock the set on current set members.
* lock_set and SUSPEND are used to protect against
* other metaset commands running on the other nodes.
*/
while (nd) {
/* All nodes are guaranteed to be ALIVE */
nd->nd_nodename) != 0) {
mdclrerror(ep);
continue;
}
rval = -1;
goto out;
}
lock_flag = 1;
}
/*
* Lock out other meta* commands by suspending
* class 1 messages across the diskset.
*/
/* All nodes are guaranteed to be ALIVE */
while (nd) {
MD_MSCF_NO_FLAGS, ep)) {
rval = -1;
goto out;
}
suspend1_flag = 1;
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
if (forceflg &&
mdclrerror(ep);
continue;
}
rval = -1;
goto out;
}
lock_flag = 1;
}
}
/* Update the mediator information on all hosts in the set */
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
ep)) {
nd->nd_nodename) != 0) {
mdclrerror(ep);
continue;
}
goto rollback;
}
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
ep)) {
mdclrerror(ep);
continue;
}
goto rollback;
}
}
}
goto rollback;
}
/*
* Set up the parameters to the call to update the
* kernel mediator list
*/
goto rollback;
/* Resolve the IP addresses for the host list */
goto rollback;
goto rollback;
}
}
/* Inform the mediator hosts of the new status */
for (i = 0; i < max_meds; i++) {
continue;
/*
* medr contains the new mediator node list.
* Send the new mediator information to the
* new mediator node list. If a node had this RPC
* called, but its node is no longer in the new mediator
* node list, rpc.metamedd will delete the mediator
* record on that node.
*/
mdclrerror(ep);
continue;
}
goto rollback;
}
}
out:
if (dd)
if (suspend1_flag) {
/*
* Unlock diskset by resuming messages across the diskset.
* Just resume all classes so that resume is the same whether
* just one class was locked or all classes were locked.
*/
/* All nodes are guaranteed to be ALIVE */
while (nd) {
if (rval == 0)
rval = -1;
"Unable to resume rpc.mdcommd.\n"));
}
}
}
if (lock_flag) {
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
if (forceflg &&
nd->nd_nodename) != 0) {
mdclrerror(ep);
continue;
}
if (rval == 0)
rval = -1;
}
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
if (forceflg &&
mdclrerror(ep);
continue;
}
if (rval == 0)
rval = -1;
}
}
}
}
if (MD_MNSET_DESC(sd)) {
/* release signals back to what they were on entry */
mdclrerror(&xep);
} else {
}
return (rval);
/* all signals already blocked for MN disket */
if (!(MD_MNSET_DESC(sd))) {
mdclrerror(&xep);
}
rval = -1;
/* level 4 */
if (rb_level > 4) {
for (i = 0; i < max_meds; i++) {
continue;
/*
* rb_medr contains the rollback mediator node list.
* Send the rollback mediator information to the
* new mediator node list. This will recreate the
* mediator record on all nodes where the mediator
* record had been removed.
*/
&xep))
mdclrerror(&xep);
}
}
/* level 3 */
mdclrerror(&xep);
mdclrerror(&xep);
}
/* level 2 */
if (rb_level > 1) {
}
/* level 1 */
if (rb_level > 0) {
/* Delete mediator information from all hosts in the set */
if (MD_MNSET_DESC(sd)) {
while (nd) {
/* All nodes are guaranteed to be ALIVE */
&xep))
mdclrerror(&xep);
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
&xep))
mdclrerror(&xep);
}
}
}
/* level 0 */
/* Unlock the set */
/* Don't test lock flag since guaranteed to be set if in rollback */
if (MD_MNSET_DESC(sd)) {
/*
* Unlock diskset by resuming messages across the diskset.
* Just resume all classes so that resume is the same whether
* just one class was locked or all classes were locked.
*/
if (suspend1_flag) {
/* All nodes are guaranteed to be ALIVE */
while (nd) {
MD_MSCF_NO_FLAGS, &xep)) {
"Unable to resume rpc.mdcommd.\n"));
mdclrerror(&xep);
}
}
}
/* All nodes are guaranteed to be ALIVE */
while (nd) {
mdclrerror(&xep);
}
} else {
for (i = 0; i < MD_MAXSIDES; i++) {
/* Skip empty slots */
continue;
mdclrerror(&xep);
}
}
/* release signals back to what they were on entry */
mdclrerror(&xep);
if (!(MD_MNSET_DESC(sd))) {
}
return (rval);
}