Kernel/VFS - Update to node cache to support extra allocated data
[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         return Inode_CacheNodeEx(Handle, Node, sizeof(*Node));
88 }
89
90 tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size)
91 {
92         tInodeCache     *cache;
93         tCachedInode    *newEnt, *ent, *prev = NULL;
94
95         ASSERT(Size >= sizeof(tVFS_Node));      
96
97         cache = Inode_int_GetFSCache(Handle);
98         if(!cache)      return NULL;
99         
100         if(Node->Inode > cache->MaxCached)
101                 cache->MaxCached = Node->Inode;
102         
103         // Search Cache
104         ent = cache->FirstNode;
105         for( ; ent; prev = ent, ent = ent->Next )
106         {
107                 if(ent->Node.Inode < Node->Inode)       continue;
108                 if(ent->Node.Inode == Node->Inode) {
109                         ent->Node.ReferenceCount ++;
110                         return &ent->Node;
111                 }
112                 break;
113         }
114         
115         // Create new entity
116         newEnt = malloc(sizeof(tCachedInode) + (Size - sizeof(tVFS_Node)));
117         newEnt->Next = ent;
118         memcpy(&newEnt->Node, Node, Size);
119         if( prev )
120                 prev->Next = newEnt;
121         else
122                 cache->FirstNode = newEnt;
123         newEnt->Node.ReferenceCount = 1;
124
125         LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
126
127         return &newEnt->Node;
128 }
129
130 /**
131  * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
132  * \brief Dereferences/Removes a cached node
133  */
134 int Inode_UncacheNode(int Handle, Uint64 Inode)
135 {
136         tInodeCache     *cache;
137         tCachedInode    *ent, *prev;
138         
139         cache = Inode_int_GetFSCache(Handle);
140         if(!cache) {
141                 Log_Notice("Inode", "Invalid cache handle %i used", Handle);
142                 return -1;
143         }
144
145         ENTER("iHandle XInode", Handle, Inode);
146
147         if(Inode > cache->MaxCached) {
148                 LEAVE('i', -1);
149                 return -1;
150         }
151         
152         // Search Cache
153         ent = cache->FirstNode;
154         prev = NULL;
155         for( ; ent; prev = ent, ent = ent->Next )
156         {
157                 if(ent->Node.Inode < Inode)     continue;
158                 if(ent->Node.Inode > Inode) {
159                         LEAVE('i', -1);
160                         return -1;
161                 }
162                 break;
163         }
164
165         LOG("ent = %p", ent);
166
167         if( !ent ) {
168                 LEAVE('i', -1);
169                 return -1;
170         }
171
172         ent->Node.ReferenceCount --;
173         // Check if node needs to be freed
174         if(ent->Node.ReferenceCount == 0)
175         {
176                 if( prev )
177                         prev->Next = ent->Next;
178                 else
179                         cache->FirstNode = ent->Next;
180                 if(ent->Node.Inode == cache->MaxCached)
181                 {
182                         if(ent != cache->FirstNode && prev)
183                                 cache->MaxCached = prev->Node.Inode;
184                         else
185                                 cache->MaxCached = 0;
186                 }
187                 
188                 if(ent->Node.Data)
189                         free(ent->Node.Data);   
190                 free(ent);
191                 LOG("Freed");
192                 LEAVE('i', 1);
193                 return 1;
194         }
195         else
196         {
197                 LEAVE('i', 0);
198                 return 0;
199         }
200 }
201
202 /**
203  * \fn void Inode_ClearCache(int Handle)
204  * \brief Removes a cache
205  */
206 void Inode_ClearCache(int Handle)
207 {
208         tInodeCache     *cache;
209         tInodeCache     *prev = NULL;
210         tCachedInode    *ent, *next;
211         
212         // Find the cache
213         for(
214                 cache = gVFS_InodeCache;
215                 cache && cache->Handle < Handle;
216                 prev = cache, cache = cache->Next
217                 );
218         if(!cache || cache->Handle != Handle)   return;
219         
220         // Search Cache
221         ent = cache->FirstNode;
222         while( ent )
223         {
224                 ent->Node.ReferenceCount = 1;
225                 next = ent->Next;
226                 
227                 if(ent->Node.Type && ent->Node.Type->Close)
228                         ent->Node.Type->Close( &ent->Node );
229                 free(ent);
230                 
231                 ent = next;
232         }
233         
234         // Free Cache
235         if(prev == NULL)
236                 gVFS_InodeCache = cache->Next;
237         else
238                 prev->Next = cache->Next;
239         free(cache);
240 }
241
242 /**
243  * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
244  * \brief Gets a cache given it's handle
245  */
246 tInodeCache *Inode_int_GetFSCache(int Handle)
247 {
248         tInodeCache     *cache = gVFS_InodeCache;
249         // Find Cache
250         for( ; cache; cache = cache->Next )
251         {
252                 if(cache->Handle > Handle)      continue;
253                 if(cache->Handle < Handle) {
254                         Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
255                         return NULL;
256                 }
257                 break;
258         }
259         if(!cache) {
260                 Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
261                 return NULL;
262         }
263         
264         return cache;
265 }

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