* added support for huge_file feature, untested (need a >2TB file)

* actually checks for readonly features if mounting read-write  
* don't use a journal when mounting readonly
* DataStream::_BlocksNeeded(): in case of double or triple indirects,
compute the additional blocks needed using the difference between the
old and new indirects blocks. This was resulting in a bad NumBlocks on an inode
* BitmapBlock: mark methods missed an iteration when the startingBit was zero.
Some blocks were then allocated two times (at most 32 for each allocation run).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38950 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2010-10-11 19:58:46 +00:00
parent b0ce12a2af
commit de66992b72
9 changed files with 136 additions and 78 deletions
@@ -94,7 +94,8 @@ BitmapBlock::CheckUnmarked(uint32 start, uint32 length)
return false;
index += 1;
}
} else
iterations++;
for (; iterations > 0; --iterations) {
if (data[index++] != 0)
@@ -153,7 +154,8 @@ BitmapBlock::CheckMarked(uint32 start, uint32 length)
return false;
index += 1;
}
} else
iterations++;
mask = 0xFFFFFFFF;
for (; iterations > 0; --iterations) {
@@ -216,7 +218,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
mask = ~((1 << startBit) - 1);
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
TRACE("BitmapBlock::Mark(): mask: %lX, bits: %lX\n", mask, bits);
TRACE("BitmapBlock::Mark(): index %lu mask: %lX, bits: %lX\n", index,
mask, bits);
if (!force && (bits & mask) != 0)
return false;
@@ -225,7 +228,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
index += 1;
}
} else
iterations++;
mask = 0xFFFFFFFF;
for (; iterations > 0; --iterations) {
@@ -237,8 +241,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
if (remainingBits != 0) {
mask = (1 << remainingBits) - 1;
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
TRACE("BitmapBlock::(): marking remaining %lu bits: %lX, mask: %lX\n",
remainingBits, bits, mask);
TRACE("BitmapBlock::Mark(): marking index %lu remaining %lu bits: %lX,"
" mask: %lX\n", index, remainingBits, bits, mask);
if (!force && (bits & mask) != 0)
return false;
@@ -310,7 +314,8 @@ BitmapBlock::Unmark(uint32 start, uint32 length, bool force)
TRACE("BitmapBlock::Unmark(): updated bits: %lx\n", bits);
index += 1;
}
} else
iterations++;
mask = 0xFFFFFFFF;
for (; iterations > 0; --iterations) {
@@ -656,9 +661,3 @@ BitmapBlock::FindLargestUnmarkedRange(uint32& start, uint32& length)
}
}
uint32
BitmapBlock::NumBits() const
{
return fNumBits;
}
@@ -36,7 +36,7 @@ public:
void FindLargestUnmarkedRange(uint32& start,
uint32& length);
uint32 NumBits() const;
uint32 NumBits() const { return fNumBits; }
protected:
uint32* fData;
@@ -180,7 +180,7 @@ status_t
AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
uint32 length)
{
TRACE("AllocationBlockGroup::Allocate()\n");
TRACE("AllocationBlockGroup::Allocate(%ld,%ld)\n", start, length);
uint32 end = start + length;
if (end > fNumBits)
return B_BAD_DATA;
@@ -463,7 +463,7 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
{
TRACE("BlockAllocator::AllocateBlocks()\n");
MutexLocker lock(fLock);
TRACE("BlockAllocator::AllocateBlocks(): Aquired lock\n");
TRACE("BlockAllocator::AllocateBlocks(): Acquired lock\n");
TRACE("BlockAllocator::AllocateBlocks(): transaction: %ld, min: %lu, "
"max: %lu, block group: %lu, start: %lu, num groups: %lu\n",
@@ -25,7 +25,7 @@ DataStream::DataStream(Volume* volume, ext2_data_stream* stream,
off_t size)
:
kBlockSize(volume->BlockSize()),
kIndirectsPerBlock(kBlockSize / 4),
kIndirectsPerBlock(kBlockSize / sizeof(uint32)),
kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock),
kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock),
kMaxDirect(EXT2_DIRECT_BLOCKS),
@@ -195,20 +195,9 @@ DataStream::_BlocksNeeded(uint32 numBlocks)
blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1)
/ kIndirectsPerBlock;
} else {
blocksNeeded += (numBlocks - fNumBlocks)
/ kIndirectsPerBlock;
uint32 halfIndirectsPerBlock = kIndirectsPerBlock / 2;
uint32 remCurrent = (fNumBlocks - kMaxIndirect - 1)
% kIndirectsPerBlock;
uint32 remTarget = (numBlocks - kMaxIndirect - 1)
% kIndirectsPerBlock;
if ((remCurrent >= halfIndirectsPerBlock
&& remTarget < halfIndirectsPerBlock)
|| (remCurrent > halfIndirectsPerBlock
&& remTarget <= halfIndirectsPerBlock))
blocksNeeded++;
blocksNeeded += (numBlocks - kMaxIndirect - 1)
/ kIndirectsPerBlock - (fNumBlocks
- kMaxIndirect - 1) / kIndirectsPerBlock;
}
if (numBlocks > kMaxDoubleIndirect) {
@@ -216,21 +205,9 @@ DataStream::_BlocksNeeded(uint32 numBlocks)
blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1)
/ kIndirectsPerBlock2;
} else {
blocksNeeded += (numBlocks - fNumBlocks)
/ kIndirectsPerBlock2;
uint32 halfIndirectsPerBlock2 = kIndirectsPerBlock2 / 2;
uint32 remCurrent = (fNumBlocks - kMaxDoubleIndirect
- 1)
% kIndirectsPerBlock2;
uint32 remTarget = (numBlocks - kMaxDoubleIndirect - 1)
% kIndirectsPerBlock2;
if ((remCurrent >= halfIndirectsPerBlock2
&& remTarget < halfIndirectsPerBlock2)
|| (remCurrent > halfIndirectsPerBlock2
&& remTarget <= halfIndirectsPerBlock2))
blocksNeeded++;
blocksNeeded += (numBlocks - kMaxDoubleIndirect - 1)
/ kIndirectsPerBlock - (fNumBlocks
- kMaxDoubleIndirect - 1) / kIndirectsPerBlock;
}
}
}
@@ -260,6 +237,9 @@ DataStream::_GetBlock(Transaction& transaction, uint32& block)
fWaiting -= fAllocated;
fAllocatedPos += fVolume->BlocksPerGroup() * blockGroup + fFirstBlock;
TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %lu,"
"newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting);
}
fAllocated--;
@@ -339,7 +319,7 @@ DataStream::_AddBlocks(Transaction& transaction, uint32* block, uint32 start,
else if (recursion == 2)
elementWidth = kIndirectsPerBlock2;
else {
panic("Undefinied recursion level\n");
panic("Undefined recursion level\n");
elementWidth = 0;
}
+39 -9
View File
@@ -868,9 +868,8 @@ Inode::RemovedFromTransaction()
status_t
Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
{
// TODO: Update fNode.num_blocks
if (size < 0)
return B_BAD_DATA;
return B_BAD_VALUE;
TRACE("Inode::_EnlargeDataStream()\n");
@@ -883,7 +882,7 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
if (size <= maxSize) {
// No need to allocate more blocks
TRACE("Inode::_EnlargeDataStream(): No need to allocate more blocks\n");
TRACE("Inode::_EnlargeDataStream(): Setting size to %ld\n", (long)size);
TRACE("Inode::_EnlargeDataStream(): Setting size to %Ld\n", size);
fNode.SetSize(size);
return B_OK;
}
@@ -892,13 +891,11 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
DataStream stream(fVolume, &fNode.stream, oldSize);
stream.Enlarge(transaction, end);
TRACE("Inode::_EnlargeDataStream(): Setting size to %ld\n", (long)size);
TRACE("Inode::_EnlargeDataStream(): Setting size to %Ld\n", size);
fNode.SetSize(size);
TRACE("Inode::_EnlargeDataStream(): Setting allocated block count to %lu\n",
end);
fNode.SetNumBlocks(fNode.NumBlocks() + end * (fVolume->BlockSize() / 512));
return B_OK;
return _SetNumBlocks(_NumBlocks() + end * (fVolume->BlockSize() / 512));
}
@@ -908,7 +905,7 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
TRACE("Inode::_ShrinkDataStream()\n");
if (size < 0)
return B_BAD_DATA;
return B_BAD_VALUE;
uint32 blockSize = fVolume->BlockSize();
off_t oldSize = Size();
@@ -929,7 +926,40 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
stream.Shrink(transaction, end);
fNode.SetSize(size);
fNode.SetNumBlocks(fNode.NumBlocks() - end * (fVolume->BlockSize() / 512));
return _SetNumBlocks(_NumBlocks() - end * (fVolume->BlockSize() / 512));
}
uint64
Inode::_NumBlocks()
{
if (fVolume->HugeFiles()) {
if (fNode.Flags() & EXT2_INODE_HUGE_FILE)
return fNode.NumBlocks64() * (fVolume->BlockSize() / 512);
else
return fNode.NumBlocks64();
} else
return fNode.NumBlocks();
}
status_t
Inode::_SetNumBlocks(uint64 numBlocks)
{
if (numBlocks <= 0xffffffff) {
fNode.SetNumBlocks(numBlocks);
fNode.ClearFlag(EXT2_INODE_HUGE_FILE);
return B_OK;
}
if (!fVolume->HugeFiles())
return E2BIG;
if (numBlocks > 0xffffffffffffULL) {
fNode.SetFlag(EXT2_INODE_HUGE_FILE);
numBlocks /= (fVolume->BlockSize() / 512);
} else
fNode.ClearFlag(EXT2_INODE_HUGE_FILE);
fNode.SetNumBlocks64(numBlocks);
return B_OK;
}
@@ -100,6 +100,8 @@ private:
off_t size);
status_t _ShrinkDataStream(Transaction& transaction, off_t size);
uint64 _NumBlocks();
status_t _SetNumBlocks(uint64 numBlocks);
rw_lock fLock;
::Volume* fVolume;
+42 -20
View File
@@ -32,6 +32,7 @@
#else
# define TRACE(x...) ;
#endif
# define FATAL(x...) dprintf("\33[34mext2:\33[0m " x)
class DeviceOpener {
@@ -284,13 +285,17 @@ Volume::Mount(const char* deviceName, uint32 flags)
if (opener.IsReadOnly())
fFlags |= VOLUME_READ_ONLY;
// read the super block
if (Identify(fDevice, &fSuperBlock) != B_OK) {
//FATAL(("invalid super block!\n"));
return B_BAD_VALUE;
}
TRACE("features %lx, incompatible features %lx, read-only features %lx\n",
fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(),
fSuperBlock.ReadOnlyFeatures());
if (_UnsupportedIncompatibleFeatures(fSuperBlock) != 0)
// read the super block
status_t status = Identify(fDevice, &fSuperBlock);
if (status != B_OK)
return status;
// check read-only features if mounting read-write
if (!IsReadOnly() && _UnsupportedReadOnlyFeatures(fSuperBlock) != 0)
return B_NOT_SUPPORTED;
// initialize short hands to the super block (to save byte swapping)
@@ -312,10 +317,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n",
fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock);
TRACE("features %lx, incompatible features %lx, read-only features %lx\n",
fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(),
fSuperBlock.ReadOnlyFeatures());
uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1) / fGroupsPerBlock;
fGroupBlocks = (ext2_block_group**)malloc(blockCount * sizeof(void*));
@@ -327,7 +329,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
// check if the device size is large enough to hold the file system
off_t diskSize;
status_t status = opener.GetSize(&diskSize);
status = opener.GetSize(&diskSize);
if (status != B_OK)
return status;
if (diskSize < (NumBlocks() << BlockShift()))
@@ -339,8 +341,9 @@ Volume::Mount(const char* deviceName, uint32 flags)
TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
// initialize journal
if ((fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
// initialize journal if mounted read-write
if (!IsReadOnly() &&
(fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
// TODO: There should be a mount option to ignore the existent journal
if (fSuperBlock.JournalInode() != 0) {
fJournalInode = new(std::nothrow) Inode(this,
@@ -469,15 +472,32 @@ Volume::_UnsupportedIncompatibleFeatures(ext2_super_block& superBlock)
| EXT2_INCOMPATIBLE_FEATURE_RECOVER
| EXT2_INCOMPATIBLE_FEATURE_JOURNAL
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
uint32 unsupported = superBlock.IncompatibleFeatures()
& ~supportedIncompatible;
if ((superBlock.IncompatibleFeatures() & ~supportedIncompatible) != 0) {
dprintf("ext2: incompatible features not supported: %lx (extents %x)\n",
superBlock.IncompatibleFeatures() & ~supportedIncompatible,
EXT2_INCOMPATIBLE_FEATURE_EXTENTS);
return superBlock.IncompatibleFeatures() & ~supportedIncompatible;
if (unsupported != 0) {
FATAL("ext2: incompatible features not supported: %lx (extents %x)\n",
unsupported, EXT2_INCOMPATIBLE_FEATURE_EXTENTS);
}
return 0;
return unsupported;
}
/*static*/ uint32
Volume::_UnsupportedReadOnlyFeatures(ext2_super_block& superBlock)
{
uint32 supportedReadOnly = EXT2_READ_ONLY_FEATURE_SPARSE_SUPER
| EXT2_READ_ONLY_FEATURE_HUGE_FILE;
// TODO actually implement EXT2_READ_ONLY_FEATURE_SPARSE_SUPER when
// implementing superblock backup copies
uint32 unsupported = superBlock.ReadOnlyFeatures() & ~supportedReadOnly;
if (unsupported != 0)
FATAL("ext2: readonly features not supported: %lx\n", unsupported);
return unsupported;
}
@@ -796,8 +816,10 @@ Volume::Identify(int fd, ext2_super_block* superBlock)
sizeof(ext2_super_block)) != sizeof(ext2_super_block))
return B_IO_ERROR;
if (!superBlock->IsValid())
if (!superBlock->IsValid()) {
FATAL("invalid super block!\n");
return B_BAD_VALUE;
}
return _UnsupportedIncompatibleFeatures(*superBlock) == 0
? B_OK : B_NOT_SUPPORTED;
@@ -79,6 +79,9 @@ public:
& EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
uint8 DefaultHashVersion() const
{ return fSuperBlock.default_hash_version; }
bool HugeFiles() const
{ return (fSuperBlock.ReadOnlyFeatures()
& EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; }
status_t SaveOrphan(Transaction& transaction,
ino_t newID, ino_t &oldID);
@@ -115,6 +118,8 @@ public:
private:
static uint32 _UnsupportedIncompatibleFeatures(
ext2_super_block& superBlock);
static uint32 _UnsupportedReadOnlyFeatures(
ext2_super_block& superBlock);
uint32 _GroupDescriptorBlock(uint32 blockIndex);
private:
+22 -2
View File
@@ -149,6 +149,7 @@ struct ext2_super_block {
#define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001
#define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002
#define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004
#define EXT2_READ_ONLY_FEATURE_HUGE_FILE 0x0008
// incompatible features
#define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001
@@ -234,8 +235,13 @@ struct ext2_inode {
uint32 size_high;
};
uint32 fragment;
uint8 fragment_number;
uint8 fragment_size;
union {
struct {
uint8 fragment_number;
uint8 fragment_size;
};
uint16 num_blocks_high;
};
uint16 _padding;
uint16 uid_high;
uint16 gid_high;
@@ -247,6 +253,8 @@ struct ext2_inode {
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
@@ -286,6 +294,11 @@ struct ext2_inode {
SetMode((Mode() & ~mask) | (newMode & mask));
}
void ClearFlag(uint32 mask)
{
flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
}
void SetFlag(uint32 mask)
{
flags |= B_HOST_TO_LENDIAN_INT32(mask);
@@ -306,6 +319,12 @@ struct ext2_inode {
num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
}
void SetNumBlocks64(uint64 numBlocks)
{
num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
}
void SetAccessTime(time_t accessTime)
{
access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime);
@@ -373,6 +392,7 @@ struct ext2_inode {
#define EXT2_INODE_COMPRESSION_ERROR 0x00000800
#define EXT2_INODE_BTREE 0x00001000
#define EXT2_INODE_INDEXED 0x00001000
#define EXT2_INODE_HUGE_FILE 0x00040000
#define EXT2_NAME_LENGTH 255