* 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
src/add-ons/kernel/file_systems/bfs
@ -3,6 +3,7 @@
|
|||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//! block bitmap handling and allocation policies
|
//! block bitmap handling and allocation policies
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//! inode access functions
|
|
||||||
|
//! Inode access functions
|
||||||
|
|
||||||
|
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
@ -175,7 +176,7 @@ InodeAllocator::~InodeAllocator()
|
|||||||
fInode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE);
|
fInode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE);
|
||||||
// this unblocks any pending bfs_read_vnode() calls
|
// this unblocks any pending bfs_read_vnode() calls
|
||||||
fInode->Free(*fTransaction);
|
fInode->Free(*fTransaction);
|
||||||
fTransaction->RemoveInode(fInode);
|
fTransaction->RemoveListener(fInode);
|
||||||
|
|
||||||
remove_vnode(volume->FSVolume(), fInode->ID());
|
remove_vnode(volume->FSVolume(), fInode->ID());
|
||||||
} else
|
} else
|
||||||
@ -291,7 +292,7 @@ InodeAllocator::_TransactionListener(int32 id, int32 event, void* _inode)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
bfs_inode::InitCheck(Volume* volume)
|
bfs_inode::InitCheck(Volume* volume) const
|
||||||
{
|
{
|
||||||
if (Magic1() != INODE_MAGIC1
|
if (Magic1() != INODE_MAGIC1
|
||||||
|| !(Flags() & INODE_IN_USE)
|
|| !(Flags() & INODE_IN_USE)
|
||||||
@ -403,7 +404,7 @@ Inode::~Inode()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Inode::InitCheck(bool checkNode)
|
Inode::InitCheck(bool checkNode) const
|
||||||
{
|
{
|
||||||
// test inode magic and flags
|
// test inode magic and flags
|
||||||
if (checkNode) {
|
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
|
status_t
|
||||||
Inode::WriteBack(Transaction& transaction)
|
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
|
// #pragma mark - creation/deletion
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,241 +23,245 @@ class NodeGetter;
|
|||||||
class Transaction;
|
class Transaction;
|
||||||
|
|
||||||
|
|
||||||
class Inode {
|
class Inode : public TransactionListener {
|
||||||
typedef DoublyLinkedListLink<Inode> Link;
|
typedef DoublyLinkedListLink<Inode> Link;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Inode(Volume* volume, ino_t id);
|
Inode(Volume* volume, ino_t id);
|
||||||
Inode(Volume* volume, Transaction& transaction,
|
Inode(Volume* volume, Transaction& transaction,
|
||||||
ino_t id, mode_t mode, block_run& run);
|
ino_t id, mode_t mode, block_run& run);
|
||||||
~Inode();
|
~Inode();
|
||||||
|
|
||||||
ino_t ID() const { return fID; }
|
status_t InitCheck(bool checkNode = true) const;
|
||||||
off_t BlockNumber() const
|
|
||||||
{ return fVolume->VnodeToBlock(fID); }
|
|
||||||
|
|
||||||
rw_lock& Lock() { return fLock; }
|
ino_t ID() const { return fID; }
|
||||||
ReadLocker ReadLock() { return ReadLocker(fLock); }
|
off_t BlockNumber() const
|
||||||
void WriteLockInTransaction(Transaction& transaction)
|
{ return fVolume->VnodeToBlock(fID); }
|
||||||
{ transaction.AddInode(this); }
|
|
||||||
|
|
||||||
recursive_lock& SmallDataLock() { return fSmallDataLock; }
|
rw_lock& Lock() { return fLock; }
|
||||||
|
ReadLocker ReadLock() { return ReadLocker(fLock); }
|
||||||
|
void WriteLockInTransaction(Transaction& transaction);
|
||||||
|
|
||||||
status_t WriteBack(Transaction& transaction);
|
recursive_lock& SmallDataLock() { return fSmallDataLock; }
|
||||||
void UpdateNodeFromDisk();
|
|
||||||
|
|
||||||
bool IsContainer() const
|
status_t WriteBack(Transaction& transaction);
|
||||||
{ return S_ISDIR(Mode()); }
|
void UpdateNodeFromDisk();
|
||||||
bool IsDirectory() const
|
|
||||||
{ return is_directory(Mode()); }
|
|
||||||
bool IsIndex() const
|
|
||||||
{ return is_index(Mode()); }
|
|
||||||
|
|
||||||
bool IsAttributeDirectory() const
|
bool IsContainer() const
|
||||||
{ return (Mode() & S_EXTENDED_TYPES)
|
{ return S_ISDIR(Mode()); }
|
||||||
== S_ATTR_DIR; }
|
bool IsDirectory() const
|
||||||
bool IsAttribute() const
|
{ return is_directory(Mode()); }
|
||||||
{ return (Mode() & S_EXTENDED_TYPES)
|
bool IsIndex() const
|
||||||
== S_ATTR; }
|
{ return is_index(Mode()); }
|
||||||
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 HasUserAccessableStream() const { return IsFile(); }
|
bool IsAttributeDirectory() const
|
||||||
// currently only files can be accessed with
|
{ return (Mode() & S_EXTENDED_TYPES)
|
||||||
// bfs_read()/bfs_write()
|
== S_ATTR_DIR; }
|
||||||
bool NeedsFileCache() const
|
bool IsAttribute() const
|
||||||
{ return IsFile() || IsAttribute()
|
{ return (Mode() & S_EXTENDED_TYPES)
|
||||||
|| IsLongSymLink(); }
|
== 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
|
bool HasUserAccessableStream() const
|
||||||
{ return (Flags() & INODE_DELETED) != 0; }
|
{ 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(); }
|
bool IsDeleted() const
|
||||||
uint32 Type() const { return fNode.Type(); }
|
{ return (Flags() & INODE_DELETED) != 0; }
|
||||||
int32 Flags() const { return fNode.Flags(); }
|
|
||||||
|
|
||||||
off_t Size() const { return fNode.data.Size(); }
|
mode_t Mode() const { return fNode.Mode(); }
|
||||||
off_t AllocatedSize() const;
|
uint32 Type() const { return fNode.Type(); }
|
||||||
off_t LastModified() const
|
int32 Flags() const { return fNode.Flags(); }
|
||||||
{ return fNode.LastModifiedTime(); }
|
|
||||||
|
|
||||||
const block_run& BlockRun() const
|
off_t Size() const { return fNode.data.Size(); }
|
||||||
{ return fNode.inode_num; }
|
off_t AllocatedSize() const;
|
||||||
block_run& Parent() { return fNode.parent; }
|
off_t LastModified() const
|
||||||
block_run& Attributes() { return fNode.attributes; }
|
{ 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 access methods
|
||||||
small_data* FindSmallData(const bfs_inode* node,
|
small_data* FindSmallData(const bfs_inode* node,
|
||||||
const char* name) const;
|
const char* name) const;
|
||||||
const char* Name(const bfs_inode* node) const;
|
const char* Name(const bfs_inode* node) const;
|
||||||
status_t GetName(char* buffer,
|
status_t GetName(char* buffer, size_t bufferSize
|
||||||
size_t bufferSize = B_FILE_NAME_LENGTH) const;
|
= B_FILE_NAME_LENGTH) const;
|
||||||
status_t SetName(Transaction& transaction, const char* name);
|
status_t SetName(Transaction& transaction,
|
||||||
|
const char* name);
|
||||||
|
|
||||||
// high-level attribute methods
|
// high-level attribute methods
|
||||||
status_t ReadAttribute(const char* name, int32 type,
|
status_t ReadAttribute(const char* name, int32 type,
|
||||||
off_t pos, uint8* buffer, size_t* _length);
|
off_t pos, uint8* buffer, size_t* _length);
|
||||||
status_t WriteAttribute(Transaction& transaction,
|
status_t WriteAttribute(Transaction& transaction,
|
||||||
const char* name, int32 type, off_t pos,
|
const char* name, int32 type, off_t pos,
|
||||||
const uint8* buffer, size_t* _length,
|
const uint8* buffer, size_t* _length,
|
||||||
bool* _created);
|
bool* _created);
|
||||||
status_t RemoveAttribute(Transaction& transaction,
|
status_t RemoveAttribute(Transaction& transaction,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
|
||||||
// attribute methods
|
// attribute methods
|
||||||
status_t GetAttribute(const char* name, Inode** attribute);
|
status_t GetAttribute(const char* name,
|
||||||
void ReleaseAttribute(Inode* attribute);
|
Inode** _attribute);
|
||||||
status_t CreateAttribute(Transaction& transaction,
|
void ReleaseAttribute(Inode* attribute);
|
||||||
const char* name, uint32 type,
|
status_t CreateAttribute(Transaction& transaction,
|
||||||
Inode** attribute);
|
const char* name, uint32 type,
|
||||||
|
Inode** attribute);
|
||||||
|
|
||||||
// for directories only:
|
// for directories only:
|
||||||
BPlusTree* Tree() const { return fTree; }
|
BPlusTree* Tree() const { return fTree; }
|
||||||
bool IsEmpty();
|
bool IsEmpty();
|
||||||
status_t ContainerContentsChanged(Transaction& transaction);
|
status_t ContainerContentsChanged(
|
||||||
|
Transaction& transaction);
|
||||||
|
|
||||||
// manipulating the data stream
|
// manipulating the data stream
|
||||||
status_t FindBlockRun(off_t pos, block_run& run,
|
status_t FindBlockRun(off_t pos, block_run& run,
|
||||||
off_t& offset);
|
off_t& offset);
|
||||||
|
|
||||||
status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
|
status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
|
||||||
status_t WriteAt(Transaction& transaction, off_t pos,
|
status_t WriteAt(Transaction& transaction, off_t pos,
|
||||||
const uint8* buffer, size_t* length);
|
const uint8* buffer, size_t* length);
|
||||||
status_t FillGapWithZeros(off_t oldSize, off_t newSize);
|
status_t FillGapWithZeros(off_t oldSize, off_t newSize);
|
||||||
|
|
||||||
status_t SetFileSize(Transaction& transaction, off_t size);
|
status_t SetFileSize(Transaction& transaction,
|
||||||
status_t Append(Transaction& transaction, off_t bytes);
|
off_t size);
|
||||||
status_t TrimPreallocation(Transaction& transaction);
|
status_t Append(Transaction& transaction, off_t bytes);
|
||||||
bool NeedsTrimming() const;
|
status_t TrimPreallocation(Transaction& transaction);
|
||||||
|
bool NeedsTrimming() const;
|
||||||
|
|
||||||
status_t Free(Transaction& transaction);
|
status_t Free(Transaction& transaction);
|
||||||
status_t Sync();
|
status_t Sync();
|
||||||
|
|
||||||
bfs_inode& Node() { return fNode; }
|
bfs_inode& Node() { return fNode; }
|
||||||
const bfs_inode& Node() const { return fNode; }
|
const bfs_inode& Node() const { return fNode; }
|
||||||
|
|
||||||
// create/remove inodes
|
// create/remove inodes
|
||||||
status_t Remove(Transaction& transaction, const char* name,
|
status_t Remove(Transaction& transaction,
|
||||||
ino_t* _id = NULL, bool isDirectory = false,
|
const char* name, ino_t* _id = NULL,
|
||||||
bool force = false);
|
bool isDirectory = false,
|
||||||
static status_t Create(Transaction& transaction, Inode* parent,
|
bool force = false);
|
||||||
const char* name, int32 mode, int openMode,
|
static status_t Create(Transaction& transaction, Inode* parent,
|
||||||
uint32 type, bool* _created = NULL,
|
const char* name, int32 mode, int openMode,
|
||||||
ino_t* _id = NULL, Inode** _inode = NULL,
|
uint32 type, bool* _created = NULL,
|
||||||
fs_vnode_ops* vnodeOps = NULL,
|
ino_t* _id = NULL, Inode** _inode = NULL,
|
||||||
uint32 publishFlags = 0);
|
fs_vnode_ops* vnodeOps = NULL,
|
||||||
|
uint32 publishFlags = 0);
|
||||||
|
|
||||||
// index maintaining helper
|
// index maintaining helper
|
||||||
void UpdateOldSize() { fOldSize = Size(); }
|
void UpdateOldSize() { fOldSize = Size(); }
|
||||||
void UpdateOldLastModified()
|
void UpdateOldLastModified()
|
||||||
{ fOldLastModified
|
{ fOldLastModified
|
||||||
= Node().LastModifiedTime(); }
|
= Node().LastModifiedTime(); }
|
||||||
off_t OldSize() { return fOldSize; }
|
off_t OldSize() { return fOldSize; }
|
||||||
off_t OldLastModified() { return fOldLastModified; }
|
off_t OldLastModified() { return fOldLastModified; }
|
||||||
|
|
||||||
bool InNameIndex() const;
|
bool InNameIndex() const;
|
||||||
bool InSizeIndex() const;
|
bool InSizeIndex() const;
|
||||||
bool InLastModifiedIndex() const;
|
bool InLastModifiedIndex() const;
|
||||||
|
|
||||||
// file cache
|
// file cache
|
||||||
void* FileCache() const { return fCache; }
|
void* FileCache() const { return fCache; }
|
||||||
void SetFileCache(void* cache) { fCache = cache; }
|
void SetFileCache(void* cache) { fCache = cache; }
|
||||||
void* Map() const { return fMap; }
|
void* Map() const { return fMap; }
|
||||||
void SetMap(void* map) { fMap = map; }
|
void SetMap(void* map) { fMap = map; }
|
||||||
|
|
||||||
#if _KERNEL_MODE && KDEBUG
|
#if _KERNEL_MODE && KDEBUG
|
||||||
void AssertReadLocked()
|
void AssertReadLocked()
|
||||||
{ ASSERT_READ_LOCKED_RW_LOCK(&fLock); }
|
{ ASSERT_READ_LOCKED_RW_LOCK(&fLock); }
|
||||||
void AssertWriteLocked()
|
void AssertWriteLocked()
|
||||||
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
|
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef B_HAIKU_64_BIT
|
Link* GetDoublyLinkedListLink()
|
||||||
Link* GetDoublyLinkedListLink()
|
{ return (Link*)TransactionListener
|
||||||
{ return &fListLink; }
|
::GetDoublyLinkedListLink(); }
|
||||||
const Link* GetDoublyLinkedListLink() const
|
const Link* GetDoublyLinkedListLink() const
|
||||||
{ return &fListLink; }
|
{ return (Link*)TransactionListener
|
||||||
#else
|
::GetDoublyLinkedListLink(); }
|
||||||
Link* GetDoublyLinkedListLink()
|
|
||||||
{ return (Link*)&fNode.pad[0]; }
|
protected:
|
||||||
const Link* GetDoublyLinkedListLink() const
|
virtual void TransactionDone(bool success);
|
||||||
{ return (Link*)&fNode.pad[0]; }
|
virtual void RemovedFromTransaction();
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Inode(const Inode& other);
|
Inode(const Inode& other);
|
||||||
Inode& operator=(const Inode& other);
|
Inode& operator=(const Inode& other);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
friend class AttributeIterator;
|
friend class AttributeIterator;
|
||||||
friend class InodeAllocator;
|
friend class InodeAllocator;
|
||||||
|
|
||||||
// small_data access methods
|
// small_data access methods
|
||||||
status_t _MakeSpaceForSmallData(Transaction& transaction,
|
status_t _MakeSpaceForSmallData(Transaction& transaction,
|
||||||
bfs_inode* node, const char* name,
|
bfs_inode* node, const char* name,
|
||||||
int32 length);
|
int32 length);
|
||||||
status_t _RemoveSmallData(Transaction& transaction,
|
status_t _RemoveSmallData(Transaction& transaction,
|
||||||
NodeGetter& node, const char* name);
|
NodeGetter& node, const char* name);
|
||||||
status_t _AddSmallData(Transaction& transaction,
|
status_t _AddSmallData(Transaction& transaction,
|
||||||
NodeGetter& node, const char* name, uint32 type,
|
NodeGetter& node, const char* name,
|
||||||
off_t pos, const uint8* data, size_t length,
|
uint32 type, off_t pos, const uint8* data,
|
||||||
bool force = false);
|
size_t length, bool force = false);
|
||||||
status_t _GetNextSmallData(bfs_inode* node,
|
status_t _GetNextSmallData(bfs_inode* node,
|
||||||
small_data** _smallData) const;
|
small_data** _smallData) const;
|
||||||
status_t _RemoveSmallData(bfs_inode* node, small_data* item,
|
status_t _RemoveSmallData(bfs_inode* node,
|
||||||
int32 index);
|
small_data* item, int32 index);
|
||||||
status_t _RemoveAttribute(Transaction& transaction,
|
status_t _RemoveAttribute(Transaction& transaction,
|
||||||
const char* name, bool hasIndex, Index* index);
|
const char* name, bool hasIndex,
|
||||||
|
Index* index);
|
||||||
|
|
||||||
void _AddIterator(AttributeIterator* iterator);
|
void _AddIterator(AttributeIterator* iterator);
|
||||||
void _RemoveIterator(AttributeIterator* iterator);
|
void _RemoveIterator(AttributeIterator* iterator);
|
||||||
|
|
||||||
size_t _DoubleIndirectBlockLength() const;
|
size_t _DoubleIndirectBlockLength() const;
|
||||||
status_t _FreeStaticStreamArray(Transaction& transaction,
|
status_t _FreeStaticStreamArray(Transaction& transaction,
|
||||||
int32 level, block_run run, off_t size,
|
int32 level, block_run run, off_t size,
|
||||||
off_t offset, off_t& max);
|
off_t offset, off_t& max);
|
||||||
status_t _FreeStreamArray(Transaction& transaction,
|
status_t _FreeStreamArray(Transaction& transaction,
|
||||||
block_run* array, uint32 arrayLength,
|
block_run* array, uint32 arrayLength,
|
||||||
off_t size, off_t& offset, off_t& max);
|
off_t size, off_t& offset, off_t& max);
|
||||||
status_t _AllocateBlockArray(Transaction& transaction,
|
status_t _AllocateBlockArray(Transaction& transaction,
|
||||||
block_run& run, size_t length,
|
block_run& run, size_t length,
|
||||||
bool variableSize = false);
|
bool variableSize = false);
|
||||||
status_t _GrowStream(Transaction& transaction, off_t size);
|
status_t _GrowStream(Transaction& transaction,
|
||||||
status_t _ShrinkStream(Transaction& transaction, off_t size);
|
off_t size);
|
||||||
|
status_t _ShrinkStream(Transaction& transaction,
|
||||||
|
off_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rw_lock fLock;
|
rw_lock fLock;
|
||||||
Volume* fVolume;
|
Volume* fVolume;
|
||||||
ino_t fID;
|
ino_t fID;
|
||||||
BPlusTree* fTree;
|
BPlusTree* fTree;
|
||||||
Inode* fAttributes;
|
Inode* fAttributes;
|
||||||
void* fCache;
|
void* fCache;
|
||||||
void* fMap;
|
void* fMap;
|
||||||
bfs_inode fNode;
|
bfs_inode fNode;
|
||||||
|
|
||||||
off_t fOldSize;
|
off_t fOldSize;
|
||||||
off_t fOldLastModified;
|
off_t fOldLastModified;
|
||||||
// we need those values to ensure we will remove
|
// we need those values to ensure we will remove
|
||||||
// the correct keys from the indices
|
// the correct keys from the indices
|
||||||
|
|
||||||
#ifdef B_HAIKU_64_BIT
|
|
||||||
Link fListLink;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mutable recursive_lock fSmallDataLock;
|
mutable recursive_lock fSmallDataLock;
|
||||||
SinglyLinkedList<AttributeIterator> fIterators;
|
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.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//! Transaction and logging
|
//! Transaction and logging
|
||||||
|
|
||||||
|
|
||||||
@ -1005,7 +1006,7 @@ Journal::Unlock(Transaction* owner, bool success)
|
|||||||
// closed.
|
// closed.
|
||||||
bool separateSubTransactions = fSeparateSubTransactions;
|
bool separateSubTransactions = fSeparateSubTransactions;
|
||||||
fSeparateSubTransactions = true;
|
fSeparateSubTransactions = true;
|
||||||
owner->UnlockInodes(success);
|
owner->NotifyListeners(success);
|
||||||
fSeparateSubTransactions = separateSubTransactions;
|
fSeparateSubTransactions = separateSubTransactions;
|
||||||
|
|
||||||
fOwner = owner->Parent();
|
fOwner = owner->Parent();
|
||||||
@ -1018,7 +1019,7 @@ Journal::Unlock(Transaction* owner, bool success)
|
|||||||
&& recursive_lock_get_recursion(&fLock) == 1)
|
&& recursive_lock_get_recursion(&fLock) == 1)
|
||||||
fSeparateSubTransactions = false;
|
fSeparateSubTransactions = false;
|
||||||
} else
|
} else
|
||||||
owner->MoveInodesTo(fOwner);
|
owner->MoveListenersTo(fOwner);
|
||||||
|
|
||||||
recursive_lock_unlock(&fLock);
|
recursive_lock_unlock(&fLock);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@ -1077,6 +1078,7 @@ Journal::_TransactionDone(bool success)
|
|||||||
|
|
||||||
#ifdef BFS_DEBUGGER_COMMANDS
|
#ifdef BFS_DEBUGGER_COMMANDS
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Journal::Dump()
|
Journal::Dump()
|
||||||
{
|
{
|
||||||
@ -1121,9 +1123,23 @@ dump_journal(int argc, char** argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // BFS_DEBUGGER_COMMANDS
|
#endif // BFS_DEBUGGER_COMMANDS
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TransactionListener
|
||||||
|
|
||||||
|
|
||||||
|
TransactionListener::TransactionListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TransactionListener::~TransactionListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Transaction
|
// #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
|
void
|
||||||
Transaction::AddInode(Inode* inode)
|
Transaction::AddListener(TransactionListener* listener)
|
||||||
{
|
{
|
||||||
if (fJournal == NULL)
|
if (fJournal == NULL)
|
||||||
panic("Transaction is not running!");
|
panic("Transaction is not running!");
|
||||||
|
|
||||||
// These flags can only change while holding the transaction lock
|
fListeners.Add(listener);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Transaction::RemoveInode(Inode* inode)
|
Transaction::RemoveListener(TransactionListener* listener)
|
||||||
{
|
{
|
||||||
if (fJournal == NULL)
|
if (fJournal == NULL)
|
||||||
panic("Transaction is not running!");
|
panic("Transaction is not running!");
|
||||||
|
|
||||||
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
fListeners.Remove(listener);
|
||||||
fLockedInodes.Remove(inode);
|
listener->RemovedFromTransaction();
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Transaction::UnlockInodes(bool success)
|
Transaction::NotifyListeners(bool success)
|
||||||
{
|
{
|
||||||
while (Inode* inode = fLockedInodes.RemoveHead()) {
|
while (TransactionListener* listener = fListeners.RemoveHead()) {
|
||||||
if (success) {
|
listener->TransactionDone(success);
|
||||||
inode->Node().flags
|
listener->RemovedFromTransaction();
|
||||||
&= ~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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,9 +1194,9 @@ Transaction::UnlockInodes(bool success)
|
|||||||
sure they will still be reverted in case the transaction is aborted.
|
sure they will still be reverted in case the transaction is aborted.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Transaction::MoveInodesTo(Transaction* transaction)
|
Transaction::MoveListenersTo(Transaction* transaction)
|
||||||
{
|
{
|
||||||
while (Inode* inode = fLockedInodes.RemoveHead()) {
|
while (TransactionListener* listener = fListeners.RemoveHead()) {
|
||||||
transaction->fLockedInodes.Add(inode);
|
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.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef JOURNAL_H
|
#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 {
|
class Transaction {
|
||||||
public:
|
public:
|
||||||
Transaction(Volume* volume, off_t refBlock)
|
Transaction(Volume* volume, off_t refBlock)
|
||||||
@ -176,11 +189,11 @@ public:
|
|||||||
int32 ID() const
|
int32 ID() const
|
||||||
{ return fJournal->TransactionID(); }
|
{ return fJournal->TransactionID(); }
|
||||||
|
|
||||||
void AddInode(Inode* inode);
|
void AddListener(TransactionListener* listener);
|
||||||
void RemoveInode(Inode* inode);
|
void RemoveListener(TransactionListener* listener);
|
||||||
|
|
||||||
void UnlockInodes(bool success);
|
void NotifyListeners(bool success);
|
||||||
void MoveInodesTo(Transaction* transaction);
|
void MoveListenersTo(Transaction* transaction);
|
||||||
|
|
||||||
void SetParent(Transaction* parent)
|
void SetParent(Transaction* parent)
|
||||||
{ fParent = parent; }
|
{ fParent = parent; }
|
||||||
@ -192,13 +205,15 @@ private:
|
|||||||
Transaction& operator=(const Transaction& other);
|
Transaction& operator=(const Transaction& other);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
Journal* fJournal;
|
Journal* fJournal;
|
||||||
InodeList fLockedInodes;
|
TransactionListeners fListeners;
|
||||||
Transaction* fParent;
|
Transaction* fParent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef BFS_DEBUGGER_COMMANDS
|
#ifdef BFS_DEBUGGER_COMMANDS
|
||||||
int dump_journal(int argc, char** argv);
|
int dump_journal(int argc, char** argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // JOURNAL_H
|
#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.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef VOLUME_H
|
#ifndef VOLUME_H
|
||||||
@ -11,10 +11,12 @@
|
|||||||
#include "bfs.h"
|
#include "bfs.h"
|
||||||
#include "BlockAllocator.h"
|
#include "BlockAllocator.h"
|
||||||
|
|
||||||
|
|
||||||
class Journal;
|
class Journal;
|
||||||
class Inode;
|
class Inode;
|
||||||
class Query;
|
class Query;
|
||||||
|
|
||||||
|
|
||||||
enum volume_flags {
|
enum volume_flags {
|
||||||
VOLUME_READ_ONLY = 0x0001
|
VOLUME_READ_ONLY = 0x0001
|
||||||
};
|
};
|
||||||
@ -25,6 +27,7 @@ enum volume_initialize_flags {
|
|||||||
|
|
||||||
typedef DoublyLinkedList<Inode> InodeList;
|
typedef DoublyLinkedList<Inode> InodeList;
|
||||||
|
|
||||||
|
|
||||||
class Volume {
|
class Volume {
|
||||||
public:
|
public:
|
||||||
Volume(fs_volume* volume);
|
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.
|
* 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.
|
* This file may be used under the terms of the MIT License.
|
||||||
@ -7,6 +7,7 @@
|
|||||||
#ifndef BFS_H
|
#ifndef BFS_H
|
||||||
#define BFS_H
|
#define BFS_H
|
||||||
|
|
||||||
|
|
||||||
//! BFS definitions and helper functions
|
//! BFS definitions and helper functions
|
||||||
|
|
||||||
|
|
||||||
@ -144,20 +145,25 @@ struct data_stream {
|
|||||||
struct bfs_inode;
|
struct bfs_inode;
|
||||||
|
|
||||||
struct small_data {
|
struct small_data {
|
||||||
uint32 type;
|
uint32 type;
|
||||||
uint16 name_size;
|
uint16 name_size;
|
||||||
uint16 data_size;
|
uint16 data_size;
|
||||||
char name[0]; // name_size long, followed by data
|
char name[0]; // name_size long, followed by data
|
||||||
|
|
||||||
uint32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); }
|
uint32 Type() const
|
||||||
uint16 NameSize() const { return BFS_ENDIAN_TO_HOST_INT16(name_size); }
|
{ return BFS_ENDIAN_TO_HOST_INT32(type); }
|
||||||
uint16 DataSize() const { return BFS_ENDIAN_TO_HOST_INT16(data_size); }
|
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 char* Name() const;
|
||||||
inline uint8 *Data() const;
|
inline uint8* Data() const;
|
||||||
inline uint32 Size() const;
|
inline uint32 Size() const;
|
||||||
inline small_data *Next() const;
|
inline small_data* Next() const;
|
||||||
inline bool IsLast(const bfs_inode *inode) const;
|
inline bool IsLast(const bfs_inode* inode) const;
|
||||||
} _PACKED;
|
} _PACKED;
|
||||||
|
|
||||||
// the file name is part of the small_data structure
|
// 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); }
|
{ return BFS_ENDIAN_TO_HOST_INT64(status_change_time); }
|
||||||
small_data* SmallDataStart() { return small_data_start; }
|
small_data* SmallDataStart() { return small_data_start; }
|
||||||
|
|
||||||
status_t InitCheck(Volume *volume);
|
status_t InitCheck(Volume* volume) const;
|
||||||
// defined in Inode.cpp
|
// defined in Inode.cpp
|
||||||
|
|
||||||
static int64 ToInode(bigtime_t time)
|
static int64 ToInode(bigtime_t time)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user