2017-05-15 01:26:29 -05:00
|
|
|
## The little filesystem
|
|
|
|
|
2017-05-18 23:44:18 -05:00
|
|
|
A little fail-safe filesystem designed for embedded systems.
|
2017-05-15 01:26:29 -05:00
|
|
|
|
2017-05-18 23:44:18 -05:00
|
|
|
```
|
|
|
|
| | | .---._____
|
|
|
|
.-----. | |
|
|
|
|
--|o |---| littlefs |
|
|
|
|
--| |---| |
|
|
|
|
'-----' '----------'
|
|
|
|
| | |
|
|
|
|
```
|
|
|
|
|
2017-11-20 00:01:14 -06:00
|
|
|
**Bounded RAM/ROM** - The littlefs is designed to work with a limited amount
|
|
|
|
of memory. Recursion is avoided and dynamic memory is limited to configurable
|
|
|
|
buffers that can be provided statically.
|
|
|
|
|
|
|
|
**Power-loss resilient** - The littlefs is designed for systems that may have
|
2018-01-20 12:25:44 +01:00
|
|
|
random power failures. The littlefs has strong copy-on-write guarantees and
|
2017-11-20 00:01:14 -06:00
|
|
|
storage on disk is always kept in a valid state.
|
|
|
|
|
|
|
|
**Wear leveling** - Since the most common form of embedded storage is erodible
|
|
|
|
flash memories, littlefs provides a form of dynamic wear leveling for systems
|
|
|
|
that can not fit a full flash translation layer.
|
2017-05-15 01:26:29 -05:00
|
|
|
|
|
|
|
## Example
|
|
|
|
|
|
|
|
Here's a simple example that updates a file named `boot_count` every time
|
|
|
|
main runs. The program can be interrupted at any time without losing track
|
|
|
|
of how many times it has been booted and without corrupting the filesystem:
|
|
|
|
|
|
|
|
``` c
|
|
|
|
#include "lfs.h"
|
|
|
|
|
|
|
|
// variables used by the filesystem
|
|
|
|
lfs_t lfs;
|
|
|
|
lfs_file_t file;
|
|
|
|
|
|
|
|
// configuration of the filesystem is provided by this struct
|
|
|
|
const struct lfs_config cfg = {
|
|
|
|
// block device operations
|
|
|
|
.read = user_provided_block_device_read,
|
|
|
|
.prog = user_provided_block_device_prog,
|
|
|
|
.erase = user_provided_block_device_erase,
|
|
|
|
.sync = user_provided_block_device_sync,
|
|
|
|
|
|
|
|
// block device configuration
|
|
|
|
.read_size = 16,
|
|
|
|
.prog_size = 16,
|
|
|
|
.block_size = 4096,
|
|
|
|
.block_count = 128,
|
|
|
|
.lookahead = 128,
|
|
|
|
};
|
|
|
|
|
|
|
|
// entry point
|
|
|
|
int main(void) {
|
|
|
|
// mount the filesystem
|
|
|
|
int err = lfs_mount(&lfs, &cfg);
|
|
|
|
|
|
|
|
// reformat if we can't mount the filesystem
|
|
|
|
// this should only happen on the first boot
|
|
|
|
if (err) {
|
|
|
|
lfs_format(&lfs, &cfg);
|
|
|
|
lfs_mount(&lfs, &cfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// read current count
|
|
|
|
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));
|
|
|
|
|
|
|
|
// update boot count
|
|
|
|
boot_count += 1;
|
|
|
|
lfs_file_rewind(&lfs, &file);
|
|
|
|
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
|
|
|
|
|
|
|
|
// remember the storage is not updated until the file is closed successfully
|
|
|
|
lfs_file_close(&lfs, &file);
|
|
|
|
|
2017-05-18 23:44:18 -05:00
|
|
|
// release any resources we were using
|
2017-05-15 01:26:29 -05:00
|
|
|
lfs_unmount(&lfs);
|
2017-07-16 12:42:17 -05:00
|
|
|
|
|
|
|
// print the boot count
|
|
|
|
printf("boot_count: %d\n", boot_count);
|
2017-05-15 01:26:29 -05:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
Detailed documentation (or at least as much detail as is currently available)
|
2018-01-20 12:25:44 +01:00
|
|
|
can be found in the comments in [lfs.h](lfs.h).
|
2017-05-15 01:26:29 -05:00
|
|
|
|
2017-11-20 00:01:14 -06:00
|
|
|
As you may have noticed, littlefs takes in a configuration structure that
|
2017-05-15 01:26:29 -05:00
|
|
|
defines how the filesystem operates. The configuration struct provides the
|
|
|
|
filesystem with the block device operations and dimensions, tweakable
|
|
|
|
parameters that tradeoff memory usage for performance, and optional
|
|
|
|
static buffers if the user wants to avoid dynamic memory.
|
|
|
|
|
|
|
|
The state of the littlefs is stored in the `lfs_t` type which is left up
|
|
|
|
to the user to allocate, allowing multiple filesystems to be in use
|
2017-11-20 00:01:14 -06:00
|
|
|
simultaneously. With the `lfs_t` and configuration struct, a user can
|
2017-05-15 01:26:29 -05:00
|
|
|
format a block device or mount the filesystem.
|
|
|
|
|
2018-01-20 12:25:44 +01:00
|
|
|
Once mounted, the littlefs provides a full set of POSIX-like file and
|
2017-05-15 01:26:29 -05:00
|
|
|
directory functions, with the deviation that the allocation of filesystem
|
2017-11-20 00:01:14 -06:00
|
|
|
structures must be provided by the user.
|
|
|
|
|
2018-01-20 12:25:44 +01:00
|
|
|
All POSIX operations, such as remove and rename, are atomic, even in event
|
|
|
|
of power-loss. Additionally, no file updates are actually committed to the
|
2017-11-20 00:01:14 -06:00
|
|
|
filesystem until sync or close is called on the file.
|
2017-05-15 01:26:29 -05:00
|
|
|
|
|
|
|
## Other notes
|
|
|
|
|
|
|
|
All littlefs have the potential to return a negative error code. The errors
|
|
|
|
can be either one of those found in the `enum lfs_error` in [lfs.h](lfs.h),
|
|
|
|
or an error returned by the user's block device operations.
|
|
|
|
|
2017-11-20 00:01:14 -06:00
|
|
|
It should also be noted that the current implementation of littlefs doesn't
|
2018-01-29 17:15:01 +01:00
|
|
|
really do anything to ensure that the data written to disk is machine portable.
|
2017-11-20 00:01:14 -06:00
|
|
|
This is fine as long as all of the involved machines share endianness
|
|
|
|
(little-endian) and don't have strange padding requirements.
|
|
|
|
|
|
|
|
## Reference material
|
2017-05-15 01:26:29 -05:00
|
|
|
|
2017-11-20 00:01:14 -06:00
|
|
|
[DESIGN.md](DESIGN.md) - DESIGN.md contains a fully detailed dive into how
|
|
|
|
littlefs actually works. I would encourage you to read it since the
|
|
|
|
solutions and tradeoffs at work here are quite interesting.
|
2017-05-18 23:44:18 -05:00
|
|
|
|
2017-11-20 00:01:14 -06:00
|
|
|
[SPEC.md](SPEC.md) - SPEC.md contains the on-disk specification of littlefs
|
|
|
|
with all the nitty-gritty details. Can be useful for developing tooling.
|
2017-05-18 23:44:18 -05:00
|
|
|
|
2017-05-15 01:26:29 -05:00
|
|
|
## Testing
|
|
|
|
|
2018-01-20 12:25:44 +01:00
|
|
|
The littlefs comes with a test suite designed to run on a PC using the
|
2017-05-15 01:26:29 -05:00
|
|
|
[emulated block device](emubd/lfs_emubd.h) found in the emubd directory.
|
2018-01-20 12:25:44 +01:00
|
|
|
The tests assume a Linux environment and can be started with make:
|
2017-05-15 01:26:29 -05:00
|
|
|
|
|
|
|
``` bash
|
|
|
|
make test
|
|
|
|
```
|
2017-11-20 00:01:14 -06:00
|
|
|
|
|
|
|
## Related projects
|
|
|
|
|
2017-12-27 12:56:40 -06:00
|
|
|
[Mbed OS](https://github.com/ARMmbed/mbed-os/tree/master/features/filesystem/littlefs) -
|
|
|
|
The easiest way to get started with littlefs is to jump into [Mbed](https://os.mbed.com/),
|
|
|
|
which already has block device drivers for most forms of embedded storage. The
|
|
|
|
littlefs is available in Mbed OS as the [LittleFileSystem](https://os.mbed.com/docs/latest/reference/littlefilesystem.html)
|
|
|
|
class.
|
2017-11-20 00:01:14 -06:00
|
|
|
|
|
|
|
[littlefs-fuse](https://github.com/geky/littlefs-fuse) - A [FUSE](https://github.com/libfuse/libfuse)
|
2018-01-29 17:15:01 +01:00
|
|
|
wrapper for littlefs. The project allows you to mount littlefs directly on a
|
2017-11-20 00:01:14 -06:00
|
|
|
Linux machine. Can be useful for debugging littlefs if you have an SD card
|
|
|
|
handy.
|
|
|
|
|
|
|
|
[littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for
|
|
|
|
littlefs. I'm not sure why you would want this, but it is handy for demos.
|
|
|
|
You can see it in action [here](http://littlefs.geky.net/demo.html).
|