From 74006f35d5ffa0ad8147891f7a4f997c4e7b78e7 Mon Sep 17 00:00:00 2001 From: geky-bot Date: Mon, 29 Apr 2024 22:11:00 +0000 Subject: [PATCH] Squashed 'littlefs/' changes from 68d28b5..d01280e 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 --- README.md | 38 +++++++++++++++----------- SPEC.md | 7 ++--- lfs.c | 15 +++++++---- tests/test_superblocks.toml | 53 ++++++++++++++++++++++++++++++++++++- 4 files changed, 89 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 3441293..5a75df3 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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 diff --git a/SPEC.md b/SPEC.md index 2370ea6..6682c74 100644 --- a/SPEC.md +++ b/SPEC.md @@ -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 diff --git a/lfs.c b/lfs.c index c14efaa..d35d5d6 100644 --- a/lfs.c +++ b/lfs.c @@ -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; } } } @@ -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; @@ -4466,6 +4469,7 @@ 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, @@ -4473,10 +4477,11 @@ static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) { 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) { diff --git a/tests/test_superblocks.toml b/tests/test_superblocks.toml index a7c2aff..e93f02e 100644 --- a/tests/test_superblocks.toml +++ b/tests/test_superblocks.toml @@ -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 = ''' @@ -28,7 +46,6 @@ code = ''' lfs_unmount(&lfs) => 0; ''' - # reentrant format [cases.test_superblocks_reentrant_format] reentrant = true @@ -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] @@ -221,6 +271,7 @@ code = ''' lfs_unmount(&lfs) => 0; ''' + # mount with unknown block_count [cases.test_superblocks_unknown_blocks] code = '''