Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: src/add-ons/kernel/file_systems/ext2/InodeJournal.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/InodeJournal.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/InodeJournal.h (revision 0)
- @@ -0,0 +1,29 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef INODEJOURNAL_H
- +#define INODEJOURNAL_H
- +
- +
- +#include "Inode.h"
- +#include "Journal.h"
- +
- +
- +class InodeJournal : public Journal {
- +public:
- + InodeJournal(Inode* inode);
- + ~InodeJournal();
- +
- + status_t InitCheck();
- +
- + status_t MapBlock(uint32 logical, uint32& physical);
- +private:
- + Inode* fInode;
- + status_t fInitStatus;
- +};
- +
- +#endif // INODEJOURNAL_H
- Index: src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp (revision 0)
- @@ -0,0 +1,110 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "InodeAllocator.h"
- +
- +#include <util/AutoLock.h>
- +
- +#include "BitmapBlock.h"
- +#include "Volume.h"
- +
- +
- +//#define TRACE_EXT2
- +#ifdef TRACE_EXT2
- +# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
- +#else
- +# define TRACE(x...) ;
- +#endif
- +
- +
- +InodeAllocator::InodeAllocator(Volume* volume)
- + :
- + fVolume(volume)
- +{
- + mutex_init(&fLock, "ext2 inode allocator");
- +}
- +
- +
- +InodeAllocator::~InodeAllocator()
- +{
- + mutex_destroy(&fLock);
- +}
- +
- +
- +status_t
- +InodeAllocator::New(Transaction& transaction, uint32 preferredBlockGroup,
- + ino_t& id)
- +{
- + MutexLocker lock(fLock);
- +
- + uint32 blockGroup = preferredBlockGroup;
- + uint32 lastBlockGroup = fVolume->NumGroups() - 1;
- +
- + for (int i = 0; i < 2; ++i) {
- + for (; blockGroup < lastBlockGroup; ++blockGroup) {
- + ext2_block_group* group;
- +
- + status_t status = fVolume->GetBlockGroup(blockGroup, &group);
- + if (status != B_OK)
- + return status;
- +
- + if (group->FreeInodes() != 0) {
- + return _MarkInBitmap(transaction, group->InodeBitmap(),
- + blockGroup, fVolume->InodesPerGroup(), id);
- + }
- + }
- +
- + if (i == 0) {
- + ext2_block_group* group;
- +
- + status_t status = fVolume->GetBlockGroup(blockGroup, &group);
- + if (status != B_OK)
- + return status;
- +
- + if (group->FreeInodes() != 0) {
- + return _MarkInBitmap(transaction, group->InodeBitmap(),
- + blockGroup, fVolume->NumInodes()
- + - blockGroup * fVolume->InodesPerGroup(), id);
- + }
- + }
- +
- + blockGroup = 0;
- + lastBlockGroup = preferredBlockGroup;
- + }
- +
- + return B_DEVICE_FULL;
- +}
- +
- +
- +status_t
- +InodeAllocator::_MarkInBitmap(Transaction& transaction, uint32 bitmapBlock,
- + uint32 blockGroup, uint32 numInodes, ino_t& id)
- +{
- + BitmapBlock inodeBitmap(fVolume, numInodes);
- +
- + if (!inodeBitmap.SetToWritable(transaction, bitmapBlock)) {
- + TRACE("Unable to open inode bitmap (block number: %lu) for block group "
- + "%lu\n", bitmapBlock, blockGroup);
- + return B_IO_ERROR;
- + }
- +
- + uint32 pos = 0;
- + inodeBitmap.FindNextUnmarked(pos);
- +
- + if (pos == inodeBitmap.NumBits()) {
- + TRACE("Even though the block group %lu indicates there are free "
- + "inodes, no unmarked bit was found in the inode bitmap at block "
- + "%lu.", blockGroup, bitmapBlock);
- + return B_ERROR;
- + }
- +
- + inodeBitmap.Mark(pos, true);
- + id = pos + blockGroup * fVolume->InodesPerGroup();
- +
- + return B_OK;
- +}
- Property changes on: src/add-ons/kernel/file_systems/ext2/InodeAllocator.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/BlockAllocator.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/BlockAllocator.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/BlockAllocator.h (revision 0)
- @@ -0,0 +1,53 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef BLOCKALLOCATOR_H
- +#define BLOCKALLOCATOR_H
- +
- +#include <lock.h>
- +
- +#include "Transaction.h"
- +
- +
- +class AllocationBlockGroup;
- +class Inode;
- +class Volume;
- +
- +
- +class BlockAllocator {
- +public:
- + BlockAllocator(Volume* volume);
- + ~BlockAllocator();
- +
- + status_t Initialize();
- +
- + status_t AllocateBlocks(Transaction& transaction,
- + uint32 minimum, uint32 maximum, uint32& blockGroup,
- + uint32& start, uint32& length);
- + status_t Allocate(Transaction& transaction, Inode* inode,
- + off_t numBlocks, uint32 minimum, uint32& start,
- + uint32& length);
- + status_t Free(Transaction& transaction, uint32 start,
- + uint32 length);
- +
- + uint32 FreeBlocks();
- +
- +protected:
- + static status_t _Initialize(BlockAllocator* allocator);
- +
- +
- + Volume* fVolume;
- + mutex fLock;
- +
- + AllocationBlockGroup* fGroups;
- + uint32 fBlocksPerGroup;
- + uint32 fNumBlocks;
- + uint32 fNumGroups;
- + uint32 fFirstBlock;
- +};
- +
- +#endif // BLOCKALLOCATOR_H
- Property changes on: src/add-ons/kernel/file_systems/ext2/BlockAllocator.h
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (working copy)
- @@ -11,6 +11,7 @@
- #include <new>
- +#include "CachedBlock.h"
- #include "HTree.h"
- #include "IndexedDirectoryIterator.h"
- #include "Inode.h"
- @@ -27,81 +28,91 @@
- HTreeEntryIterator::HTreeEntryIterator(off_t offset, Inode* directory)
- :
- + fDirectory(directory),
- + fVolume(directory->GetVolume()),
- fHasCollision(false),
- - fDirectory(directory),
- - fOffset(offset),
- + fBlockSize(directory->GetVolume()->BlockSize()),
- fParent(NULL),
- fChild(NULL)
- {
- - fBlockSize = fDirectory->GetVolume()->BlockSize();
- + fInitStatus = fDirectory->FindBlock(offset, fBlockNum);
- +
- + if (fInitStatus == B_OK)
- + fDisplacement = offset % fBlockSize;
- +
- + TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu displacement "
- + "%lu\n", fBlockNum, fDisplacement);
- }
- HTreeEntryIterator::HTreeEntryIterator(uint32 block, uint32 blockSize,
- Inode* directory, HTreeEntryIterator* parent, bool hasCollision)
- :
- + fDirectory(directory),
- + fVolume(directory->GetVolume()),
- fHasCollision(hasCollision),
- fBlockSize(blockSize),
- - fDirectory(directory),
- - fOffset(block * blockSize + sizeof(HTreeFakeDirEntry)),
- + fBlockNum(block),
- + fDisplacement(0),
- fParent(parent),
- fChild(NULL)
- {
- - TRACE("HTreeEntryIterator::HTreeEntryIterator() block %ld offset %Lx\n",
- - block, fOffset);
- + fInitStatus = B_OK;
- +
- + TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu displacement %lu\n",
- + block, fDisplacement);
- }
- status_t
- HTreeEntryIterator::Init()
- {
- - size_t length = sizeof(HTreeCountLimit);
- - HTreeCountLimit countLimit;
- -
- - status_t status = fDirectory->ReadAt(fOffset, (uint8*)&countLimit,
- - &length);
- -
- - if (status != B_OK)
- - return status;
- -
- - if (length != sizeof(HTreeCountLimit)) {
- - ERROR("HTreeEntryIterator::Init() bad length %ld fOffset 0x%Lx\n",
- - length, fOffset);
- + if (fInitStatus != B_OK)
- + return fInitStatus;
- +
- + fCurrentEntry = 0;
- +
- + CachedBlock cached(fVolume);
- + const uint8* block = cached.SetTo(fBlockNum);
- + if (block == NULL) {
- + ERROR("Failed to read htree entry block.\n");
- fCount = fLimit = 0;
- - return B_ERROR;
- + return B_IO_ERROR;
- }
- -
- - fCount = countLimit.Count();
- - fLimit = countLimit.Limit();
- + HTreeCountLimit* countLimit = (HTreeCountLimit*)(fBlockNum + fDisplacement);
- +
- + fCount = countLimit->Count();
- + fLimit = countLimit->Limit();
- +
- if (fCount >= fLimit) {
- - ERROR("HTreeEntryIterator::Init() bad fCount %d fOffset 0x%Lx\n",
- - fCount, fOffset);
- + ERROR("HTreeEntryIterator::Init() bad fCount %lu fDisplacement %lu\n",
- + (uint32)fCount, fDisplacement);
- fCount = fLimit = 0;
- return B_ERROR;
- }
- - if (fParent != NULL &&
- - fLimit != ((fBlockSize - sizeof(HTreeFakeDirEntry))
- + if (fLimit != ((fBlockSize - sizeof(HTreeFakeDirEntry))
- / sizeof(HTreeEntry)) ) {
- - ERROR("HTreeEntryIterator::Init() bad fLimit %d should be %ld "
- - "fOffset 0x%Lx\n", fLimit, (fBlockSize - sizeof(HTreeFakeDirEntry))
- - / sizeof(HTreeEntry), fOffset);
- + ERROR("HTreeEntryIterator::Init() bad fLimit %lu should be %lu "
- + "at block %lu displacement %lu\n", (uint32)fLimit,
- + (fBlockSize - fDisplacement - sizeof(HTreeFakeDirEntry))
- + / sizeof(HTreeEntry),
- + fBlockNum, fDisplacement);
- fCount = fLimit = 0;
- return B_ERROR;
- - }
- + }
- TRACE("HTreeEntryIterator::Init() count 0x%x limit 0x%x\n", fCount,
- fLimit);
- - fMaxOffset = fOffset + (fCount - 1) * sizeof(HTreeEntry);
- -
- return B_OK;
- }
- HTreeEntryIterator::~HTreeEntryIterator()
- {
- + delete fChild;
- }
- @@ -109,68 +120,65 @@
- HTreeEntryIterator::Lookup(uint32 hash, int indirections,
- DirectoryIterator** directoryIterator)
- {
- - off_t start = fOffset + sizeof(HTreeEntry);
- - off_t end = fMaxOffset;
- - off_t middle = start;
- - size_t entrySize = sizeof(HTreeEntry);
- - HTreeEntry entry;
- -
- + CachedBlock cached(fVolume);
- + const uint8* block = cached.SetTo(fBlockNum);
- + if (block == NULL) {
- + ERROR("Failed to read htree entry block.\n");
- + // Fallback to linear search
- + *directoryIterator = new(std::nothrow)
- + DirectoryIterator(fDirectory);
- +
- + if (*directoryIterator == NULL)
- + return B_NO_MEMORY;
- +
- + return B_OK;
- + }
- +
- + HTreeEntry* start = (HTreeEntry*)(block + fDisplacement) + 1;
- + HTreeEntry* end = (HTreeEntry*)(block + fBlockSize - fDisplacement);
- + HTreeEntry* middle = start;
- +
- while (start <= end) {
- - middle = (end - start) / 2;
- - middle -= middle % entrySize; // Alignment
- - middle += start;
- + middle = (HTreeEntry*)(((uint8*)end - (uint8*)start) / 2
- + + (uint8*)start);
- - TRACE("HTreeEntryIterator::Lookup() %d 0x%Lx 0x%Lx 0x%Lx\n",
- + TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n",
- indirections, start, end, middle);
- -
- - status_t status = fDirectory->ReadAt(middle, (uint8*)&entry,
- - &entrySize);
- - TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, entry.Hash());
- -
- - if (status != B_OK)
- - return status;
- - else if (entrySize != sizeof(entry)) {
- - // Fallback to linear search
- - *directoryIterator = new(std::nothrow)
- - DirectoryIterator(fDirectory);
- -
- - if (*directoryIterator == NULL)
- - return B_NO_MEMORY;
- -
- - return B_OK;
- - }
- -
- - if (hash >= entry.Hash())
- - start = middle + entrySize;
- + TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, middle->Hash());
- +
- + if (hash >= middle->Hash())
- + start = middle++;
- else
- - end = middle - entrySize;
- + end = middle--;
- }
- - status_t status = fDirectory->ReadAt(start - entrySize, (uint8*)&entry,
- - &entrySize);
- - if (status != B_OK)
- - return status;
- -
- + --start;
- +
- + fCurrentEntry = ((uint8*)start - block + fDisplacement)
- + / sizeof(HTreeEntry);
- +
- if (indirections == 0) {
- *directoryIterator = new(std::nothrow)
- - IndexedDirectoryIterator(entry.Block() * fBlockSize, fBlockSize,
- - fDirectory, this);
- -
- + IndexedDirectoryIterator(start->Block() * fBlockSize, fDirectory,
- + this);
- +
- if (*directoryIterator == NULL)
- return B_NO_MEMORY;
- return B_OK;
- }
- + uint32 blockNum;
- + status_t status = fDirectory->FindBlock(start->Block() * fBlockSize,
- + blockNum);
- +
- delete fChild;
- - fChild = new(std::nothrow) HTreeEntryIterator(entry.Block(), fBlockSize,
- - fDirectory, this, entry.Hash() & 1 == 1);
- -
- + fChild = new(std::nothrow) HTreeEntryIterator(blockNum, fBlockSize,
- + fDirectory, this, start->Hash() & 1 == 1);
- if (fChild == NULL)
- return B_NO_MEMORY;
- - fChildDeleter.SetTo(fChild);
- status = fChild->Init();
- if (status != B_OK)
- @@ -181,40 +189,37 @@
- status_t
- -HTreeEntryIterator::GetNext(off_t& childOffset)
- +HTreeEntryIterator::GetNext(uint32& childBlock)
- {
- - size_t entrySize = sizeof(HTreeEntry);
- - fOffset += entrySize;
- - bool firstEntry = fOffset >= fMaxOffset;
- -
- + fCurrentEntry++;
- + bool firstEntry = fCurrentEntry >= fCount;
- +
- if (firstEntry) {
- if (fParent == NULL)
- return B_ENTRY_NOT_FOUND;
- -
- - status_t status = fParent->GetNext(fOffset);
- +
- + status_t status = fParent->GetNext(fBlockNum);
- if (status != B_OK)
- return status;
- -
- +
- + fDisplacement = 0;
- status = Init();
- if (status != B_OK)
- return status;
- fHasCollision = fParent->HasCollision();
- }
- -
- - HTreeEntry entry;
- - status_t status = fDirectory->ReadAt(fOffset, (uint8*)&entry, &entrySize);
- - if (status != B_OK)
- - return status;
- - else if (entrySize != sizeof(entry)) {
- - // Weird error, try to skip it
- - return GetNext(childOffset);
- - }
- -
- +
- + CachedBlock cached(fVolume);
- + const uint8* block = cached.SetTo(fBlockNum);
- + if (block == NULL)
- + return B_IO_ERROR;
- +
- + HTreeEntry* entry = (HTreeEntry*)(block + fDisplacement);
- +
- if (!firstEntry)
- - fHasCollision = (entry.Hash() & 1) == 1;
- -
- - childOffset = entry.Block() * fBlockSize;
- -
- - return B_OK;
- + fHasCollision = (entry[fCurrentEntry].Hash() & 1) == 1;
- +
- + return fDirectory->FindBlock(entry[fCurrentEntry].Block() * fBlockSize,
- + childBlock);
- }
- Index: src/add-ons/kernel/file_systems/ext2/Inode.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Inode.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/Inode.h (working copy)
- @@ -23,6 +23,8 @@
- rw_lock* Lock() { return &fLock; }
- + status_t WriteBack(Transaction& transaction);
- +
- bool IsDirectory() const
- { return S_ISDIR(Mode()); }
- bool IsFile() const
- @@ -54,8 +56,17 @@
- ext2_inode& Node() { return *fNode; }
- + static status_t Create(Transaction& transaction, Inode* parent,
- + const char* name, int32 mode, int openMode,
- + uint32 type, bool* _created = NULL,
- + ino_t* _id = NULL, Inode** _inode = NULL,
- + fs_vnode_ops* vnodeOps = NULL,
- + uint32 publishFlags = 0);
- +
- void* FileCache() const { return fCache; }
- void* Map() const { return fMap; }
- + status_t DisableFileCache();
- + bool IsFileCacheDisabled() const { return !fCached; }
- private:
- Inode(const Inode&);
- @@ -63,13 +74,15 @@
- // no implementation
- private:
- - rw_lock fLock;
- - ::Volume* fVolume;
- - ino_t fID;
- - void* fCache;
- - void* fMap;
- - ext2_inode* fNode;
- - ext2_xattr_header* fAttributesBlock;
- + rw_lock fLock;
- + ::Volume* fVolume;
- + ino_t fID;
- + void* fCache;
- + void* fMap;
- + bool fCached;
- + ext2_inode* fNode;
- + ext2_xattr_header* fAttributesBlock;
- + status_t fInitStatus;
- };
- #endif // INODE_H
- Index: src/add-ons/kernel/file_systems/ext2/Volume.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Volume.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/Volume.cpp (working copy)
- @@ -20,7 +20,10 @@
- #include <util/AutoLock.h>
- +#include "CachedBlock.h"
- #include "Inode.h"
- +#include "InodeJournal.h"
- +#include "NoJournal.h"
- //#define TRACE_EXT2
- @@ -199,7 +202,7 @@
- // TODO: check some more values!
- if (Magic() != (uint32)EXT2_SUPER_BLOCK_MAGIC)
- return false;
- -
- +
- return true;
- }
- @@ -210,6 +213,8 @@
- Volume::Volume(fs_volume* volume)
- :
- fFSVolume(volume),
- + fBlockAllocator(this),
- + fInodeAllocator(this),
- fFlags(0),
- fGroupBlocks(NULL),
- fRootNode(NULL)
- @@ -229,6 +234,9 @@
- free(fGroupBlocks);
- }
- +
- + delete fJournal;
- + delete fJournalInode;
- }
- @@ -252,7 +260,7 @@
- status_t
- Volume::Mount(const char* deviceName, uint32 flags)
- {
- - flags |= B_MOUNT_READ_ONLY;
- + // flags |= B_MOUNT_READ_ONLY;
- // we only support read-only for now
- DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
- @@ -278,10 +286,17 @@
- fBlockSize = 1UL << fSuperBlock.BlockShift();
- fFirstDataBlock = fSuperBlock.FirstDataBlock();
- + fFreeBlocks = fSuperBlock.FreeBlocks();
- + fFreeInodes = fSuperBlock.FreeInodes();
- +
- + uint32 numBlocks = fSuperBlock.NumBlocks();
- + uint32 blocksPerGroup = fSuperBlock.BlocksPerGroup();
- + fNumGroups = numBlocks / blocksPerGroup;
- + if (numBlocks % blocksPerGroup != 0)
- + fNumGroups++;
- +
- + fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);
- fNumInodes = fSuperBlock.NumInodes();
- - fNumGroups = (fSuperBlock.NumBlocks() - fFirstDataBlock - 1)
- - / fSuperBlock.BlocksPerGroup() + 1;
- - fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);
- TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n",
- fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock);
- @@ -310,6 +325,45 @@
- if (fBlockCache == NULL)
- return B_ERROR;
- + // initialize journal
- + if ((fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
- + // TODO: There should be a mount option to ignore the existent journal
- + if (fSuperBlock.JournalInode() != 0) {
- + fJournalInode = new(std::nothrow) Inode(this,
- + fSuperBlock.JournalInode());
- +
- + if (fJournalInode == NULL)
- + return B_NO_MEMORY;
- +
- + TRACE("Opening an on disk, inode mapped journal.\n");
- + fJournal = new(std::nothrow) InodeJournal(fJournalInode);
- + } else {
- + // TODO: external journal
- + TRACE("Can not open an external journal.\n");
- + return B_NOT_SUPPORTED;
- + }
- + } else {
- + TRACE("Opening a fake journal (NoJournal).\n");
- + fJournal = new(std::nothrow) NoJournal(this);
- + }
- +
- + if (fJournal == NULL)
- + return B_NO_MEMORY;
- +
- + status = fJournal->InitCheck();
- + if (status != B_OK)
- + return status;
- +
- + // TODO: Only recover if asked to
- + status = fJournal->Recover();
- + if (status != B_OK)
- + return status;
- +
- + status = fJournal->StartLog();
- + if (status != B_OK)
- + return status;
- +
- + // ready
- status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode);
- if (status != B_OK) {
- TRACE("could not create root node: get_vnode() failed!\n");
- @@ -443,6 +497,96 @@
- }
- +status_t
- +Volume::AllocateInode(Transaction& transaction, uint32 preferredBlockGroup,
- + ino_t& id)
- +{
- + if ((fFlags & VOLUME_READ_ONLY) != 0)
- + return B_READ_ONLY_DEVICE;
- +
- + status_t status = fInodeAllocator.New(transaction, preferredBlockGroup, id);
- + if (status == B_OK)
- + fFreeInodes -= 1;
- +
- + return status;
- +}
- +
- +
- +status_t
- +Volume::AllocateBlocks(Transaction& transaction, uint32 blockGroup,
- + uint32 minimum, uint32 maximum, uint32& start, uint32& length)
- +{
- + if ((fFlags & VOLUME_READ_ONLY) != 0)
- + return B_READ_ONLY_DEVICE;
- +
- + status_t status = fBlockAllocator.AllocateBlocks(transaction, blockGroup,
- + minimum, maximum, start, length);
- + if (status != B_OK)
- + return status;
- +
- + fFreeBlocks -= length;
- +
- + return WriteSuperBlock(transaction);
- +}
- +
- +
- +status_t
- +Volume::LoadSuperBlock()
- +{
- + CachedBlock cached(this);
- + const uint8* block = cached.SetTo(fFirstDataBlock);
- +
- + if (block == NULL)
- + return B_IO_ERROR;
- +
- + if (fFirstDataBlock == 0)
- + memcpy(&fSuperBlock, block + 1024, sizeof(fSuperBlock));
- + else
- + memcpy(&fSuperBlock, block, sizeof(fSuperBlock));
- +
- + fFreeBlocks = fSuperBlock.FreeBlocks();
- + fFreeInodes = fSuperBlock.FreeInodes();
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Volume::WriteSuperBlock(Transaction& transaction)
- +{
- + fSuperBlock.SetFreeBlocks(fFreeBlocks);
- + fSuperBlock.SetFreeInodes(fFreeInodes);
- + // TODO: Rest of fields that can be modified
- +
- + CachedBlock cached(this);
- + uint8* block = cached.SetToWritable(transaction, fFirstDataBlock);
- +
- + if (block == NULL)
- + return B_IO_ERROR;
- +
- + if (fFirstDataBlock == 0)
- + memcpy(block + 1024, &fSuperBlock, sizeof(fSuperBlock));
- + else
- + memcpy(block, &fSuperBlock, sizeof(fSuperBlock));
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Volume::FlushDevice()
- +{
- + return block_cache_sync(fBlockCache);
- +}
- +
- +
- +status_t
- +Volume::Sync()
- +{
- + return fJournal->FlushLogAndBlocks();
- +}
- +
- +
- // #pragma mark - Disk scanning and initialization
- @@ -460,3 +604,18 @@
- ? B_OK : B_NOT_SUPPORTED;
- }
- +
- +void
- +Volume::TransactionDone(bool success)
- +{
- + status_t status = LoadSuperBlock();
- + if (status != B_OK)
- + panic("Failed to relead ext2 superblock.\n");
- +}
- +
- +
- +void
- +Volume::RemovedFromTransaction()
- +{
- + // TODO: Does it make a difference?
- +}
- Index: src/add-ons/kernel/file_systems/ext2/Journal.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Journal.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/Journal.cpp (revision 0)
- @@ -0,0 +1,990 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "Journal.h"
- +
- +#include <new>
- +#include <string.h>
- +#include <unistd.h>
- +
- +#include <fs_cache.h>
- +
- +#include "CachedBlock.h"
- +#include "HashRevokeManager.h"
- +
- +
- +//#define TRACE_EXT2
- +#ifdef TRACE_EXT2
- +# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
- +#else
- +# define TRACE(x...) ;
- +#endif
- +
- +
- +class LogEntry : public DoublyLinkedListLinkImpl<LogEntry> {
- +public:
- + LogEntry(Journal* journal, uint32 logStart,
- + uint32 length);
- + ~LogEntry();
- +
- + uint32 Start() const { return fStart; }
- + uint32 CommitID() const { return fCommitID; }
- +
- + Journal* GetJournal() { return fJournal; }
- +
- +private:
- + Journal* fJournal;
- + uint32 fStart;
- + uint32 fCommitID;
- +};
- +
- +
- +LogEntry::LogEntry(Journal* journal, uint32 logStart, uint32 commitID)
- + :
- + fJournal(journal),
- + fStart(logStart),
- + fCommitID(commitID)
- +{
- +}
- +
- +
- +LogEntry::~LogEntry()
- +{
- +}
- +
- +
- +/*void
- +add_to_iovec(iovec* vecs, int32& index, int32 max, const void* address,
- + size_t size)
- +{
- + if (index > 0 && (addr_t)vecs[index - 1].iov_base
- + + vecs[index - 1].iov_len == (addr_t)address) {
- + // the iovec can be combined with the previous one
- + vecs[index - 1].iov_len += size;
- + return;
- + }
- +
- + if (index == max)
- + panic("no more space for iovecs!");
- +
- + // start a new iovec
- + vecs[index].iov_base = const_cast<void*>(address);
- + vecs[index].iov_len = size;
- + index++;
- +}*/
- +
- +
- +void
- +JournalHeader::MakeDescriptor(uint32 sequence)
- +{
- + this->magic = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
- + this->sequence = B_HOST_TO_BENDIAN_INT32(sequence);
- + this->block_type = B_HOST_TO_BENDIAN_INT32(JOURNAL_DESCRIPTOR_BLOCK);
- +}
- +
- +
- +void
- +JournalHeader::MakeCommit(uint32 sequence)
- +{
- + this->magic = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
- + this->sequence = B_HOST_TO_BENDIAN_INT32(sequence);
- + this->block_type = B_HOST_TO_BENDIAN_INT32(JOURNAL_COMMIT_BLOCK);
- +}
- +
- +
- +Journal::Journal(Volume* fsVolume, Volume* jVolume)
- + :
- + fJournalVolume(jVolume),
- + fJournalBlockCache(jVolume->BlockCache()),
- + fFilesystemVolume(fsVolume),
- + fFilesystemBlockCache(fsVolume->BlockCache()),
- + fRevokeManager(NULL),
- + fInitStatus(B_OK),
- + fBlockSize(sizeof(JournalSuperBlock)),
- + fFirstCommitID(0),
- + fFirstCacheCommitID(0),
- + fFirstLogBlock(0),
- + fLogSize(0),
- + fVersion(0),
- + fLogStart(0),
- + fLogEnd(0),
- + fFreeBlocks(0),
- + fMaxTransactionSize(0),
- + fCurrentCommitID(0),
- + fHasSubTransaction(false),
- + fSeparateSubTransactions(false)//,
- + //fNextCommitID(0)
- +{
- + recursive_lock_init(&fLock, "ext2 journal");
- + mutex_init(&fLogEntriesLock, "ext2 journal log entries");
- +
- + fRevokeManager = new(std::nothrow) HashRevokeManager;
- +
- + if (fRevokeManager == NULL)
- + fInitStatus = B_NO_MEMORY;
- + else
- + fInitStatus = _LoadSuperBlock();
- +}
- +
- +
- +Journal::Journal()
- + :
- + fJournalVolume(NULL),
- + fJournalBlockCache(NULL),
- + fFilesystemVolume(NULL),
- + fFilesystemBlockCache(NULL),
- + fRevokeManager(NULL),
- + fInitStatus(B_OK),
- + fBlockSize(sizeof(JournalSuperBlock)),
- + fFirstCommitID(0),
- + fFirstCacheCommitID(0),
- + fFirstLogBlock(0),
- + fLogSize(0),
- + fVersion(0),
- + fLogStart(0),
- + fLogEnd(0),
- + fFreeBlocks(0),
- + fMaxTransactionSize(0),
- + fCurrentCommitID(0),
- + fHasSubTransaction(false),
- + fSeparateSubTransactions(false)//,
- + //fNextCommitID(0)
- +{
- + recursive_lock_init(&fLock, "ext2 journal");
- + mutex_init(&fLogEntriesLock, "ext2 journal log entries");
- +}
- +
- +
- +Journal::~Journal()
- +{
- + FlushLogAndBlocks();
- +
- + delete fRevokeManager;
- +
- + recursive_lock_destroy(&fLock);
- + mutex_destroy(&fLogEntriesLock);
- +}
- +
- +
- +status_t
- +Journal::InitCheck()
- +{
- + return fInitStatus;
- +}
- +
- +
- +/*virtual*/ status_t
- +Journal::StartLog()
- +{
- + fLogStart = fFirstLogBlock;
- + fLogEnd = fFirstLogBlock;
- + fFreeBlocks = 0;
- +
- + fCurrentCommitID = fFirstCommitID;
- + //fNextCommitID = fFirstCommitID;
- +
- + return _SaveSuperBlock();
- +}
- +
- +
- +status_t
- +Journal::RestartLog()
- +{
- + fFirstCommitID = 1;
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::Lock(Transaction* owner, bool separateSubTransactions)
- +{
- + status_t status = recursive_lock_lock(&fLock);
- + if (status != B_OK)
- + return status;
- +
- + if (!fSeparateSubTransactions && recursive_lock_get_recursion(&fLock) > 1) {
- + // reuse current transaction
- + return B_OK;
- + }
- +
- + if(separateSubTransactions)
- + fSeparateSubTransactions = true;
- +
- + if (owner != NULL)
- + owner->SetParent(fOwner);
- +
- + fOwner = owner;
- +
- + if (fOwner != NULL) {
- + if (fUnwrittenTransactions > 0) {
- + // start a sub transaction
- + cache_start_sub_transaction(fFilesystemBlockCache, fTransactionID);
- + fHasSubTransaction = true;
- + } else
- + fTransactionID = cache_start_transaction(fFilesystemBlockCache);
- +
- + if (fTransactionID < B_OK) {
- + recursive_lock_unlock(&fLock);
- + return fTransactionID;
- + }
- +
- + cache_add_transaction_listener(fFilesystemBlockCache, fTransactionID,
- + TRANSACTION_IDLE, _TransactionIdle, this);
- + }
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::Unlock(Transaction* owner, bool success)
- +{
- + if (fSeparateSubTransactions
- + || recursive_lock_get_recursion(&fLock) == 1) {
- + // we only end the transaction if we unlock it
- + if (owner != NULL) {
- + status_t status = _TransactionDone(success);
- + if (status != B_OK)
- + return status;
- +
- + bool separateSubTransactions = fSeparateSubTransactions;
- + fSeparateSubTransactions = true;
- + owner->NotifyListeners(success);
- + fSeparateSubTransactions = separateSubTransactions;
- +
- + fOwner = owner->Parent();
- + } else
- + fOwner = NULL;
- +
- + if (fSeparateSubTransactions
- + && recursive_lock_get_recursion(&fLock) == 1)
- + fSeparateSubTransactions = false;
- + } else
- + owner->MoveListenersTo(fOwner);
- +
- + recursive_lock_unlock(&fLock);
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::MapBlock(uint32 logical, uint32& physical)
- +{
- + physical = logical;
- +
- + return B_OK;
- +}
- +
- +
- +inline uint32
- +Journal::FreeLogBlocks() const
- +{
- + return fLogStart <= fLogEnd
- + ? fLogSize - fLogEnd + fLogStart
- + : fLogStart - fLogEnd;
- +}
- +
- +
- +status_t
- +Journal::FlushLogAndBlocks()
- +{
- + return _FlushLog(true, true);
- +}
- +
- +
- +int32
- +Journal::TransactionID() const
- +{
- + return fTransactionID;
- +}
- +
- +
- +status_t
- +Journal::_WriteTransactionToLog()
- +{
- + // Transaction enters the Flush state
- + bool detached = false;
- + size_t size = _FullTransactionSize();
- +
- + if (size > fLogSize) {
- + size = _MainTransactionSize();
- +
- + if(fHasSubTransaction && size < fMaxTransactionSize)
- + detached = true;
- + else {
- + // Error: transaction can't fit in log
- + panic("transaction too large (size: %d, max size: %d)\n",
- + (int)_MainTransactionSize(), (int)fLogSize);
- + return B_BUFFER_OVERFLOW;
- + }
- + }
- +
- + if (size > FreeLogBlocks()) {
- + cache_sync_transaction(fFilesystemBlockCache, fTransactionID);
- +
- + if (size > FreeLogBlocks()) {
- + panic("Transaction fits, but sync didn't result in enough"
- + "free space.\n\tGot %ld when at least %ld was expected.",
- + (long)FreeLogBlocks(), (long)size);
- + }
- + }
- +
- + fHasSubTransaction = false;
- +
- + uint32 logBlock = fLogStart + 1;
- + uint32 physicalBlock;
- + status_t status = MapBlock(logBlock, physicalBlock);
- + if (status != B_OK)
- + return status;
- +
- + off_t logOffset = physicalBlock * fBlockSize;
- + off_t blockNumber;
- + long cookie = 0;
- +
- + JournalHeader* blockData = NULL;
- + JournalHeader* descriptorBlock =
- + (JournalHeader*)new(std::nothrow) uint8[fBlockSize];
- + descriptorBlock->MakeDescriptor(fCurrentCommitID);
- +
- + JournalBlockTag* tag = (JournalBlockTag*)descriptorBlock->data;
- + int32 blockCount = 0;
- +
- + uint8* escapedData = NULL;
- + void* finalData = NULL;
- +
- + // TODO: use iovecs?
- + /*int maxVecs = detached ? _MainTransactionSize() : _FullTransactionSize();
- +
- + iovec* vecs = new(std::nothrow) iovecs[maxVecs];
- + if (vecs == NULL)
- + return B_NO_MEMORY;
- +
- + int32 index = 0;*/
- +
- + while (cache_next_block_in_transaction(fFilesystemBlockCache,
- + fTransactionID, detached, &cookie, &blockNumber,
- + &(void*)blockData, NULL) == B_OK) {
- + tag->SetBlockNumber(blockNumber);
- + tag->SetFlags(0);
- +
- + if (blockData == NULL) {
- + panic("Got a NULL pointer while iterating through transaction "
- + "blocks.\n");
- + return B_ERROR;
- + }
- +
- + if (blockData->CheckMagic()) {
- + // The journaled block starts with the magic value
- + // We must remove it to prevent confusion
- + tag->SetEscapedFlag();
- +
- + if (escapedData == NULL) {
- + escapedData = new(std::nothrow) uint8[fBlockSize];
- + ((int32*)escapedData)[0] = 0; // Remove magic
- + }
- +
- + memcpy(escapedData + 4, blockData->data, fBlockSize - 4);
- + finalData = escapedData;
- + } else
- + finalData = (void*)blockData;
- +
- + size_t written = write_pos(fJournalVolume->Device(), logOffset,
- + finalData, fBlockSize);
- + if (written != fBlockSize) {
- + TRACE("Failed to write journal block.\n");
- +
- + delete [] descriptorBlock;
- +
- + if (escapedData != NULL)
- + delete [] escapedData;
- +
- + return B_IO_ERROR;
- + }
- +
- + logBlock = _WrapAroundLog(++logBlock);
- + status = MapBlock(logBlock, physicalBlock);
- + if (status != B_OK)
- + return status;
- +
- + logOffset = physicalBlock & fBlockSize;
- +
- + tag++;
- + blockCount++;
- + }
- +
- + // Write descriptor block
- + --tag;
- + tag->SetLastTagFlag();
- +
- + status = MapBlock(fLogStart, physicalBlock);
- + if (status != B_OK)
- + return status;
- +
- + off_t startOffset = physicalBlock * fBlockSize;
- +
- + size_t written = write_pos(fJournalVolume->Device(), startOffset,
- + descriptorBlock, fBlockSize);
- + if (written != fBlockSize) {
- + TRACE("Failed to write journal descriptor block.\n");
- +
- + delete [] descriptorBlock;
- +
- + if (escapedData != NULL)
- + delete [] escapedData;
- +
- + return B_IO_ERROR;
- + }
- +
- + // Transaction will enter the Commit state
- + JournalHeader* commitBlock = descriptorBlock;
- + // Reuse buffer
- + commitBlock->MakeCommit(fCurrentCommitID);
- + memset(commitBlock->data, 0, fBlockSize - sizeof(JournalHeader));
- + // TODO: This probably isn't necessary
- +
- + written = write_pos(fJournalVolume->Device(), logOffset, commitBlock,
- + fBlockSize);
- + if (written != fBlockSize) {
- + TRACE("Failed to write journal commit block.\n");
- +
- + delete [] commitBlock;
- + // Which is aslo descriptorBlock
- +
- + if (escapedData != NULL)
- + delete [] escapedData;
- +
- + return B_IO_ERROR;
- + }
- +
- + fLogEnd = _WrapAroundLog(fLogEnd + blockCount);
- +
- + status = _SaveSuperBlock();
- +
- + delete [] commitBlock;
- + // Which is aslo descriptorBlock
- +
- + if (escapedData != NULL)
- + delete [] escapedData;
- +
- + // Transaction will enter Finished state
- + blockCount += 2; // Include descriptor and commit blocks
- + LogEntry *logEntry = new LogEntry(this, fLogEnd, fCurrentCommitID++);
- + if (logEntry == NULL) {
- + panic("no memory to allocate log entries!");
- + return B_NO_MEMORY;
- + }
- +
- + mutex_lock(&fLogEntriesLock);
- + fLogEntries.Add(logEntry);
- + mutex_unlock(&fLogEntriesLock);
- +
- + if (detached) {
- + fTransactionID = cache_detach_sub_transaction(fFilesystemBlockCache,
- + fTransactionID, _TransactionWritten, logEntry);
- + fUnwrittenTransactions = 1;
- +
- + if (status == B_OK && _FullTransactionSize() > fLogSize) {
- + // If the transaction is too large after writing, there is no way to
- + // recover, so let this transaction fail.
- + dprintf("transaction too large (%d blocks, log size %d)!\n",
- + (int)_FullTransactionSize(), (int)fLogSize);
- + return B_BUFFER_OVERFLOW;
- + }
- + } else {
- + cache_end_transaction(fFilesystemBlockCache, fTransactionID,
- + _TransactionWritten, logEntry);
- + fUnwrittenTransactions = 0;
- + }
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::_SaveSuperBlock()
- +{
- + uint32 physicalBlock;
- + status_t status = MapBlock(0, physicalBlock);
- + if (status != B_OK)
- + return status;
- +
- + off_t superblockPos = physicalBlock * fBlockSize;
- +
- + JournalSuperBlock superblock;
- + size_t bytesRead = read_pos(fJournalVolume->Device(), superblockPos,
- + &superblock, sizeof(superblock));
- +
- + if (bytesRead != sizeof(superblock))
- + return B_IO_ERROR;
- +
- + superblock.SetFirstCommitID(fFirstCommitID);
- + superblock.SetLogStart(fLogStart);
- +
- + size_t bytesWritten = write_pos(fJournalVolume->Device(), superblockPos,
- + &superblock, sizeof(superblock));
- +
- + if (bytesWritten != sizeof(superblock))
- + return B_IO_ERROR;
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::_LoadSuperBlock()
- +{
- + uint32 superblockPos;
- +
- + status_t status = MapBlock(0, superblockPos);
- + if (status != B_OK)
- + return status;
- +
- + JournalSuperBlock superblock;
- + size_t bytesRead = read_pos(fJournalVolume->Device(), superblockPos,
- + &superblock, sizeof(superblock));
- +
- + if (bytesRead != sizeof(superblock))
- + return B_IO_ERROR;
- +
- + if (superblock.header.Magic() != JOURNAL_MAGIC)
- + return B_BAD_VALUE;
- +
- + if (superblock.header.BlockType() == JOURNAL_SUPERBLOCK_V1)
- + fVersion = 1;
- + else if (superblock.header.BlockType() == JOURNAL_SUPERBLOCK_V2)
- + fVersion = 2;
- + else
- + return B_BAD_VALUE;
- +
- + if (fVersion >= 2) {
- + status = _CheckFeatures(&superblock);
- +
- + if (status != B_OK)
- + return status;
- + }
- +
- + fBlockSize = superblock.BlockSize();
- + fFirstCommitID = superblock.FirstCommitID();
- + fFirstLogBlock = superblock.FirstLogBlock();
- + fLogStart = superblock.LogStart();
- + fLogSize = superblock.NumBlocks();
- + fMaxTransactionSize = superblock.MaxTransactionData();
- + //fFirstCacheCommitID = fFirstCommitID - fTransactionID /*+ 1*/;
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::_CheckFeatures(JournalSuperBlock* superblock)
- +{
- + if ((superblock->ReadOnlyCompatibleFeatures()
- + & ~JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES) != 0
- + && (superblock->IncompatibleFeatures()
- + & ~JOURNAL_KNOWN_INCOMPATIBLE_FEATURES) != 0)
- + return B_NOT_SUPPORTED;
- +
- + return B_OK;
- +}
- +
- +
- +uint32
- +Journal::_CountTags(JournalHeader* descriptorBlock)
- +{
- + uint32 count = 0;
- +
- + JournalBlockTag* tags = (JournalBlockTag*)descriptorBlock->data;
- + // Skip the header
- + JournalBlockTag* lastTag = (JournalBlockTag*)
- + (descriptorBlock + fBlockSize - sizeof(JournalBlockTag));
- +
- + while (tags < lastTag && (tags->Flags() & JOURNAL_FLAG_LAST_TAG) == 0) {
- + if ((tags->Flags() & JOURNAL_FLAG_SAME_UUID) == 0) {
- + // sizeof(UUID) = 16 = 2*sizeof(JournalBlockTag)
- + tags += 2; // Skip new UUID
- + }
- +
- + tags++; // Go to next tag
- + count++;
- + }
- +
- + return count;
- +}
- +
- +
- +/*virtual*/ status_t
- +Journal::Recover()
- +{
- + if (fLogStart == 0) // Journal was cleanly unmounted
- + return B_OK;
- +
- + uint32 lastCommitID;
- +
- + status_t status = _RecoverPassScan(lastCommitID);
- + if (status != B_OK)
- + return status;
- +
- + status = _RecoverPassRevoke(lastCommitID);
- + if (status != B_OK)
- + return status;
- +
- + return _RecoverPassReplay(lastCommitID);
- +}
- +
- +
- +// First pass: Find the end of the log
- +status_t
- +Journal::_RecoverPassScan(uint32& lastCommitID)
- +{
- + TRACE("Journal Recover: 1st Pass: Scan\n");
- +
- + CachedBlock cached(fJournalVolume);
- + JournalHeader* header;
- + uint32 nextCommitID = fFirstCommitID;
- + uint32 nextBlock = fLogStart;
- + uint32 nextBlockPos;
- +
- + status_t status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK)
- + return status;
- +
- + header = (JournalHeader*)cached.SetTo(nextBlockPos);
- +
- + while (header->CheckMagic() && header->Sequence() == nextCommitID) {
- + uint32 blockType = header->BlockType();
- +
- + if (blockType == JOURNAL_DESCRIPTOR_BLOCK)
- + nextBlock = _WrapAroundLog(nextBlock + _CountTags(header));
- + else if (blockType == JOURNAL_COMMIT_BLOCK)
- + nextCommitID++;
- + else if (blockType != JOURNAL_REVOKE_BLOCK) {
- + // TODO: Warn that we found an unrecognized block
- + break;
- + } // If blockType == JOURNAL_REVOKE_BLOCK we just skip it
- +
- + nextBlock = _WrapAroundLog(nextBlock + 1);
- +
- + status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK)
- + return status;
- +
- + header = (JournalHeader*)cached.SetTo(nextBlockPos);
- + }
- +
- + TRACE("Last detected transaction ID: %lu\n", nextCommitID);
- +
- + lastCommitID = nextCommitID;
- + return B_OK;
- +}
- +
- +
- +// Second pass: Collect all revoked blocks
- +status_t
- +Journal::_RecoverPassRevoke(uint32 lastCommitID)
- +{
- + TRACE("Journal Recover: 2nd Pass: Revoke\n");
- +
- + CachedBlock cached(fJournalVolume);
- + JournalHeader* header;
- + uint32 nextCommitID = fFirstCommitID;
- + uint32 nextBlock = fLogStart;
- + uint32 nextBlockPos;
- +
- + status_t status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK)
- + return status;
- +
- + header = (JournalHeader*)cached.SetTo(nextBlockPos);
- +
- + while (nextCommitID < lastCommitID) {
- + if (!header->CheckMagic() || header->Sequence() != nextCommitID) {
- + // Somehow the log is different than the expexted
- + return B_ERROR;
- + }
- +
- + uint32 blockType = header->BlockType();
- +
- + if (blockType == JOURNAL_DESCRIPTOR_BLOCK)
- + nextBlock = _WrapAroundLog(nextBlock + _CountTags(header));
- + else if (blockType == JOURNAL_COMMIT_BLOCK)
- + nextCommitID++;
- + else if (blockType == JOURNAL_REVOKE_BLOCK) {
- + status = fRevokeManager->ScanRevokeBlock(
- + (JournalRevokeHeader*)header, nextCommitID);
- +
- + if (status != B_OK)
- + return status;
- + } else {
- + // TODO: Warn that we found an unrecognized block
- + break;
- + }
- +
- + nextBlock = _WrapAroundLog(nextBlock + 1);
- +
- + status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK)
- + return status;
- +
- + header = (JournalHeader*)cached.SetTo(nextBlockPos);
- + }
- +
- + if (nextCommitID != lastCommitID) {
- + // Possibly because of some sort of IO error
- + return B_ERROR;
- + }
- +
- + TRACE("Revoked blocks: %lu\n", fRevokeManager->NumRevokes());
- +
- + return B_OK;
- +}
- +
- +
- +// Third pass: Replay log
- +status_t
- +Journal::_RecoverPassReplay(uint32 lastCommitID)
- +{
- + TRACE("Journal Recover: 3rd Pass: Replay\n");
- +
- + uint32 nextCommitID = fFirstCommitID;
- + uint32 nextBlock = fLogStart;
- + uint32 nextBlockPos;
- +
- + status_t status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK)
- + return status;
- +
- + CachedBlock cached(fJournalVolume);
- + JournalHeader* header = (JournalHeader*)cached.SetTo(nextBlockPos);
- +
- + int count = 0;
- +
- + uint8* data = new(std::nothrow) uint8[fBlockSize];
- +
- + while (nextCommitID < lastCommitID) {
- + if (!header->CheckMagic() || header->Sequence() != nextCommitID) {
- + // Somehow the log is different than the expexted
- + return B_ERROR;
- + }
- +
- + uint32 blockType = header->BlockType();
- +
- + if (blockType == JOURNAL_DESCRIPTOR_BLOCK) {
- + JournalBlockTag* last_tag = (JournalBlockTag*)((uint8*)header
- + + fBlockSize - sizeof(JournalBlockTag));
- +
- + for (JournalBlockTag* tag = (JournalBlockTag*)header->data;
- + tag <= last_tag; ++tag) {
- + nextBlock = _WrapAroundLog(nextBlock + 1);
- +
- + status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK) {
- + delete [] data;
- + return status;
- + }
- +
- + size_t read = read_pos(fJournalVolume->Device(),
- + nextBlockPos * fBlockSize, data, fBlockSize);
- + if (read != fBlockSize) {
- + delete [] data;
- + return B_IO_ERROR;
- + }
- +
- + if (!fRevokeManager->Lookup(tag->BlockNumber(),
- + nextCommitID)) {
- + // Block isn't revoked
- + if ((tag->Flags() & JOURNAL_FLAG_ESCAPED) != 0) {
- + // Block is escaped
- + ((int32*)data)[0]
- + = B_HOST_TO_BENDIAN_INT32(JOURNAL_MAGIC);
- + }
- +
- + size_t written = write_pos(fFilesystemVolume->Device(),
- + tag->BlockNumber() * fBlockSize, data, fBlockSize);
- +
- + if (written != fBlockSize) {
- + delete [] data;
- + return B_IO_ERROR;
- + }
- +
- + ++count;
- + }
- +
- + if ((tag->Flags() & JOURNAL_FLAG_LAST_TAG) != 0)
- + break;
- + if ((tag->Flags() & JOURNAL_FLAG_SAME_UUID) == 0) {
- + // TODO: Check new UUID with file system UUID
- + tag += 2;
- + // sizeof(JournalBlockTag) = 8
- + // sizeof(UUID) = 16
- + }
- + }
- + }
- + else if (blockType == JOURNAL_COMMIT_BLOCK)
- + nextCommitID++;
- + else if (blockType != JOURNAL_REVOKE_BLOCK) {
- + // TODO: Warn that we found an unrecognized block
- + break;
- + } // If blockType == JOURNAL_REVOKE_BLOCK we just skip it
- +
- + nextBlock = _WrapAroundLog(nextBlock + 1);
- +
- + status = MapBlock(nextBlock, nextBlockPos);
- + if (status != B_OK)
- + return status;
- +
- + header = (JournalHeader*)cached.SetTo(nextBlockPos);
- + }
- +
- + delete [] data;
- +
- + if (nextCommitID != lastCommitID) {
- + // Possibly because of some sort of IO error
- + return B_ERROR;
- + }
- +
- + TRACE("Replayed blocks: %u\n", count);
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Journal::_FlushLog(bool canWait, bool flushBlocks)
- +{
- + status_t status = canWait ? recursive_lock_lock(&fLock)
- + : recursive_lock_trylock(&fLock);
- + if (status != B_OK)
- + return status;
- +
- + if (recursive_lock_get_recursion(&fLock) > 1) {
- + // Called from inside a transaction
- + recursive_lock_unlock(&fLock);
- + return B_OK;
- + }
- +
- + if (fUnwrittenTransactions != 0 && _FullTransactionSize() != 0) {
- + status = _WriteTransactionToLog();
- + if (status < B_OK)
- + panic("Failed flushing transaction: %s\n", strerror(status));
- + }
- +
- + status = fJournalVolume->FlushDevice();
- + if (status != B_OK)
- + return status;
- +
- + if (flushBlocks)
- + status = fFilesystemVolume->FlushDevice();
- +
- + recursive_lock_unlock(&fLock);
- + return status;
- +}
- +
- +
- +inline uint32
- +Journal::_WrapAroundLog(uint32 block)
- +{
- + if (block >= fLogSize)
- + return block - fLogSize + fLogStart;
- + else
- + return block;
- +}
- +
- +
- +size_t
- +Journal::_CurrentTransactionSize() const
- +{
- + return fHasSubTransaction
- + ? cache_blocks_in_sub_transaction(fFilesystemBlockCache,
- + fTransactionID)
- + : cache_blocks_in_transaction(fFilesystemBlockCache, fTransactionID);
- +}
- +
- +
- +size_t
- +Journal::_FullTransactionSize() const
- +{
- + return cache_blocks_in_transaction(fFilesystemBlockCache, fTransactionID);
- +}
- +
- +
- +size_t
- +Journal::_MainTransactionSize() const
- +{
- + return cache_blocks_in_main_transaction(fFilesystemBlockCache,
- + fTransactionID);
- +}
- +
- +
- +status_t
- +Journal::_TransactionDone(bool success)
- +{
- + if (!success) {
- + if (fHasSubTransaction) {
- + cache_abort_sub_transaction(fFilesystemBlockCache, fTransactionID);
- + // parent is unaffected
- + } else {
- + cache_abort_transaction(fFilesystemBlockCache, fTransactionID);
- + fUnwrittenTransactions = 0;
- + }
- +
- + return B_OK;
- + }
- +
- + // If possible, delay flushing the transaction
- + uint32 size = _FullTransactionSize();
- + if (size < fMaxTransactionSize) {
- + // Make sure the transaction fits in the log
- + if (size < FreeLogBlocks())
- + cache_sync_transaction(fFilesystemBlockCache, fTransactionID);
- +
- + fUnwrittenTransactions++;
- + return B_OK;
- + }
- +
- + return _WriteTransactionToLog();
- +}
- +
- +
- +/*static*/ void
- +Journal::_TransactionWritten(int32 transactionID, int32 event, void* _logEntry)
- +{
- + LogEntry* logEntry = (LogEntry*)_logEntry;
- +
- + TRACE("Transaction finished. ID: %lu\n", transactionID);
- +
- + Journal* journal = logEntry->GetJournal();
- +
- + mutex_lock(&journal->fLogEntriesLock);
- +
- + if (logEntry == journal->fLogEntries.First()) {
- + LogEntry* next = journal->fLogEntries.GetNext(logEntry);
- + if (next != NULL)
- + journal->fLogStart = next->Start();
- + else {
- + journal->fLogStart = journal->fLogEnd;
- + journal->fFirstCommitID = next->CommitID();
- + }
- +
- + journal->_SaveSuperBlock();
- + // TODO: What if this fails?
- + }
- +
- + journal->fLogEntries.Remove(logEntry);
- + mutex_unlock(&journal->fLogEntriesLock);
- +
- + delete logEntry;
- +}
- +
- +
- +/*static*/ void
- +Journal::_TransactionIdle(int32 transactionID, int32 event, void* _journal)
- +{
- + Journal* journal = (Journal*)_journal;
- + journal->_FlushLog(false, false);
- +}
- Property changes on: src/add-ons/kernel/file_systems/ext2/Journal.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/NoJournal.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/NoJournal.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/NoJournal.h (revision 0)
- @@ -0,0 +1,30 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef NOJOURNAL_H
- +#define NOJOURNAL_H
- +
- +
- +#include "Journal.h"
- +
- +
- +class NoJournal : public Journal {
- +public:
- + NoJournal(Volume* volume);
- + ~NoJournal();
- +
- + status_t InitCheck();
- + status_t Recover();
- + status_t StartLog();
- +private:
- + status_t _WriteTransactionToLog();
- +
- + static void _TransactionWritten(int32 transactionID,
- + int32 event, void* param);
- +};
- +
- +#endif // NOJOURNAL_H
- Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.h
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp (working copy)
- @@ -24,17 +24,16 @@
- IndexedDirectoryIterator::IndexedDirectoryIterator(off_t start,
- - uint32 blockSize, Inode* directory, HTreeEntryIterator* parent)
- + Inode* directory, HTreeEntryIterator* parent)
- :
- DirectoryIterator(directory),
- fIndexing(true),
- -
- fParent(parent),
- - fMaxOffset(start + blockSize),
- - fBlockSize(blockSize),
- fMaxAttempts(0)
- {
- - fOffset = start;
- + fDisplacement = start % fBlockSize;
- + fInitStatus = fInode->FindBlock(start / fBlockSize, fBlock);
- + fPreviousBlock = fBlock;
- }
- @@ -46,16 +45,20 @@
- status_t
- IndexedDirectoryIterator::GetNext(char* name, size_t* nameLength, ino_t* id)
- {
- - if (fIndexing && fOffset + sizeof(HTreeFakeDirEntry) >= fMaxOffset) {
- + if (fIndexing && fBlock != fPreviousBlock) {
- TRACE("IndexedDirectoryIterator::GetNext() calling next block\n");
- - status_t status = fParent->GetNext(fOffset);
- +
- + // TODO: If parent doesn't have collisions, the entry wasn't found
- +
- + fDisplacement = 0;
- + status_t status = fParent->GetNext(fBlock);
- if (status != B_OK)
- return status;
- + fPreviousBlock = fBlock;
- +
- if (fMaxAttempts++ > 4)
- return B_ERROR;
- -
- - fMaxOffset = fOffset + fBlockSize;
- }
- return DirectoryIterator::GetNext(name, nameLength, id);
- @@ -67,9 +70,23 @@
- {
- // The only way to rewind it is too loose indexing
- - fOffset = 0;
- - fMaxOffset = fInode->Size();
- + fDisplacement = 0;
- fIndexing = false;
- - return B_OK;
- + return fInode->FindBlock(0, fBlock);
- }
- +
- +
- +status_t
- +IndexedDirectoryIterator::AddEntry(Transaction& transaction, char* name,
- + size_t _nameLength, ino_t id)
- +{
- + panic("Adding entries to a HTree is not supported yet.\n");
- +
- + // TODO: Once the method DirectoryIterator::FindEmptyEntrySpot is
- + // implemented, we should call it to see if the offset exceeds the
- + // fMaxOffset. If it does, the current block is full, and we need
- + // to start splitting nodes.
- +
- + return B_NOT_SUPPORTED;
- +}
- Index: src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h (working copy)
- @@ -8,7 +8,9 @@
- #include <SupportDefs.h>
- +#include "Transaction.h"
- +
- class Inode;
- class DirectoryIterator {
- @@ -16,10 +18,15 @@
- DirectoryIterator(Inode* inode);
- virtual ~DirectoryIterator();
- + virtual status_t InitCheck();
- +
- virtual status_t GetNext(char* name, size_t* _nameLength, ino_t* id);
- virtual status_t Rewind();
- + virtual status_t AddEntry(Transaction& transaction, char* name,
- + size_t nameLength, ino_t id);
- +
- private:
- DirectoryIterator(const DirectoryIterator&);
- DirectoryIterator &operator=(const DirectoryIterator&);
- @@ -27,7 +34,11 @@
- protected:
- Inode* fInode;
- - off_t fOffset;
- + uint32 fBlock;
- + uint32 fDisplacement;
- + uint32 fBlockSize;
- + status_t fInitStatus;
- };
- #endif // DIRECTORY_ITERATOR_H
- +
- Index: src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp (revision 0)
- @@ -0,0 +1,38 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "RevokeManager.h"
- +
- +
- +RevokeManager::RevokeManager()
- + :
- + fRevokeCount(0)
- +{
- +}
- +
- +
- +RevokeManager::~RevokeManager()
- +{
- +}
- +
- +
- +status_t
- +RevokeManager::ScanRevokeBlock(JournalRevokeHeader* revokeBlock, uint32 commitID)
- +{
- + int count = revokeBlock->NumBytes() >> 3;
- +
- + for (int i = 0; i < count; ++i) {
- + status_t status = Insert(revokeBlock->RevokeBlock(i), commitID);
- +
- + if (status != B_OK)
- + return status;
- + }
- +
- + return B_OK;
- +}
- +
- Property changes on: src/add-ons/kernel/file_systems/ext2/RevokeManager.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/Jamfile
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Jamfile (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/Jamfile (working copy)
- @@ -18,6 +18,15 @@
- IndexedDirectoryIterator.cpp
- HTree.cpp
- HTreeEntryIterator.cpp
- + RevokeManager.cpp
- + HashRevokeManager.cpp
- + Journal.cpp
- + NoJournal.cpp
- + InodeJournal.cpp
- + Transaction.cpp
- + BitmapBlock.cpp
- + BlockAllocator.cpp
- + InodeAllocator.cpp
- kernel_interface.cpp
- ;
- Index: src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp (revision 0)
- @@ -0,0 +1,509 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "BitmapBlock.h"
- +
- +
- +BitmapBlock::BitmapBlock(Volume* volume, uint32 numBits)
- + :
- + CachedBlock(volume),
- + fData(NULL),
- + fReadOnlyData(NULL),
- + fNumBits(numBits)
- +{
- +}
- +
- +
- +BitmapBlock::~BitmapBlock()
- +{
- +}
- +
- +
- +/*virtual*/ bool
- +BitmapBlock::SetTo(uint32 block)
- +{
- + fData = NULL;
- + fReadOnlyData = (uint32*)CachedBlock::SetTo(block);
- +
- + return fReadOnlyData != NULL;
- +}
- +
- +
- +/*virtual*/ bool
- +BitmapBlock::SetToWritable(Transaction& transaction, uint32 block, bool empty)
- +{
- + fReadOnlyData = NULL;
- + fData = (uint32*)CachedBlock::SetToWritable(transaction, block, empty);
- +
- + return fData != NULL;
- +}
- +
- +
- +/*virtual*/ bool
- +BitmapBlock::CheckUnmarked(uint32 start, uint32 length)
- +{
- + const uint32* data = fData == NULL ? fReadOnlyData : fData;
- + if (data == NULL)
- + return false;
- +
- + if (start + length > fNumBits)
- + return false;
- +
- + uint32 startIndex = start >> 5;
- + uint32 startBit = start & 0x1F;
- + uint32 iterations = (length - startBit) >> 5;
- + uint32 remainingBits = (length - startBit) & 0x1F;
- +
- + uint32 index = startIndex;
- + uint32 mask = 0;
- +
- + if (startBit != 0) {
- + mask = ~((1 << startBit) - 1);
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- +
- + if ((bits & mask) != 0)
- + return false;
- +
- + index += 1;
- + }
- +
- + for (; iterations > 0; --iterations) {
- + if (data[index++] != 0)
- + return false;
- + }
- +
- + if (remainingBits != 0) {
- + mask = (1 << remainingBits + 1) - 1;
- +
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + if ((bits & mask) != 0)
- + return false;
- + }
- +
- + return true;
- +}
- +
- +
- +/*virtual*/ bool
- +BitmapBlock::CheckMarked(uint32 start, uint32 length)
- +{
- + const uint32* data = fData == NULL ? fReadOnlyData : fData;
- + if (data == NULL)
- + return false;
- +
- + if (start + length > fNumBits)
- + return false;
- +
- + uint32 startIndex = start >> 5;
- + uint32 startBit = start & 0x1F;
- + uint32 iterations = (length - startBit) >> 5;
- + uint32 remainingBits = (length - startBit) & 0x1F;
- +
- + uint32 index = startIndex;
- + uint32 mask = 0;
- +
- + if (startBit != 0) {
- + mask = ~((1 << startBit) - 1);
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- +
- + if ((bits & mask) != mask)
- + return false;
- +
- + index += 1;
- + }
- +
- + mask = 0xFFFFFFFF;
- + for (; iterations > 0; --iterations) {
- + if (data[index++] != mask)
- + return false;
- + }
- +
- + if (remainingBits != 0) {
- + mask = (1 << remainingBits + 1) - 1;
- + uint32 bits = B_HOST_TO_LENDIAN_INT32(data[index]);
- +
- + if ((bits & mask) != mask)
- + return false;
- + }
- +
- + return true;
- +}
- +
- +
- +/*virtual*/ bool
- +BitmapBlock::Mark(uint32 start, uint32 length, bool force)
- +{
- + if (fData != NULL && start + length <= fNumBits)
- + return false;
- +
- + uint32 startIndex = start >> 5;
- + uint32 startBit = start & 0x1F;
- + uint32 iterations = (length - startBit) >> 5;
- + uint32 remainingBits = (length - startBit) & 0x1F;
- +
- + uint32 index = startIndex;
- + uint32 mask = 0;
- +
- + if (startBit != 0) {
- + mask = ~((1 << startBit) - 1);
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
- +
- + if (!force && (bits & mask) != 0)
- + return false;
- +
- + bits |= mask;
- + fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
- +
- + index += 1;
- + }
- +
- + mask = 0xFFFFFFFF;
- + for (; iterations > 0; --iterations) {
- + if (!force && fData[startIndex] != 0)
- + return false;
- + fData[index++] |= mask;
- + }
- +
- + if (remainingBits != 0) {
- + mask = (1 << remainingBits + 1) - 1;
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
- +
- + if (!force && (bits & mask) != 0)
- + return false;
- +
- + bits |= mask;
- + fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
- + }
- +
- + return true;
- +}
- +
- +
- +/*virtual*/ bool
- +BitmapBlock::Unmark(uint32 start, uint32 length, bool force)
- +{
- + if (fData != NULL && start + length <= fNumBits)
- + return false;
- +
- + uint32 startIndex = start >> 5;
- + uint32 startBit = start & 0x1F;
- + uint32 iterations = (length - startBit) >> 5;
- + uint32 remainingBits = (length - startBit) & 0x1F;
- +
- + uint32 index = startIndex;
- + uint32 mask = 0;
- +
- + if (startBit != 0) {
- + mask = ~((1 << startBit) - 1);
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
- +
- + if (!force && (bits & mask) != mask)
- + return false;
- +
- + bits &= ~mask;
- + fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
- +
- + index += 1;
- + }
- +
- + mask = 0xFFFFFFFF;
- + for (; iterations > 0; --iterations) {
- + if (!force && fData[startIndex] != mask)
- + return false;
- + fData[index++] = 0;
- + }
- +
- + if (remainingBits != 0) {
- + mask = (1 << remainingBits + 1) - 1;
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
- +
- + if (!force && (bits & mask) != mask)
- + return false;
- +
- + bits &= ~mask;
- + fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
- + }
- +
- + return true;
- +}
- +
- +
- +void
- +BitmapBlock::FindNextMarked(uint32& pos)
- +{
- + const uint32* data = fData == NULL ? fReadOnlyData : fData;
- + if (data == NULL)
- + return;
- +
- + if (pos >= fNumBits) {
- + pos = fNumBits;
- + return;
- + }
- +
- + uint32 index = pos >> 5;
- + uint32 bit = pos & 0x1F;
- +
- + uint32 mask = (1 << bit) - 1;
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + bits = bits & ~mask;
- +
- + if (bits == 0) {
- + // Find an block of 32 bits that has a marked bit
- + uint32 maxIndex = fNumBits >> 5;
- +
- + do { index++; }
- + while (data[index] == 0 && index < maxIndex);
- +
- + bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + if (bits == 0) {
- + // Not found
- + pos = fNumBits;
- + return;
- + }
- +
- + bit = 0;
- + }
- +
- + for (; bit < 32; ++bit) {
- + // Find the marked bit
- + if ((bits >> bit & 1) != 0) {
- + pos = index << 5 | bit;
- + return;
- + }
- + }
- +
- + panic("Couldn't find marked bit inside an int32 which is different than "
- + "zero!?\n");
- +}
- +
- +
- +void
- +BitmapBlock::FindNextUnmarked(uint32& pos)
- +{
- + const uint32* data = fData == NULL ? fReadOnlyData : fData;
- + if (data == NULL)
- + return;
- +
- + if (pos >= fNumBits) {
- + pos = fNumBits;
- + return;
- + }
- +
- + uint32 index = pos >> 5;
- + uint32 bit = pos & 0x1F;
- +
- + uint32 mask = (1 << bit) - 1;
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + bits &= ~mask;
- +
- + if (bits == ~mask) {
- + // Find an block of 32 bits that has a unmarked bit
- + uint32 maxIndex = fNumBits >> 5;
- +
- + do { index++; }
- + while (data[index] != 0 && index < maxIndex);
- +
- + bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + if (bits != 0) {
- + // Not found
- + pos = fNumBits;
- + return;
- + }
- +
- + bit = 0;
- + }
- +
- + for (; bit < 32; ++bit) {
- + // Find the unmarked bit
- + if ((bits >> bit & 1) == 0) {
- + pos = index << 5 | bit;
- + return;
- + }
- + }
- +
- + panic("Couldn't find unmarked bit inside an int32 whith value zero!?\n");
- +}
- +
- +
- +void
- +BitmapBlock::FindPreviousMarked(uint32& pos)
- +{
- + const uint32* data = fData == NULL ? fReadOnlyData : fData;
- + if (data == NULL)
- + return;
- +
- + if (pos >= fNumBits)
- + pos = fNumBits;
- +
- + if (pos == 0)
- + return;
- +
- + uint32 index = pos >> 5;
- + uint32 bit = pos & 0x1F;
- +
- + uint32 mask = (1 << bit + 1) - 1;
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + bits = bits & mask;
- +
- + if (bits == 0) {
- + // Find an block of 32 bits that has a marked bit
- + do { index--; }
- + while (data[index] == 0 && index >= 0);
- +
- + bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + if (bits == 0) {
- + // Not found
- + pos = 0;
- + return;
- + }
- +
- + bit = 31;
- + }
- +
- + for (; bit >= 0; --bit) {
- + // Find the unmarked bit
- + if ((bits >> bit & 1) == 0) {
- + pos = index << 5 | bit;
- + return;
- + }
- + }
- +
- + panic("Couldn't find marked bit inside an int32 whith value different than "
- + "zero!?\n");
- +}
- +
- +
- +void
- +BitmapBlock::FindLargestUnmarkedRange(uint32& start, uint32& length)
- +{
- + const uint32* data = fData == NULL ? fReadOnlyData : fData;
- + if (data == NULL)
- + return;
- +
- + uint32 wordSpan = length >> 5;
- + uint32 lastIndex = fNumBits >> 5;
- + uint32 startIndex = 0;
- + uint32 index = 0;
- + uint32 bits = B_LENDIAN_TO_HOST_INT32(data[0]);
- +
- + if (wordSpan == 0) {
- + uint32 startPos = 0;
- + uint32 endPos = 0;
- +
- + while (endPos < fNumBits) {
- + FindNextUnmarked(startPos);
- + endPos = startPos;
- +
- + if (startPos != fNumBits) {
- + FindNextMarked(endPos);
- + if (endPos - startPos >= 32)
- + break;
- + else if (endPos - startPos > length) {
- + start = startPos;
- + length = endPos - startPos;
- + }
- +
- + startPos = endPos;
- + }
- + }
- +
- + if (endPos - startPos < 32) {
- + if (endPos - startPos > length) {
- + start = startPos;
- + length = endPos - startPos;
- + }
- +
- + return;
- + }
- +
- + start = startPos;
- + length = endPos - startPos;
- +
- + wordSpan = length >> 5;
- + startIndex = startPos >> 5;
- + index = (endPos >> 5) + 1;
- + bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- + }
- +
- + for (; index < lastIndex; ++index) {
- + bits = B_LENDIAN_TO_HOST_INT32(data[index]);
- +
- + if (bits != 0) {
- + // Contains marked bits
- + if (index - startIndex >= wordSpan) {
- + uint32 newLength = index - startIndex << 5;
- + uint32 newStart = startIndex + 1 << 5;
- +
- + if (newStart != 0) {
- + uint32 startBits =
- + B_LENDIAN_TO_HOST_INT32(data[startIndex]);
- +
- + for (int32 bit = 31; bit >= 0; --bit) {
- + if ((startBits >> bit & 1) != 0)
- + break;
- +
- + ++newLength;
- + --newStart;
- + }
- + }
- +
- + for (int32 bit = 0; bit < 32; ++bit) {
- + if ((bits >> bit & 1) != 0)
- + break;
- +
- + ++newLength;
- + }
- +
- + if (newLength > length) {
- + start = newStart;
- + length = newLength;
- + wordSpan = length >> 5;
- + }
- + }
- +
- + startIndex = index;
- + }
- + }
- +
- + if (index - startIndex >= wordSpan) {
- + uint32 newLength = index - startIndex << 5;
- + uint32 newStart = startIndex + 1 << 5;
- +
- + if (newStart != 0) {
- + uint32 startBits = B_LENDIAN_TO_HOST_INT32(data[startIndex]);
- +
- + for (int32 bit = 31; bit >= 0; --bit) {
- + if ((startBits >> bit & 1) != 0)
- + break;
- +
- + ++newLength;
- + --newStart;
- + }
- + }
- +
- + for (int32 bit = 0; bit < 32; ++bit) {
- + if ((bits >> bit & 1) != 0)
- + break;
- +
- + ++newLength;
- + }
- +
- + if (newLength > length) {
- + start = newStart;
- + length = newLength;
- + wordSpan = length >> 5;
- + }
- + }
- +}
- +
- +
- +uint32
- +BitmapBlock::NumBits() const
- +{
- + return fNumBits;
- +}
- Property changes on: src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/InodeJournal.cpp (revision 0)
- @@ -0,0 +1,40 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "InodeJournal.h"
- +
- +#include <fs_cache.h>
- +
- +
- +InodeJournal::InodeJournal(Inode* inode)
- + :
- + Journal(inode->GetVolume(), inode->GetVolume()),
- + fInode(inode)
- +{
- + if (!inode->IsFileCacheDisabled())
- + fInitStatus = inode->DisableFileCache();
- +}
- +
- +
- +InodeJournal::~InodeJournal()
- +{
- +}
- +
- +
- +status_t
- +InodeJournal::InitCheck()
- +{
- + return fInitStatus;
- +}
- +
- +
- +status_t
- +InodeJournal::MapBlock(uint32 logical, uint32& physical)
- +{
- + return fInode->FindBlock(logical * fBlockSize, physical);
- +}
- Index: src/add-ons/kernel/file_systems/ext2/Transaction.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Transaction.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/Transaction.h (revision 0)
- @@ -0,0 +1,72 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef TRANSACTION_H
- +#define TRANSACTION_H
- +
- +
- +#include <util/DoublyLinkedList.h>
- +
- +
- +class Journal;
- +class Volume;
- +
- +
- +class TransactionListener
- + : public DoublyLinkedListLinkImpl<TransactionListener> {
- +public:
- + TransactionListener();
- + virtual ~TransactionListener();
- +
- + virtual void TransactionDone(bool success) = 0;
- + virtual void RemovedFromTransaction() = 0;
- +};
- +
- +typedef DoublyLinkedList<TransactionListener> TransactionListeners;
- +
- +
- +class Transaction {
- +public:
- + Transaction();
- + Transaction(Journal* journal);
- + ~Transaction();
- +
- + status_t Start(Journal* journal);
- + status_t Done();
- +
- + bool IsStarted() const;
- + bool HasParent() const;
- +
- + status_t WriteBlocks(off_t blockNumber,
- + const uint8* buffer,
- + size_t numBlocks = 1);
- +
- + void Split();
- +
- + Volume* GetVolume() const;
- + int32 ID() const;
- +
- + void AddListener(TransactionListener* listener);
- + void RemoveListener(
- + TransactionListener* listener);
- +
- + void NotifyListeners(bool success);
- + void MoveListenersTo(Transaction* transaction);
- +
- + void SetParent(Transaction* transaction);
- + Transaction* Parent() const;
- +private:
- + Transaction(const Transaction& other);
- + Transaction& operator=(const Transaction& other);
- + // no implementation
- +
- + Journal* fJournal;
- + TransactionListeners fListeners;
- + Transaction* fParent;
- +};
- +
- +#endif // TRANSACTION_H
- Index: src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp (revision 0)
- @@ -0,0 +1,606 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "BlockAllocator.h"
- +
- +#include <util/AutoLock.h>
- +
- +#include "BitmapBlock.h"
- +#include "Inode.h"
- +
- +
- +//#define TRACE_EXT2
- +#ifdef TRACE_EXT2
- +# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
- +#else
- +# define TRACE(x...) ;
- +#endif
- +
- +
- +class AllocationBlockGroup : public TransactionListener {
- +public:
- + AllocationBlockGroup();
- + ~AllocationBlockGroup();
- +
- + status_t Initialize(Volume* v, uint32 blockGroup);
- +
- + status_t ScanFreeRanges();
- + bool IsFull() const;
- +
- + status_t Allocate(Transaction& transaction, uint32 start,
- + uint32 length);
- + status_t Free(Transaction& transaction, uint32 start,
- + uint32 length);
- + status_t FreeAll(Transaction& transaction);
- + status_t Check(uint32 start, uint32 length);
- +
- + uint32 NumBits() const;
- + uint32 FreeBits() const;
- + uint32 Start() const;
- +
- + uint32 LargestStart() const;
- + uint32 LargestLength() const;
- +
- + // TransactionListener implementation
- + void TransactionDone(bool success);
- + void RemovedFromTransaction();
- +
- +private:
- + void _AddFreeRange(uint32 start, uint32 length);
- +
- +
- + Volume* fVolume;
- +
- + uint32 fStart;
- + uint32 fNumBits;
- + uint32 fBitmapBlock;
- +
- + uint32 fFreeBits;
- + uint32 fFirstFree;
- + uint32 fLargestStart;
- + uint32 fLargestLength;
- +
- + uint32 fPreviousFreeBits;
- + uint32 fPreviousFirstFree;
- + uint32 fPreviousLargestStart;
- + uint32 fPreviousLargestLength;
- +};
- +
- +
- +class BlockAllocatorTransactionListener : public TransactionListener {
- +public:
- + BlockAllocatorTransactionListener(
- + BlockAllocator* allocator, uint32 blocks);
- + ~BlockAllocatorTransactionListener();
- +
- + void TransactionDone(bool success);
- + void RemovedFromTransaction();
- +private:
- + BlockAllocator* fAllocator;
- + uint32 fBlockAffected;
- +};
- +
- +
- +AllocationBlockGroup::AllocationBlockGroup()
- + :
- + fStart(0),
- + fNumBits(0),
- + fBitmapBlock(0),
- + fFreeBits(0),
- + fFirstFree(0),
- + fLargestStart(0),
- + fLargestLength(0),
- + fPreviousFreeBits(0),
- + fPreviousFirstFree(0),
- + fPreviousLargestStart(0),
- + fPreviousLargestLength(0)
- +{
- +}
- +
- +
- +AllocationBlockGroup::~AllocationBlockGroup()
- +{
- +}
- +
- +
- +status_t
- +AllocationBlockGroup::Initialize(Volume* volume, uint32 blockGroup)
- +{
- + fVolume = volume;
- +
- + ext2_block_group* group;
- + status_t status = fVolume->GetBlockGroup(blockGroup, &group);
- + if (status != B_OK)
- + return status;
- +
- + if (blockGroup == volume->NumGroups()) {
- + fNumBits = volume->NumBlocks() - volume->BlocksPerGroup() * blockGroup
- + - volume->FirstDataBlock();
- + } else
- + fNumBits = fVolume->BlocksPerGroup();
- +
- + fBitmapBlock = group->BlockBitmap();
- +
- + status = ScanFreeRanges();
- +
- + fPreviousFreeBits = fFreeBits;
- + fPreviousFirstFree = fFirstFree;
- + fPreviousLargestStart = fLargestStart;
- + fPreviousLargestLength = fLargestLength;
- +
- + return status;
- +}
- +
- +
- +status_t
- +AllocationBlockGroup::ScanFreeRanges()
- +{
- + BitmapBlock block(fVolume, fNumBits);
- +
- + if (!block.SetTo(fBitmapBlock))
- + return B_ERROR;
- +
- + uint32 start = 0;
- + uint32 end = 0;
- +
- + while (end < fNumBits) {
- + block.FindNextUnmarked(start);
- + end = start;
- +
- + if (start != block.NumBits()) {
- + block.FindNextMarked(end);
- + _AddFreeRange(start, end);
- + start = end;
- + }
- + }
- +
- + return B_OK;
- +}
- +
- +
- +bool
- +AllocationBlockGroup::IsFull() const
- +{
- + return fFreeBits == 0;
- +}
- +
- +
- +status_t
- +AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
- + uint32 length)
- +{
- + uint32 end = start + length;
- + if (end > fLargestLength)
- + return B_BAD_DATA;
- +
- + BitmapBlock block(fVolume, fNumBits);
- +
- + if (!block.SetToWritable(transaction, fBitmapBlock))
- + return B_ERROR;
- +
- + if (!block.Mark(start, length)) {
- + TRACE("Failed to allocate blocks from %lu to %lu. Some were "
- + "already allocated.\n", start, start + length);
- + return B_ERROR;
- + }
- +
- + transaction.AddListener(this);
- +
- + fFreeBits -= length;
- +
- + if (start == fLargestStart) {
- + if (fFirstFree == fLargestStart)
- + fFirstFree += length;
- +
- + fLargestStart += length;
- + fLargestLength -= length;
- + } else if (start + length == fLargestStart + fLargestLength) {
- + fLargestLength -= length;
- + } else if (start < fLargestStart + fLargestLength
- + && start > fLargestStart) {
- + uint32 firstLength = start - fLargestStart;
- + uint32 secondLength = fLargestStart + fLargestLength
- + - (start + length);
- +
- + if (firstLength >= secondLength) {
- + fLargestLength = firstLength;
- + } else {
- + fLargestLength = secondLength;
- + fLargestStart = start + length;
- + }
- + } else {
- + // No need to revalidate the largest free range
- + return B_OK;
- + }
- +
- + if (fLargestLength < fNumBits / 2)
- + block.FindLargestUnmarkedRange(fLargestStart, fLargestLength);
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +AllocationBlockGroup::Free(Transaction& transaction, uint32 start,
- + uint32 length)
- +{
- + uint32 end = start + length;
- +
- + if (end > fLargestLength)
- + return B_BAD_DATA;
- +
- + BitmapBlock block(fVolume, fNumBits);
- +
- + if (!block.SetToWritable(transaction, fBitmapBlock))
- + return B_ERROR;
- +
- + if (!block.Unmark(start, length)) {
- + TRACE("Failed to free blocks from %lu to %lu. Some were "
- + "already freed.\n", start, start + length);
- + return B_ERROR;
- + }
- +
- + transaction.AddListener(this);
- +
- + if (fFirstFree > start)
- + fFirstFree = start;
- +
- + if (start + length == fLargestStart) {
- + fLargestStart = start;
- + fLargestLength += length;
- + } else if (start == fLargestStart + fLargestLength) {
- + fLargestLength += length;
- + } else if (fLargestLength >= fNumBits / 2) {
- + // May have merged with some free blocks, becoming the largest
- + uint32 newEnd = start + length;
- + block.FindNextMarked(newEnd);
- +
- + uint32 newStart = start;
- + block.FindPreviousMarked(newStart);
- +
- + if (newEnd - newStart > fLargestLength) {
- + fLargestLength = newEnd - newStart;
- + fLargestStart = newStart;
- + }
- + }
- +
- + fFreeBits += length;
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +AllocationBlockGroup::FreeAll(Transaction& transaction)
- +{
- + return Free(transaction, 0, fNumBits);
- +}
- +
- +
- +uint32
- +AllocationBlockGroup::NumBits() const
- +{
- + return fNumBits;
- +}
- +
- +
- +uint32
- +AllocationBlockGroup::FreeBits() const
- +{
- + return fFreeBits;
- +}
- +
- +
- +uint32
- +AllocationBlockGroup::Start() const
- +{
- + return fStart;
- +}
- +
- +
- +uint32
- +AllocationBlockGroup::LargestStart() const
- +{
- + return fLargestStart;
- +}
- +
- +
- +uint32
- +AllocationBlockGroup::LargestLength() const
- +{
- + return fLargestLength;
- +}
- +
- +
- +void
- +AllocationBlockGroup::_AddFreeRange(uint32 start, uint32 length)
- +{
- + if (IsFull()) {
- + fFirstFree = start;
- + fLargestStart = start;
- + fLargestLength = length;
- + } else if (length > fLargestLength) {
- + fLargestStart = start;
- + fLargestLength = length;
- + }
- +
- + fFreeBits += length;
- +}
- +
- +
- +void
- +AllocationBlockGroup::TransactionDone(bool success)
- +{
- + if (success) {
- + fPreviousFreeBits = fFreeBits;
- + fPreviousFirstFree = fFirstFree;
- + fPreviousLargestStart = fLargestStart;
- + fPreviousLargestLength = fLargestLength;
- + } else {
- + fFreeBits = fPreviousFreeBits;
- + fFirstFree = fPreviousFirstFree;
- + fLargestStart = fPreviousLargestStart;
- + fLargestLength = fPreviousLargestLength;
- + }
- +}
- +
- +
- +void
- +AllocationBlockGroup::RemovedFromTransaction()
- +{
- + // TODO: What to do here?
- +}
- +
- +
- +BlockAllocator::BlockAllocator(Volume* volume)
- + :
- + fVolume(volume),
- + fGroups(NULL),
- + fBlocksPerGroup(volume->BlocksPerGroup()),
- + fNumBlocks(0),
- + fNumGroups(0)
- +{
- + mutex_init(&fLock, "ext2 block allocator");
- +}
- +
- +
- +BlockAllocator::~BlockAllocator()
- +{
- + mutex_destroy(&fLock);
- +
- + if (fGroups != NULL)
- + delete [] fGroups;
- +}
- +
- +
- +status_t
- +BlockAllocator::Initialize()
- +{
- + fNumGroups = fVolume->NumGroups();
- + fFirstBlock = fVolume->FirstDataBlock();
- +
- + fGroups = new(std::nothrow) AllocationBlockGroup[fNumGroups];
- + if (fGroups == NULL)
- + return B_NO_MEMORY;
- +
- + mutex_lock(&fLock);
- + // Released by _Initialize
- +
- + thread_id id = -1; // spawn_kernel_thread(
- + // (thread_func)BlockAllocator::_Initialize, "ext2 block allocator",
- + // B_LOW_PRIORITY, this);
- + if (id < B_OK)
- + return _Initialize(this);
- +
- + // mutex_transfer_lock(&fLock, id);
- +
- + // return resume_thread(id);
- + panic("Failed to fall back to synchronous block allocator"
- + "initialization.\n");
- + return B_ERROR;
- +}
- +
- +
- +status_t
- +BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
- + uint32 maximum, uint32& blockGroup, uint32& start, uint32& length)
- +{
- + MutexLocker lock(fLock);
- +
- + uint32 bestStart = 0;
- + uint32 bestLength = 0;
- + uint32 bestGroup = 0;
- +
- + uint32 groupNum = blockGroup;
- +
- + AllocationBlockGroup* last = &fGroups[fNumGroups];
- + AllocationBlockGroup* group = &fGroups[blockGroup];
- +
- + for (int32 iterations = 0; iterations < 2; iterations++) {
- + for (; group < last; ++group, ++groupNum) {
- + if (group->LargestLength() > bestLength) {
- + if (start < group->LargestStart()) {
- + bestStart = group->LargestStart();
- + bestLength = group->LargestLength();
- + bestGroup = groupNum;
- +
- + if (bestLength >= maximum)
- + break;
- + }
- + }
- +
- + start = 0;
- + }
- +
- + if (bestLength >= maximum)
- + break;
- +
- + groupNum = 0;
- +
- + group = &fGroups[0];
- + last = &fGroups[blockGroup];
- + }
- +
- + if (bestLength < minimum)
- + return B_DEVICE_FULL;
- +
- + if (bestLength > maximum)
- + bestLength = maximum;
- +
- + status_t status = fGroups[bestGroup].Allocate(transaction, bestStart,
- + bestLength);
- + if (status != B_OK) {
- + TRACE("Failed to allocate %lu blocks inside block group %lu.\n",
- + bestLength, bestGroup);
- + return status;
- + }
- +
- + start = bestStart;
- + length = bestLength;
- + blockGroup = bestGroup;
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
- + off_t numBlocks, uint32 minimum, uint32& start, uint32& allocated)
- +{
- + if (numBlocks <= 0)
- + return B_ERROR;
- +
- + uint32 group = inode->ID() / fVolume->InodesPerGroup();
- + uint32 preferred = 0;
- +
- + if (inode->Size() > 0) {
- + // Try to allocate near it's last blocks
- + ext2_data_stream* dataStream = &inode->Node().stream;
- + uint32 numBlocks = inode->Size() / fVolume->BlockSize() + 1;
- + uint32 lastBlock = 0;
- +
- + // DANGER! What happens with sparse files?
- + if (numBlocks < EXT2_DIRECT_BLOCKS) {
- + // Only direct blocks
- + lastBlock = dataStream->direct[numBlocks];
- + } else {
- + numBlocks -= EXT2_DIRECT_BLOCKS - 1;
- + uint32 numIndexes = fVolume->BlockSize() / 4;
- + // block size / sizeof(int32)
- + uint32 numIndexes2 = numIndexes * numIndexes;
- + uint32 numIndexes3 = numIndexes2 * numIndexes;
- + uint32 indexesInIndirect = numIndexes;
- + uint32 indexesInDoubleIndirect = indexesInIndirect
- + + numIndexes2;
- + // uint32 indexesInTripleIndirect = indexesInDoubleIndirect
- + // + numIndexes3;
- +
- + uint32 doubleIndirectBlock = EXT2_DIRECT_BLOCKS + 1;
- + uint32 indirectBlock = EXT2_DIRECT_BLOCKS;
- +
- + CachedBlock cached(fVolume);
- + uint32* indirectData;
- +
- + if (numBlocks > indexesInDoubleIndirect) {
- + // Triple indirect blocks
- + indirectData = (uint32*)cached.SetTo(EXT2_DIRECT_BLOCKS + 2);
- + if (indirectData == NULL)
- + return B_IO_ERROR;
- +
- + uint32 index = (numBlocks - indexesInDoubleIndirect)
- + / numIndexes3;
- + doubleIndirectBlock = indirectData[index];
- + }
- +
- + if (numBlocks > indexesInIndirect) {
- + // Double indirect blocks
- + indirectData = (uint32*)cached.SetTo(doubleIndirectBlock);
- + if (indirectData == NULL)
- + return B_IO_ERROR;
- +
- + uint32 index = (numBlocks - indexesInIndirect) / numIndexes2;
- + indirectBlock = indirectData[index];
- + }
- +
- + indirectData = (uint32*)cached.SetTo(indirectBlock);
- + if (indirectData == NULL)
- + return B_IO_ERROR;
- +
- + uint32 index = numBlocks / numIndexes;
- + lastBlock = indirectData[index];
- + }
- +
- + group = (lastBlock - fFirstBlock) / fBlocksPerGroup;
- + preferred = (lastBlock - fFirstBlock) % fBlocksPerGroup + 1;
- + }
- +
- + // TODO: Apply some more policies
- +
- + return AllocateBlocks(transaction, minimum, minimum + 8, group, start,
- + allocated);
- +}
- +
- +
- +status_t
- +BlockAllocator::Free(Transaction& transaction, uint32 start, uint32 length)
- +{
- + MutexLocker lock(fLock);
- +
- + uint32 group = (start - fFirstBlock) / fBlocksPerGroup;
- + start = (start - fFirstBlock) % fBlocksPerGroup;
- + uint32 lastGroup = (start + length - fFirstBlock) / fBlocksPerGroup;
- +
- + if (group == lastGroup)
- + return fGroups[group].Free(transaction, start, length);
- +
- + status_t status = fGroups[group].Free(transaction, start,
- + fGroups[group].NumBits());
- + if (status != B_OK)
- + return status;
- +
- + for (++group; group < lastGroup; ++group) {
- + status = fGroups[group].FreeAll(transaction);
- + if (status != B_OK)
- + return status;
- + }
- +
- + return fGroups[group].Free(transaction, 0, (start + length - fFirstBlock)
- + % fBlocksPerGroup);
- +}
- +
- +
- +/*static*/ status_t
- +BlockAllocator::_Initialize(BlockAllocator* allocator)
- +{
- + // fLock is already heald
- + Volume* volume = allocator->fVolume;
- +
- + AllocationBlockGroup* groups = allocator->fGroups;
- + uint32 numGroups = allocator->fNumGroups;
- +
- + uint32 freeBlocks = 0;
- +
- + for (uint32 i = 0; i < numGroups; ++i) {
- + status_t status = groups[i].Initialize(volume, i);
- + if (status != B_OK) {
- + mutex_unlock(&allocator->fLock);
- + return status;
- + }
- +
- + freeBlocks += groups[i].FreeBits();
- + }
- +
- + mutex_unlock(&allocator->fLock);
- +
- + if (freeBlocks != volume->FreeBlocks()) {
- + TRACE("Counted free blocks doesn't match value in the superblock.\n");
- + return B_BAD_DATA;
- + }
- +
- + return B_OK;
- +}
- Property changes on: src/add-ons/kernel/file_systems/ext2/BlockAllocator.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/Inode.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Inode.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/Inode.cpp (working copy)
- @@ -8,6 +8,7 @@
- #include <fs_cache.h>
- #include <string.h>
- +#include <util/AutoLock.h>
- #include "CachedBlock.h"
- @@ -32,50 +33,95 @@
- rw_lock_init(&fLock, "ext2 inode");
- uint32 block;
- - if (volume->GetInodeBlock(id, block) == B_OK) {
- + fInitStatus = volume->GetInodeBlock(id, block);
- + if (fInitStatus == B_OK) {
- TRACE("inode %Ld at block %lu\n", ID(), block);
- - uint8* inodeBlock = (uint8*)block_cache_get(volume->BlockCache(),
- - block);
- +
- + CachedBlock cached(volume);
- + uint8* inodeBlock = (uint8*)cached.SetTo(block);
- +
- if (inodeBlock != NULL) {
- - fNode = (ext2_inode*)(inodeBlock + volume->InodeBlockIndex(id)
- - * volume->InodeSize());
- - }
- + ext2_inode* inode = (ext2_inode*)(inodeBlock
- + + volume->InodeBlockIndex(id) * volume->InodeSize());
- +
- + fNode = (ext2_inode*)(new(std::nothrow) uint8[volume->InodeSize()]);
- + if (fNode == NULL)
- + fInitStatus = B_NO_MEMORY;
- + else
- + memcpy(fNode, inode, volume->InodeSize());
- + } else
- + fInitStatus = B_IO_ERROR;
- }
- - if (fNode != NULL) {
- - // TODO: we don't need a cache for short symlinks
- + if (fInitStatus == B_OK) {
- fCache = file_cache_create(fVolume->ID(), ID(), Size());
- fMap = file_map_create(fVolume->ID(), ID(), Size());
- - }
- + fCached = true;
- +
- + if (fCache == NULL || Size() == 0 || IsDirectory() || (IsSymLink()
- + && Size() < 60)) {
- + fInitStatus = DisableFileCache();
- + } else
- + fInitStatus = B_OK;
- + } else
- + fCached = false;
- }
- Inode::~Inode()
- {
- - file_cache_delete(FileCache());
- - file_map_delete(Map());
- + if (fCached) {
- + file_cache_delete(FileCache());
- + file_map_delete(Map());
- + }
- if (fAttributesBlock) {
- uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control);
- block_cache_put(fVolume->BlockCache(), block);
- }
- - if (fNode != NULL) {
- + delete fNode;
- +
- + /*if (fNode != NULL) {
- uint32 block;
- if (fVolume->GetInodeBlock(ID(), block) == B_OK)
- block_cache_put(fVolume->BlockCache(), block);
- - }
- + }*/
- }
- status_t
- Inode::InitCheck()
- {
- - return fNode != NULL ? B_OK : B_ERROR;
- + return fInitStatus;
- }
- status_t
- +Inode::WriteBack(Transaction& transaction)
- +{
- + WriteLocker lock(fLock);
- +
- + uint32 inodeBlock;
- +
- + status_t status = fVolume->GetInodeBlock(fID, inodeBlock);
- + if (status != B_OK)
- + return status;
- +
- + CachedBlock cached(fVolume);
- + uint8* inodeBlockData = cached.SetToWritable(transaction, inodeBlock);
- + if (inodeBlockData == NULL)
- + return B_IO_ERROR;
- +
- + memcpy(inodeBlockData +
- + fVolume->InodeBlockIndex(fID) * fVolume->InodeSize(),
- + (uint8*)fNode, sizeof(ext2_inode));
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- Inode::CheckPermissions(int accessMode) const
- {
- uid_t user = geteuid();
- @@ -114,8 +160,10 @@
- uint32 perIndirectBlock = perBlock * perBlock;
- uint32 index = offset >> fVolume->BlockShift();
- - if (offset >= Size())
- + if (offset >= Size()) {
- + TRACE("FindBlock: offset larger than inode size\n");
- return B_ENTRY_NOT_FOUND;
- + }
- // TODO: we could return the size of the sparse range, as this might be more
- // than just a block
- @@ -203,7 +251,8 @@
- // set/check boundaries for pos/length
- if (pos < 0) {
- - TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos, length);
- + TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos,
- + length);
- return B_BAD_VALUE;
- }
- @@ -245,3 +294,34 @@
- *_length = length;
- return B_NO_ERROR;
- }
- +
- +
- +/*static*/ status_t
- +Inode::Create(Transaction& transaction, Inode* parent, const char* name,
- + int32 mode, int openMode, uint32 type, bool* _created, ino_t* _id,
- + Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags)
- +{
- + //DirectoryIterator* entries = NULL;
- +
- + if (parent != NULL) {
- + }
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +Inode::DisableFileCache()
- +{
- + if (fCache == NULL) {
- + fCached = false;
- + return B_OK;
- + }
- +
- + status_t status = file_cache_disable(fCache);
- +
- + if (status == B_OK)
- + fCached = false;
- +
- + return B_OK;
- +}
- Index: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h (revision 0)
- @@ -0,0 +1,47 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef HASHREVOKEMANAGER_H
- +#define HASHREVOKEMANAGER_H
- +
- +#include <util/khash.h>
- +
- +#include "RevokeManager.h"
- +
- +
- +struct RevokeElement {
- + RevokeElement* next; // Next in hash
- + uint32 block;
- + uint32 commitID;
- +};
- +
- +
- +class HashRevokeManager : public RevokeManager {
- +public:
- + HashRevokeManager();
- + virtual ~HashRevokeManager();
- +
- + status_t Init();
- +
- + virtual status_t Insert(uint32 block, uint32 commitID);
- + virtual status_t Remove(uint32 block);
- + virtual bool Lookup(uint32 block, uint32 commitID);
- +
- + static int Compare(void* element, const void* key);
- + static uint32 Hash(void* element, const void* key, uint32 range);
- +
- +protected:
- + status_t _ForceInsert(uint32 block, uint32 commitID);
- +
- +private:
- + hash_table* fHash;
- +
- + const int kInitialHashSize;
- +};
- +
- +#endif // HASHREVOKEMANAGER_H
- +
- Property changes on: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.h
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp (working copy)
- @@ -13,6 +13,7 @@
- #include <fs_info.h>
- #include "AttributeIterator.h"
- +#include "CachedBlock.h"
- #include "DirectoryIterator.h"
- #include "ext2.h"
- #include "HTree.h"
- @@ -339,12 +340,52 @@
- if (!strcmp(buffer, name))
- break;
- }
- -
- +
- return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
- }
- static status_t
- +ext2_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
- + void* buffer, size_t bufferLength)
- +{
- + Volume* volume = (Volume*)_volume->private_volume;
- + switch (cmd) {
- + case 56742:
- + {
- + // Test the block allocator
- + Transaction transaction(volume->GetJournal());
- + CachedBlock cached(volume);
- + uint32 blocksPerGroup = volume->BlocksPerGroup();
- + uint32 blockSize = volume->BlockSize();
- + uint32 firstBlock = volume->FirstDataBlock();
- + uint32 start = 0;
- + uint32 group = 0;
- + uint32 length;
- +
- + TRACE("Attempting to test the ext3 block allocator.\n");
- +
- + while (volume->AllocateBlocks(transaction, 1, 64, group, start,
- + length) == B_OK) {
- + TRACE("Allocated blocks %lu-%lu\n", start, length);
- + uint32 blockNum = start + group * blocksPerGroup - firstBlock;
- +
- + for (uint32 i = 0; i < length; ++i) {
- + uint8* block = cached.SetToWritable(transaction, blockNum);
- + memset(block, 0, blockSize);
- + blockNum++;
- + }
- + }
- +
- + return B_OK;
- + }
- + }
- +
- + return B_OK;
- +}
- +
- +
- +static status_t
- ext2_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
- {
- Inode* inode = (Inode*)_node->private_node;
- @@ -748,8 +789,8 @@
- &ext2_get_file_map,
- + &ext2_ioctl,
- NULL,
- - NULL,
- NULL, // fs_select
- NULL, // fs_deselect
- NULL,
- Index: src/add-ons/kernel/file_systems/ext2/InodeAllocator.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/InodeAllocator.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/InodeAllocator.h (revision 0)
- @@ -0,0 +1,37 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef INODEALLOCATOR_H
- +#define INODEALLOCATOR_H
- +
- +#include <lock.h>
- +
- +#include "Transaction.h"
- +
- +
- +class Volume;
- +
- +
- +class InodeAllocator {
- +public:
- + InodeAllocator(Volume* volume);
- + ~InodeAllocator();
- +
- + status_t New(Transaction& transaction,
- + uint32 prefferedBlockGroup, ino_t& id);
- +
- +private:
- + status_t _MarkInBitmap(Transaction& transaction,
- + uint32 bitmapBlock, uint32 blockGroup,
- + uint32 numInodes, ino_t& id);
- +
- +
- + Volume* fVolume;
- + mutex fLock;
- +};
- +
- +#endif // INODEALLOCATOR_H
- Property changes on: src/add-ons/kernel/file_systems/ext2/InodeAllocator.h
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/HTree.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/HTree.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/HTree.cpp (working copy)
- @@ -7,6 +7,7 @@
- */
- +#include "CachedBlock.h"
- #include "HTree.h"
- #include <new>
- @@ -75,6 +76,7 @@
- HTree::~HTree()
- {
- + delete fRootEntry;
- }
- @@ -92,14 +94,22 @@
- return B_OK;
- }
- - HTreeRoot root;
- - size_t length = sizeof(root);
- + uint32 blockNum;
- + status_t status = fDirectory->FindBlock(0, blockNum);
- + if (status != B_OK) {
- + *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
- +
- + if (*iterator == NULL)
- + return B_NO_MEMORY;
- + return B_OK;
- + }
- +
- + CachedBlock cached(fDirectory->GetVolume());
- + const uint8* block = cached.SetTo(blockNum);
- +
- + HTreeRoot* root = (HTreeRoot*)block;
- - status_t status = fDirectory->ReadAt(0, (uint8*)&root, &length);
- - if (status < B_OK)
- - return status;
- -
- - if (length != sizeof(root) || !root.IsValid()) {
- + if (!root->IsValid()) {
- // Fallback to linear search
- *iterator = new(std::nothrow) DirectoryIterator(fDirectory);
- if (*iterator == NULL)
- @@ -108,21 +118,22 @@
- return B_OK;
- }
- - uint32 hash = _Hash(name, root.hash_version);
- + uint32 hash = _Hash(name, root->hash_version);
- - off_t start = (off_t)root.root_info_length
- + off_t start = (off_t)root->root_info_length
- + 2 * (sizeof(HTreeFakeDirEntry) + 4);
- + delete fRootEntry;
- +
- fRootEntry = new(std::nothrow) HTreeEntryIterator(start, fDirectory);
- if (fRootEntry == NULL)
- return B_NO_MEMORY;
- - fRootDeleter.SetTo(fRootEntry);
- status = fRootEntry->Init();
- if (status != B_OK)
- return status;
- - return fRootEntry->Lookup(hash, (uint32)root.indirection_levels, iterator);
- + return fRootEntry->Lookup(hash, (uint32)root->indirection_levels, iterator);
- }
- @@ -146,7 +157,7 @@
- hash = 0;
- };
- - TRACE("Filename hash: %u\n", hash);
- + TRACE("Filename hash: %lu\n", hash);
- return hash & ~1;
- }
- @@ -354,7 +365,7 @@
- int completeIterations = length / 4;
- for (int i = 0; i < completeIterations; ++i) {
- - uint32 value = 0 | *(string++);
- + uint32 value = (padding << 8) | *(string++);
- value = (value << 8) | *(string++);
- value = (value << 8) | *(string++);
- value = (value << 8) | *(string++);
- Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/NoJournal.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/NoJournal.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/NoJournal.cpp (revision 0)
- @@ -0,0 +1,75 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "NoJournal.h"
- +
- +#include <fs_cache.h>
- +
- +
- +//#define TRACE_EXT2
- +#ifdef TRACE_EXT2
- +# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
- +#else
- +# define TRACE(x...) ;
- +#endif
- +
- +
- +NoJournal::NoJournal(Volume* volume)
- + :
- + Journal()
- +{
- + fFilesystemVolume = volume;
- + fFilesystemBlockCache = volume->BlockCache();
- + fHasSubTransaction = false;
- + fSeparateSubTransactions = false;
- +}
- +
- +
- +NoJournal::~NoJournal()
- +{
- +}
- +
- +
- +status_t
- +NoJournal::InitCheck()
- +{
- + return B_OK;
- +}
- +
- +
- +status_t
- +NoJournal::Recover()
- +{
- + return B_OK;
- +}
- +
- +
- +status_t
- +NoJournal::StartLog()
- +{
- + return B_OK;
- +}
- +
- +
- +status_t
- +NoJournal::_WriteTransactionToLog()
- +{
- + TRACE("Ending transaction %ld\n", fTransactionID);
- +
- + fTransactionID = cache_end_transaction(fFilesystemBlockCache,
- + fTransactionID, _TransactionWritten, NULL);
- +
- + return B_OK;
- +}
- +
- +
- +/*static*/ void
- +NoJournal::_TransactionWritten(int32 transactionID, int32 event, void* param)
- +{
- + TRACE("Transaction %ld checkpointed\n", transactionID);
- +}
- Index: src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h (working copy)
- @@ -26,7 +26,7 @@
- DirectoryIterator** iterator);
- bool HasCollision() { return fHasCollision; }
- - status_t GetNext(off_t& offset);
- + status_t GetNext(uint32& offset);
- private:
- HTreeEntryIterator(uint32 block,
- uint32 blockSize, Inode* directory,
- @@ -34,17 +34,20 @@
- bool hasCollision);
- private:
- + Inode* fDirectory;
- + Volume* fVolume;
- + status_t fInitStatus;
- +
- bool fHasCollision;
- uint16 fLimit, fCount;
- + uint16 fCurrentEntry;
- uint32 fBlockSize;
- - Inode* fDirectory;
- - off_t fOffset;
- - off_t fMaxOffset;
- + uint32 fBlockNum;
- + uint32 fDisplacement;
- HTreeEntryIterator* fParent;
- HTreeEntryIterator* fChild;
- - ObjectDeleter<HTreeEntryIterator> fChildDeleter;
- };
- #endif // HTREE_ENTRY_ITERATOR_H
- Index: src/add-ons/kernel/file_systems/ext2/Volume.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Volume.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/Volume.h (working copy)
- @@ -9,8 +9,12 @@
- #include <lock.h>
- #include "ext2.h"
- +#include "BlockAllocator.h"
- +#include "InodeAllocator.h"
- +#include "Transaction.h"
- class Inode;
- +class Journal;
- enum volume_flags {
- @@ -18,7 +22,7 @@
- };
- -class Volume {
- +class Volume : public TransactionListener {
- public:
- Volume(fs_volume* volume);
- ~Volume();
- @@ -40,30 +44,58 @@
- uint32 NumInodes() const
- { return fNumInodes; }
- + uint32 NumGroups() const
- + { return fNumGroups; }
- off_t NumBlocks() const
- { return fSuperBlock.NumBlocks(); }
- off_t FreeBlocks() const
- { return fSuperBlock.FreeBlocks(); }
- + uint32 FirstDataBlock() const
- + { return fFirstDataBlock; }
- uint32 BlockSize() const { return fBlockSize; }
- uint32 BlockShift() const { return fBlockShift; }
- + uint32 BlocksPerGroup() const
- + { return fSuperBlock.BlocksPerGroup(); }
- uint32 InodeSize() const
- { return fSuperBlock.InodeSize(); }
- + uint32 InodesPerGroup() const
- + { return fSuperBlock.InodesPerGroup(); }
- ext2_super_block& SuperBlock() { return fSuperBlock; }
- status_t GetInodeBlock(ino_t id, uint32& block);
- uint32 InodeBlockIndex(ino_t id) const;
- status_t GetBlockGroup(int32 index,
- ext2_block_group** _group);
- -
- +
- + Journal* GetJournal() { return fJournal; }
- +
- bool IndexedDirectories() const
- { return (fSuperBlock.CompatibleFeatures()
- & EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
- + status_t AllocateInode(Transaction& transaction,
- + uint32 preferredBlockGroup, ino_t& id);
- +
- + status_t AllocateBlocks(Transaction& transaction,
- + uint32 blockGroup, uint32 minimum,
- + uint32 maximum, uint32& start,
- + uint32& length);
- +
- + status_t LoadSuperBlock();
- + status_t WriteSuperBlock(Transaction& transaction);
- +
- // cache access
- void* BlockCache() { return fBlockCache; }
- + status_t FlushDevice();
- + status_t Sync();
- +
- static status_t Identify(int fd, ext2_super_block* superBlock);
- +
- + // TransactionListener functions
- + void TransactionDone(bool success);
- + void RemovedFromTransaction();
- private:
- static uint32 _UnsupportedIncompatibleFeatures(
- @@ -76,12 +108,21 @@
- int fDevice;
- ext2_super_block fSuperBlock;
- char fName[32];
- +
- + BlockAllocator fBlockAllocator;
- + InodeAllocator fInodeAllocator;
- + Journal* fJournal;
- + Inode* fJournalInode;
- +
- uint32 fFlags;
- uint32 fBlockSize;
- uint32 fBlockShift;
- uint32 fFirstDataBlock;
- +
- uint32 fNumInodes;
- uint32 fNumGroups;
- + uint32 fFreeBlocks;
- + uint32 fFreeInodes;
- uint32 fGroupsPerBlock;
- ext2_block_group** fGroupBlocks;
- uint32 fInodesPerBlock;
- Index: src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp (working copy)
- @@ -8,6 +8,7 @@
- #include <string.h>
- +#include "CachedBlock.h"
- #include "HTree.h"
- #include "Inode.h"
- @@ -23,7 +24,9 @@
- DirectoryIterator::DirectoryIterator(Inode* inode)
- :
- fInode(inode),
- - fOffset(0)
- + fBlock(0),
- + fDisplacement(0),
- + fBlockSize(inode->GetVolume()->BlockSize())
- {
- }
- @@ -34,60 +37,129 @@
- status_t
- +DirectoryIterator::InitCheck()
- +{
- + return B_OK;
- +}
- +
- +
- +status_t
- DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
- {
- - if (fOffset + sizeof(ext2_dir_entry) >= fInode->Size()) {
- + if (fDisplacement + sizeof(ext2_dir_entry) >= fInode->Size()) {
- TRACE("DirectoryIterator::GetNext() out of entries\n");
- return B_ENTRY_NOT_FOUND;
- }
- - ext2_dir_entry entry;
- + CachedBlock cached(fInode->GetVolume());
- + ext2_dir_entry* entry;
- + uint32 physicalBlock;
- - while (true) {
- - size_t length = ext2_dir_entry::MinimumSize();
- - status_t status = fInode->ReadAt(fOffset, (uint8*)&entry, &length);
- - if (status != B_OK)
- - return status;
- - if (length < ext2_dir_entry::MinimumSize() || entry.Length() == 0)
- + status_t status = fInode->FindBlock(fBlock * fBlockSize, physicalBlock);
- + if (status != B_OK)
- + return status;
- +
- + const uint8* block = cached.SetTo(physicalBlock);
- + if (block == NULL)
- + return B_IO_ERROR;
- +
- + bool gotEntry = false;
- + while (!gotEntry) {
- + TRACE("Checking entry at block %lu, displacement %lu\n", physicalBlock,
- + fDisplacement);
- +
- + entry = (ext2_dir_entry*)(block + fDisplacement);
- +
- + if (entry->Length() == 0) {
- + TRACE("empty entry.\n");
- return B_ENTRY_NOT_FOUND;
- - if (!entry.IsValid())
- + }
- + if (!entry->IsValid()) {
- + TRACE("invalid entry.\n");
- return B_BAD_DATA;
- + }
- - if (entry.NameLength() != 0)
- - break;
- + if (entry->NameLength() != 0) {
- + // Get name
- + gotEntry = true;
- - fOffset += entry.Length();
- - TRACE("DirectoryIterator::GetNext() skipping entry\n");
- - }
- + size_t length = entry->NameLength();
- - TRACE("offset %Ld: entry ino %lu, length %u, name length %u, type %u\n",
- - fOffset, entry.InodeID(), entry.Length(), entry.NameLength(),
- - entry.FileType());
- + TRACE("block %lu, displacement %lu: entry ino %lu, length %u, "
- + "name length %lu, type %lu\n", fBlock, fDisplacement,
- + entry->InodeID(), entry->Length(), (uint32)length,
- + (uint32)entry->FileType());
- - // read name
- + if (*_nameLength < length)
- + length = *_nameLength - 1;
- + memcpy(name, entry->name, length);
- + name[length] = '\0';
- - size_t length = entry.NameLength();
- - status_t status = fInode->ReadAt(fOffset + ext2_dir_entry::MinimumSize(),
- - (uint8*)entry.name, &length);
- - if (status == B_OK) {
- - if (*_nameLength < length)
- - length = *_nameLength - 1;
- - memcpy(name, entry.name, length);
- - name[length] = '\0';
- + *_id = entry->InodeID();
- + *_nameLength = length;
- + }
- - *_id = entry.InodeID();
- - *_nameLength = length;
- + fDisplacement += entry->Length();
- - fOffset += entry.Length();
- + if (fDisplacement == fBlockSize) {
- + TRACE("Reached end of block\n");
- +
- + fDisplacement = 0;
- + fBlock++;
- +
- + if (!gotEntry) {
- + status = fInode->FindBlock(fBlock * fBlockSize, physicalBlock);
- + if (status != B_OK)
- + return status;
- +
- + block = cached.SetTo(physicalBlock);
- + if (block == NULL)
- + return B_IO_ERROR;
- + }
- + } else if (fDisplacement > fBlockSize && !gotEntry) {
- + TRACE("The entry isn't block aligned.\n");
- + // TODO: Is block alignment obligatory?
- + return B_BAD_DATA;
- + }
- +
- + TRACE("DirectoryIterator::GetNext() skipping entry\n");
- }
- - return status;
- + return B_OK;
- }
- status_t
- DirectoryIterator::Rewind()
- {
- - fOffset = 0;
- + fDisplacement = 0;
- + fBlock = 0;
- +
- return B_OK;
- }
- +
- +
- +status_t
- +DirectoryIterator::AddEntry(Transaction& transaction, char* name,
- + size_t _nameLength, ino_t id)
- +{
- + // TODO: Perhaps we should search for an empty spot with enough space for
- + // the entry, to try to minimize framgentation
- +
- + /*off_t offset = fInode->Size();
- + fBlock = FindBlock(offset,
- + uint8 nameLength = _nameLength > EXT2_NAME_LENGTH ? EXT2_NAME_LENGTH
- + : _nameLength;
- +
- + ext2_dir_entry entry;
- + entry.SetInodeID(id);
- + entry.SetLength(nameLength);
- +
- + status_t status = fInode->WriteAt(transaction, fOffset, (uint8*)&entry,
- + ext2_dir_entry::MinimumSize());
- + if (status != B_OK)
- + return status;
- + return fInode->WriteAt(transaction, fOffset
- + + ext2_dir_entry::MinimumSize(), name, (size_t)nameLength);*/
- + return B_OK;
- +}
- Index: src/add-ons/kernel/file_systems/ext2/Journal.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Journal.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/Journal.h (revision 0)
- @@ -0,0 +1,241 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef JOURNAL_H
- +#define JOURNAL_H
- +
- +
- +#define JOURNAL_MAGIC 0xc03b3998U
- +
- +#define JOURNAL_DESCRIPTOR_BLOCK 1
- +#define JOURNAL_COMMIT_BLOCK 2
- +#define JOURNAL_SUPERBLOCK_V1 3
- +#define JOURNAL_SUPERBLOCK_V2 4
- +#define JOURNAL_REVOKE_BLOCK 5
- +
- +#define JOURNAL_FLAG_ESCAPED 1
- +#define JOURNAL_FLAG_SAME_UUID 2
- +#define JOURNAL_FLAG_DELETED 4
- +#define JOURNAL_FLAG_LAST_TAG 8
- +
- +#define JOURNAL_FEATURE_INCOMPATIBLE_REVOKE 1
- +
- +#define JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES 0
- +#define JOURNAL_KNOWN_INCOMPATIBLE_FEATURES \
- + JOURNAL_FEATURE_INCOMPATIBLE_REVOKE
- +
- +
- +#include "Volume.h"
- +
- +#include <util/DoublyLinkedList.h>
- +
- +#include "Transaction.h"
- +
- +
- +class RevokeManager;
- +
- +
- +struct JournalHeader {
- + uint32 magic;
- + uint32 block_type;
- + uint32 sequence;
- + char data[0];
- +
- + uint32 Magic() const
- + { return B_BENDIAN_TO_HOST_INT32(magic); }
- + uint32 BlockType() const
- + { return B_BENDIAN_TO_HOST_INT32(block_type); }
- + uint32 Sequence() const
- + { return B_BENDIAN_TO_HOST_INT32(sequence); }
- +
- + bool CheckMagic() const
- + { return Magic() == JOURNAL_MAGIC; }
- +
- + void MakeDescriptor(uint32 sequence);
- + void MakeCommit(uint32 sequence);
- +} _PACKED;
- +
- +
- +struct JournalBlockTag {
- + uint32 block_number;
- + uint32 flags;
- +
- + uint32 BlockNumber() const
- + { return B_BENDIAN_TO_HOST_INT32(block_number); }
- + uint32 Flags() const
- + { return B_BENDIAN_TO_HOST_INT32(flags); }
- +
- + void SetBlockNumber(uint32 block)
- + { block_number = B_HOST_TO_BENDIAN_INT32(block); }
- + void SetFlags(uint32 new_flags)
- + { flags = B_HOST_TO_BENDIAN_INT32(new_flags); }
- + void SetLastTagFlag()
- + { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_LAST_TAG); }
- + void SetEscapedFlag()
- + { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_ESCAPED); }
- +} _PACKED;
- +
- +
- +struct JournalRevokeHeader {
- + JournalHeader header;
- + uint32 num_bytes;
- +
- + uint32 revoke_blocks[0];
- +
- + uint32 NumBytes() const
- + { return B_BENDIAN_TO_HOST_INT32(num_bytes); }
- + uint32 RevokeBlock(int offset) const
- + { return B_BENDIAN_TO_HOST_INT32(revoke_blocks[offset]); }
- +} _PACKED;
- +
- +
- +struct JournalSuperBlock {
- + JournalHeader header;
- +
- + uint32 block_size;
- + uint32 num_blocks;
- + uint32 first_log_block;
- +
- + uint32 first_commit_id;
- + uint32 log_start;
- +
- + uint32 error;
- +
- + uint32 compatible_features;
- + uint32 incompatible_features;
- + uint32 read_only_compatible_features;
- +
- + uint8 uuid[16];
- +
- + uint32 num_users;
- + uint32 dynamic_superblock;
- +
- + uint32 max_transaction_blocks;
- + uint32 max_transaction_data;
- +
- + uint32 padding[44];
- +
- + uint8 user_ids[16*48];
- +
- + uint32 BlockSize() const
- + { return B_BENDIAN_TO_HOST_INT32(block_size); }
- + uint32 NumBlocks() const
- + { return B_BENDIAN_TO_HOST_INT32(num_blocks); }
- + uint32 FirstLogBlock() const
- + { return B_BENDIAN_TO_HOST_INT32(first_log_block); }
- + uint32 FirstCommitID() const
- + { return B_BENDIAN_TO_HOST_INT32(first_commit_id); }
- + uint32 LogStart() const
- + { return B_BENDIAN_TO_HOST_INT32(compatible_features); }
- + uint32 IncompatibleFeatures() const
- + { return B_BENDIAN_TO_HOST_INT32(incompatible_features); }
- + uint32 ReadOnlyCompatibleFeatures() const
- + { return B_BENDIAN_TO_HOST_INT32(read_only_compatible_features); }
- + uint32 MaxTransactionData() const
- + { return B_BENDIAN_TO_HOST_INT32(max_transaction_data); }
- +
- + void SetLogStart(uint32 logStart)
- + { log_start = B_HOST_TO_BENDIAN_INT32(logStart); }
- + void SetFirstCommitID(uint32 firstCommitID)
- + { first_commit_id = B_HOST_TO_BENDIAN_INT32(firstCommitID); }
- +} _PACKED;
- +
- +class LogEntry;
- +class Transaction;
- +typedef DoublyLinkedList<LogEntry> LogEntryList;
- +
- +
- +class Journal {
- +public:
- + Journal(Volume *fsVolume, Volume *jVolume);
- + virtual ~Journal();
- +
- + virtual status_t InitCheck();
- + virtual status_t Recover();
- + virtual status_t StartLog();
- + status_t RestartLog();
- +
- + status_t Lock(Transaction* owner,
- + bool separateSubTransactions);
- + status_t Unlock(Transaction* owner, bool success);
- +
- + virtual status_t MapBlock(uint32 logical, uint32& physical);
- + inline uint32 FreeLogBlocks() const;
- +
- + status_t FlushLogAndBlocks();
- +
- + int32 TransactionID() const;
- +
- + Volume* GetFilesystemVolume()
- + { return fFilesystemVolume; }
- +protected:
- + Journal();
- +
- + virtual status_t _WriteTransactionToLog();
- +
- +
- + Volume* fJournalVolume;
- + void* fJournalBlockCache;
- + Volume* fFilesystemVolume;
- + void* fFilesystemBlockCache;
- +
- + recursive_lock fLock;
- + Transaction* fOwner;
- +
- + RevokeManager* fRevokeManager;
- +
- + status_t fInitStatus;
- + uint32 fBlockSize;
- + uint32 fFirstCommitID;
- + uint32 fFirstCacheCommitID;
- + uint32 fFirstLogBlock;
- + uint32 fLogSize;
- + uint32 fVersion;
- +
- + uint32 fLogStart;
- + uint32 fLogEnd;
- + uint32 fFreeBlocks;
- + uint32 fMaxTransactionSize;
- +
- + uint32 fCurrentCommitID;
- + //uint32 fNextCommitID;
- +
- + LogEntryList fLogEntries;
- + mutex fLogEntriesLock;
- + bool fHasSubTransaction;
- + bool fSeparateSubTransactions;
- + int32 fUnwrittenTransactions;
- + int32 fTransactionID;
- +
- +private:
- + status_t _SaveSuperBlock();
- + status_t _LoadSuperBlock();
- + status_t _CheckFeatures(JournalSuperBlock* superblock);
- +
- + uint32 _CountTags(JournalHeader *descriptorBlock);
- + status_t _RecoverPassScan(uint32& lastCommitID);
- + status_t _RecoverPassRevoke(uint32 lastCommitID);
- + status_t _RecoverPassReplay(uint32 lastCommitID);
- +
- + status_t _FlushLog(bool canWait, bool flushBlocks);
- +
- + inline uint32 _WrapAroundLog(uint32 block);
- +
- + size_t _CurrentTransactionSize() const;
- + size_t _FullTransactionSize() const;
- + size_t _MainTransactionSize() const;
- +
- + virtual status_t _TransactionDone(bool success);
- +
- + static void _TransactionWritten(int32 transactionID,
- + int32 event, void* _logEntry);
- + static void _TransactionIdle(int32 transactionID,
- + int32 event, void* _journal);
- +};
- +
- +#endif // JOURNAL_H
- +
- Property changes on: src/add-ons/kernel/file_systems/ext2/Journal.h
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h (working copy)
- @@ -17,7 +17,7 @@
- class IndexedDirectoryIterator : public DirectoryIterator {
- public:
- IndexedDirectoryIterator(off_t start,
- - uint32 blockSize, Inode* directory,
- + Inode* directory,
- HTreeEntryIterator* parent);
- virtual ~IndexedDirectoryIterator();
- @@ -25,12 +25,15 @@
- ino_t* id);
- status_t Rewind();
- +
- + status_t AddEntry(Transaction& transaction, char* name,
- + size_t _nameLength, ino_t id);
- +
- private:
- bool fIndexing;
- HTreeEntryIterator* fParent;
- - off_t fMaxOffset;
- - uint32 fBlockSize;
- uint32 fMaxAttempts;
- + uint32 fPreviousBlock;
- };
- #endif // INDEXED_DIRECTORY_ITERATOR_H
- Index: src/add-ons/kernel/file_systems/ext2/Transaction.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/Transaction.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/Transaction.cpp (revision 0)
- @@ -0,0 +1,201 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "Transaction.h"
- +
- +#include <string.h>
- +
- +#include <fs_cache.h>
- +
- +#include "Journal.h"
- +
- +
- +TransactionListener::TransactionListener()
- +{
- +}
- +
- +
- +TransactionListener::~TransactionListener()
- +{
- +}
- +
- +
- +Transaction::Transaction()
- + :
- + fJournal(NULL),
- + fParent(NULL)
- +{
- +}
- +
- +
- +Transaction::Transaction(Journal* journal)
- + :
- + fJournal(NULL),
- + fParent(NULL)
- +{
- + Start(journal);
- +}
- +
- +
- +Transaction::~Transaction()
- +{
- + if (IsStarted())
- + fJournal->Unlock(this, false);
- +}
- +
- +status_t
- +Transaction::Start(Journal* journal)
- +{
- + if (IsStarted())
- + return B_OK;
- +
- + fJournal = journal;
- + if (fJournal == NULL)
- + return B_ERROR;
- +
- + status_t status = fJournal->Lock(this, false);
- + if (status != B_OK)
- + fJournal = NULL;
- +
- + return status;
- +}
- +
- +
- +status_t
- +Transaction::Done()
- +{
- + if (!IsStarted())
- + return B_OK;
- +
- + status_t status = fJournal->Unlock(this, true);
- +
- + if (status == B_OK)
- + fJournal = NULL;
- +
- + return status;
- +}
- +
- +
- +int32
- +Transaction::ID() const
- +{
- + if (!IsStarted())
- + return -1;
- +
- + return fJournal->TransactionID();
- +}
- +
- +
- +bool
- +Transaction::IsStarted() const
- +{
- + return fJournal != NULL;
- +}
- +
- +
- +bool
- +Transaction::HasParent() const
- +{
- + return fParent != NULL;
- +}
- +
- +
- +status_t
- +Transaction::WriteBlocks(off_t blockNumber, const uint8* buffer,
- + size_t numBlocks)
- +{
- + if (!IsStarted())
- + return B_NO_INIT;
- +
- + void* cache = GetVolume()->BlockCache();
- + size_t blockSize = GetVolume()->BlockSize();
- +
- + for (size_t i = 0; i < numBlocks; ++i) {
- + void* block = block_cache_get_empty(cache, blockNumber + i, ID());
- + if (block == NULL)
- + return B_ERROR;
- +
- + memcpy(block, buffer, blockSize);
- + buffer += blockSize;
- +
- + block_cache_put(cache, blockNumber + i);
- + }
- +
- + return B_OK;
- +}
- +
- +
- +void
- +Transaction::Split()
- +{
- + cache_start_sub_transaction(fJournal->GetFilesystemVolume()->BlockCache(),
- + ID());
- +}
- +
- +
- +Volume*
- +Transaction::GetVolume() const
- +{
- + if (!IsStarted())
- + return NULL;
- +
- + return fJournal->GetFilesystemVolume();
- +}
- +
- +
- +void
- +Transaction::AddListener(TransactionListener* listener)
- +{
- + if (!IsStarted())
- + panic("Transaction is not running!");
- +
- + fListeners.Add(listener);
- +}
- +
- +
- +void
- +Transaction::RemoveListener(TransactionListener* listener)
- +{
- + if (!IsStarted())
- + panic("Transaction is not running!");
- +
- + fListeners.Remove(listener);
- + listener->RemovedFromTransaction();
- +}
- +
- +
- +void
- +Transaction::NotifyListeners(bool success)
- +{
- + while (TransactionListener* listener = fListeners.RemoveHead()) {
- + listener->TransactionDone(success);
- + listener->RemovedFromTransaction();
- + }
- +}
- +
- +
- +void
- +Transaction::MoveListenersTo(Transaction* transaction)
- +{
- + while (TransactionListener* listener = fListeners.RemoveHead())
- + transaction->fListeners.Add(listener);
- +}
- +
- +
- +void
- +Transaction::SetParent(Transaction* transaction)
- +{
- + fParent = transaction;
- +}
- +
- +
- +Transaction*
- +Transaction::Parent() const
- +{
- + return fParent;
- +}
- Index: src/add-ons/kernel/file_systems/ext2/ext2.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/ext2.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/ext2.h (working copy)
- @@ -13,6 +13,8 @@
- #include <KernelExport.h>
- +#define TRACE_EXT2
- +
- #define EXT2_SUPER_BLOCK_OFFSET 1024
- struct ext2_super_block {
- @@ -108,9 +110,16 @@
- { return B_LENDIAN_TO_HOST_INT32(read_only_features); }
- uint32 IncompatibleFeatures() const
- { return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
- + ino_t JournalInode() const
- + { return B_LENDIAN_TO_HOST_INT32(journal_inode); }
- uint32 HashSeed(uint8 i) const
- { return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
- + void SetFreeInodes(uint32 freeInodes)
- + { free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
- + void SetFreeBlocks(uint32 freeBlocks)
- + { free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks); }
- +
- bool IsValid();
- // implemented in Volume.cpp
- } _PACKED;
- @@ -162,8 +171,16 @@
- uint16 _padding;
- uint32 _reserved[3];
- + uint32 BlockBitmap() const
- + { return B_LENDIAN_TO_HOST_INT32(block_bitmap); }
- + uint32 InodeBitmap() const
- + { return B_LENDIAN_TO_HOST_INT32(inode_bitmap); }
- uint32 InodeTable() const
- { return B_LENDIAN_TO_HOST_INT32(inode_table); }
- + uint16 FreeBlocks() const
- + { return B_LENDIAN_TO_HOST_INT16(free_blocks); }
- + uint16 FreeInodes() const
- + { return B_LENDIAN_TO_HOST_INT16(free_inodes); }
- } _PACKED;
- #define EXT2_DIRECT_BLOCKS 12
- @@ -214,6 +231,7 @@
- uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
- uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
- uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
- + uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
- time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
- time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
- @@ -270,11 +288,26 @@
- uint8 file_type;
- char name[EXT2_NAME_LENGTH];
- - uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
- - uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
- - uint8 NameLength() const { return name_length; }
- - uint8 FileType() const { return file_type; }
- + uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
- + uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
- + uint8 NameLength() const { return name_length; }
- + uint8 FileType() const { return file_type; }
- + void SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
- +
- + void SetLength(uint8 nameLength)
- + {
- + name_length = nameLength;
- +
- + if (nameLength % 4 == 0) {
- + length = B_HOST_TO_LENDIAN_INT16(
- + (short)(nameLength + MinimumSize()));
- + } else {
- + length = B_HOST_TO_LENDIAN_INT16(
- + (short)(nameLength % 4 + 1 + MinimumSize()));
- + }
- + }
- +
- bool IsValid() const
- {
- return Length() > MinimumSize();
- Index: src/add-ons/kernel/file_systems/ext2/CachedBlock.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/CachedBlock.h (revision 37473)
- +++ src/add-ons/kernel/file_systems/ext2/CachedBlock.h (working copy)
- @@ -9,32 +9,40 @@
- #include <fs_cache.h>
- +#include "Transaction.h"
- #include "Volume.h"
- class CachedBlock {
- public:
- - CachedBlock(Volume* volume);
- - CachedBlock(Volume* volume, uint32 block);
- - ~CachedBlock();
- + CachedBlock(Volume* volume);
- + CachedBlock(Volume* volume, uint32 block);
- + ~CachedBlock();
- - void Keep();
- - void Unset();
- + void Keep();
- + void Unset();
- - const uint8* SetTo(uint32 block);
- + const uint8* SetTo(uint32 block);
- + uint8* SetToWritable(Transaction& transaction,
- + uint32 block, bool empty = false);
- + uint8* SetToWritableWithoutTransaction(uint32 block,
- + bool empty = false);
- - const uint8* Block() const { return fBlock; }
- - off_t BlockNumber() const { return fBlockNumber; }
- + const uint8* Block() const { return fBlock; }
- + off_t BlockNumber() const { return fBlockNumber; }
- private:
- - CachedBlock(const CachedBlock &);
- - CachedBlock &operator=(const CachedBlock &);
- - // no implementation
- + CachedBlock(const CachedBlock &);
- + CachedBlock &operator=(const CachedBlock &);
- + // no implementation
- +
- + uint8* _SetToWritableEtc(int32 transaction, uint32 block,
- + bool empty);
- protected:
- - Volume* fVolume;
- - uint32 fBlockNumber;
- - uint8* fBlock;
- + Volume* fVolume;
- + uint32 fBlockNumber;
- + uint8* fBlock;
- };
- @@ -94,4 +102,35 @@
- return fBlock = (uint8 *)block_cache_get(fVolume->BlockCache(), block);
- }
- +
- +inline uint8*
- +CachedBlock::SetToWritable(Transaction& transaction, uint32 block, bool empty)
- +{
- + return _SetToWritableEtc(transaction.ID(), block, empty);
- +}
- +
- +
- +inline uint8*
- +CachedBlock::SetToWritableWithoutTransaction(uint32 block, bool empty)
- +{
- + return _SetToWritableEtc((int32)-1, block, empty);
- +}
- +
- +inline uint8*
- +CachedBlock::_SetToWritableEtc(int32 transaction, uint32 block, bool empty)
- +{
- + Unset();
- + fBlockNumber = block;
- +
- + if (empty) {
- + fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(),
- + block, transaction);
- + } else {
- + fBlock = (uint8*)block_cache_get_writable(fVolume->BlockCache(),
- + block, transaction);
- + }
- +
- + return fBlock;
- +}
- +
- #endif // CACHED_BLOCK_H
- Index: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp (revision 0)
- @@ -0,0 +1,141 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +
- +#include "HashRevokeManager.h"
- +
- +#include <new>
- +
- +
- +HashRevokeManager::HashRevokeManager()
- + :
- + kInitialHashSize(128)
- + // TODO: Benchmark and find an optimal value
- +{
- +}
- +
- +
- +HashRevokeManager::~HashRevokeManager()
- +{
- + hash_uninit(fHash);
- +}
- +
- +
- +status_t
- +HashRevokeManager::Init()
- +{
- + RevokeElement dummyElement;
- +
- + fHash = hash_init(kInitialHashSize, offset_of_member(dummyElement, next),
- + &HashRevokeManager::Compare,
- + &HashRevokeManager::Hash);
- +
- + if (fHash == NULL)
- + return B_NO_MEMORY;
- +
- + return B_OK;
- +}
- +
- +
- +status_t
- +HashRevokeManager::Insert(uint32 block, uint32 commitID)
- +{
- + RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
- +
- + if (element != NULL) {
- + if (element->commitID < commitID) {
- + status_t retValue = hash_remove(fHash, element);
- +
- + if (retValue != B_OK)
- + return retValue;
- +
- + delete element;
- + }
- + else {
- + return B_OK;
- + // We already have a newer version of the block
- + }
- + }
- +
- + return _ForceInsert(block, commitID);
- +}
- +
- +
- +status_t
- +HashRevokeManager::Remove(uint32 block)
- +{
- + RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
- +
- + if (element == NULL)
- + return B_ERROR; // TODO: Perhaps we should just ignore?
- +
- + status_t retValue = hash_remove(fHash, element);
- +
- + if (retValue == B_OK)
- + delete element;
- +
- + return retValue;
- +}
- +
- +
- +bool
- +HashRevokeManager::Lookup(uint32 block, uint32 commitID)
- +{
- + RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
- +
- + if (element == NULL)
- + return false;
- +
- + return element->commitID >= commitID;
- +}
- +
- +
- +/*static*/ int
- +HashRevokeManager::Compare(void* _revoked, const void *_block)
- +{
- + RevokeElement* revoked = (RevokeElement*)_revoked;
- + uint32 block = *(uint32*)_block;
- +
- + if (revoked->block == block)
- + return 0;
- +
- + return (revoked->block > block) ? 1 : -1;
- +}
- +
- +
- +/*static*/ uint32
- +HashRevokeManager::Hash(void* _revoked, const void* _block, uint32 range)
- +{
- + RevokeElement* revoked = (RevokeElement*)revoked;
- + uint32 block = *(uint32*)_block;
- +
- + if (revoked != NULL)
- + return revoked->block % range;
- +
- + return block % range;
- +}
- +
- +
- +status_t
- +HashRevokeManager::_ForceInsert(uint32 block, uint32 commitID)
- +{
- + RevokeElement* element = new(std::nothrow) RevokeElement;
- +
- + if (element == NULL)
- + return B_NO_MEMORY;
- +
- + element->block = block;
- + element->commitID = commitID;
- +
- + status_t retValue = hash_insert_grow(fHash, element);
- +
- + if (retValue == B_OK)
- + fRevokeCount++;
- +
- + return retValue;
- +}
- +
- Property changes on: src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/RevokeManager.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/RevokeManager.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/RevokeManager.h (revision 0)
- @@ -0,0 +1,35 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef REVOKEMANAGER_H
- +#define REVOKEMANAGER_H
- +
- +#include "Journal.h"
- +
- +
- +struct JournalRevokeHeader;
- +
- +class RevokeManager {
- +public:
- + RevokeManager();
- + virtual ~RevokeManager() = 0;
- +
- + virtual status_t Insert(uint32 block, uint32 commitID) = 0;
- + virtual status_t Remove(uint32 block) = 0;
- + virtual bool Lookup(uint32 block, uint32 commitID) = 0;
- +
- + uint32 NumRevokes() { return fRevokeCount; }
- +
- + status_t ScanRevokeBlock(JournalRevokeHeader* revokeBlock,
- + uint32 commitID);
- +
- +protected:
- + uint32 fRevokeCount;
- +};
- +
- +#endif // REVOKEMANAGER_H
- +
- Property changes on: src/add-ons/kernel/file_systems/ext2/RevokeManager.h
- ___________________________________________________________________
- Added: svn:executable
- + *
- Index: src/add-ons/kernel/file_systems/ext2/BitmapBlock.h
- ===================================================================
- --- src/add-ons/kernel/file_systems/ext2/BitmapBlock.h (revision 0)
- +++ src/add-ons/kernel/file_systems/ext2/BitmapBlock.h (revision 0)
- @@ -0,0 +1,48 @@
- +/*
- + * Copyright 2001-2010, Haiku Inc. All rights reserved.
- + * This file may be used under the terms of the MIT License.
- + *
- + * Authors:
- + * Janito V. Ferreira Filho
- + */
- +#ifndef BITMAPBLOCK_H
- +#define BITMAPBLOCK_H
- +
- +#include "CachedBlock.h"
- +
- +
- +class BitmapBlock : public CachedBlock {
- +public:
- + BitmapBlock(Volume* volume, uint32 numBits);
- + ~BitmapBlock();
- +
- + bool SetTo(uint32 block);
- + bool SetToWritable(Transaction& transaction,
- + uint32 block, bool empty = false);
- +
- + bool CheckMarked(uint32 start, uint32 length);
- + bool CheckUnmarked(uint32 start, uint32 length);
- +
- + bool Mark(uint32 start, uint32 length,
- + bool force = false);
- + bool Unmark(uint32 start, uint32 length,
- + bool force = false);
- +
- + void FindNextMarked(uint32& pos);
- + void FindNextUnmarked(uint32& pos);
- +
- + void FindPreviousMarked(uint32& pos);
- +
- + void FindLargestUnmarkedRange(uint32& start,
- + uint32& length);
- +
- + uint32 NumBits() const;
- +
- +protected:
- + uint32* fData;
- + const uint32* fReadOnlyData;
- +
- + uint32 fNumBits;
- +};
- +
- +#endif // BITMAPBLOCK_H
- Property changes on: src/add-ons/kernel/file_systems/ext2/BitmapBlock.h
- ___________________________________________________________________
- Added: svn:executable
- + *
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement