From: Vincent Fu Date: Tue, 30 Jul 2019 15:00:56 +0000 (-0600) Subject: smalloc: fix garbage collection problem X-Git-Tag: fio-3.16~43^2 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=554461db6d57df00766e2c4cc7d18f1561d2fa4b smalloc: fix garbage collection problem If a large request arrives when pool->next_non_full points to empty space that is insufficient to satisfy the request, pool->next_non_full will be inappropriately advanced when the free space is followed by lines of fully allocated space. The free space originally pointed to by pool->next_non_full will be unavailable unless a subsequent sfree() call frees allocated space above it. Resolve this issue by advancing pool->next_non_full only outside the search loop and only when it points to fully allocated space. --- diff --git a/smalloc.c b/smalloc.c index c1ae08bd..c97bcbaa 100644 --- a/smalloc.c +++ b/smalloc.c @@ -338,6 +338,17 @@ void sfree(void *ptr) log_err("smalloc: ptr %p not from smalloc pool\n", ptr); } +static unsigned int firstfree(struct pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->nr_blocks; i++) + if (pool->bitmap[i] != -1U) + return i; + + assert(0); +} + static void *__smalloc_pool(struct pool *pool, size_t size) { size_t nr_blocks; @@ -352,7 +363,14 @@ static void *__smalloc_pool(struct pool *pool, size_t size) if (nr_blocks > pool->free_blocks) goto fail; - i = pool->next_non_full; + for (i = pool->next_non_full; pool->bitmap[i] == -1U; i++) + if (i == pool->nr_blocks - 1) { + i = firstfree(pool); + break; + } + + pool->next_non_full = i; + last_idx = 0; offset = -1U; while (i < pool->nr_blocks) { @@ -360,7 +378,6 @@ static void *__smalloc_pool(struct pool *pool, size_t size) if (pool->bitmap[i] == -1U) { i++; - pool->next_non_full = i; last_idx = 0; continue; }