From 58185669d8a0891948caaa7b357d78775b0cecb3 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 4 Nov 2023 07:55:37 +0100 Subject: [PATCH] BUG/MEDIUM: pattern: don't trim pools under lock in pat_ref_purge_range() 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 | 2 ++ src/pattern.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/map.c b/src/map.c index 2bed88a0c..3bd3de597 100644 --- 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; } diff --git a/src/pattern.c b/src/pattern.c index 080aeb00b..0d3ed60a4 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -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; }