dovecot-2.0: master: Several fixes to handling SIGHUPs.

dovecot at dovecot.org dovecot at dovecot.org
Sat Sep 5 00:07:06 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/31a283729295
changeset: 9876:31a283729295
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Sep 04 17:06:58 2009 -0400
description:
master: Several fixes to handling SIGHUPs.

diffstat:

7 files changed, 74 insertions(+), 26 deletions(-)
src/master/common.h              |    1 +
src/master/main.c                |    2 +-
src/master/service-auth-server.c |   24 ++++++++++++++++++++----
src/master/service-listen.c      |   27 +++++++++++++++++----------
src/master/service-monitor.c     |   16 ++++++++++------
src/master/service.c             |   24 +++++++++++++++++++-----
src/master/service.h             |    6 ++++++

diffs (227 lines):

diff -r 199857627883 -r 31a283729295 src/master/common.h
--- a/src/master/common.h	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/common.h	Fri Sep 04 17:06:58 2009 -0400
@@ -12,6 +12,7 @@ extern bool auth_success_written;
 extern bool auth_success_written;
 extern bool core_dumps_disabled;
 extern int null_fd;
+extern struct service_list *services;
 
 void process_exec(const char *cmd, const char *extra_args[]) ATTR_NORETURN;
 
diff -r 199857627883 -r 31a283729295 src/master/main.c
--- a/src/master/main.c	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/main.c	Fri Sep 04 17:06:58 2009 -0400
@@ -38,9 +38,9 @@ bool auth_success_written;
 bool auth_success_written;
 bool core_dumps_disabled;
 int null_fd;
+struct service_list *services;
 
 static char *pidfile_path;
-static struct service_list *services;
 static fatal_failure_callback_t *orig_fatal_callback;
 static const char *child_process_env[3]; /* @UNSAFE */
 
diff -r 199857627883 -r 31a283729295 src/master/service-auth-server.c
--- a/src/master/service-auth-server.c	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/service-auth-server.c	Fri Sep 04 17:06:58 2009 -0400
@@ -83,6 +83,22 @@ auth_process_lookup_request(struct servi
 	return request;
 }
 
+static struct service *
+auth_process_get_dest_service(struct service_process_auth_source *process)
+{
+	struct service *service = process->process.service;
+
+	if (!service->list->destroyed)
+		return service->auth_dest_service;
+
+	service = service_lookup(services, service->set->auth_dest_service);
+	if (service == NULL) {
+		i_warning("service(%s): Lost destination service %s",
+			  service->set->name, service->set->auth_dest_service);
+	}
+	return service;
+}
+
 static int
 auth_process_input_user(struct service_process_auth_server *process, const char *args)
 {
@@ -103,12 +119,12 @@ auth_process_input_user(struct service_p
 
         request = auth_process_lookup_request(process, id);
 	if (request != NULL) {
-		struct service *dest_service =
-			request->process->process.service->auth_dest_service;
+		struct service *dest_service;
 		struct service_process *dest_process;
 
-		dest_process = service_process_create(dest_service, list + 1,
-						      request);
+		dest_service = auth_process_get_dest_service(request->process);
+		dest_process = dest_service == NULL ? NULL :
+			service_process_create(dest_service, list + 1, request);
 		status = dest_process != NULL ?
 			MASTER_AUTH_STATUS_OK :
 			MASTER_AUTH_STATUS_INTERNAL_ERROR;
diff -r 199857627883 -r 31a283729295 src/master/service-listen.c
--- a/src/master/service-listen.c	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/service-listen.c	Fri Sep 04 17:06:58 2009 -0400
@@ -190,16 +190,11 @@ static int listener_equals(const struct 
 	switch (l1->type) {
 	case SERVICE_LISTENER_UNIX:
 	case SERVICE_LISTENER_FIFO:
-		if (strcmp(l1->set.fileset.set->path,
-			   l2->set.fileset.set->path) != 0)
-			return FALSE;
-		if (l1->set.fileset.set->mode != l2->set.fileset.set->mode)
-			return FALSE;
-		if (l1->set.fileset.uid != l2->set.fileset.uid)
-			return FALSE;
-		if (l1->set.fileset.gid != l2->set.fileset.gid)
-			return FALSE;
-		return TRUE;
+		/* We could just keep using the same listener, but it's more
+		   likely to cause problems if old process accepts a connection
+		   before it knows that it should die. So just always unlink
+		   and recreate unix/fifo listeners. */
+		return FALSE;
 	case SERVICE_LISTENER_INET:
 		if (memcmp(&l1->set.inetset.ip, &l2->set.inetset.ip,
 			   sizeof(l1->set.inetset.ip)) != 0)
@@ -253,6 +248,18 @@ int services_listen_using(struct service
 			if (close(old_listeners[j]->fd) < 0)
 				i_error("close(listener) failed: %m");
 		}
+		switch (old_listeners[j]->type) {
+		case SERVICE_LISTENER_UNIX:
+		case SERVICE_LISTENER_FIFO: {
+			const char *path =
+				old_listeners[j]->set.fileset.set->path;
+			if (unlink(path) < 0)
+				i_error("unlink(%s) failed: %m", path);
+			break;
+		}
+		case SERVICE_LISTENER_INET:
+			break;
+		}
 	}
 
 	/* and let services_listen() deal with the remaining fds */
diff -r 199857627883 -r 31a283729295 src/master/service-monitor.c
--- a/src/master/service-monitor.c	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/service-monitor.c	Fri Sep 04 17:06:58 2009 -0400
@@ -277,6 +277,7 @@ void services_monitor_reap_children(void
 	struct service *service;
 	pid_t pid;
 	int status;
+	bool service_destroyed;
 
 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 		process = hash_table_lookup(service_pids, &pid);
@@ -294,10 +295,13 @@ void services_monitor_reap_children(void
 		} else {
 			service_process_failure(process, status);
 		}
+		service_destroyed = service->list->destroyed;
 		service_process_destroy(process);
-		service_monitor_start_extra_avail(service);
-
-                if (service->to_throttle == NULL)
-			service_monitor_listen_start(service);
-	}
-}
+
+		if (!service_destroyed) {
+			service_monitor_start_extra_avail(service);
+			if (service->to_throttle == NULL)
+				service_monitor_listen_start(service);
+		}
+	}
+}
diff -r 199857627883 -r 31a283729295 src/master/service.c
--- a/src/master/service.c	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/service.c	Fri Sep 04 17:06:58 2009 -0400
@@ -313,7 +313,7 @@ static int pid_hash_cmp(const void *p1, 
 		*pid1 > *pid2 ? 1 : 0;
 }
 
-static struct service *
+struct service *
 service_lookup(struct service_list *service_list, const char *name)
 {
 	struct service *const *services;
@@ -455,22 +455,35 @@ void service_signal(struct service *serv
 
 static void services_kill_timeout(struct service_list *service_list)
 {
-	struct service *const *services;
+	struct service *const *services, *log_service;
 	unsigned int i, count;
+	bool sigterm_log;
 	int sig;
 
-	if (!service_list->sigterm_sent)
+	if (!service_list->sigterm_sent || !service_list->sigterm_sent_to_log)
 		sig = SIGTERM;
 	else
 		sig = SIGKILL;
+	sigterm_log = service_list->sigterm_sent;
 	service_list->sigterm_sent = TRUE;
 
 	i_warning("Processes aren't dying after reload, sending %s.",
 		  sig == SIGTERM ? "SIGTERM" : "SIGKILL");
 
+	log_service = NULL;
 	services = array_get(&service_list->services, &count);
-	for (i = 0; i < count; i++)
-		service_signal(services[i], sig);
+	for (i = 0; i < count; i++) {
+		if (services[i]->type == SERVICE_TYPE_LOG)
+			log_service = services[i];
+		else
+			service_signal(services[i], sig);
+	}
+	/* kill log service later so it could still have a chance of logging
+	   something */
+	if (log_service != NULL && sigterm_log) {
+		service_signal(log_service, sig);
+		service_list->sigterm_sent_to_log = TRUE;
+	}
 }
 
 void services_destroy(struct service_list *service_list)
@@ -487,6 +500,7 @@ void services_destroy(struct service_lis
 				    services_kill_timeout, service_list);
 	}
 
+	service_list->destroyed = TRUE;
 	service_list_unref(service_list);
 }
 
diff -r 199857627883 -r 31a283729295 src/master/service.h
--- a/src/master/service.h	Fri Sep 04 17:06:31 2009 -0400
+++ b/src/master/service.h	Fri Sep 04 17:06:58 2009 -0400
@@ -119,7 +119,9 @@ struct service_list {
 
 	ARRAY_DEFINE(services, struct service *);
 
+	unsigned int destroyed:1;
 	unsigned int sigterm_sent:1;
+	unsigned int sigterm_sent_to_log:1;
 };
 
 extern struct hash_table *service_pids;
@@ -147,6 +149,10 @@ void services_throttle_time_sensitives(s
 void services_throttle_time_sensitives(struct service_list *list,
 				       unsigned int secs);
 
+/* Find a service by name. */
+struct service *
+service_lookup(struct service_list *service_list, const char *name);
+
 void service_error(struct service *service, const char *format, ...)
 	ATTR_FORMAT(2, 3);
 


More information about the dovecot-cvs mailing list