2 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
5 * This file is part of LVM2.
7 * This copyrighted material is made available to anyone wishing to use,
8 * modify, copy, or redistribute it subject to the terms and conditions
9 * of the GNU General Public License v.2.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software Foundation,
13 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * CMAN communication layer for clvmd.
20 #include "clvmd-common.h"
24 #include "clvmd-comms.h"
27 #include "lvm-functions.h"
33 #define LOCKSPACE_NAME "clvmd"
37 struct cman_node *node;
42 static struct cman_node *nodes = NULL;
43 static struct cman_node this_node;
44 static int count_nodes; /* size of allocated nodes array */
45 static struct dm_hash_table *node_updown_hash;
46 static dlm_lshandle_t *lockspace;
47 static cman_handle_t c_handle;
49 static void count_clvmds_running(void);
50 static void get_members(void);
51 static int nodeid_from_csid(const char *csid);
52 static int name_from_nodeid(int nodeid, char *name);
53 static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
54 static void data_callback(cman_handle_t handle, void *private,
55 char *buf, int len, uint8_t port, int nodeid);
59 pthread_mutex_t mutex;
63 static int _init_cluster(void)
65 node_updown_hash = dm_hash_create(100);
67 /* Open the cluster communication socket */
68 c_handle = cman_init(NULL);
70 syslog(LOG_ERR, "Can't open cluster manager socket: %m");
73 DEBUGLOG("Connected to CMAN\n");
75 if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
76 syslog(LOG_ERR, "Can't bind cluster socket: %m");
80 if (cman_start_notification(c_handle, event_callback)) {
81 syslog(LOG_ERR, "Can't start cluster event listening");
85 /* Get the cluster members list */
87 count_clvmds_running();
89 DEBUGLOG("CMAN initialisation complete\n");
91 /* Create a lockspace for LV & VG locks to live in */
92 lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
94 if (errno == EEXIST) {
95 lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
98 syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m");
102 dlm_ls_pthread_init(lockspace);
103 DEBUGLOG("DLM initialisation complete\n");
107 static void _cluster_init_completed(void)
109 clvmd_cluster_init_completed();
112 static int _get_main_cluster_fd()
114 return cman_get_fd(c_handle);
117 static int _get_num_nodes()
122 /* return number of ACTIVE nodes */
123 for (i=0; i<num_nodes; i++) {
124 if (nodes[i].cn_member && nodes[i].cn_nodeid)
130 /* send_message with the fd check removed */
131 static int _cluster_send_message(const void *buf, int msglen, const char *csid,
137 memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
139 if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
141 log_error("%s", errtext);
146 static void _get_our_csid(char *csid)
148 if (this_node.cn_nodeid == 0) {
149 cman_get_node(c_handle, 0, &this_node);
151 memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
154 /* Call a callback routine for each node is that known (down means not running a clvmd) */
155 static int _cluster_do_node_callback(struct local_client *client,
156 void (*callback) (struct local_client *,
163 for (i = 0; i < _get_num_nodes(); i++) {
164 if (nodes[i].cn_member && nodes[i].cn_nodeid) {
165 int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int));
167 callback(client, (char *)&nodes[i].cn_nodeid, up);
175 /* Process OOB messages from the cluster socket */
176 static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
178 char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
181 case CMAN_REASON_PORTCLOSED:
182 name_from_nodeid(arg, namebuf);
183 log_notice("clvmd on node %s has died\n", namebuf);
184 DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
186 dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
189 case CMAN_REASON_STATECHANGE:
190 DEBUGLOG("Got state change message, re-reading members list\n");
194 #if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
195 case CMAN_REASON_PORTOPENED:
196 /* Ignore this, wait for startup message from clvmd itself */
199 case CMAN_REASON_TRY_SHUTDOWN:
200 DEBUGLOG("Got try shutdown, sending OK\n");
201 cman_replyto_shutdown(c_handle, 1);
206 DEBUGLOG("Got unknown event callback message: %d\n", reason);
211 static struct local_client *cman_client;
212 static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
214 struct local_client **new_client)
217 /* Save this for data_callback */
220 /* We never return a new client */
223 return cman_dispatch(c_handle, 0);
227 static void data_callback(cman_handle_t handle, void *private,
228 char *buf, int len, uint8_t port, int nodeid)
230 /* Ignore looped back messages */
231 if (nodeid == this_node.cn_nodeid)
233 process_message(cman_client, buf, len, (char *)&nodeid);
236 static void _add_up_node(const char *csid)
239 int nodeid = nodeid_from_csid(csid);
241 dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1);
242 DEBUGLOG("Added new node %d to updown list\n", nodeid);
245 static void _cluster_closedown()
248 dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
249 cman_finish(c_handle);
252 static int is_listening(int nodeid)
257 status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
258 if (status < 0 && errno == EBUSY) { /* Don't busywait */
260 errno = EBUSY; /* In case sleep trashes it */
263 while (status < 0 && errno == EBUSY);
268 /* Populate the list of CLVMDs running.
269 called only at startup time */
270 static void count_clvmds_running(void)
274 for (i = 0; i < num_nodes; i++) {
275 int nodeid = nodes[i].cn_nodeid;
277 if (is_listening(nodeid) == 1)
278 dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
280 dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
284 /* Get a list of active cluster members */
285 static void get_members()
292 num_nodes = cman_get_node_count(c_handle);
293 if (num_nodes == -1) {
294 log_error("Unable to get node count");
298 /* Not enough room for new nodes list ? */
299 if (num_nodes > count_nodes && nodes) {
305 count_nodes = num_nodes + 10; /* Overallocate a little */
306 nodes = malloc(count_nodes * sizeof(struct cman_node));
308 log_error("Unable to allocate nodes array\n");
313 status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
315 log_error("Unable to get node details");
319 /* Get the highest nodeid */
320 for (i=0; i<retnodes; i++) {
321 if (nodes[i].cn_nodeid > high_nodeid)
322 high_nodeid = nodes[i].cn_nodeid;
327 /* Convert a node name to a CSID */
328 static int _csid_from_name(char *csid, const char *name)
332 for (i = 0; i < num_nodes; i++) {
333 if (strcmp(name, nodes[i].cn_name) == 0) {
334 memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
341 /* Convert a CSID to a node name */
342 static int _name_from_csid(const char *csid, char *name)
346 for (i = 0; i < num_nodes; i++) {
347 if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
348 strcpy(name, nodes[i].cn_name);
353 strcpy(name, "Unknown");
357 /* Convert a node ID to a node name */
358 static int name_from_nodeid(int nodeid, char *name)
362 for (i = 0; i < num_nodes; i++) {
363 if (nodeid == nodes[i].cn_nodeid) {
364 strcpy(name, nodes[i].cn_name);
369 strcpy(name, "Unknown");
373 /* Convert a CSID to a node ID */
374 static int nodeid_from_csid(const char *csid)
378 memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
383 static int _is_quorate()
385 return cman_is_quorate(c_handle);
388 static void sync_ast_routine(void *arg)
390 struct lock_wait *lwait = arg;
392 pthread_mutex_lock(&lwait->mutex);
393 pthread_cond_signal(&lwait->cond);
394 pthread_mutex_unlock(&lwait->mutex);
397 static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
400 struct lock_wait lwait;
407 DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
408 /* Conversions need the lockid in the LKSB */
409 if (flags & LKF_CONVERT)
410 lwait.lksb.sb_lkid = *lockid;
412 pthread_cond_init(&lwait.cond, NULL);
413 pthread_mutex_init(&lwait.mutex, NULL);
414 pthread_mutex_lock(&lwait.mutex);
416 status = dlm_ls_lock(lockspace,
422 0, sync_ast_routine, &lwait, NULL, NULL);
426 /* Wait for it to complete */
427 pthread_cond_wait(&lwait.cond, &lwait.mutex);
428 pthread_mutex_unlock(&lwait.mutex);
430 *lockid = lwait.lksb.sb_lkid;
432 errno = lwait.lksb.sb_status;
433 DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
434 if (lwait.lksb.sb_status)
440 static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
443 struct lock_wait lwait;
445 DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
447 pthread_cond_init(&lwait.cond, NULL);
448 pthread_mutex_init(&lwait.mutex, NULL);
449 pthread_mutex_lock(&lwait.mutex);
451 status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
456 /* Wait for it to complete */
457 pthread_cond_wait(&lwait.cond, &lwait.mutex);
458 pthread_mutex_unlock(&lwait.mutex);
460 errno = lwait.lksb.sb_status;
461 if (lwait.lksb.sb_status != EUNLOCK)
468 static int _get_cluster_name(char *buf, int buflen)
470 cman_cluster_t cluster_info;
473 status = cman_get_cluster(c_handle, &cluster_info);
475 strncpy(buf, cluster_info.ci_name, buflen);
480 static struct cluster_ops _cluster_cman_ops = {
481 .cluster_init_completed = _cluster_init_completed,
482 .cluster_send_message = _cluster_send_message,
483 .name_from_csid = _name_from_csid,
484 .csid_from_name = _csid_from_name,
485 .get_num_nodes = _get_num_nodes,
486 .cluster_fd_callback = _cluster_fd_callback,
487 .get_main_cluster_fd = _get_main_cluster_fd,
488 .cluster_do_node_callback = _cluster_do_node_callback,
489 .is_quorate = _is_quorate,
490 .get_our_csid = _get_our_csid,
491 .add_up_node = _add_up_node,
492 .cluster_closedown = _cluster_closedown,
493 .get_cluster_name = _get_cluster_name,
494 .sync_lock = _sync_lock,
495 .sync_unlock = _sync_unlock,
498 struct cluster_ops *init_cman_cluster(void)
500 if (!_init_cluster())
501 return &_cluster_cman_ops;