diff -Nru dovecot-2.0.15/debian/changelog dovecot-2.0.15/debian/changelog --- dovecot-2.0.15/debian/changelog 2011-10-19 16:26:15.000000000 +0000 +++ dovecot-2.0.15/debian/changelog 2011-11-11 14:43:24.000000000 +0000 @@ -1,3 +1,17 @@ +dovecot (1:2.0.15-1ubuntu2~precise1~ppa1) precise; urgency=low + + * No-change backport to precise + + -- James Page Fri, 11 Nov 2011 14:43:24 +0000 + +dovecot (1:2.0.15-1ubuntu2) precise; urgency=low + + * d/patches/fix-racey-restart.patch: Backported patch from current + development release which ensures all child processes terminate prior + to the main dovecot process (LP: #873390). + + -- James Page Fri, 11 Nov 2011 14:38:41 +0000 + dovecot (1:2.0.15-1ubuntu1) precise; urgency=low * Merge from Debian Testing, remaining changes: diff -Nru dovecot-2.0.15/debian/patches/fix-racey-restarts.patch dovecot-2.0.15/debian/patches/fix-racey-restarts.patch --- dovecot-2.0.15/debian/patches/fix-racey-restarts.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.0.15/debian/patches/fix-racey-restarts.patch 2011-11-11 14:22:47.000000000 +0000 @@ -0,0 +1,197 @@ +Description: Ensures all services are stopped before terminating + parent process. +Origin: http://hg.dovecot.org/dovecot-2.1/rev/6894298ae5fd + +Index: dovecot/src/master/main.c +=================================================================== +--- dovecot.orig/src/master/main.c 2011-11-11 14:19:13.000000000 +0000 ++++ dovecot/src/master/main.c 2011-11-11 14:21:32.231630439 +0000 +@@ -330,7 +330,7 @@ + services->config->config_file_path); + + /* switch to new configuration. */ +- services_monitor_stop(services); ++ services_monitor_stop(services, FALSE); + if (services_listen_using(new_services, services) < 0) { + services_monitor_start(services); + return; +@@ -342,7 +342,7 @@ + while (service->processes != NULL) + service_process_destroy(service->processes); + } +- services_destroy(services); ++ services_destroy(services, FALSE); + + services = new_services; + services_monitor_start(services); +@@ -455,13 +455,26 @@ + services_monitor_start(services); + } + ++static void global_dead_pipe_close(void) ++{ ++ if (close(global_master_dead_pipe_fd[0]) < 0) ++ i_error("close(global dead pipe) failed: %m"); ++ if (close(global_master_dead_pipe_fd[1]) < 0) ++ i_error("close(global dead pipe) failed: %m"); ++ global_master_dead_pipe_fd[0] = -1; ++ global_master_dead_pipe_fd[1] = -1; ++} ++ + static void main_deinit(void) + { ++ /* kill services and wait for them to die before unlinking pid file */ ++ global_dead_pipe_close(); ++ services_destroy(services, TRUE); ++ + if (unlink(pidfile_path) < 0) + i_error("unlink(%s) failed: %m", pidfile_path); + i_free(pidfile_path); + +- services_destroy(services); + service_anvil_global_deinit(); + service_pids_deinit(); + } +Index: dovecot/src/master/service-monitor.c +=================================================================== +--- dovecot.orig/src/master/service-monitor.c 2011-11-11 14:19:13.000000000 +0000 ++++ dovecot/src/master/service-monitor.c 2011-11-11 14:22:19.407752823 +0000 +@@ -22,6 +22,7 @@ + + #define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60 + #define SERVICE_DROP_WARN_INTERVAL_SECS 60 ++#define MAX_DIE_WAIT_SECS 5 + + static void service_monitor_start_extra_avail(struct service *service); + static void service_status_more(struct service_process *process, +@@ -169,8 +170,10 @@ + if (ret <= 0) { + if (ret == 0) + service_error(service, "read(status) failed: EOF"); +- else ++ else if (errno != EAGAIN) + service_error(service, "read(status) failed: %m"); ++ else ++ return; + service_monitor_stop(service); + return; + } +@@ -423,7 +426,28 @@ + timeout_remove(&service->to_throttle); + } + +-void services_monitor_stop(struct service_list *service_list) ++static void services_monitor_wait(struct service_list *service_list) ++{ ++ struct service *const *servicep; ++ time_t max_wait_time = time(NULL) + MAX_DIE_WAIT_SECS; ++ bool finished; ++ ++ for (;;) { ++ finished = TRUE; ++ services_monitor_reap_children(); ++ array_foreach(&service_list->services, servicep) { ++ if ((*servicep)->status_fd[0] != -1) ++ service_status_input(*servicep); ++ if ((*servicep)->process_avail > 0) ++ finished = FALSE; ++ } ++ if (finished || time(NULL) > max_wait_time) ++ break; ++ usleep(100000); ++ } ++} ++ ++void services_monitor_stop(struct service_list *service_list, bool wait) + { + struct service *const *services; + +@@ -436,6 +460,13 @@ + service_list->master_dead_pipe_fd[1] = -1; + } + ++ if (wait) { ++ /* we've notified all children that the master is dead. ++ now wait for the children to either die or to tell that ++ they're no longer listening for new connections */ ++ services_monitor_wait(service_list); ++ } ++ + array_foreach(&service_list->services, services) + service_monitor_stop(*services); + +@@ -472,7 +503,8 @@ + service = process->service; + if (status == 0) { + /* success */ +- if (service->listen_pending) ++ if (service->listen_pending && ++ !service->list->destroying) + service_monitor_listen_start(service); + throttle = FALSE; + } else { +@@ -491,7 +523,8 @@ + service_monitor_throttle(service); + service_stopped = service->status_fd[0] == -1; + if (!service_stopped) { +- service_monitor_start_extra_avail(service); ++ if (!service->list->destroying) ++ service_monitor_start_extra_avail(service); + if (service->to_throttle == NULL) + service_monitor_listen_start(service); + } +Index: dovecot/src/master/service-monitor.h +=================================================================== +--- dovecot.orig/src/master/service-monitor.h 2011-11-11 14:19:13.000000000 +0000 ++++ dovecot/src/master/service-monitor.h 2011-11-11 14:21:32.235630450 +0000 +@@ -5,7 +5,7 @@ + void services_monitor_start(struct service_list *service_list); + + /* Stop services. */ +-void services_monitor_stop(struct service_list *service_list); ++void services_monitor_stop(struct service_list *service_list, bool wait); + + /* Call after SIGCHLD has been detected */ + void services_monitor_reap_children(void); +Index: dovecot/src/master/service.c +=================================================================== +--- dovecot.orig/src/master/service.c 2011-11-11 14:19:13.000000000 +0000 ++++ dovecot/src/master/service.c 2011-11-11 14:21:32.235630450 +0000 +@@ -615,12 +615,13 @@ + } + } + +-void services_destroy(struct service_list *service_list) ++void services_destroy(struct service_list *service_list, bool wait) + { + /* make sure we log if child processes died unexpectedly */ +- services_monitor_reap_children(); ++ service_list->destroying = TRUE; ++ services_monitor_reap_children(); + +- services_monitor_stop(service_list); ++ services_monitor_stop(service_list, wait); + + if (service_list->refcount > 1 && + service_list->service_set->shutdown_clients) { +Index: dovecot/src/master/service.h +=================================================================== +--- dovecot.orig/src/master/service.h 2011-11-11 14:19:13.000000000 +0000 ++++ dovecot/src/master/service.h 2011-11-11 14:21:32.235630450 +0000 +@@ -123,6 +123,7 @@ + + ARRAY_DEFINE(services, struct service *); + ++ unsigned int destroying:1; + unsigned int destroyed:1; + unsigned int sigterm_sent:1; + unsigned int sigterm_sent_to_log:1; +@@ -135,7 +136,7 @@ + struct service_list **services_r, const char **error_r); + + /* Destroy services */ +-void services_destroy(struct service_list *service_list); ++void services_destroy(struct service_list *service_list, bool wait); + + void service_list_ref(struct service_list *service_list); + void service_list_unref(struct service_list *service_list); diff -Nru dovecot-2.0.15/debian/patches/series dovecot-2.0.15/debian/patches/series --- dovecot-2.0.15/debian/patches/series 2011-10-18 16:55:17.000000000 +0000 +++ dovecot-2.0.15/debian/patches/series 2011-11-11 14:21:18.000000000 +0000 @@ -2,3 +2,4 @@ dovecot-drac.patch split-protocols.patch fix-mail_plugin_dir-default.patch +fix-racey-restarts.patch