b1b1b61cee04067b15c707726074645b3d6c817f
[tpg/acess2.git] / Kernel / vfs / nodecache.c
1 /*
2  * AcessMicro VFS
3  * - File IO Passthru's
4  */
5 #include <common.h>
6 #include "vfs.h"
7 #include "vfs_int.h"
8
9 // === TYPES ===
10 typedef struct sCachedInode {
11         struct sCachedInode     *Next;
12         tVFS_Node       Node;
13 } tCachedInode;
14 typedef struct sInodeCache {
15         struct sInodeCache      *Next;
16          int    Handle;
17         tCachedInode    *FirstNode;     // Sorted List
18         Uint64  MaxCached;              // Speeds up Searching
19 } tInodeCache;
20
21 // === PROTOTYPES ===
22 tInodeCache     *Inode_int_GetFSCache(int Handle);
23
24 // === GLOBALS ===
25  int    gVFS_NextInodeHandle = 1;
26  int    gilVFS_InodeCache = 0;
27 tInodeCache     *gVFS_InodeCache = NULL;
28
29 // === CODE ===
30 /**
31  * \fn int Inode_GetHandle()
32  */
33 int Inode_GetHandle()
34 {
35         tInodeCache     *ent;
36         
37         ent = malloc( sizeof(tInodeCache) );
38         ent->MaxCached = 0;
39         ent->Handle = gVFS_NextInodeHandle++;
40         ent->Next = NULL;       ent->FirstNode = NULL;
41         
42         // Add to list
43         LOCK( &gilVFS_InodeCache );
44         ent->Next = gVFS_InodeCache;
45         gVFS_InodeCache = ent;
46         RELEASE( &gilVFS_InodeCache );
47         
48         return gVFS_NextInodeHandle-1;
49 }
50
51 /**
52  * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
53  * \brief Gets a node from the cache
54  */
55 tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
56 {
57         tInodeCache     *cache;
58         tCachedInode    *ent;
59         
60         cache = Inode_int_GetFSCache(Handle);
61         if(!cache)      return NULL;
62         
63         if(Inode > cache->MaxCached)    return NULL;
64         
65         // Search Cache
66         ent = cache->FirstNode;
67         for( ; ent; ent = ent->Next )
68         {
69                 if(ent->Node.Inode < Inode)     continue;
70                 if(ent->Node.Inode > Inode)     return NULL;
71                 ent->Node.ReferenceCount ++;
72                 return &ent->Node;
73         }
74         
75         return NULL;    // Should never be reached
76 }
77
78 /**
79  * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
80  */
81 tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
82 {
83         tInodeCache     *cache;
84         tCachedInode    *newEnt, *ent, *prev;
85         
86         cache = Inode_int_GetFSCache(Handle);
87         if(!cache)      return NULL;
88         
89         if(Node->Inode > cache->MaxCached)
90                 cache->MaxCached = Node->Inode;
91         
92         // Search Cache
93         ent = cache->FirstNode;
94         prev = (tCachedInode*) &cache->FirstNode;
95         for( ; ent; prev = ent, ent = ent->Next )
96         {
97                 if(ent->Node.Inode < Node->Inode)       continue;
98                 if(ent->Node.Inode == Node->Inode) {
99                         ent->Node.ReferenceCount ++;
100                         return &ent->Node;
101                 }
102                 break;
103         }
104         
105         // Create new entity
106         newEnt = malloc(sizeof(tCachedInode));
107         newEnt->Next = ent;
108         memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
109         prev->Next = newEnt;
110                 
111         return &newEnt->Node;
112 }
113
114 /**
115  * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
116  * \brief Dereferences/Removes a cached node
117  */
118 void Inode_UncacheNode(int Handle, Uint64 Inode)
119 {
120         tInodeCache     *cache;
121         tCachedInode    *ent, *prev;
122         
123         cache = Inode_int_GetFSCache(Handle);
124         if(!cache)      return;
125         
126         if(Inode > cache->MaxCached)    return;
127         
128         // Search Cache
129         ent = cache->FirstNode;
130         prev = (tCachedInode*) &cache->FirstNode;       // Special case removal
131         for( ; ent; prev = ent, ent = ent->Next )
132         {
133                 if(ent->Node.Inode < Inode)     continue;
134                 if(ent->Node.Inode > Inode)     return;
135                 ent->Node.ReferenceCount --;
136                 // Check if node needs to be freed
137                 if(ent->Node.ReferenceCount == 0)
138                 {
139                         prev->Next = ent->Next;
140                         if(ent->Node.Inode == cache->MaxCached)
141                         {
142                                 if(ent != cache->FirstNode)
143                                         cache->MaxCached = prev->Node.Inode;
144                                 else
145                                         cache->MaxCached = 0;
146                         }
147                                 
148                         free(ent);
149                 }
150                 return;
151         }
152 }
153
154 /**
155  * \fn void Inode_ClearCache(int Handle)
156  * \brief Removes a cache
157  */
158 void Inode_ClearCache(int Handle)
159 {
160         tInodeCache     *cache;
161         tInodeCache     *prev = NULL;
162         tCachedInode    *ent, *next;
163         
164         // Find the cache
165         for(
166                 cache = gVFS_InodeCache;
167                 cache && cache->Handle < Handle;
168                 prev = cache, cache = cache->Next
169                 );
170         if(!cache || cache->Handle != Handle)   return;
171         
172         // Search Cache
173         ent = cache->FirstNode;
174         while( ent )
175         {
176                 ent->Node.ReferenceCount = 1;
177                 next = ent->Next;
178                 
179                 if(ent->Node.Close)
180                         ent->Node.Close( &ent->Node );
181                 free(ent);
182                 
183                 ent = next;
184         }
185         
186         // Free Cache
187         if(prev == NULL)
188                 gVFS_InodeCache = cache->Next;
189         else
190                 prev->Next = cache->Next;
191         free(cache);
192 }
193
194 /**
195  * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
196  * \brief Gets a cache given it's handle
197  */
198 tInodeCache *Inode_int_GetFSCache(int Handle)
199 {
200         tInodeCache     *cache = gVFS_InodeCache;
201         // Find Cache
202         for( ; cache; cache = cache->Next )
203         {
204                 if(cache->Handle > Handle)      continue;
205                 if(cache->Handle < Handle) {
206                         Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
207                         return NULL;
208                 }
209                 break;
210         }
211         if(!cache) {
212                 Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
213                 return NULL;
214         }
215         
216         return cache;
217 }

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