mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-10-29 19:47:49 +00:00
doc: Spelling fixes
This commit is contained in:
parent
1fb6a19520
commit
3457252fe6
30
DESIGN.md
30
DESIGN.md
@ -72,7 +72,7 @@ to three strong requirements:
|
||||
|
||||
## Existing designs?
|
||||
|
||||
There are of course, many different existing filesystem. Heres a very rough
|
||||
There are of course, many different existing filesystem. Here is a very rough
|
||||
summary of the general ideas behind some of them.
|
||||
|
||||
Most of the existing filesystems fall into the one big category of filesystem
|
||||
@ -91,7 +91,7 @@ the changes to the files are stored on disk. This has several neat advantages,
|
||||
such as the fact that the data is written in a cyclic log format naturally
|
||||
wear levels as a side effect. And, with a bit of error detection, the entire
|
||||
filesystem can easily be designed to be resilient to power loss. The
|
||||
journalling component of most modern day filesystems is actually a reduced
|
||||
journaling component of most modern day filesystems is actually a reduced
|
||||
form of a logging filesystem. However, logging filesystems have a difficulty
|
||||
scaling as the size of storage increases. And most filesystems compensate by
|
||||
caching large parts of the filesystem in RAM, a strategy that is unavailable
|
||||
@ -114,7 +114,7 @@ pairs, so that at any time there is always a backup containing the previous
|
||||
state of the metadata.
|
||||
|
||||
Consider a small example where each metadata pair has a revision count,
|
||||
a number as data, and the xor of the block as a quick checksum. If
|
||||
a number as data, and the XOR of the block as a quick checksum. If
|
||||
we update the data to a value of 9, and then to a value of 5, here is
|
||||
what the pair of blocks may look like after each update:
|
||||
```
|
||||
@ -149,7 +149,7 @@ check our checksum we notice that block 1 was corrupted. So we fall back to
|
||||
block 2 and use the value 9.
|
||||
|
||||
Using this concept, the littlefs is able to update metadata blocks atomically.
|
||||
There are a few other tweaks, such as using a 32 bit crc and using sequence
|
||||
There are a few other tweaks, such as using a 32 bit CRC and using sequence
|
||||
arithmetic to handle revision count overflow, but the basic concept
|
||||
is the same. These metadata pairs define the backbone of the littlefs, and the
|
||||
rest of the filesystem is built on top of these atomic updates.
|
||||
@ -289,15 +289,15 @@ The path to data block 0 is even more quick, requiring only two jumps:
|
||||
|
||||
We can find the runtime complexity by looking at the path to any block from
|
||||
the block containing the most pointers. Every step along the path divides
|
||||
the search space for the block in half. This gives us a runtime of O(logn).
|
||||
the search space for the block in half. This gives us a runtime of O(log n).
|
||||
To get to the block with the most pointers, we can perform the same steps
|
||||
backwards, which puts the runtime at O(2logn) = O(logn). The interesting
|
||||
backwards, which puts the runtime at O(2 log n) = O(log n). The interesting
|
||||
part about this data structure is that this optimal path occurs naturally
|
||||
if we greedily choose the pointer that covers the most distance without passing
|
||||
our target block.
|
||||
|
||||
So now we have a representation of files that can be appended trivially with
|
||||
a runtime of O(1), and can be read with a worst case runtime of O(nlogn).
|
||||
a runtime of O(1), and can be read with a worst case runtime of O(n log n).
|
||||
Given that the the runtime is also divided by the amount of data we can store
|
||||
in a block, this is pretty reasonable.
|
||||
|
||||
@ -362,7 +362,7 @@ N = file size in bytes
|
||||
|
||||
And this works quite well, but is not trivial to calculate. This equation
|
||||
requires O(n) to compute, which brings the entire runtime of reading a file
|
||||
to O(n^2logn). Fortunately, the additional O(n) does not need to touch disk,
|
||||
to O(n^2 log n). Fortunately, the additional O(n) does not need to touch disk,
|
||||
so it is not completely unreasonable. But if we could solve this equation into
|
||||
a form that is easily computable, we can avoid a big slowdown.
|
||||
|
||||
@ -383,7 +383,7 @@ ctz(i) = the number of trailing bits that are 0 in i
|
||||
popcount(i) = the number of bits that are 1 in i
|
||||
|
||||
It's a bit bewildering that these two seemingly unrelated bitwise instructions
|
||||
are related by this property. But if we start to disect this equation we can
|
||||
are related by this property. But if we start to dissect this equation we can
|
||||
see that it does hold. As n approaches infinity, we do end up with an average
|
||||
overhead of 2 pointers as we find earlier. And popcount seems to handle the
|
||||
error from this average as it accumulates in the CTZ skip-list.
|
||||
@ -503,7 +503,7 @@ However, this approach had several issues:
|
||||
- There was a lot of nuanced logic for adding blocks to the free list without
|
||||
modifying the blocks, since the blocks remain active until the metadata is
|
||||
updated.
|
||||
- The free list had to support both additions and removals in fifo order while
|
||||
- The free list had to support both additions and removals in FIFO order while
|
||||
minimizing block erases.
|
||||
- The free list had to handle the case where the file system completely ran
|
||||
out of blocks and may no longer be able to add blocks to the free list.
|
||||
@ -622,7 +622,7 @@ So, as a solution, the littlefs adopted a sort of threaded tree. Each
|
||||
directory not only contains pointers to all of its children, but also a
|
||||
pointer to the next directory. These pointers create a linked-list that
|
||||
is threaded through all of the directories in the filesystem. Since we
|
||||
only use this linked list to check for existance, the order doesn't actually
|
||||
only use this linked list to check for existence, the order doesn't actually
|
||||
matter. As an added plus, we can repurpose the pointer for the individual
|
||||
directory linked-lists and avoid using any additional space.
|
||||
|
||||
@ -773,7 +773,7 @@ deorphan step that simply iterates through every directory in the linked-list
|
||||
and checks it against every directory entry in the filesystem to see if it
|
||||
has a parent. The deorphan step occurs on the first block allocation after
|
||||
boot, so orphans should never cause the littlefs to run out of storage
|
||||
prematurely. Note that the deorphan step never needs to run in a readonly
|
||||
prematurely. Note that the deorphan step never needs to run in a read-only
|
||||
filesystem.
|
||||
|
||||
## The move problem
|
||||
@ -883,7 +883,7 @@ a power loss will occur during filesystem activity. We still need to handle
|
||||
the condition, but runtime during a power loss takes a back seat to the runtime
|
||||
during normal operations.
|
||||
|
||||
So what littlefs does is unelegantly simple. When littlefs moves a file, it
|
||||
So what littlefs does is inelegantly simple. When littlefs moves a file, it
|
||||
marks the file as "moving". This is stored as a single bit in the directory
|
||||
entry and doesn't take up much space. Then littlefs moves the directory,
|
||||
finishing with the complete remove of the "moving" directory entry.
|
||||
@ -979,7 +979,7 @@ if it exists elsewhere in the filesystem.
|
||||
So now that we have all of the pieces of a filesystem, we can look at a more
|
||||
subtle attribute of embedded storage: The wear down of flash blocks.
|
||||
|
||||
The first concern for the littlefs, is that prefectly valid blocks can suddenly
|
||||
The first concern for the littlefs, is that perfectly valid blocks can suddenly
|
||||
become unusable. As a nice side-effect of using a COW data-structure for files,
|
||||
we can simply move on to a different block when a file write fails. All
|
||||
modifications to files are performed in copies, so we will only replace the
|
||||
@ -1210,7 +1210,7 @@ So, to summarize:
|
||||
metadata block is active
|
||||
4. Directory blocks contain either references to other directories or files
|
||||
5. Files are represented by copy-on-write CTZ skip-lists which support O(1)
|
||||
append and O(nlogn) reading
|
||||
append and O(n log n) reading
|
||||
6. Blocks are allocated by scanning the filesystem for used blocks in a
|
||||
fixed-size lookahead region is that stored in a bit-vector
|
||||
7. To facilitate scanning the filesystem, all directories are part of a
|
||||
|
||||
14
README.md
14
README.md
@ -16,7 +16,7 @@ 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
|
||||
random power failures. The littlefs has strong copy-on-write guaruntees and
|
||||
random power failures. The littlefs has strong copy-on-write guarantees and
|
||||
storage on disk is always kept in a valid state.
|
||||
|
||||
**Wear leveling** - Since the most common form of embedded storage is erodible
|
||||
@ -88,7 +88,7 @@ int main(void) {
|
||||
## Usage
|
||||
|
||||
Detailed documentation (or at least as much detail as is currently available)
|
||||
can be cound in the comments in [lfs.h](lfs.h).
|
||||
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
|
||||
@ -101,12 +101,12 @@ to the user to allocate, allowing multiple filesystems to be in use
|
||||
simultaneously. With the `lfs_t` and configuration struct, a user can
|
||||
format a block device or mount the filesystem.
|
||||
|
||||
Once mounted, the littlefs provides a full set of posix-like file and
|
||||
Once mounted, the littlefs provides a full set of POSIX-like file and
|
||||
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 commited to the
|
||||
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.
|
||||
|
||||
## Other notes
|
||||
@ -131,9 +131,9 @@ with all the nitty-gritty details. Can be useful for developing tooling.
|
||||
|
||||
## Testing
|
||||
|
||||
The littlefs comes with a test suite designed to run on a pc using the
|
||||
The littlefs comes with a test suite designed to run on a PC using the
|
||||
[emulated block device](emubd/lfs_emubd.h) found in the emubd directory.
|
||||
The tests assume a linux environment and can be started with make:
|
||||
The tests assume a Linux environment and can be started with make:
|
||||
|
||||
``` bash
|
||||
make test
|
||||
|
||||
12
SPEC.md
12
SPEC.md
@ -46,7 +46,7 @@ Here's the layout of metadata blocks on disk:
|
||||
| 0x04 | 32 bits | dir size |
|
||||
| 0x08 | 64 bits | tail pointer |
|
||||
| 0x10 | size-16 bytes | dir entries |
|
||||
| 0x00+s | 32 bits | crc |
|
||||
| 0x00+s | 32 bits | CRC |
|
||||
|
||||
**Revision count** - Incremented every update, only the uncorrupted
|
||||
metadata-block with the most recent revision count contains the valid metadata.
|
||||
@ -75,7 +75,7 @@ Here's an example of a simple directory stored on disk:
|
||||
(32 bits) revision count = 10 (0x0000000a)
|
||||
(32 bits) dir size = 154 bytes, end of dir (0x0000009a)
|
||||
(64 bits) tail pointer = 37, 36 (0x00000025, 0x00000024)
|
||||
(32 bits) crc = 0xc86e3106
|
||||
(32 bits) CRC = 0xc86e3106
|
||||
|
||||
00000000: 0a 00 00 00 9a 00 00 00 25 00 00 00 24 00 00 00 ........%...$...
|
||||
00000010: 22 08 00 03 05 00 00 00 04 00 00 00 74 65 61 22 "...........tea"
|
||||
@ -138,12 +138,12 @@ not include the entry type size, attributes, or name. The full size in bytes
|
||||
of the entry is 4 + entry length + attribute length + name length.
|
||||
|
||||
**Attribute length** - Length of system-specific attributes in bytes. Since
|
||||
attributes are system specific, there is not much garuntee on the values in
|
||||
attributes are system specific, there is not much guarantee on the values in
|
||||
this section, and systems are expected to work even when it is empty. See the
|
||||
[attributes](#entry-attributes) section for more details.
|
||||
|
||||
**Name length** - Length of the entry name. Entry names are stored as utf8,
|
||||
although most systems will probably only support ascii. Entry names can not
|
||||
**Name length** - Length of the entry name. Entry names are stored as UTF8,
|
||||
although most systems will probably only support ASCII. Entry names can not
|
||||
contain '/' and can not be '.' or '..' as these are a part of the syntax of
|
||||
filesystem paths.
|
||||
|
||||
@ -222,7 +222,7 @@ Here's an example of a complete superblock:
|
||||
(32 bits) block count = 1024 blocks (0x00000400)
|
||||
(32 bits) version = 1.1 (0x00010001)
|
||||
(8 bytes) magic string = littlefs
|
||||
(32 bits) crc = 0xc50b74fa
|
||||
(32 bits) CRC = 0xc50b74fa
|
||||
|
||||
00000000: 03 00 00 00 34 00 00 00 03 00 00 00 02 00 00 00 ....4...........
|
||||
00000010: 2e 14 00 08 03 00 00 00 02 00 00 00 00 02 00 00 ................
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user