45#include <qb/qbipc_common.h>
75static uint8_t qdevice_can_operate = 1;
76static void *qdevice_reg_conn = NULL;
77static uint8_t qdevice_master_wins = 0;
79static uint8_t two_node = 0;
81static uint8_t wait_for_all = 0;
82static uint8_t wait_for_all_status = 0;
83static uint8_t wait_for_all_autoset = 0;
86static int lowest_node_id = -1;
87static int highest_node_id = -1;
89#define DEFAULT_LMS_WIN 10000
90static uint8_t last_man_standing = 0;
93static uint8_t allow_downscale = 0;
94static uint32_t ev_barrier = 0;
96static uint8_t ev_tracking = 0;
97static uint32_t ev_tracking_barrier = 0;
98static int ev_tracking_fd = -1;
151#define MESSAGE_REQ_EXEC_VOTEQUORUM_NODEINFO 0
152#define MESSAGE_REQ_EXEC_VOTEQUORUM_RECONFIGURE 1
153#define MESSAGE_REQ_EXEC_VOTEQUORUM_QDEVICE_REG 2
154#define MESSAGE_REQ_EXEC_VOTEQUORUM_QDEVICE_RECONFIGURE 3
155#define MESSAGE_REQ_EXEC_VOTEQUORUM_QDEVICE_EXTRA_NODEINFO 4
157static void votequorum_exec_send_expectedvotes_notification(
void);
158static int votequorum_exec_send_quorum_notification(
void *conn, uint64_t context);
159static int votequorum_exec_send_nodelist_notification(
void *conn, uint64_t context);
160static int votequorum_exec_send_all_qdevice_extra_info_notification(
void *conn, uint64_t context);
162#define VOTEQUORUM_RECONFIG_PARAM_EXPECTED_VOTES 1
163#define VOTEQUORUM_RECONFIG_PARAM_NODE_VOTES 2
164#define VOTEQUORUM_RECONFIG_PARAM_CANCEL_WFA 3
166static int votequorum_exec_send_reconfigure(uint8_t
param,
unsigned int nodeid, uint32_t
value);
171#define VOTEQUORUM_QDEVICE_OPERATION_UNREGISTER 0
172#define VOTEQUORUM_QDEVICE_OPERATION_REGISTER 1
178#define NODE_FLAGS_QUORATE 1
179#define NODE_FLAGS_LEAVING 2
180#define NODE_FLAGS_WFASTATUS 4
181#define NODE_FLAGS_FIRST 8
182#define NODE_FLAGS_QDEVICE_REGISTERED 16
183#define NODE_FLAGS_QDEVICE_ALIVE 32
184#define NODE_FLAGS_QDEVICE_CAST_VOTE 64
185#define NODE_FLAGS_QDEVICE_MASTER_WINS 128
186#define NODE_FLAGS_QDEVICE_EXTRA_INFO_SET 256
211static uint8_t quorum;
212static uint8_t cluster_is_quorate;
219static struct qb_list_head cluster_members_list;
223static int quorum_members_entries = 0;
224static int previous_quorum_members_entries = 0;
225static int atb_nodelist_entries = 0;
232static int cluster_nodes_entries = 0;
245static struct qb_list_head trackers_list;
252static int qdevice_timer_set = 0;
254static int last_man_standing_timer_set = 0;
255static int sync_nodeinfo_sent = 0;
256static int sync_wait_for_poll_or_timeout = 0;
262static int sync_in_progress = 0;
264static void votequorum_sync_init (
265 const unsigned int *trans_list,
266 size_t trans_list_entries,
267 const unsigned int *member_list,
268 size_t member_list_entries,
271static int votequorum_sync_process (
void);
272static void votequorum_sync_activate (
void);
273static void votequorum_sync_abort (
void);
282static int votequorum_exec_exit_fn (
void);
283static int votequorum_exec_send_nodeinfo(uint32_t
nodeid);
284static int votequorum_exec_send_set_qdevice_extra_info(uint32_t
nodeid);
286static void message_handler_req_exec_votequorum_nodeinfo (
289static void exec_votequorum_nodeinfo_endian_convert (
void *message);
291static void message_handler_req_exec_votequorum_reconfigure (
294static void exec_votequorum_reconfigure_endian_convert (
void *message);
296static void message_handler_req_exec_votequorum_qdevice_reg (
299static void exec_votequorum_qdevice_reg_endian_convert (
void *message);
301static void message_handler_req_exec_votequorum_qdevice_reconfigure (
304static void exec_votequorum_qdevice_reconfigure_endian_convert (
void *message);
306static void message_handler_req_exec_votequorum_qdevice_set_extra_info (
309static void exec_votequorum_qdevice_set_extra_info_endian_convert (
void *message);
314 .exec_handler_fn = message_handler_req_exec_votequorum_nodeinfo,
315 .exec_endian_convert_fn = exec_votequorum_nodeinfo_endian_convert
318 .exec_handler_fn = message_handler_req_exec_votequorum_reconfigure,
319 .exec_endian_convert_fn = exec_votequorum_reconfigure_endian_convert
322 .exec_handler_fn = message_handler_req_exec_votequorum_qdevice_reg,
323 .exec_endian_convert_fn = exec_votequorum_qdevice_reg_endian_convert
326 .exec_handler_fn = message_handler_req_exec_votequorum_qdevice_reconfigure,
327 .exec_endian_convert_fn = exec_votequorum_qdevice_reconfigure_endian_convert
330 .exec_handler_fn = message_handler_req_exec_votequorum_qdevice_set_extra_info,
331 .exec_endian_convert_fn = exec_votequorum_qdevice_set_extra_info_endian_convert
339static int quorum_lib_init_fn (
void *conn);
341static int quorum_lib_exit_fn (
void *conn);
343static void qdevice_timer_fn(
void *arg);
345static void message_handler_req_lib_votequorum_getinfo (
void *conn,
346 const void *message);
348static void message_handler_req_lib_votequorum_setexpected (
void *conn,
349 const void *message);
351static void message_handler_req_lib_votequorum_setvotes (
void *conn,
352 const void *message);
354static void message_handler_req_lib_votequorum_trackstart (
void *conn,
355 const void *message);
357static void message_handler_req_lib_votequorum_trackstop (
void *conn,
358 const void *message);
360static void message_handler_req_lib_votequorum_qdevice_register (
void *conn,
361 const void *message);
363static void message_handler_req_lib_votequorum_qdevice_unregister (
void *conn,
364 const void *message);
366static void message_handler_req_lib_votequorum_qdevice_update (
void *conn,
367 const void *message);
369static void message_handler_req_lib_votequorum_qdevice_poll (
void *conn,
370 const void *message);
372static void message_handler_req_lib_votequorum_qdevice_master_wins (
void *conn,
373 const void *message);
375static void message_handler_req_lib_votequorum_qdevice_set_extra_info (
void *conn,
376 const void *message);
378static void message_handler_req_lib_votequorum_qdevice_get_extra_info (
void *conn,
379 const void *message);
384 .lib_handler_fn = message_handler_req_lib_votequorum_getinfo,
388 .lib_handler_fn = message_handler_req_lib_votequorum_setexpected,
392 .lib_handler_fn = message_handler_req_lib_votequorum_setvotes,
396 .lib_handler_fn = message_handler_req_lib_votequorum_trackstart,
400 .lib_handler_fn = message_handler_req_lib_votequorum_trackstop,
404 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_register,
408 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_unregister,
412 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_update,
416 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_poll,
420 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_master_wins,
424 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_set_extra_info,
428 .lib_handler_fn = message_handler_req_lib_votequorum_qdevice_get_extra_info,
434 .name =
"corosync vote quorum service v1.0",
437 .private_data_size =
sizeof (
struct quorum_pd),
440 .lib_init_fn = quorum_lib_init_fn,
441 .lib_exit_fn = quorum_lib_exit_fn,
442 .lib_engine = quorum_lib_service,
444 .exec_init_fn = votequorum_exec_init_fn,
445 .exec_exit_fn = votequorum_exec_exit_fn,
446 .exec_engine = votequorum_exec_engine,
449 .sync_process = votequorum_sync_process,
450 .sync_activate = votequorum_sync_activate,
451 .sync_abort = votequorum_sync_abort
456 return (&votequorum_service_engine);
461 .name =
"corosync_votequorum",
471#define max(a,b) (((a) > (b)) ? (a) : (b))
473static void node_add_ordered(
struct cluster_node *newnode)
476 struct qb_list_head *tmp;
480 qb_list_for_each(tmp, &cluster_members_list) {
488 qb_list_add(&newnode->
list, &cluster_members_list);
490 qb_list_add_tail(&newnode->
list, &node->
list);
499 struct qb_list_head *tmp;
504 cl = (
struct cluster_node *)&cluster_nodes[cluster_nodes_entries];
505 cluster_nodes_entries++;
507 qb_list_for_each(tmp, &cluster_members_list) {
526 node_add_ordered(cl);
538 struct qb_list_head *tmp;
542 if (
nodeid == us->node_id) {
552 qb_list_for_each(tmp, &cluster_members_list) {
564static void get_lowest_node_id(
void)
567 struct qb_list_head *tmp;
571 lowest_node_id = us->node_id;
573 qb_list_for_each(tmp, &cluster_members_list) {
576 (node->
node_id < lowest_node_id)) {
577 lowest_node_id = node->
node_id;
586static void get_highest_node_id(
void)
589 struct qb_list_head *tmp;
593 highest_node_id = us->node_id;
595 qb_list_for_each(tmp, &cluster_members_list) {
598 (node->
node_id > highest_node_id)) {
599 highest_node_id = node->
node_id;
608static int check_low_node_id_partition(
void)
611 struct qb_list_head *tmp;
616 qb_list_for_each(tmp, &cluster_members_list) {
619 (node->
node_id == lowest_node_id)) {
628static int check_high_node_id_partition(
void)
631 struct qb_list_head *tmp;
636 qb_list_for_each(tmp, &cluster_members_list) {
639 (node->
node_id == highest_node_id)) {
648static int is_in_nodelist(
int nodeid,
unsigned int *members,
int entries)
653 for (i=0; i<entries; i++) {
654 if (
nodeid == members[i]) {
676static int check_auto_tie_breaker(
void)
683 res = check_low_node_id_partition();
689 res = check_high_node_id_partition();
696 for (i=0; i < atb_nodelist_entries; i++) {
697 if (is_in_nodelist(atb_nodelist[i], quorum_members, quorum_members_entries)) {
704 for (j=0; j<i; j++) {
705 if (is_in_nodelist(atb_nodelist[j], previous_quorum_members, previous_quorum_members_entries)) {
732static void parse_atb_string(
char *atb_string)
740 if (!strcmp(atb_string,
"lowest"))
743 if (!strcmp(atb_string,
"highest"))
746 if (atoi(atb_string)) {
748 atb_nodelist_entries = 0;
751 num = strtol(ptr, &ptr, 10);
754 atb_nodelist[atb_nodelist_entries++] = num;
758 if (atb_nodelist_entries) {
767 log_printf(
LOGSYS_LEVEL_WARNING,
"auto_tie_breaker_nodes is not valid. It must be 'lowest', 'highest' or a space-separated list of node IDs. auto_tie_breaker is disabled");
773static int check_qdevice_master(
void)
776 struct qb_list_head *tmp;
781 qb_list_for_each(tmp, &cluster_members_list) {
794static void decode_flags(uint32_t
flags)
799 "flags: quorate: %s Leaving: %s WFA Status: %s First: %s Qdevice: %s QdeviceAlive: %s QdeviceCastVote: %s QdeviceMasterWins: %s",
815static int load_ev_tracking_barrier(
void)
818 char filename[PATH_MAX];
822 snprintf(filename,
sizeof(filename) - 1,
"%s/ev_tracking",
get_state_dir());
824 ev_tracking_fd = open(filename, O_RDWR, 0700);
825 if (ev_tracking_fd != -1) {
826 res = read (ev_tracking_fd, &ev_tracking_barrier,
sizeof(uint32_t));
827 close(ev_tracking_fd);
828 if (res ==
sizeof (uint32_t)) {
834 ev_tracking_barrier = 0;
836 ev_tracking_fd = open (filename, O_CREAT|O_RDWR, 0700);
837 if (ev_tracking_fd != -1) {
838 res = write (ev_tracking_fd, &ev_tracking_barrier,
sizeof (uint32_t));
839 if ((res == -1) || (res !=
sizeof (uint32_t))) {
841 "Unable to write to %s", filename);
843 close(ev_tracking_fd);
848 "Unable to create %s file", filename);
855static void update_wait_for_all_status(uint8_t wfa_status)
859 wait_for_all_status = wfa_status;
860 if (wait_for_all_status) {
866 wait_for_all_status);
871static void update_two_node(
void)
890static void update_qdevice_can_operate(uint8_t status)
894 qdevice_can_operate = status;
895 icmap_set_uint8(
"runtime.votequorum.qdevice_can_operate", qdevice_can_operate);
900static void update_qdevice_master_wins(uint8_t allow)
904 qdevice_master_wins = allow;
905 icmap_set_uint8(
"runtime.votequorum.qdevice_master_wins", qdevice_master_wins);
910static void update_ev_tracking_barrier(uint32_t ev_t_barrier)
916 ev_tracking_barrier = ev_t_barrier;
917 icmap_set_uint32(
"runtime.votequorum.ev_tracking_barrier", ev_tracking_barrier);
919 if (lseek (ev_tracking_fd, 0, SEEK_SET) != 0) {
921 "Unable to update ev_tracking_barrier on disk data!!!");
926 res = write (ev_tracking_fd, &ev_tracking_barrier,
sizeof (uint32_t));
927 if (res !=
sizeof (uint32_t)) {
929 "Unable to update ev_tracking_barrier on disk data!!!");
932 fdatasync(ev_tracking_fd);
934 fsync(ev_tracking_fd);
944static int calculate_quorum(
int allow_decrease,
unsigned int max_expected,
unsigned int *ret_total_votes)
946 struct qb_list_head *nodelist;
948 unsigned int total_votes = 0;
949 unsigned int highest_expected = 0;
950 unsigned int newquorum, q1, q2;
951 unsigned int total_nodes = 0;
955 if ((allow_downscale) && (allow_decrease) && (max_expected)) {
956 max_expected =
max(ev_barrier, max_expected);
959 qb_list_for_each(nodelist, &cluster_members_list) {
967 total_votes += node->
votes;
974 total_votes += qdevice->votes;
978 if (max_expected > 0) {
979 highest_expected = max_expected;
986 q1 = (highest_expected + 2) / 2;
987 q2 = (total_votes + 2) / 2;
988 newquorum =
max(q1, q2);
994 if (!allow_decrease) {
995 newquorum =
max(quorum, newquorum);
1005 if (two_node && total_nodes <= 2) {
1009 if (ret_total_votes) {
1010 *ret_total_votes = total_votes;
1017static void update_node_expected_votes(
int new_expected_votes)
1019 struct qb_list_head *nodelist;
1022 if (new_expected_votes) {
1023 qb_list_for_each(nodelist, &cluster_members_list) {
1033static void are_we_quorate(
unsigned int total_votes)
1036 int quorum_change = 0;
1044 if ((wait_for_all) && (wait_for_all_status)) {
1045 if (total_votes != us->expected_votes) {
1047 "Waiting for all cluster members. "
1048 "Current votes: %d expected_votes: %d",
1049 total_votes, us->expected_votes);
1050 assert(!cluster_is_quorate);
1053 update_wait_for_all_status(0);
1056 if (quorum > total_votes) {
1060 get_lowest_node_id();
1061 get_highest_node_id();
1064 if ((auto_tie_breaker !=
ATB_NONE) &&
1066 (total_votes == (us->expected_votes / 2)) &&
1068 (previous_quorum_members_entries - quorum_members_entries < quorum) &&
1069 (check_auto_tie_breaker() == 1)) {
1073 if ((qdevice_master_wins) &&
1075 (check_qdevice_master() == 1)) {
1080 if (cluster_is_quorate && !
quorate) {
1084 if (!cluster_is_quorate &&
quorate) {
1090 if (cluster_is_quorate) {
1098 update_wait_for_all_status(0);
1100 update_wait_for_all_status(1);
1104 if ((quorum_change) &&
1105 (sync_in_progress == 0)) {
1106 quorum_callback(quorum_members, quorum_members_entries,
1107 cluster_is_quorate, &quorum_ringid);
1108 votequorum_exec_send_quorum_notification(NULL, 0L);
1114static void get_total_votes(
unsigned int *totalvotes,
unsigned int *current_members)
1116 unsigned int total_votes = 0;
1117 unsigned int cluster_members = 0;
1118 struct qb_list_head *nodelist;
1123 qb_list_for_each(nodelist, &cluster_members_list) {
1127 total_votes += node->
votes;
1131 if (qdevice->votes) {
1132 total_votes += qdevice->votes;
1136 *totalvotes = total_votes;
1137 *current_members = cluster_members;
1145static void recalculate_quorum(
int allow_decrease,
int by_current_nodes)
1147 unsigned int total_votes = 0;
1148 unsigned int cluster_members = 0;
1152 get_total_votes(&total_votes, &cluster_members);
1154 if (!by_current_nodes) {
1155 cluster_members = 0;
1162 if (total_votes > us->expected_votes) {
1163 us->expected_votes = total_votes;
1164 votequorum_exec_send_expectedvotes_notification();
1167 if ((ev_tracking) &&
1168 (us->expected_votes > ev_tracking_barrier)) {
1169 update_ev_tracking_barrier(us->expected_votes);
1172 quorum = calculate_quorum(allow_decrease, cluster_members, &total_votes);
1173 update_node_expected_votes(cluster_members);
1175 are_we_quorate(total_votes);
1184static int votequorum_read_nodelist_configuration(uint32_t *
votes,
1189 const char *iter_key;
1191 uint32_t our_pos, node_pos, last_node_pos=-1;
1192 uint32_t nodecount = 0;
1193 uint32_t nodelist_expected_votes = 0;
1194 uint32_t node_votes = 0;
1201 "No nodelist defined or our node is not in the nodelist");
1209 res = sscanf(iter_key,
"nodelist.node.%u.%s", &node_pos, tmp_key);
1219 if (last_node_pos == node_pos) {
1222 last_node_pos = node_pos;
1231 nodelist_expected_votes = nodelist_expected_votes + node_votes;
1233 if (node_pos == our_pos) {
1234 *
votes = node_votes;
1248static int votequorum_qdevice_is_configured(uint32_t *qdevice_votes)
1250 char *qdevice_model = NULL;
1256 if (strlen(qdevice_model)) {
1258 *qdevice_votes = -1;
1266 update_qdevice_can_operate(1);
1270 free(qdevice_model);
1278#define VOTEQUORUM_READCONFIG_STARTUP 0
1279#define VOTEQUORUM_READCONFIG_RUNTIME 1
1281static char *votequorum_readconfig(
int runtime)
1283 uint32_t node_votes = 0, qdevice_votes = 0;
1285 uint32_t node_count = 0;
1287 int have_nodelist, have_qdevice;
1288 char *atb_string = NULL;
1306 auto_tie_breaker = initial_auto_tie_breaker;
1314 have_nodelist = votequorum_read_nodelist_configuration(&node_votes, &node_count, &node_expected_votes);
1315 have_qdevice = votequorum_qdevice_is_configured(&qdevice_votes);
1324 error = (
char *)
"configuration error: nodelist or quorum.expected_votes must be configured!";
1337 if ((two_node) && (have_qdevice)) {
1339 error = (
char *)
"configuration error: two_node and quorum device cannot be configured at the same time!";
1348 update_qdevice_can_operate(0);
1359 wait_for_all_autoset = 1;
1361 (void)
icmap_get_uint8(
"quorum.last_man_standing", &last_man_standing);
1362 (void)
icmap_get_uint32(
"quorum.last_man_standing_window", &last_man_standing_window);
1363 (void)
icmap_get_uint8(
"quorum.expected_votes_tracking", &ev_tracking);
1376 "auto_tie_breaker_node: is meaningless if auto_tie_breaker is set to 0");
1380 if (atb && atb_string) {
1381 parse_atb_string(atb_string);
1384 initial_auto_tie_breaker = auto_tie_breaker;
1387 if (allow_downscale) {
1392 if (load_ev_tracking_barrier() < 0) {
1394 return ((
char *)
"Unable to load ev_tracking file!");
1396 update_ev_tracking_barrier(ev_tracking_barrier);
1406 if (wait_for_all_autoset) {
1407 wait_for_all = two_node;
1413 if (two_node && auto_tie_breaker !=
ATB_NONE) {
1423 if ((auto_tie_breaker !=
ATB_NONE) && (node_expected_votes % 2) &&
1425 if (last_man_standing) {
1434 error = (
char *)
"configuration error: auto_tie_breaker & last_man_standing not available in odd sized cluster";
1453 if ((have_qdevice) && (last_man_standing)) {
1455 error = (
char *)
"configuration error: quorum.device is not compatible with last_man_standing";
1460 update_qdevice_can_operate(0);
1464 if ((have_qdevice) && (auto_tie_breaker !=
ATB_NONE)) {
1466 error = (
char *)
"configuration error: quorum.device is not compatible with auto_tie_breaker";
1471 update_qdevice_can_operate(0);
1475 if ((have_qdevice) && (allow_downscale)) {
1477 error = (
char *)
"configuration error: quorum.device is not compatible with allow_downscale";
1482 update_qdevice_can_operate(0);
1491 if ((
expected_votes) && (have_qdevice) && (qdevice_votes == -1)) {
1493 error = (
char *)
"configuration error: quorum.device.votes must be specified when quorum.expected_votes is set";
1498 update_qdevice_can_operate(0);
1507 if ((have_qdevice) &&
1508 (qdevice_votes == -1) &&
1510 (node_count != node_expected_votes)) {
1512 error = (
char *)
"configuration error: quorum.device.votes must be specified when not all nodes votes 1";
1517 update_qdevice_can_operate(0);
1529 error = (
char *)
"configuration error: quorum.device.votes is too high or expected_votes is too low";
1534 update_qdevice_can_operate(0);
1543 if ((have_qdevice) &&
1544 (qdevice_votes == -1) &&
1547 (node_count == node_expected_votes)) {
1548 qdevice_votes = node_expected_votes - 1;
1549 node_expected_votes = node_expected_votes + qdevice_votes;
1561 if (have_nodelist) {
1562 us->votes = node_votes;
1563 us->expected_votes = node_expected_votes;
1577 if (!have_qdevice) {
1581 if (qdevice_votes != -1) {
1582 qdevice->votes = qdevice_votes;
1585 update_ev_barrier(us->expected_votes);
1589 update_wait_for_all_status(1);
1591 }
else if (wait_for_all_autoset && wait_for_all_status) {
1596 update_wait_for_all_status(0);
1604static void votequorum_refresh_config(
1606 const char *key_name,
1611 int old_votes, old_expected_votes;
1614 int32_t reload_status;
1622 if (
icmap_get_uint8(
"config.totemconfig_reload_in_progress", &reloading) ==
CS_OK && reloading) {
1627 if ( (strcmp(key_name,
"config.totemconfig_reload_in_progress") == 0) &&
1629 (reload_status !=
CS_OK) ) {
1634 if (strcmp(key_name,
"quorum.cancel_wait_for_all") == 0 &&
1644 old_votes = us->votes;
1645 old_expected_votes = us->expected_votes;
1655 votequorum_exec_send_nodeinfo(us->node_id);
1657 if (us->votes != old_votes) {
1659 us->node_id, us->votes)) {
1663 if (us->expected_votes != old_expected_votes) {
1665 us->node_id, us->expected_votes)) {
1673static void votequorum_exec_add_config_notification(
void)
1683 votequorum_refresh_config,
1685 &icmap_track_nodelist);
1689 votequorum_refresh_config,
1691 &icmap_track_quorum);
1695 votequorum_refresh_config,
1697 &icmap_track_reload);
1706static int votequorum_exec_send_reconfigure(uint8_t
param,
unsigned int nodeid, uint32_t
value)
1709 struct iovec iov[1];
1727 ret = corosync_api->totem_mcast (iov, 1,
TOTEM_AGREED);
1733static int votequorum_exec_send_nodeinfo(uint32_t
nodeid)
1736 struct iovec iov[1];
1742 node = find_node_by_nodeid(
nodeid);
1753 decode_flags(node->
flags);
1762 ret = corosync_api->totem_mcast (iov, 1,
TOTEM_AGREED);
1768static int votequorum_exec_send_qdevice_reconfigure(
const char *
oldname,
const char *
newname)
1771 struct iovec iov[1];
1788 ret = corosync_api->totem_mcast (iov, 1,
TOTEM_AGREED);
1794static int votequorum_exec_send_qdevice_reg(uint32_t
operation,
const char *qdevice_name_req)
1797 struct iovec iov[1];
1812 ret = corosync_api->totem_mcast (iov, 1,
TOTEM_AGREED);
1818static int votequorum_exec_send_quorum_notification(
void *conn, uint64_t context)
1821 struct qb_list_head *tmp;
1824 int cluster_members = 0;
1832 qb_list_for_each(tmp, &cluster_members_list) {
1843 res_lib_votequorum_notification->quorate = cluster_is_quorate;
1844 res_lib_votequorum_notification->context = context;
1845 res_lib_votequorum_notification->node_list_entries = cluster_members;
1847 res_lib_votequorum_notification->header.size = size;
1848 res_lib_votequorum_notification->header.error =
CS_OK;
1851 qb_list_for_each(tmp, &cluster_members_list) {
1853 res_lib_votequorum_notification->node_list[i].nodeid = node->
node_id;
1854 res_lib_votequorum_notification->node_list[i++].state = node->
state;
1858 res_lib_votequorum_notification->node_list[i++].state = qdevice->state;
1863 int ret = corosync_api->ipc_dispatch_send(conn, &buf, size);
1869 qb_list_for_each(tmp, &trackers_list) {
1872 corosync_api->ipc_dispatch_send(qpd->
conn, &buf, size);
1881static int votequorum_exec_send_nodelist_notification(
void *
conn, uint64_t context)
1886 struct qb_list_head *tmp;
1896 res_lib_votequorum_notification->node_list_entries = quorum_members_entries;
1897 res_lib_votequorum_notification->ring_id.nodeid = quorum_ringid.nodeid;
1898 res_lib_votequorum_notification->ring_id.seq = quorum_ringid.seq;
1899 res_lib_votequorum_notification->context = context;
1901 for (i=0; i<quorum_members_entries; i++) {
1902 res_lib_votequorum_notification->node_list[i] = quorum_members[i];
1906 res_lib_votequorum_notification->header.size = size;
1907 res_lib_votequorum_notification->header.error =
CS_OK;
1911 int ret = corosync_api->ipc_dispatch_send(conn, &buf, size);
1917 qb_list_for_each(tmp, &trackers_list) {
1920 corosync_api->ipc_dispatch_send(qpd->
conn, &buf, size);
1929static void votequorum_exec_send_expectedvotes_notification(
void)
1933 struct qb_list_head *tmp;
1944 qb_list_for_each(tmp, &trackers_list) {
1945 qpd = qb_list_entry(tmp,
struct quorum_pd, list);
1954static void exec_votequorum_qdevice_reconfigure_endian_convert (
void *message)
1961static void message_handler_req_exec_votequorum_qdevice_reconfigure (
1962 const void *message,
1988static void exec_votequorum_qdevice_reg_endian_convert (
void *message)
1999static void message_handler_req_exec_votequorum_qdevice_reg (
2000 const void *message,
2005 int wipe_qdevice_name = 1;
2007 struct qb_list_head *tmp;
2019 if (
nodeid != us->node_id) {
2020 if (!strlen(qdevice_name)) {
2041 if (!qdevice_reg_conn) {
2050 if (!strlen(qdevice_name)) {
2061 votequorum_exec_send_nodeinfo(us->node_id);
2064 "A new qdevice with different name (new: %s old: %s) is trying to register!",
2073 qdevice_reg_conn = NULL;
2076 qb_list_for_each(tmp, &cluster_members_list) {
2080 wipe_qdevice_name = 0;
2084 if (wipe_qdevice_name) {
2093static void exec_votequorum_nodeinfo_endian_convert (
void *message)
2107static void message_handler_req_exec_votequorum_nodeinfo (
2108 const void *message,
2109 unsigned int sender_nodeid)
2118 int allow_downgrade = 0;
2135 node = find_node_by_nodeid(
nodeid);
2137 node = allocate_node(
nodeid);
2141 corosync_api->error_memory_failure();
2152 old_votes = node->
votes;
2154 old_state = node->
state;
2155 old_flags = node->
flags;
2159 struct cluster_node *sender_node = find_node_by_nodeid(sender_nodeid);
2161 assert(sender_node != NULL);
2163 if ((!cluster_is_quorate) &&
2179 allow_downgrade = 1;
2183 if ((!cluster_is_quorate) &&
2185 allow_downgrade = 1;
2195 if ((last_man_standing) && (node->
votes > 1)) {
2197 "cluster nodes votes are set to 1. Disabling LMS.");
2198 last_man_standing = 0;
2199 if (last_man_standing_timer_set) {
2200 corosync_api->timer_delete(last_man_standing_timer);
2201 last_man_standing_timer_set = 0;
2207 (
nodeid == us->node_id) ||
2209 (old_votes != node->
votes) ||
2211 (old_flags != node->
flags) ||
2212 (old_state != node->
state)) {
2213 recalculate_quorum(allow_downgrade, by_node);
2216 if ((wait_for_all) &&
2219 update_wait_for_all_status(0);
2225static void exec_votequorum_reconfigure_endian_convert (
void *message)
2237static void message_handler_req_exec_votequorum_reconfigure (
2238 const void *message,
2253 votequorum_exec_send_expectedvotes_notification();
2256 us->expected_votes =
max(us->expected_votes, ev_tracking_barrier);
2258 recalculate_quorum(1, 0);
2268 recalculate_quorum(1, 0);
2272 update_wait_for_all_status(0);
2275 recalculate_quorum(0, 0);
2284static int votequorum_exec_exit_fn (
void)
2294 if (allow_downscale) {
2296 ret = votequorum_exec_send_nodeinfo(us->node_id);
2299 if ((ev_tracking) && (ev_tracking_fd != -1)) {
2300 close(ev_tracking_fd);
2308static void votequorum_set_icmap_ro_keys(
void)
2328 qb_list_init(&cluster_members_list);
2329 qb_list_init(&trackers_list);
2332 memset(cluster_nodes, 0,
sizeof(cluster_nodes));
2340 return ((
char *)
"Could not allocate node.");
2348 us = allocate_node(corosync_api->totem_nodeid_get());
2351 return ((
char *)
"Could not allocate node.");
2364 recalculate_quorum(0, 0);
2369 votequorum_set_icmap_ro_keys();
2374 votequorum_exec_add_config_notification();
2379 votequorum_exec_send_nodeinfo(us->node_id);
2390static void votequorum_last_man_standing_timer_fn(
void *arg)
2394 last_man_standing_timer_set = 0;
2395 if (cluster_is_quorate) {
2396 recalculate_quorum(1,1);
2402static void votequorum_sync_init (
2403 const unsigned int *trans_list,
size_t trans_list_entries,
2404 const unsigned int *member_list,
size_t member_list_entries,
2414 sync_in_progress = 1;
2415 sync_nodeinfo_sent = 0;
2416 sync_wait_for_poll_or_timeout = 0;
2418 if (member_list_entries > 1) {
2428 for (i = 0; i < quorum_members_entries; i++) {
2430 for (j = 0; j < member_list_entries; j++) {
2431 if (quorum_members[i] == member_list[j]) {
2438 node = find_node_by_nodeid(quorum_members[i]);
2445 if (last_man_standing) {
2446 if (((member_list_entries >= quorum) && (left_nodes)) ||
2447 ((member_list_entries <= quorum) && (auto_tie_breaker !=
ATB_NONE) && (check_low_node_id_partition() == 1))) {
2448 if (last_man_standing_timer_set) {
2449 corosync_api->timer_delete(last_man_standing_timer);
2450 last_man_standing_timer_set = 0;
2452 corosync_api->timer_add_duration((
unsigned long long)last_man_standing_window*1000000,
2453 NULL, votequorum_last_man_standing_timer_fn,
2454 &last_man_standing_timer);
2455 last_man_standing_timer_set = 1;
2459 memcpy(previous_quorum_members, quorum_members,
sizeof(
unsigned int) * quorum_members_entries);
2460 previous_quorum_members_entries = quorum_members_entries;
2462 memcpy(quorum_members, member_list,
sizeof(
unsigned int) * member_list_entries);
2463 quorum_members_entries = member_list_entries;
2470 if (qdevice_timer_set) {
2471 corosync_api->timer_delete(qdevice_timer);
2473 corosync_api->timer_add_duration((
unsigned long long)qdevice_sync_timeout*1000000, qdevice,
2474 qdevice_timer_fn, &qdevice_timer);
2475 qdevice_timer_set = 1;
2476 sync_wait_for_poll_or_timeout = 1;
2479 qdevice_name, qdevice_sync_timeout);
2485static int votequorum_sync_process (
void)
2487 if (!sync_nodeinfo_sent) {
2488 votequorum_exec_send_nodeinfo(us->node_id);
2490 votequorum_exec_send_set_qdevice_extra_info(us->node_id);
2493 if (strlen(qdevice_name)) {
2497 votequorum_exec_send_nodelist_notification(NULL, 0LL);
2498 sync_nodeinfo_sent = 1;
2512static void votequorum_sync_activate (
void)
2514 recalculate_quorum(0, 0);
2515 quorum_callback(quorum_members, quorum_members_entries,
2516 cluster_is_quorate, &quorum_ringid);
2517 votequorum_exec_send_quorum_notification(NULL, 0L);
2519 sync_in_progress = 0;
2522static void votequorum_sync_abort (
void)
2534 if (q_set_quorate_fn == NULL) {
2535 return ((
char *)
"Quorate function not set");
2539 quorum_callback = q_set_quorate_fn;
2542 &votequorum_service[0]);
2556static int quorum_lib_init_fn (
void *conn)
2562 qb_list_init (&pd->
list);
2569static int quorum_lib_exit_fn (
void *
conn)
2589static void qdevice_timer_fn(
void *arg)
2594 (!qdevice_timer_set)) {
2602 votequorum_exec_send_nodeinfo(us->node_id);
2604 qdevice_timer_set = 0;
2605 sync_wait_for_poll_or_timeout = 0;
2614static void message_handler_req_lib_votequorum_getinfo (
void *
conn,
const void *message)
2619 unsigned int highest_expected = 0;
2620 unsigned int total_votes = 0;
2632 node = find_node_by_nodeid(
nodeid);
2635 struct qb_list_head *nodelist;
2637 qb_list_for_each(nodelist, &cluster_members_list) {
2638 iternode = qb_list_entry(nodelist,
struct cluster_node, list);
2643 total_votes += iternode->
votes;
2648 total_votes += qdevice->votes;
2651 switch(node->
state) {
2678 if (cluster_is_quorate) {
2684 if (last_man_standing) {
2687 if (auto_tie_breaker !=
ATB_NONE) {
2690 if (allow_downscale) {
2726static void message_handler_req_lib_votequorum_setexpected (
void *conn,
const void *message)
2731 unsigned int newquorum;
2732 unsigned int total_votes;
2733 uint8_t allow_downscale_status = 0;
2737 allow_downscale_status = allow_downscale;
2738 allow_downscale = 0;
2744 allow_downscale = allow_downscale_status;
2750 (cluster_is_quorate && (newquorum > total_votes))) {
2770static void message_handler_req_lib_votequorum_setvotes (
void *conn,
const void *message)
2775 unsigned int newquorum;
2776 unsigned int total_votes;
2777 unsigned int saved_votes;
2784 node = find_node_by_nodeid(
nodeid);
2793 saved_votes = node->
votes;
2796 newquorum = calculate_quorum(1, 0, &total_votes);
2798 if (newquorum < total_votes / 2 ||
2799 newquorum > total_votes) {
2800 node->
votes = saved_votes;
2819static void message_handler_req_lib_votequorum_trackstart (
void *conn,
2820 const void *message)
2868static void message_handler_req_lib_votequorum_trackstop (
void *
conn,
2869 const void *message)
2894static void message_handler_req_lib_votequorum_qdevice_register (
void *
conn,
2895 const void *message)
2903 if (!qdevice_can_operate) {
2904 log_printf(
LOGSYS_LEVEL_INFO,
"Registration of quorum device is disabled by incorrect corosync.conf. See logs for more information");
2915 "A new qdevice with different name (new: %s old: %s) is trying to re-register!",
2921 if (qdevice_reg_conn != NULL) {
2923 "Registration request already in progress");
2927 qdevice_reg_conn = conn;
2931 "Unable to send qdevice registration request to cluster");
2933 qdevice_reg_conn = NULL;
2950static void message_handler_req_lib_votequorum_qdevice_unregister (
void *conn,
2951 const void *message)
2964 if (qdevice_timer_set) {
2965 corosync_api->timer_delete(qdevice_timer);
2966 qdevice_timer_set = 0;
2967 sync_wait_for_poll_or_timeout = 0;
2976 votequorum_exec_send_set_qdevice_extra_info(us->node_id);
2978 votequorum_exec_send_nodeinfo(us->node_id);
2994static void message_handler_req_lib_votequorum_qdevice_update (
void *conn,
2995 const void *message)
3023static void message_handler_req_lib_votequorum_qdevice_poll (
void *conn,
3024 const void *message)
3033 if (!qdevice_can_operate) {
3044 quorum_ringid.nodeid, quorum_ringid.seq);
3053 if (qdevice_timer_set) {
3054 corosync_api->timer_delete(qdevice_timer);
3055 qdevice_timer_set = 0;
3058 oldflags = us->flags;
3068 if (us->flags != oldflags) {
3069 votequorum_exec_send_nodeinfo(us->node_id);
3072 corosync_api->timer_add_duration((
unsigned long long)qdevice_timeout*1000000, qdevice,
3073 qdevice_timer_fn, &qdevice_timer);
3074 qdevice_timer_set = 1;
3075 sync_wait_for_poll_or_timeout = 0;
3089static void message_handler_req_lib_votequorum_qdevice_master_wins (
void *conn,
3090 const void *message)
3095 uint32_t oldflags = us->flags;
3099 if (!qdevice_can_operate) {
3116 if (us->flags != oldflags) {
3117 votequorum_exec_send_nodeinfo(us->node_id);
3134static void fill_extra_info_notification(
3156static int votequorum_exec_send_all_qdevice_extra_info_notification(
void *conn, uint64_t context)
3161 struct qb_list_head *tmp;
3166 qb_list_for_each(tmp, &cluster_members_list) {
3170 "Sending extra info notification for node " CS_PRI_NODE_ID " %" PRIu32
" bytes.",
3174 corosync_api->ipc_dispatch_send(conn,
3186votequorum_exec_send_qdevice_extra_info_notification(uint32_t
nodeid)
3192 struct qb_list_head *tmp;
3200 "Sending extra info notification for node " CS_PRI_NODE_ID " failed, node doesn't exist",
3207 "Sending extra info notification for node " CS_PRI_NODE_ID " %" PRIu32
" bytes.",
3212 qb_list_for_each(tmp, &trackers_list) {
3215 "Sending extra info notification for node " CS_PRI_NODE_ID " message (ctx: %" PRIx64
")",
3218 corosync_api->ipc_dispatch_send(qpd->
conn,
3229votequorum_exec_send_set_qdevice_extra_info(uint32_t
nodeid)
3234 struct iovec iov[1];
3240 node = find_node_by_nodeid(
nodeid);
3243 "Sending mcast extra info for node " CS_PRI_NODE_ID " failed because node doesn't exist",
3250 "Sending mcast extra info for node " CS_PRI_NODE_ID " %" PRIu32
" bytes.",
3266 iov[0].iov_base = (
void *)buf;
3268 ret = corosync_api->totem_mcast (iov, 1,
TOTEM_AGREED);
3276static void message_handler_req_exec_votequorum_qdevice_set_extra_info (
3277 const void *message,
3292 node = find_node_by_nodeid(
nodeid);
3295 "New extra info for node " CS_PRI_NODE_ID " is %" PRIu32
" bytes",
3307 votequorum_exec_send_qdevice_extra_info_notification(
nodeid);
3315static void exec_votequorum_qdevice_set_extra_info_endian_convert (
void *message)
3327static void message_handler_req_lib_votequorum_qdevice_set_extra_info (
void *conn,
3328 const void *message)
3337 "Local set extra info %" PRIu32
" bytes",
3338 req_lib_votequorum_qdevice_set_extra_info->
ei_size);
3340 if (!qdevice_can_operate) {
3352 if(req_lib_votequorum_qdevice_set_extra_info->
ei_size == 0) {
3356 us->ei_size = req_lib_votequorum_qdevice_set_extra_info->
ei_size;
3357 memcpy(us->extra_nodeinfo,
3358 req_lib_votequorum_qdevice_set_extra_info->
extra_info,
3359 req_lib_votequorum_qdevice_set_extra_info->
ei_size);
3362 votequorum_exec_send_set_qdevice_extra_info(us->node_id);
3376static void message_handler_req_lib_votequorum_qdevice_get_extra_info (
void *conn,
3377 const void *message)
3389 if (!qdevice_can_operate) {
3394 struct cluster_node *node = find_node_by_nodeid(req_lib_votequorum_qdevice_get_extra_info->
nodeid);
3405 res_lib_votequorum_qdevice_get_extra_info->
ei_size = 0;
3411 res_lib_votequorum_qdevice_get_extra_info->header.error = error;
3412 corosync_api->ipc_response_send(conn,
3413 res_lib_votequorum_qdevice_get_extra_info,
3414 res_lib_votequorum_qdevice_get_extra_info->header.size);
#define SERVICE_ID_MAKE(a, b)
qb_loop_timer_handle corosync_timer_handle_t
corosync_timer_handle_t
unsigned int nodeid
the ID of the node whose info needs updating
#define COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED
#define COROSYNC_LIB_FLOW_CONTROL_REQUIRED
#define PROCESSOR_COUNT_MAX
#define CS_TRACK_CHANGES_ONLY
cs_error_t
The cs_error_t enum.
void(* quorum_set_quorate_fn_t)(const unsigned int *view_list, size_t view_list_entries, int quorate, struct memb_ring_id *)
struct corosync_service_engine * votequorum_get_service_engine_ver0(void)
#define VOTEQUORUM_RECONFIG_PARAM_CANCEL_WFA
#define NODE_FLAGS_QUORATE
#define NODE_FLAGS_QDEVICE_EXTRA_INFO_SET
#define VOTEQUORUM_RECONFIG_PARAM_NODE_VOTES
char * votequorum_init(struct corosync_api_v1 *api, quorum_set_quorate_fn_t q_set_quorate_fn)
#define VOTEQUORUM_RECONFIG_PARAM_EXPECTED_VOTES
#define VOTEQUORUM_QDEVICE_OPERATION_UNREGISTER
char oldname[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
#define NODE_FLAGS_QDEVICE_REGISTERED
#define MESSAGE_REQ_EXEC_VOTEQUORUM_QDEVICE_RECONFIGURE
char newname[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
#define NODE_FLAGS_QDEVICE_CAST_VOTE
#define MESSAGE_REQ_EXEC_VOTEQUORUM_RECONFIGURE
#define NODE_FLAGS_QDEVICE_MASTER_WINS
#define VOTEQUORUM_READCONFIG_STARTUP
#define NODE_FLAGS_LEAVING
#define NODE_FLAGS_QDEVICE_ALIVE
#define NODE_FLAGS_WFASTATUS
uint32_t ei_size
length of the extra info
#define MESSAGE_REQ_EXEC_VOTEQUORUM_QDEVICE_REG
#define VOTEQUORUM_QDEVICE_OPERATION_REGISTER
#define MESSAGE_REQ_EXEC_VOTEQUORUM_NODEINFO
#define MESSAGE_REQ_EXEC_VOTEQUORUM_QDEVICE_EXTRA_NODEINFO
#define VOTEQUORUM_READCONFIG_RUNTIME
cs_error_t icmap_get_uint8(const char *key_name, uint8_t *u8)
#define ICMAP_TRACK_MODIFY
cs_error_t icmap_get_uint32(const char *key_name, uint32_t *u32)
cs_error_t icmap_set_uint8(const char *key_name, uint8_t value)
cs_error_t icmap_set_ro_access(const char *key_name, int prefix, int ro_access)
Set read-only access for given key (key_name) or prefix, If prefix is set.
#define ICMAP_TRACK_DELETE
cs_error_t icmap_track_add(const char *key_name, int32_t track_type, icmap_notify_fn_t notify_fn, void *user_data, icmap_track_t *icmap_track)
Add tracking function for given key_name.
#define ICMAP_TRACK_PREFIX
Whole prefix is tracked, instead of key only (so "totem." tracking means that "totem....
icmap_iter_t icmap_iter_init(const char *prefix)
Initialize iterator with given prefix.
const char * icmap_iter_next(icmap_iter_t iter, size_t *value_len, icmap_value_types_t *type)
Return next item in iterator iter.
qb_map_iter_t * icmap_iter_t
Itterator type.
void icmap_iter_finalize(icmap_iter_t iter)
Finalize iterator.
struct icmap_track * icmap_track_t
Track type.
cs_error_t icmap_get_int32(const char *key_name, int32_t *i32)
#define ICMAP_KEYNAME_MAXLEN
Maximum length of key in icmap.
cs_error_t icmap_set_uint32(const char *key_name, uint32_t value)
cs_error_t icmap_get_string(const char *key_name, char **str)
Shortcut for icmap_get for string type.
#define VOTEQUORUM_QDEVICE_EXTRA_NODEINFO_MAXSIZE
#define VOTEQUORUM_QDEVICE_DEFAULT_SYNC_TIMEOUT
#define VOTEQUORUM_INFO_QDEVICE_HAS_EXTRA_INFO
#define VOTEQUORUM_INFO_AUTO_TIE_BREAKER
#define VOTEQUORUM_INFO_QDEVICE_ALIVE
#define VOTEQUORUM_NODESTATE_MEMBER
#define VOTEQUORUM_NODESTATE_DEAD
#define VOTEQUORUM_INFO_ALLOW_DOWNSCALE
@ MESSAGE_RES_VOTEQUORUM_QDEVICE_GET_EXTRA_INFO
@ MESSAGE_RES_VOTEQUORUM_NODELIST_NOTIFICATION
@ MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION
@ MESSAGE_RES_VOTEQUORUM_QDEVICE_EXTRA_INFO_NOTIFICATION
@ MESSAGE_RES_VOTEQUORUM_STATUS
@ MESSAGE_RES_VOTEQUORUM_QUORUM_NOTIFICATION
@ MESSAGE_RES_VOTEQUORUM_GETINFO
#define VOTEQUORUM_INFO_QDEVICE_MASTER_WINS
#define VOTEQUORUM_NODESTATE_LEAVING
#define VOTEQUORUM_INFO_TWONODE
#define VOTEQUORUM_INFO_WAIT_FOR_ALL
#define VOTEQUORUM_INFO_QUORATE
#define VOTEQUORUM_INFO_QDEVICE_REGISTERED
#define VOTEQUORUM_INFO_LAST_MAN_STANDING
#define VOTEQUORUM_QDEVICE_MAX_NAME_LEN
#define VOTEQUORUM_QDEVICE_NODEID
#define VOTEQUORUM_INFO_QDEVICE_CAST_VOTE
#define VOTEQUORUM_QDEVICE_DEFAULT_TIMEOUT
#define LOGSYS_LEVEL_ERROR
#define log_printf(level, format, args...)
#define LOGSYS_LEVEL_INFO
#define LOGSYS_LEVEL_CRIT
#define LOGSYS_LEVEL_NOTICE
#define LOGSYS_DECLARE_SUBSYS(subsys)
The LOGSYS_DECLARE_SUBSYS macro.
#define LOGSYS_LEVEL_WARNING
#define LOGSYS_LEVEL_DEBUG
char * corosync_service_link_and_init(struct corosync_api_v1 *corosync_api, struct default_service *service)
Link and initialize a service.
struct corosync_service_engine * votequorum_get_service_engine_ver0(void)
char extra_nodeinfo[VOTEQUORUM_QDEVICE_EXTRA_NODEINFO_MAXSIZE]
The corosync_api_v1 struct.
The corosync_exec_handler struct.
The corosync_lib_handler struct.
The corosync_service_engine struct.
Structure passed as new_value and old_value in change callback.
unsigned char track_flags
uint64_t tracking_context
struct qb_ipc_request_header header __attribute__((aligned(8)))
struct qb_ipc_request_header header __attribute__((aligned(8)))
char qdevice_name[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
The req_lib_votequorum_getinfo struct.
The req_lib_votequorum_qdevice_master_wins struct.
char name[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
The req_lib_votequorum_qdevice_poll struct.
char name[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
The req_lib_votequorum_qdevice_register struct.
char name[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
The req_lib_votequorum_qdevice_unregister struct.
char name[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
The req_lib_votequorum_qdevice_update struct.
char newname[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
char oldname[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
The req_lib_votequorum_setexpected struct.
unsigned int expected_votes
The req_lib_votequorum_setvotes struct.
The req_lib_votequorum_trackstart struct.
The res_lib_votequorum_expectedvotes_notification struct.
The res_lib_votequorum_getinfo struct.
unsigned int highest_expected
char qdevice_name[VOTEQUORUM_QDEVICE_MAX_NAME_LEN]
unsigned int expected_votes
unsigned int qdevice_votes
The res_lib_votequorum_quorum_notification struct.
The res_lib_votequorum_status struct.
The votequorum_node struct.
#define swab32(x)
The swab32 macro.
int sync_init(int(*sync_callbacks_retrieve)(int service_id, struct sync_callbacks *callbacks), void(*synchronization_completed)(void))
struct memb_ring_id ring_id
struct totem_message_header header
const char * get_state_dir(void)