dovecot-2.2: master: Added reuse_port setting to inet_listeners,...
dovecot at dovecot.org
dovecot at dovecot.org
Mon Sep 23 09:45:23 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/a991a0547daa
changeset: 16823:a991a0547daa
user: Timo Sirainen <tss at iki.fi>
date: Mon Sep 23 04:25:16 2013 +0300
description:
master: Added reuse_port setting to inet_listeners, which enables SO_REUSEPORT if available.
After forking a new service process, a new listener socket is created for
each such inet_listener. Linux v3.9+ added SO_REUSEPORT feature, which
should distribute clients more uniformly to the processes. I'm not sure if
this makes any difference in BSDs.
At least in Linux v3.9 there was still a bug that if the number of listening
processes changed, some TCP handshakes might not finish. I don't see if this
has already been fixed, so this is probably safe to use only for services
whose process count doesn't change (e.g. process_min_avail is set high
enough).
diffstat:
src/imap-login/imap-login-settings.c | 4 ++--
src/lib-master/service-settings.h | 1 +
src/master/master-settings.c | 4 +++-
src/master/service-listen.c | 35 +++++++++++++++++++++--------------
src/master/service-listen.h | 2 ++
src/master/service-process.c | 20 ++++++++++++++++++++
src/master/service.h | 2 ++
src/pop3-login/pop3-login-settings.c | 4 ++--
8 files changed, 53 insertions(+), 19 deletions(-)
diffs (200 lines):
diff -r 6a814345f16c -r a991a0547daa src/imap-login/imap-login-settings.c
--- a/src/imap-login/imap-login-settings.c Mon Sep 23 04:06:08 2013 +0300
+++ b/src/imap-login/imap-login-settings.c Mon Sep 23 04:25:16 2013 +0300
@@ -11,8 +11,8 @@
/* <settings checks> */
static struct inet_listener_settings imap_login_inet_listeners_array[] = {
- { "imap", "", 143, FALSE },
- { "imaps", "", 993, TRUE }
+ { .name = "imap", .address = "", .port = 143 },
+ { .name = "imaps", .address = "", .port = 993, .ssl = TRUE }
};
static struct inet_listener_settings *imap_login_inet_listeners[] = {
&imap_login_inet_listeners_array[0],
diff -r 6a814345f16c -r a991a0547daa src/lib-master/service-settings.h
--- a/src/lib-master/service-settings.h Mon Sep 23 04:06:08 2013 +0300
+++ b/src/lib-master/service-settings.h Mon Sep 23 04:25:16 2013 +0300
@@ -31,6 +31,7 @@
const char *address;
unsigned int port;
bool ssl;
+ bool reuse_port;
};
ARRAY_DEFINE_TYPE(inet_listener_settings, struct inet_listener_settings *);
diff -r 6a814345f16c -r a991a0547daa src/master/master-settings.c
--- a/src/master/master-settings.c Mon Sep 23 04:06:08 2013 +0300
+++ b/src/master/master-settings.c Mon Sep 23 04:25:16 2013 +0300
@@ -64,6 +64,7 @@
DEF(SET_STR, address),
DEF(SET_UINT, port),
DEF(SET_BOOL, ssl),
+ DEF(SET_BOOL, reuse_port),
SETTING_DEFINE_LIST_END
};
@@ -72,7 +73,8 @@
.name = "",
.address = "",
.port = 0,
- .ssl = FALSE
+ .ssl = FALSE,
+ .reuse_port = FALSE
};
static const struct setting_parser_info inet_listener_setting_parser_info = {
diff -r 6a814345f16c -r a991a0547daa src/master/service-listen.c
--- a/src/master/service-listen.c Mon Sep 23 04:06:08 2013 +0300
+++ b/src/master/service-listen.c Mon Sep 23 04:25:16 2013 +0300
@@ -189,9 +189,11 @@
static int service_inet_listener_listen(struct service_listener *l)
{
struct service *service = l->service;
+ enum net_listen_flags flags = 0;
const struct inet_listener_settings *set = l->set.inetset.set;
unsigned int port = set->port;
int fd;
+
#ifdef HAVE_SYSTEMD
if (systemd_listen_fd(&l->set.inetset.ip, port, &fd) < 0)
return -1;
@@ -199,13 +201,16 @@
if (fd == -1)
#endif
{
- fd = net_listen(&l->set.inetset.ip, &port,
- service_get_backlog(service));
+ if (set->reuse_port)
+ flags |= NET_LISTEN_FLAG_REUSEPORT;
+ fd = net_listen_full(&l->set.inetset.ip, &port, &flags,
+ service_get_backlog(service));
if (fd < 0) {
service_error(service, "listen(%s, %u) failed: %m",
l->inet_address, set->port);
return errno == EADDRINUSE ? 0 : -1;
}
+ l->reuse_port = (flags & NET_LISTEN_FLAG_REUSEPORT) != 0;
}
net_set_nonblock(fd, TRUE);
fd_close_on_exec(fd, TRUE);
@@ -214,6 +219,19 @@
return 1;
}
+int service_listener_listen(struct service_listener *l)
+{
+ switch (l->type) {
+ case SERVICE_LISTENER_UNIX:
+ return service_unix_listener_listen(l);
+ case SERVICE_LISTENER_FIFO:
+ return service_fifo_listener_listen(l);
+ case SERVICE_LISTENER_INET:
+ return service_inet_listener_listen(l);
+ }
+ i_unreached();
+}
+
static int service_listen(struct service *service)
{
struct service_listener *const *listeners;
@@ -225,18 +243,7 @@
if (l->fd != -1)
continue;
- switch (l->type) {
- case SERVICE_LISTENER_UNIX:
- ret2 = service_unix_listener_listen(l);
- break;
- case SERVICE_LISTENER_FIFO:
- ret2 = service_fifo_listener_listen(l);
- break;
- case SERVICE_LISTENER_INET:
- ret2 = service_inet_listener_listen(l);
- break;
- }
-
+ ret2 = service_listener_listen(l);
if (ret2 < ret)
ret = ret2;
}
diff -r 6a814345f16c -r a991a0547daa src/master/service-listen.h
--- a/src/master/service-listen.h Mon Sep 23 04:06:08 2013 +0300
+++ b/src/master/service-listen.h Mon Sep 23 04:25:16 2013 +0300
@@ -13,4 +13,6 @@
int services_listen_using(struct service_list *new_service_list,
struct service_list *old_service_list);
+int service_listener_listen(struct service_listener *l);
+
#endif
diff -r 6a814345f16c -r a991a0547daa src/master/service-process.c
--- a/src/master/service-process.c Mon Sep 23 04:06:08 2013 +0300
+++ b/src/master/service-process.c Mon Sep 23 04:25:16 2013 +0300
@@ -23,6 +23,7 @@
#include "dup2-array.h"
#include "service.h"
#include "service-anvil.h"
+#include "service-listen.h"
#include "service-log.h"
#include "service-process-notify.h"
#include "service-process.h"
@@ -34,6 +35,24 @@
#include <signal.h>
#include <sys/wait.h>
+static void service_reopen_inet_listeners(struct service *service)
+{
+ struct service_listener *const *listeners;
+ unsigned int i, count;
+ int old_fd;
+
+ listeners = array_get(&service->listeners, &count);
+ for (i = 0; i < count; i++) {
+ if (!listeners[i]->reuse_port || listeners[i]->fd == -1)
+ continue;
+
+ old_fd = listeners[i]->fd;
+ listeners[i]->fd = -1;
+ if (service_listener_listen(listeners[i]) < 0)
+ listeners[i]->fd = old_fd;
+ }
+}
+
static void
service_dup_fds(struct service *service)
{
@@ -305,6 +324,7 @@
if (pid == 0) {
/* child */
service_process_setup_environment(service, uid);
+ service_reopen_inet_listeners(service);
service_dup_fds(service);
drop_privileges(service);
process_exec(service->executable, NULL);
diff -r 6a814345f16c -r a991a0547daa src/master/service.h
--- a/src/master/service.h Mon Sep 23 04:06:08 2013 +0300
+++ b/src/master/service.h Mon Sep 23 04:25:16 2013 +0300
@@ -38,6 +38,8 @@
struct ip_addr ip;
} inetset;
} set;
+
+ bool reuse_port;
};
struct service {
diff -r 6a814345f16c -r a991a0547daa src/pop3-login/pop3-login-settings.c
--- a/src/pop3-login/pop3-login-settings.c Mon Sep 23 04:06:08 2013 +0300
+++ b/src/pop3-login/pop3-login-settings.c Mon Sep 23 04:25:16 2013 +0300
@@ -11,8 +11,8 @@
/* <settings checks> */
static struct inet_listener_settings pop3_login_inet_listeners_array[] = {
- { "pop3", "", 110, FALSE },
- { "pop3s", "", 995, TRUE }
+ { .name = "pop3", .address = "", .port = 110 },
+ { .name = "pop3s", .address = "", .port = 995, .ssl = TRUE }
};
static struct inet_listener_settings *pop3_login_inet_listeners[] = {
&pop3_login_inet_listeners_array[0],
More information about the dovecot-cvs
mailing list