]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mworker: does not close inherited FD
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 15 Nov 2017 18:02:58 +0000 (19:02 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 15 Nov 2017 18:53:33 +0000 (19:53 +0100)
At the end of the master initialisation, a call to protocol_unbind_all()
was made, in order to close all the FDs.

Unfortunately, this function closes the inherited FDs (fd@), upon reload
the master wasn't able to reload a configuration with those FDs.

The create_listeners() function now store a flag to specify if the fd
was inherited or not.

Replace the protocol_unbind_all() by  mworker_cleanlisteners() +
deinit_pollers()

include/proto/listener.h
include/types/listener.h
src/cfgparse.c
src/haproxy.c
src/listener.c

index 2758a3c7ff7b01204d53dc0b32acf235b8ab94d2..a33aeed4a80c4bf559cb32eddbf6e218403bd235 100644 (file)
@@ -83,11 +83,13 @@ int unbind_all_listeners(struct protocol *proto);
  * range <portl> to <porth>, and possibly attached to fd <fd> (or -1 for auto
  * allocation). The address family is taken from ss->ss_family. The number of
  * jobs and listeners is automatically increased by the number of listeners
- * created. It returns non-zero on success, zero on error with the error message
+ * created. If the <inherited> argument is set to 1, it specifies that the FD
+ * was obtained from a parent process.
+ * It returns non-zero on success, zero on error with the error message
  * set in <err>.
  */
 int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
-                     int portl, int porth, int fd, char **err);
+                     int portl, int porth, int fd, int inherited, char **err);
 
 /* Delete a listener from its protocol's list of listeners. The listener's
  * state is automatically updated from LI_ASSIGNED to LI_INIT. The protocol's
index 545f88c450a5d51906b5efdbc6ef7d24dd5886e6..b92c35e2d9c0772818f72653c0af281b871e6fe1 100644 (file)
@@ -98,6 +98,7 @@ enum li_state {
 #define LI_O_V6ONLY             0x0400  /* bind to IPv6 only on Linux >= 2.4.21 */
 #define LI_O_V4V6               0x0800  /* bind to IPv4/IPv6 on Linux >= 2.4.21 */
 #define LI_O_ACC_CIP            0x1000  /* find the proxied address in the NetScaler Client IP header */
+#define LI_O_INHERITED          0x2000  /* inherited FD from the parent process (fd@) */
 
 /* Note: if a listener uses LI_O_UNLIMITED, it is highly recommended that it adds its own
  * maxconn setting to the global.maxsock value so that its resources are reserved.
index b42dd540422bf7bf1e44ed8688c3b92f77a90b4a..57f25fac79f52cebbca85cea21695ede020aa14f 100644 (file)
@@ -239,6 +239,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
        next = dupstr = strdup(str);
 
        while (next && *next) {
+               int inherited = 0;
                struct sockaddr_storage *ss2;
                int fd = -1;
 
@@ -277,6 +278,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
                }
                else if (ss2->ss_family == AF_UNSPEC) {
                        socklen_t addr_len;
+                       inherited = 1;
 
                        /* We want to attach to an already bound fd whose number
                         * is in the addr part of ss2 when cast to sockaddr_in.
@@ -295,7 +297,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
                }
 
                /* OK the address looks correct */
-               if (!create_listeners(bind_conf, ss2, port, end, fd, err)) {
+               if (!create_listeners(bind_conf, ss2, port, end, fd, inherited, err)) {
                        memprintf(err, "%s for address '%s'.\n", *err, str);
                        goto fail;
                }
index 00cc25b165a220916eac201fc12188aa129195d4..5b45dfbaf6d31de277cd7675914e6e5665de1e92 100644 (file)
@@ -540,6 +540,33 @@ static void mworker_kill(int sig)
        }
 }
 
+/*
+ * Upon a reload, the master worker needs to close all listeners FDs but the mworker_pipe
+ * fd, and the FD provided by fd@
+ */
+static void mworker_cleanlisteners()
+{
+       struct listener *l, *l_next;
+       struct proxy *curproxy;
+
+       for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+
+               list_for_each_entry_safe(l, l_next, &curproxy->conf.listeners, by_fe) {
+                       /* does not close if the FD is inherited with fd@
+                        * from the parent process */
+                       if (!(l->options & LI_O_INHERITED)) {
+                               close(l->fd);
+                               LIST_DEL(&l->by_fe);
+                               LIST_DEL(&l->by_bind);
+                               free(l->name);
+                               free(l->counters);
+                               free(l);
+                       }
+               }
+       }
+}
+
+
 /*
  * remove a pid forom the olpid array and decrease nb_oldpids
  * return 1 pid was found otherwise return 0
@@ -2694,7 +2721,8 @@ int main(int argc, char **argv)
 
                if (proc == global.nbproc) {
                        if (global.mode & MODE_MWORKER) {
-                               protocol_unbind_all();
+                               mworker_cleanlisteners();
+                               deinit_pollers();
                                mworker_wait();
                                /* should never get there */
                                exit(EXIT_FAILURE);
index c7db79a89b173955d9a168432a18f8e0c3841429..7cb4d6aa25c8dc74619a2b8e940a118f80cd6587 100644 (file)
@@ -372,11 +372,13 @@ int unbind_all_listeners(struct protocol *proto)
  * range <portl> to <porth>, and possibly attached to fd <fd> (or -1 for auto
  * allocation). The address family is taken from ss->ss_family. The number of
  * jobs and listeners is automatically increased by the number of listeners
- * created. It returns non-zero on success, zero on error with the error message
+ * created. If the <inherited> argument is set to 1, it specifies that the FD
+ * was obtained from a parent process.
+ * It returns non-zero on success, zero on error with the error message
  * set in <err>.
  */
 int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
-                     int portl, int porth, int fd, char **err)
+                     int portl, int porth, int fd, int inherited, char **err)
 {
        struct protocol *proto = protocol_by_family(ss->ss_family);
        struct listener *l;
@@ -404,6 +406,9 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
 
                proto->add(l, port);
 
+               if (inherited)
+                       l->options |= LI_O_INHERITED;
+
                HA_SPIN_INIT(&l->lock);
                HA_ATOMIC_ADD(&jobs, 1);
                HA_ATOMIC_ADD(&listeners, 1);