Skip to content

Commit

Permalink
Reworked the block allocator so the logic is hopefully simpler
Browse files Browse the repository at this point in the history
Some of this is just better documentation, some of this is reworking the
logic to be more intention driven... if that makes sense...
  • Loading branch information
geky committed Dec 20, 2023
1 parent 7b68441 commit 1f9c3c0
Showing 1 changed file with 40 additions and 24 deletions.
64 changes: 40 additions & 24 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,9 +607,10 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
}
#endif

// indicate allocated blocks have been committed into the filesystem, this
// is to prevent blocks from being garbage collected in the middle of a
// commit operation
// allocations should call this when all allocated blocks are committed to
// the filesystem
//
// after a checkpoint, the block allocator may realloc any untracked blocks
static void lfs_alloc_ckpoint(lfs_t *lfs) {
lfs->lookahead.ckpoint = lfs->block_count;
}
Expand All @@ -624,14 +625,16 @@ static void lfs_alloc_drop(lfs_t *lfs) {

#ifndef LFS_READONLY
static int lfs_fs_rawgc(lfs_t *lfs) {
// Move free offset at the first unused block (lfs->lookahead.next)
// lfs->lookahead.next is equal lfs->lookahead.size when all blocks are used
// move lookahead buffer to the first unused block
//
// note we limit the lookahead buffer to at most the amount of blocks
// checkpointed, this prevents the math in lfs_alloc from underflowing
lfs->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next)
% lfs->block_count;
lfs->lookahead.next = 0;
lfs->lookahead.size = lfs_min(
8*lfs->cfg->lookahead_size,
lfs->lookahead.ckpoint);
lfs->lookahead.next = 0;

// find mask of free blocks from tree
memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
Expand All @@ -648,35 +651,48 @@ static int lfs_fs_rawgc(lfs_t *lfs) {
#ifndef LFS_READONLY
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
while (true) {
while (lfs->lookahead.next != lfs->lookahead.size) {
lfs_block_t off = lfs->lookahead.next;
lfs->lookahead.next += 1;
lfs->lookahead.ckpoint -= 1;

if (!(lfs->lookahead.buffer[off / 32] & (1U << (off % 32)))) {
// scan our lookahead buffer for free blocks
while (lfs->lookahead.next < lfs->lookahead.size) {
if (!(lfs->lookahead.buffer[lfs->lookahead.next / 32]
& (1U << (lfs->lookahead.next % 32)))) {
// found a free block
*block = (lfs->lookahead.start + off) % lfs->block_count;
*block = (lfs->lookahead.start + lfs->lookahead.next)
% lfs->block_count;

// eagerly find next off so an alloc ack can
// discredit old lookahead blocks
while (lfs->lookahead.next != lfs->lookahead.size &&
(lfs->lookahead.buffer[lfs->lookahead.next / 32]
& (1U << (lfs->lookahead.next % 32)))) {
// eagerly find next free block to maximize how many blocks
// lfs_alloc_ckpoint makes available for scanning
while (true) {
lfs->lookahead.next += 1;
lfs->lookahead.ckpoint -= 1;
}

return 0;
if (lfs->lookahead.next >= lfs->lookahead.size
|| !(lfs->lookahead.buffer[lfs->lookahead.next / 32]
& (1U << (lfs->lookahead.next % 32)))) {
return 0;
}
}
}

lfs->lookahead.next += 1;
lfs->lookahead.ckpoint -= 1;
}

// check if we have looked at all blocks since last ack
if (lfs->lookahead.ckpoint == 0) {
LFS_ERROR("No more free space %"PRIu32,
lfs->lookahead.next + lfs->lookahead.start);
// In order to keep our block allocator from spinning forever when our
// filesystem is full, we mark points where there are no in-flight
// allocations with a checkpoint before starting a set of allocations.
//
// If we've looked at all blocks since the last checkpoint, we report
// the filesystem as out of storage.
//
if (lfs->lookahead.ckpoint <= 0) {
LFS_ERROR("No more free space 0x%"PRIx32,
(lfs->lookahead.start + lfs->lookahead.next)
% lfs->cfg->block_count);
return LFS_ERR_NOSPC;
}

// No blocks in our lookahead buffer, we need to scan the filesystem for
// unused blocks in the next lookahead window.
int err = lfs_fs_rawgc(lfs);
if(err) {
return err;
Expand Down

0 comments on commit 1f9c3c0

Please sign in to comment.