smb2_server: call smbXsrv_connection_disconnect_transport() early on network errors
[gd/samba-autobuild/.git] / source3 / smbd / smbd_cleanupd.c
index 6b423e3cd2cb9502bcd9d3aee02165d7a6706730..86c0212e1cced7691032300368005252627a2c27 100644 (file)
@@ -25,6 +25,7 @@
 #include "smbprofile.h"
 #include "serverid.h"
 #include "locking/proto.h"
+#include "cleanupdb.h"
 
 struct smbd_cleanupd_state {
        pid_t parent_pid;
@@ -66,12 +67,6 @@ struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       status = messaging_register(msg, NULL, MSG_SMB_BRL_VALIDATE,
-                                   brl_revalidate);
-       if (tevent_req_nterror(req, status)) {
-               return tevent_req_post(req, ev);
-       }
-
        return req;
 }
 
@@ -85,6 +80,39 @@ static void smbd_cleanupd_shutdown(struct messaging_context *msg,
        tevent_req_done(req);
 }
 
+struct cleanup_child {
+       struct cleanup_child *prev, *next;
+       pid_t pid;
+       bool unclean;
+};
+
+struct cleanupdb_traverse_state {
+       TALLOC_CTX *mem_ctx;
+       bool ok;
+       struct cleanup_child *childs;
+};
+
+static int cleanupdb_traverse_fn(const pid_t pid,
+                                const bool unclean,
+                                void *private_data)
+{
+       struct cleanupdb_traverse_state *cleanup_state =
+               (struct cleanupdb_traverse_state *)private_data;
+       struct cleanup_child *child = NULL;
+
+       child = talloc_zero(cleanup_state->mem_ctx, struct cleanup_child);
+       if (child == NULL) {
+               DBG_ERR("talloc_zero failed\n");
+               return -1;
+       }
+
+       child->pid = pid;
+       child->unclean = unclean;
+       DLIST_ADD(cleanup_state->childs, child);
+
+       return 0;
+}
+
 static void smbd_cleanupd_process_exited(struct messaging_context *msg,
                                         void *private_data, uint32_t msg_type,
                                         struct server_id server_id,
@@ -94,43 +122,58 @@ static void smbd_cleanupd_process_exited(struct messaging_context *msg,
                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;
+       struct cleanupdb_traverse_state cleanup_state;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct cleanup_child *child = NULL;
+
+       cleanup_state = (struct cleanupdb_traverse_state) {
+               .mem_ctx = frame
+       };
+
+       /*
+        * This merely collect childs in a list, whatever we're
+        * supposed to cleanup for every child, it has to take place
+        * *after* the db traverse in a list loop. This is to minimize
+        * locking interaction between the traverse and writers (ie
+        * the parent smbd).
+        */
+       ret = cleanupdb_traverse_read(cleanupdb_traverse_fn, &cleanup_state);
+       if (ret < 0) {
+               DBG_ERR("cleanupdb_traverse_read failed\n");
+               TALLOC_FREE(frame);
+               return;
+       }
 
-       if (data->length != (sizeof(pid) + sizeof(unclean_shutdown))) {
-               DBG_WARNING("Got invalid length: %zu\n", data->length);
+       if (ret == 0) {
+               TALLOC_FREE(frame);
                return;
        }
 
-       memcpy(&pid, data->data, sizeof(pid));
-       memcpy(&unclean_shutdown, data->data + sizeof(pid),
-              sizeof(unclean_shutdown));
+       for (child = cleanup_state.childs;
+            child != NULL;
+            child = child->next)
+       {
+               bool ok;
 
-       DBG_DEBUG("%d exited %sclean\n", (int)pid,
-                 unclean_shutdown ? "un" : "");
+               ok = cleanupdb_delete_child(child->pid);
+               if (!ok) {
+                       DBG_ERR("failed to delete pid %d\n", (int)child->pid);
+               }
 
-       /*
-        * 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(child->pid, state->parent_pid);
 
-       smbprofile_cleanup(pid, state->parent_pid);
+               ret = messaging_cleanup(msg, child->pid);
 
-       ret = messaging_cleanup(msg, pid);
+               if ((ret != 0) && (ret != ENOENT)) {
+                       DBG_DEBUG("messaging_cleanup returned %s\n",
+                                 strerror(ret));
+               }
 
-       if ((ret != 0) && (ret != ENOENT)) {
-               DBG_DEBUG("messaging_cleanup returned %s\n", strerror(ret));
+               DBG_DEBUG("cleaned up pid %d\n", (int)child->pid);
        }
 
-       if (!serverid_deregister(child_id)) {
-               DEBUG(1, ("Could not remove pid %d from serverid.tdb\n",
-                         (int)pid));
-       }
+       TALLOC_FREE(frame);
 }
 
 NTSTATUS smbd_cleanupd_recv(struct tevent_req *req)