]> git.proxmox.com Git - mirror_corosync.git/blob - exec/vsf_quorum.c
configure: Modernize configure.ac a bit
[mirror_corosync.git] / exec / vsf_quorum.c
1 /*
2 * Copyright (c) 2008-2020 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Christine Caulfield (ccaulfie@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of Red Hat Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <config.h>
36
37 #include <pwd.h>
38 #include <grp.h>
39 #include <sys/types.h>
40 #include <sys/poll.h>
41 #include <sys/uio.h>
42 #include <sys/mman.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <sys/time.h>
46 #include <sys/resource.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <errno.h>
54 #include <sched.h>
55 #include <time.h>
56
57 #include "quorum.h"
58 #include <corosync/corotypes.h>
59 #include <qb/qbipc_common.h>
60 #include <corosync/corodefs.h>
61 #include <corosync/swab.h>
62 #include <qb/qblist.h>
63 #include <corosync/mar_gen.h>
64 #include <corosync/ipc_quorum.h>
65 #include <corosync/coroapi.h>
66 #include <corosync/logsys.h>
67 #include <corosync/icmap.h>
68
69 #include "service.h"
70 #include "votequorum.h"
71 #include "vsf_ykd.h"
72
73 LOGSYS_DECLARE_SUBSYS ("QUORUM");
74
75 struct quorum_pd {
76 unsigned char track_flags;
77 int tracking_enabled;
78 struct qb_list_head list;
79 void *conn;
80 enum lib_quorum_model model;
81 };
82
83 struct internal_callback_pd {
84 struct qb_list_head list;
85 quorum_callback_fn_t callback;
86 void *context;
87 };
88
89 static void quorum_sync_init (
90 const unsigned int *trans_list,
91 size_t trans_list_entries,
92 const unsigned int *member_list,
93 size_t member_list_entries,
94 const struct memb_ring_id *ring_id);
95
96 static int quorum_sync_process (void);
97
98 static void quorum_sync_activate (void);
99
100 static void quorum_sync_abort (void);
101
102 static void message_handler_req_lib_quorum_getquorate (void *conn,
103 const void *msg);
104 static void message_handler_req_lib_quorum_trackstart (void *conn,
105 const void *msg);
106 static void message_handler_req_lib_quorum_trackstop (void *conn,
107 const void *msg);
108 static void message_handler_req_lib_quorum_gettype (void *conn,
109 const void *msg);
110 static void message_handler_req_lib_quorum_model_gettype (void *conn,
111 const void *msg);
112 static void send_library_notification(void *conn);
113 static void send_internal_notification(void);
114 static void send_nodelist_library_notification(void *conn, int send_joined_left_list);
115 static char *quorum_exec_init_fn (struct corosync_api_v1 *api);
116 static int quorum_lib_init_fn (void *conn);
117 static int quorum_lib_exit_fn (void *conn);
118
119 static int primary_designated = 0;
120 static int quorum_type = 0;
121 static struct corosync_api_v1 *corosync_api;
122 static struct qb_list_head lib_trackers_list;
123 static struct qb_list_head internal_trackers_list;
124 static struct memb_ring_id quorum_ring_id;
125 static struct memb_ring_id last_sync_ring_id;
126 static size_t quorum_view_list_entries = 0;
127 static int quorum_view_list[PROCESSOR_COUNT_MAX];
128 struct quorum_services_api_ver1 *quorum_iface = NULL;
129
130 static char view_buf[64];
131
132 static unsigned int my_member_list[PROCESSOR_COUNT_MAX];
133 static size_t my_member_list_entries;
134 static unsigned int my_old_member_list[PROCESSOR_COUNT_MAX];
135 static size_t my_old_member_list_entries = 0;
136 static unsigned int my_left_list[PROCESSOR_COUNT_MAX];
137 static size_t my_left_list_entries;
138 static unsigned int my_joined_list[PROCESSOR_COUNT_MAX];
139 static size_t my_joined_list_entries;
140
141 static void log_view_list(const unsigned int *view_list, size_t view_list_entries,
142 const char *view_list_type_str)
143 {
144 int total = (int)view_list_entries;
145 int len, pos, ret;
146 int i = 0;
147
148 while (1) {
149 len = sizeof(view_buf);
150 pos = 0;
151 memset(view_buf, 0, len);
152
153 for (; i < total; i++) {
154 ret = snprintf(view_buf + pos, len - pos, " " CS_PRI_NODE_ID, view_list[i]);
155 if (ret >= len - pos)
156 break;
157 pos += ret;
158 }
159 log_printf (LOGSYS_LEVEL_NOTICE, "%s[%d]:%s%s",
160 view_list_type_str, total, view_buf, i < total ? "\\" : "");
161
162 if (i == total)
163 break;
164 }
165 }
166
167 /* Internal quorum API function */
168 static void quorum_api_set_quorum(const unsigned int *view_list,
169 size_t view_list_entries,
170 int quorum, struct memb_ring_id *ring_id)
171 {
172 int old_quorum = primary_designated;
173 primary_designated = quorum;
174
175 if (primary_designated && !old_quorum) {
176 log_printf (LOGSYS_LEVEL_NOTICE, "This node is within the primary component and will provide service.");
177 } else if (!primary_designated && old_quorum) {
178 log_printf (LOGSYS_LEVEL_NOTICE, "This node is within the non-primary component and will NOT provide any services.");
179 }
180
181 quorum_view_list_entries = view_list_entries;
182 memcpy(&quorum_ring_id, ring_id, sizeof (quorum_ring_id));
183 memcpy(quorum_view_list, view_list, sizeof(unsigned int)*view_list_entries);
184
185 log_view_list(view_list, view_list_entries, "Members");
186
187 /* Tell internal listeners */
188 send_internal_notification();
189
190 /* Tell IPC listeners */
191 send_library_notification(NULL);
192 }
193
194 static struct corosync_lib_handler quorum_lib_service[] =
195 {
196 { /* 0 */
197 .lib_handler_fn = message_handler_req_lib_quorum_getquorate,
198 .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
199 },
200 { /* 1 */
201 .lib_handler_fn = message_handler_req_lib_quorum_trackstart,
202 .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
203 },
204 { /* 2 */
205 .lib_handler_fn = message_handler_req_lib_quorum_trackstop,
206 .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
207 },
208 { /* 3 */
209 .lib_handler_fn = message_handler_req_lib_quorum_gettype,
210 .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
211 },
212 { /* 4 */
213 .lib_handler_fn = message_handler_req_lib_quorum_model_gettype,
214 .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
215 }
216 };
217
218 static struct corosync_service_engine quorum_service_handler = {
219 .name = "corosync cluster quorum service v0.1",
220 .id = QUORUM_SERVICE,
221 .priority = 1,
222 .private_data_size = sizeof (struct quorum_pd),
223 .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED,
224 .allow_inquorate = CS_LIB_ALLOW_INQUORATE,
225 .lib_init_fn = quorum_lib_init_fn,
226 .lib_exit_fn = quorum_lib_exit_fn,
227 .lib_engine = quorum_lib_service,
228 .exec_init_fn = quorum_exec_init_fn,
229 .sync_init = quorum_sync_init,
230 .sync_process = quorum_sync_process,
231 .sync_activate = quorum_sync_activate,
232 .sync_abort = quorum_sync_abort,
233 .lib_engine_count = sizeof (quorum_lib_service) / sizeof (struct corosync_lib_handler)
234 };
235
236 struct corosync_service_engine *vsf_quorum_get_service_engine_ver0 (void)
237 {
238 return (&quorum_service_handler);
239 }
240
241 /* -------------------------------------------------- */
242
243
244 /*
245 * Internal API functions for corosync
246 */
247
248 static int quorum_quorate(void)
249 {
250 return primary_designated;
251 }
252
253
254 static int quorum_register_callback(quorum_callback_fn_t function, void *context)
255 {
256 struct internal_callback_pd *pd = malloc(sizeof(struct internal_callback_pd));
257 if (!pd)
258 return -1;
259
260 pd->context = context;
261 pd->callback = function;
262 qb_list_add (&pd->list, &internal_trackers_list);
263
264 return 0;
265 }
266
267 static int quorum_unregister_callback(quorum_callback_fn_t function, void *context)
268 {
269 struct internal_callback_pd *pd;
270 struct qb_list_head *tmp, *tmp_iter;
271
272 qb_list_for_each_safe(tmp, tmp_iter, &internal_trackers_list) {
273 pd = qb_list_entry(tmp, struct internal_callback_pd, list);
274 if (pd->callback == function && pd->context == context) {
275 qb_list_del(&pd->list);
276 free(pd);
277 return 0;
278 }
279 }
280 return -1;
281 }
282
283 static struct quorum_callin_functions callins = {
284 .quorate = quorum_quorate,
285 .register_callback = quorum_register_callback,
286 .unregister_callback = quorum_unregister_callback
287 };
288
289 /* --------------------------------------------------------------------- */
290
291 static void quorum_sync_init (
292 const unsigned int *trans_list,
293 size_t trans_list_entries,
294 const unsigned int *member_list,
295 size_t member_list_entries,
296 const struct memb_ring_id *ring_id)
297 {
298 int found;
299 int i, j;
300 int entries;
301 int node_joined;
302
303 memcpy (my_member_list, member_list, member_list_entries *
304 sizeof (unsigned int));
305 my_member_list_entries = member_list_entries;
306
307 last_sync_ring_id = *ring_id;
308
309 /*
310 * Determine left list of nodeids
311 */
312 entries = 0;
313 for (i = 0; i < my_old_member_list_entries; i++) {
314 found = 0;
315 for (j = 0; j < trans_list_entries; j++) {
316 if (my_old_member_list[i] == trans_list[j]) {
317 found = 1;
318 break;
319 }
320 }
321
322 if (found == 0) {
323 my_left_list[entries++] = my_old_member_list[i];
324 } else {
325 /*
326 * Check it is really in new membership
327 */
328 found = 0;
329
330 for (j = 0; j < my_member_list_entries; j++) {
331 if (my_old_member_list[i] == my_member_list[j]) {
332 found = 1;
333 break;
334 }
335 }
336
337 /*
338 * Node is in both old_member_list and trans list but not in my_member_list.
339 * (This shouldn't really happen).
340 */
341 if (!found) {
342 my_left_list[entries++] = my_old_member_list[i];
343 }
344 }
345 }
346 my_left_list_entries = entries;
347
348 /*
349 * Determine joined list of nodeids
350 */
351 entries = 0;
352 for (i = 0; i < my_member_list_entries; i++) {
353 node_joined = 1;
354 for (j = 0; j < my_old_member_list_entries; j++) {
355 if (my_member_list[i] == my_old_member_list[j]) {
356 /*
357 * Node is in member list and also in my_old_member list -> check
358 * if it is in left_list.
359 */
360 node_joined = 0;
361 break;
362 }
363 }
364
365 if (!node_joined) {
366 /*
367 * Check if node is in left list.
368 */
369 for (j = 0; j < my_left_list_entries; j++) {
370 if (my_member_list[i] == my_left_list[j]) {
371 /*
372 * Node is both in left and also in member list -> joined
373 */
374 node_joined = 1;
375 break;
376 }
377 }
378 }
379
380 if (node_joined) {
381 my_joined_list[entries++] = my_member_list[i];
382 }
383 }
384 my_joined_list_entries = entries;
385
386 log_view_list(my_member_list, my_member_list_entries, "Sync members");
387
388 if (my_joined_list_entries > 0) {
389 log_view_list(my_joined_list, my_joined_list_entries, "Sync joined");
390 }
391
392 if (my_left_list_entries > 0) {
393 log_view_list(my_left_list, my_left_list_entries, "Sync left");
394 }
395 }
396
397 static int quorum_sync_process (void)
398 {
399
400 return (0);
401 }
402
403 static void quorum_sync_activate (void)
404 {
405
406 memcpy (my_old_member_list, my_member_list,
407 my_member_list_entries * sizeof (unsigned int));
408 my_old_member_list_entries = my_member_list_entries;
409
410 /* Tell IPC listeners */
411 send_nodelist_library_notification(NULL, 1);
412 }
413
414 static void quorum_sync_abort (void)
415 {
416
417 }
418
419 static char *quorum_exec_init_fn (struct corosync_api_v1 *api)
420 {
421 char *quorum_module = NULL;
422 char *error;
423
424 corosync_api = api;
425 qb_list_init (&lib_trackers_list);
426 qb_list_init (&internal_trackers_list);
427
428 /*
429 * Tell corosync we have a quorum engine.
430 */
431 api->quorum_initialize(&callins);
432
433 /*
434 * Look for a quorum provider
435 */
436 if (icmap_get_string("quorum.provider", &quorum_module) == CS_OK) {
437 log_printf (LOGSYS_LEVEL_NOTICE,
438 "Using quorum provider %s", quorum_module);
439
440 error = (char *)"Invalid quorum provider";
441
442 if (strcmp (quorum_module, "corosync_votequorum") == 0) {
443 error = votequorum_init (api, quorum_api_set_quorum);
444 quorum_type = 1;
445 }
446 if (strcmp (quorum_module, "corosync_ykd") == 0) {
447 error = ykd_init (api, quorum_api_set_quorum);
448 quorum_type = 1;
449 }
450 if (error) {
451 log_printf (LOGSYS_LEVEL_CRIT,
452 "Quorum provider: %s failed to initialize.",
453 quorum_module);
454 free(quorum_module);
455 return (error);
456 }
457 }
458
459 if (quorum_module) {
460 free(quorum_module);
461 quorum_module = NULL;
462 }
463
464 /*
465 * setting quorum_type and primary_designated in the right order is important
466 * always try to lookup/init a quorum module, then revert back to be quorate
467 */
468
469 if (quorum_type == 0) {
470 primary_designated = 1;
471 }
472
473 return (NULL);
474 }
475
476 static int quorum_lib_init_fn (void *conn)
477 {
478 struct quorum_pd *pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
479
480 log_printf(LOGSYS_LEVEL_DEBUG, "lib_init_fn: conn=%p", conn);
481
482 qb_list_init (&pd->list);
483 pd->conn = conn;
484 pd->model = LIB_QUORUM_MODEL_V0;
485
486 return (0);
487 }
488
489 static int quorum_lib_exit_fn (void *conn)
490 {
491 struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
492
493 log_printf(LOGSYS_LEVEL_DEBUG, "lib_exit_fn: conn=%p", conn);
494
495 if (quorum_pd->tracking_enabled) {
496 qb_list_del (&quorum_pd->list);
497 qb_list_init (&quorum_pd->list);
498 }
499 return (0);
500 }
501
502
503 static void send_internal_notification(void)
504 {
505 struct qb_list_head *tmp;
506 struct internal_callback_pd *pd;
507
508 qb_list_for_each(tmp, &internal_trackers_list) {
509 pd = qb_list_entry(tmp, struct internal_callback_pd, list);
510
511 pd->callback(primary_designated, pd->context);
512 }
513 }
514
515 static void prepare_library_notification_v0(char *buf, size_t size)
516 {
517 struct res_lib_quorum_notification *res_lib_quorum_notification = (struct res_lib_quorum_notification *)buf;
518 int i;
519
520 res_lib_quorum_notification->quorate = primary_designated;
521 res_lib_quorum_notification->ring_seq = quorum_ring_id.seq;
522 res_lib_quorum_notification->view_list_entries = quorum_view_list_entries;
523 for (i=0; i<quorum_view_list_entries; i++) {
524 res_lib_quorum_notification->view_list[i] = quorum_view_list[i];
525 }
526
527 res_lib_quorum_notification->header.id = MESSAGE_RES_QUORUM_NOTIFICATION;
528 res_lib_quorum_notification->header.size = size;
529 res_lib_quorum_notification->header.error = CS_OK;
530 }
531
532 static void prepare_library_notification_v1(char *buf, size_t size)
533 {
534 struct res_lib_quorum_v1_quorum_notification *res_lib_quorum_v1_quorum_notification =
535 (struct res_lib_quorum_v1_quorum_notification *)buf;
536 int i;
537
538 res_lib_quorum_v1_quorum_notification->quorate = primary_designated;
539 res_lib_quorum_v1_quorum_notification->ring_id.nodeid = quorum_ring_id.nodeid;
540 res_lib_quorum_v1_quorum_notification->ring_id.seq = quorum_ring_id.seq;
541 res_lib_quorum_v1_quorum_notification->view_list_entries = quorum_view_list_entries;
542 for (i=0; i<quorum_view_list_entries; i++) {
543 res_lib_quorum_v1_quorum_notification->view_list[i] = quorum_view_list[i];
544 }
545
546 res_lib_quorum_v1_quorum_notification->header.id = MESSAGE_RES_QUORUM_V1_QUORUM_NOTIFICATION;
547 res_lib_quorum_v1_quorum_notification->header.size = size;
548 res_lib_quorum_v1_quorum_notification->header.error = CS_OK;
549 }
550
551 static void send_library_notification(void *conn)
552 {
553 int size_v0 = sizeof(struct res_lib_quorum_notification) +
554 sizeof(mar_uint32_t) * quorum_view_list_entries;
555 int size_v1 = sizeof(struct res_lib_quorum_v1_quorum_notification) +
556 sizeof(mar_uint32_t)*quorum_view_list_entries;
557
558 char buf_v0[size_v0];
559 char buf_v1[size_v1];
560
561 struct res_lib_quorum_notification *res_lib_quorum_notification =
562 (struct res_lib_quorum_notification *)buf_v0;
563 struct res_lib_quorum_v1_quorum_notification *res_lib_quorum_v1_quorum_notification =
564 (struct res_lib_quorum_v1_quorum_notification *)buf_v1;
565
566 struct quorum_pd *qpd;
567 struct qb_list_head *tmp;
568
569 log_printf(LOGSYS_LEVEL_DEBUG, "sending quorum notification to %p, length = %u/%u", conn, size_v0, size_v1);
570
571 prepare_library_notification_v0(buf_v0, size_v0);
572 prepare_library_notification_v1(buf_v1, size_v1);
573
574 /* Send it to all interested parties */
575 if (conn) {
576 qpd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
577
578 if (qpd->model == LIB_QUORUM_MODEL_V0) {
579 corosync_api->ipc_dispatch_send(conn, res_lib_quorum_notification, size_v0);
580 } else if (qpd->model == LIB_QUORUM_MODEL_V1) {
581 corosync_api->ipc_dispatch_send(conn, res_lib_quorum_v1_quorum_notification, size_v1);
582 }
583 }
584 else {
585 qb_list_for_each(tmp, &lib_trackers_list) {
586 qpd = qb_list_entry(tmp, struct quorum_pd, list);
587
588 if (qpd->model == LIB_QUORUM_MODEL_V0) {
589 corosync_api->ipc_dispatch_send(qpd->conn,
590 res_lib_quorum_notification, size_v0);
591 } else if (qpd->model == LIB_QUORUM_MODEL_V1) {
592 corosync_api->ipc_dispatch_send(qpd->conn,
593 res_lib_quorum_v1_quorum_notification, size_v1);
594 }
595 }
596 }
597 return;
598 }
599
600 static void send_nodelist_library_notification(void *conn, int send_joined_left_list)
601 {
602 int size = sizeof(struct res_lib_quorum_v1_nodelist_notification) +
603 sizeof(mar_uint32_t) * my_member_list_entries;
604 char *buf;
605 struct res_lib_quorum_v1_nodelist_notification *res_lib_quorum_v1_nodelist_notification;
606 struct quorum_pd *qpd;
607 struct qb_list_head *tmp;
608 mar_uint32_t *ptr;
609 int i;
610
611 if (send_joined_left_list) {
612 size += sizeof(mar_uint32_t) * my_joined_list_entries;
613 size += sizeof(mar_uint32_t) * my_left_list_entries;
614 }
615
616 buf = alloca(size);
617 memset(buf, 0, size);
618
619 res_lib_quorum_v1_nodelist_notification = (struct res_lib_quorum_v1_nodelist_notification *)buf;
620
621 res_lib_quorum_v1_nodelist_notification->ring_id.nodeid = last_sync_ring_id.nodeid;
622 res_lib_quorum_v1_nodelist_notification->ring_id.seq = last_sync_ring_id.seq;
623 res_lib_quorum_v1_nodelist_notification->member_list_entries = my_member_list_entries;
624
625 if (send_joined_left_list) {
626 res_lib_quorum_v1_nodelist_notification->joined_list_entries = my_joined_list_entries;
627 res_lib_quorum_v1_nodelist_notification->left_list_entries = my_left_list_entries;
628 }
629
630 ptr = res_lib_quorum_v1_nodelist_notification->member_list;
631
632 for (i=0; i<my_member_list_entries; i++, ptr++) {
633 *ptr = my_member_list[i];
634 }
635
636 if (send_joined_left_list) {
637 for (i=0; i<my_joined_list_entries; i++, ptr++) {
638 *ptr = my_joined_list[i];
639 }
640
641 for (i=0; i<my_left_list_entries; i++, ptr++) {
642 *ptr = my_left_list[i];
643 }
644 }
645
646 res_lib_quorum_v1_nodelist_notification->header.id = MESSAGE_RES_QUORUM_V1_NODELIST_NOTIFICATION;
647 res_lib_quorum_v1_nodelist_notification->header.size = size;
648 res_lib_quorum_v1_nodelist_notification->header.error = CS_OK;
649
650 log_printf(LOGSYS_LEVEL_DEBUG, "sending nodelist notification to %p, length = %u", conn, size);
651
652 /* Send it to all interested parties */
653 if (conn) {
654 qpd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
655
656 if (qpd->model == LIB_QUORUM_MODEL_V1) {
657 corosync_api->ipc_dispatch_send(conn, res_lib_quorum_v1_nodelist_notification, size);
658 }
659 }
660 else {
661 qb_list_for_each(tmp, &lib_trackers_list) {
662 qpd = qb_list_entry(tmp, struct quorum_pd, list);
663
664 if (qpd->model == LIB_QUORUM_MODEL_V1) {
665 corosync_api->ipc_dispatch_send(qpd->conn,
666 res_lib_quorum_v1_nodelist_notification, size);
667 }
668 }
669 }
670
671 return;
672 }
673
674 static void message_handler_req_lib_quorum_getquorate (void *conn,
675 const void *msg)
676 {
677 struct res_lib_quorum_getquorate res_lib_quorum_getquorate;
678
679 log_printf(LOGSYS_LEVEL_DEBUG, "got quorate request on %p", conn);
680
681 /* send status */
682 res_lib_quorum_getquorate.quorate = primary_designated;
683 res_lib_quorum_getquorate.header.size = sizeof(res_lib_quorum_getquorate);
684 res_lib_quorum_getquorate.header.id = MESSAGE_RES_QUORUM_GETQUORATE;
685 res_lib_quorum_getquorate.header.error = CS_OK;
686 corosync_api->ipc_response_send(conn, &res_lib_quorum_getquorate, sizeof(res_lib_quorum_getquorate));
687 }
688
689 static void message_handler_req_lib_quorum_trackstart (void *conn,
690 const void *msg)
691 {
692 const struct req_lib_quorum_trackstart *req_lib_quorum_trackstart = msg;
693 struct qb_ipc_response_header res;
694 struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
695 cs_error_t error = CS_OK;
696
697 log_printf(LOGSYS_LEVEL_DEBUG, "got trackstart request on %p", conn);
698
699 /*
700 * If an immediate listing of the current cluster membership
701 * is requested, generate membership list
702 */
703 if (req_lib_quorum_trackstart->track_flags & CS_TRACK_CURRENT ||
704 req_lib_quorum_trackstart->track_flags & CS_TRACK_CHANGES) {
705 log_printf(LOGSYS_LEVEL_DEBUG, "sending initial status to %p", conn);
706 send_nodelist_library_notification(conn, 0);
707 send_library_notification(conn);
708 }
709
710 if (quorum_pd->tracking_enabled) {
711 error = CS_ERR_EXIST;
712 goto response_send;
713 }
714
715 /*
716 * Record requests for tracking
717 */
718 if (req_lib_quorum_trackstart->track_flags & CS_TRACK_CHANGES ||
719 req_lib_quorum_trackstart->track_flags & CS_TRACK_CHANGES_ONLY) {
720
721 quorum_pd->track_flags = req_lib_quorum_trackstart->track_flags;
722 quorum_pd->tracking_enabled = 1;
723
724 qb_list_add (&quorum_pd->list, &lib_trackers_list);
725 }
726
727 response_send:
728 /* send status */
729 res.size = sizeof(res);
730 res.id = MESSAGE_RES_QUORUM_TRACKSTART;
731 res.error = error;
732 corosync_api->ipc_response_send(conn, &res, sizeof(struct qb_ipc_response_header));
733 }
734
735 static void message_handler_req_lib_quorum_trackstop (void *conn, const void *msg)
736 {
737 struct qb_ipc_response_header res;
738 struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
739
740 log_printf(LOGSYS_LEVEL_DEBUG, "got trackstop request on %p", conn);
741
742 if (quorum_pd->tracking_enabled) {
743 res.error = CS_OK;
744 quorum_pd->tracking_enabled = 0;
745 qb_list_del (&quorum_pd->list);
746 qb_list_init (&quorum_pd->list);
747 } else {
748 res.error = CS_ERR_NOT_EXIST;
749 }
750
751 /* send status */
752 res.size = sizeof(res);
753 res.id = MESSAGE_RES_QUORUM_TRACKSTOP;
754 res.error = CS_OK;
755 corosync_api->ipc_response_send(conn, &res, sizeof(struct qb_ipc_response_header));
756 }
757
758 static void message_handler_req_lib_quorum_gettype (void *conn,
759 const void *msg)
760 {
761 struct res_lib_quorum_gettype res_lib_quorum_gettype;
762
763 log_printf(LOGSYS_LEVEL_DEBUG, "got quorum_type request on %p", conn);
764
765 /* send status */
766 res_lib_quorum_gettype.quorum_type = quorum_type;
767 res_lib_quorum_gettype.header.size = sizeof(res_lib_quorum_gettype);
768 res_lib_quorum_gettype.header.id = MESSAGE_RES_QUORUM_GETTYPE;
769 res_lib_quorum_gettype.header.error = CS_OK;
770 corosync_api->ipc_response_send(conn, &res_lib_quorum_gettype, sizeof(res_lib_quorum_gettype));
771 }
772
773 static void message_handler_req_lib_quorum_model_gettype (void *conn,
774 const void *msg)
775 {
776 const struct req_lib_quorum_model_gettype *req_lib_quorum_model_gettype = msg;
777 struct res_lib_quorum_model_gettype res_lib_quorum_model_gettype;
778 struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn);
779 cs_error_t ret_err;
780
781 log_printf(LOGSYS_LEVEL_DEBUG, "got quorum_model_type request on %p", conn);
782
783 ret_err = CS_OK;
784
785 if (req_lib_quorum_model_gettype->model != LIB_QUORUM_MODEL_V0 &&
786 req_lib_quorum_model_gettype->model != LIB_QUORUM_MODEL_V1) {
787 log_printf(LOGSYS_LEVEL_ERROR, "quorum_model_type request for unsupported model %u",
788 req_lib_quorum_model_gettype->model);
789
790 ret_err = CS_ERR_INVALID_PARAM;
791 } else {
792 quorum_pd->model = req_lib_quorum_model_gettype->model;
793 }
794
795 /* send status */
796 res_lib_quorum_model_gettype.quorum_type = quorum_type;
797 res_lib_quorum_model_gettype.header.size = sizeof(res_lib_quorum_model_gettype);
798 res_lib_quorum_model_gettype.header.id = MESSAGE_RES_QUORUM_MODEL_GETTYPE;
799 res_lib_quorum_model_gettype.header.error = ret_err;
800 corosync_api->ipc_response_send(conn, &res_lib_quorum_model_gettype, sizeof(res_lib_quorum_model_gettype));
801 }