]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: cli: Make sure two instances of _getsocks don't run
authorOlivier Houchard <ohouchard@haproxy.com>
Thu, 3 Sep 2026 12:57:14 +0000 (14:57 +0200)
committerOlivier Houchard <cognet@ci0.org>
Thu, 10 Sep 2026 16:33:30 +0000 (18:33 +0200)
It should never happen, but two instances of _getsocks could run at the
same time, and cause a deadlock, so make sure that never happens by only
allowing one at the same time.

src/cli.c
src/protocol.c

index d3569fdc109ed69c043eda4188b4e4ed101064d0..b4ba0e365dcc51f294f68f56fe5a748ad16b3924 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -2619,10 +2619,8 @@ static int _getsocks(char **args, char *payload, struct appctx *appctx, void *pr
         * a separate file descriptor table.
         */
        nb_foreign = protocol_getsocks_foreign_fds(&foreign_rxs, &foreign_fds);
-       if (nb_foreign < 0) {
-               ha_warning("Failed to allocate memory to transfer other groups' sockets\n");
+       if (nb_foreign < 0)
                goto out;
-       }
 
        /*
         * First, calculates the total number of FD, so that we can let
index eb44f9802fe6387ccffd7eba1d6186340b4f51c0..c4c8fa8003dc560d6a90a47c947de7bc10e68a18 100644 (file)
@@ -182,6 +182,8 @@ void protocol_localize_rx_fds(void)
        HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
 }
 
+static uint getsocks_busy;
+
 /*
  * Collect file descriptor from other thread groups, if they have their
  * own file descriptors table.
@@ -193,6 +195,7 @@ int protocol_getsocks_foreign_fds(struct receiver ***orxs, int **ofds)
        struct receiver **rxs;
        int *fds;
        int nb, filled, done, i;
+       uint idle = 0;
 
        *orxs = NULL;
        *ofds = NULL;
@@ -200,6 +203,14 @@ int protocol_getsocks_foreign_fds(struct receiver ***orxs, int **ofds)
        if (MAX_TGROUPS < 2 || !(global.tune.options & GTUNE_NO_TG_FD_SHARING) || global.nbtgroups < 2)
                return 0;
 
+       /* a concurrent collection would overwrite the per-receiver slots, and
+        * two of them blocking their groups' runner threads would deadlock.
+        */
+       if (!HA_ATOMIC_CAS(&getsocks_busy, &idle, 1)) {
+               ha_warning("_getsocks: a collection is already in progress, giving up.\n");
+               return -1;
+       }
+
        /* first pass: count the candidates */
        nb = 0;
        HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
@@ -214,14 +225,18 @@ int protocol_getsocks_foreign_fds(struct receiver ***orxs, int **ofds)
        }
        HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
 
-       if (!nb)
+       if (!nb) {
+               HA_ATOMIC_STORE(&getsocks_busy, 0);
                return 0;
+       }
 
        rxs = calloc(nb, sizeof(*rxs));
        fds = calloc(nb, sizeof(*fds));
        if (!rxs || !fds) {
                free(rxs);
                free(fds);
+               HA_ATOMIC_STORE(&getsocks_busy, 0);
+               ha_warning("Failed to allocate memory to transfer other groups' sockets\n");
                return -1;
        }
 
@@ -282,6 +297,8 @@ int protocol_getsocks_foreign_fds(struct receiver ***orxs, int **ofds)
                done++;
        }
 
+       HA_ATOMIC_STORE(&getsocks_busy, 0);
+
        if (!done) {
                free(rxs);
                free(fds);