Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
64f70f5
lfs_bd_cmp() compares more bytes at one time
Mar 13, 2020
6d0ec5e
Added littlefs-python to the related projects section
jrast Apr 13, 2020
87a2cb0
Fix assert
sgupta20 Aug 18, 2020
10ac6b9
add thread safe wrappers
renesas-billgesner Sep 17, 2020
8e6826c
Add LFS_READYONLY define, to allow smaller builds providing read-only…
maximevince Oct 28, 2020
4bd653d
Assert that file/dir struct is not reused in lfs_file_opencfg/lfs_dir…
Jun 17, 2020
6303558
Use LFS_O_RDWR instead of magic number in lfs_file_* asserts
Jun 17, 2020
480cdd9
Fixed incorrect modulus in lfs_alloc_reset
geky Nov 14, 2020
1ae4b36
Removed unnecessary randomization of offsets in lfs_alloc_reset
geky Nov 20, 2020
f215027
Switched to CRC as seed collection function instead of xor
geky Nov 20, 2020
d04c139
Fixed allocation-eviction issue when erase state is multiple of block…
geky Nov 22, 2020
0ea2871
Fixed typo in scripts/readtree.py
geky Nov 22, 2020
0aba71d
Fixed single unchecked bit during commit verification
geky Nov 22, 2020
b8dcf10
Changed lfs_dir_alloc to maximize block cycles for new metadata pairs
geky Nov 29, 2020
817ef02
Merge pull request #412 from jrast/patch-3
geky Dec 4, 2020
1dc6ae9
Merge pull request #486 from littlefs-project/fix-assert
geky Dec 4, 2020
e273a82
Merge pull request #487 from littlefs-project/fix-alloc-reset-modulus
geky Dec 4, 2020
6627206
Merge pull request #395 from gmpy/improve-write-performance
geky Dec 4, 2020
008ebc3
Add lfs_mlist_append/remove helper
Nov 17, 2020
584eb26
Merge pull request #443 from NoahGorny/add-already-opened-assert
geky Dec 4, 2020
754b4c3
Squash of LFS_READONLY cleanup
maximevince Nov 17, 2020
2efebf8
Added read-only build+size reporting to CI
geky Nov 22, 2020
b9fa33f
Merge pull request #480 from maximevince/master
geky Dec 4, 2020
d0f055d
Squash of thread-safe PR cleanup
renesas-billgesner Oct 1, 2020
fc6988c
make raw functions static. formatting tweaks
renesas-billgesner Nov 20, 2020
00a9ba7
Tweaked thread-safe implementation
geky Nov 28, 2020
45afded
Moved LFS_TRACE calls to API wrapper functions
geky Nov 28, 2020
a99a93f
Added thread-safe build+size reporting to CI
geky Nov 28, 2020
ce425a5
Merge pull request #470 from renesas/SWFLEX-1517-littlefs-thread-safe…
geky Dec 4, 2020
7388b29
Deprecate LFS_F_OPENED and use lfs_mlist_isused instead
Nov 17, 2020
2bb5234
Moved lfs_mlist_isopen checks into the API wrappers
geky Dec 4, 2020
5783eea
Merge pull request #490 from littlefs-project/fix-alloc-eviction
geky Dec 4, 2020
288a5cb
Bumped minor version to v2.3
geky Dec 4, 2020
6a70127
Renamed internal lfs_*raw -> lfs_raw* functions
geky Dec 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fixed single unchecked bit during commit verification
This bug was exposed by the bad-block tests due to changes to block
allocation, but could have been hit before these changes.

In flash, when blocks fail, they don't fail in a predictable manner. To
account for this, the bad-block tests check a number of failure
behaviors. The interesting one here is "LFS_TESTBD_BADBLOCK_ERASENOOP",
in which bad blocks can not be erased or programmed, and are stuck with
the data written at the time the blocks go bad.

This is actually a pretty realistic failure behavior, since flash needs a
large voltage to force the electrons of the floating gates. Though
realistically, such a failure would like corrupt the data a bit, not leave the
underlying data perfectly intact.

LFS_TESTBD_BADBLOCK_ERASENOOP is rather interesting to test for because it
means bad blocks can end up with perfectly valid CRCs after a failed write,
confusing littlefs.

---

In this case, we had the perfect series of operations such that a test
was repeatedly writing the same sequence of metadata commits to the same
block, which eventually goes bad, leaving the block stuck with metadata
that occurs later in the sequence.

What this means is that after the first commit, the metadata block
contained both the first and second commits, even though the loop in the
test hadn't reached that point yet.

expected       actual
.----------.  .----------.
| commit 1 |  | commit 1 |
| crc 1    |  | crc 1    |
|          |  | commit 2 <-- (from previous iteration)
|          |  | crc 2    |
'----------'  '----------'

To protect against this, littlefs normally compares the written CRC
against the expected CRC, but because this was the exact same data that
it was going to write, this CRCs end up the same.

Ah! But doesn't littlefs also encode the state of the next page to keep
track of if the next page has been erased or not? Wouldn't that change
between iterations?

It does! In a single bit in the CRC-tag. But thanks to some incorrect
logic attempting to avoid an extra condition in the loop for writing out
padding commits, the CRC that littlefs checked against was the CRC
immediately before we include the "is-next-page-erased" bit.

Changing the verification check to use the same CRC as what is used to
verify commits on fetch solves this problem.
  • Loading branch information
geky committed Nov 22, 2020
commit 0aba71d0d6d57813db2306670a9dd9d25efdfae5
15 changes: 11 additions & 4 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1265,12 +1265,13 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit,
}

static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
const lfs_off_t off1 = commit->off;
const uint32_t crc1 = commit->crc;
// align to program units
const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t),
const lfs_off_t end = lfs_alignup(commit->off + 2*sizeof(uint32_t),
lfs->cfg->prog_size);

lfs_off_t off1 = 0;
uint32_t crc1 = 0;

// create crc tags to fill up remainder of commit, note that
// padding is not crced, which lets fetches skip padding but
// makes committing a bit more complicated
Expand Down Expand Up @@ -1306,6 +1307,12 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
return err;
}

// keep track of non-padding checksum to verify
if (off1 == 0) {
off1 = commit->off + sizeof(uint32_t);
crc1 = commit->crc;
}

commit->off += sizeof(tag)+lfs_tag_size(tag);
commit->ptag = tag ^ ((lfs_tag_t)reset << 31);
commit->crc = 0xffffffff; // reset crc for next "commit"
Expand All @@ -1319,7 +1326,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {

// successful commit, check checksums to make sure
lfs_off_t off = commit->begin;
lfs_off_t noff = off1 + sizeof(uint32_t);
lfs_off_t noff = off1;
while (off < end) {
uint32_t crc = 0xffffffff;
for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) {
Expand Down