Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lfs.c
diff options
context:
space:
mode:
authorChristopher Haster <chaster@utexas.edu>2018-02-08 10:30:21 +0300
committerChristopher Haster <chaster@utexas.edu>2018-02-08 10:52:39 +0300
commite611cf5050fc44acb97057654b6885ec9b060915 (patch)
tree380ea72c56ad27f1e608c19fd110bc7903196258 /lfs.c
parenta25743a82a5a3c074e492aeba912373ef2e74288 (diff)
Fix incorrect lookahead population before ack
Rather than tracking all in-flight blocks blocks during a lookahead, littlefs uses an ack scheme to mark the first allocated block that hasn't reached the disk yet. littlefs assumes all blocks since the last ack are bad or in-flight, and uses this to know when it's out of storage. However, these unacked allocations were still being populated in the lookahead buffer. If the whole block device fits in the lookahead buffer, _and_ littlefs managed to scan around the whole storage while an unacked block was still in-flight, it would assume the block was free and misallocate it. The fix is to only fill the lookahead buffer up to the last ack. The internal free structure was restructured to simplify the runtime calculation of lookahead size.
Diffstat (limited to 'lfs.c')
-rw-r--r--lfs.c38
1 files changed, 18 insertions, 20 deletions
diff --git a/lfs.c b/lfs.c
index b21d209..b7cc675 100644
--- a/lfs.c
+++ b/lfs.c
@@ -278,7 +278,7 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
% (lfs_soff_t)(lfs->cfg->block_count))
+ lfs->cfg->block_count) % lfs->cfg->block_count;
- if (off < lfs->cfg->lookahead) {
+ if (off < lfs->free.size) {
lfs->free.buffer[off / 32] |= 1U << (off % 32);
}
@@ -287,18 +287,7 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
while (true) {
- while (true) {
- // check if we have looked at all blocks since last ack
- if (lfs->free.begin + lfs->free.off == lfs->free.end) {
- LFS_WARN("No more free space %d", lfs->free.end);
- return LFS_ERR_NOSPC;
- }
-
- if (lfs->free.off >= lfs_min(
- lfs->cfg->lookahead, lfs->cfg->block_count)) {
- break;
- }
-
+ while (lfs->free.off != lfs->free.size) {
lfs_block_t off = lfs->free.off;
lfs->free.off += 1;
@@ -309,7 +298,15 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
}
}
- lfs->free.begin += lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
+ // check if we have looked at all blocks since last ack
+ if (lfs->free.off == lfs->free.ack - lfs->free.begin) {
+ LFS_WARN("No more free space %d", lfs->free.off + lfs->free.begin);
+ return LFS_ERR_NOSPC;
+ }
+
+ lfs->free.begin += lfs->free.size;
+ lfs->free.size = lfs_min(lfs->cfg->lookahead,
+ lfs->free.ack - lfs->free.begin);
lfs->free.off = 0;
// find mask of free blocks from tree
@@ -322,7 +319,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
}
static void lfs_alloc_ack(lfs_t *lfs) {
- lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count;
+ lfs->free.ack = lfs->free.off-1 + lfs->free.begin + lfs->cfg->block_count;
}
@@ -2035,11 +2032,11 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
// create free lookahead
memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
lfs->free.begin = 0;
+ lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
lfs->free.off = 0;
- lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count;
+ lfs_alloc_ack(lfs);
// create superblock dir
- lfs_alloc_ack(lfs);
lfs_dir_t superdir;
err = lfs_dir_alloc(lfs, &superdir);
if (err) {
@@ -2112,9 +2109,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
}
// setup free lookahead
- lfs->free.begin = -lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
- lfs->free.off = -lfs->free.begin;
- lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count;
+ lfs->free.begin = 0;
+ lfs->free.size = 0;
+ lfs->free.off = 0;
+ lfs_alloc_ack(lfs);
// load superblock
lfs_dir_t dir;