* added fsblock_t and fileblock_t definitions, used them when needed.

* validate fBlockShift in superblock.
* Volume::AllocateBlocks() now uses an absolute fsblock instead of a blockgroup related fsblock.
* AllocationBlockGroup now provides absolute fsblock values.
* added support for extents feature: ExtentStream class is the equivalent for DataStream class for extent operations.
  The extent tree implementation is very basic, should work for normal growing/shrinking
  operations, but not for sparse files. When enlarging a file and extent tree is full,
  the root is moved in a new block and a new level is added on top. Extents can usually
  be extended when adjacent blocks are allocated. Shrinking happens by removing leafs 
  one after another.
* removed empty IndexedDirectoryIterator.*


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39886 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2010-12-18 16:26:39 +00:00
parent 699dc0e367
commit 45af882d06
26 changed files with 784 additions and 81 deletions
@@ -39,7 +39,7 @@ public:
status_t ScanFreeRanges();
bool IsFull() const;
status_t Allocate(Transaction& transaction, uint32 start,
status_t Allocate(Transaction& transaction, fsblock_t start,
uint32 length);
status_t Free(Transaction& transaction, uint32 start,
uint32 length);
@@ -48,9 +48,9 @@ public:
uint32 NumBits() const;
uint32 FreeBits() const;
uint32 Start() const;
fsblock_t Start() const;
uint32 LargestStart() const;
fsblock_t LargestStart() const;
uint32 LargestLength() const;
// TransactionListener implementation
@@ -70,9 +70,9 @@ private:
mutex fTransactionLock;
int32 fCurrentTransaction;
uint32 fStart;
fsblock_t fStart;
uint32 fNumBits;
off_t fBitmapBlock;
fsblock_t fBitmapBlock;
uint32 fFreeBits;
uint32 fFirstFree;
@@ -122,6 +122,7 @@ AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup,
fVolume = volume;
fBlockGroup = blockGroup;
fNumBits = numBits;
fStart = blockGroup * numBits + fVolume->FirstDataBlock();
status_t status = fVolume->GetBlockGroup(blockGroup, &fGroupDescriptor);
if (status != B_OK)
@@ -187,13 +188,17 @@ AllocationBlockGroup::IsFull() const
status_t
AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
AllocationBlockGroup::Allocate(Transaction& transaction, fsblock_t _start,
uint32 length)
{
uint32 start = _start - fStart;
TRACE("AllocationBlockGroup::Allocate(%ld,%ld)\n", start, length);
if (length == 0)
return B_OK;
uint32 end = start + length;
if (end > fNumBits)
return B_BAD_DATA;
return B_BAD_VALUE;
_LockInTransaction(transaction);
@@ -263,9 +268,8 @@ AllocationBlockGroup::Free(Transaction& transaction, uint32 start,
return B_OK;
uint32 end = start + length;
if (end > fNumBits)
return B_BAD_DATA;
return B_BAD_VALUE;
_LockInTransaction(transaction);
@@ -342,17 +346,17 @@ AllocationBlockGroup::FreeBits() const
}
uint32
fsblock_t
AllocationBlockGroup::Start() const
{
return fStart;
}
uint32
fsblock_t
AllocationBlockGroup::LargestStart() const
{
return fLargestStart;
return fStart + fLargestStart;
}
@@ -457,7 +461,7 @@ BlockAllocator::Initialize()
fNumBlocks = fVolume->NumBlocks();
TRACE("BlockAllocator::Initialize(): blocks per group: %lu, block groups: "
"%lu, first block: %lu, num blocks: %lu\n", fBlocksPerGroup,
"%lu, first block: %llu, num blocks: %llu\n", fBlocksPerGroup,
fNumGroups, fFirstBlock, fNumBlocks);
fGroups = new(std::nothrow) AllocationBlockGroup[fNumGroups];
@@ -486,7 +490,7 @@ BlockAllocator::Initialize()
status_t
BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
uint32 maximum, uint32& blockGroup, off_t& start, uint32& length)
uint32 maximum, uint32& blockGroup, fsblock_t& start, uint32& length)
{
TRACE("BlockAllocator::AllocateBlocks()\n");
MutexLocker lock(fLock);
@@ -496,7 +500,7 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
"max: %lu, block group: %lu, start: %llu, num groups: %lu\n",
transaction.ID(), minimum, maximum, blockGroup, start, fNumGroups);
off_t bestStart = 0;
fsblock_t bestStart = 0;
uint32 bestLength = 0;
uint32 bestGroup = 0;
@@ -567,10 +571,12 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
status_t
BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
off_t numBlocks, uint32 minimum, off_t& start, uint32& allocated)
off_t numBlocks, uint32 minimum, fsblock_t& start, uint32& allocated)
{
if (numBlocks <= 0)
return B_ERROR;
if (start > fNumBlocks)
return B_BAD_VALUE;
uint32 group = inode->ID() / fVolume->InodesPerGroup();
uint32 preferred = 0;
@@ -644,28 +650,32 @@ BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
status_t
BlockAllocator::Free(Transaction& transaction, off_t start, uint32 length)
BlockAllocator::Free(Transaction& transaction, fsblock_t start, uint32 length)
{
TRACE("BlockAllocator::Free(%llu, %lu)\n", start, length);
MutexLocker lock(fLock);
if (start <= fFirstBlock) {
panic("Trying to free superblock!\n");
return B_BAD_DATA;
return B_BAD_VALUE;
}
if (length == 0)
return B_OK;
if (start > fNumBlocks || length > fNumBlocks)
return B_BAD_VALUE;
TRACE("BlockAllocator::Free(): first block: %lu, blocks per group: %lu\n",
TRACE("BlockAllocator::Free(): first block: %llu, blocks per group: %lu\n",
fFirstBlock, fBlocksPerGroup);
start -= fFirstBlock;
off_t end = start + length - 1;
uint32 group = start / fBlocksPerGroup;
if (group >= fNumGroups)
panic("BlockAllocator::Free() group %ld too big (fNumGroups %ld)\n", group, fNumGroups);
if (group >= fNumGroups) {
panic("BlockAllocator::Free() group %ld too big (fNumGroups %ld)\n",
group, fNumGroups);
}
uint32 lastGroup = end / fBlocksPerGroup;
start = start % fBlocksPerGroup;
@@ -8,8 +8,10 @@
#ifndef BLOCKALLOCATOR_H
#define BLOCKALLOCATOR_H
#include <lock.h>
#include "ext2.h"
#include "Transaction.h"
@@ -27,11 +29,11 @@ public:
status_t AllocateBlocks(Transaction& transaction,
uint32 minimum, uint32 maximum, uint32& blockGroup,
off_t& start, uint32& length);
fsblock_t& start, uint32& length);
status_t Allocate(Transaction& transaction, Inode* inode,
off_t numBlocks, uint32 minimum, off_t& start,
off_t numBlocks, uint32 minimum, fsblock_t& start,
uint32& length);
status_t Free(Transaction& transaction, off_t start,
status_t Free(Transaction& transaction, fsblock_t start,
uint32 length);
uint32 FreeBlocks();
@@ -45,9 +47,9 @@ protected:
AllocationBlockGroup* fGroups;
uint32 fBlocksPerGroup;
uint32 fNumBlocks;
fsblock_t fNumBlocks;
uint32 fNumGroups;
uint32 fFirstBlock;
fsblock_t fFirstBlock;
};
#endif // BLOCKALLOCATOR_H
@@ -53,7 +53,7 @@ DataStream::~DataStream()
status_t
DataStream::FindBlock(off_t offset, off_t& block, uint32 *_count)
DataStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
{
uint32 index = offset >> fVolume->BlockShift();
@@ -377,8 +377,7 @@ DataStream::_GetBlock(Transaction& transaction, uint32& blockNum)
if (fAllocated == 0) {
uint32 blockGroup = (fAllocatedPos - fFirstBlock)
/ fVolume->BlocksPerGroup();
fAllocatedPos %= fVolume->BlocksPerGroup();
status_t status = fVolume->AllocateBlocks(transaction, 1, fWaiting,
blockGroup, fAllocatedPos, fAllocated);
if (status != B_OK) {
@@ -387,7 +386,6 @@ DataStream::_GetBlock(Transaction& transaction, uint32& blockNum)
}
fWaiting -= fAllocated;
fAllocatedPos += fVolume->BlocksPerGroup() * blockGroup + fFirstBlock;
TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %llu,"
"newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting);
@@ -8,6 +8,7 @@
#ifndef DATASTREAM_H
#define DATASTREAM_H
#include "ext2.h"
#include "Transaction.h"
@@ -22,7 +23,7 @@ public:
off_t size);
~DataStream();
status_t FindBlock(off_t offset, off_t& block,
status_t FindBlock(off_t offset, fsblock_t& block,
uint32 *_count = NULL);
status_t Enlarge(Transaction& transaction, off_t& numBlocks);
status_t Shrink(Transaction& transaction, off_t& numBlocks);
@@ -82,7 +83,7 @@ private:
uint32 fFirstBlock;
uint32 fAllocated;
off_t fAllocatedPos;
fsblock_t fAllocatedPos;
uint32 fWaiting;
uint32 fFreeStart;
@@ -517,7 +517,7 @@ DirectoryIterator::_SplitIndexedBlock(Transaction& transaction,
return B_NO_MEMORY;
ArrayDeleter<uint8> bufferDeleter(buffer);
off_t firstPhysicalBlock = 0;
fsblock_t firstPhysicalBlock = 0;
// Prepare block to hold the first half of the entries and fill the buffer
CachedBlock cachedFirst(fVolume);
@@ -6,6 +6,8 @@
#define DIRECTORY_ITERATOR_H
#include "ext2.h"
#include <SupportDefs.h>
#include "Transaction.h"
@@ -69,7 +71,7 @@ protected:
uint32 fNumBlocks;
uint32 fLogicalBlock;
off_t fPhysicalBlock;
fsblock_t fPhysicalBlock;
uint32 fDisplacement;
uint32 fPreviousDisplacement;
@@ -0,0 +1,510 @@
/*
* Copyright 2001-2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#include "ExtentStream.h"
#include <string.h>
#include "CachedBlock.h"
#include "Volume.h"
#undef ASSERT
//#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACE(x...) dprintf("\33[34mext2:\33[0m ExtentStream::" x)
# define ASSERT(x) { if (!(x)) kernel_debugger("ext2: assert failed: " #x "\n"); }
#else
# define TRACE(x...) ;
# define ASSERT(x) ;
#endif
#define ERROR(x...) dprintf("\33[34mext2:\33[0m ExtentStream::" x)
ExtentStream::ExtentStream(Volume* volume, ext2_extent_stream* stream,
off_t size)
:
fVolume(volume),
fStream(stream),
fFirstBlock(volume->FirstDataBlock()),
fAllocatedPos(fFirstBlock),
fSize(size)
{
fNumBlocks = size == 0 ? 0 : ((size - 1) >> fVolume->BlockShift()) + 1;
}
ExtentStream::~ExtentStream()
{
}
status_t
ExtentStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
{
fileblock_t index = offset >> fVolume->BlockShift();
TRACE("FindBlock(%lld, %lld)\n", offset, index);
if (offset >= fSize) {
TRACE("FindBlock: offset larger than inode size\n");
return B_ENTRY_NOT_FOUND;
}
ext2_extent_stream *stream = fStream;
if (!stream->extent_header.IsValid())
panic("ExtentStream::FindBlock() invalid header\n");
CachedBlock cached(fVolume);
while (stream->extent_header.Depth() != 0) {
TRACE("FindBlock() depth %d\n",
stream->extent_header.Depth());
int32 i = 1;
while (i < stream->extent_header.NumEntries()
&& stream->extent_index[i].LogicalBlock() <= index) {
i++;
}
TRACE("FindBlock() getting index %ld at %lld\n", i - 1,
stream->extent_index[i - 1].PhysicalBlock());
stream = (ext2_extent_stream *)cached.SetTo(
stream->extent_index[i - 1].PhysicalBlock());
if (!stream->extent_header.IsValid())
panic("ExtentStream::FindBlock() invalid header\n");
}
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
if (stream->extent_entries[i].LogicalBlock() > index) {
// sparse block
TRACE("FindBlock() sparse block index %lld at %ld\n", index,
stream->extent_entries[i].LogicalBlock());
block = 0xffffffff;
return B_OK;
}
fileblock_t diff = index - stream->extent_entries[i].LogicalBlock();
if (diff < stream->extent_entries[i].Length()) {
block = stream->extent_entries[i].PhysicalBlock() + diff;
if (_count)
*_count = stream->extent_entries[i].Length() - diff;
TRACE("FindBlock(offset %lld): %lld %ld\n", offset,
block, _count != NULL ? *_count : 1);
return B_OK;
}
}
return B_ERROR;
}
status_t
ExtentStream::Enlarge(Transaction& transaction, off_t& numBlocks)
{
TRACE("Enlarge(): current size: %llu, target size: %llu\n",
fNumBlocks, numBlocks);
off_t targetBlocks = numBlocks;
numBlocks = targetBlocks - fNumBlocks;
uint32 allocated = 0;
while (fNumBlocks < targetBlocks) {
// allocate new blocks
uint32 blockGroup = (fAllocatedPos - fFirstBlock)
/ fVolume->BlocksPerGroup();
if (allocated == 0) {
status_t status = fVolume->AllocateBlocks(transaction, 1,
targetBlocks - fNumBlocks, blockGroup, fAllocatedPos,
allocated);
if (status != B_OK) {
ERROR("Enlarge(): AllocateBlocks() failed()\n");
return status;
}
}
ASSERT(_CheckBlock(fStream, fAllocatedPos) == B_OK);
ext2_extent_stream *stream = fStream;
fsblock_t path[stream->extent_header.Depth()];
// search for the leaf
CachedBlock cached(fVolume);
int32 level = -1;
for (; stream->extent_header.Depth() != 0;) {
if (stream->extent_header.NumEntries() == 0)
panic("stream->extent_header.NumEntries() == 0\n");
int32 lastIndex = stream->extent_header.NumEntries() - 1;
TRACE("Enlarge() depth %d\n", stream->extent_header.Depth());
TRACE("Enlarge() getting index %ld at %lld\n", lastIndex,
stream->extent_index[lastIndex].PhysicalBlock());
path[++level] = stream->extent_index[lastIndex].PhysicalBlock();
stream = (ext2_extent_stream *)cached.SetTo(path[level]);
if (stream == NULL)
return B_IO_ERROR;
}
// check if the new extent is adjacent
if (stream->extent_header.NumEntries() > 0) {
ext2_extent_entry &last = stream->extent_entries[
stream->extent_header.NumEntries() - 1];
TRACE("Enlarge() last %lld allocatedPos %lld\n",
last.PhysicalBlock() + last.Length(), fAllocatedPos);
if (last.PhysicalBlock() + last.Length() == fAllocatedPos
&& (last.Length() + allocated) <= 0xffff) {
if (stream != fStream) {
stream = (ext2_extent_stream *)cached.SetToWritable(
transaction, cached.BlockNumber());
if (stream == NULL)
return B_IO_ERROR;
}
stream->extent_entries[stream->extent_header.NumEntries() - 1]
.SetLength(last.Length() + allocated);
fNumBlocks += allocated;
allocated = 0;
TRACE("Enlarge() entry extended\n");
continue;
}
}
if (stream->extent_header.NumEntries()
>= stream->extent_header.MaxEntries()) {
TRACE("Enlarge() adding leaf and indexes at depth %d level %ld\n",
stream->extent_header.Depth(), level);
// try to add a leaf and indexes
while (--level >= 0) {
stream = (ext2_extent_stream *)cached.SetTo(path[level]);
if (stream == NULL)
return B_IO_ERROR;
if (stream->extent_header.NumEntries()
< stream->extent_header.MaxEntries()) {
break;
}
TRACE("Enlarge() going up from level %ld\n", level);
}
if (level < 0 && fStream->extent_header.NumEntries()
>= fStream->extent_header.MaxEntries()) {
TRACE("Enlarge() add a level, increment root depth\n");
fsblock_t newBlock = fStream->extent_index[0].PhysicalBlock();
uint32 _allocated;
status_t status = fVolume->AllocateBlocks(transaction, 1, 1,
blockGroup, newBlock, _allocated);
if (status != B_OK) {
ERROR("Enlarge() AllocateBlocks() failed()\n");
return status;
}
ASSERT(_CheckBlock(fStream, newBlock) == B_OK);
TRACE("Enlarge() move root to block %lld\n", newBlock);
numBlocks++;
stream = (ext2_extent_stream *)cached.SetToWritable(
transaction, newBlock);
if (stream == NULL)
return B_IO_ERROR;
ASSERT(fStream->extent_header.IsValid());
memcpy(stream, fStream, sizeof(ext2_extent_stream));
fStream->extent_header.SetDepth(stream->extent_header.Depth()
+ 1);
TRACE("Enlarge() new root depth %d\n",
fStream->extent_header.Depth());
fStream->extent_header.SetNumEntries(1);
fStream->extent_index[0].SetLogicalBlock(0);
fStream->extent_index[0].SetPhysicalBlock(newBlock);
stream->extent_header.SetMaxEntries((fVolume->BlockSize()
- sizeof(ext2_extent_header)) / sizeof(ext2_extent_index));
ASSERT(stream->extent_header.IsValid());
ASSERT(Check());
continue;
}
if (level < 0)
stream = fStream;
uint16 depth = stream->extent_header.Depth();
while (depth > 1) {
TRACE("Enlarge() adding an index block at depth %d\n", depth);
fsblock_t newBlock = path[level];
uint32 _allocated;
status_t status = fVolume->AllocateBlocks(transaction, 1, 1,
blockGroup, newBlock, _allocated);
if (status != B_OK) {
ERROR("Enlarge(): AllocateBlocks() failed()\n");
return status;
}
ASSERT(_CheckBlock(fStream, newBlock) == B_OK);
numBlocks++;
int32 index = stream->extent_header.NumEntries();
stream->extent_index[index].SetLogicalBlock(fNumBlocks);
stream->extent_index[index].SetPhysicalBlock(newBlock);
stream->extent_header.SetNumEntries(index + 1);
path[level++] = newBlock;
depth = stream->extent_header.Depth() - 1;
TRACE("Enlarge() init index block %lld at depth %d\n",
newBlock, depth);
stream = (ext2_extent_stream *)cached.SetToWritable(
transaction, newBlock);
if (stream == NULL)
return B_IO_ERROR;
stream->extent_header.magic = EXT2_EXTENT_MAGIC;
stream->extent_header.SetNumEntries(0);
stream->extent_header.SetMaxEntries((fVolume->BlockSize()
- sizeof(ext2_extent_header)) / sizeof(ext2_extent_index));
stream->extent_header.SetDepth(depth);
stream->extent_header.SetGeneration(0);
ASSERT(Check());
}
TRACE("Enlarge() depth %d level %ld\n",
stream->extent_header.Depth(), level);
if (stream->extent_header.Depth() == 1) {
TRACE("Enlarge() adding an entry block at depth %d level %ld\n",
depth, level);
fsblock_t newBlock;
if (level >= 0)
newBlock = path[level];
else
newBlock = fStream->extent_index[0].PhysicalBlock();
uint32 _allocated;
status_t status = fVolume->AllocateBlocks(transaction, 1, 1,
blockGroup, newBlock, _allocated);
if (status != B_OK) {
ERROR("Enlarge(): AllocateBlocks() failed()\n");
return status;
}
ASSERT(_CheckBlock(fStream, newBlock) == B_OK);
numBlocks++;
int32 index = stream->extent_header.NumEntries();
stream->extent_index[index].SetLogicalBlock(fNumBlocks);
stream->extent_index[index].SetPhysicalBlock(newBlock);
stream->extent_header.SetNumEntries(index + 1);
TRACE("Enlarge() init entry block %lld at depth %d\n",
newBlock, depth);
stream = (ext2_extent_stream *)cached.SetToWritable(
transaction, newBlock);
if (stream == NULL)
return B_IO_ERROR;
stream->extent_header.magic = EXT2_EXTENT_MAGIC;
stream->extent_header.SetNumEntries(0);
stream->extent_header.SetMaxEntries((fVolume->BlockSize()
- sizeof(ext2_extent_header)) / sizeof(ext2_extent_entry));
stream->extent_header.SetDepth(0);
stream->extent_header.SetGeneration(0);
ASSERT(Check());
}
}
// add a new entry
TRACE("Enlarge() add entry %lld\n", fAllocatedPos);
if (stream != fStream) {
stream = (ext2_extent_stream *)cached.SetToWritable(
transaction, cached.BlockNumber());
if (stream == NULL)
return B_IO_ERROR;
}
int32 index = stream->extent_header.NumEntries();
stream->extent_entries[index].SetLogicalBlock(fNumBlocks);
stream->extent_entries[index].SetLength(allocated);
stream->extent_entries[index].SetPhysicalBlock(fAllocatedPos);
stream->extent_header.SetNumEntries(index + 1);
TRACE("Enlarge() entry added at index %ld\n", index);
ASSERT(stream->extent_header.IsValid());
fNumBlocks += allocated;
allocated = 0;
}
return B_OK;
}
status_t
ExtentStream::Shrink(Transaction& transaction, off_t& numBlocks)
{
TRACE("DataStream::Shrink(): current size: %llu, target size: %llu\n",
fNumBlocks, numBlocks);
off_t targetBlocks = numBlocks;
numBlocks = fNumBlocks - targetBlocks;
while (targetBlocks < fNumBlocks) {
ext2_extent_stream *stream = fStream;
fsblock_t path[stream->extent_header.Depth()];
// search for the leaf
CachedBlock cached(fVolume);
int32 level = -1;
for (; stream->extent_header.Depth() != 0;) {
if (stream->extent_header.NumEntries() == 0)
panic("stream->extent_header.NumEntries() == 0\n");
int32 lastIndex = stream->extent_header.NumEntries() - 1;
TRACE("Shrink() depth %d\n", stream->extent_header.Depth());
TRACE("Shrink() getting index %ld at %lld\n", lastIndex,
stream->extent_index[lastIndex].PhysicalBlock());
path[++level] = stream->extent_index[lastIndex].PhysicalBlock();
stream = (ext2_extent_stream *)cached.SetToWritable(transaction,
path[level]);
if (stream == NULL)
return B_IO_ERROR;
if (!stream->extent_header.IsValid())
panic("Shrink() invalid header\n");
}
int32 index = stream->extent_header.NumEntries() - 1;
status_t status = B_OK;
while (index >= 0 && targetBlocks < fNumBlocks) {
ext2_extent_entry &last = stream->extent_entries[index];
if (last.LogicalBlock() + last.Length() < targetBlocks) {
status = B_BAD_DATA;
break;
}
uint16 length = min_c(last.Length(), fNumBlocks - targetBlocks);
fsblock_t block = last.PhysicalBlock() + last.Length() - length;
TRACE("Shrink() free block %lld length %d\n", block, length);
status = fVolume->FreeBlocks(transaction, block, length);
if (status != B_OK)
break;
fNumBlocks -= length;
stream->extent_entries[index].SetLength(last.Length() - length);
TRACE("Shrink() new length for %ld: %d\n", index, last.Length());
if (last.Length() != 0)
break;
index--;
TRACE("Shrink() next index: %ld\n", index);
}
TRACE("Shrink() new entry count: %ld\n", index + 1);
stream->extent_header.SetNumEntries(index + 1);
ASSERT(Check());
if (status != B_OK)
return status;
while (stream != fStream && stream->extent_header.NumEntries() == 0) {
TRACE("Shrink() empty leaf at depth %d\n",
stream->extent_header.Depth());
level--;
if (level >= 0) {
stream = (ext2_extent_stream *)cached.SetToWritable(
transaction, path[level]);
if (stream == NULL)
return B_IO_ERROR;
} else
stream = fStream;
if (!stream->extent_header.IsValid())
panic("Shrink() invalid header\n");
uint16 index = stream->extent_header.NumEntries() - 1;
ext2_extent_index &last = stream->extent_index[index];
if (last.PhysicalBlock() != path[level + 1])
panic("Shrink() last.PhysicalBlock() != path[level + 1]\n");
status = fVolume->FreeBlocks(transaction, last.PhysicalBlock(), 1);
if (status != B_OK)
return status;
numBlocks++;
stream->extent_header.SetNumEntries(index);
TRACE("Shrink() new entry count: %d\n", index);
}
if (stream == fStream && stream->extent_header.NumEntries() == 0)
stream->extent_header.SetDepth(0);
ASSERT(Check());
}
return B_OK;
}
void
ExtentStream::Init()
{
fStream->extent_header.magic = EXT2_EXTENT_MAGIC;
fStream->extent_header.SetNumEntries(0);
fStream->extent_header.SetMaxEntries(4);
fStream->extent_header.SetDepth(0);
fStream->extent_header.SetGeneration(0);
}
status_t
ExtentStream::_Check(ext2_extent_stream *stream, fileblock_t &block)
{
if (!stream->extent_header.IsValid()) {
panic("_Check() invalid header\n");
return B_BAD_VALUE;
}
if (stream->extent_header.Depth() == 0) {
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
ext2_extent_entry &entry = stream->extent_entries[i];
if (entry.LogicalBlock() < block) {
panic("_Check() entry %ld %lld %ld\n", i, block,
entry.LogicalBlock());
return B_BAD_VALUE;
}
block = entry.LogicalBlock() + entry.Length();
}
return B_OK;
}
CachedBlock cached(fVolume);
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
ext2_extent_index &index = stream->extent_index[i];
if (index.LogicalBlock() < block) {
panic("_Check() index %ld %lld %ld\n", i, block,
index.LogicalBlock());
return B_BAD_VALUE;
}
ext2_extent_stream *child = (ext2_extent_stream *)cached.SetTo(
index.PhysicalBlock());
if (child->extent_header.Depth() != (stream->extent_header.Depth() - 1)
|| _Check(child, block) != B_OK)
return B_BAD_VALUE;
}
return B_OK;
}
bool
ExtentStream::Check()
{
fileblock_t block = 0;
return _Check(fStream, block) == B_OK;
}
status_t
ExtentStream::_CheckBlock(ext2_extent_stream *stream, fsblock_t block)
{
if (stream->extent_header.Depth() == 0) {
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
ext2_extent_entry &entry = stream->extent_entries[i];
if (entry.PhysicalBlock() <= block
&& (entry.PhysicalBlock() + entry.Length()) > block) {
panic("_CheckBlock() entry %ld %lld %lld %d\n", i, block,
entry.PhysicalBlock(), entry.Length());
return B_BAD_VALUE;
}
}
return B_OK;
}
CachedBlock cached(fVolume);
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
ext2_extent_index &index = stream->extent_index[i];
if (index.PhysicalBlock() == block) {
panic("_CheckBlock() index %ld %lld\n", i, block);
return B_BAD_VALUE;
}
ext2_extent_stream *child = (ext2_extent_stream *)cached.SetTo(
index.PhysicalBlock());
if (child->extent_header.Depth() != (stream->extent_header.Depth() - 1)
|| _CheckBlock(child, block) != B_OK)
return B_BAD_VALUE;
}
return B_OK;
}
@@ -0,0 +1,48 @@
/*
* Copyright 2001-2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#ifndef EXTENTSTREAM_H
#define EXTENTSTREAM_H
#include "ext2.h"
#include "Transaction.h"
class Volume;
class ExtentStream
{
public:
ExtentStream(Volume* volume, ext2_extent_stream* stream,
off_t size);
~ExtentStream();
status_t FindBlock(off_t offset, fsblock_t& block,
uint32 *_count = NULL);
status_t Enlarge(Transaction& transaction, off_t& numBlocks);
status_t Shrink(Transaction& transaction, off_t& numBlocks);
void Init();
bool Check();
private:
status_t _Check(ext2_extent_stream *stream, fileblock_t &block);
status_t _CheckBlock(ext2_extent_stream *stream, fsblock_t block);
Volume* fVolume;
ext2_extent_stream* fStream;
fsblock_t fFirstBlock;
fsblock_t fAllocatedPos;
off_t fNumBlocks;
off_t fSize;
};
#endif // EXTENTSTREAM_H
@@ -84,7 +84,7 @@ HTree::~HTree()
status_t
HTree::PrepareForHash()
{
off_t blockNum;
fsblock_t blockNum;
status_t status = fDirectory->FindBlock(0, blockNum);
if (status != B_OK)
return status;
@@ -115,7 +115,7 @@ HTree::Lookup(const char* name, DirectoryIterator** iterator)
return _FallbackToLinearIteration(iterator);
}
off_t blockNum;
fsblock_t blockNum;
status_t status = fDirectory->FindBlock(0, blockNum);
if (status != B_OK)
return _FallbackToLinearIteration(iterator);
@@ -189,7 +189,7 @@ HTreeEntryIterator::Lookup(uint32 hash, int indirections,
TRACE("HTreeEntryIterator::Lookup(): Creating a HTree entry iterator "
"starting at block: %lu, hash: 0x%lX\n", start->Block(), start->Hash());
off_t blockNum;
fsblock_t blockNum;
status_t status = fDirectory->FindBlock(start->Block() * fBlockSize,
blockNum);
if (status != B_OK)
@@ -322,7 +322,7 @@ HTreeEntryIterator::InsertEntry(Transaction& transaction, uint32 hash,
panic("Splitting a HTree node required, but isn't yet fully "
"supported\n");
off_t physicalBlock;
fsblock_t physicalBlock;
status_t status = fDirectory->FindBlock(newBlocksPos, physicalBlock);
if (status != B_OK)
return status;
@@ -53,7 +53,7 @@ private:
uint16 fCurrentEntry;
uint32 fBlockSize;
off_t fBlockNum;
fsblock_t fBlockNum;
HTreeEntryIterator* fParent;
HTreeEntryIterator* fChild;
+38 -9
View File
@@ -13,6 +13,7 @@
#include "CachedBlock.h"
#include "DataStream.h"
#include "DirectoryIterator.h"
#include "ExtentStream.h"
#include "HTree.h"
#include "Utility.h"
@@ -224,8 +225,12 @@ Inode::CheckPermissions(int accessMode) const
status_t
Inode::FindBlock(off_t offset, off_t& block, uint32 *_count)
Inode::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
{
if (Flags() & EXT2_INODE_EXTENTS) {
ExtentStream stream(fVolume, &fNode.extent_stream, Size());
return stream.FindBlock(offset, block, _count);
}
DataStream stream(fVolume, &fNode.stream, Size());
return stream.FindBlock(offset, block, _count);
}
@@ -407,9 +412,14 @@ Inode::InitDirectory(Transaction& transaction, Inode* parent)
if (status != B_OK)
return status;
off_t blockNum;
DataStream stream(fVolume, &fNode.stream, Size());
status = stream.FindBlock(0, blockNum);
fsblock_t blockNum;
if (Flags() & EXT2_INODE_EXTENTS) {
ExtentStream stream(fVolume, &fNode.extent_stream, Size());
status = stream.FindBlock(0, blockNum);
} else {
DataStream stream(fVolume, &fNode.stream, Size());
status = stream.FindBlock(0, blockNum);
}
if (status != B_OK)
return status;
@@ -613,6 +623,14 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
inode->SetAccessTime(&timespec);
inode->SetCreationTime(&timespec);
inode->SetModificationTime(&timespec);
node.SetFlags(parent->Flags() & EXT2_INODE_INHERITED);
if (volume->HasExtentsFeature()
&& (inode->IsDirectory() || inode->IsFile())) {
node.SetFlag(EXT2_INODE_EXTENTS);
ExtentStream stream(volume, &node.extent_stream, 0);
stream.Init();
ASSERT(stream.Check());
}
if (sizeof(ext2_inode) < volume->InodeSize())
node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE);
@@ -803,9 +821,14 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
}
off_t end = size == 0 ? 0 : (size - 1) / fVolume->BlockSize() + 1;
DataStream stream(fVolume, &fNode.stream, oldSize);
stream.Enlarge(transaction, end);
if (Flags() & EXT2_INODE_EXTENTS) {
ExtentStream stream(fVolume, &fNode.extent_stream, Size());
stream.Enlarge(transaction, end);
ASSERT(stream.Check());
} else {
DataStream stream(fVolume, &fNode.stream, oldSize);
stream.Enlarge(transaction, end);
}
TRACE("Inode::_EnlargeDataStream(): Setting size to %lld\n", size);
fNode.SetSize(size);
TRACE("Inode::_EnlargeDataStream(): Setting allocated block count to %llu\n",
@@ -837,8 +860,14 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
}
off_t end = size == 0 ? 0 : (size - 1) / fVolume->BlockSize() + 1;
DataStream stream(fVolume, &fNode.stream, oldSize);
stream.Shrink(transaction, end);
if (Flags() & EXT2_INODE_EXTENTS) {
ExtentStream stream(fVolume, &fNode.extent_stream, Size());
stream.Shrink(transaction, end);
ASSERT(stream.Check());
} else {
DataStream stream(fVolume, &fNode.stream, oldSize);
stream.Shrink(transaction, end);
}
fNode.SetSize(size);
return _SetNumBlocks(_NumBlocks() - end * (fVolume->BlockSize() / 512));
+1 -1
View File
@@ -79,7 +79,7 @@ public:
//::Volume* _Volume() const { return fVolume; }
Volume* GetVolume() const { return fVolume; }
status_t FindBlock(off_t offset, off_t& block,
status_t FindBlock(off_t offset, fsblock_t& block,
uint32 *_count = NULL);
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
status_t WriteAt(Transaction& transaction, off_t pos,
@@ -156,7 +156,7 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
status_t
InodeAllocator::_MarkInBitmap(Transaction& transaction, off_t bitmapBlock,
InodeAllocator::_MarkInBitmap(Transaction& transaction, fsblock_t bitmapBlock,
uint32 blockGroup, uint32 numInodes, ino_t& id)
{
BitmapBlock inodeBitmap(fVolume, numInodes);
@@ -190,7 +190,7 @@ InodeAllocator::_MarkInBitmap(Transaction& transaction, off_t bitmapBlock,
status_t
InodeAllocator::_UnmarkInBitmap(Transaction& transaction, off_t bitmapBlock,
InodeAllocator::_UnmarkInBitmap(Transaction& transaction, fsblock_t bitmapBlock,
uint32 numInodes, ino_t id)
{
BitmapBlock inodeBitmap(fVolume, numInodes);
@@ -10,6 +10,7 @@
#include <lock.h>
#include "ext2.h"
#include "Transaction.h"
@@ -29,13 +30,13 @@ public:
private:
status_t _Allocate(Transaction& transaction,
uint32 prefferedBlockGroup, bool isDirectory,
uint32 preferredBlockGroup, bool isDirectory,
ino_t& id);
status_t _MarkInBitmap(Transaction& transaction,
off_t bitmapBlock, uint32 blockGroup,
fsblock_t bitmapBlock, uint32 blockGroup,
uint32 numInodes, ino_t& id);
status_t _UnmarkInBitmap(Transaction& transaction,
off_t bitmapBlock, uint32 numInodes, ino_t id);
fsblock_t bitmapBlock, uint32 numInodes, ino_t id);
Volume* fVolume;
@@ -84,7 +84,7 @@ InodeJournal::InitCheck()
status_t
InodeJournal::MapBlock(off_t logical, off_t& physical)
InodeJournal::MapBlock(off_t logical, fsblock_t& physical)
{
TRACE("InodeJournal::MapBlock()\n");
return fInode->FindBlock(logical * fBlockSize, physical);
@@ -20,7 +20,7 @@ public:
status_t InitCheck();
status_t MapBlock(off_t logical, off_t& physical);
status_t MapBlock(off_t logical, fsblock_t& physical);
private:
Inode* fInode;
status_t fInitStatus;
@@ -11,6 +11,7 @@ KernelAddon ext2 :
Inode.cpp
Attribute.cpp
DirectoryIterator.cpp
ExtentStream.cpp
HTree.cpp
HTreeEntryIterator.cpp
RevokeManager.cpp
@@ -304,7 +304,7 @@ Journal::Unlock(Transaction* owner, bool success)
status_t
Journal::MapBlock(off_t logical, off_t& physical)
Journal::MapBlock(off_t logical, fsblock_t& physical)
{
TRACE("Journal::MapBlock()\n");
physical = logical;
@@ -402,7 +402,7 @@ Journal::_WritePartialTransactionToLog(JournalHeader* descriptorBlock,
logBlock = _WrapAroundLog(logBlock + 1);
off_t physicalBlock;
fsblock_t physicalBlock;
status = MapBlock(logBlock, physicalBlock);
if (status != B_OK)
return status;
@@ -434,7 +434,7 @@ Journal::_WritePartialTransactionToLog(JournalHeader* descriptorBlock,
--tag;
tag->SetLastTagFlag();
off_t physicalBlock;
fsblock_t physicalBlock;
status = MapBlock(descriptorBlockPos, physicalBlock);
if (status != B_OK)
return status;
@@ -579,7 +579,7 @@ Journal::_WriteTransactionToLog()
// written. When it recovery reaches where the first commit should be
// and doesn't find it, it considers it found the end of the log.
off_t physicalBlock;
fsblock_t physicalBlock;
status = MapBlock(logBlock, physicalBlock);
if (status != B_OK)
return status;
@@ -602,7 +602,7 @@ Journal::_WriteTransactionToLog()
}
// Transaction will enter the Commit state
off_t physicalBlock;
fsblock_t physicalBlock;
status = MapBlock(commitBlockPos, physicalBlock);
if (status != B_OK)
return status;
@@ -661,7 +661,7 @@ status_t
Journal::_SaveSuperBlock()
{
TRACE("Journal::_SaveSuperBlock()\n");
off_t physicalBlock;
fsblock_t physicalBlock;
status_t status = MapBlock(0, physicalBlock);
if (status != B_OK)
return status;
@@ -695,7 +695,7 @@ status_t
Journal::_LoadSuperBlock()
{
TRACE("Journal::_LoadSuperBlock()\n");
off_t superblockPos;
fsblock_t superblockPos;
status_t status = MapBlock(0, superblockPos);
if (status != B_OK)
@@ -842,7 +842,7 @@ Journal::_RecoverPassScan(uint32& lastCommitID)
JournalHeader* header;
uint32 nextCommitID = fFirstCommitID;
uint32 nextBlock = fLogStart;
off_t nextBlockPos;
fsblock_t nextBlockPos;
status_t status = MapBlock(nextBlock, nextBlockPos);
if (status != B_OK)
@@ -898,7 +898,7 @@ Journal::_RecoverPassRevoke(uint32 lastCommitID)
JournalHeader* header;
uint32 nextCommitID = fFirstCommitID;
uint32 nextBlock = fLogStart;
off_t nextBlockPos;
fsblock_t nextBlockPos;
status_t status = MapBlock(nextBlock, nextBlockPos);
if (status != B_OK)
@@ -960,7 +960,7 @@ Journal::_RecoverPassReplay(uint32 lastCommitID)
uint32 nextCommitID = fFirstCommitID;
uint32 nextBlock = fLogStart;
off_t nextBlockPos;
fsblock_t nextBlockPos;
status_t status = MapBlock(nextBlock, nextBlockPos);
if (status != B_OK)
@@ -173,7 +173,7 @@ public:
bool separateSubTransactions);
virtual status_t Unlock(Transaction* owner, bool success);
virtual status_t MapBlock(off_t logical, off_t& physical);
virtual status_t MapBlock(off_t logical, fsblock_t& physical);
inline uint32 FreeLogBlocks() const;
status_t FlushLogAndBlocks();
@@ -279,8 +279,10 @@ Volume::Mount(const char* deviceName, uint32 flags)
DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
? O_RDONLY : O_RDWR);
fDevice = opener.Device();
if (fDevice < B_OK)
if (fDevice < B_OK) {
FATAL("Volume::Mount(): couldn't open device\n");
return fDevice;
}
if (opener.IsReadOnly())
fFlags |= VOLUME_READ_ONLY;
@@ -291,8 +293,10 @@ Volume::Mount(const char* deviceName, uint32 flags)
// read the super block
status_t status = Identify(fDevice, &fSuperBlock);
if (status != B_OK)
if (status != B_OK) {
FATAL("Volume::Mount(): Identify() failed\n");
return status;
}
// check read-only features if mounting read-write
if (!IsReadOnly() && _UnsupportedReadOnlyFeatures(fSuperBlock) != 0)
@@ -300,7 +304,9 @@ Volume::Mount(const char* deviceName, uint32 flags)
// initialize short hands to the super block (to save byte swapping)
fBlockShift = fSuperBlock.BlockShift();
fBlockSize = 1UL << fSuperBlock.BlockShift();
if (fBlockShift < 10 || fBlockShift > 16)
return B_ERROR;
fBlockSize = 1UL << fBlockShift;
fFirstDataBlock = fSuperBlock.FirstDataBlock();
fFreeBlocks = fSuperBlock.FreeBlocks(Has64bitFeature());
@@ -338,7 +344,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
status = opener.GetSize(&diskSize);
if (status != B_OK)
return status;
if (diskSize < (NumBlocks() << BlockShift()))
if (diskSize < ((off_t)NumBlocks() << BlockShift()))
return B_BAD_VALUE;
fBlockCache = opener.InitCache(NumBlocks(), fBlockSize);
@@ -501,6 +507,7 @@ Volume::_UnsupportedIncompatibleFeatures(ext2_super_block& superBlock)
uint32 supportedIncompatible = EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE
| EXT2_INCOMPATIBLE_FEATURE_RECOVER
| EXT2_INCOMPATIBLE_FEATURE_JOURNAL
| EXT2_INCOMPATIBLE_FEATURE_EXTENTS;
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
uint32 unsupported = superBlock.IncompatibleFeatures()
& ~supportedIncompatible;
@@ -742,7 +749,7 @@ Volume::FreeInode(Transaction& transaction, ino_t id, bool isDirectory)
status_t
Volume::AllocateBlocks(Transaction& transaction, uint32 minimum, uint32 maximum,
uint32& blockGroup, off_t& start, uint32& length)
uint32& blockGroup, fsblock_t& start, uint32& length)
{
TRACE("Volume::AllocateBlocks()\n");
if (IsReadOnly())
@@ -764,7 +771,7 @@ Volume::AllocateBlocks(Transaction& transaction, uint32 minimum, uint32 maximum,
status_t
Volume::FreeBlocks(Transaction& transaction, off_t start, uint32 length)
Volume::FreeBlocks(Transaction& transaction, fsblock_t start, uint32 length)
{
TRACE("Volume::FreeBlocks(%llu, %lu)\n", start, length);
if (IsReadOnly())
@@ -48,7 +48,7 @@ public:
{ return fNumInodes; }
uint32 NumGroups() const
{ return fNumGroups; }
off_t NumBlocks() const
fsblock_t NumBlocks() const
{ return fSuperBlock.NumBlocks(
Has64bitFeature()); }
off_t NumFreeBlocks() const
@@ -81,6 +81,9 @@ public:
bool Has64bitFeature() const
{ return (fSuperBlock.CompatibleFeatures()
& EXT2_INCOMPATIBLE_FEATURE_64BIT) != 0; }
bool HasExtentsFeature() const
{ return (fSuperBlock.IncompatibleFeatures()
& EXT2_INCOMPATIBLE_FEATURE_EXTENTS) != 0; }
uint8 DefaultHashVersion() const
{ return fSuperBlock.default_hash_version; }
bool HugeFiles() const
@@ -100,10 +103,10 @@ public:
status_t AllocateBlocks(Transaction& transaction,
uint32 minimum, uint32 maximum,
uint32& blockGroup, off_t& start,
uint32& blockGroup, fsblock_t& start,
uint32& length);
status_t FreeBlocks(Transaction& transaction,
off_t start, uint32 length);
fsblock_t start, uint32 length);
status_t LoadSuperBlock();
status_t WriteSuperBlock(Transaction& transaction);
+88 -2
View File
@@ -15,6 +15,11 @@
//#define TRACE_EXT2
typedef uint64 fileblock_t; // file block number
typedef uint64 fsblock_t; // filesystem block number
#define EXT2_SUPER_BLOCK_OFFSET 1024
struct ext2_super_block {
@@ -213,7 +218,7 @@ struct ext2_block_group {
uint16 unused_inodes_high;
uint32 _reserved2[3];
uint64 BlockBitmap(bool has64bits) const
fsblock_t BlockBitmap(bool has64bits) const
{
uint64 block = B_LENDIAN_TO_HOST_INT32(block_bitmap);
if (has64bits)
@@ -221,7 +226,7 @@ struct ext2_block_group {
((uint64)B_LENDIAN_TO_HOST_INT32(block_bitmap_high) << 32);
return block;
}
uint64 InodeBitmap(bool has64bits) const
fsblock_t InodeBitmap(bool has64bits) const
{
uint64 bitmap = B_LENDIAN_TO_HOST_INT32(inode_bitmap);
if (has64bits)
@@ -296,6 +301,76 @@ struct ext2_data_stream {
uint32 triple_indirect;
} _PACKED;
#define EXT2_EXTENT_MAGIC 0xf30a
struct ext2_extent_header {
uint16 magic;
uint16 num_entries;
uint16 max_entries;
uint16 depth;
uint32 generation;
bool IsValid() const
{
return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC;
}
uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); }
uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); }
uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); }
uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); }
void SetNumEntries(uint16 num)
{ num_entries = B_HOST_TO_LENDIAN_INT16(num); }
void SetMaxEntries(uint16 max)
{ max_entries = B_HOST_TO_LENDIAN_INT16(max); }
void SetDepth(uint16 _depth)
{ depth = B_HOST_TO_LENDIAN_INT16(_depth); }
void SetGeneration(uint32 _generation)
{ generation = B_HOST_TO_LENDIAN_INT32(_generation); }
} _PACKED;
struct ext2_extent_index {
uint32 logical_block;
uint32 physical_block;
uint16 physical_block_high;
uint16 _reserved;
uint32 LogicalBlock() const
{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
void SetLogicalBlock(uint32 block) {
logical_block = B_HOST_TO_LENDIAN_INT32(block); }
void SetPhysicalBlock(uint64 block) {
physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
} _PACKED;
struct ext2_extent_entry {
uint32 logical_block;
uint16 length;
uint16 physical_block_high;
uint32 physical_block;
uint32 LogicalBlock() const
{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000
? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; }
uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
void SetLogicalBlock(uint32 block) {
logical_block = B_HOST_TO_LENDIAN_INT32(block); }
void SetLength(uint16 _length) {
length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; }
void SetPhysicalBlock(uint64 block) {
physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
} _PACKED;
struct ext2_extent_stream {
ext2_extent_header extent_header;
union {
ext2_extent_entry extent_entries[4];
ext2_extent_index extent_index[4];
};
} _PACKED;
#define EXT2_INODE_NORMAL_SIZE 128
struct ext2_inode {
@@ -314,6 +389,7 @@ struct ext2_inode {
union {
ext2_data_stream stream;
char symlink[EXT2_SHORT_SYMLINK_LENGTH];
ext2_extent_stream extent_stream;
};
uint32 generation;
uint32 file_access_control;
@@ -546,9 +622,18 @@ struct ext2_inode {
#define EXT2_INODE_COMPRESSION_ERROR 0x00000800
#define EXT2_INODE_BTREE 0x00001000
#define EXT2_INODE_INDEXED 0x00001000
#define EXT2_INODE_JOURNAL_DATA 0x00004000
#define EXT2_INODE_NO_MERGE_TAIL 0x00008000
#define EXT2_INODE_DIR_SYNCH 0x00010000
#define EXT2_INODE_HUGE_FILE 0x00040000
#define EXT2_INODE_EXTENTS 0x00080000
#define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \
| EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \
| EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \
| EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \
| EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH)
#define EXT2_NAME_LENGTH 255
struct ext2_dir_entry {
@@ -680,6 +765,7 @@ struct file_cookie {
int open_mode;
};
#define EXT2_OPEN_MODE_USER_MASK 0x7fffffff
#define INODE_NOTIFICATION_INTERVAL 10000000LL
@@ -407,12 +407,17 @@ ext2_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset,
size_t index = 0, max = *_count;
while (true) {
off_t block;
fsblock_t block;
uint32 count = 1;
status_t status = inode->FindBlock(offset, block, &count);
if (status != B_OK)
return status;
if (block > volume->NumBlocks()) {
panic("ext2_get_file_map() found block %lld for offset %lld\n",
block, offset);
}
off_t blockOffset = block << volume->BlockShift();
uint32 blockLength = volume->BlockSize() * count;
@@ -506,7 +511,7 @@ ext2_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
uint32 blocksPerGroup = volume->BlocksPerGroup();
uint32 blockSize = volume->BlockSize();
uint32 firstBlock = volume->FirstDataBlock();
off_t start = 0;
fsblock_t start = 0;
uint32 group = 0;
uint32 length;
@@ -955,7 +960,7 @@ ext2_rename(fs_volume* _volume, fs_vnode* _oldDir, const char* oldName,
if (status != B_OK)
return B_IO_ERROR;
off_t blockNum;
fsblock_t blockNum;
status = parent->FindBlock(0, blockNum);
if (status != B_OK)
return status;