* 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
This commit is contained in:
Axel Dörfler
2008-01-15 15:18:02 +00:00
parent 36a3ef573d
commit 09c46ea8bd
4 changed files with 111 additions and 50 deletions
@@ -95,10 +95,12 @@ checksum(const uint8 *data, size_t size)
class Block : public AbstractTraceEntry { class Block : public AbstractTraceEntry {
public: public:
Block(const char *label, off_t blockNumber, const uint8 *data, Block(const char *label, off_t blockNumber, const uint8 *data,
size_t size) size_t size, uint32 start = 0, uint32 length = 0)
: :
fBlock(blockNumber), fBlock(blockNumber),
fData(data) fData(data),
fStart(start),
fLength(length)
{ {
strlcpy(fLabel, label, sizeof(fLabel)); strlcpy(fLabel, label, sizeof(fLabel));
fSum = checksum(data, size); fSum = checksum(data, size);
@@ -109,7 +111,8 @@ class Block : public AbstractTraceEntry {
virtual void AddDump(char *buffer, size_t size) virtual void AddDump(char *buffer, size_t size)
{ {
uint32 length = snprintf(buffer, size, "%s: block %Ld (%p), sum %lu," 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++) { for (uint32 i = 0; length < size - 1 && i < sizeof(fBytes); i++) {
length += snprintf(buffer + length, size - length, "%02x", length += snprintf(buffer + length, size - length, "%02x",
fBytes[i]); fBytes[i]);
@@ -119,6 +122,8 @@ class Block : public AbstractTraceEntry {
private: private:
off_t fBlock; off_t fBlock;
const uint8 *fData; const uint8 *fData;
uint32 fStart;
uint32 fLength;
uint32 fSum; uint32 fSum;
char fLabel[12]; char fLabel[12];
uint8 fBytes[32]; uint8 fBytes[32];
@@ -215,7 +220,8 @@ AllocationBlock::SetTo(AllocationGroup &group, uint16 block)
status_t status_t
AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group, uint16 block) AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group,
uint16 block)
{ {
// 8 blocks per byte // 8 blocks per byte
fNumBits = fVolume->BlockSize() << 3; fNumBits = fVolume->BlockSize() << 3;
@@ -226,8 +232,8 @@ AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group,
#ifdef DEBUG #ifdef DEBUG
fWritable = true; fWritable = true;
#endif #endif
return CachedBlock::SetToWritable(transaction, group.Start() + block) != NULL return CachedBlock::SetToWritable(transaction, group.Start() + block)
? B_OK : B_ERROR; != NULL ? B_OK : B_ERROR;
} }
@@ -256,13 +262,15 @@ AllocationBlock::Allocate(uint16 start, uint16 numBlocks)
DIE(("Allocation::Allocate(): tried to allocate too many blocks")); DIE(("Allocation::Allocate(): tried to allocate too many blocks"));
} }
T(Block("b-alloc-in", fBlockNumber, fBlock, fVolume->BlockSize(),
start, numBlocks));
int32 block = start >> 5; int32 block = start >> 5;
while (numBlocks > 0) { while (numBlocks > 0) {
uint32 mask = 0; uint32 mask = 0;
for (int32 i = start % 32; i < 32 && numBlocks; i++, numBlocks--) for (int32 i = start % 32; i < 32 && numBlocks; i++, numBlocks--)
mask |= 1UL << (i % 32); mask |= 1UL << i;
#ifdef DEBUG #ifdef DEBUG
// check for already set blocks // check for already set blocks
if (HOST_ENDIAN_TO_BFS_INT32(mask) & ((uint32 *)fBlock)[block]) { 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); Block(block++) |= HOST_ENDIAN_TO_BFS_INT32(mask);
start = 0; 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 - // #pragma mark -
/** The allocation groups are created and initialized in /*! The allocation groups are created and initialized in
* BlockAllocator::Initialize() and BlockAllocator::InitializeAndClearBitmap() BlockAllocator::Initialize() and BlockAllocator::InitializeAndClearBitmap()
* respectively. respectively.
*/ */
AllocationGroup::AllocationGroup() AllocationGroup::AllocationGroup()
: :
fFirstFree(-1), fFirstFree(-1),
@@ -339,15 +348,12 @@ AllocationGroup::AddFreeRange(int32 start, int32 blocks)
} }
/** Allocates the specified run in the allocation group. /*! Allocates the specified run in the allocation group.
* Doesn't check if the run is valid or already allocated Doesn't check if the run is valid or already allocated partially, nor
* partially, nor does it maintain the free ranges hints does it maintain the free ranges hints or the volume's used blocks count.
* or the volume's used blocks count. It only does the low-level work of allocating some bits in the block bitmap.
* It only does the low-level work of allocating some bits Assumes that the block bitmap lock is hold.
* in the block bitmap. */
* Assumes that the block bitmap lock is hold.
*/
status_t status_t
AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length) 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. /*! Frees the specified run in the allocation group.
* Doesn't check if the run is valid or was not completely Doesn't check if the run is valid or was not completely allocated, nor
* allocated, nor does it maintain the free ranges hints does it maintain the free ranges hints or the volume's used blocks count.
* or the volume's used blocks count. It only does the low-level work of freeing some bits in the block bitmap.
* It only does the low-level work of freeing some bits Assumes that the block bitmap lock is hold.
* in the block bitmap. */
* Assumes that the block bitmap lock is hold.
*/
status_t status_t
AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length) AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length)
{ {
@@ -642,10 +645,11 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
AllocationBlock cached(fVolume); AllocationBlock cached(fVolume);
Locker lock(fLock); 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 // wanted maximum of blocks, the second scan will just look to
// satisfy the minimal requirement // satisfy the minimal requirement
uint16 numBlocks = maximum; uint16 numBlocks = maximum;
uint32 bitsPerFullBlock = fVolume->BlockSize() << 3;
for (int32 i = 0; i < fNumGroups * 2; i++, group++, start = 0) { for (int32 i = 0; i < fNumGroups * 2; i++, group++, start = 0) {
group = group % fNumGroups; group = group % fNumGroups;
@@ -654,7 +658,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
continue; continue;
if (i >= fNumGroups) { 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 // search for in the allocation groups a second time
if (maximum == minimum) if (maximum == minimum)
return B_DEVICE_FULL; return B_DEVICE_FULL;
@@ -662,8 +666,8 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
numBlocks = minimum; numBlocks = minimum;
} }
// The wanted maximum is smaller than the largest free block in the group // The wanted maximum is smaller than the largest free block in the
// or already smaller than the minimum // group or already smaller than the minimum
// ToDo: disabled because it's currently not maintained after the first allocation // ToDo: disabled because it's currently not maintained after the first allocation
//if (numBlocks > fGroups[group].fLargest) //if (numBlocks > fGroups[group].fLargest)
// continue; // continue;
@@ -671,7 +675,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
if (start < fGroups[group].fFirstFree) if (start < fGroups[group].fFirstFree)
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. // we iterate through it to find a place for the allocation.
// (one allocation can't exceed one allocation group) // (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) if (cached.SetTo(fGroups[group], block) < B_OK)
RETURN_ERROR(B_ERROR); 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 // find a block large enough to hold the allocation
for (uint32 bit = start % cached.NumBlockBits(); for (uint32 bit = start % bitsPerFullBlock;
bit < cached.NumBlockBits(); bit++) { bit < cached.NumBlockBits(); bit++) {
if (!cached.IsUsed(bit)) { if (!cached.IsUsed(bit)) {
if (range == 0) { if (range == 0) {
// start new range // start new range
rangeStart = block * cached.NumBlockBits() + bit; rangeStart = block * bitsPerFullBlock + bit;
} }
// have we found a range large enough to hold numBlocks? // have we found a range large enough to hold numBlocks?
@@ -733,7 +737,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
T(Allocate(run)); T(Allocate(run));
T(Block("alloc-out", block, cached.Block(), T(Block("alloc-out", block, cached.Block(),
fVolume->BlockSize())); fVolume->BlockSize(), group, rangeStart));
return B_OK; return B_OK;
} }
@@ -746,8 +750,8 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
status_t status_t
BlockAllocator::AllocateForInode(Transaction &transaction, const block_run *parent, BlockAllocator::AllocateForInode(Transaction &transaction,
mode_t type, block_run &run) const block_run *parent, mode_t type, block_run &run)
{ {
// apply some allocation policies here (AllocateBlocks() will break them // apply some allocation policies here (AllocateBlocks() will break them
// if necessary) - we will start with those described in Dominic Giampaolo's // 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; 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 <ptr-to-volume>\n", argv[0]);
return 0;
}
Volume *volume = (Volume *)parse_expression(argv[1]);
BlockAllocator &allocator = volume->Allocator();
allocator.Dump();
return 0;
}
#endif // BFS_DEBUGGER_COMMANDS
@@ -1,6 +1,5 @@
/* BlockAllocator - block bitmap handling and allocation policies /*
* * Copyright 2001-2008, Axel Dörfler, [email protected].
* Copyright 2001-2006, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
#ifndef BLOCK_ALLOCATOR_H #ifndef BLOCK_ALLOCATOR_H
@@ -46,6 +45,10 @@ class BlockAllocator {
size_t BitmapSize() const; size_t BitmapSize() const;
#ifdef BFS_DEBUGGER_COMMANDS
void Dump();
#endif
private: private:
bool _IsValidCheckControl(check_control *control); bool _IsValidCheckControl(check_control *control);
bool _CheckBitmapIsUsedAt(off_t block) const; bool _CheckBitmapIsUsedAt(off_t block) const;
@@ -63,4 +66,8 @@ class BlockAllocator {
check_cookie *fCheckCookie; check_cookie *fCheckCookie;
}; };
#ifdef BFS_DEBUGGER_COMMANDS
int dump_block_allocator(int argc, char **argv);
#endif
#endif /* BLOCK_ALLOCATOR_H */ #endif /* BLOCK_ALLOCATOR_H */
@@ -7,6 +7,7 @@
#include "Debug.h" #include "Debug.h"
#include "BlockAllocator.h"
#include "BPlusTree.h" #include "BPlusTree.h"
#include "Inode.h" #include "Inode.h"
@@ -247,7 +248,7 @@ dump_bplustree_node(const bplustree_node *node, const bplustree_header *header,
static int static int
dump_inode(int argc, char **argv) dump_inode(int argc, char **argv)
{ {
if (argc != 2) { if (argc != 2 || !strcmp(argv[1], "--help")) {
kprintf("usage: bfsinode <ptr-to-inode>\n"); kprintf("usage: bfsinode <ptr-to-inode>\n");
return 0; return 0;
} }
@@ -262,7 +263,7 @@ dump_inode(int argc, char **argv)
static int static int
dump_volume(int argc, char **argv) dump_volume(int argc, char **argv)
{ {
if (argc != 2) { if (argc != 2 || !strcmp(argv[1], "--help")) {
kprintf("usage: bfs <ptr-to-volume>\n"); kprintf("usage: bfs <ptr-to-volume>\n");
return 0; return 0;
} }
@@ -281,7 +282,8 @@ dump_volume(int argc, char **argv)
void void
remove_debugger_commands() 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); remove_debugger_command("bfs", dump_volume);
} }
@@ -289,7 +291,9 @@ remove_debugger_commands()
void void
add_debugger_commands() 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"); add_debugger_command("bfs", dump_volume, "dump a BFS volume");
} }
+2 -1
View File
@@ -74,7 +74,8 @@
#define FUNCTION_START(x) ; #define FUNCTION_START(x) ;
#define D(x) ; #define D(x) ;
#ifndef ASSERT #ifndef ASSERT
# define ASSERT(x) ; # define ASSERT(x) { if (!(x)) DEBUGGER(("bfs: assert failed: " #x "\n")); }
// # define ASSERT(x) ;
#endif #endif
#endif #endif