]>
Commit | Line | Data |
---|---|---|
5bb7ca5d | 1 | /* |
4eb36297 | 2 | * Copyright (c) 2008-2020 Red Hat, Inc. |
5bb7ca5d CC |
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. | |
cfc7da35 | 18 | * - Neither the name of Red Hat Inc. nor the names of its |
5bb7ca5d CC |
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 | ||
031c02f5 FDN |
35 | #include <config.h> |
36 | ||
5bb7ca5d CC |
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> | |
5bb7ca5d CC |
54 | #include <sched.h> |
55 | #include <time.h> | |
56 | ||
7592e3b6 | 57 | #include "quorum.h" |
8126cf74 | 58 | #include <corosync/corotypes.h> |
c6895faa | 59 | #include <qb/qbipc_common.h> |
8126cf74 | 60 | #include <corosync/corodefs.h> |
5bb7ca5d | 61 | #include <corosync/swab.h> |
b4c06e52 | 62 | #include <qb/qblist.h> |
8126cf74 | 63 | #include <corosync/mar_gen.h> |
5bb7ca5d | 64 | #include <corosync/ipc_quorum.h> |
e5aba30a | 65 | #include <corosync/coroapi.h> |
8ad583a5 | 66 | #include <corosync/logsys.h> |
7e1c9771 | 67 | #include <corosync/icmap.h> |
5bb7ca5d | 68 | |
0e2f0b87 | 69 | #include "service.h" |
e423e43b | 70 | #include "votequorum.h" |
0e2f0b87 | 71 | #include "vsf_ykd.h" |
e423e43b | 72 | |
c3c75acf | 73 | LOGSYS_DECLARE_SUBSYS ("QUORUM"); |
5bb7ca5d CC |
74 | |
75 | struct quorum_pd { | |
76 | unsigned char track_flags; | |
77 | int tracking_enabled; | |
b4c06e52 | 78 | struct qb_list_head list; |
5bb7ca5d | 79 | void *conn; |
4eb36297 | 80 | enum lib_quorum_model model; |
5bb7ca5d CC |
81 | }; |
82 | ||
cfc7da35 | 83 | struct internal_callback_pd { |
b4c06e52 | 84 | struct qb_list_head list; |
cfc7da35 CC |
85 | quorum_callback_fn_t callback; |
86 | void *context; | |
87 | }; | |
88 | ||
4eb36297 JF |
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 | ||
e0021727 JM |
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); | |
e34d509d FDN |
108 | static void message_handler_req_lib_quorum_gettype (void *conn, |
109 | const void *msg); | |
4eb36297 JF |
110 | static void message_handler_req_lib_quorum_model_gettype (void *conn, |
111 | const void *msg); | |
cfc7da35 CC |
112 | static void send_library_notification(void *conn); |
113 | static void send_internal_notification(void); | |
4eb36297 | 114 | static void send_nodelist_library_notification(void *conn, int send_joined_left_list); |
007e5c94 | 115 | static char *quorum_exec_init_fn (struct corosync_api_v1 *api); |
5bb7ca5d CC |
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; | |
e34d509d | 120 | static int quorum_type = 0; |
5bb7ca5d | 121 | static struct corosync_api_v1 *corosync_api; |
b4c06e52 MJ |
122 | static struct qb_list_head lib_trackers_list; |
123 | static struct qb_list_head internal_trackers_list; | |
5bb7ca5d | 124 | static struct memb_ring_id quorum_ring_id; |
4eb36297 | 125 | static struct memb_ring_id last_sync_ring_id; |
4cb431fc | 126 | static size_t quorum_view_list_entries = 0; |
0665aca9 | 127 | static int quorum_view_list[PROCESSOR_COUNT_MAX]; |
cfc7da35 | 128 | struct quorum_services_api_ver1 *quorum_iface = NULL; |
4eb36297 | 129 | |
2e2581f5 CC |
130 | static char view_buf[64]; |
131 | ||
4eb36297 JF |
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) | |
2e2581f5 CC |
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++) { | |
5731af27 | 154 | ret = snprintf(view_buf + pos, len - pos, " " CS_PRI_NODE_ID, view_list[i]); |
2e2581f5 CC |
155 | if (ret >= len - pos) |
156 | break; | |
157 | pos += ret; | |
158 | } | |
4eb36297 JF |
159 | log_printf (LOGSYS_LEVEL_NOTICE, "%s[%d]:%s%s", |
160 | view_list_type_str, total, view_buf, i < total ? "\\" : ""); | |
2e2581f5 CC |
161 | |
162 | if (i == total) | |
163 | break; | |
164 | } | |
165 | } | |
5bb7ca5d | 166 | |
5bb7ca5d | 167 | /* Internal quorum API function */ |
db4838bc | 168 | static void quorum_api_set_quorum(const unsigned int *view_list, |
4cb431fc | 169 | size_t view_list_entries, |
5bb7ca5d CC |
170 | int quorum, struct memb_ring_id *ring_id) |
171 | { | |
e9adc518 | 172 | int old_quorum = primary_designated; |
5bb7ca5d | 173 | primary_designated = quorum; |
cfc7da35 | 174 | |
e9adc518 | 175 | if (primary_designated && !old_quorum) { |
3131601c | 176 | log_printf (LOGSYS_LEVEL_NOTICE, "This node is within the primary component and will provide service."); |
e9adc518 | 177 | } else if (!primary_designated && old_quorum) { |
3131601c | 178 | log_printf (LOGSYS_LEVEL_NOTICE, "This node is within the non-primary component and will NOT provide any services."); |
cfc7da35 CC |
179 | } |
180 | ||
5bb7ca5d | 181 | quorum_view_list_entries = view_list_entries; |
83aec0b8 | 182 | memcpy(&quorum_ring_id, ring_id, sizeof (quorum_ring_id)); |
fb833af4 | 183 | memcpy(quorum_view_list, view_list, sizeof(unsigned int)*view_list_entries); |
5bb7ca5d | 184 | |
4eb36297 | 185 | log_view_list(view_list, view_list_entries, "Members"); |
827ae57b | 186 | |
cfc7da35 CC |
187 | /* Tell internal listeners */ |
188 | send_internal_notification(); | |
5bb7ca5d | 189 | |
cfc7da35 CC |
190 | /* Tell IPC listeners */ |
191 | send_library_notification(NULL); | |
5bb7ca5d CC |
192 | } |
193 | ||
5bb7ca5d CC |
194 | static struct corosync_lib_handler quorum_lib_service[] = |
195 | { | |
196 | { /* 0 */ | |
197 | .lib_handler_fn = message_handler_req_lib_quorum_getquorate, | |
56eaee95 | 198 | .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED |
5bb7ca5d CC |
199 | }, |
200 | { /* 1 */ | |
201 | .lib_handler_fn = message_handler_req_lib_quorum_trackstart, | |
56eaee95 | 202 | .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED |
5bb7ca5d CC |
203 | }, |
204 | { /* 2 */ | |
205 | .lib_handler_fn = message_handler_req_lib_quorum_trackstop, | |
56eaee95 | 206 | .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED |
e34d509d FDN |
207 | }, |
208 | { /* 3 */ | |
209 | .lib_handler_fn = message_handler_req_lib_quorum_gettype, | |
210 | .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED | |
4eb36297 JF |
211 | }, |
212 | { /* 4 */ | |
213 | .lib_handler_fn = message_handler_req_lib_quorum_model_gettype, | |
214 | .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED | |
5bb7ca5d CC |
215 | } |
216 | }; | |
217 | ||
218 | static struct corosync_service_engine quorum_service_handler = { | |
219 | .name = "corosync cluster quorum service v0.1", | |
220 | .id = QUORUM_SERVICE, | |
9fa83dab | 221 | .priority = 1, |
5bb7ca5d | 222 | .private_data_size = sizeof (struct quorum_pd), |
56eaee95 AS |
223 | .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED, |
224 | .allow_inquorate = CS_LIB_ALLOW_INQUORATE, | |
5bb7ca5d CC |
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, | |
4eb36297 JF |
229 | .sync_init = quorum_sync_init, |
230 | .sync_process = quorum_sync_process, | |
231 | .sync_activate = quorum_sync_activate, | |
232 | .sync_abort = quorum_sync_abort, | |
8f6e5ff5 | 233 | .lib_engine_count = sizeof (quorum_lib_service) / sizeof (struct corosync_lib_handler) |
5bb7ca5d CC |
234 | }; |
235 | ||
e423e43b | 236 | struct corosync_service_engine *vsf_quorum_get_service_engine_ver0 (void) |
5bb7ca5d CC |
237 | { |
238 | return (&quorum_service_handler); | |
239 | } | |
240 | ||
5bb7ca5d CC |
241 | /* -------------------------------------------------- */ |
242 | ||
cfc7da35 CC |
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; | |
b4c06e52 | 262 | qb_list_add (&pd->list, &internal_trackers_list); |
cfc7da35 CC |
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; | |
1f90c31b | 270 | struct qb_list_head *tmp, *tmp_iter; |
cfc7da35 | 271 | |
1f90c31b | 272 | qb_list_for_each_safe(tmp, tmp_iter, &internal_trackers_list) { |
b4c06e52 | 273 | pd = qb_list_entry(tmp, struct internal_callback_pd, list); |
cfc7da35 | 274 | if (pd->callback == function && pd->context == context) { |
b4c06e52 | 275 | qb_list_del(&pd->list); |
fa71067a | 276 | free(pd); |
cfc7da35 CC |
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 | ||
4eb36297 JF |
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 | ||
007e5c94 | 419 | static char *quorum_exec_init_fn (struct corosync_api_v1 *api) |
5bb7ca5d | 420 | { |
de914ca7 | 421 | char *quorum_module = NULL; |
007e5c94 | 422 | char *error; |
e423e43b | 423 | |
5bb7ca5d | 424 | corosync_api = api; |
b4c06e52 MJ |
425 | qb_list_init (&lib_trackers_list); |
426 | qb_list_init (&internal_trackers_list); | |
cfc7da35 CC |
427 | |
428 | /* | |
429 | * Tell corosync we have a quorum engine. | |
430 | */ | |
12754324 | 431 | api->quorum_initialize(&callins); |
cfc7da35 CC |
432 | |
433 | /* | |
434 | * Look for a quorum provider | |
435 | */ | |
8a45e2b1 | 436 | if (icmap_get_string("quorum.provider", &quorum_module) == CS_OK) { |
8a45e2b1 | 437 | log_printf (LOGSYS_LEVEL_NOTICE, |
3131601c | 438 | "Using quorum provider %s", quorum_module); |
94b11502 | 439 | |
007e5c94 SD |
440 | error = (char *)"Invalid quorum provider"; |
441 | ||
e423e43b | 442 | if (strcmp (quorum_module, "corosync_votequorum") == 0) { |
007e5c94 SD |
443 | error = votequorum_init (api, quorum_api_set_quorum); |
444 | quorum_type = 1; | |
e423e43b | 445 | } |
0e2f0b87 | 446 | if (strcmp (quorum_module, "corosync_ykd") == 0) { |
007e5c94 SD |
447 | error = ykd_init (api, quorum_api_set_quorum); |
448 | quorum_type = 1; | |
0e2f0b87 | 449 | } |
007e5c94 | 450 | if (error) { |
78edc1f2 | 451 | log_printf (LOGSYS_LEVEL_CRIT, |
007e5c94 SD |
452 | "Quorum provider: %s failed to initialize.", |
453 | quorum_module); | |
939a7b2d | 454 | free(quorum_module); |
007e5c94 | 455 | return (error); |
78edc1f2 | 456 | } |
cfc7da35 | 457 | } |
e423e43b | 458 | |
de914ca7 FDN |
459 | if (quorum_module) { |
460 | free(quorum_module); | |
461 | quorum_module = NULL; | |
462 | } | |
463 | ||
e423e43b SD |
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) { | |
795e573c CC |
470 | primary_designated = 1; |
471 | } | |
cfc7da35 | 472 | |
007e5c94 | 473 | return (NULL); |
5bb7ca5d CC |
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 | ||
3131601c | 480 | log_printf(LOGSYS_LEVEL_DEBUG, "lib_init_fn: conn=%p", conn); |
5bb7ca5d | 481 | |
b4c06e52 | 482 | qb_list_init (&pd->list); |
5bb7ca5d | 483 | pd->conn = conn; |
4eb36297 | 484 | pd->model = LIB_QUORUM_MODEL_V0; |
5bb7ca5d CC |
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 | ||
3131601c | 493 | log_printf(LOGSYS_LEVEL_DEBUG, "lib_exit_fn: conn=%p", conn); |
5bb7ca5d CC |
494 | |
495 | if (quorum_pd->tracking_enabled) { | |
b4c06e52 MJ |
496 | qb_list_del (&quorum_pd->list); |
497 | qb_list_init (&quorum_pd->list); | |
5bb7ca5d CC |
498 | } |
499 | return (0); | |
500 | } | |
501 | ||
cfc7da35 CC |
502 | |
503 | static void send_internal_notification(void) | |
504 | { | |
b4c06e52 | 505 | struct qb_list_head *tmp; |
cfc7da35 | 506 | struct internal_callback_pd *pd; |
1f90c31b JF |
507 | |
508 | qb_list_for_each(tmp, &internal_trackers_list) { | |
b4c06e52 | 509 | pd = qb_list_entry(tmp, struct internal_callback_pd, list); |
cfc7da35 CC |
510 | |
511 | pd->callback(primary_designated, pd->context); | |
512 | } | |
513 | } | |
514 | ||
4eb36297 | 515 | static void prepare_library_notification_v0(char *buf, size_t size) |
5bb7ca5d | 516 | { |
5bb7ca5d | 517 | struct res_lib_quorum_notification *res_lib_quorum_notification = (struct res_lib_quorum_notification *)buf; |
5bb7ca5d CC |
518 | int i; |
519 | ||
5bb7ca5d CC |
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; | |
56eaee95 | 529 | res_lib_quorum_notification->header.error = CS_OK; |
4eb36297 JF |
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); | |
5bb7ca5d CC |
573 | |
574 | /* Send it to all interested parties */ | |
575 | if (conn) { | |
4eb36297 JF |
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 | } | |
5bb7ca5d CC |
583 | } |
584 | else { | |
4eb36297 JF |
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 | } | |
5bb7ca5d | 635 | |
4eb36297 JF |
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 { | |
1f90c31b | 661 | qb_list_for_each(tmp, &lib_trackers_list) { |
b4c06e52 | 662 | qpd = qb_list_entry(tmp, struct quorum_pd, list); |
5bb7ca5d | 663 | |
4eb36297 JF |
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 | } | |
5bb7ca5d CC |
668 | } |
669 | } | |
4eb36297 | 670 | |
cfc7da35 | 671 | return; |
5bb7ca5d CC |
672 | } |
673 | ||
e0021727 JM |
674 | static void message_handler_req_lib_quorum_getquorate (void *conn, |
675 | const void *msg) | |
5bb7ca5d CC |
676 | { |
677 | struct res_lib_quorum_getquorate res_lib_quorum_getquorate; | |
678 | ||
3131601c | 679 | log_printf(LOGSYS_LEVEL_DEBUG, "got quorate request on %p", conn); |
5bb7ca5d CC |
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; | |
56eaee95 | 685 | res_lib_quorum_getquorate.header.error = CS_OK; |
c0772557 | 686 | corosync_api->ipc_response_send(conn, &res_lib_quorum_getquorate, sizeof(res_lib_quorum_getquorate)); |
5bb7ca5d CC |
687 | } |
688 | ||
e0021727 JM |
689 | static void message_handler_req_lib_quorum_trackstart (void *conn, |
690 | const void *msg) | |
5bb7ca5d | 691 | { |
e0021727 | 692 | const struct req_lib_quorum_trackstart *req_lib_quorum_trackstart = msg; |
c6895faa | 693 | struct qb_ipc_response_header res; |
5bb7ca5d | 694 | struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn); |
82526d2f | 695 | cs_error_t error = CS_OK; |
5bb7ca5d | 696 | |
3131601c | 697 | log_printf(LOGSYS_LEVEL_DEBUG, "got trackstart request on %p", conn); |
5bb7ca5d CC |
698 | |
699 | /* | |
700 | * If an immediate listing of the current cluster membership | |
701 | * is requested, generate membership list | |
702 | */ | |
56eaee95 AS |
703 | if (req_lib_quorum_trackstart->track_flags & CS_TRACK_CURRENT || |
704 | req_lib_quorum_trackstart->track_flags & CS_TRACK_CHANGES) { | |
3131601c | 705 | log_printf(LOGSYS_LEVEL_DEBUG, "sending initial status to %p", conn); |
4eb36297 | 706 | send_nodelist_library_notification(conn, 0); |
c0772557 | 707 | send_library_notification(conn); |
5bb7ca5d CC |
708 | } |
709 | ||
82526d2f CC |
710 | if (quorum_pd->tracking_enabled) { |
711 | error = CS_ERR_EXIST; | |
712 | goto response_send; | |
713 | } | |
714 | ||
5bb7ca5d CC |
715 | /* |
716 | * Record requests for tracking | |
717 | */ | |
56eaee95 AS |
718 | if (req_lib_quorum_trackstart->track_flags & CS_TRACK_CHANGES || |
719 | req_lib_quorum_trackstart->track_flags & CS_TRACK_CHANGES_ONLY) { | |
5bb7ca5d CC |
720 | |
721 | quorum_pd->track_flags = req_lib_quorum_trackstart->track_flags; | |
722 | quorum_pd->tracking_enabled = 1; | |
723 | ||
b4c06e52 | 724 | qb_list_add (&quorum_pd->list, &lib_trackers_list); |
5bb7ca5d CC |
725 | } |
726 | ||
82526d2f | 727 | response_send: |
5bb7ca5d CC |
728 | /* send status */ |
729 | res.size = sizeof(res); | |
730 | res.id = MESSAGE_RES_QUORUM_TRACKSTART; | |
82526d2f | 731 | res.error = error; |
c6895faa | 732 | corosync_api->ipc_response_send(conn, &res, sizeof(struct qb_ipc_response_header)); |
5bb7ca5d CC |
733 | } |
734 | ||
e0021727 | 735 | static void message_handler_req_lib_quorum_trackstop (void *conn, const void *msg) |
5bb7ca5d | 736 | { |
c6895faa | 737 | struct qb_ipc_response_header res; |
5bb7ca5d CC |
738 | struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn); |
739 | ||
3131601c | 740 | log_printf(LOGSYS_LEVEL_DEBUG, "got trackstop request on %p", conn); |
5bb7ca5d CC |
741 | |
742 | if (quorum_pd->tracking_enabled) { | |
56eaee95 | 743 | res.error = CS_OK; |
5bb7ca5d | 744 | quorum_pd->tracking_enabled = 0; |
b4c06e52 MJ |
745 | qb_list_del (&quorum_pd->list); |
746 | qb_list_init (&quorum_pd->list); | |
5bb7ca5d | 747 | } else { |
56eaee95 | 748 | res.error = CS_ERR_NOT_EXIST; |
5bb7ca5d CC |
749 | } |
750 | ||
751 | /* send status */ | |
752 | res.size = sizeof(res); | |
753 | res.id = MESSAGE_RES_QUORUM_TRACKSTOP; | |
56eaee95 | 754 | res.error = CS_OK; |
c6895faa | 755 | corosync_api->ipc_response_send(conn, &res, sizeof(struct qb_ipc_response_header)); |
5bb7ca5d | 756 | } |
e34d509d FDN |
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 | ||
3131601c | 763 | log_printf(LOGSYS_LEVEL_DEBUG, "got quorum_type request on %p", conn); |
e34d509d FDN |
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 | ||
4eb36297 JF |
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 | } |