/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: */ /****************************************************************************** ******************************************************************************* ** ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions ** of the GNU General Public License v.2. ** ******************************************************************************* ******************************************************************************/ /* * Copyright (C) 2007 Oracle. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. */ #include #include #include #include #include #include #include #include #include "ocfs2-kernel/kernel-list.h" #include "o2cb/o2cb.h" #include "ocfs2_controld.h" int our_nodeid; static int cman_ci; static char * clustername; static cman_cluster_t cluster; static cman_handle_t ch; static cman_handle_t ch_admin; extern struct list_head mounts; static cman_node_t old_nodes[O2NM_MAX_NODES]; static int old_node_count; static cman_node_t cman_nodes[O2NM_MAX_NODES]; static int cman_node_count; const char *stackname = "cman"; int kill_stack_node(int nodeid) { int error; log_debug("killing node %d", nodeid); error = cman_kill_node(ch_admin, nodeid); if (error) log_debug("Unable to kill node %d, %d %d", nodeid, error, errno); return error; } static int is_member(cman_node_t *node_list, int count, int nodeid) { int i; for (i = 0; i < count; i++) { if (node_list[i].cn_nodeid == nodeid) return node_list[i].cn_member; } return 0; } static int is_old_member(int nodeid) { return is_member(old_nodes, old_node_count, nodeid); } static int is_cman_member(int nodeid) { return is_member(cman_nodes, cman_node_count, nodeid); } static cman_node_t *find_cman_node(int nodeid) { int i; for (i = 0; i < cman_node_count; i++) { if (cman_nodes[i].cn_nodeid == nodeid) return &cman_nodes[i]; } return NULL; } char *nodeid2name(int nodeid) { cman_node_t *cn; cn = find_cman_node(nodeid); if (!cn) return NULL; return cn->cn_name; } int validate_cluster(const char *cluster) { if (!clustername) { log_error("Trying to validate before cman is alive"); return 0; } if (!cluster) return 0; return !strcmp(cluster, clustername); } int get_clustername(const char **cluster) { if (!clustername) { log_error("Trying to validate before cman is alive"); return -EIO; } if (!cluster) { log_error("NULL passed!"); return -EINVAL; } *cluster = clustername; return 0; } /* keep track of the nodes */ static void statechange(void) { int i, rv; old_node_count = cman_node_count; memcpy(&old_nodes, &cman_nodes, sizeof(old_nodes)); cman_node_count = 0; memset(&cman_nodes, 0, sizeof(cman_nodes)); rv = cman_get_nodes(ch, O2NM_MAX_NODES, &cman_node_count, cman_nodes); if (rv < 0) { log_debug("cman_get_nodes error %d %d", rv, errno); return; } for (i = 0; i < old_node_count; i++) { if (old_nodes[i].cn_member && !is_cman_member(old_nodes[i].cn_nodeid)) { log_debug("cman: node %d removed", old_nodes[i].cn_nodeid); } } for (i = 0; i < cman_node_count; i++) { if (cman_nodes[i].cn_member && !is_old_member(cman_nodes[i].cn_nodeid)) { log_debug("cman: node %d added", cman_nodes[i].cn_nodeid); } } } static void cman_callback(cman_handle_t h, void *private, int reason, int arg) { switch (reason) { case CMAN_REASON_TRY_SHUTDOWN: if (!have_mounts()) cman_replyto_shutdown(ch, 1); else { log_debug("no to cman shutdown"); cman_replyto_shutdown(ch, 0); } break; case CMAN_REASON_STATECHANGE: statechange(); break; } } static void dead_cman(int ci) { if (ci != cman_ci) { log_error("Unknown connection %d", ci); return; } log_error("cman connection died"); shutdown_daemon(); connection_dead(ci); } static void process_cman(int ci) { int rv; if (ci != cman_ci) { log_error("Unknown connection %d", ci); return; } rv = cman_dispatch(ch, CMAN_DISPATCH_ALL); if (rv == -1 && errno == EHOSTDOWN) { log_error("cman connection died"); shutdown_daemon(); } } int setup_stack(void) { cman_node_t node; int rv, fd; ch = cman_init(NULL); if (!ch) { log_error("cman_init error %d", errno); rv = -ENOTCONN; goto fail_finish; } ch_admin = cman_admin_init(NULL); if (!ch_admin) { log_error("cman_admin_init error %d", errno); rv = -ENOTCONN; goto fail_finish; } rv = cman_start_notification(ch, cman_callback); if (rv < 0) { log_error("cman_start_notification error %d %d", rv, errno); goto fail_finish; } /* FIXME: wait here for us to be a member of the cluster */ memset(&cluster, 0, sizeof(cluster)); rv = cman_get_cluster(ch, &cluster); if (rv < 0) { log_error("cman_get_cluster error %d %d", rv, errno); goto fail_stop; } clustername = cluster.ci_name; memset(&node, 0, sizeof(node)); rv = cman_get_node(ch, CMAN_NODEID_US, &node); if (rv < 0) { log_error("cman_get_node error %d %d", rv, errno); goto fail_stop; } our_nodeid = node.cn_nodeid; fd = cman_get_fd(ch); old_node_count = 0; memset(&old_nodes, 0, sizeof(old_nodes)); cman_node_count = 0; memset(&cman_nodes, 0, sizeof(cman_nodes)); /* Fill the node list */ statechange(); cman_ci = connection_add(fd, process_cman, dead_cman); if (cman_ci < 0) { rv = cman_ci; log_error("Unable to add cman client: %s", strerror(-cman_ci)); goto fail_stop; } return 0; fail_stop: cman_stop_notification(ch); fail_finish: if (ch_admin) cman_finish(ch_admin); if (ch) cman_finish(ch); ch = ch_admin = NULL; return rv; } void exit_stack(void) { if (ch_admin) cman_finish(ch_admin); if (ch) { log_debug("closing cman connection"); cman_stop_notification(ch); cman_finish(ch); } }