corosync 3.1.10
sam.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009-2011 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@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 the 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/*
36 * Provides a SAM API
37 */
38
39#include <config.h>
40
41#include <limits.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#include <sys/time.h>
46#include <sys/types.h>
47#include <sys/socket.h>
48#include <errno.h>
49#include <poll.h>
50
51#include <corosync/corotypes.h>
52#include <qb/qbipcc.h>
53#include <corosync/corodefs.h>
54#include <corosync/cmap.h>
55#include <corosync/hdb.h>
56#include <corosync/quorum.h>
57
58#include <corosync/sam.h>
59
60#include "util.h"
61
62#include <stdio.h>
63#include <sys/wait.h>
64#include <signal.h>
65
66#define SAM_CMAP_S_FAILED "failed"
67#define SAM_CMAP_S_REGISTERED "stopped"
68#define SAM_CMAP_S_STARTED "running"
69#define SAM_CMAP_S_Q_WAIT "waiting for quorum"
70
71#define SAM_RP_MASK_Q(pol) (pol & (~SAM_RECOVERY_POLICY_QUORUM))
72#define SAM_RP_MASK_C(pol) (pol & (~SAM_RECOVERY_POLICY_CMAP))
73#define SAM_RP_MASK(pol) (pol & (~(SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_CMAP)))
74
82
91
96
103
110
111static struct {
115 unsigned int instance_id;
121
123 pthread_t cb_thread;
126
130
131 pthread_mutex_t lock;
132
134 uint32_t quorate;
136
139} sam_internal_data = {
140 .lock = PTHREAD_MUTEX_INITIALIZER
141};
142
143static cs_error_t sam_cmap_update_key (enum sam_cmap_key_t key, const char *value)
144{
145 cs_error_t err;
146 const char *svalue;
147 uint64_t hc_period, last_hc;
148
149 const char *ssvalue[] = { [SAM_RECOVERY_POLICY_QUIT] = "quit", [SAM_RECOVERY_POLICY_RESTART] = "restart" };
150 char key_name[CMAP_KEYNAME_MAXLEN];
151
152 switch (key) {
154 svalue = ssvalue[SAM_RP_MASK (sam_internal_data.recovery_policy)];
155
156 if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
157 "recovery") >= CMAP_KEYNAME_MAXLEN) {
158
160 goto exit_error;
161 }
162
163 if ((err = cmap_set_string(sam_internal_data.cmap_handle, key_name, svalue)) != CS_OK) {
164 goto exit_error;
165 }
166 break;
168 hc_period = sam_internal_data.time_interval;
169
170 if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
171 "poll_period") >= CMAP_KEYNAME_MAXLEN) {
172
174 goto exit_error;
175 }
176
177 if ((err = cmap_set_uint64(sam_internal_data.cmap_handle, key_name, hc_period)) != CS_OK) {
178 goto exit_error;
179 }
180 break;
182 last_hc = cs_timestamp_get();
183
184 if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
185 "last_updated") >= CMAP_KEYNAME_MAXLEN) {
186
188 goto exit_error;
189 }
190 if ((err = cmap_set_uint64(sam_internal_data.cmap_handle, key_name, last_hc)) != CS_OK) {
191 goto exit_error;
192 }
193 break;
195 svalue = value;
196 if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
197 "state") >= CMAP_KEYNAME_MAXLEN) {
198
200 goto exit_error;
201 }
202
203 if ((err = cmap_set_string(sam_internal_data.cmap_handle, key_name, svalue)) != CS_OK) {
204 goto exit_error;
205 }
206 break;
207 }
208
209 return (CS_OK);
210
211exit_error:
212 return (err);
213}
214
215static cs_error_t sam_cmap_destroy_pid_path (void)
216{
218 cs_error_t err;
219 char key_name[CMAP_KEYNAME_MAXLEN + 1];
220
221 err = cmap_iter_init(sam_internal_data.cmap_handle, sam_internal_data.cmap_pid_path, &iter);
222 if (err != CS_OK) {
223 goto error_exit;
224 }
225
226 while ((err = cmap_iter_next(sam_internal_data.cmap_handle, iter, key_name, NULL, NULL)) == CS_OK) {
227 cmap_delete(sam_internal_data.cmap_handle, key_name);
228 }
229
230 err = cmap_iter_finalize(sam_internal_data.cmap_handle, iter);
231
232error_exit:
233 return (err);
234}
235
236static cs_error_t sam_cmap_register (void)
237{
238 cs_error_t err;
240
241 if ((err = cmap_initialize (&cmap_handle)) != CS_OK) {
242 return (err);
243 }
244
245 snprintf(sam_internal_data.cmap_pid_path, CMAP_KEYNAME_MAXLEN, "resources.process.%d.", getpid());
246
247 sam_internal_data.cmap_handle = cmap_handle;
248
249 if ((err = sam_cmap_update_key (SAM_CMAP_KEY_RECOVERY, NULL)) != CS_OK) {
250 goto destroy_finalize_error;
251 }
252
253 if ((err = sam_cmap_update_key (SAM_CMAP_KEY_HC_PERIOD, NULL)) != CS_OK) {
254 goto destroy_finalize_error;
255 }
256
257 return (CS_OK);
258
259destroy_finalize_error:
260 sam_cmap_destroy_pid_path ();
262 return (err);
263}
264
265static void quorum_notification_fn (
266 quorum_handle_t handle,
267 uint32_t quorate,
268 uint64_t ring_id,
269 uint32_t view_list_entries,
270 uint32_t *view_list)
271{
272
273 sam_internal_data.quorate = quorate;
274}
275
277 int time_interval,
279{
280 quorum_callbacks_t quorum_callbacks;
281 uint32_t quorum_type;
282 cs_error_t ret;
283
284 ret = CS_OK;
285
288 return (CS_ERR_INVALID_PARAM);
289 }
290
291 pthread_mutex_lock (&sam_internal_data.lock);
292
293 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_NOT_INITIALIZED) {
294 ret = CS_ERR_BAD_HANDLE;
295 goto exit_mutex_unlock;
296 }
297
299 /*
300 * Initialize quorum
301 */
302 quorum_callbacks.quorum_notify_fn = quorum_notification_fn;
303 if ((ret = quorum_initialize (&sam_internal_data.quorum_handle, &quorum_callbacks, &quorum_type)) != CS_OK) {
304 goto exit_mutex_unlock;
305 }
306
307 if ((ret = quorum_trackstart (sam_internal_data.quorum_handle, CS_TRACK_CHANGES)) != CS_OK) {
308 goto exit_error_quorum;
309 }
310
311 if ((ret = quorum_fd_get (sam_internal_data.quorum_handle, &sam_internal_data.quorum_fd)) != CS_OK) {
312 goto exit_error_quorum;
313 }
314
315 /*
316 * Dispatch initial quorate state
317 */
318 if ((ret = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
319 goto exit_error_quorum;
320 }
321 }
322 sam_internal_data.recovery_policy = recovery_policy;
323
324 sam_internal_data.time_interval = time_interval;
325
326 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_INITIALIZED;
327
328 sam_internal_data.warn_signal = SIGTERM;
329
330 sam_internal_data.am_i_child = 0;
331
332 sam_internal_data.user_data = NULL;
333 sam_internal_data.user_data_size = 0;
334 sam_internal_data.user_data_allocated = 0;
335
336 pthread_mutex_unlock (&sam_internal_data.lock);
337
338 return (CS_OK);
339
340exit_error_quorum:
341 quorum_finalize (sam_internal_data.quorum_handle);
342
343exit_mutex_unlock:
344 pthread_mutex_unlock (&sam_internal_data.lock);
345
346 return (ret);
347}
348
349/*
350 * Wrapper on top of write(2) function. It handles EAGAIN and EINTR states and sends whole buffer if possible.
351 */
352static size_t sam_safe_write (
353 int d,
354 const void *buf,
355 size_t nbyte)
356{
357 ssize_t bytes_write;
358 ssize_t tmp_bytes_write;
359
360 bytes_write = 0;
361
362 do {
363 tmp_bytes_write = write (d, (const char *)buf + bytes_write,
364 (nbyte - bytes_write > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_write);
365
366 if (tmp_bytes_write == -1) {
367 if (!(errno == EAGAIN || errno == EINTR))
368 return -1;
369 } else {
370 bytes_write += tmp_bytes_write;
371 }
372 } while (bytes_write != nbyte);
373
374 return (bytes_write);
375}
376
377/*
378 * Wrapper on top of read(2) function. It handles EAGAIN and EINTR states and reads whole buffer if possible.
379 */
380static size_t sam_safe_read (
381 int d,
382 void *buf,
383 size_t nbyte)
384{
385 ssize_t bytes_read;
386 ssize_t tmp_bytes_read;
387
388 bytes_read = 0;
389
390 do {
391 tmp_bytes_read = read (d, (char *)buf + bytes_read,
392 (nbyte - bytes_read > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_read);
393
394 if (tmp_bytes_read == -1) {
395 if (!(errno == EAGAIN || errno == EINTR))
396 return -1;
397 } else {
398 bytes_read += tmp_bytes_read;
399 }
400
401 } while (bytes_read != nbyte && tmp_bytes_read != 0);
402
403 return (bytes_read);
404}
405
406static cs_error_t sam_read_reply (
407 int child_fd_in)
408{
409 char reply;
410 cs_error_t err;
411
412 if (sam_safe_read (sam_internal_data.child_fd_in, &reply, sizeof (reply)) != sizeof (reply)) {
413 return (CS_ERR_LIBRARY);
414 }
415
416 switch (reply) {
417 case SAM_REPLY_ERROR:
418 /*
419 * Read error and return that
420 */
421 if (sam_safe_read (sam_internal_data.child_fd_in, &err, sizeof (err)) != sizeof (err)) {
422 return (CS_ERR_LIBRARY);
423 }
424
425 return (err);
426 break;
427 case SAM_REPLY_OK:
428 /*
429 * Everything correct
430 */
431 break;
432 default:
433 return (CS_ERR_LIBRARY);
434 break;
435 }
436
437 return (CS_OK);
438}
439
441{
442 cs_error_t ret;
443
444 ret = CS_OK;
445
446 if (size == NULL) {
447 return (CS_ERR_INVALID_PARAM);
448 }
449
450 pthread_mutex_lock (&sam_internal_data.lock);
451
452 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
453 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
454 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
455
456 ret = CS_ERR_BAD_HANDLE;
457 goto exit_mutex_unlock;
458 }
459
460
461 *size = sam_internal_data.user_data_size;
462
463exit_mutex_unlock:
464 pthread_mutex_unlock (&sam_internal_data.lock);
465
466 return (ret);
467}
468
470 void *data,
471 size_t size)
472{
473 cs_error_t ret;
474
475 ret = CS_OK;
476
477 if (data == NULL) {
478 return (CS_ERR_INVALID_PARAM);
479 }
480
481 pthread_mutex_lock (&sam_internal_data.lock);
482
483 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
484 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
485 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
486
487 ret = CS_ERR_BAD_HANDLE;
488 goto exit_mutex_unlock;
489 }
490
491
492 if (sam_internal_data.user_data_size == 0) {
493 ret = CS_OK;
494
495 goto exit_mutex_unlock;
496 }
497
498 if (size < sam_internal_data.user_data_size) {
500
501 goto exit_mutex_unlock;
502 }
503
504 memcpy (data, sam_internal_data.user_data, sam_internal_data.user_data_size);
505
506exit_mutex_unlock:
507 pthread_mutex_unlock (&sam_internal_data.lock);
508
509 return (ret);
510}
511
512static cs_error_t sam_data_store_nolock (
513 const void *data,
514 size_t size)
515{
516 cs_error_t err;
517 char command;
518 char *new_data;
519
520 if (size >= SSIZE_MAX) {
521 return (CS_ERR_TOO_BIG);
522 }
523
524 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
525 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
526 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
527 return (CS_ERR_BAD_HANDLE);
528 }
529
530 if (data == NULL) {
531 size = 0;
532 }
533
534 if (sam_internal_data.am_i_child) {
535 /*
536 * We are child so we must send data to parent
537 */
538 command = SAM_COMMAND_DATA_STORE;
539 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
540 return (CS_ERR_LIBRARY);
541 }
542
543 if (sam_safe_write (sam_internal_data.child_fd_out, &size, sizeof (size)) != sizeof (size)) {
544 return (CS_ERR_LIBRARY);
545 }
546
547 if (data != NULL && sam_safe_write (sam_internal_data.child_fd_out, data, size) != size) {
548 return (CS_ERR_LIBRARY);
549 }
550
551 /*
552 * And wait for reply
553 */
554 if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
555 return (err);
556 }
557 }
558
559 /*
560 * We are parent or we received OK reply from parent -> do required action
561 */
562 if (data == NULL) {
563 free (sam_internal_data.user_data);
564 sam_internal_data.user_data = NULL;
565 sam_internal_data.user_data_allocated = 0;
566 sam_internal_data.user_data_size = 0;
567 } else {
568 if (sam_internal_data.user_data_allocated < size) {
569 if ((new_data = realloc (sam_internal_data.user_data, size)) == NULL) {
570 return (CS_ERR_NO_MEMORY);
571 }
572
573 sam_internal_data.user_data_allocated = size;
574 } else {
575 new_data = sam_internal_data.user_data;
576 }
577 sam_internal_data.user_data = new_data;
578 sam_internal_data.user_data_size = size;
579
580 memcpy (sam_internal_data.user_data, data, size);
581 }
582
583 return (CS_OK);
584}
585
587 const void *data,
588 size_t size)
589{
590 cs_error_t ret;
591
592 pthread_mutex_lock (&sam_internal_data.lock);
593
594 ret = sam_data_store_nolock (data, size);
595
596 pthread_mutex_unlock (&sam_internal_data.lock);
597
598 return (ret);
599}
600
602{
603 char command;
604 cs_error_t ret;
606
607 ret = CS_OK;
608
609 pthread_mutex_lock (&sam_internal_data.lock);
610
611 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
612 ret = CS_ERR_BAD_HANDLE;
613 goto exit_mutex_unlock;
614 }
615
616 recpol = sam_internal_data.recovery_policy;
617
618 command = SAM_COMMAND_START;
619
620 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
621 ret = CS_ERR_LIBRARY;
622 goto exit_mutex_unlock;
623 }
624
625 if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) {
626 /*
627 * Wait for parent reply
628 */
629 if ((ret = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
630 goto exit_mutex_unlock;
631 }
632 }
633
634 if (sam_internal_data.hc_callback) {
635 if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command)) {
636 ret = CS_ERR_LIBRARY;
637 goto exit_mutex_unlock;
638 }
639 }
640
641 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED;
642
643exit_mutex_unlock:
644 pthread_mutex_unlock (&sam_internal_data.lock);
645
646 return (ret);
647}
648
649static cs_error_t sam_stop_nolock (void)
650{
651 char command;
652 cs_error_t cs_err;
653
654 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
655 return (CS_ERR_BAD_HANDLE);
656 }
657
658 command = SAM_COMMAND_STOP;
659
660 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
661 return (CS_ERR_LIBRARY);
662 }
663
664 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
665 /*
666 * Wait for parent reply
667 */
668 if ((cs_err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
669 return (cs_err);
670 }
671 }
672
673 if (sam_internal_data.hc_callback) {
674 if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command)) {
675 return (CS_ERR_LIBRARY);
676 }
677 }
678
679 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
680
681 return (CS_OK);
682}
683
685{
686 cs_error_t ret;
687
688 pthread_mutex_lock (&sam_internal_data.lock);
689
690 ret = sam_stop_nolock ();
691
692 pthread_mutex_unlock (&sam_internal_data.lock);
693
694 return (ret);
695}
696
698{
699 char command;
700 cs_error_t ret;
701
702 ret = CS_OK;
703
704 pthread_mutex_lock (&sam_internal_data.lock);
705
706 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
707 ret = CS_ERR_BAD_HANDLE;
708 goto exit_mutex_unlock;
709 }
710
711 command = SAM_COMMAND_HB;
712
713 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
714 ret = CS_ERR_LIBRARY;
715 goto exit_mutex_unlock;
716 }
717
718exit_mutex_unlock:
719 pthread_mutex_unlock (&sam_internal_data.lock);
720
721 return (ret);
722}
723
725{
726 cs_error_t ret;
727
728 ret = CS_OK;
729
730 pthread_mutex_lock (&sam_internal_data.lock);
731
732 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
733 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
734 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
735 ret = CS_ERR_BAD_HANDLE;
736 goto exit_mutex_unlock;
737 }
738
739 if (sam_internal_data.internal_status == SAM_INTERNAL_STATUS_STARTED) {
740 ret = sam_stop_nolock ();
741 if (ret != CS_OK) {
742 goto exit_mutex_unlock;
743 }
744 }
745
746 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_FINALIZED;
747
748 free (sam_internal_data.user_data);
749 sam_internal_data.user_data = NULL;
750 sam_internal_data.user_data_allocated = 0;
751 sam_internal_data.user_data_size = 0;
752
753exit_mutex_unlock:
754 pthread_mutex_unlock (&sam_internal_data.lock);
755
756 return (ret);
757}
758
760{
761 char command;
762 cs_error_t ret;
763
764 ret = CS_OK;
765
766 pthread_mutex_lock (&sam_internal_data.lock);
767
768 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED &&
769 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
770 ret = CS_ERR_BAD_HANDLE;
771 goto exit_mutex_unlock;
772 }
773
774 if (!(sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP)) {
776 goto exit_mutex_unlock;
777 }
778
779 command = SAM_COMMAND_MARK_FAILED;
780
781 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
782 ret = CS_ERR_LIBRARY;
783 goto exit_mutex_unlock;
784 }
785
786exit_mutex_unlock:
787 pthread_mutex_unlock (&sam_internal_data.lock);
788
789 return (ret);
790}
791
792static cs_error_t sam_warn_signal_set_nolock (int warn_signal)
793{
794 char command;
795 cs_error_t err;
796
797 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
798 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
799 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
800 return (CS_ERR_BAD_HANDLE);
801 }
802
803 if (sam_internal_data.am_i_child) {
804 /*
805 * We are child so we must send data to parent
806 */
808 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
809 return (CS_ERR_BAD_HANDLE);
810 }
811
812 if (sam_safe_write (sam_internal_data.child_fd_out, &warn_signal, sizeof (warn_signal)) !=
813 sizeof (warn_signal)) {
814 return (CS_ERR_LIBRARY);
815 }
816
817 /*
818 * And wait for reply
819 */
820 if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
821 return (err);
822 }
823 }
824
825 /*
826 * We are parent or we received OK reply from parent -> do required action
827 */
828 sam_internal_data.warn_signal = warn_signal;
829
830 return (CS_OK);
831}
832
834{
835 cs_error_t ret;
836
837 pthread_mutex_lock (&sam_internal_data.lock);
838
839 ret = sam_warn_signal_set_nolock (warn_signal);
840
841 pthread_mutex_unlock (&sam_internal_data.lock);
842
843 return (ret);
844}
845
846static cs_error_t sam_parent_reply_send (
847 cs_error_t err,
848 int parent_fd_in,
849 int parent_fd_out)
850{
851 char reply;
852
853 if (err == CS_OK) {
854 reply = SAM_REPLY_OK;
855
856 if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
857 err = CS_ERR_LIBRARY;
858 goto error_reply;
859 }
860
861 return (CS_OK);
862 }
863
864error_reply:
865 reply = SAM_REPLY_ERROR;
866 if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
867 return (CS_ERR_LIBRARY);
868 }
869 if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) {
870 return (CS_ERR_LIBRARY);
871 }
872
873 return (err);
874}
875
876
877static cs_error_t sam_parent_warn_signal_set (
878 int parent_fd_in,
879 int parent_fd_out)
880{
881 int warn_signal;
882 cs_error_t err;
883
884 err = CS_OK;
885
886 if (sam_safe_read (parent_fd_in, &warn_signal, sizeof (warn_signal)) != sizeof (warn_signal)) {
887 err = CS_ERR_LIBRARY;
888 goto error_reply;
889 }
890
891 err = sam_warn_signal_set_nolock (warn_signal);
892 if (err != CS_OK) {
893 goto error_reply;
894 }
895
896
897 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
898
899error_reply:
900 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
901}
902
903static cs_error_t sam_parent_wait_for_quorum (
904 int parent_fd_in,
905 int parent_fd_out)
906{
907 cs_error_t err;
908 struct pollfd pfds[2];
909 int poll_err;
910
911 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
912 if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_Q_WAIT)) != CS_OK) {
913 goto error_reply;
914 }
915 }
916
917 /*
918 * Update current quorum
919 */
920 if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL)) != CS_OK) {
921 goto error_reply;
922 }
923
924 /*
925 * Wait for quorum
926 */
927 while (!sam_internal_data.quorate) {
928 pfds[0].fd = parent_fd_in;
929 pfds[0].events = 0;
930 pfds[0].revents = 0;
931
932 pfds[1].fd = sam_internal_data.quorum_fd;
933 pfds[1].events = POLLIN;
934 pfds[1].revents = 0;
935
936 poll_err = poll (pfds, 2, -1);
937
938 if (poll_err == -1) {
939 /*
940 * Error in poll
941 * If it is EINTR, continue, otherwise QUIT
942 */
943 if (errno != EINTR) {
944 err = CS_ERR_LIBRARY;
945 goto error_reply;
946 }
947 }
948
949 if (pfds[0].revents != 0) {
950 if (pfds[0].revents == POLLERR || pfds[0].revents == POLLHUP ||pfds[0].revents == POLLNVAL) {
951 /*
952 * Child has exited
953 */
954 return (CS_OK);
955 }
956 }
957
958 if (pfds[1].revents != 0) {
959 if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
960 goto error_reply;
961 }
962 }
963 }
964
965 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
966 if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_STARTED)) != CS_OK) {
967 goto error_reply;
968 }
969 }
970
971 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
972
973error_reply:
974 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
975 sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_REGISTERED);
976 }
977
978 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
979}
980
981static cs_error_t sam_parent_cmap_state_set (
982 int parent_fd_in,
983 int parent_fd_out,
984 int state)
985{
986 cs_error_t err;
987 const char *state_s;
988
989 if (state == 1) {
990 state_s = SAM_CMAP_S_STARTED;
991 } else {
992 state_s = SAM_CMAP_S_REGISTERED;
993 }
994
995 if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, state_s)) != CS_OK) {
996 goto error_reply;
997 }
998
999 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
1000
1001error_reply:
1002 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
1003}
1004
1005static cs_error_t sam_parent_kill_child (
1006 int *action,
1007 pid_t child_pid)
1008{
1009 /*
1010 * Kill child process
1011 */
1012 if (!sam_internal_data.term_send) {
1013 /*
1014 * We didn't send warn_signal yet.
1015 */
1016 kill (child_pid, sam_internal_data.warn_signal);
1017
1018 sam_internal_data.term_send = 1;
1019 } else {
1020 /*
1021 * We sent child warning. Now, we will not be so nice
1022 */
1023 kill (child_pid, SIGKILL);
1025 }
1026
1027 return (CS_OK);
1028}
1029
1030static cs_error_t sam_parent_mark_child_failed (
1031 int *action,
1032 pid_t child_pid)
1033{
1034 sam_recovery_policy_t recpol;
1035
1036 recpol = sam_internal_data.recovery_policy;
1037
1038 sam_internal_data.term_send = 1;
1039 sam_internal_data.recovery_policy = SAM_RECOVERY_POLICY_QUIT |
1040 (SAM_RP_MASK_C (recpol) ? SAM_RECOVERY_POLICY_CMAP : 0) |
1042
1043 return (sam_parent_kill_child (action, child_pid));
1044}
1045
1046static cs_error_t sam_parent_data_store (
1047 int parent_fd_in,
1048 int parent_fd_out)
1049{
1050 char *user_data;
1051 ssize_t size;
1052 cs_error_t err;
1053
1054 err = CS_OK;
1055 user_data = NULL;
1056
1057 if (sam_safe_read (parent_fd_in, &size, sizeof (size)) != sizeof (size)) {
1058 err = CS_ERR_LIBRARY;
1059 goto error_reply;
1060 }
1061
1062 if (size >= SSIZE_MAX) {
1063 err = CS_ERR_TOO_BIG;
1064 goto error_reply;
1065 }
1066
1067 if (size > 0) {
1068 user_data = malloc (size);
1069 if (user_data == NULL) {
1070 err = CS_ERR_NO_MEMORY;
1071 goto error_reply;
1072 }
1073
1074 if (sam_safe_read (parent_fd_in, user_data, size) != size) {
1075 err = CS_ERR_LIBRARY;
1076 goto free_error_reply;
1077 }
1078 }
1079
1080 err = sam_data_store_nolock (user_data, size);
1081 if (err != CS_OK) {
1082 goto free_error_reply;
1083 }
1084
1085 free (user_data);
1086
1087 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
1088
1089free_error_reply:
1090 free (user_data);
1091error_reply:
1092 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
1093}
1094
1095static enum sam_parent_action_t sam_parent_handler (
1096 int parent_fd_in,
1097 int parent_fd_out,
1098 pid_t child_pid)
1099{
1100 int poll_error;
1101 int action;
1102 int status;
1103 ssize_t bytes_read;
1104 char command;
1105 int time_interval;
1106 struct pollfd pfds[2];
1107 nfds_t nfds;
1108 cs_error_t err;
1109 sam_recovery_policy_t recpol;
1110
1111 status = 0;
1112
1114 recpol = sam_internal_data.recovery_policy;
1115
1116 while (action == SAM_PARENT_ACTION_CONTINUE) {
1117 pfds[0].fd = parent_fd_in;
1118 pfds[0].events = POLLIN;
1119 pfds[0].revents = 0;
1120 nfds = 1;
1121
1122 if (status == 1 && sam_internal_data.time_interval != 0) {
1123 time_interval = sam_internal_data.time_interval;
1124 } else {
1125 time_interval = -1;
1126 }
1127
1128 if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
1129 pfds[nfds].fd = sam_internal_data.quorum_fd;
1130 pfds[nfds].events = POLLIN;
1131 pfds[nfds].revents = 0;
1132 nfds++;
1133 }
1134
1135 poll_error = poll (pfds, nfds, time_interval);
1136
1137 if (poll_error == -1) {
1138 /*
1139 * Error in poll
1140 * If it is EINTR, continue, otherwise QUIT
1141 */
1142 if (errno != EINTR) {
1143 action = SAM_PARENT_ACTION_ERROR;
1144 }
1145 }
1146
1147 if (poll_error == 0) {
1148 /*
1149 * Time limit expires
1150 */
1151 if (status == 0) {
1152 action = SAM_PARENT_ACTION_QUIT;
1153 } else {
1154 sam_parent_kill_child (&action, child_pid);
1155 }
1156 }
1157
1158 if (poll_error > 0) {
1159 if (pfds[0].revents != 0) {
1160 /*
1161 * We have EOF or command in pipe
1162 */
1163 bytes_read = sam_safe_read (parent_fd_in, &command, 1);
1164
1165 if (bytes_read == 0) {
1166 /*
1167 * Handle EOF -> Take recovery action or quit if sam_start wasn't called
1168 */
1169 if (status == 0)
1170 action = SAM_PARENT_ACTION_QUIT;
1171 else
1173
1174 continue;
1175 }
1176
1177 if (bytes_read == -1) {
1178 action = SAM_PARENT_ACTION_ERROR;
1179 goto action_exit;
1180 }
1181
1182 if (recpol & SAM_RECOVERY_POLICY_CMAP) {
1183 sam_cmap_update_key (SAM_CMAP_KEY_LAST_HC, NULL);
1184 }
1185
1186 /*
1187 * We have read command
1188 */
1189 switch (command) {
1190 case SAM_COMMAND_START:
1191 if (status == 0) {
1192 /*
1193 * Not started yet
1194 */
1195 if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
1196 if (sam_parent_wait_for_quorum (parent_fd_in,
1197 parent_fd_out) != CS_OK) {
1198 continue;
1199 }
1200 }
1201
1202 if (recpol & SAM_RECOVERY_POLICY_CMAP) {
1203 if (sam_parent_cmap_state_set (parent_fd_in,
1204 parent_fd_out, 1) != CS_OK) {
1205 continue;
1206 }
1207 }
1208
1209 status = 1;
1210 }
1211 break;
1212 case SAM_COMMAND_STOP:
1213 if (status == 1) {
1214 /*
1215 * Started
1216 */
1217 if (recpol & SAM_RECOVERY_POLICY_CMAP) {
1218 if (sam_parent_cmap_state_set (parent_fd_in,
1219 parent_fd_out, 0) != CS_OK) {
1220 continue;
1221 }
1222 }
1223
1224 status = 0;
1225 }
1226 break;
1228 sam_parent_data_store (parent_fd_in, parent_fd_out);
1229 break;
1231 sam_parent_warn_signal_set (parent_fd_in, parent_fd_out);
1232 break;
1234 status = 1;
1235 sam_parent_mark_child_failed (&action, child_pid);
1236 break;
1237 }
1238 } /* if (pfds[0].revents != 0) */
1239
1240 if ((sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) &&
1241 pfds[1].revents != 0) {
1242 /*
1243 * Handle quorum change
1244 */
1245 err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL);
1246
1247 if (status == 1 &&
1248 (!sam_internal_data.quorate || (err != CS_ERR_TRY_AGAIN && err != CS_OK))) {
1249 sam_parent_kill_child (&action, child_pid);
1250 }
1251 }
1252 } /* select_error > 0 */
1253 } /* action == SAM_PARENT_ACTION_CONTINUE */
1254
1255action_exit:
1256 return action;
1257}
1258
1260 unsigned int *instance_id)
1261{
1262 pid_t pid;
1263 int pipe_error;
1264 int pipe_fd_out[2], pipe_fd_in[2];
1265 enum sam_parent_action_t action, old_action;
1266 int child_status;
1267 sam_recovery_policy_t recpol;
1268 cs_error_t ret;
1269
1270 ret = CS_OK;
1271
1272 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED) {
1273 ret = CS_ERR_BAD_HANDLE;
1274 goto exit_error;
1275 }
1276
1277 recpol = sam_internal_data.recovery_policy;
1278
1279 if (recpol & SAM_RECOVERY_POLICY_CMAP) {
1280 /*
1281 * Register to cmap
1282 */
1283 if ((ret = sam_cmap_register ()) != CS_OK) {
1284 ret = CS_ERR_BAD_HANDLE;
1285 goto exit_error;
1286 }
1287 }
1288
1289 while (1) {
1290 if ((pipe_error = pipe (pipe_fd_out)) != 0) {
1291 ret = CS_ERR_LIBRARY;
1292 goto exit_error;
1293 }
1294
1295 if ((pipe_error = pipe (pipe_fd_in)) != 0) {
1296 close (pipe_fd_out[0]);
1297 close (pipe_fd_out[1]);
1298
1299 ret = CS_ERR_BAD_HANDLE;
1300 goto exit_error;
1301 }
1302
1303 if (recpol & SAM_RECOVERY_POLICY_CMAP) {
1304 if ((ret = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_REGISTERED)) != CS_OK) {
1305 goto exit_error;
1306 }
1307 }
1308
1309 sam_internal_data.instance_id++;
1310
1311 sam_internal_data.term_send = 0;
1312
1313 pid = fork ();
1314
1315 if (pid == -1) {
1316 /*
1317 * Fork error
1318 */
1319 sam_internal_data.instance_id--;
1320
1321 ret = CS_ERR_BAD_HANDLE;
1322 goto exit_error;
1323 }
1324
1325 if (pid == 0) {
1326 /*
1327 * Child process
1328 */
1329 close (pipe_fd_out[0]);
1330 close (pipe_fd_in[1]);
1331
1332 sam_internal_data.child_fd_out = pipe_fd_out[1];
1333 sam_internal_data.child_fd_in = pipe_fd_in[0];
1334
1335 if (instance_id)
1336 *instance_id = sam_internal_data.instance_id;
1337
1338 sam_internal_data.am_i_child = 1;
1339 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
1340
1341 goto exit_error;
1342 } else {
1343 /*
1344 * Parent process
1345 */
1346 close (pipe_fd_out[1]);
1347 close (pipe_fd_in[0]);
1348
1349 action = sam_parent_handler (pipe_fd_out[0], pipe_fd_in[1], pid);
1350
1351 close (pipe_fd_out[0]);
1352 close (pipe_fd_in[1]);
1353
1354 if (action == SAM_PARENT_ACTION_ERROR) {
1355 ret = CS_ERR_LIBRARY;
1356 goto exit_error;
1357 }
1358
1359 /*
1360 * We really don't like zombies
1361 */
1362 while (waitpid (pid, &child_status, 0) == -1 && errno == EINTR)
1363 ;
1364
1365 old_action = action;
1366
1367 if (action == SAM_PARENT_ACTION_RECOVERY) {
1368 if (SAM_RP_MASK (sam_internal_data.recovery_policy) == SAM_RECOVERY_POLICY_QUIT)
1369 action = SAM_PARENT_ACTION_QUIT;
1370 }
1371
1372
1373 if (action == SAM_PARENT_ACTION_QUIT) {
1374 if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
1375 quorum_finalize (sam_internal_data.quorum_handle);
1376 }
1377
1378 if (recpol & SAM_RECOVERY_POLICY_CMAP) {
1379 if (old_action == SAM_PARENT_ACTION_RECOVERY) {
1380 /*
1381 * Mark as failed
1382 */
1383 sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_FAILED);
1384 } else {
1385 sam_cmap_destroy_pid_path ();
1386 }
1387 }
1388
1389 exit (WEXITSTATUS (child_status));
1390 }
1391
1392
1393 }
1394 }
1395
1396exit_error:
1397 return (ret);
1398}
1399
1400static void *hc_callback_thread (void *unused_param)
1401{
1402 int poll_error;
1403 int status;
1404 ssize_t bytes_readed;
1405 char command;
1406 int time_interval, tmp_time_interval;
1407 int counter;
1408 struct pollfd pfds;
1409
1410 status = 0;
1411 counter = 0;
1412
1413 time_interval = sam_internal_data.time_interval >> 2;
1414
1415 while (1) {
1416 pfds.fd = sam_internal_data.cb_rpipe_fd;
1417 pfds.events = POLLIN;
1418 pfds.revents = 0;
1419
1420 if (status == 1) {
1421 tmp_time_interval = time_interval;
1422 } else {
1423 tmp_time_interval = -1;
1424 }
1425
1426 poll_error = poll (&pfds, 1, tmp_time_interval);
1427
1428 if (poll_error == 0) {
1429 if (sam_hc_send () == CS_OK) {
1430 counter++;
1431 }
1432
1433 if (counter >= 4) {
1434 if (sam_internal_data.hc_callback () != 0) {
1435 status = 3;
1436 }
1437
1438 counter = 0;
1439 }
1440 }
1441
1442 if (poll_error > 0) {
1443 bytes_readed = sam_safe_read (sam_internal_data.cb_rpipe_fd, &command, 1);
1444
1445 if (bytes_readed > 0) {
1446 if (status == 0 && command == SAM_COMMAND_START)
1447 status = 1;
1448
1449 if (status == 1 && command == SAM_COMMAND_STOP)
1450 status = 0;
1451
1452 }
1453 }
1454 }
1455
1456 /*
1457 * This makes compiler happy, it's same as return (NULL);
1458 */
1459 return (unused_param);
1460}
1461
1463{
1464 cs_error_t error = CS_OK;
1465 pthread_attr_t thread_attr;
1466 int pipe_error;
1467 int pipe_fd[2];
1468
1469 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
1470 return (CS_ERR_BAD_HANDLE);
1471 }
1472
1473 if (sam_internal_data.time_interval == 0) {
1474 return (CS_ERR_INVALID_PARAM);
1475 }
1476
1477 if (sam_internal_data.cb_registered) {
1478 sam_internal_data.hc_callback = cb;
1479
1480 return (CS_OK);
1481 }
1482
1483 /*
1484 * We know, this is first registration
1485 */
1486
1487 if (cb == NULL) {
1488 return (CS_ERR_INVALID_PARAM);
1489 }
1490
1491 pipe_error = pipe (pipe_fd);
1492
1493 if (pipe_error != 0) {
1494 /*
1495 * Pipe creation error
1496 */
1497 error = CS_ERR_LIBRARY;
1498 goto error_exit;
1499 }
1500
1501 sam_internal_data.cb_rpipe_fd = pipe_fd[0];
1502 sam_internal_data.cb_wpipe_fd = pipe_fd[1];
1503
1504 /*
1505 * Create thread attributes
1506 */
1507 error = pthread_attr_init (&thread_attr);
1508 if (error != 0) {
1509 error = CS_ERR_LIBRARY;
1510 goto error_close_fd_exit;
1511 }
1512
1513
1514 pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
1515 pthread_attr_setstacksize (&thread_attr, 32768);
1516
1517 /*
1518 * Create thread
1519 */
1520 error = pthread_create (&sam_internal_data.cb_thread, &thread_attr, hc_callback_thread, NULL);
1521
1522 if (error != 0) {
1523 error = CS_ERR_LIBRARY;
1524 goto error_attr_destroy_exit;
1525 }
1526
1527 /*
1528 * Cleanup
1529 */
1530 pthread_attr_destroy(&thread_attr);
1531
1532 sam_internal_data.cb_registered = 1;
1533 sam_internal_data.hc_callback = cb;
1534
1535 return (CS_OK);
1536
1537error_attr_destroy_exit:
1538 pthread_attr_destroy(&thread_attr);
1539error_close_fd_exit:
1540 sam_internal_data.cb_rpipe_fd = sam_internal_data.cb_wpipe_fd = 0;
1541 close (pipe_fd[0]);
1542 close (pipe_fd[1]);
1543error_exit:
1544 return (error);
1545}
@ CS_DISPATCH_ONE
Definition corotypes.h:85
@ CS_DISPATCH_ALL
Definition corotypes.h:86
#define CS_TRACK_CHANGES
Definition corotypes.h:92
cs_error_t
The cs_error_t enum.
Definition corotypes.h:98
@ CS_ERR_NAME_TOO_LONG
Definition corotypes.h:111
@ CS_ERR_NO_MEMORY
Definition corotypes.h:106
@ CS_ERR_BAD_HANDLE
Definition corotypes.h:107
@ CS_ERR_TRY_AGAIN
Definition corotypes.h:104
@ CS_OK
Definition corotypes.h:99
@ CS_ERR_INVALID_PARAM
Definition corotypes.h:105
@ CS_ERR_LIBRARY
Definition corotypes.h:100
@ CS_ERR_TOO_BIG
Definition corotypes.h:124
uint32_t value
uint64_t cmap_iter_handle_t
Definition cmap.h:59
cs_error_t cmap_finalize(cmap_handle_t handle)
Close the cmap handle.
Definition lib/cmap.c:173
#define CMAP_KEYNAME_MAXLEN
Definition cmap.h:69
cs_error_t cmap_iter_next(cmap_handle_t handle, cmap_iter_handle_t iter_handle, char key_name[], size_t *value_len, cmap_value_types_t *type)
Return next item in iterator iter.
Definition lib/cmap.c:878
uint64_t cmap_handle_t
Definition cmap.h:54
cs_error_t cmap_delete(cmap_handle_t handle, const char *key_name)
Deletes key from cmap database.
Definition lib/cmap.c:507
cs_error_t cmap_initialize(cmap_handle_t *handle)
Create a new cmap connection.
Definition lib/cmap.c:89
cs_error_t cmap_iter_finalize(cmap_handle_t handle, cmap_iter_handle_t iter_handle)
Finalize iterator.
Definition lib/cmap.c:938
cs_error_t cmap_iter_init(cmap_handle_t handle, const char *prefix, cmap_iter_handle_t *cmap_iter_handle)
Initialize iterator with given prefix.
Definition lib/cmap.c:823
cs_error_t cmap_set_string(cmap_handle_t handle, const char *key_name, const char *value)
Definition lib/cmap.c:497
cs_error_t cmap_set_uint64(cmap_handle_t handle, const char *key_name, uint64_t value)
Definition lib/cmap.c:482
uint64_t quorum_handle_t
quorum_handle_t
cs_error_t quorum_initialize(quorum_handle_t *handle, quorum_callbacks_t *callbacks, uint32_t *quorum_type)
Create a new quorum connection.
Definition lib/quorum.c:73
cs_error_t quorum_fd_get(quorum_handle_t handle, int *fd)
Get a file descriptor on which to poll.
Definition lib/quorum.c:279
cs_error_t quorum_trackstart(quorum_handle_t handle, unsigned int flags)
Track node and quorum changes.
Definition lib/quorum.c:338
cs_error_t quorum_finalize(quorum_handle_t handle)
Close the quorum handle.
Definition lib/quorum.c:209
cs_error_t quorum_dispatch(quorum_handle_t handle, cs_dispatch_flags_t dispatch_types)
Dispatch messages and configuration changes.
Definition lib/quorum.c:418
cs_error_t sam_warn_signal_set(int warn_signal)
Set warning signal to be sent.
Definition sam.c:833
pthread_mutex_t lock
Definition sam.c:131
void * user_data
Definition sam.c:127
#define SAM_CMAP_S_FAILED
Definition sam.c:66
cs_error_t sam_finalize(void)
Close the SAM handle.
Definition sam.c:724
#define SAM_RP_MASK(pol)
Definition sam.c:73
cs_error_t sam_hc_callback_register(sam_hc_callback_t cb)
Register healtcheck callback.
Definition sam.c:1462
int cb_wpipe_fd
Definition sam.c:124
#define SAM_CMAP_S_STARTED
Definition sam.c:68
#define SAM_CMAP_S_Q_WAIT
Definition sam.c:69
cs_error_t sam_data_store(const void *data, size_t size)
Store user data.
Definition sam.c:586
int time_interval
Definition sam.c:112
unsigned int instance_id
Definition sam.c:115
sam_command_t
Definition sam.c:83
@ SAM_COMMAND_MARK_FAILED
Definition sam.c:89
@ SAM_COMMAND_DATA_STORE
Definition sam.c:87
@ SAM_COMMAND_HB
Definition sam.c:86
@ SAM_COMMAND_WARN_SIGNAL_SET
Definition sam.c:88
@ SAM_COMMAND_START
Definition sam.c:84
@ SAM_COMMAND_STOP
Definition sam.c:85
sam_hc_callback_t hc_callback
Definition sam.c:122
sam_reply_t
Definition sam.c:92
@ SAM_REPLY_OK
Definition sam.c:93
@ SAM_REPLY_ERROR
Definition sam.c:94
quorum_handle_t quorum_handle
Definition sam.c:133
#define SAM_CMAP_S_REGISTERED
Definition sam.c:67
int child_fd_out
Definition sam.c:116
cs_error_t sam_mark_failed(void)
Marks child as failed.
Definition sam.c:759
#define SAM_RP_MASK_C(pol)
Definition sam.c:72
int quorum_fd
Definition sam.c:135
#define SAM_RP_MASK_Q(pol)
Definition sam.c:71
pthread_t cb_thread
Definition sam.c:123
cs_error_t sam_data_restore(void *data, size_t size)
Return stored data.
Definition sam.c:469
sam_recovery_policy_t recovery_policy
Definition sam.c:113
int cb_registered
Definition sam.c:125
enum sam_internal_status_t internal_status
Definition sam.c:114
int term_send
Definition sam.c:118
sam_cmap_key_t
Definition sam.c:104
@ SAM_CMAP_KEY_RECOVERY
Definition sam.c:105
@ SAM_CMAP_KEY_STATE
Definition sam.c:108
@ SAM_CMAP_KEY_HC_PERIOD
Definition sam.c:106
@ SAM_CMAP_KEY_LAST_HC
Definition sam.c:107
sam_internal_status_t
Definition sam.c:75
@ SAM_INTERNAL_STATUS_STARTED
Definition sam.c:79
@ SAM_INTERNAL_STATUS_NOT_INITIALIZED
Definition sam.c:76
@ SAM_INTERNAL_STATUS_FINALIZED
Definition sam.c:80
@ SAM_INTERNAL_STATUS_REGISTERED
Definition sam.c:78
@ SAM_INTERNAL_STATUS_INITIALIZED
Definition sam.c:77
cs_error_t sam_register(unsigned int *instance_id)
Register application.
Definition sam.c:1259
cs_error_t sam_data_getsize(size_t *size)
Return size of stored data.
Definition sam.c:440
int warn_signal
Definition sam.c:119
int cb_rpipe_fd
Definition sam.c:124
uint32_t quorate
Definition sam.c:134
cs_error_t sam_stop(void)
Stop healthchecking.
Definition sam.c:684
int child_fd_in
Definition sam.c:117
int am_i_child
Definition sam.c:120
cs_error_t sam_initialize(int time_interval, sam_recovery_policy_t recovery_policy)
Create a new SAM connection.
Definition sam.c:276
cs_error_t sam_hc_send(void)
Send healthcheck confirmation.
Definition sam.c:697
char cmap_pid_path[CMAP_KEYNAME_MAXLEN]
Definition sam.c:138
sam_parent_action_t
Definition sam.c:97
@ SAM_PARENT_ACTION_ERROR
Definition sam.c:98
@ SAM_PARENT_ACTION_QUIT
Definition sam.c:100
@ SAM_PARENT_ACTION_CONTINUE
Definition sam.c:101
@ SAM_PARENT_ACTION_RECOVERY
Definition sam.c:99
cs_error_t sam_start(void)
Start healthchecking.
Definition sam.c:601
cmap_handle_t cmap_handle
Definition sam.c:137
size_t user_data_size
Definition sam.c:128
size_t user_data_allocated
Definition sam.c:129
sam_recovery_policy_t
sam_recovery_policy_t enum
Definition sam.h:46
@ SAM_RECOVERY_POLICY_CMAP
Definition sam.h:52
@ SAM_RECOVERY_POLICY_QUORUM
Definition sam.h:49
@ SAM_RECOVERY_POLICY_QUIT
Definition sam.h:47
@ SAM_RECOVERY_POLICY_RESTART
Definition sam.h:48
int(* sam_hc_callback_t)(void)
Callback definition for event driven checking.
Definition sam.h:59
The quorum_callbacks_t struct.
quorum_notification_fn_t quorum_notify_fn
struct memb_ring_id ring_id
Definition totemsrp.c:4