alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / rom / filesys / SFS / FS / bitmap.c
blobd7e86781dbe95be94b923070a8d7ad5b5f80f91d
1 #include "asmsupport.h"
3 #include <clib/macros.h>
4 #include <dos/dos.h>
5 #include <exec/types.h>
6 #include <proto/exec.h>
8 #include "bitmap.h"
9 #include "cachebuffers_protos.h"
10 #include "debug.h"
11 #include "objects.h"
12 #include "transactions_protos.h"
13 #include "req_protos.h"
14 #include "globals.h"
16 extern LONG readcachebuffercheck(struct CacheBuffer **,ULONG,ULONG);
17 extern void setchecksum(struct CacheBuffer *);
19 LONG getfreeblocks(ULONG *returned_freeblocks) {
20 struct CacheBuffer *cb;
21 LONG errorcode;
23 if((errorcode=readcachebuffercheck(&cb,globals->block_root,OBJECTCONTAINER_ID))==0) {
24 struct fsRootInfo *ri=(struct fsRootInfo *)((UBYTE *)cb->data+globals->bytes_block-sizeof(struct fsRootInfo));
26 *returned_freeblocks=BE2L(ri->be_freeblocks);
29 return(errorcode);
34 LONG getusedblocks(ULONG *returned_usedblocks) {
35 ULONG freeblocks;
36 LONG errorcode;
38 if((errorcode=getfreeblocks(&freeblocks))==0) {
39 *returned_usedblocks=globals->blocks_total-globals->blocks_reserved_start-globals->blocks_reserved_end-freeblocks;
42 return(errorcode);
47 LONG setfreeblocks(ULONG freeblocks) {
48 struct CacheBuffer *cb;
49 LONG errorcode;
51 if((errorcode=readcachebuffercheck(&cb,globals->block_root,OBJECTCONTAINER_ID))==0) {
52 struct fsRootInfo *ri=(struct fsRootInfo *)((UBYTE *)cb->data+globals->bytes_block-sizeof(struct fsRootInfo));
54 preparecachebuffer(cb);
56 ri->be_freeblocks=L2BE(freeblocks);
58 errorcode=storecachebuffer(cb);
61 return(errorcode);
66 static BOOL enoughspace(ULONG blocks) {
67 ULONG blocksfree;
69 if(getfreeblocks(&blocksfree)!=0 || blocksfree-transactionspace() < blocks+ALWAYSFREE) {
70 return(FALSE);
73 return(TRUE);
77 LONG availablespace(BLCK block,ULONG maxneeded);
80 LONG markspace(BLCK block,ULONG blocks) {
81 ULONG freeblocks;
82 LONG errorcode;
84 _XDEBUG((DEBUG_BITMAP,"markspace: Marking %ld blocks from block %ld\n",blocks,block));
86 if((availablespace(block, blocks))<blocks) {
87 req_unusual("Attempted to mark %ld blocks from block %ld,\n but some of them were already full.", blocks, block);
88 return(-1);
91 if((errorcode=getfreeblocks(&freeblocks))==0) {
92 if((errorcode=setfreeblocks(freeblocks-blocks))==0) {
93 struct CacheBuffer *cb;
94 ULONG skipblocks=block/globals->blocks_inbitmap;
95 ULONG longs=(globals->bytes_block-sizeof(struct fsBitmap))>>2;
96 ULONG bitmapblock;
97 // ULONG newrovingptr=block+blocks;
99 // blocks_useddiff+=blocks;
101 block-=skipblocks*globals->blocks_inbitmap;
102 bitmapblock=globals->block_bitmapbase+skipblocks;
104 /* /block/ is bitoffset in the /bitmapblock/ */
106 while(blocks>0) {
107 if((errorcode=readcachebuffercheck(&cb,bitmapblock++,BITMAP_ID))==0) {
108 struct fsBitmap *b;
110 preparecachebuffer(cb);
112 b=cb->data;
114 blocks-=bmclr(b->bitmap,longs,block,blocks);
115 block=0;
117 if((errorcode=storecachebuffer(cb))!=0) {
118 return(errorcode);
121 else {
122 return(errorcode);
126 // block_rovingblockptr=newrovingptr;
127 // if(block_rovingblockptr>=blocks_total) {
128 // block_rovingblockptr=0;
129 // }
133 return(errorcode);
138 LONG freespace(BLCK block,ULONG blocks) {
139 ULONG freeblocks;
140 LONG errorcode;
142 _XDEBUG((DEBUG_BITMAP,"freespace: Freeing %ld blocks from block %ld\n",blocks,block));
144 if((errorcode=getfreeblocks(&freeblocks))==0) {
145 if((errorcode=setfreeblocks(freeblocks+blocks))==0) {
146 struct CacheBuffer *cb;
147 ULONG skipblocks=block/globals->blocks_inbitmap;
148 ULONG longs=(globals->bytes_block-sizeof(struct fsBitmap))>>2;
149 ULONG bitmapblock;
151 // blocks_useddiff-=blocks;
153 block-=skipblocks*globals->blocks_inbitmap;
154 bitmapblock=globals->block_bitmapbase+skipblocks;
156 /* /block/ is bitoffset in the /bitmapblock/ */
158 while(blocks>0) {
159 if((errorcode=readcachebuffercheck(&cb,bitmapblock++,BITMAP_ID))==0) {
160 struct fsBitmap *b;
162 preparecachebuffer(cb);
164 b=cb->data;
166 blocks-=bmset(b->bitmap,longs,block,blocks);
167 block=0;
169 if((errorcode=storecachebuffer(cb))!=0) {
170 return(errorcode);
173 else {
174 return(errorcode);
180 return(errorcode);
186 LONG extractspace(UBYTE *dest, BLCK block, ULONG blocks) {
187 ULONG skipblocks=block/globals->blocks_inbitmap;
188 ULONG byteoffset=(block-(skipblocks*globals->blocks_inbitmap))>>3;
189 ULONG bytesinbitmap=globals->blocks_inbitmap>>3;
190 ULONG bytes=(blocks+7)>>3;
191 ULONG bitmapblock=globals->block_bitmapbase+skipblocks;
193 if((block & 0x07)!=0 || block>=globals->blocks_total || block+blocks>globals->blocks_total) {
194 return(ERROR_BAD_NUMBER);
197 /* /block/ is bitoffset in the /bitmapblock/ */
199 while(bytes>0) {
200 struct CacheBuffer *cb;
201 LONG errorcode;
203 if((errorcode=readcachebuffercheck(&cb, bitmapblock++, BITMAP_ID))==0) {
204 struct fsBitmap *b;
205 ULONG bytestocopy=bytesinbitmap-byteoffset;
207 if(bytestocopy>bytes) {
208 bytestocopy=bytes;
211 b=cb->data;
213 CopyMem((UBYTE *)b->bitmap + byteoffset, dest, bytestocopy);
215 bytes-=bytestocopy;
216 dest+=bytestocopy;
217 byteoffset=0;
219 else {
220 return(errorcode);
224 return(0);
229 LONG availablespace(BLCK block,ULONG maxneeded) {
230 struct CacheBuffer *cb;
231 struct fsBitmap *b;
232 ULONG longs=globals->blocks_inbitmap>>5;
233 ULONG maxbitmapblock=globals->block_bitmapbase+globals->blocks_bitmap;
234 LONG blocksfound=0;
235 ULONG bitstart;
236 LONG bitend;
237 LONG errorcode=0;
238 BLCK nextblock=globals->block_bitmapbase+block/globals->blocks_inbitmap;
240 /* Determines the amount of free blocks starting from block /block/.
241 If there are no blocks found or if there was an error -1 is returned,
242 otherwise this function will count the number of free blocks until
243 an allocated block is encountered or until maxneeded has been
244 exceeded. */
246 bitstart=block % globals->blocks_inbitmap;
248 while(nextblock<maxbitmapblock && (errorcode=readcachebuffercheck(&cb,nextblock++,BITMAP_ID))==0) {
249 b=cb->data;
251 if((bitend=bmffz(b->bitmap,longs,bitstart))<(32*longs)) {
252 blocksfound+=bitend-bitstart;
253 return(blocksfound);
256 blocksfound+=globals->blocks_inbitmap-bitstart;
257 if(blocksfound>=maxneeded) {
258 return(blocksfound);
261 bitstart=0;
264 if(errorcode!=0) {
265 return(-1);
268 return(blocksfound);
273 LONG allocatedspace(BLCK block,ULONG maxneeded) {
274 struct CacheBuffer *cb;
275 struct fsBitmap *b;
276 ULONG longs=globals->blocks_inbitmap>>5;
277 ULONG maxbitmapblock=globals->block_bitmapbase+globals->blocks_bitmap;
278 LONG blocksfound=0;
279 ULONG bitstart;
280 LONG bitend;
281 LONG errorcode=0;
282 BLCK nextblock=globals->block_bitmapbase+block/globals->blocks_inbitmap;
284 /* Determines the amount of free blocks starting from block /block/.
285 If there are no blocks found or if there was an error -1 is returned,
286 otherwise this function will count the number of free blocks until
287 an allocated block is encountered or until maxneeded has been
288 exceeded. */
290 bitstart=block % globals->blocks_inbitmap;
292 while(nextblock<maxbitmapblock && (errorcode=readcachebuffercheck(&cb,nextblock++,BITMAP_ID))==0) {
293 b=cb->data;
295 if((bitend=bmffo(b->bitmap,longs,bitstart))<(32*longs)) {
296 blocksfound+=bitend-bitstart;
297 return(blocksfound);
300 blocksfound+=globals->blocks_inbitmap-bitstart;
301 if(blocksfound>=maxneeded) {
302 return(blocksfound);
305 bitstart=0;
308 if(errorcode!=0) {
309 return(-1);
312 return(blocksfound);
317 LONG findspace2(ULONG maxneeded, BLCK start, BLCK end, BLCK *returned_block, ULONG *returned_blocks) {
318 struct CacheBuffer *cb;
319 ULONG longs=globals->blocks_inbitmap>>5;
320 ULONG space=0;
321 ULONG block;
322 BLCK bitmapblock=globals->block_bitmapbase + start/globals->blocks_inbitmap;
323 BLCK breakpoint;
324 LONG bitstart,bitend;
325 LONG reads;
326 LONG errorcode;
328 /* This function checks the bitmap and tries to locate /maxneeded/ adjacent
329 unused blocks, or less if there aren't that many unused adjacent blocks.
331 The number of blocks found will be stored in returned_blocks, and the
332 location of those blocks stored in returned_block. The number of blocks
333 found can be zero if the area to search in didn't contain any free blocks.
334 This is not an error -- the return value will be 0.
336 Errors which occur during the execution of this function are returned as
337 normal. The contents of returned_block and returned_blocks is undefined
338 in that case.
340 The search-area is limited by startblock (inclusive) and endblock (exclusive).
341 Note that the search-area loops, so it is possible to do wrap-around searches
342 by setting endblock<=startblock (see table below):
344 Start-block End-block Area searched
346 0 10 1111111111
347 5 10 .....11111
348 5 7 .....11...
349 5 5 2222211111
350 9 10 .........1
351 9 0 .........1
352 9 1 2........1
353 10 2 11........ */
355 if(start>=globals->blocks_total) {
356 start-=globals->blocks_total;
359 if(end==0) {
360 end=globals->blocks_total;
363 reads=((end-1)/globals->blocks_inbitmap) + 1 - start/globals->blocks_inbitmap;
364 if(start>=end) {
365 reads+=(globals->blocks_total-1)/globals->blocks_inbitmap + 1;
368 breakpoint=(start<end ? end : globals->blocks_total);
370 *returned_block=0;
371 *returned_blocks=0;
373 bitend=start % globals->blocks_inbitmap;
374 block=start-bitend;
376 while((errorcode=readcachebuffercheck(&cb, bitmapblock++, BITMAP_ID))==0) {
377 struct fsBitmap *b=cb->data;
378 ULONG localbreakpoint=breakpoint-block;
380 if(localbreakpoint>globals->blocks_inbitmap) {
381 localbreakpoint=globals->blocks_inbitmap;
384 /* At this point space contains the amount of free blocks at
385 the end of the previous bitmap block. If there are no
386 free blocks at the start of this bitmap block, space will
387 be set to zero, since in that case the space isn't adjacent. */
389 while((bitstart=bmffo(b->bitmap, longs, bitend))<globals->blocks_inbitmap) {
391 /* found the start of an empty space, now find out how large it is */
393 if(bitstart >= localbreakpoint) { // Oct 3 1999: Check if the start of this empty space is within bounds.
394 break;
397 if(bitstart!=0) {
398 space=0;
401 bitend=bmffz(b->bitmap, longs, bitstart);
403 if(bitend > localbreakpoint) {
404 bitend=localbreakpoint;
407 space+=bitend-bitstart;
409 if(*returned_blocks<space) {
410 *returned_block=block+bitend-space;
411 if(space>=maxneeded) {
412 *returned_blocks=maxneeded;
413 return(0);
415 *returned_blocks=space;
418 if(bitend>=localbreakpoint) {
419 break;
423 if(--reads==0) {
424 break;
427 /* no (more) empty spaces found in this block */
429 if(bitend!=globals->blocks_inbitmap) {
430 space=0;
433 bitend=0;
434 block+=globals->blocks_inbitmap;
436 if(block>=globals->blocks_total) {
437 block=0;
438 space=0;
439 breakpoint=end;
440 bitmapblock=globals->block_bitmapbase;
444 return(errorcode);
448 #if 0
449 LONG findspace(ULONG blocksneeded,BLCK startblock,BLCK endblock,BLCK *returned_block) {
450 ULONG blocks;
451 LONG errorcode;
453 /* This function checks the bitmap and tries to locate at least /blocksneeded/
454 adjacent unused blocks. If found it set returned_block to the start block.
455 If not it is set to zero. Any error is returned.
457 The search-area is limited by startblock (inclusive) and endblock (exclusive). */
459 if((errorcode=findspace2(blocksneeded, startblock, endblock, returned_block, &blocks))==0) {
460 if(blocks!=blocksneeded) {
461 _DEBUG(("findspace: %ld != %ld\n", blocks, blocksneeded));
462 return(ERROR_DISK_FULL);
466 return(errorcode);
468 #endif
471 LONG findspace(ULONG blocksneeded, BLCK startblock, BLCK endblock, BLCK *returned_block) {
472 ULONG blocks;
473 LONG errorcode;
475 /* This function checks the bitmap and tries to locate at least /blocksneeded/
476 adjacent unused blocks. If found it sets returned_block to the start block
477 and returns no error. If not found, ERROR_DISK_IS_FULL is returned and
478 returned_block is set to zero. Any other errors are returned as well.
480 The search-area is limited by startblock (inclusive) and endblock (exclusive).
481 Note that the search-area loops, so it is possible to do wrap-around searches
482 by setting endblock<=startblock (see table below):
484 Start-block End-block Area searched
486 0 10 1111111111
487 5 10 .....11111
488 5 7 .....11...
489 5 5 2222211111
490 9 10 .........1
491 9 0 .........1
492 9 1 2........1 */
494 if((errorcode=findspace2(blocksneeded, startblock, endblock, returned_block, &blocks))==0) {
495 if(blocks!=blocksneeded) {
496 _DEBUG(("findspace: %ld != %ld\n", blocks, blocksneeded));
497 return(ERROR_DISK_FULL);
501 return(errorcode);
506 LONG findandmarkspace(ULONG blocksneeded, BLCK *returned_block) {
507 LONG errorcode;
509 // This function is currently only used by AdminSpace allocation. */
511 if(enoughspace(blocksneeded)!=FALSE) {
513 // if((errorcode=findspace(blocksneeded, block_rovingblockptr, block_rovingblockptr, returned_block))==0)
515 if((errorcode=findspace(blocksneeded, 0, globals->blocks_total, returned_block))==0) {
516 errorcode=markspace(*returned_block,blocksneeded);
519 else {
520 errorcode=ERROR_DISK_FULL;
523 return(errorcode);
528 LONG smartfindandmarkspace(BLCK startblock,ULONG blocksneeded) {
529 LONG freeblocks,allocblocks;
530 BLCK block=startblock;
531 ULONG blocksfound=0;
532 UWORD entry=0;
533 UWORD n;
534 ULONG blocks, smallestfragment, newsmallestfragment;
535 LONG errorcode;
537 /* This function searches the bitmap to locate /blocks/ blocks. It will
538 return the amount of blocks needed in a number of fragments if necessary.
540 Followed strategy:
542 If there are less free blocks than there are needed then this function
543 will keep looking until the bitmap has been scanned completely. It will
544 return every free block available in this case.
546 If the number of blocks found is larger than the amount of needed blocks
547 then there are a couple of options:
549 a) If the blocks found are a single fragment, then return immediately.
550 b) If the blocks have fragments which average above 64K and atleast
551 a quarter of the bitmap has been scanned, then return immediately.
552 c) If the blocks have fragments which average above 16K and atleast
553 half the bitmap has been scanned, then return immediately.
554 d) Otherwise scan the bitmap completely (expensive!). */
556 if(enoughspace(blocksneeded)!=FALSE) {
558 while(entry<SPACELIST_MAX) {
559 freeblocks=availablespace(block,blocksneeded);
560 _XDEBUG((DEBUG_BITMAP,"sfams: availablespace returned %ld for block %ld while we needed %ld blocks\n",freeblocks,block,blocksneeded));
562 if(freeblocks>0) {
563 if(freeblocks>=blocksneeded) {
564 entry=0;
565 globals->spacelist[entry].block=block;
566 globals->spacelist[entry++].blocks=freeblocks;
567 blocksfound=freeblocks;
568 break;
571 globals->spacelist[entry].block=block;
573 if(block<startblock && block+freeblocks>=startblock) {
574 freeblocks=startblock-block;
576 blocksfound+=freeblocks;
577 globals->spacelist[entry++].blocks=freeblocks;
578 break;
581 blocksfound+=freeblocks;
582 globals->spacelist[entry++].blocks=freeblocks;
584 else if(freeblocks<0) {
585 return(ERROR_DISK_FULL);
588 block+=freeblocks;
589 if(block>=globals->blocks_total) {
590 if(startblock==0) {
591 break;
593 block=0;
596 allocblocks=allocatedspace(block,globals->blocks_inbitmap*2);
597 _XDEBUG((DEBUG_BITMAP,"sfams: allocatedspace returned %ld for block %ld while we needed %ld blocks\n",allocblocks,block,globals->blocks_inbitmap*2));
599 if(allocblocks<0) {
600 _DEBUG(("sfams: disk full 1\n"));
601 return(ERROR_DISK_FULL);
603 else if(block<startblock && block+allocblocks>=startblock) {
604 break;
607 block+=allocblocks;
608 if(block>=globals->blocks_total) {
609 if(startblock==0) {
610 break;
612 block=0;
616 if(entry==0) {
617 _DEBUG(("sfams: disk full 2\n"));
618 return(ERROR_DISK_FULL);
621 globals->spacelist[entry].block=0;
623 /* blocksfound, entry & blocksneeded */
625 /* We need to eliminate the smallest fragments from the spacelist. */
627 smallestfragment=1;
629 while(blocksfound>=blocksneeded+smallestfragment) {
630 n=0;
631 newsmallestfragment=0xFFFF;
633 while(globals->spacelist[n].block!=0) {
634 blocks=globals->spacelist[n].blocks;
635 if(blocks!=0) {
636 if(blocks==smallestfragment) {
637 blocksfound-=smallestfragment;
638 globals->spacelist[n].blocks=0;
639 if(blocksfound-smallestfragment<blocksneeded) {
640 break;
643 else if(blocks<newsmallestfragment) {
644 newsmallestfragment=blocks;
647 n++;
650 smallestfragment=newsmallestfragment;
653 /* Now we need to mark the remaining fragments as used space. The
654 last fragment may need to be partially marked, depending on
655 /blocksneeded/. */
657 n=0;
658 while(globals->spacelist[n].block!=0) {
659 blocks=globals->spacelist[n].blocks;
660 if(blocks!=0) {
661 if(blocksneeded<blocks) {
662 blocks=blocksneeded;
665 if((errorcode=markspace(globals->spacelist[n].block,blocks))!=0) {
666 return(errorcode);
669 blocksneeded-=blocks;
672 n++;
675 else {
676 _DEBUG(("sfams: disk full 3\n"));
677 return(ERROR_DISK_FULL);
680 return(0);
688 This function returns for (128, 353219, blocks_total) : 351840 (!!) not allowed!
694 LONG findspace2_backwards(ULONG maxneeded, BLCK start, BLCK end, BLCK *returned_block, ULONG *returned_blocks) {
695 struct CacheBuffer *cb;
696 ULONG space=0;
697 ULONG block;
698 BLCK bitmapblock=globals->block_bitmapbase+start/globals->blocks_inbitmap;
699 BLCK breakpoint;
700 BLCK prevbitmapblock=globals->block_bitmapbase+(end-1)/globals->blocks_inbitmap;
701 LONG bitstart,bitend;
702 LONG errorcode;
704 /* This function checks the bitmap and tries to locate /maxneeded/ adjacent
705 unused blocks, or less if there aren't that many unused adjacent blocks.
707 The number of blocks found will be stored in returned_blocks, and the
708 location of those blocks stored in returned_block. The number of blocks
709 found can be zero if the area to search in didn't contain any free blocks.
710 This is not an error -- the return value will be 0.
712 Errors which occur during the execution of this function are returned as
713 normal. The contents of returned_block and returned_blocks is undefined
714 in that case.
716 The search-area is limited by start (inclusive) and end (exclusive). */
719 if(start>=blocks_total) {
720 start-=blocks_total;
723 if(end==0) {
724 end=blocks_total;
727 reads=((end-1)/blocks_inbitmap) + 1 - start/blocks_inbitmap;
728 if(start>=end) {
729 reads+=(blocks_total-1)/blocks_inbitmap + 1;
732 breakpoint=(start<end ? start : 0);
734 breakpoint=start;
736 *returned_block=0;
737 *returned_blocks=0;
739 bitstart=(end-1) % globals->blocks_inbitmap;
740 block=(end-1) - bitstart;
742 while((errorcode=readcachebuffercheck(&cb, prevbitmapblock--, BITMAP_ID))==0) {
743 struct fsBitmap *b=cb->data;
744 LONG localbreakpoint=breakpoint-block;
746 if(localbreakpoint<0 || localbreakpoint>=globals->blocks_inbitmap) {
747 localbreakpoint=0;
750 while((bitend=bmflo(b->bitmap, bitstart))>=0) {
752 /* Found the end of an empty space, now find out how large it is. */
754 if(bitend < localbreakpoint) { // Check if the end of this empty space is within bounds.
755 break;
758 if(bitend!=globals->blocks_inbitmap-1) {
759 space=0;
762 bitstart=bmflz(b->bitmap, bitend);
764 if(bitstart+1 < localbreakpoint) {
765 bitstart=localbreakpoint-1;
768 space+=bitend-bitstart;
770 if(*returned_blocks<space) {
771 *returned_block=block+bitstart+1;
772 if(space>=maxneeded) {
773 *returned_block=*returned_block+space-maxneeded;
774 *returned_blocks=maxneeded;
775 return(0);
777 *returned_blocks=space;
780 if(bitstart<=localbreakpoint) {
781 break;
785 if(prevbitmapblock<bitmapblock) {
786 break;
789 /* no (more) empty spaces found in this block */
791 if(bitstart!=-1) {
792 space=0;
795 bitstart=globals->blocks_inbitmap-1;
796 block-=globals->blocks_inbitmap;
799 return(errorcode);