diff options
author | Vincent Fu <vincent.fu@wdc.com> | 2019-07-30 09:00:56 -0600 |
---|---|---|
committer | Vincent Fu <vincent.fu@wdc.com> | 2019-07-31 14:17:44 -0400 |
commit | 554461db6d57df00766e2c4cc7d18f1561d2fa4b (patch) | |
tree | f2fc1a64d94a32fcae15274ced68c30aa3b0e67d | |
parent | 6cc38ac03026f0d25b65e941b8682a618b66efb2 (diff) | |
download | fio-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.c | 21 |
1 files changed, 19 insertions, 2 deletions
@@ -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; } |