summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Fu <vincent.fu@wdc.com>2019-07-30 09:00:56 -0600
committerVincent Fu <vincent.fu@wdc.com>2019-07-31 14:17:44 -0400
commit554461db6d57df00766e2c4cc7d18f1561d2fa4b (patch)
treef2fc1a64d94a32fcae15274ced68c30aa3b0e67d
parent6cc38ac03026f0d25b65e941b8682a618b66efb2 (diff)
downloadfio-554461db6d57df00766e2c4cc7d18f1561d2fa4b.tar.gz
fio-554461db6d57df00766e2c4cc7d18f1561d2fa4b.tar.bz2
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.
-rw-r--r--smalloc.c21
1 files changed, 19 insertions, 2 deletions
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;
}