Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix metadata_max==prog_size commit->end calculation #1031

Open
wants to merge 3 commits into
base: devel
Choose a base branch
from

Conversation

geky
Copy link
Member

@geky geky commented Oct 4, 2024

I've been trying to dig into some of the early LFS_ERR_NOSPC errors users have been seeing. Some of the problem is that littlefs returns LFS_ERR_NOSPC for both "no space" errors, and internally whenever metadata can't fit in a block/mdir. This has made tracking down the actual root cause a bit tricky.

I did at least find one bug: In mdir compaction we weren't correctly adjusting commit->end to reserve space for commit-related metadata (checksums, tail pointers, etc) when metadata_max == prog_size.

This went unnoticed due to a lack of testing and requiring metadata_max == prog_size.

Added a quick test to prevent regression, and also added a few more asserts to lfs_init related to possible metadata_max configuration mistakes.

Found by @ajheck, @dpkristensen, @NLLK, and likely others.
Related #755, #896

- Added METADATA_MAX to test_runner.
- Added METADATA_MAX to bench_runner.
- Added a simple metadata_max test to test_superblocks, for lack of
  better location.

There have been several issues floating around related to metadata_max
and LFS_ERR_NOSPC which makes me think there's a bug in our metadata_max
logic.

metadata_max was a quick patch and is relatively untested, so an
undetected bug isn't too surprising. This commit adds at least some
testing over metadata_max.

Sure enough, the new test_superblocks_metadata_max test reveals a
curious LFS_ERR_NAMETOOLONG error that shouldn't be there.

More investigation needed.
The inconsistency here between the use of block_size vs metadata_max was
suspicious. Turns out there's a bug when metadata_max == prog_size.

We correctly use metadata_max for the block_size/2 check, but we weren't
using it for the block_size-40 check. The second check seems unnecessary
after the first, but it protects against running out of space in a
commit for commit-related metadata (checksums, tail pointers, etc) when
we can't program half-blocks.

Turns out this is also needed when limiting metadata_max to a single
prog, otherwise we risk erroring with LFS_ERR_NOSPC early.

Found by ajheck, dpkristensen, NLLK, and likely others.
Like the read/prog/block_size checks, these are just asserts. If these
invariants are broken the filesystem will break in surprising ways.
@geky-bot
Copy link
Collaborator

geky-bot commented Oct 4, 2024

Tests passed ✓, Code: 17068 B, Stack: 1440 B, Structs: 812 B
Code Stack Structs Coverage
Default 17068 B 1440 B 812 B Lines 2397/2576 lines
Readonly 6194 B 448 B 812 B Branches 1262/1602 branches
Threadsafe 17928 B 1440 B 820 B Benchmarks
Multiversion 17128 B 1440 B 816 B Readed 29369693876 B
Migrate 18764 B 1744 B 816 B Proged 1482874766 B
Error-asserts 17808 B 1432 B 812 B Erased 1568888832 B

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants