Minor fixes to comments.
[AROS.git] / rom / filesys / afs / cache.c
blobae7be324dea5cdcaaf96a05765e51675513046b0
1 /*
2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #undef DEBUG
7 #define DEBUG 0
8 #if defined(__AROS__)
9 #include <aros/debug.h>
10 #endif
12 #include "os.h"
13 #include "cache.h"
14 #include "checksums.h"
15 #include "error.h"
16 #include "afsblocks.h"
17 #include "baseredef.h"
19 /********************************************************
20 Name : initCache
21 Descr.: initializes block cache for a volume
22 Input : volume - the volume to initializes cache for
23 numBuffers - number of buffers for cache
24 Output: first buffer (main cache pointer)
25 *********************************************************/
26 struct BlockCache *initCache
28 struct AFSBase *afsbase,
29 struct Volume *volume,
30 ULONG numBuffers
33 struct BlockCache *head;
34 struct BlockCache *cache;
35 ULONG i;
37 head = AllocVec
39 numBuffers*(sizeof(struct BlockCache)+BLOCK_SIZE(volume)),
40 MEMF_PUBLIC | MEMF_CLEAR
42 if (head != NULL)
44 cache = head;
45 for (i=0; i<(numBuffers-1); i++)
47 cache->buffer = (ULONG *)((char *)cache+sizeof(struct BlockCache));
48 cache->next =
49 (struct BlockCache *)((char *)cache->buffer+BLOCK_SIZE(volume));
50 cache = cache->next;
52 cache->buffer = (ULONG *)((char *)cache+sizeof(struct BlockCache));
53 cache->next = NULL;
55 D(bug
57 "initCache: my Mem is 0x%p size 0x%lx\n",
58 head,
59 numBuffers*(sizeof(struct BlockCache)+BLOCK_SIZE(volume))
60 ));
61 return head;
64 void freeCache(struct AFSBase *afsbase, struct BlockCache *cache) {
65 if (cache != NULL)
66 FreeVec(cache);
69 void clearCache(struct AFSBase *afsbase, struct BlockCache *cache) {
71 while (cache != NULL)
73 if ((cache->flags & BCF_WRITE) == 0)
75 cache->blocknum = 0;
76 cache->newness = 0;
77 cache->flags = 0;
79 else
80 showText(afsbase, "You MUST re-insert ejected volume");
81 cache = cache->next;
85 VOID flushCache
86 (struct AFSBase *afsbase, struct Volume *volume)
88 struct BlockCache *block;
90 for (block = volume->blockcache; block != NULL; block = block->next)
92 if ((block->flags & (BCF_WRITE | BCF_USED)) == BCF_WRITE)
94 writeDisk(afsbase, volume, block->blocknum, 1, block->buffer);
95 block->flags &= ~BCF_WRITE;
100 struct BlockCache *getCacheBlock
101 (struct AFSBase *afsbase, struct Volume *volume, ULONG blocknum)
103 struct BlockCache *cache;
104 struct BlockCache *bestcache=NULL;
105 BOOL found = FALSE;
107 /* Check if block is already cached, or else reuse least-recently-used buffer */
108 D(bug("[afs] getCacheBlock: getting cacheblock %lu\n",blocknum));
109 cache = volume->blockcache;
110 while ((cache != NULL) && !found)
112 if (cache->blocknum == blocknum)
114 if (!(cache->flags & BCF_USED))
116 D(bug("[afs] getCacheBlock: already cached (counter=%lu)\n",
117 cache->newness));
118 bestcache = cache;
119 found = TRUE;
121 else
123 if (blocknum != volume->rootblock)
125 /* should only occur while using setBitmap()
126 ->that's ok (see setBitmap()) */
127 D(bug("Concurrent access on block %lu!\n",blocknum));
129 else
131 bestcache = cache;
132 found = TRUE;
136 else if ((cache->flags & (BCF_USED | BCF_WRITE)) == 0)
138 if (bestcache != NULL)
140 if (bestcache->newness > cache->newness)
141 bestcache = cache;
143 else
145 bestcache = cache;
148 cache = cache->next;
151 if (bestcache != NULL)
153 if (!found)
154 bestcache->blocknum = 0;
156 /* Mark buffer as the most recently used */
157 bestcache->newness = ++volume->cachecounter;
159 /* Reset cache history if counter has overflowed */
160 if (volume->cachecounter == 0)
162 for (cache = volume->blockcache; cache != NULL; cache = cache->next)
163 cache->newness = 0;
166 else
168 /* We should only run out of cache blocks if blocks need to be
169 written, so write them and try again */
170 flushCache(afsbase, volume);
171 bestcache = getCacheBlock(afsbase, volume, blocknum);
172 if (bestcache == NULL)
173 showText(afsbase, "Oh, ohhhhh, where is all the cache gone? BUG!!!");
176 return bestcache;
179 /***************************************************************************
180 Name : getFreeCacheBlock
181 Descr.: Get a cache block to fill. The returned cache block's buffer will
182 have arbitrary contents. However, to ensure cache integrity, an
183 existing cache block for the specified block will be returned if
184 present.
185 Input : volume - the volume the block is on.
186 blocknum - the block number the cache block will be used for.
187 Output: an unfilled cache block for the specified block.
188 ***************************************************************************/
189 struct BlockCache *getFreeCacheBlock
190 (struct AFSBase *afsbase, struct Volume *volume, ULONG blocknum)
192 struct BlockCache *cache;
194 cache = getCacheBlock(afsbase, volume, blocknum);
195 cache->blocknum = blocknum;
196 cache->newness = 0;
197 return cache;
200 void checkCache(struct AFSBase *afsbase, struct Volume *volume) {
201 struct BlockCache *bc;
203 bc = volume->blockcache;
204 while (bc != NULL)
206 if (((bc->flags & BCF_USED) != 0) && (bc->blocknum != volume->rootblock))
208 showText(afsbase, "Unreleased block: %lu!", bc->blocknum);
210 bc = bc->next;
214 #ifdef DEBUG
215 void umpBlock(struct AFSBase *afsbase, struct BlockCache *block) {
216 UWORD i,j;
218 for (i=0; i<=31; i++) {
219 D(bug("0x%x: ",i*16));
220 for (j=0; j<=3; j++)
221 D(bug(" %x", OS_BE2LONG(block->buffer[i*4+j])));
222 D(bug("\n"));
225 #endif
227 struct BlockCache *getBlock
228 (struct AFSBase *afsbase, struct Volume *volume, ULONG blocknum)
230 struct BlockCache *blockbuffer;
232 blockbuffer = getCacheBlock(afsbase, volume, blocknum);
233 if (blockbuffer != NULL)
235 if (blockbuffer->blocknum == 0)
237 blockbuffer->blocknum = blocknum;
238 if (readDisk(afsbase, volume, blocknum, 1, blockbuffer->buffer) != 0)
240 blockbuffer = NULL;
244 D(bug("[afs] getBlock: using cache block with address 0x%p\n", blockbuffer));
245 return blockbuffer;
248 LONG writeBlock
250 struct AFSBase *afsbase,
251 struct Volume *volume,
252 struct BlockCache *blockbuffer,
253 LONG checksumoffset
256 /* Update checksum if requested by caller */
257 if(checksumoffset != -1)
259 blockbuffer->buffer[checksumoffset] = 0;
260 blockbuffer->buffer[checksumoffset] =
261 OS_LONG2BE(0 - calcChkSum(volume->SizeBlock,blockbuffer->buffer));
264 /* Ensure bitmap isn't marked valid while there are dirty blocks in the cache */
265 if (blockbuffer->blocknum == volume->rootblock)
266 flushCache(afsbase, volume);
268 /* Write block to disk */
269 writeDisk(afsbase, volume, blockbuffer->blocknum, 1, blockbuffer->buffer);
270 blockbuffer->flags &= ~BCF_WRITE;
271 return DOSTRUE;
274 VOID writeBlockDeferred
276 struct AFSBase *afsbase,
277 struct Volume *volume,
278 struct BlockCache *blockbuffer,
279 LONG checksumoffset
282 /* Update checksum if requested by caller */
283 if(checksumoffset != -1)
285 blockbuffer->buffer[checksumoffset] = 0;
286 blockbuffer->buffer[checksumoffset] =
287 OS_LONG2BE(0 - calcChkSum(volume->SizeBlock,blockbuffer->buffer));
290 /* Mark block as needing to be written when the time comes */
291 blockbuffer->flags |= BCF_WRITE;
292 return;