mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 00:32:38 +01:00 
			
		
		
		
	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:
		
							
								
								
									
										163
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								README.md
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										271
									
								
								SPEC.md
									
									
									
									
									
								
							| @@ -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_‍th block where _n_ is divisible by | ||||
| 2‍_ˣ_, that block contains a pointer to block _n_-2‍_ˣ_. | ||||
| 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. | ||||
|  | ||||
| --- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user