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 
81 };
82 
90 };
91 
95 };
96 
102 };
103 
109 };
110 
111 static struct {
115  unsigned int instance_id;
121 
123  pthread_t cb_thread;
126 
127  void *user_data;
130 
131  pthread_mutex_t lock;
132 
134  uint32_t quorate;
136 
139 } sam_internal_data = {
140  .lock = PTHREAD_MUTEX_INITIALIZER
141 };
142 
143 static 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 
159  err = CS_ERR_NAME_TOO_LONG;
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 
173  err = CS_ERR_NAME_TOO_LONG;
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 
187  err = CS_ERR_NAME_TOO_LONG;
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;
194  case SAM_CMAP_KEY_STATE:
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 
199  err = CS_ERR_NAME_TOO_LONG;
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 
211 exit_error:
212  return (err);
213 }
214 
215 static cs_error_t sam_cmap_destroy_pid_path (void)
216 {
217  cmap_iter_handle_t iter;
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 
232 error_exit:
233  return (err);
234 }
235 
236 static 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 
259 destroy_finalize_error:
260  sam_cmap_destroy_pid_path ();
261  cmap_finalize (cmap_handle);
262  return (err);
263 }
264 
265 static 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 
286  if (SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_QUIT &&
287  SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_RESTART) {
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 
298  if (recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
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 
340 exit_error_quorum:
341  quorum_finalize (sam_internal_data.quorum_handle);
342 
343 exit_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  */
352 static 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  */
380 static 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 
406 static 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 
463 exit_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) {
499  ret = CS_ERR_INVALID_PARAM;
500 
501  goto exit_mutex_unlock;
502  }
503 
504  memcpy (data, sam_internal_data.user_data, sam_internal_data.user_data_size);
505 
506 exit_mutex_unlock:
507  pthread_mutex_unlock (&sam_internal_data.lock);
508 
509  return (ret);
510 }
511 
512 static 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;
605  sam_recovery_policy_t recpol;
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 
643 exit_mutex_unlock:
644  pthread_mutex_unlock (&sam_internal_data.lock);
645 
646  return (ret);
647 }
648 
649 static 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 
718 exit_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 
753 exit_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)) {
775  ret = CS_ERR_INVALID_PARAM;
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 
786 exit_mutex_unlock:
787  pthread_mutex_unlock (&sam_internal_data.lock);
788 
789  return (ret);
790 }
791 
792 static 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  */
807  command = SAM_COMMAND_WARN_SIGNAL_SET;
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 
846 static 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 
864 error_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 
877 static 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 
899 error_reply:
900  return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
901 }
902 
903 static 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 
973 error_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 
981 static 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 
1001 error_reply:
1002  return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
1003 }
1004 
1005 static 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);
1024  *action = SAM_PARENT_ACTION_RECOVERY;
1025  }
1026 
1027  return (CS_OK);
1028 }
1029 
1030 static 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) |
1041  (SAM_RP_MASK_Q (recpol) ? SAM_RECOVERY_POLICY_QUORUM : 0);
1042 
1043  return (sam_parent_kill_child (action, child_pid));
1044 }
1045 
1046 static 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 
1089 free_error_reply:
1090  free (user_data);
1091 error_reply:
1092  return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
1093 }
1094 
1095 static 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 
1113  action = SAM_PARENT_ACTION_CONTINUE;
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
1172  action = SAM_PARENT_ACTION_RECOVERY;
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 
1255 action_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 
1396 exit_error:
1397  return (ret);
1398 }
1399 
1400 static 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 
1537 error_attr_destroy_exit:
1538  pthread_attr_destroy(&thread_attr);
1539 error_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]);
1543 error_exit:
1544  return (error);
1545 }
cs_error_t cmap_set_uint64(cmap_handle_t handle, const char *key_name, uint64_t value)
Definition: lib/cmap.c:482
int child_fd_out
Definition: sam.c:116
int time_interval
Definition: sam.c:112
enum sam_internal_status_t internal_status
Definition: sam.c:114
uint32_t value
#define SAM_RP_MASK_Q(pol)
Definition: sam.c:71
#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
sam_hc_callback_t hc_callback
Definition: sam.c:122
unsigned int instance_id
Definition: sam.c:115
#define SAM_CMAP_S_STARTED
Definition: sam.c:68
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
int(* sam_hc_callback_t)(void)
Callback definition for event driven checking.
Definition: sam.h:59
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
int cb_registered
Definition: sam.c:125
cmap_handle_t cmap_handle
Definition: sam.c:137
cs_error_t cmap_initialize(cmap_handle_t *handle)
Create a new cmap connection.
Definition: lib/cmap.c:89
The quorum_callbacks_t struct.
int term_send
Definition: sam.c:118
cs_error_t sam_initialize(int time_interval, sam_recovery_policy_t recovery_policy)
Create a new SAM connection.
Definition: sam.c:276
quorum_handle_t quorum_handle
Definition: sam.c:133
#define CMAP_KEYNAME_MAXLEN
Definition: cmap.h:69
pthread_t cb_thread
Definition: sam.c:123
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
int am_i_child
Definition: sam.c:120
#define SAM_CMAP_S_REGISTERED
Definition: sam.c:67
cs_error_t sam_finalize(void)
Close the SAM handle.
Definition: sam.c:724
sam_recovery_policy_t recovery_policy
Definition: sam.c:113
cs_error_t cmap_iter_finalize(cmap_handle_t handle, cmap_iter_handle_t iter_handle)
Finalize iterator.
Definition: lib/cmap.c:938
#define CS_TRACK_CHANGES
Definition: corotypes.h:92
cs_error_t sam_register(unsigned int *instance_id)
Register application.
Definition: sam.c:1259
cs_error_t sam_hc_send(void)
Send healthcheck confirmation.
Definition: sam.c:697
#define SAM_CMAP_S_Q_WAIT
Definition: sam.c:69
size_t user_data_allocated
Definition: sam.c:129
sam_cmap_key_t
Definition: sam.c:104
cs_error_t sam_mark_failed(void)
Marks child as failed.
Definition: sam.c:759
pthread_mutex_t lock
Definition: sam.c:131
void * user_data
Definition: sam.c:127
char cmap_pid_path[CMAP_KEYNAME_MAXLEN]
Definition: sam.c:138
size_t user_data_size
Definition: sam.c:128
cs_error_t
The cs_error_t enum.
Definition: corotypes.h:98
sam_internal_status_t
Definition: sam.c:75
int cb_wpipe_fd
Definition: sam.c:124
cs_error_t sam_data_getsize(size_t *size)
Return size of stored data.
Definition: sam.c:440
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 sam_stop(void)
Stop healthchecking.
Definition: sam.c:684
uint32_t quorate
Definition: sam.c:134
uint64_t quorum_handle_t
quorum_handle_t
sam_reply_t
Definition: sam.c:92
cs_error_t sam_data_store(const void *data, size_t size)
Store user data.
Definition: sam.c:586
cs_error_t sam_warn_signal_set(int warn_signal)
Set warning signal to be sent.
Definition: sam.c:833
cs_error_t cmap_delete(cmap_handle_t handle, const char *key_name)
Deletes key from cmap database.
Definition: lib/cmap.c:507
int cb_rpipe_fd
Definition: sam.c:124
int warn_signal
Definition: sam.c:119
cs_error_t sam_data_restore(void *data, size_t size)
Return stored data.
Definition: sam.c:469
uint64_t cmap_iter_handle_t
Definition: cmap.h:59
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
quorum_notification_fn_t quorum_notify_fn
int child_fd_in
Definition: sam.c:117
sam_recovery_policy_t
sam_recovery_policy_t enum
Definition: sam.h:46
sam_command_t
Definition: sam.c:83
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 cmap_finalize(cmap_handle_t handle)
Close the cmap handle.
Definition: lib/cmap.c:173
int quorum_fd
Definition: sam.c:135
struct memb_ring_id ring_id
Definition: totemsrp.c:264
cs_error_t quorum_finalize(quorum_handle_t handle)
Close the quorum handle.
Definition: lib/quorum.c:209
#define SAM_CMAP_S_FAILED
Definition: sam.c:66
cs_error_t sam_start(void)
Start healthchecking.
Definition: sam.c:601
#define SAM_RP_MASK_C(pol)
Definition: sam.c:72
uint64_t cmap_handle_t
Definition: cmap.h:54
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
sam_parent_action_t
Definition: sam.c:97