VFS - Fixed unmount issues and added filesystem autodetection
[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 = NULL;
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                 if( prev )
168                         prev->Next = ent->Next;
169                 else
170                         cache->FirstNode = ent->Next;
171                 if(ent->Node.Inode == cache->MaxCached)
172                 {
173                         if(ent != cache->FirstNode && prev)
174                                 cache->MaxCached = prev->Node.Inode;
175                         else
176                                 cache->MaxCached = 0;
177                 }
178                 
179                 if(ent->Node.Data)
180                         free(ent->Node.Data);   
181                 free(ent);
182                 LOG("Freed");
183                 LEAVE('i', 1);
184                 return 1;
185         }
186         else
187         {
188                 LEAVE('i', 0);
189                 return 0;
190         }
191 }
192
193 /**
194  * \fn void Inode_ClearCache(int Handle)
195  * \brief Removes a cache
196  */
197 void Inode_ClearCache(int Handle)
198 {
199         tInodeCache     *cache;
200         tInodeCache     *prev = NULL;
201         tCachedInode    *ent, *next;
202         
203         // Find the cache
204         for(
205                 cache = gVFS_InodeCache;
206                 cache && cache->Handle < Handle;
207                 prev = cache, cache = cache->Next
208                 );
209         if(!cache || cache->Handle != Handle)   return;
210         
211         // Search Cache
212         ent = cache->FirstNode;
213         while( ent )
214         {
215                 ent->Node.ReferenceCount = 1;
216                 next = ent->Next;
217                 
218                 if(ent->Node.Type && ent->Node.Type->Close)
219                         ent->Node.Type->Close( &ent->Node );
220                 free(ent);
221                 
222                 ent = next;
223         }
224         
225         // Free Cache
226         if(prev == NULL)
227                 gVFS_InodeCache = cache->Next;
228         else
229                 prev->Next = cache->Next;
230         free(cache);
231 }
232
233 /**
234  * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
235  * \brief Gets a cache given it's handle
236  */
237 tInodeCache *Inode_int_GetFSCache(int Handle)
238 {
239         tInodeCache     *cache = gVFS_InodeCache;
240         // Find Cache
241         for( ; cache; cache = cache->Next )
242         {
243                 if(cache->Handle > Handle)      continue;
244                 if(cache->Handle < Handle) {
245                         Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
246                         return NULL;
247                 }
248                 break;
249         }
250         if(!cache) {
251                 Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
252                 return NULL;
253         }
254         
255         return cache;
256 }

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