* Made super block log handling endian-safe.

* Made all debugging functions endian-safe.
* Added tracing for log entries.
* Added new KDL command "bfs_journal" to dump all pending log entries.
* When BFS_DEBUGGER_COMMANDS is defined, the LogEntry class will also track
  the transaction ID it belonged to.
* The "bfs" KDL command now sets some useful debugger variables.
* The "bfs_allocator" KDL command now accepts the group index as 3rd argument.
* Renamed Journal::_TransactionListener() to _TransactionIdle(), as that's
  all it is for.
* Removed TODO comment in Volume::WriteSuperBlock(), as it's actually not true.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24852 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-04-07 10:32:03 +00:00
parent c9d15f8cdb
commit 797a92d84d
6 changed files with 221 additions and 67 deletions

View File

@ -1412,14 +1412,16 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
#ifdef BFS_DEBUGGER_COMMANDS
void
BlockAllocator::Dump()
BlockAllocator::Dump(int32 index)
{
kprintf("allocation groups: %ld\n", fNumGroups);
kprintf("blocks per group: %ld\n", fBlocksPerGroup);
for (int32 i = 0; i < fNumGroups; i++) {
if (index != -1 && i != index)
continue;
AllocationGroup& group = fGroups[i];
kprintf("[%3ld] num bits: %lu\n", i, group.NumBits());
@ -1436,18 +1438,23 @@ BlockAllocator::Dump()
int
dump_block_allocator(int argc, char **argv)
{
int32 group = -1;
if (argc == 3) {
group = parse_expression(argv[2]);
argc--;
}
if (argc != 2 || !strcmp(argv[1], "--help")) {
kprintf("usage: %s <ptr-to-volume>\n", argv[0]);
kprintf("usage: %s <ptr-to-volume> [group]\n", argv[0]);
return 0;
}
Volume *volume = (Volume *)parse_expression(argv[1]);
BlockAllocator &allocator = volume->Allocator();
allocator.Dump();
allocator.Dump(group);
return 0;
}
#endif // BFS_DEBUGGER_COMMANDS

View File

@ -46,7 +46,7 @@ class BlockAllocator {
size_t BitmapSize() const;
#ifdef BFS_DEBUGGER_COMMANDS
void Dump();
void Dump(int32 index);
#endif
private:

View File

@ -10,6 +10,7 @@
#include "BlockAllocator.h"
#include "BPlusTree.h"
#include "Inode.h"
#include "Journal.h"
#define Print __out
@ -36,7 +37,8 @@ get_tupel(uint32 id)
void
dump_block_run(const char *prefix, const block_run &run)
{
Print("%s(%d, %d, %d)\n", prefix, (int)run.allocation_group, run.start, run.length);
Print("%s(%d, %d, %d)\n", prefix, (int)run.allocation_group, run.start,
run.length);
}
@ -45,22 +47,33 @@ dump_super_block(const disk_super_block *superBlock)
{
Print("disk_super_block:\n");
Print(" name = %s\n", superBlock->name);
Print(" magic1 = %#08x (%s) %s\n", (int)superBlock->magic1, get_tupel(superBlock->magic1), (superBlock->magic1 == SUPER_BLOCK_MAGIC1 ? "valid" : "INVALID"));
Print(" fs_byte_order = %#08x (%s)\n", (int)superBlock->fs_byte_order, get_tupel(superBlock->fs_byte_order));
Print(" block_size = %u\n", (unsigned)superBlock->block_size);
Print(" block_shift = %u\n", (unsigned)superBlock->block_shift);
Print(" num_blocks = %Lu\n", superBlock->num_blocks);
Print(" used_blocks = %Lu\n", superBlock->used_blocks);
Print(" inode_size = %u\n", (unsigned)superBlock->inode_size);
Print(" magic2 = %#08x (%s) %s\n", (int)superBlock->magic2, get_tupel(superBlock->magic2), (superBlock->magic2 == (int)SUPER_BLOCK_MAGIC2 ? "valid" : "INVALID"));
Print(" blocks_per_ag = %u\n", (unsigned)superBlock->blocks_per_ag);
Print(" ag_shift = %u (%ld bytes)\n", (unsigned)superBlock->ag_shift, 1L << superBlock->ag_shift);
Print(" num_ags = %u\n", (unsigned)superBlock->num_ags);
Print(" flags = %#08x (%s)\n", (int)superBlock->flags, get_tupel(superBlock->flags));
Print(" magic1 = %#08x (%s) %s\n", (int)superBlock->Magic1(),
get_tupel(superBlock->magic1),
(superBlock->magic1 == SUPER_BLOCK_MAGIC1 ? "valid" : "INVALID"));
Print(" fs_byte_order = %#08x (%s)\n", (int)superBlock->fs_byte_order,
get_tupel(superBlock->fs_byte_order));
Print(" block_size = %u\n", (unsigned)superBlock->BlockSize());
Print(" block_shift = %u\n", (unsigned)superBlock->BlockShift());
Print(" num_blocks = %Lu\n", superBlock->NumBlocks());
Print(" used_blocks = %Lu\n", superBlock->UsedBlocks());
Print(" inode_size = %u\n", (unsigned)superBlock->InodeSize());
Print(" magic2 = %#08x (%s) %s\n", (int)superBlock->Magic2(),
get_tupel(superBlock->magic2),
(superBlock->magic2 == (int)SUPER_BLOCK_MAGIC2 ? "valid" : "INVALID"));
Print(" blocks_per_ag = %u\n",
(unsigned)superBlock->BlocksPerAllocationGroup());
Print(" ag_shift = %u (%ld bytes)\n",
(unsigned)superBlock->AllocationGroupShift(),
1L << superBlock->AllocationGroupShift());
Print(" num_ags = %u\n", (unsigned)superBlock->AllocationGroups());
Print(" flags = %#08x (%s)\n", (int)superBlock->Flags(),
get_tupel(superBlock->Flags()));
dump_block_run(" log_blocks = ", superBlock->log_blocks);
Print(" log_start = %Lu\n", superBlock->log_start);
Print(" log_end = %Lu\n", superBlock->log_end);
Print(" magic3 = %#08x (%s) %s\n", (int)superBlock->magic3, get_tupel(superBlock->magic3), (superBlock->magic3 == SUPER_BLOCK_MAGIC3 ? "valid" : "INVALID"));
Print(" log_start = %Lu\n", superBlock->LogStart());
Print(" log_end = %Lu\n", superBlock->LogEnd());
Print(" magic3 = %#08x (%s) %s\n", (int)superBlock->Magic3(),
get_tupel(superBlock->magic3),
(superBlock->magic3 == SUPER_BLOCK_MAGIC3 ? "valid" : "INVALID"));
dump_block_run(" root_dir = ", superBlock->root_dir);
dump_block_run(" indices = ", superBlock->indices);
}
@ -76,18 +89,21 @@ dump_data_stream(const data_stream *stream)
dump_block_run("", stream->direct[i]);
}
}
Print(" max_direct_range = %Lu\n", stream->max_direct_range);
Print(" max_direct_range = %Lu\n", stream->MaxDirectRange());
if (!stream->indirect.IsZero())
dump_block_run(" indirect = ", stream->indirect);
Print(" max_indirect_range = %Lu\n", stream->max_indirect_range);
Print(" max_indirect_range = %Lu\n", stream->MaxIndirectRange());
if (!stream->double_indirect.IsZero())
dump_block_run(" double_indirect = ", stream->double_indirect);
if (!stream->double_indirect.IsZero()) {
dump_block_run(" double_indirect = ",
stream->double_indirect);
}
Print(" max_double_indirect_range = %Lu\n", stream->max_double_indirect_range);
Print(" size = %Lu\n", stream->size);
Print(" max_double_indirect_range = %Lu\n",
stream->MaxDoubleIndirectRange());
Print(" size = %Lu\n", stream->Size());
}
@ -95,25 +111,26 @@ void
dump_inode(const bfs_inode *inode)
{
Print("inode:\n");
Print(" magic1 = %08x (%s) %s\n", (int)inode->magic1,
get_tupel(inode->magic1), (inode->magic1 == INODE_MAGIC1 ? "valid" : "INVALID"));
Print(" magic1 = %08x (%s) %s\n", (int)inode->Magic1(),
get_tupel(inode->magic1),
(inode->magic1 == INODE_MAGIC1 ? "valid" : "INVALID"));
dump_block_run( " inode_num = ", inode->inode_num);
Print(" uid = %u\n", (unsigned)inode->uid);
Print(" gid = %u\n", (unsigned)inode->gid);
Print(" mode = %08x\n", (int)inode->mode);
Print(" flags = %08x\n", (int)inode->flags);
Print(" create_time = %Ld (%Ld)\n", inode->create_time,
inode->create_time >> INODE_TIME_SHIFT);
Print(" last_modified_time = %Ld (%Ld)\n", inode->last_modified_time,
inode->last_modified_time >> INODE_TIME_SHIFT);
Print(" uid = %u\n", (unsigned)inode->UserID());
Print(" gid = %u\n", (unsigned)inode->GroupID());
Print(" mode = %08x\n", (int)inode->Mode());
Print(" flags = %08x\n", (int)inode->Flags());
Print(" create_time = %Ld (%Ld)\n", inode->CreateTime(),
inode->CreateTime() >> INODE_TIME_SHIFT);
Print(" last_modified_time = %Ld (%Ld)\n", inode->LastModifiedTime(),
inode->LastModifiedTime() >> INODE_TIME_SHIFT);
dump_block_run( " parent = ", inode->parent);
dump_block_run( " attributes = ", inode->attributes);
Print(" type = %u\n", (unsigned)inode->type);
Print(" inode_size = %u\n", (unsigned)inode->inode_size);
Print(" type = %u\n", (unsigned)inode->Type());
Print(" inode_size = %u\n", (unsigned)inode->InodeSize());
Print(" etc = %#08x\n", (int)inode->etc);
Print(" short_symlink = %s\n",
S_ISLNK(inode->mode) && (inode->flags & INODE_LONG_SYMLINK) == 0 ?
inode->short_symlink : "-");
S_ISLNK(inode->Mode()) && (inode->Flags() & INODE_LONG_SYMLINK) == 0
? inode->short_symlink : "-");
dump_data_stream(&(inode->data));
Print(" --\n pad[0] = %08x\n", (int)inode->pad[0]);
Print(" pad[1] = %08x\n", (int)inode->pad[1]);
@ -126,14 +143,16 @@ void
dump_bplustree_header(const bplustree_header *header)
{
Print("bplustree_header:\n");
Print(" magic = %#08x (%s) %s\n", (int)header->magic,
get_tupel(header->magic), (header->magic == BPLUSTREE_MAGIC ? "valid" : "INVALID"));
Print(" node_size = %u\n", (unsigned)header->node_size);
Print(" max_number_of_levels = %u\n", (unsigned)header->max_number_of_levels);
Print(" data_type = %u\n", (unsigned)header->data_type);
Print(" root_node_pointer = %Ld\n", header->root_node_pointer);
Print(" free_node_pointer = %Ld\n", header->free_node_pointer);
Print(" maximum_size = %Lu\n", header->maximum_size);
Print(" magic = %#08x (%s) %s\n", (int)header->Magic(),
get_tupel(header->magic),
(header->magic == BPLUSTREE_MAGIC ? "valid" : "INVALID"));
Print(" node_size = %u\n", (unsigned)header->NodeSize());
Print(" max_number_of_levels = %u\n",
(unsigned)header->MaxNumberOfLevels());
Print(" data_type = %u\n", (unsigned)header->DataType());
Print(" root_node_pointer = %Ld\n", header->RootNode());
Print(" free_node_pointer = %Ld\n", header->FreeNode());
Print(" maximum_size = %Lu\n", header->MaximumSize());
}
@ -279,11 +298,16 @@ dump_volume(int argc, char **argv)
Volume *volume = (Volume *)parse_expression(argv[1]);
kprintf("block cache: %p\n", volume->BlockCache());
kprintf("root node: %p\n", volume->RootNode());
kprintf("indices node: %p\n", volume->IndicesNode());
dump_super_block(&volume->SuperBlock());
set_debug_variable("_cache", (addr_t)volume->BlockCache());
set_debug_variable("_root", (addr_t)volume->RootNode());
set_debug_variable("_indices", (addr_t)volume->IndicesNode());
return 0;
}
@ -332,6 +356,7 @@ remove_debugger_commands()
{
remove_debugger_command("bfs_inode", dump_inode);
remove_debugger_command("bfs_allocator", dump_block_allocator);
remove_debugger_command("bfs_journal", dump_journal);
remove_debugger_command("bfs_btree_header", dump_bplustree_header);
remove_debugger_command("bfs_btree_node", dump_bplustree_node);
remove_debugger_command("bfs", dump_volume);
@ -344,6 +369,8 @@ add_debugger_commands()
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_journal", dump_journal,
"dump the journal log entries");
add_debugger_command("bfs_btree_header", dump_bplustree_header,
"dump a BFS B+tree header");
add_debugger_command("bfs_btree_node", dump_bplustree_node,

View File

@ -65,15 +65,75 @@ class LogEntry : public DoublyLinkedListLinkImpl<LogEntry> {
uint32 Start() const { return fStart; }
uint32 Length() const { return fLength; }
#ifdef BFS_DEBUGGER_COMMANDS
void SetTransactionID(int32 id) { fTransactionID = id; }
int32 TransactionID() const { return fTransactionID; }
#endif
Journal *GetJournal() { return fJournal; }
private:
Journal *fJournal;
uint32 fStart;
uint32 fLength;
#ifdef BFS_DEBUGGER_COMMANDS
int32 fTransactionID;
#endif
};
#if defined(BFS_TRACING) && !defined(BFS_SHELL) && !defined(_BOOT_MODE)
namespace BFSJournalTracing {
class LogEntry : public AbstractTraceEntry {
public:
LogEntry(::LogEntry* entry, off_t logPosition, bool started)
:
fEntry(entry),
#ifdef BFS_DEBUGGER_COMMANDS
fTransactionID(entry->TransactionID()),
#endif
fStart(entry->Start()),
fLength(entry->Length()),
fLogPosition(logPosition),
fStarted(started)
{
Initialized();
}
virtual void AddDump(TraceOutput& out)
{
#ifdef BFS_DEBUGGER_COMMANDS
out.Print("bfs:j:%s entry %p id %ld, start %lu, length %lu, log %s "
"%lu\n", fStarted ? "Started" : "Written", fEntry,
fTransactionID, fStart, fLength,
fStarted ? "end" : "start", fLogPosition);
#else
out.Print("bfs:j:%s entry %p start %lu, length %lu, log %s %lu\n",
fStarted ? "Started" : "Written", fEntry, fStart, fLength,
fStarted ? "end" : "start", fLogPosition);
#endif
}
private:
::LogEntry* fEntry;
#ifdef BFS_DEBUGGER_COMMANDS
int32 fTransactionID;
#endif
uint32 fStart;
uint32 fLength;
uint32 fLogPosition;
bool fStarted;
};
} // namespace BFSJournalTracing
# define T(x) new(std::nothrow) BFSJournalTracing::x;
#else
# define T(x) ;
#endif
// #pragma mark -
@ -516,8 +576,9 @@ Journal::ReplayLog()
}
PRINT(("replaying worked fine!\n"));
fVolume->SuperBlock().log_start = fVolume->LogEnd();
fVolume->LogStart() = fVolume->LogEnd();
fVolume->SuperBlock().log_start = HOST_ENDIAN_TO_BFS_INT64(
fVolume->LogEnd());
fVolume->LogStart() = HOST_ENDIAN_TO_BFS_INT64(fVolume->LogEnd());
fVolume->SuperBlock().flags = SUPER_BLOCK_DISK_CLEAN;
return fVolume->WriteSuperBlock();
@ -543,20 +604,24 @@ Journal::_TransactionWritten(int32 transactionID, int32 event, void *_logEntry)
bool update = false;
// Set log_start pointer if possible...
// TODO: this is not endian safe!
journal->fEntriesLock.Lock();
if (logEntry == journal->fEntries.First()) {
LogEntry *next = journal->fEntries.GetNext(logEntry);
if (next != NULL)
superBlock.log_start = next->Start() % journal->fLogSize;
else
superBlock.log_start = journal->fVolume->LogEnd();
if (next != NULL) {
superBlock.log_start = HOST_ENDIAN_TO_BFS_INT64(next->Start()
% journal->fLogSize);
} else {
superBlock.log_start = HOST_ENDIAN_TO_BFS_INT64(
journal->fVolume->LogEnd());
}
update = true;
}
T(LogEntry(logEntry, superBlock.LogStart(), false));
journal->fUsed -= logEntry->Length();
journal->fEntries.Remove(logEntry);
journal->fEntriesLock.Unlock();
@ -575,14 +640,14 @@ Journal::_TransactionWritten(int32 transactionID, int32 event, void *_logEntry)
strerror(status)));
}
journal->fVolume->LogStart() = superBlock.log_start;
journal->fVolume->LogStart() = superBlock.LogStart();
}
}
/*! Listens to TRANSACTION_IDLE events, and flushes the log when that happens */
/*static*/ void
Journal::_TransactionListener(int32 transactionID, int32 event, void *_journal)
Journal::_TransactionIdle(int32 transactionID, int32 event, void *_journal)
{
// The current transaction seems to be idle - flush it
@ -747,14 +812,20 @@ Journal::_WriteTransactionToLog()
return B_NO_MEMORY;
}
#ifdef BFS_DEBUGGER_COMMANDS
logEntry->SetTransactionID(fTransactionID);
#endif
// Update the log end pointer in the super block
fVolume->SuperBlock().flags = SUPER_BLOCK_DISK_DIRTY;
fVolume->SuperBlock().log_end = logPosition;
fVolume->LogEnd() = logPosition;
fVolume->SuperBlock().log_end = HOST_ENDIAN_TO_BFS_INT64(logPosition);
status = fVolume->WriteSuperBlock();
fVolume->LogEnd() = logPosition;
T(LogEntry(logEntry, fVolume->LogEnd(), true));
// We need to flush the drives own cache here to ensure
// disk consistency.
// If that call fails, we can't do anything about it anyway
@ -858,7 +929,7 @@ Journal::Lock(Transaction *owner)
}
cache_add_transaction_listener(fVolume->BlockCache(), fTransactionID,
TRANSACTION_IDLE, _TransactionListener, this);
TRANSACTION_IDLE, _TransactionIdle, this);
return B_OK;
}
@ -924,6 +995,48 @@ Journal::_TransactionDone(bool success)
}
// #pragma mark - debugger commands
#ifdef BFS_DEBUGGER_COMMANDS
void
Journal::Dump()
{
kprintf("log start: %ld\n", fVolume->LogStart());
kprintf("log end: %ld\n", fVolume->LogEnd());
kprintf("entries:\n");
kprintf(" address id start length\n");
LogEntryList::Iterator iterator = fEntries.GetIterator();
while (iterator.HasNext()) {
LogEntry *entry = iterator.Next();
kprintf(" %p %6ld %6lu %6lu\n", entry, entry->TransactionID(),
entry->Start(), entry->Length());
}
}
int
dump_journal(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]);
Journal *journal = volume->GetJournal(0);
journal->Dump();
return 0;
}
#endif // BFS_DEBUGGER_COMMANDS
// #pragma mark - Transaction

View File

@ -50,6 +50,10 @@ class Journal {
inline uint32 FreeLogBlocks() const;
#ifdef BFS_DEBUGGER_COMMANDS
void Dump();
#endif
private:
bool _HasSubTransaction() { return fHasSubtransaction; }
status_t _FlushLog(bool canWait, bool flushBlocks);
@ -61,7 +65,7 @@ class Journal {
static void _TransactionWritten(int32 transactionID, int32 event,
void *_logEntry);
static void _TransactionListener(int32 transactionID, int32 event,
static void _TransactionIdle(int32 transactionID, int32 event,
void *_journal);
Volume *fVolume;
@ -176,4 +180,8 @@ class Transaction {
Journal *fJournal;
};
#ifdef BFS_DEBUGGER_COMMANDS
int dump_journal(int argc, char **argv);
#endif
#endif /* JOURNAL_H */

View File

@ -509,7 +509,6 @@ Volume::AllocateForInode(Transaction &transaction, const Inode *parent,
status_t
Volume::WriteSuperBlock()
{
// TODO: this assumes a block size of 512 bytes of the underlying device
if (write_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block))
!= sizeof(disk_super_block))
return B_IO_ERROR;