The branch, master has been updated via ea7708d8c7f ctdb-scripts: Simplify 01.reclock.script via 38898775e6f ctdb-scripts: Drop monitoring of recovery lock via 5701f4aecaf ctdb-tests: Add some 01.reclock.script init event tests via ecef4411302 ctdb-tests: Fix 01.reclock.script tests for non-default lock via 2bd316d01d3 ctdb-tests: Add tests for cluster mutex lost handling via 41cd44724e2 ctdb-mutex: Add support for exiting if the lock file disappears via af8de1bcfd4 ctdb-mutex: Add an intermediate asynchronous computation for waiting via fae8e438f01 ctdb-mutex: Change parent checking to use an asynchronous computation via 2f768a090e0 ctdb-mutex: Exit immediately if the lock isn't taken via d716be19ea1 ctdb-tests: Add test to confirm need for cluster mutex lock file rechecking via adcf313c49c ctdb-tests: Add cluster mutex tests via 2b6f1a8ee64 ctdb-mutex: Drop dependency on ctdb_set_helper via 76ab0a2b82d ctdb-mutex: Drop unneeded assignment via 98169241ef7 ctdb-mutex: Update to use modern debug macro via c276723dd89 ctdb-tests: Set LANG=C for consistency of command output via 6fe963c3f72 ctdb-recoverd: Periodically log recovery master of incomplete cluster via f2559ef8ce0 ctdb-recoverd: Log the master at the end of elections via 6b7b1e80800 ctdb-tests: Add tests for empty values in config file via efd0c45a8b1 ctdb-common: Fix empty value handling in conf via 242ea955e67 ctdb-tests: Use required_error instead of required_result from 1f923e067db s3:rpc_server: Only dump passwords in developer builds
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit ea7708d8c7fa674111ccea58b3cd0757765c702a Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 8 16:35:57 2019 +1000 ctdb-scripts: Simplify 01.reclock.script The "init" event is only run once so don't bother caching the configured value of the recovery lock. Add some extra error checking. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> Autobuild-User(master): Martin Schwenke <mart...@samba.org> Autobuild-Date(master): Fri Jul 26 04:52:04 UTC 2019 on sn-devel-184 commit 38898775e6f1fb25171c920f2d8bcce24ec51476 Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 8 13:30:06 2019 +1000 ctdb-scripts: Drop monitoring of recovery lock The fcntl helper now does a more meaningful check. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 5701f4aecafcd4efeba5bc12ace5da3101ea49d9 Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 8 16:37:41 2019 +1000 ctdb-tests: Add some 01.reclock.script init event tests Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit ecef4411302113b0513db30169a8481a0a521316 Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 8 16:17:27 2019 +1000 ctdb-tests: Fix 01.reclock.script tests for non-default lock These tests currently do not do what is expected. They test the default case. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 2bd316d01d3ddf733787eba6092f5880b7feb65a Author: Martin Schwenke <mar...@meltin.net> Date: Fri Jul 19 13:41:30 2019 +1000 ctdb-tests: Add tests for cluster mutex lost handling Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 41cd44724e2d035d006645407ed623600d0ec6d8 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jun 27 16:14:26 2019 +1000 ctdb-mutex: Add support for exiting if the lock file disappears If the lock file is inaccessible or the inode number changes then the lock is lost, so exit. This allows the recovery daemon to trigger an election. The ensuing recovery will re-take the lock. By default the lock file is checked every 60 seconds. A lot can happen in 60 seconds but being more aggressive and accessing the lock too often could result in a performance issue for the cluster filesystem. An new optional 2nd argument is added, which is the lock file re-check time in seconds. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit af8de1bcfd4cfb2b2517b5badcc9ab564276fb92 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jun 27 14:13:50 2019 +1000 ctdb-mutex: Add an intermediate asynchronous computation for waiting This will allow more conditions to be waited on via additional sub-requests. At the moment this just completes when the parent wait completes. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit fae8e438f019e7c1d20582f167b3adeac781ddbe Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jun 27 13:45:01 2019 +1000 ctdb-mutex: Change parent checking to use an asynchronous computation Put the checking for the process being immediately re-parented into the computation too. This will be very rare and doing it consistently makes testing saner. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 2f768a090e0a1f34660227e1aedc0ed03ea98534 Author: Martin Schwenke <mar...@meltin.net> Date: Fri Jul 5 15:39:23 2019 +1000 ctdb-mutex: Exit immediately if the lock isn't taken There is no need to wait until the parent kills the helper. The parent will get the initial response, indicating contention or similar, and will then get a separate event indicating that the pipe is gone. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit d716be19ea14f15984eab8ce3388eb90bbb49d0a Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 8 20:51:11 2019 +1000 ctdb-tests: Add test to confirm need for cluster mutex lock file rechecking Remove the lock and a second locker can take the it. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit adcf313c49cbd4e411d6f3fb50e90642f3b7531c Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jul 4 21:52:00 2019 +1000 ctdb-tests: Add cluster mutex tests Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 2b6f1a8ee648017dcdb595aacc0469d28e30d00e Author: Martin Schwenke <mar...@meltin.net> Date: Fri Jul 19 11:14:43 2019 +1000 ctdb-mutex: Drop dependency on ctdb_set_helper This makes the code more explicit and makes testing easier due to less dependencies. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 76ab0a2b82db76ee48e98ae9ca6a4af18a99f68c Author: Martin Schwenke <mar...@meltin.net> Date: Wed Jul 17 13:31:27 2019 +1000 ctdb-mutex: Drop unneeded assignment clang warns: ctdb/server/ctdb_mutex_fcntl_helper.c:61:3: warning: Value stored to 'fd' is never read Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 98169241ef74d92beb433639834dfc0decc52a75 Author: Martin Schwenke <mar...@meltin.net> Date: Fri Jul 5 13:13:16 2019 +1000 ctdb-mutex: Update to use modern debug macro One of these had a missing space, so this implicitly fixes it. It also drops the need to unnecessarily include common.h, which comes with some dependency baggage. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit c276723dd89995100ec42402eee65d6e3a623d03 Author: Martin Schwenke <mar...@meltin.net> Date: Tue Jul 9 12:42:24 2019 +1000 ctdb-tests: Set LANG=C for consistency of command output Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 6fe963c3f72680ecbed1b6f9c70a7af003115666 Author: Martin Schwenke <mar...@meltin.net> Date: Tue Jul 16 08:58:33 2019 +1000 ctdb-recoverd: Periodically log recovery master of incomplete cluster Only do this if the recovery lock is unset. Log every minute for the first 10 minutes, then every 10 minutes, then every hour. This is useful for determining whether a split brain occurred. It is particularly useful if logging failed or was throttled at startup, so there is no evidence of the split brain when it began. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit f2559ef8ce01a46b33a9295e67da920a327f3929 Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 15 09:15:04 2019 +1000 ctdb-recoverd: Log the master at the end of elections Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 6b7b1e8080096ccf64bfa236db597cec0856e6b7 Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Jul 25 15:15:43 2019 +1000 ctdb-tests: Add tests for empty values in config file Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit efd0c45a8b152eb4716193bea6cf95e9e0b97d8b Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Jul 25 15:14:32 2019 +1000 ctdb-common: Fix empty value handling in conf In tini, allow_empty_value=false causes the parser to ignore the lines without '=' sign, but lines with nothing after '=' sign are allowed and cause empty string ("") to be passed as a value. This is counter-intuitive, so conf requires special handling for empty values (which are treated as invalid). Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit 242ea955e672799c45aba47f454900a5a52ce9f6 Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Jul 25 15:15:23 2019 +1000 ctdb-tests: Use required_error instead of required_result Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> ----------------------------------------------------------------------- Summary of changes: ctdb/common/conf.c | 8 + ctdb/config/events/legacy/01.reclock.script | 80 +-- ctdb/server/ctdb_cluster_mutex.c | 66 +- ctdb/server/ctdb_mutex_fcntl_helper.c | 361 +++++++++- ctdb/server/ctdb_recoverd.c | 121 +++- ctdb/tests/cunit/cluster_mutex_001.sh | 59 ++ ctdb/tests/cunit/cluster_mutex_002.sh | 91 +++ ctdb/tests/cunit/cluster_mutex_003.sh | 68 ++ ctdb/tests/cunit/conf_test_001.sh | 34 +- ...clock.monitor.001.sh => 01.reclock.init.001.sh} | 4 +- ...clock.monitor.003.sh => 01.reclock.init.002.sh} | 4 +- ctdb/tests/eventscripts/01.reclock.init.003.sh | 30 + ctdb/tests/eventscripts/01.reclock.monitor.002.sh | 12 - ctdb/tests/eventscripts/01.reclock.monitor.004.sh | 18 - ctdb/tests/eventscripts/01.reclock.monitor.005.sh | 28 - ctdb/tests/eventscripts/scripts/01.reclock.sh | 22 +- ctdb/tests/scripts/common.sh | 5 + ctdb/tests/src/cluster_mutex_test.c | 725 +++++++++++++++++++++ ctdb/wscript | 9 +- 19 files changed, 1572 insertions(+), 173 deletions(-) create mode 100755 ctdb/tests/cunit/cluster_mutex_001.sh create mode 100755 ctdb/tests/cunit/cluster_mutex_002.sh create mode 100755 ctdb/tests/cunit/cluster_mutex_003.sh rename ctdb/tests/eventscripts/{01.reclock.monitor.001.sh => 01.reclock.init.001.sh} (77%) rename ctdb/tests/eventscripts/{01.reclock.monitor.003.sh => 01.reclock.init.002.sh} (50%) create mode 100755 ctdb/tests/eventscripts/01.reclock.init.003.sh delete mode 100755 ctdb/tests/eventscripts/01.reclock.monitor.002.sh delete mode 100755 ctdb/tests/eventscripts/01.reclock.monitor.004.sh delete mode 100755 ctdb/tests/eventscripts/01.reclock.monitor.005.sh create mode 100644 ctdb/tests/src/cluster_mutex_test.c Changeset truncated at 500 lines: diff --git a/ctdb/common/conf.c b/ctdb/common/conf.c index 3d668de3122..e849ff4322f 100644 --- a/ctdb/common/conf.c +++ b/ctdb/common/conf.c @@ -1130,6 +1130,14 @@ static bool conf_load_option(const char *name, } } + if (strlen(value_str) == 0) { + D_ERR("conf: empty value [%s] -> \"%s\"\n", + state->s->name, + name); + state->err = EINVAL; + return true; + } + tmp_ctx = talloc_new(state->conf); if (tmp_ctx == NULL) { state->err = ENOMEM; diff --git a/ctdb/config/events/legacy/01.reclock.script b/ctdb/config/events/legacy/01.reclock.script index e14d8c22f48..29822e1d48c 100755 --- a/ctdb/config/events/legacy/01.reclock.script +++ b/ctdb/config/events/legacy/01.reclock.script @@ -4,71 +4,29 @@ [ -n "$CTDB_BASE" ] || \ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD") -. "${CTDB_BASE}/functions" - -load_script_options - -ctdb_setup_state_dir "service" "reclock" - -ctdb_get_reclock_option () -{ - _reclock_opt_file="${CTDB_SCRIPT_VARDIR}/recovery_lock.cache" - - if [ -f "$_reclock_opt_file" ] ; then - . "$_reclock_opt_file" - return - fi - - ctdb_translate_option "cluster" \ - "recovery lock" \ - "CTDB_RECOVERY_LOCK" >"$_reclock_opt_file" - - . "$_reclock_opt_file" -} - -ctdb_get_reclock_option - -# If CTDB_RECOVERY_LOCK specifies a helper then exit because this -# script can't do anything useful. -case "$CTDB_RECOVERY_LOCK" in -!*) exit 0 ;; -esac - case "$1" in init) - ctdb_counter_init - - if [ -n "$CTDB_RECOVERY_LOCK" ] ; then - d=$(dirname "$CTDB_RECOVERY_LOCK") - mkdir -vp "$d" + recovery_lock=$("${CTDB_HELPER_BINDIR}/ctdb-config" \ + get cluster "recovery lock") + # xshellcheck disable=SC2181 + # Above is already complicated enough without embedding into "if" + case $? in + 0) : ;; + 2) exit 0 ;; # ENOENT: not configured + *) die "Unexpected error getting recovery lock configuration" + esac + + if [ -z "$recovery_lock" ] ; then + exit 0 fi - ;; - -monitor) - # Early exit if not using a reclock file - [ -n "$CTDB_RECOVERY_LOCK" ] || exit 0 - # Try to stat the reclock file as a background process so that - # we don't block in case the cluster filesystem is unavailable - ( - if stat "$CTDB_RECOVERY_LOCK" ; then - # We could stat the file, reset the counter - ctdb_counter_init - fi - ) >/dev/null 2>&1 & + # If a helper is specified then exit because this script can't + # do anything useful + case "$recovery_lock" in + !*) exit 0 ;; + esac - ctdb_counter_incr - num_fails=$(ctdb_counter_get) - if [ "$num_fails" -ge 200 ] ; then - echo "Reclock file \"$CTDB_RECOVERY_LOCK\" can not be accessed. Shutting down." - df - sleep 1 - $CTDB shutdown - exit 1 - elif [ "$num_fails" -ge 4 ] ; then - die "ERROR: ${num_fails} consecutive failures checking reclock" - fi + d=$(dirname "$recovery_lock") + mkdir -vp "$d" ;; esac - -exit 0 diff --git a/ctdb/server/ctdb_cluster_mutex.c b/ctdb/server/ctdb_cluster_mutex.c index 719b5c14f7a..2fbe301420e 100644 --- a/ctdb/server/ctdb_cluster_mutex.c +++ b/ctdb/server/ctdb_cluster_mutex.c @@ -21,6 +21,7 @@ #include "replace.h" #include "system/network.h" +#include "system/filesys.h" #include <tevent.h> @@ -32,8 +33,6 @@ #include "lib/util/blocking.h" #include "ctdb_private.h" -#include "common/common.h" -#include "common/logging.h" #include "ctdb_cluster_mutex.h" @@ -122,21 +121,56 @@ static bool cluster_mutex_helper_args_file(TALLOC_CTX *mem_ctx, const char *argstring, char ***argv) { - bool ok; + struct stat st; + size_t size = sizeof(cluster_mutex_helper); + const char *t; char **args = NULL; + int ret; + + if (cluster_mutex_helper[0] != '\0') { + goto helper_done; + } - ok = ctdb_set_helper("cluster mutex helper", - cluster_mutex_helper, - sizeof(cluster_mutex_helper), - "CTDB_CLUSTER_MUTEX_HELPER", - CTDB_HELPER_BINDIR, - "ctdb_mutex_fcntl_helper"); - if (! ok) { - DBG_ERR("ctdb exiting with error: " - "Unable to set cluster mutex helper\n"); + t = getenv("CTDB_CLUSTER_MUTEX_HELPER"); + if (t != NULL) { + size_t len; + + len = strlcpy(cluster_mutex_helper, t, size); + if (len >= size) { + DBG_ERR("error: CTDB_CLUSTER_MUTEX_HELPER too long\n"); + exit(1); + } + } else { + ret = snprintf(cluster_mutex_helper, + size, + "%s/%s", + CTDB_HELPER_BINDIR, + "ctdb_mutex_fcntl_helper"); + if (ret < 0 || (size_t)ret >= size) { + D_ERR("Unable to set cluster mutex helper - " + "path too long\n"); + exit(1); + } + } + + ret = stat(cluster_mutex_helper, &st); + if (ret != 0) { + D_ERR("Unable to set cluster mutex helper \"%s\" - %s\n", + cluster_mutex_helper, + strerror(errno)); exit(1); } + if ((st.st_mode & S_IXUSR) == 0) { + D_ERR("Unable to set cluster_mutex helper \"%s\" - " + "not executable\n", + cluster_mutex_helper); + exit(1); + } + + D_NOTICE("Set cluster mutex helper to \"%s\"\n", cluster_mutex_helper); + +helper_done: /* Array includes default helper, file and NULL */ args = talloc_array(mem_ctx, char *, 3); @@ -234,7 +268,7 @@ ctdb_cluster_mutex(TALLOC_CTX *mem_ctx, h = talloc(mem_ctx, struct ctdb_cluster_mutex_handle); if (h == NULL) { - DEBUG(DEBUG_ERR, (__location__ " out of memory\n")); + DBG_ERR("out of memory\n"); return NULL; } @@ -246,7 +280,7 @@ ctdb_cluster_mutex(TALLOC_CTX *mem_ctx, ret = pipe(h->fd); if (ret != 0) { talloc_free(h); - DEBUG(DEBUG_ERR, (__location__ " Failed to open pipe\n")); + DBG_ERR("Failed to open pipe\n"); return NULL; } set_close_on_exec(h->fd[0]); @@ -302,7 +336,7 @@ ctdb_cluster_mutex(TALLOC_CTX *mem_ctx, execv(args[0], args); /* Only happens on error */ - DEBUG(DEBUG_ERR, (__location__ "execv() failed\n")); + DBG_ERR("execv() failed\n"); _exit(1); } @@ -313,7 +347,7 @@ ctdb_cluster_mutex(TALLOC_CTX *mem_ctx, DBG_WARNING("Failed to unblock SIGTERM (%d)\n", errno); } - DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d\n", h->fd[0])); + DBG_DEBUG("Created PIPE FD:%d\n", h->fd[0]); set_close_on_exec(h->fd[0]); close(h->fd[1]); diff --git a/ctdb/server/ctdb_mutex_fcntl_helper.c b/ctdb/server/ctdb_mutex_fcntl_helper.c index 7b66c78cd8e..1448a9062a0 100644 --- a/ctdb/server/ctdb_mutex_fcntl_helper.c +++ b/ctdb/server/ctdb_mutex_fcntl_helper.c @@ -3,6 +3,10 @@ Copyright (C) Martin Schwenke 2015 + wait_for_parent() code from ctdb_lock_helper.c: + + Copyright (C) Amitay Isaacs 2013 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or @@ -21,7 +25,11 @@ #include "system/filesys.h" #include "system/network.h" +#include <tevent.h> + #include "lib/util/sys_rw.h" +#include "lib/util/tevent_unix.h" +#include "lib/util/util.h" /* protocol.h is just needed for ctdb_sock_addr, which is used in system.h */ #include "protocol/protocol.h" @@ -50,7 +58,6 @@ static char fcntl_lock(const char *file, int *outfd) if (fcntl(fd, F_SETLK, &lock) != 0) { int saved_errno = errno; close(fd); - fd = -1; if (saved_errno == EACCES || saved_errno == EAGAIN) { /* Lock contention, fail silently */ @@ -69,40 +76,364 @@ static char fcntl_lock(const char *file, int *outfd) return '0'; } +/* + * Wait and see if the parent exits + */ + +struct wait_for_parent_state { + struct tevent_context *ev; + pid_t ppid; +}; + +static void wait_for_parent_check(struct tevent_req *subreq); + +static struct tevent_req *wait_for_parent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + pid_t ppid) +{ + struct tevent_req *req, *subreq; + struct wait_for_parent_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wait_for_parent_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->ppid = ppid; + + if (ppid == 1) { + fprintf(stderr, "parent == 1\n"); + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = tevent_wakeup_send(state, ev, + tevent_timeval_current_ofs(5,0)); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wait_for_parent_check, req); + + return req; +} + +static void wait_for_parent_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wait_for_parent_state *state = tevent_req_data( + req, struct wait_for_parent_state); + bool status; + + status = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! status) { + /* Ignore error */ + fprintf(stderr, + "ctdb_mutex_fcntl_helper: " + "tevent_wakeup_recv() failed\n"); + } + + if (kill(state->ppid, 0) == -1 && errno == ESRCH) { + fprintf(stderr, "parent gone\n"); + tevent_req_done(req); + return; + } + + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs(5,0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wait_for_parent_check, req); +} + +static bool wait_for_parent_recv(struct tevent_req *req) +{ + if (tevent_req_is_unix_error(req, NULL)) { + return false; + } + + return true; +} + +/* + * Wait and check for lost lock - file removed or replaced + */ + +struct wait_for_lost_state { + struct tevent_context *ev; + const char *lock_file; + ino_t inode; + unsigned long recheck_time; +}; + +static void wait_for_lost_check(struct tevent_req *subreq); + +static struct tevent_req *wait_for_lost_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *lock_file, + int fd, + unsigned long recheck_time) +{ + struct tevent_req *req, *subreq; + struct wait_for_lost_state *state; + struct stat sb; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct wait_for_lost_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->lock_file = lock_file; + state->recheck_time = recheck_time; + + ret = fstat(fd, &sb); + if (ret != 0) { + fprintf(stderr, + "ctdb_mutex_fcntl_helper: " + "lock lost - lock file \"%s\" check failed (ret=%d)\n", + state->lock_file, + errno); + tevent_req_done(req); + return tevent_req_post(req, ev); + } + state->inode = sb.st_ino; + + subreq = tevent_wakeup_send( + state, + ev, + tevent_timeval_current_ofs(state->recheck_time, 0)); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wait_for_lost_check, req); + + return req; +} + +static void wait_for_lost_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wait_for_lost_state *state = tevent_req_data( + req, struct wait_for_lost_state); + bool status; + struct stat sb; + int ret; + + status = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! status) { + /* Ignore error */ + fprintf(stderr, + "ctdb_mutex_fcntl_helper: " + "tevent_wakeup_recv() failed\n"); + } + + ret = stat(state->lock_file, &sb); + if (ret != 0) { + fprintf(stderr, + "ctdb_mutex_fcntl_helper: " + "lock lost - lock file \"%s\" check failed (ret=%d)\n", + state->lock_file, + errno); + tevent_req_done(req); + return; + } + + if (sb.st_ino != state->inode) { + fprintf(stderr, + "ctdb_mutex_fcntl_helper: " + "lock lost - lock file \"%s\" inode changed\n", + state->lock_file); + tevent_req_done(req); + return; + } + + subreq = tevent_wakeup_send( + state, + state->ev, + tevent_timeval_current_ofs(state->recheck_time, 0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wait_for_lost_check, req); +} + +static bool wait_for_lost_recv(struct tevent_req *req) +{ + if (tevent_req_is_unix_error(req, NULL)) { + return false; + } + + return true; +} + +/* + * Wait for a reason to exit, indicating that the lock is lost + */ + +struct wait_for_exit_state { +}; + +static void wait_for_exit_parent_done(struct tevent_req *subreq); +static void wait_for_exit_lost_done(struct tevent_req *subreq); + +static struct tevent_req *wait_for_exit_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + pid_t ppid, + const char *lock_file, + int fd, + unsigned long recheck_time) +{ + struct tevent_req *req, *subreq; + struct wait_for_exit_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wait_for_exit_state); + if (req == NULL) { + return NULL; + } + + subreq = wait_for_parent_send(state, ev, ppid); -- Samba Shared Repository