|
| 1 | +## The little filesystem |
| 2 | + |
| 3 | +A little fail-safe filesystem designed for low ram/rom footprint. |
| 4 | + |
| 5 | +**Fail-safe** - The littlefs is designed to work consistently with random power |
| 6 | +failures. During filesystem operations the storage on disk is always kept |
| 7 | +in a valid state. The filesystem also has strong copy-on-write garuntees. |
| 8 | +When updating a file, the original file will remain unmodified until the |
| 9 | +file is closed, or sync is called. |
| 10 | + |
| 11 | +**Handles bad blocks** - While the littlefs does not implement static wear |
| 12 | +leveling, if the underlying block device reports write errors, the littlefs |
| 13 | +uses a form of dynamic wear leveling to manage blocks that go bad during |
| 14 | +the lifetime of the filesystem. |
| 15 | + |
| 16 | +**Constrained memory** - The littlefs is designed to work in bounded memory, |
| 17 | +recursion is avoided, and dynamic memory is kept to a minimum. The littlefs |
| 18 | +allocates two fixed-size buffers for general operations, and one fixed-size |
| 19 | +buffer per file. If there is only ever one file in use, these buffers can be |
| 20 | +provided statically. |
| 21 | + |
| 22 | +## Example |
| 23 | + |
| 24 | +Here's a simple example that updates a file named `boot_count` every time |
| 25 | +main runs. The program can be interrupted at any time without losing track |
| 26 | +of how many times it has been booted and without corrupting the filesystem: |
| 27 | + |
| 28 | +``` c |
| 29 | +#include "lfs.h" |
| 30 | + |
| 31 | +// variables used by the filesystem |
| 32 | +lfs_t lfs; |
| 33 | +lfs_file_t file; |
| 34 | + |
| 35 | +// configuration of the filesystem is provided by this struct |
| 36 | +const struct lfs_config cfg = { |
| 37 | + // block device operations |
| 38 | + .read = user_provided_block_device_read, |
| 39 | + .prog = user_provided_block_device_prog, |
| 40 | + .erase = user_provided_block_device_erase, |
| 41 | + .sync = user_provided_block_device_sync, |
| 42 | + |
| 43 | + // block device configuration |
| 44 | + .read_size = 16, |
| 45 | + .prog_size = 16, |
| 46 | + .block_size = 4096, |
| 47 | + .block_count = 128, |
| 48 | + .lookahead = 128, |
| 49 | +}; |
| 50 | + |
| 51 | +// entry point |
| 52 | +int main(void) { |
| 53 | + // mount the filesystem |
| 54 | + int err = lfs_mount(&lfs, &cfg); |
| 55 | + |
| 56 | + // reformat if we can't mount the filesystem |
| 57 | + // this should only happen on the first boot |
| 58 | + if (err) { |
| 59 | + lfs_format(&lfs, &cfg); |
| 60 | + lfs_mount(&lfs, &cfg); |
| 61 | + } |
| 62 | + |
| 63 | + // read current count |
| 64 | + uint32_t boot_count = 0; |
| 65 | + lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); |
| 66 | + lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); |
| 67 | + |
| 68 | + // update boot count |
| 69 | + boot_count += 1; |
| 70 | + printf("boot_count: %ld\n", boot_count); |
| 71 | + lfs_file_rewind(&lfs, &file); |
| 72 | + lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count)); |
| 73 | + |
| 74 | + // remember the storage is not updated until the file is closed successfully |
| 75 | + lfs_file_close(&lfs, &file); |
| 76 | + |
| 77 | + // release and resources we were using |
| 78 | + lfs_unmount(&lfs); |
| 79 | +} |
| 80 | +``` |
| 81 | +
|
| 82 | +## Usage |
| 83 | +
|
| 84 | +Detailed documentation (or at least as much detail as is currently available) |
| 85 | +can be cound in the comments in [lfs.h](lfs.h). |
| 86 | +
|
| 87 | +As you may have noticed, the littlefs takes in a configuration structure that |
| 88 | +defines how the filesystem operates. The configuration struct provides the |
| 89 | +filesystem with the block device operations and dimensions, tweakable |
| 90 | +parameters that tradeoff memory usage for performance, and optional |
| 91 | +static buffers if the user wants to avoid dynamic memory. |
| 92 | +
|
| 93 | +The state of the littlefs is stored in the `lfs_t` type which is left up |
| 94 | +to the user to allocate, allowing multiple filesystems to be in use |
| 95 | +simultaneously. With the `lfs_t` and configuration struct, a user can either |
| 96 | +format a block device or mount the filesystem. |
| 97 | +
|
| 98 | +Once mounted, the littlefs provides a full set of posix-like file and |
| 99 | +directory functions, with the deviation that the allocation of filesystem |
| 100 | +structures must be provided by the user. An important addition is that |
| 101 | +no file updates will actually be written to disk until a sync or close |
| 102 | +is called. |
| 103 | +
|
| 104 | +## Other notes |
| 105 | +
|
| 106 | +All littlefs have the potential to return a negative error code. The errors |
| 107 | +can be either one of those found in the `enum lfs_error` in [lfs.h](lfs.h), |
| 108 | +or an error returned by the user's block device operations. |
| 109 | +
|
| 110 | +It should also be noted that the littlefs does not do anything to insure |
| 111 | +that the data written to disk is machine portable. It should be fine as |
| 112 | +long as the machines involved share endianness and don't have really |
| 113 | +strange padding requirements. If the question does come up, the littlefs |
| 114 | +metadata should be stored on disk in little-endian format. |
| 115 | +
|
| 116 | +## Testing |
| 117 | +
|
| 118 | +The littlefs comes with a test suite designed to run on a pc using the |
| 119 | +[emulated block device](emubd/lfs_emubd.h) found in the emubd directory. |
| 120 | +The tests assume a linux environment and can be started with make: |
| 121 | +
|
| 122 | +``` bash |
| 123 | +make test |
| 124 | +``` |
0 commit comments