btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / fs / unused_vnodes.h
blob5f5bb490b66fa5021e50a4c1742b5500e1e74384
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5 #ifndef UNUSED_VNODES_H
6 #define UNUSED_VNODES_H
9 #include <algorithm>
11 #include <util/AutoLock.h>
12 #include <util/list.h>
14 #include <low_resource_manager.h>
16 #include "Vnode.h"
19 const static uint32 kMaxUnusedVnodes = 8192;
20 // This is the maximum number of unused vnodes that the system
21 // will keep around (weak limit, if there is enough memory left,
22 // they won't get flushed even when hitting that limit).
23 // It may be chosen with respect to the available memory or enhanced
24 // by some timestamp/frequency heurism.
27 /*! \brief Guards sUnusedVnodeList and sUnusedVnodes.
29 Innermost lock. Must not be held when acquiring any other lock.
31 static mutex sUnusedVnodesLock = MUTEX_INITIALIZER("unused vnodes");
32 static list sUnusedVnodeList;
33 static uint32 sUnusedVnodes = 0;
35 static const int32 kMaxHotVnodes = 1024;
36 static rw_lock sHotVnodesLock = RW_LOCK_INITIALIZER("hot vnodes");
37 static Vnode* sHotVnodes[kMaxHotVnodes];
38 static int32 sNextHotVnodeIndex = 0;
40 static const int32 kUnusedVnodesCheckInterval = 64;
41 static int32 sUnusedVnodesCheckCount = 0;
44 /*! Must be called with sHotVnodesLock write-locked.
46 static void
47 flush_hot_vnodes_locked()
49 MutexLocker unusedLocker(sUnusedVnodesLock);
51 int32 count = std::min(sNextHotVnodeIndex, kMaxHotVnodes);
52 for (int32 i = 0; i < count; i++) {
53 Vnode* vnode = sHotVnodes[i];
54 if (vnode == NULL)
55 continue;
57 if (vnode->IsHot()) {
58 if (vnode->IsUnused()) {
59 list_add_item(&sUnusedVnodeList, vnode);
60 sUnusedVnodes++;
62 vnode->SetHot(false);
65 sHotVnodes[i] = NULL;
68 unusedLocker.Unlock();
70 sNextHotVnodeIndex = 0;
75 /*! To be called when the vnode's ref count drops to 0.
76 Must be called with sVnodeLock at least read-locked and the vnode locked.
77 \param vnode The vnode.
78 \return \c true, if the caller should trigger unused vnode freeing.
80 static bool
81 vnode_unused(Vnode* vnode)
83 ReadLocker hotReadLocker(sHotVnodesLock);
85 vnode->SetUnused(true);
87 bool result = false;
88 int32 checkCount = atomic_add(&sUnusedVnodesCheckCount, 1);
89 if (checkCount == kUnusedVnodesCheckInterval) {
90 uint32 unusedCount = atomic_get((int32*)&sUnusedVnodes);
91 if (unusedCount > kMaxUnusedVnodes
92 && low_resource_state(
93 B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY)
94 != B_NO_LOW_RESOURCE) {
95 // there are too many unused vnodes -- tell the caller to free the
96 // oldest ones
97 result = true;
98 } else {
99 // nothing urgent -- reset the counter and re-check then
100 atomic_set(&sUnusedVnodesCheckCount, 0);
104 // nothing to do, if the node is already hot
105 if (vnode->IsHot())
106 return result;
108 // no -- enter it
109 int32 index = atomic_add(&sNextHotVnodeIndex, 1);
110 if (index < kMaxHotVnodes) {
111 vnode->SetHot(true);
112 sHotVnodes[index] = vnode;
113 return result;
116 // the array is full -- it has to be emptied
117 hotReadLocker.Unlock();
118 WriteLocker hotWriteLocker(sHotVnodesLock);
120 // unless someone was faster than we were, we have to flush the array
121 if (sNextHotVnodeIndex >= kMaxHotVnodes)
122 flush_hot_vnodes_locked();
124 // enter the vnode
125 index = sNextHotVnodeIndex++;
126 vnode->SetHot(true);
127 sHotVnodes[index] = vnode;
129 return result;
133 /*! To be called when the vnode's ref count is changed from 0 to 1.
134 Must be called with sVnodeLock at least read-locked and the vnode locked.
135 \param vnode The vnode.
137 static void
138 vnode_used(Vnode* vnode)
140 ReadLocker hotReadLocker(sHotVnodesLock);
142 if (!vnode->IsUnused())
143 return;
145 vnode->SetUnused(false);
147 if (!vnode->IsHot()) {
148 MutexLocker unusedLocker(sUnusedVnodesLock);
149 list_remove_item(&sUnusedVnodeList, vnode);
150 sUnusedVnodes--;
155 /*! To be called when the vnode's is about to be freed.
156 Must be called with sVnodeLock at least read-locked and the vnode locked.
157 \param vnode The vnode.
159 static void
160 vnode_to_be_freed(Vnode* vnode)
162 ReadLocker hotReadLocker(sHotVnodesLock);
164 if (vnode->IsHot()) {
165 // node is hot -- remove it from the array
166 // TODO: Maybe better completely flush the array while at it?
167 int32 count = atomic_get(&sNextHotVnodeIndex);
168 count = std::min(count, kMaxHotVnodes);
169 for (int32 i = 0; i < count; i++) {
170 if (sHotVnodes[i] == vnode) {
171 sHotVnodes[i] = NULL;
172 break;
175 } else if (vnode->IsUnused()) {
176 MutexLocker unusedLocker(sUnusedVnodesLock);
177 list_remove_item(&sUnusedVnodeList, vnode);
178 sUnusedVnodes--;
181 vnode->SetUnused(false);
185 static inline void
186 flush_hot_vnodes()
188 WriteLocker hotWriteLocker(sHotVnodesLock);
189 flush_hot_vnodes_locked();
193 static inline void
194 unused_vnodes_check_started()
196 atomic_set(&sUnusedVnodesCheckCount, kUnusedVnodesCheckInterval + 1);
200 static inline void
201 unused_vnodes_check_done()
203 atomic_set(&sUnusedVnodesCheckCount, 0);
207 #endif // UNUSED_VNODES_H