s3-smbd: add a rate limited cleanup of brl, connections and locking db
[ira/wip.git] / source3 / smbd / server.c
index 09ad8d8ea55af057d8fea68b266929d1c5b634d2..37716c4171061aa4cfb79b944d422da495c8417d 100644 (file)
@@ -219,19 +219,53 @@ static void add_child_pid(pid_t pid)
        num_children += 1;
 }
 
+/*
+  at most every smbd:cleanuptime seconds (default 20), we scan the BRL
+  and locking database for entries to cleanup. As a side effect this
+  also cleans up dead entries in the connections database (due to the
+  traversal in message_send_all()
+
+  Using a timer for this prevents a flood of traversals when a large
+  number of clients disconnect at the same time (perhaps due to a
+  network outage).  
+*/
+
+static void cleanup_timeout_fn(struct event_context *event_ctx,
+                               struct timed_event *te,
+                               struct timeval now,
+                               void *private_data)
+{
+       struct timed_event **cleanup_te = (struct timed_event **)private_data;
+
+       DEBUG(1,("Cleaning up brl and lock database after unclean shutdown\n"));
+       message_send_all(smbd_messaging_context(), MSG_SMB_UNLOCK, NULL, 0, NULL);
+       messaging_send_buf(smbd_messaging_context(), procid_self(), 
+                               MSG_SMB_BRL_VALIDATE, NULL, 0);
+       /* mark the cleanup as having been done */
+       (*cleanup_te) = NULL;
+}
+
 static void remove_child_pid(pid_t pid, bool unclean_shutdown)
 {
        struct child_pid *child;
+       static struct timed_event *cleanup_te;
 
        if (unclean_shutdown) {
-               /* a child terminated uncleanly so tickle all processes to see 
-                  if they can grab any of the pending locks
-               */
-               DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", (unsigned int)pid));
-               messaging_send_buf(smbd_messaging_context(), procid_self(), 
-                                  MSG_SMB_BRL_VALIDATE, NULL, 0);
-               message_send_all(smbd_messaging_context(), 
-                                MSG_SMB_UNLOCK, NULL, 0, NULL);
+               /* a child terminated uncleanly so tickle all
+                  processes to see if they can grab any of the
+                  pending locks
+                */
+               DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", 
+                       (unsigned int)pid));
+               if (!cleanup_te) {
+                       /* call the cleanup timer, but not too often */
+                       int cleanup_time = lp_parm_int(-1, "smbd", "cleanuptime", 20);
+                       cleanup_te = event_add_timed(smbd_event_context(), NULL,
+                                               timeval_current_ofs(cleanup_time, 0),
+                                               cleanup_timeout_fn, 
+                                               &cleanup_te);
+                       DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
+               }
        }
 
        for (child = children; child != NULL; child = child->next) {
@@ -1047,6 +1081,14 @@ extern void build_options(bool screen);
        gain_root_privilege();
        gain_root_group_privilege();
 
+       /*
+        * Ensure we have CAP_KILL capability set on Linux,
+        * where we need this to communicate with threads.
+        * This is inherited by new threads, but not by new
+        * processes across exec().
+        */
+       set_effective_capability(KILL_CAPABILITY);
+
        fault_setup((void (*)(void *))exit_server_fault);
        dump_core_setup("smbd");