Sorting source tree a bit
[tpg/acess2.git] / KernelLand / Kernel / vfs / nodecache.c
diff --git a/KernelLand/Kernel/vfs/nodecache.c b/KernelLand/Kernel/vfs/nodecache.c
new file mode 100644 (file)
index 0000000..d2796c1
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * AcessMicro VFS
+ * - File IO Passthru's
+ */
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === TYPES ===
+typedef struct sCachedInode {
+       struct sCachedInode     *Next;
+       tVFS_Node       Node;
+} tCachedInode;
+typedef struct sInodeCache {
+       struct sInodeCache      *Next;
+        int    Handle;
+       tCachedInode    *FirstNode;     // Sorted List
+       Uint64  MaxCached;              // Speeds up Searching
+} tInodeCache;
+
+// === PROTOTYPES ===
+tInodeCache    *Inode_int_GetFSCache(int Handle);
+
+// === GLOBALS ===
+ int   gVFS_NextInodeHandle = 1;
+tShortSpinlock glVFS_InodeCache;
+tInodeCache    *gVFS_InodeCache = NULL;
+
+// === CODE ===
+/**
+ * \fn int Inode_GetHandle()
+ */
+int Inode_GetHandle()
+{
+       tInodeCache     *ent;
+       
+       ent = malloc( sizeof(tInodeCache) );
+       ent->MaxCached = 0;
+       ent->Handle = gVFS_NextInodeHandle++;
+       ent->Next = NULL;       ent->FirstNode = NULL;
+       
+       // Add to list
+       SHORTLOCK( &glVFS_InodeCache );
+       ent->Next = gVFS_InodeCache;
+       gVFS_InodeCache = ent;
+       SHORTREL( &glVFS_InodeCache );
+       
+       return gVFS_NextInodeHandle-1;
+}
+
+/**
+ * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+ * \brief Gets a node from the cache
+ */
+tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+{
+       tInodeCache     *cache;
+       tCachedInode    *ent;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return NULL;
+       
+       if(Inode > cache->MaxCached)    return NULL;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       for( ; ent; ent = ent->Next )
+       {
+               if(ent->Node.Inode < Inode)     continue;
+               if(ent->Node.Inode > Inode)     return NULL;
+               ent->Node.ReferenceCount ++;
+               return &ent->Node;
+       }
+       
+       return NULL;    // Should never be reached
+}
+
+/**
+ * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+ */
+tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+{
+       tInodeCache     *cache;
+       tCachedInode    *newEnt, *ent, *prev;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return NULL;
+       
+       if(Node->Inode > cache->MaxCached)
+               cache->MaxCached = Node->Inode;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       prev = (tCachedInode*) &cache->FirstNode;
+       for( ; ent; prev = ent, ent = ent->Next )
+       {
+               if(ent->Node.Inode < Node->Inode)       continue;
+               if(ent->Node.Inode == Node->Inode) {
+                       ent->Node.ReferenceCount ++;
+                       return &ent->Node;
+               }
+               break;
+       }
+       
+       // Create new entity
+       newEnt = malloc(sizeof(tCachedInode));
+       newEnt->Next = ent;
+       memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
+       prev->Next = newEnt;
+               
+       return &newEnt->Node;
+}
+
+/**
+ * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \brief Dereferences/Removes a cached node
+ */
+void Inode_UncacheNode(int Handle, Uint64 Inode)
+{
+       tInodeCache     *cache;
+       tCachedInode    *ent, *prev;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return ;
+       
+       if(Inode > cache->MaxCached)    return ;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       prev = (tCachedInode*) &cache->FirstNode;       // Special case removal
+       for( ; ent; prev = ent, ent = ent->Next )
+       {
+               if(ent->Node.Inode < Inode)     continue;
+               if(ent->Node.Inode > Inode)     return;
+               ent->Node.ReferenceCount --;
+               // Check if node needs to be freed
+               if(ent->Node.ReferenceCount == 0)
+               {
+                       prev->Next = ent->Next;
+                       if(ent->Node.Inode == cache->MaxCached)
+                       {
+                               if(ent != cache->FirstNode)
+                                       cache->MaxCached = prev->Node.Inode;
+                               else
+                                       cache->MaxCached = 0;
+                       }
+                               
+                       free(ent);
+               }
+               return ;
+       }
+       
+       return ;
+}
+
+/**
+ * \fn void Inode_ClearCache(int Handle)
+ * \brief Removes a cache
+ */
+void Inode_ClearCache(int Handle)
+{
+       tInodeCache     *cache;
+       tInodeCache     *prev = NULL;
+       tCachedInode    *ent, *next;
+       
+       // Find the cache
+       for(
+               cache = gVFS_InodeCache;
+               cache && cache->Handle < Handle;
+               prev = cache, cache = cache->Next
+               );
+       if(!cache || cache->Handle != Handle)   return;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       while( ent )
+       {
+               ent->Node.ReferenceCount = 1;
+               next = ent->Next;
+               
+               if(ent->Node.Type && ent->Node.Type->Close)
+                       ent->Node.Type->Close( &ent->Node );
+               free(ent);
+               
+               ent = next;
+       }
+       
+       // Free Cache
+       if(prev == NULL)
+               gVFS_InodeCache = cache->Next;
+       else
+               prev->Next = cache->Next;
+       free(cache);
+}
+
+/**
+ * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
+ * \brief Gets a cache given it's handle
+ */
+tInodeCache *Inode_int_GetFSCache(int Handle)
+{
+       tInodeCache     *cache = gVFS_InodeCache;
+       // Find Cache
+       for( ; cache; cache = cache->Next )
+       {
+               if(cache->Handle > Handle)      continue;
+               if(cache->Handle < Handle) {
+                       Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
+                       return NULL;
+               }
+               break;
+       }
+       if(!cache) {
+               Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
+               return NULL;
+       }
+       
+       return cache;
+}

UCC git Repository :: git.ucc.asn.au