Skip to content

Commit 951e70f

Browse files
authored
Merge pull request #6604 from geky/lfs-fix-lookahead-trust
littlefs: Fix some issues with lookahead trust
2 parents 13913c7 + 9e03b24 commit 951e70f

File tree

3 files changed

+153
-20
lines changed

3 files changed

+153
-20
lines changed

features/filesystem/littlefs/littlefs/lfs.c

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,7 @@ int lfs_deorphan(lfs_t *lfs);
270270
static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
271271
lfs_t *lfs = p;
272272

273-
lfs_block_t off = (((lfs_soff_t)(block - lfs->free.begin)
274-
% (lfs_soff_t)(lfs->cfg->block_count))
273+
lfs_block_t off = ((block - lfs->free.off)
275274
+ lfs->cfg->block_count) % lfs->cfg->block_count;
276275

277276
if (off < lfs->free.size) {
@@ -283,27 +282,38 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
283282

284283
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
285284
while (true) {
286-
while (lfs->free.off != lfs->free.size) {
287-
lfs_block_t off = lfs->free.off;
288-
lfs->free.off += 1;
285+
while (lfs->free.index != lfs->free.size) {
286+
lfs_block_t off = lfs->free.index;
287+
lfs->free.index += 1;
288+
lfs->free.ack -= 1;
289289

290290
if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) {
291291
// found a free block
292-
*block = (lfs->free.begin + off) % lfs->cfg->block_count;
292+
*block = (lfs->free.off + off) % lfs->cfg->block_count;
293+
294+
// eagerly find next off so an alloc ack can
295+
// discredit old lookahead blocks
296+
while (lfs->free.index != lfs->free.size &&
297+
(lfs->free.buffer[lfs->free.index / 32]
298+
& (1U << (lfs->free.index % 32)))) {
299+
lfs->free.index += 1;
300+
lfs->free.ack -= 1;
301+
}
302+
293303
return 0;
294304
}
295305
}
296306

297307
// check if we have looked at all blocks since last ack
298-
if (lfs->free.off == lfs->free.ack - lfs->free.begin) {
299-
LFS_WARN("No more free space %ld", lfs->free.off + lfs->free.begin);
308+
if (lfs->free.ack == 0) {
309+
LFS_WARN("No more free space %ld", lfs->free.index+lfs->free.off);
300310
return LFS_ERR_NOSPC;
301311
}
302312

303-
lfs->free.begin += lfs->free.size;
304-
lfs->free.size = lfs_min(lfs->cfg->lookahead,
305-
lfs->free.ack - lfs->free.begin);
306-
lfs->free.off = 0;
313+
lfs->free.off = (lfs->free.off + lfs->free.size)
314+
% lfs->cfg->block_count;
315+
lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->free.ack);
316+
lfs->free.index = 0;
307317

308318
// find mask of free blocks from tree
309319
memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
@@ -315,7 +325,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
315325
}
316326

317327
static void lfs_alloc_ack(lfs_t *lfs) {
318-
lfs->free.ack = lfs->free.off-1 + lfs->free.begin + lfs->cfg->block_count;
328+
lfs->free.ack = lfs->cfg->block_count;
319329
}
320330

321331

@@ -2094,9 +2104,9 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
20942104

20952105
// create free lookahead
20962106
memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
2097-
lfs->free.begin = 0;
2098-
lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
20992107
lfs->free.off = 0;
2108+
lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
2109+
lfs->free.index = 0;
21002110
lfs_alloc_ack(lfs);
21012111

21022112
// create superblock dir
@@ -2173,9 +2183,9 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
21732183
}
21742184

21752185
// setup free lookahead
2176-
lfs->free.begin = 0;
2177-
lfs->free.size = 0;
21782186
lfs->free.off = 0;
2187+
lfs->free.size = 0;
2188+
lfs->free.index = 0;
21792189
lfs_alloc_ack(lfs);
21802190

21812191
// load superblock

features/filesystem/littlefs/littlefs/lfs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,9 @@ typedef struct lfs_superblock {
259259
} lfs_superblock_t;
260260

261261
typedef struct lfs_free {
262-
lfs_block_t begin;
263-
lfs_block_t size;
264262
lfs_block_t off;
263+
lfs_block_t size;
264+
lfs_block_t index;
265265
lfs_block_t ack;
266266
uint32_t *buffer;
267267
} lfs_free_t;

features/filesystem/littlefs/littlefs/tests/test_alloc.sh

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ tests/test.py << TEST
289289
}
290290
lfs_file_close(&lfs, &file[0]) => 0;
291291
292-
// open whole
292+
// open hole
293293
lfs_remove(&lfs, "bump") => 0;
294294
295295
lfs_mkdir(&lfs, "splitdir") => 0;
@@ -301,5 +301,128 @@ tests/test.py << TEST
301301
lfs_unmount(&lfs) => 0;
302302
TEST
303303

304+
echo "--- Outdated lookahead test ---"
305+
rm -rf blocks
306+
tests/test.py << TEST
307+
lfs_format(&lfs, &cfg) => 0;
308+
309+
lfs_mount(&lfs, &cfg) => 0;
310+
311+
// fill completely with two files
312+
lfs_file_open(&lfs, &file[0], "exhaustion1",
313+
LFS_O_WRONLY | LFS_O_CREAT) => 0;
314+
size = strlen("blahblahblahblah");
315+
memcpy(buffer, "blahblahblahblah", size);
316+
for (lfs_size_t i = 0;
317+
i < ((cfg.block_count-4)/2)*(cfg.block_size-8);
318+
i += size) {
319+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
320+
}
321+
lfs_file_close(&lfs, &file[0]) => 0;
322+
323+
lfs_file_open(&lfs, &file[0], "exhaustion2",
324+
LFS_O_WRONLY | LFS_O_CREAT) => 0;
325+
size = strlen("blahblahblahblah");
326+
memcpy(buffer, "blahblahblahblah", size);
327+
for (lfs_size_t i = 0;
328+
i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8);
329+
i += size) {
330+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
331+
}
332+
lfs_file_close(&lfs, &file[0]) => 0;
333+
334+
// remount to force reset of lookahead
335+
lfs_unmount(&lfs) => 0;
336+
337+
lfs_mount(&lfs, &cfg) => 0;
338+
339+
// rewrite one file
340+
lfs_file_open(&lfs, &file[0], "exhaustion1",
341+
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
342+
lfs_file_sync(&lfs, &file[0]) => 0;
343+
size = strlen("blahblahblahblah");
344+
memcpy(buffer, "blahblahblahblah", size);
345+
for (lfs_size_t i = 0;
346+
i < ((cfg.block_count-4)/2)*(cfg.block_size-8);
347+
i += size) {
348+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
349+
}
350+
lfs_file_close(&lfs, &file[0]) => 0;
351+
352+
// rewrite second file, this requires lookahead does not
353+
// use old population
354+
lfs_file_open(&lfs, &file[0], "exhaustion2",
355+
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
356+
lfs_file_sync(&lfs, &file[0]) => 0;
357+
size = strlen("blahblahblahblah");
358+
memcpy(buffer, "blahblahblahblah", size);
359+
for (lfs_size_t i = 0;
360+
i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8);
361+
i += size) {
362+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
363+
}
364+
lfs_file_close(&lfs, &file[0]) => 0;
365+
TEST
366+
367+
echo "--- Outdated lookahead and split dir test ---"
368+
rm -rf blocks
369+
tests/test.py << TEST
370+
lfs_format(&lfs, &cfg) => 0;
371+
372+
lfs_mount(&lfs, &cfg) => 0;
373+
374+
// fill completely with two files
375+
lfs_file_open(&lfs, &file[0], "exhaustion1",
376+
LFS_O_WRONLY | LFS_O_CREAT) => 0;
377+
size = strlen("blahblahblahblah");
378+
memcpy(buffer, "blahblahblahblah", size);
379+
for (lfs_size_t i = 0;
380+
i < ((cfg.block_count-4)/2)*(cfg.block_size-8);
381+
i += size) {
382+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
383+
}
384+
lfs_file_close(&lfs, &file[0]) => 0;
385+
386+
lfs_file_open(&lfs, &file[0], "exhaustion2",
387+
LFS_O_WRONLY | LFS_O_CREAT) => 0;
388+
size = strlen("blahblahblahblah");
389+
memcpy(buffer, "blahblahblahblah", size);
390+
for (lfs_size_t i = 0;
391+
i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8);
392+
i += size) {
393+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
394+
}
395+
lfs_file_close(&lfs, &file[0]) => 0;
396+
397+
// remount to force reset of lookahead
398+
lfs_unmount(&lfs) => 0;
399+
400+
lfs_mount(&lfs, &cfg) => 0;
401+
402+
// rewrite one file with a hole of one block
403+
lfs_file_open(&lfs, &file[0], "exhaustion1",
404+
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
405+
lfs_file_sync(&lfs, &file[0]) => 0;
406+
size = strlen("blahblahblahblah");
407+
memcpy(buffer, "blahblahblahblah", size);
408+
for (lfs_size_t i = 0;
409+
i < ((cfg.block_count-4)/2 - 1)*(cfg.block_size-8);
410+
i += size) {
411+
lfs_file_write(&lfs, &file[0], buffer, size) => size;
412+
}
413+
lfs_file_close(&lfs, &file[0]) => 0;
414+
415+
// try to allocate a directory, should fail!
416+
lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC;
417+
418+
// file should not fail
419+
lfs_file_open(&lfs, &file[0], "notasplit",
420+
LFS_O_WRONLY | LFS_O_CREAT) => 0;
421+
lfs_file_write(&lfs, &file[0], "hi", 2) => 2;
422+
lfs_file_close(&lfs, &file[0]) => 0;
423+
424+
lfs_unmount(&lfs) => 0;
425+
TEST
426+
304427
echo "--- Results ---"
305428
tests/stats.py

0 commit comments

Comments
 (0)