]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: stats-file: fix shm-stats-file recover when all process slots are full
authorAurelien DARRAGON <adarragon@haproxy.com>
Wed, 18 Feb 2026 16:04:03 +0000 (17:04 +0100)
committerAurelien DARRAGON <adarragon@haproxy.com>
Thu, 19 Feb 2026 15:13:48 +0000 (16:13 +0100)
Amaury reported that when the following warning is reported by haproxy:

  [WARNING]  (296347) : config: failed to get shm stats file slot for 'haproxy.stats', all slots are occupied

haproxy would segfault right after during clock update operation.

The reason for the warning being emitted is not the object of this commit
(all shm-stats-file slots occupied by simultaneous co-processes) but since
it was is intended that haproxy is able to keep working despite that
warning (ignoring the use of shm-stats-file), we should fix the crash.

The crash is caused by the fact that we detach from the shared memory while
the global_now_ns and global_now_ms clock pointers still point to the shared
memory. Instead we should revert to using our local clock instead before
detaching from the map.

It should be backported in 3.3

src/stats-file.c

index 73c13a637b1684dab01e1fa31c19594a7673df94..99d3a03e849be621820218e32991f2e3c0082b16 100644 (file)
@@ -840,6 +840,8 @@ next:
 int shm_stats_file_prepare(void)
 {
        struct task *heartbeat_task;
+       volatile ullong *local_global_now_ns;
+       volatile uint *local_global_now_ms;
        int first = 0; // process responsible for initializing the shm memory
        int slot;
        int objects;
@@ -901,7 +903,11 @@ int shm_stats_file_prepare(void)
        else if (!shm_stats_file_check_ver(shm_stats_file_hdr))
                goto err_version;
 
-       /* from now on use the shared global time */
+       /* from now on use the shared global time, but save local global time
+        * in case reverting is required
+        */
+       local_global_now_ms = global_now_ms;
+       local_global_now_ns = global_now_ns;
        global_now_ms = &shm_stats_file_hdr->global_now_ms;
        global_now_ns = &shm_stats_file_hdr->global_now_ns;
 
@@ -968,7 +974,18 @@ int shm_stats_file_prepare(void)
        slot = shm_stats_file_get_free_slot(shm_stats_file_hdr);
        if (slot == -1) {
                ha_warning("config: failed to get shm stats file slot for '%s', all slots are occupied\n", global.shm_stats_file);
+               /* stop using shared clock since we withdraw from the shared memory,
+                * simply update the local clock and switch to using it instead
+                */
+               *local_global_now_ms = HA_ATOMIC_LOAD(global_now_ms);
+               *local_global_now_ns = HA_ATOMIC_LOAD(global_now_ns);
+
+               /* shared memory mapping no longer needed */
                munmap(shm_stats_file_hdr, sizeof(*shm_stats_file_hdr));
+               shm_stats_file_hdr = NULL;
+
+               global_now_ms = local_global_now_ms;
+               global_now_ns = local_global_now_ns;
                return ERR_WARN;
        }