s3: messages: Implement cleanup of dead records.
authorJeremy Allison <jra@samba.org>
Wed, 2 Apr 2014 23:45:25 +0000 (16:45 -0700)
committerKarolin Seeger <kseeger@samba.org>
Mon, 7 Apr 2014 09:55:50 +0000 (11:55 +0200)
When a smbd process dies, pending messages.tdb records for this process
might not get cleaned up. Implement a cleanup for dead records that is
triggered after a smbd dies uncleanly; the records for that PID are
deleted.

Based on a patchset from Christof Schmitt <cs@samba.org>.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Christof Schmitt <cs@samba.org>
(cherry picked from commit 837671f47670b16726aa96ba7a0902974a1037eb)

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10534
Cleanup messages.tdb record after unclean smbd shutdown

Autobuild-User(v4-0-test): Karolin Seeger <kseeger@samba.org>
Autobuild-Date(v4-0-test): Mon Apr  7 11:55:50 CEST 2014 on sn-devel-104

source3/include/messages.h
source3/lib/messages.c
source3/lib/messages_local.c
source3/smbd/server.c

index 4b45901afda2fe6718fce6af9895d3efde1dac1e..a45f5a5d028e10dd6d73e3f4937f4814c9715009 100644 (file)
@@ -101,6 +101,9 @@ bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx);
 void *messaging_tdb_event(TALLOC_CTX *mem_ctx, struct messaging_context *msg,
                          struct tevent_context *ev);
 
+NTSTATUS messaging_tdb_cleanup(struct messaging_context *msg_ctx,
+                       struct server_id pid);
+
 NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
                              TALLOC_CTX *mem_ctx,
                              struct messaging_backend **presult);
@@ -140,6 +143,9 @@ NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
 void messaging_dispatch_rec(struct messaging_context *msg_ctx,
                            struct messaging_rec *rec);
 
+void messaging_cleanup_server(struct messaging_context *msg_ctx,
+                               struct server_id pid);
+
 #include "librpc/gen_ndr/ndr_messaging.h"
 
 #endif
index cd763e7265af048e53855db3dcde054114478349..5e738c7461992ab9e7bafac1e71cab8b760747e5 100644 (file)
@@ -397,4 +397,21 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
        return;
 }
 
+/*
+  Call when a process has terminated abnormally.
+*/
+void messaging_cleanup_server(struct messaging_context *msg_ctx,
+                               struct server_id server)
+{
+       if (server_id_is_disconnected(&server)) {
+               return;
+       }
+
+       if (!procid_is_local(&server)) {
+               return;
+       }
+
+       (void)messaging_tdb_cleanup(msg_ctx, server);
+
+}
 /** @} **/
index 6b63d7292542ed85176656c7a0a8987ad9492c1c..859eeb858e390d6ec0ee2aa88baf2ccb345383b6 100644 (file)
@@ -45,6 +45,7 @@
 #include "includes.h"
 #include "system/filesys.h"
 #include "messages.h"
+#include "serverid.h"
 #include "lib/tdb_wrap/tdb_wrap.h"
 #include "lib/param/param.h"
 
@@ -200,6 +201,43 @@ static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
        return kbuf;
 }
 
+/*******************************************************************
+ Called when a process has terminated abnormally. Remove all messages
+ pending for it.
+******************************************************************/
+
+NTSTATUS messaging_tdb_cleanup(struct messaging_context *msg_ctx,
+                               struct server_id pid)
+{
+       struct messaging_tdb_context *ctx = talloc_get_type(
+                                       msg_ctx->local->private_data,
+                                       struct messaging_tdb_context);
+       struct tdb_wrap *tdb = ctx->tdb;
+       TDB_DATA key;
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       key = message_key_pid(frame, pid);
+       /*
+        * We have to lock the key to avoid
+        * races in case the server_id was
+        * re-used and is active (a remote
+        * possibility, true). We only
+        * clean up the database if we
+        * know server_id doesn't exist
+        * while checked under the chainlock.
+        */
+       if (tdb_chainlock(tdb->tdb, key) != 0) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_LOCK_NOT_GRANTED;
+       }
+       if (!serverid_exists(&pid)) {
+               (void)tdb_delete(tdb->tdb, key);
+       }
+       tdb_chainunlock(tdb->tdb, key);
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
 /*
   Fetch the messaging array for a process
  */
index a86fa488c80767ff04b526588019cf1b56674f69..86c20baf4357f4ada670cddc51d1e4e8686d3e23 100644 (file)
@@ -455,6 +455,13 @@ static void remove_child_pid(struct smbd_parent_context *parent,
                                                parent);
                        DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
                }
+
+               /*
+                * Ensure we flush any stored messages
+                * queued for the child process that
+                * terminated uncleanly.
+                */
+               messaging_cleanup_server(parent->msg_ctx, child_id);
        }
 
        if (!serverid_deregister(child_id)) {