3 * - By John Hodge (thePowersGang)
6 * - VFS Node Caching facility
14 typedef struct sCachedInode {
15 struct sCachedInode *Next;
18 typedef struct sInodeCache {
19 struct sInodeCache *Next;
21 tCachedInode *FirstNode; // Sorted List
22 Uint64 MaxCached; // Speeds up Searching
26 tInodeCache *Inode_int_GetFSCache(int Handle);
29 int gVFS_NextInodeHandle = 1;
30 tShortSpinlock glVFS_InodeCache;
31 tInodeCache *gVFS_InodeCache = NULL;
35 * \fn int Inode_GetHandle()
41 ent = malloc( sizeof(tInodeCache) );
43 ent->Handle = gVFS_NextInodeHandle++;
44 ent->Next = NULL; ent->FirstNode = NULL;
47 SHORTLOCK( &glVFS_InodeCache );
48 ent->Next = gVFS_InodeCache;
49 gVFS_InodeCache = ent;
50 SHORTREL( &glVFS_InodeCache );
56 * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
57 * \brief Gets a node from the cache
59 tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
64 cache = Inode_int_GetFSCache(Handle);
65 if(!cache) return NULL;
67 if(Inode > cache->MaxCached) return NULL;
70 ent = cache->FirstNode;
71 for( ; ent; ent = ent->Next )
73 if(ent->Node.Inode < Inode) continue;
74 if(ent->Node.Inode > Inode) return NULL;
75 ent->Node.ReferenceCount ++;
79 return NULL; // Should never be reached
83 * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
85 tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
87 return Inode_CacheNodeEx(Handle, Node, sizeof(*Node));
90 tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size)
93 tCachedInode *newEnt, *ent, *prev = NULL;
95 ASSERT(Size >= sizeof(tVFS_Node));
97 cache = Inode_int_GetFSCache(Handle);
98 if(!cache) return NULL;
100 if(Node->Inode > cache->MaxCached)
101 cache->MaxCached = Node->Inode;
104 ent = cache->FirstNode;
105 for( ; ent; prev = ent, ent = ent->Next )
107 if(ent->Node.Inode < Node->Inode) continue;
108 if(ent->Node.Inode == Node->Inode) {
109 ent->Node.ReferenceCount ++;
116 newEnt = malloc(sizeof(tCachedInode) + (Size - sizeof(tVFS_Node)));
118 memcpy(&newEnt->Node, Node, Size);
122 cache->FirstNode = newEnt;
123 newEnt->Node.ReferenceCount = 1;
125 LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
127 return &newEnt->Node;
131 * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
132 * \brief Dereferences/Removes a cached node
134 int Inode_UncacheNode(int Handle, Uint64 Inode)
137 tCachedInode *ent, *prev;
139 cache = Inode_int_GetFSCache(Handle);
141 Log_Notice("Inode", "Invalid cache handle %i used", Handle);
145 ENTER("iHandle XInode", Handle, Inode);
147 if(Inode > cache->MaxCached) {
153 ent = cache->FirstNode;
155 for( ; ent; prev = ent, ent = ent->Next )
157 if(ent->Node.Inode < Inode) continue;
158 if(ent->Node.Inode > Inode) {
165 LOG("ent = %p", ent);
172 ent->Node.ReferenceCount --;
173 // Check if node needs to be freed
174 if(ent->Node.ReferenceCount == 0)
177 prev->Next = ent->Next;
179 cache->FirstNode = ent->Next;
180 if(ent->Node.Inode == cache->MaxCached)
182 if(ent != cache->FirstNode && prev)
183 cache->MaxCached = prev->Node.Inode;
185 cache->MaxCached = 0;
189 free(ent->Node.Data);
203 * \fn void Inode_ClearCache(int Handle)
204 * \brief Removes a cache
206 void Inode_ClearCache(int Handle)
209 tInodeCache *prev = NULL;
210 tCachedInode *ent, *next;
214 cache = gVFS_InodeCache;
215 cache && cache->Handle < Handle;
216 prev = cache, cache = cache->Next
218 if(!cache || cache->Handle != Handle) return;
221 ent = cache->FirstNode;
224 ent->Node.ReferenceCount = 1;
227 if(ent->Node.Type && ent->Node.Type->Close)
228 ent->Node.Type->Close( &ent->Node );
236 gVFS_InodeCache = cache->Next;
238 prev->Next = cache->Next;
243 * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
244 * \brief Gets a cache given it's handle
246 tInodeCache *Inode_int_GetFSCache(int Handle)
248 tInodeCache *cache = gVFS_InodeCache;
250 for( ; cache; cache = cache->Next )
252 if(cache->Handle > Handle) continue;
253 if(cache->Handle < Handle) {
254 Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
260 Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);