Author: korli Date: 2010-10-11 21:58:46 +0200 (Mon, 11 Oct 2010) New Revision: 38950 Changeset: http://dev.haiku-os.org/changeset/38950 Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/DataStream.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h Log: * 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). Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp 2010-10-11 19:58:46 UTC (rev 38950) @@ -94,7 +94,8 @@ return false; index += 1; - } + } else + iterations++; for (; iterations > 0; --iterations) { if (data[index++] != 0) @@ -153,7 +154,8 @@ return false; index += 1; - } + } else + iterations++; mask = 0xFFFFFFFF; for (; iterations > 0; --iterations) { @@ -216,7 +218,8 @@ 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 @@ fData[index] = B_HOST_TO_LENDIAN_INT32(bits); index += 1; - } + } else + iterations++; mask = 0xFFFFFFFF; for (; iterations > 0; --iterations) { @@ -237,8 +241,8 @@ 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 @@ TRACE("BitmapBlock::Unmark(): updated bits: %lx\n", bits); index += 1; - } + } else + iterations++; mask = 0xFFFFFFFF; for (; iterations > 0; --iterations) { @@ -656,9 +661,3 @@ } } - -uint32 -BitmapBlock::NumBits() const -{ - return fNumBits; -} Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.h 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/BitmapBlock.h 2010-10-11 19:58:46 UTC (rev 38950) @@ -36,7 +36,7 @@ void FindLargestUnmarkedRange(uint32& start, uint32& length); - uint32 NumBits() const; + uint32 NumBits() const { return fNumBits; } protected: uint32* fData; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp 2010-10-11 19:58:46 UTC (rev 38950) @@ -180,7 +180,7 @@ 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 @@ { 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", Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/DataStream.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/DataStream.cpp 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/DataStream.cpp 2010-10-11 19:58:46 UTC (rev 38950) @@ -25,7 +25,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ else if (recursion == 2) elementWidth = kIndirectsPerBlock2; else { - panic("Undefinied recursion level\n"); + panic("Undefined recursion level\n"); elementWidth = 0; } Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp 2010-10-11 19:58:46 UTC (rev 38950) @@ -868,9 +868,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h 2010-10-11 19:58:46 UTC (rev 38950) @@ -100,6 +100,8 @@ off_t size); status_t _ShrinkDataStream(Transaction& transaction, off_t size); + uint64 _NumBlocks(); + status_t _SetNumBlocks(uint64 numBlocks); rw_lock fLock; ::Volume* fVolume; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp 2010-10-11 19:58:46 UTC (rev 38950) @@ -32,6 +32,7 @@ #else # define TRACE(x...) ; #endif +# define FATAL(x...) dprintf("\33[34mext2:\33[0m " x) class DeviceOpener { @@ -284,13 +285,17 @@ if (opener.IsReadOnly()) fFlags |= VOLUME_READ_ONLY; + TRACE("features %lx, incompatible features %lx, read-only features %lx\n", + fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(), + fSuperBlock.ReadOnlyFeatures()); + // read the super block - if (Identify(fDevice, &fSuperBlock) != B_OK) { - //FATAL(("invalid super block!\n")); - return B_BAD_VALUE; - } - - if (_UnsupportedIncompatibleFeatures(fSuperBlock) != 0) + 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 @@ 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 @@ // 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 @@ 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,18 +472,35 @@ | 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; +} + + uint32 Volume::_GroupDescriptorBlock(uint32 blockIndex) { @@ -796,8 +816,10 @@ 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; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h 2010-10-11 19:58:46 UTC (rev 38950) @@ -79,6 +79,9 @@ & 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 @@ private: static uint32 _UnsupportedIncompatibleFeatures( ext2_super_block& superBlock); + static uint32 _UnsupportedReadOnlyFeatures( + ext2_super_block& superBlock); uint32 _GroupDescriptorBlock(uint32 blockIndex); private: Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h 2010-10-11 17:51:44 UTC (rev 38949) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h 2010-10-11 19:58:46 UTC (rev 38950) @@ -149,6 +149,7 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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