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

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