* 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:
parent
970c0ac244
commit
d482c34e49
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -23,6 +23,7 @@ KernelAddon ext2 :
|
|||
BitmapBlock.cpp
|
||||
BlockAllocator.cpp
|
||||
InodeAllocator.cpp
|
||||
CRCTable.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.
|
||||
* 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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue