* 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().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40129 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2011-01-05 21:56:12 +00:00
parent 970c0ac244
commit d482c34e49
15 changed files with 431 additions and 35 deletions

View File

@ -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 @@ public:
status_t Initialize(Volume* volume, uint32 blockGroup,
uint32 numBits);
status_t ScanFreeRanges();
bool IsFull() const;
status_t Allocate(Transaction& transaction, fsblock_t start,
@ -58,9 +57,12 @@ public:
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;
@ -130,7 +132,17 @@ AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup,
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 @@ AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup,
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 @@ AllocationBlockGroup::Allocate(Transaction& transaction, fsblock_t _start,
return B_BAD_VALUE;
_LockInTransaction(transaction);
_InitGroup(transaction);
BitmapBlock block(fVolume, fNumBits);
@ -252,6 +267,7 @@ AllocationBlockGroup::Allocate(Transaction& transaction, fsblock_t _start,
if (fLargestLength < fNumBits / 2)
block.FindLargestUnmarkedRange(fLargestStart, fLargestLength);
ASSERT(block.CheckUnmarked(fLargestStart, fLargestLength));
return B_OK;
}
@ -272,6 +288,8 @@ AllocationBlockGroup::Free(Transaction& transaction, uint32 start,
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 @@ AllocationBlockGroup::_LockInTransaction(Transaction& transaction)
}
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)
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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 @@ ExtentStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
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

View File

@ -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"

View File

@ -54,8 +54,7 @@ HTree::HTree(Volume* volume, Inode* directory)
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);

View File

@ -1,4 +1,5 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
@ -440,7 +441,7 @@ Inode::InitDirectory(Transaction& transaction, Inode* parent)
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 @@ Inode::_SetNumBlocks(uint64 numBlocks)
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);
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
@ -50,6 +51,9 @@ public:
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 @@ public:
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; }

View File

@ -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 @@ InodeAllocator::New(Transaction& transaction, Inode* parent, int32 mode,
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 @@ InodeAllocator::Free(Transaction& transaction, ino_t id, bool isDirectory)
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 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
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 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
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 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
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 @@ InodeAllocator::_UnmarkInBitmap(Transaction& transaction, fsblock_t bitmapBlock,
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;
}

View File

@ -37,6 +37,9 @@ private:
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;

View File

@ -23,6 +23,7 @@ KernelAddon ext2 :
BitmapBlock.cpp
BlockAllocator.cpp
InodeAllocator.cpp
CRCTable.cpp
kernel_interface.cpp
;

View File

@ -1,4 +1,5 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
* 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 @@ 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_EXTENTS
| EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP;
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
uint32 unsupported = superBlock.IncompatibleFeatures()
& ~supportedIncompatible;
@ -527,7 +530,9 @@ Volume::_UnsupportedReadOnlyFeatures(ext2_super_block& superBlock)
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 @@ Volume::_GroupDescriptorBlock(uint32 blockIndex)
}
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 @@ Volume::GetBlockGroup(int32 index, ext2_block_group** _group)
return B_BAD_VALUE;
int32 blockIndex = index / fGroupsPerBlock;
int32 blockOffset = index % fGroupsPerBlock;
MutexLocker _(fLock);
@ -580,12 +605,16 @@ Volume::GetBlockGroup(int32 index, ext2_block_group** _group)
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 @@ Volume::WriteBlockGroup(Transaction& transaction, int32 index)
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));
@ -633,6 +670,20 @@ Volume::ActivateLargeFiles(Transaction& transaction)
}
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)
{

View File

@ -1,4 +1,5 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
@ -76,20 +77,29 @@ public:
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 @@ private:
uint32 _GroupDescriptorBlock(uint32 blockIndex);
uint16 _GroupDescriptorSize()
{ return fGroupDescriptorSize; }
uint16 _GroupCheckSum(ext2_block_group *group,
int32 index);
private:
mutex fLock;

View File

@ -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@dauwalder.net
//---------------------------------------------------------------------
/*! \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;
}

View File

@ -60,7 +60,7 @@ struct ext2_super_block {
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 @@ struct ext2_super_block {
{ 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 @@ struct ext2_extent_stream {
} _PACKED;
#define EXT2_INODE_NORMAL_SIZE 128
#define EXT2_INODE_MAX_LINKS 65000
struct ext2_inode {
uint16 mode;