BlockAllocator::CheckInode() now has support for the double indirect region

of the stream (so the "chkbfs" functionality is complete now).
Fixed wrong block number report in BlockAllocator::CheckBlockRun(), blocks are
now printed out in absolute numbers (not allocation_group relative anymore).
Use Inode::IsContainer() where necessary instead of Inode::IsDirectory().
Fixed a big and nasty bug in AllocationBlock::SetTo(): the number of bits in
a block could be calculated wrong for a partial allocation group which need
more than one block in the bitmap - hopefully, that was the last remaining
big bug in the block allocator.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2032 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2002-11-20 01:59:14 +00:00
parent 68ca164dc3
commit 95f8931641

View File

@ -98,7 +98,7 @@ AllocationBlock::SetTo(AllocationGroup &group, uint16 block)
// 8 blocks per byte
fNumBits = fVolume->BlockSize() << 3;
// the last group may have less bits in the last block
if ((group.fNumBits % fNumBits) != 0)
if (block * fNumBits > group.fNumBits)
fNumBits = group.fNumBits % fNumBits;
return CachedBlock::SetTo(group.fStart + block) != NULL ? B_OK : B_ERROR;
@ -574,7 +574,7 @@ BlockAllocator::Allocate(Transaction *transaction, const Inode *inode, off_t num
group = data->direct[last].allocation_group;
start = data->direct[last].start + data->direct[last].length;
}
} else if (inode->IsDirectory()) {
} else if (inode->IsContainer()) {
// directory data will go in the same allocation group as the inode is in
// but after the inode data
start = inode->BlockRun().start;
@ -749,7 +749,7 @@ BlockAllocator::CheckNextNode(check_control *control)
continue;
}
if (!inode->IsDirectory()) {
if (!inode->IsContainer()) {
FATAL(("check: inode at %Ld should have been a directory\n", fVolume->ToBlock(cookie->current)));
continue;
}
@ -849,7 +849,7 @@ BlockAllocator::CheckNextNode(check_control *control)
Transaction transaction(fVolume, cookie->parent->BlockNumber());
inode->Node()->flags |= INODE_DONT_FREE_SPACE;
status = cookie->parent->Remove(&transaction, name, NULL, inode->IsDirectory());
status = cookie->parent->Remove(&transaction, name, NULL, inode->IsContainer());
if (status == B_OK)
transaction.Done();
} else
@ -865,7 +865,7 @@ BlockAllocator::CheckNextNode(check_control *control)
cookie->stack.Push(inode->Attributes());
// push the directory on the stack so that it will be scanned later
if (inode->IsDirectory() && !inode->IsIndex())
if (inode->IsContainer() && !inode->IsIndex())
cookie->stack.Push(inode->BlockRun());
else {
// check it now
@ -922,7 +922,7 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
uint32 block = run.start / bitsPerBlock;
uint32 pos = run.start % bitsPerBlock;
int32 length = 0;
int64 firstMissing = -1, firstSet = -1;
off_t firstMissing = -1, firstSet = -1;
off_t firstGroupBlock = (off_t)run.allocation_group << fVolume->AllocationGroupShift();
AllocationBlock cached(fVolume);
@ -931,6 +931,11 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
if (cached.SetTo(fGroups[run.allocation_group], block) < B_OK)
RETURN_ERROR(B_IO_ERROR);
if (pos >= cached.NumBlockBits()) {
// something very strange has happened...
RETURN_ERROR(B_ERROR);
}
while (length < run.length && pos < cached.NumBlockBits()) {
if (!cached.IsUsed(pos)) {
if (control == NULL) {
@ -938,12 +943,12 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
return B_BAD_DATA;
}
if (firstMissing == -1) {
firstMissing = pos + block * bitsPerBlock;
firstMissing = firstGroupBlock + pos + block * bitsPerBlock;
control->errors |= BFS_MISSING_BLOCKS;
}
control->stats.missing++;
} else if (firstMissing != -1) {
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %ld are not allocated!\n", type, run.allocation_group, run.start, run.length, firstMissing, pos + block * bitsPerBlock - 1));
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not allocated!\n", type, run.allocation_group, run.start, run.length, firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1));
firstMissing = -1;
}
@ -953,13 +958,13 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
uint32 offset = pos + block * bitsPerBlock;
if (CheckBitmapIsUsedAt(firstGroupBlock + offset)) {
if (firstSet == -1) {
firstSet = offset;
firstSet = firstGroupBlock + offset;
control->errors |= BFS_BLOCKS_ALREADY_SET;
}
control->stats.already_set++;
} else {
if (firstSet != -1) {
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %ld are already set!\n", type, run.allocation_group, run.start, run.length, firstSet, offset - 1));
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are already set!\n", type, run.allocation_group, run.start, run.length, firstSet, firstGroupBlock + offset - 1));
firstSet = -1;
}
SetCheckBitmapAt(firstGroupBlock + offset);
@ -968,12 +973,14 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
length++;
pos++;
}
}
if (firstMissing != -1)
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %ld are not allocated!\n", type, run.allocation_group, run.start, run.length, firstMissing, pos + (block - 1) * bitsPerBlock - 1));
if (firstSet != -1)
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %ld are already set!\n", type, run.allocation_group, run.start, run.length, firstSet, pos + (block - 1) * bitsPerBlock - 1));
if (block + 1 >= fBlocksPerGroup || length >= run.length) {
if (firstMissing != -1)
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not allocated!\n", type, run.allocation_group, run.start, run.length, firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1));
if (firstSet != -1)
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are already set!\n", type, run.allocation_group, run.start, run.length, firstSet, firstGroupBlock + pos + block * bitsPerBlock - 1));
}
}
return B_OK;
}
@ -1044,8 +1051,47 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
if (status < B_OK)
return status;
// ToDo: add test for double indirect range!
FATAL(("*** test for the double indirect range is not yet done ***\n"));
int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT;
CachedBlock cachedDirect(fVolume);
int32 maxIndirectIndex = (data->double_indirect.length << fVolume->BlockShift()) / sizeof(block_run);
for (int32 indirectIndex = 0; indirectIndex < maxIndirectIndex; indirectIndex++) {
// get the indirect array block
block_run *array = (block_run *)cached.SetTo(fVolume->ToBlock(data->double_indirect)
+ indirectIndex / runsPerBlock);
if (array == NULL)
return B_IO_ERROR;
block_run indirect = array[indirectIndex % runsPerBlock];
// are we finished yet?
if (indirect.IsZero())
return B_OK;
status = CheckBlockRun(indirect, "double indirect->runs", control);
if (status < B_OK)
return status;
int32 maxIndex = (indirect.length << fVolume->BlockShift()) / sizeof(block_run);
for (int32 index = 0; index < maxIndex; ) {
block_run *runs = (block_run *)cachedDirect.SetTo(fVolume->ToBlock(indirect)
+ index / runsPerBlock);
if (runs == NULL)
return B_IO_ERROR;
do {
// are we finished yet?
if (runs[index % runsPerBlock].IsZero())
return B_OK;
status = CheckBlockRun(runs[index % runsPerBlock], "double indirect->runs->run", control);
if (status < B_OK)
return status;
} while ((++index % runsPerArray) != 0);
}
}
}
return B_OK;