d2796c1b9d3420d5edb737d739bcee72867a0f63
[tpg/acess2.git] / Kernel / vfs / nodecache.c
1 /*
2  * AcessMicro VFS
3  * - File IO Passthru's
4  */
5 #include <acess.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 tShortSpinlock  glVFS_InodeCache;
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         SHORTLOCK( &glVFS_InodeCache );
44         ent->Next = gVFS_InodeCache;
45         gVFS_InodeCache = ent;
46         SHORTREL( &glVFS_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         return ;
154 }
155
156 /**
157  * \fn void Inode_ClearCache(int Handle)
158  * \brief Removes a cache
159  */
160 void Inode_ClearCache(int Handle)
161 {
162         tInodeCache     *cache;
163         tInodeCache     *prev = NULL;
164         tCachedInode    *ent, *next;
165         
166         // Find the cache
167         for(
168                 cache = gVFS_InodeCache;
169                 cache && cache->Handle < Handle;
170                 prev = cache, cache = cache->Next
171                 );
172         if(!cache || cache->Handle != Handle)   return;
173         
174         // Search Cache
175         ent = cache->FirstNode;
176         while( ent )
177         {
178                 ent->Node.ReferenceCount = 1;
179                 next = ent->Next;
180                 
181                 if(ent->Node.Type && ent->Node.Type->Close)
182                         ent->Node.Type->Close( &ent->Node );
183                 free(ent);
184                 
185                 ent = next;
186         }
187         
188         // Free Cache
189         if(prev == NULL)
190                 gVFS_InodeCache = cache->Next;
191         else
192                 prev->Next = cache->Next;
193         free(cache);
194 }
195
196 /**
197  * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
198  * \brief Gets a cache given it's handle
199  */
200 tInodeCache *Inode_int_GetFSCache(int Handle)
201 {
202         tInodeCache     *cache = gVFS_InodeCache;
203         // Find Cache
204         for( ; cache; cache = cache->Next )
205         {
206                 if(cache->Handle > Handle)      continue;
207                 if(cache->Handle < Handle) {
208                         Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
209                         return NULL;
210                 }
211                 break;
212         }
213         if(!cache) {
214                 Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
215                 return NULL;
216         }
217         
218         return cache;
219 }

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