diff --git a/littlefs/README.md b/littlefs/README.md index 3441293..5a75df3 100644 --- a/littlefs/README.md +++ b/littlefs/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/littlefs/SPEC.md b/littlefs/SPEC.md index 2370ea6..6682c74 100644 --- a/littlefs/SPEC.md +++ b/littlefs/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/littlefs/lfs.c b/littlefs/lfs.c index c14efaa..d35d5d6 100644 --- a/littlefs/lfs.c +++ b/littlefs/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/littlefs/tests/test_superblocks.toml b/littlefs/tests/test_superblocks.toml index a7c2aff..e93f02e 100644 --- a/littlefs/tests/test_superblocks.toml +++ b/littlefs/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 = '''