It's possible in a two_node cluster (and others but it's more likely
with just two) that a node could be booted up after downtime or failure
and the other node is not available for some reason. In this case it
would not be allowed to proceed because wait_for_all is enforced.
This patch provides an API call to clear this flag in the desperate
situation where that becomes necessary. It should only be used with
extreme caution and will be wrapped up in pcs which should also check
that fencing has been run.
Signed-Off-By: Christine Caulfield <ccaulfie@xxxxxxxxxx>
diff --git a/exec/votequorum.c b/exec/votequorum.c
index 78e6b7b..396dddc 100644
--- a/exec/votequorum.c
+++ b/exec/votequorum.c
@@ -150,6 +150,7 @@ static int votequorum_exec_send_quorum_notification(void *conn, uint64_t context
#define VOTEQUORUM_RECONFIG_PARAM_EXPECTED_VOTES 1
#define VOTEQUORUM_RECONFIG_PARAM_NODE_VOTES 2
+#define VOTEQUORUM_RECONFIG_PARAM_CANCEL_WFA 3
static int votequorum_exec_send_reconfigure(uint8_t param, unsigned int nodeid, uint32_t value);
@@ -345,6 +346,9 @@ static void message_handler_req_lib_votequorum_qdevice_poll (void *conn,
static void message_handler_req_lib_votequorum_qdevice_master_wins (void *conn,
const void *message);
+static void message_handler_req_lib_votequorum_cancel_wait_for_all (void *conn,
+ const void *message);
+
static struct corosync_lib_handler quorum_lib_service[] =
{
{ /* 0 */
@@ -386,6 +390,10 @@ static struct corosync_lib_handler quorum_lib_service[] =
{ /* 9 */
.lib_handler_fn = message_handler_req_lib_votequorum_qdevice_master_wins,
.flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED
+ },
+ { /* 10 */
+ .lib_handler_fn = message_handler_req_lib_votequorum_cancel_wait_for_all,
+ .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED
}
};
@@ -2070,6 +2078,14 @@ static void message_handler_req_exec_votequorum_reconfigure (
recalculate_quorum(1, 0); /* Allow decrease */
break;
+ case VOTEQUORUM_RECONFIG_PARAM_CANCEL_WFA:
+ update_wait_for_all_status(0);
+ log_printf(LOGSYS_LEVEL_INFO, "wait_for_all_status reset by user on node %d.",
+ req_exec_quorum_reconfigure->nodeid);
+ recalculate_quorum(0, 0);
+
+ break;
+
}
LEAVE();
@@ -2876,3 +2892,26 @@ out:
LEAVE();
}
+
+static void message_handler_req_lib_votequorum_cancel_wait_for_all (void *conn,
+ const void *message)
+{
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+ cs_error_t error = CS_OK;
+
+ if (wait_for_all_status == 0) {
+ error = CS_ERR_NOT_EXIST;
+ goto out;
+ }
+
+ votequorum_exec_send_reconfigure(VOTEQUORUM_RECONFIG_PARAM_CANCEL_WFA,
+ us->node_id, 0);
+
+
+out:
+ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status);
+ res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_CANCEL_WFA;
+ res_lib_votequorum_status.header.error = error;
+ corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status));
+
+}
diff --git a/include/corosync/ipc_votequorum.h b/include/corosync/ipc_votequorum.h
index c06814f..16a0891 100644
--- a/include/corosync/ipc_votequorum.h
+++ b/include/corosync/ipc_votequorum.h
@@ -50,7 +50,8 @@ enum req_votequorum_types {
MESSAGE_REQ_VOTEQUORUM_QDEVICE_UNREGISTER,
MESSAGE_REQ_VOTEQUORUM_QDEVICE_UPDATE,
MESSAGE_REQ_VOTEQUORUM_QDEVICE_POLL,
- MESSAGE_REQ_VOTEQUORUM_QDEVICE_MASTER_WINS
+ MESSAGE_REQ_VOTEQUORUM_QDEVICE_MASTER_WINS,
+ MESSAGE_REQ_VOTEQUORUM_CANCEL_WFA
};
enum res_votequorum_types {
@@ -58,7 +59,8 @@ enum res_votequorum_types {
MESSAGE_RES_VOTEQUORUM_GETINFO,
MESSAGE_RES_VOTEQUORUM_TRACKSTART,
MESSAGE_RES_VOTEQUORUM_NOTIFICATION,
- MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION
+ MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION,
+ MESSAGE_RES_VOTEQUORUM_CANCEL_WFA
};
struct mar_votequorum_ring_id {
diff --git a/include/corosync/votequorum.h b/include/corosync/votequorum.h
index 9bc5690..465c993 100644
--- a/include/corosync/votequorum.h
+++ b/include/corosync/votequorum.h
@@ -183,6 +183,13 @@ cs_error_t votequorum_context_set (
void *context);
/**
+ * Cancel wait_for_all. Only to be used with GREAT care and
+ * and good knowledge and experience.
+ */
+cs_error_t votequorum_cancel_wait_for_all (
+ votequorum_handle_t handle);
+
+/**
* Register a quorum device
*
* it will be DEAD until polled
diff --git a/lib/libvotequorum.versions b/lib/libvotequorum.versions
index 7a37030..05dbc95 100644
--- a/lib/libvotequorum.versions
+++ b/lib/libvotequorum.versions
@@ -14,4 +14,5 @@ COROSYNC_VOTEQUORUM_1.0 {
votequorum_trackstop;
votequorum_context_get;
votequorum_context_set;
+ votequorum_cancel_wait_for_all;
};
diff --git a/lib/libvotequorum.verso b/lib/libvotequorum.verso
index 66ce77b..ae9a76b 100644
--- a/lib/libvotequorum.verso
+++ b/lib/libvotequorum.verso
@@ -1 +1 @@
-7.0.0
+8.0.0
diff --git a/lib/votequorum.c b/lib/votequorum.c
index be4ef43..3775bed 100644
--- a/lib/votequorum.c
+++ b/lib/votequorum.c
@@ -797,3 +797,42 @@ error_exit:
return (error);
}
+
+cs_error_t votequorum_cancel_wait_for_all (
+ votequorum_handle_t handle)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_general req_lib_votequorum_general;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_general.header.size = sizeof (struct req_lib_votequorum_general);
+ req_lib_votequorum_general.header.id = MESSAGE_REQ_VOTEQUORUM_CANCEL_WFA;
+
+ iov.iov_base = (char *)&req_lib_votequorum_general;
+ iov.iov_len = sizeof (struct req_lib_votequorum_general);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
diff --git a/man/Makefile.am b/man/Makefile.am
index 41284cb..30c3d28 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -77,6 +77,7 @@ autogen_man = cpg_context_get.3 \
votequorum_setvotes.3 \
votequorum_trackstart.3 \
votequorum_trackstop.3 \
+ votequorum_cancel_wait_for_all.3 \
votequorum_qdevice_register.3 \
votequorum_qdevice_unregister.3 \
votequorum_qdevice_update.3 \
diff --git a/man/votequorum_cancel_wait_for_all.3.in b/man/votequorum_cancel_wait_for_all.3.in
new file mode 100644
index 0000000..157d9bc
--- /dev/null
+++ b/man/votequorum_cancel_wait_for_all.3.in
@@ -0,0 +1,88 @@
+.\"/*
+.\" * Copyright (c) 2014 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Christine Caulfield <ccaulfie@xxxxxxxxxx>
+.\" *
+.\" * This software licensed under BSD license, the text of which follows:
+.\" *
+.\" * Redistribution and use in source and binary forms, with or without
+.\" * modification, are permitted provided that the following conditions are met:
+.\" *
+.\" * - Redistributions of source code must retain the above copyright notice,
+.\" * this list of conditions and the following disclaimer.
+.\" * - Redistributions in binary form must reproduce the above copyright notice,
+.\" * this list of conditions and the following disclaimer in the documentation
+.\" * and/or other materials provided with the distribution.
+.\" * - Neither the name of the MontaVista Software, Inc. nor the names of its
+.\" * contributors may be used to endorse or promote products derived from this
+.\" * software without specific prior written permission.
+.\" *
+.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+.\" * THE POSSIBILITY OF SUCH DAMAGE.
+.\" */
+.TH VOTEQUORUM_CANCEL_WAIT_FOR_ALL 3 @BUILDDATE@ "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.SH NAME
+votequorum_cancel_wait_for_all \- Force quorum in an incomplete wait_for_all cluster
+.SH SYNOPSIS
+.B #include <corosync/votequorum.h>
+.sp
+.BI "int votequorum_cancel_wait_for_all(votequorum_handle_t *" handle ");"
+.SH DESCRIPTION
+The
+.B votequorum_cancel_wait_for_all
+function is used to cancel the wait_for_all_status flag.
+.PP
+If you have not read and fully (and I mean fully) understood the votequorum(5)
+man page then don't even think about reading this one any further. It's not for you.
+.PP
+In a two_node cluster or a cluster with wait_for_all flag set (wait_for_all is
+enabled automatically in a two_node cluster), quorum will be suspended until
+all of the nodes in the nodelist have joined the cluster.
+.PP
+In some circumstances it might be necessary to override this situation, for example
+if a node comes up on its own and it is known for an absolute certainty that the other
+node is not available. In this case this call will allow the single node to proceed
+on its own.
+.PP
+This function call should not be called by any application software, it exists for
+use by the pcs cluster management software and should always be used in that context.
+.PP
+Be very, very, very careful with the use of this function and its pcs command. Using
+it without fully understanding the consequences can cause split brains and data
+corruption. You have been warned.
+.PP
+I'll say this again. Do NOT use this function unless you have checked, at least three times,
+that you fully understand the consequences of doing so and consulted your manager or Red Hat
+support. Ideally both.
+.PP
+
+.fi
+.SH RETURN VALUE
+This call returns the CS_OK value if successful, otherwise an error is returned.
+.PP
+.SH ERRORS
+@COMMONIPCERRORS@
+.SH "SEE ALSO"
+.BR votequorum_overview (8),
+.BR votequorum_initialize (3),
+.BR votequorum_finalize (3),
+.BR votequorum_getinfo (3),
+.BR votequorum_trackstop (3),
+.BR votequorum_fd_get (3),
+.BR votequorum_dispatch (3),
+.BR votequorum_context_set (3),
+.BR votequorum_context_get (3),
+.BR votequorum_setexpected (3),
+.BR votequorum_setvotes (3)
+.PP
diff --git a/test/testvotequorum2.c b/test/testvotequorum2.c
index 0a2e926..008d401 100644
--- a/test/testvotequorum2.c
+++ b/test/testvotequorum2.c
@@ -103,6 +103,7 @@ static void usage(const char *command)
printf(" -c Cast vote (default yes)\n");
printf(" -q Don't print device status every poll time (default=will print)\n");
printf(" -m Master wins (default no)\n");
+ printf(" -W Cancel wait_for_all status\n");
printf(" -1 Print status once and exit\n");
}
@@ -112,11 +113,12 @@ int main(int argc, char *argv[])
int cast_vote = 1, master_wins = 0;
int pollcount=0, polltime=1, quiet=0, once=0;
int send_old_ringid = 0;
+ int cancel_wfa = 0;
int err;
int opt;
votequorum_callbacks_t callbacks;
const char *devicename = "QDEVICE";
- const char *options = "F:n:p:t:cmq1h";
+ const char *options = "F:n:p:t:cmq1hW";
memset(&callbacks, 0, sizeof(callbacks));
callbacks.votequorum_notify_fn = votequorum_notification_fn;
@@ -147,6 +149,9 @@ int main(int argc, char *argv[])
case 't':
polltime = atoi(optarg);
break;
+ case 'W':
+ cancel_wfa = 1;
+ break;
case 'h':
usage(argv[0]);
exit(0);
@@ -167,6 +172,14 @@ int main(int argc, char *argv[])
if (!quiet) {
print_info(1);
}
+ if (cancel_wfa) {
+ ret = votequorum_cancel_wait_for_all(handle);
+ if (ret != CS_OK)
+ printf("cancel_wait_for_all returned %d\n", ret);
+ else
+ printf("cancel_wait_for_all succeeded\n");
+ goto out;
+ }
if (once) {
exit(0);
}
_______________________________________________
discuss mailing list
discuss@xxxxxxxxxxxx
http://lists.corosync.org/mailman/listinfo/discuss