* Removed no longer needed IOCTL_FILE_UNCACHED_IO definition.

* Some cleanup, no functional change.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26706 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-07-31 21:09:02 +00:00
parent 26e7ba5602
commit a9ae9781ea
5 changed files with 338 additions and 269 deletions
@@ -6,14 +6,13 @@
//! block bitmap handling and allocation policies //! block bitmap handling and allocation policies
#include "Debug.h"
#include "BlockAllocator.h" #include "BlockAllocator.h"
#include "Volume.h"
#include "Inode.h"
#include "BPlusTree.h"
#include "bfs_control.h"
#include "system_dependencies.h" #include "bfs_control.h"
#include "BPlusTree.h"
#include "Debug.h"
#include "Inode.h"
#include "Volume.h"
// Things the BlockAllocator should do: // Things the BlockAllocator should do:
@@ -150,7 +149,8 @@ class AllocationBlock : public CachedBlock {
inline bool IsUsed(uint16 block); inline bool IsUsed(uint16 block);
status_t SetTo(AllocationGroup& group, uint16 block); status_t SetTo(AllocationGroup& group, uint16 block);
status_t SetToWritable(Transaction &transaction, AllocationGroup &group, uint16 block); status_t SetToWritable(Transaction& transaction, AllocationGroup& group,
uint16 block);
uint32 NumBlockBits() const { return fNumBits; } uint32 NumBlockBits() const { return fNumBits; }
uint32& Block(int32 index) { return ((uint32*)fBlock)[index]; } uint32& Block(int32 index) { return ((uint32*)fBlock)[index]; }
@@ -185,7 +185,8 @@ class AllocationGroup {
uint32 fNumBlocks; uint32 fNumBlocks;
int32 fStart; int32 fStart;
int32 fFirstFree, fLargest, fLargestFirst; int32 fFirstFree, fLargest, fLargestFirst;
// ToDo: fLargest & fLargestFirst are not maintained (and therefore used) yet! // TODO: fLargest & fLargestFirst are not maintained
// (and therefore used) yet!
int32 fFreeBits; int32 fFreeBits;
}; };
@@ -354,7 +355,7 @@ AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length)
return B_ERROR; return B_ERROR;
// Update the allocation group info // Update the allocation group info
// ToDo: this info will be incorrect if something goes wrong later // TODO: this info will be incorrect if something goes wrong later
// Note, the fFirstFree block doesn't have to be really free // Note, the fFirstFree block doesn't have to be really free
if (start == fFirstFree) if (start == fFirstFree)
fFirstFree = start + length; fFirstFree = start + length;
@@ -401,7 +402,7 @@ AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length)
return B_ERROR; return B_ERROR;
// Update the allocation group info // Update the allocation group info
// ToDo: this info will be incorrect if something goes wrong later // TODO: this info will be incorrect if something goes wrong later
if (fFirstFree > start) if (fFirstFree > start)
fFirstFree = start; fFirstFree = start;
fFreeBits += length; fFreeBits += length;
@@ -471,10 +472,10 @@ BlockAllocator::Initialize(bool full)
// the lock will be released by the _Initialize() method // the lock will be released by the _Initialize() method
thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::_Initialize, thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::_Initialize,
"bfs block allocator", B_LOW_PRIORITY, (void *)this); "bfs block allocator", B_LOW_PRIORITY, this);
if (id < B_OK) if (id < B_OK)
return _Initialize(this); return _Initialize(this);
else
mutex_transfer_lock(&fLock, id); mutex_transfer_lock(&fLock, id);
return resume_thread(id); return resume_thread(id);
@@ -503,13 +504,15 @@ BlockAllocator::InitializeAndClearBitmap(Transaction &transaction)
// initialize the AllocationGroup objects and clear the on-disk bitmap // initialize the AllocationGroup objects and clear the on-disk bitmap
for (int32 i = 0; i < fNumGroups; i++) { for (int32 i = 0; i < fNumGroups; i++) {
if (write_pos(fVolume->Device(), offset << blockShift, buffer, blocks << blockShift) < B_OK) if (write_pos(fVolume->Device(), offset << blockShift, buffer,
blocks << blockShift) < B_OK)
return B_ERROR; return B_ERROR;
// the last allocation group may contain less blocks than the others // the last allocation group may contain less blocks than the others
if (i == fNumGroups - 1) { if (i == fNumGroups - 1) {
fGroups[i].fNumBits = fVolume->NumBlocks() - i * numBits; fGroups[i].fNumBits = fVolume->NumBlocks() - i * numBits;
fGroups[i].fNumBlocks = 1 + ((fGroups[i].NumBits() - 1) >> (blockShift + 3)); fGroups[i].fNumBlocks = 1 + ((fGroups[i].NumBits() - 1)
>> (blockShift + 3));
} else { } else {
fGroups[i].fNumBits = numBits; fGroups[i].fNumBits = numBits;
fGroups[i].fNumBlocks = blocks; fGroups[i].fNumBlocks = blocks;
@@ -529,7 +532,8 @@ BlockAllocator::InitializeAndClearBitmap(Transaction &transaction)
FATAL(("could not allocate reserved space for block bitmap/log!\n")); FATAL(("could not allocate reserved space for block bitmap/log!\n"));
return B_ERROR; return B_ERROR;
} }
fVolume->SuperBlock().used_blocks = HOST_ENDIAN_TO_BFS_INT64(reservedBlocks); fVolume->SuperBlock().used_blocks
= HOST_ENDIAN_TO_BFS_INT64(reservedBlocks);
return B_OK; return B_OK;
} }
@@ -564,7 +568,8 @@ BlockAllocator::_Initialize(BlockAllocator *allocator)
// the last allocation group may contain less blocks than the others // the last allocation group may contain less blocks than the others
if (i == numGroups - 1) { if (i == numGroups - 1) {
groups[i].fNumBits = volume->NumBlocks() - i * bitsPerGroup; groups[i].fNumBits = volume->NumBlocks() - i * bitsPerGroup;
groups[i].fNumBlocks = 1 + ((groups[i].NumBits() - 1) >> (blockShift + 3)); groups[i].fNumBlocks = 1 + ((groups[i].NumBits() - 1)
>> (blockShift + 3));
} else { } else {
groups[i].fNumBits = bitsPerGroup; groups[i].fNumBits = bitsPerGroup;
groups[i].fNumBlocks = blocks; groups[i].fNumBlocks = blocks;
@@ -670,7 +675,8 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
// The wanted maximum is smaller than the largest free block in the // The wanted maximum is smaller than the largest free block in the
// group 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;
@@ -688,7 +694,8 @@ 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", fGroups[group].Start() + block, cached.Block(), fVolume->BlockSize(), group, rangeStart)); 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 % bitsPerFullBlock; for (uint32 bit = start % bitsPerFullBlock;
@@ -703,7 +710,8 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
if (++range >= maximum) if (++range >= maximum)
break; break;
} else if (i >= fNumGroups && range >= minimum) { } else if (i >= fNumGroups && range >= minimum) {
// we have found a block larger than the required minimum (second pass) // we have found a block larger than the required minimum
// (second pass)
break; break;
} else { } else {
// end of a range // end of a range
@@ -711,18 +719,19 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
} }
} }
// ToDo: we could also remember a "largest free block that fits the minimal // TODO: we could also remember a "largest free block that fits the
// requirement" in the group, and use that - this would avoid the need // minimal requirement" in the group, and use that - this would
// for a second run // avoid the need for a second run
// if we found a suitable block, mark the blocks as in use, and write // if we found a suitable block, mark the blocks as in use, and
// the updated block bitmap back to disk // write the updated block bitmap back to disk
if (range >= numBlocks) { if (range >= numBlocks) {
// adjust allocation size // adjust allocation size
if (numBlocks < maximum) if (numBlocks < maximum)
numBlocks = range; numBlocks = range;
if (fGroups[group].Allocate(transaction, rangeStart, numBlocks) < B_OK) if (fGroups[group].Allocate(transaction, rangeStart, numBlocks)
< B_OK)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(B_IO_ERROR);
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(group); run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(group);
@@ -755,12 +764,13 @@ status_t
BlockAllocator::AllocateForInode(Transaction& transaction, BlockAllocator::AllocateForInode(Transaction& transaction,
const block_run* parent, 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
// "Practical File System Design", and see how good they work // "Practical File System Design", and see how good they work
// files are going in the same allocation group as its parent, sub-directories // Files are going in the same allocation group as its parent,
// will be inserted 8 allocation groups after the one of the parent // sub-directories will be inserted 8 allocation groups after
// the one of the parent
uint16 group = parent->AllocationGroup(); uint16 group = parent->AllocationGroup();
if ((type & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY) if ((type & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY)
group += 8; group += 8;
@@ -770,8 +780,8 @@ BlockAllocator::AllocateForInode(Transaction &transaction,
status_t status_t
BlockAllocator::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks, BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
block_run &run, uint16 minimum) off_t numBlocks, block_run& run, uint16 minimum)
{ {
if (numBlocks <= 0) if (numBlocks <= 0)
return B_ERROR; return B_ERROR;
@@ -782,26 +792,27 @@ BlockAllocator::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks
// since block_run.length is uint16, the largest number of blocks that // since block_run.length is uint16, the largest number of blocks that
// can be covered by a block_run is 65535 // can be covered by a block_run is 65535
// ToDo: if we drop compatibility, couldn't we do this any better? // TODO: if we drop compatibility, couldn't we do this any better?
// There are basically two possibilities: // There are basically two possibilities:
// a) since a length of zero doesn't have any sense, take that for 65536 - // a) since a length of zero doesn't have any sense, take that for 65536 -
// but that could cause many problems (bugs) in other areas // but that could cause many problems (bugs) in other areas
// b) reduce the maximum amount of blocks per block_run, so that the remaining // b) reduce the maximum amount of blocks per block_run, so that the
// number of free blocks can be used in a useful manner (like 4 blocks) - // remaining number of free blocks can be used in a useful manner
// but that would also reduce the maximum file size // (like 4 blocks) - but that would also reduce the maximum file size
// c) have BlockRun::Length() return (length + 1). // c) have BlockRun::Length() return (length + 1).
if (numBlocks > MAX_BLOCK_RUN_LENGTH) if (numBlocks > MAX_BLOCK_RUN_LENGTH)
numBlocks = MAX_BLOCK_RUN_LENGTH; numBlocks = MAX_BLOCK_RUN_LENGTH;
// apply some allocation policies here (AllocateBlocks() will break them // Apply some allocation policies here (AllocateBlocks() will break them
// if necessary) // if necessary)
uint16 group = inode->BlockRun().AllocationGroup(); uint16 group = inode->BlockRun().AllocationGroup();
uint16 start = 0; uint16 start = 0;
// are there already allocated blocks? (then just try to allocate near the last one) // Are there already allocated blocks? (then just try to allocate near the
// last one)
if (inode->Size() > 0) { if (inode->Size() > 0) {
const data_stream& data = inode->Node().data; const data_stream& data = inode->Node().data;
// ToDo: we currently don't care for when the data stream // TODO: we currently don't care for when the data stream
// is already grown into the indirect ranges // is already grown into the indirect ranges
if (data.max_double_indirect_range == 0 if (data.max_double_indirect_range == 0
&& data.max_indirect_range == 0) { && data.max_indirect_range == 0) {
@@ -836,7 +847,8 @@ BlockAllocator::Free(Transaction &transaction, block_run run)
uint16 start = run.Start(); uint16 start = run.Start();
uint16 length = run.Length(); uint16 length = run.Length();
FUNCTION_START(("group = %ld, start = %u, length = %u\n", group, start, length)); FUNCTION_START(("group = %ld, start = %u, length = %u\n", group, start,
length));
T(Free(run)); T(Free(run));
// doesn't use Volume::IsValidBlockRun() here because it can check better // doesn't use Volume::IsValidBlockRun() here because it can check better
@@ -845,13 +857,17 @@ BlockAllocator::Free(Transaction &transaction, block_run run)
|| start > fGroups[group].NumBits() || start > fGroups[group].NumBits()
|| uint32(start + length) > fGroups[group].NumBits() || uint32(start + length) > fGroups[group].NumBits()
|| length == 0) { || length == 0) {
FATAL(("tried to free an invalid block_run (%d, %u, %u)\n", (int)group, start, length)); FATAL(("tried to free an invalid block_run (%d, %u, %u)\n", (int)group,
start, length));
DEBUGGER(("tried to free invalid block_run")); DEBUGGER(("tried to free invalid block_run"));
return B_BAD_VALUE; return B_BAD_VALUE;
} }
// check if someone tries to free reserved areas at the beginning of the drive // check if someone tries to free reserved areas at the beginning of the
if (group == 0 && start < uint32(fVolume->Log().Start() + fVolume->Log().Length())) { // drive
FATAL(("tried to free a reserved block_run (%d, %u, %u)\n", (int)group, start, length)); if (group == 0
&& start < uint32(fVolume->Log().Start() + fVolume->Log().Length())) {
FATAL(("tried to free a reserved block_run (%d, %u, %u)\n", (int)group,
start, length));
DEBUGGER(("tried to free reserved block")); DEBUGGER(("tried to free reserved block"));
return B_BAD_VALUE; return B_BAD_VALUE;
} }
@@ -864,8 +880,10 @@ BlockAllocator::Free(Transaction &transaction, block_run run)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(B_IO_ERROR);
#ifdef DEBUG #ifdef DEBUG
if (CheckBlockRun(run, NULL, NULL, false) < B_OK) if (CheckBlockRun(run, NULL, NULL, false) < B_OK) {
DEBUGGER(("CheckBlockRun() reports allocated blocks (which were just freed)\n")); DEBUGGER(("CheckBlockRun() reports allocated blocks (which were just "
"freed)\n"));
}
#endif #endif
fVolume->SuperBlock().used_blocks = fVolume->SuperBlock().used_blocks =
@@ -881,9 +899,12 @@ BlockAllocator::BitmapSize() const
} }
// #pragma mark - // #pragma mark - Bitmap validity checking
// TODO: implement new FS checking API
// Functions to check the validity of the bitmap - they are used from // Functions to check the validity of the bitmap - they are used from
// the "chkbfs" command // the "chkbfs" command (since this does even a bit more, maybe we should
// move this some place else?)
bool bool
@@ -940,7 +961,7 @@ BlockAllocator::StartChecking(check_control *control)
fCheckCookie = cookie; fCheckCookie = cookie;
// to be able to restore nicely if "chkbfs" exited abnormally // to be able to restore nicely if "chkbfs" exited abnormally
// ToDo: check reserved area in bitmap! // TODO: check reserved area in bitmap!
return B_OK; return B_OK;
} }
@@ -973,7 +994,7 @@ BlockAllocator::StopChecking(check_control *control)
size_t size = fVolume->BlockSize() * fNumGroups * fBlocksPerGroup; size_t size = fVolume->BlockSize() * fNumGroups * fBlocksPerGroup;
off_t usedBlocks = 0LL; off_t usedBlocks = 0LL;
// ToDo: update the allocation groups used blocks info // TODO: update the allocation groups used blocks info
for (uint32 i = size >> 2; i-- > 0;) { for (uint32 i = size >> 2; i-- > 0;) {
uint32 compare = 1; uint32 compare = 1;
for (int16 j = 0; j < 32; j++, compare <<= 1) { for (int16 j = 0; j < 32; j++, compare <<= 1) {
@@ -988,13 +1009,14 @@ BlockAllocator::StopChecking(check_control *control)
control->stats.freed = 0; control->stats.freed = 0;
// Should we fix errors? Were there any errors we can fix? // Should we fix errors? Were there any errors we can fix?
if (control->flags & BFS_FIX_BITMAP_ERRORS if ((control->flags & BFS_FIX_BITMAP_ERRORS) != 0
&& (control->stats.freed != 0 || control->stats.missing != 0)) { && (control->stats.freed != 0 || control->stats.missing != 0)) {
// if so, write the check bitmap back over the original one, // if so, write the check bitmap back over the original one,
// and use transactions here to play safe - we even use several // and use transactions here to play safe - we even use several
// transactions, so that we don't blow the maximum log size // transactions, so that we don't blow the maximum log size
// on large disks; since we don't need to make this atomic // on large disks; since we don't need to make this atomic
fVolume->SuperBlock().used_blocks = HOST_ENDIAN_TO_BFS_INT64(usedBlocks); fVolume->SuperBlock().used_blocks
= HOST_ENDIAN_TO_BFS_INT64(usedBlocks);
int32 blocksInBitmap = fNumGroups * fBlocksPerGroup; int32 blocksInBitmap = fNumGroups * fBlocksPerGroup;
int32 blockSize = fVolume->BlockSize(); int32 blockSize = fVolume->BlockSize();
@@ -1049,18 +1071,21 @@ BlockAllocator::CheckNextNode(check_control *control)
Vnode vnode(fVolume, cookie->current); Vnode vnode(fVolume, cookie->current);
Inode* inode; Inode* inode;
if (vnode.Get(&inode) < B_OK) { if (vnode.Get(&inode) < B_OK) {
FATAL(("check: Could not open inode at %Ld\n", fVolume->ToBlock(cookie->current))); FATAL(("check: Could not open inode at %Ld\n",
fVolume->ToBlock(cookie->current)));
continue; continue;
} }
if (!inode->IsContainer()) { 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;
} }
BPlusTree* tree; BPlusTree* tree;
if (inode->GetTree(&tree) != B_OK) { if (inode->GetTree(&tree) != B_OK) {
FATAL(("check: could not open b+tree from inode at %Ld\n", fVolume->ToBlock(cookie->current))); FATAL(("check: could not open b+tree from inode at %Ld\n",
fVolume->ToBlock(cookie->current)));
continue; continue;
} }
@@ -1091,7 +1116,8 @@ BlockAllocator::CheckNextNode(check_control *control)
uint16 length; uint16 length;
ino_t id; ino_t id;
status_t status = cookie->iterator->GetNextEntry(name, &length, B_FILE_NAME_LENGTH, &id); status_t status = cookie->iterator->GetNextEntry(name, &length,
B_FILE_NAME_LENGTH, &id);
if (status == B_ENTRY_NOT_FOUND) { if (status == B_ENTRY_NOT_FOUND) {
// there are no more entries in this iterator, free it and go on // there are no more entries in this iterator, free it and go on
delete cookie->iterator; delete cookie->iterator;
@@ -1128,7 +1154,8 @@ BlockAllocator::CheckNextNode(check_control *control)
const char* localName = inode->Name(node.Node()); const char* localName = inode->Name(node.Node());
if (localName == NULL || strcmp(localName, name)) { if (localName == NULL || strcmp(localName, name)) {
control->errors |= BFS_NAMES_DONT_MATCH; control->errors |= BFS_NAMES_DONT_MATCH;
FATAL(("Names differ: tree \"%s\", inode \"%s\"\n", name, localName)); FATAL(("Names differ: tree \"%s\", inode \"%s\"\n", name,
localName));
} }
} }
@@ -1136,25 +1163,30 @@ BlockAllocator::CheckNextNode(check_control *control)
// Check for the correct mode of the node (if the mode of the // 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) // file don't fit to its parent, there is a serious problem)
if (((cookie->parent_mode & S_ATTR_DIR) != 0 && !inode->IsAttribute()) if (((cookie->parent_mode & S_ATTR_DIR) != 0
|| ((cookie->parent_mode & S_INDEX_DIR) != 0 && !inode->IsIndex()) && !inode->IsAttribute())
|| ((cookie->parent_mode & (S_DIRECTORY | S_ATTR_DIR | S_INDEX_DIR)) || ((cookie->parent_mode & S_INDEX_DIR) != 0
== S_DIRECTORY && !inode->IsIndex())
&& (inode->Mode() & (S_ATTR | S_ATTR_DIR | S_INDEX_DIR)) != 0)) { || (is_directory(cookie->parent_mode)
FATAL(("inode at %Ld is of wrong type: %o (parent %o at %Ld)!\n", && !inode->IsRegularNode())) {
inode->BlockNumber(), inode->Mode(), cookie->parent_mode, cookie->parent->BlockNumber())); FATAL(("inode at %Ld is of wrong type: %o (parent %o at %Ld)!"
"\n", inode->BlockNumber(), inode->Mode(),
cookie->parent_mode, cookie->parent->BlockNumber()));
// if we are allowed to fix errors, we should remove the file // if we are allowed to fix errors, we should remove the file
if (control->flags & BFS_REMOVE_WRONG_TYPES if ((control->flags & BFS_REMOVE_WRONG_TYPES) != 0
&& control->flags & BFS_FIX_BITMAP_ERRORS) { && (control->flags & BFS_FIX_BITMAP_ERRORS) != 0) {
// it's safe to start a transaction, because Inode::Remove() // it's safe to start a transaction, because Inode::Remove()
// won't touch the block bitmap (which we hold the lock for) // won't touch the block bitmap (which we hold the lock for)
// if we set the INODE_DONT_FREE_SPACE flag - since we fix // if we set the INODE_DONT_FREE_SPACE flag - since we fix
// the bitmap anyway // the bitmap anyway
Transaction transaction(fVolume, cookie->parent->BlockNumber()); Transaction transaction(fVolume,
cookie->parent->BlockNumber());
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_DONT_FREE_SPACE); inode->Node().flags
status = cookie->parent->Remove(transaction, name, NULL, inode->IsContainer()); |= HOST_ENDIAN_TO_BFS_INT32(INODE_DONT_FREE_SPACE);
status = cookie->parent->Remove(transaction, name, NULL,
inode->IsContainer());
if (status == B_OK) if (status == B_OK)
transaction.Done(); transaction.Done();
} else } else
@@ -1192,7 +1224,8 @@ BlockAllocator::_CheckBitmapIsUsedAt(off_t block) const
if (index > size / 4) if (index > size / 4)
return false; return false;
return BFS_ENDIAN_TO_HOST_INT32(fCheckBitmap[index]) & (1UL << (block & 0x1f)); return BFS_ENDIAN_TO_HOST_INT32(fCheckBitmap[index])
& (1UL << (block & 0x1f));
} }
@@ -1209,13 +1242,16 @@ BlockAllocator::_SetCheckBitmapAt(off_t block)
status_t status_t
BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *control, bool allocated) BlockAllocator::CheckBlockRun(block_run run, const char* type,
check_control* control, bool allocated)
{ {
if (run.AllocationGroup() < 0 || run.AllocationGroup() >= fNumGroups if (run.AllocationGroup() < 0 || run.AllocationGroup() >= fNumGroups
|| run.Start() > fGroups[run.AllocationGroup()].fNumBits || run.Start() > fGroups[run.AllocationGroup()].fNumBits
|| uint32(run.Start() + run.Length()) > fGroups[run.AllocationGroup()].fNumBits || uint32(run.Start() + run.Length())
> fGroups[run.AllocationGroup()].fNumBits
|| run.length == 0) { || run.length == 0) {
PRINT(("%s: block_run(%ld, %u, %u) is invalid!\n", type, run.AllocationGroup(), run.Start(), run.Length())); PRINT(("%s: block_run(%ld, %u, %u) is invalid!\n", type,
run.AllocationGroup(), run.Start(), run.Length()));
if (control == NULL) if (control == NULL)
return B_BAD_DATA; return B_BAD_DATA;
@@ -1228,7 +1264,8 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
uint32 pos = run.Start() % bitsPerBlock; uint32 pos = run.Start() % bitsPerBlock;
int32 length = 0; int32 length = 0;
off_t firstMissing = -1, firstSet = -1; off_t firstMissing = -1, firstSet = -1;
off_t firstGroupBlock = (off_t)run.AllocationGroup() << fVolume->AllocationGroupShift(); off_t firstGroupBlock
= (off_t)run.AllocationGroup() << fVolume->AllocationGroupShift();
AllocationBlock cached(fVolume); AllocationBlock cached(fVolume);
@@ -1244,8 +1281,10 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
while (length < run.Length() && pos < cached.NumBlockBits()) { while (length < run.Length() && pos < cached.NumBlockBits()) {
if (cached.IsUsed(pos) != allocated) { if (cached.IsUsed(pos) != allocated) {
if (control == NULL) { if (control == NULL) {
PRINT(("%s: block_run(%ld, %u, %u) is only partially allocated (pos = %ld, length = %ld)!\n", PRINT(("%s: block_run(%ld, %u, %u) is only partially "
type, run.AllocationGroup(), run.Start(), run.Length(), pos, length)); "allocated (pos = %ld, length = %ld)!\n", type,
run.AllocationGroup(), run.Start(), run.Length(),
pos, length));
return B_BAD_DATA; return B_BAD_DATA;
} }
if (firstMissing == -1) { if (firstMissing == -1) {
@@ -1254,15 +1293,17 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
} }
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 %sallocated!\n", PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are "
type, run.allocation_group, run.start, run.length, firstMissing, "%sallocated!\n", type, run.AllocationGroup(), run.Start(),
firstGroupBlock + pos + block * bitsPerBlock - 1, allocated ? "not " : "")); run.Length(), firstMissing,
firstGroupBlock + pos + block * bitsPerBlock - 1,
allocated ? "not " : ""));
firstMissing = -1; firstMissing = -1;
} }
if (fCheckBitmap != NULL) { if (fCheckBitmap != NULL) {
// Set the block in the check bitmap as well, but have a look if it // Set the block in the check bitmap as well, but have a look
// is already allocated first // if it is already allocated first
uint32 offset = pos + block * bitsPerBlock; uint32 offset = pos + block * bitsPerBlock;
if (_CheckBitmapIsUsedAt(firstGroupBlock + offset)) { if (_CheckBitmapIsUsedAt(firstGroupBlock + offset)) {
if (firstSet == -1) { if (firstSet == -1) {
@@ -1272,8 +1313,11 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
control->stats.already_set++; control->stats.already_set++;
} else { } else {
if (firstSet != -1) { if (firstSet != -1) {
FATAL(("%s: block_run(%d, %u, %u): blocks %Ld - %Ld are already set!\n", FATAL(("%s: block_run(%d, %u, %u): blocks %Ld - %Ld "
type, (int)run.AllocationGroup(), run.Start(), run.Length(), firstSet, firstGroupBlock + offset - 1)); "are already set!\n", type,
(int)run.AllocationGroup(), run.Start(),
run.Length(), firstSet,
firstGroupBlock + offset - 1));
firstSet = -1; firstSet = -1;
} }
_SetCheckBitmapAt(firstGroupBlock + offset); _SetCheckBitmapAt(firstGroupBlock + offset);
@@ -1284,10 +1328,18 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
} }
if (block + 1 >= fBlocksPerGroup || length >= run.Length()) { 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.AllocationGroup(), run.Start(), run.Length(), firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1)); PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not "
if (firstSet != -1) "allocated!\n", type, run.AllocationGroup(), run.Start(),
FATAL(("%s: block_run(%d, %u, %u): blocks %Ld - %Ld are already set!\n", type, (int)run.AllocationGroup(), run.Start(), run.Length(), firstSet, firstGroupBlock + pos + block * bitsPerBlock - 1)); run.Length(), firstMissing,
firstGroupBlock + pos + block * bitsPerBlock - 1));
}
if (firstSet != -1) {
FATAL(("%s: block_run(%d, %u, %u): blocks %Ld - %Ld are "
"already set!\n", type, (int)run.AllocationGroup(),
run.Start(), run.Length(), firstSet,
firstGroupBlock + pos + block * bitsPerBlock - 1));
}
} }
} }
@@ -1364,7 +1416,8 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
// check the double indirect range // check the double indirect range
if (data->max_double_indirect_range) { if (data->max_double_indirect_range) {
status = CheckBlockRun(data->double_indirect, "double indirect", control); status = CheckBlockRun(data->double_indirect, "double indirect",
control);
if (status < B_OK) if (status < B_OK)
return status; return status;
@@ -1372,12 +1425,14 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT; int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT;
CachedBlock cachedDirect(fVolume); CachedBlock cachedDirect(fVolume);
int32 maxIndirectIndex = (data->double_indirect.Length() << fVolume->BlockShift()) int32 maxIndirectIndex = (data->double_indirect.Length()
/ sizeof(block_run); << fVolume->BlockShift()) / sizeof(block_run);
for (int32 indirectIndex = 0; indirectIndex < maxIndirectIndex; indirectIndex++) { for (int32 indirectIndex = 0; indirectIndex < maxIndirectIndex;
indirectIndex++) {
// get the indirect array block // get the indirect array block
block_run *array = (block_run *)cached.SetTo(fVolume->ToBlock(data->double_indirect) block_run* array = (block_run*)cached.SetTo(
fVolume->ToBlock(data->double_indirect)
+ indirectIndex / runsPerBlock); + indirectIndex / runsPerBlock);
if (array == NULL) if (array == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -1391,11 +1446,12 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
if (status < B_OK) if (status < B_OK)
return status; return status;
int32 maxIndex = (indirect.Length() << fVolume->BlockShift()) / sizeof(block_run); int32 maxIndex = (indirect.Length() << fVolume->BlockShift())
/ sizeof(block_run);
for (int32 index = 0; index < maxIndex; ) { for (int32 index = 0; index < maxIndex; ) {
block_run *runs = (block_run *)cachedDirect.SetTo(fVolume->ToBlock(indirect) block_run* runs = (block_run*)cachedDirect.SetTo(
+ index / runsPerBlock); fVolume->ToBlock(indirect) + index / runsPerBlock);
if (runs == NULL) if (runs == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -1404,7 +1460,8 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
if (runs[index % runsPerBlock].IsZero()) if (runs[index % runsPerBlock].IsZero())
return B_OK; return B_OK;
status = CheckBlockRun(runs[index % runsPerBlock], "double indirect->runs->run", control); status = CheckBlockRun(runs[index % runsPerBlock],
"double indirect->runs->run", control);
if (status < B_OK) if (status < B_OK)
return status; return status;
} while ((++index % runsPerArray) != 0); } while ((++index % runsPerArray) != 0);
@@ -43,4 +43,19 @@ round_up(const IntType& value, const RoundType& to)
return (value + (to - 1)) & ~((IntType)to - 1); return (value + (to - 1)) & ~((IntType)to - 1);
} }
inline bool
is_index(int mode)
{
return (mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR;
// That's a stupid check, but AFAIK the only possible method...
}
inline bool
is_directory(int mode)
{
return (mode & (S_INDEX_DIR | S_ATTR_DIR | S_IFDIR)) == S_IFDIR;
}
#endif /* UTILITY_H */ #endif /* UTILITY_H */
@@ -315,7 +315,7 @@ Volume::Panic()
status_t status_t
Volume::Mount(const char* deviceName, uint32 flags) Volume::Mount(const char* deviceName, uint32 flags)
{ {
// ToDo: validate the FS in write mode as well! // TODO: validate the FS in write mode as well!
#if (B_HOST_IS_LENDIAN && defined(BFS_BIG_ENDIAN_ONLY)) \ #if (B_HOST_IS_LENDIAN && defined(BFS_BIG_ENDIAN_ONLY)) \
|| (B_HOST_IS_BENDIAN && defined(BFS_LITTLE_ENDIAN_ONLY)) || (B_HOST_IS_BENDIAN && defined(BFS_LITTLE_ENDIAN_ONLY))
// in big endian mode, we only mount read-only for now // in big endian mode, we only mount read-only for now
@@ -539,7 +539,7 @@ Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type,
bool bool
Volume::CheckForLiveQuery(const char* attribute) Volume::CheckForLiveQuery(const char* attribute)
{ {
// ToDo: check for a live query that depends on the specified attribute // TODO: check for a live query that depends on the specified attribute
return true; return true;
} }
+1 -4
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
* Parts of this code is based on work previously done by Marcus Overhagen. * Parts of this code is based on work previously done by Marcus Overhagen.
* *
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
@@ -18,9 +18,6 @@
namespace BFS { namespace BFS {
#endif #endif
// ToDo: temporary fix! (missing but public ioctls)
#define IOCTL_FILE_UNCACHED_IO 10000
#ifndef _BOOT_MODE #ifndef _BOOT_MODE
extern fs_volume_ops gBFSVolumeOps; extern fs_volume_ops gBFSVolumeOps;
extern fs_vnode_ops gBFSVnodeOps; extern fs_vnode_ops gBFSVnodeOps;
@@ -1,5 +1,5 @@
/* /*
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef BFS_ENDIAN_H #ifndef BFS_ENDIAN_H
@@ -35,7 +35,7 @@
# define HOST_ENDIAN_TO_BFS_INT32(value) __swap_int32(value) # define HOST_ENDIAN_TO_BFS_INT32(value) __swap_int32(value)
# define HOST_ENDIAN_TO_BFS_INT64(value) __swap_int64(value) # define HOST_ENDIAN_TO_BFS_INT64(value) __swap_int64(value)
#else #else
// ToDo: maybe build a version that supports both, big & little endian? // TODO: maybe build a version that supports both, big & little endian?
// But since that will need some kind of global data (to // But since that will need some kind of global data (to
// know of what type this file system is), it's probably // know of what type this file system is), it's probably
// something for the boot loader; anything else would be // something for the boot loader; anything else would be