Skip to content

Commit

Permalink
Squashed 'littlefs/' changes from 68d28b5..d01280e
Browse files Browse the repository at this point in the history
d01280e Merge pull request #968 from littlefs-project/link-pico-littlefs-usb
6e52140 Merge pull request #959 from littlefs-project/fix-expanded-magic
0bbb8bc Reorganized external project links a bit
7808233 Added a link to mklittlefs
8336ecd Added a link to pico-littlefs-usb (FAT12 emulation)
11b036c Prevented unnecessary superblock rewrites if old version in superblock chain
25ee90f Clarified what is accessible at specific superblock offsets in SPEC.md
a60a986 Duplicate the superblock entry during superblock expansion

git-subtree-dir: littlefs
git-subtree-split: d01280e64934a09ba16cac60cf9d3a37e228bb66
  • Loading branch information
geky-bot committed Apr 29, 2024
1 parent 38112db commit 74006f3
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 24 deletions.
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,25 @@ License Identifiers that are here available: http://spdx.org/licenses/
to use littlefs in a Rust-friendly API, reaping the benefits of Rust's memory
safety and other guarantees.

- [nim-littlefs] - A Nim wrapper and API for littlefs. Includes a fuse
implementation based on [littlefs-fuse]

- [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for
use with the MirageOS library operating system project. It is interoperable
with the reference implementation, with some caveats.

- [littlefs-disk-img-viewer] - A memory-efficient web application for viewing
littlefs disk images in your web browser.

- [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] - A command line tool for creating littlefs images. Used in the Lua
RTOS ecosystem.

- [mklittlefs] - A command line tool for creating littlefs images. Used in the
ESP8266 and RP2040 ecosystem.

- [pico-littlefs-usb] - An interface for littlefs that emulates a FAT12
filesystem over USB. Allows mounting littlefs on a host PC without additional
drivers.

- [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.
Expand All @@ -254,27 +268,21 @@ License Identifiers that are here available: http://spdx.org/licenses/
for microcontroller-scale devices. Due to limitations of FAT it can't provide
power-loss resilience, but it does allow easy interop with PCs.

- [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for
use with the MirageOS library operating system project. It is interoperable
with the reference implementation, with some caveats.

- [nim-littlefs] - A Nim wrapper and API for littlefs. Includes a fuse
implementation based on [littlefs-fuse]

[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html
[littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer
[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
[littlefs-python]: https://pypi.org/project/littlefs-python/
[littlefs2-rust]: https://crates.io/crates/littlefs2
[nim-littlefs]: https://github.com/Graveflo/nim-littlefs
[chamelon]: https://github.com/yomimono/chamelon
[littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer
[mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src
[Lua RTOS]: https://github.com/whitecatboard/Lua-RTOS-ESP32
[mklittlefs]: https://github.com/earlephilhower/mklittlefs
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb
[Mbed OS]: https://github.com/armmbed/mbed-os
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara
[ChaN's FatFs]: http://elm-chan.org/fsw/ff/00index_e.html
[littlefs-python]: https://pypi.org/project/littlefs-python/
[littlefs2-rust]: https://crates.io/crates/littlefs2
[chamelon]: https://github.com/yomimono/chamelon
[nim-littlefs]: https://github.com/Graveflo/nim-littlefs
7 changes: 4 additions & 3 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,10 @@ Superblock fields:

7. **Attr max (32-bits)** - Maximum size of file attributes in bytes.

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.
The superblock must always be the first entry (id 0) in the metadata pair, and
the name tag must always be the first tag in the metadata pair. This makes it
so that the magic string "littlefs" will always reside at offset=8 in a valid
littlefs superblock.

---
#### `0x2xx` LFS_TYPE_STRUCT
Expand Down
15 changes: 10 additions & 5 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2191,7 +2191,8 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
// we can do, we'll error later if we've become frozen
LFS_WARN("Unable to expand superblock");
} else {
end = begin;
// duplicate the superblock entry into the new superblock
end = 1;
}
}
}
Expand Down Expand Up @@ -2358,7 +2359,9 @@ fixmlist:;

while (d->id >= d->m.count && d->m.split) {
// we split and id is on tail now
d->id -= d->m.count;
if (lfs_pair_cmp(d->m.tail, lfs->root) != 0) {
d->id -= d->m.count;
}
int err = lfs_dir_fetch(lfs, &d->m, d->m.tail);
if (err) {
return err;
Expand Down Expand Up @@ -4466,17 +4469,19 @@ static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
// found older minor version? set an in-device only bit in the
// gstate so we know we need to rewrite the superblock before
// the first write
bool needssuperblock = false;
if (minor_version < lfs_fs_disk_version_minor(lfs)) {
LFS_DEBUG("Found older minor version "
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
major_version,
minor_version,
lfs_fs_disk_version_major(lfs),
lfs_fs_disk_version_minor(lfs));
// note this bit is reserved on disk, so fetching more gstate
// will not interfere here
lfs_fs_prepsuperblock(lfs, true);
needssuperblock = true;
}
// note this bit is reserved on disk, so fetching more gstate
// will not interfere here
lfs_fs_prepsuperblock(lfs, needssuperblock);

// check superblock configuration
if (superblock.name_max) {
Expand Down
53 changes: 52 additions & 1 deletion tests/test_superblocks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ code = '''
lfs_unmount(&lfs) => 0;
'''

# make sure the magic string "littlefs" is always at offset=8
[cases.test_superblocks_magic]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;

// check our magic string
//
// note if we lose power we may not have the magic string in both blocks!
// but we don't lose power in this test so we can assert the magic string
// is present in both
uint8_t magic[lfs_max(16, READ_SIZE)];
cfg->read(cfg, 0, 0, magic, lfs_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
cfg->read(cfg, 1, 0, magic, lfs_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
'''

# mount/unmount from interpretting a previous superblock block_count
[cases.test_superblocks_mount_unknown_block_count]
code = '''
Expand All @@ -28,7 +46,6 @@ code = '''
lfs_unmount(&lfs) => 0;
'''


# reentrant format
[cases.test_superblocks_reentrant_format]
reentrant = true
Expand Down Expand Up @@ -135,6 +152,39 @@ code = '''
lfs_unmount(&lfs) => 0;
'''

# make sure the magic string "littlefs" is always at offset=8
[cases.test_superblocks_magic_expand]
defines.BLOCK_CYCLES = [32, 33, 1]
defines.N = [10, 100, 1000]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0;
}
lfs_unmount(&lfs) => 0;

// check our magic string
//
// note if we lose power we may not have the magic string in both blocks!
// but we don't lose power in this test so we can assert the magic string
// is present in both
uint8_t magic[lfs_max(16, READ_SIZE)];
cfg->read(cfg, 0, 0, magic, lfs_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
cfg->read(cfg, 1, 0, magic, lfs_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
'''

# expanding superblock with power cycle
[cases.test_superblocks_expand_power_cycle]
defines.BLOCK_CYCLES = [32, 33, 1]
Expand Down Expand Up @@ -221,6 +271,7 @@ code = '''
lfs_unmount(&lfs) => 0;
'''


# mount with unknown block_count
[cases.test_superblocks_unknown_blocks]
code = '''
Expand Down

0 comments on commit 74006f3

Please sign in to comment.