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