* Replaced the specialized inode in transaction mechanism with a generic one.
That costs 12 more bytes per inode on 32 bit platforms, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35491 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
2a8ae7fb92
commit
fd91cf4d18
@ -3,6 +3,7 @@
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
//! block bitmap handling and allocation policies
|
||||
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
//! inode access functions
|
||||
|
||||
//! Inode access functions
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -175,7 +176,7 @@ InodeAllocator::~InodeAllocator()
|
||||
fInode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE);
|
||||
// this unblocks any pending bfs_read_vnode() calls
|
||||
fInode->Free(*fTransaction);
|
||||
fTransaction->RemoveInode(fInode);
|
||||
fTransaction->RemoveListener(fInode);
|
||||
|
||||
remove_vnode(volume->FSVolume(), fInode->ID());
|
||||
} else
|
||||
@ -291,7 +292,7 @@ InodeAllocator::_TransactionListener(int32 id, int32 event, void* _inode)
|
||||
|
||||
|
||||
status_t
|
||||
bfs_inode::InitCheck(Volume* volume)
|
||||
bfs_inode::InitCheck(Volume* volume) const
|
||||
{
|
||||
if (Magic1() != INODE_MAGIC1
|
||||
|| !(Flags() & INODE_IN_USE)
|
||||
@ -403,7 +404,7 @@ Inode::~Inode()
|
||||
|
||||
|
||||
status_t
|
||||
Inode::InitCheck(bool checkNode)
|
||||
Inode::InitCheck(bool checkNode) const
|
||||
{
|
||||
// test inode magic and flags
|
||||
if (checkNode) {
|
||||
@ -437,6 +438,33 @@ Inode::InitCheck(bool checkNode)
|
||||
}
|
||||
|
||||
|
||||
/*! Adds this inode to the specified transaction. This means that the inode will
|
||||
be write locked until the transaction ended.
|
||||
To ensure that the inode will stay valid until that point, an extra reference
|
||||
is acquired to it as long as this transaction stays active.
|
||||
*/
|
||||
void
|
||||
Inode::WriteLockInTransaction(Transaction& transaction)
|
||||
{
|
||||
// These flags can only change while holding the transaction lock
|
||||
if ((Flags() & INODE_IN_TRANSACTION) != 0)
|
||||
return;
|
||||
|
||||
// We share the same list link with the removed list, so we have to remove
|
||||
// the inode from that list here (and add it back when we no longer need it)
|
||||
if ((Flags() & INODE_DELETED) != 0)
|
||||
fVolume->RemovedInodes().Remove(this);
|
||||
|
||||
if (!fVolume->IsInitializing())
|
||||
acquire_vnode(fVolume->FSVolume(), ID());
|
||||
|
||||
rw_lock_write_lock(&Lock());
|
||||
Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||
|
||||
transaction.AddListener(this);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::WriteBack(Transaction& transaction)
|
||||
{
|
||||
@ -2379,6 +2407,35 @@ Inode::Sync()
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - TransactionListener implementation
|
||||
|
||||
|
||||
void
|
||||
Inode::TransactionDone(bool success)
|
||||
{
|
||||
if (!success) {
|
||||
// revert any changes made to the cached bfs_inode
|
||||
UpdateNodeFromDisk();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Inode::RemovedFromTransaction()
|
||||
{
|
||||
Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||
|
||||
// See AddInode() why we do this here
|
||||
if ((Flags() & INODE_DELETED) != 0)
|
||||
fVolume->RemovedInodes().Add(this);
|
||||
|
||||
rw_lock_write_unlock(&Lock());
|
||||
|
||||
if (!fVolume->IsInitializing())
|
||||
put_vnode(fVolume->FSVolume(), ID());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - creation/deletion
|
||||
|
||||
|
||||
|
@ -23,241 +23,245 @@ class NodeGetter;
|
||||
class Transaction;
|
||||
|
||||
|
||||
class Inode {
|
||||
class Inode : public TransactionListener {
|
||||
typedef DoublyLinkedListLink<Inode> Link;
|
||||
|
||||
public:
|
||||
Inode(Volume* volume, ino_t id);
|
||||
Inode(Volume* volume, Transaction& transaction,
|
||||
ino_t id, mode_t mode, block_run& run);
|
||||
~Inode();
|
||||
Inode(Volume* volume, ino_t id);
|
||||
Inode(Volume* volume, Transaction& transaction,
|
||||
ino_t id, mode_t mode, block_run& run);
|
||||
~Inode();
|
||||
|
||||
ino_t ID() const { return fID; }
|
||||
off_t BlockNumber() const
|
||||
{ return fVolume->VnodeToBlock(fID); }
|
||||
status_t InitCheck(bool checkNode = true) const;
|
||||
|
||||
rw_lock& Lock() { return fLock; }
|
||||
ReadLocker ReadLock() { return ReadLocker(fLock); }
|
||||
void WriteLockInTransaction(Transaction& transaction)
|
||||
{ transaction.AddInode(this); }
|
||||
ino_t ID() const { return fID; }
|
||||
off_t BlockNumber() const
|
||||
{ return fVolume->VnodeToBlock(fID); }
|
||||
|
||||
recursive_lock& SmallDataLock() { return fSmallDataLock; }
|
||||
rw_lock& Lock() { return fLock; }
|
||||
ReadLocker ReadLock() { return ReadLocker(fLock); }
|
||||
void WriteLockInTransaction(Transaction& transaction);
|
||||
|
||||
status_t WriteBack(Transaction& transaction);
|
||||
void UpdateNodeFromDisk();
|
||||
recursive_lock& SmallDataLock() { return fSmallDataLock; }
|
||||
|
||||
bool IsContainer() const
|
||||
{ return S_ISDIR(Mode()); }
|
||||
bool IsDirectory() const
|
||||
{ return is_directory(Mode()); }
|
||||
bool IsIndex() const
|
||||
{ return is_index(Mode()); }
|
||||
status_t WriteBack(Transaction& transaction);
|
||||
void UpdateNodeFromDisk();
|
||||
|
||||
bool IsAttributeDirectory() const
|
||||
{ return (Mode() & S_EXTENDED_TYPES)
|
||||
== S_ATTR_DIR; }
|
||||
bool IsAttribute() const
|
||||
{ return (Mode() & S_EXTENDED_TYPES)
|
||||
== S_ATTR; }
|
||||
bool IsFile() const
|
||||
{ return (Mode()
|
||||
& (S_IFMT | S_EXTENDED_TYPES)) == S_FILE; }
|
||||
bool IsRegularNode() const
|
||||
{ return (Mode() & S_EXTENDED_TYPES) == 0; }
|
||||
// a regular node in the standard namespace
|
||||
// (i.e. not an index or attribute)
|
||||
bool IsSymLink() const { return S_ISLNK(Mode()); }
|
||||
bool IsLongSymLink() const
|
||||
{ return (Flags() & INODE_LONG_SYMLINK) != 0; }
|
||||
bool IsContainer() const
|
||||
{ return S_ISDIR(Mode()); }
|
||||
bool IsDirectory() const
|
||||
{ return is_directory(Mode()); }
|
||||
bool IsIndex() const
|
||||
{ return is_index(Mode()); }
|
||||
|
||||
bool HasUserAccessableStream() const { return IsFile(); }
|
||||
// currently only files can be accessed with
|
||||
// bfs_read()/bfs_write()
|
||||
bool NeedsFileCache() const
|
||||
{ return IsFile() || IsAttribute()
|
||||
|| IsLongSymLink(); }
|
||||
bool IsAttributeDirectory() const
|
||||
{ return (Mode() & S_EXTENDED_TYPES)
|
||||
== S_ATTR_DIR; }
|
||||
bool IsAttribute() const
|
||||
{ return (Mode() & S_EXTENDED_TYPES)
|
||||
== S_ATTR; }
|
||||
bool IsFile() const
|
||||
{ return (Mode() & (S_IFMT
|
||||
| S_EXTENDED_TYPES)) == S_FILE; }
|
||||
bool IsRegularNode() const
|
||||
{ return (Mode() & S_EXTENDED_TYPES) == 0; }
|
||||
// a regular node in the standard namespace
|
||||
// (i.e. not an index or attribute)
|
||||
bool IsSymLink() const { return S_ISLNK(Mode()); }
|
||||
bool IsLongSymLink() const
|
||||
{ return (Flags() & INODE_LONG_SYMLINK)
|
||||
!= 0; }
|
||||
|
||||
bool IsDeleted() const
|
||||
{ return (Flags() & INODE_DELETED) != 0; }
|
||||
bool HasUserAccessableStream() const
|
||||
{ return IsFile(); }
|
||||
// currently only files can be accessed with
|
||||
// bfs_read()/bfs_write()
|
||||
bool NeedsFileCache() const
|
||||
{ return IsFile() || IsAttribute()
|
||||
|| IsLongSymLink(); }
|
||||
|
||||
mode_t Mode() const { return fNode.Mode(); }
|
||||
uint32 Type() const { return fNode.Type(); }
|
||||
int32 Flags() const { return fNode.Flags(); }
|
||||
bool IsDeleted() const
|
||||
{ return (Flags() & INODE_DELETED) != 0; }
|
||||
|
||||
off_t Size() const { return fNode.data.Size(); }
|
||||
off_t AllocatedSize() const;
|
||||
off_t LastModified() const
|
||||
{ return fNode.LastModifiedTime(); }
|
||||
mode_t Mode() const { return fNode.Mode(); }
|
||||
uint32 Type() const { return fNode.Type(); }
|
||||
int32 Flags() const { return fNode.Flags(); }
|
||||
|
||||
const block_run& BlockRun() const
|
||||
{ return fNode.inode_num; }
|
||||
block_run& Parent() { return fNode.parent; }
|
||||
block_run& Attributes() { return fNode.attributes; }
|
||||
off_t Size() const { return fNode.data.Size(); }
|
||||
off_t AllocatedSize() const;
|
||||
off_t LastModified() const
|
||||
{ return fNode.LastModifiedTime(); }
|
||||
|
||||
Volume* GetVolume() const { return fVolume; }
|
||||
const block_run& BlockRun() const
|
||||
{ return fNode.inode_num; }
|
||||
block_run& Parent() { return fNode.parent; }
|
||||
block_run& Attributes() { return fNode.attributes; }
|
||||
|
||||
status_t InitCheck(bool checkNode = true);
|
||||
Volume* GetVolume() const { return fVolume; }
|
||||
|
||||
status_t CheckPermissions(int accessMode) const;
|
||||
status_t CheckPermissions(int accessMode) const;
|
||||
|
||||
// small_data access methods
|
||||
small_data* FindSmallData(const bfs_inode* node,
|
||||
const char* name) const;
|
||||
const char* Name(const bfs_inode* node) const;
|
||||
status_t GetName(char* buffer,
|
||||
size_t bufferSize = B_FILE_NAME_LENGTH) const;
|
||||
status_t SetName(Transaction& transaction, const char* name);
|
||||
small_data* FindSmallData(const bfs_inode* node,
|
||||
const char* name) const;
|
||||
const char* Name(const bfs_inode* node) const;
|
||||
status_t GetName(char* buffer, size_t bufferSize
|
||||
= B_FILE_NAME_LENGTH) const;
|
||||
status_t SetName(Transaction& transaction,
|
||||
const char* name);
|
||||
|
||||
// high-level attribute methods
|
||||
status_t ReadAttribute(const char* name, int32 type,
|
||||
off_t pos, uint8* buffer, size_t* _length);
|
||||
status_t WriteAttribute(Transaction& transaction,
|
||||
const char* name, int32 type, off_t pos,
|
||||
const uint8* buffer, size_t* _length,
|
||||
bool* _created);
|
||||
status_t RemoveAttribute(Transaction& transaction,
|
||||
const char* name);
|
||||
status_t ReadAttribute(const char* name, int32 type,
|
||||
off_t pos, uint8* buffer, size_t* _length);
|
||||
status_t WriteAttribute(Transaction& transaction,
|
||||
const char* name, int32 type, off_t pos,
|
||||
const uint8* buffer, size_t* _length,
|
||||
bool* _created);
|
||||
status_t RemoveAttribute(Transaction& transaction,
|
||||
const char* name);
|
||||
|
||||
// attribute methods
|
||||
status_t GetAttribute(const char* name, Inode** attribute);
|
||||
void ReleaseAttribute(Inode* attribute);
|
||||
status_t CreateAttribute(Transaction& transaction,
|
||||
const char* name, uint32 type,
|
||||
Inode** attribute);
|
||||
status_t GetAttribute(const char* name,
|
||||
Inode** _attribute);
|
||||
void ReleaseAttribute(Inode* attribute);
|
||||
status_t CreateAttribute(Transaction& transaction,
|
||||
const char* name, uint32 type,
|
||||
Inode** attribute);
|
||||
|
||||
// for directories only:
|
||||
BPlusTree* Tree() const { return fTree; }
|
||||
bool IsEmpty();
|
||||
status_t ContainerContentsChanged(Transaction& transaction);
|
||||
BPlusTree* Tree() const { return fTree; }
|
||||
bool IsEmpty();
|
||||
status_t ContainerContentsChanged(
|
||||
Transaction& transaction);
|
||||
|
||||
// manipulating the data stream
|
||||
status_t FindBlockRun(off_t pos, block_run& run,
|
||||
off_t& offset);
|
||||
status_t FindBlockRun(off_t pos, block_run& run,
|
||||
off_t& offset);
|
||||
|
||||
status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
|
||||
status_t WriteAt(Transaction& transaction, off_t pos,
|
||||
const uint8* buffer, size_t* length);
|
||||
status_t FillGapWithZeros(off_t oldSize, off_t newSize);
|
||||
status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
|
||||
status_t WriteAt(Transaction& transaction, off_t pos,
|
||||
const uint8* buffer, size_t* length);
|
||||
status_t FillGapWithZeros(off_t oldSize, off_t newSize);
|
||||
|
||||
status_t SetFileSize(Transaction& transaction, off_t size);
|
||||
status_t Append(Transaction& transaction, off_t bytes);
|
||||
status_t TrimPreallocation(Transaction& transaction);
|
||||
bool NeedsTrimming() const;
|
||||
status_t SetFileSize(Transaction& transaction,
|
||||
off_t size);
|
||||
status_t Append(Transaction& transaction, off_t bytes);
|
||||
status_t TrimPreallocation(Transaction& transaction);
|
||||
bool NeedsTrimming() const;
|
||||
|
||||
status_t Free(Transaction& transaction);
|
||||
status_t Sync();
|
||||
status_t Free(Transaction& transaction);
|
||||
status_t Sync();
|
||||
|
||||
bfs_inode& Node() { return fNode; }
|
||||
const bfs_inode& Node() const { return fNode; }
|
||||
bfs_inode& Node() { return fNode; }
|
||||
const bfs_inode& Node() const { return fNode; }
|
||||
|
||||
// create/remove inodes
|
||||
status_t Remove(Transaction& transaction, const char* name,
|
||||
ino_t* _id = NULL, bool isDirectory = false,
|
||||
bool force = false);
|
||||
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);
|
||||
status_t Remove(Transaction& transaction,
|
||||
const char* name, ino_t* _id = NULL,
|
||||
bool isDirectory = false,
|
||||
bool force = false);
|
||||
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);
|
||||
|
||||
// index maintaining helper
|
||||
void UpdateOldSize() { fOldSize = Size(); }
|
||||
void UpdateOldLastModified()
|
||||
{ fOldLastModified
|
||||
= Node().LastModifiedTime(); }
|
||||
off_t OldSize() { return fOldSize; }
|
||||
off_t OldLastModified() { return fOldLastModified; }
|
||||
void UpdateOldSize() { fOldSize = Size(); }
|
||||
void UpdateOldLastModified()
|
||||
{ fOldLastModified
|
||||
= Node().LastModifiedTime(); }
|
||||
off_t OldSize() { return fOldSize; }
|
||||
off_t OldLastModified() { return fOldLastModified; }
|
||||
|
||||
bool InNameIndex() const;
|
||||
bool InSizeIndex() const;
|
||||
bool InLastModifiedIndex() const;
|
||||
bool InNameIndex() const;
|
||||
bool InSizeIndex() const;
|
||||
bool InLastModifiedIndex() const;
|
||||
|
||||
// file cache
|
||||
void* FileCache() const { return fCache; }
|
||||
void SetFileCache(void* cache) { fCache = cache; }
|
||||
void* Map() const { return fMap; }
|
||||
void SetMap(void* map) { fMap = map; }
|
||||
void* FileCache() const { return fCache; }
|
||||
void SetFileCache(void* cache) { fCache = cache; }
|
||||
void* Map() const { return fMap; }
|
||||
void SetMap(void* map) { fMap = map; }
|
||||
|
||||
#if _KERNEL_MODE && KDEBUG
|
||||
void AssertReadLocked()
|
||||
{ ASSERT_READ_LOCKED_RW_LOCK(&fLock); }
|
||||
void AssertWriteLocked()
|
||||
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
|
||||
void AssertReadLocked()
|
||||
{ ASSERT_READ_LOCKED_RW_LOCK(&fLock); }
|
||||
void AssertWriteLocked()
|
||||
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
|
||||
#endif
|
||||
|
||||
#ifdef B_HAIKU_64_BIT
|
||||
Link* GetDoublyLinkedListLink()
|
||||
{ return &fListLink; }
|
||||
const Link* GetDoublyLinkedListLink() const
|
||||
{ return &fListLink; }
|
||||
#else
|
||||
Link* GetDoublyLinkedListLink()
|
||||
{ return (Link*)&fNode.pad[0]; }
|
||||
const Link* GetDoublyLinkedListLink() const
|
||||
{ return (Link*)&fNode.pad[0]; }
|
||||
#endif
|
||||
Link* GetDoublyLinkedListLink()
|
||||
{ return (Link*)TransactionListener
|
||||
::GetDoublyLinkedListLink(); }
|
||||
const Link* GetDoublyLinkedListLink() const
|
||||
{ return (Link*)TransactionListener
|
||||
::GetDoublyLinkedListLink(); }
|
||||
|
||||
protected:
|
||||
virtual void TransactionDone(bool success);
|
||||
virtual void RemovedFromTransaction();
|
||||
|
||||
private:
|
||||
Inode(const Inode& other);
|
||||
Inode& operator=(const Inode& other);
|
||||
// no implementation
|
||||
Inode(const Inode& other);
|
||||
Inode& operator=(const Inode& other);
|
||||
// no implementation
|
||||
|
||||
friend class AttributeIterator;
|
||||
friend class InodeAllocator;
|
||||
|
||||
// small_data access methods
|
||||
status_t _MakeSpaceForSmallData(Transaction& transaction,
|
||||
bfs_inode* node, const char* name,
|
||||
int32 length);
|
||||
status_t _RemoveSmallData(Transaction& transaction,
|
||||
NodeGetter& node, const char* name);
|
||||
status_t _AddSmallData(Transaction& transaction,
|
||||
NodeGetter& node, const char* name, uint32 type,
|
||||
off_t pos, const uint8* data, size_t length,
|
||||
bool force = false);
|
||||
status_t _GetNextSmallData(bfs_inode* node,
|
||||
small_data** _smallData) const;
|
||||
status_t _RemoveSmallData(bfs_inode* node, small_data* item,
|
||||
int32 index);
|
||||
status_t _RemoveAttribute(Transaction& transaction,
|
||||
const char* name, bool hasIndex, Index* index);
|
||||
status_t _MakeSpaceForSmallData(Transaction& transaction,
|
||||
bfs_inode* node, const char* name,
|
||||
int32 length);
|
||||
status_t _RemoveSmallData(Transaction& transaction,
|
||||
NodeGetter& node, const char* name);
|
||||
status_t _AddSmallData(Transaction& transaction,
|
||||
NodeGetter& node, const char* name,
|
||||
uint32 type, off_t pos, const uint8* data,
|
||||
size_t length, bool force = false);
|
||||
status_t _GetNextSmallData(bfs_inode* node,
|
||||
small_data** _smallData) const;
|
||||
status_t _RemoveSmallData(bfs_inode* node,
|
||||
small_data* item, int32 index);
|
||||
status_t _RemoveAttribute(Transaction& transaction,
|
||||
const char* name, bool hasIndex,
|
||||
Index* index);
|
||||
|
||||
void _AddIterator(AttributeIterator* iterator);
|
||||
void _RemoveIterator(AttributeIterator* iterator);
|
||||
void _AddIterator(AttributeIterator* iterator);
|
||||
void _RemoveIterator(AttributeIterator* iterator);
|
||||
|
||||
size_t _DoubleIndirectBlockLength() const;
|
||||
status_t _FreeStaticStreamArray(Transaction& transaction,
|
||||
int32 level, block_run run, off_t size,
|
||||
off_t offset, off_t& max);
|
||||
status_t _FreeStreamArray(Transaction& transaction,
|
||||
block_run* array, uint32 arrayLength,
|
||||
off_t size, off_t& offset, off_t& max);
|
||||
status_t _AllocateBlockArray(Transaction& transaction,
|
||||
block_run& run, size_t length,
|
||||
bool variableSize = false);
|
||||
status_t _GrowStream(Transaction& transaction, off_t size);
|
||||
status_t _ShrinkStream(Transaction& transaction, off_t size);
|
||||
size_t _DoubleIndirectBlockLength() const;
|
||||
status_t _FreeStaticStreamArray(Transaction& transaction,
|
||||
int32 level, block_run run, off_t size,
|
||||
off_t offset, off_t& max);
|
||||
status_t _FreeStreamArray(Transaction& transaction,
|
||||
block_run* array, uint32 arrayLength,
|
||||
off_t size, off_t& offset, off_t& max);
|
||||
status_t _AllocateBlockArray(Transaction& transaction,
|
||||
block_run& run, size_t length,
|
||||
bool variableSize = false);
|
||||
status_t _GrowStream(Transaction& transaction,
|
||||
off_t size);
|
||||
status_t _ShrinkStream(Transaction& transaction,
|
||||
off_t size);
|
||||
|
||||
private:
|
||||
rw_lock fLock;
|
||||
Volume* fVolume;
|
||||
ino_t fID;
|
||||
BPlusTree* fTree;
|
||||
Inode* fAttributes;
|
||||
void* fCache;
|
||||
void* fMap;
|
||||
bfs_inode fNode;
|
||||
rw_lock fLock;
|
||||
Volume* fVolume;
|
||||
ino_t fID;
|
||||
BPlusTree* fTree;
|
||||
Inode* fAttributes;
|
||||
void* fCache;
|
||||
void* fMap;
|
||||
bfs_inode fNode;
|
||||
|
||||
off_t fOldSize;
|
||||
off_t fOldLastModified;
|
||||
off_t fOldSize;
|
||||
off_t fOldLastModified;
|
||||
// we need those values to ensure we will remove
|
||||
// the correct keys from the indices
|
||||
|
||||
#ifdef B_HAIKU_64_BIT
|
||||
Link fListLink;
|
||||
#endif
|
||||
|
||||
mutable recursive_lock fSmallDataLock;
|
||||
SinglyLinkedList<AttributeIterator> fIterators;
|
||||
};
|
||||
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
//! Transaction and logging
|
||||
|
||||
|
||||
@ -1005,7 +1006,7 @@ Journal::Unlock(Transaction* owner, bool success)
|
||||
// closed.
|
||||
bool separateSubTransactions = fSeparateSubTransactions;
|
||||
fSeparateSubTransactions = true;
|
||||
owner->UnlockInodes(success);
|
||||
owner->NotifyListeners(success);
|
||||
fSeparateSubTransactions = separateSubTransactions;
|
||||
|
||||
fOwner = owner->Parent();
|
||||
@ -1018,7 +1019,7 @@ Journal::Unlock(Transaction* owner, bool success)
|
||||
&& recursive_lock_get_recursion(&fLock) == 1)
|
||||
fSeparateSubTransactions = false;
|
||||
} else
|
||||
owner->MoveInodesTo(fOwner);
|
||||
owner->MoveListenersTo(fOwner);
|
||||
|
||||
recursive_lock_unlock(&fLock);
|
||||
return B_OK;
|
||||
@ -1077,6 +1078,7 @@ Journal::_TransactionDone(bool success)
|
||||
|
||||
#ifdef BFS_DEBUGGER_COMMANDS
|
||||
|
||||
|
||||
void
|
||||
Journal::Dump()
|
||||
{
|
||||
@ -1121,9 +1123,23 @@ dump_journal(int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif // BFS_DEBUGGER_COMMANDS
|
||||
|
||||
|
||||
// #pragma mark - TransactionListener
|
||||
|
||||
|
||||
TransactionListener::TransactionListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TransactionListener::~TransactionListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Transaction
|
||||
|
||||
|
||||
@ -1143,74 +1159,33 @@ Transaction::Start(Volume* volume, off_t refBlock)
|
||||
}
|
||||
|
||||
|
||||
/*! Adds an inode to this transaction. This means that the inode will be write
|
||||
locked until the transaction ended.
|
||||
To ensure that the inode will stay valid until that point, an extra reference
|
||||
is acquired to it as long as this transaction stays active.
|
||||
*/
|
||||
void
|
||||
Transaction::AddInode(Inode* inode)
|
||||
Transaction::AddListener(TransactionListener* listener)
|
||||
{
|
||||
if (fJournal == NULL)
|
||||
panic("Transaction is not running!");
|
||||
|
||||
// These flags can only change while holding the transaction lock
|
||||
if ((inode->Flags() & INODE_IN_TRANSACTION) != 0)
|
||||
return;
|
||||
|
||||
// We share the same list link with the removed list, so we have to remove
|
||||
// the inode from that list here (and add it back when we no longer need it)
|
||||
if ((inode->Flags() & INODE_DELETED) != 0)
|
||||
GetVolume()->RemovedInodes().Remove(inode);
|
||||
|
||||
if (!GetVolume()->IsInitializing())
|
||||
acquire_vnode(GetVolume()->FSVolume(), inode->ID());
|
||||
|
||||
rw_lock_write_lock(&inode->Lock());
|
||||
fLockedInodes.Add(inode);
|
||||
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||
fListeners.Add(listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Transaction::RemoveInode(Inode* inode)
|
||||
Transaction::RemoveListener(TransactionListener* listener)
|
||||
{
|
||||
if (fJournal == NULL)
|
||||
panic("Transaction is not running!");
|
||||
|
||||
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||
fLockedInodes.Remove(inode);
|
||||
rw_lock_write_unlock(&inode->Lock());
|
||||
|
||||
// See AddInode() why we do this here
|
||||
if ((inode->Flags() & INODE_DELETED) != 0)
|
||||
GetVolume()->RemovedInodes().Add(inode);
|
||||
|
||||
if (!GetVolume()->IsInitializing())
|
||||
put_vnode(GetVolume()->FSVolume(), inode->ID());
|
||||
fListeners.Remove(listener);
|
||||
listener->RemovedFromTransaction();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Transaction::UnlockInodes(bool success)
|
||||
Transaction::NotifyListeners(bool success)
|
||||
{
|
||||
while (Inode* inode = fLockedInodes.RemoveHead()) {
|
||||
if (success) {
|
||||
inode->Node().flags
|
||||
&= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||
} else {
|
||||
// revert any changes made to the cached bfs_inode
|
||||
inode->UpdateNodeFromDisk();
|
||||
}
|
||||
|
||||
rw_lock_write_unlock(&inode->Lock());
|
||||
|
||||
// See AddInode() why we do this here
|
||||
if ((inode->Flags() & INODE_DELETED) != 0)
|
||||
GetVolume()->RemovedInodes().Add(inode);
|
||||
|
||||
if (!GetVolume()->IsInitializing())
|
||||
put_vnode(GetVolume()->FSVolume(), inode->ID());
|
||||
while (TransactionListener* listener = fListeners.RemoveHead()) {
|
||||
listener->TransactionDone(success);
|
||||
listener->RemovedFromTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1219,9 +1194,9 @@ Transaction::UnlockInodes(bool success)
|
||||
sure they will still be reverted in case the transaction is aborted.
|
||||
*/
|
||||
void
|
||||
Transaction::MoveInodesTo(Transaction* transaction)
|
||||
Transaction::MoveListenersTo(Transaction* transaction)
|
||||
{
|
||||
while (Inode* inode = fLockedInodes.RemoveHead()) {
|
||||
transaction->fLockedInodes.Add(inode);
|
||||
while (TransactionListener* listener = fListeners.RemoveHead()) {
|
||||
transaction->fListeners.Add(listener);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JOURNAL_H
|
||||
@ -86,6 +86,19 @@ Journal::FreeLogBlocks() const
|
||||
}
|
||||
|
||||
|
||||
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(Volume* volume, off_t refBlock)
|
||||
@ -176,11 +189,11 @@ public:
|
||||
int32 ID() const
|
||||
{ return fJournal->TransactionID(); }
|
||||
|
||||
void AddInode(Inode* inode);
|
||||
void RemoveInode(Inode* inode);
|
||||
void AddListener(TransactionListener* listener);
|
||||
void RemoveListener(TransactionListener* listener);
|
||||
|
||||
void UnlockInodes(bool success);
|
||||
void MoveInodesTo(Transaction* transaction);
|
||||
void NotifyListeners(bool success);
|
||||
void MoveListenersTo(Transaction* transaction);
|
||||
|
||||
void SetParent(Transaction* parent)
|
||||
{ fParent = parent; }
|
||||
@ -192,13 +205,15 @@ private:
|
||||
Transaction& operator=(const Transaction& other);
|
||||
// no implementation
|
||||
|
||||
Journal* fJournal;
|
||||
InodeList fLockedInodes;
|
||||
Transaction* fParent;
|
||||
Journal* fJournal;
|
||||
TransactionListeners fListeners;
|
||||
Transaction* fParent;
|
||||
};
|
||||
|
||||
|
||||
#ifdef BFS_DEBUGGER_COMMANDS
|
||||
int dump_journal(int argc, char** argv);
|
||||
#endif
|
||||
|
||||
|
||||
#endif // JOURNAL_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VOLUME_H
|
||||
@ -11,10 +11,12 @@
|
||||
#include "bfs.h"
|
||||
#include "BlockAllocator.h"
|
||||
|
||||
|
||||
class Journal;
|
||||
class Inode;
|
||||
class Query;
|
||||
|
||||
|
||||
enum volume_flags {
|
||||
VOLUME_READ_ONLY = 0x0001
|
||||
};
|
||||
@ -25,6 +27,7 @@ enum volume_initialize_flags {
|
||||
|
||||
typedef DoublyLinkedList<Inode> InodeList;
|
||||
|
||||
|
||||
class Volume {
|
||||
public:
|
||||
Volume(fs_volume* volume);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Parts of this code is based on work previously done by Marcus Overhagen.
|
||||
*
|
||||
* This file may be used under the terms of the MIT License.
|
||||
@ -7,6 +7,7 @@
|
||||
#ifndef BFS_H
|
||||
#define BFS_H
|
||||
|
||||
|
||||
//! BFS definitions and helper functions
|
||||
|
||||
|
||||
@ -144,20 +145,25 @@ struct data_stream {
|
||||
struct bfs_inode;
|
||||
|
||||
struct small_data {
|
||||
uint32 type;
|
||||
uint16 name_size;
|
||||
uint16 data_size;
|
||||
char name[0]; // name_size long, followed by data
|
||||
uint32 type;
|
||||
uint16 name_size;
|
||||
uint16 data_size;
|
||||
char name[0]; // name_size long, followed by data
|
||||
|
||||
uint32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); }
|
||||
uint16 NameSize() const { return BFS_ENDIAN_TO_HOST_INT16(name_size); }
|
||||
uint16 DataSize() const { return BFS_ENDIAN_TO_HOST_INT16(data_size); }
|
||||
uint32 Type() const
|
||||
{ return BFS_ENDIAN_TO_HOST_INT32(type); }
|
||||
uint16 NameSize() const
|
||||
{ return BFS_ENDIAN_TO_HOST_INT16(
|
||||
name_size); }
|
||||
uint16 DataSize() const
|
||||
{ return BFS_ENDIAN_TO_HOST_INT16(
|
||||
data_size); }
|
||||
|
||||
inline char *Name() const;
|
||||
inline uint8 *Data() const;
|
||||
inline uint32 Size() const;
|
||||
inline small_data *Next() const;
|
||||
inline bool IsLast(const bfs_inode *inode) const;
|
||||
inline char* Name() const;
|
||||
inline uint8* Data() const;
|
||||
inline uint32 Size() const;
|
||||
inline small_data* Next() const;
|
||||
inline bool IsLast(const bfs_inode* inode) const;
|
||||
} _PACKED;
|
||||
|
||||
// the file name is part of the small_data structure
|
||||
@ -222,7 +228,7 @@ struct bfs_inode {
|
||||
{ return BFS_ENDIAN_TO_HOST_INT64(status_change_time); }
|
||||
small_data* SmallDataStart() { return small_data_start; }
|
||||
|
||||
status_t InitCheck(Volume *volume);
|
||||
status_t InitCheck(Volume* volume) const;
|
||||
// defined in Inode.cpp
|
||||
|
||||
static int64 ToInode(bigtime_t time)
|
||||
|
Loading…
x
Reference in New Issue
Block a user