oss

What littlefs saves when the power goes out

7 sources 2 primary sources October 30, 2026

Loading reads and saves…
Text

Imagine a battery-powered logger writing its latest measurement when someone pulls the cable. On restart, finding a readable file and finding that last measurement are different successes. The open-source C filesystem littlefs is designed to recover a valid state after an interrupted write. Understanding what that state contains means following the update through its data blocks, metadata and final commit.[1]

This is storage at the scale of a small circuit board. Raspberry Pi's December 2024 Pico Python SDK guide describes a default 1600 kB filesystem using littlefs2 on the original Pico's onboard flash.[6] A familiar Python file operation can therefore depend on machinery built to survive the disappearance of power halfway through its work.

Close photograph of a green Raspberry Pi Pico board, showing its RP2040 chip, smaller components, gold contacts and micro-USB socket.
Raspberry Pi Pico, photographed by Michael H. (“Laserlicht”) on January 27, 2021; crop by Elmepi, displayed at reduced resolution. CC BY-SA 4.0.[7] The board provides a concrete setting for the onboard littlefs storage documented by Raspberry Pi; the photograph does not establish which firmware is installed.[6]

Keep a usable record during the update

Flash cannot freely overwrite its old contents: programming works in smaller units than erasing. Reusing space eventually requires erasing a whole block. littlefs's design combines short metadata logs with copy-on-write file storage to accommodate that mismatch.[3]

Metadata records information such as file names and where their contents live. littlefs stores it in pairs of blocks. Within a block, successive commits extend a log, allowing newer entries to supersede older ones without erasing them immediately. Each commit ends with a CRC, a checksum that helps detect an interrupted or damaged write.[2]

The second block matters when the first needs recycling. The filesystem compacts the surviving information into its partner while retaining the previous usable record. Once the replacement is complete, the old block can be reused.[3] Revision counters identify the newer block when both contain valid commits; checksum validation distinguishes a completed commit from an unusable tail.[2]

These are two separate jobs: identify which record is newer, and establish whether it was completed. A higher revision number alone is insufficient evidence.

File contents take another route

Larger files use copy-on-write data blocks: changed contents go into replacement storage before metadata switches to the new representation. littlefs organizes these blocks as backward-pointing CTZ skip-lists. The backward links let an append reuse earlier blocks; additional links shorten traversal. Editing in the middle can require copying the following blocks, so appending a measurement and revising an old header can have different costs.[3]

Small files can instead live directly inside the metadata log as inline files.[2] The architecture therefore does not require a separate data block for every tiny value. In either case, the useful question is when the new contents become the committed contents.

Two kinds of sync must agree

At the application boundary, lfs_file_write() returns a byte count or an error. Its API documentation says the file is not updated on storage until sync or close. lfs_file_sync() writes pending changes out; lfs_file_close() performs that work before releasing resources. Both can report failure.[4]

Below the filesystem sits another interface. The integrator supplies read, prog, erase and sync callbacks for the storage device.[4] The project's README explicitly requires the lower-level sync to flush cached writes and ensure subsequent reads reach the underlying storage. A driver that reports completion while retaining essential writes in volatile memory breaks the durability assumptions above it.[1]

For the imaginary logger, “measurement accepted” and “measurement committed” should therefore be separate events. If its display promises a saved reading, that promise needs to follow successful synchronization. The application must also decide what to do when synchronization fails.

A sound filesystem can hold an unfinished task

Now give the logger two files: one for measurements and another for an index pointing to the latest record. Suppose the program commits the measurement file, then loses power before committing the index. Both files may be individually valid while the index remains behind.

That example exposes the scope of the guarantee. littlefs documents atomic operations including rename and remove, along with file commits at sync or close.[1] Those operations do not, by themselves, make the logger's two-file sequence one transaction. This is a consequence of where the application placed its boundaries.

One possible design is to make the index reconstructible from the measurement records. Another is to put information that must change together into one committed object. These are application choices; they determine what recovery means after the filesystem has done its part.

Count the memory, then choose the job

The RAM budget is explicit. cache_size sets the read cache, program cache and additional cache for each open file. lookahead_size controls a bitmap used during allocation, with each byte tracking eight blocks.[4] Opening more files consequently changes the budget even though merely enlarging the filesystem need not do so.

Espressif's independent integration guide places littlefs among its general-purpose filesystem options, while pointing out its lack of native compatibility with other platforms. The same guide directs small configuration and calibration records toward its NVS key-value storage.[5] A file tree is useful when an application needs files; it is another layer to maintain when the entire requirement is a handful of settings.

For a small firmware team able to maintain the flash driver and exercise recovery on its hardware, the architecture offers a concrete division of responsibility. littlefs manages recoverable filesystem updates; the team owns the meaning of a completed task. After the cable is pulled, the decisive question is whether the logger can explain the state it recovered.

Sources

  1. littlefs project, README — recovery guarantees, C implementation, atomic operations, file commits and the storage-driver sync contract; consulted October 30, 2026.
  2. littlefs project, technical specification, on-disk version 2.1 — metadata pairs, revision counters, commit checksums and inline files; consulted October 30, 2026.
  3. littlefs project, “The design of littlefs” — flash constraints, metadata compaction, copy-on-write storage and CTZ skip-lists; consulted October 30, 2026.
  4. littlefs project, public API header lfs.h — block-device callbacks, cache configuration and file write, sync and close contracts; consulted October 30, 2026.
  5. Espressif, “File System Considerations,” ESP-IDF v5.5 Programming Guide for ESP32-P4 — independent integration perspective on littlefs and NVS.
  6. Raspberry Pi Ltd, Raspberry Pi Pico-series Python SDK, December 4, 2024 build, Chapter 3, page 13 — default Pico filesystem using littlefs2.
  7. Michael H. (“Laserlicht”), “Raspberry pi pico (cropped) top,” Wikimedia Commons — photograph dated January 27, 2021, cropped by Elmepi in 2022; CC BY-SA 4.0.
Previous A first Sonic Pi set begins with a beat you can change Next The open-source tools between a finished film and its screening

Recommended In oss

Matched by subject and format