; ; File: VSM.a ; ; Contains: This module provides the Volume Space Management in the Turbo ; File System. ; ; Written by: Patrick W. Dirks, December 11 1984 ; ; Copyright: © 1984-1991 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; <2> 9/13/91 JSM Add a header. ; <1.2> 3/2/89 DNF removed references to forROM; HFS now builds identically for ram ; or rom ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <¥1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <1.0> 2/11/88 BBM Adding file for the first time into EASEÉ ; 10/27/86 BB Vectored ReadBM routine. ; 9/25/86 BB Updated to use new MPW equate files. ; 10/29/85 LAK Vectored BlkAlloc, BlkDealloc. ; 10/25/85 PWD Fixed FrBitScn to back up starting position before backing out ; at EOV. Added debugging code to catch partial-word $FFFF ; advances. ; 10/24/85 PWD Added debugging code to check allocation before return ; 10/22/85 PWD Fixed bug in EOV check in FrBitScan ; 10/21/85 PWD Changed BlkAlloc to check VCBFreeBks before attempting to ; allocate any block. Speed up scan for free space by checking for ; all 1's. ; 10/6/85 PWD Changed to return error instead of calling _SysError Changed to ; call common subroutine NextBit ; 10/1/85 LAK Use GBrelease option when calling GetBlock. ; 9/8/85 LAK Added routine UpdateFree to refigure the free block count for ; the MountVol consistency check. ; 9/3/85 LAK Contiguous allocation had a bug with buffer non-release. Rewrote ; this to use MarkBlock to dirty a block instead, and immediately ; call RelBlock after GetBlock. ; 8/21/85 PWD Fixed request size rounding to pre-divide by VCBAlBlSiz. ; 7/3/85 PWD Added consistency checking code. ; 5/28/85 PWD Changed to leave AllocPtr at start of last allocation (to ; minimize fragmentation after truncate on Close). ; 5/13/85 PWD Added code to BlkAlloc to check for zero free space ; 3/22/85 PWD Changed to use A6 stack, and use word-sized AlBlkSize ; 2/24/85 PWD Added explicit TST.W D0 in routines to re-set status codes ; 2/12/85 PWD Changed BlkDealloc to pass on result code in D0 ; 2/11/85 PWD Changed BlkDealloc to check for zero-length block counts. ; 12/11/84 PWD New today. ; ;________________________________________________________________________________ ; ; Routines: BlkAlloc, BlkDealloc, BlkChk ; ;________________________________________________________________________________ BLANKS ON STRING ASIS PRINT OFF LOAD 'StandardEqu.d' PRINT ON PRINT NOGEN VSM PROC EXPORT EXPORT BlkAlloc, BlkDealloc, BlkChk, UpdateFree IMPORT GetBlock,RelBlock,MarkBlock,DivUp,RoundAlloc,MarkVCB EXPORT vBlkAlloc,vBlkDealloc,vReadBM ;<27Oct86> EJECT ;________________________________________________________________________________ ; ; Routine: BlkAlloc ; ; Function: Allocate space on a volume. If contiguous allocation is requested, ; at least the requested number of bytes will be allocated or an ; error will be returned. If contiguous allocation is not forced, ; the space will be allocated at the first free fragment following ; the requested starting allocation block. If there is not enough ; room there, a block of less than the requested size will be ; allocated. ; ; If the requested starting block is 0 (for new file allocations), ; the volume's allocation block pointer will be used as a starting ; point. ; ; All requests will be rounded up to the next highest clump size, as ; indicated in the file's FCB. ; ; Input Arguments: ; A2 - Pointer to VCB for the volume to allocate space on ; A3 - Pointer to FCB for the file for which storage is being allocated ; D2.W - Preferred starting allocation block, 0 = no preference ; D3.B - Force contiguous flag - if bit 0 set (NE), allocation is contiguous ; or an error is returned ; D4.L - Number of bytes requested. If the allocation is non-contiguous, less ; than this may actually be allocated ; ; Output: ; D0.W - Error code, zero for successful allocation ; D2.W - Actual starting allocation block ; D3.W - Actual number of allocation blocks allocated ; ; Internal register usage: ; A0 - Pointed to bitmap buffer ; A1.W - Used to hold the number of allocation blocks on the volume ; D0.W - Used to hold current bitmap word ; D1.W - Count of number of unexamined bits left in D0 ; D3.L - High word used to stash starting allocation block ; D5.W - Current bitmap block number ; D6.W - Index into bitmap block buffer ; D7.W - Number of allocation blocks actually allocated ; ; Side effects: ; The volume bitmap is read and updated; the volume bitmap cache may be changed. ; ; Modification history: ; <06Oct85> PWD Changed to check for errors after calls to ReadBM and NextWord ; Relocated call to MarkBlock in allocation loop ; Changed to call NextBit ; <21Oct85> PWD Changed to check VCBFreeBks before attempting to allocate any block. ; Speed up scan for free space by checking for all 1's. ;________________________________________________________________________________ ; BlkAlloc: MOVE.L jBlkAlloc,-(SP) ; jumptable entry for vBlkAlloc <29Oct85> RTS ; go there <29Oct85> vBlkAlloc ; 'vectored' BlkAlloc routine <29Oct85> MOVE.L (SP)+,-(A6) ; Save return address MOVEM.L D1/D4-D7/A0-A1,-(A6); Save caller's registers TST.W VCBFreeBks(A2) ; Any blocks free at all? BEQ bkAllocFull ; Exit if not <03Sep85> ANDI.W #$0001,D3 ; Clear all extra bits for our use TST.W D2 ; Preferred starting block selected? BNE.S @1 ; Yes - leave it be. MOVE.W VCBAllocPtr(A2),D2 ; No - start from the volume-wide pointer BSET #7,D3 ; Set flag to update vcbAllocPtr later @1: SWAP D3 ; Get high word accessible MOVE.W D2,D3 ; Store starting block SWAP D3 ; And restore flags word for use BCLR #15,D3 ; Clear wrap-around flag blkLoop: BSR ReadBM ; Pick up the bitmap block of interest TST.W D1 ; No errors? BMI bkAllocExit ; If negative, D0 is now error code MOVEA.W VCBNmAlBlks(A2),A1 ; Set up the size of the volume ; Look for a free fragment at or beyond the starting block selected: @1: CMP.W A1,D2 ; Did we reach the end-of-volume? BCS.S @2 ; If not (D2 < A1), march merrily along ROL.L D1,D0 ; Rotate D0 back into place MOVE.L D0,0(A0,D6.W) ; Replace it in the buffer (buffer is clean) CLR.W D2 ; Reset the starting block to the beginning BSR ReadBM ; Read the appropriate bitmap block BSET #15,D3 ; Indicate we wrapped around the EOV BNE bkAllocFull ; Exit if already set, with DskFulErr, D3=0 ; It wasn't set yet, start over again @2: TST.W D1 ; Any errors occur? BMI bkAllocExit ; Punt on errors TST.L D0 ; If bit 31 clear (free alloc. block)? BPL.S bkAlFree ; If so, check if fragment is big enough BSR FrBitScan ; Look for another free bit. BRA.S @1 ; And keep trying ; We found a free fragment; check to see if it isn't too small. For a contiguous ; allocation, this should guarantee that at least as much as requested is actually ; allocated, although more may be granted; the request is rounded up to the next ; highest clump later. bkAlFree: SUB.W D2,A1 ; Change A1 to # block left to EOV BTST #0,D3 ; Is contiguous allocation requested? BEQ.S bkAllocDoIt ; If not, just start allocating here. MOVE.L D4,-(A6) ; Store original alloc. request size MOVEM.L D0-D1,-(A6) ; Free up for use in division MOVE.L D4,D0 ; Set up to divide MOVE.W vcbAlBlkSiz+2(A2),D1 ; by allocation block size JSR DivUp ; and round result up to next alloc. block MOVE.L D0,D4 ; D4 is now min. number of alloc. blocks MOVEM.L (A6)+,D0-D1 ; Restore original registers CLR.W D7 ; Set up fragment length count, al. blocks @1: CMP.W D7,D4 ; Check current length: enough already? BLS.S @5 ; If reguest <= fragment so far, go for it! CMP.W A1,D7 ; Reached the edge? BEQ.S @2 ; If so, that wasn't quite enough TST.L D0 ; If bit 31 set (allocated block)? BMI.S @2 ; If so, fragment wasn't big enough ADDQ.W #1,D7 ; If not, bump fragment length count BSR NextBit ; Pick up the next bit out of the bitmap TST.W D1 ; Any errors occur? BMI bkAllocExit ; Punt on errors BRA.S @1 ; Otherwise keep trying @2: MOVE.L (A6)+,D4 ; Restore original request size (bytes) ADD.W D7,D2 ; This fragment too small - update starting block CMP.W A1,D7 ; Did we reach to the EOV? BCS.S @3 ; Nope - try this for a next position BTST #15,D3 ; Did we wrap around yet? BNE.S @4 ; Yes - give up: history repeats itself BSET #15,D3 ; No - give it another shot CLR.W D2 ; From the beginning of the volume @3: BTST #15,D3 ; Did we wrap around yet? BEQ blkLoop ; If not, scan on SWAP D3 ; Get a hold of the starting block CMP.W D2,D3 ; Are we back where we started? BLS.S @4 ; If we're beyond the start, quit SWAP D3 ; Otherwise, restore D3 BRA blkLoop ; And scan on @4: ROL.L D1,D0 ; Rotate D0 back into place MOVE.L D0,0(A0,D6.W) ; And replace it in the buffer BRA bkAllocFull ; Exit with DskFulErr, D3=0 <03Sep85> @5: MOVE.L (A6)+,D4 ; Retrieve request size in bytes ROL.L D1,D0 ; Restore D0 to its original position ??? MOVE.L D0,0(A0,D6.W) ; Replace it in the buffer (buffer is still clean) ??? BSR ReadBM ; And set up from the current position (D2) TST.W D1 ; Any errors occur? BMI bkAllocExit ; Punt on errors ; Start allocating block at this point: round the request off to the next highest ; clump size now, and try to take as much as possible up to that limit. bkAllocDoIt: MOVEM.L D0-D1,-(A6) ; Save current bitmap word & bit count MOVE.L D4,D0 ; Get requested allocation length (bytes) <22Aug85> MOVE.L FCBClmpSize(A3),D1 ; Get clump size for file <22Aug85> JSR RoundAlloc ; Divide, rounding up -> Size in AlBlks <22Aug85> MOVE.L D0,D4 ; Stash it away <22Aug85> MOVEM.L (A6)+,D0-D1 ; And retrieve original bitmap word & count CLR.L D7 ; Zero out actual allocation counter ; Mark blocks allocated from the starting block: @1: TST.W D4 ; Allocated enough already? BEQ.S BkAllocOK ; If so, quit CMP.W A1,D7 ; If not, is there more here? BCC.S BkAllocOK ; If D7 >= A1, we've reached the EOV TST.L D0 ; Check bit 31 of current word (curr. blk) BMI.S BkAllocOK ; If allocated, stop trying TST.W VCBFreeBks(A2) ; Does vol. think there are any bits left? BEQ.S BkAllocOK ; Nope - we're done (for) then . . . SUBQ.W #1,VCBFreeBks(A2) ; Yes - well, there's one fewer now. JSR MarkVCB ; Mark the VCB dirty BSET #31,D0 ; Mark the current block as allocated ADDQ.W #1,D7 ; Add one to allocated block count SUBQ.W #1,D4 ; Subtract one from request size JSR MarkBlock ; This block is dirty . . . BSR NextBit ; Get the next bit from the bitmap TST.W D1 ; Check: any errors reading BM? BGE.S @1 ; If D1>0, all was well BRA.S BkAllocExit ; Otherwise give up (D0 is error code) ; Allocation is done: BkAllocOK: BTST #7,D3 ; Did we start from the VCB's AllocPtr? BEQ.S @2 ; If not, never mind MOVE.W D2,D4 ; Prepare new allocPtr ; Adding in the length of the current allocation might reduce the next allocate ; call by avoiding a re-scan of the already allocated space. However, the clump ; just allocated can quite conceivably end up being truncated or released when ; the file is closed or its EOF changed. Leaving the allocation pointer at the ; start of the last allocation will avoid unnecessary fragmentation in this case.; CMP.W VCBNmAlBlks(A2),D4 ; Is it at EOV? BCS.S @1 ; If CS, D4 < NmAlBlks: all is well CLR.W D4 ; If D4 >= NmAlBlks, wrap around @1: MOVE.W D4,VCBAllocPtr(A2) ; Update VCB's allocation pointer ; @2: ROL.L D1,D0 ; Rotate the bitmap word back into place MOVE.L D0,0(A0,D6.W) ; And put it back where it came from JSR MarkBlock ; Mark the buffer dirty MOVE.L D7,D3 ; Return the actual allocation size IF HFSDebug THEN ; <24Oct85> MOVE.W D3,-(A6) ; Save D3 for actual return value <24OCt85> BSR ReadBM ; Read the bitmap entry for the allocated space <24OCt85> @5 TST.W D1 ; Found it? <24Oct85> BMI.S @10 ; Nope - bomb. <24Oct85> TST.L D0 ; Check - is top bit actually set? <24Oct85> BPL.S @10 ; Nope - trouble! <24Oct85> BSR NextBit ; OK - look for the next bit in the allocation <24Oct85> SUBQ.W #1,D3 ; ...that's one block successfully allocated <24Oct85> BNE.S @5 ; Go check the other blocks allocated <24Oct85> BRA.S @20 ; Success! <24Oct85> @10 _HFSDebug $321 ; "Pause for debugging"... <24Oct85> @20 MOVE.W (A6)+,D3 ; Restore D3 for return to user <24Oct85> ENDIF ; <24Oct85> MOVEQ #0,D0 ; and success MOVEQ #0,D0 ; Sweet success BkAllocExit: MOVEM.L (A6)+,D1/D4-D7/A0-A1; Restore registers MOVE.L (A6)+,-(SP) ; Restore return address TST.W D0 ; Set condition codes for return RTS ; And call it a day. bkAllocFull: MOVEQ #0,D3 ; No Blocks allocated MOVEQ #DskFulErr,D0 ; Disk is full BRA.S BkAllocExit ; EJECT ;________________________________________________________________________________ ; ; Routine: BlkDealloc ; ; Function: Update the bitmap to deallocate a run of disk allocation blocks ; ; Input Arguments: ; A2 - Pointer to VCB for the volume to free space on ; D2.W - First allocation block to be freed ; D3.W - Number of allocation blocks to free up (must be > 0!) ; ; Output: ; D0.W - Result code ; ; Internal register usage: ; A0 - Pointed to bitmap buffer ; D0.W - Used to hold current bitmap word ; D1.W - Count of number of bits left unexamined in D0 ; D5.W - Current bitmap block number ; D6.W - Index into bitmap block buffer ; ; Side effects: ; The volume bitmap is read and updated; the volume bitmap cache may be changed. ; ; Modification history: ; ; <06Oct85> PWD Changed to check for error after calls to ReadBM and NextWord ; Now calls NextBit to read successive bits from the bitmap ;________________________________________________________________________________ ; BlkDeAlloc: MOVE.L jBlkDeAlloc,-(SP) ; jumptable entry for vBlkDeAlloc <29Oct85> RTS ; go there <29Oct85> vBlkDeAlloc ; 'vectored' BlkDeAlloc routine <29Oct85> MOVE.L (SP)+,-(A6) ; Save return address MOVEM.L D1-D6/A0,-(A6) ; Save registers for use MOVEQ #0,D0 ; Set up completion code TST.W D3 ; Check block count BEQ.S @95 ; If zero, we're done. BSR ReadBM ; Pick up the relevant bitmap information @10: TST.W D1 ; Any error occur? BMI.S @95 ; If not, keep going BCLR #31,D0 ; Free up the block IF HFSDebug THEN BNE.S @15 ; Check to make sure it was set... _hFSDebug $123 ; Pause to check this out... @15: ENDIF JSR MarkBlock ; Mark this buffer dirty (will be in a sec...) ADDQ.W #1,VCBFreeBks(A2) ; Adjust free block count JSR MarkVCB ; Mark the VCB dirty SUBQ.W #1,D3 ; That's one down: any left? BEQ.S @90 ; No - that's it BSR NextBit ; Get next bitmap bit BRA.S @10 ; @90: ROL.L D1,D0 ; Rotate D0 back into position MOVE.L D0,0(A0,D6.W) ; Put the bitmap word back where it came from ; JSR MarkBlock ; Mark the buffer dirty . . . MOVEQ #0,D0 ; success! @95: MOVEM.L (A6)+,D1-D6/A0 ; Restore registers MOVE.L (A6)+,-(SP) ; Restore return address TST.W D0 ; Set condition codes RTS ; And call it a day. EJECT ;_______________________________________________________________________ ; ; Routine: BlkChk ; Arguments: A0.L (input) -- pointer to extent record ; A2.L (input) -- VCB for volume ; ; D0.L (output) -- 0 if block was already allocated ; -1 otherwise ; ; Internal register usage: ; A0 - Pointed to bitmap buffer ; A1 - Pointed to extent record ; D0.W - Used to hold current bitmap word ; D1.W - Count of number of bits left unexamined in D0 ; D2.W - Allocation block currently being checked ; D3.L - Set in case a block was found unallocated ; D4.L - Count of number of blocks in current extent ; D5.W - Current bitmap block number ; D6.W - Index into bitmap block buffer ; D7.W - Index into extent record ; ; Called By: MountVol ; Function: Make sure the extents in the extent record are marked as ; allocated in the volume bitmap. The allocation blocks mapped ; by the extent record are marked in the bitmap if they weren't ; already marked (in which case D0 is set). ; ; Modification History: ; 3-Jul-85 PWD New today. ; <06Oct85> PWD Added check for errors after calls to ReadBM and NextWord ;_______________________________________________________________________ BlkChk: MOVE.L (SP)+,-(A6) ; Save return address MOVEM.L D1-D7/A1,-(A6) ; Save scratch registers MOVEA.L A0,A1 ; Save away the extent record pointer MOVEQ #0,D3 ; Clear trouble flag MOVEQ #0,D7 ; Prepare index into extent record @5 MOVE.W xdrStABN(A1,D7),D2 ; Pick up the first allocation block MOVEQ #0,D4 ; Clear upper word of D4 MOVE.W xdrNumABlks(A1,D7),D4 ; Pick up length of block run BEQ.S @90 ; If it's zero, we're all done BSR.S ReadBM ; Pick out the bit of interest BRA.S @50 ; Start out decrementing @10 BSET #31,D0 ; Make sure the bit is set BNE.S @30 ; If it was already set, allocation was OK MOVEQ #-1,D3 ; Otherwise, raise the trouble flag. JSR MarkBlock ; And mark the buffer dirty . .. <03Sep85> @30 ADDQ.W #1,D2 ; Advance to the next ABN ROL.L #1,D0 ; Rotate the bitmap long SUBQ.W #1,D1 ; That's one fewer bits left. BGT.S @50 ; If there are more in this D0, go for it TST.W D4 ; Any blocks left to examine? BEQ.S @60 ; If not, quit. BSR NextWord ; Pick up the next bitmap longword @50 TST.W D1 ; Any errors occur reading BM? BMI.S @95 ; If so, just punt right here & now . . . DBRA D4,@10 ; Go check next block in extent ROL.L D1,D0 ; Rotate D0 back into position @60 MOVE.L D0,0(A0,D6.W) ; Put the bitmap word back where it came from ADDQ.W #lenExt,D7 ; Advance to next extent CMP.W #lenXDR,D7 ; Hit the end of the extent record? BLO.S @5 ; If not, continue with next extent desc. @90 MOVE.L D3,D0 ; Return trouble flag @95 MOVEM.L (A6)+,D1-D7/A1 ; Restore scratch registers MOVE.L (A6)+,-(SP) ; Restore return address TST.L D0 ; Set condition codes RTS ; And call it a day. ;_______________________________________________________________________ ; ; Routine: UpdateFree ; Arguments: A2.L (input) -- VCB for volume ; ; Internal register usage: ; A0 - Pointed to bitmap buffer ; A1 - Pointed to extent record ; D0.W - Used to hold current bitmap word ; D1.W - Count of number of bits left unexamined in D0 ; D2.W - Allocation block currently being checked ; D4.L - Count of free blocks ; D5.W - Current bitmap block number ; D6.W - Index into bitmap block buffer ; ; Called By: MountVol ; Function: This routine is used as part of the MountVol consistency check ; to figure out the number of free allocation blocks in the volume. ; ; Modification History: ; <08Sep85> LAK New today. ; <06Oct85> PWD Added explicit check for errors after calls to ReadBM, NextWord ; Now calls NextBit. ;_______________________________________________________________________ UpdateFree: MOVE.L (SP)+,-(A6) ; save return address MOVEM.L D0-D6/A0-A1,-(A6) ; save all registers used MOVEQ #0,D4 ; start with zero free MOVEQ #0,D2 ; start at the beginning BSR.S ReadBM ; pick up the first bitmap block, set up D1, D0 MOVE.W VCBNmAlBlks(A2),D2 ; total number of allocation blocks @1 TST.W D1 ; Any error reading BM? BMI.S @9 ; If so, give up now TST.L D0 ; check high bit BMI.S @2 ; br if it's not free ADDQ.W #1,D4 ; increment free count @2 SUBQ.W #1,D2 ; one less block BEQ.S @3 ; br if we've finished BSR.S NextBit ; Pick up the next bitmap bit BRA.S @1 ; So keep trying @3 MOVE.W D4,VCBFreeBks(A2) ; update the free block count @9 MOVEM.L (A6)+,D0-D6/A0-A1 ; Restore registers MOVE.L (A6)+,-(SP) ; Restore return address RTS ; And call it a day. EJECT ;________________________________________________________________________________ ; ; Routine: ReadBM ; ; Function: Pick up the status bit for a particular block in the volume bitmap ; ; Input Arguments: ; A2 - Pointer to volume's VCB ; D2.W - Allocation block of interest ; ; Output: ; A0 - Pointed to bitmap block containing bit of interest ; D0.L - Relevant word of the bitmap, rotated so that the right bit is in [31] ; If an error is encountered reading the bitmap, D0 holds the error ; code, and D1 is negative ; D1.W - The number of bits originally to the right of the bit of interest ; D5.W - Bitmap block number (unsigned) ; D6.W - Index of relevant LongWord in bitmap block ; ; Side effects: ; The volume bitmap is read; the volume bitmap cache may be changed. ; ; Modification history: ; <06Oct85> PWD Changed to return error code and set D1 negative instead of ; calling _SysError. ;________________________________________________________________________________ ReadBM: MOVE.L jReadBM,-(SP) ; jumptable entry for vReadBM <27Oct86> RTS ; go there <27Oct86> vReadBM ; 'vectored' ReadBM routine <27Oct86> MOVE.L (SP)+,-(A6) ; Save return address MOVE.W D2,D5 ; Copy to extract BM block number LSR.W #8,D5 ; Shift to divide by almost 4096 (bits/block) LSR.W #4,D5 ; Finish the division by 4096 MOVE.W D2,D6 ; Copy to compute longword index AND.W #$0FE0,D6 ; Leave only middle 7 bits for index LSR.W #3,D6 ; Shift to divide by 8 (bits/byte) MOVE.W D2,D1 ; Copy to compute bit position AND.W #$001F,D1 ; Leave only lower 5 bits (bit position) BSR.S GetBMBlk ; Read the right bitmap block BEQ.S @10 ; Proceed if all seems well MOVEQ #-1,D1 ; Indicate an error occurred BRA.S @99 ; Without hope of continuing @10: MOVE.L 0(A0,D6.W),D0 ; Pick out the relevant longword ROL.L D1,D0 ; Rotate the bit into place [MSB] NEG.W D1 ; Subtract position from ADD.W #32,D1 ; 32 to get number of bits left unseen @99: MOVE.L (A6)+,-(SP) ; Restore return address RTS ; And call it a day. EJECT ;________________________________________________________________________________ ; ; Routine: NextBit ; ; Function: Pick up the next bit from the bitmap, rolling over to the next ; bitmap block if necessary. ; ; Arguments: D0.L - Current longword under examination ; D1.W - Number of bits left unexamined in D0 ; ; Side effects: ; The volume bitmap may be read, changing the cache state. ; ; Modification history: ; <06Oct85> PWD New today, filtered out of BlkAlloc/BlkDealloc ; <22Oct85> PWD Fixed bug in EOV check in FrBitScan ; <25Oct85> PWD Fixed to back up starting position before backing out at EOV. ;________________________________________________________________________________ NextBit: MOVE.L (SP)+,-(A6) ; Strip the stack for ,ASYNC I/O ROL.L #1,D0 ; Advance to next bit for examination SUBQ.W #1,D1 ; That's one fewer left unseen BNE.S NxtBitRTS ; If there are any left at all, we're all set. BSR.S NextWord ; Pick up the next bitmap word NxtBitRTS MOVE.L (A6)+,-(SP) ; Restore return address RTS ; And keep going ; Special routine for BlkAlloc free bit scan: FrBitScan: MOVE.L (SP)+,-(A6) ; Strip the stack for ,ASYNC I/O ADDQ.W #1,D2 ; Advance the starting position BSR.S NextBit ; And go pick up the next bit @0 CMP.L MinusOne,D0 ; Quick check: is it all ones (-1)? BNE.S NxtBitRTS ; Nope: go get 'em ADD.W D1,D2 ; Advance starting block by 32 CMP.W A1,D2 ; Reached the EOV? BCC.S @10 ; Yes - look no further BSR.S NextWord ; Go straight for a new word BRA.S @0 ; And try again @10 SUB.W D1,D2 ; Restore disk position BRA.S NxtBitRts ; And go use up the remainder ;________________________________________________________________________________ ; ; Routine: NextWord ; ; Function: Pick up the next word from the bitmap, rolling over to the next ; bitmap block if necessary. DOES NOT MARK THE CURRENT BUFFER DIRTY. ; ; Input Arguments: ; A0 - Pointer to bitmap buffer ; A2 - Pointer to VCB for volume being worked on ; D0 - Current bitmap word ; D5 - Bitmap block number ; D6 - LongWord index of the current word in the bitmap buffer ; ; Output: ; A0 - Pointed to current bitmap block buffer ; D0 - Next bitmap word or error code [if D1 < 0] ; D1 - Number of bits left unseen in D0 (always 32), <0 on error ; D5 - Number of current bitmap block ; D6 - Advanced to index of current LongWord in the bitmap buffer ; ; Side effects: ; The volume bitmap may be read, changing the cache state. ; ; Modification history: ; <06Oct85> PWD Changed to return error instead of calling _SysError when ; bitmap cannot be read. ;________________________________________________________________________________ ; NextWord: MOVE.L (SP)+,-(A6) ; Save return address MOVE.L D0,0(A0,D6.W) ; Store the current word ADDQ.W #4,D6 ; Bump the longword index CMPI.W #512,D6 ; Have we reached the end of BM block? BCS.S nwGetLong ; Nope - just pick out the next longword ADDQ.W #1,D5 ; Move on to the next bitmap block BSR.S GetBMBlk ; Read the new block in BEQ.S nwRstIndex ; Br if we got it <03Sep85> MOVEQ #-1,D1 ; Indicate an internal error occurred BRA.S nwExit ; Without hope of continuing nwRstIndex: CLR.W D6 ; Reset the index to the first longword nwGetLong: MOVE.L 0(A0,D6.W),D0 ; Read the next word from the bitmap buffer MOVEQ #32,D1 ; Set count for full longword nwExit MOVE.L (A6)+,-(SP) ; Restore return address RTS ; And call it a day. EJECT ;________________________________________________________________________________ ; ; Routine: GetBMBlk ; ; Function: Read a block out of the bitmap. The block will be read into cache ; storage; RelBMBlk should be called to write the page back to disk ; and release the storage. ; ; Input Arguments: ; D5.W - Bitmap block number ; A2 - Pointer to VCB for volume being worked on ; ; Output: ; A0 - Pointed to cache buffer containing bitmap block. ; D0 - Error code, 0 if block read successfully. ; ; Side effects: ; The volume bitmap is read; the volume bitmap cache may be changed. ;________________________________________________________________________________ GetBMBlk: MOVE.L (SP)+,-(A6) ; Save return address MOVEM.L D1-D2/A1-A2,-(A6) ; Save some registers from extinction MOVE.W VCBVRefNum(A2),D0 ; Set volume refNum MOVEQ #0,D2 ; Clear top of D2 MOVE.W VCBVBMSt(A2),D2 ; First sector in bitmap ADD.W D5,D2 ; Compute physical block wanted MOVEA.L VCBMAdr(A2),A1 ; Point to bitmap cache queue header MOVEQ #kGBrelease,D1 ; release it immediately (we work on <01Oct85> ; one at a time anyway - call MarkBlock later if dirtied) JSR GetBlock ; Actually read the sector MOVEM.L (A6)+,D1-D2/A1-A2 ; Restore registers MOVE.L (A6)+,-(SP) ; Restore return address TST.W D0 ; Set status codes for return RTS ; And call it a day. END