Updated DESIGN.md to reflect v2 changes

Now with graphs! Images are stored on the branch gh-images in an effort
to avoid binary bloat in the git history.

Also spruced up SPEC.md and README.md and ran a spellechecker over the
documentation. Favorite typo so far was dependendent, which is, in fact,
not a word.
This commit is contained in:
Christopher Haster
2019-03-02 19:30:05 -06:00
parent 4ad09d6c4e
commit bdff4bc59e
3 changed files with 2145 additions and 1146 deletions

2857
DESIGN.md

File diff suppressed because it is too large Load Diff

163
README.md
View File

@@ -1,6 +1,6 @@
## The little filesystem
## littlefs
A little fail-safe filesystem designed for embedded systems.
A little fail-safe filesystem designed for microcontrollers.
```
| | | .---._____
@@ -11,17 +11,19 @@ A little fail-safe filesystem designed for embedded systems.
| | |
```
**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 resilience** - littlefs is designed to handle random power
failures. All file operations have strong copy-on-write guarantees and if
power is lost the filesystem will fall back to the last known good state.
**Power-loss resilient** - The littlefs is designed for systems that may have
random power failures. The littlefs has strong copy-on-write guarantees and
storage on disk is always kept in a valid state.
**Dynamic wear leveling** - littlefs is designed with flash in mind, and
provides wear leveling over dynamic blocks. Additionally, littlefs can
detect bad blocks and work around them.
**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.
**Bounded RAM/ROM** - littlefs is designed to work with a small amount of
memory. RAM usage is strictly bounded, which means RAM consumption does not
change as the filesystem grows. The filesystem contains no unbounded
recursion and dynamic memory is limited to configurable buffers that can be
provided statically.
## Example
@@ -91,11 +93,11 @@ int main(void) {
Detailed documentation (or at least as much detail as is currently available)
can be found in the comments in [lfs.h](lfs.h).
As you may have noticed, littlefs takes in a configuration structure that
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.
littlefs takes in a configuration structure that 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
@@ -107,14 +109,14 @@ directory functions, with the deviation that the allocation of filesystem
structures must be provided by the user.
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
filesystem until sync or close is called on the file.
of power-loss. Additionally, no file updates are not actually committed to
the filesystem until sync or close is called on the file.
## 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.
All littlefs functions 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.
In the configuration struct, the `prog` and `erase` function provided by the
user may return a `LFS_ERR_CORRUPT` error if the implementation already can
@@ -128,14 +130,60 @@ from memory, otherwise data integrity can not be guaranteed. If the `write`
function does not perform caching, and therefore each `read` or `write` call
hits the memory, the `sync` function can simply return 0.
## Reference material
## Design
[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.
At a high level, littlefs is a block based filesystem that uses small logs to
store metadata and larger copy-on-write (COW) structures to store file data.
[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.
In littlefs, these ingredients form a sort of two-layered cake, with the small
logs (called metadata pairs) providing fast updates to metadata anywhere on
storage, while the COW structures store file data compactly and without any
wear amplification cost.
Both of these data structures are built out of blocks, which are fed by a
common block allocator. By limiting the number of erases allowed on a block
per allocation, the allocator provides dynamic wear leveling over the entire
filesystem.
```
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 |
| | | | | |
| | | | | |
'--------' '--------' '--------'
```
More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and
[SPEC.md](SPEC.md).
- [DESIGN.md](DESIGN.md) - A fully detailed dive into how littlefs works.
I would suggest reading it as the tradeoffs at work are quite interesting.
- [SPEC.md](SPEC.md) - The on-disk specification of littlefs with all the
nitty-gritty details. May be useful for tooling development.
## Testing
@@ -149,9 +197,9 @@ make test
## License
The littlefs is provided under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
license. See [LICENSE.md](LICENSE.md) for more information. Contributions to
this project are accepted under the same license.
The littlefs is provided under the [BSD-3-Clause] license. See
[LICENSE.md](LICENSE.md) for more information. Contributions to this project
are accepted under the same license.
Individual files contain the following tag instead of the full license text.
@@ -162,32 +210,39 @@ License Identifiers that are here available: http://spdx.org/licenses/
## Related projects
[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.
- [littlefs-fuse] - A [FUSE] wrapper for littlefs. The project allows you to
mount littlefs directly on a Linux machine. Can be useful for debugging
littlefs if you have an SD card handy.
[littlefs-fuse](https://github.com/geky/littlefs-fuse) - A [FUSE](https://github.com/libfuse/libfuse)
wrapper for littlefs. The project allows you to mount littlefs directly on a
Linux machine. Can be useful for debugging littlefs if you have an SD card
handy.
- [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][littlefs-js-demo].
[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).
- [mklfs] - A command line tool built by the [Lua RTOS] guys for making
littlefs images from a host PC. Supports Windows, Mac OS, and Linux.
[mklfs](https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src) -
A command line tool built by the [Lua RTOS](https://github.com/whitecatboard/Lua-RTOS-ESP32)
guys for making littlefs images from a host PC. Supports Windows, Mac OS,
and Linux.
- [Mbed OS] - The easiest way to get started with littlefs is to jump into Mbed
which already has block device drivers for most forms of embedded storage.
littlefs is available in Mbed OS as the [LittleFileSystem] class.
[SPIFFS](https://github.com/pellepl/spiffs) - Another excellent embedded
filesystem for NOR flash. As a more traditional logging filesystem with full
static wear-leveling, SPIFFS will likely outperform littlefs on small
memories such as the internal flash on microcontrollers.
- [SPIFFS] - Another excellent embedded filesystem for NOR flash. As a more
traditional logging filesystem with full static wear-leveling, SPIFFS will
likely outperform littlefs on small memories such as the internal flash on
microcontrollers.
[Dhara](https://github.com/dlbeer/dhara) - An interesting NAND flash
translation layer designed for small MCUs. It offers static wear-leveling and
power-resilience with only a fixed O(|address|) pointer structure stored on
each block and in RAM.
- [Dhara] - An interesting NAND flash translation layer designed for small
MCUs. It offers static wear-leveling and power-resilience with only a fixed
_O(|address|)_ pointer structure stored on each block and in RAM.
[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html
[littlefs-fuse]: https://github.com/geky/littlefs-fuse
[FUSE]: https://github.com/libfuse/libfuse
[littlefs-js]: https://github.com/geky/littlefs-js
[littlefs-js-demo]:http://littlefs.geky.net/demo.html
[mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src
[Lua RTOS]: https://github.com/whitecatboard/Lua-RTOS-ESP32
[Mbed OS]: https://github.com/armmbed/mbed-os
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara

271
SPEC.md
View File

@@ -1,9 +1,9 @@
## The little filesystem technical specification
## littlefs technical specification
This is the technical specification of the little filesystem. This document
covers the technical details of how the littlefs is stored on disk for
introspection and tool development. This document assumes you are familiar
with the design of the littlefs, for more info on how littlefs works check
introspection and tooling. This document assumes you are familiar with the
design of the littlefs, for more info on how littlefs works check
out [DESIGN.md](DESIGN.md).
```
@@ -18,22 +18,21 @@ out [DESIGN.md](DESIGN.md).
## Some quick notes
- littlefs is a block-based filesystem. The disk is divided into an array of
evenly sized blocks that are used as the logical unit of storage. Block
pointers are stored in 32 bits.
evenly sized blocks that are used as the logical unit of storage.
- Block pointers are stored in 32 bits, with the special value `0xffffffff`
representing a null block address.
- In addition to the logical block size (which usually matches the erase
block size), littlefs also uses a program block size and read block size.
These determine the alignment of block device operations, but aren't needed
for portability.
These determine the alignment of block device operations, but don't need
to be consistent for portability.
- By default, any values in littlefs are stored in little-endian byte order.
- The littlefs uses the value of `0xffffffff` to represent a null
block address.
- By default, all values in littlefs are stored in little-endian byte order.
## Directories / Metadata pairs
Metadata pairs form the backbone of the littlefs and provide a system for
Metadata pairs form the backbone of littlefs and provide a system for
distributed atomic updates. Even the superblock is stored in a metadata pair.
As their name suggests, a metadata pair is stored in two blocks, with one block
@@ -91,14 +90,14 @@ alignment.
Metadata block fields:
- **Revision count (32-bits)** - Incremented every erase cycle. If both blocks
contain valid commits, only the block with the most recent revision count
should be used. Sequence comparison must be used to avoid issues with
integer overflow.
1. **Revision count (32-bits)** - Incremented every erase cycle. If both blocks
contain valid commits, only the block with the most recent revision count
should be used. Sequence comparison must be used to avoid issues with
integer overflow.
- **CRC (32-bits)** - Detects corruption from power-loss or other write
issues. Uses a CRC-32 with a polynomial of `0x04c11db7` initialized
with `0xffffffff`.
2. **CRC (32-bits)** - Detects corruption from power-loss or other write
issues. Uses a CRC-32 with a polynomial of `0x04c11db7` initialized
with `0xffffffff`.
Entries themselves are stored as a 32-bit tag followed by a variable length
blob of data. But exactly how these tags are stored is a little bit tricky.
@@ -159,7 +158,7 @@ Here's a more complete example of metadata block containing 4 entries:
| | | || |
| |-------------------+-------------------| || |
| | tag CxCRC | CRC | || /
| |-------------------+-------------------| ||
| |-------------------+-------------------| ||
| | tag CRCxA' | data A' | || \
| |-------------------+ | || |
| | | || |
@@ -167,7 +166,7 @@ Here's a more complete example of metadata block containing 4 entries:
| | | tag CRCxA' | | || |
| |--------------+-------------------+----| || |
| | CRC | padding | || /
| |--------------+----+-------------------| ||
| |--------------+----+-------------------| ||
| | tag CRCxA'' | data A'' | <---. \
| |-------------------+ | ||| |
| | | ||| |
@@ -179,12 +178,12 @@ Here's a more complete example of metadata block containing 4 entries:
| | | tag Dx| |||| |
| |---------+-------------------+---------| |||| |
| |CRC | CRC | | |||| /
| |---------+-------------------+ | ||||
| |---------+-------------------+ | ||||
| | unwritten storage | |||| more commits
| | | |||| |
| | | |||| v
| | | ||||
| | | ||||
| | | |||| v
| | | ||||
| | | ||||
| '---------------------------------------' ||||
'---------------------------------------' |||'- most recent A
||'-- most recent B
@@ -198,7 +197,7 @@ So in littlefs, 32-bit tags describe every type of metadata. And this means
_every_ type of metadata, including file entries, directory fields, and
global state. Even the CRCs used to mark the end of commits get their own tag.
Because of this, the tag format contains some densely packed informtaion. Note
Because of this, the tag format contains some densely packed information. Note
that there are multiple levels of types which break down into more info:
```
@@ -214,9 +213,9 @@ that there are multiple levels of types which break down into more info:
```
Before we go further, there's one VERY important thing to note. These tags are
NOT stored in little-endian. Tags stored in commits are actually stored in
big-endian (and is the only thing in littlefs stored in big-endian). This
Before we go further, there's one important thing to note. These tags are
**not** stored in little-endian. Tags stored in commits are actually stored
in big-endian (and is the only thing in littlefs stored in big-endian). This
little bit of craziness comes from the fact that the valid bit must be the
first bit in a commit, and when converted to little-endian, the valid bit finds
itself in byte 4. We could restructure the tag to store the valid bit lower,
@@ -228,26 +227,26 @@ invalid and can be used for null values.
Metadata tag fields:
- **Valid bit (1-bit)** - Indicates if the tag is valid.
1. **Valid bit (1-bit)** - Indicates if the tag is valid.
- **Type3 (11-bits)** - Type of the tag. This field is broken down further
into a 3-bit abstract type and an 8-bit chunk field. Note that the value
`0x000` is invalid and not assigned a type.
2. **Type3 (11-bits)** - Type of the tag. This field is broken down further
into a 3-bit abstract type and an 8-bit chunk field. Note that the value
`0x000` is invalid and not assigned a type.
- **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into
8 categories that facilitate bitmasked lookups.
3. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into
8 categories that facilitate bitmasked lookups.
- **Chunk (8-bits)** - Chunk field used for various purposes by the different
abstract types. type1+chunk+id form a unique identifier for each tag in the
metadata block.
4. **Chunk (8-bits)** - Chunk field used for various purposes by the different
abstract types. type1+chunk+id form a unique identifier for each tag in the
metadata block.
- **Id (10-bits)** - File id associated with the tag. Each file in a metadata
block gets a unique id which is used to associate tags with that file. The
special value `0x3ff` is used for any tags that are not associated with a
file, such as directory and global metadata.
5. **Id (10-bits)** - File id associated with the tag. Each file in a metadata
block gets a unique id which is used to associate tags with that file. The
special value `0x3ff` is used for any tags that are not associated with a
file, such as directory and global metadata.
- **Length (10-bits)** - Length of the data in bytes. The special value
`0x3ff` indicates that this tag has been deleted.
6. **Length (10-bits)** - Length of the data in bytes. The special value
`0x3ff` indicates that this tag has been deleted.
## Metadata types
@@ -274,7 +273,7 @@ array of files.
---
#### `0x0xx` LFS_TYPE_NAME
Associates the id with a file name and file type.
Associates the id with a file name and file type.
The data contains the file name stored as an ASCII string (may be expanded to
UTF8 in the future).
@@ -300,9 +299,9 @@ Layout of the name tag:
Name fields:
- **file type (8-bits)** - Type of the file.
1. **file type (8-bits)** - Type of the file.
- **file name** - File name stored as an ASCII string.
2. **file name** - File name stored as an ASCII string.
---
#### `0x001` LFS_TYPE_REG
@@ -335,14 +334,15 @@ across a linked-list of metadata pairs rooted on the blocks 0 and 1. The last
metadata pair doubles as the root directory of the filesystem.
```
.--------. .--------. .--------. .--------. .--------.
| super |->| super |->| super |->| super |->| file B |
| block | | block | | block | | block | | file C |
| | | | | | | file A | | file D |
.--------. .--------. .--------. .--------. .--------.
.| super |->| super |->| super |->| super |->| file B |
|| block | || block | || block | || block | || file C |
|| | || | || | || file A | || file D |
|'--------' |'--------' |'--------' |'--------' |'--------'
'--------' '--------' '--------' '--------' '--------'
\---------------+----------------/ \---------+---------/
superblock pairs root directory
\----------------+----------------/ \----------+----------/
superblock pairs root directory
```
The filesystem starts with only the root directory. The superblock metadata
@@ -366,48 +366,41 @@ Layout of the superblock name tag and inline-struct tag:
'----------------- valid bit
tag data
[-- 32 --][-- 32 --|-- 32 --|
[1|- 11 -| 10 | 10 ][-- 32 --|-- 32 --|
^ ^ ^ ^ ^- version ^- block size
[-- 32 --][-- 32 --|-- 32 --|-- 32 --]
[1|- 11 -| 10 | 10 ][-- 32 --|-- 32 --|-- 32 --]
^ ^ ^ ^ ^- version ^- block size ^- block count
| | | | [-- 32 --|-- 32 --|-- 32 --]
| | | | [-- 32 --|-- 32 --|-- 32 --]
| | | | ^- name max ^- file max ^- attr max
| | | '- size (24)
| | '------ id (0)
| '------------ type (0x201)
'----------------- valid bit
data (cont)
|-- 32 --|-- 32 --|-- 32 --|
|-- 32 --|-- 32 --|-- 32 --|
^- block count ^- name max ^- file max
data (cont)
|-- 32 --]
|-- 32 --]
^- attr max
```
Superblock fields:
- **Magic string (8-bytes)** - Magic string indicating the presence of littlefs
on the device. Must be the string "littlefs".
1. **Magic string (8-bytes)** - Magic string indicating the presence of
littlefs on the device. Must be the string "littlefs".
- **Version (32-bits)** - The version of littlefs at format time. The version
is encoded in a 32-bit value with the upper 16-bits containing the major
version, and the lower 16-bits containing the minor version.
2. **Version (32-bits)** - The version of littlefs at format time. The version
is encoded in a 32-bit value with the upper 16-bits containing the major
version, and the lower 16-bits containing the minor version.
This specification describes version 2.0 (`0x00020000`).
This specification describes version 2.0 (`0x00020000`).
- **Block size (32-bits)** - Size of the logical block size used by the
filesystem in bytes.
3. **Block size (32-bits)** - Size of the logical block size used by the
filesystem in bytes.
- **Block count (32-bits)** - Number of blocks in the filesystem.
4. **Block count (32-bits)** - Number of blocks in the filesystem.
- **Name max (32-bits)** - Maximum size of file names in bytes.
5. **Name max (32-bits)** - Maximum size of file names in bytes.
- **File max (32-bits)** - Maximum size of files in bytes.
6. **File max (32-bits)** - Maximum size of files in bytes.
- **Attr max (32-bits)** - Maximum size of file attributes in bytes.
7. **Attr max (32-bits)** - Maximum size of file attributes in bytes.
The superblock must always be the first entry (id 0) in a metdata pair as well
The superblock must always be the first entry (id 0) in a metadata pair as well
as be the first entry written to the block. This means that the superblock
entry can be read from a device using offsets alone.
@@ -419,7 +412,7 @@ Associates the id with an on-disk data structure.
The exact layout of the data depends on the data structure type stored in the
chunk field and can be one of the following.
Any type of struct supercedes all other structs associated with the id. For
Any type of struct supersedes all other structs associated with the id. For
example, appending a ctz-struct replaces an inline-struct on the same file.
---
@@ -431,12 +424,13 @@ Directories in littlefs are stored on disk as a linked-list of metadata pairs,
each pair containing any number of files in alphabetical order.
```
|
v
.--------. .--------. .--------. .--------. .--------. .--------.
| file A |->| file D |->| file G |->| file I |->| file J |->| file M |
| file B | | file E | | file H | | | | file K | | file N |
| file C | | file F | | | | | | file L | | |
|
v
.--------. .--------. .--------. .--------. .--------. .--------.
.| file A |->| file D |->| file G |->| file I |->| file J |->| file M |
|| file B | || file E | || file H | || | || file K | || file N |
|| file C | || file F | || | || | || file L | || |
|'--------' |'--------' |'--------' |'--------' |'--------' |'--------'
'--------' '--------' '--------' '--------' '--------' '--------'
```
@@ -460,15 +454,15 @@ Layout of the dir-struct tag:
Dir-struct fields:
- **Metadata pair (8-bytes)** - Pointer to the first metadata-pair
in the directory.
1. **Metadata pair (8-bytes)** - Pointer to the first metadata-pair
in the directory.
---
#### `0x201` LFS_TYPE_INLINESTRUCT
Gives the id an inline data structure.
Inline structs store small files that can fit in the metdata pair. In this
Inline structs store small files that can fit in the metadata pair. In this
case, the file data is stored directly in the tag's data area.
Layout of the inline-struct tag:
@@ -485,7 +479,7 @@ Layout of the inline-struct tag:
Inline-struct fields:
- **Inline data** - File data stored directly in the metadata-pair.
1. **Inline data** - File data stored directly in the metadata-pair.
---
#### `0x202` LFS_TYPE_CTZSTRUCT
@@ -497,12 +491,13 @@ are stored in a skip-list in reverse, with a pointer to the head of the
skip-list. Note that the head of the skip-list and the file size is enough
information to read the file.
How exactly CTZ skip-lists work is a bit complicted. A full explanation can be
How exactly CTZ skip-lists work is a bit complicated. A full explanation can be
found in the [DESIGN.md](DESIGN.md#ctz-skip-lists).
A quick summary: For every nth block where n is divisible by 2^x, the block
contains a pointer to block n-2^x. These pointers are stored in increasing
order of x in each block of the file before the actual data.
A quick summary: For every _n_&zwj;th block where _n_ is divisible by
2&zwj;_&#739;_, that block contains a pointer to block _n_-2&zwj;_&#739;_.
These pointers are stored in increasing order of _x_ in each block of the file
before the actual data.
```
|
@@ -536,15 +531,15 @@ Layout of the CTZ-struct tag:
CTZ-struct fields:
- **File head (32-bits)** - Pointer to the block that is the head of the
file's CTZ skip-list.
1. **File head (32-bits)** - Pointer to the block that is the head of the
file's CTZ skip-list.
- **File size (32-bits)** - Size of the file in bytes.
2. **File size (32-bits)** - Size of the file in bytes.
---
#### `0x3xx` LFS_TYPE_USERATTR
Attaches a user attribute to an id.
Attaches a user attribute to an id.
littlefs has a concept of "user attributes". These are small user-provided
attributes that can be used to store things like timestamps, hashes,
@@ -571,9 +566,9 @@ Layout of the user-attr tag:
User-attr fields:
- **Attr type (8-bits)** - Type of the user attributes.
1. **Attr type (8-bits)** - Type of the user attributes.
- **Attr data** - The data associated with the user attribute.
2. **Attr data** - The data associated with the user attribute.
---
#### `0x6xx` LFS_TYPE_TAIL
@@ -586,21 +581,23 @@ which indicates if the following metadata pair is a part of the directory
(hard-tail) or only used to traverse the filesystem (soft-tail).
```
.--------.
| dir A |-.
|softtail| |
.--------.
.| dir A |-.
||softtail| |
.--------| |-'
| '--------'
| |'--------'
| '---|--|-'
| .-' '-------------.
| v v
| .--------. .--------. .--------.
'->| dir B |->| dir B |->| dir C |
|hardtail| |softtail| | |
| | | | | |
'--------' '--------' '--------'
||hardtail| ||softtail| || |
|| | || | || |
|'--------' |'--------' |'--------'
'--------' '--------' '--------'
```
Currently any type supercedes any other preceding tails in the metadata pair,
Currently any type supersedes any other preceding tails in the metadata pair,
but this may change if additional metadata pair state is added.
A note about the metadata pair linked-list: Normally, this linked-list contains
@@ -611,10 +608,10 @@ exactly this flag is stored is described below.
When the sync flag is set:
- The linked-list may contain an orphaned directory that has been removed in
the filesystem.
- The linked-list may contain a metadata pair with a bad block that has been
replaced in the filesystem.
1. The linked-list may contain an orphaned directory that has been removed in
the filesystem.
2. The linked-list may contain a metadata pair with a bad block that has been
replaced in the filesystem.
If the sync flag is set, the threaded linked-list must be checked for these
errors before it can be used reliably. Note that the threaded linked-list can
@@ -635,9 +632,9 @@ Layout of the tail tag:
Tail fields:
- **Tail type (8-bits)** - Type of the tail pointer.
1. **Tail type (8-bits)** - Type of the tail pointer.
- **Metadata pair (8-bytes)** - Pointer to the next metadata-pair.
2. **Metadata pair (8-bytes)** - Pointer to the next metadata-pair.
---
#### `0x600` LFS_TYPE_SOFTTAIL
@@ -668,18 +665,18 @@ littlefs has a concept of "global state". This is a small set of state that
can be updated by a commit to _any_ metadata pair in the filesystem.
The way this works is that the global state is stored as a set of deltas
distributed across the filesystem such that the global state can by found by
distributed across the filesystem such that the global state can be found by
the xor-sum of these deltas.
```
.--------. .--------. .--------. .--------. .--------.
| |->| gstate |->| |->| gstate |->| gstate |
| | | 0x23 | | | | 0xff | | 0xce |
| | | | | | | | | |
'--------' '--------' '--------' '--------' '--------'
| | |
v v v
0x00 --> xor ------------------> xor ------> xor --> gstate 0x12
.--------. .--------. .--------. .--------. .--------.
.| |->| gdelta |->| |->| gdelta |->| gdelta |
|| | || 0x23 | || | || 0xff | || 0xce |
|| | || | || | || | || |
|'--------' |'--------' |'--------' |'--------' |'--------'
'--------' '----|---' '--------' '----|---' '----|---'
v v v
0x00 --> xor ------------------> xor ------> xor --> gstate = 0x12
```
Note that storing globals this way is very expensive in terms of storage usage,
@@ -730,17 +727,17 @@ Layout of the move state:
Move state fields:
- **Sync bit (1-bit)** - Indicates if the metadata pair threaded linked-list is
in-sync. If set, the threaded linked-list should be checked for errors.
1. **Sync bit (1-bit)** - Indicates if the metadata pair threaded linked-list
is in-sync. If set, the threaded linked-list should be checked for errors.
- **Move type (11-bits)** - Type of move being performed. Must be either
`0x000`, indicating no move, or `0x4ff` indicating the source file should
be deleted.
2. **Move type (11-bits)** - Type of move being performed. Must be either
`0x000`, indicating no move, or `0x4ff` indicating the source file should
be deleted.
- **Move id (10-bits)** - The file id being moved.
3. **Move id (10-bits)** - The file id being moved.
- **Metadata pair (8-bytes)** - Pointer to the metadata-pair containing
the move.
4. **Metadata pair (8-bytes)** - Pointer to the metadata-pair containing
the move.
---
#### `0x5xx` LFS_TYPE_CRC
@@ -778,13 +775,13 @@ Layout of the CRC tag:
CRC fields:
- **Valid state (1-bit)** - Indicates the expected value of the valid bit for
any tags in the next commit.
1. **Valid state (1-bit)** - Indicates the expected value of the valid bit for
any tags in the next commit.
- **CRC (32-bits)** - CRC-32 with a polynomial of `0x04c11db7` initialized with
`0xffffffff`.
2. **CRC (32-bits)** - CRC-32 with a polynomial of `0x04c11db7` initialized
with `0xffffffff`.
- **Padding** - Padding to the next program-aligned boundary. No guarantees are
made about the contents.
3. **Padding** - Padding to the next program-aligned boundary. No guarantees
are made about the contents.
---