BUG/MAJOR: pools: second fix for incomplete backport of lockless pool fix
authorWilly Tarreau <w@1wt.eu>
Thu, 8 Jul 2021 15:05:10 +0000 (17:05 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 8 Jul 2021 15:08:32 +0000 (17:08 +0200)
Commit bc76411e0 ("BUG/MAJOR: pools: fix possible race with free() in
the lockless variant") was missing another unprotected access to the
pool's free_list in __pool_refill_alloc() because this one was completely
dropped from 2.4 and above. There we need to loop over POOL_BUSY just like
in the __pool_free() code, otherwise we risk to insert such a POOL_BUSY
into the list.

This fix is only for 2.3 and 2.2 since 2.2 now also contains the faulty
backport of the patch above.

src/pool.c

index 799c29f..1a4d1f8 100644 (file)
@@ -273,11 +273,16 @@ void *__pool_refill_alloc(struct pool_head *pool, unsigned int avail)
                if (++allocated > avail)
                        break;
 
-               free_list = pool->free_list;
+               free_list = _HA_ATOMIC_LOAD(&pool->free_list);
                do {
-                       *POOL_LINK(pool, ptr) = free_list;
-                       __ha_barrier_store();
-               } while (_HA_ATOMIC_CAS(&pool->free_list, &free_list, ptr) == 0);
+                       while (unlikely(free_list == POOL_BUSY)) {
+                               pl_cpu_relax();
+                               free_list = _HA_ATOMIC_LOAD(&pool->free_list);
+                       }
+                       _HA_ATOMIC_STORE(POOL_LINK(pool, ptr), (void *)free_list);
+                       __ha_barrier_atomic_store();
+               } while (!_HA_ATOMIC_CAS(&pool->free_list, &free_list, ptr));
+               __ha_barrier_atomic_store();
        }
        __ha_barrier_atomic_store();