diff --git a/configure.ac b/configure.ac index b57fdd2f..ad4b6c15 100644 --- a/configure.ac +++ b/configure.ac @@ -1,552 +1,588 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # bootstrap / init AC_PREREQ([2.61]) AC_INIT([corosync], [1.2.8], [openais@lists.osdl.org]) AM_INIT_AUTOMAKE([-Wno-portability]) AC_CONFIG_SRCDIR([lib/coroipcc.c]) AC_CONFIG_HEADER([include/corosync/config.h include/corosync/cs_config.h]) AC_CANONICAL_HOST AC_LANG([C]) # Define SVN revision AC_DEFINE([SVN_REVISION],["m4_esyscmd([svnversion >/dev/null 2>&1 && \ svnversion -n || \ echo -n exported])"], [SVN revision]) dnl Fix default variables - "prefix" variable if not specified if test "$prefix" = "NONE"; then prefix="/usr" dnl Fix "localstatedir" variable if not specified if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi dnl Fix "sysconfdir" variable if not specified if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi dnl Fix "libdir" variable if not specified if test "$libdir" = "\${exec_prefix}/lib"; then if test -e /usr/lib64; then libdir="/usr/lib64" else libdir="/usr/lib" fi fi fi if test "$srcdir" = "."; then AC_MSG_NOTICE([building in place srcdir:$srcdir]) AC_DEFINE([BUILDING_IN_PLACE], 1, [building in place]) else AC_MSG_NOTICE([building out of tree srcdir:$srcdir]) fi # Checks for programs. # check stolen from gnulib/m4/gnu-make.m4 if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then AC_MSG_ERROR([you don't seem to have GNU make; it is required]) fi sinclude(coroysync-default.m4) AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_RANLIB AC_CHECK_PROGS([GROFF], [groff]) AC_CHECK_PROGS([PKGCONFIG], [pkg-config]) AC_CHECK_PROGS([AUGTOOL], [augtool]) # Checks for libraries. AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([pthread], [pthread_create]) AC_CHECK_LIB([socket], [socket]) AC_CHECK_LIB([nsl], [t_open]) AC_CHECK_LIB([rt], [sched_getscheduler]) # Checks for header files. AC_FUNC_ALLOCA AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stdint.h \ stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h \ sys/time.h syslog.h unistd.h sys/types.h getopt.h malloc.h \ sys/sockio.h utmpx.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_UID_T AC_C_INLINE AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_INT8_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_HEADER_TIME AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T AC_C_VOLATILE # Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_FUNC_ERROR_AT_LINE AC_REPLACE_FNMATCH AC_FUNC_FORK AC_PROG_GCC_TRADITIONAL AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_REALLOC AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_FUNC_VPRINTF AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \ getcwd getpeerucred getpeereid gettimeofday inet_ntoa memmove \ memset mkdir scandir select socket strcasecmp strchr strdup \ strerror strrchr strspn strstr pthread_spin_lock \ pthread_spin_unlock pthread_setschedparam \ sched_get_priority_max sched_setscheduler]) AC_CONFIG_FILES([Makefile exec/Makefile include/Makefile init/Makefile lcr/Makefile lib/Makefile man/Makefile pkgconfig/Makefile services/Makefile test/Makefile cts/Makefile cts/agents/Makefile cts/CTSvars.py tools/Makefile]) ### Local business dnl =============================================== dnl Functions / global M4 variables dnl =============================================== dnl Global list of LIB names m4_define([local_soname_list], [])dnl dnl Upcase parameter m4_define([local_upcase], [translit([$*], [a-z], [A-Z])])dnl dnl M4 macro for include lib/lib$1.soname and subst that m4_define([LIB_SONAME_IMPORT],[dnl m4_define([local_libname], local_upcase($1)[_SONAME])dnl m4_define([local_soname], translit(m4_sinclude(lib/lib$1.verso), [ ], []))dnl local_libname="local_soname"dnl m4_define([local_soname_list], m4_defn([local_soname_list])[,]local_libname[,]local_upcase($1))dnl AC_SUBST(local_libname)dnl ])dnl dnl M4 macro for print padspaces (used in LIB_MSG_RESULT). It takes 2 arguments, length of string to pad and desired dnl (padded) length m4_define([m4_printpadspace],[ifelse(m4_eval([$2 - $1 < 1]),[1],,[ ][m4_printpadspace([$1],m4_eval([$2 - 1]))])])dnl dnl Show AC_MSG_RESULT for specific libraries m4_define([LIB_MSG_RESULT], [ifelse([$#], [1], ,[dnl AC_MSG_RESULT([ $2 Library SONAME m4_printpadspace(len($2),8) = ${$1}]) LIB_MSG_RESULT(m4_shift(m4_shift($@)))dnl ])])dnl # =============================================== # Helpers # =============================================== ## helper for CC stuff cc_supports_flag() { local CFLAGS="$@" AC_MSG_CHECKING([whether $CC supports "$@"]) AC_COMPILE_IFELSE([int main(){return 0;}] , [RC=0; AC_MSG_RESULT([yes])], [RC=1; AC_MSG_RESULT([no])]) return $RC } ## cleanup AC_MSG_NOTICE(Sanitizing prefix: ${prefix}) case $prefix in NONE) prefix=/usr/local;; esac AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix}) case $exec_prefix in dnl For consistency with Corosync, map NONE->$prefix NONE) exec_prefix=$prefix;; prefix) exec_prefix=$prefix;; esac ## local defines PACKAGE_FEATURES="" LINT_FLAGS="-weak -unrecog +posixlib +ignoresigns -fcnuse \ -badflag -D__gnuc_va_list=va_list -D__attribute\(x\)=" # default libraries SONAME SOMAJOR="4" SOMINOR="0" SOMICRO="0" SONAME="${SOMAJOR}.${SOMINOR}.${SOMICRO}" # specific libraries SONAME LIB_SONAME_IMPORT([cfg]) LIB_SONAME_IMPORT([confdb]) LIB_SONAME_IMPORT([cpg]) LIB_SONAME_IMPORT([evs]) LIB_SONAME_IMPORT([pload]) LIB_SONAME_IMPORT([quorum]) LIB_SONAME_IMPORT([sam]) LIB_SONAME_IMPORT([votequorum]) # local options AC_ARG_ENABLE([ansi], [ --enable-ansi : force to build with ANSI standards. ], [ default="no" ]) AC_ARG_ENABLE([fatal-warnings], [ --enable-fatal-warnings : enable fatal warnings. ], [ default="no" ]) AC_ARG_ENABLE([debug], [ --enable-debug : enable debug build. ], [ default="no" ]) AC_ARG_ENABLE([user-flags], [ --enable-user-flags : rely on user environment. ], [ default="no" ]) AC_ARG_ENABLE([coverage], [ --enable-coverage : coverage analysis of the codebase. ], [ default="no" ]) AC_ARG_ENABLE([small-memory-footprint], [ --enable-small-memory-footprint : Use small message queues and small messages sizes. ], [ default="no" ]) AC_ARG_ENABLE([nss], [ --enable-nss : Network Security Services encryption. ],, [ enable_nss="yes" ]) AC_ARG_ENABLE([testagents], [ --enable-testagents : Install Test Agents. ],, [ default="no" ]) AC_ARG_ENABLE([rdma], [ --enable-rdma : Infiniband RDMA transport support ],, [ enable_rdma="no" ]) AM_CONDITIONAL(BUILD_RDMA, test x$enable_rdma = xyes) +AC_ARG_ENABLE([monitoring], + [ --enable-monitoring : resource monitoring ],, + [ default="no" ]) +AM_CONDITIONAL(BUILD_MONITORING, test x$enable_monitoring = xyes) + +AC_ARG_ENABLE([watchdog], + [ --enable-watchdog : Watchdog support ],, + [ edefault="no" ]) +AM_CONDITIONAL(BUILD_WATCHDOG, test x$enable_watchdog = xyes) + AC_ARG_ENABLE([augeas], [ --enable-augeas : Install the augeas lens for corosync.conf ],, [ enable_augeas="no" ]) AM_CONDITIONAL(INSTALL_AUGEAS, test x$enable_augeas = xyes) AC_ARG_WITH([initddir], [ --with-initddir=DIR : path to init script directory. ], [ INITDDIR="$withval" ], [ INITDDIR="$sysconfdir/init.d" ]) AC_ARG_WITH([lcrso-dir], [ --with-lcrso-dir=DIR : corosync lcrso files. ], [ LCRSODIR="$withval" ], [ LCRSODIR="$libexecdir/lcrso" ]) AC_ARG_WITH([socket-dir], [ --with-socket-dir=DIR : corosync socket dir. ], [ SOCKETDIR="$withval" ], [ SOCKETDIR="$localstatedir/run" ]) # OS detection # THIS SECTION MUST DIE! CP=cp OS_LDL="-ldl" +have_linux="no" case "$host_os" in *linux*) AC_DEFINE_UNQUOTED([COROSYNC_LINUX], [1], [Compiling for Linux platform]) OS_CFLAGS="" OS_CPPFLAGS="-D_GNU_SOURCE" OS_LDFLAGS="" OS_DYFLAGS="-rdynamic" DARWIN_OPTS="" + have_linux="yes" ;; darwin*) AC_DEFINE_UNQUOTED([COROSYNC_DARWIN], [1], [Compiling for Darwin platform]) CP=rsync OS_CFLAGS="" OS_CPPFLAGS="" OS_LDFLAGS="" OS_DYFLAGS="" DARWIN_OPTS="-dynamiclib -bind_at_load \ -current_version ${SONAME} \ -compatibility_version ${SONAME} -install_name \$(libdir)/\$(@)" AC_DEFINE_UNQUOTED([MAP_ANONYMOUS], [MAP_ANON], [Shared memory define for Darwin platform]) AC_DEFINE_UNQUOTED([PATH_MAX], [4096], [Number of chars in a path name including nul]) AC_DEFINE_UNQUOTED([NAME_MAX], [255], [Number of chars in a file name]) ;; *bsd*) AC_DEFINE_UNQUOTED([COROSYNC_BSD], [1], [Compiling for BSD platform]) AC_DEFINE_UNQUOTED([MAP_ANONYMOUS], [MAP_ANON], [Shared memory define for Darwin platform]) OS_CFLAGS="" OS_CPPFLAGS="-I/usr/local/include" OS_LDFLAGS="-L/usr/local/lib" OS_DYFLAGS="-export-dynamic" DARWIN_OPTS="" OS_LDL="" case "$host_os" in *freebsd[[234567]]*) ;; *freebsd*) AC_DEFINE_UNQUOTED([COROSYNC_FREEBSD_GE_8], [1], [Compiling for FreeBSD >= 8 platform]) ;; esac ;; *solaris*) AC_DEFINE_UNQUOTED([COROSYNC_SOLARIS], [1], [Compiling for Solaris platform]) AC_DEFINE_UNQUOTED([TS_CLASS], [1], [Prevent being scheduled RR]) AC_DEFINE_UNQUOTED([_SEM_SEMUN_UNDEFINED], [1], [The semun structure is undefined]) CP=rsync OS_CFLAGS="" OS_CPPFLAGS="-D_REENTRANT" OS_LDFLAGS="" OS_DYFLAGS="-Wl,-z,lazyload" DARWIN_OPTS="" SOLARIS_OPTS=" " ;; *) AC_MSG_ERROR([Unsupported OS? hmmmm]) ;; esac AC_SUBST(CP) # *FLAGS handling goes here ENV_CFLAGS="$CFLAGS" ENV_CPPFLAGS="$CPPFLAGS" ENV_LDFLAGS="$LDFLAGS" # debug build stuff if test "x${enable_debug}" = xyes; then AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code]) OPT_CFLAGS="-O0" PACKAGE_FEATURES="$PACKAGE_FEATURES debug" else OPT_CFLAGS="-O3" fi # gdb flags if test "x${GCC}" = xyes; then GDB_FLAGS="-ggdb3" else GDB_FLAGS="-g" fi # Look for libnss if test "x${enable_nss}" = xyes; then PKG_CHECK_MODULES([nss],[nss]) AC_DEFINE_UNQUOTED([HAVE_LIBNSS], 1, [have libnss]) PACKAGE_FEATURES="$PACKAGE_FEATURES nss" fi if test "x${enable_testagents}" = xyes; then AC_DEFINE_UNQUOTED([HAVE_TESTAGENTS], 1, [have testagents]) PACKAGE_FEATURES="$PACKAGE_FEATURES testagents" fi if test "x${enable_rdma}" = xyes; then PKG_CHECK_MODULES([rdmacm],[rdmacm]) PKG_CHECK_MODULES([ibverbs],[ibverbs]) AC_DEFINE_UNQUOTED([HAVE_RDMA], 1, [have rdmacm]) PACKAGE_FEATURES="$PACKAGE_FEATURES rdma" fi +if test "x${enable_monitoring}" = xyes; then + + AC_CHECK_LIB([statgrab], [sg_get_mem_stats], have_libstatgrab="yes", have_libstatgrab="no") + + if test "x${have_libstatgrab}" = xyes; then + AC_DEFINE_UNQUOTED([HAVE_LIBSTATGRAB], 1, [have libstatgrab]) + statgrab_LIBS="-lstatgrab" + else + if test "x${have_linux}" = xno; then + AC_MSG_ERROR(monitoring requires libstatgrab on non-linux systems) + fi + fi + AC_SUBST([statgrab_LIBS]) + AC_DEFINE_UNQUOTED([HAVE_MONITORING], 1, [have resource monitoring]) + PACKAGE_FEATURES="$PACKAGE_FEATURES monitoring" +fi + +if test "x${enable_watchdog}" = xyes; then + AC_CHECK_HEADER(linux/watchdog.h,,AC_MSG_ERROR(watchdog requires linux/watchdog.h)) + AC_CHECK_HEADER(linux/reboot.h,,AC_MSG_ERROR(watchdog requires linux/reboot.h)) + AC_DEFINE_UNQUOTED([HAVE_WATCHDOG], 1, [have watchdog]) + PACKAGE_FEATURES="$PACKAGE_FEATURES watchdog" +fi + if test "x${enable_augeas}" = xyes; then PACKAGE_FEATURES="$PACKAGE_FEATURES augeas" fi # extra warnings EXTRA_WARNINGS="" WARNLIST=" all shadow missing-prototypes missing-declarations strict-prototypes declaration-after-statement pointer-arith write-strings cast-align bad-function-cast missing-format-attribute format=2 format-security format-nonliteral no-long-long unsigned-char gnu89-inline no-strict-aliasing " for j in $WARNLIST; do if cc_supports_flag -W$j; then EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j"; fi done if test "x${enable_coverage}" = xyes && \ cc_supports_flag -ftest-coverage && \ cc_supports_flag -fprofile-arcs ; then AC_MSG_NOTICE([Enabling Coverage (enable -O0 by default)]) OPT_CFLAGS="-O0" COVERAGE_CFLAGS="-ftest-coverage -fprofile-arcs" COVERAGE_LDFLAGS="-ftest-coverage -fprofile-arcs" COVERAGE_LCRSO_EXTRA_LDFLAGS="-rdynamic" PACKAGE_FEATURES="$PACKAGE_FEATURES coverage" else COVERAGE_CFLAGS="" COVERAGE_LDFLAGS="" COVERAGE_LCRSO_EXTRA_LDFLAGS="" fi if test "x${enable_small_memory_footprint}" = xyes ; then AC_DEFINE_UNQUOTED([HAVE_SMALL_MEMORY_FOOTPRINT], 1, [have small_memory_footprint]) PACKAGE_FEATURES="$PACKAGE_FEATURES small-memory-footprint" fi if test "x${enable_ansi}" = xyes && \ cc_supports_flag -std=iso9899:199409 ; then AC_MSG_NOTICE([Enabling ANSI Compatibility]) ANSI_CPPFLAGS="-ansi -D_GNU_SOURCE -DANSI_ONLY" PACKAGE_FEATURES="$PACKAGE_FEATURES ansi" else ANSI_CPPFLAGS="" fi if test "x${enable_fatal_warnings}" = xyes && \ cc_supports_flag -Werror ; then AC_MSG_NOTICE([Enabling Fatal Warnings (-Werror)]) WERROR_CFLAGS="-Werror" PACKAGE_FEATURES="$PACKAGE_FEATURES fatal-warnings" else WERROR_CFLAGS="" fi # don't add addtional cflags if test "x${enable_user_flags}" = xyes; then OPT_CFLAGS="" GDB_FLAGS="" EXTRA_WARNINGS="" fi # final build of *FLAGS CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS $OS_CFLAGS \ $COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS $NSS_CFLAGS" CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS $OS_CPPFLAGS" LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS $OS_LDFLAGS" # substitute what we need: AC_SUBST([INITDDIR]) AC_SUBST([LCRSODIR]) AC_SUBST([SOCKETDIR]) AC_SUBST([SOMAJOR]) AC_SUBST([SOMINOR]) AC_SUBST([SOMICRO]) AC_SUBST([SONAME]) AC_SUBST([COVERAGE_LCRSO_EXTRA_LDFLAGS]) AC_SUBST([OS_DYFLAGS]) AC_SUBST([OS_LDL]) AM_CONDITIONAL(INSTALL_TESTAGENTS, test -n "${enable_testagents}") AM_CONDITIONAL(AUGTOOL, test -n "${AUGTOOL}") AC_SUBST([NSS_LDFLAGS]) AM_CONDITIONAL(BUILD_DARWIN, test -n "${DARWIN_OPTS}") AM_CONDITIONAL(BUILD_SOLARIS, test -n "${SOLARIS_OPTS}") AC_SUBST([DARWIN_OPTS]) AC_SUBST([SOLARIS_OPTS]) AM_CONDITIONAL(BUILD_HTML_DOCS, test -n "${GROFF}") AC_SUBST([LINT_FLAGS]) AC_DEFINE_UNQUOTED([LCRSODIR], "$(eval echo ${LCRSODIR})", [LCRSO directory]) AC_DEFINE_UNQUOTED([SOCKETDIR], "$(eval echo ${SOCKETDIR})", [Socket directory]) AC_DEFINE_UNQUOTED([LOCALSTATEDIR], "$(eval echo ${localstatedir})", [localstate directory]) COROSYSCONFDIR=${sysconfdir}/corosync AC_SUBST([COROSYSCONFDIR]) AC_DEFINE_UNQUOTED([COROSYSCONFDIR], "$(eval echo ${COROSYSCONFDIR})", [corosync config directory]) AC_DEFINE_UNQUOTED([PACKAGE_FEATURES], "${PACKAGE_FEATURES}", [corosync built-in features]) AC_OUTPUT AC_MSG_RESULT([]) AC_MSG_RESULT([$PACKAGE configuration:]) AC_MSG_RESULT([ Version = ${VERSION}]) AC_MSG_RESULT([ Prefix = ${prefix}]) AC_MSG_RESULT([ Executables = ${sbindir}]) AC_MSG_RESULT([ Man pages = ${mandir}]) AC_MSG_RESULT([ Doc dir = ${docdir}]) AC_MSG_RESULT([ Libraries = ${libdir}]) AC_MSG_RESULT([ Header files = ${includedir}]) AC_MSG_RESULT([ Arch-independent files = ${datadir}]) AC_MSG_RESULT([ State information = ${localstatedir}]) AC_MSG_RESULT([ System configuration = ${sysconfdir}]) AC_MSG_RESULT([ System init.d directory = ${INITDDIR}]) AC_MSG_RESULT([ corosync config dir = ${COROSYSCONFDIR}]) AC_MSG_RESULT([ LCRSO = ${LCRSODIR}]) AC_MSG_RESULT([ SOCKETDIR = ${SOCKETDIR}]) AC_MSG_RESULT([ Features =${PACKAGE_FEATURES}]) AC_MSG_RESULT([]) AC_MSG_RESULT([$PACKAGE build info:]) AC_MSG_RESULT([ Library SONAME = ${SONAME}]) LIB_MSG_RESULT(m4_shift(local_soname_list))dnl AC_MSG_RESULT([ Default optimization = ${OPT_CFLAGS}]) AC_MSG_RESULT([ Default debug options = ${GDB_CFLAGS}]) AC_MSG_RESULT([ Extra compiler warnings = ${EXTRA_WARNING}]) AC_MSG_RESULT([ Env. defined CFLAG = ${ENV_CFLAGS}]) AC_MSG_RESULT([ Env. defined CPPFLAGS = ${ENV_CPPFLAGS}]) AC_MSG_RESULT([ Env. defined LDFLAGS = ${ENV_LDFLAGS}]) AC_MSG_RESULT([ OS defined CFLAGS = ${OS_CFLAGS}]) AC_MSG_RESULT([ OS defined CPPFLAGS = ${OS_CPPFLAGS}]) AC_MSG_RESULT([ OS defined LDFLAGS = ${OS_LDFLAGS}]) AC_MSG_RESULT([ OS defined LDL = ${OS_LDL}]) AC_MSG_RESULT([ OS defined DYFLAGS = ${OS_DYFLAGS}]) AC_MSG_RESULT([ ANSI defined CPPFLAGS = ${ANSI_CPPFLAGS}]) AC_MSG_RESULT([ Coverage CFLAGS = ${COVERAGE_CFLAGS}]) AC_MSG_RESULT([ Coverage LDFLAGS = ${COVERAGE_LDFLAGS}]) AC_MSG_RESULT([ Fatal War. CFLAGS = ${WERROR_CFLAGS}]) AC_MSG_RESULT([ Final CFLAGS = ${CFLAGS}]) AC_MSG_RESULT([ Final CPPFLAGS = ${CPPFLAGS}]) AC_MSG_RESULT([ Final LDFLAGS = ${LDFLAGS}]) diff --git a/corosync.spec.in b/corosync.spec.in index dafdb3c4..ed531c3f 100644 --- a/corosync.spec.in +++ b/corosync.spec.in @@ -1,263 +1,277 @@ %global alphatag @alphatag@ # Conditionals # Invoke "rpmbuild --without " or "rpmbuild --with " # to disable or enable specific features %bcond_with testagents +%bcond_with watchdog +%bcond_with monitoring Name: corosync Summary: The Corosync Cluster Engine and Application Programming Interfaces Version: @version@ Release: 1%{?alphatag:.%{alphatag}}%{?dist} License: BSD Group: System Environment/Base URL: http://www.openais.org Source0: http://developer.osdl.org/dev/openais/downloads/%{name}-%{version}/%{name}-%{version}.tar.gz # Runtime bits Requires: corosynclib = %{version}-%{release} Requires(pre): /usr/sbin/useradd Requires(post): /sbin/chkconfig Requires(preun): /sbin/chkconfig Conflicts: openais <= 0.89, openais-devel <= 0.89 # Build bits %define buildtrunk 0 %{?_with_buildtrunk: %define buildtrunk 1} %if %{buildtrunk} BuildRequires: autoconf automake %endif BuildRequires: nss-devel BuildRequires: libibverbs-devel librdmacm-devel BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) %prep %setup -q -n %{name}-%{version} %build %if %{buildtrunk} ./autogen.sh %endif export ibverbs_CFLAGS=-I/usr/include/infiniband \ export ibverbs_LIBS=-libverbs \ export rdmacm_CFLAGS=-I/usr/include/rdma \ export rdmacm_LIBS=-lrdmacm \ %{configure} \ --enable-nss \ %if %{with testagents} --enable-testagents \ +%endif +%if %{with watchdog} + --enable-watchdog \ +%endif +%if %{with monitoring} + --enable-monitoring \ %endif --enable-rdma \ --with-initddir=%{_initrddir} make %{_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} ## tree fixup # drop static libs rm -f %{buildroot}%{_libdir}/*.a # drop docs and html docs for now rm -rf %{buildroot}%{_docdir}/* %clean rm -rf %{buildroot} %description This package contains the Corosync Cluster Engine Executive, several default APIs and libraries, default configuration files, and an init script. %post if [ $1 -eq 1 ]; then /sbin/chkconfig --add corosync || : fi %preun if [ $1 -eq 0 ]; then /sbin/service corosync stop &>/dev/null || : /sbin/chkconfig --del corosync || : fi %files %defattr(-,root,root,-) %doc LICENSE SECURITY %{_sbindir}/corosync %{_sbindir}/corosync-keygen %{_sbindir}/corosync-objctl %{_sbindir}/corosync-cfgtool %{_sbindir}/corosync-fplay %{_sbindir}/corosync-pload %{_sbindir}/corosync-cpgtool %{_sbindir}/corosync-quorumtool %{_bindir}/corosync-blackbox %dir %{_sysconfdir}/corosync %dir %{_sysconfdir}/corosync/service.d %dir %{_sysconfdir}/corosync/uidgid.d %config(noreplace) %{_sysconfdir}/corosync/corosync.conf.example %{_initrddir}/corosync %dir %{_libexecdir}/lcrso %{_libexecdir}/lcrso/coroparse.lcrso %{_libexecdir}/lcrso/objdb.lcrso %{_libexecdir}/lcrso/service_cfg.lcrso %{_libexecdir}/lcrso/service_cpg.lcrso %{_libexecdir}/lcrso/service_evs.lcrso %{_libexecdir}/lcrso/service_confdb.lcrso %{_libexecdir}/lcrso/service_pload.lcrso %{_libexecdir}/lcrso/quorum_votequorum.lcrso %{_libexecdir}/lcrso/quorum_testquorum.lcrso %{_libexecdir}/lcrso/vsf_quorum.lcrso %{_libexecdir}/lcrso/vsf_ykd.lcrso +%if %{with watchdog} +%{_libexecdir}/lcrso/service_wd.lcrso +%endif +%if %{with monitoring} +%{_libexecdir}/lcrso/service_mon.lcrso +%endif %dir %{_localstatedir}/lib/corosync %dir %{_localstatedir}/log/cluster %{_mandir}/man8/corosync_overview.8* %{_mandir}/man8/corosync.8* %{_mandir}/man8/corosync-blackbox.8* %{_mandir}/man8/corosync-objctl.8* %{_mandir}/man8/corosync-keygen.8* %{_mandir}/man8/corosync-cfgtool.8* %{_mandir}/man8/corosync-cpgtool.8* %{_mandir}/man8/corosync-fplay.8* %{_mandir}/man8/corosync-pload.8* %{_mandir}/man8/corosync-quorumtool.8* %{_mandir}/man5/corosync.conf.5* # optional testagent rpm # %if %{with testagents} %package -n corosync-testagents Summary: The Corosync Cluster Engine Test Agents Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description -n corosync-testagents This package contains corosync test agents. %files -n corosync-testagents %defattr(755,root,root,-) %{_datadir}/corosync/tests/mem_leak_test.sh %{_datadir}/corosync/tests/net_breaker.sh %{_bindir}/cpg_test_agent %{_bindir}/confdb_test_agent %{_bindir}/sam_test_agent %{_bindir}/votequorum_test_agent %{_libexecdir}/lcrso/service_syncv2.lcrso %endif # library # %package -n corosynclib Summary: The Corosync Cluster Engine Libraries Group: System Environment/Libraries Requires: %{name} = %{version}-%{release} %description -n corosynclib This package contains corosync libraries. %files -n corosynclib %defattr(-,root,root,-) %doc LICENSE %{_libdir}/libcfg.so.* %{_libdir}/libcpg.so.* %{_libdir}/libconfdb.so.* %{_libdir}/libevs.so.* %{_libdir}/libtotem_pg.so.* %{_libdir}/liblogsys.so.* %{_libdir}/libcoroipcc.so.* %{_libdir}/libcoroipcs.so.* %{_libdir}/libquorum.so.* %{_libdir}/libvotequorum.so.* %{_libdir}/libpload.so.* %{_libdir}/libsam.so.* %post -n corosynclib -p /sbin/ldconfig %postun -n corosynclib -p /sbin/ldconfig %package -n corosynclib-devel Summary: The Corosync Cluster Engine Development Kit Group: Development/Libraries Requires: corosynclib = %{version}-%{release} Requires: pkgconfig Provides: corosync-devel = %{version} Obsoletes: corosync-devel < 0.92-7 %description -n corosynclib-devel This package contains include files and man pages used to develop using The Corosync Cluster Engine APIs. %files -n corosynclib-devel %defattr(-,root,root,-) %doc LICENSE README.devmap %dir %{_includedir}/corosync/ %{_includedir}/corosync/cs_config.h %{_includedir}/corosync/corodefs.h %{_includedir}/corosync/coroipc_types.h %{_includedir}/corosync/coroipcs.h %{_includedir}/corosync/coroipcc.h %{_includedir}/corosync/cfg.h %{_includedir}/corosync/confdb.h %{_includedir}/corosync/corotypes.h %{_includedir}/corosync/cpg.h %{_includedir}/corosync/evs.h %{_includedir}/corosync/hdb.h %{_includedir}/corosync/list.h %{_includedir}/corosync/mar_gen.h %{_includedir}/corosync/sam.h %{_includedir}/corosync/swab.h %{_includedir}/corosync/quorum.h %{_includedir}/corosync/votequorum.h %dir %{_includedir}/corosync/totem/ %{_includedir}/corosync/totem/coropoll.h %{_includedir}/corosync/totem/totem.h %{_includedir}/corosync/totem/totemip.h %{_includedir}/corosync/totem/totempg.h %dir %{_includedir}/corosync/lcr/ %{_includedir}/corosync/lcr/lcr_ckpt.h %{_includedir}/corosync/lcr/lcr_comp.h %{_includedir}/corosync/lcr/lcr_ifact.h %dir %{_includedir}/corosync/engine %{_includedir}/corosync/engine/config.h %{_includedir}/corosync/engine/coroapi.h %{_includedir}/corosync/engine/logsys.h %{_includedir}/corosync/engine/objdb.h %{_includedir}/corosync/engine/quorum.h %{_libdir}/libcfg.so %{_libdir}/libcpg.so %{_libdir}/libconfdb.so %{_libdir}/libevs.so %{_libdir}/libtotem_pg.so %{_libdir}/liblogsys.so %{_libdir}/libcoroipcc.so %{_libdir}/libcoroipcs.so %{_libdir}/libquorum.so %{_libdir}/libvotequorum.so %{_libdir}/libpload.so %{_libdir}/libsam.so %{_libdir}/pkgconfig/*.pc %{_mandir}/man3/cpg_*3* %{_mandir}/man3/evs_*3* %{_mandir}/man3/confdb_*3* %{_mandir}/man3/votequorum_*3* %{_mandir}/man3/sam_*3* %{_mandir}/man8/cpg_overview.8* %{_mandir}/man8/evs_overview.8* %{_mandir}/man8/confdb_overview.8* %{_mandir}/man8/logsys_overview.8* %{_mandir}/man8/votequorum_overview.8* %{_mandir}/man8/coroipc_overview.8* %{_mandir}/man8/sam_overview.8* %changelog * @date@ Autotools generated version - @version@-1.@alphatag@ - Autotools generated version diff --git a/exec/Makefile.am b/exec/Makefile.am index a3a49bff..938237cf 100644 --- a/exec/Makefile.am +++ b/exec/Makefile.am @@ -1,172 +1,172 @@ # Copyright (c) 2009 Red Hat, Inc. # # Authors: Andrew Beekhof # Steven Dake (sdake@redhat.com) # # This software licensed under BSD license, the text of which follows: # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # - Neither the name of the MontaVista Software, Inc. nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. MAINTAINERCLEANFILES = Makefile.in AM_CFLAGS = -fPIC INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include $(nss_CFLAGS) $(rdmacm_CFLAGS) $(ibverbs_CFLAGS) TOTEM_SRC = coropoll.c totemip.c totemnet.c totemudp.c \ totemrrp.c totemsrp.c totemmrp.c totempg.c \ crypto.c wthread.c tsafe.c if BUILD_RDMA TOTEM_SRC += totemiba.c endif LOGSYS_SRC = wthread.c logsys.c COROIPCS_SRC = coroipcs.c LCRSO_SRC = objdb.c vsf_ykd.c coroparse.c vsf_quorum.c LCRSO_OBJS = $(LCRSO_SRC:%.c=%.o) LCRSO = $(LCRSO_SRC:%.c=%.lcrso) lib_LIBRARIES = libtotem_pg.a liblogsys.a libcoroipcs.a sbin_PROGRAMS = corosync libtotem_pg_a_SOURCES = $(TOTEM_SRC) liblogsys_a_SOURCES = $(LOGSYS_SRC) libcoroipcs_a_SOURCES = $(COROIPCS_SRC) corosync_SOURCES = main.c util.c sync.c apidef.c service.c \ timer.c totemconfig.c mainconfig.c quorum.c schedwrk.c \ ../lcr/lcr_ifact.c evil.c syncv2.c -corosync_LDADD = -ltotem_pg -llogsys -lcoroipcs +corosync_LDADD = -ltotem_pg -llogsys -lcoroipcs $(statgrab_LIBS) corosync_DEPENDENCIES = libtotem_pg.so.$(SONAME) liblogsys.so.$(SONAME) libcoroipcs.so.$(SONAME) corosync_LDFLAGS = $(OS_DYFLAGS) -L./ TOTEM_OBJS = $(TOTEM_SRC:%.c=%.o) LOGSYS_OBJS = $(LOGSYS_SRC:%.c=%.o) COROIPCS_OBJS = $(COROIPCS_SRC:%.c=%.o) SHARED_LIBS = $(lib_LIBRARIES:%.a=%.so.$(SONAME)) SHARED_LIBS_SO = $(SHARED_LIBS:%.so.$(SONAME)=%.so) SHARED_LIBS_SO_TWO = $(SHARED_LIBS:%.so.$(SONAME)=%.so.$(SOMAJOR)) noinst_HEADERS = apidef.h crypto.h mainconfig.h main.h tsafe.h \ quorum.h service.h sync.h timer.h tlist.h totemconfig.h \ totemmrp.h totemnet.h totemudp.h totemiba.h totemrrp.h \ totemsrp.h util.h vsf.h wthread.h schedwrk.h \ evil.h syncv2.h fsm.h EXTRA_DIST = $(LCRSO_SRC) if BUILD_DARWIN %.lcrso: %.o $(CC) $(LDFLAGS) $(CFLAGS) -L$(top_builddir)/exec -llogsys -bundle -bind_at_load -bundle_loader ./corosync $^ -o $@ libtotem_pg.so.$(SONAME): $(TOTEM_OBJS) $(CC) $(LDFLAGS) $(DARWIN_OPTS) $(TOTEM_OBJS) -o $@ -lpthread ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so.$(SOMAJOR) liblogsys.so.$(SONAME): $(LOGSYS_OBJS) $(CC) $(LDFLAGS) $(DARWIN_OPTS) $(LOGSYS_OBJS) -o $@ -lpthread ln -sf liblogsys.so.$(SONAME) liblogsys.so ln -sf liblogsys.so.$(SONAME) liblogsys.so.$(SOMAJOR) libcoroipcs.so.$(SONAME): $(COROIPCS_OBJS) $(CC) $(LDFLAGS) $(DARWIN_OPTS) $(COROIPCS_OBJS) -o $@ -lpthread ln -sf libcoroipcs.so.$(SONAME) libcoroipcs.so ln -sf libcoroipcs.so.$(SONAME) libcoroipcs.so.$(SOMAJOR) else if BUILD_SOLARIS %.lcrso: %.o $(LD) $(LDFLAGS) -G $^ -o $@ libtotem_pg.so.$(SONAME): $(TOTEM_OBJS) $(LD) $(LDFLAGS) -G $(TOTEM_OBJS) -o $@ -lpthread ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so.$(SOMAJOR) liblogsys.so.$(SONAME): $(LOGSYS_OBJS) $(LD) $(LDFLAGS) -G $(LOGSYS_OBJS) -o $@ -lpthread ln -sf liblogsys.so.$(SONAME) liblogsys.so ln -sf liblogsys.so.$(SONAME) liblogsys.so.$(SOMAJOR) libcoroipcs.so.$(SONAME): $(COROIPCS_OBJS) $(LD) $(LDFLAGS) -G $(COROIPCS_OBJS) -o $@ -lpthread ln -sf libcoroipcs.so.$(SONAME) libcoroipcs.so ln -sf libcoroipcs.so.$(SONAME) libcoroipcs.so.$(SOMAJOR) else %.lcrso: %.o $(CC) $(LDFLAGS) $(CFLAGS) $(COVERAGE_LCRSO_EXTRA_LDFLAGS) -shared -Wl,-soname=$@ $^ -o $@ libtotem_pg.so.$(SONAME): $(TOTEM_OBJS) $(CC) -shared -o $@ \ -Wl,-soname=libtotem_pg.so.$(SOMAJOR) \ $(LDFLAGS) $^ $(nss_LIBS) $(rdmacm_LIBS) $(ibverbs_LIBS) -lpthread ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so.$(SOMAJOR) liblogsys.so.$(SONAME): $(LOGSYS_OBJS) $(CC) -shared -o $@ \ -Wl,-soname=liblogsys.so.$(SOMAJOR) \ $(LDFLAGS) $^ -lpthread ln -sf liblogsys.so.$(SONAME) liblogsys.so ln -sf liblogsys.so.$(SONAME) liblogsys.so.$(SOMAJOR) libcoroipcs.so.$(SONAME): $(COROIPCS_OBJS) $(CC) -shared -o $@ \ -Wl,-soname=libcoroipcs.so.$(SOMAJOR) \ $(LDFLAGS) $^ -lpthread ln -sf libcoroipcs.so.$(SONAME) libcoroipcs.so ln -sf libcoroipcs.so.$(SONAME) libcoroipcs.so.$(SOMAJOR) endif endif lint: -splint $(INCLUDES) $(LINT_FLAGS) $(CFLAGS) *.c all-local: $(LCRSO_OBJS) $(LCRSO) $(SHARED_LIBS) @echo Built corosync Executive install-exec-local: $(INSTALL) -d $(DESTDIR)/$(libdir) $(INSTALL) -m 755 $(SHARED_LIBS) $(DESTDIR)/$(libdir) $(CP) -a $(SHARED_LIBS_SO) $(SHARED_LIBS_SO_TWO) $(DESTDIR)/$(libdir) $(INSTALL) -d $(DESTDIR)/$(LCRSODIR) $(INSTALL) -m 755 $(LCRSO) $(DESTDIR)/$(LCRSODIR) uninstall-local: cd $(DESTDIR)/$(libdir) && \ rm -f $(SHARED_LIBS) $(SHARED_LIBS_SO) $(SHARED_LIBS_SO_TWO) cd $(DESTDIR)/$(LCRSODIR) && \ rm -f $(LCRSO) clean-local: rm -f corosync *.o *.lcrso gmon.out *.da *.bb *.bbg *.so* diff --git a/exec/service.c b/exec/service.c index be554593..dc304061 100644 --- a/exec/service.c +++ b/exec/service.c @@ -1,702 +1,714 @@ /* * Copyright (c) 2006 MontaVista Software, Inc. * Copyright (c) 2006-2009 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "mainconfig.h" #include "util.h" #include #include "timer.h" #include #include #include "main.h" #include #include "service.h" #include LOGSYS_DECLARE_SUBSYS ("SERV"); struct default_service { const char *name; int ver; }; static struct default_service default_services[] = { { .name = "corosync_evs", .ver = 0, }, { .name = "corosync_cfg", .ver = 0, }, { .name = "corosync_cpg", .ver = 0, }, { .name = "corosync_confdb", .ver = 0, }, { .name = "corosync_pload", .ver = 0, }, +#ifdef HAVE_MONITORING + { + .name = "corosync_mon", + .ver = 0, + }, +#endif +#ifdef HAVE_WATCHDOG + { + .name = "corosync_wd", + .ver = 0, + }, +#endif { .name = "corosync_quorum", .ver = 0, } }; /* * service exit and unlink schedwrk handler data structure */ struct seus_handler_data { hdb_handle_t service_handle; int service_engine; struct corosync_api_v1 *api; }; struct corosync_service_engine *ais_service[SERVICE_HANDLER_MAXIMUM_COUNT]; hdb_handle_t service_stats_handle[SERVICE_HANDLER_MAXIMUM_COUNT][64]; int ais_service_exiting[SERVICE_HANDLER_MAXIMUM_COUNT]; static hdb_handle_t object_internal_configuration_handle; static hdb_handle_t object_stats_services_handle; static void (*service_unlink_all_complete) (void) = NULL; static hdb_handle_t swrk_service_exit_handle; static hdb_handle_t swrk_service_unlink_handle; static unsigned int default_services_requested (struct corosync_api_v1 *corosync_api) { hdb_handle_t object_service_handle; hdb_handle_t object_find_handle; char *value; /* * Don't link default services if they have been disabled */ corosync_api->object_find_create ( OBJECT_PARENT_HANDLE, "aisexec", strlen ("aisexec"), &object_find_handle); if (corosync_api->object_find_next ( object_find_handle, &object_service_handle) == 0) { if ( ! corosync_api->object_key_get (object_service_handle, "defaultservices", strlen ("defaultservices"), (void *)&value, NULL)) { if (value && strcmp (value, "no") == 0) { return 0; } } } corosync_api->object_find_destroy (object_find_handle); return (-1); } unsigned int corosync_service_link_and_init ( struct corosync_api_v1 *corosync_api, const char *service_name, unsigned int service_ver) { struct corosync_service_engine_iface_ver0 *iface_ver0; void *iface_ver0_p; hdb_handle_t handle; struct corosync_service_engine *service; int res; hdb_handle_t object_service_handle; hdb_handle_t object_stats_handle; int fn; char object_name[32]; char *name_sufix; uint64_t zero_64 = 0; /* * reference the service interface */ iface_ver0_p = NULL; res = lcr_ifact_reference ( &handle, service_name, service_ver, &iface_ver0_p, (void *)0); iface_ver0 = (struct corosync_service_engine_iface_ver0 *)iface_ver0_p; if (res == -1 || iface_ver0 == 0) { log_printf(LOGSYS_LEVEL_ERROR, "Service failed to load '%s'.\n", service_name); return (-1); } /* * Initialize service */ service = iface_ver0->corosync_get_service_engine_ver0(); ais_service[service->id] = service; if (service->config_init_fn) { res = service->config_init_fn (corosync_api); } if (service->exec_init_fn) { res = service->exec_init_fn (corosync_api); } /* * Store service in object database */ corosync_api->object_create (object_internal_configuration_handle, &object_service_handle, "service", strlen ("service")); corosync_api->object_key_create_typed (object_service_handle, "name", service_name, strlen (service_name) + 1, OBJDB_VALUETYPE_STRING); corosync_api->object_key_create_typed (object_service_handle, "ver", &service_ver, sizeof (service_ver), OBJDB_VALUETYPE_UINT32); res = corosync_api->object_key_create_typed (object_service_handle, "handle", &handle, sizeof (handle), OBJDB_VALUETYPE_UINT64); corosync_api->object_key_create_typed (object_service_handle, "service_id", &service->id, sizeof (service->id), OBJDB_VALUETYPE_UINT16); name_sufix = strrchr (service_name, '_'); if (name_sufix) name_sufix++; else name_sufix = (char*)service_name; corosync_api->object_create (object_stats_services_handle, &object_stats_handle, name_sufix, strlen (name_sufix)); corosync_api->object_key_create_typed (object_stats_handle, "service_id", &service->id, sizeof (service->id), OBJDB_VALUETYPE_INT16); for (fn = 0; fn < service->exec_engine_count; fn++) { snprintf (object_name, 32, "%d", fn); corosync_api->object_create (object_stats_handle, &service_stats_handle[service->id][fn], object_name, strlen (object_name)); corosync_api->object_key_create_typed (service_stats_handle[service->id][fn], "tx", &zero_64, sizeof (zero_64), OBJDB_VALUETYPE_UINT64); corosync_api->object_key_create_typed (service_stats_handle[service->id][fn], "rx", &zero_64, sizeof (zero_64), OBJDB_VALUETYPE_UINT64); } log_printf (LOGSYS_LEVEL_NOTICE, "Service engine loaded: %s\n", service->name); return (res); } static int service_priority_max(void) { int lpc = 0, max = 0; for(; lpc < SERVICE_HANDLER_MAXIMUM_COUNT; lpc++) { if(ais_service[lpc] != NULL && ais_service[lpc]->priority > max) { max = ais_service[lpc]->priority; } } return max; } /* * use the force */ static unsigned int corosync_service_unlink_priority ( struct corosync_api_v1 *corosync_api, int lowest_priority, int *current_priority, int *current_service_engine, hdb_handle_t *current_service_handle) { unsigned short *service_id; hdb_handle_t object_service_handle; hdb_handle_t object_find_handle; hdb_handle_t *found_service_handle; for(; *current_priority >= lowest_priority; *current_priority = *current_priority - 1) { for(*current_service_engine = 0; *current_service_engine < SERVICE_HANDLER_MAXIMUM_COUNT; *current_service_engine = *current_service_engine + 1) { if(ais_service[*current_service_engine] == NULL || ais_service[*current_service_engine]->priority != *current_priority) { continue; } /* * find service object in object database by service id * and unload it if possible. * * If the service engine's exec_exit_fn returns -1 indicating * it was busy, this function returns -1 and can be called again * at a later time (usually via the schedwrk api). */ corosync_api->object_find_create ( object_internal_configuration_handle, "service", strlen ("service"), &object_find_handle); while (corosync_api->object_find_next ( object_find_handle, &object_service_handle) == 0) { int res = corosync_api->object_key_get ( object_service_handle, "service_id", strlen ("service_id"), (void *)&service_id, NULL); if (res == 0 && *service_id == ais_service[*current_service_engine]->id) { if (ais_service[*service_id]->exec_exit_fn) { res = ais_service[*service_id]->exec_exit_fn (); if (res == -1) { corosync_api->object_find_destroy (object_find_handle); return (-1); } } res = corosync_api->object_key_get ( object_service_handle, "handle", strlen ("handle"), (void *)&found_service_handle, NULL); *current_service_handle = *found_service_handle; ais_service_exiting[*current_service_engine] = 1; corosync_api->object_find_destroy (object_find_handle); /* * Call should call this function again */ return (1); } } corosync_api->object_find_destroy (object_find_handle); } } /* * We finish unlink of all services -> no need to call this function again */ return (0); } static unsigned int service_unlink_and_exit ( struct corosync_api_v1 *corosync_api, const char *service_name, unsigned int service_ver) { hdb_handle_t object_service_handle; char *found_service_name; unsigned short *service_id; unsigned int *found_service_ver; hdb_handle_t object_find_handle; hdb_handle_t *found_service_handle; char *name_sufix; int res; name_sufix = strrchr (service_name, '_'); if (name_sufix) name_sufix++; else name_sufix = (char*)service_name; corosync_api->object_find_create ( object_stats_services_handle, name_sufix, strlen (name_sufix), &object_find_handle); if (corosync_api->object_find_next ( object_find_handle, &object_service_handle) == 0) { corosync_api->object_destroy (object_service_handle); } corosync_api->object_find_destroy (object_find_handle); corosync_api->object_find_create ( object_internal_configuration_handle, "service", strlen ("service"), &object_find_handle); while (corosync_api->object_find_next ( object_find_handle, &object_service_handle) == 0) { corosync_api->object_key_get (object_service_handle, "name", strlen ("name"), (void *)&found_service_name, NULL); if (strcmp (service_name, found_service_name) != 0) { continue; } corosync_api->object_key_get (object_service_handle, "ver", strlen ("ver"), (void *)&found_service_ver, NULL); /* * If service found and linked exit it */ if (service_ver != *found_service_ver) { continue; } corosync_api->object_key_get ( object_service_handle, "service_id", strlen ("service_id"), (void *)&service_id, NULL); if(service_id != NULL && *service_id < SERVICE_HANDLER_MAXIMUM_COUNT && ais_service[*service_id] != NULL) { corosync_api->object_find_destroy (object_find_handle); if (ais_service[*service_id]->exec_exit_fn) { res = ais_service[*service_id]->exec_exit_fn (); if (res == -1) { return (-1); } } log_printf(LOGSYS_LEVEL_NOTICE, "Service engine unloaded: %s\n", ais_service[*service_id]->name); ais_service[*service_id] = NULL; res = corosync_api->object_key_get ( object_service_handle, "handle", strlen ("handle"), (void *)&found_service_handle, NULL); lcr_ifact_release (*found_service_handle); corosync_api->object_destroy (object_service_handle); } } corosync_api->object_find_destroy (object_find_handle); return (0); } /* * Links default services into the executive */ unsigned int corosync_service_defaults_link_and_init (struct corosync_api_v1 *corosync_api) { unsigned int i; hdb_handle_t object_service_handle; char *found_service_name; char *found_service_ver; unsigned int found_service_ver_atoi; hdb_handle_t object_find_handle; hdb_handle_t object_find2_handle; hdb_handle_t object_runtime_handle; corosync_api->object_find_create ( OBJECT_PARENT_HANDLE, "runtime", strlen ("runtime"), &object_find2_handle); if (corosync_api->object_find_next ( object_find2_handle, &object_runtime_handle) == 0) { corosync_api->object_create (object_runtime_handle, &object_stats_services_handle, "services", strlen ("services")); } corosync_api->object_create (OBJECT_PARENT_HANDLE, &object_internal_configuration_handle, "internal_configuration", strlen ("internal_configuration")); corosync_api->object_find_create ( OBJECT_PARENT_HANDLE, "service", strlen ("service"), &object_find_handle); while (corosync_api->object_find_next ( object_find_handle, &object_service_handle) == 0) { corosync_api->object_key_get (object_service_handle, "name", strlen ("name"), (void *)&found_service_name, NULL); found_service_ver = NULL; corosync_api->object_key_get (object_service_handle, "ver", strlen ("ver"), (void *)&found_service_ver, NULL); found_service_ver_atoi = (found_service_ver ? atoi (found_service_ver) : 0); corosync_service_link_and_init ( corosync_api, found_service_name, found_service_ver_atoi); } corosync_api->object_find_destroy (object_find_handle); if (default_services_requested (corosync_api) == 0) { return (0); } for (i = 0; i < sizeof (default_services) / sizeof (struct default_service); i++) { corosync_service_link_and_init ( corosync_api, default_services[i].name, default_services[i].ver); } return (0); } /* * Declaration of exit_schedwrk_handler, because of cycle * (service_exit_schedwrk_handler calls service_unlink_schedwrk_handler, and vice-versa) */ static int service_exit_schedwrk_handler (const void *data); static int service_unlink_schedwrk_handler (const void *data) { struct seus_handler_data *cb_data = (struct seus_handler_data *)data; struct corosync_api_v1 *api = (struct corosync_api_v1 *)cb_data->api; /* * Exit all ipc connections dependent on this service */ if (coroipcs_ipc_service_exit (cb_data->service_engine) == -1) return -1; log_printf(LOGSYS_LEVEL_NOTICE, "Service engine unloaded: %s\n", ais_service[cb_data->service_engine]->name); ais_service[cb_data->service_engine] = NULL; lcr_ifact_release (cb_data->service_handle); api->schedwrk_create ( &swrk_service_exit_handle, &service_exit_schedwrk_handler, data); return 0; } static int service_exit_schedwrk_handler (const void *data) { int res; static int current_priority = 0; static int current_service_engine = 0; static int called = 0; struct seus_handler_data *cb_data = (struct seus_handler_data *)data; struct corosync_api_v1 *api = (struct corosync_api_v1 *)cb_data->api; hdb_handle_t service_handle; if (called == 0) { log_printf(LOGSYS_LEVEL_NOTICE, "Unloading all Corosync service engines.\n"); current_priority = service_priority_max (); called = 1; } res = corosync_service_unlink_priority ( api, 0, ¤t_priority, ¤t_service_engine, &service_handle); if (res == 0) { service_unlink_all_complete(); return (res); } if (res == 1) { cb_data->service_engine = current_service_engine; cb_data->service_handle = service_handle; api->schedwrk_create_nolock ( &swrk_service_unlink_handle, &service_unlink_schedwrk_handler, data); return (0); } return (res); } void corosync_service_unlink_all ( struct corosync_api_v1 *api, void (*unlink_all_complete) (void)) { static int called = 0; static struct seus_handler_data cb_data; assert (api); service_unlink_all_complete = unlink_all_complete; if (called) { return; } if (called == 0) { called = 1; } cb_data.api = api; api->schedwrk_create ( &swrk_service_exit_handle, &service_exit_schedwrk_handler, &cb_data); } struct service_unlink_and_exit_data { hdb_handle_t handle; struct corosync_api_v1 *api; const char *name; unsigned int ver; }; static int service_unlink_and_exit_schedwrk_handler (void *data) { struct service_unlink_and_exit_data *service_unlink_and_exit_data = data; int res; res = service_unlink_and_exit ( service_unlink_and_exit_data->api, service_unlink_and_exit_data->name, service_unlink_and_exit_data->ver); if (res == 0) { free (service_unlink_and_exit_data); } return (res); } typedef int (*schedwrk_cast) (const void *); unsigned int corosync_service_unlink_and_exit ( struct corosync_api_v1 *api, const char *service_name, unsigned int service_ver) { struct service_unlink_and_exit_data *service_unlink_and_exit_data; assert (api); service_unlink_and_exit_data = malloc (sizeof (struct service_unlink_and_exit_data)); service_unlink_and_exit_data->api = api; service_unlink_and_exit_data->name = strdup (service_name); service_unlink_and_exit_data->ver = service_ver; api->schedwrk_create ( &service_unlink_and_exit_data->handle, (schedwrk_cast)service_unlink_and_exit_schedwrk_handler, service_unlink_and_exit_data); return (0); } diff --git a/include/corosync/corodefs.h b/include/corosync/corodefs.h index 57923e2d..a1e65391 100644 --- a/include/corosync/corodefs.h +++ b/include/corosync/corodefs.h @@ -1,73 +1,75 @@ /* * Copyright (c) 2009 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CORODEFS_H_DEFINED #define CORODEFS_H_DEFINED #include #define COROSYNC_SOCKET_NAME "corosync.ipc" enum corosync_service_types { EVS_SERVICE = 0, CLM_SERVICE = 1, AMF_SERVICE = 2, CKPT_SERVICE = 3, EVT_SERVICE = 4, LCK_SERVICE = 5, MSG_SERVICE = 6, CFG_SERVICE = 7, CPG_SERVICE = 8, CMAN_SERVICE = 9, PCMK_SERVICE = 10, CONFDB_SERVICE = 11, QUORUM_SERVICE = 12, PLOAD_SERVICE = 13, TMR_SERVICE = 14, VOTEQUORUM_SERVICE = 15, NTF_SERVICE = 16, AMF_V2_SERVICE = 17, TST_SV1_SERVICE = 18, - TST_SV2_SERVICE = 19 + TST_SV2_SERVICE = 19, + MON_SERVICE = 20, + WD_SERVICE = 21 }; #ifdef HAVE_SMALL_MEMORY_FOOTPRINT #define PROCESSOR_COUNT_MAX 16 #else #define PROCESSOR_COUNT_MAX 384 #endif /* HAVE_SMALL_MEMORY_FOOTPRINT */ #define TOTEMIP_ADDRLEN (sizeof(struct in6_addr)) #endif /* CORODEFS_H_DEFINED */ diff --git a/services/Makefile.am b/services/Makefile.am index cb640166..f39adc3e 100644 --- a/services/Makefile.am +++ b/services/Makefile.am @@ -1,97 +1,103 @@ # Copyright (c) 2009 Red Hat, Inc. # # Authors: Andrew Beekhof # Steven Dake (sdake@redhat.com) # # This software licensed under BSD license, the text of which follows: # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # - Neither the name of the MontaVista Software, Inc. nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. MAINTAINERCLEANFILES = Makefile.in AM_CFLAGS = -fPIC INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/include/corosync \ -I$(top_srcdir)/include/corosync SERVICE_LCRSO = evs cfg cpg confdb pload +if BUILD_WATCHDOG +SERVICE_LCRSO += wd +endif +if BUILD_MONITORING +SERVICE_LCRSO += mon +endif QUORUM_LCRSO = votequorum testquorum SOURCES = $(SERVICE_LCRSO:%=%.c) $(QUORUM_LCRSO:%=%.c) EXTRA_DIST = $(SOURCES) LCRSO = $(SERVICE_LCRSO:%=service_%.lcrso) $(QUORUM_LCRSO:%=quorum_%.lcrso) LCRSO_OBJS = $(SOURCES:%.c=%.o) if BUILD_DARWIN quorum_%.lcrso: %.o $(CC) $(LDFLAGS) $(CFLAGS) -L$(top_builddir)/exec -llogsys -bundle -bundle_loader $(top_builddir)/exec/corosync $^ -o $@ service_%.lcrso: %.o $(CC) $(LDFLAGS) $(CFLAGS) -L$(top_builddir)/exec -llogsys -bundle -bundle_loader $(top_builddir)/exec/corosync $^ -o $@ else if BUILD_SOLARIS quorum_%.lcrso: %.o $(LD) $(LDFLAGS) -G $^ -o $@ service_%.lcrso: %.o $(LD) $(LDFLAGS) -G $^ -o $@ else quorum_%.lcrso: %.o $(CC) $(LDFLAGS) $(CFLAGS) $(COVERAGE_LCRSO_EXTRA_LDFLAGS) -shared -Wl,-soname=$@ $^ -o $@ service_%.lcrso: %.o $(CC) $(LDFLAGS) $(CFLAGS) $(COVERAGE_LCRSO_EXTRA_LDFLAGS) -shared -Wl,-soname=$@ $^ -o $@ endif endif %.o: %.c $(CC) $(AM_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $< lint: -splint $(INCLUDES) $(LINT_FLAGS) $(CFLAGS) *.c all-local: $(LCRSO_OBJS) $(LCRSO) @echo Built Service Engines install-exec-local: $(INSTALL) -d $(DESTDIR)/$(LCRSODIR) $(INSTALL) -m 755 $(LCRSO) $(DESTDIR)/$(LCRSODIR) uninstall-local: cd $(DESTDIR)/$(LCRSODIR) && \ rm -f $(LCRSO) clean-local: rm -f *.o *.a *.so* *.da *.bb *.bbg *.lcrso diff --git a/services/mon.c b/services/mon.c new file mode 100644 index 00000000..3e475a17 --- /dev/null +++ b/services/mon.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2010 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Angus Salkeld + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#if defined(HAVE_LIBSTATGRAB) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "../exec/fsm.h" + + +LOGSYS_DECLARE_SUBSYS ("MON"); + +#undef ENTER +#define ENTER() log_printf (LOGSYS_LEVEL_INFO, "%s", __func__) + +/* + * Service Interfaces required by service_message_handler struct + */ +static int mon_exec_init_fn ( + struct corosync_api_v1 *corosync_api); + +hdb_handle_t mon_poll = 0; +static struct corosync_api_v1 *api; +static hdb_handle_t resources_obj; +static pthread_t mon_poll_thread; +#define MON_DEFAULT_PERIOD 3 + +struct corosync_service_engine mon_service_engine = { + .name = "corosync resource monitoring service", + .id = MON_SERVICE, + .priority = 1, + .private_data_size = 0, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED, + .lib_init_fn = NULL, + .lib_exit_fn = NULL, + .lib_engine = NULL, + .lib_engine_count = 0, + .exec_engine = NULL, + .exec_engine_count = 0, + .confchg_fn = NULL, + .exec_init_fn = mon_exec_init_fn, + .exec_dump_fn = NULL, + .sync_mode = CS_SYNC_V2 +}; + +static DECLARE_LIST_INIT (confchg_notify); + + +struct resource_instance { + hdb_handle_t handle; + const char *name; + poll_timer_handle timer_handle; + void (*update_stats_fn) (void *data); + struct cs_fsm fsm; + int32_t period; + objdb_value_types_t max_type; + union { + int32_t int32; + double dbl; + } max; +}; + +static void mem_update_stats_fn (void *data); +static void load_update_stats_fn (void *data); + +static struct resource_instance memory_used_inst = { + .name = "memory_used", + .update_stats_fn = mem_update_stats_fn, + .max_type = OBJDB_VALUETYPE_INT32, + .max.int32 = INT32_MAX, + .period = MON_DEFAULT_PERIOD, +}; + +static struct resource_instance load_15min_inst = { + .name = "load_15min", + .update_stats_fn = load_update_stats_fn, + .max_type = OBJDB_VALUETYPE_DOUBLE, + .max.dbl = INT32_MAX, + .period = MON_DEFAULT_PERIOD, +}; + + +/* + * F S M + */ +static void mon_config_changed (struct cs_fsm* fsm, int32_t event, void * data); +static void mon_resource_failed (struct cs_fsm* fsm, int32_t event, void * data); + +const char * mon_ok_str = "ok"; +const char * mon_failed_str = "failed"; +const char * mon_failure_str = "failure"; +const char * mon_disabled_str = "disabled"; +const char * mon_config_changed_str = "config_changed"; + +enum mon_resource_state { + MON_S_DISABLED, + MON_S_OK, + MON_S_FAILED +}; +enum mon_resource_event { + MON_E_CONFIG_CHANGED, + MON_E_FAILURE +}; + +struct cs_fsm_entry mon_fsm_table[] = { + { MON_S_DISABLED, MON_E_CONFIG_CHANGED, mon_config_changed, {MON_S_DISABLED, MON_S_OK, -1} }, + { MON_S_DISABLED, MON_E_FAILURE, NULL, {-1} }, + { MON_S_OK, MON_E_CONFIG_CHANGED, mon_config_changed, {MON_S_OK, MON_S_DISABLED, -1} }, + { MON_S_OK, MON_E_FAILURE, mon_resource_failed, {MON_S_FAILED, -1} }, + { MON_S_FAILED, MON_E_CONFIG_CHANGED, mon_config_changed, {MON_S_OK, MON_S_DISABLED, -1} }, + { MON_S_FAILED, MON_E_FAILURE, NULL, {-1} }, +}; + +/* + * Dynamic loading descriptor + */ + +static struct corosync_service_engine *mon_get_service_engine_ver0 (void); + +static struct corosync_service_engine_iface_ver0 mon_service_engine_iface = { + .corosync_get_service_engine_ver0 = mon_get_service_engine_ver0 +}; + +static struct lcr_iface corosync_mon_ver0[1] = { + { + .name = "corosync_mon", + .version = 0, + .versions_replace = 0, + .versions_replace_count = 0, + .dependencies = 0, + .dependency_count = 0, + .constructor = NULL, + .destructor = NULL, + .interfaces = NULL, + } +}; + +static struct lcr_comp mon_comp_ver0 = { + .iface_count = 1, + .ifaces = corosync_mon_ver0 +}; + +static struct corosync_service_engine *mon_get_service_engine_ver0 (void) +{ + return (&mon_service_engine); +} + +#ifdef COROSYNC_SOLARIS +void corosync_lcr_component_register (void); + +void corosync_lcr_component_register (void) { +#else +__attribute__ ((constructor)) static void corosync_lcr_component_register (void) { +#endif + lcr_interfaces_set (&corosync_mon_ver0[0], &mon_service_engine_iface); + + lcr_component_register (&mon_comp_ver0); +} + +static const char * mon_res_state_to_str(struct cs_fsm* fsm, + int32_t state) +{ + switch (state) { + case MON_S_DISABLED: + return mon_disabled_str; + break; + case MON_S_OK: + return mon_ok_str; + break; + case MON_S_FAILED: + return mon_failed_str; + break; + } + return NULL; +} + +static const char * mon_res_event_to_str(struct cs_fsm* fsm, + int32_t event) +{ + switch (event) { + case MON_E_CONFIG_CHANGED: + return mon_config_changed_str; + break; + case MON_E_FAILURE: + return mon_failure_str; + break; + } + return NULL; +} + +static void mon_fsm_state_set (struct cs_fsm* fsm, + enum mon_resource_state next_state, struct resource_instance* inst) +{ + enum mon_resource_state prev_state = fsm->curr_state; + const char *state_str; + + ENTER(); + + cs_fsm_state_set(fsm, next_state, inst); + + if (prev_state == fsm->curr_state) { + return; + } + state_str = mon_res_state_to_str(fsm, fsm->curr_state); + + api->object_key_replace (inst->handle, + "state", strlen ("state"), + state_str, strlen (state_str)); +} + + +static void mon_config_changed (struct cs_fsm* fsm, int32_t event, void * data) +{ + struct resource_instance * inst = (struct resource_instance *)data; + char *str; + size_t str_len; + objdb_value_types_t type; + int32_t tmp_value; + int32_t res; + + ENTER(); + + res = api->object_key_get_typed (inst->handle, + "poll_period", + (void**)&str, &str_len, + &type); + if (res == 0) { + tmp_value = strtol (str, NULL, 0); + if (tmp_value > 0 && tmp_value < 120) { + if (inst->period != tmp_value) { + inst->period = tmp_value; + } + } + } + + res = api->object_key_get_typed (inst->handle, "max", + (void**)&str, &str_len, &type); + if (res != 0) { + if (inst->max_type == OBJDB_VALUETYPE_INT32) { + inst->max.int32 = INT32_MAX; + } else + if (inst->max_type == OBJDB_VALUETYPE_DOUBLE) { + inst->max.dbl = INT32_MAX; + } + mon_fsm_state_set (fsm, MON_S_DISABLED, inst); + } else { + if (inst->max_type == OBJDB_VALUETYPE_INT32) { + inst->max.int32 = strtol (str, NULL, 0); + } else + if (inst->max_type == OBJDB_VALUETYPE_DOUBLE) { + inst->max.dbl = strtod (str, NULL); + } + mon_fsm_state_set (fsm, MON_S_OK, inst); + } + + if (mon_poll == 0) { + return; + } + poll_timer_delete (mon_poll, inst->timer_handle); + /* + * run the updater, incase the period has shortened + */ + inst->update_stats_fn (inst); + poll_timer_add (mon_poll, + inst->period * 1000, NULL, + inst->update_stats_fn, + &inst->timer_handle); +} + +void mon_resource_failed (struct cs_fsm* fsm, int32_t event, void * data) +{ + struct resource_instance * inst = (struct resource_instance *)data; + ENTER(); + mon_fsm_state_set (fsm, MON_S_FAILED, inst); +} + +static int32_t percent_mem_used_get(void) +{ +#if defined(HAVE_LIBSTATGRAB) + sg_mem_stats *mem_stats; + sg_swap_stats *swap_stats; + long long total, freemem; + + mem_stats = sg_get_mem_stats(); + swap_stats = sg_get_swap_stats(); + + if (mem_stats == NULL || swap_stats != NULL) { + log_printf (LOGSYS_LEVEL_ERROR, "Unable to get memory stats: %s\n", + sg_str_error(sg_get_error())); + return -1; + } + total = mem_stats->total + swap_stats->total; + freemem = mem_stats->free + swap_stats->free; + return ((total - freemem) * 100) / total; +#else +#if defined(COROSYNC_LINUX) + char *line_ptr; + char line[512]; + unsigned long long value; + FILE *f; + long long total = 0; + long long freemem = 0; + + if ((f = fopen("/proc/meminfo", "r")) == NULL) { + return -1; + } + + while ((line_ptr = fgets(line, sizeof(line), f)) != NULL) { + if (sscanf(line_ptr, "%*s %llu kB", &value) != 1) { + continue; + } + value *= 1024; + + if (strncmp(line_ptr, "MemTotal:", 9) == 0) { + total += value; + } else if (strncmp(line_ptr, "MemFree:", 8) == 0) { + freemem += value; + } else if (strncmp(line_ptr, "SwapTotal:", 10) == 0) { + total += value; + } else if (strncmp(line_ptr, "SwapFree:", 9) == 0) { + freemem += value; + } + } + + fclose(f); + return ((total - freemem) * 100) / total; +#else +#error need libstatgrab or linux. +#endif /* COROSYNC_LINUX */ +#endif /* HAVE_LIBSTATGRAB */ +} + + +static void mem_update_stats_fn (void *data) +{ + struct resource_instance * inst = (struct resource_instance *)data; + int32_t new_value; + uint64_t timestamp; + + new_value = percent_mem_used_get(); + if (new_value > 0) { + api->object_key_replace (inst->handle, + "current", strlen("current"), + &new_value, sizeof(new_value)); + + timestamp = time (NULL); + + api->object_key_replace (inst->handle, + "last_updated", strlen("last_updated"), + ×tamp, sizeof(time_t)); + + if (new_value > inst->max.int32) { + cs_fsm_process (&inst->fsm, MON_E_FAILURE, inst); + } + } + poll_timer_add (mon_poll, + inst->period * 1000, inst, + inst->update_stats_fn, + &inst->timer_handle); +} + +static double min15_loadavg_get(void) +{ +#if defined(HAVE_LIBSTATGRAB) + sg_load_stats *load_stats; + load_stats = sg_get_load_stats (); + if (load_stats == NULL) { + log_printf (LOGSYS_LEVEL_ERROR, "Unable to get load stats: %s\n", + sg_str_error (sg_get_error())); + return -1; + } + return load_stats->min15; +#else +#if defined(COROSYNC_LINUX) + double loadav[3]; + if (getloadavg(loadav,3) < 0) { + return -1; + } + return loadav[2]; +#else +#error need libstatgrab or linux. +#endif /* COROSYNC_LINUX */ +#endif /* HAVE_LIBSTATGRAB */ +} + +static void load_update_stats_fn (void *data) +{ + struct resource_instance * inst = (struct resource_instance *)data; + uint64_t timestamp; + int32_t res = 0; + double min15 = min15_loadavg_get(); + + if (min15 < 0) { + } + res = api->object_key_replace (inst->handle, + "current", strlen("current"), + &min15, sizeof (min15)); + if (res != 0) + log_printf (LOGSYS_LEVEL_ERROR, "replace current failed: %d", res); + + timestamp = cs_timestamp_get(); + + res = api->object_key_replace (inst->handle, + "last_updated", strlen("last_updated"), + ×tamp, sizeof(uint64_t)); + if (res != 0) + log_printf (LOGSYS_LEVEL_ERROR, "replace last_updated failed: %d", res); + + if (min15 > inst->max.dbl) { + cs_fsm_process (&inst->fsm, MON_E_FAILURE, &inst); + } + + poll_timer_add (mon_poll, + inst->period * 1000, inst, + inst->update_stats_fn, + &inst->timer_handle); +} + +static void *mon_thread_handler (void * unused) +{ +#ifdef HAVE_LIBSTATGRAB + sg_init(); +#endif /* HAVE_LIBSTATGRAB */ + mon_poll = poll_create (); + + poll_timer_add (mon_poll, + memory_used_inst.period * 1000, + &memory_used_inst, + memory_used_inst.update_stats_fn, + &memory_used_inst.timer_handle); + + poll_timer_add (mon_poll, + load_15min_inst.period * 1000, + &load_15min_inst, + load_15min_inst.update_stats_fn, + &load_15min_inst.timer_handle); + poll_run (mon_poll); + + return NULL; +} + +static int object_find_or_create ( + hdb_handle_t parent_object_handle, + hdb_handle_t *object_handle, + const void *object_name, + size_t object_name_len) +{ + hdb_handle_t obj_finder; + hdb_handle_t obj; + int ret = -1; + + api->object_find_create ( + parent_object_handle, + object_name, + object_name_len, + &obj_finder); + + if (api->object_find_next (obj_finder, &obj) == 0) { + /* found it */ + *object_handle = obj; + ret = 0; + } + else { + ret = api->object_create (parent_object_handle, + object_handle, + object_name, object_name_len); + } + + api->object_find_destroy (obj_finder); + return ret; +} + +static void mon_key_change_notify (object_change_type_t change_type, + hdb_handle_t parent_object_handle, + hdb_handle_t object_handle, + const void *object_name_pt, size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, + void *priv_data_pt) +{ + struct resource_instance* inst = (struct resource_instance*)priv_data_pt; + + if ((strcmp ((char*)key_name_pt, "max") == 0) || + (strcmp ((char*)key_name_pt, "poll_period") == 0)) { + ENTER(); + cs_fsm_process (&inst->fsm, MON_E_CONFIG_CHANGED, inst); + } +} + +static void mon_instance_init (hdb_handle_t parent, struct resource_instance* inst) +{ + int32_t res; + char mon_period_str[32]; + size_t mon_period_len; + objdb_value_types_t mon_period_type; + int32_t tmp_value; + int32_t zero_32 = 0; + time_t zero_64 = 0; + double zero_double = 0; + + ENTER(); + + object_find_or_create (parent, + &inst->handle, + inst->name, strlen (inst->name)); + + if (inst->max_type == OBJDB_VALUETYPE_INT32) { + api->object_key_create_typed (inst->handle, + "current", &zero_32, + sizeof (zero_32), inst->max_type); + } else { + api->object_key_create_typed (inst->handle, + "current", &zero_double, + sizeof (zero_double), inst->max_type); + } + + api->object_key_create_typed (inst->handle, + "last_updated", &zero_64, + sizeof (time_t), OBJDB_VALUETYPE_INT64); + + api->object_key_create_typed (inst->handle, + "state", mon_disabled_str, strlen (mon_disabled_str), + OBJDB_VALUETYPE_STRING); + + inst->fsm.name = inst->name; + inst->fsm.curr_entry = 0; + inst->fsm.curr_state = MON_S_DISABLED; + inst->fsm.table = mon_fsm_table; + inst->fsm.entries = sizeof(mon_fsm_table) / sizeof(struct cs_fsm_entry); + inst->fsm.state_to_str = mon_res_state_to_str; + inst->fsm.event_to_str = mon_res_event_to_str; + + res = api->object_key_get_typed (inst->handle, + "poll_period", + (void**)&mon_period_str, &mon_period_len, + &mon_period_type); + if (res != 0) { + mon_period_len = snprintf (mon_period_str, 32, "%d", + inst->period); + api->object_key_create_typed (inst->handle, + "poll_period", &mon_period_str, + mon_period_len, + OBJDB_VALUETYPE_STRING); + } + else { + tmp_value = strtol (mon_period_str, NULL, 0); + if (tmp_value > 0 && tmp_value < 120) + inst->period = tmp_value; + } + cs_fsm_process (&inst->fsm, MON_E_CONFIG_CHANGED, inst); + + poll_timer_add (mon_poll, + inst->period * 1000, inst, + inst->update_stats_fn, + &inst->timer_handle); + + api->object_track_start (inst->handle, OBJECT_TRACK_DEPTH_ONE, + mon_key_change_notify, + NULL, NULL, NULL, NULL); + +} + +static int mon_exec_init_fn ( + struct corosync_api_v1 *corosync_api) +{ + hdb_handle_t obj; + hdb_handle_t parent; + +#ifdef COROSYNC_SOLARIS + logsys_subsys_init(); +#endif + api = corosync_api; + ENTER(); + + object_find_or_create (OBJECT_PARENT_HANDLE, + &resources_obj, + "resources", strlen ("resources")); + + object_find_or_create (resources_obj, + &obj, + "system", strlen ("system")); + + parent = obj; + + mon_instance_init (parent, &memory_used_inst); + mon_instance_init (parent, &load_15min_inst); + + + pthread_create (&mon_poll_thread, NULL, mon_thread_handler, NULL); + + return 0; +} + + diff --git a/services/wd.c b/services/wd.c new file mode 100644 index 00000000..9c9ad97d --- /dev/null +++ b/services/wd.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2010 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Angus Salkeld + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "../exec/fsm.h" + + +typedef enum { + WD_RESOURCE_GOOD, + WD_RESOURCE_FAILED, + WD_RESOURCE_STATE_UNKNOWN, + WD_RESOURCE_NOT_MONITORED +} wd_resource_state_t; + +struct resource { + hdb_handle_t handle; + char *recovery; + char name[128]; + time_t last_updated; + struct cs_fsm fsm; + + corosync_timer_handle_t check_timer; + uint32_t check_timeout; +}; + +LOGSYS_DECLARE_SUBSYS("WD"); + +/* + * Service Interfaces required by service_message_handler struct + */ +static int wd_exec_init_fn ( + struct corosync_api_v1 *corosync_api); +static int wd_exec_exit_fn (void); +static void wd_resource_check_fn (void* resource_ref); + +static struct corosync_api_v1 *api; +#define WD_DEFAULT_TIMEOUT 6 +static uint32_t watchdog_timeout = WD_DEFAULT_TIMEOUT; +static uint32_t tickle_timeout = (WD_DEFAULT_TIMEOUT / 2); +static int dog = -1; +static corosync_timer_handle_t wd_timer; +static hdb_handle_t resources_obj; +static int watchdog_ok = 1; + +struct corosync_service_engine wd_service_engine = { + .name = "corosync self-fencing service", + .id = WD_SERVICE, + .priority = 1, + .private_data_size = 0, + .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED, + .lib_init_fn = NULL, + .lib_exit_fn = NULL, + .lib_engine = NULL, + .lib_engine_count = 0, + .exec_engine = NULL, + .exec_engine_count = 0, + .confchg_fn = NULL, + .exec_init_fn = wd_exec_init_fn, + .exec_exit_fn = wd_exec_exit_fn, + .exec_dump_fn = NULL, + .sync_mode = CS_SYNC_V2 +}; + +static DECLARE_LIST_INIT (confchg_notify); + +/* + * F S M + */ +static void wd_config_changed (struct cs_fsm* fsm, int32_t event, void * data); +static void wd_resource_failed (struct cs_fsm* fsm, int32_t event, void * data); + +enum wd_resource_state { + WD_S_GOOD, + WD_S_FAILED, + WD_S_DISABLED +}; + +enum wd_resource_event { + WD_E_FAILURE, + WD_E_CONFIG_CHANGED +}; + +const char * wd_ok_str = "ok"; +const char * wd_failed_str = "failed"; +const char * wd_failure_str = "failure"; +const char * wd_disabled_str = "disabled"; +const char * wd_config_changed_str = "config_changed"; + +struct cs_fsm_entry wd_fsm_table[] = { + { WD_S_DISABLED, WD_E_CONFIG_CHANGED, wd_config_changed, {WD_S_DISABLED, WD_S_GOOD, -1} }, + { WD_S_DISABLED, WD_E_FAILURE, NULL, {-1} }, + { WD_S_GOOD, WD_E_CONFIG_CHANGED, wd_config_changed, {WD_S_GOOD, WD_S_DISABLED, -1} }, + { WD_S_GOOD, WD_E_FAILURE, wd_resource_failed, {WD_S_FAILED, -1} }, + { WD_S_FAILED, WD_E_CONFIG_CHANGED, wd_config_changed, {WD_S_GOOD, WD_S_DISABLED, -1} }, + { WD_S_FAILED, WD_E_FAILURE, NULL, {-1} }, +}; + +/* + * Dynamic loading descriptor + */ + +static struct corosync_service_engine *wd_get_service_engine_ver0 (void); + +static struct corosync_service_engine_iface_ver0 wd_service_engine_iface = { + .corosync_get_service_engine_ver0 = wd_get_service_engine_ver0 +}; + +static struct lcr_iface corosync_wd_ver0[1] = { + { + .name = "corosync_wd", + .version = 0, + .versions_replace = 0, + .versions_replace_count = 0, + .dependencies = 0, + .dependency_count = 0, + .constructor = NULL, + .destructor = NULL, + .interfaces = NULL, + } +}; + +static struct lcr_comp wd_comp_ver0 = { + .iface_count = 1, + .ifaces = corosync_wd_ver0 +}; + +static struct corosync_service_engine *wd_get_service_engine_ver0 (void) +{ + return (&wd_service_engine); +} + +#ifdef COROSYNC_SOLARIS +void corosync_lcr_component_register (void); + +void corosync_lcr_component_register (void) { +#else +__attribute__ ((constructor)) static void corosync_lcr_component_register (void) { +#endif + lcr_interfaces_set (&corosync_wd_ver0[0], &wd_service_engine_iface); + + lcr_component_register (&wd_comp_ver0); +} + +static int object_find_or_create ( + hdb_handle_t parent_object_handle, + hdb_handle_t *object_handle, + const void *object_name, + size_t object_name_len) +{ + hdb_handle_t obj_finder; + hdb_handle_t obj; + int ret = -1; + + api->object_find_create ( + parent_object_handle, + object_name, + object_name_len, + &obj_finder); + + if (api->object_find_next (obj_finder, &obj) == 0) { + /* found it */ + *object_handle = obj; + ret = 0; + } + else { + ret = api->object_create (parent_object_handle, + object_handle, + object_name, object_name_len); + } + + api->object_find_destroy (obj_finder); + return ret; +} + +static const char * wd_res_state_to_str(struct cs_fsm* fsm, + int32_t state) +{ + switch (state) { + case WD_S_DISABLED: + return wd_disabled_str; + break; + case WD_S_GOOD: + return wd_ok_str; + break; + case WD_S_FAILED: + return wd_failed_str; + break; + } + return NULL; +} + +static const char * wd_res_event_to_str(struct cs_fsm* fsm, + int32_t event) +{ + switch (event) { + case WD_E_CONFIG_CHANGED: + return wd_config_changed_str; + break; + case WD_E_FAILURE: + return wd_failure_str; + break; + } + return NULL; +} + +/* + * returns (0 == OK, 1 == failed) + */ +static int32_t wd_resource_has_failed (struct resource *ref) +{ + hdb_handle_t resource = ref->handle; + int res; + char* state; + size_t state_len; + objdb_value_types_t type; + time_t *last_updated; + time_t my_time; + size_t last_updated_len; + + res = api->object_key_get_typed (resource, + "last_updated", (void*)&last_updated, &last_updated_len, &type); + if (res != 0) { + /* key does not exist. + */ + return 1; + } + res = api->object_key_get_typed (resource, + "state", (void**)&state, &state_len, &type); + if (res != 0 || strncmp (state, "disabled", strlen ("disabled")) == 0) { + /* key does not exist. + */ + return 1; + } + + my_time = time (NULL); + + if ((*last_updated + ref->check_timeout) < my_time) { + log_printf (LOGSYS_LEVEL_INFO, "delayed %ld + %d < %ld", + *last_updated, ref->check_timeout, my_time); + return 1; + } + + if ((*last_updated + ref->check_timeout) < my_time || + strcmp (state, "bad") == 0) { + return 1; + } + return 0; +} + +static void wd_config_changed (struct cs_fsm* fsm, int32_t event, void * data) +{ + int res; + size_t len; + char *state; + objdb_value_types_t type; + char mon_period_str[32]; + int32_t tmp_value; + struct resource *ref = (struct resource*)data; + + res = api->object_key_get_typed (ref->handle, + "poll_period", + (void**)&mon_period_str, &len, + &type); + if (res == 0) { + tmp_value = strtol (mon_period_str, NULL, 0); + if (tmp_value > 0 && tmp_value < 120) + ref->check_timeout = (tmp_value * 5)/4; + } + + res = api->object_key_get_typed (ref->handle, + "recovery", (void*)&ref->recovery, &len, &type); + if (res != 0) { + /* key does not exist. + */ + log_printf (LOGSYS_LEVEL_WARNING, + "resource %s missing a recovery key.", ref->name); + cs_fsm_state_set(&ref->fsm, WD_S_DISABLED, ref); + return; + } + res = api->object_key_get_typed (ref->handle, + "state", (void*)&state, &len, &type); + if (res != 0) { + /* key does not exist. + */ + log_printf (LOGSYS_LEVEL_WARNING, + "resource %s missing a state key.", ref->name); + cs_fsm_state_set(&ref->fsm, WD_S_DISABLED, ref); + return; + } + + cs_fsm_state_set(&ref->fsm, WD_S_GOOD, ref); + + if (ref->check_timer) { + api->timer_delete(ref->check_timer); + } + api->timer_add_duration((unsigned long long)ref->check_timeout*1000000000, + ref, + wd_resource_check_fn, &ref->check_timer); + +} + +static void wd_resource_failed (struct cs_fsm* fsm, int32_t event, void * data) +{ + struct resource* ref = (struct resource*)data; + + if (ref->check_timer) { + api->timer_delete(ref->check_timer); + } + + log_printf (LOGSYS_LEVEL_CRIT, "%s resource \"%s\" failed!", + ref->recovery, (char*)ref->name); + if (strcmp (ref->recovery, "watchdog") == 0 || + strcmp (ref->recovery, "quit") == 0) { + watchdog_ok = 0; + } + else if (strcmp (ref->recovery, "reboot") == 0) { + //reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, NULL); + } + else if (strcmp (ref->recovery, "shutdown") == 0) { + //reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL); + } + cs_fsm_state_set(fsm, WD_S_FAILED, data); +} + +static void wd_key_changed(object_change_type_t change_type, + hdb_handle_t parent_object_handle, + hdb_handle_t object_handle, + const void *object_name_pt, size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, + void *priv_data_pt) +{ + struct resource* ref = (struct resource*)priv_data_pt; + + if (strcmp(key_name_pt, "last_updated") == 0 || + strcmp(key_name_pt, "current") == 0) { + return; + } +// log_printf (LOGSYS_LEVEL_WARNING, +// "watchdog resource key changed: %s.%s=%s ref=%p.", +// (char*)object_name_pt, (char*)key_name_pt, (char*)key_value_pt, ref); + + if (ref == NULL) { + return; + } + cs_fsm_process(&ref->fsm, WD_E_CONFIG_CHANGED, ref); +} + +static void wd_object_destroyed( + hdb_handle_t parent_object_handle, + const void *name_pt, size_t name_len, + void *priv_data_pt) +{ + struct resource* ref = (struct resource*)priv_data_pt; + + log_printf (LOGSYS_LEVEL_WARNING, + "watchdog resource \"%s\" deleted from objdb!", + (char*)name_pt); + + if (ref) { + api->timer_delete(ref->check_timer); + ref->check_timer = NULL; + } +} + +static void wd_resource_check_fn (void* resource_ref) +{ + struct resource* ref = (struct resource*)resource_ref; + + log_printf (LOGSYS_LEVEL_INFO, + "checking watchdog resource \"%s\".", + ref->name); + if (wd_resource_has_failed (ref) ) { + cs_fsm_process(&ref->fsm, WD_E_FAILURE, ref); + log_printf (LOGSYS_LEVEL_CRIT, + "watchdog resource \"%s\" failed!", + (char*)ref->name); + return; + } + api->timer_add_duration((unsigned long long)ref->check_timeout*1000000000, + ref, wd_resource_check_fn, &ref->check_timer); +} + + +static void wd_resource_create (hdb_handle_t resource_obj) +{ + int res; + size_t len; + char *state; + objdb_value_types_t type; + char mon_period_str[32]; + int32_t tmp_value; + struct resource *ref = malloc (sizeof (struct resource)); + + ref->handle = resource_obj; + ref->check_timeout = WD_DEFAULT_TIMEOUT; + ref->check_timer = NULL; + api->object_name_get (resource_obj, + ref->name, + &len); + ref->name[len] = '\0'; + ref->fsm.name = ref->name; + ref->fsm.table = wd_fsm_table; + ref->fsm.entries = sizeof(wd_fsm_table) / sizeof(struct cs_fsm_entry); + ref->fsm.curr_entry = 0; + ref->fsm.curr_state = WD_S_DISABLED; + ref->fsm.state_to_str = wd_res_state_to_str; + ref->fsm.event_to_str = wd_res_event_to_str; + api->object_priv_set (resource_obj, NULL); + + res = api->object_key_get_typed (resource_obj, + "poll_period", + (void**)&mon_period_str, &len, + &type); + if (res != 0) { + log_printf (LOGSYS_LEVEL_ERROR, "%s : %d",__func__, res); + len = snprintf (mon_period_str, 32, "%d", ref->check_timeout); + api->object_key_create_typed (resource_obj, + "poll_period", &mon_period_str, + len, + OBJDB_VALUETYPE_STRING); + } + else { + tmp_value = strtol (mon_period_str, NULL, 0); + if (tmp_value > 0 && tmp_value < 120) + ref->check_timeout = (tmp_value * 5)/4; + } + + api->object_track_start (resource_obj, OBJECT_TRACK_DEPTH_ONE, + wd_key_changed, NULL, wd_object_destroyed, + NULL, ref); + + res = api->object_key_get_typed (resource_obj, + "recovery", (void*)&ref->recovery, &len, &type); + if (res != 0) { + /* key does not exist. + */ + log_printf (LOGSYS_LEVEL_WARNING, + "resource %s missing a recovery key.", ref->name); + return; + } + res = api->object_key_get_typed (resource_obj, + "state", (void*)&state, &len, &type); + if (res != 0) { + /* key does not exist. + */ + log_printf (LOGSYS_LEVEL_WARNING, + "resource %s missing a state key.", ref->name); + return; + } + + res = api->object_key_get_typed (resource_obj, + "last_updated", (void*)&ref->last_updated, &len, &type); + if (res != 0) { + /* key does not exist. + */ + ref->last_updated = 0; + } + + api->timer_add_duration((unsigned long long)ref->check_timeout*1000000000, + ref, + wd_resource_check_fn, &ref->check_timer); + + cs_fsm_state_set(&ref->fsm, WD_S_GOOD, ref); +} + + +static void wd_tickle_fn (void* arg) +{ + ENTER(); + + if (watchdog_ok) { + if (dog > 0) + ioctl(dog, WDIOC_KEEPALIVE, &watchdog_ok); + } + else { + log_printf (LOGSYS_LEVEL_ALERT, "NOT tickling the watchdog!"); + } + + api->timer_add_duration((unsigned long long)tickle_timeout*1000000000, NULL, + wd_tickle_fn, &wd_timer); +} + +static void wd_resource_object_created(hdb_handle_t parent_object_handle, + hdb_handle_t object_handle, + const void *name_pt, size_t name_len, + void *priv_data_pt) +{ + wd_resource_create (object_handle); +} + +static void wd_scan_resources (void) +{ + hdb_handle_t obj_finder; + hdb_handle_t obj_finder2; + hdb_handle_t resource_type; + hdb_handle_t resource; + int res; + + ENTER(); + + api->object_find_create ( + OBJECT_PARENT_HANDLE, + "resources", strlen ("resources"), + &obj_finder); + + res = api->object_find_next (obj_finder, &resources_obj); + api->object_find_destroy (obj_finder); + if (res != 0) { + log_printf (LOGSYS_LEVEL_INFO, "no resources."); + return; + } + + /* this will be the system or process level + */ + api->object_find_create ( + resources_obj, + NULL, 0, + &obj_finder); + while (api->object_find_next (obj_finder, + &resource_type) == 0) { + + api->object_find_create ( + resource_type, + NULL, 0, + &obj_finder2); + + while (api->object_find_next (obj_finder2, + &resource) == 0) { + + wd_resource_create (resource); + } + api->object_find_destroy (obj_finder2); + + api->object_track_start (resource_type, OBJECT_TRACK_DEPTH_ONE, + NULL, wd_resource_object_created, NULL, + NULL, NULL); + } + api->object_find_destroy (obj_finder); +} + + +static void watchdog_timeout_apply (uint32_t new) +{ + struct watchdog_info ident; + + if (new < 2) { + watchdog_timeout = 2; + } + else if (new > 120) { + watchdog_timeout = 120; + } + else { + watchdog_timeout = new; + } + + if (dog > 0) { + ioctl(dog, WDIOC_GETSUPPORT, &ident); + if (ident.options & WDIOF_SETTIMEOUT) { + /* yay! the dog is trained. + */ + ioctl(dog, WDIOC_SETTIMEOUT, &watchdog_timeout); + } + ioctl(dog, WDIOC_GETTIMEOUT, &watchdog_timeout); + } + tickle_timeout = watchdog_timeout / 2; + + log_printf (LOGSYS_LEVEL_DEBUG, "The Watchdog timeout is %d seconds\n", watchdog_timeout); + log_printf (LOGSYS_LEVEL_DEBUG, "The tickle timeout is %d seconds\n", tickle_timeout); +} + +static int setup_watchdog(void) +{ + struct watchdog_info ident; + + ENTER(); + if (access ("/dev/watchdog", W_OK) != 0) { + log_printf (LOGSYS_LEVEL_WARNING, "No Watchdog, try modprobe "); + dog = -1; + return -1; + } + + /* here goes, lets hope they have "Magic Close" + */ + dog = open("/dev/watchdog", O_WRONLY); + + if (dog == -1) { + log_printf (LOGSYS_LEVEL_WARNING, "Watchdog exists but couldn't be opened."); + dog = -1; + return -1; + } + + /* Right we have the dog. + * Lets see what breed it is. + */ + + ioctl(dog, WDIOC_GETSUPPORT, &ident); + log_printf (LOGSYS_LEVEL_INFO, "Watchdog is now been tickled by corosync."); + log_printf (LOGSYS_LEVEL_DEBUG, "%s", ident.identity); + + watchdog_timeout_apply (watchdog_timeout); + + ioctl(dog, WDIOC_SETOPTIONS, WDIOS_ENABLECARD); + + return 0; +} + +static void wd_top_level_key_changed(object_change_type_t change_type, + hdb_handle_t parent_object_handle, + hdb_handle_t object_handle, + const void *object_name_pt, size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, + void *priv_data_pt) +{ + uint32_t tmp_value; + + ENTER(); + if (change_type != OBJECT_KEY_DELETED && + strncmp ((char*)key_name_pt, "watchdog_timeout", key_value_len) == 0) { + tmp_value = strtol (key_value_pt, NULL, 0); + watchdog_timeout_apply (tmp_value); + } + else { + watchdog_timeout_apply (WD_DEFAULT_TIMEOUT); + } + log_printf (LOGSYS_LEVEL_INFO, "new(%d) tickle_timeout: %d", change_type, tickle_timeout); +} + + +static void watchdog_timeout_get_initial (void) +{ + int32_t res; + char watchdog_timeout_str[32]; + size_t watchdog_timeout_len; + objdb_value_types_t watchdog_timeout_type; + uint32_t tmp_value; + + ENTER(); + + res = api->object_key_get_typed (resources_obj, + "watchdog_timeout", + (void**)&watchdog_timeout_str, &watchdog_timeout_len, + &watchdog_timeout_type); + if (res != 0) { + watchdog_timeout_apply (WD_DEFAULT_TIMEOUT); + + watchdog_timeout_len = snprintf (watchdog_timeout_str, 32, "%d", watchdog_timeout); + api->object_key_create_typed (resources_obj, + "watchdog_timeout", &watchdog_timeout_str, + watchdog_timeout_len, + OBJDB_VALUETYPE_STRING); + } + else { + tmp_value = strtol (watchdog_timeout_str, NULL, 0); + watchdog_timeout_apply (tmp_value); + } + + api->object_track_start (resources_obj, OBJECT_TRACK_DEPTH_ONE, + wd_top_level_key_changed, NULL, NULL, + NULL, NULL); + +} + +static int wd_exec_init_fn ( + struct corosync_api_v1 *corosync_api) +{ + hdb_handle_t obj; + + ENTER(); +#ifdef COROSYNC_SOLARIS + logsys_subsys_init(); +#endif + api = corosync_api; + + object_find_or_create (OBJECT_PARENT_HANDLE, + &resources_obj, + "resources", strlen ("resources")); + object_find_or_create (resources_obj, + &obj, + "system", strlen ("system")); + object_find_or_create (resources_obj, + &obj, + "process", strlen ("process")); + + watchdog_timeout_get_initial(); + + setup_watchdog(); + + wd_scan_resources(); + + api->timer_add_duration((unsigned long long)tickle_timeout*1000000000, NULL, + wd_tickle_fn, &wd_timer); + + return 0; +} + +static int wd_exec_exit_fn (void) +{ + char magic = 'V'; + ENTER(); + + if (dog > 0) { + log_printf (LOGSYS_LEVEL_INFO, "magically closing the watchdog."); + write (dog, &magic, 1); + } + return 0; +} + +