Tizen 2.1 base
[external/device-mapper.git] / daemons / clvmd / clvmd-cman.c
1 /*
2  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
4  *
5  * This file is part of LVM2.
6  *
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.
10  *
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
14  */
15
16 /*
17  * CMAN communication layer for clvmd.
18  */
19
20 #include "clvmd-common.h"
21
22 #include <pthread.h>
23
24 #include "clvmd-comms.h"
25 #include "clvm.h"
26 #include "clvmd.h"
27 #include "lvm-functions.h"
28
29 #include <libdlm.h>
30
31 #include <syslog.h>
32
33 #define LOCKSPACE_NAME "clvmd"
34
35 struct clvmd_node
36 {
37         struct cman_node *node;
38         int clvmd_up;
39 };
40
41 static int num_nodes;
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;
48
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);
56
57 struct lock_wait {
58         pthread_cond_t cond;
59         pthread_mutex_t mutex;
60         struct dlm_lksb lksb;
61 };
62
63 static int _init_cluster(void)
64 {
65         node_updown_hash = dm_hash_create(100);
66
67         /* Open the cluster communication socket */
68         c_handle = cman_init(NULL);
69         if (!c_handle) {
70                 syslog(LOG_ERR, "Can't open cluster manager socket: %m");
71                 return -1;
72         }
73         DEBUGLOG("Connected to CMAN\n");
74
75         if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
76                 syslog(LOG_ERR, "Can't bind cluster socket: %m");
77                 return -1;
78         }
79
80         if (cman_start_notification(c_handle, event_callback)) {
81                 syslog(LOG_ERR, "Can't start cluster event listening");
82                 return -1;
83         }
84
85         /* Get the cluster members list */
86         get_members();
87         count_clvmds_running();
88
89         DEBUGLOG("CMAN initialisation complete\n");
90
91         /* Create a lockspace for LV & VG locks to live in */
92         lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
93         if (!lockspace) {
94                 if (errno == EEXIST) {
95                         lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
96                 }
97                 if (!lockspace) {
98                         syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m");
99                         return -1;
100                 }
101         }
102         dlm_ls_pthread_init(lockspace);
103         DEBUGLOG("DLM initialisation complete\n");
104         return 0;
105 }
106
107 static void _cluster_init_completed(void)
108 {
109         clvmd_cluster_init_completed();
110 }
111
112 static int _get_main_cluster_fd()
113 {
114         return cman_get_fd(c_handle);
115 }
116
117 static int _get_num_nodes()
118 {
119         int i;
120         int nnodes = 0;
121
122         /* return number of ACTIVE nodes */
123         for (i=0; i<num_nodes; i++) {
124                 if (nodes[i].cn_member && nodes[i].cn_nodeid)
125                         nnodes++;
126         }
127         return nnodes;
128 }
129
130 /* send_message with the fd check removed */
131 static int _cluster_send_message(const void *buf, int msglen, const char *csid,
132                                  const char *errtext)
133 {
134         int nodeid = 0;
135
136         if (csid)
137                 memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
138
139         if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
140         {
141                 log_error("%s", errtext);
142         }
143         return msglen;
144 }
145
146 static void _get_our_csid(char *csid)
147 {
148         if (this_node.cn_nodeid == 0) {
149                 cman_get_node(c_handle, 0, &this_node);
150         }
151         memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
152 }
153
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 *,
157                                                        const char *,
158                                                        int))
159 {
160         int i;
161         int somedown = 0;
162
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));
166
167                         callback(client, (char *)&nodes[i].cn_nodeid, up);
168                         if (!up)
169                                 somedown = -1;
170                 }
171         }
172         return somedown;
173 }
174
175 /* Process OOB messages from the cluster socket */
176 static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
177 {
178         char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
179
180         switch (reason) {
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);
185
186                 dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
187                 break;
188
189         case CMAN_REASON_STATECHANGE:
190                 DEBUGLOG("Got state change message, re-reading members list\n");
191                 get_members();
192                 break;
193
194 #if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
195         case CMAN_REASON_PORTOPENED:
196                 /* Ignore this, wait for startup message from clvmd itself */
197                 break;
198
199         case CMAN_REASON_TRY_SHUTDOWN:
200                 DEBUGLOG("Got try shutdown, sending OK\n");
201                 cman_replyto_shutdown(c_handle, 1);
202                 break;
203 #endif
204         default:
205                 /* ERROR */
206                 DEBUGLOG("Got unknown event callback message: %d\n", reason);
207                 break;
208         }
209 }
210
211 static struct local_client *cman_client;
212 static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
213                                 const char *csid,
214                                 struct local_client **new_client)
215 {
216
217         /* Save this for data_callback */
218         cman_client = fd;
219
220         /* We never return a new client */
221         *new_client = NULL;
222
223         return cman_dispatch(c_handle, 0);
224 }
225
226
227 static void data_callback(cman_handle_t handle, void *private,
228                           char *buf, int len, uint8_t port, int nodeid)
229 {
230         /* Ignore looped back messages */
231         if (nodeid == this_node.cn_nodeid)
232                 return;
233         process_message(cman_client, buf, len, (char *)&nodeid);
234 }
235
236 static void _add_up_node(const char *csid)
237 {
238         /* It's up ! */
239         int nodeid = nodeid_from_csid(csid);
240
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);
243 }
244
245 static void _cluster_closedown()
246 {
247         destroy_lvhash();
248         dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
249         cman_finish(c_handle);
250 }
251
252 static int is_listening(int nodeid)
253 {
254         int status;
255
256         do {
257                 status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
258                 if (status < 0 && errno == EBUSY) {     /* Don't busywait */
259                         sleep(1);
260                         errno = EBUSY;  /* In case sleep trashes it */
261                 }
262         }
263         while (status < 0 && errno == EBUSY);
264
265         return status;
266 }
267
268 /* Populate the list of CLVMDs running.
269    called only at startup time */
270 static void count_clvmds_running(void)
271 {
272         int i;
273
274         for (i = 0; i < num_nodes; i++) {
275                 int nodeid = nodes[i].cn_nodeid;
276
277                 if (is_listening(nodeid) == 1)
278                         dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
279                 else
280                         dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
281         }
282 }
283
284 /* Get a list of active cluster members */
285 static void get_members()
286 {
287         int retnodes;
288         int status;
289         int i;
290         int high_nodeid = 0;
291
292         num_nodes = cman_get_node_count(c_handle);
293         if (num_nodes == -1) {
294                 log_error("Unable to get node count");
295                 return;
296         }
297
298         /* Not enough room for new nodes list ? */
299         if (num_nodes > count_nodes && nodes) {
300                 free(nodes);
301                 nodes = NULL;
302         }
303
304         if (nodes == NULL) {
305                 count_nodes = num_nodes + 10; /* Overallocate a little */
306                 nodes = malloc(count_nodes * sizeof(struct cman_node));
307                 if (!nodes) {
308                         log_error("Unable to allocate nodes array\n");
309                         exit(5);
310                 }
311         }
312
313         status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
314         if (status < 0) {
315                 log_error("Unable to get node details");
316                 exit(6);
317         }
318
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;
323         }
324 }
325
326
327 /* Convert a node name to a CSID */
328 static int _csid_from_name(char *csid, const char *name)
329 {
330         int i;
331
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);
335                         return 0;
336                 }
337         }
338         return -1;
339 }
340
341 /* Convert a CSID to a node name */
342 static int _name_from_csid(const char *csid, char *name)
343 {
344         int i;
345
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);
349                         return 0;
350                 }
351         }
352         /* Who?? */
353         strcpy(name, "Unknown");
354         return -1;
355 }
356
357 /* Convert a node ID to a node name */
358 static int name_from_nodeid(int nodeid, char *name)
359 {
360         int i;
361
362         for (i = 0; i < num_nodes; i++) {
363                 if (nodeid == nodes[i].cn_nodeid) {
364                         strcpy(name, nodes[i].cn_name);
365                         return 0;
366                 }
367         }
368         /* Who?? */
369         strcpy(name, "Unknown");
370         return -1;
371 }
372
373 /* Convert a CSID to a node ID */
374 static int nodeid_from_csid(const char *csid)
375 {
376         int nodeid;
377
378         memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
379
380         return nodeid;
381 }
382
383 static int _is_quorate()
384 {
385         return cman_is_quorate(c_handle);
386 }
387
388 static void sync_ast_routine(void *arg)
389 {
390         struct lock_wait *lwait = arg;
391
392         pthread_mutex_lock(&lwait->mutex);
393         pthread_cond_signal(&lwait->cond);
394         pthread_mutex_unlock(&lwait->mutex);
395 }
396
397 static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
398 {
399         int status;
400         struct lock_wait lwait;
401
402         if (!lockid) {
403                 errno = EINVAL;
404                 return -1;
405         }
406
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;
411
412         pthread_cond_init(&lwait.cond, NULL);
413         pthread_mutex_init(&lwait.mutex, NULL);
414         pthread_mutex_lock(&lwait.mutex);
415
416         status = dlm_ls_lock(lockspace,
417                              mode,
418                              &lwait.lksb,
419                              flags,
420                              resource,
421                              strlen(resource),
422                              0, sync_ast_routine, &lwait, NULL, NULL);
423         if (status)
424                 return status;
425
426         /* Wait for it to complete */
427         pthread_cond_wait(&lwait.cond, &lwait.mutex);
428         pthread_mutex_unlock(&lwait.mutex);
429
430         *lockid = lwait.lksb.sb_lkid;
431
432         errno = lwait.lksb.sb_status;
433         DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
434         if (lwait.lksb.sb_status)
435                 return -1;
436         else
437                 return 0;
438 }
439
440 static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
441 {
442         int status;
443         struct lock_wait lwait;
444
445         DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
446
447         pthread_cond_init(&lwait.cond, NULL);
448         pthread_mutex_init(&lwait.mutex, NULL);
449         pthread_mutex_lock(&lwait.mutex);
450
451         status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
452
453         if (status)
454                 return status;
455
456         /* Wait for it to complete */
457         pthread_cond_wait(&lwait.cond, &lwait.mutex);
458         pthread_mutex_unlock(&lwait.mutex);
459
460         errno = lwait.lksb.sb_status;
461         if (lwait.lksb.sb_status != EUNLOCK)
462                 return -1;
463         else
464                 return 0;
465
466 }
467
468 static int _get_cluster_name(char *buf, int buflen)
469 {
470         cman_cluster_t cluster_info;
471         int status;
472
473         status = cman_get_cluster(c_handle, &cluster_info);
474         if (!status) {
475                 strncpy(buf, cluster_info.ci_name, buflen);
476         }
477         return status;
478 }
479
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,
496 };
497
498 struct cluster_ops *init_cman_cluster(void)
499 {
500         if (!_init_cluster())
501                 return &_cluster_cman_ops;
502         else
503                 return NULL;
504 }