Reworked the block allocator so the logic is hopefully simpler
Some of this is just better documentation, some of this is reworking the logic to be more intention driven... if that makes sense...
This commit is contained in:
@@ -607,9 +607,10 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// indicate allocated blocks have been committed into the filesystem, this
|
// allocations should call this when all allocated blocks are committed to
|
||||||
// is to prevent blocks from being garbage collected in the middle of a
|
// the filesystem
|
||||||
// commit operation
|
//
|
||||||
|
// after a checkpoint, the block allocator may realloc any untracked blocks
|
||||||
static void lfs_alloc_ckpoint(lfs_t *lfs) {
|
static void lfs_alloc_ckpoint(lfs_t *lfs) {
|
||||||
lfs->lookahead.ckpoint = lfs->block_count;
|
lfs->lookahead.ckpoint = lfs->block_count;
|
||||||
}
|
}
|
||||||
@@ -624,14 +625,16 @@ static void lfs_alloc_drop(lfs_t *lfs) {
|
|||||||
|
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static int lfs_fs_rawgc(lfs_t *lfs) {
|
static int lfs_fs_rawgc(lfs_t *lfs) {
|
||||||
// Move free offset at the first unused block (lfs->lookahead.next)
|
// move lookahead buffer to the first unused block
|
||||||
// lfs->lookahead.next is equal lfs->lookahead.size when all blocks are used
|
//
|
||||||
|
// 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->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next)
|
||||||
% lfs->block_count;
|
% lfs->block_count;
|
||||||
|
lfs->lookahead.next = 0;
|
||||||
lfs->lookahead.size = lfs_min(
|
lfs->lookahead.size = lfs_min(
|
||||||
8*lfs->cfg->lookahead_size,
|
8*lfs->cfg->lookahead_size,
|
||||||
lfs->lookahead.ckpoint);
|
lfs->lookahead.ckpoint);
|
||||||
lfs->lookahead.next = 0;
|
|
||||||
|
|
||||||
// find mask of free blocks from tree
|
// find mask of free blocks from tree
|
||||||
memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
|
memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
|
||||||
@@ -648,35 +651,48 @@ static int lfs_fs_rawgc(lfs_t *lfs) {
|
|||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
|
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
|
||||||
while (true) {
|
while (true) {
|
||||||
while (lfs->lookahead.next != lfs->lookahead.size) {
|
// scan our lookahead buffer for free blocks
|
||||||
lfs_block_t off = lfs->lookahead.next;
|
while (lfs->lookahead.next < lfs->lookahead.size) {
|
||||||
lfs->lookahead.next += 1;
|
if (!(lfs->lookahead.buffer[lfs->lookahead.next / 32]
|
||||||
lfs->lookahead.ckpoint -= 1;
|
& (1U << (lfs->lookahead.next % 32)))) {
|
||||||
|
|
||||||
if (!(lfs->lookahead.buffer[off / 32] & (1U << (off % 32)))) {
|
|
||||||
// found a free block
|
// 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
|
// eagerly find next free block to maximize how many blocks
|
||||||
// discredit old lookahead blocks
|
// lfs_alloc_ckpoint makes available for scanning
|
||||||
while (lfs->lookahead.next != lfs->lookahead.size &&
|
while (true) {
|
||||||
(lfs->lookahead.buffer[lfs->lookahead.next / 32]
|
|
||||||
& (1U << (lfs->lookahead.next % 32)))) {
|
|
||||||
lfs->lookahead.next += 1;
|
lfs->lookahead.next += 1;
|
||||||
lfs->lookahead.ckpoint -= 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
|
// In order to keep our block allocator from spinning forever when our
|
||||||
if (lfs->lookahead.ckpoint == 0) {
|
// filesystem is full, we mark points where there are no in-flight
|
||||||
LFS_ERROR("No more free space %"PRIu32,
|
// allocations with a checkpoint before starting a set of allocations.
|
||||||
lfs->lookahead.next + lfs->lookahead.start);
|
//
|
||||||
|
// 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;
|
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);
|
int err = lfs_fs_rawgc(lfs);
|
||||||
if(err) {
|
if(err) {
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
Reference in New Issue
Block a user