* checkfs is now working again; I couldn't test my earlier changes because I had

no time left, but I didn't want to lose them either.
* This fixes bug #5536, sorry for the inconvenience.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35770 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-03-06 13:47:50 +00:00
parent a76f629efa
commit 5edde94cab
4 changed files with 97 additions and 67 deletions
+4 -1
View File
@@ -267,7 +267,10 @@ BFSPartitionHandle::Repair(bool checkOnly)
}
// stop checking
ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result));
if (ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result)) != 0) {
close(fd);
return errno;
}
close(fd);
@@ -1,10 +1,10 @@
/*
* Copyright 2001-2009, Axel Dörfler, [email protected].
* Copyright 2001-2010, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
//! block bitmap handling and allocation policies
//! Block bitmap handling and allocation policies
#include "BlockAllocator.h"
@@ -174,6 +174,7 @@ struct check_cookie {
mode_t parent_mode;
Stack<block_run> stack;
TreeIterator* iterator;
check_control control;
};
@@ -1222,6 +1223,8 @@ BlockAllocator::StartChecking(const check_control* control)
return B_NO_MEMORY;
}
memcpy(&fCheckCookie->control, control, sizeof(check_control));
// initialize bitmap
memset(fCheckBitmap, 0, size);
for (int32 block = fVolume->Log().Start() + fVolume->Log().Length();
@@ -1250,7 +1253,7 @@ status_t
BlockAllocator::StopChecking(check_control* control)
{
if (fCheckCookie == NULL)
return B_ERROR;
return B_NO_INIT;
if (fCheckCookie->iterator != NULL) {
delete fCheckCookie->iterator;
@@ -1262,12 +1265,12 @@ BlockAllocator::StopChecking(check_control* control)
if (fVolume->IsReadOnly()) {
// We can't fix errors on this volume
control->flags &= ~BFS_FIX_BITMAP_ERRORS;
fCheckCookie->control.flags &= ~BFS_FIX_BITMAP_ERRORS;
}
// if CheckNextNode() could completely work through, we can
// fix any damages of the bitmap
if (control != NULL && control->status == B_ENTRY_NOT_FOUND) {
if (fCheckCookie->control.status == B_ENTRY_NOT_FOUND) {
// calculate the number of used blocks in the check bitmap
size_t size = BitmapSize();
off_t usedBlocks = 0LL;
@@ -1282,14 +1285,15 @@ BlockAllocator::StopChecking(check_control* control)
}
}
control->stats.freed = fVolume->UsedBlocks() - usedBlocks
+ control->stats.missing;
if (control->stats.freed < 0)
control->stats.freed = 0;
fCheckCookie->control.stats.freed = fVolume->UsedBlocks() - usedBlocks
+ fCheckCookie->control.stats.missing;
if (fCheckCookie->control.stats.freed < 0)
fCheckCookie->control.stats.freed = 0;
// Should we fix errors? Were there any errors we can fix?
if ((control->flags & BFS_FIX_BITMAP_ERRORS) != 0
&& (control->stats.freed != 0 || control->stats.missing != 0)) {
if ((fCheckCookie->control.flags & BFS_FIX_BITMAP_ERRORS) != 0
&& (fCheckCookie->control.stats.freed != 0
|| fCheckCookie->control.stats.missing != 0)) {
// If so, write the check bitmap back over the original one,
// and use transactions here to play safe - we even use several
// transactions, so that we don't blow the maximum log size
@@ -1339,6 +1343,9 @@ BlockAllocator::StopChecking(check_control* control)
fVolume->SetCheckingThread(-1);
if (control != NULL)
user_memcpy(control, &fCheckCookie->control, sizeof(check_control));
free(fCheckBitmap);
fCheckBitmap = NULL;
delete fCheckCookie;
@@ -1353,16 +1360,37 @@ BlockAllocator::StopChecking(check_control* control)
status_t
BlockAllocator::CheckNextNode(check_control* control)
{
if (!_IsValidCheckControl(control))
return B_BAD_VALUE;
if (fCheckCookie == NULL)
return B_NO_INIT;
fVolume->SetCheckingThread(find_thread(NULL));
// Make sure the user control is copied on exit
class CopyControlOnExit {
public:
CopyControlOnExit(check_control* source, check_control* userTarget)
:
fSource(source),
fTarget(userTarget)
{
}
~CopyControlOnExit()
{
if (fTarget != NULL)
user_memcpy(fTarget, fSource, sizeof(check_control));
}
private:
check_control* fSource;
check_control* fTarget;
} copyControl(&fCheckCookie->control, control);
while (true) {
if (fCheckCookie->iterator == NULL) {
if (!fCheckCookie->stack.Pop(&fCheckCookie->current)) {
// no more runs on the stack, we are obviously finished!
control->status = B_ENTRY_NOT_FOUND;
fCheckCookie->control.status = B_ENTRY_NOT_FOUND;
return B_ENTRY_NOT_FOUND;
}
@@ -1374,16 +1402,16 @@ BlockAllocator::CheckNextNode(check_control* control)
continue;
}
control->inode = inode->ID();
control->mode = inode->Mode();
fCheckCookie->control.inode = inode->ID();
fCheckCookie->control.mode = inode->Mode();
if (!inode->IsContainer()) {
// Check file
control->errors = 0;
control->status = CheckInode(inode, control);
fCheckCookie->control.errors = 0;
fCheckCookie->control.status = CheckInode(inode);
if (inode->GetName(control->name) < B_OK)
strcpy(control->name, "(node has no name)");
if (inode->GetName(fCheckCookie->control.name) < B_OK)
strcpy(fCheckCookie->control.name, "(node has no name)");
return B_OK;
}
@@ -1408,11 +1436,11 @@ BlockAllocator::CheckNextNode(check_control* control)
vnode.Keep();
// check the inode of the directory
control->errors = 0;
control->status = CheckInode(inode, control);
fCheckCookie->control.errors = 0;
fCheckCookie->control.status = CheckInode(inode);
if (inode->GetName(control->name) < B_OK)
strcpy(control->name, "(dir has no name)");
if (inode->GetName(fCheckCookie->control.name) < B_OK)
strcpy(fCheckCookie->control.name, "(dir has no name)");
return B_OK;
}
@@ -1439,23 +1467,23 @@ BlockAllocator::CheckNextNode(check_control* control)
continue;
// fill in the control data as soon as we have them
strlcpy(control->name, name, B_FILE_NAME_LENGTH);
control->inode = id;
control->errors = 0;
strlcpy(fCheckCookie->control.name, name, B_FILE_NAME_LENGTH);
fCheckCookie->control.inode = id;
fCheckCookie->control.errors = 0;
Vnode vnode(fVolume, id);
Inode* inode;
if (vnode.Get(&inode) != B_OK) {
FATAL(("Could not open inode ID %" B_PRIdINO "!\n", id));
control->errors |= BFS_COULD_NOT_OPEN;
fCheckCookie->control.errors |= BFS_COULD_NOT_OPEN;
if ((control->flags & BFS_REMOVE_INVALID) != 0) {
if ((fCheckCookie->control.flags & BFS_REMOVE_INVALID) != 0) {
status = _RemoveInvalidNode(fCheckCookie->parent,
fCheckCookie->iterator->Tree(), NULL, name);
} else
status = B_ERROR;
control->status = status;
fCheckCookie->control.status = status;
return B_OK;
}
@@ -1466,11 +1494,12 @@ BlockAllocator::CheckNextNode(check_control* control)
const char* localName = inode->Name(node.Node());
if (localName == NULL || strcmp(localName, name)) {
control->errors |= BFS_NAMES_DONT_MATCH;
fCheckCookie->control.errors |= BFS_NAMES_DONT_MATCH;
FATAL(("Names differ: tree \"%s\", inode \"%s\"\n", name,
localName));
if ((control->flags & BFS_FIX_NAME_MISMATCHES) != 0) {
if ((fCheckCookie->control.flags & BFS_FIX_NAME_MISMATCHES)
!= 0) {
// Rename the inode
Transaction transaction(fVolume, inode->BlockNumber());
@@ -1480,14 +1509,14 @@ BlockAllocator::CheckNextNode(check_control* control)
if (status == B_OK)
status = transaction.Done();
if (status != B_OK) {
control->status = status;
fCheckCookie->control.status = status;
return B_OK;
}
}
}
}
control->mode = inode->Mode();
fCheckCookie->control.mode = inode->Mode();
// Check for the correct mode of the node (if the mode of the
// file don't fit to its parent, there is a serious problem)
@@ -1503,15 +1532,16 @@ BlockAllocator::CheckNextNode(check_control* control)
fCheckCookie->parent->BlockNumber()));
// if we are allowed to fix errors, we should remove the file
if ((control->flags & BFS_REMOVE_WRONG_TYPES) != 0
&& (control->flags & BFS_FIX_BITMAP_ERRORS) != 0) {
if ((fCheckCookie->control.flags & BFS_REMOVE_WRONG_TYPES) != 0
&& (fCheckCookie->control.flags & BFS_FIX_BITMAP_ERRORS)
!= 0) {
status = _RemoveInvalidNode(fCheckCookie->parent, NULL,
inode, name);
} else
status = B_ERROR;
control->errors |= BFS_WRONG_TYPE;
control->status = status;
fCheckCookie->control.errors |= BFS_WRONG_TYPE;
fCheckCookie->control.status = status;
return B_OK;
}
@@ -1520,8 +1550,7 @@ BlockAllocator::CheckNextNode(check_control* control)
fCheckCookie->stack.Push(inode->BlockRun());
else {
// check it now
control->status = CheckInode(inode, control);
fCheckCookie->control.status = CheckInode(inode);
return B_OK;
}
}
@@ -1626,8 +1655,7 @@ BlockAllocator::CheckBlocks(off_t start, off_t length, bool allocated)
status_t
BlockAllocator::CheckBlockRun(block_run run, const char* type,
check_control* control, bool allocated)
BlockAllocator::CheckBlockRun(block_run run, const char* type, bool allocated)
{
if (run.AllocationGroup() < 0 || run.AllocationGroup() >= fNumGroups
|| run.Start() > fGroups[run.AllocationGroup()].fNumBits
@@ -1636,10 +1664,10 @@ BlockAllocator::CheckBlockRun(block_run run, const char* type,
|| run.length == 0) {
PRINT(("%s: block_run(%ld, %u, %u) is invalid!\n", type,
run.AllocationGroup(), run.Start(), run.Length()));
if (control == NULL)
if (fCheckCookie == NULL)
return B_BAD_DATA;
control->errors |= BFS_INVALID_BLOCK_RUN;
fCheckCookie->control.errors |= BFS_INVALID_BLOCK_RUN;
return B_OK;
}
@@ -1664,7 +1692,7 @@ BlockAllocator::CheckBlockRun(block_run run, const char* type,
while (length < run.Length() && pos < cached.NumBlockBits()) {
if (cached.IsUsed(pos) != allocated) {
if (control == NULL) {
if (fCheckCookie == NULL) {
PRINT(("%s: block_run(%ld, %u, %u) is only partially "
"allocated (pos = %ld, length = %ld)!\n", type,
run.AllocationGroup(), run.Start(), run.Length(),
@@ -1673,9 +1701,9 @@ BlockAllocator::CheckBlockRun(block_run run, const char* type,
}
if (firstMissing == -1) {
firstMissing = firstGroupBlock + pos + block * bitsPerBlock;
control->errors |= BFS_MISSING_BLOCKS;
fCheckCookie->control.errors |= BFS_MISSING_BLOCKS;
}
control->stats.missing++;
fCheckCookie->control.stats.missing++;
} else if (firstMissing != -1) {
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are "
"%sallocated!\n", type, run.AllocationGroup(), run.Start(),
@@ -1692,11 +1720,11 @@ BlockAllocator::CheckBlockRun(block_run run, const char* type,
if (_CheckBitmapIsUsedAt(firstGroupBlock + offset)) {
if (firstSet == -1) {
firstSet = firstGroupBlock + offset;
control->errors |= BFS_BLOCKS_ALREADY_SET;
fCheckCookie->control.errors |= BFS_BLOCKS_ALREADY_SET;
dprintf("block %" B_PRIdOFF " is already set!!!\n",
firstGroupBlock + offset);
}
control->stats.already_set++;
fCheckCookie->control.stats.already_set++;
} else {
if (firstSet != -1) {
FATAL(("%s: block_run(%d, %u, %u): blocks %" B_PRIdOFF
@@ -1735,14 +1763,14 @@ BlockAllocator::CheckBlockRun(block_run run, const char* type,
status_t
BlockAllocator::CheckInode(Inode* inode, check_control* control)
BlockAllocator::CheckInode(Inode* inode)
{
if (control != NULL && fCheckBitmap == NULL)
if (fCheckCookie != NULL && fCheckBitmap == NULL)
return B_NO_INIT;
if (inode == NULL)
return B_BAD_VALUE;
status_t status = CheckBlockRun(inode->BlockRun(), "inode", control);
status_t status = CheckBlockRun(inode->BlockRun(), "inode");
if (status != B_OK)
return status;
@@ -1767,7 +1795,7 @@ BlockAllocator::CheckInode(Inode* inode, check_control* control)
if (data->direct[i].IsZero())
break;
status = CheckBlockRun(data->direct[i], "direct", control);
status = CheckBlockRun(data->direct[i], "direct");
if (status < B_OK)
return status;
}
@@ -1778,7 +1806,7 @@ BlockAllocator::CheckInode(Inode* inode, check_control* control)
// check the indirect range
if (data->max_indirect_range) {
status = CheckBlockRun(data->indirect, "indirect", control);
status = CheckBlockRun(data->indirect, "indirect");
if (status < B_OK)
return status;
@@ -1795,7 +1823,7 @@ BlockAllocator::CheckInode(Inode* inode, check_control* control)
if (runs[index].IsZero())
break;
status = CheckBlockRun(runs[index], "indirect->run", control);
status = CheckBlockRun(runs[index], "indirect->run");
if (status < B_OK)
return status;
}
@@ -1807,8 +1835,7 @@ BlockAllocator::CheckInode(Inode* inode, check_control* control)
// check the double indirect range
if (data->max_double_indirect_range) {
status = CheckBlockRun(data->double_indirect, "double indirect",
control);
status = CheckBlockRun(data->double_indirect, "double indirect");
if (status != B_OK)
return status;
@@ -1831,7 +1858,7 @@ BlockAllocator::CheckInode(Inode* inode, check_control* control)
if (indirect.IsZero())
return B_OK;
status = CheckBlockRun(indirect, "double indirect->runs", control);
status = CheckBlockRun(indirect, "double indirect->runs");
if (status != B_OK)
return status;
@@ -1850,7 +1877,7 @@ BlockAllocator::CheckInode(Inode* inode, check_control* control)
return B_OK;
status = CheckBlockRun(runs[index % runsPerBlock],
"double indirect->runs->run", control);
"double indirect->runs->run");
if (status != B_OK)
return status;
} while ((++index % runsPerArray) != 0);
@@ -1,5 +1,5 @@
/*
* Copyright 2001-2009, Axel Dörfler, [email protected].
* Copyright 2001-2010, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
#ifndef BLOCK_ALLOCATOR_H
@@ -54,10 +54,8 @@ public:
bool allocated = true);
status_t CheckBlockRun(block_run run,
const char* type = NULL,
check_control* control = NULL,
bool allocated = true);
status_t CheckInode(Inode* inode,
check_control* control = NULL);
status_t CheckInode(Inode* inode);
size_t BitmapSize() const;
@@ -1,10 +1,11 @@
/*
* Copyright 2001-2009, Axel Dörfler, [email protected]
* Copyright 2001-2010, Axel Dörfler, [email protected]
* This file may be used under the terms of the MIT License.
*/
#ifndef BFS_CONTROL_H
#define BFS_CONTROL_H
//! additional functionality exported via ioctl()
@@ -35,8 +36,8 @@ struct update_boot_block {
#define BFS_IOCTL_STOP_CHECKING 14202
#define BFS_IOCTL_CHECK_NEXT_NODE 14203
/* all fields except "flags", and "name" must be set to zero before
* BFS_IOCTL_START_CHECKING is called
/* All fields except "flags", and "name" must be set to zero before
* BFS_IOCTL_START_CHECKING is called, and magic must be set.
*/
struct check_control {
uint32 magic;
@@ -78,4 +79,5 @@ struct check_control {
/* check control magic value */
#define BFS_IOCTL_CHECK_MAGIC 'BChk'
#endif /* BFS_CONTROL_H */