diff --git a/src/system/kernel/fs/unused_vnodes.h b/src/system/kernel/fs/unused_vnodes.h index e15860700b..10d2c8c005 100644 --- a/src/system/kernel/fs/unused_vnodes.h +++ b/src/system/kernel/fs/unused_vnodes.h @@ -26,9 +26,9 @@ const static uint32 kMaxUnusedVnodes = 8192; /*! \brief Guards sUnusedVnodeList and sUnusedVnodes. - Innermost lock. Must not be held when acquiring any other lock. + Must have at least a read-lock of sHotVnodesLock when acquiring! */ -static mutex sUnusedVnodesLock = MUTEX_INITIALIZER("unused vnodes"); +static spinlock sUnusedVnodesLock = B_SPINLOCK_INITIALIZER; typedef DoublyLinkedList > UnusedVnodeList; static UnusedVnodeList sUnusedVnodeList; @@ -48,7 +48,10 @@ static int32 sUnusedVnodesCheckCount = 0; static void flush_hot_vnodes_locked() { - MutexLocker unusedLocker(sUnusedVnodesLock); + // Since sUnusedVnodesLock is always acquired after sHotVnodesLock, + // we can safely hold it for the whole duration of the flush. + // We don't want to be descheduled while holding the write-lock, anyway. + InterruptsSpinLocker unusedLocker(sUnusedVnodesLock); int32 count = std::min(sNextHotVnodeIndex, kMaxHotVnodes); for (int32 i = 0; i < count; i++) { @@ -147,7 +150,7 @@ vnode_used(Vnode* vnode) vnode->SetUnused(false); if (!vnode->IsHot()) { - MutexLocker unusedLocker(sUnusedVnodesLock); + InterruptsSpinLocker unusedLocker(sUnusedVnodesLock); sUnusedVnodeList.Remove(vnode); sUnusedVnodes--; } @@ -175,7 +178,7 @@ vnode_to_be_freed(Vnode* vnode) } } } else if (vnode->IsUnused()) { - MutexLocker unusedLocker(sUnusedVnodesLock); + InterruptsSpinLocker unusedLocker(sUnusedVnodesLock); sUnusedVnodeList.Remove(vnode); sUnusedVnodes--; } diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 55719b8aa5..f29f795d04 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -1294,7 +1294,8 @@ free_unused_vnodes(int32 level) // determine how many nodes to free uint32 count = 1; { - MutexLocker unusedVnodesLocker(sUnusedVnodesLock); + ReadLocker hotVnodesReadLocker(sHotVnodesLock); + InterruptsSpinLocker unusedVnodesLocker(sUnusedVnodesLock); switch (level) { case B_LOW_RESOURCE_NOTE: @@ -1316,9 +1317,10 @@ free_unused_vnodes(int32 level) for (uint32 i = 0; i < count; i++) { ReadLocker vnodesReadLocker(sVnodeLock); + ReadLocker hotVnodesReadLocker(sHotVnodesLock); // get the first node - MutexLocker unusedVnodesLocker(sUnusedVnodesLock); + InterruptsSpinLocker unusedVnodesLocker(sUnusedVnodesLock); struct vnode* vnode = sUnusedVnodeList.First(); unusedVnodesLocker.Unlock(); @@ -1347,6 +1349,7 @@ free_unused_vnodes(int32 level) // write back changes and free the node nodeLocker.Unlock(); + hotVnodesReadLocker.Unlock(); vnodesReadLocker.Unlock(); if (vnode->cache != NULL)