Linux Archive

Linux Archive (http://www.linux-archive.org/)
-   Cluster Development (http://www.linux-archive.org/cluster-development/)
-   -   Cluster Project branch, master, updated. gfs-kernel_0_1_22-196-g07e949f (http://www.linux-archive.org/cluster-development/74477-cluster-project-branch-master-updated-gfs-kernel_0_1_22-196-g07e949f.html)

04-22-2008 09:55 PM

Cluster Project branch, master, updated. gfs-kernel_0_1_22-196-g07e949f
 
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Cluster Project".

http://sources.redhat.com/git/gitweb.cgi?p=cluster.git;a=commitdiff;h=07e949fa5b c4eef61f16974bf1cc5a5adb9568a4

The branch, master has been updated
via 07e949fa5bc4eef61f16974bf1cc5a5adb9568a4 (commit)
from 0b3fc5e8a21cc8e2011f513892c9e65eb399e9bb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 07e949fa5bc4eef61f16974bf1cc5a5adb9568a4
Author: David Teigland <teigland@redhat.com>
Date: Wed Apr 16 12:55:59 2008 -0500

fenced: new version

In the same theme as the new version of dlm_controld.
- uses libcpg directly without libgroup (use the -g0 option)
- runs in backward compat mode by default, using libgroup to interact
with old groupd/fenced (-g1 option)
- move code that runs agents (agent.c) into libfence

Signed-off-by: David Teigland <teigland@redhat.com>

-----------------------------------------------------------------------

Summary of changes:
fence/fence_node/Makefile | 15 +-
fence/fence_node/fence_node.c | 15 +-
fence/fenced/Makefile | 12 +-
fence/fenced/config.c | 140 ++++
fence/fenced/cpg.c | 1175 +++++++++++++++++++++++++++++++++
fence/fenced/fd.h | 294 +++++---
fence/fenced/group.c | 285 +++++++-
fence/fenced/main.c | 780 +++++++++++-----------
fence/fenced/member_cman.c | 133 ++---
fence/fenced/recover.c | 328 ++--------
{gfs => fence}/include/linux_endian.h | 0
fence/include/list.h | 11 +
{cman => fence}/lib/Makefile | 24 +-
fence/{fenced => lib}/agent.c | 40 +-
fence/lib/libfence.h | 36 +
group/dlm_controld/main.c | 2 +-
16 files changed, 2310 insertions(+), 980 deletions(-)
create mode 100644 fence/fenced/config.c
create mode 100644 fence/fenced/cpg.c
copy {gfs => fence}/include/linux_endian.h (100%)
copy {cman => fence}/lib/Makefile (67%)
rename fence/{fenced => lib}/agent.c (89%)
create mode 100644 fence/lib/libfence.h

diff --git a/fence/fence_node/Makefile b/fence/fence_node/Makefile
index 3ac1092..b9c96c4 100644
--- a/fence/fence_node/Makefile
+++ b/fence/fence_node/Makefile
@@ -2,7 +2,7 @@
################################################## #############################
##
## Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-## Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+## Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
##
## This copyrighted material is made available to anyone wishing to use,
## modify, copy, or redistribute it subject to the terms and conditions
@@ -15,7 +15,7 @@ TARGET = fence_node

SBINDIRT=$(TARGET)

-all: depends ${TARGET}
+all: ${TARGET}

include ../../make/defines.mk
include $(OBJDIR)/make/cobj.mk
@@ -23,23 +23,20 @@ include $(OBJDIR)/make/clean.mk
include $(OBJDIR)/make/install.mk
include $(OBJDIR)/make/uninstall.mk

-OBJS= ../fenced/agent.o
- fence_node.o
+OBJS= fence_node.o

CFLAGS += -D_FILE_OFFSET_BITS=64

-CFLAGS += -I${ccsincdir} -I${cmanincdir}
+CFLAGS += -I${ccsincdir} -I../lib
CFLAGS += -I../include
CFLAGS += -I${incdir}

-LDFLAGS += -L${ccslibdir} -L${cmanlibdir} -lccs -lcman
+LDFLAGS += -L${ccslibdir} -lccs
+LDFLAGS += -L../lib -lfence

${TARGET}: ${OBJS}
$(CC) -o $@ $^ $(LDFLAGS)

-depends:
- $(MAKE) -C ../fenced agent.o
-
clean: generalclean

-include $(OBJS:.o=.d)
diff --git a/fence/fence_node/fence_node.c b/fence/fence_node/fence_node.c
index 65d1e90..ad1234c 100644
--- a/fence/fence_node/fence_node.c
+++ b/fence/fence_node/fence_node.c
@@ -2,7 +2,7 @@
************************************************** *****************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -17,9 +17,10 @@
#include <string.h>
#include <syslog.h>

+#include "libfence.h"
#include "copyright.cf"

-#define OPTION_STRING ("hOuV")
+#define OPTION_STRING ("huV")

#define die(fmt, args...)
do
@@ -31,9 +32,6 @@ do
while (0)

static char *prog_name;
-static int force = 0;
-
-int dispatch_fence_agent(char *victim, int force);

static void print_usage(void)
{
@@ -44,7 +42,6 @@ static void print_usage(void)
printf("Options:
");
printf("
");
printf(" -h Print this help, then exit
");
- printf(" -O Force connection to CCS
");
printf(" -V Print program version information, then exit
");
printf("
");
}
@@ -66,10 +63,6 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
break;

- case 'O':
- force = 1;
- break;
-
case 'V':
printf("%s %s (built %s %s)
", prog_name,
RELEASE_VERSION, __DATE__, __TIME__);
@@ -105,7 +98,7 @@ int main(int argc, char *argv[])

openlog("fence_node", LOG_PID, LOG_USER);

- error = dispatch_fence_agent(victim, force);
+ error = fence_node(victim);

if (error) {
syslog(LOG_ERR, "Fence of "%s" was unsuccessful
", victim);
diff --git a/fence/fenced/Makefile b/fence/fenced/Makefile
index e9e0f54..555b430 100644
--- a/fence/fenced/Makefile
+++ b/fence/fenced/Makefile
@@ -23,18 +23,20 @@ include $(OBJDIR)/make/clean.mk
include $(OBJDIR)/make/install.mk
include $(OBJDIR)/make/uninstall.mk

-OBJS= main.o
- recover.o
+OBJS= config.o
+ cpg.o
group.o
+ main.o
member_cman.o
- agent.o
+ recover.o

CFLAGS += -D_FILE_OFFSET_BITS=64
-CFLAGS += -I${ccsincdir} -I${cmanincdir}
+CFLAGS += -I${ccsincdir} -I${cmanincdir} -I${openaisincdir}
CFLAGS += -I$(S) -I$(S)/../include -I$(SRCDIR)/group/lib
CFLAGS += -I${incdir}

-LDFLAGS += -L${ccslibdir} -L${cmanlibdir} -lccs -lcman
+LDFLAGS += -L${ccslibdir} -L${cmanlibdir} -L${openaislibdir} -lccs -lcman -lcpg
+LDFLAGS += -L../lib -lfence
LDFLAGS += -L../../group/lib -l group


diff --git a/fence/fenced/config.c b/fence/fenced/config.c
new file mode 100644
index 0000000..85f0252
--- /dev/null
+++ b/fence/fenced/config.c
@@ -0,0 +1,140 @@
+/************************************************** ****************************
+************************************************* ******************************
+**
+** Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+************************************************* ******************************
+************************************************* *****************************/
+
+#include "fd.h"
+#include "ccs.h"
+
+static int open_ccs(void)
+{
+ int i = 0, cd;
+
+ while ((cd = ccs_connect()) < 0) {
+ sleep(1);
+ if (++i > 9 && !(i % 10))
+ log_error("connect to ccs error %d, "
+ "check ccsd or cluster status", cd);
+ }
+ return cd;
+}
+
+static void read_ccs_int(int cd, char *path, int *config_val)
+{
+ char *str;
+ int val;
+ int error;
+
+ error = ccs_get(cd, path, &str);
+ if (error || !str)
+ return;
+
+ val = atoi(str);
+
+ if (val < 0) {
+ log_error("ignore invalid value %d for %s", val, path);
+ return;
+ }
+
+ *config_val = val;
+ log_debug("%s is %u", path, val);
+ free(str);
+}
+
+#define OUR_NAME_PATH "/cluster/clusternodes/clusternode[@name="%s"]/@name"
+#define GROUPD_COMPAT_PATH "/cluster/fence_daemon/@groupd_compat"
+#define CLEAN_START_PATH "/cluster/fence_daemon/@clean_start"
+#define POST_JOIN_DELAY_PATH "/cluster/fence_daemon/@post_join_delay"
+#define POST_FAIL_DELAY_PATH "/cluster/fence_daemon/@post_fail_delay"
+#define OVERRIDE_PATH_PATH "/cluster/fence_daemon/@override_path"
+#define OVERRIDE_TIME_PATH "/cluster/fence_daemon/@override_time"
+
+int read_ccs(struct fd *fd)
+{
+ char path[256];
+ char *str;
+ int error, cd, i = 0, count = 0;
+
+ cd = open_ccs();
+ if (cd < 0)
+ return cd;
+
+ /* Our own nodename must be in cluster.conf before we're allowed to
+ join the fence domain and then mount gfs; other nodes need this to
+ fence us. */
+
+ str = NULL;
+ memset(path, 0, 256);
+ snprintf(path, 256, OUR_NAME_PATH, our_name);
+
+ error = ccs_get(cd, path, &str);
+ if (error || !str) {
+ log_error("local cman node name "%s" not found in the "
+ "configuration", our_name);
+ return error;
+ }
+ if (str)
+ free(str);
+
+ /* The comline config options are initially set to the defaults,
+ then options are read from the command line to override the
+ defaults, for options not set on command line, we look for
+ values set in cluster.conf. */
+
+ if (!comline.groupd_compat_opt)
+ read_ccs_int(cd, GROUPD_COMPAT_PATH, &comline.groupd_compat);
+ if (!comline.clean_start_opt)
+ read_ccs_int(cd, CLEAN_START_PATH, &comline.clean_start);
+ if (!comline.post_join_delay_opt)
+ read_ccs_int(cd, POST_JOIN_DELAY_PATH, &comline.post_join_delay);
+ if (!comline.post_fail_delay_opt)
+ read_ccs_int(cd, POST_FAIL_DELAY_PATH, &comline.post_fail_delay);
+ if (!comline.override_time_opt)
+ read_ccs_int(cd, OVERRIDE_TIME_PATH, &comline.override_time);
+
+ if (!comline.override_path_opt) {
+ str = NULL;
+ memset(path, 0, 256);
+ sprintf(path, OVERRIDE_PATH_PATH);
+
+ error = ccs_get(cd, path, &str);
+ if (!error && str) {
+ free(comline.override_path);
+ comline.override_path = strdup(str);
+ }
+ if (str)
+ free(str);
+ }
+
+ if (comline.clean_start) {
+ log_debug("clean start, skipping initial nodes");
+ goto out;
+ }
+
+ for (i = 1; ; i++) {
+ str = NULL;
+ memset(path, 0, 256);
+ sprintf(path, "/cluster/clusternodes/clusternode[%d]/@nodeid", i);
+
+ error = ccs_get(cd, path, &str);
+ if (error || !str)
+ break;
+
+ add_complete_node(fd, atoi(str));
+ free(str);
+ count++;
+ }
+
+ log_debug("added %d nodes from ccs", count);
+ out:
+ ccs_disconnect(cd);
+ return 0;
+}
+
diff --git a/fence/fenced/cpg.c b/fence/fenced/cpg.c
new file mode 100644
index 0000000..2b6933b
--- /dev/null
+++ b/fence/fenced/cpg.c
@@ -0,0 +1,1175 @@
+/************************************************** ****************************
+************************************************* ******************************
+**
+** Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+************************************************* ******************************
+************************************************* *****************************/
+
+#include "fd.h"
+
+static unsigned int protocol_active[3] = {1, 0, 0};
+
+struct member {
+ struct list_head list;
+ int nodeid;
+ int start; /* 1 if we received a start message for this change */
+ int added; /* 1 if added by this change */
+ int failed; /* 1 if failed in this change */
+ int disallowed;
+ uint32_t start_flags;
+};
+
+static char *msg_name(int type)
+{
+ switch (type) {
+ case FD_MSG_START:
+ return "start";
+ case FD_MSG_VICTIM_DONE:
+ return "victim_done";
+ case FD_MSG_EXTERNAL:
+ return "external";
+ default:
+ return "unknown";
+ }
+}
+
+static char *str_nums(int *nums, int n_ints)
+{
+ static char buf[128];
+ int i, len, ret, pos = 0;
+
+ len = sizeof(buf);
+ memset(buf, 0, len);
+
+ for (i = 0; i < n_ints; i++) {
+ ret = snprintf(buf + pos, len - pos, "%d ",
+ le32_to_cpu(nums[i]));
+ if (ret >= len - pos)
+ break;
+ pos += ret;
+ }
+
+ return buf;
+}
+
+static int _send_message(cpg_handle_t h, void *buf, int len, int type)
+{
+ struct iovec iov;
+ cpg_error_t error;
+ int retries = 0;
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ retry:
+ error = cpg_mcast_joined(h, CPG_TYPE_AGREED, &iov, 1);
+ if (error == CPG_ERR_TRY_AGAIN) {
+ retries++;
+ usleep(1000);
+ if (!(retries % 100))
+ log_error("cpg_mcast_joined retry %d %s",
+ retries, msg_name(type));
+ goto retry;
+ }
+ if (error != CPG_OK) {
+ log_error("cpg_mcast_joined error %d handle %llx %s",
+ error, (unsigned long long)h, msg_name(type));
+ return -1;
+ }
+
+ if (retries)
+ log_debug("cpg_mcast_joined retried %d %s",
+ retries, msg_name(type));
+
+ return 0;
+}
+
+/* header fields caller needs to set: type, to_nodeid, flags, msgdata */
+
+static void fd_send_message(struct fd *fd, char *buf, int len)
+{
+ struct fd_header *hd = (struct fd_header *) buf;
+ int type = hd->type;
+
+ hd->version[0] = cpu_to_le16(protocol_active[0]);
+ hd->version[1] = cpu_to_le16(protocol_active[1]);
+ hd->version[2] = cpu_to_le16(protocol_active[2]);
+ hd->type = cpu_to_le16(hd->type);
+ hd->nodeid = cpu_to_le32(our_nodeid);
+ hd->to_nodeid = cpu_to_le32(hd->to_nodeid);
+ hd->flags = cpu_to_le32(hd->flags);
+ hd->msgdata = cpu_to_le32(hd->msgdata);
+
+ _send_message(fd->cpg_handle, buf, len, type);
+}
+
+static struct member *find_memb(struct change *cg, int nodeid)
+{
+ struct member *memb;
+
+ list_for_each_entry(memb, &cg->members, list) {
+ if (memb->nodeid == nodeid)
+ return memb;
+ }
+ return NULL;
+}
+
+static struct fd *find_fd_handle(cpg_handle_t h)
+{
+ struct fd *fd;
+
+ list_for_each_entry(fd, &domains, list) {
+ if (fd->cpg_handle == h)
+ return fd;
+ }
+ return NULL;
+}
+
+static struct fd *find_fd_ci(int ci)
+{
+ struct fd *fd;
+
+ list_for_each_entry(fd, &domains, list) {
+ if (fd->cpg_client == ci)
+ return fd;
+ }
+ return NULL;
+}
+
+void free_cg(struct change *cg)
+{
+ struct member *memb, *safe;
+
+ list_for_each_entry_safe(memb, safe, &cg->members, list) {
+ list_del(&memb->list);
+ free(memb);
+ }
+ list_for_each_entry_safe(memb, safe, &cg->removed, list) {
+ list_del(&memb->list);
+ free(memb);
+ }
+ free(cg);
+}
+
+static struct node_history *get_node_history(struct fd *fd, int nodeid)
+{
+ struct node_history *node;
+
+ list_for_each_entry(node, &fd->node_history, list) {
+ if (node->nodeid == nodeid)
+ return node;
+ }
+ return NULL;
+}
+
+static void node_history_init(struct fd *fd, int nodeid)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (node)
+ return;
+
+ node = malloc(sizeof(struct node_history));
+ if (!node)
+ return;
+ memset(node, 0, sizeof(struct node_history));
+
+ node->nodeid = nodeid;
+ list_add_tail(&node->list, &fd->node_history);
+}
+
+static void node_history_start(struct fd *fd, int nodeid)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (!node) {
+ log_error("node_history_start no nodeid %d", nodeid);
+ return;
+ }
+
+ node->add_time = time(NULL);
+}
+
+static void node_history_left(struct fd *fd, int nodeid)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (!node) {
+ log_error("node_history_left no nodeid %d", nodeid);
+ return;
+ }
+
+ node->left_time = time(NULL);
+}
+
+static void node_history_fail(struct fd *fd, int nodeid)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (!node) {
+ log_error("node_history_fail no nodeid %d", nodeid);
+ return;
+ }
+
+ node->fail_time = time(NULL);
+
+ node->check_quorum = 1;
+}
+
+/* The master node updates this info when it fences the victim, the other
+ domain members update it when they receive the status message from the
+ master. */
+
+void node_history_fence(struct fd *fd, int nodeid, int master, int how)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (!node) {
+ log_error("node_history_fence no nodeid %d", nodeid);
+ return;
+ }
+
+ node->fence_time = time(NULL);
+ node->fence_master = master;
+ node->fence_how = how;
+}
+
+/* When the fence_node command is run on a machine, it will first call
+ libfence:fence_node(victim) to do the fencing. Afterward, it should call
+ libfenced:fence_external(victim) to tell fenced what it's done, so fenced
+ can avoid fencing the node a second time. This will result in a message
+ being sent to all domain members which will update their node_history entry
+ for the victim. The recover.c:fence_victims() code can check whether
+ a victim has been externally fenced since the last add_time, and if so
+ skip the fencing. This won't always work perfectly; a node might in some
+ circumstances be fenced a second time by fenced. */
+
+static void node_history_fence_external(struct fd *fd, int nodeid, int from)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (!node) {
+ log_error("node_history_fence_external no nodeid %d", nodeid);
+ return;
+ }
+
+ node->fence_external_time = time(NULL);
+ node->fence_external_node = from;
+}
+
+/* call this from libfenced:fenced_external() */
+
+void send_external(struct fd *fd, int victim)
+{
+ struct fd_header *hd;
+ char *buf;
+ int len;
+
+ len = sizeof(struct fd_header);
+
+ buf = malloc(len);
+ if (!buf) {
+ return;
+ }
+ memset(buf, 0, len);
+
+ hd = (struct fd_header *)buf;
+ hd->type = FD_MSG_EXTERNAL;
+ hd->msgdata = victim;
+
+ log_debug("send_external %u", victim);
+
+ fd_send_message(fd, buf, len);
+
+ free(buf);
+}
+
+/* now, if the victim dies and the fence domain sees it fail,
+ it will be added as an fd victim, but fence_victims() will
+ call is_fenced_external() which will see that it's already
+ fenced and bypass fencing it again */
+
+static void receive_external(struct fd *fd, struct fd_header *hd, int len)
+{
+ log_debug("receive_external from %d len %d victim %d",
+ hd->nodeid, len, hd->msgdata);
+
+ node_history_fence_external(fd, hd->msgdata, hd->nodeid);
+}
+
+int is_fenced_external(struct fd *fd, int nodeid)
+{
+ struct node_history *node;
+
+ node = get_node_history(fd, nodeid);
+ if (!node) {
+ log_error("is_fenced_external no nodeid %d", nodeid);
+ return 0;
+ }
+
+ if (node->fence_external_time > node->add_time)
+ return 1;
+ return 0;
+}
+
+/* completed victim must be removed from victims list before calling this
+ because we count the number of entries on the victims list for remaining */
+
+void send_victim_done(struct fd *fd, int victim, int how)
+{
+ struct change *cg = list_first_entry(&fd->changes, struct change, list);
+ struct fd_header *hd;
+ int n_ints, len, *p;
+ int remaining = list_count(&fd->victims);
+ char *buf;
+
+ n_ints = 3;
+ len = sizeof(struct fd_header) + (n_ints * sizeof(int));
+
+ buf = malloc(len);
+ if (!buf) {
+ return;
+ }
+ memset(buf, 0, len);
+
+ hd = (struct fd_header *)buf;
+ hd->type = FD_MSG_VICTIM_DONE;
+ hd->msgdata = cg->seq;
+
+ if (fd->init_complete)
+ hd->flags |= FD_MFLG_COMPLETE;
+
+ p = (int *)(buf + sizeof(struct fd_header));
+
+ p[0] = cpu_to_le32(victim);
+ p[1] = cpu_to_le32(how);
+ p[2] = cpu_to_le32(remaining);
+
+ log_debug("send_victim_done %u flags %x victim %d how %d remaining %d",
+ cg->seq, hd->flags, victim, how, remaining);
+
+ fd_send_message(fd, buf, len);
+
+ free(buf);
+}
+
+static void receive_victim_done(struct fd *fd, struct fd_header *hd, int len)
+{
+ struct node *node, *safe;
+ uint32_t seq = hd->msgdata;
+ int victim, how, remaining, found;
+ int *nums;
+
+ log_debug("receive_victim_done %d:%u flags %x len %d", hd->nodeid, seq,
+ hd->flags, len);
+
+ /* check that hd->nodeids is fd->master ? */
+
+ nums = (int *)((char *)hd + sizeof(struct fd_header));
+
+ victim = le32_to_cpu(nums[0]);
+ how = le32_to_cpu(nums[1]);
+ remaining = le32_to_cpu(nums[2]);
+
+ /* I don't think there's any problem with the master removing the
+ victim when it's done instead of waiting to remove it when it
+ receives its own victim_done message, like the other nodes do */
+
+ if (hd->nodeid == our_nodeid)
+ goto out;
+
+ /* if a domain membership change involves no victims, the master sends
+ a victim_done message with victim nodeid -1 and remaining 0; new nodes
+ are interested in seeing the remaining 0 so they can clear their
+ init_victims */
+
+ if (victim == -1)
+ goto out;
+
+ found = 0;
+
+ list_for_each_entry(node, &fd->victims, list) {
+ if (node->nodeid == victim) {
+ log_debug("receive_victim_done remove %d how %d rem %d",
+ victim, how, remaining);
+ node_history_fence(fd, victim, hd->nodeid, how);
+ list_del(&node->list);
+ free(node);
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ log_error("receive_victim_done victim %d not found from %d",
+ victim, hd->nodeid);
+
+ out:
+ if (!fd->init_complete && !remaining) {
+ log_debug("receive_victim_done init_complete");
+ fd->init_complete = 1;
+
+ /* we may have victims from init which we can clear now */
+ list_for_each_entry_safe(node, safe, &fd->victims, list) {
+ log_debug("receive_victim_done clear victim %d init %d",
+ node->nodeid, node->init_victim);
+ list_del(&node->list);
+ free(node);
+ }
+ }
+}
+
+static int check_quorum_done(struct fd *fd)
+{
+ struct node_history *node;
+ int wait_count = 0;
+
+ if (!cman_quorate) {
+ log_debug("check_quorum %d", cman_quorate);
+ return 0;
+ }
+
+ list_for_each_entry(node, &fd->node_history, list) {
+ if (!node->check_quorum)
+ continue;
+
+ if (!is_cman_member(node->nodeid)) {
+ node->check_quorum = 0;
+ } else {
+ log_debug("check_quorum %d is_cman_member",
+ node->nodeid);
+ wait_count++;
+ }
+ }
+
+ if (wait_count)
+ return 0;
+
+ log_debug("check_quorum done");
+ return 1;
+}
+
+static int wait_conditions_done(struct fd *fd)
+{
+ if (!check_quorum_done(fd))
+ return 0;
+ return 1;
+}
+
+static int wait_messages_done(struct fd *fd)
+{
+ struct change *cg = list_first_entry(&fd->changes, struct change, list);
+ struct member *memb;
+ int need = 0, total = 0;
+
+ list_for_each_entry(memb, &cg->members, list) {
+ if (!memb->start)
+ need++;
+ total++;
+ }
+
+ if (need) {
+ log_debug("wait_messages_done need %d of %d", need, total);
+ return 0;
+ }
+
+ log_debug("wait_messages_done got all %d", total);
+ return 1;
+}
+
+static void cleanup_changes(struct fd *fd)
+{
+ struct change *cg = list_first_entry(&fd->changes, struct change, list);
+ struct change *safe;
+
+ list_del(&cg->list);
+ if (fd->started_change)
+ free_cg(fd->started_change);
+ fd->started_change = cg;
+
+ list_for_each_entry_safe(cg, safe, &fd->changes, list) {
+ list_del(&cg->list);
+ free_cg(cg);
+ }
+}
+
+static void set_master(struct fd *fd)
+{
+ struct change *cg = list_first_entry(&fd->changes, struct change, list);
+ struct member *memb;
+ int low = 0, complete = 0;
+
+ list_for_each_entry(memb, &cg->members, list) {
+ if (!low || memb->nodeid < low)
+ low = memb->nodeid;
+
+ if (!(memb->start_flags & FD_MFLG_COMPLETE))
+ continue;
+
+ if (!complete || memb->nodeid < complete)
+ complete = memb->nodeid;
+ }
+
+ log_debug("set_master from %d to %s node %d", fd->master,
+ complete ? "complete" : "low",
+ complete ? complete : low);
+
+ fd->master = complete ? complete : low;
+}
+
+/* do the change details in the message match the details of the given change */
+
+static int match_change(struct fd *fd, struct change *cg,
+ struct fd_header *hd, int len)
+{
+ struct member *memb;
+ int member_count, joined_count, remove_count, failed_count;
+ int i, n_ints, *nums, nodeid, members_mismatch;
+ uint32_t seq = hd->msgdata;
+
+ nums = (int *)((char *)hd + sizeof(struct fd_header));
+
+ member_count = le32_to_cpu(nums[0]);
+ joined_count = le32_to_cpu(nums[1]);
+ remove_count = le32_to_cpu(nums[2]);
+ failed_count = le32_to_cpu(nums[3]);
+
+ n_ints = 4 + member_count;
+ if (len != (sizeof(struct fd_header) + (n_ints * sizeof(int)))) {
+ log_debug("match_change fail %d:%u bad len %d nums %s",
+ hd->nodeid, seq, len, str_nums(nums, n_ints));
+ return 0;
+ }
+
+ /* We can ignore messages if we're not in the list of members. The one
+ known time this will happen is after we've joined the cpg, we can
+ get messages for changes prior to the change in which we're added. */
+
+ for (i = 0; i < member_count; i++) {
+ if (our_nodeid == le32_to_cpu(nums[4+i]))
+ break;
+ }
+ if (i == member_count) {
+ log_debug("match_change fail %d:%u we are not in members",
+ hd->nodeid, seq);
+ return 0;
+ }
+
+ memb = find_memb(cg, hd->nodeid);
+ if (!memb) {
+ log_debug("match_change fail %d:%u sender not member",
+ hd->nodeid, seq);
+ return 0;
+ }
+
+ /* verify this is the right change by matching the counts
+ and the nodeids of the current members */
+
+ if (member_count != cg->member_count ||
+ joined_count != cg->joined_count ||
+ remove_count != cg->remove_count ||
+ failed_count != cg->failed_count) {
+ log_debug("match_change fail %d:%u expect counts "
+ "%d %d %d %d nums %s",
+ hd->nodeid, seq,
+ cg->member_count, cg->joined_count,
+ cg->remove_count, cg->failed_count,
+ str_nums(nums, n_ints));
+ return 0;
+ }
+
+ members_mismatch = 0;
+ for (i = 0; i < member_count; i++) {
+ nodeid = le32_to_cpu(nums[4+i]);
+ memb = find_memb(cg, nodeid);
+ if (memb)
+ continue;
+ log_debug("match_change fail %d:%u no memb %d",
+ hd->nodeid, seq, nodeid);
+ members_mismatch = 1;
+ }
+ if (members_mismatch)
+ return 0;
+
+ return 1;
+}
+
+/* Unfortunately, there's no really simple way to match a message with the
+ specific change that it was sent for. We hope that by passing all the
+ details of the change in the message, we will be able to uniquely match the
+ it to the correct change. */
+
+/* A start message will usually be for the first (current) change on our list.
+ In some cases it will be for a non-current change, and we can ignore it:
+
+ 1. A,B,C get confchg1 adding C
+ 2. C sends start for confchg1
+ 3. A,B,C get confchg2 adding D
+ 4. A,B,C,D recv start from C for confchg1 - ignored
+ 5. C,D send start for confchg2
+ 6. A,B send start for confchg2
+ 7. A,B,C,D recv all start messages for confchg2, and start kernel
+
+ In step 4, how do the nodes know whether the start message from C is
+ for confchg1 or confchg2? Hopefully by comparing the counts and members. */
+
+static struct change *find_change(struct fd *fd, struct fd_header *hd, int len)
+{
+ struct change *cg;
+
+ list_for_each_entry_reverse(cg, &fd->changes, list) {
+ if (!match_change(fd, cg, hd, len))
+ continue;
+ return cg;
+ }
+
+ log_debug("find_change %d:%u no match", hd->nodeid, hd->msgdata);
+ return NULL;
+}
+
+/* We require new members (memb->added) to be joining the domain
+ (memb->joining). New members that are not joining the domain can happen
+ when the cpg partitions and is then merged back together (shouldn't happen
+ in general, but is possible). We label these new members that are not
+ joining as "disallowed", and ignore their start message. */
+
+/* Handle spurious joins by ignoring this start message if the node says it's
+ not joining (i.e. it's already a member), but we see it being added (i.e.
+ it's not already a member) */
+
+static void receive_start(struct fd *fd, struct fd_header *hd, int len)
+{
+ struct change *cg;
+ struct member *memb;
+ int joining = 0;
+ uint32_t seq = hd->msgdata;
+
+ log_debug("receive_start %d:%u flags %x len %d", hd->nodeid, seq,
+ hd->flags, len);
+
+ cg = find_change(fd, hd, len);
+ if (!cg)
+ return;
+
+ memb = find_memb(cg, hd->nodeid);
+ if (!memb) {
+ /* this should never happen since match_change checks it */
+ log_error("receive_start no member %d", hd->nodeid);
+ return;
+ }
+
+ memb->start_flags = hd->flags;
+
+ if (memb->start_flags & FD_MFLG_JOINING)
+ joining = 1;
+
+ if ((memb->added && !joining) || (!memb->added && joining)) {
+ log_error("receive_start %d:%u disallowed added %d joining %d",
+ hd->nodeid, seq, memb->added, joining);
+ memb->disallowed = 1;
+ } else {
+ node_history_start(fd, hd->nodeid);
+ memb->start = 1;
+ }
+}
+
+static void send_start(struct fd *fd)
+{
+ struct change *cg = list_first_entry(&fd->changes, struct change, list);
+ struct fd_header *hd;
+ struct member *memb;
+ int n_ints, len, *p, i;
+ char *buf;
+
+ n_ints = 4 + cg->member_count;
+ len = sizeof(struct fd_header) + (n_ints * sizeof(int));
+
+ buf = malloc(len);
+ if (!buf) {
+ return;
+ }
+ memset(buf, 0, len);
+
+ hd = (struct fd_header *)buf;
+ hd->type = FD_MSG_START;
+ hd->msgdata = cg->seq;
+
+ if (cg->we_joined)
+ hd->flags |= FD_MFLG_JOINING;
+ if (fd->init_complete)
+ hd->flags |= FD_MFLG_COMPLETE;
+
+ p = (int *)(buf + sizeof(struct fd_header));
+
+ /* sending all this stuff is probably unnecessary, but gives
+ us more certainty in matching stopped messages to the correct
+ change that they are for */
+
+ p[0] = cpu_to_le32(cg->member_count);
+ p[1] = cpu_to_le32(cg->joined_count);
+ p[2] = cpu_to_le32(cg->remove_count);
+ p[3] = cpu_to_le32(cg->failed_count);
+
+ i = 4;
+ list_for_each_entry(memb, &cg->members, list)
+ p[i++] = cpu_to_le32(memb->nodeid);
+
+ log_debug("send_start %u flags %x counts %d %d %d %d", cg->seq,
+ hd->flags, cg->member_count, cg->joined_count,
+ cg->remove_count, cg->failed_count);
+
+ fd_send_message(fd, buf, len);
+
+ free(buf);
+}
+
+static int nodes_added(struct fd *fd)
+{
+ struct change *cg;
+
+ list_for_each_entry(cg, &fd->changes, list) {
+ if (cg->joined_count)
+ return 1;
+ }
+ return 0;
+}
+
+/* If we're being added by the current change, we'll have an empty victims
+ list, while other previous members may already have nodes in their
+ victims list. So, we need to assume that any node in cluster.conf that's
+ not a cluster member when we're added to the fd is already a victim.
+ We can go back on that assumption, and clear out any presumed victims, when
+ we see a message from a previous member saying that are no current victims. */
+
+static void add_victims(struct fd *fd, struct change *cg)
+{
+ struct member *memb;
+ struct node *node;
+
+ list_for_each_entry(memb, &cg->removed, list) {
+ if (!memb->failed)
+ continue;
+ node = get_new_node(fd, memb->nodeid);
+ if (!node)
+ return;
+ list_add(&node->list, &fd->victims);
+ log_debug("add node %d to victims", node->nodeid);
+ }
+}
+
+/* with start messages from all members, we can pick which one should be master
+ and do the fencing (low nodeid with state, "COMPLETE"). as the master
+ successfully fences each victim, it sends a status message such that all
+ members remove the node from their victims list. the status message also
+ indicates the number of remaining victims.
+
+ when a node sees via status message that there are no more outstanding
+ victims, it sets fd->init_complete. if a node is going from !complete to
+ complete, it may still have entries on its victims list at this point from
+ startup init; it can clear them out. this node will volunteer to be master
+ in the next round of start messages by setting COMPLETE flag.
+
+ once the master begins fencing victims, it won't process any new changes
+ until it's done. the non-master members will process changes while the
+ master is fencing, but will wait for the master to catch up in
+ WAIT_MESSAGES. if the master fails, the others will no longer wait for it. */
+
+static void apply_changes(struct fd *fd)
+{
+ struct change *cg;
+
+ if (list_empty(&fd->changes))
+ return;
+ cg = list_first_entry(&fd->changes, struct change, list);
+
+ switch (cg->state) {
+
+ case CGST_WAIT_CONDITIONS:
+ if (wait_conditions_done(fd)) {
+ send_start(fd);
+ cg->state = CGST_WAIT_MESSAGES;
+ }
+ break;
+
+ case CGST_WAIT_MESSAGES:
+ if (wait_messages_done(fd)) {
+ set_master(fd);
+ if (fd->master == our_nodeid) {
+ if (!list_empty(&fd->victims)) {
+ delay_fencing(fd, nodes_added(fd));
+ fence_victims(fd);
+ } else {
+ send_victim_done(fd, -1, 0);
+ }
+ } else {
+ defer_fencing(fd);
+ }
+
+ cleanup_changes(fd);
+ fd->joining_group = 0;
+ }
+ break;
+
+ default:
+ log_error("apply_changes invalid state %d", cg->state);
+ }
+}
+
+void process_fd_changes(void)
+{
+ struct fd *fd, *safe;
+
+ list_for_each_entry_safe(fd, safe, &domains, list) {
+ if (!list_empty(&fd->changes))
+ apply_changes(fd);
+ }
+}
+
+static int add_change(struct fd *fd,
+ struct cpg_address *member_list, int member_list_entries,
+ struct cpg_address *left_list, int left_list_entries,
+ struct cpg_address *joined_list, int joined_list_entries,
+ struct change **cg_out)
+{
+ struct change *cg;
+ struct member *memb;
+ int i, error;
+
+ cg = malloc(sizeof(struct change));
+ if (!cg)
+ goto fail_nomem;
+ memset(cg, 0, sizeof(struct change));
+ INIT_LIST_HEAD(&cg->members);
+ INIT_LIST_HEAD(&cg->removed);
+ cg->seq = ++fd->change_seq;
+ cg->state = CGST_WAIT_CONDITIONS;
+
+ cg->member_count = member_list_entries;
+ cg->joined_count = joined_list_entries;
+ cg->remove_count = left_list_entries;
+
+ for (i = 0; i < member_list_entries; i++) {
+ memb = malloc(sizeof(struct member));
+ if (!memb)
+ goto fail_nomem;
+ memset(memb, 0, sizeof(struct member));
+ memb->nodeid = member_list[i].nodeid;
+ list_add_tail(&memb->list, &cg->members);
+ }
+
+ for (i = 0; i < left_list_entries; i++) {
+ memb = malloc(sizeof(struct member));
+ if (!memb)
+ goto fail_nomem;
+ memset(memb, 0, sizeof(struct member));
+ memb->nodeid = left_list[i].nodeid;
+ if (left_list[i].reason == CPG_REASON_NODEDOWN ||
+ left_list[i].reason == CPG_REASON_PROCDOWN) {
+ memb->failed = 1;
+ cg->failed_count++;
+ }
+ list_add_tail(&memb->list, &cg->removed);
+
+ if (memb->failed)
+ node_history_fail(fd, memb->nodeid);
+ else
+ node_history_left(fd, memb->nodeid);
+
+ log_debug("add_change %u nodeid %d remove reason %d",
+ cg->seq, memb->nodeid, left_list[i].reason);
+ }
+
+ for (i = 0; i < joined_list_entries; i++) {
+ memb = find_memb(cg, joined_list[i].nodeid);
+ if (!memb) {
+ log_error("no member %d", joined_list[i].nodeid);
+ error = -ENOENT;
+ goto fail;
+ }
+ memb->added = 1;
+
+ if (memb->nodeid == our_nodeid)
+ cg->we_joined = 1;
+ else
+ node_history_init(fd, memb->nodeid);
+
+ log_debug("add_change %u nodeid %d joined", cg->seq,
+ memb->nodeid);
+ }
+
+ if (cg->we_joined)
+ list_for_each_entry(memb, &cg->members, list)
+ node_history_init(fd, memb->nodeid);
+
+ log_debug("add_change %u member %d joined %d remove %d failed %d",
+ cg->seq, cg->member_count, cg->joined_count, cg->remove_count,
+ cg->failed_count);
+
+ list_add(&cg->list, &fd->changes);
+ *cg_out = cg;
+ return 0;
+
+ fail_nomem:
+ log_error("no memory");
+ error = -ENOMEM;
+ fail:
+ free_cg(cg);
+ return error;
+}
+
+static int is_victim(struct fd *fd, int nodeid)
+{
+ struct node *node;
+
+ list_for_each_entry(node, &fd->victims, list) {
+ if (node->nodeid == nodeid)
+ return 1;
+ }
+ return 0;
+}
+
+static void add_victims_init(struct fd *fd, struct change *cg)
+{
+ struct node *node, *safe;
+
+ /* add a victim for each node in complete list that is not
+ a cman member (and not already a victim) */
+
+ list_for_each_entry_safe(node, safe, &fd->complete, list) {
+ list_del(&node->list);
+
+ if (!is_cman_member(node->nodeid) &&
+ !find_memb(cg, node->nodeid) &&
+ !is_victim(fd, node->nodeid)) {
+ node->init_victim = 1;
+ list_add(&node->list, &fd->victims);
+ log_debug("add_victims_init %d", node->nodeid);
+ } else {
+ free(node);
+ }
+ }
+}
+
+static int we_left(struct cpg_address *left_list, int left_list_entries)
+{
+ int i;
+
+ for (i = 0; i < left_list_entries; i++) {
+ if (left_list[i].nodeid == our_nodeid)
+ return 1;
+ }
+ return 0;
+}
+
+static void confchg_cb(cpg_handle_t handle, struct cpg_name *group_name,
+ struct cpg_address *member_list, int member_list_entries,
+ struct cpg_address *left_list, int left_list_entries,
+ struct cpg_address *joined_list, int joined_list_entries)
+{
+ struct fd *fd;
+ struct change *cg;
+ int rv;
+
+ fd = find_fd_handle(handle);
+ if (!fd) {
+ log_error("confchg_cb no fence domain for cpg %s",
+ group_name->value);
+ return;
+ }
+
+ if (fd->leaving_group && we_left(left_list, left_list_entries)) {
+ /* we called cpg_leave(), and this should be the final
+ cpg callback we receive */
+ log_debug("confchg for our leave");
+ cpg_finalize(fd->cpg_handle);
+ client_dead(fd->cpg_client);
+ list_del(&fd->list);
+ free_fd(fd);
+ return;
+ }
+
+ rv = add_change(fd, member_list, member_list_entries,
+ left_list, left_list_entries,
+ joined_list, joined_list_entries, &cg);
+ if (rv)
+ return;
+
+ /* failed nodes in this change become victims */
+
+ add_victims(fd, cg);
+
+ /* We need to assume non-member nodes are already victims;
+ these initial victims are cleared when we get a status
+ with zero remaining victims from the master. But, if
+ we're the master, we do end up fencing these init nodes. */
+
+ if (cg->we_joined)
+ add_victims_init(fd, cg);
+}
+
+static void deliver_cb(cpg_handle_t handle, struct cpg_name *group_name,
+ uint32_t nodeid, uint32_t pid, void *data, int len)
+{
+ struct fd *fd;
+ struct fd_header *hd;
+
+ fd = find_fd_handle(handle);
+ if (!fd) {
+ log_error("deliver_cb no fd for cpg %s", group_name->value);
+ return;
+ }
+
+ hd = (struct fd_header *)data;
+
+ hd->version[0] = le16_to_cpu(hd->version[0]);
+ hd->version[1] = le16_to_cpu(hd->version[1]);
+ hd->version[2] = le16_to_cpu(hd->version[2]);
+ hd->type = le16_to_cpu(hd->type);
+ hd->nodeid = le32_to_cpu(hd->nodeid);
+ hd->to_nodeid = le32_to_cpu(hd->to_nodeid);
+ hd->global_id = le32_to_cpu(hd->global_id);
+ hd->flags = le32_to_cpu(hd->flags);
+ hd->msgdata = le32_to_cpu(hd->msgdata);
+
+ if (hd->version[0] != protocol_active[0]) {
+ log_error("reject message from %d version %u.%u.%u vs %u.%u.%u",
+ nodeid, hd->version[0], hd->version[1],
+ hd->version[2], protocol_active[0],
+ protocol_active[1], protocol_active[2]);
+ return;
+ }
+
+ if (hd->nodeid != nodeid) {
+ log_error("bad msg nodeid %d %d", hd->nodeid, nodeid);
+ return;
+ }
+
+ switch (hd->type) {
+ case FD_MSG_START:
+ receive_start(fd, hd, len);
+ break;
+ case FD_MSG_VICTIM_DONE:
+ receive_victim_done(fd, hd, len);
+ break;
+ case FD_MSG_EXTERNAL:
+ receive_external(fd, hd, len);
+ break;
+ default:
+ log_error("unknown msg type %d", hd->type);
+ }
+}
+
+static cpg_callbacks_t cpg_callbacks = {
+ .cpg_deliver_fn = deliver_cb,
+ .cpg_confchg_fn = confchg_cb,
+};
+
+static void process_fd_cpg(int ci)
+{
+ struct fd *fd;
+ cpg_error_t error;
+
+ fd = find_fd_ci(ci);
+ if (!fd) {
+ log_error("process_fd_cpg no fence domain for ci %d", ci);
+ return;
+ }
+
+ error = cpg_dispatch(fd->cpg_handle, CPG_DISPATCH_ALL);
+ if (error != CPG_OK) {
+ log_error("cpg_dispatch error %d", error);
+ return;
+ }
+
+ apply_changes(fd);
+}
+
+int fd_join(struct fd *fd)
+{
+ cpg_error_t error;
+ cpg_handle_t h;
+ struct cpg_name name;
+ int i = 0, f, ci;
+
+ error = cpg_initialize(&h, &cpg_callbacks);
+ if (error != CPG_OK) {
+ log_error("cpg_initialize error %d", error);
+ goto fail_free;
+ }
+
+ cpg_fd_get(h, &f);
+
+ ci = client_add(f, process_fd_cpg, NULL);
+
+ list_add(&fd->list, &domains);
+ fd->cpg_handle = h;
+ fd->cpg_client = ci;
+ fd->cpg_fd = f;
+ fd->joining_group = 1;
+
+ memset(&name, 0, sizeof(name));
+ sprintf(name.value, "fenced:%s", fd->name);
+ name.length = strlen(name.value) + 1;
+
+ retry:
+ error = cpg_join(h, &name);
+ if (error == CPG_ERR_TRY_AGAIN) {
+ sleep(1);
+ if (!(++i % 10))
+ log_error("cpg_join error retrying");
+ goto retry;
+ }
+ if (error != CPG_OK) {
+ log_error("cpg_join error %d", error);
+ cpg_finalize(h);
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ list_del(&fd->list);
+ client_dead(ci);
+ cpg_finalize(h);
+ fail_free:
+ free(fd);
+ return error;
+}
+
+int fd_leave(struct fd *fd)
+{
+ cpg_error_t error;
+ struct cpg_name name;
+ int i = 0;
+
+ fd->leaving_group = 1;
+
+ memset(&name, 0, sizeof(name));
+ sprintf(name.value, "fenced:%s", fd->name);
+ name.length = strlen(name.value) + 1;
+
+ retry:
+ error = cpg_leave(fd->cpg_handle, &name);
+ if (error == CPG_ERR_TRY_AGAIN) {
+ sleep(1);
+ if (!(++i % 10))
+ log_error("cpg_leave error retrying");
+ goto retry;
+ }
+ if (error != CPG_OK)
+ log_error("cpg_leave error %d", error);
+
+ return 0;
+}
+
diff --git a/fence/fenced/fd.h b/fence/fenced/fd.h
index 990190e..2695de8 100644
--- a/fence/fenced/fd.h
+++ b/fence/fenced/fd.h
@@ -2,7 +2,7 @@
************************************************** *****************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -14,12 +14,6 @@
#ifndef __FD_DOT_H__
#define __FD_DOT_H__

-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -30,82 +24,68 @@
#include <string.h>
#include <stdint.h>
#include <syslog.h>
+#include <time.h>
+#include <sched.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
-#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <openais/saAis.h>
+#include <openais/cpg.h>

#include "list.h"
-#include "libgroup.h"
+#include "linux_endian.h"

-#define MAX_NODENAME_LEN 255 /* should match libcman.h */
-#define MAX_GROUPNAME_LEN 32 /* should match libgroup.h */
-#define MAX_NODES 256
-#define MAXARGS 100 /* FIXME */
-#define MAXLINE 256
-#define MAX_CLIENTS 5
-#define DUMP_SIZE (1024 * 1024)
+/* Max name length for a group, pointless since we only ever create the
+ "default" group. Regardless, set arbitrary max to match dlm's
+ DLM_LOCKSPACE_LEN 64. The libcpg limit is larger at 128; we prefix
+ the fence domain name with "fenced:" to create the cpg name. */

-#define DEFAULT_POST_JOIN_DELAY 6
-#define DEFAULT_POST_FAIL_DELAY 0
-#define DEFAULT_CLEAN_START 0
-#define DEFAULT_OVERRIDE_PATH "/var/run/cluster/fenced_override"
-#define FENCED_SOCK_PATH "fenced_socket"
+#define MAX_GROUPNAME_LEN 64
+
+/* Max name length for a node. This should match libcman's
+ CMAN_MAX_NODENAME_LEN which is 255. */
+
+#define MAX_NODENAME_LEN 255

-extern char *prog_name;
-extern int daemon_debug_opt;
-extern char daemon_debug_buf[256];
+/* Maximum members of the fence domain, or cluster. Should match
+ CPG_MEMBERS_MAX in openais/cpg.h. */
+
+#define MAX_NODES 128
+
+/* Max string length printed on a line, for debugging/dump output. */
+
+#define MAXLINE 256
+
+/* Size of the circular debug buffer. */
+
+#define DUMP_SIZE (1024 * 1024)
+
+/* group_mode */
+
+#define GROUP_LIBGROUP 2
+#define GROUP_LIBCPG 3
+
+extern int daemon_debug_opt;
+extern int daemon_quit;
+extern struct list_head domains;
+extern int cman_quorate;
+extern int our_nodeid;
+extern char our_name[MAX_NODENAME_LEN+1];
+extern char daemon_debug_buf[256];
extern char dump_buf[DUMP_SIZE];
extern int dump_point;
extern int dump_wrap;
+extern int group_mode;

extern void daemon_dump_save(void);

-/* use this one before we fork into the background */
-#define die1(fmt, args...)
-do
-{
- fprintf(stderr, "%s: ", prog_name);
- fprintf(stderr, fmt "
", ##args);
- exit(EXIT_FAILURE);
-}
-while (0)
-
-#define die(fmt, args...)
-do
-{
- fprintf(stderr, "%s: ", prog_name);
- fprintf(stderr, fmt "
", ##args);
- syslog(LOG_ERR, fmt, ##args);
- exit(EXIT_FAILURE);
-}
-while (0)
-
-#define ASSERT(x, todo)
-do
-{
- if (!(x))
- {
- {todo}
- die("assertion failed on line %d of file %s
", __LINE__, __FILE__);
- }
-}
-while (0)
-
-#define FENCE_RETRY(do_this, until_this)
-for (;;)
-{
- do { do_this; } while (0);
- if (until_this)
- break;
- fprintf(stderr, "fenced: out of memory: %s, %u
", __FILE__, __LINE__);
- sleep(1);
-}
-
#define log_debug(fmt, args...)
do {
snprintf(daemon_debug_buf, 255, "%ld " fmt "
", time(NULL), ##args);
@@ -119,82 +99,174 @@ do {
syslog(LOG_ERR, fmt, ##args);
} while (0)

+/* config option defaults */

-struct fd;
-struct fd_node;
-struct commandline;
-
-typedef struct fd fd_t;
-typedef struct fd_node fd_node_t;
-typedef struct commandline commandline_t;
+#define DEFAULT_GROUPD_COMPAT 1
+#define DEFAULT_CLEAN_START 0
+#define DEFAULT_POST_JOIN_DELAY 6
+#define DEFAULT_POST_FAIL_DELAY 0
+#define DEFAULT_OVERRIDE_TIME 3
+#define DEFAULT_OVERRIDE_PATH "/var/run/cluster/fenced_override"

struct commandline
{
+ int groupd_compat;
+ int clean_start;
int post_join_delay;
int post_fail_delay;
int override_time;
- int pad;
char *override_path;
- int8_t clean_start;
+
+ int8_t groupd_compat_opt;
+ int8_t clean_start_opt;
int8_t post_join_delay_opt;
int8_t post_fail_delay_opt;
- int8_t clean_start_opt;
- int8_t override_path_opt;
int8_t override_time_opt;
+ int8_t override_path_opt;
+};
+
+extern struct commandline comline;
+
+#define FD_MSG_START 1
+#define FD_MSG_VICTIM_DONE 2
+#define FD_MSG_EXTERNAL 3
+
+#define FD_MFLG_JOINING 1 /* accompanies start, we are joining */
+#define FD_MFLG_COMPLETE 2 /* accompanies start, we have complete info */
+
+struct fd_header {
+ uint16_t version[3];
+ uint16_t type; /* FD_MSG_ */
+ uint32_t nodeid; /* sender */
+ uint32_t to_nodeid; /* recipient, 0 for all */
+ uint32_t global_id; /* global unique id for this domain */
+ uint32_t flags; /* FD_MFLG_ */
+ uint32_t msgdata; /* in-header payload depends on MSG type */
+ uint32_t pad1;
+ uint64_t pad2;
+};
+
+#define CGST_WAIT_CONDITIONS 1
+#define CGST_WAIT_MESSAGES 2
+
+struct change {
+ struct list_head list;
+ struct list_head members;
+ struct list_head removed; /* nodes removed by this change */
+ int member_count;
+ int joined_count;
+ int remove_count;
+ int failed_count;
+ int state; /* CGST_ */
+ int we_joined;
+ uint32_t seq; /* just used as a reference when debugging */
};

-#define FDFL_RUN (0)
-#define FDFL_START (1)
-#define FDFL_FINISH (2)
+#define VIC_DONE_AGENT 1
+#define VIC_DONE_MEMBER 2
+#define VIC_DONE_OVERRIDE 3
+#define VIC_DONE_EXTERNAL 4
+
+struct node_history {
+ struct list_head list;
+ int nodeid;
+ int check_quorum;
+ uint64_t add_time;
+ uint64_t left_time;
+ uint64_t fail_time;
+ uint64_t fence_time;
+ uint64_t fence_external_time;
+ int fence_external_node;
+ int fence_master;
+ int fence_how; /* VIC_DONE_ */
+};
+
+struct node {
+ struct list_head list;
+ int nodeid;
+ int init_victim;
+ char name[MAX_NODENAME_LEN+1];
+};

struct fd {
struct list_head list;
- int global_id; /* global unique fd ID */
+ char name[MAX_GROUPNAME_LEN+1];
+
+ /* libcpg domain membership */
+
+ cpg_handle_t cpg_handle;
+ int cpg_client;
+ int cpg_fd;
+ uint32_t change_seq;
+ struct change *started_change;
+ struct list_head changes;
+ struct list_head node_history;
+ int init_complete;
+
+ /* general domain membership */
+
+ int master;
+ int joining_group;
+ int leaving_group;
+ struct list_head victims;
+ struct list_head complete;
+
+ /* libgroup domain membership */
+
int last_stop;
int last_start;
int last_finish;
int first_recovery;
int prev_count;
- int leave;
struct list_head prev;
- struct list_head victims;
struct list_head leaving;
- struct list_head complete;
- char name[MAX_GROUPNAME_LEN+1];
};

-struct fd_node {
- struct list_head list;
- int nodeid;
- char name[MAX_NODENAME_LEN+1];
-};
+/* config.c */

+int read_ccs(struct fd *fd);

-/* main.c */
-fd_t *find_domain(char *name);
-
-/* recover.c */
-void add_complete_node(fd_t *fd, int nodeid, char *name);
-void do_recovery(fd_t *fd, int start_type, int member_count, int *nodeids);
-void do_recovery_done(fd_t *fd);
+/* cpg.c */

-/* agent.c */
-int dispatch_fence_agent(char *victim, int force);
+void free_cg(struct change *cg);
+void node_history_fence(struct fd *fd, int nodeid, int master, int how);
+void send_external(struct fd *fd, int victim);
+int is_fenced_external(struct fd *fd, int nodeid);
+void send_victim_done(struct fd *fd, int victim, int how);
+void process_fd_changes(void);
+int fd_join(struct fd *fd);
+int fd_leave(struct fd *fd);

/* group.c */
+
+void process_groupd(int ci);
int setup_groupd(void);
-void exit_groupd(void);
-int process_groupd(void);
-int in_groupd_cpg(int nodeid);
-
-/* member_xxx.c */
-int setup_member(void);
-int process_member(void);
-void exit_member(void);
-int update_cluster_members(void);
-int is_member(char *name);
-int is_fenced(char *name);
-fd_node_t *get_new_node(fd_t *fd, int nodeid, char *in_name);
-void update_cman(char *victim, char *agent);
+int fd_join_group(struct fd *fd);
+int fd_leave_group(struct fd *fd);
+
+/* main.c */
+
+void client_dead(int ci);
+int client_add(int fd, void (*workfn)(int ci), void (*deadfn)(int ci));
+void free_fd(struct fd *fd);
+struct fd *find_fd(char *name);
+
+/* member_cman.c */
+
+void process_cman(int ci);
+int setup_cman(void);
+int is_cman_member(int nodeid);
+char *nodeid_to_name(int nodeid);
+struct node *get_new_node(struct fd *fd, int nodeid);
+
+/* recover.c */
+
+void free_node_list(struct list_head *head);
+void add_complete_node(struct fd *fd, int nodeid);
+int list_count(struct list_head *head);
+void delay_fencing(struct fd *fd, int node_join);
+void defer_fencing(struct fd *fd);
+void fence_victims(struct fd *fd);

#endif /* __FD_DOT_H__ */
+
diff --git a/fence/fenced/group.c b/fence/fenced/group.c
index 126212e..92386fe 100644
--- a/fence/fenced/group.c
+++ b/fence/fenced/group.c
@@ -11,6 +11,7 @@
************************************************** ****************************/

#include "fd.h"
+#include "libgroup.h"

#define DO_STOP 1
#define DO_START 2
@@ -23,14 +24,14 @@
/* save all the params from callback functions here because we can't
do the processing within the callback function itself */

-group_handle_t gh;
+static group_handle_t gh;
static int cb_action;
-static char cb_name[MAX_GROUP_NAME_LEN+1];
+static char cb_name[MAX_GROUPNAME_LEN+1];
static int cb_event_nr;
static int cb_id;
static int cb_type;
static int cb_member_count;
-static int cb_members[MAX_GROUP_MEMBERS];
+static int cb_members[MAX_NODES];


static void stop_cbfn(group_handle_t h, void *private, char *name)
@@ -84,7 +85,7 @@ group_callbacks_t callbacks = {
setid_cbfn
};

-char *str_members(void)
+static char *str_members(void)
{
static char mbuf[MAXLINE];
int i, len = 0;
@@ -96,9 +97,202 @@ char *str_members(void)
return mbuf;
}

-int process_groupd(void)
+static int id_in_nodeids(int nodeid, int count, int *nodeids)
{
- fd_t *fd;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (nodeid == nodeids[i])
+ return 1;
+ }
+ return 0;
+}
+
+static int next_complete_nodeid(struct fd *fd, int gt)
+{
+ struct node *node;
+ int low = -1;
+
+ /* find lowest node id in fd_complete greater than gt,
+ if none, return -1 */
+
+ list_for_each_entry(node, &fd->complete, list) {
+ if (node->nodeid <= gt)
+ continue;
+
+ if (low == -1)
+ low = node->nodeid;
+ else if (node->nodeid < low)
+ low = node->nodeid;
+ }
+ return low;
+}
+
+static void set_master(struct fd *fd)
+{
+ struct node *node;
+ int low = -1;
+
+ /* Find the lowest nodeid common to fd->fd_prev (newest member list)
+ * and fd->fd_complete (last complete member list). */
+
+ for (;;) {
+ low = next_complete_nodeid(fd, low);
+ if (low == -1)
+ break;
+
+ list_for_each_entry(node, &fd->prev, list) {
+ if (low != node->nodeid)
+ continue;
+ goto out;
+ }
+ }
+
+ /* Special case: we're the first and only FD member */
+
+ if (fd->prev_count == 1)
+ low = our_nodeid;
+
+ /* We end up returning -1 when we're not the only node and we've just
+ joined. Because we've just joined we weren't in the last complete
+ domain group and won't be chosen as master. We defer to someone who
+ _was_ in the last complete group. All we know is it isn't us. */
+
+ out:
+ fd->master = low;
+}
+
+static void new_prev_nodes(struct fd *fd, int member_count, int *nodeids)
+{
+ struct node *node;
+ int i;
+
+ for (i = 0; i < member_count; i++) {
+ node = get_new_node(fd, nodeids[i]);
+ list_add(&node->list, &fd->prev);
+ }
+
+ fd->prev_count = member_count;
+}
+
+static void _add_first_victims(struct fd *fd)
+{
+ struct node *prev_node, *safe;
+
+ /* complete list initialised in init_nodes() to all nodes from ccs */
+ if (list_empty(&fd->complete))
+ log_debug("first complete list empty warning");
+
+ list_for_each_entry_safe(prev_node, safe, &fd->complete, list) {
+ if (!is_cman_member(prev_node->nodeid)) {
+ list_del(&prev_node->list);
+ list_add(&prev_node->list, &fd->victims);
+ log_debug("add first victim %s", prev_node->name);
+ prev_node->init_victim = 1;
+ }
+ }
+}
+
+static void _add_victims(struct fd *fd, int start_type, int member_count,
+ int *nodeids)
+{
+ struct node *node, *safe;
+
+ /* nodes which haven't completed leaving when a failure restart happens
+ * are dead (and need fencing) or are still members */
+
+ if (start_type == GROUP_NODE_FAILED) {
+ list_for_each_entry_safe(node, safe, &fd->leaving, list) {
+ list_del(&node->list);
+ if (id_in_nodeids(node->nodeid, member_count, nodeids))
+ list_add(&node->list, &fd->complete);
+ else {
+ list_add(&node->list, &fd->victims);
+ log_debug("add victim %u, was leaving",
+ node->nodeid);
+ }
+ }
+ }
+
+ /* nodes in last completed group but missing from fr_nodeids are added
+ * to victims list or leaving list, depending on the type of start. */
+
+ if (list_empty(&fd->complete))
+ log_debug("complete list empty warning");
+
+ list_for_each_entry_safe(node, safe, &fd->complete, list) {
+ if (!id_in_nodeids(node->nodeid, member_count, nodeids)) {
+ list_del(&node->list);
+
+ if (start_type == GROUP_NODE_FAILED)
+ list_add(&node->list, &fd->victims);
+ else
+ list_add(&node->list, &fd->leaving);
+
+ log_debug("add node %u to list %u", node->nodeid,
+ start_type);
+ }
+ }
+}
+
+static void add_victims(struct fd *fd, int start_type, int member_count,
+ int *nodeids)
+{
+ /* Reset things when the last stop aborted our first
+ * start, i.e. there was no finish; we got a
+ * start/stop/start immediately upon joining. */
+
+ if (!fd->last_finish && fd->last_stop) {
+ log_debug("revert aborted first start");
+ fd->last_stop = 0;
+ fd->first_recovery = 0;
+ free_node_list(&fd->prev);
+ free_node_list(&fd->victims);
+ free_node_list(&fd->leaving);
+ }
+
+ log_debug("add_victims stop %d start %d finish %d",
+ fd->last_stop, fd->last_start, fd->last_finish);
+
+ if (!fd->first_recovery) {
+ fd->first_recovery = 1;
+ _add_first_victims(fd);
+ } else
+ _add_victims(fd, start_type, member_count, nodeids);
+
+ /* "prev" is just a temporary list of node structs matching the list of
+ nodeids from the start; these nodes are moved to the "complete" list
+ in the finish callback, and will be used to compare against the
+ next set of started nodes */
+
+ free_node_list(&fd->prev);
+ new_prev_nodes(fd, member_count, nodeids);
+}
+
+static void clear_victims(struct fd *fd)
+{
+ struct node *node, *safe;
+
+ if (fd->last_finish == fd->last_start) {
+ free_node_list(&fd->leaving);
+ free_node_list(&fd->victims);
+ }
+
+ /* Save a copy of this set of nodes which constitutes the latest
+ * complete group. Any of these nodes missing in the next start will
+ * either be leaving or victims. For the next recovery, the lowest
+ * remaining nodeid in this group will be the master. */
+
+ free_node_list(&fd->complete);
+ list_for_each_entry_safe(node, safe, &fd->prev, list) {
+ list_del(&node->list);
+ list_add(&node->list, &fd->complete);
+ }
+}
+
+void process_groupd(int ci)
+{
+ struct fd *fd;
int error = -EINVAL;

group_dispatch(gh);
@@ -106,45 +300,56 @@ int process_groupd(void)
if (!cb_action)
goto out;

- fd = find_domain(cb_name);
+ fd = find_fd(cb_name);
if (!fd)
goto out;

- /*
- log_debug("process %s global_id %d cb_action %d last_stop %d "
- "last_start %d last_finish %d first %d prev_count %d",
- fd->name, fd->global_id, cb_action,
- fd->last_stop, fd->last_start, fd->last_finish,
- fd->first_recovery, fd->prev_count);
- */
-
switch (cb_action) {
case DO_STOP:
log_debug("stop %s", cb_name);
fd->last_stop = fd->last_start;
group_stop_done(gh, cb_name);
break;
+
case DO_START:
log_debug("start %s %d members %s", cb_name, cb_event_nr,
str_members());
fd->last_start = cb_event_nr;
- do_recovery(fd, cb_type, cb_member_count, cb_members);
+
+ /* we don't get a start callback until there's quorum */
+
+ add_victims(fd, cb_type, cb_member_count, cb_members);
+ set_master(fd);
+ if (fd->master == our_nodeid) {
+ delay_fencing(fd, cb_type == GROUP_NODE_JOIN);
+ fence_victims(fd);
+ } else {
+ defer_fencing(fd);
+ }
+
group_start_done(gh, cb_name, cb_event_nr);
+ fd->joining_group = 0;
break;
+
case DO_FINISH:
log_debug("finish %s %d", cb_name, cb_event_nr);
fd->last_finish = cb_event_nr;
- do_recovery_done(fd);
+
+ /* we get terminate callback when all have started, which means
+ that the low node has successfully fenced all victims */
+ clear_victims(fd);
+
break;
+
case DO_TERMINATE:
log_debug("terminate %s", cb_name);
- ASSERT(fd->leave,);
+ if (!fd->leaving_group)
+ log_error("process_groupd terminate not leaving");
list_del(&fd->list);
- free(fd);
+ free_fd(fd);
break;
+
case DO_SETID:
- log_debug("setid %s %d", cb_name, cb_id);
- fd->global_id = cb_id;
break;
default:
error = -EINVAL;
@@ -152,7 +357,7 @@ int process_groupd(void)

cb_action = 0;
out:
- return error;
+ return;
}

int setup_groupd(void)
@@ -170,27 +375,39 @@ int setup_groupd(void)
return rv;
}

+/*
void exit_groupd(void)
{
group_exit(gh);
}
+*/

-int in_groupd_cpg(int nodeid)
+int fd_join_group(struct fd *fd)
{
- group_data_t data;
- int i, rv;
-
- memset(&data, 0, sizeof(data));
+ int rv;

- rv = group_get_group(-1, "groupd", &data);
- if (rv)
- return 0;
+ list_add(&fd->list, &domains);
+ fd->joining_group = 1;

- for (i = 0; i < data.member_count; i++) {
- if (data.members[i] == nodeid)
- return 1;
+ rv = group_join(gh, fd->name);
+ if (rv) {
+ log_error("group_join error %d", rv);
+ list_del(&fd->list);
+ free(fd);
}
+ return rv;
+}

- return 0;
+int fd_leave_group(struct fd *fd)
+{
+ int rv;
+
+ fd->leaving_group = 1;
+
+ rv = group_leave(gh, fd->name);
+ if (rv)
+ log_error("group_leave error %d", rv);
+
+ return rv;
}

diff --git a/fence/fenced/main.c b/fence/fenced/main.c
index e9ebfb8..05b0923 100644
--- a/fence/fenced/main.c
+++ b/fence/fenced/main.c
@@ -2,7 +2,7 @@
************************************************** *****************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -12,47 +12,23 @@
************************************************** ****************************/

#include "fd.h"
-#include "ccs.h"
#include "copyright.cf"

-#define OPTION_STRING ("cj:f:Dn:O:T:hVS")
-#define LOCKFILE_NAME "/var/run/fenced.pid"
+#define FENCED_SOCK_PATH "fenced_socket"
+#define LOCKFILE_NAME "/var/run/fenced.pid"
+#define CLIENT_NALLOC 32
+
+static int client_maxi;
+static int client_size = 0;
+static struct client *client = NULL;
+static struct pollfd *pollfd = NULL;

struct client {
int fd;
- char type[32];
+ void *workfn;
+ void *deadfn;
};

-extern group_handle_t gh;
-extern char *our_name;
-
-static int client_size = MAX_CLIENTS;
-static struct client client[MAX_CLIENTS];
-static struct pollfd pollfd[MAX_CLIENTS];
-static int fenced_exit;
-commandline_t comline;
-struct list_head domains;
-
-static int do_write(int fd, void *buf, size_t count)
-{
- int rv, off = 0;
-
- retry:
- rv = write(fd, buf + off, count);
- if (rv == -1 && errno == EINTR)
- goto retry;
- if (rv < 0)
- return rv;
-
- if (rv != count) {
- count -= rv;
- off += rv;
- goto retry;
- }
- return 0;
-}
-
-/*
static int do_read(int fd, void *buf, size_t count)
{
int rv, off = 0;
@@ -69,236 +45,225 @@ static int do_read(int fd, void *buf, size_t count)
}
return 0;
}
-*/

-static int setup_ccs(fd_t *fd)
+static int do_write(int fd, void *buf, size_t count)
{
- char path[256];
- char *name = NULL, *str = NULL;
- int error, cd, i = 0, count = 0;
-
+ int rv, off = 0;

- while ((cd = ccs_connect()) < 0) {
- sleep(1);
- if (++i > 9 && !(i % 10))
- log_error("connect to ccs error %d, "
- "check ccsd or cluster status", cd);
+ retry:
+ rv = write(fd, buf + off, count);
+ if (rv == -1 && errno == EINTR)
+ goto retry;
+ if (rv < 0) {
+ log_error("write errno %d", errno);
+ return rv;
}

+ if (rv != count) {
+ count -= rv;
+ off += rv;
+ goto retry;
+ }
+ return 0;
+}

- /* Our own nodename must be in cluster.conf before we're allowed to
- join the fence domain and then mount gfs; other nodes need this to
- fence us. */
-
- memset(path, 0, 256);
- snprintf(path, 256,
- "/cluster/clusternodes/clusternode[@name="%s"]/@name",
- our_name);
-
- error = ccs_get(cd, path, &str);
- if (error)
- die1("local cman node name "%s" not found in the configuration",
- our_name);
-
-
- /* If an option was set on the command line, don't set it from ccs. */
-
- if (comline.clean_start_opt == FALSE) {
- str = NULL;
- memset(path, 0, 256);
- sprintf(path, "/cluster/fence_daemon/@clean_start");
+static void do_dump(int fd)
+{
+ int len;

- error = ccs_get(cd, path, &str);
- if (!error)
- comline.clean_start = atoi(str);
- else
- comline.clean_start = DEFAULT_CLEAN_START;
- if (str)
- free(str);
- }
+ if (dump_wrap) {
+ len = DUMP_SIZE - dump_point;
+ do_write(fd, dump_buf + dump_point, len);
+ len = dump_point;
+ } else
+ len = dump_point;

- if (comline.post_join_delay_opt == FALSE) {
- str = NULL;
- memset(path, 0, 256);
- sprintf(path, "/cluster/fence_daemon/@post_join_delay");
-
- error = ccs_get(cd, path, &str);
- if (!error)
- comline.post_join_delay = atoi(str);
- else
- comline.post_join_delay = DEFAULT_POST_JOIN_DELAY;
- if (str)
- free(str);
- }
+ /* NUL terminate the debug string */
+ dump_buf[dump_point] = '';

- if (comline.post_fail_delay_opt == FALSE) {
- str = NULL;
- memset(path, 0, 256);
- sprintf(path, "/cluster/fence_daemon/@post_fail_delay");
-
- error = ccs_get(cd, path, &str);
- if (!error)
- comline.post_fail_delay = atoi(str);
- else
- comline.post_fail_delay = DEFAULT_POST_FAIL_DELAY;
- if (str)
- free(str);
- }
+ do_write(fd, dump_buf, len);
+}

- if (comline.override_path_opt == FALSE) {
- str = NULL;
- memset(path, 0, 256);
- sprintf(path, "/cluster/fence_daemon/@override_path");
-
- error = ccs_get(cd, path, &str);
- if (!error)
- /* XXX These are not explicitly freed on exit; if
- we decide to make fenced handle SIGHUP at a later
- time, we will need to free this. */
- comline.override_path = strdup(str);
- else
- comline.override_path = strdup(DEFAULT_OVERRIDE_PATH);
- if (str)
- free(str);
- }
+static void client_alloc(void)
+{
+ int i;

- if (comline.override_time_opt == FALSE) {
- str = NULL;
- memset(path, 0, 256);
- sprintf(path, "/cluster/fence_daemon/@override_time");
-
- error = ccs_get(cd, path, &str);
- if (!error && str)
- comline.override_time = atoi(str);
- if (str)
- free(str);
- if (comline.override_time < 3)
- comline.override_time = 3;
+ if (!client) {
+ client = malloc(CLIENT_NALLOC * sizeof(struct client));
+ pollfd = malloc(CLIENT_NALLOC * sizeof(struct pollfd));
+ } else {
+ client = realloc(client, (client_size + CLIENT_NALLOC) *
+ sizeof(struct client));
+ pollfd = realloc(pollfd, (client_size + CLIENT_NALLOC) *
+ sizeof(struct pollfd));
+ if (!pollfd)
+ log_error("can't alloc for pollfd");
}
+ if (!client || !pollfd)
+ log_error("can't alloc for client array");

- log_debug("delay post_join %ds post_fail %ds",
- comline.post_join_delay, comline.post_fail_delay);
-
- if (comline.clean_start) {
- log_debug("clean start, skipping initial nodes");
- goto out;
+ for (i = client_size; i < client_size + CLIENT_NALLOC; i++) {
+ client[i].workfn = NULL;
+ client[i].deadfn = NULL;
+ client[i].fd = -1;
+ pollfd[i].fd = -1;
+ pollfd[i].revents = 0;
}
+ client_size += CLIENT_NALLOC;
+}

- for (i = 1; ; i++) {
- name = NULL;
- memset(path, 0, 256


All times are GMT. The time now is 02:54 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.