diff options
author | Christopher Haster <geky@geky.net> | 2023-09-21 21:01:19 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-21 21:01:19 +0300 |
commit | 0eb52a2df1ce6ee7993ba70ef3c9d29a05e03563 (patch) | |
tree | 57fc8bac75895ac308bc3c809dfd81c2e630323f | |
parent | 1ba4ed03f085d424198c7b14a47cac566b252e39 (diff) | |
parent | 6b33ee5e34a29508e928dce2e6f32d3c6936131a (diff) |
Merge pull request #875 from littlefs-project/fs-gc
Add lfs_fs_gc to enable proactive finding of free blocks
-rw-r--r-- | lfs.c | 48 | ||||
-rw-r--r-- | lfs.h | 12 | ||||
-rw-r--r-- | tests/test_alloc.toml | 18 |
3 files changed, 68 insertions, 10 deletions
@@ -623,6 +623,26 @@ 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->free.i) + // lfs->free.i is equal lfs->free.size when all blocks are used + lfs->free.off = (lfs->free.off + lfs->free.i) % lfs->block_count; + lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack); + lfs->free.i = 0; + + // find mask of free blocks from tree + memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); + int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); + if (err) { + lfs_alloc_drop(lfs); + return err; + } + + return 0; +} +#endif + +#ifndef LFS_READONLY static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { while (lfs->free.i != lfs->free.size) { @@ -654,16 +674,8 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { return LFS_ERR_NOSPC; } - lfs->free.off = (lfs->free.off + lfs->free.size) - % lfs->block_count; - lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack); - lfs->free.i = 0; - - // find mask of free blocks from tree - memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); - if (err) { - lfs_alloc_drop(lfs); + int err = lfs_fs_rawgc(lfs); + if(err) { return err; } } @@ -6239,6 +6251,22 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) { } #ifndef LFS_READONLY +int lfs_fs_gc(lfs_t *lfs) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs); + + err = lfs_fs_rawgc(lfs); + + LFS_TRACE("lfs_fs_gc -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +#ifndef LFS_READONLY int lfs_fs_mkconsistent(lfs_t *lfs) { int err = LFS_LOCK(lfs->cfg); if (err) { @@ -712,6 +712,18 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); // Returns a negative error code on failure. int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); +// Attempt to proactively find free blocks +// +// Calling this function is not required, but may allowing the offloading of +// the expensive block allocation scan to a less time-critical code path. +// +// Note: littlefs currently does not persist any found free blocks to disk. +// This may change in the future. +// +// Returns a negative error code on failure. Finding no free blocks is +// not an error. +int lfs_fs_gc(lfs_t *lfs); + #ifndef LFS_READONLY // Attempt to make the filesystem consistent and ready for writing // diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml index 916fc2a..e6fba97 100644 --- a/tests/test_alloc.toml +++ b/tests/test_alloc.toml @@ -6,6 +6,7 @@ if = 'BLOCK_CYCLES == -1' [cases.test_alloc_parallel] defines.FILES = 3 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +defines.GC = [false, true] code = ''' const char *names[] = {"bacon", "eggs", "pancakes"}; lfs_file_t files[FILES]; @@ -24,6 +25,9 @@ code = ''' LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; } for (int n = 0; n < FILES; n++) { + if (GC) { + lfs_fs_gc(&lfs) => 0; + } size_t size = strlen(names[n]); for (lfs_size_t i = 0; i < SIZE; i += size) { lfs_file_write(&lfs, &files[n], names[n], size) => size; @@ -55,6 +59,7 @@ code = ''' [cases.test_alloc_serial] defines.FILES = 3 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +defines.GC = [false, true] code = ''' const char *names[] = {"bacon", "eggs", "pancakes"}; @@ -75,6 +80,9 @@ code = ''' uint8_t buffer[1024]; memcpy(buffer, names[n], size); for (int i = 0; i < SIZE; i += size) { + if (GC) { + lfs_fs_gc(&lfs) => 0; + } lfs_file_write(&lfs, &file, buffer, size) => size; } lfs_file_close(&lfs, &file) => 0; @@ -247,6 +255,9 @@ code = ''' } res => LFS_ERR_NOSPC; + // note that lfs_fs_gc should not error here + lfs_fs_gc(&lfs) => 0; + lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; @@ -298,6 +309,9 @@ code = ''' } res => LFS_ERR_NOSPC; + // note that lfs_fs_gc should not error here + lfs_fs_gc(&lfs) => 0; + lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; @@ -337,6 +351,8 @@ code = ''' count += 1; } err => LFS_ERR_NOSPC; + // note that lfs_fs_gc should not error here + lfs_fs_gc(&lfs) => 0; lfs_file_close(&lfs, &file) => 0; lfs_remove(&lfs, "exhaustion") => 0; @@ -435,6 +451,8 @@ code = ''' break; } } + // note that lfs_fs_gc should not error here + lfs_fs_gc(&lfs) => 0; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; |