alloc: fix and improve the block allocation algorithm

The block allocation algorithm, as implemented in _balloc(), is first
trying to find a single free memory block to satisfy the request. If
that fails it is then trying to allocate several blocks in a
sequence. That part is implemented wrongly. It can end up allocating
multiple such block sequences, and not using but leaking them
instead. This patch first simplifies the search for a single suitable
buffer, then fixes the leakage.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Guennadi Liakhovetski 2019-01-17 10:29:56 +01:00 committed by Liam Girdwood
parent 8c62c4457c
commit c8f1edfaa4
1 changed files with 22 additions and 30 deletions

View File

@ -656,40 +656,32 @@ void *_balloc(int zone, uint32_t caps, size_t bytes)
for (i = 0; i < heap->blocks; i++) { for (i = 0; i < heap->blocks; i++) {
map = &heap->map[i]; map = &heap->map[i];
/* is block big enough */ /* Check if blocks are big enough and at least one is free */
if (map->block_size < bytes) if (map->block_size >= bytes && map->free_count) {
continue; /* found: grab a block */
/* does block have free space */
if (map->free_count == 0)
continue;
/* allocate block */
ptr = alloc_block(heap, i, caps); ptr = alloc_block(heap, i, caps);
goto out; break;
}
} }
/* request spans > 1 block */ /* request spans > 1 block */
if (!ptr) {
/* only 1 choice for block size */ /*
if (heap->blocks == 1) { * Find the best block size for request. We know, that we failed
ptr = alloc_cont_blocks(heap, 0, caps, bytes); * to find a single large enough block, so, skip those.
goto out; */
} else { for (i = heap->blocks - 1; i >= 0; i--) {
/* find best block size for request */
for (i = 0; i < heap->blocks; i++) {
map = &heap->map[i]; map = &heap->map[i];
/* allocate is block size smaller than request */ /* allocate if block size is smaller than request */
if (map->block_size < bytes) if (heap->size >= bytes && map->block_size < bytes) {
alloc_cont_blocks(heap, i, caps, bytes); ptr = alloc_cont_blocks(heap, i, caps, bytes);
if (ptr)
break;
}
} }
} }
ptr = alloc_cont_blocks(heap, heap->blocks - 1, caps, bytes);
out:
if (ptr && ((zone & RZONE_FLAG_MASK) == RZONE_FLAG_UNCACHED)) if (ptr && ((zone & RZONE_FLAG_MASK) == RZONE_FLAG_UNCACHED))
ptr = cache_to_uncache(ptr); ptr = cache_to_uncache(ptr);