Fixed issue with lookahead trusting old lookahead blocks

One of the big simplifications in littlefs's implementation is the
complete lack of tracking free blocks, allowing operations to simply
drop blocks that are no longer in use.

However, this means the lookahead buffer can easily contain outdated
blocks that were previously deleted. This is usually fine, as littlefs
will rescan the storage if it can't find a free block in the lookahead
buffer, but after changes that caused littlefs to more conservatively
respect the alloc acks (e611cf5), any scanned blocks after an ack would
be incorrectly trusted.

The fix is to eagerly scan ahead in the lookahead when we allocate so
that alloc acks are better able to discredit old lookahead blocks. Since
usually alloc acks are tightly coupled to allocations of one or two blocks,
this allows littlefs to properly rescan every set of allocations.

This may still be a concern if there is a long series of worn out
blocks, but in the worst case littlefs will conservatively avoid using
blocks it's not sure about.

Found by davidefer
This commit is contained in:
Christopher Haster
2018-04-06 17:00:29 -05:00
parent 43eac3083b
commit 89a7630d84
2 changed files with 134 additions and 2 deletions

11
lfs.c
View File

@@ -290,6 +290,15 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) {
// found a free block
*block = (lfs->free.begin + off) % lfs->cfg->block_count;
// eagerly find next off so an alloc ack can
// discredit old lookahead blocks
while (lfs->free.off != lfs->free.size &&
(lfs->free.buffer[lfs->free.off / 32] &
(1U << (lfs->free.off % 32)))) {
lfs->free.off += 1;
}
return 0;
}
}
@@ -315,7 +324,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
}
static void lfs_alloc_ack(lfs_t *lfs) {
lfs->free.ack = lfs->free.off-1 + lfs->free.begin + lfs->cfg->block_count;
lfs->free.ack = lfs->free.begin+lfs->free.off + lfs->cfg->block_count;
}