Usermode/libc - Fix strchr and strrchr behavior
[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 struct sInodeCache
19 {
20         struct sInodeCache      *Next;
21         tInode_CleanUpNode      CleanUpNode;
22         tCachedInode    *FirstNode;     // Sorted List
23         Uint64  MaxCached;              // Speeds up Searching
24 };
25
26 // === GLOBALS ===
27 tShortSpinlock  glVFS_InodeCache;
28 tInodeCache     *gVFS_InodeCache = NULL;
29
30 // === CODE ===
31
32 // Create a new inode cache
33 tInodeCache *Inode_GetHandle(tInode_CleanUpNode CleanUpNode)
34 {
35         tInodeCache     *ent;
36         
37         ent = malloc( sizeof(tInodeCache) );
38         ent->MaxCached = 0;
39         ent->Next = NULL;
40         ent->FirstNode = NULL;
41         ent->CleanUpNode = CleanUpNode;
42         
43         // Add to list
44         SHORTLOCK( &glVFS_InodeCache );
45         ent->Next = gVFS_InodeCache;
46         gVFS_InodeCache = ent;
47         SHORTREL( &glVFS_InodeCache );
48         
49         return ent;
50 }
51
52 /**
53  * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
54  * \brief Gets a node from the cache
55  */
56 tVFS_Node *Inode_GetCache(tInodeCache *Cache, Uint64 Inode)
57 {
58         tCachedInode    *ent;
59         
60         if(Inode > Cache->MaxCached)    return NULL;
61         
62         // Search Cache
63         for( ent = Cache->FirstNode; ent; ent = ent->Next )
64         {
65                 if(ent->Node.Inode < Inode)     continue;
66                 if(ent->Node.Inode > Inode)     return NULL;
67                 ent->Node.ReferenceCount ++;
68                 return &ent->Node;
69         }
70         
71         return NULL;    // Should never be reached
72 }
73
74 /**
75  * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
76  */
77 tVFS_Node *Inode_CacheNode(tInodeCache *Handle, tVFS_Node *Node)
78 {
79         return Inode_CacheNodeEx(Handle, Node, sizeof(*Node));
80 }
81
82 tVFS_Node *Inode_CacheNodeEx(tInodeCache *Cache, tVFS_Node *Node, size_t Size)
83 {
84         tCachedInode    *newEnt, *prev = NULL;
85
86         ASSERT(Size >= sizeof(tVFS_Node));      
87         
88         if(Node->Inode > Cache->MaxCached)
89                 Cache->MaxCached = Node->Inode;
90         
91         // Search Cache
92         tCachedInode *ent;
93         for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next )
94         {
95                 if(ent->Node.Inode < Node->Inode)       continue;
96                 if(ent->Node.Inode == Node->Inode) {
97                         ent->Node.ReferenceCount ++;
98                         return &ent->Node;
99                 }
100                 break;
101         }
102         
103         // Create new entity
104         newEnt = malloc(sizeof(tCachedInode) + (Size - sizeof(tVFS_Node)));
105         newEnt->Next = ent;
106         memcpy(&newEnt->Node, Node, Size);
107         if( prev )
108                 prev->Next = newEnt;
109         else
110                 Cache->FirstNode = newEnt;
111         newEnt->Node.ReferenceCount = 1;
112
113         LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
114
115         return &newEnt->Node;
116 }
117
118 /**
119  * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
120  * \brief Dereferences/Removes a cached node
121  */
122 int Inode_UncacheNode(tInodeCache *Cache, Uint64 Inode)
123 {
124         tCachedInode    *ent, *prev;
125         
126         ENTER("pHandle XInode", Cache, Inode);
127
128         if(Inode > Cache->MaxCached) {
129                 LEAVE('i', -1);
130                 return -1;
131         }
132         
133         // Search Cache
134         prev = NULL;
135         for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next )
136         {
137                 if(ent->Node.Inode < Inode)     continue;
138                 if(ent->Node.Inode > Inode) {
139                         LEAVE('i', -1);
140                         return -1;
141                 }
142                 break;
143         }
144
145         LOG("ent = %p", ent);
146
147         if( !ent ) {
148                 LEAVE('i', -1);
149                 return -1;
150         }
151
152         ent->Node.ReferenceCount --;
153         // Check if node needs to be freed
154         if(ent->Node.ReferenceCount == 0)
155         {
156                 if( prev )
157                         prev->Next = ent->Next;
158                 else
159                         Cache->FirstNode = ent->Next;
160                 if(ent->Node.Inode == Cache->MaxCached)
161                 {
162                         if(ent != Cache->FirstNode && prev)
163                                 Cache->MaxCached = prev->Node.Inode;
164                         else
165                                 Cache->MaxCached = 0;
166                 }
167         
168                 if(Cache->CleanUpNode)
169                         Cache->CleanUpNode(&ent->Node);
170                 if(ent->Node.Data)
171                         free(ent->Node.Data);   
172                 free(ent);
173                 LOG("Freed");
174                 LEAVE('i', 1);
175                 return 1;
176         }
177         else
178         {
179                 LEAVE('i', 0);
180                 return 0;
181         }
182 }
183
184 /**
185  * \fn void Inode_ClearCache(int Handle)
186  * \brief Removes a cache
187  */
188 void Inode_ClearCache(tInodeCache *Cache)
189 {
190         tInodeCache     *prev = NULL;
191         tCachedInode    *ent, *next;
192         
193         // Find the cache
194         for( prev = (void*)&gVFS_InodeCache; prev && prev->Next != Cache; prev = prev->Next )
195                 ;
196         if( !prev ) {
197                 // Oops?
198                 return;
199         }
200         
201         // Search Cache
202         for( ent = Cache->FirstNode; ent; ent = next )
203         {
204                 next = ent->Next;
205                 ent->Node.ReferenceCount = 1;
206                 
207                 // Usually has the side-effect of freeing this node
208                 // TODO: Ensure that node is freed
209                 if(ent->Node.Type && ent->Node.Type->Close)
210                         ent->Node.Type->Close( &ent->Node );
211                 else
212                         free(ent);
213         }
214         
215         // Free Cache
216         if(prev == NULL)
217                 gVFS_InodeCache = Cache->Next;
218         else
219                 prev->Next = Cache->Next;
220         free(Cache);
221 }
222

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