1 #include "asmsupport.h"
3 #include <clib/macros.h>
5 #include <exec/types.h>
6 #include <proto/exec.h>
9 #include "cachebuffers_protos.h"
12 #include "transactions_protos.h"
13 #include "req_protos.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
;
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
);
34 LONG
getusedblocks(ULONG
*returned_usedblocks
) {
38 if((errorcode
=getfreeblocks(&freeblocks
))==0) {
39 *returned_usedblocks
=globals
->blocks_total
-globals
->blocks_reserved_start
-globals
->blocks_reserved_end
-freeblocks
;
47 LONG
setfreeblocks(ULONG freeblocks
) {
48 struct CacheBuffer
*cb
;
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
);
66 static BOOL
enoughspace(ULONG blocks
) {
69 if(getfreeblocks(&blocksfree
)!=0 || blocksfree
-transactionspace() < blocks
+ALWAYSFREE
) {
77 LONG
availablespace(BLCK block
,ULONG maxneeded
);
80 LONG
markspace(BLCK block
,ULONG blocks
) {
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
);
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;
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/ */
107 if((errorcode
=readcachebuffercheck(&cb
,bitmapblock
++,BITMAP_ID
))==0) {
110 preparecachebuffer(cb
);
114 blocks
-=bmclr(b
->bitmap
,longs
,block
,blocks
);
117 if((errorcode
=storecachebuffer(cb
))!=0) {
126 // block_rovingblockptr=newrovingptr;
127 // if(block_rovingblockptr>=blocks_total) {
128 // block_rovingblockptr=0;
138 LONG
freespace(BLCK block
,ULONG blocks
) {
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;
151 // blocks_useddiff-=blocks;
153 block
-=skipblocks
*globals
->blocks_inbitmap
;
154 bitmapblock
=globals
->block_bitmapbase
+skipblocks
;
156 /* /block/ is bitoffset in the /bitmapblock/ */
159 if((errorcode
=readcachebuffercheck(&cb
,bitmapblock
++,BITMAP_ID
))==0) {
162 preparecachebuffer(cb
);
166 blocks
-=bmset(b
->bitmap
,longs
,block
,blocks
);
169 if((errorcode
=storecachebuffer(cb
))!=0) {
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/ */
200 struct CacheBuffer
*cb
;
203 if((errorcode
=readcachebuffercheck(&cb
, bitmapblock
++, BITMAP_ID
))==0) {
205 ULONG bytestocopy
=bytesinbitmap
-byteoffset
;
207 if(bytestocopy
>bytes
) {
213 CopyMem((UBYTE
*)b
->bitmap
+ byteoffset
, dest
, bytestocopy
);
229 LONG
availablespace(BLCK block
,ULONG maxneeded
) {
230 struct CacheBuffer
*cb
;
232 ULONG longs
=globals
->blocks_inbitmap
>>5;
233 ULONG maxbitmapblock
=globals
->block_bitmapbase
+globals
->blocks_bitmap
;
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
246 bitstart
=block
% globals
->blocks_inbitmap
;
248 while(nextblock
<maxbitmapblock
&& (errorcode
=readcachebuffercheck(&cb
,nextblock
++,BITMAP_ID
))==0) {
251 if((bitend
=bmffz(b
->bitmap
,longs
,bitstart
))<(32*longs
)) {
252 blocksfound
+=bitend
-bitstart
;
256 blocksfound
+=globals
->blocks_inbitmap
-bitstart
;
257 if(blocksfound
>=maxneeded
) {
273 LONG
allocatedspace(BLCK block
,ULONG maxneeded
) {
274 struct CacheBuffer
*cb
;
276 ULONG longs
=globals
->blocks_inbitmap
>>5;
277 ULONG maxbitmapblock
=globals
->block_bitmapbase
+globals
->blocks_bitmap
;
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
290 bitstart
=block
% globals
->blocks_inbitmap
;
292 while(nextblock
<maxbitmapblock
&& (errorcode
=readcachebuffercheck(&cb
,nextblock
++,BITMAP_ID
))==0) {
295 if((bitend
=bmffo(b
->bitmap
,longs
,bitstart
))<(32*longs
)) {
296 blocksfound
+=bitend
-bitstart
;
300 blocksfound
+=globals
->blocks_inbitmap
-bitstart
;
301 if(blocksfound
>=maxneeded
) {
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;
322 BLCK bitmapblock
=globals
->block_bitmapbase
+ start
/globals
->blocks_inbitmap
;
324 LONG bitstart
,bitend
;
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
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
355 if(start
>=globals
->blocks_total
) {
356 start
-=globals
->blocks_total
;
360 end
=globals
->blocks_total
;
363 reads
=((end
-1)/globals
->blocks_inbitmap
) + 1 - start
/globals
->blocks_inbitmap
;
365 reads
+=(globals
->blocks_total
-1)/globals
->blocks_inbitmap
+ 1;
368 breakpoint
=(start
<end
? end
: globals
->blocks_total
);
373 bitend
=start
% globals
->blocks_inbitmap
;
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.
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
;
415 *returned_blocks
=space
;
418 if(bitend
>=localbreakpoint
) {
427 /* no (more) empty spaces found in this block */
429 if(bitend
!=globals
->blocks_inbitmap
) {
434 block
+=globals
->blocks_inbitmap
;
436 if(block
>=globals
->blocks_total
) {
440 bitmapblock
=globals
->block_bitmapbase
;
449 LONG
findspace(ULONG blocksneeded
,BLCK startblock
,BLCK endblock
,BLCK
*returned_block
) {
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
);
471 LONG
findspace(ULONG blocksneeded
, BLCK startblock
, BLCK endblock
, BLCK
*returned_block
) {
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
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
);
506 LONG
findandmarkspace(ULONG blocksneeded
, BLCK
*returned_block
) {
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
);
520 errorcode
=ERROR_DISK_FULL
;
528 LONG
smartfindandmarkspace(BLCK startblock
,ULONG blocksneeded
) {
529 LONG freeblocks
,allocblocks
;
530 BLCK block
=startblock
;
534 ULONG blocks
, smallestfragment
, newsmallestfragment
;
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.
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
));
563 if(freeblocks
>=blocksneeded
) {
565 globals
->spacelist
[entry
].block
=block
;
566 globals
->spacelist
[entry
++].blocks
=freeblocks
;
567 blocksfound
=freeblocks
;
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
;
581 blocksfound
+=freeblocks
;
582 globals
->spacelist
[entry
++].blocks
=freeblocks
;
584 else if(freeblocks
<0) {
585 return(ERROR_DISK_FULL
);
589 if(block
>=globals
->blocks_total
) {
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));
600 _DEBUG(("sfams: disk full 1\n"));
601 return(ERROR_DISK_FULL
);
603 else if(block
<startblock
&& block
+allocblocks
>=startblock
) {
608 if(block
>=globals
->blocks_total
) {
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. */
629 while(blocksfound
>=blocksneeded
+smallestfragment
) {
631 newsmallestfragment
=0xFFFF;
633 while(globals
->spacelist
[n
].block
!=0) {
634 blocks
=globals
->spacelist
[n
].blocks
;
636 if(blocks
==smallestfragment
) {
637 blocksfound
-=smallestfragment
;
638 globals
->spacelist
[n
].blocks
=0;
639 if(blocksfound
-smallestfragment
<blocksneeded
) {
643 else if(blocks
<newsmallestfragment
) {
644 newsmallestfragment
=blocks
;
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
658 while(globals
->spacelist
[n
].block
!=0) {
659 blocks
=globals
->spacelist
[n
].blocks
;
661 if(blocksneeded
<blocks
) {
665 if((errorcode
=markspace(globals
->spacelist
[n
].block
,blocks
))!=0) {
669 blocksneeded
-=blocks
;
676 _DEBUG(("sfams: disk full 3\n"));
677 return(ERROR_DISK_FULL
);
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
;
698 BLCK bitmapblock
=globals
->block_bitmapbase
+start
/globals
->blocks_inbitmap
;
700 BLCK prevbitmapblock
=globals
->block_bitmapbase
+(end
-1)/globals
->blocks_inbitmap
;
701 LONG bitstart
,bitend
;
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
716 The search-area is limited by start (inclusive) and end (exclusive). */
719 if(start>=blocks_total) {
727 reads=((end-1)/blocks_inbitmap) + 1 - start/blocks_inbitmap;
729 reads+=(blocks_total-1)/blocks_inbitmap + 1;
732 breakpoint=(start<end ? start : 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
) {
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.
758 if(bitend
!=globals
->blocks_inbitmap
-1) {
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
;
777 *returned_blocks
=space
;
780 if(bitstart
<=localbreakpoint
) {
785 if(prevbitmapblock
<bitmapblock
) {
789 /* no (more) empty spaces found in this block */
795 bitstart
=globals
->blocks_inbitmap
-1;
796 block
-=globals
->blocks_inbitmap
;