Skip to content

LFSv2 + Chunked Contacts - #2964

Draft
oltaco wants to merge 20 commits into
meshcore-dev:devfrom
oltaco:lfs2-chunked-contacts
Draft

LFSv2 + Chunked Contacts#2964
oltaco wants to merge 20 commits into
meshcore-dev:devfrom
oltaco:lfs2-chunked-contacts

Conversation

@oltaco

@oltaco oltaco commented Jul 15, 2026

Copy link
Copy Markdown
Member

This PR upgrades all LFSv1 filesystems (including UserData) to LFSv2, and in the case of ExtraFS it will reformat to 4kB blocks as well.
The monolithic contacts file is converted into chunks that each fit into a single 4kB block, and all file writes are atomic.
Identity and preferences are migrated to ExtraFS/QSPIFlash, and a "backup" copy of identity is left on UserData just in case. At load time if an identity can't be found on the storage filesystem (ExtraFS/QSPIFlash) an attempt is made to restore identity from UserData.

adv_blobs doesn't make the migration from ExtraFS because there isn't enough space in RAM to store it during the reformat to 4kB blocks. adv_blobs is basically treated as ephemeral data anyway so this shouldn't be an issue.

Maximum adv_blobs is reduced from 100 to 40 in order to free up a few blocks for the overhead required for atomic writes and the metadata compaction that happens occasionally on LFSv2. Could be increased to 45 without any extra block overhead.

I've done quite a bit of testing on nRF (Seeed WioTrackerL1, Seeed T1000e, Heltec T114, Xiao NRF52, and others), and also a limited amount of testing on ESP32, RP2040 and STM32.

Something this huge really needs a lot of testing, so please help out if you're game.

Please add the debug macros-D MESH_DEBUG=1 and -D CFG_DEBUG=1 in order to get useful debug prints, especially for the first boot migration process which is where I anticipate issues might be lurking.

Best effort is made to migrate your data but better to be safe than sorry, and switching back to any firmware that doesn't support LFSv2 will wipe your filesystems!

Please backup your node before testing this PR!

@IoTThinks

IoTThinks commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR.
I have this issue on my T1000e a few times.

May I know how this PR solves the root cause of the issue?

Thanks a lot and have a nice day.

@oltaco

oltaco commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

Hi @IoTThinks, thanks for your interest. The main cause of the filesystem corruption issue is a mismatch of block size to page erase size. LittleFS uses metadata block pairs to avoid corruption during PowerLossOnWrite but because on Adafruit LittleFS the block size is 128 byte vs the page erase of 4kB it's possible to lose both metadata blocks from a pair (or even both superblocks, which causes hang on boot in LittleFSv1). Devices using CustomLFS on external flash already use 4kB blocks which is why you basically never see corruption there. Unfortunately due to metadata overhead there's not really room for 4kB blocks for ExtraFS unless we move to LFSv2.

This PR would switch to LittleFSv2 and 4kB blocks for ExtraFS, and also switches to chunked contacts with atomic write instead of a monolithic contacts file. This way any time there is a new contact or updated contact we only write ~4kB of data instead of all of the contacts, and if powerloss happens during the write window we only lose that update instead of the entire file.
As an added bonus there is only one flash write call to write a 4kB file, write time is minimised and so is flash wear.

@IoTThinks

Copy link
Copy Markdown
Contributor

Thanks a lot for your detailed information.

Let me see how to "replicate" the issue to test on my T1000e.
May be flash the firmware many times.

@oltaco

oltaco commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

Let me see how to "replicate" the issue to test on my T1000e. May be flash the firmware many times.

The easiest way to force corruption is to make sure you have a full contacts list, and then use another node to send an advert, and then while the T1000e is writing the contacts to flash you reset it by holding the button and briefly disconnecting the USB cable.

This will corrupt the filesystem every time, sometimes you lose the contacts file, sometimes the contacts file is there but it's corrupted and can lead to crashes on the next advert arrival, or the worst case scenario it corrupts the superblock pair and the node can't boot.

I'll rebase this PR on current dev and force push tomorrow, it will still need more work and testing before it's ready for merge anyway.

@oltaco
oltaco force-pushed the lfs2-chunked-contacts branch 2 times, most recently from 585bace to afbb489 Compare August 10, 2026 04:05
@oltaco
oltaco force-pushed the lfs2-chunked-contacts branch from afbb489 to 6b06784 Compare August 10, 2026 08:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants