From b98d9a335ae4abd0200a4c03a5d07c8004ba07e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 7 Sep 2002 02:44:42 +0000 Subject: [PATCH] Fixed two bugs in the block allocator: - the maximum number of blocks a block_run can cover is 65535 not 65536 - allocations over a block boundary in the block bitmap always failed due to a incorrectly handled status Both bugs could prevent BFS to create the VM swap file which led BeOS to stop booting under certain circumstances. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@989 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../file_systems/bfs/BlockAllocator.cpp | 35 +++++++++++++------ src/add-ons/kernel/file_systems/bfs/Inode.h | 4 +-- src/add-ons/kernel/file_systems/bfs/ToDo | 5 ++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index deb22895c9..4e8c5435b9 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -162,8 +162,8 @@ AllocationGroup::AllocationGroup() void AllocationGroup::AddFreeRange(int32 start, int32 blocks) { - D(if (blocks > 512) - PRINT(("range of %ld blocks starting at %ld\n",blocks,start))); + //D(if (blocks > 512) + // PRINT(("range of %ld blocks starting at %ld\n",blocks,start))); if (fFirstFree == -1) fFirstFree = start; @@ -205,7 +205,7 @@ BlockAllocator::Initialize() fGroups = new AllocationGroup[fNumGroups]; if (fGroups == NULL) return B_NO_MEMORY; - + thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::initialize,"bfs block allocator",B_LOW_PRIORITY,(void *)this); if (id < B_OK) return initialize(this); @@ -279,6 +279,9 @@ BlockAllocator::initialize(BlockAllocator *allocator) status_t BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start,uint16 maximum,uint16 minimum, block_run &run) { + if (maximum == 0) + return B_BAD_VALUE; + AllocationBlock cached(fVolume); Locker lock(fLock); @@ -319,7 +322,7 @@ BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start int32 range = 0, rangeStart = 0,rangeBlock = 0; for (;block < fBlocksPerGroup;block++) { - if (cached.SetTo(fGroups[group],block) < B_OK) + if (cached.SetTo(fGroups[group], block) < B_OK) RETURN_ERROR(B_ERROR); // find a block large enough to hold the allocation @@ -358,15 +361,15 @@ BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start if (block != rangeBlock) { // allocate the part that's in the current block - cached.Allocate(0,(rangeStart + numBlocks) % cached.NumBlockBits()); + cached.Allocate(0, (rangeStart + numBlocks) % cached.NumBlockBits()); if (cached.WriteBack(transaction) < B_OK) RETURN_ERROR(B_ERROR); // set the blocks in the previous block - if (cached.SetTo(fGroups[group],block - 1) < B_OK) - cached.Allocate(rangeStart); - else + if (cached.SetTo(fGroups[group], block - 1) < B_OK) RETURN_ERROR(B_ERROR); + + cached.Allocate(rangeStart); } else { // just allocate the bits in the current block cached.Allocate(rangeStart,numBlocks); @@ -420,12 +423,24 @@ BlockAllocator::Allocate(Transaction *transaction,const Inode *inode, off_t numB if (numBlocks > fGroups[0].fNumBits) numBlocks = fGroups[0].fNumBits; + // since block_run.length is uint16, the largest number of blocks that + // can be covered by a block_run is 65535 + // ToDo: if we drop compatibility, couldn't we do this any better? + // There are basically two possibilities: + // a) since a length of zero doesn't have any sense, take that for 65536 - + // but that could cause many problems (bugs) in other areas + // b) reduce the maximum amount of blocks per block_run, so that the remaining + // number of free blocks can be used in a useful manner (like 4 blocks) - + // but that would also reduce the maximum file size + if (numBlocks == 65536) + numBlocks = 65535; + // apply some allocation policies here (AllocateBlocks() will break them // if necessary) uint16 group = inode->BlockRun().allocation_group; uint16 start = 0; - // are there already allocated blocks? (then just allocate near the last) + // are there already allocated blocks? (then just try to allocate near the last one) if (inode->Size() > 0) { data_stream *data = &inode->Node()->data; // we currently don't care for when the data stream is @@ -449,7 +464,7 @@ BlockAllocator::Allocate(Transaction *transaction,const Inode *inode, off_t numB group = inode->BlockRun().allocation_group + 1; } - return AllocateBlocks(transaction,group,start,numBlocks,minimum,run); + return AllocateBlocks(transaction, group, start, numBlocks, minimum, run); } diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h b/src/add-ons/kernel/file_systems/bfs/Inode.h index 9e81c99ecb..d3d256e701 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.h +++ b/src/add-ons/kernel/file_systems/bfs/Inode.h @@ -84,7 +84,7 @@ class CachedBlock { release_block(fVolume->Device(),fBlockNumber); } - uint8 *SetTo(off_t block,bool empty = false) + uint8 *SetTo(off_t block, bool empty = false) { Unset(); fBlockNumber = block; @@ -92,7 +92,7 @@ class CachedBlock { : (uint8 *)get_block(fVolume->Device(),block,fVolume->BlockSize()); } - uint8 *SetTo(block_run run,bool empty = false) + uint8 *SetTo(block_run run, bool empty = false) { return SetTo(fVolume->ToBlock(run),empty); } diff --git a/src/add-ons/kernel/file_systems/bfs/ToDo b/src/add-ons/kernel/file_systems/bfs/ToDo index 01f9914929..3e812a97e9 100644 --- a/src/add-ons/kernel/file_systems/bfs/ToDo +++ b/src/add-ons/kernel/file_systems/bfs/ToDo @@ -1,4 +1,4 @@ -BFS - ToDo, August 12th, 2002 +BFS - ToDo, September 7th, 2002 ----- BlockAllocator @@ -11,9 +11,8 @@ BlockAllocator DataStream - - growing/shrinking the stream size is not implemented for the double indirect range - only files are trimmed back (in bfs_close()), but every inode has a preallocated stream... - - merging of block_runs doesn't work between range/block boundaries + - Inode::GrowStream(): merging of block_runs doesn't work between range/block boundaries Queries