From fb2c311bb4ce0c25f3ead159cfd1d1e75558b0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Mon, 14 Jun 2021 12:12:38 +0200 Subject: [PATCH 01/10] Fix compiler warnings when LFS_READONLY defined --- lfs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lfs.c b/lfs.c index d976389..da17280 100644 --- a/lfs.c +++ b/lfs.c @@ -11,12 +11,15 @@ #define LFS_BLOCK_INLINE ((lfs_block_t)-2) /// Caching block device operations /// + +#ifndef LFS_READONLY static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { // do not zero, cheaper if cache is readonly or only going to be // written with identical data (during relocates) (void)lfs; rcache->block = LFS_BLOCK_NULL; } +#endif static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { // zero to avoid information leak @@ -268,22 +271,26 @@ static inline int lfs_pair_cmp( paira[0] == pairb[1] || paira[1] == pairb[0]); } +#ifndef LFS_READONLY static inline bool lfs_pair_sync( const lfs_block_t paira[2], const lfs_block_t pairb[2]) { return (paira[0] == pairb[0] && paira[1] == pairb[1]) || (paira[0] == pairb[1] && paira[1] == pairb[0]); } +#endif static inline void lfs_pair_fromle32(lfs_block_t pair[2]) { pair[0] = lfs_fromle32(pair[0]); pair[1] = lfs_fromle32(pair[1]); } +#ifndef LFS_READONLY static inline void lfs_pair_tole32(lfs_block_t pair[2]) { pair[0] = lfs_tole32(pair[0]); pair[1] = lfs_tole32(pair[1]); } +#endif // operations on 32-bit entry tags typedef uint32_t lfs_tag_t; @@ -365,6 +372,7 @@ static inline bool lfs_gstate_iszero(const lfs_gstate_t *a) { return true; } +#ifndef LFS_READONLY static inline bool lfs_gstate_hasorphans(const lfs_gstate_t *a) { return lfs_tag_size(a->tag); } @@ -376,6 +384,7 @@ static inline uint8_t lfs_gstate_getorphans(const lfs_gstate_t *a) { static inline bool lfs_gstate_hasmove(const lfs_gstate_t *a) { return lfs_tag_type1(a->tag); } +#endif static inline bool lfs_gstate_hasmovehere(const lfs_gstate_t *a, const lfs_block_t *pair) { @@ -388,11 +397,13 @@ static inline void lfs_gstate_fromle32(lfs_gstate_t *a) { a->pair[1] = lfs_fromle32(a->pair[1]); } +#ifndef LFS_READONLY static inline void lfs_gstate_tole32(lfs_gstate_t *a) { a->tag = lfs_tole32(a->tag); a->pair[0] = lfs_tole32(a->pair[0]); a->pair[1] = lfs_tole32(a->pair[1]); } +#endif // other endianness operations static void lfs_ctz_fromle32(struct lfs_ctz *ctz) { @@ -416,6 +427,7 @@ static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { superblock->attr_max = lfs_fromle32(superblock->attr_max); } +#ifndef LFS_READONLY static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { superblock->version = lfs_tole32(superblock->version); superblock->block_size = lfs_tole32(superblock->block_size); @@ -424,6 +436,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { superblock->file_max = lfs_tole32(superblock->file_max); superblock->attr_max = lfs_tole32(superblock->attr_max); } +#endif #ifndef LFS_NO_ASSERT static bool lfs_mlist_isopen(struct lfs_mlist *head, From fdda3b4aa2a30698f8bccf47e794ffa7eda67239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sun, 14 Nov 2021 16:10:54 +0100 Subject: [PATCH 02/10] Always zero rambd buffer before first use This fixes warnings produced by tools such as memcheck without requiring the user to set an erase value. --- bd/lfs_rambd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bd/lfs_rambd.c b/bd/lfs_rambd.c index 0a6b5cc..beb0267 100644 --- a/bd/lfs_rambd.c +++ b/bd/lfs_rambd.c @@ -36,6 +36,8 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, if (bd->cfg->erase_value != -1) { memset(bd->buffer, bd->cfg->erase_value, cfg->block_size * cfg->block_count); + } else { + memset(bd->buffer, 0, cfg->block_size * cfg->block_count); } LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); From 4977fa0c0e6b586fd71f0d1f1a312bb9b0a9a44d Mon Sep 17 00:00:00 2001 From: mikee47 Date: Fri, 10 Dec 2021 13:36:28 +0000 Subject: [PATCH 03/10] Fix spelling errors --- bd/lfs_filebd.c | 2 +- bd/lfs_rambd.c | 2 +- lfs.c | 4 ++-- lfs.h | 14 +++++++------- scripts/test.py | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bd/lfs_filebd.c b/bd/lfs_filebd.c index 2d36a42..248a67f 100644 --- a/bd/lfs_filebd.c +++ b/bd/lfs_filebd.c @@ -80,7 +80,7 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, LFS_ASSERT(size % cfg->read_size == 0); LFS_ASSERT(block < cfg->block_count); - // zero for reproducability (in case file is truncated) + // zero for reproducibility (in case file is truncated) if (bd->cfg->erase_value != -1) { memset(buffer, bd->cfg->erase_value, size); } diff --git a/bd/lfs_rambd.c b/bd/lfs_rambd.c index 0a6b5cc..73fd5be 100644 --- a/bd/lfs_rambd.c +++ b/bd/lfs_rambd.c @@ -32,7 +32,7 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, } } - // zero for reproducability? + // zero for reproducibility? if (bd->cfg->erase_value != -1) { memset(bd->buffer, bd->cfg->erase_value, cfg->block_size * cfg->block_count); diff --git a/lfs.c b/lfs.c index d976389..019a9c3 100644 --- a/lfs.c +++ b/lfs.c @@ -1449,7 +1449,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { } } - // zero for reproducability in case initial block is unreadable + // zero for reproducibility in case initial block is unreadable dir->rev = 0; // rather than clobbering one of the blocks we just pretend @@ -4074,7 +4074,7 @@ static int lfs_fs_relocate(lfs_t *lfs, lfs_fs_prepmove(lfs, 0x3ff, NULL); } - // replace bad pair, either we clean up desync, or no desync occured + // replace bad pair, either we clean up desync, or no desync occurred lfs_pair_tole32(newpair); err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( {LFS_MKTAG_IF(moveid != 0x3ff, diff --git a/lfs.h b/lfs.h index ad49162..b2dbe76 100644 --- a/lfs.h +++ b/lfs.h @@ -159,34 +159,34 @@ struct lfs_config { // information to the block device operations void *context; - // Read a region in a block. Negative error codes are propogated + // Read a region in a block. Negative error codes are propagated // to the user. int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); // Program a region in a block. The block must have previously - // been erased. Negative error codes are propogated to the user. + // been erased. Negative error codes are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); // Erase a block. A block must be erased before being programmed. // The state of an erased block is undefined. Negative error codes - // are propogated to the user. + // are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. int (*erase)(const struct lfs_config *c, lfs_block_t block); // Sync the state of the underlying block device. Negative error codes - // are propogated to the user. + // are propagated to the user. int (*sync)(const struct lfs_config *c); #ifdef LFS_THREADSAFE // Lock the underlying block device. Negative error codes - // are propogated to the user. + // are propagated to the user. int (*lock)(const struct lfs_config *c); // Unlock the underlying block device. Negative error codes - // are propogated to the user. + // are propagated to the user. int (*unlock)(const struct lfs_config *c); #endif @@ -485,7 +485,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); // Returns the size of the attribute, or a negative error code on failure. // Note, the returned size is the size of the attribute on disk, irrespective // of the size of the buffer. This can be used to dynamically allocate a buffer -// or check for existance. +// or check for existence. lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size); diff --git a/scripts/test.py b/scripts/test.py index 42a10f9..f8051f0 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -565,7 +565,7 @@ class TestSuite: path=self.path)) mk.write('\n') - # add truely global defines globally + # add truly global defines globally for k, v in sorted(self.defines.items()): mk.write('%s.test: override CFLAGS += -D%s=%r\n' % (self.path, k, v)) @@ -656,7 +656,7 @@ def main(**args): for path in glob.glob(testpath): suites.append(TestSuite(path, classes, defines, filter, **args)) - # sort for reproducability + # sort for reproducibility suites = sorted(suites) # generate permutations From e29e7aeefa09809595e244e4c0c4f5e338e8e4a6 Mon Sep 17 00:00:00 2001 From: Emilio Lopes Date: Fri, 29 Oct 2021 11:16:06 +0200 Subject: [PATCH 04/10] Specify unit of the size members of the lfs_config struct Fixes littlefs-project/littlefs#568 --- lfs.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lfs.h b/lfs.h index ad49162..cfcb075 100644 --- a/lfs.h +++ b/lfs.h @@ -190,18 +190,18 @@ struct lfs_config { int (*unlock)(const struct lfs_config *c); #endif - // Minimum size of a block read. All read operations will be a + // Minimum size of a block read in bytes. All read operations will be a // multiple of this value. lfs_size_t read_size; - // Minimum size of a block program. All program operations will be a - // multiple of this value. + // Minimum size of a block program in bytes. All program operations will be + // a multiple of this value. lfs_size_t prog_size; - // Size of an erasable block. This does not impact ram consumption and - // may be larger than the physical erase size. However, non-inlined files - // take up at minimum one block. Must be a multiple of the read - // and program sizes. + // Size of an erasable block in bytes. This does not impact ram consumption + // and may be larger than the physical erase size. However, non-inlined + // files take up at minimum one block. Must be a multiple of the read and + // program sizes. lfs_size_t block_size; // Number of erasable blocks on the device. @@ -215,11 +215,11 @@ struct lfs_config { // Set to -1 to disable block-level wear-leveling. int32_t block_cycles; - // Size of block caches. Each cache buffers a portion of a block in RAM. - // The littlefs needs a read cache, a program cache, and one additional + // Size of block caches in bytes. Each cache buffers a portion of a block in + // RAM. The littlefs needs a read cache, a program cache, and one additional // cache per file. Larger caches can improve performance by storing more - // data and reducing the number of disk accesses. Must be a multiple of - // the read and program sizes, and a factor of the block size. + // data and reducing the number of disk accesses. Must be a multiple of the + // read and program sizes, and a factor of the block size. lfs_size_t cache_size; // Size of the lookahead buffer in bytes. A larger lookahead buffer From 1877c40aacafd74f55ba4607e2b34f1505aef20b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 23 Aug 2021 14:13:52 -0700 Subject: [PATCH 05/10] Indent sub-portions of tag fields This makes the bit breakdown clearer. --- SPEC.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/SPEC.md b/SPEC.md index cc602c1..3663ea5 100644 --- a/SPEC.md +++ b/SPEC.md @@ -233,19 +233,19 @@ Metadata tag fields: into a 3-bit abstract type and an 8-bit chunk field. Note that the value `0x000` is invalid and not assigned a type. -3. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into - 8 categories that facilitate bitmasked lookups. + 1. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into + 8 categories that facilitate bitmasked lookups. -4. **Chunk (8-bits)** - Chunk field used for various purposes by the different - abstract types. type1+chunk+id form a unique identifier for each tag in the - metadata block. + 2. **Chunk (8-bits)** - Chunk field used for various purposes by the different + abstract types. type1+chunk+id form a unique identifier for each tag in the + metadata block. -5. **Id (10-bits)** - File id associated with the tag. Each file in a metadata +3. **Id (10-bits)** - File id associated with the tag. Each file in a metadata block gets a unique id which is used to associate tags with that file. The special value `0x3ff` is used for any tags that are not associated with a file, such as directory and global metadata. -6. **Length (10-bits)** - Length of the data in bytes. The special value +4. **Length (10-bits)** - Length of the data in bytes. The special value `0x3ff` indicates that this tag has been deleted. ## Metadata types From 5bc682a0d486c779c297d49aa818e4e08d3ea876 Mon Sep 17 00:00:00 2001 From: Kongduino Date: Fri, 25 Feb 2022 10:18:58 +0800 Subject: [PATCH 06/10] Typo s/propogated/propagated/ --- lfs.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lfs.h b/lfs.h index ad49162..9fe6ef2 100644 --- a/lfs.h +++ b/lfs.h @@ -159,34 +159,34 @@ struct lfs_config { // information to the block device operations void *context; - // Read a region in a block. Negative error codes are propogated + // Read a region in a block. Negative error codes are propagated // to the user. int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); // Program a region in a block. The block must have previously - // been erased. Negative error codes are propogated to the user. + // been erased. Negative error codes are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); // Erase a block. A block must be erased before being programmed. // The state of an erased block is undefined. Negative error codes - // are propogated to the user. + // are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. int (*erase)(const struct lfs_config *c, lfs_block_t block); // Sync the state of the underlying block device. Negative error codes - // are propogated to the user. + // are propagated to the user. int (*sync)(const struct lfs_config *c); #ifdef LFS_THREADSAFE // Lock the underlying block device. Negative error codes - // are propogated to the user. + // are propagated to the user. int (*lock)(const struct lfs_config *c); // Unlock the underlying block device. Negative error codes - // are propogated to the user. + // are propagated to the user. int (*unlock)(const struct lfs_config *c); #endif From 1363c9f9d411e59f8ac8f509e5bf51c2ef5315bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=98=95?= Date: Tue, 30 Nov 2021 20:52:29 +0800 Subject: [PATCH 07/10] fix bug:lfs_alloc will alloc one block repeatedly in multiple split BUG CASE:Assume there are 6 blocks in littlefs, block 0,1,2,3 already allocated. 0 has a tail pair of {2, 3}. Now we try to write more into 0. When writing to block 0, we will split(FIRST SPLIT), thus allocate block 4 and 5. Up to now , everything is as expected. Then we will try to commit in block 4, during which split(SECOND SPLIT) is triggered again(In our case, some files are large, some are small, one split may not be enough). Still as expected now. BUG happens when we try to alloc a new block pair for the second split: As lookahead buffer reaches the end , a new lookahead buffer will be generated from flash content, and block 4, 5 are unused blocks in the new lookahead buffer because they are not programed yet. HOWEVER, block 4,5 should be occupied in the first split!!!!! The result is block 4,5 are allocated again(This is where things are getting wrong). commit ce2c01f results in this bug. In the commit, a lfs_alloc_ack is inserted in lfs_dir_split, which will cause split to reset lfs->free.ack to block count. In summary, this problem exists after 2.1.3. Solution: don't call lfs_alloc_ack in lfs_dir_split. --- lfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lfs.c b/lfs.c index d976389..dfb2850 100644 --- a/lfs.c +++ b/lfs.c @@ -1509,7 +1509,6 @@ static int lfs_dir_split(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t split, uint16_t end) { // create tail directory - lfs_alloc_ack(lfs); lfs_mdir_t tail; int err = lfs_dir_alloc(lfs, &tail); if (err) { From e955b9f65d64b6a8852e321513283020911a3eb3 Mon Sep 17 00:00:00 2001 From: ondrap Date: Mon, 31 Jan 2022 13:37:33 +0100 Subject: [PATCH 08/10] Fix lfs_file_seek doesn't update cache properties correctly in readonly mode. Invalidate cache to fix it. --- lfs.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lfs.c b/lfs.c index d976389..351a126 100644 --- a/lfs.c +++ b/lfs.c @@ -2730,14 +2730,18 @@ static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { } #endif -#ifndef LFS_READONLY -static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { +static void lfs_file_invalidate_reading_flag(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_READING) { if (!(file->flags & LFS_F_INLINE)) { lfs_cache_drop(lfs, &file->cache); } file->flags &= ~LFS_F_READING; } +} + +#ifndef LFS_READONLY +static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { + lfs_file_invalidate_reading_flag(lfs, file); if (file->flags & LFS_F_WRITING) { lfs_off_t pos = file->pos; @@ -3087,6 +3091,10 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, if (err) { return err; } +#else + // Seek doesn't update cache parameters properly. + // It has to be invalidated otherwise next read will return incorrect values. + lfs_file_invalidate_reading_flag(lfs,file); #endif // update pos From 03f088b92c024bd64b2635d3d6896403514fb9b7 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 20 Mar 2022 23:14:34 -0500 Subject: [PATCH 09/10] Tweaked lfs_file_flush to still flush caches when build under LFS_READONLY A slight varation to the fix from ondrap --- lfs.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lfs.c b/lfs.c index 351a126..2da68b5 100644 --- a/lfs.c +++ b/lfs.c @@ -2730,19 +2730,15 @@ static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { } #endif -static void lfs_file_invalidate_reading_flag(lfs_t *lfs, lfs_file_t *file) { +static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_READING) { if (!(file->flags & LFS_F_INLINE)) { lfs_cache_drop(lfs, &file->cache); } file->flags &= ~LFS_F_READING; } -} #ifndef LFS_READONLY -static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { - lfs_file_invalidate_reading_flag(lfs, file); - if (file->flags & LFS_F_WRITING) { lfs_off_t pos = file->pos; @@ -2809,10 +2805,10 @@ relocate: file->pos = pos; } +#endif return 0; } -#endif #ifndef LFS_READONLY static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { @@ -3085,17 +3081,11 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, return npos; } -#ifndef LFS_READONLY // write out everything beforehand, may be noop if rdonly int err = lfs_file_flush(lfs, file); if (err) { return err; } -#else - // Seek doesn't update cache parameters properly. - // It has to be invalidated otherwise next read will return incorrect values. - lfs_file_invalidate_reading_flag(lfs,file); -#endif // update pos file->pos = npos; From 9c7e232086f865cff0bb96fe753deb66431d91fd Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 21 Mar 2022 20:29:04 -0500 Subject: [PATCH 10/10] Fixed missing definition of lfs_cache_drop in readonly mode Interestingly this was introduced by two different PRs which were not tested together until pre-release testing: - Fix lfs_file_seek doesn't update cache properties correctly - Fix compiler warnings when LFS_READONLY defined --- lfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lfs.c b/lfs.c index d7c692d..e165e54 100644 --- a/lfs.c +++ b/lfs.c @@ -12,14 +12,12 @@ /// Caching block device operations /// -#ifndef LFS_READONLY static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { // do not zero, cheaper if cache is readonly or only going to be // written with identical data (during relocates) (void)lfs; rcache->block = LFS_BLOCK_NULL; } -#endif static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { // zero to avoid information leak