alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / rom / filesys / afs / cache.c
blob0d9a5fd4399ce2e8b165404b42da990484eca8f6
1 /*
2 Copyright © 1995-2013, 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 FreeVec(cache);
68 void clearCache(struct AFSBase *afsbase, struct BlockCache *cache) {
70 while (cache != NULL)
72 if ((cache->flags & BCF_WRITE) == 0)
74 cache->blocknum = 0;
75 cache->newness = 0;
76 cache->flags = 0;
78 else
79 showText(afsbase, "You MUST re-insert ejected volume");
80 cache = cache->next;
84 VOID flushCache
85 (struct AFSBase *afsbase, struct Volume *volume)
87 struct BlockCache *block;
89 for (block = volume->blockcache; block != NULL; block = block->next)
91 if ((block->flags & (BCF_WRITE | BCF_USED)) == BCF_WRITE)
93 writeDisk(afsbase, volume, block->blocknum, 1, block->buffer);
94 block->flags &= ~BCF_WRITE;
99 struct BlockCache *getCacheBlock
100 (struct AFSBase *afsbase, struct Volume *volume, ULONG blocknum)
102 struct BlockCache *cache;
103 struct BlockCache *bestcache=NULL;
104 BOOL found = FALSE;
106 /* Check if block is already cached, or else reuse least-recently-used buffer */
107 D(bug("[afs] getCacheBlock: getting cacheblock %lu\n",blocknum));
108 cache = volume->blockcache;
109 while ((cache != NULL) && !found)
111 if (cache->blocknum == blocknum)
113 if (!(cache->flags & BCF_USED))
115 D(bug("[afs] getCacheBlock: already cached (counter=%lu)\n",
116 cache->newness));
117 bestcache = cache;
118 found = TRUE;
120 else
122 if (blocknum != volume->rootblock)
124 /* should only occur while using setBitmap()
125 ->that's ok (see setBitmap()) */
126 D(bug("Concurrent access on block %lu!\n",blocknum));
128 else
130 bestcache = cache;
131 found = TRUE;
135 else if ((cache->flags & (BCF_USED | BCF_WRITE)) == 0)
137 if (bestcache != NULL)
139 if (bestcache->newness > cache->newness)
140 bestcache = cache;
142 else
144 bestcache = cache;
147 cache = cache->next;
150 if (bestcache != NULL)
152 if (!found)
153 bestcache->blocknum = 0;
155 /* Mark buffer as the most recently used */
156 bestcache->newness = ++volume->cachecounter;
158 /* Reset cache history if counter has overflowed */
159 if (volume->cachecounter == 0)
161 for (cache = volume->blockcache; cache != NULL; cache = cache->next)
162 cache->newness = 0;
165 else
167 /* We should only run out of cache blocks if blocks need to be
168 written, so write them and try again */
169 flushCache(afsbase, volume);
170 bestcache = getCacheBlock(afsbase, volume, blocknum);
171 if (bestcache == NULL)
172 showText(afsbase, "Oh, ohhhhh, where is all the cache gone? BUG!!!");
175 return bestcache;
178 /***************************************************************************
179 Name : getFreeCacheBlock
180 Descr.: Get a cache block to fill. The returned cache block's buffer will
181 have arbitrary contents. However, to ensure cache integrity, an
182 existing cache block for the specified block will be returned if
183 present.
184 Input : volume - the volume the block is on.
185 blocknum - the block number the cache block will be used for.
186 Output: an unfilled cache block for the specified block.
187 ***************************************************************************/
188 struct BlockCache *getFreeCacheBlock
189 (struct AFSBase *afsbase, struct Volume *volume, ULONG blocknum)
191 struct BlockCache *cache;
193 cache = getCacheBlock(afsbase, volume, blocknum);
194 cache->blocknum = blocknum;
195 cache->newness = 0;
196 return cache;
199 void checkCache(struct AFSBase *afsbase, struct Volume *volume) {
200 struct BlockCache *bc;
202 bc = volume->blockcache;
203 while (bc != NULL)
205 if (((bc->flags & BCF_USED) != 0) && (bc->blocknum != volume->rootblock))
207 showText(afsbase, "Unreleased block: %lu!", bc->blocknum);
209 bc = bc->next;
213 #ifdef DEBUG
214 void umpBlock(struct AFSBase *afsbase, struct BlockCache *block) {
215 UWORD i,j;
217 for (i=0; i<=31; i++) {
218 D(bug("0x%x: ",i*16));
219 for (j=0; j<=3; j++)
220 D(bug(" %x", OS_BE2LONG(block->buffer[i*4+j])));
221 D(bug("\n"));
224 #endif
226 struct BlockCache *getBlock
227 (struct AFSBase *afsbase, struct Volume *volume, ULONG blocknum)
229 struct BlockCache *blockbuffer;
231 blockbuffer = getCacheBlock(afsbase, volume, blocknum);
232 if (blockbuffer != NULL)
234 if (blockbuffer->blocknum == 0)
236 blockbuffer->blocknum = blocknum;
237 if (readDisk(afsbase, volume, blocknum, 1, blockbuffer->buffer) != 0)
239 blockbuffer = NULL;
243 D(bug("[afs] getBlock: using cache block with address 0x%p\n", blockbuffer));
244 return blockbuffer;
247 LONG writeBlock
249 struct AFSBase *afsbase,
250 struct Volume *volume,
251 struct BlockCache *blockbuffer,
252 LONG checksumoffset
255 /* Update checksum if requested by caller */
256 if(checksumoffset != -1)
258 blockbuffer->buffer[checksumoffset] = 0;
259 blockbuffer->buffer[checksumoffset] =
260 OS_LONG2BE(0 - calcChkSum(volume->SizeBlock,blockbuffer->buffer));
263 /* Ensure bitmap isn't marked valid while there are dirty blocks in the cache */
264 if (blockbuffer->blocknum == volume->rootblock)
265 flushCache(afsbase, volume);
267 /* Write block to disk */
268 writeDisk(afsbase, volume, blockbuffer->blocknum, 1, blockbuffer->buffer);
269 blockbuffer->flags &= ~BCF_WRITE;
270 return DOSTRUE;
273 VOID writeBlockDeferred
275 struct AFSBase *afsbase,
276 struct Volume *volume,
277 struct BlockCache *blockbuffer,
278 LONG checksumoffset
281 /* Update checksum if requested by caller */
282 if(checksumoffset != -1)
284 blockbuffer->buffer[checksumoffset] = 0;
285 blockbuffer->buffer[checksumoffset] =
286 OS_LONG2BE(0 - calcChkSum(volume->SizeBlock,blockbuffer->buffer));
289 /* Mark block as needing to be written when the time comes */
290 blockbuffer->flags |= BCF_WRITE;
291 return;