3 * - By John Hodge (thePowersGang)
6 * - VFS Node Caching facility
14 typedef struct sCachedInode {
15 struct sCachedInode *Next;
20 struct sInodeCache *Next;
21 tInode_CleanUpNode CleanUpNode;
22 tCachedInode *FirstNode; // Sorted List
23 Uint64 MaxCached; // Speeds up Searching
27 tShortSpinlock glVFS_InodeCache;
28 tInodeCache *gVFS_InodeCache = NULL;
32 // Create a new inode cache
33 tInodeCache *Inode_GetHandle(tInode_CleanUpNode CleanUpNode)
37 ent = malloc( sizeof(tInodeCache) );
40 ent->FirstNode = NULL;
41 ent->CleanUpNode = CleanUpNode;
44 SHORTLOCK( &glVFS_InodeCache );
45 ent->Next = gVFS_InodeCache;
46 gVFS_InodeCache = ent;
47 SHORTREL( &glVFS_InodeCache );
53 * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
54 * \brief Gets a node from the cache
56 tVFS_Node *Inode_GetCache(tInodeCache *Cache, Uint64 Inode)
60 if(Inode > Cache->MaxCached) return NULL;
63 for( ent = Cache->FirstNode; ent; ent = ent->Next )
65 if(ent->Node.Inode < Inode) continue;
66 if(ent->Node.Inode > Inode) return NULL;
67 ent->Node.ReferenceCount ++;
71 return NULL; // Should never be reached
75 * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
77 tVFS_Node *Inode_CacheNode(tInodeCache *Handle, tVFS_Node *Node)
79 return Inode_CacheNodeEx(Handle, Node, sizeof(*Node));
82 tVFS_Node *Inode_CacheNodeEx(tInodeCache *Cache, tVFS_Node *Node, size_t Size)
84 tCachedInode *newEnt, *prev = NULL;
86 ASSERT(Size >= sizeof(tVFS_Node));
88 if(Node->Inode > Cache->MaxCached)
89 Cache->MaxCached = Node->Inode;
93 for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next )
95 if(ent->Node.Inode < Node->Inode) continue;
96 if(ent->Node.Inode == Node->Inode) {
97 ent->Node.ReferenceCount ++;
104 newEnt = malloc(sizeof(tCachedInode) + (Size - sizeof(tVFS_Node)));
106 memcpy(&newEnt->Node, Node, Size);
110 Cache->FirstNode = newEnt;
111 newEnt->Node.ReferenceCount = 1;
113 LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
115 return &newEnt->Node;
119 * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
120 * \brief Dereferences/Removes a cached node
122 int Inode_UncacheNode(tInodeCache *Cache, Uint64 Inode)
124 tCachedInode *ent, *prev;
126 ENTER("pHandle XInode", Cache, Inode);
128 if(Inode > Cache->MaxCached) {
135 for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next )
137 if(ent->Node.Inode < Inode) continue;
138 if(ent->Node.Inode > Inode) {
145 LOG("ent = %p", ent);
152 ent->Node.ReferenceCount --;
153 // Check if node needs to be freed
154 if(ent->Node.ReferenceCount == 0)
157 prev->Next = ent->Next;
159 Cache->FirstNode = ent->Next;
160 if(ent->Node.Inode == Cache->MaxCached)
162 if(ent != Cache->FirstNode && prev)
163 Cache->MaxCached = prev->Node.Inode;
165 Cache->MaxCached = 0;
168 if(Cache->CleanUpNode)
169 Cache->CleanUpNode(&ent->Node);
171 free(ent->Node.Data);
185 * \fn void Inode_ClearCache(int Handle)
186 * \brief Removes a cache
188 void Inode_ClearCache(tInodeCache *Cache)
190 tInodeCache *prev = NULL;
191 tCachedInode *ent, *next;
194 for( prev = (void*)&gVFS_InodeCache; prev && prev->Next != Cache; prev = prev->Next )
202 for( ent = Cache->FirstNode; ent; ent = next )
205 ent->Node.ReferenceCount = 1;
207 // Usually has the side-effect of freeing this node
208 // TODO: Ensure that node is freed
209 if(ent->Node.Type && ent->Node.Type->Close)
210 ent->Node.Type->Close( &ent->Node );
217 gVFS_InodeCache = Cache->Next;
219 prev->Next = Cache->Next;