* BFS allocated always full allocation groups in the bitmap, even if the last
group was a partial one. This caused bug #3963 (Be's BFS didn't do that). * Added new BlockAllocator::CheckBlocks() that does not depend on allocation group limits - this fixes the problematic check in BlockAllocator::_Initialize() to see if the super block, the block bitmap, and the log area are all allocated - this only worked if they all fit into the first allocation group (which happens only with partitions with more than 1 billion blocks, ie. 2 TB would already be problematic with a 2K block size). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31248 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -533,6 +533,9 @@ BlockAllocator::Initialize(bool full)
|
||||
{
|
||||
fNumGroups = fVolume->AllocationGroups();
|
||||
fBlocksPerGroup = fVolume->SuperBlock().BlocksPerAllocationGroup();
|
||||
fNumBlocks = (fVolume->NumBlocks() + fVolume->BlockSize() * 8 - 1)
|
||||
/ (fVolume->BlockSize() * 8);
|
||||
|
||||
fGroups = new AllocationGroup[fNumGroups];
|
||||
if (fGroups == NULL)
|
||||
return B_NO_MEMORY;
|
||||
@@ -558,11 +561,10 @@ status_t
|
||||
BlockAllocator::InitializeAndClearBitmap(Transaction& transaction)
|
||||
{
|
||||
status_t status = Initialize(false);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
uint32 blocks = fBlocksPerGroup;
|
||||
uint32 numBits = 8 * blocks * fVolume->BlockSize();
|
||||
uint32 numBits = 8 * fBlocksPerGroup * fVolume->BlockSize();
|
||||
uint32 blockShift = fVolume->BlockShift();
|
||||
|
||||
uint32* buffer = (uint32*)malloc(numBits >> 3);
|
||||
@@ -572,12 +574,13 @@ BlockAllocator::InitializeAndClearBitmap(Transaction& transaction)
|
||||
memset(buffer, 0, numBits >> 3);
|
||||
|
||||
off_t offset = 1;
|
||||
// the bitmap starts directly after the super block
|
||||
|
||||
// initialize the AllocationGroup objects and clear the on-disk bitmap
|
||||
|
||||
for (int32 i = 0; i < fNumGroups; i++) {
|
||||
if (write_pos(fVolume->Device(), offset << blockShift, buffer,
|
||||
blocks << blockShift) < B_OK)
|
||||
fBlocksPerGroup << blockShift) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// the last allocation group may contain less blocks than the others
|
||||
@@ -587,14 +590,14 @@ BlockAllocator::InitializeAndClearBitmap(Transaction& transaction)
|
||||
>> (blockShift + 3));
|
||||
} else {
|
||||
fGroups[i].fNumBits = numBits;
|
||||
fGroups[i].fNumBlocks = blocks;
|
||||
fGroups[i].fNumBlocks = fBlocksPerGroup;
|
||||
}
|
||||
fGroups[i].fStart = offset;
|
||||
fGroups[i].fFirstFree = fGroups[i].fLargestStart = 0;
|
||||
fGroups[i].fFreeBits = fGroups[i].fLargestLength = fGroups[i].fNumBits;
|
||||
fGroups[i].fLargestValid = true;
|
||||
|
||||
offset += blocks;
|
||||
offset += fBlocksPerGroup;
|
||||
}
|
||||
free(buffer);
|
||||
|
||||
@@ -679,16 +682,16 @@ BlockAllocator::_Initialize(BlockAllocator* allocator)
|
||||
|
||||
// check if block bitmap and log area are reserved
|
||||
uint32 reservedBlocks = volume->Log().Start() + volume->Log().Length();
|
||||
if (allocator->CheckBlockRun(block_run::Run(0, 0, reservedBlocks)) < B_OK) {
|
||||
|
||||
if (allocator->CheckBlocks(0, reservedBlocks) != B_OK) {
|
||||
Transaction transaction(volume, 0);
|
||||
if (groups[0].Allocate(transaction, 0, reservedBlocks) < B_OK) {
|
||||
if (groups[0].Allocate(transaction, 0, reservedBlocks) != B_OK) {
|
||||
FATAL(("could not allocate reserved space for block "
|
||||
"bitmap/log!\n"));
|
||||
volume->Panic();
|
||||
} else {
|
||||
FATAL(("space for block bitmap or log area was not reserved!\n"));
|
||||
|
||||
transaction.Done();
|
||||
FATAL(("space for block bitmap or log area was not reserved!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1011,19 +1014,19 @@ BlockAllocator::Free(Transaction& transaction, block_run run)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (CheckBlockRun(run) < B_OK)
|
||||
if (CheckBlockRun(run) != B_OK)
|
||||
return B_BAD_DATA;
|
||||
#endif
|
||||
|
||||
CHECK_ALLOCATION_GROUP(group);
|
||||
|
||||
if (fGroups[group].Free(transaction, start, length) < B_OK)
|
||||
if (fGroups[group].Free(transaction, start, length) != B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
CHECK_ALLOCATION_GROUP(group);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CheckBlockRun(run, NULL, NULL, false) < B_OK) {
|
||||
if (CheckBlockRun(run, NULL, NULL, false) != B_OK) {
|
||||
DEBUGGER(("CheckBlockRun() reports allocated blocks (which were just "
|
||||
"freed)\n"));
|
||||
}
|
||||
@@ -1038,7 +1041,7 @@ BlockAllocator::Free(Transaction& transaction, block_run run)
|
||||
size_t
|
||||
BlockAllocator::BitmapSize() const
|
||||
{
|
||||
return fVolume->BlockSize() * fNumGroups * fBlocksPerGroup;
|
||||
return fVolume->BlockSize() * fNumBlocks;
|
||||
}
|
||||
|
||||
|
||||
@@ -1501,6 +1504,42 @@ BlockAllocator::_SetCheckBitmapAt(off_t block)
|
||||
}
|
||||
|
||||
|
||||
/*! Checks whether or not the specified block range is allocated or not,
|
||||
depending on the \a allocated argument.
|
||||
*/
|
||||
status_t
|
||||
BlockAllocator::CheckBlocks(off_t start, off_t length, bool allocated)
|
||||
{
|
||||
if (start < 0 || start + length > fVolume->NumBlocks())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint32 group = start >> fVolume->AllocationGroupShift();
|
||||
uint32 groupBlock = start % (fVolume->BlockSize() << 3);
|
||||
uint32 blockOffset = start % fVolume->BlockSize();
|
||||
|
||||
AllocationBlock cached(fVolume);
|
||||
|
||||
while (groupBlock < fGroups[group].NumBlocks() && length > 0) {
|
||||
if (cached.SetTo(fGroups[group], groupBlock) != B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
for (; blockOffset < cached.NumBlockBits() && length > 0;
|
||||
blockOffset++, length--) {
|
||||
if (cached.IsUsed(blockOffset) != allocated) {
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
if (++groupBlock >= fGroups[group].NumBlocks()) {
|
||||
groupBlock = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BlockAllocator::CheckBlockRun(block_run run, const char* type,
|
||||
check_control* control, bool allocated)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2008, Axel Dörfler, [email protected].
|
||||
* Copyright 2001-2009, Axel Dörfler, [email protected].
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BLOCK_ALLOCATOR_H
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
status_t StopChecking(check_control* control);
|
||||
status_t CheckNextNode(check_control* control);
|
||||
|
||||
status_t CheckBlocks(off_t start, off_t length,
|
||||
bool allocated = true);
|
||||
status_t CheckBlockRun(block_run run,
|
||||
const char* type = NULL,
|
||||
check_control* control = NULL,
|
||||
@@ -76,6 +78,7 @@ private:
|
||||
AllocationGroup* fGroups;
|
||||
int32 fNumGroups;
|
||||
uint32 fBlocksPerGroup;
|
||||
uint32 fNumBlocks;
|
||||
|
||||
uint32* fCheckBitmap;
|
||||
check_cookie* fCheckCookie;
|
||||
|
||||
@@ -655,8 +655,9 @@ Volume::Initialize(int fd, const char* name, uint32 blockSize,
|
||||
|
||||
// since the allocator has not been initialized yet, we
|
||||
// cannot use BlockAllocator::BitmapSize() here
|
||||
fSuperBlock.log_blocks = ToBlockRun(AllocationGroups()
|
||||
* fSuperBlock.BlocksPerAllocationGroup() + 1);
|
||||
off_t bitmapBlocks = (numBlocks + blockSize * 8 - 1) / (blockSize * 8);
|
||||
|
||||
fSuperBlock.log_blocks = ToBlockRun(bitmapBlocks + 1);
|
||||
fSuperBlock.log_blocks.length = HOST_ENDIAN_TO_BFS_INT16(logSize);
|
||||
fSuperBlock.log_start = fSuperBlock.log_end = HOST_ENDIAN_TO_BFS_INT64(
|
||||
ToBlock(Log()));
|
||||
|
||||
Reference in New Issue
Block a user