Rearranged some code in the BlockAllocator; AllocationGroup now has Allocate()
and Free() methods which operate on the AllocationBlocks. BlockAllocator::AllocateBlocks() couldn't correctly reserve space for allocation groups with more than 2 blocks - AllocationGroup::Allocate() now can, which is now used by AllocateBlocks() (but it's slightly less fast). Began implementing functionality for a chkbfs-like command. Some style changes. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1603 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
// Things the BlockAllocator should do:
|
// Things the BlockAllocator should do:
|
||||||
|
|
||||||
// - find a range of blocks of a certain size nearby a specific position
|
// - find a range of blocks of a certain size nearby a specific position
|
||||||
// - allocating a unsharp range of blocks for pre-allocation
|
// - allocating an unsharp range of blocks for pre-allocation
|
||||||
// - free blocks
|
// - free blocks
|
||||||
// - know how to deal with each allocation, special handling for directories,
|
// - know how to deal with each allocation, special handling for directories,
|
||||||
// files, symlinks, etc. (type sensitive allocation policies)
|
// files, symlinks, etc. (type sensitive allocation policies)
|
||||||
@@ -31,10 +31,9 @@
|
|||||||
// group can span several blocks in the block bitmap, the AllocationBlock
|
// group can span several blocks in the block bitmap, the AllocationBlock
|
||||||
// class is there to make handling those easier.
|
// class is there to make handling those easier.
|
||||||
|
|
||||||
// The current implementation is very basic and will be heavily optimized
|
// The current implementation is only slightly optimized and could probably
|
||||||
// in the future.
|
// be improved a lot. Furthermore, the allocation policies used here should
|
||||||
// Furthermore, the allocation policies used here (when they will be in place)
|
// have some real world tests.
|
||||||
// should have some real world tests.
|
|
||||||
|
|
||||||
|
|
||||||
class AllocationBlock : public CachedBlock {
|
class AllocationBlock : public CachedBlock {
|
||||||
@@ -61,6 +60,9 @@ class 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 Free(Transaction *transaction, uint16 start, int32 length);
|
||||||
|
|
||||||
int32 fNumBits;
|
int32 fNumBits;
|
||||||
int32 fStart;
|
int32 fStart;
|
||||||
int32 fFirstFree, fLargest, fLargestFirst;
|
int32 fFirstFree, fLargest, fLargestFirst;
|
||||||
@@ -105,7 +107,9 @@ AllocationBlock::Allocate(uint16 start,uint16 numBlocks)
|
|||||||
// allocate all blocks after "start"
|
// allocate all blocks after "start"
|
||||||
numBlocks = fNumBits - start;
|
numBlocks = fNumBits - start;
|
||||||
} else if (start + numBlocks > fNumBits) {
|
} else if (start + numBlocks > fNumBits) {
|
||||||
FATAL(("should allocate more blocks than there are in a block!\n"));
|
FATAL(("Allocation::Allocate(): tried to allocate too many blocks: %u (numBlocks = %u)!\n", numBlocks, fNumBits));
|
||||||
|
DEBUGGER(("Allocation::Allocate(): tried to allocate too many blocks"));
|
||||||
|
|
||||||
numBlocks = fNumBits - start;
|
numBlocks = fNumBits - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +134,9 @@ AllocationBlock::Free(uint16 start,uint16 numBlocks)
|
|||||||
// free all blocks after "start"
|
// free all blocks after "start"
|
||||||
numBlocks = fNumBits - start;
|
numBlocks = fNumBits - start;
|
||||||
} else if (start + numBlocks > fNumBits) {
|
} else if (start + numBlocks > fNumBits) {
|
||||||
FATAL(("should free more blocks than there are in a block!\n"));
|
FATAL(("Allocation::Free(): tried to free too many blocks: %u (numBlocks = %u)!\n", numBlocks, fNumBits));
|
||||||
|
DEBUGGER(("Allocation::Free(): tried to free too many blocks"));
|
||||||
|
|
||||||
numBlocks = fNumBits - start;
|
numBlocks = fNumBits - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,13 +184,85 @@ AllocationGroup::AddFreeRange(int32 start, int32 blocks)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Allocates the specified run in the allocation group.
|
||||||
|
* Doesn't check if the run is valid or already allocated
|
||||||
|
* partially, nor does it maintain the free ranges hints
|
||||||
|
* or the volume's used blocks count.
|
||||||
|
* It only does the low-level work of allocating some bits
|
||||||
|
* in the block bitmap.
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AllocationGroup::Allocate(Transaction *transaction, uint16 start, int32 length)
|
||||||
|
{
|
||||||
|
Volume *volume = transaction->GetVolume();
|
||||||
|
uint32 block = start / (volume->BlockSize() << 3);
|
||||||
|
AllocationBlock cached(volume);
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
if (cached.SetTo(*this, block) < B_OK)
|
||||||
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
|
uint32 numBlocks = length;
|
||||||
|
if (start + numBlocks > cached.NumBlockBits())
|
||||||
|
numBlocks = cached.NumBlockBits() - start;
|
||||||
|
|
||||||
|
cached.Allocate(start, numBlocks);
|
||||||
|
|
||||||
|
if (cached.WriteBack(transaction) < B_OK)
|
||||||
|
return B_IO_ERROR;
|
||||||
|
|
||||||
|
length -= numBlocks;
|
||||||
|
start = 0;
|
||||||
|
block++;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Frees the specified run in the allocation group.
|
||||||
|
* Doesn't check if the run is valid or was not completely
|
||||||
|
* allocated, nor does it maintain the free ranges hints
|
||||||
|
* or the volume's used blocks count.
|
||||||
|
* It only does the low-level work of freeing some bits
|
||||||
|
* in the block bitmap.
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AllocationGroup::Free(Transaction *transaction, uint16 start, int32 length)
|
||||||
|
{
|
||||||
|
Volume *volume = transaction->GetVolume();
|
||||||
|
uint32 block = start / (volume->BlockSize() << 3);
|
||||||
|
AllocationBlock cached(volume);
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
if (cached.SetTo(*this, block) < B_OK)
|
||||||
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
|
uint16 freeLength = length;
|
||||||
|
if (start + length > cached.NumBlockBits())
|
||||||
|
freeLength = cached.NumBlockBits() - start;
|
||||||
|
|
||||||
|
cached.Free(start, freeLength);
|
||||||
|
|
||||||
|
if (cached.WriteBack(transaction) < B_OK)
|
||||||
|
return B_IO_ERROR;
|
||||||
|
|
||||||
|
length -= freeLength;
|
||||||
|
start = 0;
|
||||||
|
block++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
BlockAllocator::BlockAllocator(Volume *volume)
|
BlockAllocator::BlockAllocator(Volume *volume)
|
||||||
:
|
:
|
||||||
fVolume(volume),
|
fVolume(volume),
|
||||||
fGroups(NULL)
|
fGroups(NULL),
|
||||||
|
fCheckBitmap(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +285,8 @@ BlockAllocator::Initialize()
|
|||||||
if (fGroups == NULL)
|
if (fGroups == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::initialize,"bfs block allocator",B_LOW_PRIORITY,(void *)this);
|
thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::initialize,
|
||||||
|
"bfs block allocator", B_LOW_PRIORITY, (void *)this);
|
||||||
if (id < B_OK)
|
if (id < B_OK)
|
||||||
return initialize(this);
|
return initialize(this);
|
||||||
|
|
||||||
@@ -265,6 +344,20 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
|||||||
}
|
}
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
|
// check if block bitmap and log area are reserved
|
||||||
|
uint32 reservedBlocks = volume->Log().start + volume->Log().length;
|
||||||
|
if (allocator->CheckBlockRun(block_run::Run(0, 0, reservedBlocks)) < B_OK) {
|
||||||
|
Transaction transaction(volume, 0);
|
||||||
|
if (groups[0].Allocate(&transaction, 0, reservedBlocks) < B_OK) {
|
||||||
|
FATAL(("could not allocate reserved space for block bitmap/log!\n"));
|
||||||
|
volume->Panic();
|
||||||
|
} else {
|
||||||
|
FATAL(("space for block bitmap or log area was not reserved!\n"));
|
||||||
|
|
||||||
|
transaction.Done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
off_t usedBlocks = volume->NumBlocks() - freeBlocks;
|
off_t usedBlocks = volume->NumBlocks() - freeBlocks;
|
||||||
if (volume->UsedBlocks() != usedBlocks) {
|
if (volume->UsedBlocks() != usedBlocks) {
|
||||||
// If the disk in a dirty state at mount time, it's
|
// If the disk in a dirty state at mount time, it's
|
||||||
@@ -278,7 +371,8 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start,uint16 maximum,uint16 minimum, block_run &run)
|
BlockAllocator::AllocateBlocks(Transaction *transaction, int32 group, uint16 start,
|
||||||
|
uint16 maximum, uint16 minimum, block_run &run)
|
||||||
{
|
{
|
||||||
if (maximum == 0)
|
if (maximum == 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -320,7 +414,7 @@ BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start
|
|||||||
// (one allocation can't exceed one allocation group)
|
// (one allocation can't exceed one allocation group)
|
||||||
|
|
||||||
uint32 block = start / (fVolume->BlockSize() << 3);
|
uint32 block = start / (fVolume->BlockSize() << 3);
|
||||||
int32 range = 0, rangeStart = 0,rangeBlock = 0;
|
int32 range = 0, rangeStart = 0;
|
||||||
|
|
||||||
for (;block < fBlocksPerGroup;block++) {
|
for (;block < fBlocksPerGroup;block++) {
|
||||||
if (cached.SetTo(fGroups[group], block) < B_OK)
|
if (cached.SetTo(fGroups[group], block) < B_OK)
|
||||||
@@ -332,7 +426,6 @@ BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start
|
|||||||
if (range == 0) {
|
if (range == 0) {
|
||||||
// start new range
|
// start new range
|
||||||
rangeStart = block * cached.NumBlockBits() + bit;
|
rangeStart = block * cached.NumBlockBits() + bit;
|
||||||
rangeBlock = block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// have we found a range large enough to hold numBlocks?
|
// have we found a range large enough to hold numBlocks?
|
||||||
@@ -360,21 +453,9 @@ BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start
|
|||||||
fGroups[group].fFirstFree = rangeStart + numBlocks;
|
fGroups[group].fFirstFree = rangeStart + numBlocks;
|
||||||
fGroups[group].fFreeBits -= numBlocks;
|
fGroups[group].fFreeBits -= numBlocks;
|
||||||
|
|
||||||
if (block != rangeBlock) {
|
if (fGroups[group].Allocate(transaction, rangeStart, numBlocks) < B_OK)
|
||||||
// allocate the part that's in the current block
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
cached.Allocate(0, (rangeStart + numBlocks) % cached.NumBlockBits());
|
|
||||||
if (cached.WriteBack(transaction) < B_OK)
|
|
||||||
RETURN_ERROR(B_ERROR);
|
|
||||||
|
|
||||||
// set the blocks in the previous block
|
|
||||||
if (cached.SetTo(fGroups[group], block - 1) < B_OK)
|
|
||||||
RETURN_ERROR(B_ERROR);
|
|
||||||
|
|
||||||
cached.Allocate(rangeStart);
|
|
||||||
} else {
|
|
||||||
// just allocate the bits in the current block
|
|
||||||
cached.Allocate(rangeStart,numBlocks);
|
|
||||||
}
|
|
||||||
run.allocation_group = group;
|
run.allocation_group = group;
|
||||||
run.start = rangeStart;
|
run.start = rangeStart;
|
||||||
run.length = numBlocks;
|
run.length = numBlocks;
|
||||||
@@ -386,7 +467,7 @@ BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start
|
|||||||
// If the value is not correct at mount time, it will be
|
// If the value is not correct at mount time, it will be
|
||||||
// fixed anyway.
|
// fixed anyway.
|
||||||
|
|
||||||
return cached.WriteBack(transaction);
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start from the beginning of the next block
|
// start from the beginning of the next block
|
||||||
@@ -484,12 +565,14 @@ BlockAllocator::Free(Transaction *transaction, block_run run)
|
|||||||
|| start > fGroups[group].fNumBits
|
|| start > fGroups[group].fNumBits
|
||||||
|| start + length > fGroups[group].fNumBits
|
|| start + length > fGroups[group].fNumBits
|
||||||
|| length == 0) {
|
|| length == 0) {
|
||||||
FATAL(("someone tried to free an invalid block_run (%ld, %u, %u)\n",group,start,length));
|
FATAL(("tried to free an invalid block_run (%ld, %u, %u)\n", group, start, length));
|
||||||
|
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 drive
|
||||||
if (group == 0 && start < fVolume->Log().start + fVolume->Log().length) {
|
if (group == 0 && start < fVolume->Log().start + fVolume->Log().length) {
|
||||||
FATAL(("someone tried to free a reserved block_run (%ld, %u, %u)\n",group,start,length));
|
FATAL(("tried to free a reserved block_run (%ld, %u, %u)\n", group, start, length));
|
||||||
|
DEBUGGER(("tried to free reserved block"));
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -497,40 +580,47 @@ BlockAllocator::Free(Transaction *transaction, block_run run)
|
|||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AllocationBlock cached(fVolume);
|
|
||||||
|
|
||||||
uint32 block = run.start / (fVolume->BlockSize() << 3);
|
|
||||||
|
|
||||||
if (fGroups[group].fFirstFree > start)
|
if (fGroups[group].fFirstFree > start)
|
||||||
fGroups[group].fFirstFree = start;
|
fGroups[group].fFirstFree = start;
|
||||||
fGroups[group].fFreeBits += length;
|
fGroups[group].fFreeBits += length;
|
||||||
|
|
||||||
for (;block < fBlocksPerGroup;block++) {
|
if (fGroups[group].Free(transaction, start, length) < B_OK)
|
||||||
if (cached.SetTo(fGroups[group],block) < B_OK)
|
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
uint16 freeLength = length;
|
|
||||||
if (start + length > cached.NumBlockBits())
|
|
||||||
freeLength = cached.NumBlockBits() - start;
|
|
||||||
|
|
||||||
cached.Free(start,freeLength);
|
|
||||||
|
|
||||||
if (cached.WriteBack(transaction) < B_OK)
|
|
||||||
return B_IO_ERROR;
|
|
||||||
|
|
||||||
length -= freeLength;
|
|
||||||
if (length <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fVolume->SuperBlock().used_blocks -= run.length;
|
fVolume->SuperBlock().used_blocks -= run.length;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#include "BPlusTree.h"
|
status_t
|
||||||
|
BlockAllocator::StartChecking()
|
||||||
|
{
|
||||||
|
status_t status = fLock.Lock();
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
size_t size = fVolume->BlockSize() * fNumGroups * fBlocksPerGroup;
|
||||||
|
fCheckBitmap = (uint32 *)malloc(size);
|
||||||
|
if (fCheckBitmap == NULL) {
|
||||||
|
fLock.Unlock();
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
memset(fCheckBitmap, 0, size);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BlockAllocator::StopChecking()
|
||||||
|
{
|
||||||
|
free(fCheckBitmap);
|
||||||
|
fCheckBitmap = NULL;
|
||||||
|
fLock.Unlock();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BlockAllocator::CheckBlockRun(block_run run)
|
BlockAllocator::CheckBlockRun(block_run run)
|
||||||
@@ -549,7 +639,6 @@ BlockAllocator::CheckBlockRun(block_run run)
|
|||||||
while (pos < run.length && start + pos < cached.NumBlockBits()) {
|
while (pos < run.length && start + pos < cached.NumBlockBits()) {
|
||||||
if (!cached.IsUsed(start + pos)) {
|
if (!cached.IsUsed(start + pos)) {
|
||||||
PRINT(("block_run(%ld,%u,%u) is only partially allocated!\n", run.allocation_group, run.start, run.length));
|
PRINT(("block_run(%ld,%u,%u) is only partially allocated!\n", run.allocation_group, run.start, run.length));
|
||||||
fVolume->Panic();
|
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
}
|
}
|
||||||
pos++;
|
pos++;
|
||||||
@@ -563,11 +652,14 @@ BlockAllocator::CheckBlockRun(block_run run)
|
|||||||
status_t
|
status_t
|
||||||
BlockAllocator::CheckInode(Inode *inode)
|
BlockAllocator::CheckInode(Inode *inode)
|
||||||
{
|
{
|
||||||
|
if (fCheckBitmap == NULL)
|
||||||
|
return B_NO_INIT;
|
||||||
|
|
||||||
status_t status = CheckBlockRun(inode->BlockRun());
|
status_t status = CheckBlockRun(inode->BlockRun());
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
// only checks the direct range for now...
|
// check the direct range
|
||||||
|
|
||||||
data_stream *data = &inode->Node()->data;
|
data_stream *data = &inode->Node()->data;
|
||||||
for (int32 i = 0;i < NUM_DIRECT_BLOCKS;i++) {
|
for (int32 i = 0;i < NUM_DIRECT_BLOCKS;i++) {
|
||||||
@@ -578,38 +670,48 @@ BlockAllocator::CheckInode(Inode *inode)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
CachedBlock cached(fVolume);
|
||||||
|
|
||||||
status_t
|
// check the indirect range
|
||||||
BlockAllocator::Check(Inode *inode)
|
|
||||||
{
|
|
||||||
if (!inode || !inode->IsDirectory())
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
BPlusTree *tree;
|
if (data->max_indirect_range) {
|
||||||
status_t status = inode->GetTree(&tree);
|
status = CheckBlockRun(data->indirect);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
TreeIterator iterator(tree);
|
off_t block = fVolume->ToBlock(data->indirect);
|
||||||
char key[BPLUSTREE_MAX_KEY_LENGTH];
|
|
||||||
uint16 length;
|
for (int32 i = 0; i < data->indirect.length; i++) {
|
||||||
off_t offset;
|
block_run *runs = (block_run *)cached.SetTo(block + i);
|
||||||
while (iterator.GetNextEntry(key,&length,BPLUSTREE_MAX_KEY_LENGTH,&offset) == B_OK) {
|
if (runs == NULL)
|
||||||
Vnode vnode(fVolume,offset);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
Inode *entry;
|
|
||||||
if (vnode.Get(&entry) < B_OK) {
|
int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
|
||||||
FATAL(("could not get inode in tree at: %Ld\n",offset));
|
int32 index = 0;
|
||||||
continue;
|
for (; index < runsPerBlock; index++) {
|
||||||
}
|
if (runs[index].IsZero())
|
||||||
block_run run = entry->BlockRun();
|
break;
|
||||||
PRINT(("check allocations of inode \"%s\" (%ld,%u,%u)\n",key,run.allocation_group,run.start,run.length));
|
|
||||||
status = CheckInode(entry);
|
status = CheckBlockRun(runs[index]);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
if (index < runsPerBlock)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the double indirect range
|
||||||
|
|
||||||
|
if (data->max_double_indirect_range) {
|
||||||
|
status = CheckBlockRun(data->double_indirect);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
#endif /* DEBUG */
|
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ struct disk_super_block;
|
|||||||
struct block_run;
|
struct block_run;
|
||||||
|
|
||||||
|
|
||||||
|
struct check_result {
|
||||||
|
int8 type;
|
||||||
|
uint64 missing_blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class BlockAllocator {
|
class BlockAllocator {
|
||||||
public:
|
public:
|
||||||
BlockAllocator(Volume *volume);
|
BlockAllocator(Volume *volume);
|
||||||
@@ -31,11 +37,11 @@ class BlockAllocator {
|
|||||||
|
|
||||||
status_t AllocateBlocks(Transaction *transaction,int32 group, uint16 start, uint16 numBlocks, uint16 minimum, block_run &run);
|
status_t AllocateBlocks(Transaction *transaction,int32 group, uint16 start, uint16 numBlocks, uint16 minimum, block_run &run);
|
||||||
|
|
||||||
#ifdef DEBUG
|
status_t StartChecking();
|
||||||
|
status_t StopChecking();
|
||||||
|
|
||||||
status_t CheckBlockRun(block_run run);
|
status_t CheckBlockRun(block_run run);
|
||||||
status_t CheckInode(Inode *inode);
|
status_t CheckInode(Inode *inode/*, bool fix, check_result &result, uint32 numResults*/);
|
||||||
status_t Check(Inode *inode);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static status_t initialize(BlockAllocator *);
|
static status_t initialize(BlockAllocator *);
|
||||||
@@ -44,6 +50,7 @@ class BlockAllocator {
|
|||||||
Benaphore fLock;
|
Benaphore fLock;
|
||||||
AllocationGroup *fGroups;
|
AllocationGroup *fGroups;
|
||||||
int32 fNumGroups, fBlocksPerGroup;
|
int32 fNumGroups, fBlocksPerGroup;
|
||||||
|
uint32 *fCheckBitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* BLOCK_ALLOCATOR_H */
|
#endif /* BLOCK_ALLOCATOR_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user