The branch, master has been updated via b486398 smbd: Move a message_send_all to the cleanupd via de6fe2a smbd: Move cleanupd revalidate to a separate fn via bbeabd3 smbd: Move brl_validate to the cleanupd via 14fc901 smbd: Move serverid_deregister() to the cleanupd via 99833c9 smbd: Move messaging_cleanup() to the cleanupd via 1dddba5 smbd: Move smbprofile_cleanup() to the cleanupd via b4b4fd0 smbprofile: Add dst pid to smbprofile_cleanup via e3e0a29 smbd: Implement a cleanup daemon from db99742 build:wafsamba: Waf 1.8 compatible declaration of 'mandatory' configuration tests
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit b486398d06b1c5d82a1e9728d757c79ccc401875 Author: Volker Lendecke <v...@samba.org> Date: Mon Nov 16 08:11:20 2015 +0100 smbd: Move a message_send_all to the cleanupd message_send_all traverses serverid.tdb, which can be expensive Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Autobuild-User(master): Volker Lendecke <v...@samba.org> Autobuild-Date(master): Mon Nov 16 17:55:36 CET 2015 on sn-devel-104 commit de6fe2a1dd6ab03b1c369b61da17fded72305b2d Author: Volker Lendecke <v...@samba.org> Date: Mon Nov 16 08:08:46 2015 +0100 smbd: Move cleanupd revalidate to a separate fn Simple preparation for the next patch... Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit bbeabd346de1e339b1cafbad03d892ac48b3cb25 Author: Volker Lendecke <v...@samba.org> Date: Sat Nov 7 20:18:52 2015 +0100 smbd: Move brl_validate to the cleanupd This walks brlock.tdb, which can be time-consuming. This adds a new includes.h include. It's too much of a pain for me now to make locking/proto.h clean to include on its own. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 14fc9018aa8abfd3255f0f3a1b2b5541e8a9dc61 Author: Volker Lendecke <v...@samba.org> Date: Fri Nov 6 17:01:02 2015 +0100 smbd: Move serverid_deregister() to the cleanupd Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 99833c94288a99d9f106252227842fe991763d56 Author: Volker Lendecke <v...@samba.org> Date: Fri Nov 6 15:32:46 2015 +0100 smbd: Move messaging_cleanup() to the cleanupd Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 1dddba5f173c5db288957ceb448b19c56163b240 Author: Volker Lendecke <v...@samba.org> Date: Fri Nov 6 15:21:59 2015 +0100 smbd: Move smbprofile_cleanup() to the cleanupd Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit b4b4fd0ba0f838cc30d7c331dae33335015096f7 Author: Volker Lendecke <v...@samba.org> Date: Fri Nov 6 14:55:35 2015 +0100 smbprofile: Add dst pid to smbprofile_cleanup The consolidation will soon be done by a separate process. We need to avoid the getpid() call in smbprofile_cleanup(). Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit e3e0a295c3fc25391260a8bb7d7d29137f7129fa Author: Volker Lendecke <v...@samba.org> Date: Mon Nov 2 12:47:13 2015 +0100 smbd: Implement a cleanup daemon We do way too much stuff in the parent smbd in remove_child_pid(). In particular accessing ctdbd is not a good idea when ctdbd is stuck in something. We've had a case where smbd exited itself with "ctdb timeout" being set to 60 seconds. ctdb was just stuck doing recoveries, and the parent smbd was sitting in serverid_exists trying to retrieve a record for a child that had exited. Not good. This daemon sits there as parent->cleanupd and receives MSG_SMB_NOTIFY_CLEANUP messages that hold the serverid and exit status of a former child. The next commits will step by step empty remove_child_pid in the parent and move the tasks to the helper. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/include/smbprofile.h | 4 +- source3/profile/profile.c | 4 +- source3/smbd/server.c | 161 +++++++++++++++++---- source3/smbd/smbd_cleanupd.c | 156 ++++++++++++++++++++ lib/util/iov_buf.h => source3/smbd/smbd_cleanupd.h | 21 +-- source3/wscript_build | 2 +- 6 files changed, 308 insertions(+), 40 deletions(-) create mode 100644 source3/smbd/smbd_cleanupd.c copy lib/util/iov_buf.h => source3/smbd/smbd_cleanupd.h (68%) Changeset truncated at 500 lines: diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h index 76d9d2b..c771fd4 100644 --- a/source3/include/smbprofile.h +++ b/source3/include/smbprofile.h @@ -533,7 +533,7 @@ static inline bool smbprofile_dump_pending(void) void smbprofile_dump(void); -void smbprofile_cleanup(pid_t pid); +void smbprofile_cleanup(pid_t pid, pid_t dst); void smbprofile_stats_accumulate(struct profile_stats *acc, const struct profile_stats *add); void smbprofile_collect(struct profile_stats *stats); @@ -610,7 +610,7 @@ static inline void smbprofile_dump(void) return; } -static inline void smbprofile_cleanup(pid_t pid) +static inline void smbprofile_cleanup(pid_t pid, pid_t dst) { return; } diff --git a/source3/profile/profile.c b/source3/profile/profile.c index 00cb3e5..1464a42 100644 --- a/source3/profile/profile.c +++ b/source3/profile/profile.c @@ -312,7 +312,7 @@ void smbprofile_dump(void) return; } -void smbprofile_cleanup(pid_t pid) +void smbprofile_cleanup(pid_t pid, pid_t dst) { TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) }; struct profile_stats s = {}; @@ -336,7 +336,7 @@ void smbprofile_cleanup(pid_t pid) tdb_delete(smbprofile_state.internal.db->tdb, key); tdb_chainunlock(smbprofile_state.internal.db->tdb, key); - pid = getpid(); + pid = dst; ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key); if (ret != 0) { return; diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 72c4642..1dd4f89 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -49,6 +49,8 @@ #include "scavenger.h" #include "locking/leases_db.h" #include "smbd/notifyd/notifyd.h" +#include "smbd/smbd_cleanupd.h" +#include "lib/util/sys_rw.h" #ifdef CLUSTER_SUPPORT #include "ctdb_protocol.h" @@ -70,6 +72,8 @@ struct smbd_parent_context { struct smbd_child_pid *children; size_t num_children; + struct server_id cleanupd; + struct tevent_timer *cleanup_te; }; @@ -279,8 +283,10 @@ static int smbd_parent_ctdb_reconfigured( * Someone from the family died, validate our locks */ - messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx), - MSG_SMB_BRL_VALIDATE, NULL, 0); + if (am_parent) { + messaging_send_buf(msg_ctx, am_parent->cleanupd, + MSG_SMB_BRL_VALIDATE, NULL, 0); + } return 0; } @@ -405,6 +411,118 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive) return tevent_req_poll(req, ev); } +static void cleanupd_stopped(struct tevent_req *req); + +static bool cleanupd_init(struct messaging_context *msg, bool interactive, + struct server_id *ppid) +{ + struct tevent_context *ev = messaging_tevent_context(msg); + struct server_id parent_id = messaging_server_id(msg); + struct tevent_req *req; + pid_t pid; + NTSTATUS status; + ssize_t rwret; + int ret; + bool ok; + char c; + int up_pipe[2]; + + if (interactive) { + req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid); + *ppid = messaging_server_id(msg); + return (req != NULL); + } + + ret = pipe(up_pipe); + if (ret == -1) { + DBG_WARNING("pipe failed: %s\n", strerror(errno)); + return false; + } + + pid = fork(); + if (pid == -1) { + DBG_WARNING("fork failed: %s\n", strerror(errno)); + close(up_pipe[0]); + close(up_pipe[1]); + return false; + } + + if (pid != 0) { + + close(up_pipe[1]); + rwret = sys_read(up_pipe[0], &c, 1); + close(up_pipe[0]); + + if (rwret == -1) { + DBG_WARNING("sys_read failed: %s\n", strerror(errno)); + return false; + } + if (rwret == 0) { + DBG_WARNING("cleanupd could not start\n"); + return false; + } + if (c != 0) { + DBG_WARNING("cleanupd returned %d\n", (int)c); + return false; + } + + DBG_DEBUG("Started cleanupd pid=%d\n", (int)pid); + + *ppid = pid_to_procid(pid); + return true; + } + + close(up_pipe[0]); + + status = reinit_after_fork(msg, ev, true, "cleanupd"); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("reinit_after_fork failed: %s\n", + nt_errstr(status)); + c = 1; + sys_write(up_pipe[1], &c, 1); + + exit(1); + } + + req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid); + if (req == NULL) { + DBG_WARNING("smbd_cleanupd_send failed\n"); + c = 2; + sys_write(up_pipe[1], &c, 1); + + exit(1); + } + + tevent_req_set_callback(req, cleanupd_stopped, msg); + + c = 0; + rwret = sys_write(up_pipe[1], &c, 1); + close(up_pipe[1]); + + if (rwret == -1) { + DBG_WARNING("sys_write failed: %s\n", strerror(errno)); + exit(1); + } + if (rwret != 1) { + DBG_WARNING("sys_write could not write result\n"); + exit(1); + } + + ok = tevent_req_poll(req, ev); + if (!ok) { + DBG_WARNING("tevent_req_poll returned %s\n", strerror(errno)); + } + exit(0); +} + +static void cleanupd_stopped(struct tevent_req *req) +{ + NTSTATUS status; + + status = smbd_cleanupd_recv(req); + DBG_WARNING("cleanupd stopped: %s\n", nt_errstr(status)); +} + /* at most every smbd:cleanuptime seconds (default 20), we scan the BRL and locking database for entries to cleanup. As a side effect this @@ -427,11 +545,8 @@ static void cleanup_timeout_fn(struct tevent_context *event_ctx, parent->cleanup_te = NULL; - DEBUG(1,("Cleaning up brl and lock database after unclean shutdown\n")); - message_send_all(parent->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL); - messaging_send_buf(parent->msg_ctx, - messaging_server_id(parent->msg_ctx), - MSG_SMB_BRL_VALIDATE, NULL, 0); + messaging_send_buf(parent->msg_ctx, parent->cleanupd, + MSG_SMB_UNLOCK, NULL, 0); } static void remove_child_pid(struct smbd_parent_context *parent, @@ -439,19 +554,18 @@ static void remove_child_pid(struct smbd_parent_context *parent, bool unclean_shutdown) { struct smbd_child_pid *child; - struct server_id child_id; - int ret; - - child_id = pid_to_procid(pid); - - ret = messaging_cleanup(parent->msg_ctx, pid); + struct iovec iov[2]; + NTSTATUS status; - if ((ret != 0) && (ret != ENOENT)) { - DEBUG(10, ("%s: messaging_cleanup returned %s\n", - __func__, strerror(ret))); - } + iov[0] = (struct iovec) { .iov_base = (uint8_t *)&pid, + .iov_len = sizeof(pid) }; + iov[1] = (struct iovec) { .iov_base = (uint8_t *)&unclean_shutdown, + .iov_len = sizeof(bool) }; - smbprofile_cleanup(pid); + status = messaging_send_iov(parent->msg_ctx, parent->cleanupd, + MSG_SMB_NOTIFY_CLEANUP, + iov, ARRAY_SIZE(iov), NULL, 0); + DEBUG(10, ("messaging_send_iov returned %s\n", nt_errstr(status))); for (child = parent->children; child != NULL; child = child->next) { if (child->pid == pid) { @@ -487,11 +601,6 @@ static void remove_child_pid(struct smbd_parent_context *parent, DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n")); } } - - if (!serverid_deregister(child_id)) { - DEBUG(1, ("Could not remove pid %d from serverid.tdb\n", - (int)pid)); - } } /**************************************************************************** @@ -893,8 +1002,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent, messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete); messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug); - messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE, - brl_revalidate); messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS, smb_parent_send_to_children); messaging_register(msg_ctx, NULL, MSG_SMB_KILL_CLIENT_IP, @@ -1476,6 +1583,10 @@ extern void build_options(bool screen); exit_daemon("Samba cannot init notification", EACCES); } + if (!cleanupd_init(msg_ctx, interactive, &parent->cleanupd)) { + exit_daemon("Samba cannot init the cleanupd", EACCES); + } + if (!messaging_parent_dgm_cleanup_init(msg_ctx)) { exit(1); } diff --git a/source3/smbd/smbd_cleanupd.c b/source3/smbd/smbd_cleanupd.c new file mode 100644 index 0000000..c940ef1 --- /dev/null +++ b/source3/smbd/smbd_cleanupd.c @@ -0,0 +1,156 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (C) Volker Lendecke 2015 + * + * 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 "includes.h" +#include "smbd_cleanupd.h" +#include "lib/util_procid.h" +#include "lib/util/tevent_ntstatus.h" +#include "lib/util/debug.h" +#include "smbprofile.h" +#include "serverid.h" +#include "locking/proto.h" + +struct smbd_cleanupd_state { + pid_t parent_pid; +}; + +static void smbd_cleanupd_shutdown(struct messaging_context *msg, + void *private_data, uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data); +static void smbd_cleanupd_process_exited(struct messaging_context *msg, + void *private_data, uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data); +static void smbd_cleanupd_unlock(struct messaging_context *msg, + void *private_data, uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data); + +struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct messaging_context *msg, + pid_t parent_pid) +{ + struct tevent_req *req; + struct smbd_cleanupd_state *state; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, struct smbd_cleanupd_state); + if (req == NULL) { + return NULL; + } + state->parent_pid = parent_pid; + + status = messaging_register(msg, req, MSG_SHUTDOWN, + smbd_cleanupd_shutdown); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + status = messaging_register(msg, req, MSG_SMB_NOTIFY_CLEANUP, + smbd_cleanupd_process_exited); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + status = messaging_register(msg, NULL, MSG_SMB_UNLOCK, + smbd_cleanupd_unlock); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + return req; +} + +static void smbd_cleanupd_shutdown(struct messaging_context *msg, + void *private_data, uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + tevent_req_done(req); +} + +static void smbd_cleanupd_unlock(struct messaging_context *msg, + void *private_data, uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + DBG_WARNING("Cleaning up brl and lock database after unclean " + "shutdown\n"); + + message_send_all(msg, MSG_SMB_UNLOCK, NULL, 0, NULL); + + brl_revalidate(msg, private_data, msg_type, server_id, data); +} + +static void smbd_cleanupd_process_exited(struct messaging_context *msg, + void *private_data, uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct smbd_cleanupd_state *state = tevent_req_data( + req, struct smbd_cleanupd_state); + pid_t pid; + struct server_id child_id; + bool unclean_shutdown; + int ret; + + if (data->length != (sizeof(pid) + sizeof(unclean_shutdown))) { + DBG_WARNING("Got invalid length: %zu\n", data->length); + return; + } + + memcpy(&pid, data->data, sizeof(pid)); + memcpy(&unclean_shutdown, data->data + sizeof(pid), + sizeof(unclean_shutdown)); + + DBG_DEBUG("%d exited %sclean\n", (int)pid, + unclean_shutdown ? "un" : ""); + + /* + * Get child_id before messaging_cleanup which wipes the + * unique_id. Not that it really matters here for functionality (the + * child should have properly cleaned up :-)) though, but it looks + * nicer. + */ + child_id = pid_to_procid(pid); + + smbprofile_cleanup(pid, state->parent_pid); + + ret = messaging_cleanup(msg, pid); + + if ((ret != 0) && (ret != ENOENT)) { + DBG_DEBUG("messaging_cleanup returned %s\n", strerror(ret)); + } + + if (!serverid_deregister(child_id)) { + DEBUG(1, ("Could not remove pid %d from serverid.tdb\n", + (int)pid)); + } +} + +NTSTATUS smbd_cleanupd_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} diff --git a/lib/util/iov_buf.h b/source3/smbd/smbd_cleanupd.h similarity index 68% copy from lib/util/iov_buf.h copy to source3/smbd/smbd_cleanupd.h index 8f0ca26..6e5d87f 100644 --- a/lib/util/iov_buf.h +++ b/source3/smbd/smbd_cleanupd.h @@ -1,6 +1,6 @@ /* * Unix SMB/CIFS implementation. - * Samba system utilities + * * Copyright (C) Volker Lendecke 2014 * * This program is free software; you can redistribute it and/or modify @@ -17,16 +17,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef __LIB_IOV_BUF_H__ -#define __LIB_IOV_BUF_H__ +#ifndef __SMBD_CLEANUPD_H__ +#define __SMBD_CLEANUPD_H__ -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> +#include "replace.h" +#include <tevent.h> +#include "messages.h" -ssize_t iov_buflen(const struct iovec *iov, int iovlen); -ssize_t iov_buf(const struct iovec *iov, int iovcnt, - uint8_t *buf, size_t buflen); -bool iov_advance(struct iovec **iov, int *iovcnt, size_t n); +struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct messaging_context *msg, + pid_t parent_pid); +NTSTATUS smbd_cleanupd_recv(struct tevent_req *req); #endif diff --git a/source3/wscript_build b/source3/wscript_build index 4c6390e..b5b5ea0 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -858,7 +858,7 @@ bld.SAMBA3_SUBSYSTEM('LIBLSA', ########################## BINARIES ################################# bld.SAMBA3_BINARY('smbd/smbd', - source='smbd/server.c', + source='smbd/server.c smbd/smbd_cleanupd.c', deps='smbd_base EPMD LSASD FSSD MDSSD', install_path='${SBINDIR}') -- Samba Shared Repository