* No longer hold the write lock when calling Inode::FillGapWithZeros(), as this

potentially deadlocks as described in bug #3768. The system is still
  completely unresponsive, but gets back to a working state after some time now.
* Since the rw_lock is public, Transaction and InodeReadLocker no longer need to
  be friends with Inode.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30221 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-04-17 09:51:42 +00:00
parent e50b251243
commit 24b822d843
4 changed files with 12 additions and 10 deletions
@@ -1498,7 +1498,7 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
if (pos + length > Size()) { if (pos + length > Size()) {
// let's grow the data stream to the size needed // let's grow the data stream to the size needed
status_t status = SetFileSize(transaction, pos + length); status_t status = SetFileSize(transaction, pos + length);
if (status < B_OK) { if (status != B_OK) {
*_length = 0; *_length = 0;
WriteLockInTransaction(transaction); WriteLockInTransaction(transaction);
RETURN_ERROR(status); RETURN_ERROR(status);
@@ -1511,7 +1511,7 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
// go into this transaction (we cannot wait until the file // go into this transaction (we cannot wait until the file
// is closed) // is closed)
status = WriteBack(transaction); status = WriteBack(transaction);
if (status < B_OK) { if (status != B_OK) {
WriteLockInTransaction(transaction); WriteLockInTransaction(transaction);
return status; return status;
} }
+1 -4
View File
@@ -19,7 +19,6 @@ class TreeIterator;
class AttributeIterator; class AttributeIterator;
class Index; class Index;
class InodeAllocator; class InodeAllocator;
class InodeReadLocker;
class NodeGetter; class NodeGetter;
class Transaction; class Transaction;
@@ -188,8 +187,6 @@ private:
friend class AttributeIterator; friend class AttributeIterator;
friend class InodeAllocator; friend class InodeAllocator;
friend class InodeReadLocker;
friend class Transaction;
// small_data access methods // small_data access methods
status_t _MakeSpaceForSmallData(Transaction& transaction, status_t _MakeSpaceForSmallData(Transaction& transaction,
@@ -253,7 +250,7 @@ class InodeReadLocker {
public: public:
InodeReadLocker(Inode* inode) InodeReadLocker(Inode* inode)
: :
fLock(&inode->fLock) fLock(&inode->Lock())
{ {
rw_lock_read_lock(fLock); rw_lock_read_lock(fLock);
} }
@@ -1103,7 +1103,7 @@ Transaction::AddInode(Inode* inode)
if (!GetVolume()->IsInitializing()) if (!GetVolume()->IsInitializing())
acquire_vnode(GetVolume()->FSVolume(), inode->ID()); acquire_vnode(GetVolume()->FSVolume(), inode->ID());
rw_lock_write_lock(&inode->fLock); rw_lock_write_lock(&inode->Lock());
fLockedInodes.Add(inode); fLockedInodes.Add(inode);
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION); inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
} }
@@ -1117,7 +1117,7 @@ Transaction::RemoveInode(Inode* inode)
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION); inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
fLockedInodes.Remove(inode); fLockedInodes.Remove(inode);
rw_lock_write_unlock(&inode->fLock); rw_lock_write_unlock(&inode->Lock());
// See AddInode() why we do this here // See AddInode() why we do this here
if ((inode->Flags() & INODE_DELETED) != 0) if ((inode->Flags() & INODE_DELETED) != 0)
@@ -1133,7 +1133,7 @@ Transaction::_UnlockInodes()
{ {
while (Inode* inode = fLockedInodes.RemoveHead()) { while (Inode* inode = fLockedInodes.RemoveHead()) {
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION); inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
rw_lock_write_unlock(&inode->fLock); rw_lock_write_unlock(&inode->Lock());
// See AddInode() why we do this here // See AddInode() why we do this here
if ((inode->Flags() & INODE_DELETED) != 0) if ((inode->Flags() & INODE_DELETED) != 0)
@@ -755,8 +755,13 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
return status; return status;
// fill the new blocks (if any) with zeros // fill the new blocks (if any) with zeros
if ((mask & B_STAT_SIZE_INSECURE) == 0) if ((mask & B_STAT_SIZE_INSECURE) == 0) {
// We must not keep the inode locked during a write operation,
// or else we might deadlock.
rw_lock_write_unlock(&inode->Lock());
inode->FillGapWithZeros(oldSize, inode->Size()); inode->FillGapWithZeros(oldSize, inode->Size());
rw_lock_write_lock(&inode->Lock());
}
if (!inode->IsDeleted()) { if (!inode->IsDeleted()) {
Index index(volume); Index index(volume);