Compare commits

..

1 Commits

Author SHA1 Message Date
Christopher Haster
b93cd18bf5 Tighten bound on mlist isopen asserts
Unbalanced open/close calls continue to be a pain point for users, it
doesn't help that this sometimes results in hard-to-debug infinite loops
caused by the open-file linked-list (the mlist) getting tangled up in
itself.

Moving the mlist isopen asserts lower into the actual list append/remove
functions will help:

1. Make sure coverage of potential linked-list issues is complete.

2. Also assert against multiple close calls, which isn't an issue for
   the mlist, but can result in double free and memory corruption.
2024-01-16 13:13:49 -06:00
25 changed files with 379 additions and 964 deletions

View File

@@ -10,7 +10,7 @@ defaults:
jobs: jobs:
post-release: post-release:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
# trigger post-release in dependency repo, this indirection allows the # trigger post-release in dependency repo, this indirection allows the
# dependency repo to be updated often without affecting this repo. At # dependency repo to be updated often without affecting this repo. At

View File

@@ -11,7 +11,7 @@ defaults:
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
# need to manually check for a couple things # need to manually check for a couple things
# - tests passed? # - tests passed?
@@ -20,7 +20,7 @@ jobs:
github.event.workflow_run.head_sha == github.sha}} github.event.workflow_run.head_sha == github.sha}}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
with: with:
ref: ${{github.event.workflow_run.head_sha}} ref: ${{github.event.workflow_run.head_sha}}
# need workflow access since we push branches # need workflow access since we push branches
@@ -30,29 +30,26 @@ jobs:
fetch-depth: 0 fetch-depth: 0
# try to get results from tests # try to get results from tests
- uses: actions/download-artifact@v4 - uses: dawidd6/action-download-artifact@v2
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} workflow: ${{github.event.workflow_run.name}}
run-id: ${{github.event.workflow_run.id}} run_id: ${{github.event.workflow_run.id}}
pattern: '{sizes,sizes-*}' name: sizes
merge-multiple: true
path: sizes path: sizes
- uses: actions/download-artifact@v4 - uses: dawidd6/action-download-artifact@v2
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} workflow: ${{github.event.workflow_run.name}}
run-id: ${{github.event.workflow_run.id}} run_id: ${{github.event.workflow_run.id}}
pattern: '{cov,cov-*}' name: cov
merge-multiple: true
path: cov path: cov
- uses: actions/download-artifact@v4 - uses: dawidd6/action-download-artifact@v2
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} workflow: ${{github.event.workflow_run.name}}
run-id: ${{github.event.workflow_run.id}} run_id: ${{github.event.workflow_run.id}}
pattern: '{bench,bench-*}' name: bench
merge-multiple: true
path: bench path: bench
- name: find-version - name: find-version

View File

@@ -11,15 +11,14 @@ defaults:
jobs: jobs:
# forward custom statuses # forward custom statuses
status: status:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/download-artifact@v4 - uses: dawidd6/action-download-artifact@v2
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} workflow: ${{github.event.workflow_run.name}}
run-id: ${{github.event.workflow_run.id}} run_id: ${{github.event.workflow_run.id}}
pattern: '{status,status-*}' name: status
merge-multiple: true
path: status path: status
- name: update-status - name: update-status
continue-on-error: true continue-on-error: true
@@ -61,20 +60,19 @@ jobs:
# forward custom pr-comments # forward custom pr-comments
comment: comment:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
# only run on success (we don't want garbage comments!) # only run on success (we don't want garbage comments!)
if: ${{github.event.workflow_run.conclusion == 'success'}} if: ${{github.event.workflow_run.conclusion == 'success'}}
steps: steps:
# generated comment? # generated comment?
- uses: actions/download-artifact@v4 - uses: dawidd6/action-download-artifact@v2
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} workflow: ${{github.event.workflow_run.name}}
run-id: ${{github.event.workflow_run.id}} run_id: ${{github.event.workflow_run.id}}
pattern: '{comment,comment-*}' name: comment
merge-multiple: true
path: comment path: comment
- name: update-comment - name: update-comment
continue-on-error: true continue-on-error: true

View File

@@ -14,14 +14,14 @@ env:
jobs: jobs:
# run tests # run tests
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
arch: [x86_64, thumb, mips, powerpc] arch: [x86_64, thumb, mips, powerpc]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -235,9 +235,9 @@ jobs:
# create size statuses # create size statuses
- name: upload-sizes - name: upload-sizes
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: sizes-${{matrix.arch}} name: sizes
path: sizes path: sizes
- name: status-sizes - name: status-sizes
run: | run: |
@@ -273,17 +273,16 @@ jobs:
}' | tee status/$(basename $f .csv).json }' | tee status/$(basename $f .csv).json
done done
- name: upload-status-sizes - name: upload-status-sizes
if: ${{matrix.arch == 'x86_64'}} uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with: with:
name: status-sizes-${{matrix.arch}} name: status
path: status path: status
retention-days: 1 retention-days: 1
# create cov statuses # create cov statuses
- name: upload-cov - name: upload-cov
if: ${{matrix.arch == 'x86_64'}} if: ${{matrix.arch == 'x86_64'}}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: cov name: cov
path: cov path: cov
@@ -318,11 +317,11 @@ jobs:
target_step: env.STEP, target_step: env.STEP,
}' | tee status/$(basename $f .csv)-$s.json }' | tee status/$(basename $f .csv)-$s.json
done done
- name: upload-status-cov - name: upload-status-sizes
if: ${{matrix.arch == 'x86_64'}} if: ${{matrix.arch == 'x86_64'}}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: status-cov name: status
path: status path: status
retention-days: 1 retention-days: 1
@@ -330,14 +329,14 @@ jobs:
# #
# this grows exponentially, so it doesn't turn out to be that many # this grows exponentially, so it doesn't turn out to be that many
test-pls: test-pls:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
pls: [1, 2] pls: [1, 2]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -360,9 +359,9 @@ jobs:
# run with LFS_NO_INTRINSICS to make sure that works # run with LFS_NO_INTRINSICS to make sure that works
test-no-intrinsics: test-no-intrinsics:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -377,9 +376,9 @@ jobs:
# run LFS_MULTIVERSION tests # run LFS_MULTIVERSION tests
test-multiversion: test-multiversion:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -394,9 +393,9 @@ jobs:
# run tests on the older version lfs2.0 # run tests on the older version lfs2.0
test-lfs2_0: test-lfs2_0:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -413,9 +412,9 @@ jobs:
# run under Valgrind to check for memory errors # run under Valgrind to check for memory errors
test-valgrind: test-valgrind:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -435,9 +434,9 @@ jobs:
# test that compilation is warning free under clang # test that compilation is warning free under clang
# run with Clang, mostly to check for Clang-specific warnings # run with Clang, mostly to check for Clang-specific warnings
test-clang: test-clang:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -458,9 +457,9 @@ jobs:
# #
# note there's no real benefit to running these on multiple archs # note there's no real benefit to running these on multiple archs
bench: bench:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -492,7 +491,7 @@ jobs:
# create bench statuses # create bench statuses
- name: upload-bench - name: upload-bench
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: bench name: bench
path: bench path: bench
@@ -526,20 +525,20 @@ jobs:
}' | tee status/$(basename $f .csv)-$s.json }' | tee status/$(basename $f .csv)-$s.json
done done
- name: upload-status-bench - name: upload-status-bench
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: status-bench name: status
path: status path: status
retention-days: 1 retention-days: 1
# run compatibility tests using the current master as the previous version # run compatibility tests using the current master as the previous version
test-compat: test-compat:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
# checkout the current pr target into lfsp # checkout the current pr target into lfsp
- uses: actions/checkout@v4 - uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
with: with:
ref: ${{github.event.pull_request.base.ref}} ref: ${{github.event.pull_request.base.ref}}
@@ -570,10 +569,10 @@ jobs:
# self-host with littlefs-fuse for a fuzz-like test # self-host with littlefs-fuse for a fuzz-like test
fuse: fuse:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
if: ${{!endsWith(github.ref, '-prefix')}} if: ${{!endsWith(github.ref, '-prefix')}}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -583,7 +582,7 @@ jobs:
gcc --version gcc --version
python3 --version python3 --version
fusermount -V fusermount -V
- uses: actions/checkout@v4 - uses: actions/checkout@v2
with: with:
repository: littlefs-project/littlefs-fuse repository: littlefs-project/littlefs-fuse
ref: v2 ref: v2
@@ -620,10 +619,10 @@ jobs:
# test migration using littlefs-fuse # test migration using littlefs-fuse
migrate: migrate:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
if: ${{!endsWith(github.ref, '-prefix')}} if: ${{!endsWith(github.ref, '-prefix')}}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: install - name: install
run: | run: |
# need a few things # need a few things
@@ -633,12 +632,12 @@ jobs:
gcc --version gcc --version
python3 --version python3 --version
fusermount -V fusermount -V
- uses: actions/checkout@v4 - uses: actions/checkout@v2
with: with:
repository: littlefs-project/littlefs-fuse repository: littlefs-project/littlefs-fuse
ref: v2 ref: v2
path: v2 path: v2
- uses: actions/checkout@v4 - uses: actions/checkout@v2
with: with:
repository: littlefs-project/littlefs-fuse repository: littlefs-project/littlefs-fuse
ref: v1 ref: v1
@@ -692,10 +691,10 @@ jobs:
# status related tasks that run after tests # status related tasks that run after tests
status: status:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
needs: [test, bench] needs: [test, bench]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
- name: install - name: install
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
@@ -705,26 +704,23 @@ jobs:
pip3 install toml pip3 install toml
gcc --version gcc --version
python3 --version python3 --version
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
continue-on-error: true continue-on-error: true
with: with:
pattern: '{sizes,sizes-*}' name: sizes
merge-multiple: true
path: sizes path: sizes
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
continue-on-error: true continue-on-error: true
with: with:
pattern: '{cov,cov-*}' name: cov
merge-multiple: true
path: cov path: cov
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
continue-on-error: true continue-on-error: true
with: with:
pattern: '{bench,bench-*}' name: bench
merge-multiple: true
path: bench path: bench
# try to find results from tests # try to find results from tests
@@ -866,7 +862,7 @@ jobs:
body: $comment, body: $comment,
}' | tee comment/comment.json }' | tee comment/comment.json
- name: upload-comment - name: upload-comment
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: comment name: comment
path: comment path: comment

View File

@@ -231,25 +231,11 @@ 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 to use littlefs in a Rust-friendly API, reaping the benefits of Rust's memory
safety and other guarantees. 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-img-viewer] - A memory-efficient web application for viewing
littlefs disk images in your web browser. littlefs disk images in your web browser.
- [mklfs] - A command line tool for creating littlefs images. Used in the Lua - [mklfs] - A command line tool built by the [Lua RTOS] guys for making
RTOS ecosystem. littlefs images from a host PC. Supports Windows, Mac OS, and Linux.
- [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 - [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. which already has block device drivers for most forms of embedded storage.
@@ -268,21 +254,23 @@ License Identifiers that are here available: http://spdx.org/licenses/
for microcontroller-scale devices. Due to limitations of FAT it can't provide for microcontroller-scale devices. Due to limitations of FAT it can't provide
power-loss resilience, but it does allow easy interop with PCs. 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.
[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html [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 [littlefs-fuse]: https://github.com/geky/littlefs-fuse
[FUSE]: https://github.com/libfuse/libfuse [FUSE]: https://github.com/libfuse/libfuse
[littlefs-js]: https://github.com/geky/littlefs-js [littlefs-js]: https://github.com/geky/littlefs-js
[littlefs-js-demo]:http://littlefs.geky.net/demo.html [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 [mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src
[mklittlefs]: https://github.com/earlephilhower/mklittlefs [Lua RTOS]: https://github.com/whitecatboard/Lua-RTOS-ESP32
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb
[Mbed OS]: https://github.com/armmbed/mbed-os [Mbed OS]: https://github.com/armmbed/mbed-os
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs [SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara [Dhara]: https://github.com/dlbeer/dhara
[ChaN's FatFs]: http://elm-chan.org/fsw/ff/00index_e.html [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

View File

@@ -441,10 +441,9 @@ Superblock fields:
7. **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 the metadata pair, and The superblock must always be the first entry (id 0) in a metadata pair as well
the name tag must always be the first tag in the metadata pair. This makes it as be the first entry written to the block. This means that the superblock
so that the magic string "littlefs" will always reside at offset=8 in a valid entry can be read from a device using offsets alone.
littlefs superblock.
--- ---
#### `0x2xx` LFS_TYPE_STRUCT #### `0x2xx` LFS_TYPE_STRUCT

View File

@@ -129,8 +129,6 @@ int lfs_emubd_create(const struct lfs_config *cfg,
bd->proged = 0; bd->proged = 0;
bd->erased = 0; bd->erased = 0;
bd->power_cycles = bd->cfg->power_cycles; bd->power_cycles = bd->cfg->power_cycles;
bd->ooo_block = -1;
bd->ooo_data = NULL;
bd->disk = NULL; bd->disk = NULL;
if (bd->cfg->disk_path) { if (bd->cfg->disk_path) {
@@ -197,7 +195,6 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
free(bd->blocks); free(bd->blocks);
// clean up other resources // clean up other resources
lfs_emubd_decblock(bd->ooo_data);
if (bd->disk) { if (bd->disk) {
bd->disk->rc -= 1; bd->disk->rc -= 1;
if (bd->disk->rc == 0) { if (bd->disk->rc == 0) {
@@ -212,75 +209,6 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
} }
// powerloss hook
static int lfs_emubd_powerloss(const struct lfs_config *cfg) {
lfs_emubd_t *bd = cfg->context;
// emulate out-of-order writes?
lfs_emubd_block_t *ooo_data = NULL;
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
// since writes between syncs are allowed to be out-of-order, it
// shouldn't hurt to restore the first write on powerloss, right?
ooo_data = bd->blocks[bd->ooo_block];
bd->blocks[bd->ooo_block] = lfs_emubd_incblock(bd->ooo_data);
// mirror to disk file?
if (bd->disk
&& (bd->blocks[bd->ooo_block]
|| bd->cfg->erase_value != -1)) {
off_t res1 = lseek(bd->disk->fd,
(off_t)bd->ooo_block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
return -errno;
}
ssize_t res2 = write(bd->disk->fd,
(bd->blocks[bd->ooo_block])
? bd->blocks[bd->ooo_block]->data
: bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
return -errno;
}
}
}
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
// if we continue, undo out-of-order write emulation
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
lfs_emubd_decblock(bd->blocks[bd->ooo_block]);
bd->blocks[bd->ooo_block] = ooo_data;
// mirror to disk file?
if (bd->disk
&& (bd->blocks[bd->ooo_block]
|| bd->cfg->erase_value != -1)) {
off_t res1 = lseek(bd->disk->fd,
(off_t)bd->ooo_block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
return -errno;
}
ssize_t res2 = write(bd->disk->fd,
(bd->blocks[bd->ooo_block])
? bd->blocks[bd->ooo_block]->data
: bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
return -errno;
}
}
}
return 0;
}
// block device API // block device API
@@ -416,11 +344,8 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
if (bd->power_cycles > 0) { if (bd->power_cycles > 0) {
bd->power_cycles -= 1; bd->power_cycles -= 1;
if (bd->power_cycles == 0) { if (bd->power_cycles == 0) {
int err = lfs_emubd_powerloss(cfg); // simulate power loss
if (err) { bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err);
return err;
}
} }
} }
@@ -436,17 +361,10 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < bd->cfg->erase_count); LFS_ASSERT(block < bd->cfg->erase_count);
// emulate out-of-order writes? save first write
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
&& bd->ooo_block == -1) {
bd->ooo_block = block;
bd->ooo_data = lfs_emubd_incblock(bd->blocks[block]);
}
// get the block // get the block
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]); lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) { if (!b) {
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_NOMEM); LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM; return LFS_ERR_NOMEM;
} }
@@ -512,11 +430,8 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
if (bd->power_cycles > 0) { if (bd->power_cycles > 0) {
bd->power_cycles -= 1; bd->power_cycles -= 1;
if (bd->power_cycles == 0) { if (bd->power_cycles == 0) {
int err = lfs_emubd_powerloss(cfg); // simulate power loss
if (err) { bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
return err;
}
} }
} }
@@ -526,24 +441,17 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
int lfs_emubd_sync(const struct lfs_config *cfg) { int lfs_emubd_sync(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_sync(%p)", (void*)cfg); LFS_EMUBD_TRACE("lfs_emubd_sync(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
// emulate out-of-order writes? reset first write, writes // do nothing
// cannot be out-of-order across sync (void)cfg;
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) {
lfs_emubd_decblock(bd->ooo_data);
bd->ooo_block = -1;
bd->ooo_data = NULL;
}
LFS_EMUBD_TRACE("lfs_emubd_sync -> %d", 0); LFS_EMUBD_TRACE("lfs_emubd_sync -> %d", 0);
return 0; return 0;
} }
/// Additional extended API for driving test features /// /// Additional extended API for driving test features ///
static int lfs_emubd_crc_(const struct lfs_config *cfg, static int lfs_emubd_rawcrc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) { lfs_block_t block, uint32_t *crc) {
lfs_emubd_t *bd = cfg->context; lfs_emubd_t *bd = cfg->context;
@@ -572,7 +480,7 @@ int lfs_emubd_crc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) { lfs_block_t block, uint32_t *crc) {
LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)", LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)",
(void*)cfg, block, crc); (void*)cfg, block, crc);
int err = lfs_emubd_crc_(cfg, block, crc); int err = lfs_emubd_rawcrc(cfg, block, crc);
LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err); LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err);
return err; return err;
} }
@@ -583,7 +491,7 @@ int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc) {
uint32_t crc_ = 0xffffffff; uint32_t crc_ = 0xffffffff;
for (lfs_block_t i = 0; i < cfg->block_count; i++) { for (lfs_block_t i = 0; i < cfg->block_count; i++) {
uint32_t i_crc; uint32_t i_crc;
int err = lfs_emubd_crc_(cfg, i, &i_crc); int err = lfs_emubd_rawcrc(cfg, i, &i_crc);
if (err) { if (err) {
LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err); LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err);
return err; return err;
@@ -725,8 +633,6 @@ int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) {
copy->proged = bd->proged; copy->proged = bd->proged;
copy->erased = bd->erased; copy->erased = bd->erased;
copy->power_cycles = bd->power_cycles; copy->power_cycles = bd->power_cycles;
copy->ooo_block = bd->ooo_block;
copy->ooo_data = lfs_emubd_incblock(bd->ooo_data);
copy->disk = bd->disk; copy->disk = bd->disk;
if (copy->disk) { if (copy->disk) {
copy->disk->rc += 1; copy->disk->rc += 1;

View File

@@ -36,18 +36,17 @@ extern "C"
// Not that read-noop is not allowed. Read _must_ return a consistent (but // Not that read-noop is not allowed. Read _must_ return a consistent (but
// may be arbitrary) value on every read. // may be arbitrary) value on every read.
typedef enum lfs_emubd_badblock_behavior { typedef enum lfs_emubd_badblock_behavior {
LFS_EMUBD_BADBLOCK_PROGERROR = 0, // Error on prog LFS_EMUBD_BADBLOCK_PROGERROR,
LFS_EMUBD_BADBLOCK_ERASEERROR = 1, // Error on erase LFS_EMUBD_BADBLOCK_ERASEERROR,
LFS_EMUBD_BADBLOCK_READERROR = 2, // Error on read LFS_EMUBD_BADBLOCK_READERROR,
LFS_EMUBD_BADBLOCK_PROGNOOP = 3, // Prog does nothing silently LFS_EMUBD_BADBLOCK_PROGNOOP,
LFS_EMUBD_BADBLOCK_ERASENOOP = 4, // Erase does nothing silently LFS_EMUBD_BADBLOCK_ERASENOOP,
} lfs_emubd_badblock_behavior_t; } lfs_emubd_badblock_behavior_t;
// Mode determining how power-loss behaves during testing. For now this // Mode determining how power-loss behaves during testing. For now this
// only supports a noop behavior, leaving the data on-disk untouched. // only supports a noop behavior, leaving the data on-disk untouched.
typedef enum lfs_emubd_powerloss_behavior { typedef enum lfs_emubd_powerloss_behavior {
LFS_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic LFS_EMUBD_POWERLOSS_NOOP,
LFS_EMUBD_POWERLOSS_OOO = 1, // Blocks are written out-of-order
} lfs_emubd_powerloss_behavior_t; } lfs_emubd_powerloss_behavior_t;
// Type for measuring read/program/erase operations // Type for measuring read/program/erase operations
@@ -153,8 +152,6 @@ typedef struct lfs_emubd {
lfs_emubd_io_t proged; lfs_emubd_io_t proged;
lfs_emubd_io_t erased; lfs_emubd_io_t erased;
lfs_emubd_powercycles_t power_cycles; lfs_emubd_powercycles_t power_cycles;
lfs_ssize_t ooo_block;
lfs_emubd_block_t *ooo_data;
lfs_emubd_disk_t *disk; lfs_emubd_disk_t *disk;
const struct lfs_emubd_config *cfg; const struct lfs_emubd_config *cfg;

543
lfs.c

File diff suppressed because it is too large Load Diff

94
lfs.h
View File

@@ -21,7 +21,7 @@ extern "C"
// Software library version // Software library version
// Major (top-nibble), incremented on backwards incompatible changes // Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions // Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00020009 #define LFS_VERSION 0x00020008
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -52,15 +52,16 @@ typedef uint32_t lfs_block_t;
#endif #endif
// Maximum size of a file in bytes, may be redefined to limit to support other // Maximum size of a file in bytes, may be redefined to limit to support other
// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be // drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
// respected by other littlefs drivers. // functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS_FILE_MAX #ifndef LFS_FILE_MAX
#define LFS_FILE_MAX 2147483647 #define LFS_FILE_MAX 2147483647
#endif #endif
// Maximum size of custom attributes in bytes, may be redefined, but there is // Maximum size of custom attributes in bytes, may be redefined, but there is
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored // no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
// in superblock and must be respected by other littlefs drivers.
#ifndef LFS_ATTR_MAX #ifndef LFS_ATTR_MAX
#define LFS_ATTR_MAX 1022 #define LFS_ATTR_MAX 1022
#endif #endif
@@ -204,8 +205,7 @@ struct lfs_config {
// program sizes. // program sizes.
lfs_size_t block_size; lfs_size_t block_size;
// Number of erasable blocks on the device. Defaults to block_count stored // Number of erasable blocks on the device.
// on disk when zero.
lfs_size_t block_count; lfs_size_t block_count;
// Number of erase cycles before littlefs evicts metadata logs and moves // Number of erase cycles before littlefs evicts metadata logs and moves
@@ -226,20 +226,9 @@ struct lfs_config {
// Size of the lookahead buffer in bytes. A larger lookahead buffer // Size of the lookahead buffer in bytes. A larger lookahead buffer
// increases the number of blocks found during an allocation pass. The // increases the number of blocks found during an allocation pass. The
// lookahead buffer is stored as a compact bitmap, so each byte of RAM // lookahead buffer is stored as a compact bitmap, so each byte of RAM
// can track 8 blocks. // can track 8 blocks. Must be a multiple of 8.
lfs_size_t lookahead_size; lfs_size_t lookahead_size;
// Threshold for metadata compaction during lfs_fs_gc in bytes. Metadata
// pairs that exceed this threshold will be compacted during lfs_fs_gc.
// Defaults to ~88% block_size when zero, though the default may change
// in the future.
//
// Note this only affects lfs_fs_gc. Normal compactions still only occur
// when full.
//
// Set to -1 to disable metadata compaction during lfs_fs_gc.
lfs_size_t compact_thresh;
// Optional statically allocated read buffer. Must be cache_size. // Optional statically allocated read buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer. // By default lfs_malloc is used to allocate this buffer.
void *read_buffer; void *read_buffer;
@@ -248,24 +237,25 @@ struct lfs_config {
// By default lfs_malloc is used to allocate this buffer. // By default lfs_malloc is used to allocate this buffer.
void *prog_buffer; void *prog_buffer;
// Optional statically allocated lookahead buffer. Must be lookahead_size. // Optional statically allocated lookahead buffer. Must be lookahead_size
// By default lfs_malloc is used to allocate this buffer. // and aligned to a 32-bit boundary. By default lfs_malloc is used to
// allocate this buffer.
void *lookahead_buffer; void *lookahead_buffer;
// Optional upper limit on length of file names in bytes. No downside for // Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by // larger names except the size of the info struct which is controlled by
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
// disk when zero. // superblock and must be respected by other littlefs drivers.
lfs_size_t name_max; lfs_size_t name_max;
// Optional upper limit on files in bytes. No downside for larger files // Optional upper limit on files in bytes. No downside for larger files
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
// on disk when zero. // in superblock and must be respected by other littlefs drivers.
lfs_size_t file_max; lfs_size_t file_max;
// Optional upper limit on custom attributes in bytes. No downside for // Optional upper limit on custom attributes in bytes. No downside for
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX or attr_max stored on disk when zero. // LFS_ATTR_MAX when zero.
lfs_size_t attr_max; lfs_size_t attr_max;
// Optional upper limit on total space given to metadata pairs in bytes. On // Optional upper limit on total space given to metadata pairs in bytes. On
@@ -274,15 +264,6 @@ struct lfs_config {
// Defaults to block_size when zero. // Defaults to block_size when zero.
lfs_size_t metadata_max; lfs_size_t metadata_max;
// Optional upper limit on inlined files in bytes. Inlined files live in
// metadata and decrease storage requirements, but may be limited to
// improve metadata-related performance. Must be <= cache_size, <=
// attr_max, and <= block_size/8. Defaults to the largest possible
// inline_max when zero.
//
// Set to -1 to disable inlined files.
lfs_size_t inline_max;
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
// On-disk version to use when writing in the form of 16-bit major version // On-disk version to use when writing in the form of 16-bit major version
// + 16-bit minor version. This limiting metadata to what is supported by // + 16-bit minor version. This limiting metadata to what is supported by
@@ -449,20 +430,19 @@ typedef struct lfs {
lfs_gstate_t gdisk; lfs_gstate_t gdisk;
lfs_gstate_t gdelta; lfs_gstate_t gdelta;
struct lfs_lookahead { struct lfs_free {
lfs_block_t start; lfs_block_t off;
lfs_block_t size; lfs_block_t size;
lfs_block_t next; lfs_block_t i;
lfs_block_t ckpoint; lfs_block_t ack;
uint8_t *buffer; uint32_t *buffer;
} lookahead; } free;
const struct lfs_config *cfg; const struct lfs_config *cfg;
lfs_size_t block_count; lfs_size_t block_count;
lfs_size_t name_max; lfs_size_t name_max;
lfs_size_t file_max; lfs_size_t file_max;
lfs_size_t attr_max; lfs_size_t attr_max;
lfs_size_t inline_max;
#ifdef LFS_MIGRATE #ifdef LFS_MIGRATE
struct lfs1 *lfs1; struct lfs1 *lfs1;
@@ -732,6 +712,18 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
// Attempt to proactively find free blocks
//
// Calling this function is not required, but may allowing the offloading of
// the expensive block allocation scan to a less time-critical code path.
//
// Note: littlefs currently does not persist any found free blocks to disk.
// This may change in the future.
//
// Returns a negative error code on failure. Finding no free blocks is
// not an error.
int lfs_fs_gc(lfs_t *lfs);
#ifndef LFS_READONLY #ifndef LFS_READONLY
// Attempt to make the filesystem consistent and ready for writing // Attempt to make the filesystem consistent and ready for writing
// //
@@ -744,24 +736,6 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
int lfs_fs_mkconsistent(lfs_t *lfs); int lfs_fs_mkconsistent(lfs_t *lfs);
#endif #endif
#ifndef LFS_READONLY
// Attempt any janitorial work
//
// This currently:
// 1. Calls mkconsistent if not already consistent
// 2. Compacts metadata > compact_thresh
// 3. Populates the block allocator
//
// Though additional janitorial work may be added in the future.
//
// Calling this function is not required, but may allow the offloading of
// expensive janitorial work to a less time-critical code path.
//
// Returns a negative error code on failure. Accomplishing nothing is not
// an error.
int lfs_fs_gc(lfs_t *lfs);
#endif
#ifndef LFS_READONLY #ifndef LFS_READONLY
// Grows the filesystem to a new size, updating the superblock with the new // Grows the filesystem to a new size, updating the superblock with the new
// block count. // block count.

View File

@@ -11,8 +11,6 @@
#ifndef LFS_CONFIG #ifndef LFS_CONFIG
// If user provides their own CRC impl we don't need this
#ifndef LFS_CRC
// Software CRC implementation with small lookup table // Software CRC implementation with small lookup table
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = { static const uint32_t rtable[16] = {
@@ -31,7 +29,6 @@ uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
return crc; return crc;
} }
#endif
#endif #endif

View File

@@ -212,22 +212,12 @@ static inline uint32_t lfs_tobe32(uint32_t a) {
} }
// Calculate CRC-32 with polynomial = 0x04c11db7 // Calculate CRC-32 with polynomial = 0x04c11db7
#ifdef LFS_CRC
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
return LFS_CRC(crc, buffer, size)
}
#else
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
#endif
// Allocate memory, only used if buffers are not provided to littlefs // Allocate memory, only used if buffers are not provided to littlefs
// // Note, memory must be 64-bit aligned
// littlefs current has no alignment requirements, as it only allocates
// byte-level buffers.
static inline void *lfs_malloc(size_t size) { static inline void *lfs_malloc(size_t size) {
#if defined(LFS_MALLOC) #ifndef LFS_NO_MALLOC
return LFS_MALLOC(size);
#elif !defined(LFS_NO_MALLOC)
return malloc(size); return malloc(size);
#else #else
(void)size; (void)size;
@@ -237,9 +227,7 @@ static inline void *lfs_malloc(size_t size) {
// Deallocate memory, only used if buffers are not provided to littlefs // Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) { static inline void lfs_free(void *p) {
#if defined(LFS_FREE) #ifndef LFS_NO_MALLOC
LFS_FREE(p);
#elif !defined(LFS_NO_MALLOC)
free(p); free(p);
#else #else
(void)p; (void)p;

View File

@@ -1321,8 +1321,6 @@ void perm_run(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
}; };
struct lfs_emubd_config bdcfg = { struct lfs_emubd_config bdcfg = {

View File

@@ -95,13 +95,11 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT_i 5 #define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6 #define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7 #define LOOKAHEAD_SIZE_i 7
#define COMPACT_THRESH_i 8 #define BLOCK_CYCLES_i 8
#define INLINE_MAX_i 9 #define ERASE_VALUE_i 9
#define BLOCK_CYCLES_i 10 #define ERASE_CYCLES_i 10
#define ERASE_VALUE_i 11 #define BADBLOCK_BEHAVIOR_i 11
#define ERASE_CYCLES_i 12 #define POWERLOSS_BEHAVIOR_i 12
#define BADBLOCK_BEHAVIOR_i 13
#define POWERLOSS_BEHAVIOR_i 14
#define READ_SIZE bench_define(READ_SIZE_i) #define READ_SIZE bench_define(READ_SIZE_i)
#define PROG_SIZE bench_define(PROG_SIZE_i) #define PROG_SIZE bench_define(PROG_SIZE_i)
@@ -111,8 +109,6 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i) #define BLOCK_COUNT bench_define(BLOCK_COUNT_i)
#define CACHE_SIZE bench_define(CACHE_SIZE_i) #define CACHE_SIZE bench_define(CACHE_SIZE_i)
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i) #define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
#define COMPACT_THRESH bench_define(COMPACT_THRESH_i)
#define INLINE_MAX bench_define(INLINE_MAX_i)
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i) #define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
#define ERASE_VALUE bench_define(ERASE_VALUE_i) #define ERASE_VALUE bench_define(ERASE_VALUE_i)
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i) #define ERASE_CYCLES bench_define(ERASE_CYCLES_i)
@@ -128,8 +124,6 @@ intmax_t bench_define(size_t define);
BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\ BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\
BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
BENCH_DEF(LOOKAHEAD_SIZE, 16) \ BENCH_DEF(LOOKAHEAD_SIZE, 16) \
BENCH_DEF(COMPACT_THRESH, 0) \
BENCH_DEF(INLINE_MAX, 0) \
BENCH_DEF(BLOCK_CYCLES, -1) \ BENCH_DEF(BLOCK_CYCLES, -1) \
BENCH_DEF(ERASE_VALUE, 0xff) \ BENCH_DEF(ERASE_VALUE, 0xff) \
BENCH_DEF(ERASE_CYCLES, 0) \ BENCH_DEF(ERASE_CYCLES, 0) \
@@ -137,7 +131,7 @@ intmax_t bench_define(size_t define);
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
#define BENCH_GEOMETRY_DEFINE_COUNT 4 #define BENCH_GEOMETRY_DEFINE_COUNT 4
#define BENCH_IMPLICIT_DEFINE_COUNT 15 #define BENCH_IMPLICIT_DEFINE_COUNT 13
#endif #endif

View File

@@ -1346,8 +1346,6 @@ static void run_powerloss_none(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1424,8 +1422,6 @@ static void run_powerloss_linear(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1519,8 +1515,6 @@ static void run_powerloss_log(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1612,8 +1606,6 @@ static void run_powerloss_cycles(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1803,8 +1795,6 @@ static void run_powerloss_exhaustive(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif

View File

@@ -88,14 +88,12 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT_i 5 #define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6 #define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7 #define LOOKAHEAD_SIZE_i 7
#define COMPACT_THRESH_i 8 #define BLOCK_CYCLES_i 8
#define INLINE_MAX_i 9 #define ERASE_VALUE_i 9
#define BLOCK_CYCLES_i 10 #define ERASE_CYCLES_i 10
#define ERASE_VALUE_i 11 #define BADBLOCK_BEHAVIOR_i 11
#define ERASE_CYCLES_i 12 #define POWERLOSS_BEHAVIOR_i 12
#define BADBLOCK_BEHAVIOR_i 13 #define DISK_VERSION_i 13
#define POWERLOSS_BEHAVIOR_i 14
#define DISK_VERSION_i 15
#define READ_SIZE TEST_DEFINE(READ_SIZE_i) #define READ_SIZE TEST_DEFINE(READ_SIZE_i)
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i) #define PROG_SIZE TEST_DEFINE(PROG_SIZE_i)
@@ -105,8 +103,6 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i) #define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i)
#define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i) #define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i)
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i) #define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i)
#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i)
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i) #define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i) #define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i)
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i) #define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i)
@@ -123,8 +119,6 @@ intmax_t test_define(size_t define);
TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \ TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \
TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
TEST_DEF(LOOKAHEAD_SIZE, 16) \ TEST_DEF(LOOKAHEAD_SIZE, 16) \
TEST_DEF(COMPACT_THRESH, 0) \
TEST_DEF(INLINE_MAX, 0) \
TEST_DEF(BLOCK_CYCLES, -1) \ TEST_DEF(BLOCK_CYCLES, -1) \
TEST_DEF(ERASE_VALUE, 0xff) \ TEST_DEF(ERASE_VALUE, 0xff) \
TEST_DEF(ERASE_CYCLES, 0) \ TEST_DEF(ERASE_CYCLES, 0) \
@@ -133,7 +127,7 @@ intmax_t test_define(size_t define);
TEST_DEF(DISK_VERSION, 0) TEST_DEF(DISK_VERSION, 0)
#define TEST_GEOMETRY_DEFINE_COUNT 4 #define TEST_GEOMETRY_DEFINE_COUNT 4
#define TEST_IMPLICIT_DEFINE_COUNT 16 #define TEST_IMPLICIT_DEFINE_COUNT 14
#endif #endif

View File

@@ -7,23 +7,17 @@ if = 'BLOCK_CYCLES == -1'
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.GC = [false, true] defines.GC = [false, true]
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -44,7 +38,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -66,23 +60,17 @@ code = '''
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.GC = [false, true] defines.GC = [false, true]
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file; lfs_file_t file;
@@ -101,7 +89,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -123,24 +111,19 @@ code = '''
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.CYCLES = [1, 10] defines.CYCLES = [1, 10]
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg;
if (INFER_BC) {
cfg_.block_count = 0;
}
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -158,7 +141,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -174,7 +157,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -190,24 +173,19 @@ code = '''
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.CYCLES = [1, 10] defines.CYCLES = [1, 10]
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg;
if (INFER_BC) {
cfg_.block_count = 0;
}
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file; lfs_file_t file;
@@ -252,15 +230,10 @@ code = '''
# exhaustion test # exhaustion test
[cases.test_alloc_exhaustion] [cases.test_alloc_exhaustion]
defines.INFER_BC = [false, true]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_file_t file; lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size_t size = strlen("exhaustion"); size_t size = strlen("exhaustion");
@@ -288,7 +261,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -301,15 +274,10 @@ code = '''
# exhaustion wraparound test # exhaustion wraparound test
[cases.test_alloc_exhaustion_wraparound] [cases.test_alloc_exhaustion_wraparound]
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
defines.INFER_BC = [false, true]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_file_t file; lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
@@ -347,7 +315,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -360,15 +328,10 @@ code = '''
# dir exhaustion test # dir exhaustion test
[cases.test_alloc_dir_exhaustion] [cases.test_alloc_dir_exhaustion]
defines.INFER_BC = [false, true]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;

View File

@@ -181,10 +181,6 @@ code = '''
defines.N = [5, 11] defines.N = [5, 11]
if = 'BLOCK_COUNT >= 4*N' if = 'BLOCK_COUNT >= 4*N'
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -443,10 +439,6 @@ code = '''
defines.N = [5, 25] defines.N = [5, 25]
if = 'N < BLOCK_COUNT/2' if = 'N < BLOCK_COUNT/2'
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -755,11 +747,6 @@ code = '''
lfs_file_open(&lfs, &file, "potato", lfs_file_open(&lfs, &file, "potato",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "tacoto", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_rename(&lfs, "tacoto", "potato") => LFS_ERR_ISDIR;
lfs_rename(&lfs, "potato", "tacoto") => LFS_ERR_NOTDIR;
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
lfs_file_open(&lfs, &file, "/", lfs_file_open(&lfs, &file, "/",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
@@ -783,10 +770,6 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "potato") == 0); assert(strcmp(info.name, "potato") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
assert(strcmp(info.name, "tacoto") == 0);
assert(info.size == 0);
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
@@ -807,10 +790,6 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "potato") == 0); assert(strcmp(info.name, "potato") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
assert(strcmp(info.name, "tacoto") == 0);
assert(info.size == 0);
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;

View File

@@ -1,6 +1,5 @@
[cases.test_files_simple] [cases.test_files_simple]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -26,7 +25,6 @@ code = '''
[cases.test_files_large] [cases.test_files_large]
defines.SIZE = [32, 8192, 262144, 0, 7, 8193] defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 33, 1, 1023] defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -69,7 +67,6 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -155,7 +152,6 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -236,7 +232,6 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -308,12 +303,7 @@ code = '''
[cases.test_files_reentrant_write] [cases.test_files_reentrant_write]
defines.SIZE = [32, 0, 7, 2049] defines.SIZE = [32, 0, 7, 2049]
defines.CHUNKSIZE = [31, 16, 65] defines.CHUNKSIZE = [31, 16, 65]
defines.INLINE_MAX = [0, -1, 8]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -364,20 +354,11 @@ code = '''
[cases.test_files_reentrant_write_sync] [cases.test_files_reentrant_write_sync]
defines = [ defines = [
# append (O(n)) # append (O(n))
{MODE='LFS_O_APPEND', {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
SIZE=[32, 0, 7, 2049],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
# truncate (O(n^2)) # truncate (O(n^2))
{MODE='LFS_O_TRUNC', {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
SIZE=[32, 0, 7, 200],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
# rewrite (O(n^2)) # rewrite (O(n^2))
{MODE=0, {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
SIZE=[32, 0, 7, 200],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
] ]
reentrant = true reentrant = true
code = ''' code = '''
@@ -504,10 +485,6 @@ code = '''
[cases.test_files_many_power_loss] [cases.test_files_many_power_loss]
defines.N = 300 defines.N = 300
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);

View File

@@ -195,10 +195,6 @@ code = '''
defines.SIZE = [10, 100] defines.SIZE = [10, 100]
defines.FILES = [4, 10, 26] defines.FILES = [4, 10, 26]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_file_t files[FILES]; lfs_file_t files[FILES];

View File

@@ -357,10 +357,6 @@ code = '''
[cases.test_move_reentrant_file] [cases.test_move_reentrant_file]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -843,10 +839,6 @@ code = '''
[cases.test_reentrant_dir] [cases.test_reentrant_dir]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);

View File

@@ -98,7 +98,7 @@ code = '''
lfs_mount(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// create an orphan // create an orphan
lfs_mdir_t orphan; lfs_mdir_t orphan;
lfs_alloc_ckpoint(&lfs); lfs_alloc_ack(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0; lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
@@ -170,7 +170,7 @@ code = '''
lfs_mount(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// create an orphan // create an orphan
lfs_mdir_t orphan; lfs_mdir_t orphan;
lfs_alloc_ckpoint(&lfs); lfs_alloc_ack(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0; lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;

View File

@@ -329,10 +329,6 @@ code = '''
# must be power-of-2 for quadratic probing to be exhaustive # must be power-of-2 for quadratic probing to be exhaustive
defines.COUNT = [4, 64, 128] defines.COUNT = [4, 64, 128]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -405,111 +401,3 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
# test possible overflow/underflow conditions
#
# note these need -fsanitize=undefined to consistently detect
# overflow/underflow conditions
[cases.test_seek_filemax]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs_file_write(&lfs, &file, buffer, size) => size;
// seek with LFS_SEEK_SET
lfs_file_seek(&lfs, &file, LFS_FILE_MAX, LFS_SEEK_SET) => LFS_FILE_MAX;
// seek with LFS_SEEK_CUR
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => LFS_FILE_MAX;
// the file hasn't changed size, so seek end takes us back to the offset=0
lfs_file_seek(&lfs, &file, +10, LFS_SEEK_END) => size+10;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_seek_underflow]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs_file_write(&lfs, &file, buffer, size) => size;
// underflow with LFS_SEEK_CUR, should error
lfs_file_seek(&lfs, &file, -(size+10), LFS_SEEK_CUR) => LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file, -LFS_FILE_MAX, LFS_SEEK_CUR) => LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file, -(size+LFS_FILE_MAX), LFS_SEEK_CUR)
=> LFS_ERR_INVAL;
// underflow with LFS_SEEK_END, should error
lfs_file_seek(&lfs, &file, -(size+10), LFS_SEEK_END) => LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file, -LFS_FILE_MAX, LFS_SEEK_END) => LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file, -(size+LFS_FILE_MAX), LFS_SEEK_END)
=> LFS_ERR_INVAL;
// file pointer should not have changed
lfs_file_tell(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_seek_overflow]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs_file_write(&lfs, &file, buffer, size) => size;
// seek to LFS_FILE_MAX
lfs_file_seek(&lfs, &file, LFS_FILE_MAX, LFS_SEEK_SET) => LFS_FILE_MAX;
// overflow with LFS_SEEK_CUR, should error
lfs_file_seek(&lfs, &file, +10, LFS_SEEK_CUR) => LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file, +LFS_FILE_MAX, LFS_SEEK_CUR) => LFS_ERR_INVAL;
// LFS_SEEK_SET/END don't care about the current file position, but we can
// still overflow with a large offset
// overflow with LFS_SEEK_SET, should error
lfs_file_seek(&lfs, &file,
+((uint32_t)LFS_FILE_MAX+10),
LFS_SEEK_SET) => LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file,
+((uint32_t)LFS_FILE_MAX+(uint32_t)LFS_FILE_MAX),
LFS_SEEK_SET) => LFS_ERR_INVAL;
// overflow with LFS_SEEK_END, should error
lfs_file_seek(&lfs, &file, +(LFS_FILE_MAX-size+10), LFS_SEEK_END)
=> LFS_ERR_INVAL;
lfs_file_seek(&lfs, &file, +(LFS_FILE_MAX-size+LFS_FILE_MAX), LFS_SEEK_END)
=> LFS_ERR_INVAL;
// file pointer should not have changed
lfs_file_tell(&lfs, &file) => LFS_FILE_MAX;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -14,24 +14,6 @@ code = '''
lfs_unmount(&lfs) => 0; 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 # mount/unmount from interpretting a previous superblock block_count
[cases.test_superblocks_mount_unknown_block_count] [cases.test_superblocks_mount_unknown_block_count]
code = ''' code = '''
@@ -46,13 +28,10 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
# reentrant format # reentrant format
[cases.test_superblocks_reentrant_format] [cases.test_superblocks_reentrant_format]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -152,39 +131,6 @@ code = '''
lfs_unmount(&lfs) => 0; 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 # expanding superblock with power cycle
[cases.test_superblocks_expand_power_cycle] [cases.test_superblocks_expand_power_cycle]
defines.BLOCK_CYCLES = [32, 33, 1] defines.BLOCK_CYCLES = [32, 33, 1]
@@ -228,10 +174,6 @@ code = '''
defines.BLOCK_CYCLES = [2, 1] defines.BLOCK_CYCLES = [2, 1]
defines.N = 24 defines.N = 24
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -271,7 +213,6 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
# mount with unknown block_count # mount with unknown block_count
[cases.test_superblocks_unknown_blocks] [cases.test_superblocks_unknown_blocks]
code = ''' code = '''

View File

@@ -231,10 +231,6 @@ defines.SMALLSIZE = [4, 512]
defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025] defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025]
defines.LARGESIZE = 2048 defines.LARGESIZE = 2048
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);