littlefs Documentation

repository·master·Indexed 27 days ago

https://github.com/littlefs-project/littlefs

A fail-safe, power-loss resilient filesystem optimized for microcontrollers and flash memory. It features dynamic wear leveling, bounded RAM/ROM usage, and a design combining Logging and Copy-on-Bounded-Writes (CObW). The documentation covers basic workflows using lfs_config and lfs_mount, the CTZ skip-list data structure for file data, metadata compaction strategies, and a wide ecosystem of language wrappers (Python, Rust, JavaScript, Nim, OCaml) and CLI tools like littlefs-toy.

Tokens
7K
Snippets
3
Records
37
Agent score
92%

What's inside littlefs

  1. Overview of littlefs

    master

    littlefs is a fail-safe filesystem designed specifically for microcontrollers. It features:

    • Power-loss resilience: Uses strong copy-on-write guarantees to ensure the filesystem falls back to the last known good state if power is lost during operations.
    • Dynamic wear leveling: Designed for flash memory, providing wear leveling over dynamic blocks and the ability to detect and work around bad blocks.
    • Bounded RAM/ROM: RAM usage is strictly bounded and does not increase as the filesystem grows. It avoids unbounded recursion and allows for static buffer configuration to avoid dynamic memory allocation.
  2. Understand littlefs directory and traversal design

    master

    littlefs organizes directories as linked lists of metadata pairs, allowing for an unlimited number of files per directory without unbounded runtime complexity. While the filesystem structure is a tree, littlefs implements a threaded linked-list through the tree to enable full filesystem traversal using only a constant, bounded amount of RAM.

    Key concepts:

    • Directory Tree: The hierarchical structure of directories and files.
    • Threaded Linked-list: A secondary structure that threads through the tree to allow cheap, low-RAM traversal.
    • Orphaned Metadata Pairs (Orphans): Metadata pairs that exist in the threaded linked-list but have no parent in the directory tree, typically caused by power loss during tree manipulation.
    • Half-orphans: A state occurring when a bad block is replaced; the filesystem tree references the new replacement block, but the threaded linked-list still contains the old, evicted block due to power loss during the eviction process.
  3. Understand the littlefs block allocation strategy

    master
    littlefs uses a Copy-on-Write (COW) design that avoids maintaining a traditional free list or bitmap on disk. Instead, it employs a "drop it on the floor" strategy where block deallocation is a no-op, and the block allocator identifies free blocks by scanning the filesystem for unused blocks on demand. This approach ensures power resilience and simplifies the management of on-disk data structures by treating the filesystem as a mirror of used blocks.
  4. Understand Metadata Pairs and Atomic Updates

    master

    Metadata pairs are the core mechanism for distributed atomic updates in littlefs. Even the superblock is stored in a metadata pair.

    Structure and Behavior:

    • Redundancy: A metadata pair consists of two blocks. One block serves as a backup during erase cycles to protect against power loss. These blocks are not necessarily sequential.
    • Pointers: A pointer to a metadata pair is represented by two block pointers.
    • Appendable Logs: Each metadata block acts as an appendable log containing multiple commits. Commits can be appended to update metadata without requiring an erase cycle.
    • Validity: Successive commits may supersede previous ones. Only the most recent metadata commit should be considered valid.
  5. Explore littlefs wrappers and ecosystem tools

    master

    The littlefs ecosystem includes several wrappers and tools for different programming languages and use cases:

    Language Wrappers

    • Python: littlefs-python allows creating filesystem images on a PC for later download to target memory or inspecting binary images.
    • Rust: littlefs2-rust provides a Rust-friendly API with memory safety guarantees.
    • JavaScript: littlefs-js is available for web-based demos.
    • Nim: nim-littlefs provides a Nim API and includes a FUSE implementation.
    • OCaml: chamelon is a pure-OCaml implementation designed for MirageOS.

    CLI Tools and Image Management

    • littlefs-toy: A command-line tool for creating and working with littlefs images using syntax similar to tar. It supports working on images embedded inside other files (like firmware).
    • mklfs: A CLI tool for creating littlefs images, used in the Lua RTOS ecosystem.
    • mklittlefs: A CLI tool for creating littlefs images, used in the ESP8266 and RP2040 ecosystems.
    • littlefs-disk-img-viewer: A web application for viewing littlefs disk images in a browser.

    Integration and Debugging

    • littlefs-fuse: A FUSE wrapper that allows mounting littlefs directly on a Linux machine for debugging via SD cards.
    • Mbed OS: The easiest way to get started; littlefs is available as the LittleFileSystem class and includes block device drivers for most embedded storage.
    • pico-littlefs-usb: Emulates a FAT12 filesystem over USB, allowing mounting on a host PC without extra drivers.

    Specialized Implementations

    • ramcrc32bd / ramrsbd: Example block devices using 32-bit CRC or Reed-Solomon codes for error correction.
  6. Understand the Global State mechanism in littlefs

    master

    littlefs uses a mechanism called "global state" to enable atomic operations that span multiple directories, such as moving a file or directory.

    Global state is implemented as a set of small deltas (gdelta) distributed across metadata pairs. The actual global state is reconstructed by XORing all these deltas together during the filesystem mount process.

    Key Characteristics:

    • Atomicity: Allows complex operations to be crafted using multiple commits.
    • Efficiency: A copy of the global state is kept in RAM to avoid repeated disk traversals. The state is rebuilt only during mounting.
    • Constraint: Because deltas are stored in metadata pairs and are difficult to clean up, the global state must be kept extremely small and bounded in size.
  7. Understand wear leveling in littlefs

    master

    littlefs protects storage longevity through two primary methods:

    1. Detection and recovery from bad blocks: The filesystem detects write errors by verifying data in RAM against what was written to the block. If a mismatch occurs, the bad block is evicted, a new block is allocated, and the write is retried using copy-on-bounded-writes (CObW) mechanisms.
    2. Dynamic wear leveling: To prevent premature device failure, littlefs distributes wear across all unused (dynamic) blocks. It uses a statistical approach rather than active tracking to minimize code complexity.

    Note on Read Errors: littlefs does not provide Error-Correction-Codes (ECC). It relies on the underlying block device to handle ECC or uses proactive wear leveling to avoid read errors. If a block device reports an error, littlefs respects it.

  8. Understand littlefs block-based storage architecture

    master

    littlefs is a block-based filesystem. The storage is divided into an array of evenly sized blocks, which serve as the logical unit of storage.

    Key technical details:

    • Block Pointers: Stored in 32 bits. The value 0xffffffff represents a null block address.
    • Block Sizes: In addition to the logical block size (typically matching the erase block size), littlefs uses a program block size and a read block size to determine the alignment of block device operations.
    • Endianness: By default, all values in littlefs are stored in little-endian byte order.
  9. Understand littlefs metadata pairs and atomicity

    master

    littlefs uses metadata pairs (two-block logs) to enable atomic updates and power-loss resilience.

    Key concepts:

    • Two-block structure: Metadata is stored in pairs of blocks. This allows the filesystem to append new data to one block while keeping the previous state intact in the other, or to perform compaction (garbage collection) by writing to a fresh block before erasing the old one.
    • Atomicity: Achieved through redundancy (keeping old data until new data is safe) and error detection (using a 32-bit CRC checksum).
    • Revision Counts: Each metadata block contains a revision count. The most recent metadata is determined by comparing these counts using sequence arithmetic to avoid integer overflow.
    • Commit Groups: Instead of checksumming every individual entry, littlefs groups multiple entries into a single 'commit' that shares one checksum. This allows multiple unrelated metadata updates to be performed in a single atomic operation.
  10. Understand the littlefs design architecture

    master

    littlefs uses a hybrid approach to balance atomicity, performance, and wear leveling by merging two design patterns: Logging and Copy-on-Bounded-Writes (CObW).

    • Sub-block level (Logging): Uses small, two-block logs to provide atomic updates to metadata anywhere on the filesystem. This provides atomicity without the high runtime or RAM costs typically associated with unbounded logging.
    • Super-block level (CObW): Uses a tree of blocks that employs a Copy-on-Bounded-Writes strategy. Instead of copying on every single write (which pushes wear upwards), it copies after n writes. This divides the propagation of wear by n, preventing wear from concentrating on specific blocks.

    Key Trade-offs to consider:

    • Storage Overhead: Small logs can be expensive; in the worst case, a small log can cost 4x the size of the original data.
    • Allocation Requirements: Because CObW structures trigger allocation every n writes, an efficient block allocator is required.
    • RAM Management: The design aims to keep RAM usage constant despite these structures.
  11. Understand littlefs file storage and inline files

    master

    littlefs optimizes storage for small files (common in embedded systems) using two primary strategies to minimize overhead on flash memory:

    1. Directory-linked Metadata Pairs: Instead of assigning a unique metadata pair (inode) to every file, multiple files can share a single metadata pair associated with a directory. This reduces collective storage overhead and allows for efficient logging.

    2. Inline Files: For very small files, littlefs stores the file data directly within the directory's metadata pair rather than allocating separate data blocks.

      • A file is considered an inline file if it is smaller than 1/4 of the block size.
      • This prevents the massive overhead seen in traditional designs where a tiny file (e.g., 4 bytes) might otherwise consume multiple full blocks (e.g., 12 KiB on a 4 KiB block system).
      • Once a file exceeds 1/4 of the block size, littlefs automatically switches to using a CTZ skip-list to manage data blocks.

    This approach ensures that file storage overhead never exceeds 4x the actual file size, with the overhead ratio decreasing as the file grows.

  12. Understand the CTZ skip-list data structure

    master

    littlefs uses a specialized Copy-on-Write (COW) data structure called a CTZ skip-list to manage file data. This design allows for efficient, power-resilient file operations with minimal RAM usage.

    Key Characteristics:

    • Append Performance: $O(1)$ runtime. Appending blocks only requires adding a new block at the end of a backwards linked-list.
    • Read Performance: $O(n \log n)$ worst-case runtime. The skip-list structure allows for efficient navigation through data blocks.
    • Storage Overhead: On average, only 2 pointers per block are required.
    • Memory Efficiency: Designed to be traversable with a constant amount of RAM, making it suitable for constrained embedded systems.
    • Implementation Detail: The skip-list is deterministic and utilizes the count-trailing-zeros (CTZ) instruction to calculate pointer offsets efficiently.