* 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:
@@ -40,7 +39,7 @@
namespace BFSBlockTracing { namespace BFSBlockTracing {
class Allocate : public AbstractTraceEntry { class Allocate : public AbstractTraceEntry {
public: public:
Allocate(block_run run) Allocate(block_run run)
: :
fRun(run) fRun(run)
@@ -54,12 +53,12 @@ class Allocate : public AbstractTraceEntry {
fRun.Start(), fRun.Length()); fRun.Start(), fRun.Length());
} }
private: private:
block_run fRun; block_run fRun;
}; };
class Free : public AbstractTraceEntry { class Free : public AbstractTraceEntry {
public: public:
Free(block_run run) Free(block_run run)
: :
fRun(run) fRun(run)
@@ -73,15 +72,15 @@ class Free : public AbstractTraceEntry {
fRun.Start(), fRun.Length()); fRun.Start(), fRun.Length());
} }
private: private:
block_run fRun; block_run fRun;
}; };
static uint32 static uint32
checksum(const uint8 *data, size_t size) checksum(const uint8* data, size_t size)
{ {
const uint32 *data4 = (const uint32 *)data; const uint32* data4 = (const uint32*)data;
uint32 sum = 0; uint32 sum = 0;
while (size >= 4) { while (size >= 4) {
sum += *data4; sum += *data4;
@@ -93,8 +92,8 @@ checksum(const uint8 *data, size_t size)
class Block : public AbstractTraceEntry { class Block : public AbstractTraceEntry {
public: public:
Block(const char *label, off_t blockNumber, const uint8 *data, Block(const char* label, off_t blockNumber, const uint8* data,
size_t size, uint32 start = 0, uint32 length = 0) size_t size, uint32 start = 0, uint32 length = 0)
: :
fBlock(blockNumber), fBlock(blockNumber),
@@ -113,7 +112,7 @@ class Block : public AbstractTraceEntry {
fBlock, fData, fSum, fStart, fLength); fBlock, fData, fSum, fStart, fLength);
} }
private: private:
off_t fBlock; off_t fBlock;
const uint8 *fData; const uint8 *fData;
uint32 fStart; uint32 fStart;
@@ -142,21 +141,22 @@ struct check_cookie {
class AllocationBlock : public CachedBlock { class AllocationBlock : public CachedBlock {
public: public:
AllocationBlock(Volume *volume); AllocationBlock(Volume* volume);
void Allocate(uint16 start, uint16 numBlocks); void Allocate(uint16 start, uint16 numBlocks);
void Free(uint16 start, uint16 numBlocks); void Free(uint16 start, uint16 numBlocks);
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]; }
uint8 *Block() const { return (uint8 *)fBlock; } uint8* Block() const { return (uint8*)fBlock; }
private: private:
uint32 fNumBits; uint32 fNumBits;
#ifdef DEBUG #ifdef DEBUG
bool fWritable; bool fWritable;
@@ -165,39 +165,40 @@ class AllocationBlock : public CachedBlock {
class AllocationGroup { class AllocationGroup {
public: public:
AllocationGroup(); AllocationGroup();
void AddFreeRange(int32 start, int32 blocks); void AddFreeRange(int32 start, int32 blocks);
bool IsFull() const { return fFreeBits == 0; } bool IsFull() const { return fFreeBits == 0; }
status_t Allocate(Transaction &transaction, uint16 start, int32 length); status_t Allocate(Transaction& transaction, uint16 start, int32 length);
status_t Free(Transaction &transaction, uint16 start, int32 length); status_t Free(Transaction& transaction, uint16 start, int32 length);
uint32 NumBits() const { return fNumBits; } uint32 NumBits() const { return fNumBits; }
uint32 NumBlocks() const { return fNumBlocks; } uint32 NumBlocks() const { return fNumBlocks; }
int32 Start() const { return fStart; } int32 Start() const { return fStart; }
private: private:
friend class BlockAllocator; friend class BlockAllocator;
uint32 fNumBits; uint32 fNumBits;
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;
}; };
AllocationBlock::AllocationBlock(Volume *volume) AllocationBlock::AllocationBlock(Volume* volume)
: CachedBlock(volume) : CachedBlock(volume)
{ {
} }
status_t status_t
AllocationBlock::SetTo(AllocationGroup &group, uint16 block) AllocationBlock::SetTo(AllocationGroup& group, uint16 block)
{ {
// 8 blocks per byte // 8 blocks per byte
fNumBits = fVolume->BlockSize() << 3; fNumBits = fVolume->BlockSize() << 3;
@@ -213,7 +214,7 @@ AllocationBlock::SetTo(AllocationGroup &group, uint16 block)
status_t status_t
AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group, AllocationBlock::SetToWritable(Transaction& transaction, AllocationGroup& group,
uint16 block) uint16 block)
{ {
// 8 blocks per byte // 8 blocks per byte
@@ -266,7 +267,7 @@ AllocationBlock::Allocate(uint16 start, uint16 numBlocks)
mask |= 1UL << i; mask |= 1UL << i;
#ifdef DEBUG #ifdef DEBUG
// check for already set blocks // check for already set blocks
if (HOST_ENDIAN_TO_BFS_INT32(mask) & ((uint32 *)fBlock)[block]) { if (HOST_ENDIAN_TO_BFS_INT32(mask) & ((uint32*)fBlock)[block]) {
FATAL(("AllocationBlock::Allocate(): some blocks are already allocated, start = %u, numBlocks = %u\n", start, numBlocks)); FATAL(("AllocationBlock::Allocate(): some blocks are already allocated, start = %u, numBlocks = %u\n", start, numBlocks));
DEBUGGER(("blocks already set!")); DEBUGGER(("blocks already set!"));
} }
@@ -348,19 +349,19 @@ AllocationGroup::AddFreeRange(int32 start, int32 blocks)
Assumes that the block bitmap lock is hold. Assumes that the block bitmap lock is hold.
*/ */
status_t status_t
AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length) AllocationGroup::Allocate(Transaction& transaction, uint16 start, int32 length)
{ {
if (start > fNumBits) if (start > fNumBits)
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;
fFreeBits -= length; fFreeBits -= length;
Volume *volume = transaction.GetVolume(); Volume* volume = transaction.GetVolume();
// calculate block in the block bitmap and position within // calculate block in the block bitmap and position within
uint32 bitsPerBlock = volume->BlockSize() << 3; uint32 bitsPerBlock = volume->BlockSize() << 3;
@@ -395,18 +396,18 @@ AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length)
Assumes that the block bitmap lock is hold. Assumes that the block bitmap lock is hold.
*/ */
status_t status_t
AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length) AllocationGroup::Free(Transaction& transaction, uint16 start, int32 length)
{ {
if (start > fNumBits) if (start > fNumBits)
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;
Volume *volume = transaction.GetVolume(); Volume* volume = transaction.GetVolume();
// calculate block in the block bitmap and position within // calculate block in the block bitmap and position within
uint32 bitsPerBlock = volume->BlockSize() << 3; uint32 bitsPerBlock = volume->BlockSize() << 3;
@@ -438,7 +439,7 @@ AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length)
// #pragma mark - // #pragma mark -
BlockAllocator::BlockAllocator(Volume *volume) BlockAllocator::BlockAllocator(Volume* volume)
: :
fVolume(volume), fVolume(volume),
fGroups(NULL), fGroups(NULL),
@@ -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);
@@ -482,7 +483,7 @@ BlockAllocator::Initialize(bool full)
status_t status_t
BlockAllocator::InitializeAndClearBitmap(Transaction &transaction) BlockAllocator::InitializeAndClearBitmap(Transaction& transaction)
{ {
status_t status = Initialize(false); status_t status = Initialize(false);
if (status < B_OK) if (status < B_OK)
@@ -492,7 +493,7 @@ BlockAllocator::InitializeAndClearBitmap(Transaction &transaction)
uint32 numBits = 8 * blocks * fVolume->BlockSize(); uint32 numBits = 8 * blocks * fVolume->BlockSize();
uint32 blockShift = fVolume->BlockShift(); uint32 blockShift = fVolume->BlockShift();
uint32 *buffer = (uint32 *)malloc(numBits >> 3); uint32* buffer = (uint32*)malloc(numBits >> 3);
if (buffer == NULL) if (buffer == NULL)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
@@ -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,29 +532,30 @@ 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;
} }
status_t status_t
BlockAllocator::_Initialize(BlockAllocator *allocator) BlockAllocator::_Initialize(BlockAllocator* allocator)
{ {
// The lock must already be held at this point // The lock must already be held at this point
Volume *volume = allocator->fVolume; Volume* volume = allocator->fVolume;
uint32 blocks = allocator->fBlocksPerGroup; uint32 blocks = allocator->fBlocksPerGroup;
uint32 blockShift = volume->BlockShift(); uint32 blockShift = volume->BlockShift();
off_t freeBlocks = 0; off_t freeBlocks = 0;
uint32 *buffer = (uint32 *)malloc(blocks << blockShift); uint32* buffer = (uint32*)malloc(blocks << blockShift);
if (buffer == NULL) { if (buffer == NULL) {
mutex_unlock(&allocator->fLock); mutex_unlock(&allocator->fLock);
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
} }
AllocationGroup *groups = allocator->fGroups; AllocationGroup* groups = allocator->fGroups;
off_t offset = 1; off_t offset = 1;
uint32 bitsPerGroup = 8 * (blocks << blockShift); uint32 bitsPerGroup = 8 * (blocks << blockShift);
int32 numGroups = allocator->fNumGroups; int32 numGroups = allocator->fNumGroups;
@@ -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;
@@ -636,8 +641,8 @@ BlockAllocator::Uninitialize()
status_t status_t
BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, BlockAllocator::AllocateBlocks(Transaction& transaction, int32 group,
uint16 start, uint16 maximum, uint16 minimum, block_run &run) uint16 start, uint16 maximum, uint16 minimum, block_run& run)
{ {
if (maximum == 0) if (maximum == 0)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -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);
@@ -752,15 +761,16 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
status_t 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) {
@@ -828,7 +839,7 @@ BlockAllocator::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks
status_t status_t
BlockAllocator::Free(Transaction &transaction, block_run run) BlockAllocator::Free(Transaction& transaction, block_run run)
{ {
MutexLocker lock(fLock); MutexLocker lock(fLock);
@@ -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,13 +899,16 @@ 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
BlockAllocator::_IsValidCheckControl(check_control *control) BlockAllocator::_IsValidCheckControl(check_control* control)
{ {
if (control == NULL if (control == NULL
|| control->magic != BFS_IOCTL_CHECK_MAGIC) { || control->magic != BFS_IOCTL_CHECK_MAGIC) {
@@ -900,7 +921,7 @@ BlockAllocator::_IsValidCheckControl(check_control *control)
status_t status_t
BlockAllocator::StartChecking(check_control *control) BlockAllocator::StartChecking(check_control* control)
{ {
if (!_IsValidCheckControl(control)) if (!_IsValidCheckControl(control))
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -910,13 +931,13 @@ BlockAllocator::StartChecking(check_control *control)
return status; return status;
size_t size = BitmapSize(); size_t size = BitmapSize();
fCheckBitmap = (uint32 *)malloc(size); fCheckBitmap = (uint32*)malloc(size);
if (fCheckBitmap == NULL) { if (fCheckBitmap == NULL) {
mutex_unlock(&fLock); mutex_unlock(&fLock);
return B_NO_MEMORY; return B_NO_MEMORY;
} }
check_cookie *cookie = new check_cookie(); check_cookie* cookie = new check_cookie();
if (cookie == NULL) { if (cookie == NULL) {
free(fCheckBitmap); free(fCheckBitmap);
fCheckBitmap = NULL; fCheckBitmap = NULL;
@@ -940,20 +961,20 @@ 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;
} }
status_t status_t
BlockAllocator::StopChecking(check_control *control) BlockAllocator::StopChecking(check_control* control)
{ {
check_cookie *cookie; check_cookie* cookie;
if (control == NULL) if (control == NULL)
cookie = fCheckCookie; cookie = fCheckCookie;
else else
cookie = (check_cookie *)control->cookie; cookie = (check_cookie*)control->cookie;
if (cookie == NULL) if (cookie == NULL)
return B_ERROR; return B_ERROR;
@@ -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();
@@ -1007,7 +1029,7 @@ BlockAllocator::StopChecking(check_control *control)
blocksToWrite = blocksInBitmap - i; blocksToWrite = blocksInBitmap - i;
status_t status = transaction.WriteBlocks(1 + i, status_t status = transaction.WriteBlocks(1 + i,
(uint8 *)fCheckBitmap + i * blockSize, blocksToWrite); (uint8*)fCheckBitmap + i * blockSize, blocksToWrite);
if (status < B_OK) { if (status < B_OK) {
FATAL(("error writing bitmap: %s\n", strerror(status))); FATAL(("error writing bitmap: %s\n", strerror(status)));
break; break;
@@ -1029,12 +1051,12 @@ BlockAllocator::StopChecking(check_control *control)
status_t status_t
BlockAllocator::CheckNextNode(check_control *control) BlockAllocator::CheckNextNode(check_control* control)
{ {
if (!_IsValidCheckControl(control)) if (!_IsValidCheckControl(control))
return B_BAD_VALUE; return B_BAD_VALUE;
check_cookie *cookie = (check_cookie *)control->cookie; check_cookie* cookie = (check_cookie*)control->cookie;
while (true) { while (true) {
if (cookie->iterator == NULL) { if (cookie->iterator == NULL) {
@@ -1047,20 +1069,23 @@ BlockAllocator::CheckNextNode(check_control *control)
// get iterator for the next directory // get iterator for the next directory
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;
@@ -1112,7 +1138,7 @@ BlockAllocator::CheckNextNode(check_control *control)
control->errors = 0; control->errors = 0;
Vnode vnode(fVolume, id); Vnode vnode(fVolume, id);
Inode *inode; Inode* inode;
if (vnode.Get(&inode) < B_OK) { if (vnode.Get(&inode) < B_OK) {
FATAL(("Could not open inode ID %Ld!\n", id)); FATAL(("Could not open inode ID %Ld!\n", id));
control->errors |= BFS_COULD_NOT_OPEN; control->errors |= BFS_COULD_NOT_OPEN;
@@ -1125,10 +1151,11 @@ BlockAllocator::CheckNextNode(check_control *control)
RecursiveLocker locker(inode->SmallDataLock()); RecursiveLocker locker(inode->SmallDataLock());
NodeGetter node(fVolume, inode); NodeGetter node(fVolume, inode);
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));
}
} }
} }
@@ -1296,7 +1348,7 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
status_t status_t
BlockAllocator::CheckInode(Inode *inode, check_control *control) BlockAllocator::CheckInode(Inode* inode, check_control* control)
{ {
if (control != NULL && fCheckBitmap == NULL) if (control != NULL && fCheckBitmap == NULL)
return B_NO_INIT; return B_NO_INIT;
@@ -1315,7 +1367,7 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
return B_OK; return B_OK;
} }
data_stream *data = &inode->Node().data; data_stream* data = &inode->Node().data;
// check the direct range // check the direct range
@@ -1342,7 +1394,7 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
off_t block = fVolume->ToBlock(data->indirect); off_t block = fVolume->ToBlock(data->indirect);
for (int32 i = 0; i < data->indirect.Length(); i++) { for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run *runs = (block_run *)cached.SetTo(block + i); block_run* runs = (block_run*)cached.SetTo(block + i);
if (runs == NULL) if (runs == NULL)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(B_IO_ERROR);
@@ -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);
@@ -1445,7 +1502,7 @@ BlockAllocator::Dump(int32 index)
int int
dump_block_allocator(int argc, char **argv) dump_block_allocator(int argc, char** argv)
{ {
int32 group = -1; int32 group = -1;
if (argc == 3) { if (argc == 3) {
@@ -1458,8 +1515,8 @@ dump_block_allocator(int argc, char **argv)
return 0; return 0;
} }
Volume *volume = (Volume *)parse_expression(argv[1]); Volume* volume = (Volume*)parse_expression(argv[1]);
BlockAllocator &allocator = volume->Allocator(); BlockAllocator& allocator = volume->Allocator();
allocator.Dump(group); allocator.Dump(group);
return 0; return 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 */
+28 -28
View File
@@ -26,14 +26,14 @@ static const int32 kDesiredAllocationGroups = 56;
class DeviceOpener { class DeviceOpener {
public: public:
DeviceOpener(int fd, int mode); DeviceOpener(int fd, int mode);
DeviceOpener(const char *device, int mode); DeviceOpener(const char* device, int mode);
~DeviceOpener(); ~DeviceOpener();
int Open(const char *device, int mode); int Open(const char* device, int mode);
int Open(int fd, int mode); int Open(int fd, int mode);
void *InitCache(off_t numBlocks, uint32 blockSize); void* InitCache(off_t numBlocks, uint32 blockSize);
void RemoveCache(bool allowWrites); void RemoveCache(bool allowWrites);
void Keep(); void Keep();
@@ -42,9 +42,9 @@ class DeviceOpener {
int Mode() const { return fMode; } int Mode() const { return fMode; }
bool IsReadOnly() const { return _IsReadOnly(fMode); } bool IsReadOnly() const { return _IsReadOnly(fMode); }
status_t GetSize(off_t *_size, uint32 *_blockSize = NULL); status_t GetSize(off_t* _size, uint32* _blockSize = NULL);
private: private:
static bool _IsReadOnly(int mode) static bool _IsReadOnly(int mode)
{ return (mode & O_RWMASK) == O_RDONLY;} { return (mode & O_RWMASK) == O_RDONLY;}
static bool _IsReadWrite(int mode) static bool _IsReadWrite(int mode)
@@ -52,11 +52,11 @@ class DeviceOpener {
int fDevice; int fDevice;
int fMode; int fMode;
void *fBlockCache; void* fBlockCache;
}; };
DeviceOpener::DeviceOpener(const char *device, int mode) DeviceOpener::DeviceOpener(const char* device, int mode)
: :
fBlockCache(NULL) fBlockCache(NULL)
{ {
@@ -82,7 +82,7 @@ DeviceOpener::~DeviceOpener()
int int
DeviceOpener::Open(const char *device, int mode) DeviceOpener::Open(const char* device, int mode)
{ {
fDevice = open(device, mode | O_NOCACHE); fDevice = open(device, mode | O_NOCACHE);
if (fDevice < 0) if (fDevice < 0)
@@ -126,7 +126,7 @@ DeviceOpener::Open(int fd, int mode)
} }
void * void*
DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize) DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize)
{ {
return fBlockCache = block_cache_create(fDevice, numBlocks, blockSize, return fBlockCache = block_cache_create(fDevice, numBlocks, blockSize,
@@ -156,7 +156,7 @@ DeviceOpener::Keep()
to compute the size, or fstat() if that failed. to compute the size, or fstat() if that failed.
*/ */
status_t status_t
DeviceOpener::GetSize(off_t *_size, uint32 *_blockSize) DeviceOpener::GetSize(off_t* _size, uint32* _blockSize)
{ {
device_geometry geometry; device_geometry geometry;
if (ioctl(fDevice, B_GET_GEOMETRY, &geometry) < 0) { if (ioctl(fDevice, B_GET_GEOMETRY, &geometry) < 0) {
@@ -209,7 +209,7 @@ disk_super_block::IsValid()
void void
disk_super_block::Initialize(const char *diskName, off_t numBlocks, disk_super_block::Initialize(const char* diskName, off_t numBlocks,
uint32 blockSize) uint32 blockSize)
{ {
memset(this, 0, sizeof(disk_super_block)); memset(this, 0, sizeof(disk_super_block));
@@ -272,7 +272,7 @@ disk_super_block::Initialize(const char *diskName, off_t numBlocks,
// #pragma mark - // #pragma mark -
Volume::Volume(fs_volume *volume) Volume::Volume(fs_volume* volume)
: :
fVolume(volume), fVolume(volume),
fBlockAllocator(this), fBlockAllocator(this),
@@ -313,9 +313,9 @@ 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
@@ -385,7 +385,7 @@ Volume::Mount(const char *deviceName, uint32 flags)
fRootNode = new Inode(this, ToVnode(Root())); fRootNode = new Inode(this, ToVnode(Root()));
if (fRootNode != NULL && fRootNode->InitCheck() == B_OK) { if (fRootNode != NULL && fRootNode->InitCheck() == B_OK) {
status = publish_vnode(fVolume, ToVnode(Root()), (void *)fRootNode, status = publish_vnode(fVolume, ToVnode(Root()), (void*)fRootNode,
&gBFSVnodeOps, fRootNode->Mode(), 0); &gBFSVnodeOps, fRootNode->Mode(), 0);
if (status == B_OK) { if (status == B_OK) {
// try to get indices root dir // try to get indices root dir
@@ -482,7 +482,7 @@ Volume::ToBlockRun(off_t block) const
status_t status_t
Volume::CreateIndicesRoot(Transaction &transaction) Volume::CreateIndicesRoot(Transaction& transaction)
{ {
off_t id; off_t id;
status_t status = Inode::Create(transaction, NULL, NULL, status_t status = Inode::Create(transaction, NULL, NULL,
@@ -497,8 +497,8 @@ Volume::CreateIndicesRoot(Transaction &transaction)
status_t status_t
Volume::AllocateForInode(Transaction &transaction, const Inode *parent, Volume::AllocateForInode(Transaction& transaction, const Inode* parent,
mode_t type, block_run &run) mode_t type, block_run& run)
{ {
return fBlockAllocator.AllocateForInode(transaction, &parent->BlockRun(), return fBlockAllocator.AllocateForInode(transaction, &parent->BlockRun(),
type, run); type, run);
@@ -517,13 +517,13 @@ Volume::WriteSuperBlock()
void void
Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type, Volume::UpdateLiveQueries(Inode* inode, const char* attribute, int32 type,
const uint8 *oldKey, size_t oldLength, const uint8 *newKey, const uint8* oldKey, size_t oldLength, const uint8* newKey,
size_t newLength) size_t newLength)
{ {
MutexLocker _(fQueryLock); MutexLocker _(fQueryLock);
Query *query = NULL; Query* query = NULL;
while ((query = fQueries.Next(query)) != NULL) { while ((query = fQueries.Next(query)) != NULL) {
query->LiveUpdate(inode, attribute, type, oldKey, oldLength, newKey, query->LiveUpdate(inode, attribute, type, oldKey, oldLength, newKey,
newLength); newLength);
@@ -537,15 +537,15 @@ Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type,
the queries - it wouldn't safe you anything in this case. the queries - it wouldn't safe you anything in this case.
*/ */
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;
} }
void void
Volume::AddQuery(Query *query) Volume::AddQuery(Query* query)
{ {
MutexLocker _(fQueryLock); MutexLocker _(fQueryLock);
fQueries.Add(query); fQueries.Add(query);
@@ -553,7 +553,7 @@ Volume::AddQuery(Query *query)
void void
Volume::RemoveQuery(Query *query) Volume::RemoveQuery(Query* query)
{ {
MutexLocker _(fQueryLock); MutexLocker _(fQueryLock);
fQueries.Remove(query); fQueries.Remove(query);
@@ -588,7 +588,7 @@ Volume::CheckSuperBlock(const uint8* data, uint32* _offset)
/*static*/ status_t /*static*/ status_t
Volume::Identify(int fd, disk_super_block *superBlock) Volume::Identify(int fd, disk_super_block* superBlock)
{ {
uint8 buffer[1024]; uint8 buffer[1024];
if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer)) if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer))
@@ -604,7 +604,7 @@ Volume::Identify(int fd, disk_super_block *superBlock)
status_t status_t
Volume::Initialize(int fd, const char *name, uint32 blockSize, Volume::Initialize(int fd, const char* name, uint32 blockSize,
uint32 flags) uint32 flags)
{ {
// although there is no really good reason for it, we won't // although there is no really good reason for it, we won't
+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