From 09c46ea8bd43d9b8ccb6eeaf24f9fd5be4e8291b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 15 Jan 2008 15:18:02 +0000 Subject: [PATCH] * Fixed bug in the BlockAllocator::Allocate() function which did not compute the bit offsets correctly if the last block of the whole bitmap was only a partial block. * Added new bfs_allocator KDL command. * Renamed the KDL command bfsinode to bfs_inode. * Added "--help" argument to bfs_inode and bfs KDL commands. * Added more tracing in the block allocator. * Turned on the ASSERT() macro in non-debug builds. * Minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23534 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../file_systems/bfs/BlockAllocator.cpp | 133 ++++++++++++------ .../kernel/file_systems/bfs/BlockAllocator.h | 13 +- src/add-ons/kernel/file_systems/bfs/Debug.cpp | 12 +- src/add-ons/kernel/file_systems/bfs/Debug.h | 3 +- 4 files changed, 111 insertions(+), 50 deletions(-) diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index c0f70b53c4..bda5cf445e 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -95,10 +95,12 @@ checksum(const uint8 *data, size_t size) class Block : public AbstractTraceEntry { public: Block(const char *label, off_t blockNumber, const uint8 *data, - size_t size) + size_t size, uint32 start = 0, uint32 length = 0) : fBlock(blockNumber), - fData(data) + fData(data), + fStart(start), + fLength(length) { strlcpy(fLabel, label, sizeof(fLabel)); fSum = checksum(data, size); @@ -109,7 +111,8 @@ class Block : public AbstractTraceEntry { virtual void AddDump(char *buffer, size_t size) { uint32 length = snprintf(buffer, size, "%s: block %Ld (%p), sum %lu," - " bytes ", fLabel, fBlock, fData, fSum); + " s/l %lu/%lu, bytes ", fLabel, fBlock, fData, fSum, fStart, + fLength); for (uint32 i = 0; length < size - 1 && i < sizeof(fBytes); i++) { length += snprintf(buffer + length, size - length, "%02x", fBytes[i]); @@ -119,6 +122,8 @@ class Block : public AbstractTraceEntry { private: off_t fBlock; const uint8 *fData; + uint32 fStart; + uint32 fLength; uint32 fSum; char fLabel[12]; uint8 fBytes[32]; @@ -215,7 +220,8 @@ AllocationBlock::SetTo(AllocationGroup &group, uint16 block) status_t -AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group, uint16 block) +AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group, + uint16 block) { // 8 blocks per byte fNumBits = fVolume->BlockSize() << 3; @@ -226,8 +232,8 @@ AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group, #ifdef DEBUG fWritable = true; #endif - return CachedBlock::SetToWritable(transaction, group.Start() + block) != NULL - ? B_OK : B_ERROR; + return CachedBlock::SetToWritable(transaction, group.Start() + block) + != NULL ? B_OK : B_ERROR; } @@ -256,13 +262,15 @@ AllocationBlock::Allocate(uint16 start, uint16 numBlocks) DIE(("Allocation::Allocate(): tried to allocate too many blocks")); } + T(Block("b-alloc-in", fBlockNumber, fBlock, fVolume->BlockSize(), + start, numBlocks)); + int32 block = start >> 5; while (numBlocks > 0) { uint32 mask = 0; for (int32 i = start % 32; i < 32 && numBlocks; i++, numBlocks--) - mask |= 1UL << (i % 32); - + mask |= 1UL << i; #ifdef DEBUG // check for already set blocks if (HOST_ENDIAN_TO_BFS_INT32(mask) & ((uint32 *)fBlock)[block]) { @@ -273,6 +281,8 @@ AllocationBlock::Allocate(uint16 start, uint16 numBlocks) Block(block++) |= HOST_ENDIAN_TO_BFS_INT32(mask); start = 0; } + T(Block("b-alloc-out", fBlockNumber, fBlock, fVolume->BlockSize(), + start, numBlocks)); } @@ -306,11 +316,10 @@ AllocationBlock::Free(uint16 start, uint16 numBlocks) // #pragma mark - -/** The allocation groups are created and initialized in - * BlockAllocator::Initialize() and BlockAllocator::InitializeAndClearBitmap() - * respectively. - */ - +/*! The allocation groups are created and initialized in + BlockAllocator::Initialize() and BlockAllocator::InitializeAndClearBitmap() + respectively. +*/ AllocationGroup::AllocationGroup() : fFirstFree(-1), @@ -339,15 +348,12 @@ AllocationGroup::AddFreeRange(int32 start, int32 blocks) } -/** Allocates the specified run in the allocation group. - * Doesn't check if the run is valid or already allocated - * partially, nor does it maintain the free ranges hints - * or the volume's used blocks count. - * It only does the low-level work of allocating some bits - * in the block bitmap. - * Assumes that the block bitmap lock is hold. - */ - +/*! Allocates the specified run in the allocation group. + Doesn't check if the run is valid or already allocated partially, nor + does it maintain the free ranges hints or the volume's used blocks count. + It only does the low-level work of allocating some bits in the block bitmap. + Assumes that the block bitmap lock is hold. +*/ status_t AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length) { @@ -389,15 +395,12 @@ AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length) } -/** Frees the specified run in the allocation group. - * Doesn't check if the run is valid or was not completely - * allocated, nor does it maintain the free ranges hints - * or the volume's used blocks count. - * It only does the low-level work of freeing some bits - * in the block bitmap. - * Assumes that the block bitmap lock is hold. - */ - +/*! Frees the specified run in the allocation group. + Doesn't check if the run is valid or was not completely allocated, nor + does it maintain the free ranges hints or the volume's used blocks count. + It only does the low-level work of freeing some bits in the block bitmap. + Assumes that the block bitmap lock is hold. +*/ status_t AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length) { @@ -642,10 +645,11 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, AllocationBlock cached(fVolume); Locker lock(fLock); - // the first scan through all allocation groups will look for the + // The first scan through all allocation groups will look for the // wanted maximum of blocks, the second scan will just look to // satisfy the minimal requirement uint16 numBlocks = maximum; + uint32 bitsPerFullBlock = fVolume->BlockSize() << 3; for (int32 i = 0; i < fNumGroups * 2; i++, group++, start = 0) { group = group % fNumGroups; @@ -654,7 +658,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, continue; if (i >= fNumGroups) { - // if the minimum is the same as the maximum, it's not necessary to + // If the minimum is the same as the maximum, it's not necessary to // search for in the allocation groups a second time if (maximum == minimum) return B_DEVICE_FULL; @@ -662,8 +666,8 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, numBlocks = minimum; } - // The wanted maximum is smaller than the largest free block in the group - // or already smaller than the minimum + // The wanted maximum is smaller than the largest free block in the + // group or already smaller than the minimum // ToDo: disabled because it's currently not maintained after the first allocation //if (numBlocks > fGroups[group].fLargest) // continue; @@ -671,7 +675,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, if (start < fGroups[group].fFirstFree) start = fGroups[group].fFirstFree; - // there may be more than one block per allocation group - and + // There may be more than one block per allocation group - and // we iterate through it to find a place for the allocation. // (one allocation can't exceed one allocation group) @@ -682,15 +686,15 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, if (cached.SetTo(fGroups[group], block) < B_OK) RETURN_ERROR(B_ERROR); - T(Block("alloc-in", block, cached.Block(), fVolume->BlockSize())); + T(Block("alloc-in", fGroups[group].Start() + block, cached.Block(), fVolume->BlockSize(), group, rangeStart)); // find a block large enough to hold the allocation - for (uint32 bit = start % cached.NumBlockBits(); + for (uint32 bit = start % bitsPerFullBlock; bit < cached.NumBlockBits(); bit++) { if (!cached.IsUsed(bit)) { if (range == 0) { // start new range - rangeStart = block * cached.NumBlockBits() + bit; + rangeStart = block * bitsPerFullBlock + bit; } // have we found a range large enough to hold numBlocks? @@ -733,7 +737,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, T(Allocate(run)); T(Block("alloc-out", block, cached.Block(), - fVolume->BlockSize())); + fVolume->BlockSize(), group, rangeStart)); return B_OK; } @@ -746,8 +750,8 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, status_t -BlockAllocator::AllocateForInode(Transaction &transaction, const block_run *parent, - mode_t type, block_run &run) +BlockAllocator::AllocateForInode(Transaction &transaction, + const block_run *parent, mode_t type, block_run &run) { // apply some allocation policies here (AllocateBlocks() will break them // if necessary) - we will start with those described in Dominic Giampaolo's @@ -1407,3 +1411,48 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control) return B_OK; } + +// #pragma mark - debugger commands + + +#ifdef BFS_DEBUGGER_COMMANDS + + +void +BlockAllocator::Dump() +{ + kprintf("allocation groups: %ld\n", fNumGroups); + kprintf("blocks per group: %ld\n", fBlocksPerGroup); + + for (int32 i = 0; i < fNumGroups; i++) { + AllocationGroup& group = fGroups[i]; + + kprintf("[%3ld] num bits: %lu\n", i, group.NumBits()); + kprintf(" num blocks: %lu\n", group.NumBlocks()); + kprintf(" start: %ld\n", group.Start()); + kprintf(" first free: %ld\n", group.fFirstFree); + kprintf(" largest: %ld\n", group.fLargest); + kprintf(" largest first: %ld\n", group.fLargestFirst); + kprintf(" free bits: %ld\n", group.fFreeBits); + } +} + + +int +dump_block_allocator(int argc, char **argv) +{ + if (argc != 2 || !strcmp(argv[1], "--help")) { + kprintf("usage: %s \n", argv[0]); + return 0; + } + + Volume *volume = (Volume *)parse_expression(argv[1]); + BlockAllocator &allocator = volume->Allocator(); + + allocator.Dump(); + return 0; +} + + +#endif // BFS_DEBUGGER_COMMANDS + diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h index 5aca0e743c..add4f45927 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h @@ -1,6 +1,5 @@ -/* BlockAllocator - block bitmap handling and allocation policies - * - * Copyright 2001-2006, Axel Dörfler, axeld@pinc-software.de. +/* + * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ #ifndef BLOCK_ALLOCATOR_H @@ -46,6 +45,10 @@ class BlockAllocator { size_t BitmapSize() const; +#ifdef BFS_DEBUGGER_COMMANDS + void Dump(); +#endif + private: bool _IsValidCheckControl(check_control *control); bool _CheckBitmapIsUsedAt(off_t block) const; @@ -63,4 +66,8 @@ class BlockAllocator { check_cookie *fCheckCookie; }; +#ifdef BFS_DEBUGGER_COMMANDS +int dump_block_allocator(int argc, char **argv); +#endif + #endif /* BLOCK_ALLOCATOR_H */ diff --git a/src/add-ons/kernel/file_systems/bfs/Debug.cpp b/src/add-ons/kernel/file_systems/bfs/Debug.cpp index b1ab3536f1..d93c0d10fe 100644 --- a/src/add-ons/kernel/file_systems/bfs/Debug.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Debug.cpp @@ -7,6 +7,7 @@ #include "Debug.h" +#include "BlockAllocator.h" #include "BPlusTree.h" #include "Inode.h" @@ -247,7 +248,7 @@ dump_bplustree_node(const bplustree_node *node, const bplustree_header *header, static int dump_inode(int argc, char **argv) { - if (argc != 2) { + if (argc != 2 || !strcmp(argv[1], "--help")) { kprintf("usage: bfsinode \n"); return 0; } @@ -262,7 +263,7 @@ dump_inode(int argc, char **argv) static int dump_volume(int argc, char **argv) { - if (argc != 2) { + if (argc != 2 || !strcmp(argv[1], "--help")) { kprintf("usage: bfs \n"); return 0; } @@ -281,7 +282,8 @@ dump_volume(int argc, char **argv) void remove_debugger_commands() { - remove_debugger_command("bfsinode", dump_inode); + remove_debugger_command("bfs_inode", dump_inode); + remove_debugger_command("bfs_allocator", dump_block_allocator); remove_debugger_command("bfs", dump_volume); } @@ -289,7 +291,9 @@ remove_debugger_commands() void add_debugger_commands() { - add_debugger_command("bfsinode", dump_inode, "dump an Inode object"); + add_debugger_command("bfs_inode", dump_inode, "dump an Inode object"); + add_debugger_command("bfs_allocator", dump_block_allocator, + "dump a BFS block allocator."); add_debugger_command("bfs", dump_volume, "dump a BFS volume"); } diff --git a/src/add-ons/kernel/file_systems/bfs/Debug.h b/src/add-ons/kernel/file_systems/bfs/Debug.h index 7fa21d6041..db73d2a470 100644 --- a/src/add-ons/kernel/file_systems/bfs/Debug.h +++ b/src/add-ons/kernel/file_systems/bfs/Debug.h @@ -74,7 +74,8 @@ #define FUNCTION_START(x) ; #define D(x) ; #ifndef ASSERT - # define ASSERT(x) ; + # define ASSERT(x) { if (!(x)) DEBUGGER(("bfs: assert failed: " #x "\n")); } +// # define ASSERT(x) ; #endif #endif