Merge branch 'master' of git://localhost/acess2
[tpg/acess2.git] / KernelLand / Kernel / vfs / nodecache.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * vfs/nodecache.c
6  * - VFS Node Caching facility
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include "vfs.h"
11 #include "vfs_int.h"
12
13 // === TYPES ===
14 typedef struct sCachedInode {
15         struct sCachedInode     *Next;
16         tVFS_Node       Node;
17 } tCachedInode;
18 typedef struct sInodeCache {
19         struct sInodeCache      *Next;
20          int    Handle;
21         tCachedInode    *FirstNode;     // Sorted List
22         Uint64  MaxCached;              // Speeds up Searching
23 } tInodeCache;
24
25 // === PROTOTYPES ===
26 tInodeCache     *Inode_int_GetFSCache(int Handle);
27
28 // === GLOBALS ===
29  int    gVFS_NextInodeHandle = 1;
30 tShortSpinlock  glVFS_InodeCache;
31 tInodeCache     *gVFS_InodeCache = NULL;
32
33 // === CODE ===
34 /**
35  * \fn int Inode_GetHandle()
36  */
37 int Inode_GetHandle()
38 {
39         tInodeCache     *ent;
40         
41         ent = malloc( sizeof(tInodeCache) );
42         ent->MaxCached = 0;
43         ent->Handle = gVFS_NextInodeHandle++;
44         ent->Next = NULL;       ent->FirstNode = NULL;
45         
46         // Add to list
47         SHORTLOCK( &glVFS_InodeCache );
48         ent->Next = gVFS_InodeCache;
49         gVFS_InodeCache = ent;
50         SHORTREL( &glVFS_InodeCache );
51         
52         return ent->Handle;
53 }
54
55 /**
56  * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
57  * \brief Gets a node from the cache
58  */
59 tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
60 {
61         tInodeCache     *cache;
62         tCachedInode    *ent;
63         
64         cache = Inode_int_GetFSCache(Handle);
65         if(!cache)      return NULL;
66         
67         if(Inode > cache->MaxCached)    return NULL;
68         
69         // Search Cache
70         ent = cache->FirstNode;
71         for( ; ent; ent = ent->Next )
72         {
73                 if(ent->Node.Inode < Inode)     continue;
74                 if(ent->Node.Inode > Inode)     return NULL;
75                 ent->Node.ReferenceCount ++;
76                 return &ent->Node;
77         }
78         
79         return NULL;    // Should never be reached
80 }
81
82 /**
83  * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
84  */
85 tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
86 {
87         tInodeCache     *cache;
88         tCachedInode    *newEnt, *ent, *prev = NULL;
89         
90         cache = Inode_int_GetFSCache(Handle);
91         if(!cache)      return NULL;
92         
93         if(Node->Inode > cache->MaxCached)
94                 cache->MaxCached = Node->Inode;
95         
96         // Search Cache
97         ent = cache->FirstNode;
98         for( ; ent; prev = ent, ent = ent->Next )
99         {
100                 if(ent->Node.Inode < Node->Inode)       continue;
101                 if(ent->Node.Inode == Node->Inode) {
102                         ent->Node.ReferenceCount ++;
103                         return &ent->Node;
104                 }
105                 break;
106         }
107         
108         // Create new entity
109         newEnt = malloc(sizeof(tCachedInode));
110         newEnt->Next = ent;
111         memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
112         if( prev )
113                 prev->Next = newEnt;
114         else
115                 cache->FirstNode = newEnt;
116         newEnt->Node.ReferenceCount = 1;
117
118         LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
119
120         return &newEnt->Node;
121 }
122
123 /**
124  * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
125  * \brief Dereferences/Removes a cached node
126  */
127 int Inode_UncacheNode(int Handle, Uint64 Inode)
128 {
129         tInodeCache     *cache;
130         tCachedInode    *ent, *prev;
131         
132         cache = Inode_int_GetFSCache(Handle);
133         if(!cache) {
134                 Log_Notice("Inode", "Invalid cache handle %i used", Handle);
135                 return -1;
136         }
137
138         ENTER("iHandle XInode", Handle, Inode);
139
140         if(Inode > cache->MaxCached) {
141                 LEAVE('i', -1);
142                 return -1;
143         }
144         
145         // Search Cache
146         ent = cache->FirstNode;
147         prev = NULL;
148         for( ; ent; prev = ent, ent = ent->Next )
149         {
150                 if(ent->Node.Inode < Inode)     continue;
151                 if(ent->Node.Inode > Inode) {
152                         LEAVE('i', -1);
153                         return -1;
154                 }
155                 break;
156         }
157
158         LOG("ent = %p", ent);
159
160         if( !ent ) {
161                 LEAVE('i', -1);
162                 return -1;
163         }
164
165         ent->Node.ReferenceCount --;
166         // Check if node needs to be freed
167         if(ent->Node.ReferenceCount == 0)
168         {
169                 if( prev )
170                         prev->Next = ent->Next;
171                 else
172                         cache->FirstNode = ent->Next;
173                 if(ent->Node.Inode == cache->MaxCached)
174                 {
175                         if(ent != cache->FirstNode && prev)
176                                 cache->MaxCached = prev->Node.Inode;
177                         else
178                                 cache->MaxCached = 0;
179                 }
180                 
181                 if(ent->Node.Data)
182                         free(ent->Node.Data);   
183                 free(ent);
184                 LOG("Freed");
185                 LEAVE('i', 1);
186                 return 1;
187         }
188         else
189         {
190                 LEAVE('i', 0);
191                 return 0;
192         }
193 }
194
195 /**
196  * \fn void Inode_ClearCache(int Handle)
197  * \brief Removes a cache
198  */
199 void Inode_ClearCache(int Handle)
200 {
201         tInodeCache     *cache;
202         tInodeCache     *prev = NULL;
203         tCachedInode    *ent, *next;
204         
205         // Find the cache
206         for(
207                 cache = gVFS_InodeCache;
208                 cache && cache->Handle < Handle;
209                 prev = cache, cache = cache->Next
210                 );
211         if(!cache || cache->Handle != Handle)   return;
212         
213         // Search Cache
214         ent = cache->FirstNode;
215         while( ent )
216         {
217                 ent->Node.ReferenceCount = 1;
218                 next = ent->Next;
219                 
220                 if(ent->Node.Type && ent->Node.Type->Close)
221                         ent->Node.Type->Close( &ent->Node );
222                 free(ent);
223                 
224                 ent = next;
225         }
226         
227         // Free Cache
228         if(prev == NULL)
229                 gVFS_InodeCache = cache->Next;
230         else
231                 prev->Next = cache->Next;
232         free(cache);
233 }
234
235 /**
236  * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
237  * \brief Gets a cache given it's handle
238  */
239 tInodeCache *Inode_int_GetFSCache(int Handle)
240 {
241         tInodeCache     *cache = gVFS_InodeCache;
242         // Find Cache
243         for( ; cache; cache = cache->Next )
244         {
245                 if(cache->Handle > Handle)      continue;
246                 if(cache->Handle < Handle) {
247                         Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
248                         return NULL;
249                 }
250                 break;
251         }
252         if(!cache) {
253                 Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
254                 return NULL;
255         }
256         
257         return cache;
258 }

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