From 8f9427dd53cc3f5eb9194f1235e6357fab5b476d Mon Sep 17 00:00:00 2001 From: Brian Pugh Date: Sun, 29 Oct 2023 13:50:38 -0700 Subject: [PATCH 01/17] Add value-range checks for user-definable macros --- lfs.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lfs.c b/lfs.c index 0827331c..6c517a42 100644 --- a/lfs.c +++ b/lfs.c @@ -8,6 +8,23 @@ #include "lfs.h" #include "lfs_util.h" +// Configuration Sanity Check +#if (LFS_NAME_MAX <= 0) || (LFS_NAME_MAX > 1022) +#error "LFS_NAME_MAX must be in the range (0, 1022]" +#endif + +#if (LFS_FILE_MAX <= 0) || (LFS_FILE_MAX > 4294967296) +#error "LFS_FILE_MAX must be in the range (0, 4294967296]" +#endif + +#if (LFS_FILE_MAX > 2147483647) +#warning "LFS_FILE_MAX>2147483647; lfs_file_seek, lfs_file_size, and lfs_file_tell will not function properly." +#endif + +#if (LFS_ATTR_MAX < 0) || (LFS_ATTR_MAX > 1022) +#error "LFS_ATTR_MAX must be in the range [0, 1022]" +#endif + // some constants used throughout the code #define LFS_BLOCK_NULL ((lfs_block_t)-1) From c531a5e88f09e71f948725131ec47bb5776d6108 Mon Sep 17 00:00:00 2001 From: Brian Pugh Date: Mon, 30 Oct 2023 11:18:20 -0700 Subject: [PATCH 02/17] Replace erroneous LFS_FILE_MAX upper bound 4294967296 to 4294967295 --- lfs.c | 4 ++-- lfs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lfs.c b/lfs.c index 6c517a42..a18752c4 100644 --- a/lfs.c +++ b/lfs.c @@ -13,8 +13,8 @@ #error "LFS_NAME_MAX must be in the range (0, 1022]" #endif -#if (LFS_FILE_MAX <= 0) || (LFS_FILE_MAX > 4294967296) -#error "LFS_FILE_MAX must be in the range (0, 4294967296]" +#if (LFS_FILE_MAX <= 0) || (LFS_FILE_MAX > 4294967295) +#error "LFS_FILE_MAX must be in the range (0, 4294967295]" #endif #if (LFS_FILE_MAX > 2147483647) diff --git a/lfs.h b/lfs.h index 9eeab230..d7f61367 100644 --- a/lfs.h +++ b/lfs.h @@ -52,7 +52,7 @@ typedef uint32_t lfs_block_t; #endif // Maximum size of a file in bytes, may be redefined to limit to support other -// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the +// drivers. Limited on disk to <= 4294967295. However, above 2147483647 the // functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return // incorrect values due to using signed integers. Stored in superblock and // must be respected by other littlefs drivers. From a0c6c54345921cb98a4feb39651939122f99fa19 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Dec 2023 13:57:17 -0600 Subject: [PATCH 03/17] Added LFS_MALLOC/FREE, easier overrides for lfs_malloc/free Now you can override littlefs's malloc with some simple defines: -DLFS_MALLOC=my_malloc -DLFS_FREE=my_free This is probably what most users expected when wanting to override malloc/free in littlefs, but it hasn't been available, since instead littlefs provides a file-level override of builtin utils. The thinking was that there's just too many builtins that could be overriden, lfs_max/min/alignup/npw2/etc/etc/etc, so allowing users to just override the util file provides the best flexibility without a ton of ifdefs. But it's become clear this is awkward for users that just want to replace malloc. Maybe the original goal was too optimistic, maybe there's a better way to structure this file, or maybe the best API is just a bunch of ifdefs, I have no idea! This will hopefully continue to evolve. --- lfs_util.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lfs_util.h b/lfs_util.h index 13e93961..30f96121 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -217,7 +217,9 @@ uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); // Allocate memory, only used if buffers are not provided to littlefs // Note, memory must be 64-bit aligned static inline void *lfs_malloc(size_t size) { -#ifndef LFS_NO_MALLOC +#if defined(LFS_MALLOC) + return LFS_MALLOC(size); +#elif !defined(LFS_NO_MALLOC) return malloc(size); #else (void)size; @@ -227,7 +229,9 @@ static inline void *lfs_malloc(size_t size) { // Deallocate memory, only used if buffers are not provided to littlefs static inline void lfs_free(void *p) { -#ifndef LFS_NO_MALLOC +#if defined(LFS_FREE) + LFS_FREE(p); +#elif !defined(LFS_NO_MALLOC) free(p); #else (void)p; From 9a620c730c097a4ddccebca983e35625c1f4fb2e Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Dec 2023 14:12:10 -0600 Subject: [PATCH 04/17] Added LFS_CRC, easier override for lfs_crc Now you can override littlefs's CRC implementation with some simple defines: -DLFS_CRC=lfs_crc The motivation for this is the same for LFS_MALLOC/LFS_FREE. I think these are the main "system-level" utils that users want to override. Don't override with this something that's not CRC32! Your filesystem will no longer be compatible with other tools! This is only intended for provided hardware acceleration! --- lfs_util.c | 3 +++ lfs_util.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/lfs_util.c b/lfs_util.c index 9cdd1c60..dac72abc 100644 --- a/lfs_util.c +++ b/lfs_util.c @@ -11,6 +11,8 @@ #ifndef LFS_CONFIG +// If user provides their own CRC impl we don't need this +#ifndef LFS_CRC // Software CRC implementation with small lookup table uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { static const uint32_t rtable[16] = { @@ -29,6 +31,7 @@ uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { return crc; } +#endif #endif diff --git a/lfs_util.h b/lfs_util.h index 30f96121..45cefc95 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -212,7 +212,13 @@ static inline uint32_t lfs_tobe32(uint32_t a) { } // Calculate CRC-32 with polynomial = 0x04c11db7 +#ifdef LFS_CRC +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { + return LFS_CRC(crc, buffer, size) +} +#else uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); +#endif // Allocate memory, only used if buffers are not provided to littlefs // Note, memory must be 64-bit aligned From 7b6844188837519b23f67342f92a0ef58613a13a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Dec 2023 15:02:40 -0600 Subject: [PATCH 05/17] Renamed a number of internal block-allocator fields - Renamed lfs.free -> lfs.lookahead - Renamed lfs.free.off -> lfs.lookahead.start - Renamed lfs.free.i -> lfs.lookahead.next - Renamed lfs.free.ack -> lfs.lookahead.ckpoint - Renamed lfs_alloc_ack -> lfs_alloc_ckpoint These have been named a bit confusingly, and I think the new names make their relevant purposes a bit clearer. At the very it's clear lfs.lookahead is related to the lookahead buffer. (and doesn't imply a closed free-bitmap). --- lfs.c | 93 +++++++++++++++++++++-------------------- lfs.h | 10 ++--- tests/test_orphans.toml | 4 +- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/lfs.c b/lfs.c index aed1b072..27a66e9c 100644 --- a/lfs.c +++ b/lfs.c @@ -596,11 +596,11 @@ static int lfs_rawunmount(lfs_t *lfs); #ifndef LFS_READONLY static int lfs_alloc_lookahead(void *p, lfs_block_t block) { lfs_t *lfs = (lfs_t*)p; - lfs_block_t off = ((block - lfs->free.off) + lfs_block_t off = ((block - lfs->lookahead.start) + lfs->block_count) % lfs->block_count; - if (off < lfs->free.size) { - lfs->free.buffer[off / 32] |= 1U << (off % 32); + if (off < lfs->lookahead.size) { + lfs->lookahead.buffer[off / 32] |= 1U << (off % 32); } return 0; @@ -610,28 +610,31 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { // indicate allocated blocks have been committed into the filesystem, this // is to prevent blocks from being garbage collected in the middle of a // commit operation -static void lfs_alloc_ack(lfs_t *lfs) { - lfs->free.ack = lfs->block_count; +static void lfs_alloc_ckpoint(lfs_t *lfs) { + lfs->lookahead.ckpoint = lfs->block_count; } // drop the lookahead buffer, this is done during mounting and failed // traversals in order to avoid invalid lookahead state static void lfs_alloc_drop(lfs_t *lfs) { - lfs->free.size = 0; - lfs->free.i = 0; - lfs_alloc_ack(lfs); + lfs->lookahead.size = 0; + lfs->lookahead.next = 0; + lfs_alloc_ckpoint(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; + // Move free offset at the first unused block (lfs->lookahead.next) + // lfs->lookahead.next is equal lfs->lookahead.size when all blocks are used + lfs->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next) + % lfs->block_count; + lfs->lookahead.size = lfs_min( + 8*lfs->cfg->lookahead_size, + lfs->lookahead.ckpoint); + lfs->lookahead.next = 0; // find mask of free blocks from tree - memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); + memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size); int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); if (err) { lfs_alloc_drop(lfs); @@ -645,22 +648,22 @@ static int lfs_fs_rawgc(lfs_t *lfs) { #ifndef LFS_READONLY static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { - while (lfs->free.i != lfs->free.size) { - lfs_block_t off = lfs->free.i; - lfs->free.i += 1; - lfs->free.ack -= 1; + while (lfs->lookahead.next != lfs->lookahead.size) { + lfs_block_t off = lfs->lookahead.next; + lfs->lookahead.next += 1; + lfs->lookahead.ckpoint -= 1; - if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { + if (!(lfs->lookahead.buffer[off / 32] & (1U << (off % 32)))) { // found a free block - *block = (lfs->free.off + off) % lfs->block_count; + *block = (lfs->lookahead.start + off) % lfs->block_count; // eagerly find next off so an alloc ack can // discredit old lookahead blocks - while (lfs->free.i != lfs->free.size && - (lfs->free.buffer[lfs->free.i / 32] - & (1U << (lfs->free.i % 32)))) { - lfs->free.i += 1; - lfs->free.ack -= 1; + while (lfs->lookahead.next != lfs->lookahead.size && + (lfs->lookahead.buffer[lfs->lookahead.next / 32] + & (1U << (lfs->lookahead.next % 32)))) { + lfs->lookahead.next += 1; + lfs->lookahead.ckpoint -= 1; } return 0; @@ -668,9 +671,9 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { } // check if we have looked at all blocks since last ack - if (lfs->free.ack == 0) { + if (lfs->lookahead.ckpoint == 0) { LFS_ERROR("No more free space %"PRIu32, - lfs->free.i + lfs->free.off); + lfs->lookahead.next + lfs->lookahead.start); return LFS_ERR_NOSPC; } @@ -2586,7 +2589,7 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) { } // build up new directory - lfs_alloc_ack(lfs); + lfs_alloc_ckpoint(lfs); lfs_mdir_t dir; err = lfs_dir_alloc(lfs, &dir); if (err) { @@ -3272,7 +3275,7 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { #ifndef LFS_READONLY static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { file->off = file->pos; - lfs_alloc_ack(lfs); + lfs_alloc_ckpoint(lfs); int err = lfs_file_relocate(lfs, file); if (err) { return err; @@ -3535,7 +3538,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file, } // extend file with new blocks - lfs_alloc_ack(lfs); + lfs_alloc_ckpoint(lfs); int err = lfs_ctz_extend(lfs, &file->cache, &lfs->rcache, file->block, file->pos, &file->block, &file->off); @@ -3578,7 +3581,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file, data += diff; nsize -= diff; - lfs_alloc_ack(lfs); + lfs_alloc_ckpoint(lfs); } return size; @@ -4185,10 +4188,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { LFS_ASSERT(lfs->cfg->lookahead_size % 8 == 0 && (uintptr_t)lfs->cfg->lookahead_buffer % 4 == 0); if (lfs->cfg->lookahead_buffer) { - lfs->free.buffer = lfs->cfg->lookahead_buffer; + lfs->lookahead.buffer = lfs->cfg->lookahead_buffer; } else { - lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead_size); - if (!lfs->free.buffer) { + lfs->lookahead.buffer = lfs_malloc(lfs->cfg->lookahead_size); + if (!lfs->lookahead.buffer) { err = LFS_ERR_NOMEM; goto cleanup; } @@ -4245,7 +4248,7 @@ static int lfs_deinit(lfs_t *lfs) { } if (!lfs->cfg->lookahead_buffer) { - lfs_free(lfs->free.buffer); + lfs_free(lfs->lookahead.buffer); } return 0; @@ -4265,12 +4268,12 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) { LFS_ASSERT(cfg->block_count != 0); // create free lookahead - memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - lfs->free.off = 0; - lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, + memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size); + lfs->lookahead.start = 0; + lfs->lookahead.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->block_count); - lfs->free.i = 0; - lfs_alloc_ack(lfs); + lfs->lookahead.next = 0; + lfs_alloc_ckpoint(lfs); // create root dir lfs_mdir_t root; @@ -4478,7 +4481,7 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { // setup free lookahead, to distribute allocations uniformly across // boots, we start the allocator at a random location - lfs->free.off = lfs->seed % lfs->block_count; + lfs->lookahead.start = lfs->seed % lfs->block_count; lfs_alloc_drop(lfs); return 0; @@ -5451,10 +5454,10 @@ static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1, lfs->lfs1->root[1] = LFS_BLOCK_NULL; // setup free lookahead - lfs->free.off = 0; - lfs->free.size = 0; - lfs->free.i = 0; - lfs_alloc_ack(lfs); + lfs->lookahead.start = 0; + lfs->lookahead.size = 0; + lfs->lookahead.next = 0; + lfs_alloc_ckpoint(lfs); // load superblock lfs1_dir_t dir; diff --git a/lfs.h b/lfs.h index 9eeab230..524d087a 100644 --- a/lfs.h +++ b/lfs.h @@ -430,13 +430,13 @@ typedef struct lfs { lfs_gstate_t gdisk; lfs_gstate_t gdelta; - struct lfs_free { - lfs_block_t off; + struct lfs_lookahead { + lfs_block_t start; lfs_block_t size; - lfs_block_t i; - lfs_block_t ack; + lfs_block_t next; + lfs_block_t ckpoint; uint32_t *buffer; - } free; + } lookahead; const struct lfs_config *cfg; lfs_size_t block_count; diff --git a/tests/test_orphans.toml b/tests/test_orphans.toml index 2c8405aa..d7040ed0 100644 --- a/tests/test_orphans.toml +++ b/tests/test_orphans.toml @@ -98,7 +98,7 @@ code = ''' lfs_mount(&lfs, cfg) => 0; // create an orphan lfs_mdir_t orphan; - lfs_alloc_ack(&lfs); + lfs_alloc_ckpoint(&lfs); lfs_dir_alloc(&lfs, &orphan) => 0; lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; @@ -170,7 +170,7 @@ code = ''' lfs_mount(&lfs, cfg) => 0; // create an orphan lfs_mdir_t orphan; - lfs_alloc_ack(&lfs); + lfs_alloc_ckpoint(&lfs); lfs_dir_alloc(&lfs, &orphan) => 0; lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; From 1f9c3c04b1f936d925f9101ca2ea84d71ce2c3e5 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Dec 2023 00:23:04 -0600 Subject: [PATCH 06/17] 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... --- lfs.c | 64 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/lfs.c b/lfs.c index 27a66e9c..f6001a59 100644 --- a/lfs.c +++ b/lfs.c @@ -607,9 +607,10 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { } #endif -// indicate allocated blocks have been committed into the filesystem, this -// is to prevent blocks from being garbage collected in the middle of a -// commit operation +// allocations should call this when all allocated blocks are committed to +// the filesystem +// +// after a checkpoint, the block allocator may realloc any untracked blocks static void lfs_alloc_ckpoint(lfs_t *lfs) { lfs->lookahead.ckpoint = lfs->block_count; } @@ -624,14 +625,16 @@ 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->lookahead.next) - // lfs->lookahead.next is equal lfs->lookahead.size when all blocks are used + // move lookahead buffer to the first unused block + // + // 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->block_count; + lfs->lookahead.next = 0; lfs->lookahead.size = lfs_min( 8*lfs->cfg->lookahead_size, lfs->lookahead.ckpoint); - lfs->lookahead.next = 0; // find mask of free blocks from tree memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size); @@ -648,35 +651,48 @@ static int lfs_fs_rawgc(lfs_t *lfs) { #ifndef LFS_READONLY static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { - while (lfs->lookahead.next != lfs->lookahead.size) { - lfs_block_t off = lfs->lookahead.next; - lfs->lookahead.next += 1; - lfs->lookahead.ckpoint -= 1; - - if (!(lfs->lookahead.buffer[off / 32] & (1U << (off % 32)))) { + // scan our lookahead buffer for free blocks + while (lfs->lookahead.next < lfs->lookahead.size) { + if (!(lfs->lookahead.buffer[lfs->lookahead.next / 32] + & (1U << (lfs->lookahead.next % 32)))) { // 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 - // discredit old lookahead blocks - while (lfs->lookahead.next != lfs->lookahead.size && - (lfs->lookahead.buffer[lfs->lookahead.next / 32] - & (1U << (lfs->lookahead.next % 32)))) { + // eagerly find next free block to maximize how many blocks + // lfs_alloc_ckpoint makes available for scanning + while (true) { lfs->lookahead.next += 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 - if (lfs->lookahead.ckpoint == 0) { - LFS_ERROR("No more free space %"PRIu32, - lfs->lookahead.next + lfs->lookahead.start); + // In order to keep our block allocator from spinning forever when our + // filesystem is full, we mark points where there are no in-flight + // allocations with a checkpoint before starting a set of allocations. + // + // 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; } + // 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); if(err) { return err; From b1b10c0e7559adcb7f2600e7bb7b5cf481d02d0d Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Dec 2023 00:32:17 -0600 Subject: [PATCH 07/17] Relaxed lookahead buffer alignment This drops the lookahead buffer from operating on 32-bit words to operating on 8-bit bytes, and removes any alignment requirement. This may have some minor performance impact, but it is unlikely to be significant when you consider IO overhead. The original motivation for 32-bit alignment was an attempt at future-proofing in case we wanted some more complex on-disk data structure. This never happened, and even if it did, it could have been added via additional config options. This has been a significant pain point for users, since providing word-aligned byte-sized buffers in C can be a bit annoying. --- lfs.c | 15 +++++++-------- lfs.h | 9 ++++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/lfs.c b/lfs.c index f6001a59..dbcf0f02 100644 --- a/lfs.c +++ b/lfs.c @@ -600,7 +600,7 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { + lfs->block_count) % lfs->block_count; if (off < lfs->lookahead.size) { - lfs->lookahead.buffer[off / 32] |= 1U << (off % 32); + lfs->lookahead.buffer[off / 8] |= 1U << (off % 8); } return 0; @@ -653,8 +653,8 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { // scan our lookahead buffer for free blocks while (lfs->lookahead.next < lfs->lookahead.size) { - if (!(lfs->lookahead.buffer[lfs->lookahead.next / 32] - & (1U << (lfs->lookahead.next % 32)))) { + if (!(lfs->lookahead.buffer[lfs->lookahead.next / 8] + & (1U << (lfs->lookahead.next % 8)))) { // found a free block *block = (lfs->lookahead.start + lfs->lookahead.next) % lfs->block_count; @@ -666,8 +666,8 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { lfs->lookahead.ckpoint -= 1; if (lfs->lookahead.next >= lfs->lookahead.size - || !(lfs->lookahead.buffer[lfs->lookahead.next / 32] - & (1U << (lfs->lookahead.next % 32)))) { + || !(lfs->lookahead.buffer[lfs->lookahead.next / 8] + & (1U << (lfs->lookahead.next % 8)))) { return 0; } } @@ -4199,10 +4199,9 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs_cache_zero(lfs, &lfs->rcache); lfs_cache_zero(lfs, &lfs->pcache); - // setup lookahead, must be multiple of 64-bits, 32-bit aligned + // setup lookahead buffer, note mount finishes initializing this after + // we establish a decent pseudo-random seed LFS_ASSERT(lfs->cfg->lookahead_size > 0); - LFS_ASSERT(lfs->cfg->lookahead_size % 8 == 0 && - (uintptr_t)lfs->cfg->lookahead_buffer % 4 == 0); if (lfs->cfg->lookahead_buffer) { lfs->lookahead.buffer = lfs->cfg->lookahead_buffer; } else { diff --git a/lfs.h b/lfs.h index 524d087a..ad1da35a 100644 --- a/lfs.h +++ b/lfs.h @@ -226,7 +226,7 @@ struct lfs_config { // Size of the lookahead buffer in bytes. A larger lookahead buffer // increases the number of blocks found during an allocation pass. The // lookahead buffer is stored as a compact bitmap, so each byte of RAM - // can track 8 blocks. Must be a multiple of 8. + // can track 8 blocks. lfs_size_t lookahead_size; // Optional statically allocated read buffer. Must be cache_size. @@ -237,9 +237,8 @@ struct lfs_config { // By default lfs_malloc is used to allocate this buffer. void *prog_buffer; - // Optional statically allocated lookahead buffer. Must be lookahead_size - // and aligned to a 32-bit boundary. By default lfs_malloc is used to - // allocate this buffer. + // Optional statically allocated lookahead buffer. Must be lookahead_size. + // By default lfs_malloc is used to allocate this buffer. void *lookahead_buffer; // Optional upper limit on length of file names in bytes. No downside for @@ -435,7 +434,7 @@ typedef struct lfs { lfs_block_t size; lfs_block_t next; lfs_block_t ckpoint; - uint32_t *buffer; + uint8_t *buffer; } lookahead; const struct lfs_config *cfg; From 897b571318526aaae2bc9ea1964b407ff4968316 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 21 Dec 2023 00:33:44 -0600 Subject: [PATCH 08/17] Changed CI to just run on ubuntu-latest If we already have to bump this version as GitHub phases out older Ubuntu runners (which is reasonable), I don't really see the value of pinning a specific version. We might as well just respond to any broken dependencies caused by GitHub's implicit updates as they happen... It's not like CI is truly continuous. --- .github/workflows/post-release.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/status.yml | 4 ++-- .github/workflows/test.yml | 24 ++++++++++++------------ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml index 6524124d..8104a948 100644 --- a/.github/workflows/post-release.yml +++ b/.github/workflows/post-release.yml @@ -10,7 +10,7 @@ defaults: jobs: post-release: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: # trigger post-release in dependency repo, this indirection allows the # dependency repo to be updated often without affecting this repo. At diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 61b29721..6400a471 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ defaults: jobs: release: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest # need to manually check for a couple things # - tests passed? diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml index 8bd3990c..e6e983a5 100644 --- a/.github/workflows/status.yml +++ b/.github/workflows/status.yml @@ -11,7 +11,7 @@ defaults: jobs: # forward custom statuses status: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: dawidd6/action-download-artifact@v2 continue-on-error: true @@ -60,7 +60,7 @@ jobs: # forward custom pr-comments comment: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest # only run on success (we don't want garbage comments!) if: ${{github.event.workflow_run.conclusion == 'success'}} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ccb08fea..db3413bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ env: jobs: # run tests test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: @@ -329,7 +329,7 @@ jobs: # # this grows exponentially, so it doesn't turn out to be that many test-pls: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: @@ -359,7 +359,7 @@ jobs: # run with LFS_NO_INTRINSICS to make sure that works test-no-intrinsics: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install @@ -376,7 +376,7 @@ jobs: # run LFS_MULTIVERSION tests test-multiversion: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install @@ -393,7 +393,7 @@ jobs: # run tests on the older version lfs2.0 test-lfs2_0: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install @@ -412,7 +412,7 @@ jobs: # run under Valgrind to check for memory errors test-valgrind: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install @@ -434,7 +434,7 @@ jobs: # test that compilation is warning free under clang # run with Clang, mostly to check for Clang-specific warnings test-clang: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install @@ -457,7 +457,7 @@ jobs: # # note there's no real benefit to running these on multiple archs bench: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install @@ -533,7 +533,7 @@ jobs: # run compatibility tests using the current master as the previous version test-compat: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 if: ${{github.event_name == 'pull_request'}} @@ -569,7 +569,7 @@ jobs: # self-host with littlefs-fuse for a fuzz-like test fuse: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest if: ${{!endsWith(github.ref, '-prefix')}} steps: - uses: actions/checkout@v2 @@ -619,7 +619,7 @@ jobs: # test migration using littlefs-fuse migrate: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest if: ${{!endsWith(github.ref, '-prefix')}} steps: - uses: actions/checkout@v2 @@ -691,7 +691,7 @@ jobs: # status related tasks that run after tests status: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest needs: [test, bench] steps: - uses: actions/checkout@v2 From 60567677b95205d50d98815d073a5f466d052e68 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 16 Jan 2024 00:27:07 -0600 Subject: [PATCH 09/17] Relaxed alignment requirements for lfs_malloc The only reason we needed this alignment was for the lookahead buffer. Now that the lookahead buffer is relaxed to operate on bytes, we can relax our malloc alignment requirement all the way down to the byte level, since we mainly use lfs_malloc to allocate byte-level buffers. This does introduce a risk that we might need word-level mallocs in the future. If that happens we will need to decide if changing the malloc alignment is a breaking change, or gate alignment requirements behind user provided defines. Found by HiFiPhile. --- lfs_util.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lfs_util.h b/lfs_util.h index 13e93961..8248d1d4 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -215,7 +215,9 @@ static inline uint32_t lfs_tobe32(uint32_t a) { uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); // Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned +// +// littlefs current has no alignment requirements, as it only allocates +// byte-level buffers. static inline void *lfs_malloc(size_t size) { #ifndef LFS_NO_MALLOC return malloc(size); From 1fefcbbcba6875a4e0d140eaa8486a36cf4f45f0 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 16 Jan 2024 23:34:20 -0600 Subject: [PATCH 10/17] Rearranged compile-time constant checks to live near lfs_init lfs_init handles the checks/asserts of most configuration, moving these checks near lfs_init attempts to keep all of these checks nearby each other. Also updated the comments to avoid somtimes-ambiguous range notation. And removed negative bounds checks. Negative bounds should be obviously incorrect, and 0 is _technically_ not illegal for any define (though admittedly unlikely to be correct). --- lfs.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lfs.c b/lfs.c index a18752c4..3d716acc 100644 --- a/lfs.c +++ b/lfs.c @@ -8,23 +8,6 @@ #include "lfs.h" #include "lfs_util.h" -// Configuration Sanity Check -#if (LFS_NAME_MAX <= 0) || (LFS_NAME_MAX > 1022) -#error "LFS_NAME_MAX must be in the range (0, 1022]" -#endif - -#if (LFS_FILE_MAX <= 0) || (LFS_FILE_MAX > 4294967295) -#error "LFS_FILE_MAX must be in the range (0, 4294967295]" -#endif - -#if (LFS_FILE_MAX > 2147483647) -#warning "LFS_FILE_MAX>2147483647; lfs_file_seek, lfs_file_size, and lfs_file_tell will not function properly." -#endif - -#if (LFS_ATTR_MAX < 0) || (LFS_ATTR_MAX > 1022) -#error "LFS_ATTR_MAX must be in the range [0, 1022]" -#endif - // some constants used throughout the code #define LFS_BLOCK_NULL ((lfs_block_t)-1) @@ -4123,6 +4106,21 @@ static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) { /// Filesystem operations /// + +// compile time checks, see lfs.h for why these limits exist +#if LFS_NAME_MAX > 1022 +#error "Invalid LFS_NAME_MAX, must be <= 1022" +#endif + +#if LFS_FILE_MAX > 4294967295 +#error "Invalid LFS_FILE_MAX, must be <= 4294967295" +#endif + +#if LFS_ATTR_MAX > 1022 +#error "Invalid LFS_ATTR_MAX, must be <= 1022" +#endif + +// common filesystem initialization static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs->cfg = cfg; lfs->block_count = cfg->block_count; // May be 0 From 6691718b18def310516d1e7724fece766c7c09b1 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 16 Jan 2024 23:40:30 -0600 Subject: [PATCH 11/17] Restricted LFS_FILE_MAX to signed 32-bits, <2^31, <=2147483647 I think realistically no one is using this. It's already only partially supported and untested. Worst case, if someone does depend on this we can always revert. --- lfs.c | 4 ++-- lfs.h | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lfs.c b/lfs.c index 3d716acc..9e1fdb65 100644 --- a/lfs.c +++ b/lfs.c @@ -4112,8 +4112,8 @@ static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) { #error "Invalid LFS_NAME_MAX, must be <= 1022" #endif -#if LFS_FILE_MAX > 4294967295 -#error "Invalid LFS_FILE_MAX, must be <= 4294967295" +#if LFS_FILE_MAX > 2147483647 +#error "Invalid LFS_FILE_MAX, must be <= 2147483647" #endif #if LFS_ATTR_MAX > 1022 diff --git a/lfs.h b/lfs.h index d7f61367..452dd0e9 100644 --- a/lfs.h +++ b/lfs.h @@ -52,10 +52,8 @@ typedef uint32_t lfs_block_t; #endif // Maximum size of a file in bytes, may be redefined to limit to support other -// drivers. Limited on disk to <= 4294967295. However, above 2147483647 the -// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return -// incorrect values due to using signed integers. Stored in superblock and -// must be respected by other littlefs drivers. +// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be +// respected by other littlefs drivers. #ifndef LFS_FILE_MAX #define LFS_FILE_MAX 2147483647 #endif From 4f32738cd6a861e9c3f077e86349f0c28ae5f589 Mon Sep 17 00:00:00 2001 From: Tom Szilagyi Date: Wed, 3 Jan 2024 16:13:31 +0100 Subject: [PATCH 12/17] Fix return value of lfs_rename() When lfs_rename() is called trying to rename (move) a file to an existing directory, LFS_ERR_ISDIR is (correctly) returned. However, in the opposite case, if one tries to rename (move) a directory to a path currently occupied by a regular file, LFS_ERR_NOTDIR should be returned (since the error is that the destination is NOT a directory), but in reality, LFS_ERR_ISDIR is returned in this case as well. This commit fixes the code so that in the latter case, LFS_ERR_NOTDIR is returned. --- lfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lfs.c b/lfs.c index a152687f..c7dc3eba 100644 --- a/lfs.c +++ b/lfs.c @@ -3940,7 +3940,9 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) { newoldid += 1; } } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) { - return LFS_ERR_ISDIR; + return (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) + ? LFS_ERR_ISDIR + : LFS_ERR_NOTDIR; } else if (samepair && newid == newoldid) { // we're renaming to ourselves?? return 0; From f522ed907af5de03f13487d3e75704ecf1557733 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 17 Jan 2024 00:10:30 -0600 Subject: [PATCH 13/17] Added tests over rename type errors --- tests/test_dirs.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml index 4262a1aa..181dd6ad 100644 --- a/tests/test_dirs.toml +++ b/tests/test_dirs.toml @@ -747,6 +747,11 @@ code = ''' lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "tacoto", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_rename(&lfs, "tacoto", "potato") => LFS_ERR_ISDIR; + lfs_rename(&lfs, "potato", "tacoto") => LFS_ERR_NOTDIR; + lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; @@ -770,6 +775,10 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "potato") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, "tacoto") == 0); + assert(info.size == 0); lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; @@ -790,6 +799,10 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "potato") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, "tacoto") == 0); + assert(info.size == 0); lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; From b5cd957f42d33f5960014dddbca7414502638a2d Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Dec 2023 18:05:29 -0600 Subject: [PATCH 14/17] Extended lfs_fs_gc to compact metadata, compact_thresh This extends lfs_fs_gc to now handle three things: 1. Calls mkconsistent if not already consistent 2. Compacts metadata > compact_thresh 3. Populates the block allocator Which should be all of the janitorial work that can be done without additional on-disk data structures. Normally, metadata compaction occurs when an mdir is full, and results in mdirs that are at most block_size/2. Now, if you call lfs_fs_gc, littlefs will eagerly compact any mdirs that exceed the compact_thresh configuration option. Because the resulting mdirs are at most block_size/2, it only makes sense for compact_thresh to be >= block_size/2 and <= block_size. Additionally, there are some special values: - compact_thresh=0 => defaults to ~88% block_size, may change - compact_thresh=-1 => disables metadata compaction during lfs_fs_gc Note that compact_thresh only affects lfs_fs_gc. Normal compactions still only occur when full. --- lfs.c | 106 ++++++++++++++++++++++++++++++++--------- lfs.h | 41 +++++++++++----- runners/bench_runner.c | 1 + runners/bench_runner.h | 15 +++--- runners/test_runner.c | 5 ++ runners/test_runner.h | 17 ++++--- tests/test_alloc.toml | 2 + 7 files changed, 139 insertions(+), 48 deletions(-) diff --git a/lfs.c b/lfs.c index dbcf0f02..b9c09bc8 100644 --- a/lfs.c +++ b/lfs.c @@ -593,19 +593,6 @@ static int lfs_rawunmount(lfs_t *lfs); /// Block allocator /// -#ifndef LFS_READONLY -static int lfs_alloc_lookahead(void *p, lfs_block_t block) { - lfs_t *lfs = (lfs_t*)p; - lfs_block_t off = ((block - lfs->lookahead.start) - + lfs->block_count) % lfs->block_count; - - if (off < lfs->lookahead.size) { - lfs->lookahead.buffer[off / 8] |= 1U << (off % 8); - } - - return 0; -} -#endif // allocations should call this when all allocated blocks are committed to // the filesystem @@ -624,7 +611,21 @@ static void lfs_alloc_drop(lfs_t *lfs) { } #ifndef LFS_READONLY -static int lfs_fs_rawgc(lfs_t *lfs) { +static int lfs_alloc_lookahead(void *p, lfs_block_t block) { + lfs_t *lfs = (lfs_t*)p; + lfs_block_t off = ((block - lfs->lookahead.start) + + lfs->block_count) % lfs->block_count; + + if (off < lfs->lookahead.size) { + lfs->lookahead.buffer[off / 8] |= 1U << (off % 8); + } + + return 0; +} +#endif + +#ifndef LFS_READONLY +static int lfs_alloc_scan(lfs_t *lfs) { // move lookahead buffer to the first unused block // // note we limit the lookahead buffer to at most the amount of blocks @@ -693,7 +694,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { // 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_alloc_scan(lfs); if(err) { return err; } @@ -4172,6 +4173,14 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { // wear-leveling. LFS_ASSERT(lfs->cfg->block_cycles != 0); + // check that compact_thresh makes sense + // + // metadata can't be compacted below block_size/2, and metadata can't + // exceed a block_size + LFS_ASSERT(lfs->cfg->compact_thresh == 0 + || lfs->cfg->compact_thresh >= lfs->cfg->block_size/2); + LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1 + || lfs->cfg->compact_thresh <= lfs->cfg->block_size); // setup read cache if (lfs->cfg->read_buffer) { @@ -5063,6 +5072,57 @@ static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) { return size; } +// explicit garbage collection +#ifndef LFS_READONLY +static int lfs_fs_rawgc(lfs_t *lfs) { + // force consistency, even if we're not necessarily going to write, + // because this function is supposed to take care of janitorial work + // isn't it? + int err = lfs_fs_forceconsistency(lfs); + if (err) { + return err; + } + + // try to compact metadata pairs, note we can't really accomplish + // anything if compact_thresh doesn't at least leave a prog_size + // available + if (lfs->cfg->compact_thresh + < lfs->cfg->block_size - lfs->cfg->prog_size) { + // iterate over all mdirs + lfs_mdir_t mdir = {.tail = {0, 1}}; + while (!lfs_pair_isnull(mdir.tail)) { + err = lfs_dir_fetch(lfs, &mdir, mdir.tail); + if (err) { + return err; + } + + // not erased? exceeds our compaction threshold? + if (!mdir.erased || ((lfs->cfg->compact_thresh == 0) + ? mdir.off > lfs->cfg->block_size - lfs->cfg->block_size/8 + : mdir.off > lfs->cfg->compact_thresh)) { + // the easiest way to trigger a compaction is to mark + // the mdir as unerased and add an empty commit + mdir.erased = false; + err = lfs_dir_commit(lfs, &mdir, NULL, 0); + if (err) { + return err; + } + } + } + } + + // try to populate the lookahead buffer, unless it's already full + if (lfs->lookahead.size < 8*lfs->cfg->lookahead_size) { + err = lfs_alloc_scan(lfs); + if (err) { + return err; + } + } + + return 0; +} +#endif + #ifndef LFS_READONLY static int lfs_fs_rawgrow(lfs_t *lfs, lfs_size_t block_count) { // shrinking is not supported @@ -6269,32 +6329,32 @@ 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 lfs_fs_mkconsistent(lfs_t *lfs) { int err = LFS_LOCK(lfs->cfg); if (err) { return err; } - LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs); + LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs); - err = lfs_fs_rawgc(lfs); + err = lfs_fs_rawmkconsistent(lfs); - LFS_TRACE("lfs_fs_gc -> %d", err); + LFS_TRACE("lfs_fs_mkconsistent -> %d", err); LFS_UNLOCK(lfs->cfg); return err; } #endif #ifndef LFS_READONLY -int lfs_fs_mkconsistent(lfs_t *lfs) { +int lfs_fs_gc(lfs_t *lfs) { int err = LFS_LOCK(lfs->cfg); if (err) { return err; } - LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs); + LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs); - err = lfs_fs_rawmkconsistent(lfs); + err = lfs_fs_rawgc(lfs); - LFS_TRACE("lfs_fs_mkconsistent -> %d", err); + LFS_TRACE("lfs_fs_gc -> %d", err); LFS_UNLOCK(lfs->cfg); return err; } diff --git a/lfs.h b/lfs.h index ad1da35a..f53fd866 100644 --- a/lfs.h +++ b/lfs.h @@ -229,6 +229,17 @@ struct lfs_config { // can track 8 blocks. lfs_size_t lookahead_size; + // Threshold for metadata compaction during lfs_fs_gc in bytes. Metadata + // pairs that exceed this threshold will be compacted during lfs_fs_gc. + // Defaults to ~88% block_size when zero, though the default may change + // in the future. + // + // Note this only affects lfs_fs_gc. Normal compactions still only occur + // when full. + // + // Set to -1 to disable metadata compaction during lfs_fs_gc. + lfs_size_t compact_thresh; + // Optional statically allocated read buffer. Must be cache_size. // By default lfs_malloc is used to allocate this buffer. void *read_buffer; @@ -711,18 +722,6 @@ 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 // @@ -735,6 +734,24 @@ int lfs_fs_gc(lfs_t *lfs); int lfs_fs_mkconsistent(lfs_t *lfs); #endif +#ifndef LFS_READONLY +// Attempt any janitorial work +// +// This currently: +// 1. Calls mkconsistent if not already consistent +// 2. Compacts metadata > compact_thresh +// 3. Populates the block allocator +// +// Though additional janitorial work may be added in the future. +// +// Calling this function is not required, but may allow the offloading of +// expensive janitorial work to a less time-critical code path. +// +// Returns a negative error code on failure. Accomplishing nothing is not +// an error. +int lfs_fs_gc(lfs_t *lfs); +#endif + #ifndef LFS_READONLY // Grows the filesystem to a new size, updating the superblock with the new // block count. diff --git a/runners/bench_runner.c b/runners/bench_runner.c index f4dce22b..58cae683 100644 --- a/runners/bench_runner.c +++ b/runners/bench_runner.c @@ -1321,6 +1321,7 @@ void perm_run( .block_cycles = BLOCK_CYCLES, .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, + .compact_thresh = COMPACT_THRESH, }; struct lfs_emubd_config bdcfg = { diff --git a/runners/bench_runner.h b/runners/bench_runner.h index b072970e..986ac904 100644 --- a/runners/bench_runner.h +++ b/runners/bench_runner.h @@ -95,11 +95,12 @@ intmax_t bench_define(size_t define); #define BLOCK_COUNT_i 5 #define CACHE_SIZE_i 6 #define LOOKAHEAD_SIZE_i 7 -#define BLOCK_CYCLES_i 8 -#define ERASE_VALUE_i 9 -#define ERASE_CYCLES_i 10 -#define BADBLOCK_BEHAVIOR_i 11 -#define POWERLOSS_BEHAVIOR_i 12 +#define COMPACT_THRESH_i 8 +#define BLOCK_CYCLES_i 9 +#define ERASE_VALUE_i 10 +#define ERASE_CYCLES_i 11 +#define BADBLOCK_BEHAVIOR_i 12 +#define POWERLOSS_BEHAVIOR_i 13 #define READ_SIZE bench_define(READ_SIZE_i) #define PROG_SIZE bench_define(PROG_SIZE_i) @@ -109,6 +110,7 @@ intmax_t bench_define(size_t define); #define BLOCK_COUNT bench_define(BLOCK_COUNT_i) #define CACHE_SIZE bench_define(CACHE_SIZE_i) #define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i) +#define COMPACT_THRESH bench_define(COMPACT_THRESH_i) #define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i) #define ERASE_VALUE bench_define(ERASE_VALUE_i) #define ERASE_CYCLES bench_define(ERASE_CYCLES_i) @@ -124,6 +126,7 @@ intmax_t bench_define(size_t define); BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\ BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ BENCH_DEF(LOOKAHEAD_SIZE, 16) \ + BENCH_DEF(COMPACT_THRESH, 0) \ BENCH_DEF(BLOCK_CYCLES, -1) \ BENCH_DEF(ERASE_VALUE, 0xff) \ BENCH_DEF(ERASE_CYCLES, 0) \ @@ -131,7 +134,7 @@ intmax_t bench_define(size_t define); BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) #define BENCH_GEOMETRY_DEFINE_COUNT 4 -#define BENCH_IMPLICIT_DEFINE_COUNT 13 +#define BENCH_IMPLICIT_DEFINE_COUNT 14 #endif diff --git a/runners/test_runner.c b/runners/test_runner.c index 13befdc3..c6e933e0 100644 --- a/runners/test_runner.c +++ b/runners/test_runner.c @@ -1346,6 +1346,7 @@ static void run_powerloss_none( .block_cycles = BLOCK_CYCLES, .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, + .compact_thresh = COMPACT_THRESH, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1422,6 +1423,7 @@ static void run_powerloss_linear( .block_cycles = BLOCK_CYCLES, .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, + .compact_thresh = COMPACT_THRESH, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1515,6 +1517,7 @@ static void run_powerloss_log( .block_cycles = BLOCK_CYCLES, .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, + .compact_thresh = COMPACT_THRESH, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1606,6 +1609,7 @@ static void run_powerloss_cycles( .block_cycles = BLOCK_CYCLES, .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, + .compact_thresh = COMPACT_THRESH, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1795,6 +1799,7 @@ static void run_powerloss_exhaustive( .block_cycles = BLOCK_CYCLES, .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, + .compact_thresh = COMPACT_THRESH, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif diff --git a/runners/test_runner.h b/runners/test_runner.h index 4be72e42..96099997 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -88,12 +88,13 @@ intmax_t test_define(size_t define); #define BLOCK_COUNT_i 5 #define CACHE_SIZE_i 6 #define LOOKAHEAD_SIZE_i 7 -#define BLOCK_CYCLES_i 8 -#define ERASE_VALUE_i 9 -#define ERASE_CYCLES_i 10 -#define BADBLOCK_BEHAVIOR_i 11 -#define POWERLOSS_BEHAVIOR_i 12 -#define DISK_VERSION_i 13 +#define COMPACT_THRESH_i 8 +#define BLOCK_CYCLES_i 9 +#define ERASE_VALUE_i 10 +#define ERASE_CYCLES_i 11 +#define BADBLOCK_BEHAVIOR_i 12 +#define POWERLOSS_BEHAVIOR_i 13 +#define DISK_VERSION_i 14 #define READ_SIZE TEST_DEFINE(READ_SIZE_i) #define PROG_SIZE TEST_DEFINE(PROG_SIZE_i) @@ -103,6 +104,7 @@ intmax_t test_define(size_t define); #define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i) #define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i) #define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i) +#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i) #define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i) #define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i) #define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i) @@ -119,6 +121,7 @@ intmax_t test_define(size_t define); TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \ TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ TEST_DEF(LOOKAHEAD_SIZE, 16) \ + TEST_DEF(COMPACT_THRESH, 0) \ TEST_DEF(BLOCK_CYCLES, -1) \ TEST_DEF(ERASE_VALUE, 0xff) \ TEST_DEF(ERASE_CYCLES, 0) \ @@ -127,7 +130,7 @@ intmax_t test_define(size_t define); TEST_DEF(DISK_VERSION, 0) #define TEST_GEOMETRY_DEFINE_COUNT 4 -#define TEST_IMPLICIT_DEFINE_COUNT 14 +#define TEST_IMPLICIT_DEFINE_COUNT 15 #endif diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml index e6fba975..9e4daee5 100644 --- a/tests/test_alloc.toml +++ b/tests/test_alloc.toml @@ -7,6 +7,7 @@ if = 'BLOCK_CYCLES == -1' defines.FILES = 3 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.GC = [false, true] +defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2'] code = ''' const char *names[] = {"bacon", "eggs", "pancakes"}; lfs_file_t files[FILES]; @@ -60,6 +61,7 @@ code = ''' defines.FILES = 3 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.GC = [false, true] +defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2'] code = ''' const char *names[] = {"bacon", "eggs", "pancakes"}; From 8b8fd14187d8b798606f579c49fbd8a0b7d4355c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Dec 2023 22:56:26 -0600 Subject: [PATCH 15/17] Added inline_max, to optionally limit the size of inlined files Inlined files live in metadata and decrease storage requirements, but may be limited to improve metadata-related performance. This is especially important given the current plague of metadata performance. Though decreasing inline_max may make metadata more dense and increase block usage, so it's important to benchmark if optimizing for speed. The underlying limits of inlined files haven't changed: 1. Inlined files need to fit in RAM, so <= cache_size 2. Inlined files need to fit in a single attr, so <= attr_max 3. Inlined files need to fit in 1/8 of a block to avoid metadata overflow issues, this is after limiting by metadata_max, so <= min(metadata_max, block_size)/8 By default, the largest possible inline_max is used. This preserves backwards compatibility and is probably a good default for most use cases. This does have the awkward effect of requiring inline_max=-1 to indicate disabled inlined files, but I don't think there's a good way around this. --- lfs.c | 35 ++++++++++++++++++++++++++--------- lfs.h | 10 ++++++++++ runners/bench_runner.c | 1 + runners/bench_runner.h | 15 +++++++++------ runners/test_runner.c | 5 +++++ runners/test_runner.h | 17 ++++++++++------- tests/test_files.toml | 21 ++++++++++++++++++--- 7 files changed, 79 insertions(+), 25 deletions(-) diff --git a/lfs.c b/lfs.c index 44a8261b..93b9b8f8 100644 --- a/lfs.c +++ b/lfs.c @@ -3524,11 +3524,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file, lfs_size_t nsize = size; if ((file->flags & LFS_F_INLINE) && - lfs_max(file->pos+nsize, file->ctz.size) > - lfs_min(0x3fe, lfs_min( - lfs->cfg->cache_size, - (lfs->cfg->metadata_max ? - lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) { + lfs_max(file->pos+nsize, file->ctz.size) > lfs->inline_max) { // inline file doesn't fit anymore int err = lfs_file_outline(lfs, file); if (err) { @@ -3725,10 +3721,7 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { lfs_off_t oldsize = lfs_file_rawsize(lfs, file); if (size < oldsize) { // revert to inline file? - if (size <= lfs_min(0x3fe, lfs_min( - lfs->cfg->cache_size, - (lfs->cfg->metadata_max ? - lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) { + if (size <= lfs->inline_max) { // flush+seek to head lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET); if (res < 0) { @@ -4259,6 +4252,27 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size); + LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1 + || lfs->cfg->inline_max <= lfs->cfg->cache_size); + LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1 + || lfs->cfg->inline_max <= lfs->attr_max); + LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1 + || lfs->cfg->inline_max <= ((lfs->cfg->metadata_max) + ? lfs->cfg->metadata_max + : lfs->cfg->block_size)/8); + lfs->inline_max = lfs->cfg->inline_max; + if (lfs->inline_max == (lfs_size_t)-1) { + lfs->inline_max = 0; + } else if (lfs->inline_max == 0) { + lfs->inline_max = lfs_min( + lfs->cfg->cache_size, + lfs_min( + lfs->attr_max, + ((lfs->cfg->metadata_max) + ? lfs->cfg->metadata_max + : lfs->cfg->block_size)/8)); + } + // setup default state lfs->root[0] = LFS_BLOCK_NULL; lfs->root[1] = LFS_BLOCK_NULL; @@ -4482,6 +4496,9 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { } lfs->attr_max = superblock.attr_max; + + // we also need to update inline_max in case attr_max changed + lfs->inline_max = lfs_min(lfs->inline_max, lfs->attr_max); } // this is where we get the block_count from disk if block_count=0 diff --git a/lfs.h b/lfs.h index e144b847..79fd685b 100644 --- a/lfs.h +++ b/lfs.h @@ -272,6 +272,15 @@ struct lfs_config { // Defaults to block_size when zero. lfs_size_t metadata_max; + // Optional upper limit on inlined files in bytes. Inlined files live in + // metadata and decrease storage requirements, but may be limited to + // improve metadata-related performance. Must be <= cache_size, <= + // attr_max, and <= block_size/8. Defaults to the largest possible + // inline_max when zero. + // + // Set to -1 to disable inlined files. + lfs_size_t inline_max; + #ifdef LFS_MULTIVERSION // On-disk version to use when writing in the form of 16-bit major version // + 16-bit minor version. This limiting metadata to what is supported by @@ -451,6 +460,7 @@ typedef struct lfs { lfs_size_t name_max; lfs_size_t file_max; lfs_size_t attr_max; + lfs_size_t inline_max; #ifdef LFS_MIGRATE struct lfs1 *lfs1; diff --git a/runners/bench_runner.c b/runners/bench_runner.c index 58cae683..387889d1 100644 --- a/runners/bench_runner.c +++ b/runners/bench_runner.c @@ -1322,6 +1322,7 @@ void perm_run( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .inline_max = INLINE_MAX, }; struct lfs_emubd_config bdcfg = { diff --git a/runners/bench_runner.h b/runners/bench_runner.h index 986ac904..174733c1 100644 --- a/runners/bench_runner.h +++ b/runners/bench_runner.h @@ -96,11 +96,12 @@ intmax_t bench_define(size_t define); #define CACHE_SIZE_i 6 #define LOOKAHEAD_SIZE_i 7 #define COMPACT_THRESH_i 8 -#define BLOCK_CYCLES_i 9 -#define ERASE_VALUE_i 10 -#define ERASE_CYCLES_i 11 -#define BADBLOCK_BEHAVIOR_i 12 -#define POWERLOSS_BEHAVIOR_i 13 +#define INLINE_MAX_i 9 +#define BLOCK_CYCLES_i 10 +#define ERASE_VALUE_i 11 +#define ERASE_CYCLES_i 12 +#define BADBLOCK_BEHAVIOR_i 13 +#define POWERLOSS_BEHAVIOR_i 14 #define READ_SIZE bench_define(READ_SIZE_i) #define PROG_SIZE bench_define(PROG_SIZE_i) @@ -111,6 +112,7 @@ intmax_t bench_define(size_t define); #define CACHE_SIZE bench_define(CACHE_SIZE_i) #define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i) #define COMPACT_THRESH bench_define(COMPACT_THRESH_i) +#define INLINE_MAX bench_define(INLINE_MAX_i) #define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i) #define ERASE_VALUE bench_define(ERASE_VALUE_i) #define ERASE_CYCLES bench_define(ERASE_CYCLES_i) @@ -127,6 +129,7 @@ intmax_t bench_define(size_t define); BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ BENCH_DEF(LOOKAHEAD_SIZE, 16) \ BENCH_DEF(COMPACT_THRESH, 0) \ + BENCH_DEF(INLINE_MAX, 0) \ BENCH_DEF(BLOCK_CYCLES, -1) \ BENCH_DEF(ERASE_VALUE, 0xff) \ BENCH_DEF(ERASE_CYCLES, 0) \ @@ -134,7 +137,7 @@ intmax_t bench_define(size_t define); BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) #define BENCH_GEOMETRY_DEFINE_COUNT 4 -#define BENCH_IMPLICIT_DEFINE_COUNT 14 +#define BENCH_IMPLICIT_DEFINE_COUNT 15 #endif diff --git a/runners/test_runner.c b/runners/test_runner.c index c6e933e0..ff526730 100644 --- a/runners/test_runner.c +++ b/runners/test_runner.c @@ -1347,6 +1347,7 @@ static void run_powerloss_none( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1424,6 +1425,7 @@ static void run_powerloss_linear( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1518,6 +1520,7 @@ static void run_powerloss_log( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1610,6 +1613,7 @@ static void run_powerloss_cycles( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif @@ -1800,6 +1804,7 @@ static void run_powerloss_exhaustive( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, #endif diff --git a/runners/test_runner.h b/runners/test_runner.h index 96099997..0f0e594e 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -89,12 +89,13 @@ intmax_t test_define(size_t define); #define CACHE_SIZE_i 6 #define LOOKAHEAD_SIZE_i 7 #define COMPACT_THRESH_i 8 -#define BLOCK_CYCLES_i 9 -#define ERASE_VALUE_i 10 -#define ERASE_CYCLES_i 11 -#define BADBLOCK_BEHAVIOR_i 12 -#define POWERLOSS_BEHAVIOR_i 13 -#define DISK_VERSION_i 14 +#define INLINE_MAX_i 9 +#define BLOCK_CYCLES_i 10 +#define ERASE_VALUE_i 11 +#define ERASE_CYCLES_i 12 +#define BADBLOCK_BEHAVIOR_i 13 +#define POWERLOSS_BEHAVIOR_i 14 +#define DISK_VERSION_i 15 #define READ_SIZE TEST_DEFINE(READ_SIZE_i) #define PROG_SIZE TEST_DEFINE(PROG_SIZE_i) @@ -105,6 +106,7 @@ intmax_t test_define(size_t define); #define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i) #define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i) #define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i) +#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i) #define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i) #define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i) #define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i) @@ -122,6 +124,7 @@ intmax_t test_define(size_t define); TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ TEST_DEF(LOOKAHEAD_SIZE, 16) \ TEST_DEF(COMPACT_THRESH, 0) \ + TEST_DEF(INLINE_MAX, 0) \ TEST_DEF(BLOCK_CYCLES, -1) \ TEST_DEF(ERASE_VALUE, 0xff) \ TEST_DEF(ERASE_CYCLES, 0) \ @@ -130,7 +133,7 @@ intmax_t test_define(size_t define); TEST_DEF(DISK_VERSION, 0) #define TEST_GEOMETRY_DEFINE_COUNT 4 -#define TEST_IMPLICIT_DEFINE_COUNT 15 +#define TEST_IMPLICIT_DEFINE_COUNT 16 #endif diff --git a/tests/test_files.toml b/tests/test_files.toml index afb0811f..1c86cd8d 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -1,5 +1,6 @@ [cases.test_files_simple] +defines.INLINE_MAX = [0, -1, 8] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; @@ -25,6 +26,7 @@ code = ''' [cases.test_files_large] defines.SIZE = [32, 8192, 262144, 0, 7, 8193] defines.CHUNKSIZE = [31, 16, 33, 1, 1023] +defines.INLINE_MAX = [0, -1, 8] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; @@ -67,6 +69,7 @@ code = ''' defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.CHUNKSIZE = [31, 16, 1] +defines.INLINE_MAX = [0, -1, 8] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; @@ -152,6 +155,7 @@ code = ''' defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.CHUNKSIZE = [31, 16, 1] +defines.INLINE_MAX = [0, -1, 8] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; @@ -232,6 +236,7 @@ code = ''' defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.CHUNKSIZE = [31, 16, 1] +defines.INLINE_MAX = [0, -1, 8] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; @@ -303,6 +308,7 @@ code = ''' [cases.test_files_reentrant_write] defines.SIZE = [32, 0, 7, 2049] defines.CHUNKSIZE = [31, 16, 65] +defines.INLINE_MAX = [0, -1, 8] reentrant = true code = ''' lfs_t lfs; @@ -354,11 +360,20 @@ code = ''' [cases.test_files_reentrant_write_sync] defines = [ # append (O(n)) - {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, + {MODE='LFS_O_APPEND', + SIZE=[32, 0, 7, 2049], + CHUNKSIZE=[31, 16, 65], + INLINE_MAX=[0, -1, 8]}, # truncate (O(n^2)) - {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, + {MODE='LFS_O_TRUNC', + SIZE=[32, 0, 7, 200], + CHUNKSIZE=[31, 16, 65], + INLINE_MAX=[0, -1, 8]}, # rewrite (O(n^2)) - {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, + {MODE=0, + SIZE=[32, 0, 7, 200], + CHUNKSIZE=[31, 16, 65], + INLINE_MAX=[0, -1, 8]}, ] reentrant = true code = ''' From a70870c628dfd3ed8ddb908b0f2844c5717dc3b9 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Dec 2023 23:20:16 -0600 Subject: [PATCH 16/17] Renamed internal functions _raw* -> _*_ So instead of lfs_file_rawopencfg, it's now lfs_file_opencfg_. The "raw" prefix is annoying, doesn't really add meaning ("internal" would have been better), and gets in the way of finding the relevant function implementations. I have been using _s as suffixes for unimportant name collisions in other codebases, and it seems to work well at reducing wasted brain cycles naming things. Adopting it here avoids the need for "raw" prefixes. It's quite a bit like the use of prime symbols to resolve name collisions in math, e.g. x' = x + 1. Which is even supported in Haskell and is quite nice there. And the main benefit: Now if you search for the public API name, you get the internal function first, which is probably what you care about. Here is the exact script: sed -i 's/_raw\([a-z0-9_]*\)\>/_\1_/g' $(git ls-tree -r HEAD --name-only | grep '.*\.c') --- bd/lfs_emubd.c | 6 +- lfs.c | 184 ++++++++++++++++++++++++------------------------- 2 files changed, 95 insertions(+), 95 deletions(-) diff --git a/bd/lfs_emubd.c b/bd/lfs_emubd.c index c27ae300..9d88d053 100644 --- a/bd/lfs_emubd.c +++ b/bd/lfs_emubd.c @@ -451,7 +451,7 @@ int lfs_emubd_sync(const struct lfs_config *cfg) { /// Additional extended API for driving test features /// -static int lfs_emubd_rawcrc(const struct lfs_config *cfg, +static int lfs_emubd_crc_(const struct lfs_config *cfg, lfs_block_t block, uint32_t *crc) { lfs_emubd_t *bd = cfg->context; @@ -480,7 +480,7 @@ int lfs_emubd_crc(const struct lfs_config *cfg, lfs_block_t block, uint32_t *crc) { LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)", (void*)cfg, block, crc); - int err = lfs_emubd_rawcrc(cfg, block, crc); + int err = lfs_emubd_crc_(cfg, block, crc); LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err); return err; } @@ -491,7 +491,7 @@ int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc) { uint32_t crc_ = 0xffffffff; for (lfs_block_t i = 0; i < cfg->block_count; i++) { uint32_t i_crc; - int err = lfs_emubd_rawcrc(cfg, i, &i_crc); + int err = lfs_emubd_crc_(cfg, i, &i_crc); if (err) { LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err); return err; diff --git a/lfs.c b/lfs.c index 9ad16839..d5885ca0 100644 --- a/lfs.c +++ b/lfs.c @@ -550,9 +550,9 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *source, uint16_t begin, uint16_t end); static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size); -static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, +static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size); -static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file); +static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file); static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); @@ -574,22 +574,22 @@ static int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); #endif -static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir); +static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir); static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size); -static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, +static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size); -static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file); -static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file); +static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file); +static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file); -static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs); -static int lfs_fs_rawtraverse(lfs_t *lfs, +static lfs_ssize_t lfs_fs_size_(lfs_t *lfs); +static int lfs_fs_traverse_(lfs_t *lfs, int (*cb)(void *data, lfs_block_t block), void *data, bool includeorphans); static int lfs_deinit(lfs_t *lfs); -static int lfs_rawunmount(lfs_t *lfs); +static int lfs_unmount_(lfs_t *lfs); /// Block allocator /// @@ -639,7 +639,7 @@ static int lfs_alloc_scan(lfs_t *lfs) { // find mask of free blocks from tree memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size); - int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); + int err = lfs_fs_traverse_(lfs, lfs_alloc_lookahead, lfs, true); if (err) { lfs_alloc_drop(lfs); return err; @@ -2166,7 +2166,7 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir, && lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? - lfs_ssize_t size = lfs_fs_rawsize(lfs); + lfs_ssize_t size = lfs_fs_size_(lfs); if (size < 0) { return size; } @@ -2586,7 +2586,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, /// Top level directory operations /// #ifndef LFS_READONLY -static int lfs_rawmkdir(lfs_t *lfs, const char *path) { +static int lfs_mkdir_(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { @@ -2682,7 +2682,7 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) { } #endif -static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) { +static int lfs_dir_open_(lfs_t *lfs, lfs_dir_t *dir, const char *path) { lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL); if (tag < 0) { return tag; @@ -2726,14 +2726,14 @@ static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) { return 0; } -static int lfs_dir_rawclose(lfs_t *lfs, lfs_dir_t *dir) { +static int lfs_dir_close_(lfs_t *lfs, lfs_dir_t *dir) { // remove from list of mdirs lfs_mlist_remove(lfs, (struct lfs_mlist *)dir); return 0; } -static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { +static int lfs_dir_read_(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { memset(info, 0, sizeof(*info)); // special offset for '.' and '..' @@ -2778,9 +2778,9 @@ static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { return true; } -static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { +static int lfs_dir_seek_(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { // simply walk from head dir - int err = lfs_dir_rawrewind(lfs, dir); + int err = lfs_dir_rewind_(lfs, dir); if (err) { return err; } @@ -2815,12 +2815,12 @@ static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { return 0; } -static lfs_soff_t lfs_dir_rawtell(lfs_t *lfs, lfs_dir_t *dir) { +static lfs_soff_t lfs_dir_tell_(lfs_t *lfs, lfs_dir_t *dir) { (void)lfs; return dir->pos; } -static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir) { +static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir) { // reload the head dir int err = lfs_dir_fetch(lfs, &dir->m, dir->head); if (err) { @@ -3026,7 +3026,7 @@ static int lfs_ctz_traverse(lfs_t *lfs, /// Top level file operations /// -static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, +static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file, const char *path, int flags, const struct lfs_file_config *cfg) { #ifndef LFS_READONLY @@ -3188,22 +3188,22 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, #ifndef LFS_READONLY file->flags |= LFS_F_ERRED; #endif - lfs_file_rawclose(lfs, file); + lfs_file_close_(lfs, file); return err; } #ifndef LFS_NO_MALLOC -static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file, +static int lfs_file_open_(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { static const struct lfs_file_config defaults = {0}; - int err = lfs_file_rawopencfg(lfs, file, path, flags, &defaults); + int err = lfs_file_opencfg_(lfs, file, path, flags, &defaults); return err; } #endif -static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) { +static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file) { #ifndef LFS_READONLY - int err = lfs_file_rawsync(lfs, file); + int err = lfs_file_sync_(lfs, file); #else int err = 0; #endif @@ -3386,7 +3386,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { } #ifndef LFS_READONLY -static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { +static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_ERRED) { // it's not safe to do anything if our file errored return 0; @@ -3499,7 +3499,7 @@ static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file, return size; } -static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, +static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size) { LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY); @@ -3602,7 +3602,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file, return size; } -static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, +static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size) { LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); @@ -3646,7 +3646,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, } #endif -static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, +static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence) { // find new pos lfs_off_t npos = file->pos; @@ -3659,7 +3659,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, npos = file->pos + off; } } else if (whence == LFS_SEEK_END) { - lfs_soff_t res = lfs_file_rawsize(lfs, file) + off; + lfs_soff_t res = lfs_file_size_(lfs, file) + off; if (res < 0) { return LFS_ERR_INVAL; } else { @@ -3710,7 +3710,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, } #ifndef LFS_READONLY -static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { +static int lfs_file_truncate_(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); if (size > LFS_FILE_MAX) { @@ -3718,12 +3718,12 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { } lfs_off_t pos = file->pos; - lfs_off_t oldsize = lfs_file_rawsize(lfs, file); + lfs_off_t oldsize = lfs_file_size_(lfs, file); if (size < oldsize) { // revert to inline file? if (size <= lfs->inline_max) { // flush+seek to head - lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET); + lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET); if (res < 0) { return (int)res; } @@ -3768,14 +3768,14 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { } } else if (size > oldsize) { // flush+seek if not already at end - lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END); + lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_END); if (res < 0) { return (int)res; } // fill with zeros while (file->pos < size) { - res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1); + res = lfs_file_write_(lfs, file, &(uint8_t){0}, 1); if (res < 0) { return (int)res; } @@ -3783,7 +3783,7 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { } // restore pos - lfs_soff_t res = lfs_file_rawseek(lfs, file, pos, LFS_SEEK_SET); + lfs_soff_t res = lfs_file_seek_(lfs, file, pos, LFS_SEEK_SET); if (res < 0) { return (int)res; } @@ -3792,13 +3792,13 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { } #endif -static lfs_soff_t lfs_file_rawtell(lfs_t *lfs, lfs_file_t *file) { +static lfs_soff_t lfs_file_tell_(lfs_t *lfs, lfs_file_t *file) { (void)lfs; return file->pos; } -static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) { - lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET); +static int lfs_file_rewind_(lfs_t *lfs, lfs_file_t *file) { + lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET); if (res < 0) { return (int)res; } @@ -3806,7 +3806,7 @@ static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) { return 0; } -static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) { +static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file) { (void)lfs; #ifndef LFS_READONLY @@ -3820,7 +3820,7 @@ static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) { /// General fs operations /// -static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) { +static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) { lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0) { @@ -3831,7 +3831,7 @@ static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) { } #ifndef LFS_READONLY -static int lfs_rawremove(lfs_t *lfs, const char *path) { +static int lfs_remove_(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { @@ -3910,7 +3910,7 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) { #endif #ifndef LFS_READONLY -static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) { +static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { @@ -4047,7 +4047,7 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) { } #endif -static lfs_ssize_t lfs_rawgetattr(lfs_t *lfs, const char *path, +static lfs_ssize_t lfs_getattr_(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size) { lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); @@ -4105,7 +4105,7 @@ static int lfs_commitattr(lfs_t *lfs, const char *path, #endif #ifndef LFS_READONLY -static int lfs_rawsetattr(lfs_t *lfs, const char *path, +static int lfs_setattr_(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { if (size > lfs->attr_max) { return LFS_ERR_NOSPC; @@ -4116,7 +4116,7 @@ static int lfs_rawsetattr(lfs_t *lfs, const char *path, #endif #ifndef LFS_READONLY -static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) { +static int lfs_removeattr_(lfs_t *lfs, const char *path, uint8_t type) { return lfs_commitattr(lfs, path, type, NULL, 0x3ff); } #endif @@ -4314,7 +4314,7 @@ static int lfs_deinit(lfs_t *lfs) { #ifndef LFS_READONLY -static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) { +static int lfs_format_(lfs_t *lfs, const struct lfs_config *cfg) { int err = 0; { err = lfs_init(lfs, cfg); @@ -4381,7 +4381,7 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) { } #endif -static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { +static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) { int err = lfs_init(lfs, cfg); if (err) { return err; @@ -4547,17 +4547,17 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { return 0; cleanup: - lfs_rawunmount(lfs); + lfs_unmount_(lfs); return err; } -static int lfs_rawunmount(lfs_t *lfs) { +static int lfs_unmount_(lfs_t *lfs) { return lfs_deinit(lfs); } /// Filesystem filesystem operations /// -static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) { +static int lfs_fs_stat_(lfs_t *lfs, struct lfs_fsinfo *fsinfo) { // if the superblock is up-to-date, we must be on the most recent // minor version of littlefs if (!lfs_gstate_needssuperblock(&lfs->gstate)) { @@ -4597,7 +4597,7 @@ static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) { return 0; } -int lfs_fs_rawtraverse(lfs_t *lfs, +int lfs_fs_traverse_(lfs_t *lfs, int (*cb)(void *data, lfs_block_t block), void *data, bool includeorphans) { // iterate over metadata pairs @@ -5062,7 +5062,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { #endif #ifndef LFS_READONLY -static int lfs_fs_rawmkconsistent(lfs_t *lfs) { +static int lfs_fs_mkconsistent_(lfs_t *lfs) { // lfs_fs_forceconsistency does most of the work here int err = lfs_fs_forceconsistency(lfs); if (err) { @@ -5098,9 +5098,9 @@ static int lfs_fs_size_count(void *p, lfs_block_t block) { return 0; } -static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) { +static lfs_ssize_t lfs_fs_size_(lfs_t *lfs) { lfs_size_t size = 0; - int err = lfs_fs_rawtraverse(lfs, lfs_fs_size_count, &size, false); + int err = lfs_fs_traverse_(lfs, lfs_fs_size_count, &size, false); if (err) { return err; } @@ -5110,7 +5110,7 @@ static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) { // explicit garbage collection #ifndef LFS_READONLY -static int lfs_fs_rawgc(lfs_t *lfs) { +static int lfs_fs_gc_(lfs_t *lfs) { // force consistency, even if we're not necessarily going to write, // because this function is supposed to take care of janitorial work // isn't it? @@ -5160,7 +5160,7 @@ static int lfs_fs_rawgc(lfs_t *lfs) { #endif #ifndef LFS_READONLY -static int lfs_fs_rawgrow(lfs_t *lfs, lfs_size_t block_count) { +static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) { // shrinking is not supported LFS_ASSERT(block_count >= lfs->block_count); @@ -5619,7 +5619,7 @@ static int lfs1_unmount(lfs_t *lfs) { } /// v1 migration /// -static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) { +static int lfs_migrate_(lfs_t *lfs, const struct lfs_config *cfg) { struct lfs1 lfs1; // Indeterminate filesystem size not allowed for migration. @@ -5886,7 +5886,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs_rawformat(lfs, cfg); + err = lfs_format_(lfs, cfg); LFS_TRACE("lfs_format -> %d", err); LFS_UNLOCK(cfg); @@ -5916,7 +5916,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs_rawmount(lfs, cfg); + err = lfs_mount_(lfs, cfg); LFS_TRACE("lfs_mount -> %d", err); LFS_UNLOCK(cfg); @@ -5930,7 +5930,7 @@ int lfs_unmount(lfs_t *lfs) { } LFS_TRACE("lfs_unmount(%p)", (void*)lfs); - err = lfs_rawunmount(lfs); + err = lfs_unmount_(lfs); LFS_TRACE("lfs_unmount -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -5945,7 +5945,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { } LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); - err = lfs_rawremove(lfs, path); + err = lfs_remove_(lfs, path); LFS_TRACE("lfs_remove -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -5961,7 +5961,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { } LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); - err = lfs_rawrename(lfs, oldpath, newpath); + err = lfs_rename_(lfs, oldpath, newpath); LFS_TRACE("lfs_rename -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -5976,7 +5976,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { } LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); - err = lfs_rawstat(lfs, path, info); + err = lfs_stat_(lfs, path, info); LFS_TRACE("lfs_stat -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -5992,7 +5992,7 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs, path, type, buffer, size); - lfs_ssize_t res = lfs_rawgetattr(lfs, path, type, buffer, size); + lfs_ssize_t res = lfs_getattr_(lfs, path, type, buffer, size); LFS_TRACE("lfs_getattr -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6009,7 +6009,7 @@ int lfs_setattr(lfs_t *lfs, const char *path, LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs, path, type, buffer, size); - err = lfs_rawsetattr(lfs, path, type, buffer, size); + err = lfs_setattr_(lfs, path, type, buffer, size); LFS_TRACE("lfs_setattr -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6025,7 +6025,7 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { } LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); - err = lfs_rawremoveattr(lfs, path, type); + err = lfs_removeattr_(lfs, path, type); LFS_TRACE("lfs_removeattr -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6043,7 +6043,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { (void*)lfs, (void*)file, path, flags); LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - err = lfs_file_rawopen(lfs, file, path, flags); + err = lfs_file_open_(lfs, file, path, flags); LFS_TRACE("lfs_file_open -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6064,7 +6064,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - err = lfs_file_rawopencfg(lfs, file, path, flags, cfg); + err = lfs_file_opencfg_(lfs, file, path, flags, cfg); LFS_TRACE("lfs_file_opencfg -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6079,7 +6079,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - err = lfs_file_rawclose(lfs, file); + err = lfs_file_close_(lfs, file); LFS_TRACE("lfs_file_close -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6095,7 +6095,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - err = lfs_file_rawsync(lfs, file); + err = lfs_file_sync_(lfs, file); LFS_TRACE("lfs_file_sync -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6113,7 +6113,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, (void*)lfs, (void*)file, buffer, size); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size); + lfs_ssize_t res = lfs_file_read_(lfs, file, buffer, size); LFS_TRACE("lfs_file_read -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6131,7 +6131,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, (void*)lfs, (void*)file, buffer, size); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size); + lfs_ssize_t res = lfs_file_write_(lfs, file, buffer, size); LFS_TRACE("lfs_file_write -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6149,7 +6149,7 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, (void*)lfs, (void*)file, off, whence); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence); + lfs_soff_t res = lfs_file_seek_(lfs, file, off, whence); LFS_TRACE("lfs_file_seek -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6166,7 +6166,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { (void*)lfs, (void*)file, size); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - err = lfs_file_rawtruncate(lfs, file, size); + err = lfs_file_truncate_(lfs, file, size); LFS_TRACE("lfs_file_truncate -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6182,7 +6182,7 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - lfs_soff_t res = lfs_file_rawtell(lfs, file); + lfs_soff_t res = lfs_file_tell_(lfs, file); LFS_TRACE("lfs_file_tell -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6196,7 +6196,7 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { } LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); - err = lfs_file_rawrewind(lfs, file); + err = lfs_file_rewind_(lfs, file); LFS_TRACE("lfs_file_rewind -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6211,7 +6211,7 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); - lfs_soff_t res = lfs_file_rawsize(lfs, file); + lfs_soff_t res = lfs_file_size_(lfs, file); LFS_TRACE("lfs_file_size -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6226,7 +6226,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { } LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); - err = lfs_rawmkdir(lfs, path); + err = lfs_mkdir_(lfs, path); LFS_TRACE("lfs_mkdir -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6242,7 +6242,7 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)dir)); - err = lfs_dir_rawopen(lfs, dir, path); + err = lfs_dir_open_(lfs, dir, path); LFS_TRACE("lfs_dir_open -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6256,7 +6256,7 @@ int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { } LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); - err = lfs_dir_rawclose(lfs, dir); + err = lfs_dir_close_(lfs, dir); LFS_TRACE("lfs_dir_close -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6271,7 +6271,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { LFS_TRACE("lfs_dir_read(%p, %p, %p)", (void*)lfs, (void*)dir, (void*)info); - err = lfs_dir_rawread(lfs, dir, info); + err = lfs_dir_read_(lfs, dir, info); LFS_TRACE("lfs_dir_read -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6286,7 +6286,7 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", (void*)lfs, (void*)dir, off); - err = lfs_dir_rawseek(lfs, dir, off); + err = lfs_dir_seek_(lfs, dir, off); LFS_TRACE("lfs_dir_seek -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6300,7 +6300,7 @@ lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { } LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); - lfs_soff_t res = lfs_dir_rawtell(lfs, dir); + lfs_soff_t res = lfs_dir_tell_(lfs, dir); LFS_TRACE("lfs_dir_tell -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6314,7 +6314,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { } LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); - err = lfs_dir_rawrewind(lfs, dir); + err = lfs_dir_rewind_(lfs, dir); LFS_TRACE("lfs_dir_rewind -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6328,7 +6328,7 @@ int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) { } LFS_TRACE("lfs_fs_stat(%p, %p)", (void*)lfs, (void*)fsinfo); - err = lfs_fs_rawstat(lfs, fsinfo); + err = lfs_fs_stat_(lfs, fsinfo); LFS_TRACE("lfs_fs_stat -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6342,7 +6342,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs) { } LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); - lfs_ssize_t res = lfs_fs_rawsize(lfs); + lfs_ssize_t res = lfs_fs_size_(lfs); LFS_TRACE("lfs_fs_size -> %"PRId32, res); LFS_UNLOCK(lfs->cfg); @@ -6357,7 +6357,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) { LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", (void*)lfs, (void*)(uintptr_t)cb, data); - err = lfs_fs_rawtraverse(lfs, cb, data, true); + err = lfs_fs_traverse_(lfs, cb, data, true); LFS_TRACE("lfs_fs_traverse -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6372,7 +6372,7 @@ int lfs_fs_mkconsistent(lfs_t *lfs) { } LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs); - err = lfs_fs_rawmkconsistent(lfs); + err = lfs_fs_mkconsistent_(lfs); LFS_TRACE("lfs_fs_mkconsistent -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6388,7 +6388,7 @@ int lfs_fs_gc(lfs_t *lfs) { } LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs); - err = lfs_fs_rawgc(lfs); + err = lfs_fs_gc_(lfs); LFS_TRACE("lfs_fs_gc -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6404,7 +6404,7 @@ int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count) { } LFS_TRACE("lfs_fs_grow(%p, %"PRIu32")", (void*)lfs, block_count); - err = lfs_fs_rawgrow(lfs, block_count); + err = lfs_fs_grow_(lfs, block_count); LFS_TRACE("lfs_fs_grow -> %d", err); LFS_UNLOCK(lfs->cfg); @@ -6435,7 +6435,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs_rawmigrate(lfs, cfg); + err = lfs_migrate_(lfs, cfg); LFS_TRACE("lfs_migrate -> %d", err); LFS_UNLOCK(cfg); From 42910bc8e595dfe458624328bfac075d14f92e0a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 19 Jan 2024 14:37:37 -0600 Subject: [PATCH 17/17] Bumped minor version to v2.9 --- lfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lfs.h b/lfs.h index 79fd685b..99145022 100644 --- a/lfs.h +++ b/lfs.h @@ -21,7 +21,7 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS_VERSION 0x00020008 +#define LFS_VERSION 0x00020009 #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))