]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: fd: add a new FD_DISOWN flag to prevent from closing a deleted FD
authorEmeric Brun <ebrun@haproxy.com>
Fri, 1 Jul 2022 15:31:25 +0000 (17:31 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 1 Jul 2022 15:41:40 +0000 (17:41 +0200)
Some FDs might be offered to some external code (external libraries)
which will deal with them until they close them. As such we must not
close them upon fd_delete() but we need to delete them anyway so that
they do not appear anymore in the fdtab. This used to be handled by
fd_remove() before 2.3 but we don't have this anymore.

This patch introduces a new flag FD_DISOWN to let fd_delete() know that
the core doesn't own the fd and it must not be closed upon removal from
the fd_tab. This way it's totally unregistered from the poller but still
open.

This patch must be backported on branches >= 2.3 because it will be
needed to fix a bug affecting SSL async. it should be adapted on 2.3
because state flags were stored in a different way (via bits in the
structure).

include/haproxy/fd-t.h
src/fd.c

index 433a3f3aec066235ae0eb8a22a67b5b3638d8e95..64416d6dcbb063d5debaae7ee464fa749c2d14d9 100644 (file)
@@ -69,6 +69,7 @@ enum {
 #define FD_ET_POSSIBLE_BIT 19  /* edge-triggered is possible on this FD */
 #define FD_EXPORTED_BIT    20  /* FD is exported and must not be closed */
 #define FD_EXCL_SYSCALL_BIT 21 /* a syscall claims exclusivity on this FD */
+#define FD_DISOWN_BIT      22  /* this fd will be closed by some external code */
 
 
 /* and flag values */
@@ -109,6 +110,7 @@ enum {
 #define FD_ET_POSSIBLE      (1U << FD_ET_POSSIBLE_BIT)
 #define FD_EXPORTED         (1U << FD_EXPORTED_BIT)
 #define FD_EXCL_SYSCALL     (1U << FD_EXCL_SYSCALL_BIT)
+#define FD_DISOWN           (1U << FD_DISOWN_BIT)
 
 /* FD update status after fd_update_events() */
 enum {
index 4fbdaef457f43ab8ed7cf37d64acefcf037610e2..079df15af0519e1d16ca40047566df33ffdc558c 100644 (file)
--- a/src/fd.c
+++ b/src/fd.c
@@ -306,6 +306,9 @@ done:
  */
 void _fd_delete_orphan(int fd)
 {
+       uint fd_disown;
+
+       fd_disown = fdtab[fd].state & FD_DISOWN;
        if (fdtab[fd].state & FD_LINGER_RISK) {
                /* this is generally set when connecting to servers */
                DISGUISE(setsockopt(fd, SOL_SOCKET, SO_LINGER,
@@ -327,7 +330,8 @@ void _fd_delete_orphan(int fd)
        /* perform the close() call last as it's what unlocks the instant reuse
         * of this FD by any other thread.
         */
-       close(fd);
+       if (!fd_disown)
+               close(fd);
        _HA_ATOMIC_DEC(&ha_used_fds);
 }