* 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
@@ -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. * This file may be used under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -36,7 +36,6 @@ public:
status_t Initialize(Volume* volume, uint32 blockGroup, status_t Initialize(Volume* volume, uint32 blockGroup,
uint32 numBits); uint32 numBits);
status_t ScanFreeRanges();
bool IsFull() const; bool IsFull() const;
status_t Allocate(Transaction& transaction, fsblock_t start, status_t Allocate(Transaction& transaction, fsblock_t start,
@@ -58,9 +57,12 @@ public:
void RemovedFromTransaction(); void RemovedFromTransaction();
private: private:
status_t _ScanFreeRanges();
void _AddFreeRange(uint32 start, uint32 length); void _AddFreeRange(uint32 start, uint32 length);
void _LockInTransaction(Transaction& transaction); void _LockInTransaction(Transaction& transaction);
status_t _InitGroup(Transaction& transaction);
bool _IsSparse();
uint32 _FirstFreeBlock();
Volume* fVolume; Volume* fVolume;
uint32 fBlockGroup; uint32 fBlockGroup;
@@ -130,7 +132,17 @@ AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup,
fBitmapBlock = fGroupDescriptor->BlockBitmap(fVolume->Has64bitFeature()); 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()) if (fGroupDescriptor->FreeBlocks(fVolume->Has64bitFeature())
!= fFreeBits) { != fFreeBits) {
@@ -152,14 +164,16 @@ AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup,
status_t status_t
AllocationBlockGroup::ScanFreeRanges() AllocationBlockGroup::_ScanFreeRanges()
{ {
TRACE("AllocationBlockGroup::ScanFreeRanges()\n"); TRACE("AllocationBlockGroup::_ScanFreeRanges() for group %ld\n",
fBlockGroup);
BitmapBlock block(fVolume, fNumBits); BitmapBlock block(fVolume, fNumBits);
if (!block.SetTo(fBitmapBlock)) if (!block.SetTo(fBitmapBlock))
return B_ERROR; return B_ERROR;
fFreeBits = 0;
uint32 start = 0; uint32 start = 0;
uint32 end = 0; uint32 end = 0;
@@ -201,6 +215,7 @@ AllocationBlockGroup::Allocate(Transaction& transaction, fsblock_t _start,
return B_BAD_VALUE; return B_BAD_VALUE;
_LockInTransaction(transaction); _LockInTransaction(transaction);
_InitGroup(transaction);
BitmapBlock block(fVolume, fNumBits); BitmapBlock block(fVolume, fNumBits);
@@ -252,6 +267,7 @@ AllocationBlockGroup::Allocate(Transaction& transaction, fsblock_t _start,
if (fLargestLength < fNumBits / 2) if (fLargestLength < fNumBits / 2)
block.FindLargestUnmarkedRange(fLargestStart, fLargestLength); block.FindLargestUnmarkedRange(fLargestStart, fLargestLength);
ASSERT(block.CheckUnmarked(fLargestStart, fLargestLength));
return B_OK; return B_OK;
} }
@@ -272,6 +288,8 @@ AllocationBlockGroup::Free(Transaction& transaction, uint32 start,
return B_BAD_VALUE; return B_BAD_VALUE;
_LockInTransaction(transaction); _LockInTransaction(transaction);
if (fGroupDescriptor->Flags() & EXT2_BLOCK_GROUP_BLOCK_UNINIT)
panic("AllocationBlockGroup::Free() can't free blocks if uninit\n");
BitmapBlock block(fVolume, fNumBits); 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 void
AllocationBlockGroup::TransactionDone(bool success) AllocationBlockGroup::TransactionDone(bool success)
{ {
@@ -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;
}
@@ -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);
@@ -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. * This file may be used under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -77,6 +77,41 @@ ExtentStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
panic("ExtentStream::FindBlock() invalid header\n"); 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++) { for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
if (stream->extent_entries[i].LogicalBlock() > index) { if (stream->extent_entries[i].LogicalBlock() > index) {
// sparse block // sparse block
@@ -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. * This file may be used under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -8,6 +8,7 @@
#ifndef EXTENTSTREAM_H #ifndef EXTENTSTREAM_H
#define EXTENTSTREAM_H #define EXTENTSTREAM_H
#include "ext2.h" #include "ext2.h"
#include "Transaction.h" #include "Transaction.h"
@@ -54,8 +54,7 @@ HTree::HTree(Volume* volume, Inode* directory)
fRootEntry(NULL) fRootEntry(NULL)
{ {
fBlockSize = volume->BlockSize(); fBlockSize = volume->BlockSize();
fIndexed = volume->IndexedDirectories() fIndexed = directory->IsIndexed();
&& (directory->Flags() & EXT2_INODE_INDEXED) != 0;
ext2_super_block superBlock = volume->SuperBlock(); ext2_super_block superBlock = volume->SuperBlock();
fHashSeed[0] = superBlock.HashSeed(0); fHashSeed[0] = superBlock.HashSeed(0);
+14 -1
View File
@@ -1,4 +1,5 @@
/* /*
* Copyright 2011, Jérôme Duval, [email protected].
* Copyright 2008, Axel Dörfler, [email protected]. * Copyright 2008, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License. * 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[0] = '.';
root->dotdot_entry_name[1] = '.'; root->dotdot_entry_name[1] = '.';
parent->Node().SetNumLinks(parent->Node().NumLinks() + 1); parent->IncrementNumLinks(transaction);
return parent->WriteBack(transaction); return parent->WriteBack(transaction);
} }
@@ -911,3 +912,15 @@ Inode::_SetNumBlocks(uint64 numBlocks)
return B_OK; 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);
}
}
@@ -1,4 +1,5 @@
/* /*
* Copyright 2011, Jérôme Duval, [email protected].
* Copyright 2008, Axel Dörfler, [email protected]. * Copyright 2008, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -50,6 +51,9 @@ public:
bool IsDeleted() const { return fUnlinked; } bool IsDeleted() const { return fUnlinked; }
bool HasExtraAttributes() const bool HasExtraAttributes() const
{ return fHasExtraAttributes; } { return fHasExtraAttributes; }
bool IsIndexed() const
{ return fVolume->IndexedDirectories()
&& (Flags() & EXT2_INODE_INDEXED) != 0; }
mode_t Mode() const { return fNode.Mode(); } mode_t Mode() const { return fNode.Mode(); }
int32 Flags() const { return fNode.Flags(); } int32 Flags() const { return fNode.Flags(); }
@@ -75,6 +79,7 @@ public:
fHasExtraAttributes); } fHasExtraAttributes); }
void SetAccessTime(const struct timespec *timespec) void SetAccessTime(const struct timespec *timespec)
{ fNode.SetAccessTime(timespec, fHasExtraAttributes); } { fNode.SetAccessTime(timespec, fHasExtraAttributes); }
void IncrementNumLinks(Transaction& transaction);
//::Volume* _Volume() const { return fVolume; } //::Volume* _Volume() const { return fVolume; }
Volume* GetVolume() const { return fVolume; } Volume* GetVolume() const { return fVolume; }
@@ -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. * This file may be used under the terms of the MIT License.
* *
* Authors: * Authors:
* Jérôme Duval
* Janito V. Ferreira Filho * Janito V. Ferreira Filho
*/ */
@@ -44,7 +45,7 @@ InodeAllocator::New(Transaction& transaction, Inode* parent, int32 mode,
ino_t& id) ino_t& id)
{ {
// Apply allocation policy // Apply allocation policy
uint32 preferredBlockGroup = parent == NULL ? parent->ID() uint32 preferredBlockGroup = parent != NULL ? (parent->ID() - 1)
/ parent->GetVolume()->InodesPerGroup() : 0; / parent->GetVolume()->InodesPerGroup() : 0;
return _Allocate(transaction, preferredBlockGroup, S_ISDIR(mode), id); 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) if (status != B_OK)
return status; 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) if (blockGroup == fVolume->NumGroups() - 1)
numInodes = fVolume->NumInodes() - blockGroup * numInodes; numInodes = fVolume->NumInodes() - blockGroup * numInodes;
TRACE("InodeAllocator::Free(): Updating block group data\n"); TRACE("InodeAllocator::Free(): Updating block group data\n");
group->SetFreeInodes(group->FreeInodes(fVolume->Has64bitFeature()) + 1, group->SetFreeInodes(group->FreeInodes(fVolume->Has64bitFeature()) + 1,
fVolume->Has64bitFeature()); fVolume->Has64bitFeature());
if (isDirectory) if (isDirectory) {
group->SetUsedDirectories( group->SetUsedDirectories(
group->UsedDirectories(fVolume->Has64bitFeature()) - 1, group->UsedDirectories(fVolume->Has64bitFeature()) - 1,
fVolume->Has64bitFeature()); fVolume->Has64bitFeature());
}
status = fVolume->WriteBlockGroup(transaction, blockGroup); status = fVolume->WriteBlockGroup(transaction, blockGroup);
if (status != B_OK) if (status != B_OK)
@@ -104,6 +109,8 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
return status; return status;
} }
fsblock_t block = group->InodeBitmap(fVolume->Has64bitFeature());
_InitGroup(transaction, group, block, fVolume->InodesPerGroup());
uint32 freeInodes = group->FreeInodes(fVolume->Has64bitFeature()); uint32 freeInodes = group->FreeInodes(fVolume->Has64bitFeature());
if (freeInodes != 0) { if (freeInodes != 0) {
TRACE("InodeAllocator::_Allocate() freeInodes %ld bitmap %lld\n", TRACE("InodeAllocator::_Allocate() freeInodes %ld bitmap %lld\n",
@@ -118,8 +125,7 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
if (status != B_OK) if (status != B_OK)
return status; return status;
return _MarkInBitmap(transaction, return _MarkInBitmap(transaction, block,
group->InodeBitmap(fVolume->Has64bitFeature()),
blockGroup, fVolume->InodesPerGroup(), id); blockGroup, fVolume->InodesPerGroup(), id);
} }
} }
@@ -133,16 +139,27 @@ InodeAllocator::_Allocate(Transaction& transaction, uint32 preferredBlockGroup,
return status; 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()); uint32 freeInodes = group->FreeInodes(fVolume->Has64bitFeature());
if (freeInodes != 0) { if (freeInodes != 0) {
TRACE("InodeAllocator::_Allocate() freeInodes %ld\n", freeInodes); TRACE("InodeAllocator::_Allocate() freeInodes %ld\n", freeInodes);
group->SetFreeInodes(freeInodes - 1, group->SetFreeInodes(freeInodes - 1,
fVolume->Has64bitFeature()); fVolume->Has64bitFeature());
if (isDirectory) {
group->SetUsedDirectories(group->UsedDirectories(
fVolume->Has64bitFeature()) + 1,
fVolume->Has64bitFeature());
}
return _MarkInBitmap(transaction, status = fVolume->WriteBlockGroup(transaction, blockGroup);
group->InodeBitmap(fVolume->Has64bitFeature()), if (status != B_OK)
blockGroup, fVolume->NumInodes() return status;
- blockGroup * fVolume->InodesPerGroup(), id);
return _MarkInBitmap(transaction, block,
blockGroup, numInodes, id);
} }
} }
@@ -209,3 +226,23 @@ InodeAllocator::_UnmarkInBitmap(Transaction& transaction, fsblock_t bitmapBlock,
return B_OK; 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;
}
@@ -37,6 +37,9 @@ private:
uint32 numInodes, ino_t& id); uint32 numInodes, ino_t& id);
status_t _UnmarkInBitmap(Transaction& transaction, status_t _UnmarkInBitmap(Transaction& transaction,
fsblock_t bitmapBlock, uint32 numInodes, ino_t id); fsblock_t bitmapBlock, uint32 numInodes, ino_t id);
status_t _InitGroup(Transaction& transaction,
ext2_block_group* group, fsblock_t bitmapBlock,
uint32 numInodes);
Volume* fVolume; Volume* fVolume;
@@ -23,6 +23,7 @@ KernelAddon ext2 :
BitmapBlock.cpp BitmapBlock.cpp
BlockAllocator.cpp BlockAllocator.cpp
InodeAllocator.cpp InodeAllocator.cpp
CRCTable.cpp
kernel_interface.cpp kernel_interface.cpp
; ;
@@ -1,4 +1,5 @@
/* /*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -21,6 +22,7 @@
#include <util/AutoLock.h> #include <util/AutoLock.h>
#include "CachedBlock.h" #include "CachedBlock.h"
#include "CRCTable.h"
#include "Inode.h" #include "Inode.h"
#include "InodeJournal.h" #include "InodeJournal.h"
#include "NoJournal.h" #include "NoJournal.h"
@@ -507,7 +509,8 @@ Volume::_UnsupportedIncompatibleFeatures(ext2_super_block& superBlock)
uint32 supportedIncompatible = EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE uint32 supportedIncompatible = EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE
| EXT2_INCOMPATIBLE_FEATURE_RECOVER | EXT2_INCOMPATIBLE_FEATURE_RECOVER
| EXT2_INCOMPATIBLE_FEATURE_JOURNAL | EXT2_INCOMPATIBLE_FEATURE_JOURNAL
| EXT2_INCOMPATIBLE_FEATURE_EXTENTS; | EXT2_INCOMPATIBLE_FEATURE_EXTENTS
| EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP;
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/; /*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
uint32 unsupported = superBlock.IncompatibleFeatures() uint32 unsupported = superBlock.IncompatibleFeatures()
& ~supportedIncompatible; & ~supportedIncompatible;
@@ -527,7 +530,9 @@ Volume::_UnsupportedReadOnlyFeatures(ext2_super_block& superBlock)
uint32 supportedReadOnly = EXT2_READ_ONLY_FEATURE_SPARSE_SUPER uint32 supportedReadOnly = EXT2_READ_ONLY_FEATURE_SPARSE_SUPER
| EXT2_READ_ONLY_FEATURE_LARGE_FILE | EXT2_READ_ONLY_FEATURE_LARGE_FILE
| EXT2_READ_ONLY_FEATURE_HUGE_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 // TODO actually implement EXT2_READ_ONLY_FEATURE_SPARSE_SUPER when
// implementing superblock backup copies // 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. /*! Makes the requested block group available.
The block groups are loaded on demand, but are kept in memory until the 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. 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; return B_BAD_VALUE;
int32 blockIndex = index / fGroupsPerBlock; int32 blockIndex = index / fGroupsPerBlock;
int32 blockOffset = index % fGroupsPerBlock;
MutexLocker _(fLock); MutexLocker _(fLock);
@@ -580,12 +605,16 @@ Volume::GetBlockGroup(int32 index, ext2_block_group** _group)
memcpy(fGroupBlocks[blockIndex], block, fBlockSize); memcpy(fGroupBlocks[blockIndex], block, fBlockSize);
TRACE("group [%ld]: inode table %lld\n", index, ((ext2_block_group*) TRACE("group [%ld]: inode table %lld\n", index, ((ext2_block_group*)
(fGroupBlocks[blockIndex] + (index % fGroupsPerBlock) (fGroupBlocks[blockIndex] + blockOffset
* fGroupDescriptorSize))->InodeTable(Has64bitFeature())); * fGroupDescriptorSize))->InodeTable(Has64bitFeature()));
} }
*_group = (ext2_block_group*)(fGroupBlocks[blockIndex] *_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; return B_OK;
} }
@@ -599,12 +628,20 @@ Volume::WriteBlockGroup(Transaction& transaction, int32 index)
TRACE("Volume::WriteBlockGroup()\n"); TRACE("Volume::WriteBlockGroup()\n");
int32 blockIndex = index / fGroupsPerBlock; int32 blockIndex = index / fGroupsPerBlock;
int32 blockOffset = index % fGroupsPerBlock;
MutexLocker _(fLock); MutexLocker _(fLock);
if (fGroupBlocks[blockIndex] == NULL) if (fGroupBlocks[blockIndex] == NULL)
return B_BAD_VALUE; 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); CachedBlock cached(this);
uint8* block = cached.SetToWritable(transaction, uint8* block = cached.SetToWritable(transaction,
_GroupDescriptorBlock(blockIndex)); _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 status_t
Volume::SaveOrphan(Transaction& transaction, ino_t newID, ino_t& oldID) Volume::SaveOrphan(Transaction& transaction, ino_t newID, ino_t& oldID)
{ {
+21 -9
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. * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -76,20 +77,29 @@ public:
Journal* GetJournal() { return fJournal; } Journal* GetJournal() { return fJournal; }
bool IndexedDirectories() const bool IndexedDirectories() const
{ return (fSuperBlock.CompatibleFeatures() { return (fSuperBlock.CompatibleFeatures()
& EXT2_FEATURE_DIRECTORY_INDEX) != 0; } & EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
bool Has64bitFeature() const bool Has64bitFeature() const
{ return (fSuperBlock.CompatibleFeatures() { return (fSuperBlock.CompatibleFeatures()
& EXT2_INCOMPATIBLE_FEATURE_64BIT) != 0; } & EXT2_INCOMPATIBLE_FEATURE_64BIT) != 0; }
bool HasExtentsFeature() const bool HasExtentsFeature() const
{ return (fSuperBlock.IncompatibleFeatures() { return (fSuperBlock.IncompatibleFeatures()
& EXT2_INCOMPATIBLE_FEATURE_EXTENTS) != 0; } & 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 uint8 DefaultHashVersion() const
{ return fSuperBlock.default_hash_version; } { return fSuperBlock.default_hash_version; }
bool HugeFiles() const bool HugeFiles() const
{ return (fSuperBlock.ReadOnlyFeatures() { return (fSuperBlock.ReadOnlyFeatures()
& EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; } & EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; }
status_t ActivateLargeFiles(Transaction& transaction); status_t ActivateLargeFiles(Transaction& transaction);
status_t ActivateDirNLink(Transaction& transaction);
status_t SaveOrphan(Transaction& transaction, status_t SaveOrphan(Transaction& transaction,
ino_t newID, ino_t &oldID); ino_t newID, ino_t &oldID);
@@ -131,6 +141,8 @@ private:
uint32 _GroupDescriptorBlock(uint32 blockIndex); uint32 _GroupDescriptorBlock(uint32 blockIndex);
uint16 _GroupDescriptorSize() uint16 _GroupDescriptorSize()
{ return fGroupDescriptorSize; } { return fGroupDescriptorSize; }
uint16 _GroupCheckSum(ext2_block_group *group,
int32 index);
private: private:
mutex fLock; mutex fLock;
@@ -0,0 +1,55 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
//---------------------------------------------------------------------
/*! \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;
}
+4 -1
View File
@@ -60,7 +60,7 @@ struct ext2_super_block {
uint32 algorithm_usage_bitmap; uint32 algorithm_usage_bitmap;
uint8 preallocated_blocks; uint8 preallocated_blocks;
uint8 preallocated_directory_blocks; uint8 preallocated_directory_blocks;
uint16 _padding; uint16 reserved_gdt_blocks;
// journaling ext3 support // journaling ext3 support
uint8 journal_uuid[16]; uint8 journal_uuid[16];
@@ -127,6 +127,8 @@ struct ext2_super_block {
{ return B_LENDIAN_TO_HOST_INT32(read_only_features); } { return B_LENDIAN_TO_HOST_INT32(read_only_features); }
uint32 IncompatibleFeatures() const uint32 IncompatibleFeatures() const
{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); } { return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
uint16 ReservedGDTBlocks() const
{ return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); }
ino_t JournalInode() const ino_t JournalInode() const
{ return B_LENDIAN_TO_HOST_INT32(journal_inode); } { return B_LENDIAN_TO_HOST_INT32(journal_inode); }
ino_t LastOrphan() const ino_t LastOrphan() const
@@ -383,6 +385,7 @@ struct ext2_extent_stream {
} _PACKED; } _PACKED;
#define EXT2_INODE_NORMAL_SIZE 128 #define EXT2_INODE_NORMAL_SIZE 128
#define EXT2_INODE_MAX_LINKS 65000
struct ext2_inode { struct ext2_inode {
uint16 mode; uint16 mode;