Author: korli Date: 2011-01-05 22:56:12 +0100 (Wed, 05 Jan 2011) New Revision: 40129 Changeset: http://dev.haiku-os.org/changeset/40129 Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/crc_table.cpp Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/HTree.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/InodeAllocator.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile 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 flex group, dirnlink and gdtchecksum features for ext4. * I reused crc_table.cpp from the UDF filesystem and switched it to have the reversed algorithm, then generated the table in CRCTable.cpp * added a binary search for extent tree leaves. * fixed a check in InodeAllocator::New(). Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Haiku Inc. All rights reserved. + * Copyright 2001-2011, Haiku Inc. All rights reserved. * This file may be used under the terms of the MIT License. * * Authors: @@ -36,7 +36,6 @@ status_t Initialize(Volume* volume, uint32 blockGroup, uint32 numBits); - status_t ScanFreeRanges(); bool IsFull() const; status_t Allocate(Transaction& transaction, fsblock_t start, @@ -58,10 +57,13 @@ void RemovedFromTransaction(); private: + status_t _ScanFreeRanges(); void _AddFreeRange(uint32 start, uint32 length); void _LockInTransaction(Transaction& transaction); + status_t _InitGroup(Transaction& transaction); + bool _IsSparse(); + uint32 _FirstFreeBlock(); - Volume* fVolume; uint32 fBlockGroup; ext2_block_group* fGroupDescriptor; @@ -130,7 +132,17 @@ fBitmapBlock = fGroupDescriptor->BlockBitmap(fVolume->Has64bitFeature()); - status = ScanFreeRanges(); + if (fGroupDescriptor->Flags() & EXT2_BLOCK_GROUP_BLOCK_UNINIT) { + fFreeBits = fGroupDescriptor->FreeBlocks(fVolume->Has64bitFeature()); + fLargestLength = fFreeBits; + fLargestStart = _FirstFreeBlock(); + TRACE("Group %ld is uninit\n", fBlockGroup); + return B_OK; + } + + status = _ScanFreeRanges(); + if (status != B_OK) + return status; if (fGroupDescriptor->FreeBlocks(fVolume->Has64bitFeature()) != fFreeBits) { @@ -152,14 +164,16 @@ status_t -AllocationBlockGroup::ScanFreeRanges() +AllocationBlockGroup::_ScanFreeRanges() { - TRACE("AllocationBlockGroup::ScanFreeRanges()\n"); + TRACE("AllocationBlockGroup::_ScanFreeRanges() for group %ld\n", + fBlockGroup); BitmapBlock block(fVolume, fNumBits); if (!block.SetTo(fBitmapBlock)) return B_ERROR; + fFreeBits = 0; uint32 start = 0; uint32 end = 0; @@ -201,6 +215,7 @@ return B_BAD_VALUE; _LockInTransaction(transaction); + _InitGroup(transaction); BitmapBlock block(fVolume, fNumBits); @@ -252,6 +267,7 @@ if (fLargestLength < fNumBits / 2) block.FindLargestUnmarkedRange(fLargestStart, fLargestLength); + ASSERT(block.CheckUnmarked(fLargestStart, fLargestLength)); return B_OK; } @@ -272,6 +288,8 @@ return B_BAD_VALUE; _LockInTransaction(transaction); + if (fGroupDescriptor->Flags() & EXT2_BLOCK_GROUP_BLOCK_UNINIT) + panic("AllocationBlockGroup::Free() can't free blocks if uninit\n"); BitmapBlock block(fVolume, fNumBits); @@ -402,6 +420,89 @@ } +status_t +AllocationBlockGroup::_InitGroup(Transaction& transaction) +{ + TRACE("AllocationBlockGroup::_InitGroup()\n"); + uint16 flags = fGroupDescriptor->Flags(); + if ((flags & EXT2_BLOCK_GROUP_BLOCK_UNINIT) == 0) + return B_OK; + + TRACE("AllocationBlockGroup::_InitGroup() initing\n"); + + BitmapBlock blockBitmap(fVolume, fNumBits); + if (!blockBitmap.SetToWritable(transaction, fBitmapBlock)) + return B_ERROR; + blockBitmap.Mark(0, _FirstFreeBlock(), true); + blockBitmap.Unmark(0, fNumBits, true); + + fGroupDescriptor->SetFlags(flags & ~EXT2_BLOCK_GROUP_BLOCK_UNINIT); + fVolume->WriteBlockGroup(transaction, fBlockGroup); + + status_t status = _ScanFreeRanges(); + if (status != B_OK) + return status; + + if (fGroupDescriptor->FreeBlocks(fVolume->Has64bitFeature()) + != fFreeBits) { + ERROR("AllocationBlockGroup(%lu,%lld)::_InitGroup(): Mismatch between " + "counted free blocks (%lu/%lu) and what is set on the group " + "descriptor (%lu)\n", fBlockGroup, fBitmapBlock, fFreeBits, + fNumBits, fGroupDescriptor->FreeBlocks( + fVolume->Has64bitFeature())); + return B_BAD_DATA; + } + + TRACE("AllocationBlockGroup::_InitGroup() init OK\n"); + + return B_OK; +} + + +bool +AllocationBlockGroup::_IsSparse() +{ + if (fBlockGroup <= 1) + return true; + if (fBlockGroup & 0x1) + return false; + + uint32 i = fBlockGroup; + while (i % 7 == 0) + i /= 7; + if (i == 1) + return true; + + i = fBlockGroup; + while (i % 5 == 0) + i /= 5; + if (i == 1) + return true; + + i = fBlockGroup; + while (i % 3 == 0) + i /= 3; + if (i == 1) + return true; + + return false; +} + + +uint32 +AllocationBlockGroup::_FirstFreeBlock() +{ + uint32 first = 1; + if (_IsSparse()) + first = 0; + else if (!fVolume->HasMetaGroupFeature()) { + first += fVolume->SuperBlock().ReservedGDTBlocks(); + first += fVolume->NumGroups(); + } + return first; +} + + void AllocationBlockGroup::TransactionDone(bool success) { Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -0,0 +1,69 @@ +/* + * Copyright 2011, Haiku Inc. All rights reserved. + * This file may be used under the terms of the MIT License. + * + * Authors: + * Jérôme Duval + */ + + +#include <SupportDefs.h> + + +//! CRC 0120001 table, as generated by crc_table.cpp +static uint16 kCrcTable[256] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 +}; + + +/*! \brief Calculates the UDF crc checksum for the given byte stream. + + Based on crc code from UDF-2.50 6.5, as permitted. + This is reversed. + + \param data Pointer to the byte stream. + \param length Length of the byte stream in bytes. + + \return The crc checksum, or 0 if an error occurred. +*/ +uint16 +calculate_crc(uint16 crc, uint8 *data, uint16 length) +{ + if (data) { + for ( ; length > 0; length--, data++) + crc = kCrcTable[(crc ^ *data) & 0xff] ^ (crc >> 8); + } + return crc; +} + Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.h (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/CRCTable.h 2011-01-05 21:56:12 UTC (rev 40129) @@ -0,0 +1,11 @@ +/* + * Copyright 2011, Haiku Inc. All rights reserved. + * This file may be used under the terms of the MIT License. + * + * Authors: + * Jérôme Duval + */ + +uint16 calculate_crc(uint16 crc, uint8 *data, uint16 length); + + Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Haiku Inc. All rights reserved. + * Copyright 2001-2011, Haiku Inc. All rights reserved. * This file may be used under the terms of the MIT License. * * Authors: @@ -77,6 +77,41 @@ panic("ExtentStream::FindBlock() invalid header\n"); } + if (stream->extent_header.NumEntries() > 7) { + // binary search when enough entries + int32 low = 0; + int32 high = stream->extent_header.NumEntries() - 1; + int32 middle = 0; + while (low <= high) { + middle = (high + low) / 2; + if (stream->extent_entries[middle].LogicalBlock() == index) + break; + if (stream->extent_entries[middle].LogicalBlock() < index) + low = middle + 1; + else + high = middle - 1; + } + if (stream->extent_entries[middle].LogicalBlock() > index) + middle--; + if (stream->extent_entries[middle].LogicalBlock() + + stream->extent_entries[middle].Length() > index) { + // sparse block + TRACE("FindBlock() sparse block index %lld at %ld\n", index, + stream->extent_entries[middle].LogicalBlock()); + block = 0xffffffff; + return B_OK; + } + + fileblock_t diff = index + - stream->extent_entries[middle].LogicalBlock(); + block = stream->extent_entries[middle].PhysicalBlock() + diff; + if (_count) + *_count = stream->extent_entries[middle].Length() - diff; + TRACE("FindBlock(offset %lld): %lld %ld\n", offset, + block, _count != NULL ? *_count : 1); + return B_OK; + } + for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) { if (stream->extent_entries[i].LogicalBlock() > index) { // sparse block Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.h 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/ExtentStream.h 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Haiku Inc. All rights reserved. + * Copyright 2001-2011, Haiku Inc. All rights reserved. * This file may be used under the terms of the MIT License. * * Authors: @@ -8,6 +8,7 @@ #ifndef EXTENTSTREAM_H #define EXTENTSTREAM_H + #include "ext2.h" #include "Transaction.h" Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/HTree.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/HTree.cpp 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/HTree.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -54,8 +54,7 @@ fRootEntry(NULL) { fBlockSize = volume->BlockSize(); - fIndexed = volume->IndexedDirectories() - && (directory->Flags() & EXT2_INODE_INDEXED) != 0; + fIndexed = directory->IsIndexed(); ext2_super_block superBlock = volume->SuperBlock(); fHashSeed[0] = superBlock.HashSeed(0); Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,4 +1,5 @@ /* + * Copyright 2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ @@ -440,7 +441,7 @@ root->dotdot_entry_name[0] = '.'; root->dotdot_entry_name[1] = '.'; - parent->Node().SetNumLinks(parent->Node().NumLinks() + 1); + parent->IncrementNumLinks(transaction); return parent->WriteBack(transaction); } @@ -911,3 +912,15 @@ return B_OK; } + +void +Inode::IncrementNumLinks(Transaction& transaction) +{ + fNode.SetNumLinks(fNode.NumLinks() + 1); + if (IsIndexed() && (fNode.NumLinks() >= EXT2_INODE_MAX_LINKS + || fNode.NumLinks() == 2)) { + fNode.SetNumLinks(1); + fVolume->ActivateDirNLink(transaction); + } +} + Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,4 +1,5 @@ /* + * Copyright 2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ @@ -50,6 +51,9 @@ bool IsDeleted() const { return fUnlinked; } bool HasExtraAttributes() const { return fHasExtraAttributes; } + bool IsIndexed() const + { return fVolume->IndexedDirectories() + && (Flags() & EXT2_INODE_INDEXED) != 0; } mode_t Mode() const { return fNode.Mode(); } int32 Flags() const { return fNode.Flags(); } @@ -75,6 +79,7 @@ fHasExtraAttributes); } void SetAccessTime(const struct timespec *timespec) { fNode.SetAccessTime(timespec, fHasExtraAttributes); } + void IncrementNumLinks(Transaction& transaction); //::Volume* _Volume() const { return fVolume; } Volume* GetVolume() const { return fVolume; } Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,8 +1,9 @@ /* - * Copyright 2001-2010, Haiku Inc. All rights reserved. + * Copyright 2001-2011, Haiku Inc. All rights reserved. * This file may be used under the terms of the MIT License. * * Authors: + * Jérôme Duval * Janito V. Ferreira Filho */ @@ -44,7 +45,7 @@ ino_t& id) { // Apply allocation policy - uint32 preferredBlockGroup = parent == NULL ? parent->ID() + uint32 preferredBlockGroup = parent != NULL ? (parent->ID() - 1) / parent->GetVolume()->InodesPerGroup() : 0; return _Allocate(transaction, preferredBlockGroup, S_ISDIR(mode), id); @@ -65,16 +66,20 @@ if (status != B_OK) return status; + if (group->Flags() & EXT2_BLOCK_GROUP_INODE_UNINIT) + panic("InodeAllocator::Free() can't free inodes if uninit\n"); + if (blockGroup == fVolume->NumGroups() - 1) numInodes = fVolume->NumInodes() - blockGroup * numInodes; TRACE("InodeAllocator::Free(): Updating block group data\n"); group->SetFreeInodes(group->FreeInodes(fVolume->Has64bitFeature()) + 1, fVolume->Has64bitFeature()); - if (isDirectory) + if (isDirectory) { group->SetUsedDirectories( group->UsedDirectories(fVolume->Has64bitFeature()) - 1, fVolume->Has64bitFeature()); + } status = fVolume->WriteBlockGroup(transaction, blockGroup); if (status != B_OK) @@ -104,6 +109,8 @@ return status; } + fsblock_t block = group->InodeBitmap(fVolume->Has64bitFeature()); + _InitGroup(transaction, group, block, fVolume->InodesPerGroup()); uint32 freeInodes = group->FreeInodes(fVolume->Has64bitFeature()); if (freeInodes != 0) { TRACE("InodeAllocator::_Allocate() freeInodes %ld bitmap %lld\n", @@ -118,8 +125,7 @@ if (status != B_OK) return status; - return _MarkInBitmap(transaction, - group->InodeBitmap(fVolume->Has64bitFeature()), + return _MarkInBitmap(transaction, block, blockGroup, fVolume->InodesPerGroup(), id); } } @@ -133,16 +139,27 @@ return status; } + uint32 numInodes = fVolume->NumInodes() + - blockGroup * fVolume->InodesPerGroup(); + fsblock_t block = group->InodeBitmap(fVolume->Has64bitFeature()); + _InitGroup(transaction, group, block, numInodes); uint32 freeInodes = group->FreeInodes(fVolume->Has64bitFeature()); if (freeInodes != 0) { TRACE("InodeAllocator::_Allocate() freeInodes %ld\n", freeInodes); group->SetFreeInodes(freeInodes - 1, fVolume->Has64bitFeature()); + if (isDirectory) { + group->SetUsedDirectories(group->UsedDirectories( + fVolume->Has64bitFeature()) + 1, + fVolume->Has64bitFeature()); + } - return _MarkInBitmap(transaction, - group->InodeBitmap(fVolume->Has64bitFeature()), - blockGroup, fVolume->NumInodes() - - blockGroup * fVolume->InodesPerGroup(), id); + status = fVolume->WriteBlockGroup(transaction, blockGroup); + if (status != B_OK) + return status; + + return _MarkInBitmap(transaction, block, + blockGroup, numInodes, id); } } @@ -209,3 +226,23 @@ return B_OK; } + + +status_t +InodeAllocator::_InitGroup(Transaction& transaction, ext2_block_group* group, + fsblock_t bitmapBlock, uint32 numInodes) +{ + uint16 flags = group->Flags(); + if ((flags & EXT2_BLOCK_GROUP_INODE_UNINIT) == 0) + return B_OK; + + TRACE("InodeAllocator::_InitGroup() initing group\n"); + BitmapBlock inodeBitmap(fVolume, numInodes); + if (!inodeBitmap.SetToWritable(transaction, bitmapBlock)) + return B_ERROR; + inodeBitmap.Unmark(0, numInodes, true); + group->SetFlags(flags & ~EXT2_BLOCK_GROUP_INODE_UNINIT); + + return B_OK; +} + Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.h 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/InodeAllocator.h 2011-01-05 21:56:12 UTC (rev 40129) @@ -37,6 +37,9 @@ uint32 numInodes, ino_t& id); status_t _UnmarkInBitmap(Transaction& transaction, fsblock_t bitmapBlock, uint32 numInodes, ino_t id); + status_t _InitGroup(Transaction& transaction, + ext2_block_group* group, fsblock_t bitmapBlock, + uint32 numInodes); Volume* fVolume; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile 2011-01-05 21:56:12 UTC (rev 40129) @@ -23,6 +23,7 @@ BitmapBlock.cpp BlockAllocator.cpp InodeAllocator.cpp + CRCTable.cpp kernel_interface.cpp ; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,4 +1,5 @@ /* + * Copyright 2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ @@ -21,6 +22,7 @@ #include <util/AutoLock.h> #include "CachedBlock.h" +#include "CRCTable.h" #include "Inode.h" #include "InodeJournal.h" #include "NoJournal.h" @@ -507,7 +509,8 @@ uint32 supportedIncompatible = EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE | EXT2_INCOMPATIBLE_FEATURE_RECOVER | EXT2_INCOMPATIBLE_FEATURE_JOURNAL - | EXT2_INCOMPATIBLE_FEATURE_EXTENTS; + | EXT2_INCOMPATIBLE_FEATURE_EXTENTS + | EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP; /*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/; uint32 unsupported = superBlock.IncompatibleFeatures() & ~supportedIncompatible; @@ -527,7 +530,9 @@ uint32 supportedReadOnly = EXT2_READ_ONLY_FEATURE_SPARSE_SUPER | EXT2_READ_ONLY_FEATURE_LARGE_FILE | EXT2_READ_ONLY_FEATURE_HUGE_FILE - | EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE; + | EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE + | EXT2_READ_ONLY_FEATURE_DIR_NLINK + | EXT2_READ_ONLY_FEATURE_GDT_CSUM; // TODO actually implement EXT2_READ_ONLY_FEATURE_SPARSE_SUPER when // implementing superblock backup copies @@ -553,6 +558,25 @@ } +uint16 +Volume::_GroupCheckSum(ext2_block_group *group, int32 index) +{ + uint16 checksum = 0; + if (HasChecksumFeature()) { + int32 number = B_HOST_TO_LENDIAN_INT32(index); + checksum = calculate_crc(0xffff, fSuperBlock.uuid, + sizeof(fSuperBlock.uuid)); + checksum = calculate_crc(checksum, (uint8*)&number, sizeof(number)); + checksum = calculate_crc(checksum, (uint8*)group, 30); + if (Has64bitFeature()) { + checksum = calculate_crc(checksum, (uint8*)group + 34, + fGroupDescriptorSize - 34); + } + } + return checksum; +} + + /*! Makes the requested block group available. The block groups are loaded on demand, but are kept in memory until the volume is unmounted; therefore we don't use the block cache. @@ -564,6 +588,7 @@ return B_BAD_VALUE; int32 blockIndex = index / fGroupsPerBlock; + int32 blockOffset = index % fGroupsPerBlock; MutexLocker _(fLock); @@ -580,12 +605,16 @@ memcpy(fGroupBlocks[blockIndex], block, fBlockSize); TRACE("group [%ld]: inode table %lld\n", index, ((ext2_block_group*) - (fGroupBlocks[blockIndex] + (index % fGroupsPerBlock) - * fGroupDescriptorSize))->InodeTable(Has64bitFeature())); + (fGroupBlocks[blockIndex] + blockOffset + * fGroupDescriptorSize))->InodeTable(Has64bitFeature())); } *_group = (ext2_block_group*)(fGroupBlocks[blockIndex] - + (index % fGroupsPerBlock) * fGroupDescriptorSize); + + blockOffset * fGroupDescriptorSize); + if (HasChecksumFeature() + && (*_group)->checksum != _GroupCheckSum(*_group, index)) { + return B_BAD_DATA; + } return B_OK; } @@ -599,12 +628,20 @@ TRACE("Volume::WriteBlockGroup()\n"); int32 blockIndex = index / fGroupsPerBlock; + int32 blockOffset = index % fGroupsPerBlock; MutexLocker _(fLock); if (fGroupBlocks[blockIndex] == NULL) return B_BAD_VALUE; + ext2_block_group *group = (ext2_block_group*)(fGroupBlocks[blockIndex] + + blockOffset * fGroupDescriptorSize); + + group->checksum = _GroupCheckSum(group, index); + TRACE("Volume::WriteBlockGroup() checksum 0x%x for group %ld\n", + group->checksum, index); + CachedBlock cached(this); uint8* block = cached.SetToWritable(transaction, _GroupDescriptorBlock(blockIndex)); @@ -634,6 +671,20 @@ status_t +Volume::ActivateDirNLink(Transaction& transaction) +{ + if ((fSuperBlock.ReadOnlyFeatures() + & EXT2_READ_ONLY_FEATURE_DIR_NLINK) != 0) + return B_OK; + + fSuperBlock.SetReadOnlyFeatures(fSuperBlock.ReadOnlyFeatures() + | EXT2_READ_ONLY_FEATURE_DIR_NLINK); + + return WriteSuperBlock(transaction); +} + + +status_t Volume::SaveOrphan(Transaction& transaction, ino_t newID, ino_t& oldID) { oldID = fSuperBlock.LastOrphan(); Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Volume.h 2011-01-05 21:56:12 UTC (rev 40129) @@ -1,4 +1,5 @@ /* + * Copyright 2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ @@ -76,20 +77,29 @@ Journal* GetJournal() { return fJournal; } bool IndexedDirectories() const - { return (fSuperBlock.CompatibleFeatures() - & EXT2_FEATURE_DIRECTORY_INDEX) != 0; } + { return (fSuperBlock.CompatibleFeatures() + & EXT2_FEATURE_DIRECTORY_INDEX) != 0; } bool Has64bitFeature() const - { return (fSuperBlock.CompatibleFeatures() - & EXT2_INCOMPATIBLE_FEATURE_64BIT) != 0; } + { return (fSuperBlock.CompatibleFeatures() + & EXT2_INCOMPATIBLE_FEATURE_64BIT) != 0; } bool HasExtentsFeature() const - { return (fSuperBlock.IncompatibleFeatures() - & EXT2_INCOMPATIBLE_FEATURE_EXTENTS) != 0; } + { return (fSuperBlock.IncompatibleFeatures() + & EXT2_INCOMPATIBLE_FEATURE_EXTENTS) + != 0; } + bool HasChecksumFeature() const + { return (fSuperBlock.ReadOnlyFeatures() + & EXT2_READ_ONLY_FEATURE_GDT_CSUM) != 0; } + bool HasMetaGroupFeature() const + { return (fSuperBlock.IncompatibleFeatures() + & EXT2_INCOMPATIBLE_FEATURE_META_GROUP) + != 0; } uint8 DefaultHashVersion() const - { return fSuperBlock.default_hash_version; } + { return fSuperBlock.default_hash_version; } bool HugeFiles() const - { return (fSuperBlock.ReadOnlyFeatures() - & EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; } + { return (fSuperBlock.ReadOnlyFeatures() + & EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; } status_t ActivateLargeFiles(Transaction& transaction); + status_t ActivateDirNLink(Transaction& transaction); status_t SaveOrphan(Transaction& transaction, ino_t newID, ino_t &oldID); @@ -131,6 +141,8 @@ uint32 _GroupDescriptorBlock(uint32 blockIndex); uint16 _GroupDescriptorSize() { return fGroupDescriptorSize; } + uint16 _GroupCheckSum(ext2_block_group *group, + int32 index); private: mutex fLock; Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/crc_table.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/crc_table.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/crc_table.cpp 2011-01-05 21:56:12 UTC (rev 40129) @@ -0,0 +1,55 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx +//--------------------------------------------------------------------- + +/*! \file crc_table.cpp + + Standalone program to generate the CRC table used for calculating + UDF tag id CRC values. + + This code based off of crc code in UDF-2.50 specs, as permitted. + See UDF-2.50 6.5 for more information. + + Reversed version by Jérôme Duval +*/ + +#include <stdio.h> +#include <sys/types.h> + +int +main(int argc, char *argv[]) { + ulong crc, poly; + + if (argc != 2) { + fprintf(stderr, "USAGE: crc_table <octal polynomial=120001 for ext2>\n"); + return 0; + } + + sscanf(argv[1], "%lo", &poly); + if (poly & 0xffff0000) { + fprintf(stderr, "ERROR: polynomial is too large, sucka.\n"); + return 0; + } + + printf("//! CRC 0%o table, as generated by crc_table.cpp\n", poly); + printf("static uint16 crc_table[256] = { \n"); + for (int n = 0; n < 256; n++) { + if (n%8 == 0) + printf(" "); + crc = n; + for (int i = 0; i < 8; i++) { + if (crc & 0x0001) + crc = (crc >> 1) ^ poly; + else + crc >>= 1; + } + printf("0x%04x%s ", crc, (n != 255 ? "," : "")); + if (n%8 == 7) + printf("\n"); + } + printf("};\n"); + return 0; +} Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h 2011-01-05 21:06:57 UTC (rev 40128) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h 2011-01-05 21:56:12 UTC (rev 40129) @@ -60,7 +60,7 @@ uint32 algorithm_usage_bitmap; uint8 preallocated_blocks; uint8 preallocated_directory_blocks; - uint16 _padding; + uint16 reserved_gdt_blocks; // journaling ext3 support uint8 journal_uuid[16]; @@ -127,6 +127,8 @@ { return B_LENDIAN_TO_HOST_INT32(read_only_features); } uint32 IncompatibleFeatures() const { return B_LENDIAN_TO_HOST_INT32(incompatible_features); } + uint16 ReservedGDTBlocks() const + { return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); } ino_t JournalInode() const { return B_LENDIAN_TO_HOST_INT32(journal_inode); } ino_t LastOrphan() const @@ -383,6 +385,7 @@ } _PACKED; #define EXT2_INODE_NORMAL_SIZE 128 +#define EXT2_INODE_MAX_LINKS 65000 struct ext2_inode { uint16 mode;