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:
@@ -98,7 +98,7 @@ AllocationBlock::SetTo(AllocationGroup &group, uint16 block)
|
|||||||
// 8 blocks per byte
|
// 8 blocks per byte
|
||||||
fNumBits = fVolume->BlockSize() << 3;
|
fNumBits = fVolume->BlockSize() << 3;
|
||||||
// the last group may have less bits in the last block
|
// 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;
|
fNumBits = group.fNumBits % fNumBits;
|
||||||
|
|
||||||
return CachedBlock::SetTo(group.fStart + block) != NULL ? B_OK : B_ERROR;
|
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;
|
group = data->direct[last].allocation_group;
|
||||||
start = data->direct[last].start + data->direct[last].length;
|
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
|
// directory data will go in the same allocation group as the inode is in
|
||||||
// but after the inode data
|
// but after the inode data
|
||||||
start = inode->BlockRun().start;
|
start = inode->BlockRun().start;
|
||||||
@@ -749,7 +749,7 @@ BlockAllocator::CheckNextNode(check_control *control)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inode->IsDirectory()) {
|
if (!inode->IsContainer()) {
|
||||||
FATAL(("check: inode at %Ld should have been a directory\n", fVolume->ToBlock(cookie->current)));
|
FATAL(("check: inode at %Ld should have been a directory\n", fVolume->ToBlock(cookie->current)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -849,7 +849,7 @@ BlockAllocator::CheckNextNode(check_control *control)
|
|||||||
Transaction transaction(fVolume, cookie->parent->BlockNumber());
|
Transaction transaction(fVolume, cookie->parent->BlockNumber());
|
||||||
|
|
||||||
inode->Node()->flags |= INODE_DONT_FREE_SPACE;
|
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)
|
if (status == B_OK)
|
||||||
transaction.Done();
|
transaction.Done();
|
||||||
} else
|
} else
|
||||||
@@ -865,7 +865,7 @@ BlockAllocator::CheckNextNode(check_control *control)
|
|||||||
cookie->stack.Push(inode->Attributes());
|
cookie->stack.Push(inode->Attributes());
|
||||||
|
|
||||||
// push the directory on the stack so that it will be scanned later
|
// 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());
|
cookie->stack.Push(inode->BlockRun());
|
||||||
else {
|
else {
|
||||||
// check it now
|
// check it now
|
||||||
@@ -922,7 +922,7 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
|||||||
uint32 block = run.start / bitsPerBlock;
|
uint32 block = run.start / bitsPerBlock;
|
||||||
uint32 pos = run.start % bitsPerBlock;
|
uint32 pos = run.start % bitsPerBlock;
|
||||||
int32 length = 0;
|
int32 length = 0;
|
||||||
int64 firstMissing = -1, firstSet = -1;
|
off_t firstMissing = -1, firstSet = -1;
|
||||||
off_t firstGroupBlock = (off_t)run.allocation_group << fVolume->AllocationGroupShift();
|
off_t firstGroupBlock = (off_t)run.allocation_group << fVolume->AllocationGroupShift();
|
||||||
|
|
||||||
AllocationBlock cached(fVolume);
|
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)
|
if (cached.SetTo(fGroups[run.allocation_group], block) < B_OK)
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
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()) {
|
while (length < run.length && pos < cached.NumBlockBits()) {
|
||||||
if (!cached.IsUsed(pos)) {
|
if (!cached.IsUsed(pos)) {
|
||||||
if (control == NULL) {
|
if (control == NULL) {
|
||||||
@@ -938,12 +943,12 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
|||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
}
|
}
|
||||||
if (firstMissing == -1) {
|
if (firstMissing == -1) {
|
||||||
firstMissing = pos + block * bitsPerBlock;
|
firstMissing = firstGroupBlock + pos + block * bitsPerBlock;
|
||||||
control->errors |= BFS_MISSING_BLOCKS;
|
control->errors |= BFS_MISSING_BLOCKS;
|
||||||
}
|
}
|
||||||
control->stats.missing++;
|
control->stats.missing++;
|
||||||
} else if (firstMissing != -1) {
|
} 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;
|
firstMissing = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -953,13 +958,13 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
|||||||
uint32 offset = pos + block * bitsPerBlock;
|
uint32 offset = pos + block * bitsPerBlock;
|
||||||
if (CheckBitmapIsUsedAt(firstGroupBlock + offset)) {
|
if (CheckBitmapIsUsedAt(firstGroupBlock + offset)) {
|
||||||
if (firstSet == -1) {
|
if (firstSet == -1) {
|
||||||
firstSet = offset;
|
firstSet = firstGroupBlock + offset;
|
||||||
control->errors |= BFS_BLOCKS_ALREADY_SET;
|
control->errors |= BFS_BLOCKS_ALREADY_SET;
|
||||||
}
|
}
|
||||||
control->stats.already_set++;
|
control->stats.already_set++;
|
||||||
} else {
|
} else {
|
||||||
if (firstSet != -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, 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;
|
firstSet = -1;
|
||||||
}
|
}
|
||||||
SetCheckBitmapAt(firstGroupBlock + offset);
|
SetCheckBitmapAt(firstGroupBlock + offset);
|
||||||
@@ -968,12 +973,14 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
|||||||
length++;
|
length++;
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (block + 1 >= fBlocksPerGroup || length >= run.length) {
|
||||||
if (firstMissing != -1)
|
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));
|
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)
|
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));
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -1044,8 +1051,47 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
// ToDo: add test for double indirect range!
|
int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
|
||||||
FATAL(("*** test for the double indirect range is not yet done ***\n"));
|
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;
|
return B_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user