mdmn_subr.c revision 80148899834a4078a2bd348504aa2d6de9752837
/*
* 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 <unistd.h>
#include <thread.h>
#include "meta.h"
#include "mdmn_subr.h"
/* the wakeup table for the initiator's side */
/* the wakeup table for the master */
/* List of licensed ip addresses */
/* speed up the search for licensed ip addresses */
/*
* If in use, returns TRUE
* Otherwise returns FALSE
*
* Must be called with mdmn_busy_mutex held
*/
{
return (TRUE);
} else {
return (FALSE);
}
}
/*
* If the class was already in use, returns FALSE
* Otherwise returns TRUE
*
* So mdmn_mark_class_busy can be used like
* if (mdmn_mark_class_busy(setno, class) == FALSE)
* failure;
* else
* success;
*
* Must be called with mdmn_busy_mutex held
*/
{
return (FALSE);
} else {
return (TRUE);
}
}
/*
* Always succeeds, thus void.
*
* If this class is marked MDMN_SUSPEND_ALL, we are in the middle of
* draining all classes of this set.
* We have to mark class+1 as MDMN_SUSPEND_ALL too.
* If class+2 wasn't busy, we proceed with class+2, and so on
* If any class is busy, we return.
* Then the drain process will be continued by the mdmn_mark_class_unbusy() of
* that busy class
*/
void
{
/* something changed, inform threads waiting for that */
return;
}
while (++class < MD_MN_NCLASSES) {
== MDMNE_SET_NOT_DRAINED) {
break;
}
}
}
/*
*/
{
return (TRUE);
} else {
return (FALSE);
}
}
/*
* No checking is done here, so routine can be void.
*
* Must be called with mdmn_busy_mutex held
*/
void
{
}
/*
* No checking is done here, so routine can be void.
*
* Must be called with mdmn_busy_mutex held
*/
void
{
}
/*
*
* If called during draining all classes of a set susptype is MDMN_SUSPEND_ALL.
* If only one class is about to be drained susptype is MDMN_SUSPEND_1.
*
* Returns:
* MDMNE_ACK if there are no outstanding messages
* MDMNE_SET_NOT_DRAINED otherwise
*
* Must be called with mdmn_busy_mutex held for this set.
*/
int
{
/*
* We use the mdmn_busy array to mark this set is suspended.
*/
/*
* return MDMNE_SET_NOT_DRAINED, otherwise we return MDMNE_ACK
*/
return (MDMNE_SET_NOT_DRAINED);
}
return (MDMNE_ACK);
}
/*
* previously suspended
*
* If called from mdmn_comm_resume_svc_1 to resume _one_ specific class
* then susptype will be MDMN_SUSPEND_1
* Otherwise to resume all classes of one set,
* then susptype equals (MDMN_SUSPEND_ALL | MDMN_SUSPEND_1)
*
* Always succeeds, thus void.
*
* Must be called with mdmn_busy_mutex held for this set.
*/
void
{
/* simply the reverse operation to mdmn_mark_set_drained() */
}
/*
*
* Must be called with mdmn_busy_mutex held for this set.
*/
{
return (TRUE);
} else {
return (FALSE);
}
}
/*
* Put a result into the wakeup table for the master
* It's ensured that the msg id from the master_table entry and from
* result are matching
*/
void
{
}
void
{
}
void
{
}
{
}
void
{
}
cond_t *
{
}
mutex_t *
{
}
{
}
/* here come the functions dealing with the wakeup table for the initiators */
void
{
/*
* as the point in time where we want to be guaranteed to be woken up
* again, we chose the
* current time + nnodes times the timeout value for the message type
*/
}
/*
* Otherwise return MDMNE_ACK
*/
int
{
return (MDMNE_ACK);
return (MDMNE_CLASS_BUSY);
}
/*
* Remove an entry from the initiator table entirely,
* This must be done with mutex held.
*/
void
{
}
void
{
}
SVCXPRT *
{
}
char *
{
}
mutex_t *
{
}
{
}
extern hrtime_t __savetime;
/*
* Print debug messages to the terminal or to syslog
* commd_debug(MD_MMV_SYSLOG,....) is always printed (and always via syslog),
* even if md_commd_global_verb is zero.
*
* Otherwise the correct bit must be set in the bitmask md_commd_global_verb
*/
void
{
/* Is this a message for syslog? */
if (debug_class == MD_MMV_SYSLOG) {
} else {
/* Is this debug_class set in the global verbosity state? */
if ((md_commd_global_verb & debug_class) == 0) {
return;
}
/* Is our output file already functioning? */
return;
}
/* Are timestamps activated ? */
if (md_commd_global_verb & MD_MMV_TIMESTAMP) {
/* print time since last TRESET in usecs */
}
/* Now print the real message */
}
}
void
{
cnt /= sizeof (unsigned int);
while (cnt--) {
if (cnt % 4)
continue;
}
}
/* debug output: dump a message */
void
{
if (msg->msg_event_size) {
}
}
/* debug output: dump a result structure */
void
{
if (res->mmr_out_size)
if (res->mmr_err_size)
}
/*
* Here we find out, where to store or find the results for a given msg.
*
* Per set we have a pointer to a three dimensional array:
* mct[set] -> mct_mce[NNODES][MD_MN_NCLASSES][MAX_SUBMESSAGES]
* So, for every possible node and for every possible class we can store
* MAX_SUBMESSAGES results.
* the way to find the correct index is
* submessage +
* class * MAX_SUBMESSAGES +
* nodeid * MAX_SUBMESSAGES * MD_MN_NCLASSES.
*
* To find the correct address the index has to be multiplied
* by the size of one entry.
*/
static md_mn_mce_t *
{
int mct_index;
return ((md_mn_mce_t *)MDMN_MCT_ERROR);
}
}
if (submsg == 0) {
} else {
}
/* LINTED Pointer alignment */
/*
* the lint clean version would be:
* return (&(mct[setno]->mct_mce[0][0][0]) + mct_index);
* :-)
*/
}
/*
* mdmn_mark_completion(msg, result, flag)
* Stores the result of this message into the mmaped memory MCT[setno]
* In case the same message comes along a second time we will know that
* this message has already been processed and we can deliver the
* results immediately.
*
* Before a message handler is called, the message in the MCT is flagged
* as currently being processed (flag == MDMN_MCT_IN_PROGRESS).
* This we need so we don't start a second handler for the same message.
*
* After a message handler is completed, this routine is called with
* flag == MDMN_MCT_DONE and the appropriate result that we store in the MCT.
* As MCT[setno] is memory mapped to disks, this information is persistent
* even across a crash of the commd.
* It doesn't have to be persistent across a reboot, though.
*
* Returns MDMN_MCT_DONE in case of success
* Returns MDMN_MCT_ERROR in case of error creating the mct
*/
int
{
return (MDMN_MCT_ERROR);
}
if (flag == MDMN_MCT_IN_PROGRESS) {
goto mmc_out;
}
/*
* In case the message flags indicate that the result should not be
* stored in the MCT, we return a MDMN_MCT_NOT_DONE,
* so the message will be processed at any rate,
* even if we process this message twice.
* this makes sense if the result of the message is a dynamic status
* and might have changed meanwhile.
*/
return (MDMN_MCT_DONE);
}
/* This msg is no longer in progress */
/* if mmr_exitval is zero, we store stdout, otherwise stderr */
if (result->mmr_exitval == 0) {
if (result->mmr_out_size > 0) {
}
} else {
if (result->mmr_err_size > 0) {
}
}
/* now flush this entry to disk */
return (MDMN_MCT_DONE);
}
/*
* mdmn_check_completion(msg, resultp)
* checks if msg has already been processed on this node, and if so copies
* the stored result to resultp.
*
* returns MDMN_MCT_DONE and the result filled out acurately in case the
* msg has already been processed before
* returns MDMN_MCT_NOT_DONE if the message has not been processed before
* returns MDMN_MCT_IN_PROGRESS if the message is currently being processed
* This can only occur on a slave node.
* return MDMN_MCT_ERROR in case of error creating the mct
*/
int
{
return (MDMN_MCT_ERROR); /* what to do in that case ? */
}
/* is the message completed, or in progress? */
return (MDMN_MCT_IN_PROGRESS);
}
/*
* See comment on MD_MSGF_NO_MCT above, if this flag is set
* for a message no result was stored and so the message has
* to be processed no matter if this is the 2nd time then.
*/
return (MDMN_MCT_NOT_DONE);
}
/* Paranoia check: mce_flags must be MDMN_MCT_DONE here */
"mdmn_check_completion: msg not done and not in "
"progress! ID = (%d, 0x%llx-%d)\n",
return (MDMN_MCT_NOT_DONE);
}
/*
* Already processed.
* Copy saved results data;
* return only a pointer to any output.
*/
/*
* if the exit val is zero only stdout was stored (if any)
* otherwise only stderr was stored (if any)
*/
if (result->mmr_exitval == 0) {
if (outsize != 0) {
outsize);
}
} else {
if (errsize != 0) {
errsize);
}
}
"mdmn_check_completion: msg already processed \n");
return (MDMN_MCT_DONE);
}
"mdmn_check_completion: msg not yet processed\n");
return (MDMN_MCT_NOT_DONE);
}
/*
* check_license(rqstp, chknid)
*
* Is this RPC request sent from a licensed host?
*
* If chknid is non-zero, the caller of check_license() knows the ID of
* the sender. Then we check just the one entry of licensed_nodes[]
*
* If chknid is zero, the sender is not known. In that case the sender must be
* the local node.
*
* If the host is licensed, return TRUE, else return FALSE
*/
{
char buf[INET6_ADDRSTRLEN];
caller = (void *)&caller_ipv4;
if (chknid == 0) {
/* check against local node */
return (TRUE);
}
} else {
/* check against one specific node */
return (TRUE);
} else {
"Bad attempt from %x ln[%d]=%x\n",
}
}
caller = (void *)&caller_ipv6;
if (chknid == 0) {
/* check against local node */
if (IN6_IS_ADDR_LOOPBACK(&caller_ipv6)) {
return (TRUE);
}
} else {
/* check against one specific node */
return (TRUE);
}
}
}
/* if we are here, we were contacted by an unlicensed node */
"Bad attempt to contact rpc.mdcommd from %s\n",
caller ?
"unknown");
return (FALSE);
}
/*
* Add a node to the list of licensed nodes.
*
* Only IPv4 is currently supported.
* for IPv6, we need to change md_mnnode_desc.
*/
void
{
char buf[INET6_ADDRSTRLEN];
/*
* If this node is not yet licensed, do it now.
* For now only IPv4 addresses are supported.
*/
/* keep track of the last entry for faster search */
if (nid > maxlicnodes)
maxlicnodes = nid;
}
/* in any case bump up the reference count */
}
/*
* lower the reference count for one node.
* If that drops to zero, remove the node from the list of licensed nodes
*
* Only IPv4 is currently supported.
* for IPv6, we need to change md_mnnode_desc.
*/
void
{
char buf[INET6_ADDRSTRLEN];
/*
* If this was the last reference to that node, it's license expires
* For now only IPv4 addresses are supported.
*/
}
}