BUG/MEDIUM: stick-tables: Fix race with peers when killing a sticky session

When a sticky session is killed, we must be sure no other entity is still
referencing it. The session's ref_cnt must be 0. However, there is a race
with peers, as decribed in 21447b1dd4 ("BUG/MAJOR: stick-tables: fix race
with peers in entry expiration"). When the update lock is acquire, we must
recheck the ref_cnt value.

This patch is part of a debugging session about issue #2552. It must be
backported to 2.9.
This commit is contained in:
Christopher Faulet 2024-05-23 11:14:41 +02:00 committed by Willy Tarreau
parent dfd938bad6
commit 9938fb9c7a

View File

@ -141,17 +141,25 @@ void stksess_free(struct stktable *t, struct stksess *ts)
*/ */
int __stksess_kill(struct stktable *t, struct stksess *ts) int __stksess_kill(struct stktable *t, struct stksess *ts)
{ {
int updt_locked = 0;
if (HA_ATOMIC_LOAD(&ts->ref_cnt)) if (HA_ATOMIC_LOAD(&ts->ref_cnt))
return 0; return 0;
eb32_delete(&ts->exp);
if (ts->upd.node.leaf_p) { if (ts->upd.node.leaf_p) {
updt_locked = 1;
HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock); HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock);
eb32_delete(&ts->upd); if (HA_ATOMIC_LOAD(&ts->ref_cnt))
HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->updt_lock); goto out_unlock;
} }
eb32_delete(&ts->exp);
eb32_delete(&ts->upd);
ebmb_delete(&ts->key); ebmb_delete(&ts->key);
__stksess_free(t, ts); __stksess_free(t, ts);
out_unlock:
if (updt_locked)
HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->updt_lock);
return 1; return 1;
} }