]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: pattern: don't trim pools under lock in pat_ref_purge_range()
authorWilly Tarreau <w@1wt.eu>
Sat, 4 Nov 2023 06:55:37 +0000 (07:55 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 4 Nov 2023 06:55:37 +0000 (07:55 +0100)
There's a subtle issue that results from pat_ref_purge_range() trying
to release memory. Since commit 0d93a8186 ("MINOR: pools: work around
possibly slow malloc_trim() during gc") that was backported to 2.3,
trim_all_pools() now protects itself against concurrent malloc() and
free() by isolating itself. The problem is that pat_ref_purge_range()
must be called under a lock, which is precisely what's done in
cli_io_handler_clear_map(). Thus during a clearing of a map, if
another thread tries to access or update an entry in the same map, it
will wait for the ref->lock to be released, and trim_all_pools() will
wait for all threads to be harmless, thus causing a deadlock. Note
that disabling memory trimming cannot work around the problem here
because it's tested only under isolation.

The solution here consists in moving the call to trim_all_pools() to
the caller, out of the lock.

This must be backported as far as 2.4.

src/map.c
src/pattern.c

index 2bed88a0c92b60d4eb7c3f6a504248060cd57f81..3bd3de59743de559e56296098024d5f8228a56ee 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -1027,6 +1027,8 @@ static int cli_io_handler_clear_map(struct appctx *appctx)
                applet_have_more_data(appctx);
                return 0;
        }
+
+       trim_all_pools();
        return 1;
 }
 
index 080aeb00bbbe38f0c07019ee4919f972faac1232..0d3ed60a4d3c47f86778e643b5a5b5c1ffcdcfdb 100644 (file)
@@ -2090,9 +2090,6 @@ int pat_ref_purge_range(struct pat_ref *ref, uint from, uint to, int budget)
        list_for_each_entry(expr, &ref->pat, list)
                HA_RWLOCK_WRUNLOCK(PATEXP_LOCK, &expr->lock);
 
-       if (done)
-               trim_all_pools();
-
        return done;
 }