]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: stick-table: make sure never to miss a process_table_expire update
authorWilly Tarreau <w@1wt.eu>
Wed, 10 Sep 2025 16:45:01 +0000 (18:45 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 10 Sep 2025 16:45:01 +0000 (18:45 +0200)
In stktable_requeue_exp(), there's a tiny race at the beginning during
which we check the task's expiration date to decide whether or not to
wake process_table_expire() up. During this race, the task might just
have finished running on its owner thread and we can miss a task_queue()
opportunity, which probably explains why during testing it seldom happens
that a few entries are left at the end.

Let's perform a CAS to confirm the value is still the same before
leaving. This way we're certain that our value has been seen at least
once.

This should be backported to 3.2.

src/stick_table.c

index 54d9699a627c2ee3b0177201a781ea027cec6d3c..b7f6f89bbafc4362a0a9edfef32a4f5d790e0d18 100644 (file)
@@ -724,14 +724,18 @@ void stktable_requeue_exp(struct stktable *t, const struct stksess *ts)
        old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
        new_exp = tick_first(expire, old_exp);
 
-       /* let's not go further if we're already up to date */
-       if (new_exp == old_exp)
+       /* let's not go further if we're already up to date. We have
+        * to make sure the compared date doesn't change under us.
+        */
+       if (new_exp == old_exp &&
+           HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp))
                return;
 
        HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
 
-       while (new_exp != old_exp &&
-              !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) {
+       while (!HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) {
+               if (new_exp == old_exp)
+                       break;
                __ha_cpu_relax();
                new_exp = tick_first(expire, old_exp);
        }