The branch, master has been updated via 0ec0182 ctdb-daemon: Log when removing stale Unix domain socket via 8eff9e9 ctdb-daemon: Drop attempt to connect to Unix domain socket via d719a87 ctdb-daemon: Don't try to reopen TDB files via 1e501c7 ctdb-daemon: Bind to Unix domain socket after PID file creation via 5148e02 ctdb-daemon: Use PID file abstraction via 97b6ac7 ctdb-common: Add routines to manage PID file via 8b979c7 ctdb-locking: Restrict lock debugging to once per second via cdc46ef ctdb-locking: Log if ctdb is unable to take db locks in INACTIVE state via 25c7fa2 ctdb-tests: Produce clear errors for missing IPv6 node IP addresses via 8772e1c ctdb-tests: Fix typo in local daemons IPv6 setup from 8f0cc7e remove duplicate lines from 'man smb.conf'
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 0ec01826d32019b06dd10bb9b6ea5232786d5699 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Sep 22 14:52:55 2016 +1000 ctdb-daemon: Log when removing stale Unix domain socket BUG: https://bugzilla.samba.org/show_bug.cgi?id=12287 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> Autobuild-User(master): Amitay Isaacs <ami...@samba.org> Autobuild-Date(master): Thu Sep 22 12:28:12 CEST 2016 on sn-devel-144 commit 8eff9e96037627b1e4adf3ccc8da94ef8f0bad2a Author: Martin Schwenke <mar...@meltin.net> Date: Thu Sep 22 14:47:02 2016 +1000 ctdb-daemon: Drop attempt to connect to Unix domain socket This was a weak attempt at exclusivity. PID file creation now does that properly. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12287 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit d719a87fe021b0c704fc4b12ddfc0345fe3af146 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Sep 22 14:46:12 2016 +1000 ctdb-daemon: Don't try to reopen TDB files There aren't any open at this stage. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12287 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 1e501c77492d25b760c7b10849460ee6490f39dc Author: Martin Schwenke <mar...@meltin.net> Date: Thu Sep 22 14:43:58 2016 +1000 ctdb-daemon: Bind to Unix domain socket after PID file creation No use touching the socket if PID file creation fails. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12287 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 5148e02adb7b2ea34da9c826a682c1387773402b Author: Martin Schwenke <mar...@meltin.net> Date: Thu Sep 22 14:35:03 2016 +1000 ctdb-daemon: Use PID file abstraction BUG: https://bugzilla.samba.org/show_bug.cgi?id=12287 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 97b6ac7f662d8de316ed520e038779e79bcdb7bc Author: Amitay Isaacs <ami...@gmail.com> Date: Mon Sep 19 16:30:12 2016 +1000 ctdb-common: Add routines to manage PID file BUG: https://bugzilla.samba.org/show_bug.cgi?id=12287 Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit 8b979c729b66c8a9c3eeff971ad5e34415ed44d7 Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Sep 22 14:06:44 2016 +1000 ctdb-locking: Restrict lock debugging to once per second Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit cdc46ef9d72b0beb8696c8b6f7c3c40768834045 Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Sep 22 13:58:06 2016 +1000 ctdb-locking: Log if ctdb is unable to take db locks in INACTIVE state This is useful information if ctdb is unable to freeze any of the databases on banning or stopping. Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit 25c7fa285dae93ac867b6f549c1f8b90586a8017 Author: Martin Schwenke <mar...@meltin.net> Date: Wed Sep 21 11:51:50 2016 +1000 ctdb-tests: Produce clear errors for missing IPv6 node IP addresses This replaces a broken FIXME comment in the code. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 8772e1c795e58cc881f4c208c51df2a26b53d361 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Sep 8 19:01:31 2016 +1000 ctdb-tests: Fix typo in local daemons IPv6 setup This should be a sub-shell not an arithmetic expansion. Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> ----------------------------------------------------------------------- Summary of changes: ctdb/common/pidfile.c | 143 ++++++++++++++++ ctdb/common/pidfile.h | 51 ++++++ ctdb/server/ctdb_daemon.c | 66 +++----- ctdb/server/ctdb_lock.c | 23 ++- ctdb/tests/cunit/pidfile_test_001.sh | 8 + ctdb/tests/simple/scripts/local_daemons.bash | 35 +++- ctdb/tests/src/pidfile_test.c | 241 +++++++++++++++++++++++++++ ctdb/wscript | 4 +- 8 files changed, 520 insertions(+), 51 deletions(-) create mode 100644 ctdb/common/pidfile.c create mode 100644 ctdb/common/pidfile.h create mode 100755 ctdb/tests/cunit/pidfile_test_001.sh create mode 100644 ctdb/tests/src/pidfile_test.c Changeset truncated at 500 lines: diff --git a/ctdb/common/pidfile.c b/ctdb/common/pidfile.c new file mode 100644 index 0000000..b3f29e3 --- /dev/null +++ b/ctdb/common/pidfile.c @@ -0,0 +1,143 @@ +/* + Create and remove pidfile + + Copyright (C) Amitay Isaacs 2016 + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include <talloc.h> + +#include "common/pidfile.h" + +struct pidfile_context { + const char *pidfile; + int fd; + pid_t pid; +}; + +static int pidfile_context_destructor(struct pidfile_context *pid_ctx); + +int pidfile_create(TALLOC_CTX *mem_ctx, const char *pidfile, + struct pidfile_context **result) +{ + struct pidfile_context *pid_ctx; + struct flock lck; + char tmp[64]; + int fd, ret = 0; + int len; + ssize_t nwritten; + + pid_ctx = talloc_zero(mem_ctx, struct pidfile_context); + if (pid_ctx == NULL) { + return ENOMEM; + } + + pid_ctx->pidfile = talloc_strdup(pid_ctx, pidfile); + if (pid_ctx->pidfile == NULL) { + ret = ENOMEM; + goto fail; + } + + pid_ctx->pid = getpid(); + + fd = open(pidfile, O_CREAT|O_WRONLY|O_NONBLOCK, 0644); + if (fd == -1) { + ret = errno; + goto fail; + } + + pid_ctx->fd = fd; + + lck = (struct flock) { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + }; + + do { + ret = fcntl(fd, F_SETLK, &lck); + } while ((ret == -1) && (errno == EINTR)); + + if (ret != 0) { + ret = errno; + goto fail; + } + + do { + ret = ftruncate(fd, 0); + } while ((ret == -1) && (errno == EINTR)); + + if (ret == -1) { + ret = EIO; + goto fail_unlink; + } + + len = snprintf(tmp, sizeof(tmp), "%u\n", pid_ctx->pid); + if (len < 0) { + ret = EIO; + goto fail_unlink; + } + + do { + nwritten = write(fd, tmp, len); + } while ((nwritten == -1) && (errno == EINTR)); + + if ((nwritten == -1) || (nwritten != len)) { + ret = EIO; + goto fail_unlink; + } + + talloc_set_destructor(pid_ctx, pidfile_context_destructor); + + *result = pid_ctx; + return 0; + +fail_unlink: + unlink(pidfile); + close(fd); + +fail: + talloc_free(pid_ctx); + return ret; +} + +static int pidfile_context_destructor(struct pidfile_context *pid_ctx) +{ + struct flock lck; + int ret; + + if (getpid() != pid_ctx->pid) { + return 0; + } + + lck = (struct flock) { + .l_type = F_UNLCK, + .l_whence = SEEK_SET, + }; + + (void) unlink(pid_ctx->pidfile); + + do { + ret = fcntl(pid_ctx->fd, F_SETLK, &lck); + } while ((ret == -1) && (errno == EINTR)); + + do { + ret = close(pid_ctx->fd); + } while ((ret == -1) && (errno == EINTR)); + + return 0; +} diff --git a/ctdb/common/pidfile.h b/ctdb/common/pidfile.h new file mode 100644 index 0000000..1450134 --- /dev/null +++ b/ctdb/common/pidfile.h @@ -0,0 +1,51 @@ +/* + Create and remove pidfile + + Copyright (C) Amitay Isaacs 2016 + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __CTDB_PIDFILE_H__ +#define __CTDB_PIDFILE_H__ + +#include <talloc.h> + +/** + * @file pidfile.h + * + * @brief Routines to manage PID file + */ + +/** + * @brief Abstract struct to store pidfile details + */ +struct pidfile_context; + +/** + * @brief Create a PID file + * + * This creates a PID file, locks it, and writes PID. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] pidfile Path of PID file + * @param[out] result Pidfile context + * @return 0 on success, errno on failure + * + * Freeing the pidfile_context, will delete the pidfile. + */ +int pidfile_create(TALLOC_CTX *mem_ctx, const char *pidfile, + struct pidfile_context **result); + +#endif /* __CTDB_PIDFILE_H__ */ diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c index a1579f9..fc1ce27 100644 --- a/ctdb/server/ctdb_daemon.c +++ b/ctdb/server/ctdb_daemon.c @@ -44,6 +44,7 @@ #include "common/system.h" #include "common/common.h" #include "common/logging.h" +#include "common/pidfile.h" struct ctdb_client_pid_list { struct ctdb_client_pid_list *next, *prev; @@ -53,6 +54,7 @@ struct ctdb_client_pid_list { }; const char *ctdbd_pidfile = NULL; +static struct pidfile_context *ctdbd_pidfile_ctx = NULL; static void daemon_incoming_packet(void *, struct ctdb_req_header *); @@ -1005,17 +1007,16 @@ static int ux_socket_bind(struct ctdb_context *ctdb) addr.sun_family = AF_UNIX; strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path)-1); - /* First check if an old ctdbd might be running */ - if (connect(ctdb->daemon.sd, - (struct sockaddr *)&addr, sizeof(addr)) == 0) { - DEBUG(DEBUG_CRIT, - ("Something is already listening on ctdb socket '%s'\n", - ctdb->daemon.name)); - goto failed; - } - /* Remove any old socket */ - unlink(ctdb->daemon.name); + ret = unlink(ctdb->daemon.name); + if (ret == 0) { + DEBUG(DEBUG_WARNING, + ("Removed stale socket %s\n", ctdb->daemon.name)); + } else if (errno != ENOENT) { + DEBUG(DEBUG_ERR, + ("Failed to remove stale socket %s\n", ctdb->daemon.name)); + return -1; + } set_close_on_exec(ctdb->daemon.sd); @@ -1155,32 +1156,21 @@ static void ctdb_tevent_trace(enum tevent_trace_point tp, static void ctdb_remove_pidfile(void) { - /* Only the main ctdbd's PID matches the SID */ - if (ctdbd_pidfile != NULL && getsid(0) == getpid()) { - if (unlink(ctdbd_pidfile) == 0) { - DEBUG(DEBUG_NOTICE, ("Removed PID file %s\n", - ctdbd_pidfile)); - } else { - DEBUG(DEBUG_WARNING, ("Failed to Remove PID file %s\n", - ctdbd_pidfile)); - } - } + TALLOC_FREE(ctdbd_pidfile_ctx); } -static void ctdb_create_pidfile(pid_t pid) +static void ctdb_create_pidfile(TALLOC_CTX *mem_ctx) { if (ctdbd_pidfile != NULL) { - FILE *fp; - - fp = fopen(ctdbd_pidfile, "w"); - if (fp == NULL) { - DEBUG(DEBUG_ALERT, - ("Failed to open PID file %s\n", ctdbd_pidfile)); + int ret = pidfile_create(mem_ctx, ctdbd_pidfile, + &ctdbd_pidfile_ctx); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Failed to create PID file %s\n", + ctdbd_pidfile)); exit(11); } - fprintf(fp, "%d\n", pid); - fclose(fp); DEBUG(DEBUG_NOTICE, ("Created PID file %s\n", ctdbd_pidfile)); atexit(ctdb_remove_pidfile); } @@ -1242,19 +1232,10 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork) int res, ret = -1; struct tevent_fd *fde; - /* create a unix domain stream socket to listen to */ - res = ux_socket_bind(ctdb); - if (res!=0) { - DEBUG(DEBUG_ALERT,("Cannot continue. Exiting!\n")); - exit(10); - } - if (do_fork && fork()) { return 0; } - tdb_reopen_all(false); - if (do_fork) { if (setsid() == -1) { ctdb_die(ctdb, "Failed to setsid()\n"); @@ -1271,7 +1252,14 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork) ctdb->ctdbd_pid = getpid(); DEBUG(DEBUG_ERR, ("Starting CTDBD (Version %s) as PID: %u\n", CTDB_VERSION_STRING, ctdb->ctdbd_pid)); - ctdb_create_pidfile(ctdb->ctdbd_pid); + ctdb_create_pidfile(ctdb); + + /* create a unix domain stream socket to listen to */ + res = ux_socket_bind(ctdb); + if (res!=0) { + DEBUG(DEBUG_ALERT,("Cannot continue. Exiting!\n")); + exit(10); + } /* Make sure we log something when the daemon terminates. * This must be the first exit handler to run (so the last to diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index 405a29e..3a58711 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -392,8 +392,10 @@ static void ctdb_lock_timeout_handler(struct tevent_context *ev, void *private_data) { static char debug_locks[PATH_MAX+1] = ""; + static struct timeval last_debug_time; struct lock_context *lock_ctx; struct ctdb_context *ctdb; + struct timeval now; pid_t pid; double elapsed_time; int new_timer; @@ -401,12 +403,6 @@ static void ctdb_lock_timeout_handler(struct tevent_context *ev, lock_ctx = talloc_get_type_abort(private_data, struct lock_context); ctdb = lock_ctx->ctdb; - /* If a node stopped/banned, don't spam the logs */ - if (ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_INACTIVE) { - lock_ctx->ttimer = NULL; - return; - } - elapsed_time = timeval_elapsed(&lock_ctx->start_time); if (lock_ctx->ctdb_db) { DEBUG(DEBUG_WARNING, @@ -419,6 +415,19 @@ static void ctdb_lock_timeout_handler(struct tevent_context *ev, elapsed_time)); } + /* If a node stopped/banned, don't spam the logs */ + if (ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_INACTIVE) { + goto skip_lock_debug; + } + + /* Restrict log debugging to once per second */ + now = timeval_current(); + if (last_debug_time.tv_sec == now.tv_sec) { + goto skip_lock_debug; + } + + last_debug_time.tv_sec = now.tv_sec; + if (ctdb_set_helper("lock debugging helper", debug_locks, sizeof(debug_locks), "CTDB_DEBUG_LOCKS", @@ -435,6 +444,8 @@ static void ctdb_lock_timeout_handler(struct tevent_context *ev, " Unable to setup lock debugging\n")); } +skip_lock_debug: + /* Back-off logging if lock is not obtained for a long time */ if (elapsed_time < 100.0) { new_timer = 10; diff --git a/ctdb/tests/cunit/pidfile_test_001.sh b/ctdb/tests/cunit/pidfile_test_001.sh new file mode 100755 index 0000000..620682e --- /dev/null +++ b/ctdb/tests/cunit/pidfile_test_001.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +pidfile=$(mktemp --tmpdir="$TEST_VAR_DIR") + +ok_null +unit_test pidfile_test $pidfile diff --git a/ctdb/tests/simple/scripts/local_daemons.bash b/ctdb/tests/simple/scripts/local_daemons.bash index 2d6ec56..8624cb9 100644 --- a/ctdb/tests/simple/scripts/local_daemons.bash +++ b/ctdb/tests/simple/scripts/local_daemons.bash @@ -31,6 +31,21 @@ config_from_environment () sed -e 's@=\([^"]\)@="\1@' -e 's@[^"]$@&"@' -e 's@="$@&"@' } +# If the given IP is hosted then print 2 items: maskbits and iface +have_ip () +{ + local addr="$1" + local bits t + + case "$addr" in + *:*) bits=128 ;; + *) bits=32 ;; + esac + + t=$(ip addr show to "${addr}/${bits}") + [ -n "$t" ] +} + setup_ctdb () { mkdir -p "${TEST_VAR_DIR}/test.db/persistent" @@ -53,13 +68,19 @@ setup_ctdb () mkdir -p "${TEST_VAR_DIR}/events.d" cp -p "${events_d}/"* "${TEST_VAR_DIR}/events.d/" + local have_all_ips=true local i for i in $(seq 1 $TEST_LOCAL_DAEMONS) ; do - if [ "${CTDB_USE_IPV6}x" != "x" ]; then - j=$((printf "%02x" $i)) - echo "fd00::5357:5f${j}" >>"$CTDB_NODES" - # FIXME: need to add addresses to lo as root before running :-( - # ip addr add "fc00:10::${i}/64" dev lo + if [ -n "$CTDB_USE_IPV6" ]; then + local j=$(printf "%02x" $i) + local node_ip="fd00::5357:5f${j}" + if have_ip "$node_ip" ; then + echo "$node_ip" >>"$CTDB_NODES" + else + echo "ERROR: ${node_ip} not on an interface, please add it" + have_all_ips=false + fi + # 2 public addresses on most nodes, just to make things interesting. if [ $(($i - 1)) -ne $no_public_ips ] ; then echo "fc00:10::1:${i}/64 lo" >>"$public_addresses_all" @@ -76,6 +97,10 @@ setup_ctdb () fi done + if ! $have_all_ips ; then + return 1 + fi + local pnn for pnn in $(seq 0 $(($TEST_LOCAL_DAEMONS - 1))) ; do local public_addresses_mine="${TEST_VAR_DIR}/public_addresses.${pnn}" diff --git a/ctdb/tests/src/pidfile_test.c b/ctdb/tests/src/pidfile_test.c new file mode 100644 index 0000000..ad8bf14 --- /dev/null +++ b/ctdb/tests/src/pidfile_test.c @@ -0,0 +1,241 @@ +/* + pidfile tests + + Copyright (C) Amitay Isaacs 2016 + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/wait.h" + +#include <assert.h> + +#include "common/pidfile.c" + + +/* create pid file, check pid file exists, check pid and remove pid file */ +static void test1(const char *pidfile) +{ + struct pidfile_context *pid_ctx; -- Samba Shared Repository