Fixed various bugs in the block allocator: new free ranges were never added
to the free list, so a new range was started for every allocation (!). block_range::Free() did not update the chunk's used_mask correctly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13021 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+35
-14
@@ -15,6 +15,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
//#define TRACE_BLOCK_ALLOCATOR
|
||||||
|
#ifdef TRACE_BLOCK_ALLOCATOR
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static class BlockAddressPool sBlockAddressPool;
|
static class BlockAddressPool sBlockAddressPool;
|
||||||
|
|
||||||
|
|
||||||
@@ -91,7 +99,7 @@ block_range::Compare(void *_blockRange, const void *_address)
|
|||||||
addr_t address = (addr_t)_address;
|
addr_t address = (addr_t)_address;
|
||||||
|
|
||||||
return ((range->base - sBlockAddressPool.BaseAddress()) >> sBlockAddressPool.RangeShift())
|
return ((range->base - sBlockAddressPool.BaseAddress()) >> sBlockAddressPool.RangeShift())
|
||||||
== ((address - sBlockAddressPool.BaseAddress()) >> sBlockAddressPool.RangeShift());
|
- ((address - sBlockAddressPool.BaseAddress()) >> sBlockAddressPool.RangeShift());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,9 +110,10 @@ block_range::Hash(void *_blockRange, const void *_address, uint32 range)
|
|||||||
block_range *blockRange = (block_range *)_blockRange;
|
block_range *blockRange = (block_range *)_blockRange;
|
||||||
addr_t address = (addr_t)_address;
|
addr_t address = (addr_t)_address;
|
||||||
|
|
||||||
if (blockRange != NULL)
|
if (blockRange != NULL) {
|
||||||
return ((blockRange->base - sBlockAddressPool.BaseAddress())
|
return ((blockRange->base - sBlockAddressPool.BaseAddress())
|
||||||
>> sBlockAddressPool.RangeShift()) % range;
|
>> sBlockAddressPool.RangeShift()) % range;
|
||||||
|
}
|
||||||
|
|
||||||
return ((address - sBlockAddressPool.BaseAddress())
|
return ((address - sBlockAddressPool.BaseAddress())
|
||||||
>> sBlockAddressPool.RangeShift()) % range;
|
>> sBlockAddressPool.RangeShift()) % range;
|
||||||
@@ -121,12 +130,19 @@ block_range::NewBlockRange(block_cache *cache, block_range **_range)
|
|||||||
|
|
||||||
block_range *range = (block_range *)malloc(sizeof(block_range)
|
block_range *range = (block_range *)malloc(sizeof(block_range)
|
||||||
+ cache->chunks_per_range * sizeof(block_chunk));
|
+ cache->chunks_per_range * sizeof(block_chunk));
|
||||||
if (range == NULL)
|
if (range == NULL) {
|
||||||
|
sBlockAddressPool.Put(address);
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("new block range %p, base = %p!\n", range, (void *)address));
|
||||||
memset(range, 0, sizeof(block_range) + cache->chunks_per_range * sizeof(block_chunk));
|
memset(range, 0, sizeof(block_range) + cache->chunks_per_range * sizeof(block_chunk));
|
||||||
range->base = address;
|
range->base = address;
|
||||||
|
|
||||||
|
// insert into free ranges list in cache
|
||||||
|
range->free_next = cache->free_ranges;
|
||||||
|
cache->free_ranges = range;
|
||||||
|
|
||||||
*_range = range;
|
*_range = range;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -201,26 +217,28 @@ block_range::Free(block_cache *cache, cached_block *block)
|
|||||||
void *
|
void *
|
||||||
block_range::Allocate(block_cache *cache, block_chunk **_chunk)
|
block_range::Allocate(block_cache *cache, block_chunk **_chunk)
|
||||||
{
|
{
|
||||||
// get free chunk
|
// get free chunk in range
|
||||||
|
|
||||||
uint32 chunk;
|
uint32 chunk;
|
||||||
for (chunk = 0; chunk < cache->chunks_per_range; chunk++) {
|
for (chunk = 0; chunk < cache->chunks_per_range; chunk++) {
|
||||||
if ((used_mask & (1UL << chunk)) == 0)
|
if ((used_mask & (1UL << chunk)) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (chunk == cache->chunks_per_range)
|
if (chunk == cache->chunks_per_range) {
|
||||||
|
panic("block_range %p pretended to be free but isn't\n", this);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// get free block in chunk
|
// get free block in chunk
|
||||||
|
|
||||||
uint32 numBlocks = cache->chunk_size / cache->block_size;
|
uint32 numBlocks = cache->chunk_size / cache->block_size;
|
||||||
uint32 i;
|
uint32 block;
|
||||||
for (i = 0; i < numBlocks; i++) {
|
for (block = 0; block < numBlocks; block++) {
|
||||||
if ((chunks[chunk].used_mask & (1UL << i)) == 0)
|
if ((chunks[chunk].used_mask & (1UL << block)) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i == numBlocks) {
|
if (block == numBlocks) {
|
||||||
panic("block_chunk %lu in range %p pretended to be free but isn't\n", i, this);
|
panic("block_chunk %lu in range %p pretended to be free but isn't\n", block, this);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,8 +278,8 @@ block_range::Allocate(block_cache *cache, block_chunk **_chunk)
|
|||||||
chunks[chunk].mapped = true;
|
chunks[chunk].mapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks[chunk].used_mask |= 1UL << i;
|
chunks[chunk].used_mask |= 1UL << block;
|
||||||
if (chunks[chunk].used_mask == (1UL << numBlocks) - 1) {
|
if (chunks[chunk].used_mask == cache->chunk_mask) {
|
||||||
// all blocks are used in this chunk, propagate usage bit
|
// all blocks are used in this chunk, propagate usage bit
|
||||||
used_mask |= 1UL << chunk;
|
used_mask |= 1UL << chunk;
|
||||||
|
|
||||||
@@ -284,10 +302,11 @@ block_range::Allocate(block_cache *cache, block_chunk **_chunk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TRACE(("Allocate: used masks: chunk = %x, range = %lx\n", chunks[chunk].used_mask, used_mask));
|
||||||
|
|
||||||
if (_chunk)
|
if (_chunk)
|
||||||
*_chunk = &chunks[chunk];
|
*_chunk = &chunks[chunk];
|
||||||
return (void *)(base + cache->chunk_size * chunk + cache->block_size * i);
|
return (void *)(base + cache->chunk_size * chunk + cache->block_size * block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -305,7 +324,9 @@ block_range::Free(block_cache *cache, void *address)
|
|||||||
// chunk was full before, propagate usage bit to range
|
// chunk was full before, propagate usage bit to range
|
||||||
used_mask &= ~(1UL << chunk);
|
used_mask &= ~(1UL << chunk);
|
||||||
}
|
}
|
||||||
chunks[chunk].used_mask |= BlockIndex(cache, address);
|
chunks[chunk].used_mask &= ~(1UL << BlockIndex(cache, address));
|
||||||
|
|
||||||
|
TRACE(("Free: used masks: chunk = %x, range = %lx\n", chunks[chunk].used_mask, used_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user