From: Ralph Boehme Date: Wed, 18 Sep 2019 00:13:20 +0000 (-0700) Subject: cleanupd: Persistent Handle cleanup X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bdfddf91f24b055d9f537be7632de2c048cc7ac4;p=thirdparty%2Fsamba.git cleanupd: Persistent Handle cleanup This adds the logic to trigger scavending Persistent Handles from a few places: - when we got the cluster exclusive ph-cleanup glock after starting - when the current glock holder node died - after an unclean process exit This traverses the node local persistent smbXsrv_open_global_persistent.tdb which is expected to be leightweight and fast. Signed-off-by: Ralph Boehme Reviewed-by: Anoop C S --- diff --git a/source3/smbd/smbd_cleanupd.c b/source3/smbd/smbd_cleanupd.c index 0a50b183311..7d33ac8b1ca 100644 --- a/source3/smbd/smbd_cleanupd.c +++ b/source3/smbd/smbd_cleanupd.c @@ -26,9 +26,26 @@ #include "serverid.h" #include "locking/proto.h" #include "cleanupdb.h" +#include "g_lock.h" +#include "lib/util/util_tdb.h" +#include "smbd/globals.h" +#include "librpc/gen_ndr/ndr_open_files.h" +#include "scavenger.h" +#include "source3/smbd/smbXsrv_open.h" + +struct cleanup_rec { + struct cleanup_rec *prev, *next; + uint64_t open_persistent_id; + struct file_id id; + uint32_t name_hash; +}; struct smbd_cleanupd_state { pid_t parent_pid; + struct messaging_context *msg; + struct g_lock_ctx *glock_ctx; + bool got_glock; + struct cleanup_rec *cleanup_list; }; static void smbd_cleanupd_shutdown(struct messaging_context *msg, @@ -39,6 +56,7 @@ 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_got_glock(struct tevent_req *subreq); struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -46,6 +64,7 @@ struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx, pid_t parent_pid) { struct tevent_req *req; + struct tevent_req *subreq = NULL; struct smbd_cleanupd_state *state; NTSTATUS status; @@ -54,6 +73,13 @@ struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx, return NULL; } state->parent_pid = parent_pid; + state->msg = msg; + + state->glock_ctx = g_lock_ctx_init(state, msg); + if (state->glock_ctx == NULL) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return tevent_req_post(req, ev); + } status = messaging_register(msg, req, MSG_SHUTDOWN, smbd_cleanupd_shutdown); @@ -67,9 +93,111 @@ struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } + if (!lp_persistent_handles()) { + return req; + } + + subreq = g_lock_lock_send(state, + ev, + state->glock_ctx, + string_term_tdb_data("cleanupd"), + G_LOCK_WRITE, + NULL, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, + smbd_cleanupd_got_glock, + req); + return req; } +static int cleanup_ph_fn(struct db_record *dbrec, + struct smbXsrv_open_global0 *global, + TDB_DATA *rc_open_global_key, + void *private_data) +{ + struct smbd_cleanupd_state *state = talloc_get_type_abort( + private_data, struct smbd_cleanupd_state); + struct cleanup_rec *rec = NULL; + + if (global == NULL) { + return 0; + } + + rec = talloc_zero(state, struct cleanup_rec); + if (rec == NULL) { + DBG_ERR("talloc_zero failed\n"); + return -1; + } + *rec = (struct cleanup_rec) { + .open_persistent_id = global->open_persistent_id, + .id = global->file_id, + .name_hash = global->name_hash, + }; + + DLIST_ADD(state->cleanup_list, rec); + return 0; +} + +static NTSTATUS cleanup_ph(struct smbd_cleanupd_state *state) +{ + struct cleanup_rec *rec = NULL; + NTSTATUS status; + + if (!lp_persistent_handles()) { + return NT_STATUS_OK; + } + + DBG_INFO("Cleaning up persistent handles\n"); + + status = smbXsrv_open_global_traverse_per_rec_persistent_read( + cleanup_ph_fn, state); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("PH cleanup failed\n"); + return status; + } + + rec = state->cleanup_list; + while (rec != NULL) { + struct cleanup_rec *next = rec->next; + + scavenger_schedule_disconnected(state->msg, + rec->open_persistent_id, + &rec->id, + rec->name_hash); + DLIST_REMOVE(state->cleanup_list, rec); + TALLOC_FREE(rec); + rec = next; + } + + + return NT_STATUS_OK; +} + +static void smbd_cleanupd_got_glock(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct smbd_cleanupd_state *state = tevent_req_data( + req, struct smbd_cleanupd_state); + NTSTATUS status; + + status = g_lock_lock_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + state->got_glock = true; + + status = cleanup_ph(state); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("Persistent handle cleanup failed\n"); + return; + } +} + static void smbd_cleanupd_shutdown(struct messaging_context *msg, void *private_data, uint32_t msg_type, struct server_id server_id, @@ -77,6 +205,20 @@ static void smbd_cleanupd_shutdown(struct messaging_context *msg, { 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); + NTSTATUS status; + + if (!state->got_glock) { + tevent_req_done(req); + return; + } + + status = g_lock_unlock(state->glock_ctx, + string_term_tdb_data("cleanupd")); + if (tevent_req_nterror(req, status)) { + return; + } tevent_req_done(req); } @@ -126,6 +268,8 @@ static void smbd_cleanupd_process_exited(struct messaging_context *msg, struct cleanupdb_traverse_state cleanup_state; TALLOC_CTX *frame = talloc_stackframe(); struct cleanup_child *child = NULL; + bool unclean = false; + NTSTATUS status; cleanup_state = (struct cleanupdb_traverse_state) { .mem_ctx = frame @@ -170,9 +314,20 @@ static void smbd_cleanupd_process_exited(struct messaging_context *msg, strerror(ret)); } + if (child->unclean) { + unclean = true; + } + DBG_DEBUG("cleaned up pid %d\n", (int)child->pid); } + if (unclean) { + status = cleanup_ph(state); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("Persistent handle cleanup failed\n"); + } + } + TALLOC_FREE(frame); }