* Removed the home-brewn locking classes in BFS besides the read/write lock
(for now). * Inode::fSmallDataLock is now a recursive_lock, Journal::fLock is now a recursive_lock, too, Journal::fEntriesLock is now a mutex, as is BPlusTree::fIteratorLock. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26298 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
SubDir HAIKU_TOP src add-ons disk_systems bfs ;
|
||||
|
||||
UsePrivateHeaders kernel ;
|
||||
UsePrivateHeaders shared ;
|
||||
UsePrivateHeaders storage ;
|
||||
UsePrivateKernelHeaders ;
|
||||
UsePrivateHeaders shared storage ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems bfs ] ;
|
||||
|
||||
|
||||
@@ -79,13 +79,13 @@ Attribute::Get(const char *name)
|
||||
fName = name;
|
||||
|
||||
// try to find it in the small data region
|
||||
if (fInode->SmallDataLock().Lock() == B_OK) {
|
||||
if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
|
||||
fNodeGetter.SetToNode(fInode);
|
||||
fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char *)name);
|
||||
if (fSmall != NULL)
|
||||
return B_OK;
|
||||
|
||||
fInode->SmallDataLock().Unlock();
|
||||
recursive_lock_unlock(&fInode->SmallDataLock());
|
||||
fNodeGetter.Unset();
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ void
|
||||
Attribute::Put()
|
||||
{
|
||||
if (fSmall != NULL) {
|
||||
fInode->SmallDataLock().Unlock();
|
||||
recursive_lock_unlock(&fInode->SmallDataLock());
|
||||
fNodeGetter.Unset();
|
||||
fSmall = NULL;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ Attribute::Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length)
|
||||
if (fSmall == NULL && fAttribute == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
// ToDo: move small_data logic from Inode::ReadAttribute() over to here!
|
||||
// TODO: move small_data logic from Inode::ReadAttribute() over to here!
|
||||
return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length);
|
||||
}
|
||||
|
||||
|
||||
@@ -341,6 +341,7 @@ BPlusTree::BPlusTree(Transaction &transaction, Inode *stream, int32 nodeSize)
|
||||
fHeader(NULL),
|
||||
fCachedHeader(this)
|
||||
{
|
||||
mutex_init(&fIteratorLock, "bfs b+tree iterator");
|
||||
SetTo(transaction, stream);
|
||||
}
|
||||
|
||||
@@ -351,6 +352,7 @@ BPlusTree::BPlusTree(Inode *stream)
|
||||
fHeader(NULL),
|
||||
fCachedHeader(this)
|
||||
{
|
||||
mutex_init(&fIteratorLock, "bfs b+tree iterator");
|
||||
SetTo(stream);
|
||||
}
|
||||
|
||||
@@ -364,6 +366,7 @@ BPlusTree::BPlusTree()
|
||||
fAllowDuplicates(true),
|
||||
fStatus(B_NO_INIT)
|
||||
{
|
||||
mutex_init(&fIteratorLock, "bfs b+tree iterator");
|
||||
}
|
||||
|
||||
|
||||
@@ -372,14 +375,13 @@ BPlusTree::~BPlusTree()
|
||||
// if there are any TreeIterators left, we need to stop them
|
||||
// (can happen when the tree's inode gets deleted while
|
||||
// traversing the tree - a TreeIterator doesn't lock the inode)
|
||||
if (fIteratorLock.Lock() < B_OK)
|
||||
return;
|
||||
mutex_lock(&fIteratorLock);
|
||||
|
||||
TreeIterator *iterator = NULL;
|
||||
while ((iterator = fIterators.Next(iterator)) != NULL)
|
||||
iterator->Stop();
|
||||
|
||||
fIteratorLock.Unlock();
|
||||
mutex_destroy(&fIteratorLock);
|
||||
}
|
||||
|
||||
|
||||
@@ -565,38 +567,27 @@ BPlusTree::_UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex,
|
||||
// Although every iterator which is affected by this update currently
|
||||
// waits on a semaphore, other iterators could be added/removed at
|
||||
// any time, so we need to protect this loop
|
||||
if (fIteratorLock.Lock() < B_OK)
|
||||
return;
|
||||
MutexLocker _(fIteratorLock);
|
||||
|
||||
TreeIterator *iterator = NULL;
|
||||
while ((iterator = fIterators.Next(iterator)) != NULL)
|
||||
iterator->Update(offset, nextOffset, keyIndex, splitAt, change);
|
||||
|
||||
fIteratorLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPlusTree::_AddIterator(TreeIterator *iterator)
|
||||
{
|
||||
if (fIteratorLock.Lock() < B_OK)
|
||||
return;
|
||||
|
||||
MutexLocker _(fIteratorLock);
|
||||
fIterators.Add(iterator);
|
||||
|
||||
fIteratorLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BPlusTree::_RemoveIterator(TreeIterator *iterator)
|
||||
{
|
||||
if (fIteratorLock.Lock() < B_OK)
|
||||
return;
|
||||
|
||||
MutexLocker _(fIteratorLock);
|
||||
fIterators.Remove(iterator);
|
||||
|
||||
fIteratorLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -2139,7 +2130,8 @@ TreeIterator::SkipDuplicates()
|
||||
|
||||
|
||||
void
|
||||
TreeIterator::Update(off_t offset, off_t nextOffset, uint16 keyIndex, uint16 splitAt, int8 change)
|
||||
TreeIterator::Update(off_t offset, off_t nextOffset, uint16 keyIndex,
|
||||
uint16 splitAt, int8 change)
|
||||
{
|
||||
if (offset != fCurrentNodeOffset)
|
||||
return;
|
||||
@@ -2158,7 +2150,7 @@ TreeIterator::Update(off_t offset, off_t nextOffset, uint16 keyIndex, uint16 spl
|
||||
if (keyIndex <= fCurrentKey)
|
||||
fCurrentKey += change;
|
||||
|
||||
// ToDo: duplicate handling!
|
||||
// TODO: duplicate handling!
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class BPlusTree {
|
||||
int32 fNodeSize;
|
||||
bool fAllowDuplicates;
|
||||
status_t fStatus;
|
||||
SimpleLock fIteratorLock;
|
||||
mutex fIteratorLock;
|
||||
Chain<TreeIterator> fIterators;
|
||||
};
|
||||
|
||||
|
||||
@@ -441,15 +441,16 @@ AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length)
|
||||
BlockAllocator::BlockAllocator(Volume *volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fLock("bfs allocator"),
|
||||
fGroups(NULL),
|
||||
fCheckBitmap(NULL)
|
||||
{
|
||||
mutex_init(&fLock, "bfs allocator");
|
||||
}
|
||||
|
||||
|
||||
BlockAllocator::~BlockAllocator()
|
||||
{
|
||||
mutex_destroy(&fLock);
|
||||
delete[] fGroups;
|
||||
}
|
||||
|
||||
@@ -457,9 +458,6 @@ BlockAllocator::~BlockAllocator()
|
||||
status_t
|
||||
BlockAllocator::Initialize(bool full)
|
||||
{
|
||||
if (fLock.InitCheck() < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
fNumGroups = fVolume->AllocationGroups();
|
||||
fBlocksPerGroup = fVolume->SuperBlock().BlocksPerAllocationGroup();
|
||||
fGroups = new AllocationGroup[fNumGroups];
|
||||
@@ -469,8 +467,8 @@ BlockAllocator::Initialize(bool full)
|
||||
if (!full)
|
||||
return B_OK;
|
||||
|
||||
fLock.Lock();
|
||||
// the lock will be released by the initialize() function
|
||||
mutex_lock(&fLock);
|
||||
// the lock will be released by the _Initialize() method
|
||||
|
||||
thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::_Initialize,
|
||||
"bfs block allocator", B_LOW_PRIORITY, (void *)this);
|
||||
@@ -547,7 +545,7 @@ BlockAllocator::_Initialize(BlockAllocator *allocator)
|
||||
|
||||
uint32 *buffer = (uint32 *)malloc(blocks << blockShift);
|
||||
if (buffer == NULL) {
|
||||
allocator->fLock.Unlock();
|
||||
mutex_unlock(&allocator->fLock);
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
}
|
||||
|
||||
@@ -621,7 +619,7 @@ BlockAllocator::_Initialize(BlockAllocator *allocator)
|
||||
volume->SuperBlock().used_blocks = HOST_ENDIAN_TO_BFS_INT64(usedBlocks);
|
||||
}
|
||||
|
||||
allocator->fLock.Unlock();
|
||||
mutex_unlock(&allocator->fLock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -636,7 +634,7 @@ BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group,
|
||||
FUNCTION_START(("group = %ld, start = %u, maximum = %u, minimum = %u\n", group, start, maximum, minimum));
|
||||
|
||||
AllocationBlock cached(fVolume);
|
||||
Locker lock(fLock);
|
||||
MutexLocker lock(fLock);
|
||||
|
||||
// The first scan through all allocation groups will look for the
|
||||
// wanted maximum of blocks, the second scan will just look to
|
||||
@@ -821,7 +819,7 @@ BlockAllocator::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks
|
||||
status_t
|
||||
BlockAllocator::Free(Transaction &transaction, block_run run)
|
||||
{
|
||||
Locker lock(fLock);
|
||||
MutexLocker lock(fLock);
|
||||
|
||||
int32 group = run.AllocationGroup();
|
||||
uint16 start = run.Start();
|
||||
@@ -896,14 +894,14 @@ BlockAllocator::StartChecking(check_control *control)
|
||||
if (!_IsValidCheckControl(control))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status_t status = fLock.Lock();
|
||||
status_t status = mutex_lock(&fLock);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
size_t size = BitmapSize();
|
||||
fCheckBitmap = (uint32 *)malloc(size);
|
||||
if (fCheckBitmap == NULL) {
|
||||
fLock.Unlock();
|
||||
mutex_unlock(&fLock);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
@@ -911,7 +909,7 @@ BlockAllocator::StartChecking(check_control *control)
|
||||
if (cookie == NULL) {
|
||||
free(fCheckBitmap);
|
||||
fCheckBitmap = NULL;
|
||||
fLock.Unlock();
|
||||
mutex_unlock(&fLock);
|
||||
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
@@ -1013,7 +1011,7 @@ BlockAllocator::StopChecking(check_control *control)
|
||||
fCheckBitmap = NULL;
|
||||
fCheckCookie = NULL;
|
||||
delete cookie;
|
||||
fLock.Unlock();
|
||||
mutex_unlock(&fLock);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -1113,7 +1111,7 @@ BlockAllocator::CheckNextNode(check_control *control)
|
||||
|
||||
// check if the inode's name is the same as in the b+tree
|
||||
if (inode->IsRegularNode()) {
|
||||
SimpleLocker locker(inode->SmallDataLock());
|
||||
RecursiveLocker locker(inode->SmallDataLock());
|
||||
NodeGetter node(fVolume, inode);
|
||||
|
||||
const char *localName = inode->Name(node.Node());
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define BLOCK_ALLOCATOR_H
|
||||
|
||||
|
||||
#include "Lock.h"
|
||||
#include "system_dependencies.h"
|
||||
|
||||
|
||||
class AllocationGroup;
|
||||
@@ -57,7 +57,7 @@ class BlockAllocator {
|
||||
static status_t _Initialize(BlockAllocator *);
|
||||
|
||||
Volume *fVolume;
|
||||
Semaphore fLock;
|
||||
mutex fLock;
|
||||
AllocationGroup *fGroups;
|
||||
int32 fNumGroups;
|
||||
uint32 fBlocksPerGroup;
|
||||
|
||||
@@ -330,6 +330,8 @@ Inode::Inode(Volume *volume, ino_t id)
|
||||
(int)BlockRun().AllocationGroup(), BlockRun().Start());
|
||||
fLock.Initialize(lockName);
|
||||
|
||||
recursive_lock_init(&fSmallDataLock, "bfs inode small data");
|
||||
|
||||
// these two will help to maintain the indices
|
||||
fOldSize = Size();
|
||||
fOldLastModified = LastModified();
|
||||
@@ -361,6 +363,8 @@ Inode::Inode(Volume *volume, Transaction &transaction, ino_t id, mode_t mode,
|
||||
(int)run.AllocationGroup(), run.Start());
|
||||
fLock.Initialize(lockName);
|
||||
|
||||
recursive_lock_init(&fSmallDataLock, "bfs inode small data");
|
||||
|
||||
NodeGetter node(volume, transaction, this, true);
|
||||
memset(&fNode, 0, sizeof(bfs_inode));
|
||||
|
||||
@@ -482,24 +486,16 @@ Inode::CheckPermissions(int accessMode) const
|
||||
void
|
||||
Inode::_AddIterator(AttributeIterator *iterator)
|
||||
{
|
||||
if (fSmallDataLock.Lock() < B_OK)
|
||||
return;
|
||||
|
||||
RecursiveLocker _(fSmallDataLock);
|
||||
fIterators.Add(iterator);
|
||||
|
||||
fSmallDataLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Inode::_RemoveIterator(AttributeIterator *iterator)
|
||||
{
|
||||
if (fSmallDataLock.Lock() < B_OK)
|
||||
return;
|
||||
|
||||
RecursiveLocker _(fSmallDataLock);
|
||||
fIterators.Remove(iterator);
|
||||
|
||||
fSmallDataLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -511,7 +507,7 @@ status_t
|
||||
Inode::_MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node,
|
||||
const char *name, int32 bytes)
|
||||
{
|
||||
ASSERT(fSmallDataLock.IsLocked());
|
||||
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
||||
|
||||
while (bytes > 0) {
|
||||
small_data *item = node->SmallDataStart(), *max = NULL;
|
||||
@@ -575,7 +571,7 @@ Inode::_MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node,
|
||||
status_t
|
||||
Inode::_RemoveSmallData(bfs_inode *node, small_data *item, int32 index)
|
||||
{
|
||||
ASSERT(fSmallDataLock.IsLocked());
|
||||
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
||||
|
||||
small_data *next = item->Next();
|
||||
if (!next->IsLast(node)) {
|
||||
@@ -617,7 +613,7 @@ Inode::_RemoveSmallData(Transaction &transaction, NodeGetter &nodeGetter,
|
||||
return B_BAD_VALUE;
|
||||
|
||||
bfs_inode *node = nodeGetter.WritableNode();
|
||||
SimpleLocker locker(fSmallDataLock);
|
||||
RecursiveLocker locker(fSmallDataLock);
|
||||
|
||||
// search for the small_data item
|
||||
|
||||
@@ -668,7 +664,7 @@ Inode::_AddSmallData(Transaction &transaction, NodeGetter &nodeGetter,
|
||||
return B_DEVICE_FULL;
|
||||
|
||||
nodeGetter.MakeWritable(transaction);
|
||||
SimpleLocker locker(fSmallDataLock);
|
||||
RecursiveLocker locker(fSmallDataLock);
|
||||
|
||||
// Find the last item or one with the same name we have to add
|
||||
small_data *item = node->SmallDataStart();
|
||||
@@ -809,7 +805,7 @@ Inode::_GetNextSmallData(bfs_inode *node, small_data **_smallData) const
|
||||
if (node == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
ASSERT(fSmallDataLock.IsLocked());
|
||||
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
||||
|
||||
small_data *data = *_smallData;
|
||||
|
||||
@@ -836,7 +832,7 @@ Inode::_GetNextSmallData(bfs_inode *node, small_data **_smallData) const
|
||||
small_data *
|
||||
Inode::FindSmallData(const bfs_inode *node, const char *name) const
|
||||
{
|
||||
ASSERT(fSmallDataLock.IsLocked());
|
||||
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
||||
|
||||
small_data *smallData = NULL;
|
||||
while (_GetNextSmallData(const_cast<bfs_inode *>(node), &smallData)
|
||||
@@ -855,7 +851,7 @@ Inode::FindSmallData(const bfs_inode *node, const char *name) const
|
||||
const char *
|
||||
Inode::Name(const bfs_inode *node) const
|
||||
{
|
||||
ASSERT(fSmallDataLock.IsLocked());
|
||||
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
||||
|
||||
small_data *smallData = NULL;
|
||||
while (_GetNextSmallData((bfs_inode *)node, &smallData) == B_OK) {
|
||||
@@ -874,7 +870,7 @@ status_t
|
||||
Inode::GetName(char *buffer, size_t size) const
|
||||
{
|
||||
NodeGetter node(fVolume, this);
|
||||
SimpleLocker locker(fSmallDataLock);
|
||||
RecursiveLocker locker(fSmallDataLock);
|
||||
|
||||
const char *name = Name(node.Node());
|
||||
if (name == NULL)
|
||||
@@ -966,7 +962,7 @@ Inode::ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer,
|
||||
// search in the small_data section (which has to be locked first)
|
||||
{
|
||||
NodeGetter node(fVolume, this);
|
||||
SimpleLocker locker(fSmallDataLock);
|
||||
RecursiveLocker locker(fSmallDataLock);
|
||||
|
||||
small_data *smallData = FindSmallData(node.Node(), name);
|
||||
if (smallData != NULL) {
|
||||
@@ -1025,7 +1021,7 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
|
||||
if (GetAttribute(name, &attribute) < B_OK) {
|
||||
// save the old attribute data
|
||||
NodeGetter node(fVolume, transaction, this);
|
||||
fSmallDataLock.Lock();
|
||||
recursive_lock_lock(&fSmallDataLock);
|
||||
|
||||
small_data *smallData = FindSmallData(node.Node(), name);
|
||||
if (smallData != NULL) {
|
||||
@@ -1036,7 +1032,7 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
|
||||
memcpy(oldData = oldBuffer, smallData->Data(), oldLength);
|
||||
}
|
||||
}
|
||||
fSmallDataLock.Unlock();
|
||||
recursive_lock_unlock(&fSmallDataLock);
|
||||
|
||||
// if the attribute doesn't exist yet (as a file), try to put it in the
|
||||
// small_data section first - if that fails (due to insufficent space),
|
||||
@@ -1128,7 +1124,7 @@ Inode::RemoveAttribute(Transaction &transaction, const char *name)
|
||||
|
||||
// update index for attributes in the small_data section
|
||||
{
|
||||
fSmallDataLock.Lock();
|
||||
RecursiveLocker _(fSmallDataLock);
|
||||
|
||||
small_data *smallData = FindSmallData(node.Node(), name);
|
||||
if (smallData != NULL) {
|
||||
@@ -1138,7 +1134,6 @@ Inode::RemoveAttribute(Transaction &transaction, const char *name)
|
||||
index.Update(transaction, name, smallData->Type(),
|
||||
smallData->Data(), length, NULL, 0, this);
|
||||
}
|
||||
fSmallDataLock.Unlock();
|
||||
}
|
||||
|
||||
status_t status = _RemoveSmallData(transaction, node, name);
|
||||
@@ -2561,7 +2556,7 @@ AttributeIterator::GetNext(char *name, size_t *_length, uint32 *_type,
|
||||
const bfs_inode *node = nodeGetter.Node();
|
||||
const small_data *item = ((bfs_inode *)node)->SmallDataStart();
|
||||
|
||||
fInode->SmallDataLock().Lock();
|
||||
RecursiveLocker _(&fInode->SmallDataLock());
|
||||
|
||||
int32 i = 0;
|
||||
for (;;item = item->Next()) {
|
||||
@@ -2589,8 +2584,6 @@ AttributeIterator::GetNext(char *name, size_t *_length, uint32 *_type,
|
||||
fCurrentSmallData = -1;
|
||||
}
|
||||
|
||||
fInode->SmallDataLock().Unlock();
|
||||
|
||||
if (fCurrentSmallData != -1)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class Inode {
|
||||
off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); }
|
||||
|
||||
ReadWriteLock &Lock() { return fLock; }
|
||||
SimpleLock &SmallDataLock() { return fSmallDataLock; }
|
||||
recursive_lock &SmallDataLock() { return fSmallDataLock; }
|
||||
status_t WriteBack(Transaction &transaction);
|
||||
|
||||
bool IsContainer() const
|
||||
@@ -207,7 +207,7 @@ class Inode {
|
||||
// we need those values to ensure we will remove
|
||||
// the correct keys from the indices
|
||||
|
||||
mutable SimpleLock fSmallDataLock;
|
||||
mutable recursive_lock fSmallDataLock;
|
||||
Chain<AttributeIterator> fIterators;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,10 +24,9 @@ SubDir HAIKU_TOP src add-ons kernel file_systems bfs ;
|
||||
SubDirC++Flags $(defines) -Wall -Wno-multichar ;
|
||||
}
|
||||
|
||||
UsePrivateHeaders [ FDirName kernel ] ; # For kernel_cpp.cpp
|
||||
UsePrivateKernelHeaders ;
|
||||
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
|
||||
UsePrivateHeaders [ FDirName shared ] ;
|
||||
UsePrivateHeaders [ FDirName storage ] ;
|
||||
UsePrivateHeaders shared storage ;
|
||||
|
||||
KernelAddon bfs :
|
||||
bfs_disk_system.cpp
|
||||
|
||||
@@ -395,7 +395,6 @@ RunArrays::MaxArrayLength()
|
||||
Journal::Journal(Volume *volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fLock("bfs journal"),
|
||||
fOwner(NULL),
|
||||
fLogSize(volume->Log().Length()),
|
||||
fMaxTransactionSize(fLogSize / 2 - 5),
|
||||
@@ -403,19 +402,24 @@ Journal::Journal(Volume *volume)
|
||||
fUnwrittenTransactions(0),
|
||||
fHasSubtransaction(false)
|
||||
{
|
||||
recursive_lock_init(&fLock, "bfs journal");
|
||||
mutex_init(&fEntriesLock, "bfs journal entries");
|
||||
}
|
||||
|
||||
|
||||
Journal::~Journal()
|
||||
{
|
||||
FlushLogAndBlocks();
|
||||
|
||||
recursive_lock_destroy(&fLock);
|
||||
mutex_destroy(&fEntriesLock);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Journal::InitCheck()
|
||||
{
|
||||
return fLock.InitCheck();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -605,7 +609,7 @@ Journal::_TransactionWritten(int32 transactionID, int32 event, void *_logEntry)
|
||||
|
||||
// Set log_start pointer if possible...
|
||||
|
||||
journal->fEntriesLock.Lock();
|
||||
mutex_lock(&journal->fEntriesLock);
|
||||
|
||||
if (logEntry == journal->fEntries.First()) {
|
||||
LogEntry *next = journal->fEntries.GetNext(logEntry);
|
||||
@@ -624,7 +628,7 @@ Journal::_TransactionWritten(int32 transactionID, int32 event, void *_logEntry)
|
||||
|
||||
journal->fUsed -= logEntry->Length();
|
||||
journal->fEntries.Remove(logEntry);
|
||||
journal->fEntriesLock.Unlock();
|
||||
mutex_unlock(&journal->fEntriesLock);
|
||||
|
||||
delete logEntry;
|
||||
|
||||
@@ -839,10 +843,10 @@ Journal::_WriteTransactionToLog()
|
||||
// at this point, we can finally end the transaction - we're in
|
||||
// a guaranteed valid state
|
||||
|
||||
fEntriesLock.Lock();
|
||||
mutex_lock(&fEntriesLock);
|
||||
fEntries.Add(logEntry);
|
||||
fUsed += logEntry->Length();
|
||||
fEntriesLock.Unlock();
|
||||
mutex_unlock(&fEntriesLock);
|
||||
|
||||
if (detached) {
|
||||
fTransactionID = cache_detach_sub_transaction(fVolume->BlockCache(),
|
||||
@@ -864,13 +868,14 @@ Journal::_WriteTransactionToLog()
|
||||
status_t
|
||||
Journal::_FlushLog(bool canWait, bool flushBlocks)
|
||||
{
|
||||
status_t status = canWait ? fLock.Lock() : fLock.LockWithTimeout(0);
|
||||
status_t status = canWait ? recursive_lock_lock(&fLock)
|
||||
: recursive_lock_trylock(&fLock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (fLock.OwnerCount() > 1) {
|
||||
if (recursive_lock_get_recursion(&fLock) > 1) {
|
||||
// whoa, FlushLogAndBlocks() was called from inside a transaction
|
||||
fLock.Unlock();
|
||||
recursive_lock_unlock(&fLock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -885,7 +890,7 @@ Journal::_FlushLog(bool canWait, bool flushBlocks)
|
||||
if (flushBlocks)
|
||||
status = fVolume->FlushDevice();
|
||||
|
||||
fLock.Unlock();
|
||||
recursive_lock_unlock(&fLock);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -903,11 +908,11 @@ Journal::FlushLogAndBlocks()
|
||||
status_t
|
||||
Journal::Lock(Transaction *owner)
|
||||
{
|
||||
status_t status = fLock.Lock();
|
||||
status_t status = recursive_lock_lock(&fLock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (fLock.OwnerCount() > 1) {
|
||||
if (recursive_lock_get_recursion(&fLock) > 1) {
|
||||
// we'll just use the current transaction again
|
||||
return B_OK;
|
||||
}
|
||||
@@ -929,7 +934,7 @@ Journal::Lock(Transaction *owner)
|
||||
fTransactionID = cache_start_transaction(fVolume->BlockCache());
|
||||
|
||||
if (fTransactionID < B_OK) {
|
||||
fLock.Unlock();
|
||||
recursive_lock_unlock(&fLock);
|
||||
return fTransactionID;
|
||||
}
|
||||
|
||||
@@ -943,7 +948,7 @@ Journal::Lock(Transaction *owner)
|
||||
void
|
||||
Journal::Unlock(Transaction *owner, bool success)
|
||||
{
|
||||
if (fLock.OwnerCount() == 1) {
|
||||
if (recursive_lock_get_recursion(&fLock) == 1) {
|
||||
// we only end the transaction if we would really unlock it
|
||||
// ToDo: what about failing transactions that do not unlock?
|
||||
_TransactionDone(success);
|
||||
@@ -952,7 +957,7 @@ Journal::Unlock(Transaction *owner, bool success)
|
||||
fOwner = NULL;
|
||||
}
|
||||
|
||||
fLock.Unlock();
|
||||
recursive_lock_unlock(&fLock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "Volume.h"
|
||||
#include "Chain.h"
|
||||
#include "Lock.h"
|
||||
#include "Utility.h"
|
||||
|
||||
|
||||
@@ -69,11 +70,11 @@ class Journal {
|
||||
void *_journal);
|
||||
|
||||
Volume *fVolume;
|
||||
RecursiveLock fLock;
|
||||
recursive_lock fLock;
|
||||
Transaction *fOwner;
|
||||
uint32 fLogSize, fMaxTransactionSize, fUsed;
|
||||
int32 fUnwrittenTransactions;
|
||||
SimpleLock fEntriesLock;
|
||||
mutex fEntriesLock;
|
||||
LogEntryList fEntries;
|
||||
bigtime_t fTimestamp;
|
||||
int32 fTransactionID;
|
||||
|
||||
@@ -26,201 +26,7 @@
|
||||
# error implement recursive write locking first
|
||||
#endif
|
||||
|
||||
class Semaphore {
|
||||
public:
|
||||
Semaphore(const char *name)
|
||||
:
|
||||
#ifdef USE_BENAPHORE
|
||||
fSemaphore(create_sem(0, name)),
|
||||
fCount(1)
|
||||
#else
|
||||
fSemaphore(create_sem(1, name))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
~Semaphore()
|
||||
{
|
||||
delete_sem(fSemaphore);
|
||||
}
|
||||
|
||||
status_t InitCheck()
|
||||
{
|
||||
if (fSemaphore < B_OK)
|
||||
return fSemaphore;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t Lock()
|
||||
{
|
||||
#ifdef USE_BENAPHORE
|
||||
if (atomic_add(&fCount, -1) <= 0)
|
||||
#endif
|
||||
return acquire_sem(fSemaphore);
|
||||
#ifdef USE_BENAPHORE
|
||||
return B_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
status_t Unlock()
|
||||
{
|
||||
#ifdef USE_BENAPHORE
|
||||
if (atomic_add(&fCount, 1) < 0)
|
||||
#endif
|
||||
return release_sem(fSemaphore);
|
||||
#ifdef USE_BENAPHORE
|
||||
return B_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
sem_id fSemaphore;
|
||||
#ifdef USE_BENAPHORE
|
||||
vint32 fCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
// a convenience class to lock a Semaphore object
|
||||
|
||||
class Locker {
|
||||
public:
|
||||
Locker(Semaphore &lock)
|
||||
: fLock(lock)
|
||||
{
|
||||
fStatus = lock.Lock();
|
||||
ASSERT(fStatus == B_OK);
|
||||
}
|
||||
|
||||
~Locker()
|
||||
{
|
||||
if (fStatus == B_OK)
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
status_t Status() const
|
||||
{
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
private:
|
||||
Semaphore &fLock;
|
||||
status_t fStatus;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - Recursive Lock
|
||||
|
||||
class RecursiveLock {
|
||||
public:
|
||||
RecursiveLock(const char *name)
|
||||
:
|
||||
#ifdef USE_BENAPHORE
|
||||
fSemaphore(create_sem(0, name)),
|
||||
fCount(1),
|
||||
#else
|
||||
fSemaphore(create_sem(1, name)),
|
||||
#endif
|
||||
fOwner(-1)
|
||||
{
|
||||
}
|
||||
|
||||
status_t InitCheck() const
|
||||
{
|
||||
if (fSemaphore < B_OK)
|
||||
return fSemaphore;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t LockWithTimeout(bigtime_t timeout)
|
||||
{
|
||||
thread_id thread = find_thread(NULL);
|
||||
if (thread == fOwner) {
|
||||
fOwnerCount++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t status;
|
||||
#ifdef USE_BENAPHORE
|
||||
if (atomic_add(&fCount, -1) > 0)
|
||||
status = B_OK;
|
||||
else
|
||||
#endif
|
||||
status = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, timeout);
|
||||
|
||||
if (status == B_OK) {
|
||||
fOwner = thread;
|
||||
fOwnerCount = 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t Lock()
|
||||
{
|
||||
return LockWithTimeout(B_INFINITE_TIMEOUT);
|
||||
}
|
||||
|
||||
status_t Unlock()
|
||||
{
|
||||
thread_id thread = find_thread(NULL);
|
||||
if (thread != fOwner) {
|
||||
panic("RecursiveLock unlocked by %d, owned by %d\n", (int)thread, (int)fOwner);
|
||||
}
|
||||
|
||||
if (--fOwnerCount == 0) {
|
||||
fOwner = -1;
|
||||
#ifdef USE_BENAPHORE
|
||||
if (atomic_add(&fCount, 1) < 0)
|
||||
#endif
|
||||
return release_sem(fSemaphore);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
thread_id Owner() const { return fOwner; }
|
||||
int32 OwnerCount() const { return fOwnerCount; }
|
||||
|
||||
private:
|
||||
sem_id fSemaphore;
|
||||
#ifdef USE_BENAPHORE
|
||||
vint32 fCount;
|
||||
#endif
|
||||
thread_id fOwner;
|
||||
int32 fOwnerCount;
|
||||
};
|
||||
|
||||
// a convenience class to lock an RecursiveLock object
|
||||
|
||||
class RecursiveLocker {
|
||||
public:
|
||||
RecursiveLocker(RecursiveLock &lock)
|
||||
: fLock(lock)
|
||||
{
|
||||
fStatus = lock.Lock();
|
||||
ASSERT(fStatus == B_OK);
|
||||
}
|
||||
|
||||
~RecursiveLocker()
|
||||
{
|
||||
if (fStatus == B_OK)
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
status_t Status() const
|
||||
{
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
private:
|
||||
RecursiveLock &fLock;
|
||||
status_t fStatus;
|
||||
};
|
||||
|
||||
|
||||
//**** Many Reader/Single Writer Lock
|
||||
// #pragma mark - Many Reader/Single Writer Lock
|
||||
|
||||
// This is a "fast" implementation of a single writer/many reader
|
||||
// locking scheme. It's fast because it uses the benaphore idea
|
||||
@@ -523,78 +329,4 @@ class WriteLocked {
|
||||
status_t fStatus;
|
||||
};
|
||||
|
||||
|
||||
// A simple locking structure that doesn't use a semaphore - it's useful
|
||||
// if you have to protect critical parts with a short runtime.
|
||||
// It also allows to nest several locks for the same thread.
|
||||
|
||||
class SimpleLock {
|
||||
public:
|
||||
SimpleLock()
|
||||
:
|
||||
fHolder(-1),
|
||||
fCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
status_t Lock(bigtime_t time = 500)
|
||||
{
|
||||
int32 thisThread = find_thread(NULL);
|
||||
int32 current;
|
||||
while (1) {
|
||||
/*if (fHolder == -1) {
|
||||
current = fHolder;
|
||||
fHolder = thisThread;
|
||||
}*/
|
||||
current = atomic_test_and_set(&fHolder, thisThread, -1);
|
||||
if (current == -1)
|
||||
break;
|
||||
if (current == thisThread)
|
||||
break;
|
||||
|
||||
snooze(time);
|
||||
}
|
||||
|
||||
// ToDo: the lock cannot fail currently! We may want
|
||||
// to change this
|
||||
atomic_add(&fCount, 1);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
if (atomic_add(&fCount, -1) == 1)
|
||||
atomic_set(&fHolder, -1);
|
||||
}
|
||||
|
||||
bool IsLocked() const
|
||||
{
|
||||
return fHolder == find_thread(NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
vint32 fHolder;
|
||||
vint32 fCount;
|
||||
};
|
||||
|
||||
// A convenience class to lock the SimpleLock, note the
|
||||
// different timing compared to the direct call
|
||||
|
||||
class SimpleLocker {
|
||||
public:
|
||||
SimpleLocker(SimpleLock &lock,bigtime_t time = 1000)
|
||||
: fLock(lock)
|
||||
{
|
||||
lock.Lock(time);
|
||||
}
|
||||
|
||||
~SimpleLocker()
|
||||
{
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleLock &fLock;
|
||||
};
|
||||
|
||||
#endif /* LOCK_H */
|
||||
|
||||
@@ -805,13 +805,13 @@ Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8
|
||||
// we need to lock before accessing Inode::Name()
|
||||
nodeGetter.SetToNode(inode);
|
||||
|
||||
inode->SmallDataLock().Lock();
|
||||
recursive_lock_lock(&inode->SmallDataLock());
|
||||
locked = true;
|
||||
|
||||
// if not, check for "fake" attributes, "name", "size", "last_modified",
|
||||
buffer = (uint8 *)inode->Name(nodeGetter.Node());
|
||||
if (buffer == NULL) {
|
||||
inode->SmallDataLock().Unlock();
|
||||
recursive_lock_unlock(&inode->SmallDataLock());
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -837,7 +837,7 @@ Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8
|
||||
nodeGetter.SetToNode(inode);
|
||||
Inode *attribute;
|
||||
|
||||
inode->SmallDataLock().Lock();
|
||||
recursive_lock_lock(&inode->SmallDataLock());
|
||||
small_data *smallData = inode->FindSmallData(nodeGetter.Node(), fAttribute);
|
||||
if (smallData != NULL) {
|
||||
buffer = smallData->Data();
|
||||
@@ -846,7 +846,7 @@ Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8
|
||||
locked = true;
|
||||
} else {
|
||||
// needed to unlock the small_data section as fast as possible
|
||||
inode->SmallDataLock().Unlock();
|
||||
recursive_lock_unlock(&inode->SmallDataLock());
|
||||
nodeGetter.Unset();
|
||||
|
||||
if (inode->GetAttribute(fAttribute, &attribute) == B_OK) {
|
||||
@@ -872,7 +872,7 @@ Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8
|
||||
status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
|
||||
|
||||
if (locked)
|
||||
inode->SmallDataLock().Unlock();
|
||||
recursive_lock_unlock(&inode->SmallDataLock());
|
||||
|
||||
RETURN_ERROR(status);
|
||||
}
|
||||
|
||||
@@ -276,18 +276,20 @@ Volume::Volume(fs_volume *volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlockAllocator(this),
|
||||
fLock("bfs volume"),
|
||||
fRootNode(NULL),
|
||||
fIndicesNode(NULL),
|
||||
fDirtyCachedBlocks(0),
|
||||
fUniqueID(0),
|
||||
fFlags(0)
|
||||
{
|
||||
mutex_init(&fLock, "bfs volume");
|
||||
mutex_init(&fQueryLock, "bfs queries");
|
||||
}
|
||||
|
||||
|
||||
Volume::~Volume()
|
||||
{
|
||||
mutex_destroy(&fLock);
|
||||
}
|
||||
|
||||
|
||||
@@ -516,16 +518,13 @@ Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type,
|
||||
const uint8 *oldKey, size_t oldLength, const uint8 *newKey,
|
||||
size_t newLength)
|
||||
{
|
||||
if (fQueryLock.Lock() < B_OK)
|
||||
return;
|
||||
MutexLocker _(fQueryLock);
|
||||
|
||||
Query *query = NULL;
|
||||
while ((query = fQueries.Next(query)) != NULL) {
|
||||
query->LiveUpdate(inode, attribute, type, oldKey, oldLength, newKey,
|
||||
newLength);
|
||||
}
|
||||
|
||||
fQueryLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -545,24 +544,16 @@ Volume::CheckForLiveQuery(const char *attribute)
|
||||
void
|
||||
Volume::AddQuery(Query *query)
|
||||
{
|
||||
if (fQueryLock.Lock() < B_OK)
|
||||
return;
|
||||
|
||||
MutexLocker _(fQueryLock);
|
||||
fQueries.Add(query);
|
||||
|
||||
fQueryLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Volume::RemoveQuery(Query *query)
|
||||
{
|
||||
if (fQueryLock.Lock() < B_OK)
|
||||
return;
|
||||
|
||||
MutexLocker _(fQueryLock);
|
||||
fQueries.Remove(query);
|
||||
|
||||
fQueryLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VOLUME_H
|
||||
@@ -37,7 +37,7 @@ class Volume {
|
||||
bool IsValidSuperBlock();
|
||||
bool IsReadOnly() const;
|
||||
void Panic();
|
||||
RecursiveLock &Lock();
|
||||
mutex &Lock();
|
||||
|
||||
block_run Root() const { return fSuperBlock.root_dir; }
|
||||
Inode *RootNode() const { return fRootNode; }
|
||||
@@ -117,7 +117,7 @@ class Volume {
|
||||
uint32 fAllocationGroupShift;
|
||||
|
||||
BlockAllocator fBlockAllocator;
|
||||
RecursiveLock fLock;
|
||||
mutex fLock;
|
||||
Journal *fJournal;
|
||||
vint32 fLogStart, fLogEnd;
|
||||
|
||||
@@ -126,7 +126,7 @@ class Volume {
|
||||
|
||||
vint32 fDirtyCachedBlocks;
|
||||
|
||||
SimpleLock fQueryLock;
|
||||
mutex fQueryLock;
|
||||
Chain<Query> fQueries;
|
||||
|
||||
int32 fUniqueID;
|
||||
@@ -145,7 +145,7 @@ Volume::IsReadOnly() const
|
||||
}
|
||||
|
||||
|
||||
inline RecursiveLock &
|
||||
inline mutex &
|
||||
Volume::Lock()
|
||||
{
|
||||
return fLock;
|
||||
|
||||
@@ -149,7 +149,7 @@ bfs_read_fs_stat(fs_volume *_volume, struct fs_info *info)
|
||||
FUNCTION();
|
||||
|
||||
Volume *volume = (Volume *)_volume->private_volume;
|
||||
RecursiveLocker locker(volume->Lock());
|
||||
MutexLocker locker(volume->Lock());
|
||||
|
||||
// File system flags.
|
||||
info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME
|
||||
@@ -181,7 +181,7 @@ bfs_write_fs_stat(fs_volume *_volume, const struct fs_info *info, uint32 mask)
|
||||
if (volume->IsReadOnly())
|
||||
return B_READ_ONLY_DEVICE;
|
||||
|
||||
RecursiveLocker locker(volume->Lock());
|
||||
MutexLocker locker(volume->Lock());
|
||||
|
||||
status_t status = B_BAD_VALUE;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#else // !BFS_SHELL
|
||||
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#include <util/Stack.h>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
SubDir HAIKU_TOP src system boot loader file_systems bfs ;
|
||||
|
||||
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
|
||||
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
|
||||
UsePrivateHeaders kernel shared storage ;
|
||||
UsePrivateKernelHeaders ;
|
||||
UsePrivateHeaders shared storage ;
|
||||
|
||||
SubDirHdrs $(HAIKU_TOP) src add-ons kernel file_systems bfs ;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user