littlefs的设计
摘要
littlefs是一个专为微控制器设计的故障安全文件系统,具有掉电恢复能力、动态磨损均衡以及有限的RAM/ROM。它提供类似POSIX的API,并用C语言编写,以实现较小的内存占用。
查看缓存全文
缓存时间: 2026/06/18 22:07
littlefs-project/littlefs
来源:https://github.com/littlefs-project/littlefs
littlefs
一款专为微控制器设计的小型故障安全文件系统。
| | | .---._____ .-----. | | --|o |---| littlefs | --| |---| | '-----' '----------' | | |
掉电恢复能力 - littlefs 设计用于处理随机断电故障。所有文件操作均具有强写时复制保证,若电源中断,文件系统将回退至最后一个已知的良好状态。
动态磨损均衡 - littlefs 专为闪存设计,在动态块上提供磨损均衡。此外,littlefs 能够检测坏块并绕过它们。
有限 RAM/ROM - littlefs 设计用于少量内存。RAM 使用严格受限,意味着内存消耗不会随文件系统增长而变化。文件系统不包含无界递归,动态内存限制为可配置的缓冲器,这些缓冲器可以静态提供。
示例
以下是一个简单示例,每次 main 运行时更新名为 boot_count 的文件。程序可以随时中断,而不会丢失已启动次数的记录,也不会损坏文件系统:
`` c #include “lfs.h”
// 文件系统使用的变量 lfs_t lfs; lfs_file_t file;
// 文件系统的配置由此结构体提供 const struct lfs_config cfg = { // 块设备操作 .read = user_provided_block_device_read, .prog = user_provided_block_device_prog, .erase = user_provided_block_device_erase, .sync = user_provided_block_device_sync,
// 块设备配置
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
};
// 入口点 int main(void) { // 挂载文件系统 int err = lfs_mount(&lfs, &cfg);
// 如果无法挂载文件系统则重新格式化
// 这仅应在首次启动时发生
if (err) {
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
}
// 读取当前计数值
uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// 更新启动计数
boot_count += 1;
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// 注意:存储更新仅在文件成功关闭后生效
lfs_file_close(&lfs, &file);
// 释放使用的所有资源
lfs_unmount(&lfs);
// 打印启动计数
printf("boot_count: %d\n", boot_count);
} ``
用法
详细文档(至少是目前可用的细节)可以在 lfs.h 的注释中找到。
littlefs 接收一个定义文件系统操作方式的配置结构体。配置结构体向文件系统提供块设备操作和尺寸、可调节参数(用于权衡内存使用和性能),以及可选的静态缓冲区(若用户希望避免动态内存)。
littlefs 的状态存储在 lfs_t 类型中,该类型由用户分配,从而可以同时使用多个文件系统。使用 lfs_t 和配置结构体,用户可以格式化块设备或挂载文件系统。
挂载后,littlefs 提供了一整套类 POSIX 的文件和目录函数,不同之处在于文件系统结构的分配必须由用户提供。
所有 POSIX 操作(如删除和重命名)都是原子性的,即使在断电情况下也是如此。此外,文件更新实际上不会提交到文件系统,直到对文件调用 sync 或 close。
其他说明
Littlefs 使用 C 语言编写,并且特别地应该能够与任何符合 C99 标准的编译器编译。
所有 littlefs 调用都可能返回负错误码。错误可以是 lfs.h 中 enum lfs_error 中的某个错误,也可以是用户块设备操作返回的错误。
在配置结构体中,用户提供的 prog 和 erase 函数若实现已能检测损坏块,则可返回 LFS_ERR_CORRUPT 错误。然而,磨损均衡不依赖于这些函数的返回码,相反所有数据都会被读回并检查完整性。
如果您的存储缓存写入,请确保提供的 sync 函数将所有数据刷新到内存,并确保后续读取从内存获取数据,否则数据完整性无法保证。如果 write 函数不进行缓存,因此每次 read 或 write 调用都直接访问内存,则 sync 函数可以简单地返回 0。
设计
从高层次来看,littlefs 是一个基于块的文件系统,使用小型日志存储元数据,使用更大的写时复制 (COW) 结构存储文件数据。
在 littlefs 中,这些成分构成了一种双层蛋糕结构:小型日志(称为元数据对)提供对存储设备上任意位置的元数据的快速更新,而 COW 结构则紧凑地存储文件数据且无磨损放大成本。
这两种数据结构均由块构建,这些块由公共块分配器提供。通过限制每个块在每次分配时可擦除的次数,分配器在整个文件系统上提供动态磨损均衡。
root .--------.--------. | A'| B'| | | | |-> | | | | | '--------'--------' .----' '--------------. A v B v .--------.--------. .--------.--------. | C'| D'| | | E'|new| | | | |-> | | | E'|-> | | | | | | | | | '--------'--------' '--------'--------' .-' '--. | '------------------. v v .-' v .--------. .--------. v .--------. | C | | D | .--------. write | new E | | | | | | E | ==> | | | | | | | | | | '--------' '--------' | | '--------' '--------' .-' | .-' '-. .-------------|------' v v v v .--------. .--------. .--------. | F | | G | | new F | | | | | | | | | | | | | '--------' '--------' '--------'
更多关于 littlefs 工作原理的细节可以在 DESIGN.md 和 SPEC.md 中找到。
-
DESIGN.md - 关于 littlefs 工作原理的全面深入探讨。建议阅读,因为其中的权衡取舍非常有趣。
-
SPEC.md - littlefs 的磁盘规范,包含所有具体细节。可能对工具开发有用。
测试
littlefs 附带一套测试套件,设计用于在 PC 上运行,使用 bd 目录中的仿真块设备。测试假定 Linux 环境,可以通过 make 启动:
bash make test
测试以 C 语言实现,位于 tests 目录的 .toml 文件中。在开发功能或修复错误时,经常需要运行单个测试用例或测试套件:
bash ./scripts/test.py -l runners/test_runner # 列出可用的测试套件 ./scripts/test.py -L runners/test_runner test_dirs # 列出可用的测试用例 ./scripts/test.py runners/test_runner test_dirs # 运行特定测试套件
如果测试中断言失败,test.py 将尝试打印失败信息:
bash tests/test_dirs.toml:1:failure: test_dirs_root:1g12gg2 (PROG_SIZE=16, ERASE_SIZE=512) failed tests/test_dirs.toml:5:assert: assert failed with 0, expected eq 42 lfs_mount(&lfs, cfg) => 42;
这包括测试 ID,可以传递给 test.py 以仅运行该特定测试排列:
bash ./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 # 运行特定测试排列 ./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 --gdb # 失败时进入 gdb
一些其他可能有用的标志:
bash ./scripts/test.py runners/test_runner -b -j # 并行运行测试 ./scripts/test.py runners/test_runner -v -O- # 将 stdout 重定向到 stdout ./scripts/test.py runners/test_runner -ddisk # 捕获生成的磁盘映像
查看 -h/--help 以获得所有可用标志的完整列表:
bash ./scripts/test.py --help
许可证
littlefs 使用 BSD-3-Clause 许可证提供。更多信息请参见 LICENSE.md。对本项目的贡献应以相同许可证接受。
个别文件包含以下标签,而非完整许可证文本。
SPDX-License-Identifier: BSD-3-Clause
这使得基于 SPDX 许可证标识符(此处可用:http://spdx.org/licenses/)的许可证信息机器处理成为可能。
相关项目
-
littlefs-fuse - littlefs 的 FUSE 包装器。该项目允许您直接在 Linux 机器上挂载 littlefs。如果您有 SD 卡,可能对调试 littlefs 有用。
-
littlefs-js - littlefs 的 JavaScript 包装器。我不确定您为什么需要这个,但它对演示很有用。您可以在此处看到它的运行效果。
-
littlefs-python - littlefs 的 Python 包装器。该项目允许您在 PC 上创建文件系统映像。检查 littlefs 是否满足您的需求,创建后续下载到目标内存的映像,或检查目标内存二进制映像的内容。
-
littlefs-toy - 用于创建和处理 littlefs 映像的命令行工具。语法类似于 tar 命令,易于使用。支持处理嵌入在其他文件(固件映像等)中的 littlefs 映像。
-
littlefs2-rust - littlefs 的 Rust 包装器。该项目允许您使用 Rust 友好的 API 使用 littlefs,从而受益于 Rust 的内存安全性及其他保证。
-
nim-littlefs - littlefs 的 Nim 包装器和 API。包含基于 littlefs-fuse 的 FUSE 实现。
-
chamelon - 一个纯 OCaml 实现的 littlefs(大部分功能),设计用于 MirageOS 库操作系统项目。与参考实现可互操作,但有一些注意事项。
-
littlefs-disk-img-viewer - 一个内存效率高的 Web 应用程序,用于在 Web 浏览器中查看 littlefs 磁盘映像。
-
mklfs - 用于创建 littlefs 映像的命令行工具。用于 Lua RTOS 生态系统。
-
mklittlefs - 用于创建 littlefs 映像的命令行工具。用于 ESP8266 和 RP2040 生态系统。
-
pico-littlefs-usb - littlefs 的接口,通过 USB 模拟 FAT12 文件系统。允许在主机 PC 上挂载 littlefs 而无需额外驱动程序。
-
ramcrc32bd - 一个示例块设备,使用 littlefs 的 32 位 CRC 进行纠错。
-
ramrsbd - 一个示例块设备,使用 Reed-Solomon 码进行纠错。
-
Mbed OS - 入门 littlefs 的最简单方式是使用 Mbed,它已经为大多数嵌入式存储形式提供了块设备驱动程序。littlefs 在 Mbed OS 中作为 LittleFileSystem 类可用。
-
SPIFFS - 另一个优秀的 NOR 闪存嵌入式文件系统。作为一个具有完全静态磨损均衡的更传统的日志文件系统,SPIFFS 很可能在小型内存(如微控制器内部闪存)上胜过 littlefs。
-
Dhara - 一个专为小型微控制器设计的有趣的 NAND 闪存转换层。它提供静态磨损均衡和电源恢复能力,仅需在每个块和 RAM 中存储一个固定的 O(|address|) 指针结构。
-
ChaN’s FatFs - 臭名昭著的 FAT 文件系统在微控制器级别设备上的轻量级重新实现。由于 FAT 的局限性,它无法提供掉电恢复能力,但允许与 PC 轻松互操作。
相似文章
UTFS:类似TAR的嵌入式系统文件系统(2025)
UTFS是一个小巧的嵌入式文件系统,受TAR格式启发,专为微控制器设计,支持基于字符串的文件名存储数据,将数据存储与应用程序逻辑分离。
探索构建微型FUSE文件系统
本文将引导你使用Rust构建一个名为magicfs的最小FUSE文件系统,该系统使用metadata.json和blob文件作为后端存储,演示了名称查找、inode稳定性和内核缓存等核心文件系统概念。
F* 文件系统——直接绕过操作系统内核读取SSD的文件搜索
一款名为 ffs 的 CLI 工具,通过直接读取磁盘来搜索文件,绕过操作系统内核的 VFS 层,在处理大型、未缓存目录时相比 ripgrep 等工具具有潜在的速度优势。支持 ext4、btrfs 和 APFS 文件系统。
单片软盘上的嵌入式Linux
FLOPPINUX 是一个完整的 Linux 发行版,可安装在一张 1.44MB 软盘上,支持 Intel 486DX 和 20MB RAM 等最低配置硬件。启动后进入终端,具有持久化存储和基本工具。
我在Arduino UNO(2KB内存)上写了个微型类Unix“操作系统”,带Shell和文件系统
Arc1011发布KernelUNO,为Arduino UNO打造的类Unix Shell与文件系统,仅占用2KB RAM,提供22条命令用于硬件控制与文件操作。