On 02/23/2012 04:30 PM, Christine Caulfield wrote: > ACK with some changes as discussed on IRC Thanks for the review, I am going to implement the qdevice_register locking directly and that will save some 255 bytes on the network, plus simplify some of the code that we were discussing about on IRC. I'll try to send a patch by Monday. Fabio > > Reviewed-By: Christine Caulfield <ccaulfie@xxxxxxxxxx> > > On 23/02/12 11:04, Fabio M. Di Nitto wrote: >> From: "Fabio M. Di Nitto"<fdinitto@xxxxxxxxxx> >> >> qdevice is a very special node in the cluster and it adds a certain >> amount of complexity and special cases across the code. >> >> most of the qdevice data are shared across the cluster (name/votes) >> but effectively each node has a different view of the qdevice >> (registered/unregistered/voting/etc.) >> >> with this change, we align the qdevice view across the node, >> exchanging more data between nodes and we fix how qdevice behaves >> and it is configured. >> >> The only side effect is that the amount of data transmitted on wire >> is slightly higher. >> >> The qdevice API is still disabled by default. This means that >> the amount of real changes in current code are a lot smaller >> than it appears by this patch. >> >> TODO: documentation/man pages needs to be updated once >> this change is in (and behavior finalized). >> >> User visible changes: >> >> - configuration (coroparse, exec/votequorum): >> the quorum device section is now standalone within the quorum. >> >> quorum { >> provider: corosync_votequorum >> device { >> model: (name) >> timeout: (millisec) >> votes: >> } >> } >> >> the keyword "model:" is mandatory to enable qdevice in configuration >> and should express the name of the script/daemon that will provide >> the qdevice. Looking into the future, an init script or systemd >> service will look for that name in /path/to/be/decided/name >> and start/stop qdevice. >> >> timeout: defines the maximum interval the qdevice implementation >> has available between poll (see votequorum_qdevice_poll.3) before >> the device is considered dead and votes discarded >> >> votes: is now a configuration parameter and not an API call. >> quorum devices don't care what they need to vote. >> votes is autocalculated when a nodelist is available and all >> nodes in the list vote 1. Otherwise this parameter is mandatory. >> >> - configuration (exec/votequorum): >> startup and runtime configuration changes have been improved. >> errors at startup are considered fatal. errors at runtime >> have different exit paths. >> >> startup: >> >> * quorum.two_node and qdevice are incompatible. >> * quorum.expected_votes requires quorum.device.votes. >> * quorum.expected_votes - quorum.device.votes cannot be lower >> than 2. >> * qdevice and last_man_standing are mutually exclusive. >> * qdevice and auto_tie_breaker are mutually exclusive. >> >> runtime config changes: >> >> * quorum.two_node and qdevice are incompatible: >> if quorum device is alive, two_node is disabled. >> if quorum device is not alive and node count is 2, two_node is >> enabled, and quorum device cannot be registered >> >> * if either last_man_standing or auto_tie_breaker were enabled >> at startup, and at runtime quorum device is configured, >> quorum device registration will be blocked. >> >> * if quorum.expected_votes is configured but not quorum.device.votes, >> quorum device registration will be blocked. >> >> * if quorum.device.votes is not configured and we cannot >> automatically calculate it, quorum device registration will be >> blocked. >> >> * An error in configuring quorum.expected_votes and >> quorum.device.votes >> will block quorum device registration. >> >> blocking quorum device registation, also means dropping the votes. >> >> quorum.device.votes (either set or automatically calculated) is now >> used to determine current expected_votes in the cluster. >> >> - logging (exec/votequorum): >> >> all errors from configuration are treated as WARNING/CRITICAL. >> >> lots of extra DEBUG output is added (see internal changes too). >> >> - corosync-quorumtool (tools/corosync-quorumtool): >> >> * added option to forcefully kick out a quorum device from the local >> node. This is for emergency recovery only and it is only >> available when qdevice API is built-in. >> >> * Improved status output, specifically add node state and qdevice >> information >> >> [root@fedora-master-node2 coro]# corosync-quorumtool -s >> Version: 1.99.4.12-9c7d-dirty >> Quorum type: corosync_votequorum >> Nodes: 2 >> Ring ID: 132 >> Quorate: Yes >> Node votes: 1 >> Node state: Member >> Expected votes: 3 >> Highest expected: 3 >> Total votes: 3 >> Quorum: 2 >> Flags: Quorate Qdevice >> Nodeid Votes Name >> 1 1 fedora-master-node1.int.fabbione.net >> 2 1 fedora-master-node2.int.fabbione.net >> 0 1 QDEVICE (Voting) >> >> * allow to print status for any node in the cluster known to >> local node. >> >> [root@fedora-master-node1 coro]# corosync-quorumtool -s >> Version: 1.99.4.12-9c7d-dirty >> Quorum type: corosync_votequorum >> Nodes: 2 >> Ring ID: 144 >> Quorate: Yes >> Node votes: 1 >> Node state: Member >> Expected votes: 3 >> Highest expected: 3 >> Total votes: 2 >> Quorum: 2 >> Flags: Quorate >> Nodeid Votes Name >> 1 1 fedora-master-node1.int.fabbione.net >> 2 1 fedora-master-node2.int.fabbione.net >> >> [root@fedora-master-node1 coro]# corosync-quorumtool -s -n 2 >> Version: 1.99.4.12-9c7d-dirty >> Quorum type: corosync_votequorum >> Nodes: 2 >> Ring ID: 144 >> Quorate: Yes >> Node votes: 1 >> Node state: Member >> Expected votes: 3 >> Highest expected: 3 >> Total votes: 3 >> Quorum: 2 >> Flags: Quorate Qdevice >> Nodeid Votes Name >> 1 1 fedora-master-node1.int.fabbione.net >> 2 1 fedora-master-node2.int.fabbione.net >> 0 1 QDEVICE (Voting) >> >> Internal changes: >> >> - change qdevice to not run all time, but only when necessary. >> - change votequorum_nodeinfo on wire data to include >> qdevice name and use flags instead of uint8_t. >> - allocate nodeid 0 to qdevice since it's the only real >> nodeid that be reserved. >> - change send_nodeinfo to allow to send nodeinfo for any node >> so that we can share qdevice info across the cluster >> (and this might be useful in future if we need to sync >> internal cluster view). >> - add votequorum api call to update qdevice name >> - add runtime data if quorum device has been forcefully disabled >> by config error >> - add qdevice votes to expected_votes calculation (this >> is probably the biggest difference vs cman) >> - change votequorum_read_nodelist_configuration so that >> we can autocalculate votes for qdevice (we need the nodecount >> vs votes). >> - add all checks for startup/runtime config (see above). >> - maintain qdevice information for each node. This is necessary >> because the qdevice cluster_node is local only and >> lay down the road to improve user error configuration in future >> (for example we will be able to block 2 different qdevice model >> to be used in the cluster at the same time). >> - do not make qdevice part of the membership_list received from >> totem. None of our users care about it and it is not a real node. >> - change onwire message handlers to deal with "data for this node from >> any node" >> case and undersand nodeid 0 for qdevice info >> - always allocate qdevice at startup. this simplifies code a lot. >> - dispatch qdevice nodeinfo on membership changes. >> - inform libvotequorum users when a qdevice is registered >> - improve substantially qdevice api and add a simple (for now) >> barrier based on qdevice name. Plan is that only qdevice >> with the same name can register across the cluster. >> - qdevice getinfo can now report status for qdevice on any node. >> - change slightly the way the qdevice API is built-in/out: >> only the libvotequorum calls are #ifdef'out now. Doing so in >> the core is too complex and would make the code unreadable >> with the risk of missing a bit or two effectively introducing >> an on-wire incompatibility if we will ever turn the API on. >> - probably added some bugs on the way... >> >> TODO: update qdevice_* API once the above is settled and test >> qdevice integration with other features. >> >> Signed-off-by: Fabio M. Di Nitto<fdinitto@xxxxxxxxxx> >> --- >> exec/coroparse.c | 17 +- >> exec/votequorum.c | 728 >> +++++++++++++++++++++++++++---------- >> include/corosync/ipc_votequorum.h | 31 ++- >> include/corosync/votequorum.h | 26 +- >> lib/votequorum.c | 46 ++- >> test/testvotequorum2.c | 23 +- >> tools/corosync-quorumtool.c | 133 ++++++- >> 7 files changed, 766 insertions(+), 238 deletions(-) >> >> diff --git a/exec/coroparse.c b/exec/coroparse.c >> index e6a5cb8..1d97323 100644 >> --- a/exec/coroparse.c >> +++ b/exec/coroparse.c >> @@ -87,6 +87,7 @@ enum main_cp_cb_data_state { >> MAIN_CP_CB_DATA_STATE_LOGGING_DAEMON, >> MAIN_CP_CB_DATA_STATE_MEMBER, >> MAIN_CP_CB_DATA_STATE_QUORUM, >> + MAIN_CP_CB_DATA_STATE_QDEVICE, >> MAIN_CP_CB_DATA_STATE_NODELIST, >> MAIN_CP_CB_DATA_STATE_NODELIST_NODE, >> }; >> @@ -388,7 +389,6 @@ static int main_config_parser_cb(const char *path, >> case MAIN_CP_CB_DATA_STATE_QUORUM: >> if ((strcmp(path, "quorum.expected_votes") == 0) || >> (strcmp(path, "quorum.votes") == 0) || >> - (strcmp(path, "quorum.quorumdev_poll") == 0) || >> (strcmp(path, "quorum.last_man_standing_window") == >> 0) || >> (strcmp(path, "quorum.leaving_timeout") == 0)) { >> if (safe_atoi(value,&i) != 0) { >> @@ -410,6 +410,15 @@ static int main_config_parser_cb(const char *path, >> add_as_string = 0; >> } >> break; >> + case MAIN_CP_CB_DATA_STATE_QDEVICE: >> + if ((strcmp(path, "quorum.device.timeout") == 0) || >> + (strcmp(path, "quorum.device.votes") == 0)) { >> + if (safe_atoi(value,&i) != 0) { >> + goto atoi_error; >> + } >> + icmap_set_uint32(path, i); >> + add_as_string = 0; >> + } >> case MAIN_CP_CB_DATA_STATE_TOTEM: >> if ((strcmp(path, "totem.version") == 0) || >> (strcmp(path, "totem.nodeid") == 0) || >> @@ -671,6 +680,9 @@ static int main_config_parser_cb(const char *path, >> if (strcmp(path, "quorum") == 0) { >> data->state = MAIN_CP_CB_DATA_STATE_QUORUM; >> } >> + if (strcmp(path, "quorum.device") == 0) { >> + data->state = MAIN_CP_CB_DATA_STATE_QDEVICE; >> + } >> if (strcmp(path, "nodelist") == 0) { >> data->state = MAIN_CP_CB_DATA_STATE_NODELIST; >> data->node_number = 0; >> @@ -858,6 +870,9 @@ static int main_config_parser_cb(const char *path, >> case MAIN_CP_CB_DATA_STATE_QUORUM: >> data->state = MAIN_CP_CB_DATA_STATE_NORMAL; >> break; >> + case MAIN_CP_CB_DATA_STATE_QDEVICE: >> + data->state = MAIN_CP_CB_DATA_STATE_QUORUM; >> + break; >> case MAIN_CP_CB_DATA_STATE_NODELIST: >> data->state = MAIN_CP_CB_DATA_STATE_NORMAL; >> break; >> diff --git a/exec/votequorum.c b/exec/votequorum.c >> index f7d708f..83f4488 100644 >> --- a/exec/votequorum.c >> +++ b/exec/votequorum.c >> @@ -39,8 +39,6 @@ >> #include<stdint.h> >> >> #include<qb/qbipc_common.h> >> -#include<qb/qbdefs.h> >> -#include<qb/qbutil.h> >> >> #include "quorum.h" >> #include<corosync/corodefs.h> >> @@ -64,12 +62,12 @@ static struct corosync_api_v1 *corosync_api; >> * votequorum global config vars >> */ >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> -#define DEFAULT_QDEV_POLL 10000 >> +#define DEFAULT_QDEVICE_TIMEOUT 10000 >> >> -static unsigned int quorumdev_poll = DEFAULT_QDEV_POLL; >> -static char quorum_device_name[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> -#endif >> +static struct cluster_node *qdevice = NULL; >> +static unsigned int qdevice_timeout = DEFAULT_QDEVICE_TIMEOUT; >> +static uint8_t qdevice_can_operate = 1; >> +static uint8_t qdevice_is_registered = 0; >> >> static uint8_t two_node = 0; >> >> @@ -85,21 +83,18 @@ static uint32_t last_man_standing_window = >> DEFAULT_LMS_WIN; >> >> static uint8_t leave_remove = 0; >> static uint32_t ev_barrier = 0; >> + >> /* >> * votequorum_exec defines/structs/forward definitions >> */ >> >> struct req_exec_quorum_nodeinfo { >> - struct qb_ipc_request_header header __attribute__((aligned(8))); >> + struct qb_ipc_request_header header __attribute__((aligned(8))); >> + uint32_t nodeid; >> uint32_t votes; >> uint32_t expected_votes; >> - uint16_t flags; >> - uint8_t quorate; >> - uint8_t wait_for_all_status; >> - uint8_t first_trans; >> - uint8_t _pad0; >> - uint8_t _pad1; >> - uint8_t _pad2; >> + uint32_t flags; >> + char qdevice_name[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> } __attribute__((packed)); >> >> struct req_exec_quorum_reconfigure { >> @@ -137,10 +132,14 @@ static int >> votequorum_exec_send_reconfigure(uint8_t param, unsigned int nodeid, >> * votequorum internal node status/view >> */ >> >> -#define NODE_FLAGS_LEAVING 1 >> +#define NODE_FLAGS_QUORATE 1 >> +#define NODE_FLAGS_LEAVING 2 >> +#define NODE_FLAGS_WFASTATUS 4 >> +#define NODE_FLAGS_FIRST 8 >> +#define NODE_FLAGS_QDEVICE 16 >> +#define NODE_FLAGS_QDEVICE_STATE 32 >> >> -#define NODEID_US 0 >> -#define NODEID_QDEVICE UINT32_MAX >> +#define NODEID_QDEVICE 0 >> >> typedef enum { >> NODESTATE_MEMBER=1, >> @@ -149,13 +148,13 @@ typedef enum { >> } nodestate_t; >> >> struct cluster_node { >> - int node_id; >> + int node_id; >> nodestate_t state; >> - uint32_t votes; >> - uint32_t expected_votes; >> - uint16_t flags; >> - unsigned long long int last_hello; /* Only used for quorum >> devices */ >> - struct list_head list; >> + uint32_t votes; >> + uint32_t expected_votes; >> + uint32_t flags; >> + char qdevice_name[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> + struct list_head list; >> }; >> >> /* >> @@ -164,14 +163,12 @@ struct cluster_node { >> >> static uint8_t quorum; >> static uint8_t cluster_is_quorate; >> -static uint8_t first_trans = 1; >> >> /* >> * votequorum membership data >> */ >> >> static struct cluster_node *us; >> -static struct cluster_node *quorum_device = NULL; >> static struct list_head cluster_members_list; >> static unsigned int quorum_members[PROCESSOR_COUNT_MAX+1]; >> static int quorum_members_entries = 0; >> @@ -194,9 +191,8 @@ static struct list_head trackers_list; >> * votequorum timers >> */ >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> -static corosync_timer_handle_t quorum_device_timer; >> -#endif >> +static corosync_timer_handle_t qdevice_timer; >> +static int qdevice_timer_set = 0; >> static corosync_timer_handle_t last_man_standing_timer; >> static int last_man_standing_timer_set = 0; >> >> @@ -219,6 +215,7 @@ static quorum_set_quorate_fn_t quorum_callback; >> >> static char *votequorum_exec_init_fn (struct corosync_api_v1 *api); >> static int votequorum_exec_exit_fn (void); >> +static int votequorum_exec_send_nodeinfo(uint32_t nodeid); >> >> static void message_handler_req_exec_votequorum_nodeinfo ( >> const void *message, >> @@ -265,19 +262,20 @@ static void >> message_handler_req_lib_votequorum_trackstart (void *conn, >> static void message_handler_req_lib_votequorum_trackstop (void *conn, >> const void *message); >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> static void message_handler_req_lib_votequorum_qdevice_register >> (void *conn, >> - const void *message); >> + const void *message); >> >> static void message_handler_req_lib_votequorum_qdevice_unregister >> (void *conn, >> - const void *message); >> + const void *message); >> + >> +static void message_handler_req_lib_votequorum_qdevice_update (void >> *conn, >> + const void *message); >> >> static void message_handler_req_lib_votequorum_qdevice_poll (void >> *conn, >> - const void *message); >> + const void *message); >> >> static void message_handler_req_lib_votequorum_qdevice_getinfo (void >> *conn, >> - const void *message); >> -#endif >> + const void *message); >> >> static struct corosync_lib_handler quorum_lib_service[] = >> { >> @@ -300,7 +298,6 @@ static struct corosync_lib_handler >> quorum_lib_service[] = >> { /* 4 */ >> .lib_handler_fn = >> message_handler_req_lib_votequorum_trackstop, >> .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> }, >> { /* 5 */ >> .lib_handler_fn = >> message_handler_req_lib_votequorum_qdevice_register, >> @@ -311,13 +308,16 @@ static struct corosync_lib_handler >> quorum_lib_service[] = >> .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED >> }, >> { /* 7 */ >> - .lib_handler_fn = >> message_handler_req_lib_votequorum_qdevice_poll, >> + .lib_handler_fn = >> message_handler_req_lib_votequorum_qdevice_update, >> .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED >> }, >> { /* 8 */ >> + .lib_handler_fn = >> message_handler_req_lib_votequorum_qdevice_poll, >> + .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED >> + }, >> + { /* 9 */ >> .lib_handler_fn = >> message_handler_req_lib_votequorum_qdevice_getinfo, >> .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED >> -#endif >> } >> }; >> >> @@ -399,7 +399,7 @@ static struct cluster_node *allocate_node(unsigned >> int nodeid) >> if (cl) { >> memset(cl, 0, sizeof(struct cluster_node)); >> cl->node_id = nodeid; >> - if (nodeid) { >> + if (nodeid != NODEID_QDEVICE) { >> node_add_ordered(cl); >> } >> } >> @@ -416,14 +416,14 @@ static struct cluster_node >> *find_node_by_nodeid(unsigned int nodeid) >> >> ENTER(); >> >> - if (nodeid == NODEID_US) { >> + if (nodeid == us->node_id) { >> LEAVE(); >> return us; >> } >> >> if (nodeid == NODEID_QDEVICE) { >> LEAVE(); >> - return quorum_device; >> + return qdevice; >> } >> >> list_iterate(tmp,&cluster_members_list) { >> @@ -483,6 +483,11 @@ static int check_low_node_id_partition(void) >> static void update_wait_for_all_status(uint8_t wfa_status) >> { >> wait_for_all_status = wfa_status; >> + if (wait_for_all_status) { >> + us->flags |= NODE_FLAGS_WFASTATUS; >> + } else { >> + us->flags&= ~NODE_FLAGS_WFASTATUS; >> + } >> icmap_set_uint8("runtime.votequorum.wait_for_all_status", >> wait_for_all_status); >> } >> @@ -498,6 +503,12 @@ static void update_ev_barrier(uint32_t >> expected_votes) >> icmap_set_uint32("runtime.votequorum.ev_barrier", ev_barrier); >> } >> >> +static void update_qdevice_can_operate(uint8_t status) >> +{ >> + qdevice_can_operate = status; >> + icmap_set_uint8("runtime.votequorum.qdevice_can_operate", >> qdevice_can_operate); >> +} >> + >> /* >> * quorum calculation core bits >> */ >> @@ -534,8 +545,13 @@ static int calculate_quorum(int allow_decrease, >> unsigned int max_expected, unsig >> } >> } >> >> - if (quorum_device&& quorum_device->state == NODESTATE_MEMBER) { >> - total_votes += quorum_device->votes; >> + if (qdevice_is_registered) { >> + log_printf(LOGSYS_LEVEL_DEBUG, "node %u state=%d, votes=%u", >> + qdevice->node_id, qdevice->state, qdevice->votes); >> + if (qdevice->state == NODESTATE_MEMBER) { >> + total_votes += qdevice->votes; >> + total_nodes++; >> + } >> } >> >> if (max_expected> 0) { >> @@ -623,6 +639,11 @@ static void are_we_quorate(unsigned int total_votes) >> } >> >> cluster_is_quorate = quorate; >> + if (cluster_is_quorate) { >> + us->flags |= NODE_FLAGS_QUORATE; >> + } else { >> + us->flags&= ~NODE_FLAGS_QUORATE; >> + } >> >> if (wait_for_all) { >> if (quorate) { >> @@ -640,7 +661,9 @@ static void are_we_quorate(unsigned int total_votes) >> LEAVE(); >> } >> >> -/* Recalculate cluster quorum, set quorate and notify changes */ >> +/* >> + * Recalculate cluster quorum, set quorate and notify changes >> + */ >> static void recalculate_quorum(int allow_decrease, int >> by_current_nodes) >> { >> unsigned int total_votes = 0; >> @@ -660,6 +683,13 @@ static void recalculate_quorum(int >> allow_decrease, int by_current_nodes) >> } >> } >> >> + if (qdevice->votes) { >> + total_votes += qdevice->votes; >> + if (by_current_nodes) { >> + cluster_members++; >> + } >> + } >> + >> /* >> * Keep expected_votes at the highest number of votes in the >> cluster >> */ >> @@ -682,12 +712,14 @@ static void recalculate_quorum(int >> allow_decrease, int by_current_nodes) >> */ >> >> static int votequorum_read_nodelist_configuration(uint32_t *votes, >> + uint32_t *nodes, >> uint32_t *expected_votes) >> { >> icmap_iter_t iter; >> const char *iter_key; >> char tmp_key[ICMAP_KEYNAME_MAXLEN]; >> uint32_t our_pos, node_pos; >> + uint32_t nodecount = 0; >> uint32_t nodelist_expected_votes = 0; >> uint32_t node_votes = 0; >> int res = 0; >> @@ -697,7 +729,7 @@ static int >> votequorum_read_nodelist_configuration(uint32_t *votes, >> if (icmap_get_uint32("nodelist.local_node_pos",&our_pos) != >> CS_OK) { >> log_printf(LOGSYS_LEVEL_DEBUG, >> "No nodelist defined or our node is not in the >> nodelist"); >> - return -1; >> + return 0; >> } >> >> iter = icmap_iter_init("nodelist.node."); >> @@ -713,6 +745,8 @@ static int >> votequorum_read_nodelist_configuration(uint32_t *votes, >> continue; >> } >> >> + nodecount++; >> + >> snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, >> "nodelist.node.%u.quorum_votes", node_pos); >> if (icmap_get_uint32(tmp_key,&node_votes) != CS_OK) { >> node_votes = 1; >> @@ -726,30 +760,103 @@ static int >> votequorum_read_nodelist_configuration(uint32_t *votes, >> } >> >> *expected_votes = nodelist_expected_votes; >> + *nodes = nodecount; >> >> icmap_iter_finalize(iter); >> >> LEAVE(); >> >> + return 1; >> +} >> + >> +static int votequorum_qdevice_is_configured(uint32_t *qdevice_votes) >> +{ >> + char *qdevice_model = NULL; >> + >> + ENTER(); >> + >> + if ((icmap_get_string("quorum.device.model",&qdevice_model) == >> CS_OK)&& >> + (strlen(qdevice_model))) { >> + free(qdevice_model); >> + if (icmap_get_uint32("quorum.device.votes", qdevice_votes) != >> CS_OK) { >> + *qdevice_votes = -1; >> + } >> + if >> (icmap_get_uint32("quorum.device.timeout",&qdevice_timeout) != CS_OK) { >> + qdevice_timeout = DEFAULT_QDEVICE_TIMEOUT; >> + } >> + update_qdevice_can_operate(1); >> + return 1; >> + } >> + >> + LEAVE(); >> + >> return 0; >> } >> >> /* >> * votequorum_readconfig_static is executed before >> * votequorum_readconfig_dynamic >> + * >> + * errors from _static are fatal >> + * errors from _dynamic need to be handled at runtime without >> self-destruction >> + * >> + * TODO: static/dynamic shares a lot of checks _and_ >> + * there are probably more options we can change at runtime >> + * than we allow now. Review this in 2.1 >> */ >> >> static char *votequorum_readconfig_static(void) >> { >> - uint32_t node_votes, node_expected_votes, expected_votes; >> + uint32_t node_votes = 0, qdevice_votes = 0; >> + uint32_t node_expected_votes = 0, expected_votes = 0; >> + uint32_t node_count = 0; >> + int have_nodelist, have_qdevice; >> >> ENTER(); >> >> log_printf(LOGSYS_LEVEL_DEBUG, "Reading static configuration"); >> >> + /* >> + * gather basic data here >> + */ >> + icmap_get_uint32("quorum.expected_votes",&expected_votes); >> + have_nodelist = >> votequorum_read_nodelist_configuration(&node_votes,&node_count,&node_expected_votes); >> >> + have_qdevice = votequorum_qdevice_is_configured(&qdevice_votes); >> icmap_get_uint8("quorum.two_node",&two_node); >> update_two_node(); >> >> + /* >> + * do basic config verification >> + */ >> + if ((!have_nodelist)&& (!expected_votes)) { >> + return ((char *)"configuration error: nodelist or >> quorum.expected_votes must be configured!"); >> + } >> + >> + if ((two_node)&& (have_qdevice)) { >> + return ((char *)"configuration error: two_node and quorum >> device cannot be configured at the same time!"); >> + } >> + >> + if ((expected_votes)&& (have_qdevice)&& (qdevice_votes == -1)) { >> + return ((char *)"configuration error: quorum.device.votes >> must be specified when quorum.expected_votes is set"); >> + } >> + >> + if ((have_qdevice)&& >> + (qdevice_votes == -1)&& >> + (have_nodelist)&& >> + (node_count != node_expected_votes)) { >> + return ((char *)"configuration error: quorum.device.votes >> must be specified when not all nodes votes 1"); >> + } >> + >> + if ((qdevice_votes> 0)&& (expected_votes)) { >> + int delta = expected_votes - qdevice_votes; >> + if (delta< 2) { >> + return ((char *)"configuration error: quorum.device.votes >> is too high or expected_votes is too low"); >> + } >> + } >> + >> + /* >> + * Enable special features >> + */ >> if (two_node) { >> wait_for_all = 1; >> } >> @@ -760,9 +867,12 @@ static char *votequorum_readconfig_static(void) >> icmap_get_uint8("quorum.last_man_standing",&last_man_standing); >> >> icmap_get_uint32("quorum.last_man_standing_window",&last_man_standing_window); >> >> >> - if >> ((votequorum_read_nodelist_configuration(&node_votes,&node_expected_votes))&& >> >> - (icmap_get_uint32("quorum.expected_votes",&expected_votes) != >> CS_OK)) { >> - return ((char *)"configuration error: nodelist or >> quorum.expected_votes must be configured!"); >> + if ((have_qdevice)&& (last_man_standing)) { >> + return ((char *)"configuration error: quorum device is not >> compatible with last_man_standing feature"); >> + } >> + >> + if ((have_qdevice)&& (auto_tie_breaker)) { >> + return ((char *)"configuration error: quorum device is not >> compatible with auto_tie_breaker feature"); >> } >> >> if (wait_for_all) { >> @@ -776,43 +886,152 @@ static char *votequorum_readconfig_static(void) >> >> static void votequorum_readconfig_dynamic(void) >> { >> - int cluster_members = 0; >> - struct list_head *tmp; >> + uint32_t node_votes = 0, qdevice_votes = 0; >> + uint32_t node_expected_votes = 0, expected_votes = 0; >> + uint32_t node_count = 0; >> + int have_nodelist, have_qdevice; >> >> ENTER(); >> >> log_printf(LOGSYS_LEVEL_DEBUG, "Reading dynamic configuration"); >> >> - if >> (votequorum_read_nodelist_configuration(&us->votes,&us->expected_votes)) >> { >> - us->votes = 1; >> - icmap_get_uint32("quorum.votes",&us->votes); >> + /* >> + * gather basic data here >> + * TODO: make it common with static!!! >> + */ >> + icmap_get_uint32("quorum.expected_votes",&expected_votes); >> + have_nodelist = >> votequorum_read_nodelist_configuration(&node_votes,&node_count,&node_expected_votes); >> >> + have_qdevice = votequorum_qdevice_is_configured(&qdevice_votes); >> + icmap_get_uint8("quorum.two_node",&two_node); >> + >> + /* >> + * do config verification and enablement >> + */ >> + >> + if ((!have_nodelist)&& (!expected_votes)) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: nodelist >> or quorum.expected_votes must be configured!"); >> + log_printf(LOGSYS_LEVEL_CRIT, "will continue with current >> runtime data"); >> + goto out; >> } >> >> - icmap_get_uint32("quorum.expected_votes",&us->expected_votes); >> + /* >> + * two_node and qdevice are not compatible in the same config. >> + * try to make an educated guess of what to do >> + */ >> >> - update_ev_barrier(us->expected_votes); >> + if ((two_node)&& (have_qdevice)) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: two_node >> and quorum device cannot be configured at the same time!"); >> + if (qdevice_is_registered) { >> + log_printf(LOGSYS_LEVEL_CRIT, "quorum device is >> registered, disabling two_node"); >> + two_node = 0; >> + } else { >> + log_printf(LOGSYS_LEVEL_CRIT, "quorum device is not >> registered, allowing two_node"); >> + update_qdevice_can_operate(0); >> + } >> + } >> + >> + /* >> + * quorum device is not compatible with last_man_standing and >> auto_tie_breaker >> + * neither lms or atb can be set at runtime, so there is no need >> to check for >> + * runtime incompatibilities, but qdevice can be configured >> _after_ LMS and ATB have >> + * been enabled at startup. >> + */ >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> - if (icmap_get_uint32("quorum.quorumdev_poll",&quorumdev_poll) != >> CS_OK) { >> - quorumdev_poll = DEFAULT_QDEV_POLL; >> + if ((have_qdevice)&& (last_man_standing)) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: >> quorum.device is not compatible with last_man_standing"); >> + log_printf(LOGSYS_LEVEL_CRIT, "disabling quorum device >> operations"); >> + update_qdevice_can_operate(0); >> + } >> + >> + if ((have_qdevice)&& (auto_tie_breaker)) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: >> quorum.device is not compatible with auto_tie_breaker"); >> + log_printf(LOGSYS_LEVEL_CRIT, "disabling quorum device >> operations"); >> + update_qdevice_can_operate(0); >> } >> -#endif >> >> - icmap_get_uint8("quorum.two_node",&two_node); >> - update_two_node(); >> /* >> - * two_node mode is invalid if there are more than 2 nodes in the >> cluster! >> + * if user specifies quorum.expected_votes + quorum.device but >> NOT the device.votes >> + * we don't know what the quorum device should vote. >> */ >> - list_iterate(tmp,&cluster_members_list) { >> - cluster_members++; >> - } >> >> - if (two_node&& cluster_members> 2) { >> - log_printf(LOGSYS_LEVEL_WARNING, "quorum.two_node was set but >> there are more than 2 nodes in the cluster. It will be ignored."); >> - two_node = 0; >> - update_two_node(); >> + if ((expected_votes)&& (have_qdevice)&& (qdevice_votes == -1)) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: >> quorum.device.votes must be specified when quorum.expected_votes is >> set"); >> + log_printf(LOGSYS_LEVEL_CRIT, "disabling quorum device >> operations"); >> + update_qdevice_can_operate(0); >> + } >> + >> + /* >> + * if user specifies a node list with uneven votes and no >> device.votes >> + * we cannot autocalculate the votes >> + */ >> + >> + if ((have_qdevice)&& >> + (qdevice_votes == -1)&& >> + (have_nodelist)&& >> + (node_count != node_expected_votes)) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: >> quorum.device.votes must be specified when not all nodes votes 1"); >> + log_printf(LOGSYS_LEVEL_CRIT, "disabling quorum device >> operations"); >> + update_qdevice_can_operate(0); >> + } >> + >> + /* >> + * validate quorum device votes vs expected_votes >> + */ >> + >> + if ((qdevice_votes> 0)&& (expected_votes)) { >> + int delta = expected_votes - qdevice_votes; >> + if (delta< 2) { >> + log_printf(LOGSYS_LEVEL_CRIT, "configuration error: >> quorum.device.votes is too high or expected_votes is too low"); >> + log_printf(LOGSYS_LEVEL_CRIT, "disabling quorum device >> operations"); >> + update_qdevice_can_operate(0); >> + } >> + } >> + >> + /* >> + * automatically calculate device votes and adjust expected_votes >> from nodelist >> + */ >> + >> + if ((have_qdevice)&& >> + (qdevice_votes == -1)&& >> + (!expected_votes)&& >> + (have_nodelist)&& >> + (node_count == node_expected_votes)) { >> + qdevice_votes = node_expected_votes - 1; >> + node_expected_votes = node_expected_votes + qdevice_votes; >> + } >> + >> + /* >> + * set this node votes and expected_votes >> + */ >> + >> + if (have_nodelist) { >> + us->votes = node_votes; >> + us->expected_votes = node_expected_votes; >> + } else { >> + us->votes = 1; >> + icmap_get_uint32("quorum.votes",&us->votes); >> + } >> + >> + if (expected_votes) { >> + us->expected_votes = expected_votes; >> + } >> + >> + /* >> + * set qdevice votes >> + */ >> + >> + if (!have_qdevice) { >> + qdevice->votes = 0; >> + } >> + >> + if (qdevice_votes != -1) { >> + qdevice->votes = qdevice_votes; >> } >> >> + update_ev_barrier(us->expected_votes); >> + update_two_node(); >> + >> +out: >> LEAVE(); >> } >> >> @@ -825,11 +1044,13 @@ static void votequorum_refresh_config( >> { >> unsigned int old_votes; >> unsigned int old_expected; >> + unsigned int old_qdevice_votes; >> >> ENTER(); >> >> old_votes = us->votes; >> old_expected = us->expected_votes; >> + old_qdevice_votes = qdevice->votes; >> >> /* >> * Reload the configuration >> @@ -845,6 +1066,9 @@ static void votequorum_refresh_config( >> if (old_expected != us->expected_votes) { >> >> votequorum_exec_send_reconfigure(VOTEQUORUM_RECONFIG_PARAM_EXPECTED_VOTES, >> us->node_id, us->expected_votes); >> } >> + if (old_qdevice_votes != qdevice->votes) { >> + >> votequorum_exec_send_reconfigure(VOTEQUORUM_RECONFIG_PARAM_NODE_VOTES, >> NODEID_QDEVICE, qdevice->votes); >> + } >> >> LEAVE(); >> } >> @@ -902,23 +1126,29 @@ static int >> votequorum_exec_send_reconfigure(uint8_t param, unsigned int nodeid, >> return ret; >> } >> >> -static int votequorum_exec_send_nodeinfo(void) >> +static int votequorum_exec_send_nodeinfo(uint32_t nodeid) >> { >> struct req_exec_quorum_nodeinfo req_exec_quorum_nodeinfo; >> struct iovec iov[1]; >> + struct cluster_node *node; >> int ret; >> >> ENTER(); >> >> - req_exec_quorum_nodeinfo.votes = us->votes; >> - req_exec_quorum_nodeinfo.expected_votes = us->expected_votes; >> - req_exec_quorum_nodeinfo.flags = us->flags; >> - req_exec_quorum_nodeinfo.quorate = cluster_is_quorate; >> - req_exec_quorum_nodeinfo.wait_for_all_status = wait_for_all_status; >> - req_exec_quorum_nodeinfo.first_trans = first_trans; >> - req_exec_quorum_nodeinfo._pad0 = 0; >> - req_exec_quorum_nodeinfo._pad1 = 0; >> - req_exec_quorum_nodeinfo._pad2 = 0; >> + node = find_node_by_nodeid(nodeid); >> + if (!node) { >> + return -1; >> + } >> + >> + req_exec_quorum_nodeinfo.nodeid = nodeid; >> + req_exec_quorum_nodeinfo.votes = node->votes; >> + req_exec_quorum_nodeinfo.expected_votes = node->expected_votes; >> + req_exec_quorum_nodeinfo.flags = node->flags; >> + if (qdevice_is_registered) { >> + strcpy(req_exec_quorum_nodeinfo.qdevice_name, >> qdevice->qdevice_name); >> + } else { >> + memset(req_exec_quorum_nodeinfo.qdevice_name, 0, >> VOTEQUORUM_MAX_QDEVICE_NAME_LEN); >> + } >> >> req_exec_quorum_nodeinfo.header.id = >> SERVICE_ID_MAKE(VOTEQUORUM_SERVICE, >> MESSAGE_REQ_EXEC_VOTEQUORUM_NODEINFO); >> req_exec_quorum_nodeinfo.header.size = >> sizeof(req_exec_quorum_nodeinfo); >> @@ -948,7 +1178,7 @@ static int >> votequorum_exec_send_quorum_notification(void *conn, uint64_t context >> node = list_entry(tmp, struct cluster_node, list); >> cluster_members++; >> } >> - if (quorum_device) { >> + if (qdevice_is_registered) { >> cluster_members++; >> } >> >> @@ -968,9 +1198,9 @@ static int >> votequorum_exec_send_quorum_notification(void *conn, uint64_t context >> res_lib_votequorum_notification->node_list[i].nodeid = >> node->node_id; >> res_lib_votequorum_notification->node_list[i++].state = >> node->state; >> } >> - if (quorum_device) { >> - res_lib_votequorum_notification->node_list[i].nodeid = 0; >> - res_lib_votequorum_notification->node_list[i++].state = >> quorum_device->state | 0x80; >> + if (qdevice_is_registered) { >> + res_lib_votequorum_notification->node_list[i].nodeid = >> NODEID_QDEVICE; >> + res_lib_votequorum_notification->node_list[i++].state = >> qdevice->state; >> } >> res_lib_votequorum_notification->header.id = >> MESSAGE_RES_VOTEQUORUM_NOTIFICATION; >> res_lib_votequorum_notification->header.size = size; >> @@ -1027,16 +1257,17 @@ static void >> exec_votequorum_nodeinfo_endian_convert (void *message) >> >> ENTER(); >> >> + nodeinfo->nodeid = swab32(nodeinfo->nodeid); >> nodeinfo->votes = swab32(nodeinfo->votes); >> nodeinfo->expected_votes = swab32(nodeinfo->expected_votes); >> - nodeinfo->flags = swab16(nodeinfo->flags); >> + nodeinfo->flags = swab32(nodeinfo->flags); >> >> LEAVE(); >> } >> >> static void message_handler_req_exec_votequorum_nodeinfo ( >> const void *message, >> - unsigned int nodeid) >> + unsigned int sender_nodeid) >> { >> const struct req_exec_quorum_nodeinfo *req_exec_quorum_nodeinfo >> = message; >> struct cluster_node *node = NULL; >> @@ -1047,16 +1278,15 @@ static void >> message_handler_req_exec_votequorum_nodeinfo ( >> int new_node = 0; >> int allow_downgrade = 0; >> int by_node = 0; >> + unsigned int nodeid = req_exec_quorum_nodeinfo->nodeid; >> >> ENTER(); >> >> - log_printf(LOGSYS_LEVEL_DEBUG, "got nodeinfo message from cluster >> node %u", nodeid); >> - log_printf(LOGSYS_LEVEL_DEBUG, "nodeinfo message[%u]: votes: %d, >> expected: %d wfa: %d quorate: %d flags: %d", >> + log_printf(LOGSYS_LEVEL_DEBUG, "got nodeinfo message from cluster >> node %u", sender_nodeid); >> + log_printf(LOGSYS_LEVEL_DEBUG, "nodeinfo message[%u]: votes: %d, >> expected: %d flags: %d", >> nodeid, >> req_exec_quorum_nodeinfo->votes, >> req_exec_quorum_nodeinfo->expected_votes, >> - req_exec_quorum_nodeinfo->wait_for_all_status, >> - req_exec_quorum_nodeinfo->quorate, >> req_exec_quorum_nodeinfo->flags); >> >> node = find_node_by_nodeid(nodeid); >> @@ -1083,41 +1313,74 @@ static void >> message_handler_req_exec_votequorum_nodeinfo ( >> } >> >> /* Update node state */ >> - node->votes = req_exec_quorum_nodeinfo->votes; >> node->flags = req_exec_quorum_nodeinfo->flags; >> >> + if (nodeid != NODEID_QDEVICE) { >> + node->votes = req_exec_quorum_nodeinfo->votes; >> + >> + memset(node->qdevice_name, 0, VOTEQUORUM_MAX_QDEVICE_NAME_LEN); >> + if (node->flags& NODE_FLAGS_QDEVICE) { >> + int state = 0; >> + >> + if (node->flags& NODE_FLAGS_QDEVICE_STATE) { >> + state = 1; >> + } >> + >> + strcpy(node->qdevice_name, >> req_exec_quorum_nodeinfo->qdevice_name); >> + log_printf(LOGSYS_LEVEL_DEBUG, "Got qdevice data from >> node[%u]: state %u name %s", >> + node->node_id, state, node->qdevice_name); >> + } >> + } else { >> + if ((!cluster_is_quorate)&& >> + (req_exec_quorum_nodeinfo->flags& NODE_FLAGS_QUORATE)) { >> + node->votes = req_exec_quorum_nodeinfo->votes; >> + } else { >> + node->votes = max(node->votes, >> req_exec_quorum_nodeinfo->votes); >> + } >> + } >> + >> if (node->flags& NODE_FLAGS_LEAVING) { >> node->state = NODESTATE_LEAVING; >> allow_downgrade = 1; >> by_node = 1; >> } else { >> - node->state = NODESTATE_MEMBER; >> + if (nodeid != NODEID_QDEVICE) { >> + node->state = NODESTATE_MEMBER; >> + } else { >> + /* >> + * qdevice status is only local to the node >> + */ >> + node->state = old_state; >> + } >> } >> >> - if ((!cluster_is_quorate)&& >> - (req_exec_quorum_nodeinfo->quorate)) { >> - allow_downgrade = 1; >> - us->expected_votes = req_exec_quorum_nodeinfo->expected_votes; >> - } >> + if (nodeid != NODEID_QDEVICE) { >> + if ((!cluster_is_quorate)&& >> + (req_exec_quorum_nodeinfo->flags& NODE_FLAGS_QUORATE)) { >> + allow_downgrade = 1; >> + us->expected_votes = >> req_exec_quorum_nodeinfo->expected_votes; >> + } >> >> - if (req_exec_quorum_nodeinfo->quorate) { >> - node->expected_votes = req_exec_quorum_nodeinfo->expected_votes; >> - } else { >> - node->expected_votes = us->expected_votes; >> - } >> + if (req_exec_quorum_nodeinfo->flags& NODE_FLAGS_QUORATE) { >> + node->expected_votes = >> req_exec_quorum_nodeinfo->expected_votes; >> + } else { >> + node->expected_votes = us->expected_votes; >> + } >> >> - if ((last_man_standing)&& (req_exec_quorum_nodeinfo->votes> 1)) { >> - log_printf(LOGSYS_LEVEL_WARNING, "Last Man Standing feature >> is supported only when all" >> - "cluster nodes votes are set to 1. Disabling >> LMS."); >> - last_man_standing = 0; >> - if (last_man_standing_timer_set) { >> - corosync_api->timer_delete(last_man_standing_timer); >> - last_man_standing_timer_set = 0; >> + if ((last_man_standing)&& (req_exec_quorum_nodeinfo->votes> >> 1)) { >> + log_printf(LOGSYS_LEVEL_WARNING, "Last Man Standing >> feature is supported only when all" >> + "cluster nodes votes are set to 1. >> Disabling LMS."); >> + last_man_standing = 0; >> + if (last_man_standing_timer_set) { >> + corosync_api->timer_delete(last_man_standing_timer); >> + last_man_standing_timer_set = 0; >> + } >> } >> } >> >> if (new_node || >> - req_exec_quorum_nodeinfo->first_trans || >> + nodeid == NODEID_QDEVICE || >> + req_exec_quorum_nodeinfo->flags& NODE_FLAGS_FIRST || >> old_votes != node->votes || >> old_expected != node->expected_votes || >> old_flags != node->flags || >> @@ -1126,8 +1389,8 @@ static void >> message_handler_req_exec_votequorum_nodeinfo ( >> } >> >> if ((wait_for_all)&& >> - (!req_exec_quorum_nodeinfo->wait_for_all_status)&& >> - (req_exec_quorum_nodeinfo->quorate)) { >> + (!(req_exec_quorum_nodeinfo->flags& NODE_FLAGS_WFASTATUS))&& >> + (req_exec_quorum_nodeinfo->flags& NODE_FLAGS_QUORATE)) { >> update_wait_for_all_status(0); >> } >> >> @@ -1156,7 +1419,8 @@ static void >> message_handler_req_exec_votequorum_reconfigure ( >> >> ENTER(); >> >> - log_printf(LOGSYS_LEVEL_DEBUG, "got reconfigure message from >> cluster node %u", nodeid); >> + log_printf(LOGSYS_LEVEL_DEBUG, "got reconfigure message from >> cluster node %u for %u", >> + nodeid, req_exec_quorum_reconfigure->nodeid); >> >> node = find_node_by_nodeid(req_exec_quorum_reconfigure->nodeid); >> if (!node) { >> @@ -1196,7 +1460,7 @@ static int votequorum_exec_exit_fn (void) >> >> if (leave_remove) { >> us->flags |= NODE_FLAGS_LEAVING; >> - ret = votequorum_exec_send_nodeinfo(); >> + ret = votequorum_exec_send_nodeinfo(us->node_id); >> } >> >> LEAVE(); >> @@ -1227,6 +1491,16 @@ static char *votequorum_exec_init_fn (struct >> corosync_api_v1 *api) >> >> us->state = NODESTATE_MEMBER; >> us->votes = 1; >> + us->flags |= NODE_FLAGS_FIRST; >> + >> + qdevice = allocate_node(NODEID_QDEVICE); >> + if (!qdevice) { >> + LEAVE(); >> + return ((char *)"Could not allocate node."); >> + } >> + qdevice->state = NODESTATE_DEAD; >> + qdevice->votes = 0; >> + memset(qdevice->qdevice_name, 0, VOTEQUORUM_MAX_QDEVICE_NAME_LEN); >> >> votequorum_readconfig_dynamic(); >> recalculate_quorum(0, 0); >> @@ -1239,7 +1513,7 @@ static char *votequorum_exec_init_fn (struct >> corosync_api_v1 *api) >> /* >> * Start us off with one node >> */ >> - votequorum_exec_send_nodeinfo(); >> + votequorum_exec_send_nodeinfo(us->node_id); >> >> LEAVE(); >> >> @@ -1275,7 +1549,7 @@ static void votequorum_confchg_fn ( >> ENTER(); >> >> if (member_list_entries> 1) { >> - first_trans = 0; >> + us->flags&= ~NODE_FLAGS_FIRST; >> } >> >> if (left_list_entries) { >> @@ -1304,10 +1578,8 @@ static void votequorum_confchg_fn ( >> if (member_list_entries) { >> memcpy(quorum_members, member_list, sizeof(unsigned int) * >> member_list_entries); >> quorum_members_entries = member_list_entries; >> - if (quorum_device) { >> - quorum_members[quorum_members_entries++] = 0; >> - } >> - votequorum_exec_send_nodeinfo(); >> + votequorum_exec_send_nodeinfo(us->node_id); >> + votequorum_exec_send_nodeinfo(NODEID_QDEVICE); >> } >> >> memcpy(&quorum_ringid, ring_id, sizeof(*ring_id)); >> @@ -1392,29 +1664,26 @@ static int quorum_lib_exit_fn (void *conn) >> * library internal functions >> */ >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> -static void quorum_device_timer_fn(void *arg) >> +static void qdevice_timer_fn(void *arg) >> { >> ENTER(); >> >> - if (!quorum_device || quorum_device->state == NODESTATE_DEAD) { >> + if ((!qdevice_is_registered) || >> + (qdevice->state == NODESTATE_DEAD) || >> + (!qdevice_timer_set)) { >> LEAVE(); >> return; >> } >> >> - if ((quorum_device->last_hello / QB_TIME_NS_IN_SEC) + >> quorumdev_poll/1000< >> - (qb_util_nano_current_get () / QB_TIME_NS_IN_SEC)) { >> - quorum_device->state = NODESTATE_DEAD; >> - log_printf(LOGSYS_LEVEL_INFO, "lost contact with quorum >> device"); >> - recalculate_quorum(0, 0); >> - } else { >> - corosync_api->timer_add_duration((unsigned long >> long)quorumdev_poll*1000000, quorum_device, >> - quorum_device_timer_fn,&quorum_device_timer); >> - } >> + qdevice->state = NODESTATE_DEAD; >> + us->flags&= ~NODE_FLAGS_QDEVICE_STATE; >> + log_printf(LOGSYS_LEVEL_INFO, "lost contact with quorum device >> %s", qdevice->qdevice_name); >> + votequorum_exec_send_nodeinfo(us->node_id); >> + >> + qdevice_timer_set = 0; >> >> LEAVE(); >> } >> -#endif >> >> /* >> * Library Handler Functions >> @@ -1448,12 +1717,14 @@ static void >> message_handler_req_lib_votequorum_getinfo (void *conn, const void * >> } >> } >> >> - if (quorum_device&& quorum_device->state == NODESTATE_MEMBER) { >> - total_votes += quorum_device->votes; >> + if (((qdevice_is_registered)&& (qdevice->state == >> NODESTATE_MEMBER)) || >> + ((node->flags& NODE_FLAGS_QDEVICE)&& (node->flags& >> NODE_FLAGS_QDEVICE_STATE))) { >> + total_votes += qdevice->votes; >> } >> >> - res_lib_votequorum_getinfo.votes = us->votes; >> - res_lib_votequorum_getinfo.expected_votes = us->expected_votes; >> + res_lib_votequorum_getinfo.state = node->state; >> + res_lib_votequorum_getinfo.votes = node->votes; >> + res_lib_votequorum_getinfo.expected_votes = >> node->expected_votes; >> res_lib_votequorum_getinfo.highest_expected = highest_expected; >> >> res_lib_votequorum_getinfo.quorum = quorum; >> @@ -1479,6 +1750,9 @@ static void >> message_handler_req_lib_votequorum_getinfo (void *conn, const void * >> if (leave_remove) { >> res_lib_votequorum_getinfo.flags |= >> VOTEQUORUM_INFO_LEAVE_REMOVE; >> } >> + if (node->flags& NODE_FLAGS_QDEVICE) { >> + res_lib_votequorum_getinfo.flags |= VOTEQUORUM_INFO_QDEVICE; >> + } >> } else { >> error = CS_ERR_NOT_EXIST; >> } >> @@ -1564,10 +1838,6 @@ static void >> message_handler_req_lib_votequorum_setvotes (void *conn, const void >> goto error_exit; >> } >> >> - if (!nodeid) { >> - nodeid = corosync_api->totem_nodeid_get(); >> - } >> - >> >> votequorum_exec_send_reconfigure(VOTEQUORUM_RECONFIG_PARAM_NODE_VOTES, >> nodeid, >> req_lib_votequorum_setvotes->votes); >> >> @@ -1645,9 +1915,8 @@ static void >> message_handler_req_lib_votequorum_trackstop (void *conn, >> LEAVE(); >> } >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> static void message_handler_req_lib_votequorum_qdevice_register >> (void *conn, >> - const void *message) >> + const void *message) >> { >> const struct req_lib_votequorum_qdevice_register >> *req_lib_votequorum_qdevice_register = message; >> struct res_lib_votequorum_status res_lib_votequorum_status; >> @@ -1655,16 +1924,33 @@ static void >> message_handler_req_lib_votequorum_qdevice_register (void *conn, >> >> ENTER(); >> >> - if (quorum_device) { >> - error = CS_ERR_EXIST; >> + if (!qdevice_can_operate) { >> + log_printf(LOGSYS_LEVEL_INFO, "Registration of quorum device >> is disabled by incorrect corosync.conf. See logs for more information"); >> + error = CS_ERR_ACCESS; >> + goto out; >> + } >> + >> + if (qdevice_is_registered) { >> + if ((!strncmp(req_lib_votequorum_qdevice_register->name, >> + qdevice->qdevice_name, VOTEQUORUM_MAX_QDEVICE_NAME_LEN))) { >> + goto out; >> + } else { >> + log_printf(LOGSYS_LEVEL_WARNING, >> + "A new qdevice with different name (new: %s old: >> %s) is trying to re-register!", >> + req_lib_votequorum_qdevice_register->name, >> qdevice->qdevice_name); >> + error = CS_ERR_EXIST; >> + goto out; >> + } >> } else { >> - quorum_device = allocate_node(0); >> - quorum_device->state = NODESTATE_DEAD; >> - quorum_device->votes = >> req_lib_votequorum_qdevice_register->votes; >> - strcpy(quorum_device_name, >> req_lib_votequorum_qdevice_register->name); >> - list_add(&quorum_device->list,&cluster_members_list); >> + qdevice_is_registered = 1; >> + strcpy(qdevice->qdevice_name, >> req_lib_votequorum_qdevice_register->name); >> + us->flags |= NODE_FLAGS_QDEVICE; >> + votequorum_exec_send_nodeinfo(NODEID_QDEVICE); >> + votequorum_exec_send_nodeinfo(us->node_id); >> } >> >> +out: >> + >> res_lib_votequorum_status.header.size = >> sizeof(res_lib_votequorum_status); >> res_lib_votequorum_status.header.id = >> MESSAGE_RES_VOTEQUORUM_STATUS; >> res_lib_votequorum_status.header.error = error; >> @@ -1674,24 +1960,62 @@ static void >> message_handler_req_lib_votequorum_qdevice_register (void *conn, >> } >> >> static void message_handler_req_lib_votequorum_qdevice_unregister >> (void *conn, >> - const void *message) >> + const void *message) >> { >> + const struct req_lib_votequorum_qdevice_unregister >> *req_lib_votequorum_qdevice_unregister = message; >> struct res_lib_votequorum_status res_lib_votequorum_status; >> cs_error_t error = CS_OK; >> >> ENTER(); >> >> - if (quorum_device) { >> - struct cluster_node *node = quorum_device; >> + if (qdevice_is_registered) { >> + if (strncmp(req_lib_votequorum_qdevice_unregister->name, >> qdevice->qdevice_name, VOTEQUORUM_MAX_QDEVICE_NAME_LEN)) { >> + error = CS_ERR_INVALID_PARAM; >> + goto out; >> + } >> + if (qdevice_timer_set) { >> + corosync_api->timer_delete(qdevice_timer); >> + qdevice_timer_set = 0; >> + } >> + qdevice_is_registered = 0; >> + us->flags&= ~NODE_FLAGS_QDEVICE; >> + us->flags&= ~NODE_FLAGS_QDEVICE_STATE; >> + votequorum_exec_send_nodeinfo(us->node_id); >> + } else { >> + error = CS_ERR_NOT_EXIST; >> + } >> >> - quorum_device = NULL; >> - list_del(&node->list); >> - free(node); >> - recalculate_quorum(0, 0); >> +out: >> + res_lib_votequorum_status.header.size = >> sizeof(res_lib_votequorum_status); >> + res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; >> + res_lib_votequorum_status.header.error = error; >> + corosync_api->ipc_response_send(conn,&res_lib_votequorum_status, >> sizeof(res_lib_votequorum_status)); >> + >> + LEAVE(); >> +} >> + >> +static void message_handler_req_lib_votequorum_qdevice_update (void >> *conn, >> + const void *message) >> +{ >> + const struct req_lib_votequorum_qdevice_update >> *req_lib_votequorum_qdevice_update = message; >> + struct res_lib_votequorum_status res_lib_votequorum_status; >> + cs_error_t error = CS_OK; >> + >> + ENTER(); >> + >> + if (qdevice_is_registered) { >> + if (strncmp(req_lib_votequorum_qdevice_update->oldname, >> qdevice->qdevice_name, VOTEQUORUM_MAX_QDEVICE_NAME_LEN)) { >> + error = CS_ERR_INVALID_PARAM; >> + goto out; >> + } >> + memset(qdevice->qdevice_name, 0, >> VOTEQUORUM_MAX_QDEVICE_NAME_LEN); >> + strcpy(qdevice->qdevice_name, >> req_lib_votequorum_qdevice_update->newname); >> + votequorum_exec_send_nodeinfo(us->node_id); >> } else { >> error = CS_ERR_NOT_EXIST; >> } >> >> +out: >> res_lib_votequorum_status.header.size = >> sizeof(res_lib_votequorum_status); >> res_lib_votequorum_status.header.id = >> MESSAGE_RES_VOTEQUORUM_STATUS; >> res_lib_votequorum_status.header.error = error; >> @@ -1701,7 +2025,7 @@ static void >> message_handler_req_lib_votequorum_qdevice_unregister (void *conn, >> } >> >> static void message_handler_req_lib_votequorum_qdevice_poll (void >> *conn, >> - const void *message) >> + const void *message) >> { >> const struct req_lib_votequorum_qdevice_poll >> *req_lib_votequorum_qdevice_poll = message; >> struct res_lib_votequorum_status res_lib_votequorum_status; >> @@ -1709,30 +2033,43 @@ static void >> message_handler_req_lib_votequorum_qdevice_poll (void *conn, >> >> ENTER(); >> >> - if (quorum_device) { >> - if (req_lib_votequorum_qdevice_poll->state) { >> - quorum_device->last_hello = qb_util_nano_current_get (); >> - if (quorum_device->state == NODESTATE_DEAD) { >> - quorum_device->state = NODESTATE_MEMBER; >> - recalculate_quorum(0, 0); >> + if (!qdevice_can_operate) { >> + error = CS_ERR_ACCESS; >> + goto out; >> + } >> >> - corosync_api->timer_add_duration((unsigned long >> long)quorumdev_poll*1000000, quorum_device, >> - >> quorum_device_timer_fn,&quorum_device_timer); >> + if (qdevice_is_registered) { >> + if (strncmp(req_lib_votequorum_qdevice_poll->name, >> qdevice->qdevice_name, VOTEQUORUM_MAX_QDEVICE_NAME_LEN)) { >> + error = CS_ERR_INVALID_PARAM; >> + goto out; >> + } >> + if (qdevice_timer_set) { >> + corosync_api->timer_delete(qdevice_timer); >> + qdevice_timer_set = 0; >> + } >> + >> + if (req_lib_votequorum_qdevice_poll->state) { >> + if (qdevice->state == NODESTATE_DEAD) { >> + qdevice->state = NODESTATE_MEMBER; >> + us->flags |= NODE_FLAGS_QDEVICE_STATE; >> + votequorum_exec_send_nodeinfo(us->node_id); >> } >> } else { >> - if (quorum_device->state == NODESTATE_MEMBER) { >> - quorum_device->state = NODESTATE_DEAD; >> - recalculate_quorum(0, 0); >> - corosync_api->timer_delete(quorum_device_timer); >> + if (qdevice->state == NODESTATE_MEMBER) { >> + qdevice->state = NODESTATE_DEAD; >> + us->flags&= ~NODE_FLAGS_QDEVICE_STATE; >> + votequorum_exec_send_nodeinfo(us->node_id); >> } >> } >> + >> + corosync_api->timer_add_duration((unsigned long >> long)qdevice_timeout*1000000, qdevice, >> + qdevice_timer_fn,&qdevice_timer); >> + qdevice_timer_set = 1; >> } else { >> error = CS_ERR_NOT_EXIST; >> } >> >> - /* >> - * send status >> - */ >> +out: >> res_lib_votequorum_status.header.size = >> sizeof(res_lib_votequorum_status); >> res_lib_votequorum_status.header.id = >> MESSAGE_RES_VOTEQUORUM_STATUS; >> res_lib_votequorum_status.header.error = error; >> @@ -1742,24 +2079,50 @@ static void >> message_handler_req_lib_votequorum_qdevice_poll (void *conn, >> } >> >> static void message_handler_req_lib_votequorum_qdevice_getinfo (void >> *conn, >> - const void *message) >> + const void *message) >> { >> + const struct req_lib_votequorum_qdevice_getinfo >> *req_lib_votequorum_qdevice_getinfo = message; >> struct res_lib_votequorum_qdevice_getinfo >> res_lib_votequorum_qdevice_getinfo; >> cs_error_t error = CS_OK; >> + struct cluster_node *node; >> + uint32_t nodeid = req_lib_votequorum_qdevice_getinfo->nodeid; >> >> ENTER(); >> >> - if (quorum_device) { >> - log_printf(LOGSYS_LEVEL_DEBUG, "got qdevice_getinfo state >> %d", quorum_device->state); >> - res_lib_votequorum_qdevice_getinfo.votes = quorum_device->votes; >> - if (quorum_device->state == NODESTATE_MEMBER) { >> - res_lib_votequorum_qdevice_getinfo.state = 1; >> + if ((nodeid != us->node_id)&& >> + (nodeid != NODEID_QDEVICE)) { >> + node = >> find_node_by_nodeid(req_lib_votequorum_qdevice_getinfo->nodeid); >> + if ((node)&& >> + (node->flags& NODE_FLAGS_QDEVICE)) { >> + int state = 0; >> + >> + if (node->flags& NODE_FLAGS_QDEVICE_STATE) { >> + state = 1; >> + } >> + log_printf(LOGSYS_LEVEL_DEBUG, "got qdevice_getinfo node >> %u state %d", nodeid, state); >> + res_lib_votequorum_qdevice_getinfo.votes = qdevice->votes; >> + if (state) { >> + res_lib_votequorum_qdevice_getinfo.state = 1; >> + } else { >> + res_lib_votequorum_qdevice_getinfo.state = 0; >> + } >> + strcpy(res_lib_votequorum_qdevice_getinfo.name, >> node->qdevice_name); >> } else { >> - res_lib_votequorum_qdevice_getinfo.state = 0; >> + error = CS_ERR_NOT_EXIST; >> } >> - strcpy(res_lib_votequorum_qdevice_getinfo.name, >> quorum_device_name); >> } else { >> - error = CS_ERR_NOT_EXIST; >> + if (qdevice_is_registered) { >> + log_printf(LOGSYS_LEVEL_DEBUG, "got qdevice_getinfo node >> %u state %d", us->node_id, qdevice->state); >> + res_lib_votequorum_qdevice_getinfo.votes = qdevice->votes; >> + if (qdevice->state == NODESTATE_MEMBER) { >> + res_lib_votequorum_qdevice_getinfo.state = 1; >> + } else { >> + res_lib_votequorum_qdevice_getinfo.state = 0; >> + } >> + strcpy(res_lib_votequorum_qdevice_getinfo.name, >> qdevice->qdevice_name); >> + } else { >> + error = CS_ERR_NOT_EXIST; >> + } >> } >> >> res_lib_votequorum_qdevice_getinfo.header.size = >> sizeof(res_lib_votequorum_qdevice_getinfo); >> @@ -1769,4 +2132,3 @@ static void >> message_handler_req_lib_votequorum_qdevice_getinfo (void *conn, >> >> LEAVE(); >> } >> -#endif >> diff --git a/include/corosync/ipc_votequorum.h >> b/include/corosync/ipc_votequorum.h >> index e63bbc5..b633ece 100644 >> --- a/include/corosync/ipc_votequorum.h >> +++ b/include/corosync/ipc_votequorum.h >> @@ -48,6 +48,7 @@ enum req_votequorum_types { >> , >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_REGISTER, >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_UNREGISTER, >> + MESSAGE_REQ_VOTEQUORUM_QDEVICE_UPDATE, >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_POLL, >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_GETINFO >> #endif >> @@ -62,23 +63,39 @@ enum res_votequorum_types { >> MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION >> }; >> >> -struct req_lib_votequorum_setvotes { >> +struct req_lib_votequorum_qdevice_register { >> struct qb_ipc_request_header header __attribute__((aligned(8))); >> - unsigned int votes; >> - int nodeid; >> + char name[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> }; >> >> -struct req_lib_votequorum_qdevice_register { >> +struct req_lib_votequorum_qdevice_unregister { >> struct qb_ipc_request_header header __attribute__((aligned(8))); >> - unsigned int votes; >> char name[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> }; >> >> +struct req_lib_votequorum_qdevice_update { >> + struct qb_ipc_request_header header __attribute__((aligned(8))); >> + char oldname[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> + char newname[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> +}; >> + >> struct req_lib_votequorum_qdevice_poll { >> struct qb_ipc_request_header header __attribute__((aligned(8))); >> + char name[VOTEQUORUM_MAX_QDEVICE_NAME_LEN]; >> int state; >> }; >> >> +struct req_lib_votequorum_qdevice_getinfo { >> + struct qb_ipc_request_header header __attribute__((aligned(8))); >> + int nodeid; >> +}; >> + >> +struct req_lib_votequorum_setvotes { >> + struct qb_ipc_request_header header __attribute__((aligned(8))); >> + unsigned int votes; >> + int nodeid; >> +}; >> + >> struct req_lib_votequorum_setexpected { >> struct qb_ipc_request_header header __attribute__((aligned(8))); >> unsigned int expected_votes; >> @@ -109,10 +126,12 @@ struct res_lib_votequorum_status { >> #define VOTEQUORUM_INFO_LAST_MAN_STANDING 8 >> #define VOTEQUORUM_INFO_AUTO_TIE_BREAKER 16 >> #define VOTEQUORUM_INFO_LEAVE_REMOVE 32 >> +#define VOTEQUORUM_INFO_QDEVICE 64 >> >> struct res_lib_votequorum_getinfo { >> struct qb_ipc_response_header header __attribute__((aligned(8))); >> - int nodeid; >> + unsigned int nodeid; >> + unsigned int state; >> unsigned int votes; >> unsigned int expected_votes; >> unsigned int highest_expected; >> diff --git a/include/corosync/votequorum.h >> b/include/corosync/votequorum.h >> index 8173c45..98b7b76 100644 >> --- a/include/corosync/votequorum.h >> +++ b/include/corosync/votequorum.h >> @@ -42,19 +42,16 @@ extern "C" { >> >> typedef uint64_t votequorum_handle_t; >> >> -#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> -#define VOTEQUORUM_MAX_QDEVICE_NAME_LEN 255 >> -#endif >> - >> #define VOTEQUORUM_INFO_FLAG_TWONODE 1 >> #define VOTEQUORUM_INFO_FLAG_QUORATE 2 >> #define VOTEQUORUM_INFO_WAIT_FOR_ALL 4 >> #define VOTEQUORUM_INFO_LAST_MAN_STANDING 8 >> #define VOTEQUORUM_INFO_AUTO_TIE_BREAKER 16 >> #define VOTEQUORUM_INFO_LEAVE_REMOVE 32 >> +#define VOTEQUORUM_INFO_QDEVICE 64 >> >> -#define VOTEQUORUM_NODEID_US 0 >> -#define VOTEQUORUM_NODEID_QDEVICE -1 >> +#define VOTEQUORUM_NODEID_QDEVICE 0 >> +#define VOTEQUORUM_MAX_QDEVICE_NAME_LEN 255 >> >> #define NODESTATE_MEMBER 1 >> #define NODESTATE_DEAD 2 >> @@ -64,6 +61,7 @@ typedef uint64_t votequorum_handle_t; >> >> struct votequorum_info { >> unsigned int node_id; >> + unsigned int state; >> unsigned int node_votes; >> unsigned int node_expected_votes; >> unsigned int highest_expected; >> @@ -187,20 +185,29 @@ cs_error_t votequorum_context_set ( >> */ >> cs_error_t votequorum_qdevice_register ( >> votequorum_handle_t handle, >> - const char *name, >> - unsigned int votes); >> + const char *name); >> >> /** >> * Unregister a quorum device >> */ >> cs_error_t votequorum_qdevice_unregister ( >> - votequorum_handle_t handle); >> + votequorum_handle_t handle, >> + const char *name); >> + >> +/** >> + * Update registered name of a quorum device >> + */ >> +cs_error_t votequorum_qdevice_update ( >> + votequorum_handle_t handle, >> + const char *oldname, >> + const char *newname); >> >> /** >> * Poll a quorum device >> */ >> cs_error_t votequorum_qdevice_poll ( >> votequorum_handle_t handle, >> + const char *name, >> unsigned int state); >> >> /** >> @@ -208,6 +215,7 @@ cs_error_t votequorum_qdevice_poll ( >> */ >> cs_error_t votequorum_qdevice_getinfo ( >> votequorum_handle_t handle, >> + unsigned int nodeid, >> struct votequorum_qdevice_info *info); >> >> #endif >> diff --git a/lib/votequorum.c b/lib/votequorum.c >> index 32f5a6b..133e706 100644 >> --- a/lib/votequorum.c >> +++ b/lib/votequorum.c >> @@ -174,6 +174,7 @@ cs_error_t votequorum_getinfo ( >> error = res_lib_votequorum_getinfo.header.error; >> >> info->node_id = res_lib_votequorum_getinfo.nodeid; >> + info->state = res_lib_votequorum_getinfo.state; >> info->node_votes = res_lib_votequorum_getinfo.votes; >> info->node_expected_votes = >> res_lib_votequorum_getinfo.expected_votes; >> info->highest_expected = >> res_lib_votequorum_getinfo.highest_expected; >> @@ -539,8 +540,7 @@ error_put: >> #ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> cs_error_t votequorum_qdevice_register ( >> votequorum_handle_t handle, >> - const char *name, >> - unsigned int votes) >> + const char *name) >> { >> cs_error_t error; >> struct votequorum_inst *votequorum_inst; >> @@ -548,8 +548,9 @@ cs_error_t votequorum_qdevice_register ( >> struct req_lib_votequorum_qdevice_register >> req_lib_votequorum_qdevice_register; >> struct res_lib_votequorum_status res_lib_votequorum_status; >> >> - if (strlen(name)>= VOTEQUORUM_MAX_QDEVICE_NAME_LEN) >> + if (strlen(name)>= VOTEQUORUM_MAX_QDEVICE_NAME_LEN) { >> return CS_ERR_INVALID_PARAM; >> + } >> >> error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, >> handle, (void *)&votequorum_inst)); >> if (error != CS_OK) { >> @@ -560,7 +561,6 @@ cs_error_t votequorum_qdevice_register ( >> req_lib_votequorum_qdevice_register.header.size = sizeof (struct >> req_lib_votequorum_qdevice_register); >> req_lib_votequorum_qdevice_register.header.id = >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_REGISTER; >> strcpy(req_lib_votequorum_qdevice_register.name, name); >> - req_lib_votequorum_qdevice_register.votes = votes; >> >> iov.iov_base = (char *)&req_lib_votequorum_qdevice_register; >> iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_register); >> @@ -586,6 +586,7 @@ error_exit: >> >> cs_error_t votequorum_qdevice_poll ( >> votequorum_handle_t handle, >> + const char *name, >> unsigned int state) >> { >> cs_error_t error; >> @@ -594,14 +595,18 @@ cs_error_t votequorum_qdevice_poll ( >> struct req_lib_votequorum_qdevice_poll >> req_lib_votequorum_qdevice_poll; >> struct res_lib_votequorum_status res_lib_votequorum_status; >> >> + if (strlen(name)>= VOTEQUORUM_MAX_QDEVICE_NAME_LEN) { >> + return CS_ERR_INVALID_PARAM; >> + } >> + >> 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_qdevice_poll.header.size = sizeof (struct >> req_lib_votequorum_qdevice_poll); >> req_lib_votequorum_qdevice_poll.header.id = >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_POLL; >> + strcpy(req_lib_votequorum_qdevice_poll.name, name); >> req_lib_votequorum_qdevice_poll.state = state; >> >> iov.iov_base = (char *)&req_lib_votequorum_qdevice_poll; >> @@ -627,24 +632,30 @@ error_exit: >> } >> >> cs_error_t votequorum_qdevice_unregister ( >> - votequorum_handle_t handle) >> + votequorum_handle_t handle, >> + const char *name) >> { >> cs_error_t error; >> struct votequorum_inst *votequorum_inst; >> struct iovec iov; >> - struct req_lib_votequorum_general req_lib_votequorum_general; >> + struct req_lib_votequorum_qdevice_unregister >> req_lib_votequorum_qdevice_unregister; >> struct res_lib_votequorum_status res_lib_votequorum_status; >> >> + if (strlen(name)>= VOTEQUORUM_MAX_QDEVICE_NAME_LEN) { >> + return CS_ERR_INVALID_PARAM; >> + } >> + >> 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_QDEVICE_UNREGISTER; >> + req_lib_votequorum_qdevice_unregister.header.size = sizeof >> (struct req_lib_votequorum_qdevice_unregister); >> + req_lib_votequorum_qdevice_unregister.header.id = >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_UNREGISTER; >> + strcpy(req_lib_votequorum_qdevice_unregister.name, name); >> >> - iov.iov_base = (char *)&req_lib_votequorum_general; >> - iov.iov_len = sizeof (struct req_lib_votequorum_general); >> + iov.iov_base = (char *)&req_lib_votequorum_qdevice_unregister; >> + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_unregister); >> >> error = qb_to_cs_error(qb_ipcc_sendv_recv ( >> votequorum_inst->c, >> @@ -667,12 +678,13 @@ error_exit: >> >> cs_error_t votequorum_qdevice_getinfo ( >> votequorum_handle_t handle, >> + unsigned int nodeid, >> struct votequorum_qdevice_info *qinfo) >> { >> cs_error_t error; >> struct votequorum_inst *votequorum_inst; >> struct iovec iov; >> - struct req_lib_votequorum_general req_lib_votequorum_general; >> + struct req_lib_votequorum_qdevice_getinfo >> req_lib_votequorum_qdevice_getinfo; >> struct res_lib_votequorum_qdevice_getinfo >> res_lib_votequorum_qdevice_getinfo; >> >> error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, >> handle, (void *)&votequorum_inst)); >> @@ -680,12 +692,12 @@ cs_error_t votequorum_qdevice_getinfo ( >> return (error); >> } >> >> + req_lib_votequorum_qdevice_getinfo.header.size = sizeof (struct >> req_lib_votequorum_qdevice_getinfo); >> + req_lib_votequorum_qdevice_getinfo.header.id = >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_GETINFO; >> + req_lib_votequorum_qdevice_getinfo.nodeid = nodeid; >> >> - req_lib_votequorum_general.header.size = sizeof (struct >> req_lib_votequorum_general); >> - req_lib_votequorum_general.header.id = >> MESSAGE_REQ_VOTEQUORUM_QDEVICE_GETINFO; >> - >> - iov.iov_base = (char *)&req_lib_votequorum_general; >> - iov.iov_len = sizeof (struct req_lib_votequorum_general); >> + iov.iov_base = (char *)&req_lib_votequorum_qdevice_getinfo; >> + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_getinfo); >> >> error = qb_to_cs_error(qb_ipcc_sendv_recv ( >> votequorum_inst->c, >> diff --git a/test/testvotequorum2.c b/test/testvotequorum2.c >> index 39a7cbf..560f8ca 100644 >> --- a/test/testvotequorum2.c >> +++ b/test/testvotequorum2.c >> @@ -50,7 +50,7 @@ static void print_info(int ok_to_fail) >> struct votequorum_qdevice_info qinfo; >> int err; >> >> - if ( (err=votequorum_qdevice_getinfo(handle,&qinfo)) != CS_OK) >> + if ( (err=votequorum_qdevice_getinfo(handle, >> VOTEQUORUM_NODEID_QDEVICE,&qinfo)) != CS_OK) >> fprintf(stderr, "votequorum_qdevice_getinfo error %d: %s\n", >> err, ok_to_fail?"OK":"FAILED"); >> else { >> printf("qdevice votes %d\n", qinfo.votes); >> @@ -63,6 +63,7 @@ static void print_info(int ok_to_fail) >> >> int main(int argc, char *argv[]) >> { >> + int ret = 0; >> #ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> int pollcount=0, polltime=1; >> int err; >> @@ -82,24 +83,34 @@ int main(int argc, char *argv[]) >> } >> >> if (argc>= 2) { >> - if ( (err=votequorum_qdevice_register(handle, "QDEVICE", 4)) >> != CS_OK) >> + if ( (err=votequorum_qdevice_register(handle, "QDEVICE")) != >> CS_OK) { >> fprintf(stderr, "qdevice_register FAILED: %d\n", err); >> + ret = -1; >> + goto out; >> + } >> >> while (pollcount--) { >> print_info(0); >> - if ((err=votequorum_qdevice_poll(handle, 1)) != CS_OK) >> + if ((err=votequorum_qdevice_poll(handle, "QDEVICE", 1)) >> != CS_OK) { >> fprintf(stderr, "qdevice poll FAILED: %d\n", err); >> + ret = -1; >> + goto out; >> + } >> print_info(0); >> sleep(polltime); >> } >> - if ((err= votequorum_qdevice_unregister(handle)) != CS_OK) >> + if ((err= votequorum_qdevice_unregister(handle, "QDEVICE")) >> != CS_OK) { >> fprintf(stderr, "qdevice unregister FAILED: %d\n", err); >> + ret = -1; >> + goto out; >> + } >> } >> print_info(1); >> >> +out: >> votequorum_finalize(handle); >> #else >> - fprintf(stderr, "qdevice support is not built in >> corosync/votequorum\n"); >> + fprintf(stderr, "qdevice support is not built in >> corosync/votequorum\n"); >> #endif >> - return 0; >> + return ret; >> } >> diff --git a/tools/corosync-quorumtool.c b/tools/corosync-quorumtool.c >> index 0a21a3c..f60d7fd 100644 >> --- a/tools/corosync-quorumtool.c >> +++ b/tools/corosync-quorumtool.c >> @@ -63,7 +63,8 @@ typedef enum { >> CMD_SHOWSTATUS, >> CMD_SETVOTES, >> CMD_SETEXPECTED, >> - CMD_MONITOR >> + CMD_MONITOR, >> + CMD_UNREGISTER_QDEVICE >> } command_t; >> >> /* >> @@ -108,6 +109,8 @@ static votequorum_callbacks_t v_callbacks = { >> .votequorum_notify_fn = NULL, >> .votequorum_expectedvotes_notify_fn = NULL >> }; >> +static uint32_t our_nodeid = 0; >> +static uint8_t display_qdevice = 0; >> >> /* >> * cfg bits >> @@ -132,6 +135,7 @@ static void show_usage(const char *name) >> printf(" -e<expected> change expected votes for the cluster >> *\n"); >> printf(" -H show nodeids in hexadecimal rather than >> decimal\n"); >> printf(" -i show node IP addresses instead of the >> resolved name\n"); >> + printf(" -f forcefully unregister a quorum device >> *DANGEROUS*\n"); >> printf(" -h show this help text\n"); >> printf("\n"); >> printf(" * Starred items only work if votequorum is the quorum >> provider for corosync\n"); >> @@ -283,7 +287,7 @@ static void quorum_notification_fn( >> } >> } >> >> -static void display_nodes_data(nodeid_format_t nodeid_format, >> name_format_t name_format) >> +static void display_nodes_data(uint32_t nodeid, nodeid_format_t >> nodeid_format, name_format_t name_format) >> { >> int i; >> >> @@ -305,13 +309,51 @@ static void display_nodes_data(nodeid_format_t >> nodeid_format, name_format_t name >> printf("%s\n", node_name(g_view_list[i], name_format)); >> } >> } >> + >> if (g_view_list_entries) { >> free(g_view_list); >> g_view_list = NULL; >> } >> + >> +#if EXPERIMENTAL_QUORUM_DEVICE_API >> + if ((display_qdevice)&& (v_handle)) { >> + int err; >> + struct votequorum_qdevice_info qinfo; >> + >> + err = votequorum_qdevice_getinfo(v_handle, nodeid,&qinfo); >> + if (err != CS_OK) { >> + fprintf(stderr, "votequorum_qdevice_getinfo error: %d\n", >> err); >> + } else { >> + if (nodeid_format == NODEID_FORMAT_DECIMAL) { >> + printf("%10u ", VOTEQUORUM_NODEID_QDEVICE); >> + } else { >> + printf("0x%08x ", VOTEQUORUM_NODEID_QDEVICE); >> + } >> + printf("%3d %s (%s)\n", qinfo.votes, qinfo.name, >> qinfo.state?"Voting":"Not voting"); >> + } >> + } >> +#endif >> +} >> + >> +static const char *decode_state(int state) >> +{ >> + switch(state) { >> + case NODESTATE_MEMBER: >> + return "Member"; >> + break; >> + case NODESTATE_DEAD: >> + return "Dead"; >> + break; >> + case NODESTATE_LEAVING: >> + return "Leaving"; >> + break; >> + default: >> + return "Unknown state (this is bad)"; >> + break; >> + } >> } >> >> -static int display_quorum_data(int is_quorate, int loop) >> +static int display_quorum_data(int is_quorate, uint32_t nodeid, int >> loop) >> { >> struct votequorum_info info; >> int err; >> @@ -335,8 +377,9 @@ static int display_quorum_data(int is_quorate, int >> loop) >> return CS_OK; >> } >> >> - if ((err=votequorum_getinfo(v_handle, 0,&info)) == CS_OK) { >> + if ((err=votequorum_getinfo(v_handle, nodeid,&info)) == CS_OK) { >> printf("Node votes: %d\n", info.node_votes); >> + printf("Node state: %s\n", decode_state(info.state)); >> printf("Expected votes: %d\n", info.node_expected_votes); >> printf("Highest expected: %d\n", info.highest_expected); >> printf("Total votes: %d\n", info.total_votes); >> @@ -348,6 +391,12 @@ static int display_quorum_data(int is_quorate, >> int loop) >> if (info.flags& VOTEQUORUM_INFO_LAST_MAN_STANDING) >> printf("LastManStanding "); >> if (info.flags& VOTEQUORUM_INFO_AUTO_TIE_BREAKER) >> printf("AutoTieBreaker "); >> if (info.flags& VOTEQUORUM_INFO_LEAVE_REMOVE) >> printf("LeaveRemove "); >> + if (info.flags& VOTEQUORUM_INFO_QDEVICE) { >> + printf("Qdevice "); >> + display_qdevice = 1; >> + } else { >> + display_qdevice = 0; >> + } >> printf("\n"); >> } else { >> fprintf(stderr, "votequorum_getinfo FAILED: %d\n", err); >> @@ -361,7 +410,7 @@ static int display_quorum_data(int is_quorate, int >> loop) >> * 0 if not quorate >> * -1 on error >> */ >> -static int show_status(nodeid_format_t nodeid_format, name_format_t >> name_format) >> +static int show_status(uint32_t nodeid, nodeid_format_t >> nodeid_format, name_format_t name_format) >> { >> int is_quorate; >> int err; >> @@ -395,11 +444,11 @@ quorum_err: >> return -1; >> } >> >> - err = display_quorum_data(is_quorate, 0); >> + err = display_quorum_data(is_quorate, nodeid, 0); >> if (err != CS_OK) { >> return -1; >> } >> - display_nodes_data(nodeid_format, name_format); >> + display_nodes_data(nodeid, nodeid_format, name_format); >> >> return is_quorate; >> } >> @@ -410,7 +459,7 @@ static int monitor_status(nodeid_format_t >> nodeid_format, name_format_t name_form >> >> if (q_type == QUORUM_FREE) { >> printf("\nQuorum is not configured - cannot monitor\n"); >> - return show_status(nodeid_format, name_format); >> + return show_status(our_nodeid, nodeid_format, name_format); >> } >> >> err=quorum_trackstart(q_handle, CS_TRACK_CHANGES); >> @@ -429,8 +478,8 @@ static int monitor_status(nodeid_format_t >> nodeid_format, name_format_t name_form >> } >> time(&t); >> printf("date: %s", ctime((const time_t *)&t)); >> - err = display_quorum_data(g_quorate, loop); >> - display_nodes_data(nodeid_format, name_format); >> + err = display_quorum_data(g_quorate, our_nodeid, loop); >> + display_nodes_data(our_nodeid, nodeid_format, name_format); >> printf("\n"); >> loop = 1; >> if (err != CS_OK) { >> @@ -463,13 +512,37 @@ static int show_nodes(nodeid_format_t >> nodeid_format, name_format_t name_format) >> } >> } >> >> - display_nodes_data(nodeid_format, name_format); >> + display_nodes_data(our_nodeid, nodeid_format, name_format); >> >> result = EXIT_SUCCESS; >> err_exit: >> return result; >> } >> >> +static int unregister_qdevice(void) >> +{ >> +#ifdef EXPERIMENTAL_QUORUM_DEVICE_API >> + int err; >> + struct votequorum_qdevice_info qinfo; >> + >> + err = votequorum_qdevice_getinfo(v_handle, our_nodeid,&qinfo); >> + if (err != CS_OK) { >> + fprintf(stderr, "votequorum_qdevice_getinfo FAILED: %d\n", err); >> + return -1; >> + } >> + >> + err = votequorum_qdevice_unregister(v_handle, qinfo.name); >> + if (err != CS_OK) { >> + fprintf(stderr, "votequorum_qdevice_unregister FAILED: %d\n", >> err); >> + return -1; >> + } >> + return 0; >> +#else >> + fprintf(stderr, "votequorum quorum device support is not >> built-in\n"); >> + return -1; >> +#endif >> +} >> + >> /* >> * return -1 on error >> * 0 if OK >> @@ -509,6 +582,11 @@ static int init_all(void) { >> goto out; >> } >> >> + if (cmap_get_uint32(cmap_handle, >> "runtime.votequorum.this_node_id",&our_nodeid) != CS_OK) { >> + fprintf(stderr, "Unable to retrive this node nodeid\n"); >> + goto out; >> + } >> + >> return 0; >> out: >> return -1; >> @@ -530,12 +608,13 @@ static void close_all(void) { >> } >> >> int main (int argc, char *argv[]) { >> - const char *options = "VHslme:v:hin:d:"; >> + const char *options = "VHslmfe:v:hin:d:"; >> char *endptr; >> int opt; >> int votes = 0; >> int ret = 0; >> - uint32_t nodeid = VOTEQUORUM_NODEID_US; >> + uint32_t nodeid = 0; >> + uint32_t nodeid_set = 0; >> nodeid_format_t nodeid_format = NODEID_FORMAT_DECIMAL; >> name_format_t address_format = ADDRESS_FORMAT_NAME; >> command_t command_opt = CMD_UNKNOWN; >> @@ -552,6 +631,14 @@ int main (int argc, char *argv[]) { >> >> while ( (opt = getopt(argc, argv, options)) != -1 ) { >> switch (opt) { >> + case 'f': >> + if (using_votequorum()> 0) { >> + command_opt = CMD_UNREGISTER_QDEVICE; >> + } else { >> + fprintf(stderr, "You cannot unregister quorum device, >> corosync is not using votequorum\n"); >> + exit(2); >> + } >> + break; >> case 's': >> command_opt = CMD_SHOWSTATUS; >> break; >> @@ -582,15 +669,18 @@ int main (int argc, char *argv[]) { >> break; >> case 'n': >> nodeid = strtol(optarg,&endptr, 0); >> - if ((nodeid == 0&& endptr == optarg) || nodeid<= 0) { >> + if ((nodeid == 0&& endptr == optarg) || nodeid< 0) { >> fprintf(stderr, "The nodeid was not valid, try a >> positive number\n"); >> + exit(2); >> } >> + nodeid_set = 1; >> break; >> case 'v': >> if (using_votequorum()> 0) { >> votes = strtol(optarg,&endptr, 0); >> if ((votes == 0&& endptr == optarg) || votes< 0) { >> fprintf(stderr, "New votes value was not valid, >> try a positive number or zero\n"); >> + exit(2); >> } else { >> command_opt = CMD_SETVOTES; >> } >> @@ -600,10 +690,12 @@ int main (int argc, char *argv[]) { >> exit(2); >> } >> break; >> + case ':': >> case 'h': >> case '?': >> default: >> - break; >> + command_opt = CMD_UNKNOWN; >> + break; >> } >> } >> >> @@ -616,9 +708,15 @@ int main (int argc, char *argv[]) { >> ret = show_nodes(nodeid_format, address_format); >> break; >> case CMD_SHOWSTATUS: >> - ret = show_status(nodeid_format, address_format); >> + if (!nodeid_set) { >> + nodeid = our_nodeid; >> + } >> + ret = show_status(nodeid, nodeid_format, address_format); >> break; >> case CMD_SETVOTES: >> + if (!nodeid_set) { >> + nodeid = our_nodeid; >> + } >> ret = set_votes(nodeid, votes); >> break; >> case CMD_SETEXPECTED: >> @@ -627,6 +725,9 @@ int main (int argc, char *argv[]) { >> case CMD_MONITOR: >> ret = monitor_status(nodeid_format, address_format); >> break; >> + case CMD_UNREGISTER_QDEVICE: >> + ret = unregister_qdevice(); >> + break; >> } >> >> close_all(); > > _______________________________________________ > discuss mailing list > discuss@xxxxxxxxxxxx > http://lists.corosync.org/mailman/listinfo/discuss _______________________________________________ discuss mailing list discuss@xxxxxxxxxxxx http://lists.corosync.org/mailman/listinfo/discuss