fs: implement block reuse in fsAlloc

This commit is contained in:
Virgil Dupras 2019-04-23 14:00:54 -04:00
parent 684f083e8e
commit ad217c018e

View File

@ -47,6 +47,11 @@
; The last block of the chain is either a block that has no valid block next to ; The last block of the chain is either a block that has no valid block next to
; it or a block that reports a 0 allocated block count. ; it or a block that reports a 0 allocated block count.
; ;
; However, to simplify processing, whenever fsNext encounter a chain end of the
; first type (a valid block with > 0 allocated blocks), it places an empty block
; at the end of the chain. This makes the whole "end of chain" processing much
; easier: we assume that we always have a 0 block at the end.
;
; *** Deleted files ; *** Deleted files
; ;
; When a file is deleted, its name is set to null. This indicates that the ; When a file is deleted, its name is set to null. This indicates that the
@ -135,7 +140,6 @@ fsBegin:
; Sets Z according to whether we moved. ; Sets Z according to whether we moved.
fsNext: fsNext:
push bc push bc
push de
push hl push hl
ld a, (FS_META+FS_META_ALLOC_OFFSET) ld a, (FS_META+FS_META_ALLOC_OFFSET)
cp 0 cp 0
@ -149,27 +153,27 @@ fsNext:
call blkSeek call blkSeek
djnz .loop djnz .loop
; Good, were here. We're going to read meta from our current position. ; Good, were here. We're going to read meta from our current position.
; But before we do, let's keep a copy of FS_PTR around. We might need
; to go back.
ld de, (FS_PTR)
call blkTell ; --> HL call blkTell ; --> HL
ld (FS_PTR), hl ld (FS_PTR), hl
call fsReadMeta call fsReadMeta
jr nz, .goback ; error! let's bail out jr nz, .createChainEnd
call fsIsValid call fsIsValid
jr nz, .goback ; error! let's bail out jr nz, .createChainEnd
; We're good! We have a valid FS block and FS_PTR is already updated. ; We're good! We have a valid FS block and FS_PTR is already updated.
; Meta is already read. Nothing to do! ; Meta is already read. Nothing to do!
cp a ; ensure Z cp a ; ensure Z
jr .end jr .end
.goback: .createChainEnd:
ld (FS_PTR), de ; We are on an invalid block where a valid block should be. This is
call fsReadMeta ; the end of the line, but we should mark it a bit more explicitly.
; Let's initialize an empty block
call fsInitMeta
call fsWriteMeta
; continue out to error condition: we're still at the end of the line.
.error: .error:
call unsetZ call unsetZ
.end: .end:
pop hl pop hl
pop de
pop bc pop bc
ret ret
@ -202,6 +206,7 @@ fsWriteMeta:
; Initializes FS_META with "CFS" followed by zeroes ; Initializes FS_META with "CFS" followed by zeroes
fsInitMeta: fsInitMeta:
push af push af
push bc
push de push de
push hl push hl
ld hl, P_FS_MAGIC ld hl, P_FS_MAGIC
@ -213,6 +218,7 @@ fsInitMeta:
call fill call fill
pop hl pop hl
pop de pop de
pop bc
pop af pop af
ret ret
@ -239,36 +245,33 @@ fsPlace:
fsAlloc: fsAlloc:
push bc push bc
push de push de
push hl ; keep HL for later ld c, a ; Let's store our A arg somewhere...
push af ; keep A for later
; First step: find last block
call fsBegin call fsBegin
ret nz ; not a valid block? hum, something's wrong jr nz, .end ; not a valid block? hum, something's wrong
; First step: find last block
push hl ; keep HL for later
.loop1: .loop1:
call fsNext call fsNext
jr z, .loop1 jr nz, .found ; end of the line
call fsIsDeleted
jr nz, .loop1 ; not deleted? loop
; This is a deleted block. Maybe it fits...
ld a, (FS_META+FS_META_ALLOC_OFFSET)
cp c ; Same as asked size?
jr z, .found ; yes? great!
; TODO: handle case where C < A (block splitting)
jr .loop1
.found:
call fsPlace ; Make sure that our block device points to call fsPlace ; Make sure that our block device points to
; the beginning of our FS block ; the beginning of our FS block
; We've reached last block. Two situations are possible at this point: ; We've reached last block. Two situations are possible at this point:
; 1 - the block is unallocated (0 alloc size) ; 1 - the block is the "end of line" block
; 2 - the block is allocated, but there are no next block ; 2 - the block is a deleted block that we we're re-using.
; So, what we need to do is check our allocation size ; In both case, the processing is the same: write new metadata.
ld a, (FS_META+FS_META_ALLOC_OFFSET)
cp 0
jr z, .proceed ; 0 allocated blocks? this is our block
; > 0 allocated blocks. We need to allocate further
ld b, a ; we will seek A times
ld a, BLOCKDEV_SEEK_FORWARD
ld hl, FS_BLOCKSIZE
.loop2:
call blkSeek
djnz .loop2
.proceed:
; At this point, the blockdev is placed right where we want to allocate ; At this point, the blockdev is placed right where we want to allocate
; But first, let's prepare the FS_META we're going to write ; But first, let's prepare the FS_META we're going to write
call fsInitMeta call fsInitMeta
pop af ; now we want our A arg ld a, c ; C == the number of blocks user asked for
ld a, 1
ld (FS_META+FS_META_ALLOC_OFFSET), a ld (FS_META+FS_META_ALLOC_OFFSET), a
pop hl ; now we want our HL arg pop hl ; now we want our HL arg
ld de, FS_META+FS_META_FNAME_OFFSET ld de, FS_META+FS_META_FNAME_OFFSET
@ -280,6 +283,7 @@ fsAlloc:
ld (FS_PTR), hl ld (FS_PTR), hl
; Ok, now we can write our metadata ; Ok, now we can write our metadata
call fsWriteMeta call fsWriteMeta
.end:
pop de pop de
pop bc pop bc
ret ret