diff --git a/lib/cfg.c b/lib/cfg.c index 34b8ea4f..248df4d6 100644 --- a/lib/cfg.c +++ b/lib/cfg.c @@ -1,607 +1,621 @@ /* * Copyright (c) 2002-2005 MontaVista Software, Inc. * Copyright (c) 2006-2011 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" /* * Data structure for instance data */ struct cfg_inst { qb_ipcc_connection_t *c; corosync_cfg_callbacks_t callbacks; cs_name_t comp_name; int comp_registered; int finalize; }; /* * All instances in one database */ -DECLARE_HDB_DATABASE (cfg_hdb,NULL); +static void cfg_inst_free (void *inst); + +DECLARE_HDB_DATABASE (cfg_hdb, cfg_inst_free); /* * Implementation */ cs_error_t corosync_cfg_initialize ( corosync_cfg_handle_t *cfg_handle, const corosync_cfg_callbacks_t *cfg_callbacks) { struct cfg_inst *cfg_inst; cs_error_t error = CS_OK; error = hdb_error_to_cs (hdb_handle_create (&cfg_hdb, sizeof (struct cfg_inst), cfg_handle)); if (error != CS_OK) { goto error_no_destroy; } error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, *cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { goto error_destroy; } + cfg_inst->finalize = 0; cfg_inst->c = qb_ipcc_connect ("cfg", IPC_REQUEST_SIZE); if (cfg_inst->c == NULL) { error = qb_to_cs_error(-errno); goto error_put_destroy; } if (cfg_callbacks) { memcpy (&cfg_inst->callbacks, cfg_callbacks, sizeof (corosync_cfg_callbacks_t)); } (void)hdb_handle_put (&cfg_hdb, *cfg_handle); return (CS_OK); error_put_destroy: (void)hdb_handle_put (&cfg_hdb, *cfg_handle); error_destroy: (void)hdb_handle_destroy (&cfg_hdb, *cfg_handle); error_no_destroy: return (error); } cs_error_t corosync_cfg_fd_get ( corosync_cfg_handle_t cfg_handle, int32_t *selection_fd) { struct cfg_inst *cfg_inst; cs_error_t error; error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } error = qb_to_cs_error (qb_ipcc_fd_get (cfg_inst->c, selection_fd)); (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (error); } cs_error_t corosync_cfg_dispatch ( corosync_cfg_handle_t cfg_handle, cs_dispatch_flags_t dispatch_flags) { int timeout = -1; cs_error_t error; int cont = 1; /* always continue do loop except when set to 0 */ struct cfg_inst *cfg_inst; struct res_lib_cfg_testshutdown *res_lib_cfg_testshutdown; corosync_cfg_callbacks_t callbacks; struct qb_ipc_response_header *dispatch_data; char dispatch_buf[IPC_DISPATCH_SIZE]; error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } /* * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING */ if (dispatch_flags == CS_DISPATCH_ALL || dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) { timeout = 0; } dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; do { error = qb_to_cs_error (qb_ipcc_event_recv ( cfg_inst->c, dispatch_buf, IPC_DISPATCH_SIZE, timeout)); if (error == CS_ERR_BAD_HANDLE) { error = CS_OK; goto error_put; } if (error == CS_ERR_TRY_AGAIN) { if (dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) { /* * Don't mask error */ goto error_put; } error = CS_OK; if (dispatch_flags == CS_DISPATCH_ALL) { break; /* exit do while cont is 1 loop */ } else { continue; /* next poll */ } } if (error != CS_OK) { goto error_put; } /* * Make copy of callbacks, message data, unlock instance, and call callback * A risk of this dispatch method is that the callback routines may * operate at the same time that cfgFinalize has been called in another thread. */ memcpy (&callbacks, &cfg_inst->callbacks, sizeof (corosync_cfg_callbacks_t)); /* * Dispatch incoming response */ switch (dispatch_data->id) { case MESSAGE_RES_CFG_TESTSHUTDOWN: if (callbacks.corosync_cfg_shutdown_callback == NULL) { break; } res_lib_cfg_testshutdown = (struct res_lib_cfg_testshutdown *)dispatch_data; callbacks.corosync_cfg_shutdown_callback(cfg_handle, res_lib_cfg_testshutdown->flags); break; default: error = CS_ERR_LIBRARY; goto error_nounlock; break; } + if (cfg_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } /* * Determine if more messages should be processed */ if (dispatch_flags == CS_DISPATCH_ONE || dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) { cont = 0; } } while (cont); error_put: (void)hdb_handle_put (&cfg_hdb, cfg_handle); error_nounlock: return (error); } +static void cfg_inst_free (void *inst) +{ + struct cfg_inst *cfg_inst = (struct cfg_inst *)inst; + qb_ipcc_disconnect(cfg_inst->c); +} + cs_error_t corosync_cfg_finalize ( corosync_cfg_handle_t cfg_handle) { struct cfg_inst *cfg_inst; cs_error_t error; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } /* * Another thread has already started finalizing */ if (cfg_inst->finalize) { (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (CS_ERR_BAD_HANDLE); } cfg_inst->finalize = 1; - qb_ipcc_disconnect (cfg_inst->c); - (void)hdb_handle_destroy (&cfg_hdb, cfg_handle); (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (error); } cs_error_t corosync_cfg_ring_status_get ( corosync_cfg_handle_t cfg_handle, char ***interface_names, char ***status, unsigned int *interface_count) { struct cfg_inst *cfg_inst; struct req_lib_cfg_ringstatusget req_lib_cfg_ringstatusget; struct res_lib_cfg_ringstatusget res_lib_cfg_ringstatusget; unsigned int i, j; cs_error_t error; struct iovec iov; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_ringstatusget.header.size = sizeof (struct req_lib_cfg_ringstatusget); req_lib_cfg_ringstatusget.header.id = MESSAGE_REQ_CFG_RINGSTATUSGET; iov.iov_base = (void *)&req_lib_cfg_ringstatusget, iov.iov_len = sizeof (struct req_lib_cfg_ringstatusget), error = qb_to_cs_error (qb_ipcc_sendv_recv(cfg_inst->c, &iov, 1, &res_lib_cfg_ringstatusget, sizeof (struct res_lib_cfg_ringstatusget), CS_IPC_TIMEOUT_MS)); *interface_count = res_lib_cfg_ringstatusget.interface_count; *interface_names = malloc (sizeof (char *) * *interface_count); if (*interface_names == NULL) { return (CS_ERR_NO_MEMORY); } memset (*interface_names, 0, sizeof (char *) * *interface_count); *status = malloc (sizeof (char *) * *interface_count); if (*status == NULL) { error = CS_ERR_NO_MEMORY; goto error_free_interface_names_array; } memset (*status, 0, sizeof (char *) * *interface_count); for (i = 0; i < res_lib_cfg_ringstatusget.interface_count; i++) { (*(interface_names))[i] = strdup (res_lib_cfg_ringstatusget.interface_name[i]); if ((*(interface_names))[i] == NULL) { error = CS_ERR_NO_MEMORY; goto error_free_interface_names; } } for (i = 0; i < res_lib_cfg_ringstatusget.interface_count; i++) { (*(status))[i] = strdup (res_lib_cfg_ringstatusget.interface_status[i]); if ((*(status))[i] == NULL) { error = CS_ERR_NO_MEMORY; goto error_free_status; } } goto no_error; error_free_status: for (j = 0; j < i; j++) { free ((*(status))[j]); } i = *interface_count; error_free_interface_names: for (j = 0; j < i; j++) { free ((*(interface_names))[j]); } free (*status); error_free_interface_names_array: free (*interface_names); no_error: (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (error); } cs_error_t corosync_cfg_ring_reenable ( corosync_cfg_handle_t cfg_handle) { struct cfg_inst *cfg_inst; struct req_lib_cfg_ringreenable req_lib_cfg_ringreenable; struct res_lib_cfg_ringreenable res_lib_cfg_ringreenable; cs_error_t error; struct iovec iov; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_ringreenable.header.size = sizeof (struct req_lib_cfg_ringreenable); req_lib_cfg_ringreenable.header.id = MESSAGE_REQ_CFG_RINGREENABLE; iov.iov_base = (void *)&req_lib_cfg_ringreenable, iov.iov_len = sizeof (struct req_lib_cfg_ringreenable); error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, &iov, 1, &res_lib_cfg_ringreenable, sizeof (struct res_lib_cfg_ringreenable), CS_IPC_TIMEOUT_MS)); (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (error); } cs_error_t corosync_cfg_kill_node ( corosync_cfg_handle_t cfg_handle, unsigned int nodeid, const char *reason) { struct cfg_inst *cfg_inst; struct req_lib_cfg_killnode req_lib_cfg_killnode; struct res_lib_cfg_killnode res_lib_cfg_killnode; cs_error_t error; struct iovec iov; if (strlen(reason) >= CS_MAX_NAME_LENGTH) return CS_ERR_NAME_TOO_LONG; error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_killnode.header.id = MESSAGE_REQ_CFG_KILLNODE; req_lib_cfg_killnode.header.size = sizeof (struct req_lib_cfg_killnode); req_lib_cfg_killnode.nodeid = nodeid; strcpy((char *)req_lib_cfg_killnode.reason.value, reason); req_lib_cfg_killnode.reason.length = strlen(reason)+1; iov.iov_base = (void *)&req_lib_cfg_killnode; iov.iov_len = sizeof (struct req_lib_cfg_killnode); error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, &iov, 1, &res_lib_cfg_killnode, sizeof (struct res_lib_cfg_killnode), CS_IPC_TIMEOUT_MS)); error = res_lib_cfg_killnode.header.error; (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (error == CS_OK ? res_lib_cfg_killnode.header.error : error); } cs_error_t corosync_cfg_try_shutdown ( corosync_cfg_handle_t cfg_handle, corosync_cfg_shutdown_flags_t flags) { struct cfg_inst *cfg_inst; struct req_lib_cfg_tryshutdown req_lib_cfg_tryshutdown; struct res_lib_cfg_tryshutdown res_lib_cfg_tryshutdown; cs_error_t error; struct iovec iov; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_tryshutdown.header.id = MESSAGE_REQ_CFG_TRYSHUTDOWN; req_lib_cfg_tryshutdown.header.size = sizeof (struct req_lib_cfg_tryshutdown); req_lib_cfg_tryshutdown.flags = flags; iov.iov_base = (void *)&req_lib_cfg_tryshutdown; iov.iov_len = sizeof (req_lib_cfg_tryshutdown); error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, &iov, 1, &res_lib_cfg_tryshutdown, sizeof (struct res_lib_cfg_tryshutdown), CS_IPC_TIMEOUT_MS)); (void)hdb_handle_put (&cfg_hdb, cfg_handle); return (error == CS_OK ? res_lib_cfg_tryshutdown.header.error : error); } cs_error_t corosync_cfg_replyto_shutdown ( corosync_cfg_handle_t cfg_handle, corosync_cfg_shutdown_reply_flags_t response) { struct cfg_inst *cfg_inst; struct req_lib_cfg_replytoshutdown req_lib_cfg_replytoshutdown; struct res_lib_cfg_replytoshutdown res_lib_cfg_replytoshutdown; struct iovec iov; cs_error_t error; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_replytoshutdown.header.id = MESSAGE_REQ_CFG_REPLYTOSHUTDOWN; req_lib_cfg_replytoshutdown.header.size = sizeof (struct req_lib_cfg_replytoshutdown); req_lib_cfg_replytoshutdown.response = response; iov.iov_base = (void *)&req_lib_cfg_replytoshutdown; iov.iov_len = sizeof (struct req_lib_cfg_replytoshutdown); error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, &iov, 1, &res_lib_cfg_replytoshutdown, sizeof (struct res_lib_cfg_replytoshutdown), CS_IPC_TIMEOUT_MS)); return (error); } cs_error_t corosync_cfg_get_node_addrs ( corosync_cfg_handle_t cfg_handle, int nodeid, size_t max_addrs, int *num_addrs, corosync_cfg_node_address_t *addrs) { cs_error_t error; struct req_lib_cfg_get_node_addrs req_lib_cfg_get_node_addrs; struct res_lib_cfg_get_node_addrs *res_lib_cfg_get_node_addrs; struct cfg_inst *cfg_inst; int addrlen = 0; int i; struct iovec iov; const char *addr_buf; char response_buf[IPC_RESPONSE_SIZE]; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_get_node_addrs.header.size = sizeof (req_lib_cfg_get_node_addrs); req_lib_cfg_get_node_addrs.header.id = MESSAGE_REQ_CFG_GET_NODE_ADDRS; req_lib_cfg_get_node_addrs.nodeid = nodeid; iov.iov_base = (char *)&req_lib_cfg_get_node_addrs; iov.iov_len = sizeof (req_lib_cfg_get_node_addrs); error = qb_to_cs_error (qb_ipcc_sendv_recv ( cfg_inst->c, &iov, 1, response_buf, IPC_RESPONSE_SIZE, CS_IPC_TIMEOUT_MS)); res_lib_cfg_get_node_addrs = (struct res_lib_cfg_get_node_addrs *)response_buf; if (error != CS_OK) { goto error_put; } if (res_lib_cfg_get_node_addrs->family == AF_INET) addrlen = sizeof(struct sockaddr_in); if (res_lib_cfg_get_node_addrs->family == AF_INET6) addrlen = sizeof(struct sockaddr_in6); for (i = 0, addr_buf = (char *)res_lib_cfg_get_node_addrs->addrs; i < max_addrs && inum_addrs; i++, addr_buf += TOTEMIP_ADDRLEN) { struct sockaddr_in *in; struct sockaddr_in6 *in6; addrs[i].address_length = addrlen; if (res_lib_cfg_get_node_addrs->family == AF_INET) { in = (struct sockaddr_in *)addrs[i].address; in->sin_family = AF_INET; memcpy(&in->sin_addr, addr_buf, sizeof(struct in_addr)); } if (res_lib_cfg_get_node_addrs->family == AF_INET6) { in6 = (struct sockaddr_in6 *)addrs[i].address; in6->sin6_family = AF_INET6; memcpy(&in6->sin6_addr, addr_buf, sizeof(struct in6_addr)); } } *num_addrs = res_lib_cfg_get_node_addrs->num_addrs; errno = error = res_lib_cfg_get_node_addrs->header.error; error_put: hdb_handle_put (&cfg_hdb, cfg_handle); return (error); } cs_error_t corosync_cfg_local_get ( corosync_cfg_handle_t handle, unsigned int *local_nodeid) { cs_error_t error; struct cfg_inst *cfg_inst; struct iovec iov; struct req_lib_cfg_local_get req_lib_cfg_local_get; struct res_lib_cfg_local_get res_lib_cfg_local_get; error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst)); if (error != CS_OK) { return (error); } req_lib_cfg_local_get.header.size = sizeof (struct qb_ipc_request_header); req_lib_cfg_local_get.header.id = MESSAGE_REQ_CFG_LOCAL_GET; iov.iov_base = (void *)&req_lib_cfg_local_get; iov.iov_len = sizeof (struct req_lib_cfg_local_get); error = qb_to_cs_error (qb_ipcc_sendv_recv ( cfg_inst->c, &iov, 1, &res_lib_cfg_local_get, sizeof (struct res_lib_cfg_local_get), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_cfg_local_get.header.error; *local_nodeid = res_lib_cfg_local_get.local_nodeid; error_exit: (void)hdb_handle_put (&cfg_hdb, handle); return (error); } diff --git a/lib/cmap.c b/lib/cmap.c index 1a585413..bfe7d6ee 100644 --- a/lib/cmap.c +++ b/lib/cmap.c @@ -1,1018 +1,1039 @@ /* * Copyright (c) 2011-2012 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the Red Hat, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include struct cmap_inst { + int finalize; qb_ipcc_connection_t *c; const void *context; }; struct cmap_track_inst { void *user_data; cmap_notify_fn_t notify_fn; qb_ipcc_connection_t *c; cmap_track_handle_t track_handle; }; -DECLARE_HDB_DATABASE(cmap_handle_t_db,NULL); +static void cmap_inst_free (void *inst); + +DECLARE_HDB_DATABASE(cmap_handle_t_db, cmap_inst_free); DECLARE_HDB_DATABASE(cmap_track_handle_t_db,NULL); /* * Function prototypes */ static cs_error_t cmap_get_int( cmap_handle_t handle, const char *key_name, void *value, size_t value_size, cmap_value_types_t type); static cs_error_t cmap_adjust_int(cmap_handle_t handle, const char *key_name, int32_t step); /* * Function implementations */ cs_error_t cmap_initialize (cmap_handle_t *handle) { cs_error_t error; struct cmap_inst *cmap_inst; error = hdb_error_to_cs(hdb_handle_create(&cmap_handle_t_db, sizeof(*cmap_inst), handle)); if (error != CS_OK) { goto error_no_destroy; } error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, *handle, (void *)&cmap_inst)); if (error != CS_OK) { goto error_destroy; } error = CS_OK; + cmap_inst->finalize = 0; cmap_inst->c = qb_ipcc_connect("cmap", IPC_REQUEST_SIZE); if (cmap_inst->c == NULL) { error = qb_to_cs_error(-errno); goto error_put_destroy; } (void)hdb_handle_put(&cmap_handle_t_db, *handle); return (CS_OK); error_put_destroy: (void)hdb_handle_put(&cmap_handle_t_db, *handle); error_destroy: (void)hdb_handle_destroy(&cmap_handle_t_db, *handle); error_no_destroy: return (error); } +static void cmap_inst_free (void *inst) +{ + struct cmap_inst *cmap_inst = (struct cmap_inst *)inst; + qb_ipcc_disconnect(cmap_inst->c); +} + cs_error_t cmap_finalize(cmap_handle_t handle) { struct cmap_inst *cmap_inst; cs_error_t error; hdb_handle_t track_inst_handle = 0; struct cmap_track_inst *cmap_track_inst; error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } - qb_ipcc_disconnect(cmap_inst->c); + if (cmap_inst->finalize) { + (void)hdb_handle_put (&cmap_handle_t_db, handle); + return (CS_ERR_BAD_HANDLE); + } + cmap_inst->finalize = 1; /* * Destroy all track instances for given connection */ hdb_iterator_reset(&cmap_track_handle_t_db); while (hdb_iterator_next(&cmap_track_handle_t_db, (void*)&cmap_track_inst, &track_inst_handle) == 0) { if (cmap_track_inst->c == cmap_inst->c) { (void)hdb_handle_destroy(&cmap_track_handle_t_db, track_inst_handle); } (void)hdb_handle_put (&cmap_track_handle_t_db, track_inst_handle); } (void)hdb_handle_destroy(&cmap_handle_t_db, handle); (void)hdb_handle_put(&cmap_handle_t_db, handle); return (CS_OK); } cs_error_t cmap_fd_get(cmap_handle_t handle, int *fd) { cs_error_t error; struct cmap_inst *cmap_inst; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } error = qb_to_cs_error (qb_ipcc_fd_get (cmap_inst->c, fd)); (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_dispatch ( cmap_handle_t handle, cs_dispatch_flags_t dispatch_types) { int timeout = -1; cs_error_t error; int cont = 1; /* always continue do loop except when set to 0 */ struct cmap_inst *cmap_inst; struct qb_ipc_response_header *dispatch_data; char dispatch_buf[IPC_DISPATCH_SIZE]; struct res_lib_cmap_notify_callback *res_lib_cmap_notify_callback; struct cmap_track_inst *cmap_track_inst; struct cmap_notify_value old_val; struct cmap_notify_value new_val; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } /* * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING */ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { timeout = 0; } dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; do { error = qb_to_cs_error(qb_ipcc_event_recv ( cmap_inst->c, dispatch_buf, IPC_DISPATCH_SIZE, timeout)); if (error == CS_ERR_BAD_HANDLE) { error = CS_OK; goto error_put; } if (error == CS_ERR_TRY_AGAIN) { if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { /* * Don't mask error */ goto error_put; } error = CS_OK; if (dispatch_types == CS_DISPATCH_ALL) { break; /* exit do while cont is 1 loop */ } else { continue; /* next poll */ } } if (error != CS_OK) { goto error_put; } /* * Dispatch incoming message */ switch (dispatch_data->id) { case MESSAGE_RES_CMAP_NOTIFY_CALLBACK: res_lib_cmap_notify_callback = (struct res_lib_cmap_notify_callback *)dispatch_data; error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db, res_lib_cmap_notify_callback->track_inst_handle, (void *)&cmap_track_inst)); if (error == CS_ERR_BAD_HANDLE) { /* * User deleted tracker -> ignore error */ break; } if (error != CS_OK) { goto error_put; } new_val.type = res_lib_cmap_notify_callback->new_value_type; old_val.type = res_lib_cmap_notify_callback->old_value_type; new_val.len = res_lib_cmap_notify_callback->new_value_len; old_val.len = res_lib_cmap_notify_callback->old_value_len; new_val.data = res_lib_cmap_notify_callback->new_value; old_val.data = (((const char *)res_lib_cmap_notify_callback->new_value) + new_val.len); cmap_track_inst->notify_fn(handle, cmap_track_inst->track_handle, res_lib_cmap_notify_callback->event, (char *)res_lib_cmap_notify_callback->key_name.value, new_val, old_val, cmap_track_inst->user_data); (void)hdb_handle_put(&cmap_track_handle_t_db, res_lib_cmap_notify_callback->track_inst_handle); break; default: error = CS_ERR_LIBRARY; goto error_put; break; } + if (cmap_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } /* * Determine if more messages should be processed */ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { cont = 0; } } while (cont); error_put: (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_context_get ( cmap_handle_t handle, const void **context) { cs_error_t error; struct cmap_inst *cmap_inst; error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } *context = cmap_inst->context; (void)hdb_handle_put (&cmap_handle_t_db, handle); return (CS_OK); } cs_error_t cmap_context_set ( cmap_handle_t handle, const void *context) { cs_error_t error; struct cmap_inst *cmap_inst; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } cmap_inst->context = context; (void)hdb_handle_put (&cmap_handle_t_db, handle); return (CS_OK); } cs_error_t cmap_set ( cmap_handle_t handle, const char *key_name, const void *value, size_t value_len, cmap_value_types_t type) { cs_error_t error; struct iovec iov[2]; struct cmap_inst *cmap_inst; struct req_lib_cmap_set req_lib_cmap_set; struct res_lib_cmap_set res_lib_cmap_set; if (key_name == NULL) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_set, 0, sizeof(req_lib_cmap_set)); req_lib_cmap_set.header.size = sizeof(req_lib_cmap_set) + value_len; req_lib_cmap_set.header.id = MESSAGE_REQ_CMAP_SET; memcpy(req_lib_cmap_set.key_name.value, key_name, strlen(key_name)); req_lib_cmap_set.key_name.length = strlen(key_name); req_lib_cmap_set.value_len = value_len; req_lib_cmap_set.type = type; iov[0].iov_base = (char *)&req_lib_cmap_set; iov[0].iov_len = sizeof(req_lib_cmap_set); iov[1].iov_base = (void *)value; iov[1].iov_len = value_len; error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, iov, 2, &res_lib_cmap_set, sizeof (struct res_lib_cmap_set), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_set.header.error; } (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_set_int8(cmap_handle_t handle, const char *key_name, int8_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT8)); } cs_error_t cmap_set_uint8(cmap_handle_t handle, const char *key_name, uint8_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT8)); } cs_error_t cmap_set_int16(cmap_handle_t handle, const char *key_name, int16_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT16)); } cs_error_t cmap_set_uint16(cmap_handle_t handle, const char *key_name, uint16_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT16)); } cs_error_t cmap_set_int32(cmap_handle_t handle, const char *key_name, int32_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT32)); } cs_error_t cmap_set_uint32(cmap_handle_t handle, const char *key_name, uint32_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT32)); } cs_error_t cmap_set_int64(cmap_handle_t handle, const char *key_name, int64_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT64)); } cs_error_t cmap_set_uint64(cmap_handle_t handle, const char *key_name, uint64_t value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT64)); } cs_error_t cmap_set_float(cmap_handle_t handle, const char *key_name, float value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_FLOAT)); } cs_error_t cmap_set_double(cmap_handle_t handle, const char *key_name, double value) { return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_DOUBLE)); } cs_error_t cmap_set_string(cmap_handle_t handle, const char *key_name, const char *value) { if (value == NULL) { return (CS_ERR_INVALID_PARAM); } return (cmap_set(handle, key_name, value, strlen(value), CMAP_VALUETYPE_STRING)); } cs_error_t cmap_delete(cmap_handle_t handle, const char *key_name) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct req_lib_cmap_delete req_lib_cmap_delete; struct res_lib_cmap_delete res_lib_cmap_delete; if (key_name == NULL) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_delete, 0, sizeof(req_lib_cmap_delete)); req_lib_cmap_delete.header.size = sizeof(req_lib_cmap_delete); req_lib_cmap_delete.header.id = MESSAGE_REQ_CMAP_DELETE; memcpy(req_lib_cmap_delete.key_name.value, key_name, strlen(key_name)); req_lib_cmap_delete.key_name.length = strlen(key_name); iov.iov_base = (char *)&req_lib_cmap_delete; iov.iov_len = sizeof(req_lib_cmap_delete); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_delete, sizeof (struct res_lib_cmap_delete), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_delete.header.error; } (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_get( cmap_handle_t handle, const char *key_name, void *value, size_t *value_len, cmap_value_types_t *type) { cs_error_t error; struct cmap_inst *cmap_inst; struct iovec iov; struct req_lib_cmap_get req_lib_cmap_get; struct res_lib_cmap_get *res_lib_cmap_get; size_t res_size; if (key_name == NULL) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_get, 0, sizeof(req_lib_cmap_get)); req_lib_cmap_get.header.size = sizeof(req_lib_cmap_get); req_lib_cmap_get.header.id = MESSAGE_REQ_CMAP_GET; memcpy(req_lib_cmap_get.key_name.value, key_name, strlen(key_name)); req_lib_cmap_get.key_name.length = strlen(key_name); if (value != NULL && value_len != NULL) { req_lib_cmap_get.value_len = *value_len; } else { req_lib_cmap_get.value_len = 0; } iov.iov_base = (char *)&req_lib_cmap_get; iov.iov_len = sizeof(req_lib_cmap_get); res_size = sizeof(struct res_lib_cmap_get) + req_lib_cmap_get.value_len; res_lib_cmap_get = malloc(res_size); if (res_lib_cmap_get == NULL) { return (CS_ERR_NO_MEMORY); } error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, res_lib_cmap_get, res_size, CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_get->header.error; } if (error == CS_OK) { if (type != NULL) { *type = res_lib_cmap_get->type; } if (value_len != NULL) { *value_len = res_lib_cmap_get->value_len; } if (value != NULL) { memcpy(value, res_lib_cmap_get->value, res_lib_cmap_get->value_len); } } free(res_lib_cmap_get); (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } static cs_error_t cmap_get_int( cmap_handle_t handle, const char *key_name, void *value, size_t value_size, cmap_value_types_t type) { char key_value[16]; size_t key_size; cs_error_t err; cmap_value_types_t key_type; key_size = sizeof(key_value); memset(key_value, 0, key_size); err = cmap_get(handle, key_name, key_value, &key_size, &key_type); if (err != CS_OK) return (err); if (key_type != type) { return (CS_ERR_INVALID_PARAM); } memcpy(value, key_value, value_size); return (CS_OK); } cs_error_t cmap_get_int8(cmap_handle_t handle, const char *key_name, int8_t *i8) { return (cmap_get_int(handle, key_name, i8, sizeof(*i8), CMAP_VALUETYPE_INT8)); } cs_error_t cmap_get_uint8(cmap_handle_t handle, const char *key_name, uint8_t *u8) { return (cmap_get_int(handle, key_name, u8, sizeof(*u8), CMAP_VALUETYPE_UINT8)); } cs_error_t cmap_get_int16(cmap_handle_t handle, const char *key_name, int16_t *i16) { return (cmap_get_int(handle, key_name, i16, sizeof(*i16), CMAP_VALUETYPE_INT16)); } cs_error_t cmap_get_uint16(cmap_handle_t handle, const char *key_name, uint16_t *u16) { return (cmap_get_int(handle, key_name, u16, sizeof(*u16), CMAP_VALUETYPE_UINT16)); } cs_error_t cmap_get_int32(cmap_handle_t handle, const char *key_name, int32_t *i32) { return (cmap_get_int(handle, key_name, i32, sizeof(*i32), CMAP_VALUETYPE_INT32)); } cs_error_t cmap_get_uint32(cmap_handle_t handle, const char *key_name, uint32_t *u32) { return (cmap_get_int(handle, key_name, u32, sizeof(*u32), CMAP_VALUETYPE_UINT32)); } cs_error_t cmap_get_int64(cmap_handle_t handle, const char *key_name, int64_t *i64) { return (cmap_get_int(handle, key_name, i64, sizeof(*i64), CMAP_VALUETYPE_INT64)); } cs_error_t cmap_get_uint64(cmap_handle_t handle, const char *key_name, uint64_t *u64) { return (cmap_get_int(handle, key_name, u64, sizeof(*u64), CMAP_VALUETYPE_UINT64)); } cs_error_t cmap_get_float(cmap_handle_t handle, const char *key_name, float *flt) { return (cmap_get_int(handle, key_name, flt, sizeof(*flt), CMAP_VALUETYPE_FLOAT)); } cs_error_t cmap_get_double(cmap_handle_t handle, const char *key_name, double *dbl) { return (cmap_get_int(handle, key_name, dbl, sizeof(*dbl), CMAP_VALUETYPE_DOUBLE)); } cs_error_t cmap_get_string(cmap_handle_t handle, const char *key_name, char **str) { cs_error_t res; size_t str_len; cmap_value_types_t type; res = cmap_get(handle, key_name, NULL, &str_len, &type); if (res != CS_OK || type != CMAP_VALUETYPE_STRING) { if (res == CS_OK) { res = CS_ERR_INVALID_PARAM; } goto return_error; } *str = malloc(str_len); if (*str == NULL) { res = CS_ERR_NO_MEMORY; goto return_error; } res = cmap_get(handle, key_name, *str, &str_len, &type); if (res != CS_OK) { free(*str); goto return_error; } return (CS_OK); return_error: return (res); } static cs_error_t cmap_adjust_int(cmap_handle_t handle, const char *key_name, int32_t step) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct req_lib_cmap_adjust_int req_lib_cmap_adjust_int; struct res_lib_cmap_adjust_int res_lib_cmap_adjust_int; if (key_name == NULL) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_adjust_int, 0, sizeof(req_lib_cmap_adjust_int)); req_lib_cmap_adjust_int.header.size = sizeof(req_lib_cmap_adjust_int); req_lib_cmap_adjust_int.header.id = MESSAGE_REQ_CMAP_ADJUST_INT; memcpy(req_lib_cmap_adjust_int.key_name.value, key_name, strlen(key_name)); req_lib_cmap_adjust_int.key_name.length = strlen(key_name); req_lib_cmap_adjust_int.step = step; iov.iov_base = (char *)&req_lib_cmap_adjust_int; iov.iov_len = sizeof(req_lib_cmap_adjust_int); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_adjust_int, sizeof (struct res_lib_cmap_adjust_int), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_adjust_int.header.error; } (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_inc(cmap_handle_t handle, const char *key_name) { return (cmap_adjust_int(handle, key_name, 1)); } cs_error_t cmap_dec(cmap_handle_t handle, const char *key_name) { return (cmap_adjust_int(handle, key_name, -1)); } cs_error_t cmap_iter_init( cmap_handle_t handle, const char *prefix, cmap_iter_handle_t *cmap_iter_handle) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct req_lib_cmap_iter_init req_lib_cmap_iter_init; struct res_lib_cmap_iter_init res_lib_cmap_iter_init; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_iter_init, 0, sizeof(req_lib_cmap_iter_init)); req_lib_cmap_iter_init.header.size = sizeof(req_lib_cmap_iter_init); req_lib_cmap_iter_init.header.id = MESSAGE_REQ_CMAP_ITER_INIT; if (prefix) { memcpy(req_lib_cmap_iter_init.prefix.value, prefix, strlen(prefix)); req_lib_cmap_iter_init.prefix.length = strlen(prefix); } iov.iov_base = (char *)&req_lib_cmap_iter_init; iov.iov_len = sizeof(req_lib_cmap_iter_init); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_iter_init, sizeof (struct res_lib_cmap_iter_init), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_iter_init.header.error; } if (error == CS_OK) { *cmap_iter_handle = res_lib_cmap_iter_init.iter_handle; } (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_iter_next( cmap_handle_t handle, cmap_iter_handle_t iter_handle, char key_name[], size_t *value_len, cmap_value_types_t *type) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct req_lib_cmap_iter_next req_lib_cmap_iter_next; struct res_lib_cmap_iter_next res_lib_cmap_iter_next; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_iter_next, 0, sizeof(req_lib_cmap_iter_next)); req_lib_cmap_iter_next.header.size = sizeof(req_lib_cmap_iter_next); req_lib_cmap_iter_next.header.id = MESSAGE_REQ_CMAP_ITER_NEXT; req_lib_cmap_iter_next.iter_handle = iter_handle; iov.iov_base = (char *)&req_lib_cmap_iter_next; iov.iov_len = sizeof(req_lib_cmap_iter_next); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_iter_next, sizeof (struct res_lib_cmap_iter_next), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_iter_next.header.error; } if (error == CS_OK) { strncpy(key_name, (const char *)res_lib_cmap_iter_next.key_name.value, CMAP_KEYNAME_MAXLEN); if (value_len != NULL) { *value_len = res_lib_cmap_iter_next.value_len; } if (type != NULL) { *type = res_lib_cmap_iter_next.type; } } (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_iter_finalize( cmap_handle_t handle, cmap_iter_handle_t iter_handle) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct req_lib_cmap_iter_finalize req_lib_cmap_iter_finalize; struct res_lib_cmap_iter_finalize res_lib_cmap_iter_finalize; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_iter_finalize, 0, sizeof(req_lib_cmap_iter_finalize)); req_lib_cmap_iter_finalize.header.size = sizeof(req_lib_cmap_iter_finalize); req_lib_cmap_iter_finalize.header.id = MESSAGE_REQ_CMAP_ITER_FINALIZE; req_lib_cmap_iter_finalize.iter_handle = iter_handle; iov.iov_base = (char *)&req_lib_cmap_iter_finalize; iov.iov_len = sizeof(req_lib_cmap_iter_finalize); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_iter_finalize, sizeof (struct res_lib_cmap_iter_finalize), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_iter_finalize.header.error; } (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_track_add( cmap_handle_t handle, const char *key_name, int32_t track_type, cmap_notify_fn_t notify_fn, void *user_data, cmap_track_handle_t *cmap_track_handle) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct req_lib_cmap_track_add req_lib_cmap_track_add; struct res_lib_cmap_track_add res_lib_cmap_track_add; struct cmap_track_inst *cmap_track_inst; cmap_track_handle_t cmap_track_inst_handle; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } error = hdb_error_to_cs(hdb_handle_create(&cmap_track_handle_t_db, sizeof(*cmap_track_inst), &cmap_track_inst_handle)); if (error != CS_OK) { goto error_put; } error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db, cmap_track_inst_handle, (void *)&cmap_track_inst)); if (error != CS_OK) { goto error_put_destroy; } cmap_track_inst->user_data = user_data; cmap_track_inst->notify_fn = notify_fn; cmap_track_inst->c = cmap_inst->c; memset(&req_lib_cmap_track_add, 0, sizeof(req_lib_cmap_track_add)); req_lib_cmap_track_add.header.size = sizeof(req_lib_cmap_track_add); req_lib_cmap_track_add.header.id = MESSAGE_REQ_CMAP_TRACK_ADD; if (key_name) { memcpy(req_lib_cmap_track_add.key_name.value, key_name, strlen(key_name)); req_lib_cmap_track_add.key_name.length = strlen(key_name); } req_lib_cmap_track_add.track_type = track_type; req_lib_cmap_track_add.track_inst_handle = cmap_track_inst_handle; iov.iov_base = (char *)&req_lib_cmap_track_add; iov.iov_len = sizeof(req_lib_cmap_track_add); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_track_add, sizeof (struct res_lib_cmap_track_add), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_track_add.header.error; } if (error == CS_OK) { *cmap_track_handle = res_lib_cmap_track_add.track_handle; cmap_track_inst->track_handle = *cmap_track_handle; } (void)hdb_handle_put (&cmap_track_handle_t_db, cmap_track_inst_handle); (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); error_put_destroy: (void)hdb_handle_put (&cmap_track_handle_t_db, cmap_track_inst_handle); (void)hdb_handle_destroy (&cmap_track_handle_t_db, cmap_track_inst_handle); error_put: (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } cs_error_t cmap_track_delete( cmap_handle_t handle, cmap_track_handle_t track_handle) { cs_error_t error; struct iovec iov; struct cmap_inst *cmap_inst; struct cmap_track_inst *cmap_track_inst; struct req_lib_cmap_track_delete req_lib_cmap_track_delete; struct res_lib_cmap_track_delete res_lib_cmap_track_delete; error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); if (error != CS_OK) { return (error); } memset(&req_lib_cmap_track_delete, 0, sizeof(req_lib_cmap_track_delete)); req_lib_cmap_track_delete.header.size = sizeof(req_lib_cmap_track_delete); req_lib_cmap_track_delete.header.id = MESSAGE_REQ_CMAP_TRACK_DELETE; req_lib_cmap_track_delete.track_handle = track_handle; iov.iov_base = (char *)&req_lib_cmap_track_delete; iov.iov_len = sizeof(req_lib_cmap_track_delete); error = qb_to_cs_error(qb_ipcc_sendv_recv( cmap_inst->c, &iov, 1, &res_lib_cmap_track_delete, sizeof (struct res_lib_cmap_track_delete), CS_IPC_TIMEOUT_MS)); if (error == CS_OK) { error = res_lib_cmap_track_delete.header.error; } if (error == CS_OK) { error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle, (void *)&cmap_track_inst)); if (error != CS_OK) { goto error_put; } (void)hdb_handle_put(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle); (void)hdb_handle_destroy(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle); } error_put: (void)hdb_handle_put (&cmap_handle_t_db, handle); return (error); } diff --git a/lib/cpg.c b/lib/cpg.c index 700303f6..0c9fa1ae 100644 --- a/lib/cpg.c +++ b/lib/cpg.c @@ -1,1141 +1,1155 @@ /* * vi: set autoindent tabstop=4 shiftwidth=4 : * * Copyright (c) 2006-2012 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfi@redhat.com) * Author: Jan Friesse (jfriesse@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Provides a closed process group API using the coroipcc executive */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" struct cpg_inst { qb_ipcc_connection_t *c; int finalize; void *context; union { cpg_model_data_t model_data; cpg_model_v1_data_t model_v1_data; }; struct list_head iteration_list_head; }; +static void cpg_inst_free (void *inst); -DECLARE_HDB_DATABASE(cpg_handle_t_db,NULL); +DECLARE_HDB_DATABASE(cpg_handle_t_db, cpg_inst_free); struct cpg_iteration_instance_t { cpg_iteration_handle_t cpg_iteration_handle; qb_ipcc_connection_t *conn; hdb_handle_t executive_iteration_handle; struct list_head list; }; DECLARE_HDB_DATABASE(cpg_iteration_handle_t_db,NULL); /* * Internal (not visible by API) functions */ static cs_error_t coroipcc_msg_send_reply_receive ( qb_ipcc_connection_t *c, const struct iovec *iov, unsigned int iov_len, void *res_msg, size_t res_len) { return qb_to_cs_error(qb_ipcc_sendv_recv(c, iov, iov_len, res_msg, res_len, CS_IPC_TIMEOUT_MS)); } static void cpg_iteration_instance_finalize (struct cpg_iteration_instance_t *cpg_iteration_instance) { list_del (&cpg_iteration_instance->list); hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle); } +static void cpg_inst_free (void *inst) +{ + struct cpg_inst *cpg_inst = (struct cpg_inst *)inst; + qb_ipcc_disconnect(cpg_inst->c); +} + static void cpg_inst_finalize (struct cpg_inst *cpg_inst, hdb_handle_t handle) { struct list_head *iter, *iter_next; struct cpg_iteration_instance_t *cpg_iteration_instance; /* * Traverse thru iteration instances and delete them */ for (iter = cpg_inst->iteration_list_head.next; iter != &cpg_inst->iteration_list_head;iter = iter_next) { iter_next = iter->next; cpg_iteration_instance = list_entry (iter, struct cpg_iteration_instance_t, list); cpg_iteration_instance_finalize (cpg_iteration_instance); } hdb_handle_destroy (&cpg_handle_t_db, handle); } /** * @defgroup cpg_coroipcc The closed process group API * @ingroup coroipcc * * @{ */ cs_error_t cpg_initialize ( cpg_handle_t *handle, cpg_callbacks_t *callbacks) { cpg_model_v1_data_t model_v1_data; memset (&model_v1_data, 0, sizeof (cpg_model_v1_data_t)); if (callbacks) { model_v1_data.cpg_deliver_fn = callbacks->cpg_deliver_fn; model_v1_data.cpg_confchg_fn = callbacks->cpg_confchg_fn; } return (cpg_model_initialize (handle, CPG_MODEL_V1, (cpg_model_data_t *)&model_v1_data, NULL)); } cs_error_t cpg_model_initialize ( cpg_handle_t *handle, cpg_model_t model, cpg_model_data_t *model_data, void *context) { cs_error_t error; struct cpg_inst *cpg_inst; if (model != CPG_MODEL_V1) { error = CS_ERR_INVALID_PARAM; goto error_no_destroy; } error = hdb_error_to_cs (hdb_handle_create (&cpg_handle_t_db, sizeof (struct cpg_inst), handle)); if (error != CS_OK) { goto error_no_destroy; } error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, *handle, (void *)&cpg_inst)); if (error != CS_OK) { goto error_destroy; } cpg_inst->c = qb_ipcc_connect ("cpg", IPC_REQUEST_SIZE); if (cpg_inst->c == NULL) { error = qb_to_cs_error(-errno); goto error_put_destroy; } if (model_data != NULL) { switch (model) { case CPG_MODEL_V1: memcpy (&cpg_inst->model_v1_data, model_data, sizeof (cpg_model_v1_data_t)); if ((cpg_inst->model_v1_data.flags & ~(CPG_MODEL_V1_DELIVER_INITIAL_TOTEM_CONF)) != 0) { error = CS_ERR_INVALID_PARAM; goto error_destroy; } break; } } cpg_inst->model_data.model = model; cpg_inst->context = context; list_init(&cpg_inst->iteration_list_head); hdb_handle_put (&cpg_handle_t_db, *handle); return (CS_OK); error_put_destroy: hdb_handle_put (&cpg_handle_t_db, *handle); error_destroy: hdb_handle_destroy (&cpg_handle_t_db, *handle); error_no_destroy: return (error); } cs_error_t cpg_finalize ( cpg_handle_t handle) { struct cpg_inst *cpg_inst; struct iovec iov; struct req_lib_cpg_finalize req_lib_cpg_finalize; struct res_lib_cpg_finalize res_lib_cpg_finalize; cs_error_t error; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } /* * Another thread has already started finalizing */ if (cpg_inst->finalize) { hdb_handle_put (&cpg_handle_t_db, handle); return (CS_ERR_BAD_HANDLE); } cpg_inst->finalize = 1; /* * Send service request */ req_lib_cpg_finalize.header.size = sizeof (struct req_lib_cpg_finalize); req_lib_cpg_finalize.header.id = MESSAGE_REQ_CPG_FINALIZE; iov.iov_base = (void *)&req_lib_cpg_finalize; iov.iov_len = sizeof (struct req_lib_cpg_finalize); error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1, &res_lib_cpg_finalize, sizeof (struct res_lib_cpg_finalize)); - qb_ipcc_disconnect(cpg_inst->c); - cpg_inst_finalize (cpg_inst, handle); hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_fd_get ( cpg_handle_t handle, int *fd) { cs_error_t error; struct cpg_inst *cpg_inst; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } error = qb_to_cs_error (qb_ipcc_fd_get (cpg_inst->c, fd)); hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_context_get ( cpg_handle_t handle, void **context) { cs_error_t error; struct cpg_inst *cpg_inst; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } *context = cpg_inst->context; hdb_handle_put (&cpg_handle_t_db, handle); return (CS_OK); } cs_error_t cpg_context_set ( cpg_handle_t handle, void *context) { cs_error_t error; struct cpg_inst *cpg_inst; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } cpg_inst->context = context; hdb_handle_put (&cpg_handle_t_db, handle); return (CS_OK); } cs_error_t cpg_dispatch ( cpg_handle_t handle, cs_dispatch_flags_t dispatch_types) { int timeout = -1; cs_error_t error; int cont = 1; /* always continue do loop except when set to 0 */ struct cpg_inst *cpg_inst; struct res_lib_cpg_confchg_callback *res_cpg_confchg_callback; struct res_lib_cpg_deliver_callback *res_cpg_deliver_callback; struct res_lib_cpg_totem_confchg_callback *res_cpg_totem_confchg_callback; struct cpg_inst cpg_inst_copy; struct qb_ipc_response_header *dispatch_data; struct cpg_address member_list[CPG_MEMBERS_MAX]; struct cpg_address left_list[CPG_MEMBERS_MAX]; struct cpg_address joined_list[CPG_MEMBERS_MAX]; struct cpg_name group_name; mar_cpg_address_t *left_list_start; mar_cpg_address_t *joined_list_start; unsigned int i; struct cpg_ring_id ring_id; uint32_t totem_member_list[CPG_MEMBERS_MAX]; int32_t errno_res; char dispatch_buf[IPC_DISPATCH_SIZE]; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } /* * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING */ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { timeout = 0; } dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; do { errno_res = qb_ipcc_event_recv ( cpg_inst->c, dispatch_buf, IPC_DISPATCH_SIZE, timeout); error = qb_to_cs_error (errno_res); if (error == CS_ERR_BAD_HANDLE) { error = CS_OK; goto error_put; } if (error == CS_ERR_TRY_AGAIN) { if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { /* * Don't mask error */ goto error_put; } error = CS_OK; if (dispatch_types == CS_DISPATCH_ALL) { break; /* exit do while cont is 1 loop */ } else { continue; /* next poll */ } } if (error != CS_OK) { goto error_put; } /* * Make copy of callbacks, message data, unlock instance, and call callback * A risk of this dispatch method is that the callback routines may * operate at the same time that cpgFinalize has been called. */ memcpy (&cpg_inst_copy, cpg_inst, sizeof (struct cpg_inst)); switch (cpg_inst_copy.model_data.model) { case CPG_MODEL_V1: /* * Dispatch incoming message */ switch (dispatch_data->id) { case MESSAGE_RES_CPG_DELIVER_CALLBACK: if (cpg_inst_copy.model_v1_data.cpg_deliver_fn == NULL) { break; } res_cpg_deliver_callback = (struct res_lib_cpg_deliver_callback *)dispatch_data; marshall_from_mar_cpg_name_t ( &group_name, &res_cpg_deliver_callback->group_name); cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle, &group_name, res_cpg_deliver_callback->nodeid, res_cpg_deliver_callback->pid, &res_cpg_deliver_callback->message, res_cpg_deliver_callback->msglen); break; case MESSAGE_RES_CPG_CONFCHG_CALLBACK: if (cpg_inst_copy.model_v1_data.cpg_confchg_fn == NULL) { break; } res_cpg_confchg_callback = (struct res_lib_cpg_confchg_callback *)dispatch_data; for (i = 0; i < res_cpg_confchg_callback->member_list_entries; i++) { marshall_from_mar_cpg_address_t (&member_list[i], &res_cpg_confchg_callback->member_list[i]); } left_list_start = res_cpg_confchg_callback->member_list + res_cpg_confchg_callback->member_list_entries; for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) { marshall_from_mar_cpg_address_t (&left_list[i], &left_list_start[i]); } joined_list_start = res_cpg_confchg_callback->member_list + res_cpg_confchg_callback->member_list_entries + res_cpg_confchg_callback->left_list_entries; for (i = 0; i < res_cpg_confchg_callback->joined_list_entries; i++) { marshall_from_mar_cpg_address_t (&joined_list[i], &joined_list_start[i]); } marshall_from_mar_cpg_name_t ( &group_name, &res_cpg_confchg_callback->group_name); cpg_inst_copy.model_v1_data.cpg_confchg_fn (handle, &group_name, member_list, res_cpg_confchg_callback->member_list_entries, left_list, res_cpg_confchg_callback->left_list_entries, joined_list, res_cpg_confchg_callback->joined_list_entries); break; case MESSAGE_RES_CPG_TOTEM_CONFCHG_CALLBACK: if (cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn == NULL) { break; } res_cpg_totem_confchg_callback = (struct res_lib_cpg_totem_confchg_callback *)dispatch_data; marshall_from_mar_cpg_ring_id_t (&ring_id, &res_cpg_totem_confchg_callback->ring_id); for (i = 0; i < res_cpg_totem_confchg_callback->member_list_entries; i++) { totem_member_list[i] = res_cpg_totem_confchg_callback->member_list[i]; } cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn (handle, ring_id, res_cpg_totem_confchg_callback->member_list_entries, totem_member_list); break; default: error = CS_ERR_LIBRARY; goto error_put; break; } /* - switch (dispatch_data->id) */ break; /* case CPG_MODEL_V1 */ } /* - switch (cpg_inst_copy.model_data.model) */ + if (cpg_inst_copy.finalize || cpg_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + cpg_inst->finalize = 1; + error = CS_ERR_BAD_HANDLE; + goto error_put; + } + /* * Determine if more messages should be processed */ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { cont = 0; } } while (cont); error_put: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_join ( cpg_handle_t handle, const struct cpg_name *group) { cs_error_t error; struct cpg_inst *cpg_inst; struct iovec iov[2]; struct req_lib_cpg_join req_lib_cpg_join; struct res_lib_cpg_join response; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } /* Now join */ req_lib_cpg_join.header.size = sizeof (struct req_lib_cpg_join); req_lib_cpg_join.header.id = MESSAGE_REQ_CPG_JOIN; req_lib_cpg_join.pid = getpid(); req_lib_cpg_join.flags = 0; switch (cpg_inst->model_data.model) { case CPG_MODEL_V1: req_lib_cpg_join.flags = cpg_inst->model_v1_data.flags; break; } marshall_to_mar_cpg_name_t (&req_lib_cpg_join.group_name, group); iov[0].iov_base = (void *)&req_lib_cpg_join; iov[0].iov_len = sizeof (struct req_lib_cpg_join); do { error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1, &response, sizeof (struct res_lib_cpg_join)); if (error != CS_OK) { goto error_exit; } } while (response.header.error == CS_ERR_BUSY); error = response.header.error; error_exit: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_leave ( cpg_handle_t handle, const struct cpg_name *group) { cs_error_t error; struct cpg_inst *cpg_inst; struct iovec iov[2]; struct req_lib_cpg_leave req_lib_cpg_leave; struct res_lib_cpg_leave res_lib_cpg_leave; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } req_lib_cpg_leave.header.size = sizeof (struct req_lib_cpg_leave); req_lib_cpg_leave.header.id = MESSAGE_REQ_CPG_LEAVE; req_lib_cpg_leave.pid = getpid(); marshall_to_mar_cpg_name_t (&req_lib_cpg_leave.group_name, group); iov[0].iov_base = (void *)&req_lib_cpg_leave; iov[0].iov_len = sizeof (struct req_lib_cpg_leave); do { error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1, &res_lib_cpg_leave, sizeof (struct res_lib_cpg_leave)); if (error != CS_OK) { goto error_exit; } } while (res_lib_cpg_leave.header.error == CS_ERR_BUSY); error = res_lib_cpg_leave.header.error; error_exit: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_membership_get ( cpg_handle_t handle, struct cpg_name *group_name, struct cpg_address *member_list, int *member_list_entries) { cs_error_t error; struct cpg_inst *cpg_inst; struct iovec iov; struct req_lib_cpg_membership_get req_lib_cpg_membership_get; struct res_lib_cpg_membership_get res_lib_cpg_membership_get; unsigned int i; if (member_list == NULL) { return (CS_ERR_INVALID_PARAM); } if (member_list_entries == NULL) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } req_lib_cpg_membership_get.header.size = sizeof (struct req_lib_cpg_membership_get); req_lib_cpg_membership_get.header.id = MESSAGE_REQ_CPG_MEMBERSHIP; marshall_to_mar_cpg_name_t (&req_lib_cpg_membership_get.group_name, group_name); iov.iov_base = (void *)&req_lib_cpg_membership_get; iov.iov_len = sizeof (struct req_lib_cpg_membership_get); error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1, &res_lib_cpg_membership_get, sizeof (res_lib_cpg_membership_get)); if (error != CS_OK) { goto error_exit; } error = res_lib_cpg_membership_get.header.error; /* * Copy results to caller */ *member_list_entries = res_lib_cpg_membership_get.member_count; if (member_list) { for (i = 0; i < res_lib_cpg_membership_get.member_count; i++) { marshall_from_mar_cpg_address_t (&member_list[i], &res_lib_cpg_membership_get.member_list[i]); } } error_exit: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_local_get ( cpg_handle_t handle, unsigned int *local_nodeid) { cs_error_t error; struct cpg_inst *cpg_inst; struct iovec iov; struct req_lib_cpg_local_get req_lib_cpg_local_get; struct res_lib_cpg_local_get res_lib_cpg_local_get; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } req_lib_cpg_local_get.header.size = sizeof (struct qb_ipc_request_header); req_lib_cpg_local_get.header.id = MESSAGE_REQ_CPG_LOCAL_GET; iov.iov_base = (void *)&req_lib_cpg_local_get; iov.iov_len = sizeof (struct req_lib_cpg_local_get); error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1, &res_lib_cpg_local_get, sizeof (res_lib_cpg_local_get)); if (error != CS_OK) { goto error_exit; } error = res_lib_cpg_local_get.header.error; *local_nodeid = res_lib_cpg_local_get.local_nodeid; error_exit: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_flow_control_state_get ( cpg_handle_t handle, cpg_flow_control_state_t *flow_control_state) { cs_error_t error; struct cpg_inst *cpg_inst; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } *flow_control_state = CPG_FLOW_CONTROL_DISABLED; error = CS_OK; hdb_handle_put (&cpg_handle_t_db, handle); return (error); } static int memory_map (char *path, const char *file, void **buf, size_t bytes) { int32_t fd; void *addr_orig; void *addr; int32_t res; char *buffer; int32_t i; size_t written; size_t page_size; snprintf (path, PATH_MAX, "/dev/shm/%s", file); fd = mkstemp (path); if (fd == -1) { snprintf (path, PATH_MAX, LOCALSTATEDIR "/run/%s", file); fd = mkstemp (path); if (fd == -1) { return (-1); } } res = ftruncate (fd, bytes); if (res == -1) { goto error_close_unlink; } page_size = (size_t)sysconf(_SC_PAGESIZE); buffer = malloc (page_size); if (buffer == NULL) { goto error_close_unlink; } memset (buffer, 0, page_size); for (i = 0; i < (bytes / page_size); i++) { retry_write: written = write (fd, buffer, page_size); if (written == -1 && errno == EINTR) { goto retry_write; } if (written != page_size) { free (buffer); goto error_close_unlink; } } free (buffer); addr_orig = mmap (NULL, bytes, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (addr_orig == MAP_FAILED) { goto error_close_unlink; } addr = mmap (addr_orig, bytes, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); if (addr != addr_orig) { goto error_close_unlink; } #ifdef COROSYNC_BSD madvise(addr_orig, bytes, MADV_NOSYNC); #endif res = close (fd); if (res) { return (-1); } *buf = addr_orig; return 0; error_close_unlink: close (fd); unlink(path); return -1; } cs_error_t cpg_zcb_alloc ( cpg_handle_t handle, size_t size, void **buffer) { void *buf = NULL; char path[PATH_MAX]; mar_req_coroipcc_zc_alloc_t req_coroipcc_zc_alloc; struct qb_ipc_response_header res_coroipcs_zc_alloc; size_t map_size; struct iovec iovec; struct coroipcs_zc_header *hdr; cs_error_t error; struct cpg_inst *cpg_inst; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } map_size = size + sizeof (struct req_lib_cpg_mcast) + sizeof (struct coroipcs_zc_header); assert(memory_map (path, "corosync_zerocopy-XXXXXX", &buf, map_size) != -1); req_coroipcc_zc_alloc.header.size = sizeof (mar_req_coroipcc_zc_alloc_t); req_coroipcc_zc_alloc.header.id = MESSAGE_REQ_CPG_ZC_ALLOC; req_coroipcc_zc_alloc.map_size = map_size; strcpy (req_coroipcc_zc_alloc.path_to_file, path); iovec.iov_base = (void *)&req_coroipcc_zc_alloc; iovec.iov_len = sizeof (mar_req_coroipcc_zc_alloc_t); error = coroipcc_msg_send_reply_receive ( cpg_inst->c, &iovec, 1, &res_coroipcs_zc_alloc, sizeof (struct qb_ipc_response_header)); hdr = (struct coroipcs_zc_header *)buf; hdr->map_size = map_size; *buffer = ((char *)buf) + sizeof (struct coroipcs_zc_header); hdb_handle_put (&cpg_handle_t_db, handle); *buffer = ((char *)*buffer) + sizeof (struct req_lib_cpg_mcast); return (error); } cs_error_t cpg_zcb_free ( cpg_handle_t handle, void *buffer) { cs_error_t error; struct cpg_inst *cpg_inst; mar_req_coroipcc_zc_free_t req_coroipcc_zc_free; struct qb_ipc_response_header res_coroipcs_zc_free; struct iovec iovec; struct coroipcs_zc_header *header = (struct coroipcs_zc_header *)((char *)buffer - sizeof (struct coroipcs_zc_header)); error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } req_coroipcc_zc_free.header.size = sizeof (mar_req_coroipcc_zc_free_t); req_coroipcc_zc_free.header.id = MESSAGE_REQ_CPG_ZC_FREE; req_coroipcc_zc_free.map_size = header->map_size; req_coroipcc_zc_free.server_address = header->server_address; iovec.iov_base = (void *)&req_coroipcc_zc_free; iovec.iov_len = sizeof (mar_req_coroipcc_zc_free_t); error = coroipcc_msg_send_reply_receive ( cpg_inst->c, &iovec, 1, &res_coroipcs_zc_free, sizeof (struct qb_ipc_response_header)); munmap ((void *)header, header->map_size); hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_zcb_mcast_joined ( cpg_handle_t handle, cpg_guarantee_t guarantee, void *msg, size_t msg_len) { cs_error_t error; struct cpg_inst *cpg_inst; struct req_lib_cpg_mcast *req_lib_cpg_mcast; struct res_lib_cpg_mcast res_lib_cpg_mcast; mar_req_coroipcc_zc_execute_t req_coroipcc_zc_execute; struct coroipcs_zc_header *hdr; struct iovec iovec; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } req_lib_cpg_mcast = (struct req_lib_cpg_mcast *)(((char *)msg) - sizeof (struct req_lib_cpg_mcast)); req_lib_cpg_mcast->header.size = sizeof (struct req_lib_cpg_mcast) + msg_len; req_lib_cpg_mcast->header.id = MESSAGE_REQ_CPG_MCAST; req_lib_cpg_mcast->guarantee = guarantee; req_lib_cpg_mcast->msglen = msg_len; hdr = (struct coroipcs_zc_header *)(((char *)req_lib_cpg_mcast) - sizeof (struct coroipcs_zc_header)); req_coroipcc_zc_execute.header.size = sizeof (mar_req_coroipcc_zc_execute_t); req_coroipcc_zc_execute.header.id = MESSAGE_REQ_CPG_ZC_EXECUTE; req_coroipcc_zc_execute.server_address = hdr->server_address; iovec.iov_base = (void *)&req_coroipcc_zc_execute; iovec.iov_len = sizeof (mar_req_coroipcc_zc_execute_t); error = coroipcc_msg_send_reply_receive ( cpg_inst->c, &iovec, 1, &res_lib_cpg_mcast, sizeof(res_lib_cpg_mcast)); if (error != CS_OK) { goto error_exit; } error = res_lib_cpg_mcast.header.error; error_exit: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_mcast_joined ( cpg_handle_t handle, cpg_guarantee_t guarantee, const struct iovec *iovec, unsigned int iov_len) { int i; cs_error_t error; struct cpg_inst *cpg_inst; struct iovec iov[64]; struct req_lib_cpg_mcast req_lib_cpg_mcast; size_t msg_len = 0; error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } for (i = 0; i < iov_len; i++ ) { msg_len += iovec[i].iov_len; } req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_mcast) + msg_len; req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_MCAST; req_lib_cpg_mcast.guarantee = guarantee; req_lib_cpg_mcast.msglen = msg_len; iov[0].iov_base = (void *)&req_lib_cpg_mcast; iov[0].iov_len = sizeof (struct req_lib_cpg_mcast); memcpy (&iov[1], iovec, iov_len * sizeof (struct iovec)); qb_ipcc_fc_enable_max_set(cpg_inst->c, 2); error = qb_to_cs_error(qb_ipcc_sendv(cpg_inst->c, iov, iov_len + 1)); qb_ipcc_fc_enable_max_set(cpg_inst->c, 1); hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_iteration_initialize( cpg_handle_t handle, cpg_iteration_type_t iteration_type, const struct cpg_name *group, cpg_iteration_handle_t *cpg_iteration_handle) { cs_error_t error; struct iovec iov; struct cpg_inst *cpg_inst; struct cpg_iteration_instance_t *cpg_iteration_instance; struct req_lib_cpg_iterationinitialize req_lib_cpg_iterationinitialize; struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize; if (cpg_iteration_handle == NULL) { return (CS_ERR_INVALID_PARAM); } if ((iteration_type == CPG_ITERATION_ONE_GROUP && group == NULL) || (iteration_type != CPG_ITERATION_ONE_GROUP && group != NULL)) { return (CS_ERR_INVALID_PARAM); } if (iteration_type != CPG_ITERATION_NAME_ONLY && iteration_type != CPG_ITERATION_ONE_GROUP && iteration_type != CPG_ITERATION_ALL) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); if (error != CS_OK) { return (error); } error = hdb_error_to_cs (hdb_handle_create (&cpg_iteration_handle_t_db, sizeof (struct cpg_iteration_instance_t), cpg_iteration_handle)); if (error != CS_OK) { goto error_put_cpg_db; } error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, *cpg_iteration_handle, (void *)&cpg_iteration_instance)); if (error != CS_OK) { goto error_destroy; } cpg_iteration_instance->conn = cpg_inst->c; list_init (&cpg_iteration_instance->list); req_lib_cpg_iterationinitialize.header.size = sizeof (struct req_lib_cpg_iterationinitialize); req_lib_cpg_iterationinitialize.header.id = MESSAGE_REQ_CPG_ITERATIONINITIALIZE; req_lib_cpg_iterationinitialize.iteration_type = iteration_type; if (group) { marshall_to_mar_cpg_name_t (&req_lib_cpg_iterationinitialize.group_name, group); } iov.iov_base = (void *)&req_lib_cpg_iterationinitialize; iov.iov_len = sizeof (struct req_lib_cpg_iterationinitialize); error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1, &res_lib_cpg_iterationinitialize, sizeof (struct res_lib_cpg_iterationinitialize)); if (error != CS_OK) { goto error_put_destroy; } cpg_iteration_instance->executive_iteration_handle = res_lib_cpg_iterationinitialize.iteration_handle; cpg_iteration_instance->cpg_iteration_handle = *cpg_iteration_handle; list_add (&cpg_iteration_instance->list, &cpg_inst->iteration_list_head); hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle); hdb_handle_put (&cpg_handle_t_db, handle); return (res_lib_cpg_iterationinitialize.header.error); error_put_destroy: hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle); error_destroy: hdb_handle_destroy (&cpg_iteration_handle_t_db, *cpg_iteration_handle); error_put_cpg_db: hdb_handle_put (&cpg_handle_t_db, handle); return (error); } cs_error_t cpg_iteration_next( cpg_iteration_handle_t handle, struct cpg_iteration_description_t *description) { cs_error_t error; struct cpg_iteration_instance_t *cpg_iteration_instance; struct req_lib_cpg_iterationnext req_lib_cpg_iterationnext; struct res_lib_cpg_iterationnext res_lib_cpg_iterationnext; if (description == NULL) { return CS_ERR_INVALID_PARAM; } error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle, (void *)&cpg_iteration_instance)); if (error != CS_OK) { goto error_exit; } req_lib_cpg_iterationnext.header.size = sizeof (struct req_lib_cpg_iterationnext); req_lib_cpg_iterationnext.header.id = MESSAGE_REQ_CPG_ITERATIONNEXT; req_lib_cpg_iterationnext.iteration_handle = cpg_iteration_instance->executive_iteration_handle; error = qb_to_cs_error (qb_ipcc_send (cpg_iteration_instance->conn, &req_lib_cpg_iterationnext, req_lib_cpg_iterationnext.header.size)); if (error != CS_OK) { goto error_put; } error = qb_to_cs_error (qb_ipcc_recv (cpg_iteration_instance->conn, &res_lib_cpg_iterationnext, sizeof(struct res_lib_cpg_iterationnext), -1)); if (error != CS_OK) { goto error_put; } marshall_from_mar_cpg_iteration_description_t( description, &res_lib_cpg_iterationnext.description); error = res_lib_cpg_iterationnext.header.error; error_put: hdb_handle_put (&cpg_iteration_handle_t_db, handle); error_exit: return (error); } cs_error_t cpg_iteration_finalize ( cpg_iteration_handle_t handle) { cs_error_t error; struct iovec iov; struct cpg_iteration_instance_t *cpg_iteration_instance; struct req_lib_cpg_iterationfinalize req_lib_cpg_iterationfinalize; struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize; error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle, (void *)&cpg_iteration_instance)); if (error != CS_OK) { goto error_exit; } req_lib_cpg_iterationfinalize.header.size = sizeof (struct req_lib_cpg_iterationfinalize); req_lib_cpg_iterationfinalize.header.id = MESSAGE_REQ_CPG_ITERATIONFINALIZE; req_lib_cpg_iterationfinalize.iteration_handle = cpg_iteration_instance->executive_iteration_handle; iov.iov_base = (void *)&req_lib_cpg_iterationfinalize; iov.iov_len = sizeof (struct req_lib_cpg_iterationfinalize); error = coroipcc_msg_send_reply_receive (cpg_iteration_instance->conn, &iov, 1, &res_lib_cpg_iterationfinalize, sizeof (struct req_lib_cpg_iterationfinalize)); if (error != CS_OK) { goto error_put; } cpg_iteration_instance_finalize (cpg_iteration_instance); hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle); return (res_lib_cpg_iterationfinalize.header.error); error_put: hdb_handle_put (&cpg_iteration_handle_t_db, handle); error_exit: return (error); } /** @} */ diff --git a/lib/quorum.c b/lib/quorum.c index 1ee2f066..eb53b7fe 100644 --- a/lib/quorum.c +++ b/lib/quorum.c @@ -1,450 +1,462 @@ /* * Copyright (c) 2008-2012 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Provides a quorum API using the corosync executive */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" struct quorum_inst { qb_ipcc_connection_t *c; int finalize; const void *context; quorum_callbacks_t callbacks; }; -DECLARE_HDB_DATABASE(quorum_handle_t_db,NULL); +static void quorum_inst_free (void *inst); + +DECLARE_HDB_DATABASE(quorum_handle_t_db, quorum_inst_free); cs_error_t quorum_initialize ( quorum_handle_t *handle, quorum_callbacks_t *callbacks, uint32_t *quorum_type) { cs_error_t error; struct quorum_inst *quorum_inst; struct iovec iov; struct qb_ipc_request_header req; struct res_lib_quorum_gettype res_lib_quorum_gettype; error = hdb_error_to_cs(hdb_handle_create (&quorum_handle_t_db, sizeof (struct quorum_inst), handle)); if (error != CS_OK) { goto error_no_destroy; } error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, *handle, (void *)&quorum_inst)); if (error != CS_OK) { goto error_destroy; } error = CS_OK; + quorum_inst->finalize = 0; quorum_inst->c = qb_ipcc_connect ("quorum", IPC_REQUEST_SIZE); if (quorum_inst->c == NULL) { error = qb_to_cs_error(-errno); goto error_put_destroy; } req.size = sizeof (req); req.id = MESSAGE_REQ_QUORUM_GETTYPE; iov.iov_base = (char *)&req; iov.iov_len = sizeof (req); error = qb_to_cs_error(qb_ipcc_sendv_recv ( quorum_inst->c, &iov, 1, &res_lib_quorum_gettype, sizeof (struct res_lib_quorum_gettype), -1)); if (error != CS_OK) { goto error_put_destroy; } error = res_lib_quorum_gettype.header.error; *quorum_type = res_lib_quorum_gettype.quorum_type; if (callbacks) memcpy(&quorum_inst->callbacks, callbacks, sizeof (*callbacks)); else memset(&quorum_inst->callbacks, 0, sizeof (*callbacks)); (void)hdb_handle_put (&quorum_handle_t_db, *handle); return (CS_OK); error_put_destroy: (void)hdb_handle_put (&quorum_handle_t_db, *handle); error_destroy: (void)hdb_handle_destroy (&quorum_handle_t_db, *handle); error_no_destroy: return (error); } +static void quorum_inst_free (void *inst) +{ + struct quorum_inst *quorum_inst = (struct quorum_inst *)inst; + qb_ipcc_disconnect(quorum_inst->c); +} + cs_error_t quorum_finalize ( quorum_handle_t handle) { struct quorum_inst *quorum_inst; cs_error_t error; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } /* * Another thread has already started finalizing */ if (quorum_inst->finalize) { (void)hdb_handle_put (&quorum_handle_t_db, handle); return (CS_ERR_BAD_HANDLE); } quorum_inst->finalize = 1; - qb_ipcc_disconnect (quorum_inst->c); - (void)hdb_handle_destroy (&quorum_handle_t_db, handle); (void)hdb_handle_put (&quorum_handle_t_db, handle); return (CS_OK); } cs_error_t quorum_getquorate ( quorum_handle_t handle, int *quorate) { cs_error_t error; struct quorum_inst *quorum_inst; struct iovec iov; struct qb_ipc_request_header req; struct res_lib_quorum_getquorate res_lib_quorum_getquorate; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } req.size = sizeof (req); req.id = MESSAGE_REQ_QUORUM_GETQUORATE; iov.iov_base = (char *)&req; iov.iov_len = sizeof (req); error = qb_to_cs_error(qb_ipcc_sendv_recv ( quorum_inst->c, &iov, 1, &res_lib_quorum_getquorate, sizeof (struct res_lib_quorum_getquorate), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_quorum_getquorate.header.error; *quorate = res_lib_quorum_getquorate.quorate; error_exit: (void)hdb_handle_put (&quorum_handle_t_db, handle); return (error); } cs_error_t quorum_fd_get ( quorum_handle_t handle, int *fd) { cs_error_t error; struct quorum_inst *quorum_inst; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } error = qb_to_cs_error(qb_ipcc_fd_get (quorum_inst->c, fd)); (void)hdb_handle_put (&quorum_handle_t_db, handle); return (error); } cs_error_t quorum_context_get ( quorum_handle_t handle, const void **context) { cs_error_t error; struct quorum_inst *quorum_inst; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } *context = quorum_inst->context; (void)hdb_handle_put (&quorum_handle_t_db, handle); return (CS_OK); } cs_error_t quorum_context_set ( quorum_handle_t handle, const void *context) { cs_error_t error; struct quorum_inst *quorum_inst; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } quorum_inst->context = context; (void)hdb_handle_put (&quorum_handle_t_db, handle); return (CS_OK); } cs_error_t quorum_trackstart ( quorum_handle_t handle, unsigned int flags ) { cs_error_t error; struct quorum_inst *quorum_inst; struct iovec iov; struct req_lib_quorum_trackstart req_lib_quorum_trackstart; struct qb_ipc_response_header res; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } req_lib_quorum_trackstart.header.size = sizeof (struct req_lib_quorum_trackstart); req_lib_quorum_trackstart.header.id = MESSAGE_REQ_QUORUM_TRACKSTART; req_lib_quorum_trackstart.track_flags = flags; iov.iov_base = (char *)&req_lib_quorum_trackstart; iov.iov_len = sizeof (struct req_lib_quorum_trackstart); error = qb_to_cs_error(qb_ipcc_sendv_recv ( quorum_inst->c, &iov, 1, &res, sizeof (res), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)hdb_handle_put (&quorum_handle_t_db, handle); return (error); } cs_error_t quorum_trackstop ( quorum_handle_t handle) { cs_error_t error; struct quorum_inst *quorum_inst; struct iovec iov; struct qb_ipc_request_header req; struct qb_ipc_response_header res; error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } req.size = sizeof (req); req.id = MESSAGE_REQ_QUORUM_TRACKSTOP; iov.iov_base = (char *)&req; iov.iov_len = sizeof (req); error = qb_to_cs_error(qb_ipcc_sendv_recv ( quorum_inst->c, &iov, 1, &res, sizeof (res), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)hdb_handle_put (&quorum_handle_t_db, handle); return (error); } cs_error_t quorum_dispatch ( quorum_handle_t handle, cs_dispatch_flags_t dispatch_types) { int timeout = -1; cs_error_t error; int cont = 1; /* always continue do loop except when set to 0 */ struct quorum_inst *quorum_inst; quorum_callbacks_t callbacks; struct qb_ipc_response_header *dispatch_data; char dispatch_buf[IPC_DISPATCH_SIZE]; struct res_lib_quorum_notification *res_lib_quorum_notification; if (dispatch_types != CS_DISPATCH_ONE && dispatch_types != CS_DISPATCH_ALL && dispatch_types != CS_DISPATCH_BLOCKING && dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) { return (CS_ERR_INVALID_PARAM); } error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); if (error != CS_OK) { return (error); } /* * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING */ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { timeout = 0; } dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; do { error = qb_to_cs_error (qb_ipcc_event_recv ( quorum_inst->c, dispatch_buf, IPC_DISPATCH_SIZE, timeout)); if (error == CS_ERR_BAD_HANDLE) { error = CS_OK; goto error_put; } if (error == CS_ERR_TRY_AGAIN) { if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { /* * Don't mask error */ goto error_put; } error = CS_OK; if (dispatch_types == CS_DISPATCH_ALL) { break; /* exit do while cont is 1 loop */ } else { continue; /* next poll */ } } if (error != CS_OK) { goto error_put; } /* * Make copy of callbacks, message data, unlock instance, and call callback * A risk of this dispatch method is that the callback routines may * operate at the same time that quorum_finalize has been called in another thread. */ memcpy (&callbacks, &quorum_inst->callbacks, sizeof (quorum_callbacks_t)); /* * Dispatch incoming message */ switch (dispatch_data->id) { case MESSAGE_RES_QUORUM_NOTIFICATION: if (callbacks.quorum_notify_fn == NULL) { break; } res_lib_quorum_notification = (struct res_lib_quorum_notification *)dispatch_data; callbacks.quorum_notify_fn ( handle, res_lib_quorum_notification->quorate, res_lib_quorum_notification->ring_seq, res_lib_quorum_notification->view_list_entries, res_lib_quorum_notification->view_list); break; default: error = CS_ERR_LIBRARY; goto error_put; break; } + if (quorum_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } /* * Determine if more messages should be processed */ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { cont = 0; } } while (cont); - goto error_put; - error_put: (void)hdb_handle_put (&quorum_handle_t_db, handle); return (error); } diff --git a/lib/votequorum.c b/lib/votequorum.c index 6240f99e..e2b578ff 100644 --- a/lib/votequorum.c +++ b/lib/votequorum.c @@ -1,726 +1,739 @@ /* * Copyright (c) 2009-2012 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Provides a quorum API using the corosync executive */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" struct votequorum_inst { qb_ipcc_connection_t *c; int finalize; void *context; votequorum_callbacks_t callbacks; }; -DECLARE_HDB_DATABASE(votequorum_handle_t_db,NULL); +static void votequorum_inst_free (void *inst); + +DECLARE_HDB_DATABASE(votequorum_handle_t_db, votequorum_inst_free); cs_error_t votequorum_initialize ( votequorum_handle_t *handle, votequorum_callbacks_t *callbacks) { cs_error_t error; struct votequorum_inst *votequorum_inst; error = hdb_error_to_cs(hdb_handle_create (&votequorum_handle_t_db, sizeof (struct votequorum_inst), handle)); if (error != CS_OK) { goto error_no_destroy; } error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, *handle, (void *)&votequorum_inst)); if (error != CS_OK) { goto error_destroy; } + votequorum_inst->finalize = 0; votequorum_inst->c = qb_ipcc_connect ("votequorum", IPC_REQUEST_SIZE); if (votequorum_inst->c == NULL) { error = qb_to_cs_error(-errno); goto error_put_destroy; } if (callbacks) memcpy(&votequorum_inst->callbacks, callbacks, sizeof (*callbacks)); else memset(&votequorum_inst->callbacks, 0, sizeof (*callbacks)); hdb_handle_put (&votequorum_handle_t_db, *handle); return (CS_OK); error_put_destroy: hdb_handle_put (&votequorum_handle_t_db, *handle); error_destroy: hdb_handle_destroy (&votequorum_handle_t_db, *handle); error_no_destroy: return (error); } +static void votequorum_inst_free (void *inst) +{ + struct votequorum_inst *vq_inst = (struct votequorum_inst *)inst; + qb_ipcc_disconnect(vq_inst->c); +} + cs_error_t votequorum_finalize ( votequorum_handle_t handle) { struct votequorum_inst *votequorum_inst; cs_error_t error; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } /* * Another thread has already started finalizing */ if (votequorum_inst->finalize) { hdb_handle_put (&votequorum_handle_t_db, handle); return (CS_ERR_BAD_HANDLE); } votequorum_inst->finalize = 1; - qb_ipcc_disconnect (votequorum_inst->c); - hdb_handle_destroy (&votequorum_handle_t_db, handle); hdb_handle_put (&votequorum_handle_t_db, handle); return (CS_OK); } cs_error_t votequorum_getinfo ( votequorum_handle_t handle, unsigned int nodeid, struct votequorum_info *info) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; struct req_lib_votequorum_getinfo req_lib_votequorum_getinfo; struct res_lib_votequorum_getinfo res_lib_votequorum_getinfo; 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_getinfo.header.size = sizeof (struct req_lib_votequorum_getinfo); req_lib_votequorum_getinfo.header.id = MESSAGE_REQ_VOTEQUORUM_GETINFO; req_lib_votequorum_getinfo.nodeid = nodeid; iov.iov_base = (char *)&req_lib_votequorum_getinfo; iov.iov_len = sizeof (struct req_lib_votequorum_getinfo); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_getinfo, sizeof (struct res_lib_votequorum_getinfo), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_getinfo.header.error; info->node_id = res_lib_votequorum_getinfo.nodeid; info->node_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; info->total_votes = res_lib_votequorum_getinfo.total_votes; info->quorum = res_lib_votequorum_getinfo.quorum; info->flags = res_lib_votequorum_getinfo.flags; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_setexpected ( votequorum_handle_t handle, unsigned int expected_votes) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; struct req_lib_votequorum_setexpected req_lib_votequorum_setexpected; struct res_lib_votequorum_status res_lib_votequorum_status; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } req_lib_votequorum_setexpected.header.size = sizeof (struct req_lib_votequorum_setexpected); req_lib_votequorum_setexpected.header.id = MESSAGE_REQ_VOTEQUORUM_SETEXPECTED; req_lib_votequorum_setexpected.expected_votes = expected_votes; iov.iov_base = (char *)&req_lib_votequorum_setexpected; iov.iov_len = sizeof (struct req_lib_votequorum_setexpected); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_setvotes ( votequorum_handle_t handle, unsigned int nodeid, unsigned int votes) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; struct req_lib_votequorum_setvotes req_lib_votequorum_setvotes; struct res_lib_votequorum_status res_lib_votequorum_status; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } req_lib_votequorum_setvotes.header.size = sizeof (struct req_lib_votequorum_setvotes); req_lib_votequorum_setvotes.header.id = MESSAGE_REQ_VOTEQUORUM_SETVOTES; req_lib_votequorum_setvotes.nodeid = nodeid; req_lib_votequorum_setvotes.votes = votes; iov.iov_base = (char *)&req_lib_votequorum_setvotes; iov.iov_len = sizeof (struct req_lib_votequorum_setvotes); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_trackstart ( votequorum_handle_t handle, uint64_t context, unsigned int flags) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; struct req_lib_votequorum_trackstart req_lib_votequorum_trackstart; struct res_lib_votequorum_status res_lib_votequorum_status; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } req_lib_votequorum_trackstart.header.size = sizeof (struct req_lib_votequorum_trackstart); req_lib_votequorum_trackstart.header.id = MESSAGE_REQ_VOTEQUORUM_TRACKSTART; req_lib_votequorum_trackstart.track_flags = flags; req_lib_votequorum_trackstart.context = context; iov.iov_base = (char *)&req_lib_votequorum_trackstart; iov.iov_len = sizeof (struct req_lib_votequorum_trackstart); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_trackstop ( votequorum_handle_t handle) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; struct req_lib_votequorum_general req_lib_votequorum_general; struct res_lib_votequorum_status res_lib_votequorum_status; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } req_lib_votequorum_general.header.size = sizeof (struct req_lib_votequorum_general); req_lib_votequorum_general.header.id = MESSAGE_REQ_VOTEQUORUM_TRACKSTOP; iov.iov_base = (char *)&req_lib_votequorum_general; iov.iov_len = sizeof (struct req_lib_votequorum_general); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_context_get ( votequorum_handle_t handle, void **context) { cs_error_t error; struct votequorum_inst *votequorum_inst; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } *context = votequorum_inst->context; hdb_handle_put (&votequorum_handle_t_db, handle); return (CS_OK); } cs_error_t votequorum_context_set ( votequorum_handle_t handle, void *context) { cs_error_t error; struct votequorum_inst *votequorum_inst; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } votequorum_inst->context = context; hdb_handle_put (&votequorum_handle_t_db, handle); return (CS_OK); } cs_error_t votequorum_fd_get ( votequorum_handle_t handle, int *fd) { cs_error_t error; struct votequorum_inst *votequorum_inst; error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); if (error != CS_OK) { return (error); } error = qb_to_cs_error(qb_ipcc_fd_get (votequorum_inst->c, fd)); (void)hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_dispatch ( votequorum_handle_t handle, cs_dispatch_flags_t dispatch_types) { int timeout = -1; cs_error_t error; int cont = 1; /* always continue do loop except when set to 0 */ struct votequorum_inst *votequorum_inst; votequorum_callbacks_t callbacks; struct qb_ipc_response_header *dispatch_data; struct res_lib_votequorum_notification *res_lib_votequorum_notification; struct res_lib_votequorum_expectedvotes_notification *res_lib_votequorum_expectedvotes_notification; char dispatch_buf[IPC_DISPATCH_SIZE]; if (dispatch_types != CS_DISPATCH_ONE && dispatch_types != CS_DISPATCH_ALL && dispatch_types != CS_DISPATCH_BLOCKING && dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) { 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); } /* * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING */ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { timeout = 0; } dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; do { error = qb_to_cs_error (qb_ipcc_event_recv ( votequorum_inst->c, dispatch_buf, IPC_DISPATCH_SIZE, timeout)); if (error == CS_ERR_BAD_HANDLE) { error = CS_OK; goto error_put; } if (error == CS_ERR_TRY_AGAIN) { if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { /* * Don't mask error */ goto error_put; } error = CS_OK; if (dispatch_types == CS_DISPATCH_ALL) { break; /* exit do while cont is 1 loop */ } else { continue; /* next poll */ } } if (error != CS_OK) { goto error_put; } /* * Make copy of callbacks, message data, unlock instance, and call callback * A risk of this dispatch method is that the callback routines may * operate at the same time that votequorum_finalize has been called in another thread. */ memcpy (&callbacks, &votequorum_inst->callbacks, sizeof (votequorum_callbacks_t)); /* * Dispatch incoming message */ switch (dispatch_data->id) { case MESSAGE_RES_VOTEQUORUM_NOTIFICATION: if (callbacks.votequorum_notify_fn == NULL) { break; } res_lib_votequorum_notification = (struct res_lib_votequorum_notification *)dispatch_data; callbacks.votequorum_notify_fn ( handle, res_lib_votequorum_notification->context, res_lib_votequorum_notification->quorate, res_lib_votequorum_notification->node_list_entries, (votequorum_node_t *)res_lib_votequorum_notification->node_list ); ; break; case MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION: if (callbacks.votequorum_expectedvotes_notify_fn == NULL) { break; } res_lib_votequorum_expectedvotes_notification = (struct res_lib_votequorum_expectedvotes_notification *)dispatch_data; callbacks.votequorum_expectedvotes_notify_fn ( handle, res_lib_votequorum_expectedvotes_notification->context, res_lib_votequorum_expectedvotes_notification->expected_votes); break; default: error = CS_ERR_LIBRARY; goto error_put; break; } + if (votequorum_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } /* * Determine if more messages should be processed */ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { cont = 0; } } while (cont); - goto error_put; error_put: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } #ifdef EXPERIMENTAL_QUORUM_DEVICE_API cs_error_t votequorum_qdevice_register ( votequorum_handle_t handle, const char *name) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; 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) { 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_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); iov.iov_base = (char *)&req_lib_votequorum_qdevice_register; iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_register); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_qdevice_poll ( votequorum_handle_t handle, const char *name, unsigned int state) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; 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; iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_poll); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } cs_error_t votequorum_qdevice_unregister ( votequorum_handle_t handle, const char *name) { cs_error_t error; struct votequorum_inst *votequorum_inst; struct iovec iov; 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_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_qdevice_unregister; iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_unregister); error = qb_to_cs_error(qb_ipcc_sendv_recv ( votequorum_inst->c, &iov, 1, &res_lib_votequorum_status, sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_status.header.error; error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } 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_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)); if (error != CS_OK) { 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; 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, &iov, 1, &res_lib_votequorum_qdevice_getinfo, sizeof (struct res_lib_votequorum_qdevice_getinfo), CS_IPC_TIMEOUT_MS)); if (error != CS_OK) { goto error_exit; } error = res_lib_votequorum_qdevice_getinfo.header.error; qinfo->votes = res_lib_votequorum_qdevice_getinfo.votes; qinfo->state = res_lib_votequorum_qdevice_getinfo.state; strcpy(qinfo->name, res_lib_votequorum_qdevice_getinfo.name); error_exit: hdb_handle_put (&votequorum_handle_t_db, handle); return (error); } #endif